Merge branch 'main' into expanded_tests

This commit is contained in:
Fabian Dill 2020-12-19 19:40:12 +01:00
commit c87dd5d2d3
39 changed files with 2270 additions and 369 deletions

2
.gitignore vendored
View File

@ -32,3 +32,5 @@ mystery_result_*.yaml
/db.db3 /db.db3
*-errors.txt *-errors.txt
success.txt success.txt
output/
Output Logs/

View File

@ -139,7 +139,7 @@ def link_entrances(world, player):
dw_must_exits = list(DW_Entrances_Must_Exit) dw_must_exits = list(DW_Entrances_Must_Exit)
old_man_entrances = list(Old_Man_Entrances) old_man_entrances = list(Old_Man_Entrances)
caves = list(Cave_Exits + Cave_Three_Exits) 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) 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) blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors)
door_targets = list(Single_Cave_Targets) door_targets = list(Single_Cave_Targets)

16
Gui.py
View File

@ -1525,8 +1525,8 @@ class SpriteSelector():
title_link.pack(side=LEFT) title_link.pack(side=LEFT)
title_link.bind("<Button-1>", open_custom_sprite_dir) title_link.bind("<Button-1>", 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(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(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 = Frame(self.window)
frame.pack(side=BOTTOM, fill=X, pady=5) frame.pack(side=BOTTOM, fill=X, pady=5)
@ -1585,19 +1585,21 @@ class SpriteSelector():
sprites = [] sprites = []
for file in glob(output_path(path)): for file in os.listdir(path):
sprites.append(Sprite(file)) 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 = [] frame.buttons = []
for sprite in sprites: for file, sprite in sprites:
image = get_image_for_sprite(sprite) image = get_image_for_sprite(sprite)
if image is None: if image is None:
continue continue
self.all_sprites.append(sprite) self.all_sprites.append(sprite)
button = Button(frame, image=image, command=lambda spr=sprite: self.select_sprite(spr)) 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 button.image = image
frame.buttons.append(button) frame.buttons.append(button)

View File

@ -1,4 +1,5 @@
import collections import collections
import typing
from BaseClasses import Region, Location, Entrance, RegionType, Shop, TakeAny, UpgradeShop, ShopType 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] 'Ganons Tower - Mini Helmasaur Key Drop': [0x14001e, 0x14001f]
} }
location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'), # tuple contents:
'Bottle Merchant': (0x2eb18, 0x186339, False, 'with a merchant'), # address to write to for item
'Flute Spot': (0x18014a, 0x18633d, False, 'underground'), # address to write to for player getting the item
'Sunken Treasure': (0x180145, 0x186354, False, 'underwater'), # can this location drop a crystal
'Purple Chest': (0x33d68, 0x186359, False, 'from a box'), # hint tile/npc text for this location
"Blind's Hideout - Top": (0xeb0f, 0x1862e3, False, 'in a basement'), location_table: typing.Dict[str,
"Blind's Hideout - Left": (0xeb12, 0x1862e6, False, 'in a basement'), typing.Tuple[typing.Optional[typing.Union[int, typing.List[int]]],
"Blind's Hideout - Right": (0xeb15, 0x1862e9, False, 'in a basement'), typing.Optional[int],
"Blind's Hideout - Far Left": (0xeb18, 0x1862ec, False, 'in a basement'), bool,
"Blind's Hideout - Far Right": (0xeb1b, 0x1862ef, False, 'in a basement'), typing.Optional[str]]] = \
"Link's Uncle": (0x2df45, 0x18635f, False, 'with your uncle'), {'Mushroom': (0x180013, 0x186338, False, 'in the woods'),
'Secret Passage': (0xe971, 0x186145, False, 'near your uncle'), 'Bottle Merchant': (0x2eb18, 0x186339, False, 'with a merchant'),
'King Zora': (0xee1c3, 0x186360, False, 'at a high price'), 'Flute Spot': (0x18014a, 0x18633d, False, 'underground'),
"Zora's Ledge": (0x180149, 0x186358, False, 'near Zora'), 'Sunken Treasure': (0x180145, 0x186354, False, 'underwater'),
'Waterfall Fairy - Left': (0xe9b0, 0x186184, False, 'near a fairy'), 'Purple Chest': (0x33d68, 0x186359, False, 'from a box'),
'Waterfall Fairy - Right': (0xe9d1, 0x1861a5, False, 'near a fairy'), "Blind's Hideout - Top": (0xeb0f, 0x1862e3, False, 'in a basement'),
"King's Tomb": (0xe97a, 0x18614e, False, 'alone in a cave'), "Blind's Hideout - Left": (0xeb12, 0x1862e6, False, 'in a basement'),
'Floodgate Chest': (0xe98c, 0x186160, False, 'in the dam'), "Blind's Hideout - Right": (0xeb15, 0x1862e9, False, 'in a basement'),
"Link's House": (0xe9bc, 0x186190, False, 'in your home'), "Blind's Hideout - Far Left": (0xeb18, 0x1862ec, False, 'in a basement'),
'Kakariko Tavern': (0xe9ce, 0x1861a2, False, 'in the bar'), "Blind's Hideout - Far Right": (0xeb1b, 0x1862ef, False, 'in a basement'),
'Chicken House': (0xe9e9, 0x1861bd, False, 'near poultry'), "Link's Uncle": (0x2df45, 0x18635f, False, 'with your uncle'),
"Aginah's Cave": (0xe9f2, 0x1861c6, False, 'with Aginah'), 'Secret Passage': (0xe971, 0x186145, False, 'near your uncle'),
"Sahasrahla's Hut - Left": (0xea82, 0x186256, False, 'near the elder'), 'King Zora': (0xee1c3, 0x186360, False, 'at a high price'),
"Sahasrahla's Hut - Middle": (0xea85, 0x186259, False, 'near the elder'), "Zora's Ledge": (0x180149, 0x186358, False, 'near Zora'),
"Sahasrahla's Hut - Right": (0xea88, 0x18625c, False, 'near the elder'), 'Waterfall Fairy - Left': (0xe9b0, 0x186184, False, 'near a fairy'),
'Sahasrahla': (0x2f1fc, 0x186365, False, 'with the elder'), 'Waterfall Fairy - Right': (0xe9d1, 0x1861a5, False, 'near a fairy'),
'Kakariko Well - Top': (0xea8e, 0x186262, False, 'in a well'), "King's Tomb": (0xe97a, 0x18614e, False, 'alone in a cave'),
'Kakariko Well - Left': (0xea91, 0x186265, False, 'in a well'), 'Floodgate Chest': (0xe98c, 0x186160, False, 'in the dam'),
'Kakariko Well - Middle': (0xea94, 0x186268, False, 'in a well'), "Link's House": (0xe9bc, 0x186190, False, 'in your home'),
'Kakariko Well - Right': (0xea97, 0x18626b, False, 'in a well'), 'Kakariko Tavern': (0xe9ce, 0x1861a2, False, 'in the bar'),
'Kakariko Well - Bottom': (0xea9a, 0x18626e, False, 'in a well'), 'Chicken House': (0xe9e9, 0x1861bd, False, 'near poultry'),
'Blacksmith': (0x18002a, 0x186366, False, 'with the smith'), "Aginah's Cave": (0xe9f2, 0x1861c6, False, 'with Aginah'),
'Magic Bat': (0x180015, 0x18635e, False, 'with the bat'), "Sahasrahla's Hut - Left": (0xea82, 0x186256, False, 'near the elder'),
'Sick Kid': (0x339cf, 0x186367, False, 'with the sick'), "Sahasrahla's Hut - Middle": (0xea85, 0x186259, False, 'near the elder'),
'Hobo': (0x33e7d, 0x186368, False, 'with the hobo'), "Sahasrahla's Hut - Right": (0xea88, 0x18625c, False, 'near the elder'),
'Lost Woods Hideout': (0x180000, 0x186348, False, 'near a thief'), 'Sahasrahla': (0x2f1fc, 0x186365, False, 'with the elder'),
'Lumberjack Tree': (0x180001, 0x186349, False, 'in a hole'), 'Kakariko Well - Top': (0xea8e, 0x186262, False, 'in a well'),
'Cave 45': (0x180003, 0x18634b, False, 'alone in a cave'), 'Kakariko Well - Left': (0xea91, 0x186265, False, 'in a well'),
'Graveyard Cave': (0x180004, 0x18634c, False, 'alone in a cave'), 'Kakariko Well - Middle': (0xea94, 0x186268, False, 'in a well'),
'Checkerboard Cave': (0x180005, 0x18634d, False, 'alone in a cave'), 'Kakariko Well - Right': (0xea97, 0x18626b, False, 'in a well'),
'Mini Moldorm Cave - Far Left': (0xeb42, 0x186316, False, 'near Moldorms'), 'Kakariko Well - Bottom': (0xea9a, 0x18626e, False, 'in a well'),
'Mini Moldorm Cave - Left': (0xeb45, 0x186319, False, 'near Moldorms'), 'Blacksmith': (0x18002a, 0x186366, False, 'with the smith'),
'Mini Moldorm Cave - Right': (0xeb48, 0x18631c, False, 'near Moldorms'), 'Magic Bat': (0x180015, 0x18635e, False, 'with the bat'),
'Mini Moldorm Cave - Far Right': (0xeb4b, 0x18631f, False, 'near Moldorms'), 'Sick Kid': (0x339cf, 0x186367, False, 'with the sick'),
'Mini Moldorm Cave - Generous Guy': (0x180010, 0x18635a, False, 'near Moldorms'), 'Hobo': (0x33e7d, 0x186368, False, 'with the hobo'),
'Ice Rod Cave': (0xeb4e, 0x186322, False, 'in a frozen cave'), 'Lost Woods Hideout': (0x180000, 0x186348, False, 'near a thief'),
'Bonk Rock Cave': (0xeb3f, 0x186313, False, 'alone in a cave'), 'Lumberjack Tree': (0x180001, 0x186349, False, 'in a hole'),
'Library': (0x180012, 0x18635c, False, 'near books'), 'Cave 45': (0x180003, 0x18634b, False, 'alone in a cave'),
'Potion Shop': (0x180014, 0x18635d, False, 'near potions'), 'Graveyard Cave': (0x180004, 0x18634c, False, 'alone in a cave'),
'Lake Hylia Island': (0x180144, 0x186353, False, 'on an island'), 'Checkerboard Cave': (0x180005, 0x18634d, False, 'alone in a cave'),
'Maze Race': (0x180142, 0x186351, False, 'at the race'), 'Mini Moldorm Cave - Far Left': (0xeb42, 0x186316, False, 'near Moldorms'),
'Desert Ledge': (0x180143, 0x186352, False, 'in the desert'), 'Mini Moldorm Cave - Left': (0xeb45, 0x186319, False, 'near Moldorms'),
'Desert Palace - Big Chest': (0xe98f, 0x186163, False, 'in Desert Palace'), 'Mini Moldorm Cave - Right': (0xeb48, 0x18631c, False, 'near Moldorms'),
'Desert Palace - Torch': (0x180160, 0x186362, False, 'in Desert Palace'), 'Mini Moldorm Cave - Far Right': (0xeb4b, 0x18631f, False, 'near Moldorms'),
'Desert Palace - Map Chest': (0xe9b6, 0x18618a, False, 'in Desert Palace'), 'Mini Moldorm Cave - Generous Guy': (0x180010, 0x18635a, False, 'near Moldorms'),
'Desert Palace - Compass Chest': (0xe9cb, 0x18619f, False, 'in Desert Palace'), 'Ice Rod Cave': (0xeb4e, 0x186322, False, 'in a frozen cave'),
'Desert Palace - Big Key Chest': (0xe9c2, 0x186196, False, 'in Desert Palace'), 'Bonk Rock Cave': (0xeb3f, 0x186313, False, 'alone in a cave'),
'Desert Palace - Boss': (0x180151, 0x18633f, False, 'with Lanmolas'), 'Library': (0x180012, 0x18635c, False, 'near books'),
'Eastern Palace - Compass Chest': (0xe977, 0x18614b, False, 'in Eastern Palace'), 'Potion Shop': (0x180014, 0x18635d, False, 'near potions'),
'Eastern Palace - Big Chest': (0xe97d, 0x186151, False, 'in Eastern Palace'), 'Lake Hylia Island': (0x180144, 0x186353, False, 'on an island'),
'Eastern Palace - Cannonball Chest': (0xe9b3, 0x186187, False, 'in Eastern Palace'), 'Maze Race': (0x180142, 0x186351, False, 'at the race'),
'Eastern Palace - Big Key Chest': (0xe9b9, 0x18618d, False, 'in Eastern Palace'), 'Desert Ledge': (0x180143, 0x186352, False, 'in the desert'),
'Eastern Palace - Map Chest': (0xe9f5, 0x1861c9, False, 'in Eastern Palace'), 'Desert Palace - Big Chest': (0xe98f, 0x186163, False, 'in Desert Palace'),
'Eastern Palace - Boss': (0x180150, 0x18633e, False, 'with the Armos'), 'Desert Palace - Torch': (0x180160, 0x186362, False, 'in Desert Palace'),
'Master Sword Pedestal': (0x289b0, 0x186369, False, 'at the pedestal'), 'Desert Palace - Map Chest': (0xe9b6, 0x18618a, False, 'in Desert Palace'),
'Hyrule Castle - Boomerang Chest': (0xe974, 0x186148, False, 'in Hyrule Castle'), 'Desert Palace - Compass Chest': (0xe9cb, 0x18619f, False, 'in Desert Palace'),
'Hyrule Castle - Map Chest': (0xeb0c, 0x1862e0, False, 'in Hyrule Castle'), 'Desert Palace - Big Key Chest': (0xe9c2, 0x186196, False, 'in Desert Palace'),
"Hyrule Castle - Zelda's Chest": (0xeb09, 0x1862dd, False, 'in Hyrule Castle'), 'Desert Palace - Boss': (0x180151, 0x18633f, False, 'with Lanmolas'),
'Sewers - Dark Cross': (0xe96e, 0x186142, False, 'in the sewers'), 'Eastern Palace - Compass Chest': (0xe977, 0x18614b, False, 'in Eastern Palace'),
'Sewers - Secret Room - Left': (0xeb5d, 0x186331, False, 'in the sewers'), 'Eastern Palace - Big Chest': (0xe97d, 0x186151, False, 'in Eastern Palace'),
'Sewers - Secret Room - Middle': (0xeb60, 0x186334, False, 'in the sewers'), 'Eastern Palace - Cannonball Chest': (0xe9b3, 0x186187, False, 'in Eastern Palace'),
'Sewers - Secret Room - Right': (0xeb63, 0x186337, False, 'in the sewers'), 'Eastern Palace - Big Key Chest': (0xe9b9, 0x18618d, False, 'in Eastern Palace'),
'Sanctuary': (0xea79, 0x18624d, False, 'in Sanctuary'), 'Eastern Palace - Map Chest': (0xe9f5, 0x1861c9, False, 'in Eastern Palace'),
'Castle Tower - Room 03': (0xeab5, 0x186289, False, 'in Castle Tower'), 'Eastern Palace - Boss': (0x180150, 0x18633e, False, 'with the Armos'),
'Castle Tower - Dark Maze': (0xeab2, 0x186286, False, 'in Castle Tower'), 'Master Sword Pedestal': (0x289b0, 0x186369, False, 'at the pedestal'),
'Old Man': (0xf69fa, 0x186364, False, 'with the old man'), 'Hyrule Castle - Boomerang Chest': (0xe974, 0x186148, False, 'in Hyrule Castle'),
'Spectacle Rock Cave': (0x180002, 0x18634a, False, 'alone in a cave'), 'Hyrule Castle - Map Chest': (0xeb0c, 0x1862e0, False, 'in Hyrule Castle'),
'Paradox Cave Lower - Far Left': (0xeb2a, 0x1862fe, False, 'in a cave with seven chests'), "Hyrule Castle - Zelda's Chest": (0xeb09, 0x1862dd, False, 'in Hyrule Castle'),
'Paradox Cave Lower - Left': (0xeb2d, 0x186301, False, 'in a cave with seven chests'), 'Sewers - Dark Cross': (0xe96e, 0x186142, False, 'in the sewers'),
'Paradox Cave Lower - Right': (0xeb30, 0x186304, False, 'in a cave with seven chests'), 'Sewers - Secret Room - Left': (0xeb5d, 0x186331, False, 'in the sewers'),
'Paradox Cave Lower - Far Right': (0xeb33, 0x186307, False, 'in a cave with seven chests'), 'Sewers - Secret Room - Middle': (0xeb60, 0x186334, False, 'in the sewers'),
'Paradox Cave Lower - Middle': (0xeb36, 0x18630a, False, 'in a cave with seven chests'), 'Sewers - Secret Room - Right': (0xeb63, 0x186337, False, 'in the sewers'),
'Paradox Cave Upper - Left': (0xeb39, 0x18630d, False, 'in a cave with seven chests'), 'Sanctuary': (0xea79, 0x18624d, False, 'in Sanctuary'),
'Paradox Cave Upper - Right': (0xeb3c, 0x186310, False, 'in a cave with seven chests'), 'Castle Tower - Room 03': (0xeab5, 0x186289, False, 'in Castle Tower'),
'Spiral Cave': (0xe9bf, 0x186193, False, 'in spiral cave'), 'Castle Tower - Dark Maze': (0xeab2, 0x186286, False, 'in Castle Tower'),
'Ether Tablet': (0x180016, 0x18633b, False, 'at a monolith'), 'Old Man': (0xf69fa, 0x186364, False, 'with the old man'),
'Spectacle Rock': (0x180140, 0x18634f, False, 'atop a rock'), 'Spectacle Rock Cave': (0x180002, 0x18634a, False, 'alone in a cave'),
'Tower of Hera - Basement Cage': (0x180162, 0x18633a, False, 'in Tower of Hera'), 'Paradox Cave Lower - Far Left': (0xeb2a, 0x1862fe, False, 'in a cave with seven chests'),
'Tower of Hera - Map Chest': (0xe9ad, 0x186181, False, 'in Tower of Hera'), 'Paradox Cave Lower - Left': (0xeb2d, 0x186301, False, 'in a cave with seven chests'),
'Tower of Hera - Big Key Chest': (0xe9e6, 0x1861ba, False, 'in Tower of Hera'), 'Paradox Cave Lower - Right': (0xeb30, 0x186304, False, 'in a cave with seven chests'),
'Tower of Hera - Compass Chest': (0xe9fb, 0x1861cf, False, 'in Tower of Hera'), 'Paradox Cave Lower - Far Right': (0xeb33, 0x186307, False, 'in a cave with seven chests'),
'Tower of Hera - Big Chest': (0xe9f8, 0x1861cc, False, 'in Tower of Hera'), 'Paradox Cave Lower - Middle': (0xeb36, 0x18630a, False, 'in a cave with seven chests'),
'Tower of Hera - Boss': (0x180152, 0x186340, False, 'with Moldorm'), 'Paradox Cave Upper - Left': (0xeb39, 0x18630d, False, 'in a cave with seven chests'),
'Pyramid': (0x180147, 0x186356, False, 'on the pyramid'), 'Paradox Cave Upper - Right': (0xeb3c, 0x186310, False, 'in a cave with seven chests'),
'Catfish': (0xee185, 0x186361, False, 'with a catfish'), 'Spiral Cave': (0xe9bf, 0x186193, False, 'in spiral cave'),
'Stumpy': (0x330c7, 0x18636a, False, 'with tree boy'), 'Ether Tablet': (0x180016, 0x18633b, False, 'at a monolith'),
'Digging Game': (0x180148, 0x186357, False, 'underground'), 'Spectacle Rock': (0x180140, 0x18634f, False, 'atop a rock'),
'Bombos Tablet': (0x180017, 0x18633c, False, 'at a monolith'), 'Tower of Hera - Basement Cage': (0x180162, 0x18633a, False, 'in Tower of Hera'),
'Hype Cave - Top': (0xeb1e, 0x1862f2, False, 'near a bat-like man'), 'Tower of Hera - Map Chest': (0xe9ad, 0x186181, False, 'in Tower of Hera'),
'Hype Cave - Middle Right': (0xeb21, 0x1862f5, False, 'near a bat-like man'), 'Tower of Hera - Big Key Chest': (0xe9e6, 0x1861ba, False, 'in Tower of Hera'),
'Hype Cave - Middle Left': (0xeb24, 0x1862f8, False, 'near a bat-like man'), 'Tower of Hera - Compass Chest': (0xe9fb, 0x1861cf, False, 'in Tower of Hera'),
'Hype Cave - Bottom': (0xeb27, 0x1862fb, False, 'near a bat-like man'), 'Tower of Hera - Big Chest': (0xe9f8, 0x1861cc, False, 'in Tower of Hera'),
'Hype Cave - Generous Guy': (0x180011, 0x18635b, False, 'with a bat-like man'), 'Tower of Hera - Boss': (0x180152, 0x186340, False, 'with Moldorm'),
'Peg Cave': (0x180006, 0x18634e, False, 'alone in a cave'), 'Pyramid': (0x180147, 0x186356, False, 'on the pyramid'),
'Pyramid Fairy - Left': (0xe980, 0x186154, False, 'near a fairy'), 'Catfish': (0xee185, 0x186361, False, 'with a catfish'),
'Pyramid Fairy - Right': (0xe983, 0x186157, False, 'near a fairy'), 'Stumpy': (0x330c7, 0x18636a, False, 'with tree boy'),
'Brewery': (0xe9ec, 0x1861c0, False, 'alone in a home'), 'Digging Game': (0x180148, 0x186357, False, 'underground'),
'C-Shaped House': (0xe9ef, 0x1861c3, False, 'alone in a home'), 'Bombos Tablet': (0x180017, 0x18633c, False, 'at a monolith'),
'Chest Game': (0xeda8, 0x18636b, False, 'as a prize'), 'Hype Cave - Top': (0xeb1e, 0x1862f2, False, 'near a bat-like man'),
'Bumper Cave Ledge': (0x180146, 0x186355, False, 'on a ledge'), 'Hype Cave - Middle Right': (0xeb21, 0x1862f5, False, 'near a bat-like man'),
'Mire Shed - Left': (0xea73, 0x186247, False, 'near sparks'), 'Hype Cave - Middle Left': (0xeb24, 0x1862f8, False, 'near a bat-like man'),
'Mire Shed - Right': (0xea76, 0x18624a, False, 'near sparks'), 'Hype Cave - Bottom': (0xeb27, 0x1862fb, False, 'near a bat-like man'),
'Superbunny Cave - Top': (0xea7c, 0x186250, False, 'in a connection'), 'Hype Cave - Generous Guy': (0x180011, 0x18635b, False, 'with a bat-like man'),
'Superbunny Cave - Bottom': (0xea7f, 0x186253, False, 'in a connection'), 'Peg Cave': (0x180006, 0x18634e, False, 'alone in a cave'),
'Spike Cave': (0xea8b, 0x18625f, False, 'beyond spikes'), 'Pyramid Fairy - Left': (0xe980, 0x186154, False, 'near a fairy'),
'Hookshot Cave - Top Right': (0xeb51, 0x186325, False, 'across pits'), 'Pyramid Fairy - Right': (0xe983, 0x186157, False, 'near a fairy'),
'Hookshot Cave - Top Left': (0xeb54, 0x186328, False, 'across pits'), 'Brewery': (0xe9ec, 0x1861c0, False, 'alone in a home'),
'Hookshot Cave - Bottom Right': (0xeb5a, 0x18632e, False, 'across pits'), 'C-Shaped House': (0xe9ef, 0x1861c3, False, 'alone in a home'),
'Hookshot Cave - Bottom Left': (0xeb57, 0x18632b, False, 'across pits'), 'Chest Game': (0xeda8, 0x18636b, False, 'as a prize'),
'Floating Island': (0x180141, 0x186350, False, 'on an island'), 'Bumper Cave Ledge': (0x180146, 0x186355, False, 'on a ledge'),
'Mimic Cave': (0xe9c5, 0x186199, False, 'in a cave of mimicry'), 'Mire Shed - Left': (0xea73, 0x186247, False, 'near sparks'),
'Swamp Palace - Entrance': (0xea9d, 0x186271, False, 'in Swamp Palace'), 'Mire Shed - Right': (0xea76, 0x18624a, False, 'near sparks'),
'Swamp Palace - Map Chest': (0xe986, 0x18615a, False, 'in Swamp Palace'), 'Superbunny Cave - Top': (0xea7c, 0x186250, False, 'in a connection'),
'Swamp Palace - Big Chest': (0xe989, 0x18615d, False, 'in Swamp Palace'), 'Superbunny Cave - Bottom': (0xea7f, 0x186253, False, 'in a connection'),
'Swamp Palace - Compass Chest': (0xeaa0, 0x186274, False, 'in Swamp Palace'), 'Spike Cave': (0xea8b, 0x18625f, False, 'beyond spikes'),
'Swamp Palace - Big Key Chest': (0xeaa6, 0x18627a, False, 'in Swamp Palace'), 'Hookshot Cave - Top Right': (0xeb51, 0x186325, False, 'across pits'),
'Swamp Palace - West Chest': (0xeaa3, 0x186277, False, 'in Swamp Palace'), 'Hookshot Cave - Top Left': (0xeb54, 0x186328, False, 'across pits'),
'Swamp Palace - Flooded Room - Left': (0xeaa9, 0x18627d, False, 'in Swamp Palace'), 'Hookshot Cave - Bottom Right': (0xeb5a, 0x18632e, False, 'across pits'),
'Swamp Palace - Flooded Room - Right': (0xeaac, 0x186280, False, 'in Swamp Palace'), 'Hookshot Cave - Bottom Left': (0xeb57, 0x18632b, False, 'across pits'),
'Swamp Palace - Waterfall Room': (0xeaaf, 0x186283, False, 'in Swamp Palace'), 'Floating Island': (0x180141, 0x186350, False, 'on an island'),
'Swamp Palace - Boss': (0x180154, 0x186342, False, 'with Arrghus'), 'Mimic Cave': (0xe9c5, 0x186199, False, 'in a cave of mimicry'),
"Thieves' Town - Big Key Chest": (0xea04, 0x1861d8, False, "in Thieves' Town"), 'Swamp Palace - Entrance': (0xea9d, 0x186271, False, 'in Swamp Palace'),
"Thieves' Town - Map Chest": (0xea01, 0x1861d5, False, "in Thieves' Town"), 'Swamp Palace - Map Chest': (0xe986, 0x18615a, False, 'in Swamp Palace'),
"Thieves' Town - Compass Chest": (0xea07, 0x1861db, False, "in Thieves' Town"), 'Swamp Palace - Big Chest': (0xe989, 0x18615d, False, 'in Swamp Palace'),
"Thieves' Town - Ambush Chest": (0xea0a, 0x1861de, False, "in Thieves' Town"), 'Swamp Palace - Compass Chest': (0xeaa0, 0x186274, False, 'in Swamp Palace'),
"Thieves' Town - Attic": (0xea0d, 0x1861e1, False, "in Thieves' Town"), 'Swamp Palace - Big Key Chest': (0xeaa6, 0x18627a, False, 'in Swamp Palace'),
"Thieves' Town - Big Chest": (0xea10, 0x1861e4, False, "in Thieves' Town"), 'Swamp Palace - West Chest': (0xeaa3, 0x186277, False, 'in Swamp Palace'),
"Thieves' Town - Blind's Cell": (0xea13, 0x1861e7, False, "in Thieves' Town"), 'Swamp Palace - Flooded Room - Left': (0xeaa9, 0x18627d, False, 'in Swamp Palace'),
"Thieves' Town - Boss": (0x180156, 0x186344, False, 'with Blind'), 'Swamp Palace - Flooded Room - Right': (0xeaac, 0x186280, False, 'in Swamp Palace'),
'Skull Woods - Compass Chest': (0xe992, 0x186166, False, 'in Skull Woods'), 'Swamp Palace - Waterfall Room': (0xeaaf, 0x186283, False, 'in Swamp Palace'),
'Skull Woods - Map Chest': (0xe99b, 0x18616f, False, 'in Skull Woods'), 'Swamp Palace - Boss': (0x180154, 0x186342, False, 'with Arrghus'),
'Skull Woods - Big Chest': (0xe998, 0x18616c, False, 'in Skull Woods'), "Thieves' Town - Big Key Chest": (0xea04, 0x1861d8, False, "in Thieves' Town"),
'Skull Woods - Pot Prison': (0xe9a1, 0x186175, False, 'in Skull Woods'), "Thieves' Town - Map Chest": (0xea01, 0x1861d5, False, "in Thieves' Town"),
'Skull Woods - Pinball Room': (0xe9c8, 0x18619c, False, 'in Skull Woods'), "Thieves' Town - Compass Chest": (0xea07, 0x1861db, False, "in Thieves' Town"),
'Skull Woods - Big Key Chest': (0xe99e, 0x186172, False, 'in Skull Woods'), "Thieves' Town - Ambush Chest": (0xea0a, 0x1861de, False, "in Thieves' Town"),
'Skull Woods - Bridge Room': (0xe9fe, 0x1861d2, False, 'near Mothula'), "Thieves' Town - Attic": (0xea0d, 0x1861e1, False, "in Thieves' Town"),
'Skull Woods - Boss': (0x180155, 0x186343, False, 'with Mothula'), "Thieves' Town - Big Chest": (0xea10, 0x1861e4, False, "in Thieves' Town"),
'Ice Palace - Compass Chest': (0xe9d4, 0x1861a8, False, 'in Ice Palace'), "Thieves' Town - Blind's Cell": (0xea13, 0x1861e7, False, "in Thieves' Town"),
'Ice Palace - Freezor Chest': (0xe995, 0x186169, False, 'in Ice Palace'), "Thieves' Town - Boss": (0x180156, 0x186344, False, 'with Blind'),
'Ice Palace - Big Chest': (0xe9aa, 0x18617e, False, 'in Ice Palace'), 'Skull Woods - Compass Chest': (0xe992, 0x186166, False, 'in Skull Woods'),
'Ice Palace - Iced T Room': (0xe9e3, 0x1861b7, False, 'in Ice Palace'), 'Skull Woods - Map Chest': (0xe99b, 0x18616f, False, 'in Skull Woods'),
'Ice Palace - Spike Room': (0xe9e0, 0x1861b4, False, 'in Ice Palace'), 'Skull Woods - Big Chest': (0xe998, 0x18616c, False, 'in Skull Woods'),
'Ice Palace - Big Key Chest': (0xe9a4, 0x186178, False, 'in Ice Palace'), 'Skull Woods - Pot Prison': (0xe9a1, 0x186175, False, 'in Skull Woods'),
'Ice Palace - Map Chest': (0xe9dd, 0x1861b1, False, 'in Ice Palace'), 'Skull Woods - Pinball Room': (0xe9c8, 0x18619c, False, 'in Skull Woods'),
'Ice Palace - Boss': (0x180157, 0x186345, False, 'with Kholdstare'), 'Skull Woods - Big Key Chest': (0xe99e, 0x186172, False, 'in Skull Woods'),
'Misery Mire - Big Chest': (0xea67, 0x18623b, False, 'in Misery Mire'), 'Skull Woods - Bridge Room': (0xe9fe, 0x1861d2, False, 'near Mothula'),
'Misery Mire - Map Chest': (0xea6a, 0x18623e, False, 'in Misery Mire'), 'Skull Woods - Boss': (0x180155, 0x186343, False, 'with Mothula'),
'Misery Mire - Main Lobby': (0xea5e, 0x186232, False, 'in Misery Mire'), 'Ice Palace - Compass Chest': (0xe9d4, 0x1861a8, False, 'in Ice Palace'),
'Misery Mire - Bridge Chest': (0xea61, 0x186235, False, 'in Misery Mire'), 'Ice Palace - Freezor Chest': (0xe995, 0x186169, False, 'in Ice Palace'),
'Misery Mire - Spike Chest': (0xe9da, 0x1861ae, False, 'in Misery Mire'), 'Ice Palace - Big Chest': (0xe9aa, 0x18617e, False, 'in Ice Palace'),
'Misery Mire - Compass Chest': (0xea64, 0x186238, False, 'in Misery Mire'), 'Ice Palace - Iced T Room': (0xe9e3, 0x1861b7, False, 'in Ice Palace'),
'Misery Mire - Big Key Chest': (0xea6d, 0x186241, False, 'in Misery Mire'), 'Ice Palace - Spike Room': (0xe9e0, 0x1861b4, False, 'in Ice Palace'),
'Misery Mire - Boss': (0x180158, 0x186346, False, 'with Vitreous'), 'Ice Palace - Big Key Chest': (0xe9a4, 0x186178, False, 'in Ice Palace'),
'Turtle Rock - Compass Chest': (0xea22, 0x1861f6, False, 'in Turtle Rock'), 'Ice Palace - Map Chest': (0xe9dd, 0x1861b1, False, 'in Ice Palace'),
'Turtle Rock - Roller Room - Left': (0xea1c, 0x1861f0, False, 'in Turtle Rock'), 'Ice Palace - Boss': (0x180157, 0x186345, False, 'with Kholdstare'),
'Turtle Rock - Roller Room - Right': (0xea1f, 0x1861f3, False, 'in Turtle Rock'), 'Misery Mire - Big Chest': (0xea67, 0x18623b, False, 'in Misery Mire'),
'Turtle Rock - Chain Chomps': (0xea16, 0x1861ea, False, 'in Turtle Rock'), 'Misery Mire - Map Chest': (0xea6a, 0x18623e, False, 'in Misery Mire'),
'Turtle Rock - Big Key Chest': (0xea25, 0x1861f9, False, 'in Turtle Rock'), 'Misery Mire - Main Lobby': (0xea5e, 0x186232, False, 'in Misery Mire'),
'Turtle Rock - Big Chest': (0xea19, 0x1861ed, False, 'in Turtle Rock'), 'Misery Mire - Bridge Chest': (0xea61, 0x186235, False, 'in Misery Mire'),
'Turtle Rock - Crystaroller Room': (0xea34, 0x186208, False, 'in Turtle Rock'), 'Misery Mire - Spike Chest': (0xe9da, 0x1861ae, False, 'in Misery Mire'),
'Turtle Rock - Eye Bridge - Bottom Left': (0xea31, 0x186205, False, 'in Turtle Rock'), 'Misery Mire - Compass Chest': (0xea64, 0x186238, False, 'in Misery Mire'),
'Turtle Rock - Eye Bridge - Bottom Right': (0xea2e, 0x186202, False, 'in Turtle Rock'), 'Misery Mire - Big Key Chest': (0xea6d, 0x186241, False, 'in Misery Mire'),
'Turtle Rock - Eye Bridge - Top Left': (0xea2b, 0x1861ff, False, 'in Turtle Rock'), 'Misery Mire - Boss': (0x180158, 0x186346, False, 'with Vitreous'),
'Turtle Rock - Eye Bridge - Top Right': (0xea28, 0x1861fc, False, 'in Turtle Rock'), 'Turtle Rock - Compass Chest': (0xea22, 0x1861f6, False, 'in Turtle Rock'),
'Turtle Rock - Boss': (0x180159, 0x186347, False, 'with Trinexx'), 'Turtle Rock - Roller Room - Left': (0xea1c, 0x1861f0, False, 'in Turtle Rock'),
'Palace of Darkness - Shooter Room': (0xea5b, 0x18622f, False, 'in Palace of Darkness'), 'Turtle Rock - Roller Room - Right': (0xea1f, 0x1861f3, False, 'in Turtle Rock'),
'Palace of Darkness - The Arena - Bridge': (0xea3d, 0x186211, False, 'in Palace of Darkness'), 'Turtle Rock - Chain Chomps': (0xea16, 0x1861ea, False, 'in Turtle Rock'),
'Palace of Darkness - Stalfos Basement': (0xea49, 0x18621d, False, 'in Palace of Darkness'), 'Turtle Rock - Big Key Chest': (0xea25, 0x1861f9, False, 'in Turtle Rock'),
'Palace of Darkness - Big Key Chest': (0xea37, 0x18620b, False, 'in Palace of Darkness'), 'Turtle Rock - Big Chest': (0xea19, 0x1861ed, False, 'in Turtle Rock'),
'Palace of Darkness - The Arena - Ledge': (0xea3a, 0x18620e, False, 'in Palace of Darkness'), 'Turtle Rock - Crystaroller Room': (0xea34, 0x186208, False, 'in Turtle Rock'),
'Palace of Darkness - Map Chest': (0xea52, 0x186226, False, 'in Palace of Darkness'), 'Turtle Rock - Eye Bridge - Bottom Left': (0xea31, 0x186205, False, 'in Turtle Rock'),
'Palace of Darkness - Compass Chest': (0xea43, 0x186217, False, 'in Palace of Darkness'), 'Turtle Rock - Eye Bridge - Bottom Right': (0xea2e, 0x186202, False, 'in Turtle Rock'),
'Palace of Darkness - Dark Basement - Left': (0xea4c, 0x186220, False, 'in Palace of Darkness'), 'Turtle Rock - Eye Bridge - Top Left': (0xea2b, 0x1861ff, False, 'in Turtle Rock'),
'Palace of Darkness - Dark Basement - Right': (0xea4f, 0x186223, False, 'in Palace of Darkness'), 'Turtle Rock - Eye Bridge - Top Right': (0xea28, 0x1861fc, False, 'in Turtle Rock'),
'Palace of Darkness - Dark Maze - Top': (0xea55, 0x186229, False, 'in Palace of Darkness'), 'Turtle Rock - Boss': (0x180159, 0x186347, False, 'with Trinexx'),
'Palace of Darkness - Dark Maze - Bottom': (0xea58, 0x18622c, False, 'in Palace of Darkness'), 'Palace of Darkness - Shooter Room': (0xea5b, 0x18622f, False, 'in Palace of Darkness'),
'Palace of Darkness - Big Chest': (0xea40, 0x186214, False, 'in Palace of Darkness'), 'Palace of Darkness - The Arena - Bridge': (0xea3d, 0x186211, False, 'in Palace of Darkness'),
'Palace of Darkness - Harmless Hellway': (0xea46, 0x18621a, False, 'in Palace of Darkness'), 'Palace of Darkness - Stalfos Basement': (0xea49, 0x18621d, False, 'in Palace of Darkness'),
'Palace of Darkness - Boss': (0x180153, 0x186341, False, 'with Helmasaur King'), 'Palace of Darkness - Big Key Chest': (0xea37, 0x18620b, False, 'in Palace of Darkness'),
"Ganons Tower - Bob's Torch": (0x180161, 0x186363, False, "in Ganon's Tower"), 'Palace of Darkness - The Arena - Ledge': (0xea3a, 0x18620e, False, 'in Palace of Darkness'),
'Ganons Tower - Hope Room - Left': (0xead9, 0x1862ad, False, "in Ganon's Tower"), 'Palace of Darkness - Map Chest': (0xea52, 0x186226, False, 'in Palace of Darkness'),
'Ganons Tower - Hope Room - Right': (0xeadc, 0x1862b0, False, "in Ganon's Tower"), 'Palace of Darkness - Compass Chest': (0xea43, 0x186217, False, 'in Palace of Darkness'),
'Ganons Tower - Tile Room': (0xeae2, 0x1862b6, False, "in Ganon's Tower"), 'Palace of Darkness - Dark Basement - Left': (0xea4c, 0x186220, False, 'in Palace of Darkness'),
'Ganons Tower - Compass Room - Top Left': (0xeae5, 0x1862b9, False, "in Ganon's Tower"), 'Palace of Darkness - Dark Basement - Right': (0xea4f, 0x186223, False, 'in Palace of Darkness'),
'Ganons Tower - Compass Room - Top Right': (0xeae8, 0x1862bc, False, "in Ganon's Tower"), 'Palace of Darkness - Dark Maze - Top': (0xea55, 0x186229, False, 'in Palace of Darkness'),
'Ganons Tower - Compass Room - Bottom Left': (0xeaeb, 0x1862bf, False, "in Ganon's Tower"), 'Palace of Darkness - Dark Maze - Bottom': (0xea58, 0x18622c, False, 'in Palace of Darkness'),
'Ganons Tower - Compass Room - Bottom Right': (0xeaee, 0x1862c2, False, "in Ganon's Tower"), 'Palace of Darkness - Big Chest': (0xea40, 0x186214, False, 'in Palace of Darkness'),
'Ganons Tower - DMs Room - Top Left': (0xeab8, 0x18628c, False, "in Ganon's Tower"), 'Palace of Darkness - Harmless Hellway': (0xea46, 0x18621a, False, 'in Palace of Darkness'),
'Ganons Tower - DMs Room - Top Right': (0xeabb, 0x18628f, False, "in Ganon's Tower"), 'Palace of Darkness - Boss': (0x180153, 0x186341, False, 'with Helmasaur King'),
'Ganons Tower - DMs Room - Bottom Left': (0xeabe, 0x186292, False, "in Ganon's Tower"), "Ganons Tower - Bob's Torch": (0x180161, 0x186363, False, "in Ganon's Tower"),
'Ganons Tower - DMs Room - Bottom Right': (0xeac1, 0x186295, False, "in Ganon's Tower"), 'Ganons Tower - Hope Room - Left': (0xead9, 0x1862ad, False, "in Ganon's Tower"),
'Ganons Tower - Map Chest': (0xead3, 0x1862a7, False, "in Ganon's Tower"), 'Ganons Tower - Hope Room - Right': (0xeadc, 0x1862b0, False, "in Ganon's Tower"),
'Ganons Tower - Firesnake Room': (0xead0, 0x1862a4, False, "in Ganon's Tower"), 'Ganons Tower - Tile Room': (0xeae2, 0x1862b6, False, "in Ganon's Tower"),
'Ganons Tower - Randomizer Room - Top Left': (0xeac4, 0x186298, False, "in Ganon's Tower"), 'Ganons Tower - Compass Room - Top Left': (0xeae5, 0x1862b9, False, "in Ganon's Tower"),
'Ganons Tower - Randomizer Room - Top Right': (0xeac7, 0x18629b, False, "in Ganon's Tower"), 'Ganons Tower - Compass Room - Top Right': (0xeae8, 0x1862bc, False, "in Ganon's Tower"),
'Ganons Tower - Randomizer Room - Bottom Left': (0xeaca, 0x18629e, False, "in Ganon's Tower"), 'Ganons Tower - Compass Room - Bottom Left': (0xeaeb, 0x1862bf, False, "in Ganon's Tower"),
'Ganons Tower - Randomizer Room - Bottom Right': (0xeacd, 0x1862a1, False, "in Ganon's Tower"), 'Ganons Tower - Compass Room - Bottom Right': (0xeaee, 0x1862c2, False, "in Ganon's Tower"),
"Ganons Tower - Bob's Chest": (0xeadf, 0x1862b3, False, "in Ganon's Tower"), 'Ganons Tower - DMs Room - Top Left': (0xeab8, 0x18628c, False, "in Ganon's Tower"),
'Ganons Tower - Big Chest': (0xead6, 0x1862aa, False, "in Ganon's Tower"), 'Ganons Tower - DMs Room - Top Right': (0xeabb, 0x18628f, False, "in Ganon's Tower"),
'Ganons Tower - Big Key Room - Left': (0xeaf4, 0x1862c8, False, "in Ganon's Tower"), 'Ganons Tower - DMs Room - Bottom Left': (0xeabe, 0x186292, False, "in Ganon's Tower"),
'Ganons Tower - Big Key Room - Right': (0xeaf7, 0x1862cb, False, "in Ganon's Tower"), 'Ganons Tower - DMs Room - Bottom Right': (0xeac1, 0x186295, False, "in Ganon's Tower"),
'Ganons Tower - Big Key Chest': (0xeaf1, 0x1862c5, False, "in Ganon's Tower"), 'Ganons Tower - Map Chest': (0xead3, 0x1862a7, False, "in Ganon's Tower"),
'Ganons Tower - Mini Helmasaur Room - Left': (0xeafd, 0x1862d1, False, "atop Ganon's Tower"), 'Ganons Tower - Firesnake Room': (0xead0, 0x1862a4, False, "in Ganon's Tower"),
'Ganons Tower - Mini Helmasaur Room - Right': (0xeb00, 0x1862d4, False, "atop Ganon's Tower"), 'Ganons Tower - Randomizer Room - Top Left': (0xeac4, 0x186298, False, "in Ganon's Tower"),
'Ganons Tower - Pre-Moldorm Chest': (0xeb03, 0x1862d7, False, "atop Ganon's Tower"), 'Ganons Tower - Randomizer Room - Top Right': (0xeac7, 0x18629b, False, "in Ganon's Tower"),
'Ganons Tower - Validation Chest': (0xeb06, 0x1862da, False, "atop Ganon's Tower"), 'Ganons Tower - Randomizer Room - Bottom Left': (0xeaca, 0x18629e, False, "in Ganon's Tower"),
'Ganon': (None, None, False, 'from me'), 'Ganons Tower - Randomizer Room - Bottom Right': (0xeacd, 0x1862a1, False, "in Ganon's Tower"),
'Agahnim 1': (None, None, False, 'from Ganon\'s wizardry form'), "Ganons Tower - Bob's Chest": (0xeadf, 0x1862b3, False, "in Ganon's Tower"),
'Agahnim 2': (None, None, False, 'from Ganon\'s wizardry form'), 'Ganons Tower - Big Chest': (0xead6, 0x1862aa, False, "in Ganon's Tower"),
'Floodgate': (None, None, False, None), 'Ganons Tower - Big Key Room - Left': (0xeaf4, 0x1862c8, False, "in Ganon's Tower"),
'Frog': (None, None, False, None), 'Ganons Tower - Big Key Room - Right': (0xeaf7, 0x1862cb, False, "in Ganon's Tower"),
'Missing Smith': (None, None, False, None), 'Ganons Tower - Big Key Chest': (0xeaf1, 0x1862c5, False, "in Ganon's Tower"),
'Dark Blacksmith Ruins': (None, None, False, None), 'Ganons Tower - Mini Helmasaur Room - Left': (0xeafd, 0x1862d1, False, "atop Ganon's Tower"),
'Eastern Palace - Prize': ([0x1209D, 0x53EF8, 0x53EF9, 0x180052, 0x18007C, 0xC6FE], None, True, 'Eastern Palace'), 'Ganons Tower - Mini Helmasaur Room - Right': (0xeb00, 0x1862d4, False, "atop Ganon's Tower"),
'Desert Palace - Prize': ([0x1209E, 0x53F1C, 0x53F1D, 0x180053, 0x180078, 0xC6FF], None, True, 'Desert Palace'), 'Ganons Tower - Pre-Moldorm Chest': (0xeb03, 0x1862d7, False, "atop Ganon's Tower"),
'Tower of Hera - Prize': ( 'Ganons Tower - Validation Chest': (0xeb06, 0x1862da, False, "atop Ganon's Tower"),
[0x120A5, 0x53F0A, 0x53F0B, 0x18005A, 0x18007A, 0xC706], None, True, 'Tower of Hera'), 'Ganon': (None, None, False, 'from me'),
'Palace of Darkness - Prize': ( 'Agahnim 1': (None, None, False, 'from Ganon\'s wizardry form'),
[0x120A1, 0x53F00, 0x53F01, 0x180056, 0x18007D, 0xC702], None, True, 'Palace of Darkness'), 'Agahnim 2': (None, None, False, 'from Ganon\'s wizardry form'),
'Swamp Palace - Prize': ( 'Floodgate': (None, None, False, None),
[0x120A0, 0x53F6C, 0x53F6D, 0x180055, 0x180071, 0xC701], None, True, 'Swamp Palace'), 'Frog': (None, None, False, None),
'Thieves\' Town - Prize': ( 'Missing Smith': (None, None, False, None),
[0x120A6, 0x53F36, 0x53F37, 0x18005B, 0x180077, 0xC707], None, True, 'Thieves\' Town'), 'Dark Blacksmith Ruins': (None, None, False, None),
'Skull Woods - Prize': ( 'Eastern Palace - Prize': ([0x1209D, 0x53EF8, 0x53EF9, 0x180052, 0x18007C, 0xC6FE], None, True, 'Eastern Palace'),
[0x120A3, 0x53F12, 0x53F13, 0x180058, 0x18007B, 0xC704], None, True, 'Skull Woods'), 'Desert Palace - Prize': ([0x1209E, 0x53F1C, 0x53F1D, 0x180053, 0x180078, 0xC6FF], None, True, 'Desert Palace'),
'Ice Palace - Prize': ( 'Tower of Hera - Prize': (
[0x120A4, 0x53F5A, 0x53F5B, 0x180059, 0x180073, 0xC705], None, True, 'Ice Palace'), [0x120A5, 0x53F0A, 0x53F0B, 0x18005A, 0x18007A, 0xC706], None, True, 'Tower of Hera'),
'Misery Mire - Prize': ( 'Palace of Darkness - Prize': (
[0x120A2, 0x53F48, 0x53F49, 0x180057, 0x180075, 0xC703], None, True, 'Misery Mire'), [0x120A1, 0x53F00, 0x53F01, 0x180056, 0x18007D, 0xC702], None, True, 'Palace of Darkness'),
'Turtle Rock - Prize': ( 'Swamp Palace - Prize': (
[0x120A7, 0x53F24, 0x53F25, 0x18005C, 0x180079, 0xC708], None, True, 'Turtle Rock')} [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 = {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"} lookup_id_to_name = {**lookup_id_to_name, **{data[1]: name for name, data in key_drop_data.items()}, -1: "cheat console"}

10
Text.py
View File

@ -258,6 +258,16 @@ TavernMan_texts = [
] ]
junk_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}\nIts a secret\nto everybody.\n >", "{C:GREEN}\nIts a secret\nto everybody.\n >",
"{C:GREEN}\nDodongo\ndislikes\nsmoke. >", "{C:GREEN}\nDodongo\ndislikes\nsmoke. >",
"{C:GREEN}\n> Digdogger\nhates certain\nkind of sound.", "{C:GREEN}\n> Digdogger\nhates certain\nkind of sound.",

View File

@ -6,7 +6,7 @@ def tuplize_version(version: str) -> typing.Tuple[int, ...]:
return tuple(int(piece, 10) for piece in version.split(".")) return tuple(int(piece, 10) for piece in version.split("."))
__version__ = "3.4.1" __version__ = "3.4.2"
_version_tuple = tuplize_version(__version__) _version_tuple = tuplize_version(__version__)
import os import os

View File

@ -7,7 +7,8 @@ from ..models import Room
api_endpoints = Blueprint('api', __name__, url_prefix="/api") api_endpoints = Blueprint('api', __name__, url_prefix="/api")
from . import generate from . import generate, user # trigger registration
# unsorted/misc endpoints # unsorted/misc endpoints
@ -20,4 +21,4 @@ def room_info(room: UUID):
"players": room.seed.multidata["names"], "players": room.seed.multidata["names"],
"last_port": room.last_port, "last_port": room.last_port,
"last_activity": room.last_activity, "last_activity": room.last_activity,
"timeout": room.timeout} "timeout": room.timeout}

33
WebHostLib/api/user.py Normal file
View File

@ -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)

View File

@ -45,8 +45,14 @@ def generate(race=False):
return redirect(url_for("wait_seed", seed=gen.id)) return redirect(url_for("wait_seed", seed=gen.id))
else: else:
seed_id = gen_game({name: vars(options) for name, options in gen_options.items()}, try:
race=race, owner=session["_id"].int) 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 redirect(url_for("viewSeed", seed=seed_id))
return render_template("generate.html", race=race) return render_template("generate.html", race=race)
@ -114,8 +120,7 @@ def wait_seed(seed: UUID):
if not generation: if not generation:
return "Generation not found." return "Generation not found."
elif generation.state == STATE_ERROR: elif generation.state == STATE_ERROR:
import html return render_template("seedError.html", seed_error=generation.meta.decode())
return f"Generation failed, please retry. <br> {html.escape(generation.meta.decode())}"
return render_template("waitSeed.html", seed_id=seed_id) return render_template("waitSeed.html", seed_id=seed_id)

View File

@ -0,0 +1,9 @@
window.addEventListener('load', () => {
let tables = $(".autodatatable").DataTable({
"paging": false,
"ordering": true,
"info": false,
"dom": "t",
});
console.log(tables);
});

View File

@ -5,6 +5,10 @@ window.addEventListener('load', () => {
const cookieNotice = document.createElement('div'); const cookieNotice = document.createElement('div');
cookieNotice.innerText = "This website uses cookies to store information about the games you play."; cookieNotice.innerText = "This website uses cookies to store information about the games you play.";
cookieNotice.setAttribute('id', 'cookie-notice'); 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); document.body.appendChild(cookieNotice);
cookieNotice.addEventListener('click', () => { cookieNotice.addEventListener('click', () => {
localStorage.setItem('cookieNotice', "1"); localStorage.setItem('cookieNotice', "1");

View File

@ -7,12 +7,5 @@ window.addEventListener('load', () => {
document.getElementById('host-game-form').submit(); document.getElementById('host-game-form').submit();
}); });
$("#host-game-table").DataTable({
"paging": false,
"ordering": true,
"order": [[ 3, "desc" ]],
"info": false,
"dom": "t",
});
adjustFooterHeight(); adjustFooterHeight();
}); });

View File

@ -19,12 +19,12 @@ window.addEventListener('load', () => {
// Sprite options // Sprite options
const spriteData = JSON.parse(results[1]); const spriteData = JSON.parse(results[1]);
const spriteSelect = document.getElementById('sprite'); const spriteSelect = document.getElementById('sprite');
Object.keys(spriteData).forEach((sprite) => { spriteData.sprites.forEach((sprite) => {
if (sprite.trim().length === 0) { return; } if (sprite.name.trim().length === 0) { return; }
const option = document.createElement('option'); const option = document.createElement('option');
option.setAttribute('value', spriteData[sprite]); option.setAttribute('value', sprite.name.trim());
if (playerSettings.rom.sprite === sprite) { option.selected = true; } if (playerSettings.rom.sprite === sprite.name.trim()) { option.selected = true; }
option.innerText = sprite; option.innerText = sprite.name;
spriteSelect.appendChild(option); spriteSelect.appendChild(option);
}); });
}).catch((error) => { }).catch((error) => {

View File

@ -9,7 +9,7 @@
## Logiciels requis ## Logiciels requis
- [Utilitaires du MultiWorld](https://github.com/Berserker66/MultiWorld-Utilities/releases) - [Utilitaires du MultiWorld](https://github.com/Berserker66/MultiWorld-Utilities/releases)
- [QUsb2Snes](https://github.com/Skarsnik/QUsb2snes/releases) (Inclus dans les utilitaires précédents) - [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 - Un émulateur capable d'éxécuter des scripts Lua
([snes9x Multitroid](https://drive.google.com/drive/folders/1_ej-pwWtCAHYXIrvs5Hro16A1s9Hi3Jz), ([snes9x Multitroid](https://drive.google.com/drive/folders/1_ej-pwWtCAHYXIrvs5Hro16A1s9Hi3Jz),
[BizHawk](http://tasvideos.org/BizHawk.html)) [BizHawk](http://tasvideos.org/BizHawk.html))
@ -21,17 +21,17 @@
### Installation sur Windows ### 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. 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, **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` téléchargez `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 - 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`. `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 - 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. 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 - 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. 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. 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...** 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** 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** 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. 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 ? ### 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 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.
`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.
### Votre fichier YAML est pondéré ### Configuration avancée du fichier YAML
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 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
sont les chances qu'une certaine option apparaisse par rapport aux autres disponibles. 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 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. 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. 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é. 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 ### 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 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). [Validateur de YAML](/mysterycheck).
## Générer une partie pour un joueur ## 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. 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 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). 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 [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). [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. 1. Fermez votre émulateur, qui s'est potentiellement lancé automatiquement.
2. Fermez QUsb2Snes, qui s'est lancé automatiquement avec le client. 2. Fermez QUsb2Snes, qui s'est lancé automatiquement avec le client.
3. Lancez la version appropriée de QUsb2Snes (v0.7.16). 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. 1. Récupérez les fichiers YAML des joueurs.
2. Créez une archive zip contenant ces fichiers YAML. 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. 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 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. 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, **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. 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 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. 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. 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

View File

@ -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",
});
});

View File

@ -13,11 +13,8 @@ window.addEventListener('load', () => {
localStorage.setItem(`weightedSettings${i}`, JSON.stringify(updatedObj)); localStorage.setItem(`weightedSettings${i}`, JSON.stringify(updatedObj));
} }
// Parse spriteData into useful sets
spriteData = JSON.parse(results[2]);
// Build the entire UI // 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 // Populate the UI and add event listeners
populateSettings(); populateSettings();
@ -29,6 +26,7 @@ window.addEventListener('load', () => {
document.getElementById('reset-to-default').addEventListener('click', resetToDefaults); document.getElementById('reset-to-default').addEventListener('click', resetToDefaults);
adjustHeaderWidth(); adjustHeaderWidth();
}).catch((error) => { }).catch((error) => {
console.error(error);
gameSettings.innerHTML = ` gameSettings.innerHTML = `
<h2>Something went wrong while loading your game settings page.</h2> <h2>Something went wrong while loading your game settings page.</h2>
<h2>${error}</h2> <h2>${error}</h2>
@ -170,7 +168,7 @@ const download = (filename, text) => {
document.body.removeChild(downloadLink); document.body.removeChild(downloadLink);
}; };
const buildUI = (settings) => { const buildUI = (settings, spriteData) => {
const settingsWrapper = document.getElementById('settings-wrapper'); const settingsWrapper = document.getElementById('settings-wrapper');
const settingTypes = { const settingTypes = {
gameOptions: 'Game Options', gameOptions: 'Game Options',
@ -244,7 +242,7 @@ const buildUI = (settings) => {
settingsWrapper.appendChild(spriteOptionsWrapper); settingsWrapper.appendChild(spriteOptionsWrapper);
// Append sprite picker // Append sprite picker
settingsWrapper.appendChild(buildSpritePicker()); settingsWrapper.appendChild(buildSpritePicker(spriteData));
}; };
const buildRangeSettings = (parentElement, settings) => { const buildRangeSettings = (parentElement, settings) => {
@ -404,7 +402,7 @@ const removeSpriteOption = (event) => {
tr.parentNode.removeChild(tr); tr.parentNode.removeChild(tr);
}; };
const buildSpritePicker = () => { const buildSpritePicker = (spriteData) => {
const spritePicker = document.createElement('div'); const spritePicker = document.createElement('div');
spritePicker.setAttribute('id', 'sprite-picker'); spritePicker.setAttribute('id', 'sprite-picker');
@ -415,18 +413,18 @@ const buildSpritePicker = () => {
const sprites = document.createElement('div'); const sprites = document.createElement('div');
sprites.setAttribute('id', 'sprite-picker-sprites'); sprites.setAttribute('id', 'sprite-picker-sprites');
Object.keys(spriteData).forEach((spriteName) => { spriteData.sprites.forEach((sprite) => {
const spriteImg = document.createElement('img'); const spriteImg = document.createElement('img');
spriteImg.setAttribute('src', `static/static/sprites/${spriteName}.gif`); spriteImg.setAttribute('src', `static/static/sprites/${sprite.name}.gif`);
spriteImg.setAttribute('data-sprite', spriteName); spriteImg.setAttribute('data-sprite', sprite.name);
spriteImg.setAttribute('alt', spriteName); spriteImg.setAttribute('alt', sprite.name);
// Wrap the image in a span to allow for tooltip presence // Wrap the image in a span to allow for tooltip presence
const imgWrapper = document.createElement('span'); const imgWrapper = document.createElement('span');
imgWrapper.className = 'sprite-img-wrapper'; 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.appendChild(spriteImg);
imgWrapper.setAttribute('data-sprite', spriteName); imgWrapper.setAttribute('data-sprite', sprite.name);
sprites.appendChild(imgWrapper); sprites.appendChild(imgWrapper);
imgWrapper.addEventListener('click', addSpriteOption); imgWrapper.addEventListener('click', addSpriteOption);
}); });

View File

@ -37,9 +37,17 @@
"name": "Master Sword Pedestal", "name": "Master Sword Pedestal",
"value": "pedestal" "value": "pedestal"
}, },
{
"name": "Master Sword Pedestal + Ganon",
"value": "ganon_pedestal"
},
{ {
"name": "Triforce Hunt", "name": "Triforce Hunt",
"value": "triforce_hunt" "value": "triforce_hunt"
},
{
"name": "Triforce Hunt + Ganon",
"value": "ganon_triforce_hunt"
} }
] ]
}, },
@ -209,7 +217,7 @@
}, },
"hints": { "hints": {
"type": "select", "type": "select",
"friendlyName": "Tile Hints", "friendlyName": "Hints",
"description": "Choose to enable or disable tile hints", "description": "Choose to enable or disable tile hints",
"defaultValue": "on", "defaultValue": "on",
"options": [ "options": [
@ -313,6 +321,10 @@
"name": "Big Keys Only", "name": "Big Keys Only",
"value": "b" "value": "b"
}, },
{
"name": "Small and Big Keys",
"value": "sb"
},
{ {
"name": "Full Keysanity", "name": "Full Keysanity",
"value": "mscb" "value": "mscb"
@ -334,15 +346,15 @@
"value": "none" "value": "none"
}, },
{ {
"name": "Dungeon Entrances", "name": "Only Dungeons, Simple",
"value": "dungeonssimple" "value": "dungeonssimple"
}, },
{ {
"name": "Dungeon Interiors", "name": "Only Dungeons, Full",
"value": "dungeonsfull" "value": "dungeonsfull"
}, },
{ {
"name": "Simple Entrances", "name": "Simple",
"value": "simple" "value": "simple"
}, },
{ {
@ -350,15 +362,15 @@
"value": "restricted" "value": "restricted"
}, },
{ {
"name": "Full Shuffle", "name": "Full",
"value": "full" "value": "full"
}, },
{ {
"name": "Crossed Shuffle", "name": "Crossed",
"value": "crossed" "value": "crossed"
}, },
{ {
"name": "Insanity Shuffle", "name": "Insanity",
"value": "insanity" "value": "insanity"
} }
] ]
@ -466,16 +478,24 @@
"value": "none" "value": "none"
}, },
{ {
"name": "Shuffle Inventory", "name": "Inventory",
"value": "i" "value": "i"
}, },
{ {
"name": "Shuffle Prices", "name": "Prices",
"value": "p" "value": "p"
}, },
{ {
"name": "Shuffle Both", "name": "Capacity Upgrades",
"value": "u"
},
{
"name": "Inventory and Prices",
"value": "ip" "value": "ip"
},
{
"name": "Inventory, Prices, and Upgrades",
"value": "ipu"
} }
] ]
} }
@ -612,7 +632,7 @@
"value": "default" "value": "default"
}, },
{ {
"name": "Shuffled", "name": "Randomized",
"value": "random" "value": "random"
} }
] ]
@ -628,7 +648,7 @@
"value": "default" "value": "default"
}, },
{ {
"name": "Shuffled", "name": "Randomized",
"value": "random" "value": "random"
} }
] ]
@ -644,7 +664,7 @@
"value": "default" "value": "default"
}, },
{ {
"name": "Shuffled", "name": "Randomized",
"value": "random" "value": "random"
} }
] ]
@ -660,7 +680,7 @@
"value": "default" "value": "default"
}, },
{ {
"name": "Shuffled", "name": "Randomized",
"value": "random" "value": "random"
} }
] ]

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 541 B

View File

Before

Width:  |  Height:  |  Size: 541 B

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 541 B

View File

@ -9,3 +9,8 @@
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
} }
#cookie-notice #close-button{
float: right;
padding-right: 10px;
}

View File

@ -28,25 +28,3 @@
#host-game button{ #host-game button{
margin-top: 5px; 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;
}

View File

@ -75,6 +75,7 @@ html{
padding: 3px; padding: 3px;
border-radius: 3px; border-radius: 3px;
min-width: 150px; min-width: 150px;
background-color: #ffffff;
} }
#player-settings #game-options, #player-settings #rom-options{ #player-settings #game-options, #player-settings #rom-options{
@ -97,7 +98,7 @@ html{
cursor: default; 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{ #player-settings #game-options, #player-settings #rom-options{
justify-content: flex-start; justify-content: flex-start;
flex-wrap: wrap; flex-wrap: wrap;

View File

@ -5,12 +5,14 @@ html{
} }
#tutorial-wrapper{ #tutorial-wrapper{
width: 70rem; display: flex;
flex-direction: column;
max-width: 70rem;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
background-color: rgba(0, 0, 0, 0.15); background-color: rgba(0, 0, 0, 0.15);
border-radius: 8px; border-radius: 8px;
padding: 1rem; padding: 1rem 1rem 3rem;
color: #eeffeb; color: #eeffeb;
} }

View File

@ -31,3 +31,24 @@
#user-content .center{ #user-content .center{
text-align: 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;
}

View File

@ -148,5 +148,6 @@ html{
padding: 3px; padding: 3px;
border-radius: 3px; border-radius: 3px;
min-width: 150px; min-width: 150px;
background-color: #ffffff;
} }

View File

@ -0,0 +1,5 @@
{% extends "tablepage.html" %}
{% block head %}
{{ super() }}
<script type="application/ecmascript" src="{{ static_autoversion("assets/autodatatable.js") }}"></script>
{% endblock %}

View File

@ -1,8 +1,8 @@
{% extends 'pageWrapper.html' %} {% extends 'autotablepage.html' %}
{% block head %} {% block head %}
{{ super() }} {{ super() }}
<title>Upload Mystery YAML</title> <title>Mystery YAML Test Roll Results</title>
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/checkResult.css") }}" /> <link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/checkResult.css") }}" />
{% endblock %} {% endblock %}
@ -12,7 +12,7 @@
<div id="check-result" class="grass-island"> <div id="check-result" class="grass-island">
<h1>Verification Results</h1> <h1>Verification Results</h1>
<p>The results of your requested file check are below.</p> <p>The results of your requested file check are below.</p>
<table> <table class="table autodatatable">
<thead> <thead>
<tr> <tr>
<th>File</th> <th>File</th>

View File

@ -1,4 +1,4 @@
{% extends 'tablepage.html' %} {% extends 'pageWrapper.html' %}
{% block head %} {% block head %}
{{ super() }} {{ super() }}

View File

@ -11,10 +11,10 @@
{% block body %} {% block body %}
{% include 'header/grassHeader.html' %} {% include 'header/grassHeader.html' %}
<div id="player-settings"> <div id="player-settings">
<h1>Generate Game</h1> <h1>Start Game</h1>
<p>Choose the options you would like to play with! You may generate a single-player game from this page, <p>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 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 <a href="/weighted-settings">weighted settings</a> your settings extra random, check out the advanced <a href="/weighted-settings">weighted settings</a>
page. There, you will find examples of all available sprites as well.</p> page. There, you will find examples of all available sprites as well.</p>
<p>A list of all games you have generated can be found <a href="/user-content">here</a>.</p> <p>A list of all games you have generated can be found <a href="/user-content">here</a>.</p>

View File

@ -0,0 +1,19 @@
{% extends 'pageWrapper.html' %}
{% import "macros.html" as macros %}
{% block head %}
<title>Generation failed, please retry.</title>
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/waitSeed.css") }}"/>
{% endblock %}
{% block body %}
{% include 'header/oceanHeader.html' %}
<div id="wait-seed-wrapper" class="grass-island">
<div id="wait-seed">
<h1>Generation failed</h1>
<h2>please retry</h2>
{{ seed_error }}
</div>
</div>
{% include 'islandFooter.html' %}
{% endblock %}

View File

@ -1,9 +1,10 @@
{% extends 'pageWrapper.html' %} {% extends 'tablepage.html' %}
{% block head %} {% block head %}
{{ super() }} {{ super() }}
<title>Generate Game</title> <title>Generate Game</title>
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/userContent.css") }}" /> <link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/userContent.css") }}" />
<script type="application/ecmascript" src="{{ static_autoversion("assets/userContent.js") }}"></script>
{% endblock %} {% endblock %}
{% block body %} {% block body %}
@ -15,7 +16,7 @@
<h2>Your Rooms</h2> <h2>Your Rooms</h2>
{% if rooms %} {% if rooms %}
<table> <table id="rooms-table" class="table">
<thead> <thead>
<tr> <tr>
<th>Seed</th> <th>Seed</th>
@ -46,7 +47,7 @@
<h2>Your Seeds</h2> <h2>Your Seeds</h2>
{% if seeds %} {% if seeds %}
<table> <table id="seeds-table" class="table">
<thead> <thead>
<tr> <tr>
<th>Seed</th> <th>Seed</th>

View File

@ -5694,9 +5694,9 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
}, },
"inquirer": { "inquirer": {
"version": "7.1.0", "version": "7.1.0",

View File

@ -15,7 +15,7 @@ while not done.isSet():
print("Done updating sprites") print("Done updating sprites")
spriteData = {} spriteData = []
for file in os.listdir(input_dir): for file in os.listdir(input_dir):
sprite = Sprite(os.path.join(input_dir, file)) sprite = Sprite(os.path.join(input_dir, file))
@ -27,9 +27,9 @@ for file in os.listdir(input_dir):
if sprite.valid: if sprite.valid:
with open(os.path.join(output_dir, "sprites", f"{sprite.name}.gif"), 'wb') as image: with open(os.path.join(output_dir, "sprites", f"{sprite.name}.gif"), 'wb') as image:
image.write(get_image_for_sprite(sprite, True)) image.write(get_image_for_sprite(sprite, True))
spriteData[sprite.name] = file spriteData.append({"file": file, "author": sprite.author_name, "name": sprite.name})
else: else:
print(file, "dropped, as it has no valid sprite data.") 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: with open(f'{output_dir}/spriteData.json', 'w') as file:
json.dump(spriteData, file) json.dump({"sprites": spriteData}, file, indent=1)

BIN
icon.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 214 KiB

141
inno_setup_38.iss Normal file
View File

@ -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;

View File

@ -13,9 +13,9 @@ buildfolder = Path("build", folder)
sbuildfolder = str(buildfolder) sbuildfolder = str(buildfolder)
libfolder = Path(buildfolder, "lib") libfolder = Path(buildfolder, "lib")
library = Path(libfolder, "library.zip") library = Path(libfolder, "library.zip")
print("Outputting to: " + str(buildfolder)) print("Outputting to: " + sbuildfolder)
compress = False
icon="icon.ico" icon = "icon.ico"
if os.path.exists("X:/pw.txt"): if os.path.exists("X:/pw.txt"):
print("Using signtool") print("Using signtool")
@ -28,13 +28,16 @@ else:
from hashlib import sha3_512 from hashlib import sha3_512
import base64 import base64
def _threaded_hash(filepath): def _threaded_hash(filepath):
hasher = sha3_512() hasher = sha3_512()
hasher.update(open(filepath, "rb").read()) hasher.update(open(filepath, "rb").read())
return base64.b85encode(hasher.digest()).decode() return base64.b85encode(hasher.digest()).decode()
os.makedirs(buildfolder, exist_ok=True) os.makedirs(buildfolder, exist_ok=True)
def manifest_creation(): def manifest_creation():
hashes = {} hashes = {}
manifestpath = os.path.join(buildfolder, "manifest.json") manifestpath = os.path.join(buildfolder, "manifest.json")
@ -51,11 +54,11 @@ def manifest_creation():
print("Created Manifest") print("Created Manifest")
scripts = {"MultiClient.py" : "BerserkerMultiClient", scripts = {"MultiClient.py": "BerserkerMultiClient",
"MultiMystery.py" : "BerserkerMultiMystery", "MultiMystery.py": "BerserkerMultiMystery",
"MultiServer.py" : "BerserkerMultiServer", "MultiServer.py": "BerserkerMultiServer",
"gui.py" : "BerserkerMultiCreator", "gui.py": "BerserkerMultiCreator",
"Mystery.py" : "BerserkerMystery"} "Mystery.py": "BerserkerMystery"}
exes = [] exes = []
@ -66,7 +69,6 @@ for script, scriptname in scripts.items():
icon=icon, icon=icon,
)) ))
import datetime import datetime
buildtime = datetime.datetime.utcnow() buildtime = datetime.datetime.utcnow()
@ -137,5 +139,4 @@ if signtool:
print(f"Signing {exe.targetName}") print(f"Signing {exe.targetName}")
os.system(signtool + exe.targetName) os.system(signtool + exe.targetName)
manifest_creation() manifest_creation()