diff --git a/.gitignore b/.gitignore index 1b54572f2f..9ba862d685 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ mystery_result_*.yaml /db.db3 *-errors.txt success.txt +output/ +Output Logs/ diff --git a/EntranceShuffle.py b/EntranceShuffle.py index a89ac83793..66a9a65746 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -139,7 +139,7 @@ def link_entrances(world, player): dw_must_exits = list(DW_Entrances_Must_Exit) old_man_entrances = list(Old_Man_Entrances) caves = list(Cave_Exits + Cave_Three_Exits) - single_doors = list(Single_Cave_Doors) + bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors) blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) door_targets = list(Single_Cave_Targets) diff --git a/Gui.py b/Gui.py index 94a145abeb..9dc00d6a20 100755 --- a/Gui.py +++ b/Gui.py @@ -1525,8 +1525,8 @@ class SpriteSelector(): title_link.pack(side=LEFT) title_link.bind("", open_custom_sprite_dir) - self.icon_section(alttpr_frametitle, self.alttpr_sprite_dir + '/*', 'ALTTPR sprites not found. Click "Update alttpr sprites" to download them.') - self.icon_section(custom_frametitle, self.custom_sprite_dir + '/*', 'Put sprites in the custom sprites folder (see open link above) to have them appear here.') + self.icon_section(alttpr_frametitle, self.alttpr_sprite_dir, 'ALTTPR sprites not found. Click "Update alttpr sprites" to download them.') + self.icon_section(custom_frametitle, self.custom_sprite_dir, 'Put sprites in the custom sprites folder (see open link above) to have them appear here.') frame = Frame(self.window) frame.pack(side=BOTTOM, fill=X, pady=5) @@ -1585,19 +1585,21 @@ class SpriteSelector(): sprites = [] - for file in glob(output_path(path)): - sprites.append(Sprite(file)) + for file in os.listdir(path): + sprites.append((file, Sprite(os.path.join(path, file)))) - sprites.sort(key=lambda s: str.lower(s.name or "").strip()) + sprites.sort(key=lambda s: str.lower(s[1].name or "").strip()) frame.buttons = [] - for sprite in sprites: + for file, sprite in sprites: image = get_image_for_sprite(sprite) if image is None: continue self.all_sprites.append(sprite) button = Button(frame, image=image, command=lambda spr=sprite: self.select_sprite(spr)) - ToolTips.register(button, sprite.name + ("\nBy: %s" % sprite.author_name if sprite.author_name else "")) + ToolTips.register(button, sprite.name + + ("\nBy: %s" % sprite.author_name if sprite.author_name else "") + + f"\nFrom: {file}") button.image = image frame.buttons.append(button) diff --git a/Regions.py b/Regions.py index bdef78acb5..4326e7d16f 100644 --- a/Regions.py +++ b/Regions.py @@ -1,4 +1,5 @@ import collections +import typing from BaseClasses import Region, Location, Entrance, RegionType, Shop, TakeAny, UpgradeShop, ShopType @@ -450,247 +451,257 @@ key_drop_data = { 'Ganons Tower - Mini Helmasaur Key Drop': [0x14001e, 0x14001f] } -location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'), - 'Bottle Merchant': (0x2eb18, 0x186339, False, 'with a merchant'), - 'Flute Spot': (0x18014a, 0x18633d, False, 'underground'), - 'Sunken Treasure': (0x180145, 0x186354, False, 'underwater'), - 'Purple Chest': (0x33d68, 0x186359, False, 'from a box'), - "Blind's Hideout - Top": (0xeb0f, 0x1862e3, False, 'in a basement'), - "Blind's Hideout - Left": (0xeb12, 0x1862e6, False, 'in a basement'), - "Blind's Hideout - Right": (0xeb15, 0x1862e9, False, 'in a basement'), - "Blind's Hideout - Far Left": (0xeb18, 0x1862ec, False, 'in a basement'), - "Blind's Hideout - Far Right": (0xeb1b, 0x1862ef, False, 'in a basement'), - "Link's Uncle": (0x2df45, 0x18635f, False, 'with your uncle'), - 'Secret Passage': (0xe971, 0x186145, False, 'near your uncle'), - 'King Zora': (0xee1c3, 0x186360, False, 'at a high price'), - "Zora's Ledge": (0x180149, 0x186358, False, 'near Zora'), - 'Waterfall Fairy - Left': (0xe9b0, 0x186184, False, 'near a fairy'), - 'Waterfall Fairy - Right': (0xe9d1, 0x1861a5, False, 'near a fairy'), - "King's Tomb": (0xe97a, 0x18614e, False, 'alone in a cave'), - 'Floodgate Chest': (0xe98c, 0x186160, False, 'in the dam'), - "Link's House": (0xe9bc, 0x186190, False, 'in your home'), - 'Kakariko Tavern': (0xe9ce, 0x1861a2, False, 'in the bar'), - 'Chicken House': (0xe9e9, 0x1861bd, False, 'near poultry'), - "Aginah's Cave": (0xe9f2, 0x1861c6, False, 'with Aginah'), - "Sahasrahla's Hut - Left": (0xea82, 0x186256, False, 'near the elder'), - "Sahasrahla's Hut - Middle": (0xea85, 0x186259, False, 'near the elder'), - "Sahasrahla's Hut - Right": (0xea88, 0x18625c, False, 'near the elder'), - 'Sahasrahla': (0x2f1fc, 0x186365, False, 'with the elder'), - 'Kakariko Well - Top': (0xea8e, 0x186262, False, 'in a well'), - 'Kakariko Well - Left': (0xea91, 0x186265, False, 'in a well'), - 'Kakariko Well - Middle': (0xea94, 0x186268, False, 'in a well'), - 'Kakariko Well - Right': (0xea97, 0x18626b, False, 'in a well'), - 'Kakariko Well - Bottom': (0xea9a, 0x18626e, False, 'in a well'), - 'Blacksmith': (0x18002a, 0x186366, False, 'with the smith'), - 'Magic Bat': (0x180015, 0x18635e, False, 'with the bat'), - 'Sick Kid': (0x339cf, 0x186367, False, 'with the sick'), - 'Hobo': (0x33e7d, 0x186368, False, 'with the hobo'), - 'Lost Woods Hideout': (0x180000, 0x186348, False, 'near a thief'), - 'Lumberjack Tree': (0x180001, 0x186349, False, 'in a hole'), - 'Cave 45': (0x180003, 0x18634b, False, 'alone in a cave'), - 'Graveyard Cave': (0x180004, 0x18634c, False, 'alone in a cave'), - 'Checkerboard Cave': (0x180005, 0x18634d, False, 'alone in a cave'), - 'Mini Moldorm Cave - Far Left': (0xeb42, 0x186316, False, 'near Moldorms'), - 'Mini Moldorm Cave - Left': (0xeb45, 0x186319, False, 'near Moldorms'), - 'Mini Moldorm Cave - Right': (0xeb48, 0x18631c, False, 'near Moldorms'), - 'Mini Moldorm Cave - Far Right': (0xeb4b, 0x18631f, False, 'near Moldorms'), - 'Mini Moldorm Cave - Generous Guy': (0x180010, 0x18635a, False, 'near Moldorms'), - 'Ice Rod Cave': (0xeb4e, 0x186322, False, 'in a frozen cave'), - 'Bonk Rock Cave': (0xeb3f, 0x186313, False, 'alone in a cave'), - 'Library': (0x180012, 0x18635c, False, 'near books'), - 'Potion Shop': (0x180014, 0x18635d, False, 'near potions'), - 'Lake Hylia Island': (0x180144, 0x186353, False, 'on an island'), - 'Maze Race': (0x180142, 0x186351, False, 'at the race'), - 'Desert Ledge': (0x180143, 0x186352, False, 'in the desert'), - 'Desert Palace - Big Chest': (0xe98f, 0x186163, False, 'in Desert Palace'), - 'Desert Palace - Torch': (0x180160, 0x186362, False, 'in Desert Palace'), - 'Desert Palace - Map Chest': (0xe9b6, 0x18618a, False, 'in Desert Palace'), - 'Desert Palace - Compass Chest': (0xe9cb, 0x18619f, False, 'in Desert Palace'), - 'Desert Palace - Big Key Chest': (0xe9c2, 0x186196, False, 'in Desert Palace'), - 'Desert Palace - Boss': (0x180151, 0x18633f, False, 'with Lanmolas'), - 'Eastern Palace - Compass Chest': (0xe977, 0x18614b, False, 'in Eastern Palace'), - 'Eastern Palace - Big Chest': (0xe97d, 0x186151, False, 'in Eastern Palace'), - 'Eastern Palace - Cannonball Chest': (0xe9b3, 0x186187, False, 'in Eastern Palace'), - 'Eastern Palace - Big Key Chest': (0xe9b9, 0x18618d, False, 'in Eastern Palace'), - 'Eastern Palace - Map Chest': (0xe9f5, 0x1861c9, False, 'in Eastern Palace'), - 'Eastern Palace - Boss': (0x180150, 0x18633e, False, 'with the Armos'), - 'Master Sword Pedestal': (0x289b0, 0x186369, False, 'at the pedestal'), - 'Hyrule Castle - Boomerang Chest': (0xe974, 0x186148, False, 'in Hyrule Castle'), - 'Hyrule Castle - Map Chest': (0xeb0c, 0x1862e0, False, 'in Hyrule Castle'), - "Hyrule Castle - Zelda's Chest": (0xeb09, 0x1862dd, False, 'in Hyrule Castle'), - 'Sewers - Dark Cross': (0xe96e, 0x186142, False, 'in the sewers'), - 'Sewers - Secret Room - Left': (0xeb5d, 0x186331, False, 'in the sewers'), - 'Sewers - Secret Room - Middle': (0xeb60, 0x186334, False, 'in the sewers'), - 'Sewers - Secret Room - Right': (0xeb63, 0x186337, False, 'in the sewers'), - 'Sanctuary': (0xea79, 0x18624d, False, 'in Sanctuary'), - 'Castle Tower - Room 03': (0xeab5, 0x186289, False, 'in Castle Tower'), - 'Castle Tower - Dark Maze': (0xeab2, 0x186286, False, 'in Castle Tower'), - 'Old Man': (0xf69fa, 0x186364, False, 'with the old man'), - 'Spectacle Rock Cave': (0x180002, 0x18634a, False, 'alone in a cave'), - 'Paradox Cave Lower - Far Left': (0xeb2a, 0x1862fe, False, 'in a cave with seven chests'), - 'Paradox Cave Lower - Left': (0xeb2d, 0x186301, False, 'in a cave with seven chests'), - 'Paradox Cave Lower - Right': (0xeb30, 0x186304, False, 'in a cave with seven chests'), - 'Paradox Cave Lower - Far Right': (0xeb33, 0x186307, False, 'in a cave with seven chests'), - 'Paradox Cave Lower - Middle': (0xeb36, 0x18630a, False, 'in a cave with seven chests'), - 'Paradox Cave Upper - Left': (0xeb39, 0x18630d, False, 'in a cave with seven chests'), - 'Paradox Cave Upper - Right': (0xeb3c, 0x186310, False, 'in a cave with seven chests'), - 'Spiral Cave': (0xe9bf, 0x186193, False, 'in spiral cave'), - 'Ether Tablet': (0x180016, 0x18633b, False, 'at a monolith'), - 'Spectacle Rock': (0x180140, 0x18634f, False, 'atop a rock'), - 'Tower of Hera - Basement Cage': (0x180162, 0x18633a, False, 'in Tower of Hera'), - 'Tower of Hera - Map Chest': (0xe9ad, 0x186181, False, 'in Tower of Hera'), - 'Tower of Hera - Big Key Chest': (0xe9e6, 0x1861ba, False, 'in Tower of Hera'), - 'Tower of Hera - Compass Chest': (0xe9fb, 0x1861cf, False, 'in Tower of Hera'), - 'Tower of Hera - Big Chest': (0xe9f8, 0x1861cc, False, 'in Tower of Hera'), - 'Tower of Hera - Boss': (0x180152, 0x186340, False, 'with Moldorm'), - 'Pyramid': (0x180147, 0x186356, False, 'on the pyramid'), - 'Catfish': (0xee185, 0x186361, False, 'with a catfish'), - 'Stumpy': (0x330c7, 0x18636a, False, 'with tree boy'), - 'Digging Game': (0x180148, 0x186357, False, 'underground'), - 'Bombos Tablet': (0x180017, 0x18633c, False, 'at a monolith'), - 'Hype Cave - Top': (0xeb1e, 0x1862f2, False, 'near a bat-like man'), - 'Hype Cave - Middle Right': (0xeb21, 0x1862f5, False, 'near a bat-like man'), - 'Hype Cave - Middle Left': (0xeb24, 0x1862f8, False, 'near a bat-like man'), - 'Hype Cave - Bottom': (0xeb27, 0x1862fb, False, 'near a bat-like man'), - 'Hype Cave - Generous Guy': (0x180011, 0x18635b, False, 'with a bat-like man'), - 'Peg Cave': (0x180006, 0x18634e, False, 'alone in a cave'), - 'Pyramid Fairy - Left': (0xe980, 0x186154, False, 'near a fairy'), - 'Pyramid Fairy - Right': (0xe983, 0x186157, False, 'near a fairy'), - 'Brewery': (0xe9ec, 0x1861c0, False, 'alone in a home'), - 'C-Shaped House': (0xe9ef, 0x1861c3, False, 'alone in a home'), - 'Chest Game': (0xeda8, 0x18636b, False, 'as a prize'), - 'Bumper Cave Ledge': (0x180146, 0x186355, False, 'on a ledge'), - 'Mire Shed - Left': (0xea73, 0x186247, False, 'near sparks'), - 'Mire Shed - Right': (0xea76, 0x18624a, False, 'near sparks'), - 'Superbunny Cave - Top': (0xea7c, 0x186250, False, 'in a connection'), - 'Superbunny Cave - Bottom': (0xea7f, 0x186253, False, 'in a connection'), - 'Spike Cave': (0xea8b, 0x18625f, False, 'beyond spikes'), - 'Hookshot Cave - Top Right': (0xeb51, 0x186325, False, 'across pits'), - 'Hookshot Cave - Top Left': (0xeb54, 0x186328, False, 'across pits'), - 'Hookshot Cave - Bottom Right': (0xeb5a, 0x18632e, False, 'across pits'), - 'Hookshot Cave - Bottom Left': (0xeb57, 0x18632b, False, 'across pits'), - 'Floating Island': (0x180141, 0x186350, False, 'on an island'), - 'Mimic Cave': (0xe9c5, 0x186199, False, 'in a cave of mimicry'), - 'Swamp Palace - Entrance': (0xea9d, 0x186271, False, 'in Swamp Palace'), - 'Swamp Palace - Map Chest': (0xe986, 0x18615a, False, 'in Swamp Palace'), - 'Swamp Palace - Big Chest': (0xe989, 0x18615d, False, 'in Swamp Palace'), - 'Swamp Palace - Compass Chest': (0xeaa0, 0x186274, False, 'in Swamp Palace'), - 'Swamp Palace - Big Key Chest': (0xeaa6, 0x18627a, False, 'in Swamp Palace'), - 'Swamp Palace - West Chest': (0xeaa3, 0x186277, False, 'in Swamp Palace'), - 'Swamp Palace - Flooded Room - Left': (0xeaa9, 0x18627d, False, 'in Swamp Palace'), - 'Swamp Palace - Flooded Room - Right': (0xeaac, 0x186280, False, 'in Swamp Palace'), - 'Swamp Palace - Waterfall Room': (0xeaaf, 0x186283, False, 'in Swamp Palace'), - 'Swamp Palace - Boss': (0x180154, 0x186342, False, 'with Arrghus'), - "Thieves' Town - Big Key Chest": (0xea04, 0x1861d8, False, "in Thieves' Town"), - "Thieves' Town - Map Chest": (0xea01, 0x1861d5, False, "in Thieves' Town"), - "Thieves' Town - Compass Chest": (0xea07, 0x1861db, False, "in Thieves' Town"), - "Thieves' Town - Ambush Chest": (0xea0a, 0x1861de, False, "in Thieves' Town"), - "Thieves' Town - Attic": (0xea0d, 0x1861e1, False, "in Thieves' Town"), - "Thieves' Town - Big Chest": (0xea10, 0x1861e4, False, "in Thieves' Town"), - "Thieves' Town - Blind's Cell": (0xea13, 0x1861e7, False, "in Thieves' Town"), - "Thieves' Town - Boss": (0x180156, 0x186344, False, 'with Blind'), - 'Skull Woods - Compass Chest': (0xe992, 0x186166, False, 'in Skull Woods'), - 'Skull Woods - Map Chest': (0xe99b, 0x18616f, False, 'in Skull Woods'), - 'Skull Woods - Big Chest': (0xe998, 0x18616c, False, 'in Skull Woods'), - 'Skull Woods - Pot Prison': (0xe9a1, 0x186175, False, 'in Skull Woods'), - 'Skull Woods - Pinball Room': (0xe9c8, 0x18619c, False, 'in Skull Woods'), - 'Skull Woods - Big Key Chest': (0xe99e, 0x186172, False, 'in Skull Woods'), - 'Skull Woods - Bridge Room': (0xe9fe, 0x1861d2, False, 'near Mothula'), - 'Skull Woods - Boss': (0x180155, 0x186343, False, 'with Mothula'), - 'Ice Palace - Compass Chest': (0xe9d4, 0x1861a8, False, 'in Ice Palace'), - 'Ice Palace - Freezor Chest': (0xe995, 0x186169, False, 'in Ice Palace'), - 'Ice Palace - Big Chest': (0xe9aa, 0x18617e, False, 'in Ice Palace'), - 'Ice Palace - Iced T Room': (0xe9e3, 0x1861b7, False, 'in Ice Palace'), - 'Ice Palace - Spike Room': (0xe9e0, 0x1861b4, False, 'in Ice Palace'), - 'Ice Palace - Big Key Chest': (0xe9a4, 0x186178, False, 'in Ice Palace'), - 'Ice Palace - Map Chest': (0xe9dd, 0x1861b1, False, 'in Ice Palace'), - 'Ice Palace - Boss': (0x180157, 0x186345, False, 'with Kholdstare'), - 'Misery Mire - Big Chest': (0xea67, 0x18623b, False, 'in Misery Mire'), - 'Misery Mire - Map Chest': (0xea6a, 0x18623e, False, 'in Misery Mire'), - 'Misery Mire - Main Lobby': (0xea5e, 0x186232, False, 'in Misery Mire'), - 'Misery Mire - Bridge Chest': (0xea61, 0x186235, False, 'in Misery Mire'), - 'Misery Mire - Spike Chest': (0xe9da, 0x1861ae, False, 'in Misery Mire'), - 'Misery Mire - Compass Chest': (0xea64, 0x186238, False, 'in Misery Mire'), - 'Misery Mire - Big Key Chest': (0xea6d, 0x186241, False, 'in Misery Mire'), - 'Misery Mire - Boss': (0x180158, 0x186346, False, 'with Vitreous'), - 'Turtle Rock - Compass Chest': (0xea22, 0x1861f6, False, 'in Turtle Rock'), - 'Turtle Rock - Roller Room - Left': (0xea1c, 0x1861f0, False, 'in Turtle Rock'), - 'Turtle Rock - Roller Room - Right': (0xea1f, 0x1861f3, False, 'in Turtle Rock'), - 'Turtle Rock - Chain Chomps': (0xea16, 0x1861ea, False, 'in Turtle Rock'), - 'Turtle Rock - Big Key Chest': (0xea25, 0x1861f9, False, 'in Turtle Rock'), - 'Turtle Rock - Big Chest': (0xea19, 0x1861ed, False, 'in Turtle Rock'), - 'Turtle Rock - Crystaroller Room': (0xea34, 0x186208, False, 'in Turtle Rock'), - 'Turtle Rock - Eye Bridge - Bottom Left': (0xea31, 0x186205, False, 'in Turtle Rock'), - 'Turtle Rock - Eye Bridge - Bottom Right': (0xea2e, 0x186202, False, 'in Turtle Rock'), - 'Turtle Rock - Eye Bridge - Top Left': (0xea2b, 0x1861ff, False, 'in Turtle Rock'), - 'Turtle Rock - Eye Bridge - Top Right': (0xea28, 0x1861fc, False, 'in Turtle Rock'), - 'Turtle Rock - Boss': (0x180159, 0x186347, False, 'with Trinexx'), - 'Palace of Darkness - Shooter Room': (0xea5b, 0x18622f, False, 'in Palace of Darkness'), - 'Palace of Darkness - The Arena - Bridge': (0xea3d, 0x186211, False, 'in Palace of Darkness'), - 'Palace of Darkness - Stalfos Basement': (0xea49, 0x18621d, False, 'in Palace of Darkness'), - 'Palace of Darkness - Big Key Chest': (0xea37, 0x18620b, False, 'in Palace of Darkness'), - 'Palace of Darkness - The Arena - Ledge': (0xea3a, 0x18620e, False, 'in Palace of Darkness'), - 'Palace of Darkness - Map Chest': (0xea52, 0x186226, False, 'in Palace of Darkness'), - 'Palace of Darkness - Compass Chest': (0xea43, 0x186217, False, 'in Palace of Darkness'), - 'Palace of Darkness - Dark Basement - Left': (0xea4c, 0x186220, False, 'in Palace of Darkness'), - 'Palace of Darkness - Dark Basement - Right': (0xea4f, 0x186223, False, 'in Palace of Darkness'), - 'Palace of Darkness - Dark Maze - Top': (0xea55, 0x186229, False, 'in Palace of Darkness'), - 'Palace of Darkness - Dark Maze - Bottom': (0xea58, 0x18622c, False, 'in Palace of Darkness'), - 'Palace of Darkness - Big Chest': (0xea40, 0x186214, False, 'in Palace of Darkness'), - 'Palace of Darkness - Harmless Hellway': (0xea46, 0x18621a, False, 'in Palace of Darkness'), - 'Palace of Darkness - Boss': (0x180153, 0x186341, False, 'with Helmasaur King'), - "Ganons Tower - Bob's Torch": (0x180161, 0x186363, False, "in Ganon's Tower"), - 'Ganons Tower - Hope Room - Left': (0xead9, 0x1862ad, False, "in Ganon's Tower"), - 'Ganons Tower - Hope Room - Right': (0xeadc, 0x1862b0, False, "in Ganon's Tower"), - 'Ganons Tower - Tile Room': (0xeae2, 0x1862b6, False, "in Ganon's Tower"), - 'Ganons Tower - Compass Room - Top Left': (0xeae5, 0x1862b9, False, "in Ganon's Tower"), - 'Ganons Tower - Compass Room - Top Right': (0xeae8, 0x1862bc, False, "in Ganon's Tower"), - 'Ganons Tower - Compass Room - Bottom Left': (0xeaeb, 0x1862bf, False, "in Ganon's Tower"), - 'Ganons Tower - Compass Room - Bottom Right': (0xeaee, 0x1862c2, False, "in Ganon's Tower"), - 'Ganons Tower - DMs Room - Top Left': (0xeab8, 0x18628c, False, "in Ganon's Tower"), - 'Ganons Tower - DMs Room - Top Right': (0xeabb, 0x18628f, False, "in Ganon's Tower"), - 'Ganons Tower - DMs Room - Bottom Left': (0xeabe, 0x186292, False, "in Ganon's Tower"), - 'Ganons Tower - DMs Room - Bottom Right': (0xeac1, 0x186295, False, "in Ganon's Tower"), - 'Ganons Tower - Map Chest': (0xead3, 0x1862a7, False, "in Ganon's Tower"), - 'Ganons Tower - Firesnake Room': (0xead0, 0x1862a4, False, "in Ganon's Tower"), - 'Ganons Tower - Randomizer Room - Top Left': (0xeac4, 0x186298, False, "in Ganon's Tower"), - 'Ganons Tower - Randomizer Room - Top Right': (0xeac7, 0x18629b, False, "in Ganon's Tower"), - 'Ganons Tower - Randomizer Room - Bottom Left': (0xeaca, 0x18629e, False, "in Ganon's Tower"), - 'Ganons Tower - Randomizer Room - Bottom Right': (0xeacd, 0x1862a1, False, "in Ganon's Tower"), - "Ganons Tower - Bob's Chest": (0xeadf, 0x1862b3, False, "in Ganon's Tower"), - 'Ganons Tower - Big Chest': (0xead6, 0x1862aa, False, "in Ganon's Tower"), - 'Ganons Tower - Big Key Room - Left': (0xeaf4, 0x1862c8, False, "in Ganon's Tower"), - 'Ganons Tower - Big Key Room - Right': (0xeaf7, 0x1862cb, False, "in Ganon's Tower"), - 'Ganons Tower - Big Key Chest': (0xeaf1, 0x1862c5, False, "in Ganon's Tower"), - 'Ganons Tower - Mini Helmasaur Room - Left': (0xeafd, 0x1862d1, False, "atop Ganon's Tower"), - 'Ganons Tower - Mini Helmasaur Room - Right': (0xeb00, 0x1862d4, False, "atop Ganon's Tower"), - 'Ganons Tower - Pre-Moldorm Chest': (0xeb03, 0x1862d7, False, "atop Ganon's Tower"), - 'Ganons Tower - Validation Chest': (0xeb06, 0x1862da, False, "atop Ganon's Tower"), - 'Ganon': (None, None, False, 'from me'), - 'Agahnim 1': (None, None, False, 'from Ganon\'s wizardry form'), - 'Agahnim 2': (None, None, False, 'from Ganon\'s wizardry form'), - 'Floodgate': (None, None, False, None), - 'Frog': (None, None, False, None), - 'Missing Smith': (None, None, False, None), - 'Dark Blacksmith Ruins': (None, None, False, None), - 'Eastern Palace - Prize': ([0x1209D, 0x53EF8, 0x53EF9, 0x180052, 0x18007C, 0xC6FE], None, True, 'Eastern Palace'), - 'Desert Palace - Prize': ([0x1209E, 0x53F1C, 0x53F1D, 0x180053, 0x180078, 0xC6FF], None, True, 'Desert Palace'), - 'Tower of Hera - Prize': ( - [0x120A5, 0x53F0A, 0x53F0B, 0x18005A, 0x18007A, 0xC706], None, True, 'Tower of Hera'), - 'Palace of Darkness - Prize': ( - [0x120A1, 0x53F00, 0x53F01, 0x180056, 0x18007D, 0xC702], None, True, 'Palace of Darkness'), - 'Swamp Palace - Prize': ( - [0x120A0, 0x53F6C, 0x53F6D, 0x180055, 0x180071, 0xC701], None, True, 'Swamp Palace'), - 'Thieves\' Town - Prize': ( - [0x120A6, 0x53F36, 0x53F37, 0x18005B, 0x180077, 0xC707], None, True, 'Thieves\' Town'), - 'Skull Woods - Prize': ( - [0x120A3, 0x53F12, 0x53F13, 0x180058, 0x18007B, 0xC704], None, True, 'Skull Woods'), - 'Ice Palace - Prize': ( - [0x120A4, 0x53F5A, 0x53F5B, 0x180059, 0x180073, 0xC705], None, True, 'Ice Palace'), - 'Misery Mire - Prize': ( - [0x120A2, 0x53F48, 0x53F49, 0x180057, 0x180075, 0xC703], None, True, 'Misery Mire'), - 'Turtle Rock - Prize': ( - [0x120A7, 0x53F24, 0x53F25, 0x18005C, 0x180079, 0xC708], None, True, 'Turtle Rock')} +# tuple contents: +# address to write to for item +# address to write to for player getting the item +# can this location drop a crystal +# hint tile/npc text for this location +location_table: typing.Dict[str, + typing.Tuple[typing.Optional[typing.Union[int, typing.List[int]]], + typing.Optional[int], + bool, + typing.Optional[str]]] = \ + {'Mushroom': (0x180013, 0x186338, False, 'in the woods'), + 'Bottle Merchant': (0x2eb18, 0x186339, False, 'with a merchant'), + 'Flute Spot': (0x18014a, 0x18633d, False, 'underground'), + 'Sunken Treasure': (0x180145, 0x186354, False, 'underwater'), + 'Purple Chest': (0x33d68, 0x186359, False, 'from a box'), + "Blind's Hideout - Top": (0xeb0f, 0x1862e3, False, 'in a basement'), + "Blind's Hideout - Left": (0xeb12, 0x1862e6, False, 'in a basement'), + "Blind's Hideout - Right": (0xeb15, 0x1862e9, False, 'in a basement'), + "Blind's Hideout - Far Left": (0xeb18, 0x1862ec, False, 'in a basement'), + "Blind's Hideout - Far Right": (0xeb1b, 0x1862ef, False, 'in a basement'), + "Link's Uncle": (0x2df45, 0x18635f, False, 'with your uncle'), + 'Secret Passage': (0xe971, 0x186145, False, 'near your uncle'), + 'King Zora': (0xee1c3, 0x186360, False, 'at a high price'), + "Zora's Ledge": (0x180149, 0x186358, False, 'near Zora'), + 'Waterfall Fairy - Left': (0xe9b0, 0x186184, False, 'near a fairy'), + 'Waterfall Fairy - Right': (0xe9d1, 0x1861a5, False, 'near a fairy'), + "King's Tomb": (0xe97a, 0x18614e, False, 'alone in a cave'), + 'Floodgate Chest': (0xe98c, 0x186160, False, 'in the dam'), + "Link's House": (0xe9bc, 0x186190, False, 'in your home'), + 'Kakariko Tavern': (0xe9ce, 0x1861a2, False, 'in the bar'), + 'Chicken House': (0xe9e9, 0x1861bd, False, 'near poultry'), + "Aginah's Cave": (0xe9f2, 0x1861c6, False, 'with Aginah'), + "Sahasrahla's Hut - Left": (0xea82, 0x186256, False, 'near the elder'), + "Sahasrahla's Hut - Middle": (0xea85, 0x186259, False, 'near the elder'), + "Sahasrahla's Hut - Right": (0xea88, 0x18625c, False, 'near the elder'), + 'Sahasrahla': (0x2f1fc, 0x186365, False, 'with the elder'), + 'Kakariko Well - Top': (0xea8e, 0x186262, False, 'in a well'), + 'Kakariko Well - Left': (0xea91, 0x186265, False, 'in a well'), + 'Kakariko Well - Middle': (0xea94, 0x186268, False, 'in a well'), + 'Kakariko Well - Right': (0xea97, 0x18626b, False, 'in a well'), + 'Kakariko Well - Bottom': (0xea9a, 0x18626e, False, 'in a well'), + 'Blacksmith': (0x18002a, 0x186366, False, 'with the smith'), + 'Magic Bat': (0x180015, 0x18635e, False, 'with the bat'), + 'Sick Kid': (0x339cf, 0x186367, False, 'with the sick'), + 'Hobo': (0x33e7d, 0x186368, False, 'with the hobo'), + 'Lost Woods Hideout': (0x180000, 0x186348, False, 'near a thief'), + 'Lumberjack Tree': (0x180001, 0x186349, False, 'in a hole'), + 'Cave 45': (0x180003, 0x18634b, False, 'alone in a cave'), + 'Graveyard Cave': (0x180004, 0x18634c, False, 'alone in a cave'), + 'Checkerboard Cave': (0x180005, 0x18634d, False, 'alone in a cave'), + 'Mini Moldorm Cave - Far Left': (0xeb42, 0x186316, False, 'near Moldorms'), + 'Mini Moldorm Cave - Left': (0xeb45, 0x186319, False, 'near Moldorms'), + 'Mini Moldorm Cave - Right': (0xeb48, 0x18631c, False, 'near Moldorms'), + 'Mini Moldorm Cave - Far Right': (0xeb4b, 0x18631f, False, 'near Moldorms'), + 'Mini Moldorm Cave - Generous Guy': (0x180010, 0x18635a, False, 'near Moldorms'), + 'Ice Rod Cave': (0xeb4e, 0x186322, False, 'in a frozen cave'), + 'Bonk Rock Cave': (0xeb3f, 0x186313, False, 'alone in a cave'), + 'Library': (0x180012, 0x18635c, False, 'near books'), + 'Potion Shop': (0x180014, 0x18635d, False, 'near potions'), + 'Lake Hylia Island': (0x180144, 0x186353, False, 'on an island'), + 'Maze Race': (0x180142, 0x186351, False, 'at the race'), + 'Desert Ledge': (0x180143, 0x186352, False, 'in the desert'), + 'Desert Palace - Big Chest': (0xe98f, 0x186163, False, 'in Desert Palace'), + 'Desert Palace - Torch': (0x180160, 0x186362, False, 'in Desert Palace'), + 'Desert Palace - Map Chest': (0xe9b6, 0x18618a, False, 'in Desert Palace'), + 'Desert Palace - Compass Chest': (0xe9cb, 0x18619f, False, 'in Desert Palace'), + 'Desert Palace - Big Key Chest': (0xe9c2, 0x186196, False, 'in Desert Palace'), + 'Desert Palace - Boss': (0x180151, 0x18633f, False, 'with Lanmolas'), + 'Eastern Palace - Compass Chest': (0xe977, 0x18614b, False, 'in Eastern Palace'), + 'Eastern Palace - Big Chest': (0xe97d, 0x186151, False, 'in Eastern Palace'), + 'Eastern Palace - Cannonball Chest': (0xe9b3, 0x186187, False, 'in Eastern Palace'), + 'Eastern Palace - Big Key Chest': (0xe9b9, 0x18618d, False, 'in Eastern Palace'), + 'Eastern Palace - Map Chest': (0xe9f5, 0x1861c9, False, 'in Eastern Palace'), + 'Eastern Palace - Boss': (0x180150, 0x18633e, False, 'with the Armos'), + 'Master Sword Pedestal': (0x289b0, 0x186369, False, 'at the pedestal'), + 'Hyrule Castle - Boomerang Chest': (0xe974, 0x186148, False, 'in Hyrule Castle'), + 'Hyrule Castle - Map Chest': (0xeb0c, 0x1862e0, False, 'in Hyrule Castle'), + "Hyrule Castle - Zelda's Chest": (0xeb09, 0x1862dd, False, 'in Hyrule Castle'), + 'Sewers - Dark Cross': (0xe96e, 0x186142, False, 'in the sewers'), + 'Sewers - Secret Room - Left': (0xeb5d, 0x186331, False, 'in the sewers'), + 'Sewers - Secret Room - Middle': (0xeb60, 0x186334, False, 'in the sewers'), + 'Sewers - Secret Room - Right': (0xeb63, 0x186337, False, 'in the sewers'), + 'Sanctuary': (0xea79, 0x18624d, False, 'in Sanctuary'), + 'Castle Tower - Room 03': (0xeab5, 0x186289, False, 'in Castle Tower'), + 'Castle Tower - Dark Maze': (0xeab2, 0x186286, False, 'in Castle Tower'), + 'Old Man': (0xf69fa, 0x186364, False, 'with the old man'), + 'Spectacle Rock Cave': (0x180002, 0x18634a, False, 'alone in a cave'), + 'Paradox Cave Lower - Far Left': (0xeb2a, 0x1862fe, False, 'in a cave with seven chests'), + 'Paradox Cave Lower - Left': (0xeb2d, 0x186301, False, 'in a cave with seven chests'), + 'Paradox Cave Lower - Right': (0xeb30, 0x186304, False, 'in a cave with seven chests'), + 'Paradox Cave Lower - Far Right': (0xeb33, 0x186307, False, 'in a cave with seven chests'), + 'Paradox Cave Lower - Middle': (0xeb36, 0x18630a, False, 'in a cave with seven chests'), + 'Paradox Cave Upper - Left': (0xeb39, 0x18630d, False, 'in a cave with seven chests'), + 'Paradox Cave Upper - Right': (0xeb3c, 0x186310, False, 'in a cave with seven chests'), + 'Spiral Cave': (0xe9bf, 0x186193, False, 'in spiral cave'), + 'Ether Tablet': (0x180016, 0x18633b, False, 'at a monolith'), + 'Spectacle Rock': (0x180140, 0x18634f, False, 'atop a rock'), + 'Tower of Hera - Basement Cage': (0x180162, 0x18633a, False, 'in Tower of Hera'), + 'Tower of Hera - Map Chest': (0xe9ad, 0x186181, False, 'in Tower of Hera'), + 'Tower of Hera - Big Key Chest': (0xe9e6, 0x1861ba, False, 'in Tower of Hera'), + 'Tower of Hera - Compass Chest': (0xe9fb, 0x1861cf, False, 'in Tower of Hera'), + 'Tower of Hera - Big Chest': (0xe9f8, 0x1861cc, False, 'in Tower of Hera'), + 'Tower of Hera - Boss': (0x180152, 0x186340, False, 'with Moldorm'), + 'Pyramid': (0x180147, 0x186356, False, 'on the pyramid'), + 'Catfish': (0xee185, 0x186361, False, 'with a catfish'), + 'Stumpy': (0x330c7, 0x18636a, False, 'with tree boy'), + 'Digging Game': (0x180148, 0x186357, False, 'underground'), + 'Bombos Tablet': (0x180017, 0x18633c, False, 'at a monolith'), + 'Hype Cave - Top': (0xeb1e, 0x1862f2, False, 'near a bat-like man'), + 'Hype Cave - Middle Right': (0xeb21, 0x1862f5, False, 'near a bat-like man'), + 'Hype Cave - Middle Left': (0xeb24, 0x1862f8, False, 'near a bat-like man'), + 'Hype Cave - Bottom': (0xeb27, 0x1862fb, False, 'near a bat-like man'), + 'Hype Cave - Generous Guy': (0x180011, 0x18635b, False, 'with a bat-like man'), + 'Peg Cave': (0x180006, 0x18634e, False, 'alone in a cave'), + 'Pyramid Fairy - Left': (0xe980, 0x186154, False, 'near a fairy'), + 'Pyramid Fairy - Right': (0xe983, 0x186157, False, 'near a fairy'), + 'Brewery': (0xe9ec, 0x1861c0, False, 'alone in a home'), + 'C-Shaped House': (0xe9ef, 0x1861c3, False, 'alone in a home'), + 'Chest Game': (0xeda8, 0x18636b, False, 'as a prize'), + 'Bumper Cave Ledge': (0x180146, 0x186355, False, 'on a ledge'), + 'Mire Shed - Left': (0xea73, 0x186247, False, 'near sparks'), + 'Mire Shed - Right': (0xea76, 0x18624a, False, 'near sparks'), + 'Superbunny Cave - Top': (0xea7c, 0x186250, False, 'in a connection'), + 'Superbunny Cave - Bottom': (0xea7f, 0x186253, False, 'in a connection'), + 'Spike Cave': (0xea8b, 0x18625f, False, 'beyond spikes'), + 'Hookshot Cave - Top Right': (0xeb51, 0x186325, False, 'across pits'), + 'Hookshot Cave - Top Left': (0xeb54, 0x186328, False, 'across pits'), + 'Hookshot Cave - Bottom Right': (0xeb5a, 0x18632e, False, 'across pits'), + 'Hookshot Cave - Bottom Left': (0xeb57, 0x18632b, False, 'across pits'), + 'Floating Island': (0x180141, 0x186350, False, 'on an island'), + 'Mimic Cave': (0xe9c5, 0x186199, False, 'in a cave of mimicry'), + 'Swamp Palace - Entrance': (0xea9d, 0x186271, False, 'in Swamp Palace'), + 'Swamp Palace - Map Chest': (0xe986, 0x18615a, False, 'in Swamp Palace'), + 'Swamp Palace - Big Chest': (0xe989, 0x18615d, False, 'in Swamp Palace'), + 'Swamp Palace - Compass Chest': (0xeaa0, 0x186274, False, 'in Swamp Palace'), + 'Swamp Palace - Big Key Chest': (0xeaa6, 0x18627a, False, 'in Swamp Palace'), + 'Swamp Palace - West Chest': (0xeaa3, 0x186277, False, 'in Swamp Palace'), + 'Swamp Palace - Flooded Room - Left': (0xeaa9, 0x18627d, False, 'in Swamp Palace'), + 'Swamp Palace - Flooded Room - Right': (0xeaac, 0x186280, False, 'in Swamp Palace'), + 'Swamp Palace - Waterfall Room': (0xeaaf, 0x186283, False, 'in Swamp Palace'), + 'Swamp Palace - Boss': (0x180154, 0x186342, False, 'with Arrghus'), + "Thieves' Town - Big Key Chest": (0xea04, 0x1861d8, False, "in Thieves' Town"), + "Thieves' Town - Map Chest": (0xea01, 0x1861d5, False, "in Thieves' Town"), + "Thieves' Town - Compass Chest": (0xea07, 0x1861db, False, "in Thieves' Town"), + "Thieves' Town - Ambush Chest": (0xea0a, 0x1861de, False, "in Thieves' Town"), + "Thieves' Town - Attic": (0xea0d, 0x1861e1, False, "in Thieves' Town"), + "Thieves' Town - Big Chest": (0xea10, 0x1861e4, False, "in Thieves' Town"), + "Thieves' Town - Blind's Cell": (0xea13, 0x1861e7, False, "in Thieves' Town"), + "Thieves' Town - Boss": (0x180156, 0x186344, False, 'with Blind'), + 'Skull Woods - Compass Chest': (0xe992, 0x186166, False, 'in Skull Woods'), + 'Skull Woods - Map Chest': (0xe99b, 0x18616f, False, 'in Skull Woods'), + 'Skull Woods - Big Chest': (0xe998, 0x18616c, False, 'in Skull Woods'), + 'Skull Woods - Pot Prison': (0xe9a1, 0x186175, False, 'in Skull Woods'), + 'Skull Woods - Pinball Room': (0xe9c8, 0x18619c, False, 'in Skull Woods'), + 'Skull Woods - Big Key Chest': (0xe99e, 0x186172, False, 'in Skull Woods'), + 'Skull Woods - Bridge Room': (0xe9fe, 0x1861d2, False, 'near Mothula'), + 'Skull Woods - Boss': (0x180155, 0x186343, False, 'with Mothula'), + 'Ice Palace - Compass Chest': (0xe9d4, 0x1861a8, False, 'in Ice Palace'), + 'Ice Palace - Freezor Chest': (0xe995, 0x186169, False, 'in Ice Palace'), + 'Ice Palace - Big Chest': (0xe9aa, 0x18617e, False, 'in Ice Palace'), + 'Ice Palace - Iced T Room': (0xe9e3, 0x1861b7, False, 'in Ice Palace'), + 'Ice Palace - Spike Room': (0xe9e0, 0x1861b4, False, 'in Ice Palace'), + 'Ice Palace - Big Key Chest': (0xe9a4, 0x186178, False, 'in Ice Palace'), + 'Ice Palace - Map Chest': (0xe9dd, 0x1861b1, False, 'in Ice Palace'), + 'Ice Palace - Boss': (0x180157, 0x186345, False, 'with Kholdstare'), + 'Misery Mire - Big Chest': (0xea67, 0x18623b, False, 'in Misery Mire'), + 'Misery Mire - Map Chest': (0xea6a, 0x18623e, False, 'in Misery Mire'), + 'Misery Mire - Main Lobby': (0xea5e, 0x186232, False, 'in Misery Mire'), + 'Misery Mire - Bridge Chest': (0xea61, 0x186235, False, 'in Misery Mire'), + 'Misery Mire - Spike Chest': (0xe9da, 0x1861ae, False, 'in Misery Mire'), + 'Misery Mire - Compass Chest': (0xea64, 0x186238, False, 'in Misery Mire'), + 'Misery Mire - Big Key Chest': (0xea6d, 0x186241, False, 'in Misery Mire'), + 'Misery Mire - Boss': (0x180158, 0x186346, False, 'with Vitreous'), + 'Turtle Rock - Compass Chest': (0xea22, 0x1861f6, False, 'in Turtle Rock'), + 'Turtle Rock - Roller Room - Left': (0xea1c, 0x1861f0, False, 'in Turtle Rock'), + 'Turtle Rock - Roller Room - Right': (0xea1f, 0x1861f3, False, 'in Turtle Rock'), + 'Turtle Rock - Chain Chomps': (0xea16, 0x1861ea, False, 'in Turtle Rock'), + 'Turtle Rock - Big Key Chest': (0xea25, 0x1861f9, False, 'in Turtle Rock'), + 'Turtle Rock - Big Chest': (0xea19, 0x1861ed, False, 'in Turtle Rock'), + 'Turtle Rock - Crystaroller Room': (0xea34, 0x186208, False, 'in Turtle Rock'), + 'Turtle Rock - Eye Bridge - Bottom Left': (0xea31, 0x186205, False, 'in Turtle Rock'), + 'Turtle Rock - Eye Bridge - Bottom Right': (0xea2e, 0x186202, False, 'in Turtle Rock'), + 'Turtle Rock - Eye Bridge - Top Left': (0xea2b, 0x1861ff, False, 'in Turtle Rock'), + 'Turtle Rock - Eye Bridge - Top Right': (0xea28, 0x1861fc, False, 'in Turtle Rock'), + 'Turtle Rock - Boss': (0x180159, 0x186347, False, 'with Trinexx'), + 'Palace of Darkness - Shooter Room': (0xea5b, 0x18622f, False, 'in Palace of Darkness'), + 'Palace of Darkness - The Arena - Bridge': (0xea3d, 0x186211, False, 'in Palace of Darkness'), + 'Palace of Darkness - Stalfos Basement': (0xea49, 0x18621d, False, 'in Palace of Darkness'), + 'Palace of Darkness - Big Key Chest': (0xea37, 0x18620b, False, 'in Palace of Darkness'), + 'Palace of Darkness - The Arena - Ledge': (0xea3a, 0x18620e, False, 'in Palace of Darkness'), + 'Palace of Darkness - Map Chest': (0xea52, 0x186226, False, 'in Palace of Darkness'), + 'Palace of Darkness - Compass Chest': (0xea43, 0x186217, False, 'in Palace of Darkness'), + 'Palace of Darkness - Dark Basement - Left': (0xea4c, 0x186220, False, 'in Palace of Darkness'), + 'Palace of Darkness - Dark Basement - Right': (0xea4f, 0x186223, False, 'in Palace of Darkness'), + 'Palace of Darkness - Dark Maze - Top': (0xea55, 0x186229, False, 'in Palace of Darkness'), + 'Palace of Darkness - Dark Maze - Bottom': (0xea58, 0x18622c, False, 'in Palace of Darkness'), + 'Palace of Darkness - Big Chest': (0xea40, 0x186214, False, 'in Palace of Darkness'), + 'Palace of Darkness - Harmless Hellway': (0xea46, 0x18621a, False, 'in Palace of Darkness'), + 'Palace of Darkness - Boss': (0x180153, 0x186341, False, 'with Helmasaur King'), + "Ganons Tower - Bob's Torch": (0x180161, 0x186363, False, "in Ganon's Tower"), + 'Ganons Tower - Hope Room - Left': (0xead9, 0x1862ad, False, "in Ganon's Tower"), + 'Ganons Tower - Hope Room - Right': (0xeadc, 0x1862b0, False, "in Ganon's Tower"), + 'Ganons Tower - Tile Room': (0xeae2, 0x1862b6, False, "in Ganon's Tower"), + 'Ganons Tower - Compass Room - Top Left': (0xeae5, 0x1862b9, False, "in Ganon's Tower"), + 'Ganons Tower - Compass Room - Top Right': (0xeae8, 0x1862bc, False, "in Ganon's Tower"), + 'Ganons Tower - Compass Room - Bottom Left': (0xeaeb, 0x1862bf, False, "in Ganon's Tower"), + 'Ganons Tower - Compass Room - Bottom Right': (0xeaee, 0x1862c2, False, "in Ganon's Tower"), + 'Ganons Tower - DMs Room - Top Left': (0xeab8, 0x18628c, False, "in Ganon's Tower"), + 'Ganons Tower - DMs Room - Top Right': (0xeabb, 0x18628f, False, "in Ganon's Tower"), + 'Ganons Tower - DMs Room - Bottom Left': (0xeabe, 0x186292, False, "in Ganon's Tower"), + 'Ganons Tower - DMs Room - Bottom Right': (0xeac1, 0x186295, False, "in Ganon's Tower"), + 'Ganons Tower - Map Chest': (0xead3, 0x1862a7, False, "in Ganon's Tower"), + 'Ganons Tower - Firesnake Room': (0xead0, 0x1862a4, False, "in Ganon's Tower"), + 'Ganons Tower - Randomizer Room - Top Left': (0xeac4, 0x186298, False, "in Ganon's Tower"), + 'Ganons Tower - Randomizer Room - Top Right': (0xeac7, 0x18629b, False, "in Ganon's Tower"), + 'Ganons Tower - Randomizer Room - Bottom Left': (0xeaca, 0x18629e, False, "in Ganon's Tower"), + 'Ganons Tower - Randomizer Room - Bottom Right': (0xeacd, 0x1862a1, False, "in Ganon's Tower"), + "Ganons Tower - Bob's Chest": (0xeadf, 0x1862b3, False, "in Ganon's Tower"), + 'Ganons Tower - Big Chest': (0xead6, 0x1862aa, False, "in Ganon's Tower"), + 'Ganons Tower - Big Key Room - Left': (0xeaf4, 0x1862c8, False, "in Ganon's Tower"), + 'Ganons Tower - Big Key Room - Right': (0xeaf7, 0x1862cb, False, "in Ganon's Tower"), + 'Ganons Tower - Big Key Chest': (0xeaf1, 0x1862c5, False, "in Ganon's Tower"), + 'Ganons Tower - Mini Helmasaur Room - Left': (0xeafd, 0x1862d1, False, "atop Ganon's Tower"), + 'Ganons Tower - Mini Helmasaur Room - Right': (0xeb00, 0x1862d4, False, "atop Ganon's Tower"), + 'Ganons Tower - Pre-Moldorm Chest': (0xeb03, 0x1862d7, False, "atop Ganon's Tower"), + 'Ganons Tower - Validation Chest': (0xeb06, 0x1862da, False, "atop Ganon's Tower"), + 'Ganon': (None, None, False, 'from me'), + 'Agahnim 1': (None, None, False, 'from Ganon\'s wizardry form'), + 'Agahnim 2': (None, None, False, 'from Ganon\'s wizardry form'), + 'Floodgate': (None, None, False, None), + 'Frog': (None, None, False, None), + 'Missing Smith': (None, None, False, None), + 'Dark Blacksmith Ruins': (None, None, False, None), + 'Eastern Palace - Prize': ([0x1209D, 0x53EF8, 0x53EF9, 0x180052, 0x18007C, 0xC6FE], None, True, 'Eastern Palace'), + 'Desert Palace - Prize': ([0x1209E, 0x53F1C, 0x53F1D, 0x180053, 0x180078, 0xC6FF], None, True, 'Desert Palace'), + 'Tower of Hera - Prize': ( + [0x120A5, 0x53F0A, 0x53F0B, 0x18005A, 0x18007A, 0xC706], None, True, 'Tower of Hera'), + 'Palace of Darkness - Prize': ( + [0x120A1, 0x53F00, 0x53F01, 0x180056, 0x18007D, 0xC702], None, True, 'Palace of Darkness'), + 'Swamp Palace - Prize': ( + [0x120A0, 0x53F6C, 0x53F6D, 0x180055, 0x180071, 0xC701], None, True, 'Swamp Palace'), + 'Thieves\' Town - Prize': ( + [0x120A6, 0x53F36, 0x53F37, 0x18005B, 0x180077, 0xC707], None, True, 'Thieves\' Town'), + 'Skull Woods - Prize': ( + [0x120A3, 0x53F12, 0x53F13, 0x180058, 0x18007B, 0xC704], None, True, 'Skull Woods'), + 'Ice Palace - Prize': ( + [0x120A4, 0x53F5A, 0x53F5B, 0x180059, 0x180073, 0xC705], None, True, 'Ice Palace'), + 'Misery Mire - Prize': ( + [0x120A2, 0x53F48, 0x53F49, 0x180057, 0x180075, 0xC703], None, True, 'Misery Mire'), + 'Turtle Rock - Prize': ( + [0x120A7, 0x53F24, 0x53F25, 0x18005C, 0x180079, 0xC708], None, True, 'Turtle Rock')} lookup_id_to_name = {data[0]: name for name, data in location_table.items() if type(data[0]) == int} lookup_id_to_name = {**lookup_id_to_name, **{data[1]: name for name, data in key_drop_data.items()}, -1: "cheat console"} diff --git a/Text.py b/Text.py index 76b33849ba..e04c24e2ab 100644 --- a/Text.py +++ b/Text.py @@ -258,6 +258,16 @@ TavernMan_texts = [ ] junk_texts = [ + "{C:GREEN}\nAgitha's good\nin Hyrule\nWarriors. >", + "{C:GREEN}\nConsult Fi if\nthe batteries\nare low. >", + "{C:GREEN}\nThere is no\n3rd quest in\nthis game. >", + "{C:GREEN}\nI am Error.\n \n >", + "{C:GREEN}\nThe Wind Fish\nknows all in\nhere. Hoot! >", + "{C:GREEN}\nThere are no\nwallets in\nthis game. >", + "{C:GREEN}\nCrossbow\nTraining is\na fun game. >", + "{C:GREEN}\nThe shrine\ncontains\nMagnesis. >", + "{C:GREEN}\nThe loftwing\nlet the duck\ntake over. >", + "{C:GREEN}\nStasis would\nbe very\noverpowered.>", "{C:GREEN}\nIt’s a secret\nto everybody.\n >", "{C:GREEN}\nDodongo\ndislikes\nsmoke. >", "{C:GREEN}\n> Digdogger\nhates certain\nkind of sound.", diff --git a/Utils.py b/Utils.py index fe7d726d8f..981092392c 100644 --- a/Utils.py +++ b/Utils.py @@ -6,7 +6,7 @@ def tuplize_version(version: str) -> typing.Tuple[int, ...]: return tuple(int(piece, 10) for piece in version.split(".")) -__version__ = "3.4.1" +__version__ = "3.4.2" _version_tuple = tuplize_version(__version__) import os diff --git a/WebHostLib/api/__init__.py b/WebHostLib/api/__init__.py index abe4aeb2f4..76878e4979 100644 --- a/WebHostLib/api/__init__.py +++ b/WebHostLib/api/__init__.py @@ -7,7 +7,8 @@ from ..models import Room api_endpoints = Blueprint('api', __name__, url_prefix="/api") -from . import generate +from . import generate, user # trigger registration + # unsorted/misc endpoints @@ -20,4 +21,4 @@ def room_info(room: UUID): "players": room.seed.multidata["names"], "last_port": room.last_port, "last_activity": room.last_activity, - "timeout": room.timeout} \ No newline at end of file + "timeout": room.timeout} diff --git a/WebHostLib/api/user.py b/WebHostLib/api/user.py new file mode 100644 index 0000000000..43a7bdcf9e --- /dev/null +++ b/WebHostLib/api/user.py @@ -0,0 +1,33 @@ +from flask import session, jsonify + +from WebHostLib.models import * +from . import api_endpoints + + +@api_endpoints.route('/get_rooms') +def get_rooms(): + response = [] + for room in select(room for room in Room if room.owner == session["_id"]): + response.append({ + "room_id": room.id, + "seed_id": room.seed.id, + "creation_time": room.creation_time, + "last_activity": room.last_activity, + "last_port": room.last_port, + "timeout": room.timeout, + "tracker": room.tracker, + "players": room.seed.multidata["names"] if room.seed.multidata else [["Singleplayer"]], + }) + return jsonify(response) + + +@api_endpoints.route('/get_seeds') +def get_seeds(): + response = [] + for seed in select(seed for seed in Seed if seed.owner == session["_id"]): + response.append({ + "seed_id": seed.id, + "creation_time": seed.creation_time, + "players": seed.multidata["names"] if seed.multidata else [["Singleplayer"]], + }) + return jsonify(response) \ No newline at end of file diff --git a/WebHostLib/generate.py b/WebHostLib/generate.py index d8c78ee02e..8d6aa0772b 100644 --- a/WebHostLib/generate.py +++ b/WebHostLib/generate.py @@ -45,8 +45,14 @@ def generate(race=False): return redirect(url_for("wait_seed", seed=gen.id)) else: - seed_id = gen_game({name: vars(options) for name, options in gen_options.items()}, - race=race, owner=session["_id"].int) + try: + seed_id = gen_game({name: vars(options) for name, options in gen_options.items()}, + race=race, owner=session["_id"].int) + except BaseException as e: + from .autolauncher import handle_generation_failure + handle_generation_failure(e) + return render_template("seedError.html", seed_error=(e.__class__.__name__ + ": "+ str(e))) + return redirect(url_for("viewSeed", seed=seed_id)) return render_template("generate.html", race=race) @@ -114,8 +120,7 @@ def wait_seed(seed: UUID): if not generation: return "Generation not found." elif generation.state == STATE_ERROR: - import html - return f"Generation failed, please retry.
{html.escape(generation.meta.decode())}" + return render_template("seedError.html", seed_error=generation.meta.decode()) return render_template("waitSeed.html", seed_id=seed_id) diff --git a/WebHostLib/static/assets/autodatatable.js b/WebHostLib/static/assets/autodatatable.js new file mode 100644 index 0000000000..a1437514e9 --- /dev/null +++ b/WebHostLib/static/assets/autodatatable.js @@ -0,0 +1,9 @@ +window.addEventListener('load', () => { + let tables = $(".autodatatable").DataTable({ + "paging": false, + "ordering": true, + "info": false, + "dom": "t", + }); + console.log(tables); +}); diff --git a/WebHostLib/static/assets/cookieNotice.js b/WebHostLib/static/assets/cookieNotice.js index f9cbb20092..4149d07620 100644 --- a/WebHostLib/static/assets/cookieNotice.js +++ b/WebHostLib/static/assets/cookieNotice.js @@ -5,6 +5,10 @@ window.addEventListener('load', () => { const cookieNotice = document.createElement('div'); cookieNotice.innerText = "This website uses cookies to store information about the games you play."; cookieNotice.setAttribute('id', 'cookie-notice'); + const closeButton = document.createElement('span'); + closeButton.setAttribute('id', 'close-button'); + closeButton.innerText = 'X'; + cookieNotice.appendChild(closeButton); document.body.appendChild(cookieNotice); cookieNotice.addEventListener('click', () => { localStorage.setItem('cookieNotice', "1"); diff --git a/WebHostLib/static/assets/hostGame.js b/WebHostLib/static/assets/hostGame.js index e5756d349d..db1ab1ddde 100644 --- a/WebHostLib/static/assets/hostGame.js +++ b/WebHostLib/static/assets/hostGame.js @@ -7,12 +7,5 @@ window.addEventListener('load', () => { document.getElementById('host-game-form').submit(); }); - $("#host-game-table").DataTable({ - "paging": false, - "ordering": true, - "order": [[ 3, "desc" ]], - "info": false, - "dom": "t", - }); adjustFooterHeight(); }); diff --git a/WebHostLib/static/assets/playerSettings.js b/WebHostLib/static/assets/playerSettings.js index de9f75e5af..e74bd47b5e 100644 --- a/WebHostLib/static/assets/playerSettings.js +++ b/WebHostLib/static/assets/playerSettings.js @@ -19,12 +19,12 @@ window.addEventListener('load', () => { // Sprite options const spriteData = JSON.parse(results[1]); const spriteSelect = document.getElementById('sprite'); - Object.keys(spriteData).forEach((sprite) => { - if (sprite.trim().length === 0) { return; } + spriteData.sprites.forEach((sprite) => { + if (sprite.name.trim().length === 0) { return; } const option = document.createElement('option'); - option.setAttribute('value', spriteData[sprite]); - if (playerSettings.rom.sprite === sprite) { option.selected = true; } - option.innerText = sprite; + option.setAttribute('value', sprite.name.trim()); + if (playerSettings.rom.sprite === sprite.name.trim()) { option.selected = true; } + option.innerText = sprite.name; spriteSelect.appendChild(option); }); }).catch((error) => { diff --git a/WebHostLib/static/assets/tutorial/tutorial_fr.md b/WebHostLib/static/assets/tutorial/tutorial_fr.md index 4999493202..114a0b0dfe 100644 --- a/WebHostLib/static/assets/tutorial/tutorial_fr.md +++ b/WebHostLib/static/assets/tutorial/tutorial_fr.md @@ -9,7 +9,7 @@ ## Logiciels requis - [Utilitaires du MultiWorld](https://github.com/Berserker66/MultiWorld-Utilities/releases) - [QUsb2Snes](https://github.com/Skarsnik/QUsb2snes/releases) (Inclus dans les utilitaires précédents) -- Une solution logicielle ou matérielle capable de charger et de jouer des fichiers ROM de SNES +- Une solution logicielle ou matérielle capable de charger et de lancer des fichiers ROM de SNES - Un émulateur capable d'éxécuter des scripts Lua ([snes9x Multitroid](https://drive.google.com/drive/folders/1_ej-pwWtCAHYXIrvs5Hro16A1s9Hi3Jz), [BizHawk](http://tasvideos.org/BizHawk.html)) @@ -21,17 +21,17 @@ ### Installation sur Windows 1. Téléchargez et installez les utilitaires du MultiWorld à l'aide du lien au-dessus, faites attention à bien installer la version la plus récente. **Le fichier se situe dans la section "assets" en bas des informations de version**. Si vous voulez jouer des parties classiques de multiworld, -vous voudrez télécharger `Setup.BerserkerMultiWorld.exe` - - Si vous voulez jouer à la version alternative avec le mélangeur de portes dans les donjons, vous voudrez télécharger le fichier +téléchargez `Setup.BerserkerMultiWorld.exe` + - Si vous voulez jouer à la version alternative avec le mélangeur de portes dans les donjons, vous téléchargez le fichier `Setup.BerserkerMultiWorld.Doors.exe`. - Durant le processus d'installation, il vous sera demandé de localiser votre ROM v1.0 japonaise. Si vous avez déjà installé le logiciel auparavant et qu'il s'agit simplement d'une mise à jour, la localisation de la ROM originale ne sera pas requise. - Il vous sera peut-être également demandé d'installer Microsoft Visual C++. Si vous le possédez déjà (possiblement parce qu'un jeu Steam l'a déjà installé), l'installateur ne reproposera pas de l'installer. -2. Si vous utilisez un émulateur, vous devriez assigner votre émulateur capable d'éxécuter des scripts Lua comme programme +2. Si vous utilisez un émulateur, il est recommandé d'assigner votre émulateur capable d'éxécuter des scripts Lua comme programme par défaut pour ouvrir vos ROMs. - 1. Extrayez votre dossier d'émulateur sur votre Bureau, ou quelque part dont vous vous souviendrez. + 1. Extrayez votre dossier d'émulateur sur votre Bureau, ou à un endroit dont vous vous souviendrez. 2. Faites un clic droit sur un fichier ROM et sélectionnez **Ouvrir avec...** 3. Cochez la case à côté de **Toujours utiliser cette application pour ouvrir les fichiers .sfc** 4. Descendez jusqu'en bas de la liste et sélectionnez **Rechercher une autre application sur ce PC** @@ -49,14 +49,12 @@ sur comment il devrait générer votre seed. Chaque joueur d'un multiwolrd devra joueur d'apprécier une expérience customisée selon ses goûts, et les différents joueurs d'un même multiworld peuvent avoir différentes options. ### Où est-ce que j'obtiens un fichier YAML ? -Un fichier YAML de base est disponible dans le dossier où les utilitaires du MultiWorld sont installés. Il est situé dans le dossier -`players` et se nomme `easy.yaml` -La page des [paramètres du joueur](/player-settings) vous permet de configurer vos paramètres personnels et de télécharger un fichier `yaml`. -Vous pouvez configurez jusqu'à trois pré-paramétrages sur cette page. +La page [Génération de partie](/player-settings) vous permet de configurer vos paramètres personnels et de les exporter vers un fichier YAML. -### Votre fichier YAML est pondéré -La page de paramétrage a de nombreuses options qui sont essentiellement représentées avec des curseurs glissants. Cela vous permet de choisir quelles -sont les chances qu'une certaine option apparaisse par rapport aux autres disponibles. +### Configuration avancée du fichier YAML +Une version plus avancée du fichier YAML peut être créée en utilisant la page des [paramètres de pondération](/weighted-settings), qui vous permet +de configurer jusqu'à trois préréglages. Cette page a de nombreuses options qui sont essentiellement représentées avec des curseurs glissants. +Cela vous permet de choisir quelles sont les chances qu'une certaine option apparaisse par rapport aux autres disponibles dans une même catégorie. Par exemple, imaginez que le générateur crée un seau étiqueté "Mélange des cartes", et qu'il place un morceau de papier pour chaque sous-option. Imaginez également que la valeur pour "On" est 20 et la valeur pour "Off" est 40. @@ -65,14 +63,15 @@ Dans cet exemple, il y a soixante morceaux de papier dans le seau : vingt pour " décide s'il doit oui ou non activer le mélange des cartes pour votre partie, , il tire aléatoirement un papier dans le seau. Dans cet exemple, il y a de plus grandes chances d'avoir le mélange de cartes désactivé. -S'il y a une option dont vous ne voulez jamais, mettez simplement sa valeur à zéro. +S'il y a une option dont vous ne voulez jamais, mettez simplement sa valeur à zéro. N'oubliez pas qu'il faut que pour chaque paramètre il faut +au moins une option qui soit paramétrée sur un nombre strictement positif. ### Vérifier son fichier YAML Si vous voulez valider votre fichier YAML pour être sûr qu'il fonctionne, vous pouvez le vérifier sur la page du [Validateur de YAML](/mysterycheck). ## Générer une partie pour un joueur -1. Aller sur la [page du générateur](/generate) et téléversez votre fichier YAML. +1. Aller sur la page [Génération de partie](/player-settings), configurez vos options, et cliquez sur le bouton "Generate Game". 2. Il vous sera alors présenté une page d'informations sur la seed, où vous pourrez télécharger votre patch. 3. Double-cliquez sur le patch et l'émulateur devrait se lancer automatiquement avec la seed. Etant donné que le client n'est pas requis pour les parties à un joueur, vous pouvez le fermer ainsi que l'interface Web (WebUI). @@ -120,10 +119,6 @@ Les utilisateurs de SD2SNES et de FXPak Pro peuvent télécharger le micro-logic [ici](https://github.com/RedGuyyyy/sd2snes/releases). Pour les autres solutions, de l'aide peut être trouvée [sur cette page](http://usb2snes.com/#supported-platforms). -**Pour vous connecter avec une solution matérielle vous devez utiliser une ancienne version de QUsb2Snes -([v0.7.16](https://github.com/Skarsnik/QUsb2snes/releases/tag/v0.7.16)).** -Les versions postérieures brisent la compatibilité avec le multiworld. - 1. Fermez votre émulateur, qui s'est potentiellement lancé automatiquement. 2. Fermez QUsb2Snes, qui s'est lancé automatiquement avec le client. 3. Lancez la version appropriée de QUsb2Snes (v0.7.16). @@ -149,13 +144,31 @@ La méthode recommandée pour héberger une partie est d'utiliser le service d'h 1. Récupérez les fichiers YAML des joueurs. 2. Créez une archive zip contenant ces fichiers YAML. -3. Téléversez l'archive zip sur le lien au-dessus. +3. Téléversez l'archive zip sur le lien ci-dessus. 4. Attendez un moment que les seed soient générées. -5. Lorsque les seeds sont générées, vous serez redirigé vers une page d'informations. +5. Lorsque les seeds sont générées, vous serez redirigé vers une page d'informations "Seed Info". 6. Cliquez sur "Create New Room". Cela vous amènera à la page du serveur. Fournissez le lien de cette page aux autres joueurs afin qu'ils puissent récupérer leurs patchs. **Note:** Les patchs fournis sur cette page permettront aux joueurs de se connecteur automatiquement au serveur, tandis que ceux de la page "Seed Info" non. 7. Remarquez qu'un lien vers le traqueur du MultiWorld est en haut de la page de la salle. Vous devriez également fournir ce lien aux joueurs - pour qu'ils puissent la progression de la partie. N'importe quel personne voulant observer devrait avoir accès à ce lien. -8. Une fois que tous les joueurs ont rejoint, vous pouvez commencer à jouer. \ No newline at end of file + pour qu'ils puissent suivre la progression de la partie. N'importe quel personne voulant observer devrait avoir accès à ce lien. +8. Une fois que tous les joueurs ont rejoint, vous pouvez commencer à jouer. + +## Auto-tracking +Si vous voulez utiliser l'auto-tracking, plusieurs logiciels offrent cette possibilité. +Le logiciel recommandé pour l'auto-tracking actuellement est +[OpenTracker](https://github.com/trippsc2/OpenTracker/releases). + +### Installation +1. Téléchargez le fichier d'installation approprié pour votre ordinateur (Les utilisateurs Windows voudront le fichier `.msi`). +2. Durant le processus d'installation, il vous sera peut-être demandé d'installer les outils "Microsoft Visual Studio Build Tools". Un +lien est fourni durant l'installation d'OpenTracker, et celle des outils doit se faire manuellement. + +### Activer l'auto-tracking +1. Une fois OpenTracker démarré, cliquez sur le menu "Tracking" en haut de la fenêtre, puis choisissez **AutoTracker...** +2. Appuyez sur le bouton **Get Devices** +3. Sélectionnez votre appareil SNES dans la liste déroulante. +4. Si vous voulez tracquer les petites clés ainsi que les objets des donjons, cochez la case **Race Illegal Tracking** +5. Cliquez sur le bouton **Start Autotracking** +6. Fermez la fenêtre "AutoTracker" maintenant, elle n'est plus nécessaire \ No newline at end of file diff --git a/WebHostLib/static/assets/userContent.js b/WebHostLib/static/assets/userContent.js new file mode 100644 index 0000000000..dcc8f56505 --- /dev/null +++ b/WebHostLib/static/assets/userContent.js @@ -0,0 +1,17 @@ +window.addEventListener('load', () => { + console.log("loaded"); + $("#rooms-table").DataTable({ + "paging": false, + "ordering": true, + "order": [[ 3, "desc" ]], + "info": false, + "dom": "t", + }); + $("#seeds-table").DataTable({ + "paging": false, + "ordering": true, + "order": [[ 2, "desc" ]], + "info": false, + "dom": "t", + }); +}); diff --git a/WebHostLib/static/assets/weightedSettings.js b/WebHostLib/static/assets/weightedSettings.js index 7f6afcd25c..19b2f5e4e1 100644 --- a/WebHostLib/static/assets/weightedSettings.js +++ b/WebHostLib/static/assets/weightedSettings.js @@ -13,11 +13,8 @@ window.addEventListener('load', () => { localStorage.setItem(`weightedSettings${i}`, JSON.stringify(updatedObj)); } - // Parse spriteData into useful sets - spriteData = JSON.parse(results[2]); - // Build the entire UI - buildUI(JSON.parse(results[1])); + buildUI(JSON.parse(results[1]), JSON.parse(results[2])); // Populate the UI and add event listeners populateSettings(); @@ -29,6 +26,7 @@ window.addEventListener('load', () => { document.getElementById('reset-to-default').addEventListener('click', resetToDefaults); adjustHeaderWidth(); }).catch((error) => { + console.error(error); gameSettings.innerHTML = `

Something went wrong while loading your game settings page.

${error}

@@ -170,7 +168,7 @@ const download = (filename, text) => { document.body.removeChild(downloadLink); }; -const buildUI = (settings) => { +const buildUI = (settings, spriteData) => { const settingsWrapper = document.getElementById('settings-wrapper'); const settingTypes = { gameOptions: 'Game Options', @@ -244,7 +242,7 @@ const buildUI = (settings) => { settingsWrapper.appendChild(spriteOptionsWrapper); // Append sprite picker - settingsWrapper.appendChild(buildSpritePicker()); + settingsWrapper.appendChild(buildSpritePicker(spriteData)); }; const buildRangeSettings = (parentElement, settings) => { @@ -404,7 +402,7 @@ const removeSpriteOption = (event) => { tr.parentNode.removeChild(tr); }; -const buildSpritePicker = () => { +const buildSpritePicker = (spriteData) => { const spritePicker = document.createElement('div'); spritePicker.setAttribute('id', 'sprite-picker'); @@ -415,18 +413,18 @@ const buildSpritePicker = () => { const sprites = document.createElement('div'); sprites.setAttribute('id', 'sprite-picker-sprites'); - Object.keys(spriteData).forEach((spriteName) => { + spriteData.sprites.forEach((sprite) => { const spriteImg = document.createElement('img'); - spriteImg.setAttribute('src', `static/static/sprites/${spriteName}.gif`); - spriteImg.setAttribute('data-sprite', spriteName); - spriteImg.setAttribute('alt', spriteName); + spriteImg.setAttribute('src', `static/static/sprites/${sprite.name}.gif`); + spriteImg.setAttribute('data-sprite', sprite.name); + spriteImg.setAttribute('alt', sprite.name); // Wrap the image in a span to allow for tooltip presence const imgWrapper = document.createElement('span'); imgWrapper.className = 'sprite-img-wrapper'; - imgWrapper.setAttribute('data-tooltip', spriteName); + imgWrapper.setAttribute('data-tooltip', `${sprite.name}${sprite.author ? `, by ${sprite.author}` : ''}`); imgWrapper.appendChild(spriteImg); - imgWrapper.setAttribute('data-sprite', spriteName); + imgWrapper.setAttribute('data-sprite', sprite.name); sprites.appendChild(imgWrapper); imgWrapper.addEventListener('click', addSpriteOption); }); diff --git a/WebHostLib/static/static/playerSettings.json b/WebHostLib/static/static/playerSettings.json index 4d9d5c2daf..d57fb58905 100644 --- a/WebHostLib/static/static/playerSettings.json +++ b/WebHostLib/static/static/playerSettings.json @@ -37,9 +37,17 @@ "name": "Master Sword Pedestal", "value": "pedestal" }, + { + "name": "Master Sword Pedestal + Ganon", + "value": "ganon_pedestal" + }, { "name": "Triforce Hunt", "value": "triforce_hunt" + }, + { + "name": "Triforce Hunt + Ganon", + "value": "ganon_triforce_hunt" } ] }, @@ -209,7 +217,7 @@ }, "hints": { "type": "select", - "friendlyName": "Tile Hints", + "friendlyName": "Hints", "description": "Choose to enable or disable tile hints", "defaultValue": "on", "options": [ @@ -313,6 +321,10 @@ "name": "Big Keys Only", "value": "b" }, + { + "name": "Small and Big Keys", + "value": "sb" + }, { "name": "Full Keysanity", "value": "mscb" @@ -334,15 +346,15 @@ "value": "none" }, { - "name": "Dungeon Entrances", + "name": "Only Dungeons, Simple", "value": "dungeonssimple" }, { - "name": "Dungeon Interiors", + "name": "Only Dungeons, Full", "value": "dungeonsfull" }, { - "name": "Simple Entrances", + "name": "Simple", "value": "simple" }, { @@ -350,15 +362,15 @@ "value": "restricted" }, { - "name": "Full Shuffle", + "name": "Full", "value": "full" }, { - "name": "Crossed Shuffle", + "name": "Crossed", "value": "crossed" }, { - "name": "Insanity Shuffle", + "name": "Insanity", "value": "insanity" } ] @@ -466,16 +478,24 @@ "value": "none" }, { - "name": "Shuffle Inventory", + "name": "Inventory", "value": "i" }, { - "name": "Shuffle Prices", + "name": "Prices", "value": "p" }, { - "name": "Shuffle Both", + "name": "Capacity Upgrades", + "value": "u" + }, + { + "name": "Inventory and Prices", "value": "ip" + }, + { + "name": "Inventory, Prices, and Upgrades", + "value": "ipu" } ] } @@ -612,7 +632,7 @@ "value": "default" }, { - "name": "Shuffled", + "name": "Randomized", "value": "random" } ] @@ -628,7 +648,7 @@ "value": "default" }, { - "name": "Shuffled", + "name": "Randomized", "value": "random" } ] @@ -644,7 +664,7 @@ "value": "default" }, { - "name": "Shuffled", + "name": "Randomized", "value": "random" } ] @@ -660,7 +680,7 @@ "value": "default" }, { - "name": "Shuffled", + "name": "Randomized", "value": "random" } ] diff --git a/WebHostLib/static/static/spriteData.json b/WebHostLib/static/static/spriteData.json index fdf9e7f5f2..4f7ab8a4d1 100644 --- a/WebHostLib/static/static/spriteData.json +++ b/WebHostLib/static/static/spriteData.json @@ -1 +1,1609 @@ -{"Link": "001.link.1.zspr", "Four Swords Link": "4slink-armors.1.zspr", "Abigail": "abigail.1.zspr", "Adol": "adol.1.zspr", "Aggretsuko": "aggretsuko.1.zspr", "Alice": "alice.1.zspr", "Angry Video Game Nerd": "angry-video-game-nerd.1.zspr", "Arcane": "arcane.1.zspr", "Ark (No Cape)": "ark-dorana.1.zspr", "Ark (Cape)": "ark.1.zspr", "Arrghus": "arrghus.2.zspr", "Astronaut": "astronaut.1.zspr", "Asuna": "asuna.1.zspr", "Badeline": "badeline.1.zspr", "Bananas In Pyjamas": "bananas-in-pyjamas.1.zspr", "Bandit": "bandit.1.zspr", "Batman": "batman.1.zspr", "Beau": "beau.1.zspr", "Bewp": "bewp.1.zspr", "Big Key": "bigkey.1.zspr", "Birb": "birb.1.zspr", "Birdo": "birdo.1.zspr", "Black Mage": "blackmage.1.zspr", "Blacksmith Link": "blacksmithlink.1.zspr", "Blazer": "blazer.1.zspr", "Blossom": "blossom.1.zspr", "Bob": "bob.1.zspr", "Bob Ross": "bobross.1.zspr", "boco": "boco.1.zspr", "Boo 2": "boo-two.1.zspr", "Boo": "boo.2.zspr", "Bottle o' Goo": "bottle_o_goo.1.zspr", "BotW Link": "botw-link.1.zspr", "botw-zelda": "botw-zelda.1.zspr", "Bowser": "bowser.1.zspr", "Bowsette Red": "bowsette-red.1.zspr", "Bowsette": "bowsette.1.zspr", "Branch": "branch.1.zspr", "Brian": "brian.1.zspr", "Broccoli": "broccoli.1.zspr", "Bronzor": "bronzor.1.zspr", "B.S. Boy": "bsboy.1.zspr", "B.S. Girl": "bsgirl.1.zspr", "Bubbles": "bubbles.1.zspr", "Bullet Bill": "bullet_bill.1.zspr", "Buttercup": "buttercup.1.zspr", "Cactuar": "cactuar.1.zspr", "Cadence": "cadence.1.zspr", "CarlSagan42": "carlsagan42.1.zspr", "Casual Zelda": "casual-zelda.1.zspr", "Marvin the Cat": "cat.3.zspr", "Cat Boo": "catboo.1.zspr", "CD-i Link": "cdilink.1.zspr", "Celes": "celes.1.zspr", "Charizard": "charizard.1.zspr", "Cheep Cheep": "cheepcheep.1.zspr", "Chibity": "chibity.1.zspr", "Chrizzz": "chrizzz.1.zspr", "Cirno": "cirno.1.zspr", "Clifford": "clifford.1.zspr", "Clyde": "clyde.1.zspr", "Conker": "conker.1.zspr", "Cornelius": "cornelius.1.zspr", "Untitled": "corona.1.zspr", "Imposter": "crewmate.1.zspr", "Cucco": "cucco.1.zspr", "Cursor": "cursor.1.zspr", "Dark Panda": "dark-panda.1.zspr", "Dark Boy": "darkboy.1.zspr", "Dark Girl": "darkgirl.1.zspr", "Dark Link (Tunic)": "darklink-tunic.1.zspr", "Dark Link": "darklink.1.zspr", "Dark Swatchy": "darkswatchy.1.zspr", "Dark Zelda": "darkzelda.1.zspr", "Dark Zora": "darkzora.2.zspr", "Deadpool (Mythic)": "deadpool-mythic.1.zspr", "Deadpool (SirCzah)": "deadpool.1.zspr", "Deadrock": "deadrock.1.zspr", "Decidueye": "decidueye.1.zspr", "Dekar": "dekar.1.zspr", "Demon Link": "demonlink.1.zspr", "Dragonite": "dragonite.2.zspr", "Drake The Dragon": "drake.1.zspr", "D.Owls": "d_owls.2.zspr", "Eggplant": "eggplant.1.zspr", "EmoSaru": "emosaru.1.zspr", "Ezlo": "ezlo.1.zspr", "Fierce Deity Link": "fierce-deity-link.2.zspr", "Finn Merten": "finn.3.zspr", "Finny Bear": "finny_bear.1.zspr", "Floodgate Fish": "fish_floodgate.1.zspr", "Flavor Guy": "flavor_guy.1.zspr", "Fox Link": "foxlink.1.zspr", "Freya Crescent": "freya.1.zspr", "Frisk": "frisk.1.zspr", "Frog Link": "froglink.3.zspr", "Fujin": "fujin.2.zspr", "Future Trunks": "future_trunks.1.zspr", "Gamer": "gamer.1.zspr", "Mini Ganon": "ganon.1.zspr", "Ganondorf": "ganondorf.1.zspr", "Garfield": "garfield.2.zspr", "Garnet": "garnet.1.zspr", "Garo Master": "garomaster.1.zspr", "GBC Link": "gbc-link.1.zspr", "Geno": "geno.1.zspr", "GliitchWiitch": "gliitchwiitch.1.zspr", "Gobli": "gobli.1.zspr", "Goomba": "goomba.1.zspr", "Goose": "goose.1.zspr", "GrandPOOBear": "grandpoobear.2.zspr", "Gretis": "gretis.1.zspr", "Gruncle Stan": "grunclestan.1.zspr", "GuizDP": "guiz.1.zspr", "Hanna": "hanna.1.zspr", "Hardhat Beetle": "hardhat_beetle.1.zspr", "Hat Kid": "hat-kid.1.zspr", "Headless Link": "headlesslink.1.zspr", "Hello Kitty": "hello_kitty.1.zspr", "Hidari": "hidari.1.zspr", "Hint Tile": "hint_tile.1.zspr", "Hoarder (Bush)": "hoarder-bush.1.zspr", "Hoarder (Pot)": "hoarder-pot.1.zspr", "Hoarder (Rock)": "hoarder-rock.1.zspr", "hollow_test": "hollow-knight.1.zspr", "Homer Simpson": "homer.1.zspr", "Hotdog": "hotdog.1.zspr", "Hyrule Knight": "hyruleknight.1.zspr", "iBazly": "ibazly.1.zspr", "Ignignokt": "ignignokt.2.zspr", "Informant Woman": "informant_woman.1.zspr", "Inkling": "inkling.1.zspr", "Invisible Link": "invisibleman.1.zspr", "Jack Frost": "jack-frost.1.zspr", "Jason Frudnick": "jason_frudnick.1.zspr", "Jasp": "jasp.1.zspr", "Jogurt": "jogurt.1.zspr", "Katsura": "katsura.1.zspr", "Kecleon": "kecleon.1.zspr", "Kenny McCormick": "kenny_mccormick.1.zspr", "Ketchup": "ketchup.1.zspr", "Kholdstare": "kholdstare.1.zspr", "King Gothalion": "king_gothalion.1.zspr", "King Graham v1.1": "king_graham.1.zspr", "Kirby": "kirby-meta.1.zspr", "Kore8": "kore8.1.zspr", "Korok": "korok.1.zspr", "Lakitu": "lakitu.1.zspr", "Lapras": "lapras.1.zspr", "Lest": "lest.1.zspr", "Lily": "lily.1.zspr", "Linja": "linja.1.zspr", "Link Redrawn": "link-redrawn.1.zspr", "Hat Color Link": "linkhatcolor.1.zspr", "Tunic Color Link": "linktuniccolor.1.zspr", "Little Hylian": "little-hylian.1.zspr", "Pony": "littlepony.1.zspr", "Locke": "locke.1.zspr", "Figaro Merchant": "locke_merchant.1.zspr", "Lucario": "lucario.1.zspr", "Hitsuyan1337": "luffy.1.zspr", "Luigi": "luigi.1.zspr", "Luna Maindo": "luna-maindo.1.zspr", "Madeline": "madeline.1.zspr", "Magus": "magus.1.zspr", "Maiden": "maiden.1.zspr", "Mallow (Cat)": "mallow-cat.1.zspr", "Manga Link": "mangalink.1.zspr", "Maple Queen": "maplequeen.2.zspr", "Marin": "marin.2.zspr", "Mario (Classic)": "mario-classic.2.zspr", "Mario and Cappy": "mariocappy.1.zspr", "Tanooki Mario": "mario_tanooki.1.zspr", "Marisa Kirisame": "marisa.1.zspr", "Matthias": "matthias.1.zspr", "Meatwad": "meatwad.1.zspr", "Medallions": "medallions.1.zspr", "Medli": "medli.1.zspr", "Megaman X": "megaman-x.2.zspr", "Baby Metroid": "metroid.1.zspr", "MewLp": "mew.1.zspr", "Mike Jones": "mike-jones.2.zspr", "Minish Cap Link": "minishcaplink.2.zspr", "Minish Link": "minish_link.1.zspr", "missingno": "missingno.1.zspr", "MoblinSprite": "moblin.1.zspr", "Modern Link": "modernlink.1.zspr", "Mog": "mog.2.zspr", "Momiji Inubashiri": "momiji.1.zspr", "Moosh": "moosh.1.zspr", "Mouse": "mouse.1.zspr", "Ms. Paint Dog": "ms-paintdog.1.zspr", "Power Up with Pride Mushroom": "mushy.1.zspr", "Nature Link": "naturelink.1.zspr", "Navi": "navi.1.zspr", "Navirou": "navirou.2.zspr", "Ned Flanders": "ned-flanders.1.zspr", "Negative Link": "negativelink.1.zspr", "Neosad": "neosad.1.zspr", " NES Link": "neslink.1.zspr", "Ness (Earthbound)": "ness.1.zspr", "Nia": "nia.1.zspr", "Niddraig": "niddraig.1.zspr", "Niko": "niko.1.zspr", "Old Man": "oldman.2.zspr", "Ori": "ori.2.zspr", "Outline Link": "outlinelink.1.zspr", "Parallel Worlds Link": "parallelworldslink.1.zspr", "Paula": "paula.1.zspr", "Princess Peach": "peach.1.zspr", "Penguin Link": "penguinlink.1.zspr", "Pete (Harvest Moon)": "pete.1.zspr", "Phoenix Wright": "phoenix-wright.1.zspr", "Pikachu": "pikachu.1.zspr", "Pink Ribbon Link": "pinkribbonlink.2.zspr", "Piranha Plant": "piranha_plant.1.zspr", "Plague Knight": "plagueknight.1.zspr", "Pokey": "pokey.1.zspr", "Popoi": "popoi.1.zspr", "Poppy": "poppy.1.zspr", "Porg Knight": "porg_knight.1.zspr", "Powerpuff Girl": "powerpuff_girl.1.zspr", "Pride Link": "pridelink.2.zspr", "Primm": "primm.1.zspr", "Princess Bubblegum": "princess_bubblegum.1.zspr", "Psyduck": "psyduck.2.zspr", "The Pug": "pug.1.zspr", "Purple Chest": "purplechest-bottle.1.zspr", "Pyro": "pyro.1.zspr", "Rainbow Link": "rainbowlink.1.zspr", "Rat": "rat.1.zspr", "Red Mage": "red-mage.1.zspr", "Remeer": "remeer.1.zspr", "Rick (Redacted)": "rick.1.zspr", "Robo-Link 9000": "robotlink.1.zspr", "Rocko": "rocko.1.zspr", "Rottytops": "rottytops.1.zspr", "Rover": "rover.1.zspr", "Roy Koopa": "roykoopa.1.zspr", "Rumia": "rumia.1.zspr", "Rydia": "rydia.1.zspr", "Ryu": "ryu.1.zspr", "Sailor Moon": "sailormoon.1.zspr", "Saitama": "saitama.1.zspr", "Samus (Super Metroid)": "samus-sm.1.zspr", "Samus": "samus.2.zspr", "Samus (Classic)": "samus_classic.1.zspr", "Santa Link": "santalink.2.zspr", "Scholar": "scholar.1.zspr", "Selan": "selan.1.zspr", "SevenS1ns": "sevens1ns.1.zspr", "Shadow": "shadow.1.zspr", "Shadow Sakura": "shadowsaku.2.zspr", "Shantae": "shantae.1.zspr", "Shuppet": "shuppet.1.zspr", "Shy Gal": "shy-gal.1.zspr", "Shy Guy": "shy-guy.1.zspr", "SighnWaive": "sighn_waive.1.zspr", "DQ Slime": "slime.1.zspr", "Slowpoke": "slowpoke.1.zspr", "SNES Controller": "snes-controller.1.zspr", "Soda Can": "sodacan.1.zspr", "Solaire of Astora": "solaire.1.zspr", "Hyrule Soldier": "soldiersprite.1.zspr", "Sonic the Hedgehog": "sonic.1.zspr", "Sora": "sora.1.zspr", "Sora (KH1)": "sora_kh1.1.zspr", "SpongeBob SquarePants": "spongebob.1.zspr", "Squall": "squall.1.zspr", "Squirrel": "squirrel.1.zspr", "Squirtle": "squirtle.1.zspr", "Stalfos": "stalfos.1.zspr", "Stan": "stan.1.zspr", "Static Link": "staticlink.1.zspr", "Steamed Ham": "steamedhams.1.zspr", "Stick Man": "stick_man.1.zspr", "Super Bomb": "superbomb.1.zspr", "Super Bunny": "superbunny.2.zspr", "Super Meat Boy": "supermeatboy.1.zspr", "Susie": "susie.1.zspr", "Swatchy": "swatchy.1.zspr", "TASBot": "tasbot.1.zspr", "Tea Time": "teatime.1.zspr", "Terra (Esper)": "terra.1.zspr", "Tetra Sheet": "tetra.1.zspr", "TGH": "tgh.1.zspr", "Thief": "thief.1.zspr", "Thomcrow": "thomcrow.1.zspr", "Tile": "tile.2.zspr", "Tingle": "tingle.1.zspr", "TMNT": "tmnt.1.zspr", "Toad": "toad.2.zspr", "Toadette": "toadette.2.zspr", "Captain Toadette": "toadette_captain.1.zspr", "TotemLinks": "totem-links.1.zspr", "Trogdor the Burninator": "trogdor.1.zspr", "TP Zelda": "twilightprincesszelda.2.zspr", "TwoFaced": "two_faced.1.zspr", "Ty the Tasmanian Tiger": "ty.1.zspr", "Ultros": "ultros.1.zspr", "Valeera": "valeera.1.zspr", "VanillaLink": "vanillalink.1.zspr", "Vaporeon": "vaporeon.1.zspr", "Vegeta": "vegeta.1.zspr", "Vera": "vera.1.zspr", "Vitreous": "vitreous.1.zspr", "Vivi": "vivi.1.zspr", "Vivian": "vivian.1.zspr", "Wario": "wario.1.zspr", "Will": "will.1.zspr", "Wizzrobe": "wizzrobe.2.zspr", "Wolf Link (Festive)": "wolf_link.1.zspr", "Wolf Link (TP)": "wolf_link_tp.1.zspr", "Yoshi": "yoshi.1.zspr", "Yunica Tovah": "yunica.1.zspr", "Zandra": "zandra.1.zspr", "Zebra Unicorn": "zebraunicorn.1.zspr", "Zeckemyro": "zeck.1.zspr", "Zelda": "zelda.1.zspr", "Zero Suit Samus": "zerosuitsamus.2.zspr", "Zora": "zora.2.zspr"} \ No newline at end of file +{ + "sprites": [ + { + "file": "neslink.1.zspr", + "author": "MikeTrethewey/Fatmanspanda", + "name": " NES Link" + }, + { + "file": "abigail.1.zspr", + "author": "Fish_waffle64", + "name": "Abigail" + }, + { + "file": "adol.1.zspr", + "author": "Yuushia", + "name": "Adol" + }, + { + "file": "aggretsuko.1.zspr", + "author": "skovacs1", + "name": "Aggretsuko" + }, + { + "file": "alice.1.zspr", + "author": "Artheau", + "name": "Alice" + }, + { + "file": "angry-video-game-nerd.1.zspr", + "author": "ABOhiccups", + "name": "Angry Video Game Nerd" + }, + { + "file": "arcane.1.zspr", + "author": "MM102", + "name": "Arcane" + }, + { + "file": "ark.1.zspr", + "author": "wzl", + "name": "Ark (Cape)" + }, + { + "file": "ark-dorana.1.zspr", + "author": "Matt Dorana", + "name": "Ark (No Cape)" + }, + { + "file": "arrghus.2.zspr", + "author": "fatmanspanda", + "name": "Arrghus" + }, + { + "file": "astronaut.1.zspr", + "author": "Malmo", + "name": "Astronaut" + }, + { + "file": "asuna.1.zspr", + "author": "Natsuru Kiyohoshi", + "name": "Asuna" + }, + { + "file": "bsboy.1.zspr", + "author": "InTheBeef", + "name": "B.S. Boy" + }, + { + "file": "bsgirl.1.zspr", + "author": "InTheBeef", + "name": "B.S. Girl" + }, + { + "file": "metroid.1.zspr", + "author": "Jam", + "name": "Baby Metroid" + }, + { + "file": "badeline.1.zspr", + "author": "Jam", + "name": "Badeline" + }, + { + "file": "bananas-in-pyjamas.1.zspr", + "author": "codemann8", + "name": "Bananas In Pyjamas" + }, + { + "file": "bandit.1.zspr", + "author": "Fenrika", + "name": "Bandit" + }, + { + "file": "batman.1.zspr", + "author": "Ninjakauz", + "name": "Batman" + }, + { + "file": "beau.1.zspr", + "author": "Achy", + "name": "Beau" + }, + { + "file": "bewp.1.zspr", + "author": "Valechec", + "name": "Bewp" + }, + { + "file": "bigkey.1.zspr", + "author": "Fouton", + "name": "Big Key" + }, + { + "file": "birb.1.zspr", + "author": "Andrew Copple", + "name": "Birb" + }, + { + "file": "birdo.1.zspr", + "author": "BlackTycoon", + "name": "Birdo" + }, + { + "file": "blackmage.1.zspr", + "author": "TheRedMage", + "name": "Black Mage" + }, + { + "file": "blacksmithlink.1.zspr", + "author": "Glan", + "name": "Blacksmith Link" + }, + { + "file": "blazer.1.zspr", + "author": "Herowho", + "name": "Blazer" + }, + { + "file": "blossom.1.zspr", + "author": "Artheau", + "name": "Blossom" + }, + { + "file": "bob.1.zspr", + "author": "fatmanspanda", + "name": "Bob" + }, + { + "file": "bobross.1.zspr", + "author": "CaptainApathy", + "name": "Bob Ross" + }, + { + "file": "boo.2.zspr", + "author": "Zarby89", + "name": "Boo" + }, + { + "file": "boo-two.1.zspr", + "author": "Achy", + "name": "Boo 2" + }, + { + "file": "botw-link.1.zspr", + "author": "Pasta La Vista", + "name": "BotW Link" + }, + { + "file": "botw-zelda.1.zspr", + "author": "Roo", + "name": "BotW Zelda" + }, + { + "file": "bottle_o_goo.1.zspr", + "author": "Fish_waffle64", + "name": "Bottle o' Goo" + }, + { + "file": "bowser.1.zspr", + "author": "Artheau", + "name": "Bowser" + }, + { + "file": "bowsette.1.zspr", + "author": "Sarah Shinespark", + "name": "Bowsette" + }, + { + "file": "bowsette-red.1.zspr", + "author": "Sarah Shinespark", + "name": "Bowsette Red" + }, + { + "file": "branch.1.zspr", + "author": "cbass601", + "name": "Branch" + }, + { + "file": "brian.1.zspr", + "author": "Herowho", + "name": "Brian" + }, + { + "file": "broccoli.1.zspr", + "author": "fatmanspanda", + "name": "Broccoli" + }, + { + "file": "bronzor.1.zspr", + "author": "fatmanspanda", + "name": "Bronzor" + }, + { + "file": "bubbles.1.zspr", + "author": "Artheau", + "name": "Bubbles" + }, + { + "file": "bullet_bill.1.zspr", + "author": "Artheau", + "name": "Bullet Bill" + }, + { + "file": "buttercup.1.zspr", + "author": "Artheau", + "name": "Buttercup" + }, + { + "file": "cdilink.1.zspr", + "author": "SnipSlum", + "name": "CD-i Link" + }, + { + "file": "cactuar.1.zspr", + "author": "RyuTech", + "name": "Cactuar" + }, + { + "file": "cadence.1.zspr", + "author": "Fish_waffle64", + "name": "Cadence" + }, + { + "file": "toadette_captain.1.zspr", + "author": "Devan2002", + "name": "Captain Toadette" + }, + { + "file": "carlsagan42.1.zspr", + "author": "FedoraFriday", + "name": "CarlSagan42" + }, + { + "file": "casual-zelda.1.zspr", + "author": "Fish_waffle64", + "name": "Casual Zelda" + }, + { + "file": "catboo.1.zspr", + "author": "JaySee87", + "name": "Cat Boo" + }, + { + "file": "celes.1.zspr", + "author": "Deagans", + "name": "Celes" + }, + { + "file": "charizard.1.zspr", + "author": "Charmander106", + "name": "Charizard" + }, + { + "file": "cheepcheep.1.zspr", + "author": "Faw", + "name": "Cheep Cheep" + }, + { + "file": "chibity.1.zspr", + "author": "Ecyro", + "name": "Chibity" + }, + { + "file": "chrizzz.1.zspr", + "author": "Chrizzz", + "name": "Chrizzz" + }, + { + "file": "cirno.1.zspr", + "author": "Achy", + "name": "Cirno" + }, + { + "file": "clifford.1.zspr", + "author": "PlaguedOne", + "name": "Clifford" + }, + { + "file": "clyde.1.zspr", + "author": "Artheau", + "name": "Clyde" + }, + { + "file": "conker.1.zspr", + "author": "Charmander106/SePH", + "name": "Conker" + }, + { + "file": "cornelius.1.zspr", + "author": "Lori", + "name": "Cornelius" + }, + { + "file": "cucco.1.zspr", + "author": "MikeTrethewey", + "name": "Cucco" + }, + { + "file": "cursor.1.zspr", + "author": "PlaguedOne", + "name": "Cursor" + }, + { + "file": "d_owls.2.zspr", + "author": "D.Owls", + "name": "D.Owls" + }, + { + "file": "slime.1.zspr", + "author": "KamenRideDecade", + "name": "DQ Slime" + }, + { + "file": "darkboy.1.zspr", + "author": "iBazly", + "name": "Dark Boy" + }, + { + "file": "darkgirl.1.zspr", + "author": "iBazly", + "name": "Dark Girl" + }, + { + "file": "darklink.1.zspr", + "author": "iBazly", + "name": "Dark Link" + }, + { + "file": "darklink-tunic.1.zspr", + "author": "Damon", + "name": "Dark Link (Tunic)" + }, + { + "file": "dark-panda.1.zspr", + "author": "MM102", + "name": "Dark Panda" + }, + { + "file": "darkswatchy.1.zspr", + "author": "Mike Trethewey", + "name": "Dark Swatchy" + }, + { + "file": "darkzelda.1.zspr", + "author": "iBazly", + "name": "Dark Zelda" + }, + { + "file": "darkzora.2.zspr", + "author": "iBazly", + "name": "Dark Zora" + }, + { + "file": "deadpool-mythic.1.zspr", + "author": "Mythic", + "name": "Deadpool (Mythic)" + }, + { + "file": "deadpool.1.zspr", + "author": "SirCzah", + "name": "Deadpool (SirCzah)" + }, + { + "file": "deadrock.1.zspr", + "author": "Glan", + "name": "Deadrock" + }, + { + "file": "decidueye.1.zspr", + "author": "Achy", + "name": "Decidueye" + }, + { + "file": "dekar.1.zspr", + "author": "The3X", + "name": "Dekar" + }, + { + "file": "demonlink.1.zspr", + "author": "Krelbel", + "name": "Demon Link" + }, + { + "file": "dragonite.2.zspr", + "author": "Fish_waffle64", + "name": "Dragonite" + }, + { + "file": "drake.1.zspr", + "author": "No Body The Dragon", + "name": "Drake The Dragon" + }, + { + "file": "eggplant.1.zspr", + "author": "PlaguedOne", + "name": "Eggplant" + }, + { + "file": "emosaru.1.zspr", + "author": "Achy", + "name": "EmoSaru" + }, + { + "file": "ezlo.1.zspr", + "author": "cbass601", + "name": "Ezlo" + }, + { + "file": "fierce-deity-link.2.zspr", + "author": "jeffreygriggs2", + "name": "Fierce Deity Link" + }, + { + "file": "locke_merchant.1.zspr", + "author": "Artheau", + "name": "Figaro Merchant" + }, + { + "file": "finn.3.zspr", + "author": "Devan2002", + "name": "Finn Merten" + }, + { + "file": "finny_bear.1.zspr", + "author": "skovacs1", + "name": "Finny Bear" + }, + { + "file": "flavor_guy.1.zspr", + "author": "PlaguedOne", + "name": "Flavor Guy" + }, + { + "file": "fish_floodgate.1.zspr", + "author": "Delphi1024", + "name": "Floodgate Fish" + }, + { + "file": "4slink-armors.1.zspr", + "author": "Mike Trethewey", + "name": "Four Swords Link" + }, + { + "file": "foxlink.1.zspr", + "author": "InTheBeef", + "name": "Fox Link" + }, + { + "file": "freya.1.zspr", + "author": "Demoncraze", + "name": "Freya Crescent" + }, + { + "file": "frisk.1.zspr", + "author": "Original by Toby Fox, sprite edit by MisterKerr", + "name": "Frisk" + }, + { + "file": "froglink.3.zspr", + "author": "Mike Trethewey", + "name": "Frog Link" + }, + { + "file": "fujin.2.zspr", + "author": "FujinAkari", + "name": "Fujin" + }, + { + "file": "future_trunks.1.zspr", + "author": "Merciter", + "name": "Future Trunks" + }, + { + "file": "gbc-link.1.zspr", + "author": "skovacs1", + "name": "GBC Link" + }, + { + "file": "gamer.1.zspr", + "author": "Unknown", + "name": "Gamer" + }, + { + "file": "ganondorf.1.zspr", + "author": "Fish_waffle64", + "name": "Ganondorf" + }, + { + "file": "garfield.2.zspr", + "author": "Fwiller", + "name": "Garfield" + }, + { + "file": "garnet.1.zspr", + "author": "Artheau", + "name": "Garnet" + }, + { + "file": "garomaster.1.zspr", + "author": "Herowho", + "name": "Garo Master" + }, + { + "file": "geno.1.zspr", + "author": "FedoraFriday", + "name": "Geno" + }, + { + "file": "gliitchwiitch.1.zspr", + "author": "Ivy-IV", + "name": "GliitchWiitch" + }, + { + "file": "gobli.1.zspr", + "author": "Lantis", + "name": "Gobli" + }, + { + "file": "goomba.1.zspr", + "author": "SirCzah", + "name": "Goomba" + }, + { + "file": "goose.1.zspr", + "author": "Jam", + "name": "Goose" + }, + { + "file": "grandpoobear.2.zspr", + "author": "proximitysound", + "name": "GrandPOOBear" + }, + { + "file": "gretis.1.zspr", + "author": "SnakeGrunger", + "name": "Gretis" + }, + { + "file": "grunclestan.1.zspr", + "author": "SirCzah", + "name": "Gruncle Stan" + }, + { + "file": "guiz.1.zspr", + "author": "GuizDP", + "name": "GuizDP" + }, + { + "file": "hanna.1.zspr", + "author": "Maya-Neko", + "name": "Hanna" + }, + { + "file": "hardhat_beetle.1.zspr", + "author": "Artheau", + "name": "Hardhat Beetle" + }, + { + "file": "linkhatcolor.1.zspr", + "author": "Damon", + "name": "Hat Color Link" + }, + { + "file": "hat-kid.1.zspr", + "author": "skovacs1", + "name": "Hat Kid" + }, + { + "file": "headlesslink.1.zspr", + "author": "fatmanspanda", + "name": "Headless Link" + }, + { + "file": "hello_kitty.1.zspr", + "author": "qeeen", + "name": "Hello Kitty" + }, + { + "file": "hidari.1.zspr", + "author": "Hidari", + "name": "Hidari" + }, + { + "file": "hint_tile.1.zspr", + "author": "PlaguedOne", + "name": "Hint Tile" + }, + { + "file": "luffy.1.zspr", + "author": "BOtheMighty", + "name": "Hitsuyan1337" + }, + { + "file": "hoarder-bush.1.zspr", + "author": "Restomak", + "name": "Hoarder (Bush)" + }, + { + "file": "hoarder-pot.1.zspr", + "author": "Restomak", + "name": "Hoarder (Pot)" + }, + { + "file": "hoarder-rock.1.zspr", + "author": "Restomak", + "name": "Hoarder (Rock)" + }, + { + "file": "homer.1.zspr", + "author": "Fwiller", + "name": "Homer Simpson" + }, + { + "file": "hotdog.1.zspr", + "author": "Xag & Tylo", + "name": "Hotdog" + }, + { + "file": "hyruleknight.1.zspr", + "author": "InTheBeef", + "name": "Hyrule Knight" + }, + { + "file": "soldiersprite.1.zspr", + "author": "InTheBeef", + "name": "Hyrule Soldier" + }, + { + "file": "ignignokt.2.zspr", + "author": "fatmanspanda", + "name": "Ignignokt" + }, + { + "file": "crewmate.1.zspr", + "author": "Fish_waffle64", + "name": "Imposter" + }, + { + "file": "informant_woman.1.zspr", + "author": "Herowho", + "name": "Informant Woman" + }, + { + "file": "inkling.1.zspr", + "author": "RyuTech", + "name": "Inkling" + }, + { + "file": "invisibleman.1.zspr", + "author": "Mike Trethewey", + "name": "Invisible Link" + }, + { + "file": "jack-frost.1.zspr", + "author": "xypotion", + "name": "Jack Frost" + }, + { + "file": "jason_frudnick.1.zspr", + "author": "Artheau", + "name": "Jason Frudnick" + }, + { + "file": "jasp.1.zspr", + "author": "Chonixtu", + "name": "Jasp" + }, + { + "file": "jogurt.1.zspr", + "author": "Nakuri", + "name": "Jogurt" + }, + { + "file": "katsura.1.zspr", + "author": "atth3h3art0fwinter", + "name": "Katsura" + }, + { + "file": "kecleon.1.zspr", + "author": "Gylergin", + "name": "Kecleon" + }, + { + "file": "kenny_mccormick.1.zspr", + "author": "Artheau", + "name": "Kenny McCormick" + }, + { + "file": "ketchup.1.zspr", + "author": "t0uchan", + "name": "Ketchup" + }, + { + "file": "kholdstare.1.zspr", + "author": "fatmanspanda", + "name": "Kholdstare" + }, + { + "file": "king_gothalion.1.zspr", + "author": "kickpixel", + "name": "King Gothalion" + }, + { + "file": "king_graham.1.zspr", + "author": "MisterKerr", + "name": "King Graham v1.1" + }, + { + "file": "kirby-meta.1.zspr", + "author": "KHRoxas", + "name": "Kirby" + }, + { + "file": "kore8.1.zspr", + "author": "Skewer", + "name": "Kore8" + }, + { + "file": "korok.1.zspr", + "author": "atth3h3art0fwinter", + "name": "Korok" + }, + { + "file": "lakitu.1.zspr", + "author": "SirCzah", + "name": "Lakitu" + }, + { + "file": "lapras.1.zspr", + "author": "Fish_waffle64", + "name": "Lapras" + }, + { + "file": "lest.1.zspr", + "author": "PrideToRuleEarth", + "name": "Lest" + }, + { + "file": "lily.1.zspr", + "author": "ScatlinkSean", + "name": "Lily" + }, + { + "file": "linja.1.zspr", + "author": "Razhagal", + "name": "Linja" + }, + { + "file": "001.link.1.zspr", + "author": "Nintendo", + "name": "Link" + }, + { + "file": "link-redrawn.1.zspr", + "author": "Spiffy", + "name": "Link Redrawn" + }, + { + "file": "little-hylian.1.zspr", + "author": "MM102", + "name": "Little Hylian" + }, + { + "file": "locke.1.zspr", + "author": "Rose", + "name": "Locke" + }, + { + "file": "lucario.1.zspr", + "author": "Achy", + "name": "Lucario" + }, + { + "file": "luigi.1.zspr", + "author": "Achy", + "name": "Luigi" + }, + { + "file": "luna-maindo.1.zspr", + "author": "IkkyLights", + "name": "Luna Maindo" + }, + { + "file": "madeline.1.zspr", + "author": "Jam", + "name": "Madeline" + }, + { + "file": "magus.1.zspr", + "author": "PlaguedOne", + "name": "Magus" + }, + { + "file": "maiden.1.zspr", + "author": "Plan", + "name": "Maiden" + }, + { + "file": "mallow-cat.1.zspr", + "author": "FedoraFriday", + "name": "Mallow (Cat)" + }, + { + "file": "mangalink.1.zspr", + "author": "fatmanspanda", + "name": "Manga Link" + }, + { + "file": "maplequeen.2.zspr", + "author": "Zarby89", + "name": "Maple Queen" + }, + { + "file": "marin.2.zspr", + "author": "Nocturnesthesia", + "name": "Marin" + }, + { + "file": "mario-classic.2.zspr", + "author": "Damon", + "name": "Mario (Classic)" + }, + { + "file": "mariocappy.1.zspr", + "author": "Damon", + "name": "Mario and Cappy" + }, + { + "file": "marisa.1.zspr", + "author": "Achy", + "name": "Marisa Kirisame" + }, + { + "file": "cat.3.zspr", + "author": "Fish_waffle64", + "name": "Marvin the Cat" + }, + { + "file": "matthias.1.zspr", + "author": "Marcus Bolduc", + "name": "Matthias" + }, + { + "file": "meatwad.1.zspr", + "author": "fatmanspanda", + "name": "Meatwad" + }, + { + "file": "medallions.1.zspr", + "author": "Mike Trethewey", + "name": "Medallions" + }, + { + "file": "medli.1.zspr", + "author": "Kzinssie", + "name": "Medli" + }, + { + "file": "megaman-x.2.zspr", + "author": "PlaguedOne", + "name": "Megaman X" + }, + { + "file": "mew.1.zspr", + "author": "MewLp", + "name": "MewLp" + }, + { + "file": "mike-jones.2.zspr", + "author": "Fish_waffle64", + "name": "Mike Jones" + }, + { + "file": "ganon.1.zspr", + "author": "atth3h3art0fwinter", + "name": "Mini Ganon" + }, + { + "file": "minishcaplink.2.zspr", + "author": "InTheBeef", + "name": "Minish Cap Link" + }, + { + "file": "minish_link.1.zspr", + "author": "Artheau", + "name": "Minish Link" + }, + { + "file": "moblin.1.zspr", + "author": "Noctai_", + "name": "MoblinSprite" + }, + { + "file": "modernlink.1.zspr", + "author": "RyuTech", + "name": "Modern Link" + }, + { + "file": "mog.2.zspr", + "author": "Krelbel", + "name": "Mog" + }, + { + "file": "momiji.1.zspr", + "author": "Ardaceus", + "name": "Momiji Inubashiri" + }, + { + "file": "moosh.1.zspr", + "author": "PlaguedOne", + "name": "Moosh" + }, + { + "file": "mouse.1.zspr", + "author": "Malthaez", + "name": "Mouse" + }, + { + "file": "ms-paintdog.1.zspr", + "author": "TehRealSalt", + "name": "Ms. Paint Dog" + }, + { + "file": "naturelink.1.zspr", + "author": "iBazly", + "name": "Nature Link" + }, + { + "file": "navi.1.zspr", + "author": "qwertymodo", + "name": "Navi" + }, + { + "file": "navirou.2.zspr", + "author": "Lori", + "name": "Navirou" + }, + { + "file": "ned-flanders.1.zspr", + "author": "JJ0033LL", + "name": "Ned Flanders" + }, + { + "file": "negativelink.1.zspr", + "author": "iBazly", + "name": "Negative Link" + }, + { + "file": "neosad.1.zspr", + "author": "Andrew Copple", + "name": "Neosad" + }, + { + "file": "ness.1.zspr", + "author": "Lantis", + "name": "Ness (Earthbound)" + }, + { + "file": "nia.1.zspr", + "author": "Mojonbo", + "name": "Nia" + }, + { + "file": "niddraig.1.zspr", + "author": "Jakebob", + "name": "Niddraig" + }, + { + "file": "niko.1.zspr", + "author": "ScatlinkSean", + "name": "Niko" + }, + { + "file": "oldman.2.zspr", + "author": "Zarby89", + "name": "Old Man" + }, + { + "file": "ori.2.zspr", + "author": "Phant", + "name": "Ori" + }, + { + "file": "outlinelink.1.zspr", + "author": "VT", + "name": "Outline Link" + }, + { + "file": "parallelworldslink.1.zspr", + "author": "SePH/InTheBeef", + "name": "Parallel Worlds Link" + }, + { + "file": "paula.1.zspr", + "author": "Fish_waffle64", + "name": "Paula" + }, + { + "file": "penguinlink.1.zspr", + "author": "Fish_waffle64", + "name": "Penguin Link" + }, + { + "file": "pete.1.zspr", + "author": "Lantis", + "name": "Pete (Harvest Moon)" + }, + { + "file": "phoenix-wright.1.zspr", + "author": "SnipSlum", + "name": "Phoenix Wright" + }, + { + "file": "pikachu.1.zspr", + "author": "toucansham", + "name": "Pikachu" + }, + { + "file": "pinkribbonlink.2.zspr", + "author": "fatmanspanda", + "name": "Pink Ribbon Link" + }, + { + "file": "piranha_plant.1.zspr", + "author": "lecremateur", + "name": "Piranha Plant" + }, + { + "file": "plagueknight.1.zspr", + "author": "Jenichi", + "name": "Plague Knight" + }, + { + "file": "pokey.1.zspr", + "author": "fatmanspanda", + "name": "Pokey" + }, + { + "file": "littlepony.1.zspr", + "author": "Botchos", + "name": "Pony" + }, + { + "file": "popoi.1.zspr", + "author": "ItsSupercar", + "name": "Popoi" + }, + { + "file": "poppy.1.zspr", + "author": "cbass601", + "name": "Poppy" + }, + { + "file": "porg_knight.1.zspr", + "author": "PorgCollector", + "name": "Porg Knight" + }, + { + "file": "mushy.1.zspr", + "author": "Achy", + "name": "Power Up with Pride Mushroom" + }, + { + "file": "powerpuff_girl.1.zspr", + "author": "Jenichi", + "name": "Powerpuff Girl" + }, + { + "file": "pridelink.2.zspr", + "author": "proximitysound", + "name": "Pride Link" + }, + { + "file": "primm.1.zspr", + "author": "Artheau", + "name": "Primm" + }, + { + "file": "princess_bubblegum.1.zspr", + "author": "Devan2002", + "name": "Princess Bubblegum" + }, + { + "file": "peach.1.zspr", + "author": "RoPan", + "name": "Princess Peach" + }, + { + "file": "psyduck.2.zspr", + "author": "skovacs1", + "name": "Psyduck" + }, + { + "file": "purplechest-bottle.1.zspr", + "author": "Mike Trethewey", + "name": "Purple Chest" + }, + { + "file": "pyro.1.zspr", + "author": "malmo", + "name": "Pyro" + }, + { + "file": "rainbowlink.1.zspr", + "author": "fatmanspanda", + "name": "Rainbow Link" + }, + { + "file": "rat.1.zspr", + "author": "atth3h3art0fwinter", + "name": "Rat" + }, + { + "file": "red-mage.1.zspr", + "author": "TheRedMage", + "name": "Red Mage" + }, + { + "file": "remeer.1.zspr", + "author": "Herowho", + "name": "Remeer" + }, + { + "file": "rick.1.zspr", + "author": "Eric the Terrible/Devan 2002", + "name": "Rick (Redacted)" + }, + { + "file": "robotlink.1.zspr", + "author": "fatmanspanda", + "name": "Robo-Link 9000" + }, + { + "file": "rocko.1.zspr", + "author": "toucansham", + "name": "Rocko" + }, + { + "file": "rottytops.1.zspr", + "author": "PlaguedOne", + "name": "Rottytops" + }, + { + "file": "rover.1.zspr", + "author": "NO Body The Dragon", + "name": "Rover" + }, + { + "file": "roykoopa.1.zspr", + "author": "Achy", + "name": "Roy Koopa" + }, + { + "file": "rumia.1.zspr", + "author": "Achy", + "name": "Rumia" + }, + { + "file": "rydia.1.zspr", + "author": "Sho", + "name": "Rydia" + }, + { + "file": "ryu.1.zspr", + "author": "PlaguedOne", + "name": "Ryu" + }, + { + "file": "snes-controller.1.zspr", + "author": "Cbass601", + "name": "SNES Controller" + }, + { + "file": "sailormoon.1.zspr", + "author": "Jenichi", + "name": "Sailor Moon" + }, + { + "file": "saitama.1.zspr", + "author": "Dabeanjelly/Ath3h3art0fwinter", + "name": "Saitama" + }, + { + "file": "samus.2.zspr", + "author": "Fish_waffle64", + "name": "Samus" + }, + { + "file": "samus_classic.1.zspr", + "author": "Fish_waffle64", + "name": "Samus (Classic)" + }, + { + "file": "samus-sm.1.zspr", + "author": "Ben G", + "name": "Samus (Super Metroid)" + }, + { + "file": "santalink.2.zspr", + "author": "HOHOHO", + "name": "Santa Link" + }, + { + "file": "scholar.1.zspr", + "author": "Damon", + "name": "Scholar" + }, + { + "file": "selan.1.zspr", + "author": "atth3h3art0fwinter", + "name": "Selan" + }, + { + "file": "sevens1ns.1.zspr", + "author": "Hroun", + "name": "SevenS1ns" + }, + { + "file": "shadow.1.zspr", + "author": "CGG Zayik", + "name": "Shadow" + }, + { + "file": "shadowsaku.2.zspr", + "author": "iBazly", + "name": "Shadow Sakura" + }, + { + "file": "shantae.1.zspr", + "author": "skovacs1", + "name": "Shantae" + }, + { + "file": "shuppet.1.zspr", + "author": "fatmanspanda", + "name": "Shuppet" + }, + { + "file": "shy-gal.1.zspr", + "author": "FedoraFriday", + "name": "Shy Gal" + }, + { + "file": "shy-guy.1.zspr", + "author": "skovacs1", + "name": "Shy Guy" + }, + { + "file": "sighn_waive.1.zspr", + "author": "GenoCL", + "name": "SighnWaive" + }, + { + "file": "slowpoke.1.zspr", + "author": "Joey Rat", + "name": "Slowpoke" + }, + { + "file": "sodacan.1.zspr", + "author": "Zarby89", + "name": "Soda Can" + }, + { + "file": "solaire.1.zspr", + "author": "Knilip", + "name": "Solaire of Astora" + }, + { + "file": "sonic.1.zspr", + "author": "Osaka", + "name": "Sonic the Hedgehog" + }, + { + "file": "sora.1.zspr", + "author": "roxas232", + "name": "Sora" + }, + { + "file": "sora_kh1.1.zspr", + "author": "ScatlinkSean", + "name": "Sora (KH1)" + }, + { + "file": "spongebob.1.zspr", + "author": "JJ0033LL", + "name": "SpongeBob SquarePants" + }, + { + "file": "squall.1.zspr", + "author": "Maessan", + "name": "Squall" + }, + { + "file": "squirrel.1.zspr", + "author": "Fish_waffle64", + "name": "Squirrel" + }, + { + "file": "squirtle.1.zspr", + "author": "Numberplay", + "name": "Squirtle" + }, + { + "file": "stalfos.1.zspr", + "author": "Artheau", + "name": "Stalfos" + }, + { + "file": "stan.1.zspr", + "author": "Kan", + "name": "Stan" + }, + { + "file": "staticlink.1.zspr", + "author": "fatmanspanda", + "name": "Static Link" + }, + { + "file": "steamedhams.1.zspr", + "author": "AFewGoodTaters", + "name": "Steamed Ham" + }, + { + "file": "stick_man.1.zspr", + "author": "skovacs1", + "name": "Stick Man" + }, + { + "file": "superbomb.1.zspr", + "author": "Ninjakauz", + "name": "Super Bomb" + }, + { + "file": "superbunny.2.zspr", + "author": "TheOkayGuy", + "name": "Super Bunny" + }, + { + "file": "supermeatboy.1.zspr", + "author": "Achy", + "name": "Super Meat Boy" + }, + { + "file": "susie.1.zspr", + "author": "ZandraVandra", + "name": "Susie" + }, + { + "file": "swatchy.1.zspr", + "author": "Mike Trethewey", + "name": "Swatchy" + }, + { + "file": "tasbot.1.zspr", + "author": "GenoCL", + "name": "TASBot" + }, + { + "file": "tgh.1.zspr", + "author": "Drew Wise, pizza_for_free", + "name": "TGH" + }, + { + "file": "tmnt.1.zspr", + "author": "SirCzah", + "name": "TMNT" + }, + { + "file": "twilightprincesszelda.2.zspr", + "author": "Fish_waffle64", + "name": "TP Zelda" + }, + { + "file": "mario_tanooki.1.zspr", + "author": "Nocturnesthesia", + "name": "Tanooki Mario" + }, + { + "file": "teatime.1.zspr", + "author": "SirCzah", + "name": "Tea Time" + }, + { + "file": "terra.1.zspr", + "author": "All-in-one Mighty", + "name": "Terra (Esper)" + }, + { + "file": "tetra.1.zspr", + "author": "Ferelheart", + "name": "Tetra Sheet" + }, + { + "file": "pug.1.zspr", + "author": "Achy", + "name": "The Pug" + }, + { + "file": "thief.1.zspr", + "author": "Devan2002", + "name": "Thief" + }, + { + "file": "thomcrow.1.zspr", + "author": "Thom", + "name": "Thomcrow" + }, + { + "file": "tile.2.zspr", + "author": "fatmanspanda", + "name": "Tile" + }, + { + "file": "tingle.1.zspr", + "author": "Xenobond", + "name": "Tingle" + }, + { + "file": "toad.2.zspr", + "author": "Zarby89", + "name": "Toad" + }, + { + "file": "toadette.2.zspr", + "author": "Devan2002", + "name": "Toadette" + }, + { + "file": "totem-links.1.zspr", + "author": "Yotohan", + "name": "TotemLinks" + }, + { + "file": "trogdor.1.zspr", + "author": "MikeTrethewey/Spanda", + "name": "Trogdor the Burninator" + }, + { + "file": "linktuniccolor.1.zspr", + "author": "Damon", + "name": "Tunic Color Link" + }, + { + "file": "two_faced.1.zspr", + "author": "Devan2002", + "name": "TwoFaced" + }, + { + "file": "ty.1.zspr", + "author": "Fish_waffle64", + "name": "Ty the Tasmanian Tiger" + }, + { + "file": "ultros.1.zspr", + "author": "PlaguedOne", + "name": "Ultros" + }, + { + "file": "corona.1.zspr", + "author": "Unknown", + "name": "Untitled" + }, + { + "file": "valeera.1.zspr", + "author": "Glan", + "name": "Valeera" + }, + { + "file": "vanillalink.1.zspr", + "author": "Jenichi", + "name": "VanillaLink" + }, + { + "file": "vaporeon.1.zspr", + "author": "Aquana", + "name": "Vaporeon" + }, + { + "file": "vegeta.1.zspr", + "author": "Merciter", + "name": "Vegeta" + }, + { + "file": "vera.1.zspr", + "author": "aitchFactor", + "name": "Vera" + }, + { + "file": "vitreous.1.zspr", + "author": "Glan", + "name": "Vitreous" + }, + { + "file": "vivi.1.zspr", + "author": "RyuTech", + "name": "Vivi" + }, + { + "file": "vivian.1.zspr", + "author": "SirCzah", + "name": "Vivian" + }, + { + "file": "wario.1.zspr", + "author": "Deagans", + "name": "Wario" + }, + { + "file": "will.1.zspr", + "author": "Xenobond", + "name": "Will" + }, + { + "file": "wizzrobe.2.zspr", + "author": "iBazly", + "name": "Wizzrobe" + }, + { + "file": "wolf_link.1.zspr", + "author": "Fish/Beef-Chan", + "name": "Wolf Link (Festive)" + }, + { + "file": "wolf_link_tp.1.zspr", + "author": "Gfish59", + "name": "Wolf Link (TP)" + }, + { + "file": "yoshi.1.zspr", + "author": "Yotohan", + "name": "Yoshi" + }, + { + "file": "yunica.1.zspr", + "author": "Fish_waffle64", + "name": "Yunica Tovah" + }, + { + "file": "zandra.1.zspr", + "author": "ZandraVandra", + "name": "Zandra" + }, + { + "file": "zebraunicorn.1.zspr", + "author": "Brass Man", + "name": "Zebra Unicorn" + }, + { + "file": "zeck.1.zspr", + "author": "aitchFactor", + "name": "Zeckemyro" + }, + { + "file": "zelda.1.zspr", + "author": "Myriachan", + "name": "Zelda" + }, + { + "file": "zerosuitsamus.2.zspr", + "author": "Fish_waffle64", + "name": "Zero Suit Samus" + }, + { + "file": "zora.2.zspr", + "author": "Zarby, InTheBeef", + "name": "Zora" + }, + { + "file": "boco.1.zspr", + "author": "", + "name": "boco" + }, + { + "file": "hollow-knight.1.zspr", + "author": "Chew_Terr", + "name": "hollow_test" + }, + { + "file": "ibazly.1.zspr", + "author": "Achy", + "name": "iBazly" + }, + { + "file": "missingno.1.zspr", + "author": "", + "name": "missingno" + } + ] +} \ No newline at end of file diff --git a/WebHostLib/static/static/sprites/Ark.gif b/WebHostLib/static/static/sprites/Ark.gif deleted file mode 100644 index 3d0d928942..0000000000 Binary files a/WebHostLib/static/static/sprites/Ark.gif and /dev/null differ diff --git a/WebHostLib/static/static/sprites/.gif b/WebHostLib/static/static/sprites/BotW Zelda.gif similarity index 100% rename from WebHostLib/static/static/sprites/.gif rename to WebHostLib/static/static/sprites/BotW Zelda.gif diff --git a/WebHostLib/static/static/sprites/botw-zelda.gif b/WebHostLib/static/static/sprites/botw-zelda.gif deleted file mode 100644 index 3ad3ab04bf..0000000000 Binary files a/WebHostLib/static/static/sprites/botw-zelda.gif and /dev/null differ diff --git a/WebHostLib/static/styles/cookieNotice.css b/WebHostLib/static/styles/cookieNotice.css index 25ed2abe3f..cb6b110920 100644 --- a/WebHostLib/static/styles/cookieNotice.css +++ b/WebHostLib/static/styles/cookieNotice.css @@ -9,3 +9,8 @@ text-align: center; cursor: pointer; } + +#cookie-notice #close-button{ + float: right; + padding-right: 10px; +} diff --git a/WebHostLib/static/styles/hostGame.css b/WebHostLib/static/styles/hostGame.css index 82946367d5..751dc7c8ed 100644 --- a/WebHostLib/static/styles/hostGame.css +++ b/WebHostLib/static/styles/hostGame.css @@ -28,25 +28,3 @@ #host-game button{ margin-top: 5px; } - -#host-game-table{ - margin-right: auto; - text-align: left; -} - -#host-game-table th{ - padding: 0 20px 0 0; -} - -#host-game-table td{ - padding: 6px 20px 0 0; -} - -#host-game-table td.center{ - text-align: center; -} - -#host-game-table.dataTable{ - width: unset; - -} diff --git a/WebHostLib/static/styles/playerSettings.css b/WebHostLib/static/styles/playerSettings.css index b0fc2262b1..33a76d3d94 100644 --- a/WebHostLib/static/styles/playerSettings.css +++ b/WebHostLib/static/styles/playerSettings.css @@ -75,6 +75,7 @@ html{ padding: 3px; border-radius: 3px; min-width: 150px; + background-color: #ffffff; } #player-settings #game-options, #player-settings #rom-options{ @@ -97,7 +98,7 @@ html{ cursor: default; } -@media all and (max-width: 1000px){ +@media all and (max-width: 1000px), all and (orientation: portrait){ #player-settings #game-options, #player-settings #rom-options{ justify-content: flex-start; flex-wrap: wrap; diff --git a/WebHostLib/static/styles/tutorial.css b/WebHostLib/static/styles/tutorial.css index 5499f92eee..c79bfed1a0 100644 --- a/WebHostLib/static/styles/tutorial.css +++ b/WebHostLib/static/styles/tutorial.css @@ -5,12 +5,14 @@ html{ } #tutorial-wrapper{ - width: 70rem; + display: flex; + flex-direction: column; + max-width: 70rem; margin-left: auto; margin-right: auto; background-color: rgba(0, 0, 0, 0.15); border-radius: 8px; - padding: 1rem; + padding: 1rem 1rem 3rem; color: #eeffeb; } diff --git a/WebHostLib/static/styles/userContent.css b/WebHostLib/static/styles/userContent.css index 40fdc7dad6..847747268c 100644 --- a/WebHostLib/static/styles/userContent.css +++ b/WebHostLib/static/styles/userContent.css @@ -31,3 +31,24 @@ #user-content .center{ text-align: center; } + +#user-content-table{ + margin-right: auto; + text-align: left; +} + +#user-content .table td.center{ + text-align: center; +} + +#user-content table.dataTable{ + width: unset; +} + +table.dataTable thead th{ + padding: 0 20px 0 0; +} + +table.dataTable tbody td{ + padding: 6px 20px 0 0; +} diff --git a/WebHostLib/static/styles/weightedSettings.css b/WebHostLib/static/styles/weightedSettings.css index 303095cb51..4f78893162 100644 --- a/WebHostLib/static/styles/weightedSettings.css +++ b/WebHostLib/static/styles/weightedSettings.css @@ -148,5 +148,6 @@ html{ padding: 3px; border-radius: 3px; min-width: 150px; + background-color: #ffffff; } diff --git a/WebHostLib/templates/autotablepage.html b/WebHostLib/templates/autotablepage.html new file mode 100644 index 0000000000..0bb30f8716 --- /dev/null +++ b/WebHostLib/templates/autotablepage.html @@ -0,0 +1,5 @@ +{% extends "tablepage.html" %} +{% block head %} + {{ super() }} + +{% endblock %} diff --git a/WebHostLib/templates/checkResult.html b/WebHostLib/templates/checkResult.html index a6e8e0b8bb..5bc4fa9dca 100644 --- a/WebHostLib/templates/checkResult.html +++ b/WebHostLib/templates/checkResult.html @@ -1,8 +1,8 @@ -{% extends 'pageWrapper.html' %} +{% extends 'autotablepage.html' %} {% block head %} {{ super() }} - Upload Mystery YAML + Mystery YAML Test Roll Results {% endblock %} @@ -12,7 +12,7 @@

Verification Results

The results of your requested file check are below.

- +
diff --git a/WebHostLib/templates/hostGame.html b/WebHostLib/templates/hostGame.html index 9e4eff8011..a8d6e5b12e 100644 --- a/WebHostLib/templates/hostGame.html +++ b/WebHostLib/templates/hostGame.html @@ -1,4 +1,4 @@ -{% extends 'tablepage.html' %} +{% extends 'pageWrapper.html' %} {% block head %} {{ super() }} diff --git a/WebHostLib/templates/playerSettings.html b/WebHostLib/templates/playerSettings.html index 78416ee79e..8f3e584a4f 100644 --- a/WebHostLib/templates/playerSettings.html +++ b/WebHostLib/templates/playerSettings.html @@ -11,10 +11,10 @@ {% block body %} {% include 'header/grassHeader.html' %}
-

Generate Game

+

Start Game

Choose the options you would like to play with! You may generate a single-player game from this page, or download a settings file you can use to participate in a MultiWorld. If you would like to make - your settings extra random, check out the weighted settings + your settings extra random, check out the advanced weighted settings page. There, you will find examples of all available sprites as well.

A list of all games you have generated can be found here.

diff --git a/WebHostLib/templates/seedError.html b/WebHostLib/templates/seedError.html new file mode 100644 index 0000000000..b0414f838f --- /dev/null +++ b/WebHostLib/templates/seedError.html @@ -0,0 +1,19 @@ +{% extends 'pageWrapper.html' %} +{% import "macros.html" as macros %} + +{% block head %} + Generation failed, please retry. + +{% endblock %} + +{% block body %} + {% include 'header/oceanHeader.html' %} +
+
+

Generation failed

+

please retry

+ {{ seed_error }} +
+
+ {% include 'islandFooter.html' %} +{% endblock %} diff --git a/WebHostLib/templates/userContent.html b/WebHostLib/templates/userContent.html index 811300c942..59c81f83c5 100644 --- a/WebHostLib/templates/userContent.html +++ b/WebHostLib/templates/userContent.html @@ -1,9 +1,10 @@ -{% extends 'pageWrapper.html' %} +{% extends 'tablepage.html' %} {% block head %} {{ super() }} Generate Game + {% endblock %} {% block body %} @@ -15,7 +16,7 @@

Your Rooms

{% if rooms %} -
File
+
@@ -46,7 +47,7 @@

Your Seeds

{% if seeds %} -
Seed
+
diff --git a/data/web/package-lock.json b/data/web/package-lock.json index fda4a04e27..b89355163c 100644 --- a/data/web/package-lock.json +++ b/data/web/package-lock.json @@ -5694,9 +5694,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "inquirer": { "version": "7.1.0", diff --git a/dumpSprites.py b/dumpSprites.py index 84fde3a73b..f29ad20259 100644 --- a/dumpSprites.py +++ b/dumpSprites.py @@ -15,7 +15,7 @@ while not done.isSet(): print("Done updating sprites") -spriteData = {} +spriteData = [] for file in os.listdir(input_dir): sprite = Sprite(os.path.join(input_dir, file)) @@ -27,9 +27,9 @@ for file in os.listdir(input_dir): if sprite.valid: with open(os.path.join(output_dir, "sprites", f"{sprite.name}.gif"), 'wb') as image: image.write(get_image_for_sprite(sprite, True)) - spriteData[sprite.name] = file + spriteData.append({"file": file, "author": sprite.author_name, "name": sprite.name}) else: print(file, "dropped, as it has no valid sprite data.") - +spriteData.sort(key=lambda entry: entry["name"]) with open(f'{output_dir}/spriteData.json', 'w') as file: - json.dump(spriteData, file) + json.dump({"sprites": spriteData}, file, indent=1) diff --git a/icon.ico b/icon.ico index 797410abee..a142b56b14 100644 Binary files a/icon.ico and b/icon.ico differ diff --git a/inno_setup_38.iss b/inno_setup_38.iss new file mode 100644 index 0000000000..0e6c860875 --- /dev/null +++ b/inno_setup_38.iss @@ -0,0 +1,141 @@ +#define sourcepath "build\exe.win-amd64-3.8\" +#define MyAppName "BerserkerMultiWorld" +#define MyAppExeName "BerserkerMultiClient.exe" +#define MyAppIcon "icon.ico" + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +; Do not use the same AppId value in installers for other applications. +AppId={{6D826EE0-49BE-4B36-BACE-09C6971CD85C}} +AppName={#MyAppName} +AppVerName={#MyAppName} +DefaultDirName={commonappdata}\{#MyAppName} +DisableProgramGroupPage=yes +DefaultGroupName=Berserker's Multiworld +OutputDir=setups +OutputBaseFilename=Setup {#MyAppName} +Compression=lzma2 +SolidCompression=yes +LZMANumBlockThreads=8 +ArchitecturesInstallIn64BitMode=x64 +ChangesAssociations=yes +ArchitecturesAllowed=x64 +AllowNoIcons=yes +SetupIconFile={#MyAppIcon} +UninstallDisplayIcon={app}\{#MyAppExeName} +SignTool= signtool +LicenseFile= LICENSE +WizardStyle= modern +SetupLogging=yes + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; + + +[Dirs] +NAME: "{app}"; Flags: setntfscompression; Permissions: everyone-modify users-modify authusers-modify; + +[Files] +Source: "{code:GetROMPath}"; DestDir: "{app}"; DestName: "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc"; Flags: external +Source: "{#sourcepath}*"; Excludes: "*.sfc, *.log, data\sprites\alttpr"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "vc_redist.x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{group}\{#MyAppName} Folder"; Filename: "{app}"; +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; +Name: "{commondesktop}\{#MyAppName} Folder"; Filename: "{app}"; Tasks: desktopicon +Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon + +[Run] +Filename: "{tmp}\vc_redist.x64.exe"; Parameters: "/passive /norestart"; Check: IsVCRedist64BitNeeded; StatusMsg: "Installing VC++ redistributable..." +Filename: "{app}\BerserkerMultiCreator"; Parameters: "update_sprites"; StatusMsg: "Updating Sprite Library..." + +[UninstallDelete] +Type: dirifempty; Name: "{app}" + +[Registry] + +Root: HKCR; Subkey: ".bmbp"; ValueData: "{#MyAppName}patch"; Flags: uninsdeletevalue; ValueType: string; ValueName: "" +Root: HKCR; Subkey: "{#MyAppName}patch"; ValueData: "Berserker's Multiworld Binary Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: "" +Root: HKCR; Subkey: "{#MyAppName}patch\DefaultIcon"; ValueData: "{app}\{#MyAppExeName},0"; ValueType: string; ValueName: "" +Root: HKCR; Subkey: "{#MyAppName}patch\shell\open\command"; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; ValueType: string; ValueName: "" + +Root: HKCR; Subkey: ".multidata"; ValueData: "{#MyAppName}multidata"; Flags: uninsdeletevalue; ValueType: string; ValueName: "" +Root: HKCR; Subkey: "{#MyAppName}multidata"; ValueData: "Berserker's Multiworld Server Data"; Flags: uninsdeletekey; ValueType: string; ValueName: "" +Root: HKCR; Subkey: "{#MyAppName}multidata\DefaultIcon"; ValueData: "{app}\BerserkerMultiServer.exe,0"; ValueType: string; ValueName: "" +Root: HKCR; Subkey: "{#MyAppName}multidata\shell\open\command"; ValueData: """{app}\BerserkerMultiServer.exe"" --multidata ""%1"""; ValueType: string; ValueName: "" + + + +[Code] +// See: https://stackoverflow.com/a/51614652/2287576 +function IsVCRedist64BitNeeded(): boolean; +var + strVersion: string; +begin + if (RegQueryStringValue(HKEY_LOCAL_MACHINE, + 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Version', strVersion)) then + begin + // Is the installed version at least the packaged one ? + Log('VC Redist x64 Version : found ' + strVersion); + Result := (CompareStr(strVersion, 'v14.28.29325') < 0); + end + else + begin + // Not even an old version installed + Log('VC Redist x64 is not already installed'); + Result := True; + end; +end; + +var ROMFilePage: TInputFileWizardPage; +var R : longint; +var rom: string; + +procedure InitializeWizard(); +begin + rom := FileSearch('Zelda no Densetsu - Kamigami no Triforce (Japan).sfc', WizardDirValue()); + if Length(rom) > 0 then + begin + log('existing ROM found'); + log(IntToStr(CompareStr(GetMD5OfFile(rom), '03a63945398191337e896e5771f77173'))); + if CompareStr(GetMD5OfFile(rom), '03a63945398191337e896e5771f77173') = 0 then + begin + log('existing ROM verified'); + exit; + end; + log('existing ROM failed verification'); + end; + rom := '' + ROMFilePage := + CreateInputFilePage( + wpLicense, + 'Select ROM File', + 'Where is your Zelda no Densetsu - Kamigami no Triforce (Japan).sfc located?', + 'Select the file, then click Next.'); + + ROMFilePage.Add( + 'Location of ROM file:', + 'SNES ROM files|*.sfc|All files|*.*', + '.sfc'); +end; + +function GetROMPath(Param: string): string; +begin + if Length(rom) > 0 then + Result := rom + else if Assigned(RomFilePage) then + begin + R := CompareStr(GetMD5OfFile(ROMFilePage.Values[0]), '03a63945398191337e896e5771f77173') + if R <> 0 then + MsgBox('ROM validation failed. Very likely wrong file.', mbInformation, MB_OK); + + Result := ROMFilePage.Values[0] + end + else + Result := ''; + end; diff --git a/inno_setup.iss b/inno_setup_39.iss similarity index 100% rename from inno_setup.iss rename to inno_setup_39.iss diff --git a/setup.py b/setup.py index 80ad9064c0..48872d7b63 100644 --- a/setup.py +++ b/setup.py @@ -13,9 +13,9 @@ buildfolder = Path("build", folder) sbuildfolder = str(buildfolder) libfolder = Path(buildfolder, "lib") library = Path(libfolder, "library.zip") -print("Outputting to: " + str(buildfolder)) -compress = False -icon="icon.ico" +print("Outputting to: " + sbuildfolder) + +icon = "icon.ico" if os.path.exists("X:/pw.txt"): print("Using signtool") @@ -28,13 +28,16 @@ else: from hashlib import sha3_512 import base64 + def _threaded_hash(filepath): hasher = sha3_512() hasher.update(open(filepath, "rb").read()) return base64.b85encode(hasher.digest()).decode() + os.makedirs(buildfolder, exist_ok=True) + def manifest_creation(): hashes = {} manifestpath = os.path.join(buildfolder, "manifest.json") @@ -51,11 +54,11 @@ def manifest_creation(): print("Created Manifest") -scripts = {"MultiClient.py" : "BerserkerMultiClient", - "MultiMystery.py" : "BerserkerMultiMystery", - "MultiServer.py" : "BerserkerMultiServer", - "gui.py" : "BerserkerMultiCreator", - "Mystery.py" : "BerserkerMystery"} +scripts = {"MultiClient.py": "BerserkerMultiClient", + "MultiMystery.py": "BerserkerMultiMystery", + "MultiServer.py": "BerserkerMultiServer", + "gui.py": "BerserkerMultiCreator", + "Mystery.py": "BerserkerMystery"} exes = [] @@ -66,7 +69,6 @@ for script, scriptname in scripts.items(): icon=icon, )) - import datetime buildtime = datetime.datetime.utcnow() @@ -137,5 +139,4 @@ if signtool: print(f"Signing {exe.targetName}") os.system(signtool + exe.targetName) - manifest_creation()
Seed