commit
67fe623f00
|
@ -29,6 +29,8 @@ def main():
|
||||||
Select the rate at which the heart beep sound is played at
|
Select the rate at which the heart beep sound is played at
|
||||||
low health. (default: %(default)s)
|
low health. (default: %(default)s)
|
||||||
''')
|
''')
|
||||||
|
parser.add_argument('--heartcolor', default='red', const='red', nargs='?', choices=['red', 'blue', 'green', 'yellow'],
|
||||||
|
help='Select the color of Link\'s heart meter. (default: %(default)s)')
|
||||||
parser.add_argument('--sprite', help='''\
|
parser.add_argument('--sprite', help='''\
|
||||||
Path to a sprite sheet to use for Link. Needs to be in
|
Path to a sprite sheet to use for Link. Needs to be in
|
||||||
binary format and have a length of 0x7000 (28672) bytes,
|
binary format and have a length of 0x7000 (28672) bytes,
|
||||||
|
|
|
@ -26,7 +26,7 @@ def adjust(args):
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('Provided Rom is not a valid Link to the Past Randomizer Rom. Please provide one for adjusting.')
|
raise RuntimeError('Provided Rom is not a valid Link to the Past Randomizer Rom. Please provide one for adjusting.')
|
||||||
|
|
||||||
apply_rom_settings(rom, args.heartbeep, args.quickswap, args.fastmenu, args.disablemusic, sprite)
|
apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic, sprite)
|
||||||
|
|
||||||
rom.write_to_file(output_path('%s.sfc' % outfilebase))
|
rom.write_to_file(output_path('%s.sfc' % outfilebase))
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import copy
|
import copy
|
||||||
|
from enum import Enum, unique
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
@ -6,7 +7,7 @@ from collections import OrderedDict
|
||||||
|
|
||||||
class World(object):
|
class World(object):
|
||||||
|
|
||||||
def __init__(self, shuffle, logic, mode, difficulty, timer, progressive, goal, algorithm, place_dungeon_items, check_beatable_only, shuffle_ganon, quickswap, fastmenu, disable_music, keysanity):
|
def __init__(self, shuffle, logic, mode, difficulty, timer, progressive, goal, algorithm, place_dungeon_items, check_beatable_only, shuffle_ganon, quickswap, fastmenu, disable_music, keysanity, custom, customitemarray):
|
||||||
self.shuffle = shuffle
|
self.shuffle = shuffle
|
||||||
self.logic = logic
|
self.logic = logic
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
|
@ -30,13 +31,16 @@ class World(object):
|
||||||
self.place_dungeon_items = place_dungeon_items # configurable in future
|
self.place_dungeon_items = place_dungeon_items # configurable in future
|
||||||
self.shuffle_bonk_prizes = False
|
self.shuffle_bonk_prizes = False
|
||||||
self.swamp_patch_required = False
|
self.swamp_patch_required = False
|
||||||
|
self.powder_patch_required = False
|
||||||
self.ganon_at_pyramid = True
|
self.ganon_at_pyramid = True
|
||||||
|
self.ganonstower_vanilla = True
|
||||||
self.sewer_light_cone = mode == 'standard'
|
self.sewer_light_cone = mode == 'standard'
|
||||||
self.light_world_light_cone = False
|
self.light_world_light_cone = False
|
||||||
self.dark_world_light_cone = False
|
self.dark_world_light_cone = False
|
||||||
self.treasure_hunt_count = 0
|
self.treasure_hunt_count = 0
|
||||||
self.treasure_hunt_icon = 'Triforce Piece'
|
self.treasure_hunt_icon = 'Triforce Piece'
|
||||||
self.clock_mode = 'off'
|
self.clock_mode = 'off'
|
||||||
|
self.rupoor_cost = 10
|
||||||
self.aga_randomness = True
|
self.aga_randomness = True
|
||||||
self.lock_aga_door_in_escape = False
|
self.lock_aga_door_in_escape = False
|
||||||
self.fix_trock_doors = self.shuffle != 'vanilla'
|
self.fix_trock_doors = self.shuffle != 'vanilla'
|
||||||
|
@ -52,9 +56,13 @@ class World(object):
|
||||||
self.fastmenu = fastmenu
|
self.fastmenu = fastmenu
|
||||||
self.disable_music = disable_music
|
self.disable_music = disable_music
|
||||||
self.keysanity = keysanity
|
self.keysanity = keysanity
|
||||||
|
self.custom = custom
|
||||||
|
self.customitemarray = customitemarray
|
||||||
self.can_take_damage = True
|
self.can_take_damage = True
|
||||||
self.difficulty_requirements = None
|
self.difficulty_requirements = None
|
||||||
|
self.fix_fake_world = True
|
||||||
self.spoiler = Spoiler(self)
|
self.spoiler = Spoiler(self)
|
||||||
|
self.lamps_needed_for_dark_rooms = 1
|
||||||
|
|
||||||
def intialize_regions(self):
|
def intialize_regions(self):
|
||||||
for region in self.regions:
|
for region in self.regions:
|
||||||
|
@ -247,19 +255,31 @@ class World(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def option_identifier(self):
|
def option_identifier(self):
|
||||||
logic = 0 if self.logic == 'noglitches' else 1
|
id_value = 0
|
||||||
mode = ['standard', 'open', 'swordless'].index(self.mode)
|
id_value_max = 1
|
||||||
dungeonitems = 0 if self.place_dungeon_items else 1
|
|
||||||
goal = ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals'].index(self.goal)
|
def markbool(value):
|
||||||
shuffle = ['vanilla', 'simple', 'restricted', 'full', 'madness', 'insanity', 'dungeonsfull', 'dungeonssimple'].index(self.shuffle)
|
nonlocal id_value, id_value_max
|
||||||
difficulty = ['easy', 'normal', 'hard', 'expert', 'insane'].index(self.difficulty)
|
id_value += id_value_max * bool(value)
|
||||||
timer = ['none', 'display', 'timed', 'timed-ohko', 'timed-countdown', 'ohko'].index(self.timer)
|
id_value_max *= 2
|
||||||
progressive = ['on', 'off', 'random'].index(self.progressive)
|
def marksequence(options, value):
|
||||||
algorithm = ['freshness', 'flood', 'vt21', 'vt22', 'vt25', 'vt26', 'balanced'].index(self.algorithm)
|
nonlocal id_value, id_value_max
|
||||||
beatableonly = 1 if self.check_beatable_only else 0
|
id_value += id_value_max * options.index(value)
|
||||||
shuffleganon = 1 if self.shuffle_ganon else 0
|
id_value_max *= len(options)
|
||||||
keysanity = 1 if self.keysanity else 0
|
markbool(self.logic == 'noglitches')
|
||||||
return logic | (beatableonly << 1) | (dungeonitems << 2) | (shuffleganon << 3) | (goal << 4) | (shuffle << 7) | (difficulty << 11) | (algorithm << 13) | (mode << 16) | (keysanity << 18) | (timer << 19) | (progressive << 21)
|
marksequence(['standard', 'open', 'swordless'], self.mode)
|
||||||
|
markbool(self.place_dungeon_items)
|
||||||
|
marksequence(['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals'], self.goal)
|
||||||
|
marksequence(['vanilla', 'simple', 'restricted', 'full', 'crossed', 'insanity', 'restricted_legacy', 'full_legacy', 'madness_legacy', 'insanity_legacy', 'dungeonsfull', 'dungeonssimple'], self.shuffle)
|
||||||
|
marksequence(['easy', 'normal', 'hard', 'expert', 'insane'], self.difficulty)
|
||||||
|
marksequence(['none', 'display', 'timed', 'timed-ohko', 'timed-countdown', 'ohko'], self.timer)
|
||||||
|
marksequence(['on', 'off', 'random'], self.progressive)
|
||||||
|
marksequence(['freshness', 'flood', 'vt21', 'vt22', 'vt25', 'vt26', 'balanced'], self.algorithm)
|
||||||
|
markbool(self.check_beatable_only)
|
||||||
|
markbool(self.shuffle_ganon)
|
||||||
|
markbool(self.keysanity)
|
||||||
|
assert id_value_max <= 0xFFFFFFFF
|
||||||
|
return id_value
|
||||||
|
|
||||||
|
|
||||||
class CollectionState(object):
|
class CollectionState(object):
|
||||||
|
@ -383,17 +403,17 @@ class CollectionState(object):
|
||||||
def can_lift_heavy_rocks(self):
|
def can_lift_heavy_rocks(self):
|
||||||
return self.has('Titans Mitts')
|
return self.has('Titans Mitts')
|
||||||
|
|
||||||
def can_extend_magic(self, smallmagic=8): #This reflects the total magic Link has, not the total extra he has.
|
def can_extend_magic(self, smallmagic=8, fullrefill=False): #This reflects the total magic Link has, not the total extra he has.
|
||||||
basemagic = 8
|
basemagic = 8
|
||||||
if self.has('Quarter Magic'):
|
if self.has('Quarter Magic'):
|
||||||
basemagic = 32
|
basemagic = 32
|
||||||
elif self.has('Half Magic'):
|
elif self.has('Half Magic'):
|
||||||
basemagic = 16
|
basemagic = 16
|
||||||
if self.world.difficulty == 'hard':
|
if self.world.difficulty == 'hard' and not fullrefill:
|
||||||
basemagic = basemagic + int(basemagic * 0.5 * self.bottle_count())
|
basemagic = basemagic + int(basemagic * 0.5 * self.bottle_count())
|
||||||
elif self.world.difficulty == 'expert':
|
elif self.world.difficulty == 'expert' and not fullrefill:
|
||||||
basemagic = basemagic + int(basemagic * 0.25 * self.bottle_count())
|
basemagic = basemagic + int(basemagic * 0.25 * self.bottle_count())
|
||||||
elif self.world.difficulty == 'insane':
|
elif self.world.difficulty == 'insane' and not fullrefill:
|
||||||
basemagic = basemagic
|
basemagic = basemagic
|
||||||
else:
|
else:
|
||||||
basemagic = basemagic + basemagic * self.bottle_count()
|
basemagic = basemagic + basemagic * self.bottle_count()
|
||||||
|
@ -532,17 +552,32 @@ class CollectionState(object):
|
||||||
|
|
||||||
raise RuntimeError('Cannot parse %s.' % item)
|
raise RuntimeError('Cannot parse %s.' % item)
|
||||||
|
|
||||||
|
@unique
|
||||||
|
class RegionType(Enum):
|
||||||
|
LightWorld = 1
|
||||||
|
DarkWorld = 2
|
||||||
|
Cave = 3 # Also includes Houses
|
||||||
|
Dungeon = 4
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_indoors(self):
|
||||||
|
"""Shorthand for checking if Cave or Dungeon"""
|
||||||
|
return self in (RegionType.Cave, RegionType.Dungeon)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Region(object):
|
class Region(object):
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name, type):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.type = type
|
||||||
self.entrances = []
|
self.entrances = []
|
||||||
self.exits = []
|
self.exits = []
|
||||||
self.locations = []
|
self.locations = []
|
||||||
self.dungeon = None
|
self.dungeon = None
|
||||||
self.world = None
|
self.world = None
|
||||||
self.is_light_world = False # will be set aftermaking connections.
|
self.is_light_world = False # will be set aftermaking connections.
|
||||||
|
self.is_dark_world = False
|
||||||
self.spot_type = 'Region'
|
self.spot_type = 'Region'
|
||||||
self.hint_text = 'Hyrule'
|
self.hint_text = 'Hyrule'
|
||||||
self.recursion_count = 0
|
self.recursion_count = 0
|
||||||
|
|
|
@ -12,9 +12,9 @@ def create_dungeons(world):
|
||||||
world.get_region(region).dungeon = dungeon
|
world.get_region(region).dungeon = dungeon
|
||||||
return dungeon
|
return dungeon
|
||||||
|
|
||||||
ES = make_dungeon('Hyrule Castle', ['Hyrule Castle', 'Sewers', 'Sewers (Dark)', 'Sanctuary'], None, [ItemFactory('Small Key (Escape)')], [ItemFactory('Map (Escape)')])
|
ES = make_dungeon('Hyrule Castle', ['Hyrule Castle', 'Sewers', 'Sewer Drop', 'Sewers (Dark)', 'Sanctuary'], None, [ItemFactory('Small Key (Escape)')], [ItemFactory('Map (Escape)')])
|
||||||
EP = make_dungeon('Eastern Palace', ['Eastern Palace'], ItemFactory('Big Key (Eastern Palace)'), [], ItemFactory(['Map (Eastern Palace)', 'Compass (Eastern Palace)']))
|
EP = make_dungeon('Eastern Palace', ['Eastern Palace'], ItemFactory('Big Key (Eastern Palace)'), [], ItemFactory(['Map (Eastern Palace)', 'Compass (Eastern Palace)']))
|
||||||
DP = make_dungeon('Desert Palace', ['Desert Palace North', 'Desert Palace Main', 'Desert Palace East'], ItemFactory('Big Key (Desert Palace)'), [ItemFactory('Small Key (Desert Palace)')], ItemFactory(['Map (Desert Palace)', 'Compass (Desert Palace)']))
|
DP = make_dungeon('Desert Palace', ['Desert Palace North', 'Desert Palace Main (Inner)', 'Desert Palace Main (Outer)', 'Desert Palace East'], ItemFactory('Big Key (Desert Palace)'), [ItemFactory('Small Key (Desert Palace)')], ItemFactory(['Map (Desert Palace)', 'Compass (Desert Palace)']))
|
||||||
ToH = make_dungeon('Tower of Hera', ['Tower of Hera (Bottom)', 'Tower of Hera (Basement)', 'Tower of Hera (Top)'], ItemFactory('Big Key (Tower of Hera)'), [ItemFactory('Small Key (Tower of Hera)')], ItemFactory(['Map (Tower of Hera)', 'Compass (Tower of Hera)']))
|
ToH = make_dungeon('Tower of Hera', ['Tower of Hera (Bottom)', 'Tower of Hera (Basement)', 'Tower of Hera (Top)'], ItemFactory('Big Key (Tower of Hera)'), [ItemFactory('Small Key (Tower of Hera)')], ItemFactory(['Map (Tower of Hera)', 'Compass (Tower of Hera)']))
|
||||||
AT = make_dungeon('Agahnims Tower', ['Agahnims Tower', 'Agahnim 1'], None, ItemFactory(['Small Key (Agahnims Tower)'] * 2), [])
|
AT = make_dungeon('Agahnims Tower', ['Agahnims Tower', 'Agahnim 1'], None, ItemFactory(['Small Key (Agahnims Tower)'] * 2), [])
|
||||||
PoD = make_dungeon('Palace of Darkness', ['Palace of Darkness (Entrance)', 'Palace of Darkness (Center)', 'Palace of Darkness (Big Key Chest)', 'Palace of Darkness (Bonk Section)', 'Palace of Darkness (North)', 'Palace of Darkness (Maze)', 'Palace of Darkness (Harmless Hellway)', 'Palace of Darkness (Final Section)'], ItemFactory('Big Key (Palace of Darkness)'), ItemFactory(['Small Key (Palace of Darkness)'] * 6), ItemFactory(['Map (Palace of Darkness)', 'Compass (Palace of Darkness)']))
|
PoD = make_dungeon('Palace of Darkness', ['Palace of Darkness (Entrance)', 'Palace of Darkness (Center)', 'Palace of Darkness (Big Key Chest)', 'Palace of Darkness (Bonk Section)', 'Palace of Darkness (North)', 'Palace of Darkness (Maze)', 'Palace of Darkness (Harmless Hellway)', 'Palace of Darkness (Final Section)'], ItemFactory('Big Key (Palace of Darkness)'), ItemFactory(['Small Key (Palace of Darkness)'] * 6), ItemFactory(['Map (Palace of Darkness)', 'Compass (Palace of Darkness)']))
|
||||||
|
|
|
@ -120,25 +120,27 @@ def start():
|
||||||
slightly biased to placing progression items with
|
slightly biased to placing progression items with
|
||||||
less restrictions.
|
less restrictions.
|
||||||
''')
|
''')
|
||||||
parser.add_argument('--shuffle', default='full', const='full', nargs='?', choices=['vanilla', 'simple', 'restricted', 'full', 'madness', 'insanity', 'dungeonsfull', 'dungeonssimple'],
|
parser.add_argument('--shuffle', default='full', const='full', nargs='?', choices=['vanilla', 'simple', 'restricted', 'full', 'crossed', 'insanity', 'restricted_legacy', 'full_legacy', 'madness_legacy', 'insanity_legacy', 'dungeonsfull', 'dungeonssimple'],
|
||||||
help='''\
|
help='''\
|
||||||
Select Entrance Shuffling Algorithm. (default: %(default)s)
|
Select Entrance Shuffling Algorithm. (default: %(default)s)
|
||||||
Full: Mix cave and dungeon entrances freely.
|
Full: Mix cave and dungeon entrances freely while limiting
|
||||||
|
multi-entrance caves to one world.
|
||||||
Simple: Shuffle Dungeon Entrances/Exits between each other
|
Simple: Shuffle Dungeon Entrances/Exits between each other
|
||||||
and keep all 4-entrance dungeons confined to one
|
and keep all 4-entrance dungeons confined to one
|
||||||
location. All caves outside of death mountain are
|
location. All caves outside of death mountain are
|
||||||
shuffled in pairs.
|
shuffled in pairs and matched by original type.
|
||||||
Restricted: Use Dungeons shuffling from Simple but freely
|
Restricted: Use Dungeons shuffling from Simple but freely
|
||||||
connect remaining entrances.
|
connect remaining entrances.
|
||||||
Madness: Decouple entrances and exits from each other and
|
Crossed: Mix cave and dungeon entrances freely while allowing
|
||||||
shuffle them freely, only ensuring that no fake
|
caves to cross between worlds.
|
||||||
Light/Dark World happens and all locations are
|
Insanity: Decouple entrances and exits from each other and
|
||||||
reachable.
|
shuffle them freely. Caves that used to be single
|
||||||
Insanity: Madness without the world restrictions. Mirror and
|
entrance will still exit to the same location from
|
||||||
Pearl are provided early to ensure Filling algorithm
|
which they are entered.
|
||||||
works properly. Deal with Fake LW/DW at your
|
Vanilla: All entrances are in the same locations they were
|
||||||
discretion.
|
in the base game.
|
||||||
Experimental.
|
Legacy shuffles preserve behavior from older versions of the
|
||||||
|
entrance randomizer including significant technical limitations.
|
||||||
The dungeon variants only mix up dungeons and keep the rest of
|
The dungeon variants only mix up dungeons and keep the rest of
|
||||||
the overworld vanilla.
|
the overworld vanilla.
|
||||||
''')
|
''')
|
||||||
|
@ -163,6 +165,8 @@ def start():
|
||||||
Keys (and other dungeon items) are no longer restricted to
|
Keys (and other dungeon items) are no longer restricted to
|
||||||
their dungeons, but can be anywhere
|
their dungeons, but can be anywhere
|
||||||
''', action='store_true')
|
''', action='store_true')
|
||||||
|
parser.add_argument('--custom', default=False, help='Not supported.')
|
||||||
|
parser.add_argument('--customitemarray', default=False, help='Not supported.')
|
||||||
parser.add_argument('--nodungeonitems', help='''\
|
parser.add_argument('--nodungeonitems', help='''\
|
||||||
Remove Maps and Compasses from Itempool, replacing them by
|
Remove Maps and Compasses from Itempool, replacing them by
|
||||||
empty slots.
|
empty slots.
|
||||||
|
@ -172,15 +176,19 @@ def start():
|
||||||
ensure all locations are reachable. This only has an effect
|
ensure all locations are reachable. This only has an effect
|
||||||
on the restrictive algorithm currently.
|
on the restrictive algorithm currently.
|
||||||
''', action='store_true')
|
''', action='store_true')
|
||||||
parser.add_argument('--shuffleganon', help='''\
|
# included for backwards compatibility
|
||||||
If set, include the Pyramid Hole and Ganon's Tower in the
|
parser.add_argument('--shuffleganon', help=argparse.SUPPRESS, action='store_true', default=True)
|
||||||
entrance shuffle pool.
|
parser.add_argument('--no-shuffleganon', help='''\
|
||||||
''', action='store_true')
|
If set, the Pyramid Hole and Ganon's Tower are not
|
||||||
|
included entrance shuffle pool.
|
||||||
|
''', action='store_false', dest='shuffleganon')
|
||||||
parser.add_argument('--heartbeep', default='normal', const='normal', nargs='?', choices=['normal', 'half', 'quarter', 'off'],
|
parser.add_argument('--heartbeep', default='normal', const='normal', nargs='?', choices=['normal', 'half', 'quarter', 'off'],
|
||||||
help='''\
|
help='''\
|
||||||
Select the rate at which the heart beep sound is played at
|
Select the rate at which the heart beep sound is played at
|
||||||
low health. (default: %(default)s)
|
low health. (default: %(default)s)
|
||||||
''')
|
''')
|
||||||
|
parser.add_argument('--heartcolor', default='red', const='red', nargs='?', choices=['red', 'blue', 'green', 'yellow'],
|
||||||
|
help='Select the color of Link\'s heart meter. (default: %(default)s)')
|
||||||
parser.add_argument('--sprite', help='''\
|
parser.add_argument('--sprite', help='''\
|
||||||
Path to a sprite sheet to use for Link. Needs to be in
|
Path to a sprite sheet to use for Link. Needs to be in
|
||||||
binary format and have a length of 0x7000 (28672) bytes,
|
binary format and have a length of 0x7000 (28672) bytes,
|
||||||
|
|
1119
EntranceShuffle.py
1119
EntranceShuffle.py
File diff suppressed because it is too large
Load Diff
16
Fill.py
16
Fill.py
|
@ -1,6 +1,8 @@
|
||||||
import random
|
import random
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
class FillError(RuntimeError):
|
||||||
|
pass
|
||||||
|
|
||||||
def distribute_items_cutoff(world, cutoffrate=0.33):
|
def distribute_items_cutoff(world, cutoffrate=0.33):
|
||||||
# get list of locations to fill in
|
# get list of locations to fill in
|
||||||
|
@ -53,7 +55,7 @@ def distribute_items_cutoff(world, cutoffrate=0.33):
|
||||||
logging.getLogger('').warning('Not all locations reachable. Game beatable anyway.')
|
logging.getLogger('').warning('Not all locations reachable. Game beatable anyway.')
|
||||||
progress_done = True
|
progress_done = True
|
||||||
continue
|
continue
|
||||||
raise RuntimeError('No more progress items left to place.')
|
raise FillError('No more progress items left to place.')
|
||||||
|
|
||||||
spot_to_fill = None
|
spot_to_fill = None
|
||||||
for location in fill_locations if placed_advancement_items / total_advancement_items < cutoffrate else reversed(fill_locations):
|
for location in fill_locations if placed_advancement_items / total_advancement_items < cutoffrate else reversed(fill_locations):
|
||||||
|
@ -66,7 +68,7 @@ def distribute_items_cutoff(world, cutoffrate=0.33):
|
||||||
if world.can_beat_game():
|
if world.can_beat_game():
|
||||||
logging.getLogger('').warning('Not all items placed. Game beatable anyway.')
|
logging.getLogger('').warning('Not all items placed. Game beatable anyway.')
|
||||||
break
|
break
|
||||||
raise RuntimeError('No more spots to place %s' % item_to_place)
|
raise FillError('No more spots to place %s' % item_to_place)
|
||||||
|
|
||||||
world.push_item(spot_to_fill, item_to_place, True)
|
world.push_item(spot_to_fill, item_to_place, True)
|
||||||
itempool.remove(item_to_place)
|
itempool.remove(item_to_place)
|
||||||
|
@ -121,7 +123,7 @@ def distribute_items_staleness(world):
|
||||||
logging.getLogger('').warning('Not all locations reachable. Game beatable anyway.')
|
logging.getLogger('').warning('Not all locations reachable. Game beatable anyway.')
|
||||||
progress_done = True
|
progress_done = True
|
||||||
continue
|
continue
|
||||||
raise RuntimeError('No more progress items left to place.')
|
raise FillError('No more progress items left to place.')
|
||||||
|
|
||||||
spot_to_fill = None
|
spot_to_fill = None
|
||||||
for location in fill_locations:
|
for location in fill_locations:
|
||||||
|
@ -147,7 +149,7 @@ def distribute_items_staleness(world):
|
||||||
if world.can_beat_game():
|
if world.can_beat_game():
|
||||||
logging.getLogger('').warning('Not all items placed. Game beatable anyway.')
|
logging.getLogger('').warning('Not all items placed. Game beatable anyway.')
|
||||||
break
|
break
|
||||||
raise RuntimeError('No more spots to place %s' % item_to_place)
|
raise FillError('No more spots to place %s' % item_to_place)
|
||||||
|
|
||||||
world.push_item(spot_to_fill, item_to_place, True)
|
world.push_item(spot_to_fill, item_to_place, True)
|
||||||
itempool.remove(item_to_place)
|
itempool.remove(item_to_place)
|
||||||
|
@ -185,7 +187,7 @@ def fill_restrictive(world, base_state, locations, itempool):
|
||||||
if not world.check_beatable_only:
|
if not world.check_beatable_only:
|
||||||
logging.getLogger('').warning('Not all items placed. Game beatable anyway.')
|
logging.getLogger('').warning('Not all items placed. Game beatable anyway.')
|
||||||
break
|
break
|
||||||
raise RuntimeError('No more spots to place %s' % item_to_place)
|
raise FillError('No more spots to place %s' % item_to_place)
|
||||||
|
|
||||||
world.push_item(spot_to_fill, item_to_place, False)
|
world.push_item(spot_to_fill, item_to_place, False)
|
||||||
locations.remove(spot_to_fill)
|
locations.remove(spot_to_fill)
|
||||||
|
@ -205,7 +207,7 @@ def distribute_items_restrictive(world, gftower_trash_count=0, fill_locations=No
|
||||||
restitempool = [item for item in world.itempool if not item.advancement and not item.priority]
|
restitempool = [item for item in world.itempool if not item.advancement and not item.priority]
|
||||||
|
|
||||||
# fill in gtower locations with trash first
|
# fill in gtower locations with trash first
|
||||||
if not world.shuffle_ganon:
|
if world.ganonstower_vanilla:
|
||||||
gtower_locations = [location for location in fill_locations if 'Ganons Tower' in location.name]
|
gtower_locations = [location for location in fill_locations if 'Ganons Tower' in location.name]
|
||||||
random.shuffle(gtower_locations)
|
random.shuffle(gtower_locations)
|
||||||
trashcnt = 0
|
trashcnt = 0
|
||||||
|
@ -281,7 +283,7 @@ def flood_items(world):
|
||||||
if candidate_item_to_place is not None:
|
if candidate_item_to_place is not None:
|
||||||
item_to_place = candidate_item_to_place
|
item_to_place = candidate_item_to_place
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('No more progress items left to place.')
|
raise FillError('No more progress items left to place.')
|
||||||
|
|
||||||
# find item to replace with progress item
|
# find item to replace with progress item
|
||||||
location_list = world.get_reachable_locations()
|
location_list = world.get_reachable_locations()
|
||||||
|
|
605
Gui.py
605
Gui.py
|
@ -25,8 +25,10 @@ def guiMain(args=None):
|
||||||
notebook = ttk.Notebook(mainWindow)
|
notebook = ttk.Notebook(mainWindow)
|
||||||
randomizerWindow = ttk.Frame(notebook)
|
randomizerWindow = ttk.Frame(notebook)
|
||||||
adjustWindow = ttk.Frame(notebook)
|
adjustWindow = ttk.Frame(notebook)
|
||||||
|
customWindow = ttk.Frame(notebook)
|
||||||
notebook.add(randomizerWindow, text='Randomize')
|
notebook.add(randomizerWindow, text='Randomize')
|
||||||
notebook.add(adjustWindow, text='Adjust')
|
notebook.add(adjustWindow, text='Adjust')
|
||||||
|
notebook.add(customWindow, text='Custom')
|
||||||
notebook.pack()
|
notebook.pack()
|
||||||
|
|
||||||
# Shared Controls
|
# Shared Controls
|
||||||
|
@ -67,7 +69,10 @@ def guiMain(args=None):
|
||||||
disableMusicVar = IntVar()
|
disableMusicVar = IntVar()
|
||||||
disableMusicCheckbutton = Checkbutton(checkBoxFrame, text="Disable game music", variable=disableMusicVar)
|
disableMusicCheckbutton = Checkbutton(checkBoxFrame, text="Disable game music", variable=disableMusicVar)
|
||||||
shuffleGanonVar = IntVar()
|
shuffleGanonVar = IntVar()
|
||||||
|
shuffleGanonVar.set(1) #set default
|
||||||
shuffleGanonCheckbutton = Checkbutton(checkBoxFrame, text="Include Ganon's Tower and Pyramid Hole in shuffle pool", variable=shuffleGanonVar)
|
shuffleGanonCheckbutton = Checkbutton(checkBoxFrame, text="Include Ganon's Tower and Pyramid Hole in shuffle pool", variable=shuffleGanonVar)
|
||||||
|
customVar = IntVar()
|
||||||
|
customCheckbutton = Checkbutton(checkBoxFrame, text="Use custom item pool", variable=customVar)
|
||||||
|
|
||||||
createSpoilerCheckbutton.pack(expand=True, anchor=W)
|
createSpoilerCheckbutton.pack(expand=True, anchor=W)
|
||||||
suppressRomCheckbutton.pack(expand=True, anchor=W)
|
suppressRomCheckbutton.pack(expand=True, anchor=W)
|
||||||
|
@ -77,6 +82,7 @@ def guiMain(args=None):
|
||||||
beatableOnlyCheckbutton.pack(expand=True, anchor=W)
|
beatableOnlyCheckbutton.pack(expand=True, anchor=W)
|
||||||
disableMusicCheckbutton.pack(expand=True, anchor=W)
|
disableMusicCheckbutton.pack(expand=True, anchor=W)
|
||||||
shuffleGanonCheckbutton.pack(expand=True, anchor=W)
|
shuffleGanonCheckbutton.pack(expand=True, anchor=W)
|
||||||
|
customCheckbutton.pack(expand=True, anchor=W)
|
||||||
|
|
||||||
fileDialogFrame = Frame(rightHalfFrame)
|
fileDialogFrame = Frame(rightHalfFrame)
|
||||||
|
|
||||||
|
@ -188,7 +194,7 @@ def guiMain(args=None):
|
||||||
shuffleFrame = Frame(drowDownFrame)
|
shuffleFrame = Frame(drowDownFrame)
|
||||||
shuffleVar = StringVar()
|
shuffleVar = StringVar()
|
||||||
shuffleVar.set('full')
|
shuffleVar.set('full')
|
||||||
shuffleOptionMenu = OptionMenu(shuffleFrame, shuffleVar, 'vanilla', 'simple', 'restricted', 'full', 'madness', 'insanity', 'dungeonsfull', 'dungeonssimple')
|
shuffleOptionMenu = OptionMenu(shuffleFrame, shuffleVar, 'vanilla', 'simple', 'restricted', 'full', 'crossed', 'insanity', 'restricted_legacy', 'full_legacy', 'madness_legacy', 'insanity_legacy', 'dungeonsfull', 'dungeonssimple')
|
||||||
shuffleOptionMenu.pack(side=RIGHT)
|
shuffleOptionMenu.pack(side=RIGHT)
|
||||||
shuffleLabel = Label(shuffleFrame, text='Entrance shuffle algorithm')
|
shuffleLabel = Label(shuffleFrame, text='Entrance shuffle algorithm')
|
||||||
shuffleLabel.pack(side=LEFT)
|
shuffleLabel.pack(side=LEFT)
|
||||||
|
@ -201,6 +207,13 @@ def guiMain(args=None):
|
||||||
heartbeepLabel = Label(heartbeepFrame, text='Heartbeep sound rate')
|
heartbeepLabel = Label(heartbeepFrame, text='Heartbeep sound rate')
|
||||||
heartbeepLabel.pack(side=LEFT)
|
heartbeepLabel.pack(side=LEFT)
|
||||||
|
|
||||||
|
heartcolorFrame = Frame(drowDownFrame)
|
||||||
|
heartcolorVar = StringVar()
|
||||||
|
heartcolorVar.set('red')
|
||||||
|
heartcolorOptionMenu = OptionMenu(heartcolorFrame, heartcolorVar, 'red', 'blue', 'green', 'yellow')
|
||||||
|
heartcolorOptionMenu.pack(side=RIGHT)
|
||||||
|
heartcolorLabel = Label(heartcolorFrame, text='Heart color')
|
||||||
|
heartcolorLabel.pack(side=LEFT)
|
||||||
|
|
||||||
fastMenuFrame = Frame(drowDownFrame)
|
fastMenuFrame = Frame(drowDownFrame)
|
||||||
fastMenuVar = StringVar()
|
fastMenuVar = StringVar()
|
||||||
|
@ -219,6 +232,7 @@ def guiMain(args=None):
|
||||||
algorithmFrame.pack(expand=True, anchor=E)
|
algorithmFrame.pack(expand=True, anchor=E)
|
||||||
shuffleFrame.pack(expand=True, anchor=E)
|
shuffleFrame.pack(expand=True, anchor=E)
|
||||||
heartbeepFrame.pack(expand=True, anchor=E)
|
heartbeepFrame.pack(expand=True, anchor=E)
|
||||||
|
heartcolorFrame.pack(expand=True, anchor=E)
|
||||||
fastMenuFrame.pack(expand=True, anchor=E)
|
fastMenuFrame.pack(expand=True, anchor=E)
|
||||||
|
|
||||||
bottomFrame = Frame(randomizerWindow)
|
bottomFrame = Frame(randomizerWindow)
|
||||||
|
@ -243,6 +257,7 @@ def guiMain(args=None):
|
||||||
guiargs.algorithm = algorithmVar.get()
|
guiargs.algorithm = algorithmVar.get()
|
||||||
guiargs.shuffle = shuffleVar.get()
|
guiargs.shuffle = shuffleVar.get()
|
||||||
guiargs.heartbeep = heartbeepVar.get()
|
guiargs.heartbeep = heartbeepVar.get()
|
||||||
|
guiargs.heartcolor = heartcolorVar.get()
|
||||||
guiargs.fastmenu = fastMenuVar.get()
|
guiargs.fastmenu = fastMenuVar.get()
|
||||||
guiargs.create_spoiler = bool(createSpoilerVar.get())
|
guiargs.create_spoiler = bool(createSpoilerVar.get())
|
||||||
guiargs.suppress_rom = bool(suppressRomVar.get())
|
guiargs.suppress_rom = bool(suppressRomVar.get())
|
||||||
|
@ -252,6 +267,16 @@ def guiMain(args=None):
|
||||||
guiargs.quickswap = bool(quickSwapVar.get())
|
guiargs.quickswap = bool(quickSwapVar.get())
|
||||||
guiargs.disablemusic = bool(disableMusicVar.get())
|
guiargs.disablemusic = bool(disableMusicVar.get())
|
||||||
guiargs.shuffleganon = bool(shuffleGanonVar.get())
|
guiargs.shuffleganon = bool(shuffleGanonVar.get())
|
||||||
|
guiargs.custom = bool(customVar.get())
|
||||||
|
guiargs.customitemarray = [int(bowVar.get()), int(silverarrowVar.get()), int(boomerangVar.get()), int(magicboomerangVar.get()), int(hookshotVar.get()), int(mushroomVar.get()), int(magicpowderVar.get()), int(firerodVar.get()),
|
||||||
|
int(icerodVar.get()), int(bombosVar.get()), int(etherVar.get()), int(quakeVar.get()), int(lampVar.get()), int(hammerVar.get()), int(shovelVar.get()), int(fluteVar.get()), int(bugnetVar.get()),
|
||||||
|
int(bookVar.get()), int(bottleVar.get()), int(somariaVar.get()), int(byrnaVar.get()), int(capeVar.get()), int(mirrorVar.get()), int(bootsVar.get()), int(powergloveVar.get()), int(titansmittVar.get()),
|
||||||
|
int(proggloveVar.get()), int(flippersVar.get()), int(pearlVar.get()), int(heartpieceVar.get()), int(fullheartVar.get()), int(sancheartVar.get()), int(sword1Var.get()), int(sword2Var.get()),
|
||||||
|
int(sword3Var.get()), int(sword4Var.get()), int(progswordVar.get()), int(shield1Var.get()), int(shield2Var.get()), int(shield3Var.get()), int(progshieldVar.get()), int(bluemailVar.get()),
|
||||||
|
int(redmailVar.get()), int(progmailVar.get()), int(halfmagicVar.get()), int(quartermagicVar.get()), int(bcap5Var.get()), int(bcap10Var.get()), int(acap5Var.get()), int(acap10Var.get()),
|
||||||
|
int(arrow1Var.get()), int(arrow10Var.get()), int(bomb1Var.get()), int(bomb3Var.get()), int(rupee1Var.get()), int(rupee5Var.get()), int(rupee20Var.get()), int(rupee50Var.get()), int(rupee100Var.get()),
|
||||||
|
int(rupee300Var.get()), int(rupoorVar.get()), int(blueclockVar.get()), int(greenclockVar.get()), int(redclockVar.get()), int(triforcepieceVar.get()), int(triforcecountVar.get()),
|
||||||
|
int(triforceVar.get()), int(rupoorcostVar.get())]
|
||||||
guiargs.rom = romVar.get()
|
guiargs.rom = romVar.get()
|
||||||
guiargs.jsonout = None
|
guiargs.jsonout = None
|
||||||
guiargs.sprite = sprite
|
guiargs.sprite = sprite
|
||||||
|
@ -337,6 +362,12 @@ def guiMain(args=None):
|
||||||
heartbeepLabel2 = Label(heartbeepFrame2, text='Heartbeep sound rate')
|
heartbeepLabel2 = Label(heartbeepFrame2, text='Heartbeep sound rate')
|
||||||
heartbeepLabel2.pack(side=LEFT)
|
heartbeepLabel2.pack(side=LEFT)
|
||||||
|
|
||||||
|
heartcolorFrame2 = Frame(drowDownFrame2)
|
||||||
|
heartcolorOptionMenu2 = OptionMenu(heartcolorFrame2, heartcolorVar, 'red', 'blue', 'green', 'yellow')
|
||||||
|
heartcolorOptionMenu2.pack(side=RIGHT)
|
||||||
|
heartcolorLabel2 = Label(heartcolorFrame2, text='Heart color')
|
||||||
|
heartcolorLabel2.pack(side=LEFT)
|
||||||
|
|
||||||
fastMenuFrame2 = Frame(drowDownFrame2)
|
fastMenuFrame2 = Frame(drowDownFrame2)
|
||||||
fastMenuOptionMenu2 = OptionMenu(fastMenuFrame2, fastMenuVar, 'normal', 'instant', 'double', 'triple', 'quadruple', 'half')
|
fastMenuOptionMenu2 = OptionMenu(fastMenuFrame2, fastMenuVar, 'normal', 'instant', 'double', 'triple', 'quadruple', 'half')
|
||||||
fastMenuOptionMenu2.pack(side=RIGHT)
|
fastMenuOptionMenu2.pack(side=RIGHT)
|
||||||
|
@ -344,6 +375,7 @@ def guiMain(args=None):
|
||||||
fastMenuLabel2.pack(side=LEFT)
|
fastMenuLabel2.pack(side=LEFT)
|
||||||
|
|
||||||
heartbeepFrame2.pack(expand=True, anchor=E)
|
heartbeepFrame2.pack(expand=True, anchor=E)
|
||||||
|
heartcolorFrame2.pack(expand=True, anchor=E)
|
||||||
fastMenuFrame2.pack(expand=True, anchor=E)
|
fastMenuFrame2.pack(expand=True, anchor=E)
|
||||||
|
|
||||||
bottomFrame2 = Frame(topFrame2)
|
bottomFrame2 = Frame(topFrame2)
|
||||||
|
@ -351,6 +383,7 @@ def guiMain(args=None):
|
||||||
def adjustRom():
|
def adjustRom():
|
||||||
guiargs = Namespace
|
guiargs = Namespace
|
||||||
guiargs.heartbeep = heartbeepVar.get()
|
guiargs.heartbeep = heartbeepVar.get()
|
||||||
|
guiargs.heartcolor = heartcolorVar.get()
|
||||||
guiargs.fastmenu = fastMenuVar.get()
|
guiargs.fastmenu = fastMenuVar.get()
|
||||||
guiargs.quickswap = bool(quickSwapVar.get())
|
guiargs.quickswap = bool(quickSwapVar.get())
|
||||||
guiargs.disablemusic = bool(disableMusicVar.get())
|
guiargs.disablemusic = bool(disableMusicVar.get())
|
||||||
|
@ -369,9 +402,577 @@ def guiMain(args=None):
|
||||||
|
|
||||||
drowDownFrame2.pack(side=LEFT, pady=(0, 40))
|
drowDownFrame2.pack(side=LEFT, pady=(0, 40))
|
||||||
rightHalfFrame2.pack(side=RIGHT)
|
rightHalfFrame2.pack(side=RIGHT)
|
||||||
topFrame2.pack(side=TOP, pady=30)
|
topFrame2.pack(side=TOP, pady=70)
|
||||||
bottomFrame2.pack(side=BOTTOM, pady=(180, 0))
|
bottomFrame2.pack(side=BOTTOM, pady=(180, 0))
|
||||||
|
|
||||||
|
# Custom Controls
|
||||||
|
|
||||||
|
topFrame3 = Frame(customWindow)
|
||||||
|
|
||||||
|
def validation(P):
|
||||||
|
if str.isdigit(P) or P == "":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
vcmd=(topFrame3.register(validation), '%P')
|
||||||
|
|
||||||
|
itemList1 = Frame(topFrame3)
|
||||||
|
itemList2 = Frame(topFrame3)
|
||||||
|
itemList3 = Frame(topFrame3)
|
||||||
|
itemList4 = Frame(topFrame3)
|
||||||
|
itemList5 = Frame(topFrame3)
|
||||||
|
|
||||||
|
bowFrame = Frame(itemList1)
|
||||||
|
bowLabel = Label(bowFrame, text='Bow')
|
||||||
|
bowVar = StringVar(value='1')
|
||||||
|
bowEntry = Entry(bowFrame, textvariable=bowVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bowFrame.pack()
|
||||||
|
bowLabel.pack(anchor=W, side=LEFT, padx=(0,53))
|
||||||
|
bowEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
silverarrowFrame = Frame(itemList1)
|
||||||
|
silverarrowLabel = Label(silverarrowFrame, text='Silver Arrow')
|
||||||
|
silverarrowVar = StringVar(value='1')
|
||||||
|
silverarrowEntry = Entry(silverarrowFrame, textvariable=silverarrowVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
silverarrowFrame.pack()
|
||||||
|
silverarrowLabel.pack(anchor=W, side=LEFT, padx=(0,13))
|
||||||
|
silverarrowEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
boomerangFrame = Frame(itemList1)
|
||||||
|
boomerangLabel = Label(boomerangFrame, text='Boomerang')
|
||||||
|
boomerangVar = StringVar(value='1')
|
||||||
|
boomerangEntry = Entry(boomerangFrame, textvariable=boomerangVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
boomerangFrame.pack()
|
||||||
|
boomerangLabel.pack(anchor=W, side=LEFT, padx=(0,14))
|
||||||
|
boomerangEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
magicboomerangFrame = Frame(itemList1)
|
||||||
|
magicboomerangLabel = Label(magicboomerangFrame, text='M.Boomerang')
|
||||||
|
magicboomerangVar = StringVar(value='1')
|
||||||
|
magicboomerangEntry = Entry(magicboomerangFrame, textvariable=magicboomerangVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
magicboomerangFrame.pack()
|
||||||
|
magicboomerangLabel.pack(anchor=W, side=LEFT)
|
||||||
|
magicboomerangEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
hookshotFrame = Frame(itemList1)
|
||||||
|
hookshotLabel = Label(hookshotFrame, text='Hookshot')
|
||||||
|
hookshotVar = StringVar(value='1')
|
||||||
|
hookshotEntry = Entry(hookshotFrame, textvariable=hookshotVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
hookshotFrame.pack()
|
||||||
|
hookshotLabel.pack(anchor=W, side=LEFT, padx=(0,24))
|
||||||
|
hookshotEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
mushroomFrame = Frame(itemList1)
|
||||||
|
mushroomLabel = Label(mushroomFrame, text='Mushroom')
|
||||||
|
mushroomVar = StringVar(value='1')
|
||||||
|
mushroomEntry = Entry(mushroomFrame, textvariable=mushroomVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
mushroomFrame.pack()
|
||||||
|
mushroomLabel.pack(anchor=W, side=LEFT, padx=(0,17))
|
||||||
|
mushroomEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
magicpowderFrame = Frame(itemList1)
|
||||||
|
magicpowderLabel = Label(magicpowderFrame, text='Magic Powder')
|
||||||
|
magicpowderVar = StringVar(value='1')
|
||||||
|
magicpowderEntry = Entry(magicpowderFrame, textvariable=magicpowderVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
magicpowderFrame.pack()
|
||||||
|
magicpowderLabel.pack(anchor=W, side=LEFT)
|
||||||
|
magicpowderEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
firerodFrame = Frame(itemList1)
|
||||||
|
firerodLabel = Label(firerodFrame, text='Fire Rod')
|
||||||
|
firerodVar = StringVar(value='1')
|
||||||
|
firerodEntry = Entry(firerodFrame, textvariable=firerodVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
firerodFrame.pack()
|
||||||
|
firerodLabel.pack(anchor=W, side=LEFT, padx=(0,33))
|
||||||
|
firerodEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
icerodFrame = Frame(itemList1)
|
||||||
|
icerodLabel = Label(icerodFrame, text='Ice Rod')
|
||||||
|
icerodVar = StringVar(value='1')
|
||||||
|
icerodEntry = Entry(icerodFrame, textvariable=icerodVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
icerodFrame.pack()
|
||||||
|
icerodLabel.pack(anchor=W, side=LEFT, padx=(0,37))
|
||||||
|
icerodEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
bombosFrame = Frame(itemList1)
|
||||||
|
bombosLabel = Label(bombosFrame, text='Bombos')
|
||||||
|
bombosVar = StringVar(value='1')
|
||||||
|
bombosEntry = Entry(bombosFrame, textvariable=bombosVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bombosFrame.pack()
|
||||||
|
bombosLabel.pack(anchor=W, side=LEFT, padx=(0,32))
|
||||||
|
bombosEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
etherFrame = Frame(itemList1)
|
||||||
|
etherLabel = Label(etherFrame, text='Ether')
|
||||||
|
etherVar = StringVar(value='1')
|
||||||
|
etherEntry = Entry(etherFrame, textvariable=etherVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
etherFrame.pack()
|
||||||
|
etherLabel.pack(anchor=W, side=LEFT, padx=(0,49))
|
||||||
|
etherEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
quakeFrame = Frame(itemList1)
|
||||||
|
quakeLabel = Label(quakeFrame, text='Quake')
|
||||||
|
quakeVar = StringVar(value='1')
|
||||||
|
quakeEntry = Entry(quakeFrame, textvariable=quakeVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
quakeFrame.pack()
|
||||||
|
quakeLabel.pack(anchor=W, side=LEFT, padx=(0,42))
|
||||||
|
quakeEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
lampFrame = Frame(itemList1)
|
||||||
|
lampLabel = Label(lampFrame, text='Lamp')
|
||||||
|
lampVar = StringVar(value='1')
|
||||||
|
lampEntry = Entry(lampFrame, textvariable=lampVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
lampFrame.pack()
|
||||||
|
lampLabel.pack(anchor=W, side=LEFT, padx=(0,46))
|
||||||
|
lampEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
hammerFrame = Frame(itemList1)
|
||||||
|
hammerLabel = Label(hammerFrame, text='Hammer')
|
||||||
|
hammerVar = StringVar(value='1')
|
||||||
|
hammerEntry = Entry(hammerFrame, textvariable=hammerVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
hammerFrame.pack()
|
||||||
|
hammerLabel.pack(anchor=W, side=LEFT, padx=(0,29))
|
||||||
|
hammerEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
shovelFrame = Frame(itemList1)
|
||||||
|
shovelLabel = Label(shovelFrame, text='Shovel')
|
||||||
|
shovelVar = StringVar(value='1')
|
||||||
|
shovelEntry = Entry(shovelFrame, textvariable=shovelVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
shovelFrame.pack()
|
||||||
|
shovelLabel.pack(anchor=W, side=LEFT, padx=(0,41))
|
||||||
|
shovelEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
fluteFrame = Frame(itemList1)
|
||||||
|
fluteLabel = Label(fluteFrame, text='Flute')
|
||||||
|
fluteVar = StringVar(value='1')
|
||||||
|
fluteEntry = Entry(fluteFrame, textvariable=fluteVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
fluteFrame.pack()
|
||||||
|
fluteLabel.pack(anchor=W, side=LEFT, padx=(0,50))
|
||||||
|
fluteEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
bugnetFrame = Frame(itemList2)
|
||||||
|
bugnetLabel = Label(bugnetFrame, text='Bug Net')
|
||||||
|
bugnetVar = StringVar(value='1')
|
||||||
|
bugnetEntry = Entry(bugnetFrame, textvariable=bugnetVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bugnetFrame.pack()
|
||||||
|
bugnetLabel.pack(anchor=W, side=LEFT, padx=(0,41))
|
||||||
|
bugnetEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
bookFrame = Frame(itemList2)
|
||||||
|
bookLabel = Label(bookFrame, text='Book')
|
||||||
|
bookVar = StringVar(value='1')
|
||||||
|
bookEntry = Entry(bookFrame, textvariable=bookVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bookFrame.pack()
|
||||||
|
bookLabel.pack(anchor=W, side=LEFT, padx=(0,57))
|
||||||
|
bookEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
bottleFrame = Frame(itemList2)
|
||||||
|
bottleLabel = Label(bottleFrame, text='Bottle')
|
||||||
|
bottleVar = StringVar(value='4')
|
||||||
|
bottleEntry = Entry(bottleFrame, textvariable=bottleVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bottleFrame.pack()
|
||||||
|
bottleLabel.pack(anchor=W, side=LEFT, padx=(0,53))
|
||||||
|
bottleEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
somariaFrame = Frame(itemList2)
|
||||||
|
somariaLabel = Label(somariaFrame, text='C.Somaria')
|
||||||
|
somariaVar = StringVar(value='1')
|
||||||
|
somariaEntry = Entry(somariaFrame, textvariable=somariaVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
somariaFrame.pack()
|
||||||
|
somariaLabel.pack(anchor=W, side=LEFT, padx=(0,30))
|
||||||
|
somariaEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
byrnaFrame = Frame(itemList2)
|
||||||
|
byrnaLabel = Label(byrnaFrame, text='C.Byrna')
|
||||||
|
byrnaVar = StringVar(value='1')
|
||||||
|
byrnaEntry = Entry(byrnaFrame, textvariable=byrnaVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
byrnaFrame.pack()
|
||||||
|
byrnaLabel.pack(anchor=W, side=LEFT, padx=(0,43))
|
||||||
|
byrnaEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
capeFrame = Frame(itemList2)
|
||||||
|
capeLabel = Label(capeFrame, text='Magic Cape')
|
||||||
|
capeVar = StringVar(value='1')
|
||||||
|
capeEntry = Entry(capeFrame, textvariable=capeVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
capeFrame.pack()
|
||||||
|
capeLabel.pack(anchor=W, side=LEFT, padx=(0,21))
|
||||||
|
capeEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
mirrorFrame = Frame(itemList2)
|
||||||
|
mirrorLabel = Label(mirrorFrame, text='Magic Mirror')
|
||||||
|
mirrorVar = StringVar(value='1')
|
||||||
|
mirrorEntry = Entry(mirrorFrame, textvariable=mirrorVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
mirrorFrame.pack()
|
||||||
|
mirrorLabel.pack(anchor=W, side=LEFT, padx=(0,15))
|
||||||
|
mirrorEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
bootsFrame = Frame(itemList2)
|
||||||
|
bootsLabel = Label(bootsFrame, text='Pegasus Boots')
|
||||||
|
bootsVar = StringVar(value='1')
|
||||||
|
bootsEntry = Entry(bootsFrame, textvariable=bootsVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bootsFrame.pack()
|
||||||
|
bootsLabel.pack(anchor=W, side=LEFT, padx=(0,8))
|
||||||
|
bootsEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
powergloveFrame = Frame(itemList2)
|
||||||
|
powergloveLabel = Label(powergloveFrame, text='Power Glove')
|
||||||
|
powergloveVar = StringVar(value='0')
|
||||||
|
powergloveEntry = Entry(powergloveFrame, textvariable=powergloveVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
powergloveFrame.pack()
|
||||||
|
powergloveLabel.pack(anchor=W, side=LEFT, padx=(0,18))
|
||||||
|
powergloveEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
titansmittFrame = Frame(itemList2)
|
||||||
|
titansmittLabel = Label(titansmittFrame, text='Titan\'s Mitt')
|
||||||
|
titansmittVar = StringVar(value='0')
|
||||||
|
titansmittEntry = Entry(titansmittFrame, textvariable=titansmittVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
titansmittFrame.pack()
|
||||||
|
titansmittLabel.pack(anchor=W, side=LEFT, padx=(0,24))
|
||||||
|
titansmittEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
proggloveFrame = Frame(itemList2)
|
||||||
|
proggloveLabel = Label(proggloveFrame, text='Prog.Glove')
|
||||||
|
proggloveVar = StringVar(value='2')
|
||||||
|
proggloveEntry = Entry(proggloveFrame, textvariable=proggloveVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
proggloveFrame.pack()
|
||||||
|
proggloveLabel.pack(anchor=W, side=LEFT, padx=(0,26))
|
||||||
|
proggloveEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
flippersFrame = Frame(itemList2)
|
||||||
|
flippersLabel = Label(flippersFrame, text='Flippers')
|
||||||
|
flippersVar = StringVar(value='1')
|
||||||
|
flippersEntry = Entry(flippersFrame, textvariable=flippersVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
flippersFrame.pack()
|
||||||
|
flippersLabel.pack(anchor=W, side=LEFT, padx=(0,43))
|
||||||
|
flippersEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
pearlFrame = Frame(itemList2)
|
||||||
|
pearlLabel = Label(pearlFrame, text='Moon Pearl')
|
||||||
|
pearlVar = StringVar(value='1')
|
||||||
|
pearlEntry = Entry(pearlFrame, textvariable=pearlVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
pearlFrame.pack()
|
||||||
|
pearlLabel.pack(anchor=W, side=LEFT, padx=(0,23))
|
||||||
|
pearlEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
heartpieceFrame = Frame(itemList2)
|
||||||
|
heartpieceLabel = Label(heartpieceFrame, text='Piece of Heart')
|
||||||
|
heartpieceVar = StringVar(value='24')
|
||||||
|
heartpieceEntry = Entry(heartpieceFrame, textvariable=heartpieceVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
heartpieceFrame.pack()
|
||||||
|
heartpieceLabel.pack(anchor=W, side=LEFT, padx=(0,10))
|
||||||
|
heartpieceEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
fullheartFrame = Frame(itemList2)
|
||||||
|
fullheartLabel = Label(fullheartFrame, text='Heart Container')
|
||||||
|
fullheartVar = StringVar(value='10')
|
||||||
|
fullheartEntry = Entry(fullheartFrame, textvariable=fullheartVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
fullheartFrame.pack()
|
||||||
|
fullheartLabel.pack(anchor=W, side=LEFT)
|
||||||
|
fullheartEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
sancheartFrame = Frame(itemList2)
|
||||||
|
sancheartLabel = Label(sancheartFrame, text='Sanctuary Heart')
|
||||||
|
sancheartVar = StringVar(value='1')
|
||||||
|
sancheartEntry = Entry(sancheartFrame, textvariable=sancheartVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
sancheartFrame.pack()
|
||||||
|
sancheartLabel.pack(anchor=W, side=LEFT)
|
||||||
|
sancheartEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
sword1Frame = Frame(itemList3)
|
||||||
|
sword1Label = Label(sword1Frame, text='Sword 1')
|
||||||
|
sword1Var = StringVar(value='0')
|
||||||
|
sword1Entry = Entry(sword1Frame, textvariable=sword1Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
sword1Frame.pack()
|
||||||
|
sword1Label.pack(anchor=W, side=LEFT, padx=(0,34))
|
||||||
|
sword1Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
sword2Frame = Frame(itemList3)
|
||||||
|
sword2Label = Label(sword2Frame, text='Sword 2')
|
||||||
|
sword2Var = StringVar(value='0')
|
||||||
|
sword2Entry = Entry(sword2Frame, textvariable=sword2Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
sword2Frame.pack()
|
||||||
|
sword2Label.pack(anchor=W, side=LEFT, padx=(0,34))
|
||||||
|
sword2Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
sword3Frame = Frame(itemList3)
|
||||||
|
sword3Label = Label(sword3Frame, text='Sword 3')
|
||||||
|
sword3Var = StringVar(value='0')
|
||||||
|
sword3Entry = Entry(sword3Frame, textvariable=sword3Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
sword3Frame.pack()
|
||||||
|
sword3Label.pack(anchor=W, side=LEFT, padx=(0,34))
|
||||||
|
sword3Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
sword4Frame = Frame(itemList3)
|
||||||
|
sword4Label = Label(sword4Frame, text='Sword 4')
|
||||||
|
sword4Var = StringVar(value='0')
|
||||||
|
sword4Entry = Entry(sword4Frame, textvariable=sword4Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
sword4Frame.pack()
|
||||||
|
sword4Label.pack(anchor=W, side=LEFT, padx=(0,34))
|
||||||
|
sword4Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
progswordFrame = Frame(itemList3)
|
||||||
|
progswordLabel = Label(progswordFrame, text='Prog.Sword')
|
||||||
|
progswordVar = StringVar(value='4')
|
||||||
|
progswordEntry = Entry(progswordFrame, textvariable=progswordVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
progswordFrame.pack()
|
||||||
|
progswordLabel.pack(anchor=W, side=LEFT, padx=(0,15))
|
||||||
|
progswordEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
shield1Frame = Frame(itemList3)
|
||||||
|
shield1Label = Label(shield1Frame, text='Shield 1')
|
||||||
|
shield1Var = StringVar(value='0')
|
||||||
|
shield1Entry = Entry(shield1Frame, textvariable=shield1Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
shield1Frame.pack()
|
||||||
|
shield1Label.pack(anchor=W, side=LEFT, padx=(0,35))
|
||||||
|
shield1Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
shield2Frame = Frame(itemList3)
|
||||||
|
shield2Label = Label(shield2Frame, text='Shield 2')
|
||||||
|
shield2Var = StringVar(value='0')
|
||||||
|
shield2Entry = Entry(shield2Frame, textvariable=shield2Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
shield2Frame.pack()
|
||||||
|
shield2Label.pack(anchor=W, side=LEFT, padx=(0,35))
|
||||||
|
shield2Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
shield3Frame = Frame(itemList3)
|
||||||
|
shield3Label = Label(shield3Frame, text='Shield 3')
|
||||||
|
shield3Var = StringVar(value='0')
|
||||||
|
shield3Entry = Entry(shield3Frame, textvariable=shield3Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
shield3Frame.pack()
|
||||||
|
shield3Label.pack(anchor=W, side=LEFT, padx=(0,35))
|
||||||
|
shield3Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
progshieldFrame = Frame(itemList3)
|
||||||
|
progshieldLabel = Label(progshieldFrame, text='Prog.Shield')
|
||||||
|
progshieldVar = StringVar(value='3')
|
||||||
|
progshieldEntry = Entry(progshieldFrame, textvariable=progshieldVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
progshieldFrame.pack()
|
||||||
|
progshieldLabel.pack(anchor=W, side=LEFT, padx=(0,16))
|
||||||
|
progshieldEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
bluemailFrame = Frame(itemList3)
|
||||||
|
bluemailLabel = Label(bluemailFrame, text='Blue Mail')
|
||||||
|
bluemailVar = StringVar(value='0')
|
||||||
|
bluemailEntry = Entry(bluemailFrame, textvariable=bluemailVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bluemailFrame.pack()
|
||||||
|
bluemailLabel.pack(anchor=W, side=LEFT, padx=(0,27))
|
||||||
|
bluemailEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
redmailFrame = Frame(itemList3)
|
||||||
|
redmailLabel = Label(redmailFrame, text='Red Mail')
|
||||||
|
redmailVar = StringVar(value='0')
|
||||||
|
redmailEntry = Entry(redmailFrame, textvariable=redmailVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
redmailFrame.pack()
|
||||||
|
redmailLabel.pack(anchor=W, side=LEFT, padx=(0,30))
|
||||||
|
redmailEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
progmailFrame = Frame(itemList3)
|
||||||
|
progmailLabel = Label(progmailFrame, text='Prog.Mail')
|
||||||
|
progmailVar = StringVar(value='2')
|
||||||
|
progmailEntry = Entry(progmailFrame, textvariable=progmailVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
progmailFrame.pack()
|
||||||
|
progmailLabel.pack(anchor=W, side=LEFT, padx=(0,25))
|
||||||
|
progmailEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
halfmagicFrame = Frame(itemList3)
|
||||||
|
halfmagicLabel = Label(halfmagicFrame, text='Half Magic')
|
||||||
|
halfmagicVar = StringVar(value='1')
|
||||||
|
halfmagicEntry = Entry(halfmagicFrame, textvariable=halfmagicVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
halfmagicFrame.pack()
|
||||||
|
halfmagicLabel.pack(anchor=W, side=LEFT, padx=(0,18))
|
||||||
|
halfmagicEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
quartermagicFrame = Frame(itemList3)
|
||||||
|
quartermagicLabel = Label(quartermagicFrame, text='Quarter Magic')
|
||||||
|
quartermagicVar = StringVar(value='0')
|
||||||
|
quartermagicEntry = Entry(quartermagicFrame, textvariable=quartermagicVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
quartermagicFrame.pack()
|
||||||
|
quartermagicLabel.pack(anchor=W, side=LEFT)
|
||||||
|
quartermagicEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
bcap5Frame = Frame(itemList3)
|
||||||
|
bcap5Label = Label(bcap5Frame, text='Bomb C.+5')
|
||||||
|
bcap5Var = StringVar(value='6')
|
||||||
|
bcap5Entry = Entry(bcap5Frame, textvariable=bcap5Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bcap5Frame.pack()
|
||||||
|
bcap5Label.pack(anchor=W, side=LEFT, padx=(0,16))
|
||||||
|
bcap5Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
bcap10Frame = Frame(itemList3)
|
||||||
|
bcap10Label = Label(bcap10Frame, text='Bomb C.+10')
|
||||||
|
bcap10Var = StringVar(value='1')
|
||||||
|
bcap10Entry = Entry(bcap10Frame, textvariable=bcap10Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bcap10Frame.pack()
|
||||||
|
bcap10Label.pack(anchor=W, side=LEFT, padx=(0,10))
|
||||||
|
bcap10Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
acap5Frame = Frame(itemList4)
|
||||||
|
acap5Label = Label(acap5Frame, text='Arrow C.+5')
|
||||||
|
acap5Var = StringVar(value='6')
|
||||||
|
acap5Entry = Entry(acap5Frame, textvariable=acap5Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
acap5Frame.pack()
|
||||||
|
acap5Label.pack(anchor=W, side=LEFT, padx=(0,7))
|
||||||
|
acap5Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
acap10Frame = Frame(itemList4)
|
||||||
|
acap10Label = Label(acap10Frame, text='Arrow C.+10')
|
||||||
|
acap10Var = StringVar(value='1')
|
||||||
|
acap10Entry = Entry(acap10Frame, textvariable=acap10Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
acap10Frame.pack()
|
||||||
|
acap10Label.pack(anchor=W, side=LEFT, padx=(0,1))
|
||||||
|
acap10Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
arrow1Frame = Frame(itemList4)
|
||||||
|
arrow1Label = Label(arrow1Frame, text='Arrow (1)')
|
||||||
|
arrow1Var = StringVar(value='1')
|
||||||
|
arrow1Entry = Entry(arrow1Frame, textvariable=arrow1Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
arrow1Frame.pack()
|
||||||
|
arrow1Label.pack(anchor=W, side=LEFT, padx=(0,18))
|
||||||
|
arrow1Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
arrow10Frame = Frame(itemList4)
|
||||||
|
arrow10Label = Label(arrow10Frame, text='Arrows (10)')
|
||||||
|
arrow10Var = StringVar(value='5')
|
||||||
|
arrow10Entry = Entry(arrow10Frame, textvariable=arrow10Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
arrow10Frame.pack()
|
||||||
|
arrow10Label.pack(anchor=W, side=LEFT, padx=(0,7))
|
||||||
|
arrow10Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
bomb1Frame = Frame(itemList4)
|
||||||
|
bomb1Label = Label(bomb1Frame, text='Bomb (1)')
|
||||||
|
bomb1Var = StringVar(value='0')
|
||||||
|
bomb1Entry = Entry(bomb1Frame, textvariable=bomb1Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bomb1Frame.pack()
|
||||||
|
bomb1Label.pack(anchor=W, side=LEFT, padx=(0,18))
|
||||||
|
bomb1Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
bomb3Frame = Frame(itemList4)
|
||||||
|
bomb3Label = Label(bomb3Frame, text='Bombs (3)')
|
||||||
|
bomb3Var = StringVar(value='10')
|
||||||
|
bomb3Entry = Entry(bomb3Frame, textvariable=bomb3Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
bomb3Frame.pack()
|
||||||
|
bomb3Label.pack(anchor=W, side=LEFT, padx=(0,13))
|
||||||
|
bomb3Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
rupee1Frame = Frame(itemList4)
|
||||||
|
rupee1Label = Label(rupee1Frame, text='Rupee (1)')
|
||||||
|
rupee1Var = StringVar(value='2')
|
||||||
|
rupee1Entry = Entry(rupee1Frame, textvariable=rupee1Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
rupee1Frame.pack()
|
||||||
|
rupee1Label.pack(anchor=W, side=LEFT, padx=(0,17))
|
||||||
|
rupee1Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
rupee5Frame = Frame(itemList4)
|
||||||
|
rupee5Label = Label(rupee5Frame, text='Rupees (5)')
|
||||||
|
rupee5Var = StringVar(value='4')
|
||||||
|
rupee5Entry = Entry(rupee5Frame, textvariable=rupee5Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
rupee5Frame.pack()
|
||||||
|
rupee5Label.pack(anchor=W, side=LEFT, padx=(0,12))
|
||||||
|
rupee5Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
rupee20Frame = Frame(itemList4)
|
||||||
|
rupee20Label = Label(rupee20Frame, text='Rupees (20)')
|
||||||
|
rupee20Var = StringVar(value='28')
|
||||||
|
rupee20Entry = Entry(rupee20Frame, textvariable=rupee20Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
rupee20Frame.pack()
|
||||||
|
rupee20Label.pack(anchor=W, side=LEFT, padx=(0,6))
|
||||||
|
rupee20Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
rupee50Frame = Frame(itemList4)
|
||||||
|
rupee50Label = Label(rupee50Frame, text='Rupees (50)')
|
||||||
|
rupee50Var = StringVar(value='7')
|
||||||
|
rupee50Entry = Entry(rupee50Frame, textvariable=rupee50Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
rupee50Frame.pack()
|
||||||
|
rupee50Label.pack(anchor=W, side=LEFT, padx=(0,6))
|
||||||
|
rupee50Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
rupee100Frame = Frame(itemList4)
|
||||||
|
rupee100Label = Label(rupee100Frame, text='Rupees (100)')
|
||||||
|
rupee100Var = StringVar(value='1')
|
||||||
|
rupee100Entry = Entry(rupee100Frame, textvariable=rupee100Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
rupee100Frame.pack()
|
||||||
|
rupee100Label.pack(anchor=W, side=LEFT, padx=(0,0))
|
||||||
|
rupee100Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
rupee300Frame = Frame(itemList4)
|
||||||
|
rupee300Label = Label(rupee300Frame, text='Rupees (300)')
|
||||||
|
rupee300Var = StringVar(value='5')
|
||||||
|
rupee300Entry = Entry(rupee300Frame, textvariable=rupee300Var, width=3, validate='all', vcmd=vcmd)
|
||||||
|
rupee300Frame.pack()
|
||||||
|
rupee300Label.pack(anchor=W, side=LEFT, padx=(0,0))
|
||||||
|
rupee300Entry.pack(anchor=E)
|
||||||
|
|
||||||
|
rupoorFrame = Frame(itemList4)
|
||||||
|
rupoorLabel = Label(rupoorFrame, text='Rupoor')
|
||||||
|
rupoorVar = StringVar(value='0')
|
||||||
|
rupoorEntry = Entry(rupoorFrame, textvariable=rupoorVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
rupoorFrame.pack()
|
||||||
|
rupoorLabel.pack(anchor=W, side=LEFT, padx=(0,28))
|
||||||
|
rupoorEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
blueclockFrame = Frame(itemList4)
|
||||||
|
blueclockLabel = Label(blueclockFrame, text='Blue Clock')
|
||||||
|
blueclockVar = StringVar(value='0')
|
||||||
|
blueclockEntry = Entry(blueclockFrame, textvariable=blueclockVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
blueclockFrame.pack()
|
||||||
|
blueclockLabel.pack(anchor=W, side=LEFT, padx=(0,11))
|
||||||
|
blueclockEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
greenclockFrame = Frame(itemList4)
|
||||||
|
greenclockLabel = Label(greenclockFrame, text='Green Clock')
|
||||||
|
greenclockVar = StringVar(value='0')
|
||||||
|
greenclockEntry = Entry(greenclockFrame, textvariable=greenclockVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
greenclockFrame.pack()
|
||||||
|
greenclockLabel.pack(anchor=W, side=LEFT, padx=(0,3))
|
||||||
|
greenclockEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
redclockFrame = Frame(itemList4)
|
||||||
|
redclockLabel = Label(redclockFrame, text='Red Clock')
|
||||||
|
redclockVar = StringVar(value='0')
|
||||||
|
redclockEntry = Entry(redclockFrame, textvariable=redclockVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
redclockFrame.pack()
|
||||||
|
redclockLabel.pack(anchor=W, side=LEFT, padx=(0,14))
|
||||||
|
redclockEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
triforcepieceFrame = Frame(itemList5)
|
||||||
|
triforcepieceLabel = Label(triforcepieceFrame, text='Triforce Piece')
|
||||||
|
triforcepieceVar = StringVar(value='0')
|
||||||
|
triforcepieceEntry = Entry(triforcepieceFrame, textvariable=triforcepieceVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
triforcepieceFrame.pack()
|
||||||
|
triforcepieceLabel.pack(anchor=W, side=LEFT, padx=(0,55))
|
||||||
|
triforcepieceEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
triforcecountFrame = Frame(itemList5)
|
||||||
|
triforcecountLabel = Label(triforcecountFrame, text='Triforce Pieces Required')
|
||||||
|
triforcecountVar = StringVar(value='0')
|
||||||
|
triforcecountEntry = Entry(triforcecountFrame, textvariable=triforcecountVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
triforcecountFrame.pack()
|
||||||
|
triforcecountLabel.pack(anchor=W, side=LEFT, padx=(0,0))
|
||||||
|
triforcecountEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
triforceFrame = Frame(itemList5)
|
||||||
|
triforceLabel = Label(triforceFrame, text='Triforce (win game)')
|
||||||
|
triforceVar = StringVar(value='0')
|
||||||
|
triforceEntry = Entry(triforceFrame, textvariable=triforceVar, width=3, validate='all', vcmd=vcmd)
|
||||||
|
triforceFrame.pack()
|
||||||
|
triforceLabel.pack(anchor=W, side=LEFT, padx=(0,23))
|
||||||
|
triforceEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
rupoorcostFrame = Frame(itemList5)
|
||||||
|
rupoorcostLabel = Label(rupoorcostFrame, text='Rupoor Cost')
|
||||||
|
rupoorcostVar = StringVar(value='10')
|
||||||
|
rupoorcostEntry = Entry(rupoorcostFrame, textvariable=rupoorcostVar, width=6, validate='all', vcmd=vcmd)
|
||||||
|
rupoorcostFrame.pack()
|
||||||
|
rupoorcostLabel.pack(anchor=W, side=LEFT, padx=(0,43))
|
||||||
|
rupoorcostEntry.pack(anchor=E)
|
||||||
|
|
||||||
|
itemList1.pack(side=LEFT, padx=(0,0))
|
||||||
|
itemList2.pack(side=LEFT, padx=(0,0))
|
||||||
|
itemList3.pack(side=LEFT, padx=(0,0))
|
||||||
|
itemList4.pack(side=LEFT, padx=(0,0))
|
||||||
|
itemList5.pack(side=LEFT, padx=(0,0))
|
||||||
|
topFrame3.pack(side=TOP, pady=(17,0))
|
||||||
|
|
||||||
if args is not None:
|
if args is not None:
|
||||||
# load values from commandline args
|
# load values from commandline args
|
||||||
createSpoilerVar.set(int(args.create_spoiler))
|
createSpoilerVar.set(int(args.create_spoiler))
|
||||||
|
|
245
ItemList.py
245
ItemList.py
|
@ -1,8 +1,9 @@
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
import logging
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from Items import ItemFactory
|
from Items import ItemFactory
|
||||||
from Fill import fill_restrictive
|
from Fill import FillError, fill_restrictive
|
||||||
from Dungeons import get_dungeon_item_pool
|
from Dungeons import get_dungeon_item_pool
|
||||||
|
|
||||||
#This file sets the item pools for various modes. Timed modes and triforce hunt are enforced first, and then extra items are specified per mode to fill in the remaining space.
|
#This file sets the item pools for various modes. Timed modes and triforce hunt are enforced first, and then extra items are specified per mode to fill in the remaining space.
|
||||||
|
@ -25,8 +26,8 @@ normalfourth5extra = ['Arrows (10)'] * 2 + ['Rupees (20)'] * 2 + ['Rupees (5)']
|
||||||
normalfinal25extra = ['Rupees (20)'] * 23 + ['Rupees (5)'] * 2
|
normalfinal25extra = ['Rupees (20)'] * 23 + ['Rupees (5)'] * 2
|
||||||
|
|
||||||
|
|
||||||
easybaseitems = (['Blue Boomerang', 'Red Boomerang', 'Silver Arrows'] + ['Rupees (300)'] * 4 + ['Magic Upgrade (1/2)'] * 2 + ['Lamp'] * 2 +
|
easybaseitems = (['Blue Boomerang', 'Red Boomerang', 'Sanctuary Heart Container'] + ['Rupees (300)'] * 4 + ['Magic Upgrade (1/2)'] * 2 + ['Lamp'] * 2 +
|
||||||
['Single Arrow', 'Sanctuary Heart Container'] + ['Boss Heart Container'] * 10 + ['Piece of Heart'] * 12)
|
['Silver Arrows'] * 2 + ['Boss Heart Container'] * 10 + ['Piece of Heart'] * 12)
|
||||||
easyextra = ['Piece of Heart'] * 12 + ['Rupees (300)']
|
easyextra = ['Piece of Heart'] * 12 + ['Rupees (300)']
|
||||||
easylimitedextra = ['Boss Heart Container'] * 3 # collapsing down the 12 pieces of heart
|
easylimitedextra = ['Boss Heart Container'] * 3 # collapsing down the 12 pieces of heart
|
||||||
easyfirst15extra = ['Rupees (100)', 'Arrow Upgrade (+10)', 'Bomb Upgrade (+10)'] + ['Arrow Upgrade (+5)'] * 6 + ['Bomb Upgrade (+5)'] * 6
|
easyfirst15extra = ['Rupees (100)', 'Arrow Upgrade (+10)', 'Bomb Upgrade (+10)'] + ['Arrow Upgrade (+5)'] * 6 + ['Bomb Upgrade (+5)'] * 6
|
||||||
|
@ -35,26 +36,28 @@ easythird5extra = ['Rupees (50)'] * 2 + ['Bombs (3)'] * 2 + ['Arrows (10)']
|
||||||
easyfinal25extra = ['Rupees (50)'] * 4 + ['Rupees (20)'] * 14 + ['Rupee (1)'] + ['Arrows (10)'] * 4 + ['Rupees (5)'] * 2
|
easyfinal25extra = ['Rupees (50)'] * 4 + ['Rupees (20)'] * 14 + ['Rupee (1)'] + ['Arrows (10)'] * 4 + ['Rupees (5)'] * 2
|
||||||
easytimedotherextra = ['Red Clock'] * 5
|
easytimedotherextra = ['Red Clock'] * 5
|
||||||
|
|
||||||
hardbaseitems = (['Silver Arrows', 'Single Arrow'] + ['Rupees (300)'] + ['Rupees (100)'] * 2 + ['Rupees (50)'] + ['Bombs (3)'] +
|
hardbaseitems = (['Silver Arrows', 'Single Arrow', 'Single Bomb'] + ['Rupees (300)'] + ['Rupees (100)'] * 3 + ['Rupees (50)'] * 5 + ['Bombs (3)'] * 5 +
|
||||||
['Boss Heart Container'] * 5 + ['Piece of Heart'] * 24)
|
['Boss Heart Container'] * 5 + ['Piece of Heart'] * 24)
|
||||||
hardfirst20extra = ['Bombs (3)'] * 4 + ['Single Bomb'] * 4 + ['Rupees (5)'] * 5 + ['Rupee (1)'] * 2 + ['Rupees (100)'] + ['Rupees (50)'] * 4
|
hardfirst20extra = ['Single Bomb'] * 7 + ['Rupees (5)'] * 8 + ['Rupee (1)'] * 2 + ['Rupees (20)'] * 2 + ['Arrows (10)']
|
||||||
hardsecond20extra = ['Single Bomb'] * 4 + ['Rupees (5)'] * 10 + ['Rupees (20)'] * 2 + ['Rupee (1)'] * 3 + ['Arrows (10)']
|
hardsecond10extra = ['Rupees (5)'] * 7 + ['Rupee (1)'] * 3
|
||||||
hardthird20extra = ['Arrows (10)'] * 4 + ['Rupees (20)'] * 3 + ['Rupees (5)'] * 3 + ['Single Bomb'] * 5 + ['Single Arrow'] * 5
|
hardthird10extra = ['Arrows (10)'] * 4 + ['Rupees (20)'] * 3 + ['Single Bomb'] * 3
|
||||||
|
hardfourth10extra = ['Rupees (5)'] * 3 + ['Single Arrow'] * 5 + ['Single Bomb'] * 2
|
||||||
hardfinal20extra = ['Single Bomb'] * 4 + ['Rupees (5)'] * 2 + ['Single Arrow'] * 14
|
hardfinal20extra = ['Single Bomb'] * 4 + ['Rupees (5)'] * 2 + ['Single Arrow'] * 14
|
||||||
|
|
||||||
expertbaseitems = (['Single Arrow', 'Rupees (300)', 'Rupees (100)', 'Bombs (3)', 'Arrows (10)'] + ['Rupees (50)'] * 4 + ['Rupees (5)'] * 5 +
|
expertbaseitems = (['Single Arrow', 'Rupees (300)', 'Rupees (100)', 'Bombs (3)', 'Arrows (10)'] + ['Rupees (50)'] * 4 + ['Rupees (5)'] * 5 +
|
||||||
['Rupees (20)'] + ['Single Bomb'] * 2 + ['Piece of Heart'] * 24)
|
['Rupees (20)'] * 3 + ['Single Bomb'] * 10 + ['Piece of Heart'] * 24)
|
||||||
expertfirst15extra = ['Single Bomb'] * 13 + ['Rupees (20)'] * 2
|
expertfirst15extra = ['Single Bomb'] * 7 + ['Rupees (20)'] * 3 + ['Single Arrow'] * 5
|
||||||
expertsecond25extra = ['Single Bomb'] * 8 + ['Single Arrow'] * 9 + ['Rupees (20)'] * 3 + ['Rupee (1)'] * 5
|
expertsecond15extra = ['Single Bomb'] * 6 + ['Single Arrow'] * 4 + ['Rupee (1)'] * 5
|
||||||
expertthird15extra = ['Rupees (5)'] * 5 + ['Single Bomb'] * 3 + ['Rupees (20)'] * 2 + ['Single Arrow'] * 5
|
expertthird10extra = ['Rupees (5)'] * 3 + ['Single Bomb'] * 3 + ['Rupees (20)'] * 2 + ['Single Arrow'] * 2
|
||||||
|
expertfourth5extra = ['Rupees (5)'] * 2 + ['Single Arrow'] * 3
|
||||||
expertfinal25extra = ['Single Bomb'] * 4 + ['Rupees (20)'] * 3 + ['Single Arrow'] * 18
|
expertfinal25extra = ['Single Bomb'] * 4 + ['Rupees (20)'] * 3 + ['Single Arrow'] * 18
|
||||||
|
|
||||||
insanebaseitems = (['Single Arrow', 'Bombs (3)', 'Arrows (10)'] + ['Rupees (50)'] * 3 + ['Rupees (5)'] * 10 + ['Rupees (300)'] * 4 + ['Rupees (100)'] * 3 +
|
insanebaseitems = (['Bombs (3)', 'Arrows (10)'] + ['Rupees (50)'] * 4 + ['Rupees (5)'] * 10 + ['Rupees (300)'] * 5 + ['Rupees (100)'] * 4 +
|
||||||
['Rupee (1)'] * 4 + ['Single Bomb'] * 4)
|
['Rupee (1)'] * 8 + ['Rupees (20)'] * 4 + ['Single Bomb'] * 8 + ['Single Arrow'] * 6)
|
||||||
insanefirst15extra = ['Single Bomb'] * 4 + ['Single Arrow'] * 4 + ['Rupee (1)'] * 4 + ['Rupees (300)'] + ['Rupees (100)'] + ['Rupees (50)']
|
insanefirst15extra = ['Single Bomb'] * 5 + ['Single Arrow'] * 4 + ['Rupee (1)'] * 5 + ['Rupees (20)']
|
||||||
insanesecond25extra = ['Single Bomb'] * 7 + ['Single Arrow'] * 7 + ['Rupee (1)'] * 7 + ['Rupees (20)'] * 4
|
insanesecond15extra = ['Single Bomb'] * 5 + ['Single Arrow'] * 5 + ['Rupee (1)'] * 5
|
||||||
insanethird10extra = ['Single Bomb'] * 3 + ['Single Arrow'] * 3 + ['Rupee (1)'] * 3 + ['Rupees (20)']
|
insanethird10extra = ['Single Bomb'] * 4 + ['Single Arrow'] * 3 + ['Rupee (1)'] * 3
|
||||||
insanefourth15extra = ['Single Bomb'] * 5 + ['Single Arrow'] * 5 + ['Rupee (1)'] * 5
|
insanefourth5extra = ['Single Bomb'] + ['Single Arrow'] * 2 + ['Rupee (1)'] * 2
|
||||||
insanefinal25extra = ['Single Bomb'] * 2 + ['Single Arrow'] * 10 + ['Rupee (1)'] * 7 + ['Rupees (20)'] * 6
|
insanefinal25extra = ['Single Bomb'] * 2 + ['Single Arrow'] * 10 + ['Rupee (1)'] * 7 + ['Rupees (20)'] * 6
|
||||||
|
|
||||||
Difficulty = namedtuple('Difficulty',
|
Difficulty = namedtuple('Difficulty',
|
||||||
|
@ -118,7 +121,7 @@ difficulties = {
|
||||||
timedohko = ['Green Clock'] * 25,
|
timedohko = ['Green Clock'] * 25,
|
||||||
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 5, # +5 more Red Clocks if there is room
|
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 5, # +5 more Red Clocks if there is room
|
||||||
triforcehunt = ['Triforce Piece'] * 30,
|
triforcehunt = ['Triforce Piece'] * 30,
|
||||||
triforce_pieces_required = 10,
|
triforce_pieces_required = 20,
|
||||||
conditional_extras = easy_conditional_extras,
|
conditional_extras = easy_conditional_extras,
|
||||||
extras = [easyextra, easyfirst15extra, easysecond10extra, easythird5extra, easyfinal25extra],
|
extras = [easyextra, easyfirst15extra, easysecond10extra, easythird5extra, easyfinal25extra],
|
||||||
progressive_sword_limit = 4,
|
progressive_sword_limit = 4,
|
||||||
|
@ -140,10 +143,10 @@ difficulties = {
|
||||||
basicsword = ['Master Sword', 'Master Sword', 'Tempered Sword'],
|
basicsword = ['Master Sword', 'Master Sword', 'Tempered Sword'],
|
||||||
timedohko = ['Green Clock'] * 20,
|
timedohko = ['Green Clock'] * 20,
|
||||||
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
||||||
triforcehunt = ['Triforce Piece'] * 40,
|
triforcehunt = ['Triforce Piece'] * 30,
|
||||||
triforce_pieces_required = 30,
|
triforce_pieces_required = 20,
|
||||||
conditional_extras = no_conditonal_extras,
|
conditional_extras = no_conditonal_extras,
|
||||||
extras = [hardfirst20extra, hardsecond20extra, hardthird20extra, hardfinal20extra],
|
extras = [hardfirst20extra, hardsecond10extra, hardthird10extra, hardfourth10extra, hardfinal20extra],
|
||||||
progressive_sword_limit = 3,
|
progressive_sword_limit = 3,
|
||||||
progressive_shield_limit = 2,
|
progressive_shield_limit = 2,
|
||||||
progressive_armor_limit = 1,
|
progressive_armor_limit = 1,
|
||||||
|
@ -163,10 +166,10 @@ difficulties = {
|
||||||
basicsword = ['Fighter Sword', 'Master Sword', 'Master Sword'],
|
basicsword = ['Fighter Sword', 'Master Sword', 'Master Sword'],
|
||||||
timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5,
|
timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5,
|
||||||
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
||||||
triforcehunt = ['Triforce Piece'] * 40,
|
triforcehunt = ['Triforce Piece'] * 30,
|
||||||
triforce_pieces_required = 40,
|
triforce_pieces_required = 20,
|
||||||
conditional_extras = no_conditonal_extras,
|
conditional_extras = no_conditonal_extras,
|
||||||
extras = [expertfirst15extra, expertsecond25extra, expertthird15extra, expertfinal25extra],
|
extras = [expertfirst15extra, expertsecond15extra, expertthird10extra, expertfourth5extra, expertfinal25extra],
|
||||||
progressive_sword_limit = 2,
|
progressive_sword_limit = 2,
|
||||||
progressive_shield_limit = 0,
|
progressive_shield_limit = 0,
|
||||||
progressive_armor_limit = 0,
|
progressive_armor_limit = 0,
|
||||||
|
@ -186,10 +189,10 @@ difficulties = {
|
||||||
basicsword = ['Fighter Sword', 'Master Sword', 'Master Sword'],
|
basicsword = ['Fighter Sword', 'Master Sword', 'Master Sword'],
|
||||||
timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5,
|
timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5,
|
||||||
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
||||||
triforcehunt = ['Triforce Piece'] * 50,
|
triforcehunt = ['Triforce Piece'] * 30,
|
||||||
triforce_pieces_required = 50,
|
triforce_pieces_required = 20,
|
||||||
conditional_extras = no_conditonal_extras,
|
conditional_extras = no_conditonal_extras,
|
||||||
extras = [insanefirst15extra, insanesecond25extra, insanethird10extra, insanefourth15extra, insanefinal25extra],
|
extras = [insanefirst15extra, insanesecond15extra, insanethird10extra, insanefourth5extra, insanefinal25extra],
|
||||||
progressive_sword_limit = 2,
|
progressive_sword_limit = 2,
|
||||||
progressive_shield_limit = 0,
|
progressive_shield_limit = 0,
|
||||||
progressive_armor_limit = 0,
|
progressive_armor_limit = 0,
|
||||||
|
@ -213,11 +216,16 @@ def generate_itempool(world):
|
||||||
world.get_location('Agahnim 2').event = True
|
world.get_location('Agahnim 2').event = True
|
||||||
|
|
||||||
# set up item pool
|
# set up item pool
|
||||||
(pool, placed_items, clock_mode, treasure_hunt_count, treasure_hunt_icon) = get_pool_core(world.progressive, world.shuffle, world.difficulty, world.timer, world.goal, world.mode)
|
if world.custom:
|
||||||
|
(pool, placed_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle, world.difficulty, world.timer, world.goal, world.mode, world.customitemarray)
|
||||||
|
world.rupoor_cost = min(world.customitemarray[67], 9999)
|
||||||
|
else:
|
||||||
|
(pool, placed_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle, world.difficulty, world.timer, world.goal, world.mode)
|
||||||
world.itempool = ItemFactory(pool)
|
world.itempool = ItemFactory(pool)
|
||||||
for (location, item) in placed_items:
|
for (location, item) in placed_items:
|
||||||
world.push_item(location, ItemFactory(item), False)
|
world.push_item(location, ItemFactory(item), False)
|
||||||
world.get_location(location).event = True
|
world.get_location(location).event = True
|
||||||
|
world.lamps_needed_for_dark_rooms = lamps_needed_for_dark_rooms
|
||||||
if clock_mode is not None:
|
if clock_mode is not None:
|
||||||
world.clock_mode = clock_mode
|
world.clock_mode = clock_mode
|
||||||
if treasure_hunt_count is not None:
|
if treasure_hunt_count is not None:
|
||||||
|
@ -230,10 +238,10 @@ def generate_itempool(world):
|
||||||
|
|
||||||
# logic has some branches where having 4 hearts is one possible requirement (of several alternatives)
|
# logic has some branches where having 4 hearts is one possible requirement (of several alternatives)
|
||||||
# rather than making all hearts/heart pieces progression items (which slows down generation considerably)
|
# rather than making all hearts/heart pieces progression items (which slows down generation considerably)
|
||||||
# We mark one random heart container as an advancement item (or 4 heart peices in expert mode)
|
# We mark one random heart container as an advancement item (or 4 heart pieces in expert mode)
|
||||||
if world.difficulty in ['easy', 'normal', 'hard']:
|
if world.difficulty in ['easy', 'normal', 'hard'] and not (world.custom and world.customitemarray[30] == 0):
|
||||||
[item for item in world.itempool if item.name == 'Boss Heart Container'][0].advancement = True
|
[item for item in world.itempool if item.name == 'Boss Heart Container'][0].advancement = True
|
||||||
elif world.difficulty in ['expert']:
|
elif world.difficulty in ['expert'] and not (world.custom and world.customitemarray[29] < 4):
|
||||||
adv_heart_pieces = [item for item in world.itempool if item.name == 'Piece of Heart'][0:4]
|
adv_heart_pieces = [item for item in world.itempool if item.name == 'Piece of Heart'][0:4]
|
||||||
for hp in adv_heart_pieces:
|
for hp in adv_heart_pieces:
|
||||||
hp.advancement = True
|
hp.advancement = True
|
||||||
|
@ -244,14 +252,35 @@ def generate_itempool(world):
|
||||||
world.required_medallions = (mm_medallion, tr_medallion)
|
world.required_medallions = (mm_medallion, tr_medallion)
|
||||||
|
|
||||||
# distribute crystals
|
# distribute crystals
|
||||||
|
fill_prizes(world)
|
||||||
|
|
||||||
|
def fill_prizes(world, attempts=15):
|
||||||
crystals = ItemFactory(['Red Pendant', 'Blue Pendant', 'Green Pendant', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 7', 'Crystal 5', 'Crystal 6'])
|
crystals = ItemFactory(['Red Pendant', 'Blue Pendant', 'Green Pendant', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 7', 'Crystal 5', 'Crystal 6'])
|
||||||
crystal_locations = [world.get_location('Turtle Rock - Prize'), world.get_location('Eastern Palace - Prize'), world.get_location('Desert Palace - Prize'), world.get_location('Tower of Hera - Prize'), world.get_location('Palace of Darkness - Prize'),
|
crystal_locations = [world.get_location('Turtle Rock - Prize'), world.get_location('Eastern Palace - Prize'), world.get_location('Desert Palace - Prize'), world.get_location('Tower of Hera - Prize'), world.get_location('Palace of Darkness - Prize'),
|
||||||
world.get_location('Thieves Town - Prize'), world.get_location('Skull Woods - Prize'), world.get_location('Swamp Palace - Prize'), world.get_location('Ice Palace - Prize'),
|
world.get_location('Thieves Town - Prize'), world.get_location('Skull Woods - Prize'), world.get_location('Swamp Palace - Prize'), world.get_location('Ice Palace - Prize'),
|
||||||
world.get_location('Misery Mire - Prize')]
|
world.get_location('Misery Mire - Prize')]
|
||||||
|
placed_prizes = [loc.item.name for loc in crystal_locations if loc.item is not None]
|
||||||
|
unplaced_prizes = [crystal for crystal in crystals if crystal.name not in placed_prizes]
|
||||||
|
empty_crystal_locations = [loc for loc in crystal_locations if loc.item is None]
|
||||||
|
|
||||||
|
while attempts:
|
||||||
|
attempts -= 1
|
||||||
|
try:
|
||||||
|
prizepool = list(unplaced_prizes)
|
||||||
|
prize_locs = list(empty_crystal_locations)
|
||||||
|
random.shuffle(prizepool)
|
||||||
|
random.shuffle(prize_locs)
|
||||||
|
fill_restrictive(world, world.get_all_state(keys=True), prize_locs, prizepool)
|
||||||
|
except FillError:
|
||||||
|
logging.getLogger('').info("Failed to place dungeon prizes. Will retry %s more times", attempts)
|
||||||
|
for location in empty_crystal_locations:
|
||||||
|
location.item = None
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise FillError('Unable to place dungeon prizes')
|
||||||
|
|
||||||
random.shuffle(crystal_locations)
|
|
||||||
|
|
||||||
fill_restrictive(world, world.get_all_state(keys=True), crystal_locations, crystals)
|
|
||||||
|
|
||||||
|
|
||||||
def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode):
|
def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode):
|
||||||
|
@ -271,8 +300,12 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode):
|
||||||
else:
|
else:
|
||||||
pool.extend(basicgloves)
|
pool.extend(basicgloves)
|
||||||
|
|
||||||
|
lamps_needed_for_dark_rooms = 1
|
||||||
|
if difficulty == 'easy':
|
||||||
|
lamps_needed_for_dark_rooms = 3
|
||||||
|
|
||||||
# insanity shuffle doesn't have fake LW/DW logic so for now guaranteed Mirror and Moon Pearl at the start
|
# insanity shuffle doesn't have fake LW/DW logic so for now guaranteed Mirror and Moon Pearl at the start
|
||||||
if shuffle == 'insanity':
|
if shuffle == 'insanity_legacy':
|
||||||
placed_items.append(('Link\'s House', 'Magic Mirror'))
|
placed_items.append(('Link\'s House', 'Magic Mirror'))
|
||||||
placed_items.append(('Sanctuary', 'Moon Pearl'))
|
placed_items.append(('Sanctuary', 'Moon Pearl'))
|
||||||
else:
|
else:
|
||||||
|
@ -349,7 +382,149 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode):
|
||||||
|
|
||||||
if goal == 'pedestal':
|
if goal == 'pedestal':
|
||||||
placed_items.append(('Master Sword Pedestal', 'Triforce'))
|
placed_items.append(('Master Sword Pedestal', 'Triforce'))
|
||||||
return (pool, placed_items, clock_mode, treasure_hunt_count, treasure_hunt_icon)
|
return (pool, placed_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms)
|
||||||
|
|
||||||
|
def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, customitemarray):
|
||||||
|
pool = []
|
||||||
|
placed_items = []
|
||||||
|
clock_mode = None
|
||||||
|
treasure_hunt_count = None
|
||||||
|
treasure_hunt_icon = None
|
||||||
|
|
||||||
|
# Correct for insanely oversized item counts and take initial steps to handle undersized pools.
|
||||||
|
for x in range(0, 64):
|
||||||
|
if customitemarray[x] > total_items_to_place:
|
||||||
|
customitemarray[x] = total_items_to_place
|
||||||
|
if customitemarray[66] > total_items_to_place:
|
||||||
|
customitemarray[66] = total_items_to_place
|
||||||
|
itemtotal = 0
|
||||||
|
for x in range(0, 65):
|
||||||
|
itemtotal = itemtotal + customitemarray[x]
|
||||||
|
itemtotal = itemtotal + customitemarray[66]
|
||||||
|
|
||||||
|
pool.extend(['Bow'] * customitemarray[0])
|
||||||
|
pool.extend(['Silver Arrows']* customitemarray[1])
|
||||||
|
pool.extend(['Blue Boomerang'] * customitemarray[2])
|
||||||
|
pool.extend(['Red Boomerang'] * customitemarray[3])
|
||||||
|
pool.extend(['Hookshot'] * customitemarray[4])
|
||||||
|
pool.extend(['Mushroom'] * customitemarray[5])
|
||||||
|
pool.extend(['Magic Powder'] * customitemarray[6])
|
||||||
|
pool.extend(['Fire Rod'] * customitemarray[7])
|
||||||
|
pool.extend(['Ice Rod'] * customitemarray[8])
|
||||||
|
pool.extend(['Bombos'] * customitemarray[9])
|
||||||
|
pool.extend(['Ether'] * customitemarray[10])
|
||||||
|
pool.extend(['Quake'] * customitemarray[11])
|
||||||
|
pool.extend(['Lamp'] * customitemarray[12])
|
||||||
|
pool.extend(['Hammer'] * customitemarray[13])
|
||||||
|
pool.extend(['Shovel'] * customitemarray[14])
|
||||||
|
pool.extend(['Ocarina'] * customitemarray[15])
|
||||||
|
pool.extend(['Bug Catching Net'] * customitemarray[16])
|
||||||
|
pool.extend(['Book of Mudora'] * customitemarray[17])
|
||||||
|
pool.extend(['Cane of Somaria'] * customitemarray[19])
|
||||||
|
pool.extend(['Cane of Byrna'] * customitemarray[20])
|
||||||
|
pool.extend(['Cape'] * customitemarray[21])
|
||||||
|
pool.extend(['Pegasus Boots'] * customitemarray[23])
|
||||||
|
pool.extend(['Power Glove'] * customitemarray[24])
|
||||||
|
pool.extend(['Titans Mitts'] * customitemarray[25])
|
||||||
|
pool.extend(['Progressive Glove'] * customitemarray[26])
|
||||||
|
pool.extend(['Flippers'] * customitemarray[27])
|
||||||
|
pool.extend(['Piece of Heart'] * customitemarray[29])
|
||||||
|
pool.extend(['Boss Heart Container'] * customitemarray[30])
|
||||||
|
pool.extend(['Sanctuary Heart Container'] * customitemarray[31])
|
||||||
|
pool.extend(['Master Sword'] * customitemarray[33])
|
||||||
|
pool.extend(['Tempered Sword'] * customitemarray[34])
|
||||||
|
pool.extend(['Golden Sword'] * customitemarray[35])
|
||||||
|
pool.extend(['Blue Shield'] * customitemarray[37])
|
||||||
|
pool.extend(['Red Shield'] * customitemarray[38])
|
||||||
|
pool.extend(['Mirror Shield'] * customitemarray[39])
|
||||||
|
pool.extend(['Progressive Shield'] * customitemarray[40])
|
||||||
|
pool.extend(['Blue Mail'] * customitemarray[41])
|
||||||
|
pool.extend(['Red Mail'] * customitemarray[42])
|
||||||
|
pool.extend(['Progressive Armor'] * customitemarray[43])
|
||||||
|
pool.extend(['Magic Upgrade (1/2)'] * customitemarray[44])
|
||||||
|
pool.extend(['Magic Upgrade (1/4)'] * customitemarray[45])
|
||||||
|
pool.extend(['Bomb Upgrade (+5)'] * customitemarray[46])
|
||||||
|
pool.extend(['Bomb Upgrade (+10)'] * customitemarray[47])
|
||||||
|
pool.extend(['Arrow Upgrade (+5)'] * customitemarray[48])
|
||||||
|
pool.extend(['Arrow Upgrade (+10)'] * customitemarray[49])
|
||||||
|
pool.extend(['Single Arrow'] * customitemarray[50])
|
||||||
|
pool.extend(['Arrows (10)'] * customitemarray[51])
|
||||||
|
pool.extend(['Single Bomb'] * customitemarray[52])
|
||||||
|
pool.extend(['Bombs (3)'] * customitemarray[53])
|
||||||
|
pool.extend(['Rupee (1)'] * customitemarray[54])
|
||||||
|
pool.extend(['Rupees (5)'] * customitemarray[55])
|
||||||
|
pool.extend(['Rupees (20)'] * customitemarray[56])
|
||||||
|
pool.extend(['Rupees (50)'] * customitemarray[57])
|
||||||
|
pool.extend(['Rupees (100)'] * customitemarray[58])
|
||||||
|
pool.extend(['Rupees (300)'] * customitemarray[59])
|
||||||
|
pool.extend(['Rupoor'] * customitemarray[60])
|
||||||
|
pool.extend(['Blue Clock'] * customitemarray[61])
|
||||||
|
pool.extend(['Green Clock'] * customitemarray[62])
|
||||||
|
pool.extend(['Red Clock'] * customitemarray[63])
|
||||||
|
pool.extend(['Triforce Piece'] * customitemarray[64])
|
||||||
|
pool.extend(['Triforce'] * customitemarray[66])
|
||||||
|
|
||||||
|
diff = difficulties[difficulty]
|
||||||
|
|
||||||
|
lamps_needed_for_dark_rooms = 1
|
||||||
|
if difficulty == 'easy':
|
||||||
|
lamps_needed_for_dark_rooms = customitemarray[12]
|
||||||
|
|
||||||
|
# expert+ difficulties produce the same contents for
|
||||||
|
# all bottles, since only one bottle is available
|
||||||
|
if diff.same_bottle:
|
||||||
|
thisbottle = random.choice(diff.bottles)
|
||||||
|
for _ in range(customitemarray[18]):
|
||||||
|
if not diff.same_bottle:
|
||||||
|
thisbottle = random.choice(diff.bottles)
|
||||||
|
pool.append(thisbottle)
|
||||||
|
|
||||||
|
if customitemarray[64] > 0 or customitemarray[65] > 0:
|
||||||
|
treasure_hunt_count = max(min(customitemarray[65], 99), 1) #To display, count must be between 1 and 99.
|
||||||
|
treasure_hunt_icon = 'Triforce Piece'
|
||||||
|
# Ensure game is always possible to complete here, force sufficient pieces if the player is unwilling.
|
||||||
|
if (customitemarray[64] < treasure_hunt_count) and (goal == 'triforcehunt') and (customitemarray[66] == 0):
|
||||||
|
extrapieces = treasure_hunt_count - customitemarray[64]
|
||||||
|
pool.extend(['Triforce Piece'] * extrapieces)
|
||||||
|
itemtotal = itemtotal + extrapieces
|
||||||
|
|
||||||
|
if timer in ['display', 'timed', 'timed-countdown']:
|
||||||
|
clock_mode = 'countdown' if timer == 'timed-countdown' else 'stopwatch'
|
||||||
|
elif timer == 'timed-ohko':
|
||||||
|
clock_mode = 'countdown-ohko'
|
||||||
|
elif timer == 'ohko':
|
||||||
|
clock_mode = 'ohko'
|
||||||
|
|
||||||
|
if goal == 'pedestal':
|
||||||
|
placed_items.append(('Master Sword Pedestal', 'Triforce'))
|
||||||
|
itemtotal = itemtotal + 1
|
||||||
|
|
||||||
|
if mode == 'standard':
|
||||||
|
if progressive == 'off':
|
||||||
|
placed_items.append(('Link\'s Uncle', 'Fighter Sword'))
|
||||||
|
pool.extend(['Fighter Sword'] * max((customitemarray[32] - 1), 0))
|
||||||
|
pool.extend(['Progressive Sword'] * customitemarray[36])
|
||||||
|
else:
|
||||||
|
placed_items.append(('Link\'s Uncle', 'Progressive Sword'))
|
||||||
|
pool.extend(['Fighter Sword'] * customitemarray[32])
|
||||||
|
pool.extend(['Progressive Sword'] * max((customitemarray[36] - 1), 0))
|
||||||
|
else:
|
||||||
|
pool.extend(['Fighter Sword'] * customitemarray[32])
|
||||||
|
pool.extend(['Progressive Sword'] * customitemarray[36])
|
||||||
|
|
||||||
|
if shuffle == 'insanity_legacy':
|
||||||
|
placed_items.append(('Link\'s House', 'Magic Mirror'))
|
||||||
|
placed_items.append(('Sanctuary', 'Moon Pearl'))
|
||||||
|
pool.extend(['Magic Mirror'] * max((customitemarray[22] -1 ), 0))
|
||||||
|
pool.extend(['Moon Pearl'] * max((customitemarray[28] - 1), 0))
|
||||||
|
else:
|
||||||
|
pool.extend(['Magic Mirror'] * customitemarray[22])
|
||||||
|
pool.extend(['Moon Pearl'] * customitemarray[28])
|
||||||
|
|
||||||
|
if itemtotal < total_items_to_place:
|
||||||
|
pool.extend(['Nothing'] * (total_items_to_place - itemtotal))
|
||||||
|
|
||||||
|
return (pool, placed_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms)
|
||||||
|
|
||||||
# A quick test to ensure all combinations generate the correct amount of items.
|
# A quick test to ensure all combinations generate the correct amount of items.
|
||||||
def test():
|
def test():
|
||||||
|
|
2
Items.py
2
Items.py
|
@ -72,7 +72,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 'You have\nchosen the\narcher cla
|
||||||
'Crystal 5': (True, False, 'Crystal', [0x04, 0x32, 0x64, 0x40, 0x6E, 0x06], None, None, None, None, None, None),
|
'Crystal 5': (True, False, 'Crystal', [0x04, 0x32, 0x64, 0x40, 0x6E, 0x06], None, None, None, None, None, None),
|
||||||
'Crystal 6': (True, False, 'Crystal', [0x01, 0x32, 0x64, 0x40, 0x6F, 0x06], None, None, None, None, None, None),
|
'Crystal 6': (True, False, 'Crystal', [0x01, 0x32, 0x64, 0x40, 0x6F, 0x06], None, None, None, None, None, None),
|
||||||
'Crystal 7': (True, False, 'Crystal', [0x08, 0x34, 0x64, 0x40, 0x7C, 0x06], None, None, None, None, None, None),
|
'Crystal 7': (True, False, 'Crystal', [0x08, 0x34, 0x64, 0x40, 0x7C, 0x06], None, None, None, None, None, None),
|
||||||
'Single Arrow': (False, False, None, 0x43, 'a lonely arrow\nsits here.', 'and the arrow', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrow', 'archer boy sews again'),
|
'Single Arrow': (False, False, None, 0x43, 'a lonely arrow\nsits here.', 'and the arrow', 'stick-collecting kid', 'sewing needle for sale', 'fungus for arrow', 'archer boy sews again'),
|
||||||
'Arrows (10)': (False, False, None, 0x44, 'This will give\nyou ten shots\nwith your bow!', 'and the arrow pack', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again'),
|
'Arrows (10)': (False, False, None, 0x44, 'This will give\nyou ten shots\nwith your bow!', 'and the arrow pack', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again'),
|
||||||
'Arrow Upgrade (+10)': (False, False, None, 0x54, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again'),
|
'Arrow Upgrade (+10)': (False, False, None, 0x54, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again'),
|
||||||
'Arrow Upgrade (+5)': (False, False, None, 0x53, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again'),
|
'Arrow Upgrade (+5)': (False, False, None, 0x53, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again'),
|
||||||
|
|
56
Main.py
56
Main.py
|
@ -15,31 +15,31 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute
|
||||||
from ItemList import generate_itempool, difficulties
|
from ItemList import generate_itempool, difficulties
|
||||||
from Utils import output_path
|
from Utils import output_path
|
||||||
|
|
||||||
__version__ = '0.5.2.1-dev'
|
__version__ = '0.6.0'
|
||||||
|
|
||||||
logic_hash = [85, 160, 173, 64, 16, 14, 97, 193, 219, 26, 11, 156, 198, 142, 213, 141,
|
logic_hash = [26, 76, 4, 144, 72, 105, 234, 233, 12, 184, 95, 94, 100, 13, 15, 174,
|
||||||
55, 60, 32, 174, 77, 128, 147, 3, 1, 118, 74, 50, 243, 6, 251, 36,
|
186, 135, 130, 189, 246, 254, 123, 245, 85, 241, 101, 129, 70, 255, 55, 248,
|
||||||
194, 65, 217, 120, 94, 150, 108, 99, 222, 233, 96, 70, 225, 236, 103, 21,
|
43, 146, 23, 179, 243, 208, 230, 176, 9, 88, 239, 226, 222, 203, 244, 183,
|
||||||
241, 138, 144, 95, 164, 62, 183, 25, 203, 33, 240, 228, 224, 181, 176, 155,
|
205, 74, 44, 5, 122, 220, 206, 47, 221, 125, 138, 155, 98, 79, 238, 119,
|
||||||
247, 151, 140, 24, 221, 53, 83, 37, 71, 195, 188, 184, 90, 61, 13, 154,
|
30, 24, 159, 39, 253, 27, 33, 218, 62, 82, 200, 28, 141, 191, 93, 22,
|
||||||
57, 230, 179, 45, 23, 59, 238, 130, 121, 5, 165, 38, 216, 136, 199, 132,
|
192, 54, 227, 108, 48, 78, 242, 166, 60, 250, 75, 145, 49, 212, 41, 25,
|
||||||
255, 34, 212, 208, 227, 126, 226, 104, 98, 75, 166, 158, 40, 234, 111, 72,
|
127, 89, 178, 157, 19, 158, 177, 231, 207, 66, 172, 17, 133, 61, 109, 86,
|
||||||
58, 133, 157, 252, 192, 84, 152, 116, 177, 124, 190, 46, 214, 8, 10, 81,
|
57, 143, 142, 219, 148, 209, 181, 87, 163, 40, 81, 114, 240, 103, 31, 175,
|
||||||
244, 67, 182, 2, 0, 237, 145, 80, 7, 197, 137, 168, 102, 235, 204, 91,
|
237, 185, 18, 173, 168, 45, 216, 106, 161, 16, 151, 139, 104, 134, 110, 21,
|
||||||
69, 9, 100, 139, 54, 172, 232, 105, 162, 115, 242, 170, 169, 254, 20, 117,
|
32, 131, 118, 182, 215, 67, 3, 73, 171, 71, 150, 147, 223, 247, 42, 132,
|
||||||
180, 220, 191, 110, 93, 163, 223, 185, 211, 210, 39, 47, 114, 207, 73, 146,
|
107, 149, 232, 153, 10, 201, 156, 225, 116, 194, 187, 204, 46, 165, 124, 92,
|
||||||
112, 12, 78, 4, 88, 171, 106, 87, 127, 123, 41, 178, 43, 201, 202, 167,
|
7, 0, 251, 126, 162, 80, 90, 154, 252, 197, 188, 52, 137, 117, 198, 63,
|
||||||
35, 30, 122, 44, 209, 19, 249, 18, 113, 186, 49, 52, 161, 86, 200, 149,
|
167, 38, 136, 96, 58, 11, 1, 115, 229, 224, 37, 112, 170, 59, 68, 196,
|
||||||
218, 107, 29, 27, 135, 159, 66, 17, 131, 129, 76, 250, 15, 248, 82, 239,
|
36, 64, 91, 213, 14, 180, 190, 164, 8, 56, 214, 77, 202, 193, 97, 84,
|
||||||
68, 63, 143, 28, 153, 48, 101, 119, 51, 31, 215, 42, 187, 92, 109, 245,
|
152, 83, 236, 211, 20, 217, 2, 228, 140, 69, 121, 111, 113, 128, 210, 51,
|
||||||
22, 56, 89, 206, 148, 229, 175, 134, 189, 205, 79, 196, 246, 253, 231, 125]
|
53, 6, 235, 34, 102, 29, 120, 35, 50, 65, 160, 249, 99, 169, 199, 195]
|
||||||
|
|
||||||
|
|
||||||
def main(args, seed=None):
|
def main(args, seed=None):
|
||||||
start = time.clock()
|
start = time.clock()
|
||||||
|
|
||||||
# initialize the world
|
# initialize the world
|
||||||
world = World(args.shuffle, args.logic, args.mode, args.difficulty, args.timer, args.progressive, args.goal, args.algorithm, not args.nodungeonitems, args.beatableonly, args.shuffleganon, args.quickswap, args.fastmenu, args.disablemusic, args.keysanity)
|
world = World(args.shuffle, args.logic, args.mode, args.difficulty, args.timer, args.progressive, args.goal, args.algorithm, not args.nodungeonitems, args.beatableonly, args.shuffleganon, args.quickswap, args.fastmenu, args.disablemusic, args.keysanity, args.custom, args.customitemarray)
|
||||||
logger = logging.getLogger('')
|
logger = logging.getLogger('')
|
||||||
if seed is None:
|
if seed is None:
|
||||||
random.seed(None)
|
random.seed(None)
|
||||||
|
@ -92,9 +92,10 @@ def main(args, seed=None):
|
||||||
elif args.algorithm == 'vt25':
|
elif args.algorithm == 'vt25':
|
||||||
distribute_items_restrictive(world, 0)
|
distribute_items_restrictive(world, 0)
|
||||||
elif args.algorithm == 'vt26':
|
elif args.algorithm == 'vt26':
|
||||||
distribute_items_restrictive(world, random.randint(0, 15), shuffled_locations)
|
|
||||||
|
distribute_items_restrictive(world, gt_filler(world), shuffled_locations)
|
||||||
elif args.algorithm == 'balanced':
|
elif args.algorithm == 'balanced':
|
||||||
distribute_items_restrictive(world, random.randint(0, 15))
|
distribute_items_restrictive(world, gt_filler(world))
|
||||||
|
|
||||||
logger.info('Calculating playthrough.')
|
logger.info('Calculating playthrough.')
|
||||||
|
|
||||||
|
@ -117,7 +118,7 @@ def main(args, seed=None):
|
||||||
rom = JsonRom()
|
rom = JsonRom()
|
||||||
else:
|
else:
|
||||||
rom = LocalRom(args.rom)
|
rom = LocalRom(args.rom)
|
||||||
patch_rom(world, rom, bytearray(logic_hash), args.heartbeep, sprite)
|
patch_rom(world, rom, bytearray(logic_hash), args.heartbeep, args.heartcolor, sprite)
|
||||||
if args.jsonout:
|
if args.jsonout:
|
||||||
print(json.dumps({'patch': rom.patches, 'spoiler': world.spoiler.to_json()}))
|
print(json.dumps({'patch': rom.patches, 'spoiler': world.spoiler.to_json()}))
|
||||||
else:
|
else:
|
||||||
|
@ -131,9 +132,14 @@ def main(args, seed=None):
|
||||||
|
|
||||||
return world
|
return world
|
||||||
|
|
||||||
|
def gt_filler(world):
|
||||||
|
if world.goal == 'triforcehunt':
|
||||||
|
return random.randint(15, 50)
|
||||||
|
return random.randint(0, 15)
|
||||||
|
|
||||||
def copy_world(world):
|
def copy_world(world):
|
||||||
# ToDo: Not good yet
|
# ToDo: Not good yet
|
||||||
ret = World(world.shuffle, world.logic, world.mode, world.difficulty, world.timer, world.progressive, world.goal, world.algorithm, world.place_dungeon_items, world.check_beatable_only, world.shuffle_ganon, world.quickswap, world.fastmenu, world.disable_music, world.keysanity)
|
ret = World(world.shuffle, world.logic, world.mode, world.difficulty, world.timer, world.progressive, world.goal, world.algorithm, world.place_dungeon_items, world.check_beatable_only, world.shuffle_ganon, world.quickswap, world.fastmenu, world.disable_music, world.keysanity, world.custom, world.customitemarray)
|
||||||
ret.required_medallions = list(world.required_medallions)
|
ret.required_medallions = list(world.required_medallions)
|
||||||
ret.swamp_patch_required = world.swamp_patch_required
|
ret.swamp_patch_required = world.swamp_patch_required
|
||||||
ret.ganon_at_pyramid = world.ganon_at_pyramid
|
ret.ganon_at_pyramid = world.ganon_at_pyramid
|
||||||
|
@ -146,6 +152,8 @@ def copy_world(world):
|
||||||
ret.can_access_trock_eyebridge = world.can_access_trock_eyebridge
|
ret.can_access_trock_eyebridge = world.can_access_trock_eyebridge
|
||||||
ret.can_take_damage = world.can_take_damage
|
ret.can_take_damage = world.can_take_damage
|
||||||
ret.difficulty_requirements = world.difficulty_requirements
|
ret.difficulty_requirements = world.difficulty_requirements
|
||||||
|
ret.fix_fake_world = world.fix_fake_world
|
||||||
|
ret.lamps_needed_for_dark_rooms = world.lamps_needed_for_dark_rooms
|
||||||
create_regions(ret)
|
create_regions(ret)
|
||||||
create_dungeons(ret)
|
create_dungeons(ret)
|
||||||
|
|
||||||
|
@ -153,6 +161,7 @@ def copy_world(world):
|
||||||
for region in world.regions:
|
for region in world.regions:
|
||||||
copied_region = ret.get_region(region.name)
|
copied_region = ret.get_region(region.name)
|
||||||
copied_region.is_light_world = region.is_light_world
|
copied_region.is_light_world = region.is_light_world
|
||||||
|
copied_region.is_dark_world = region.is_dark_world
|
||||||
for entrance in region.entrances:
|
for entrance in region.entrances:
|
||||||
ret.get_entrance(entrance.name).connect(copied_region)
|
ret.get_entrance(entrance.name).connect(copied_region)
|
||||||
|
|
||||||
|
@ -285,7 +294,8 @@ def create_playthrough(world):
|
||||||
old_world.spoiler.paths = {location.name : get_path(state, location.parent_region) for sphere in collection_spheres for location in sphere}
|
old_world.spoiler.paths = {location.name : get_path(state, location.parent_region) for sphere in collection_spheres for location in sphere}
|
||||||
if any(exit == 'Pyramid Fairy' for path in old_world.spoiler.paths.values() for (_, exit) in path):
|
if any(exit == 'Pyramid Fairy' for path in old_world.spoiler.paths.values() for (_, exit) in path):
|
||||||
old_world.spoiler.paths['Big Bomb Shop'] = get_path(state, world.get_region('Big Bomb Shop'))
|
old_world.spoiler.paths['Big Bomb Shop'] = get_path(state, world.get_region('Big Bomb Shop'))
|
||||||
print(world.seed)
|
if any(exit == 'Swamp Palace Moat' for path in old_world.spoiler.paths.values() for (_, exit) in path) or 'Sunken Treasure' in old_world.required_locations:
|
||||||
|
old_world.spoiler.paths['Dam'] = get_path(state, world.get_region('Dam'))
|
||||||
|
|
||||||
# we can finally output our playthrough
|
# we can finally output our playthrough
|
||||||
old_world.spoiler.playthrough = OrderedDict([(str(i + 1), {str(location): str(location.item) for location in sphere}) for i, sphere in enumerate(collection_spheres)])
|
old_world.spoiler.playthrough = OrderedDict([(str(i + 1), {str(location): str(location.item) for location in sphere}) for i, sphere in enumerate(collection_spheres)])
|
||||||
|
|
|
@ -33,7 +33,7 @@ def main(args):
|
||||||
start_time = time.clock()
|
start_time = time.clock()
|
||||||
|
|
||||||
# initialize the world
|
# initialize the world
|
||||||
world = World('vanilla', 'noglitches', 'standard', 'normal', 'none', 'on', 'ganon', 'freshness', False, False, False, args.quickswap, args.fastmenu, args.disablemusic, False)
|
world = World('vanilla', 'noglitches', 'standard', 'normal', 'none', 'on', 'ganon', 'freshness', False, False, False, args.quickswap, args.fastmenu, args.disablemusic, False, False, None)
|
||||||
logger = logging.getLogger('')
|
logger = logging.getLogger('')
|
||||||
|
|
||||||
hasher = hashlib.md5()
|
hasher = hashlib.md5()
|
||||||
|
@ -84,7 +84,7 @@ def main(args):
|
||||||
sprite = None
|
sprite = None
|
||||||
|
|
||||||
rom = LocalRom(args.rom)
|
rom = LocalRom(args.rom)
|
||||||
patch_rom(world, rom, logic_hash, args.heartbeep, sprite)
|
patch_rom(world, rom, logic_hash, args.heartbeep, args.heartcolor, sprite)
|
||||||
|
|
||||||
for textname, texttype, text in text_patches:
|
for textname, texttype, text in text_patches:
|
||||||
if texttype == 'text':
|
if texttype == 'text':
|
||||||
|
@ -219,6 +219,8 @@ def start():
|
||||||
parser.add_argument('--disablemusic', help='Disables game music.', action='store_true')
|
parser.add_argument('--disablemusic', help='Disables game music.', action='store_true')
|
||||||
parser.add_argument('--heartbeep', default='normal', const='normal', nargs='?', choices=['normal', 'half', 'quarter', 'off'],
|
parser.add_argument('--heartbeep', default='normal', const='normal', nargs='?', choices=['normal', 'half', 'quarter', 'off'],
|
||||||
help='Select the rate at which the heart beep sound is played at low health.')
|
help='Select the rate at which the heart beep sound is played at low health.')
|
||||||
|
parser.add_argument('--heartcolor', default='red', const='red', nargs='?', choices=['red', 'blue', 'green', 'yellow'],
|
||||||
|
help='Select the color of Link\'s heart meter. (default: %(default)s)')
|
||||||
parser.add_argument('--sprite', help='Path to a sprite sheet to use for Link. Needs to be in binary format and have a length of 0x7000 (28672) bytes.')
|
parser.add_argument('--sprite', help='Path to a sprite sheet to use for Link. Needs to be in binary format and have a length of 0x7000 (28672) bytes.')
|
||||||
parser.add_argument('--plando', help='Filled out template to use for setting up the rom.')
|
parser.add_argument('--plando', help='Filled out template to use for setting up the rom.')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
61
README.md
61
README.md
|
@ -71,25 +71,20 @@ Ganon cannot be damaged until all dungeons (including Hyrule Castle Tower and Ga
|
||||||
### Triforce Hunt
|
### Triforce Hunt
|
||||||
|
|
||||||
Triforce Pieces are added to the item pool, and some number of them being found will trigger game completion. Ganon cannot be damaged.
|
Triforce Pieces are added to the item pool, and some number of them being found will trigger game completion. Ganon cannot be damaged.
|
||||||
Counts are based on the difficulty setting as well as the required number.
|
By default 30 Triforce Pieces are placed while 20 are needed to beat the game. Both values can be adjusted with the custom item pool feature.
|
||||||
Difficulty Need/Total
|
|
||||||
Easy 10/30
|
|
||||||
Normal 20/30
|
|
||||||
Hard 30/40
|
|
||||||
Expert 40/40
|
|
||||||
Insane 50/50
|
|
||||||
|
|
||||||
### Crystals
|
### Crystals
|
||||||
|
|
||||||
Standard game completion requiring you to collect the 7 crystals and then beat Ganon.
|
Standard game completion requiring you to collect the 7 crystals and then beat Ganon.
|
||||||
|
|
||||||
This is only noticeably different if the --shuffleganon option is enabled.
|
This is only noticeably different if the the Ganon shuffle option is enabled.
|
||||||
|
|
||||||
## Game Difficulty
|
## Game Difficulty
|
||||||
|
|
||||||
### Easy
|
### Easy
|
||||||
|
|
||||||
This setting doubles the number of swords, shields, armors, and bottles in the item pool.
|
This setting doubles the number of swords, shields, armors, bottles, and silver arrows in the item pool.
|
||||||
|
This setting will also triple the number of Lamps available, and all will be obtainable before dark rooms.
|
||||||
Within dungeons, the number of items found will be displayed on screen if there is no timer.
|
Within dungeons, the number of items found will be displayed on screen if there is no timer.
|
||||||
|
|
||||||
### Normal
|
### Normal
|
||||||
|
@ -204,32 +199,38 @@ staleness, decreasing the likelihood of receiving a progress item.
|
||||||
|
|
||||||
## Entrance Shuffle Algorithm
|
## Entrance Shuffle Algorithm
|
||||||
|
|
||||||
Determines how locations are shuffled.
|
Determines how locations are shuffled. In all modes other than Insanity and the similar legacy versions, holes shuffle as a pair with the connecting cave and the front
|
||||||
|
two sections of Skull Woods remain confined to the general Skull Woods area. Link's house is never shuffled as a design decision.
|
||||||
|
|
||||||
### Default
|
### Vanilla
|
||||||
|
|
||||||
Is the Vanilla layout.
|
Places entrances in the same locations they were in the original The Legend of Zelda: A Link to the Past.
|
||||||
|
|
||||||
### Simple
|
### Simple
|
||||||
|
|
||||||
Shuffles Dungeon Entrances/Exits between each other and keeps all 4-entrance dungeons confined to one location. Outside Light World Death Mountain, interiors are shuffled but still connect the same points
|
Shuffles dungeon entrances between each other and keeps all 4-entrance dungeons confined to one location such that dungeons will one to one swap with each other.
|
||||||
on the overworld. On Death Mountain, entrances are connected more freely.
|
Other than on Light World Death Mountain, interiors are shuffled but still connect the same points on the overworld. On Death Mountain, entrances are connected more freely.
|
||||||
|
|
||||||
### Full
|
|
||||||
|
|
||||||
Mixes cave and dungeon entrances freely.
|
|
||||||
|
|
||||||
### Restricted
|
### Restricted
|
||||||
|
|
||||||
Uses Dungeons shuffling from Simple but freely connects remaining entrances.
|
Uses dungeon shuffling from Simple but freely connects remaining entrances. Caves and dungeons with multiple entrances will be confined to one world.
|
||||||
|
|
||||||
### Madness
|
### Full
|
||||||
|
|
||||||
Decouples entrances and exits from each other and shuffles them freely, only ensuring that no fake Light/Dark World happens and all locations are reachable.
|
Mixes cave and dungeon entrances freely. Caves and dungeons with multiple entrances will be confined to one world.
|
||||||
|
|
||||||
|
### Crossed
|
||||||
|
|
||||||
|
Mixes cave and dungeon entrances freely, but now connector caves and dungeons can link Light World and Dark World.
|
||||||
|
|
||||||
### Insanity
|
### Insanity
|
||||||
|
|
||||||
Madness, but without the light/dark world restrictions. Gives access to Mirror and Moon Pearl from the start.
|
Decouples entrances and exits from each other and shuffles them freely. Caves that were single entrance in vanilla still can only exit to the same location from which they were entered.
|
||||||
|
|
||||||
|
### Legacy Variants
|
||||||
|
|
||||||
|
Similar to the base shuffles, but the distinction between single entrance and multi-entrance caves from older versions of the randomizer is maintained.
|
||||||
|
Madness_Legacy is the more similar to the modern Insanity. Insanity_Legacy has fake worlds and guaranteed Moon Pearl and Magic Mirror for a very different experience.
|
||||||
|
|
||||||
### Dungeon Variants
|
### Dungeon Variants
|
||||||
|
|
||||||
|
@ -239,6 +240,10 @@ The dungeon variants only mix up dungeons and keep the rest of the overworld van
|
||||||
|
|
||||||
Select frequency of beeps when on low health. Can completely disable them.
|
Select frequency of beeps when on low health. Can completely disable them.
|
||||||
|
|
||||||
|
## Heart Color
|
||||||
|
|
||||||
|
Select the color of Link's hearts.
|
||||||
|
|
||||||
## Menu Speed
|
## Menu Speed
|
||||||
|
|
||||||
A setting that lets the player set the rate at which the menu opens and closes.
|
A setting that lets the player set the rate at which the menu opens and closes.
|
||||||
|
@ -275,7 +280,13 @@ If set, will only ensure the goal can be achieved, but not necessarily that all
|
||||||
|
|
||||||
## Include Ganon's Tower and Pyramid Hole in Shuffle pool
|
## Include Ganon's Tower and Pyramid Hole in Shuffle pool
|
||||||
|
|
||||||
If set, Ganon's Tower is included in the dungeon shuffle pool and the Pyramid Hole/Exit pair is included in the Holes shuffle pool. Ganon can not be defeated until the primary goal is fulfilled. This setting removes any bias against Ganon's Tower that some algorithms may have.
|
If set, Ganon's Tower is included in the dungeon shuffle pool and the Pyramid Hole/Exit pair is included in the Holes shuffle pool. Ganon can not be defeated until the primary goal is fulfilled.
|
||||||
|
This setting removes any bias against Ganon's Tower that some algorithms may have.
|
||||||
|
|
||||||
|
## Use Custom Item Pool
|
||||||
|
|
||||||
|
If set, the item pool normally associated with your difficulty setting is replaced by the item pool specified in the custom tab. This feature is only supported when the randomizer is run
|
||||||
|
via the GUI; attempting to set this via the command line does nothing.
|
||||||
|
|
||||||
## Seed
|
## Seed
|
||||||
|
|
||||||
|
@ -422,10 +433,10 @@ Use to select a different sprite sheet to use for Link. Path to a binary file of
|
||||||
Enables the "Only Ensure Seed Beatable" option (default: False)
|
Enables the "Only Ensure Seed Beatable" option (default: False)
|
||||||
|
|
||||||
```
|
```
|
||||||
--shuffleganon
|
--no-shuffleganon
|
||||||
```
|
```
|
||||||
|
|
||||||
Enables the "Include Ganon's Tower and Pyramid Hole in Shuffle pool" option. (default: false)
|
Disables the "Include Ganon's Tower and Pyramid Hole in Shuffle pool" option. (default: Enabled)
|
||||||
|
|
||||||
```
|
```
|
||||||
--suppress_rom
|
--suppress_rom
|
||||||
|
|
587
Regions.py
587
Regions.py
|
@ -1,280 +1,311 @@
|
||||||
import collections
|
import collections
|
||||||
from BaseClasses import Region, Location, Entrance
|
from BaseClasses import Region, Location, Entrance, RegionType
|
||||||
|
|
||||||
|
|
||||||
def create_regions(world):
|
def create_regions(world):
|
||||||
|
|
||||||
world.regions = [
|
world.regions = [
|
||||||
create_region('Light World', ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest'],
|
create_lw_region('Light World', ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest'],
|
||||||
["Blinds Hideout", "Hyrule Castle Secret Entrance Drop", 'Zoras River', 'Kings Grave', 'Dam',
|
["Blinds Hideout", "Hyrule Castle Secret Entrance Drop", 'Zoras River', 'Kings Grave Outer Rocks', 'Dam',
|
||||||
'Links House', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave',
|
'Links House', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave',
|
||||||
'Blacksmiths Hut', 'Bat Cave Drop Ledge', 'Bat Cave Cave', 'Sick Kids House', 'Hobo Bridge', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump',
|
'Blacksmiths Hut', 'Bat Cave Drop Ledge', 'Bat Cave Cave', 'Sick Kids House', 'Hobo Bridge', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump',
|
||||||
'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Lake Hylia Central Island Pier',
|
'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Lake Hylia Central Island Pier',
|
||||||
'Bonk Rock Cave', 'Library', 'Potion Shop', 'Two Brothers House (East)', 'Desert Palace Stairs', 'Eastern Palace', 'Master Sword Meadow',
|
'Bonk Rock Cave', 'Library', 'Potion Shop', 'Two Brothers House (East)', 'Desert Palace Stairs', 'Eastern Palace', 'Master Sword Meadow',
|
||||||
'Sanctuary', 'Sanctuary Grave', 'Old Man Cave (West)', 'Flute Spot 1', 'Dark Desert Teleporter', 'East Hyrule Teleporter', 'South Hyrule Teleporter', 'Kakariko Teleporter',
|
'Sanctuary', 'Sanctuary Grave', 'Death Mountain Entrance Rock', 'Flute Spot 1', 'Dark Desert Teleporter', 'East Hyrule Teleporter', 'South Hyrule Teleporter', 'Kakariko Teleporter',
|
||||||
'Elder House (East)', 'Elder House (West)', 'North Fairy Cave', 'North Fairy Cave Drop', 'Lost Woods Gamble', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Tavern (Front)',
|
'Elder House (East)', 'Elder House (West)', 'North Fairy Cave', 'North Fairy Cave Drop', 'Lost Woods Gamble', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Tavern (Front)',
|
||||||
'Bush Covered House', 'Light World Bomb Hut', 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Cave Shop (Lake Hylia)', 'Waterfall of Wishing', 'Hyrule Castle Main Gate',
|
'Bush Covered House', 'Light World Bomb Hut', 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Cave Shop (Lake Hylia)', 'Waterfall of Wishing', 'Hyrule Castle Main Gate',
|
||||||
'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Swamp Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Top of Pyramid']),
|
'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Top of Pyramid']),
|
||||||
create_region('Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Teleporter']),
|
create_lw_region('Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop']),
|
||||||
create_region('Blinds Hideout', ["Blind\'s Hideout - Top",
|
create_lw_region('Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Teleporter']),
|
||||||
"Blind\'s Hideout - Left",
|
create_cave_region('Blinds Hideout', ["Blind\'s Hideout - Top",
|
||||||
"Blind\'s Hideout - Right",
|
"Blind\'s Hideout - Left",
|
||||||
"Blind\'s Hideout - Far Left",
|
"Blind\'s Hideout - Right",
|
||||||
"Blind\'s Hideout - Far Right"]),
|
"Blind\'s Hideout - Far Left",
|
||||||
create_region('Hyrule Castle Secret Entrance', ['Link\'s Uncle', 'Secret Passage'], ['Hyrule Castle Secret Entrance Exit']),
|
"Blind\'s Hideout - Far Right"]),
|
||||||
create_region('Zoras River', ['King Zora', 'Zora\'s Ledge']),
|
create_cave_region('Hyrule Castle Secret Entrance', ['Link\'s Uncle', 'Secret Passage'], ['Hyrule Castle Secret Entrance Exit']),
|
||||||
create_region('Waterfall of Wishing', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']),
|
create_lw_region('Zoras River', ['King Zora', 'Zora\'s Ledge']),
|
||||||
create_region('Kings Grave', ['King\'s Tomb']),
|
create_cave_region('Waterfall of Wishing', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']),
|
||||||
create_region('North Fairy Cave', None, ['North Fairy Cave Exit']),
|
create_lw_region('Kings Grave Area', None, ['Kings Grave', 'Kings Grave Inner Rocks']),
|
||||||
create_region('Dam', ['Floodgate Chest']),
|
create_cave_region('Kings Grave', ['King\'s Tomb']),
|
||||||
create_region('Links House', ['Link\'s House'], ['Links House Exit']),
|
create_cave_region('North Fairy Cave', None, ['North Fairy Cave Exit']),
|
||||||
create_region('Tavern', ['Kakariko Tavern']),
|
create_cave_region('Dam', ['Floodgate Chest']),
|
||||||
create_region('Elder House', None, ['Elder House Exit (East)', 'Elder House Exit (West)']),
|
create_cave_region('Links House', ['Link\'s House'], ['Links House Exit']),
|
||||||
create_region('Snitch Lady (East)'),
|
create_cave_region('Chris Houlihan Room', None, ['Chris Houlihan Room Exit']),
|
||||||
create_region('Snitch Lady (West)'),
|
create_cave_region('Tavern', ['Kakariko Tavern']),
|
||||||
create_region('Bush Covered House'),
|
create_cave_region('Elder House', None, ['Elder House Exit (East)', 'Elder House Exit (West)']),
|
||||||
create_region('Tavern (Front)'),
|
create_cave_region('Snitch Lady (East)'),
|
||||||
create_region('Light World Bomb Hut'),
|
create_cave_region('Snitch Lady (West)'),
|
||||||
create_region('Kakariko Shop'),
|
create_cave_region('Bush Covered House'),
|
||||||
create_region('Fortune Teller (Light)'),
|
create_cave_region('Tavern (Front)'),
|
||||||
create_region('Lumberjack House'),
|
create_cave_region('Light World Bomb Hut'),
|
||||||
create_region('Bonk Fairy'), # near links house both worlds
|
create_cave_region('Kakariko Shop'),
|
||||||
create_region('Healer Fairy'), # 8 entrances?
|
create_cave_region('Fortune Teller (Light)'),
|
||||||
create_region('Chicken House', ['Chicken House']),
|
create_cave_region('Lake Hylia Fortune Teller'),
|
||||||
create_region('Aginahs Cave', ['Aginah\'s Cave']),
|
create_cave_region('Lumberjack House'),
|
||||||
create_region('Sahasrahlas Hut', ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla']),
|
create_cave_region('Bonk Fairy (Light)'),
|
||||||
create_region('Kakariko Well (top)', ['Kakariko Well - Top', 'Kakariko Well - Left', 'Kakariko Well - Middle',
|
create_cave_region('Bonk Fairy (Dark)'),
|
||||||
'Kakariko Well - Right', 'Kakariko Well - Bottom'], ['Kakariko Well (top to bottom)']),
|
create_cave_region('Lake Hylia Healer Fairy'),
|
||||||
create_region('Kakariko Well (bottom)', None, ['Kakariko Well Exit']),
|
create_cave_region('Swamp Healer Fairy'),
|
||||||
create_region('Blacksmiths Hut', ['Blacksmith']),
|
create_cave_region('Desert Healer Fairy'),
|
||||||
create_region('Bat Cave Drop Ledge', None, ['Bat Cave Drop']),
|
create_cave_region('Dark Lake Hylia Healer Fairy'),
|
||||||
create_region('Bat Cave (right)', ['Magic Bat'], ['Bat Cave Door']),
|
create_cave_region('Dark Lake Hylia Ledge Healer Fairy'),
|
||||||
create_region('Bat Cave (left)', None, ['Bat Cave Exit']),
|
create_cave_region('Dark Desert Healer Fairy'),
|
||||||
create_region('Sick Kids House', ['Sick Kid']),
|
create_cave_region('Dark Death Mountain Healer Fairy'),
|
||||||
create_region('Hobo Bridge', ['Hobo']),
|
create_cave_region('Chicken House', ['Chicken House']),
|
||||||
create_region('Lost Woods Hideout (top)', ['Lost Woods Hideout'], ['Lost Woods Hideout (top to bottom)']),
|
create_cave_region('Aginahs Cave', ['Aginah\'s Cave']),
|
||||||
create_region('Lost Woods Hideout (bottom)', None, ['Lost Woods Hideout Exit']),
|
create_cave_region('Sahasrahlas Hut', ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla']),
|
||||||
create_region('Lumberjack Tree (top)', ['Lumberjack Tree'], ['Lumberjack Tree (top to bottom)']),
|
create_cave_region('Kakariko Well (top)', ['Kakariko Well - Top', 'Kakariko Well - Left', 'Kakariko Well - Middle',
|
||||||
create_region('Lumberjack Tree (bottom)', None, ['Lumberjack Tree Exit']),
|
'Kakariko Well - Right', 'Kakariko Well - Bottom'], ['Kakariko Well (top to bottom)']),
|
||||||
create_region('Cave 45 Ledge', None, ['Cave 45']),
|
create_cave_region('Kakariko Well (bottom)', None, ['Kakariko Well Exit']),
|
||||||
create_region('Cave 45', ['Cave 45']),
|
create_cave_region('Blacksmiths Hut', ['Blacksmith']),
|
||||||
create_region('Graveyard Ledge', None, ['Graveyard Cave']),
|
create_lw_region('Bat Cave Drop Ledge', None, ['Bat Cave Drop']),
|
||||||
create_region('Graveyard Cave', ['Graveyard Cave']),
|
create_cave_region('Bat Cave (right)', ['Magic Bat'], ['Bat Cave Door']),
|
||||||
create_region('Checkerboard Cave', ['Checkerboard Cave']),
|
create_cave_region('Bat Cave (left)', None, ['Bat Cave Exit']),
|
||||||
create_region('Long Fairy Cave'),
|
create_cave_region('Sick Kids House', ['Sick Kid']),
|
||||||
create_region('Mini Moldorm Cave', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right',
|
create_lw_region('Hobo Bridge', ['Hobo']),
|
||||||
'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']),
|
create_cave_region('Lost Woods Hideout (top)', ['Lost Woods Hideout'], ['Lost Woods Hideout (top to bottom)']),
|
||||||
create_region('Ice Rod Cave', ['Ice Rod Cave']),
|
create_cave_region('Lost Woods Hideout (bottom)', None, ['Lost Woods Hideout Exit']),
|
||||||
create_region('Good Bee Cave'),
|
create_cave_region('Lumberjack Tree (top)', ['Lumberjack Tree'], ['Lumberjack Tree (top to bottom)']),
|
||||||
create_region('20 Rupee Cave'),
|
create_cave_region('Lumberjack Tree (bottom)', None, ['Lumberjack Tree Exit']),
|
||||||
create_region('Cave Shop'), # two connectors in vanilla
|
create_lw_region('Cave 45 Ledge', None, ['Cave 45']),
|
||||||
create_region('Bonk Rock Cave', ['Bonk Rock Cave']),
|
create_cave_region('Cave 45', ['Cave 45']),
|
||||||
create_region('Library', ['Library']),
|
create_lw_region('Graveyard Ledge', None, ['Graveyard Cave']),
|
||||||
create_region('Kakariko Gamble Game'),
|
create_cave_region('Graveyard Cave', ['Graveyard Cave']),
|
||||||
create_region('Potion Shop', ['Potion Shop']),
|
create_cave_region('Checkerboard Cave', ['Checkerboard Cave']),
|
||||||
create_region('Lake Hylia Island', ['Lake Hylia Island']),
|
create_cave_region('Long Fairy Cave'),
|
||||||
create_region('Capacity Upgrade'),
|
create_cave_region('Mini Moldorm Cave', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right',
|
||||||
create_region('Two Brothers House', None, ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)']),
|
'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']),
|
||||||
create_region('Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)']),
|
create_cave_region('Ice Rod Cave', ['Ice Rod Cave']),
|
||||||
create_region('50 Rupee Cave'),
|
create_cave_region('Good Bee Cave'),
|
||||||
create_region('Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (West)']),
|
create_cave_region('20 Rupee Cave'),
|
||||||
create_region('Desert Ledge (Northeast)', None, ['Checkerboard Cave']),
|
create_cave_region('Cave Shop (Lake Hylia)'),
|
||||||
create_region('Desert Palace Stairs', None, ['Desert Palace Entrance (South)']),
|
create_cave_region('Cave Shop (Dark Death Mountain)'),
|
||||||
create_region('Desert Palace Lone Stairs', None, ['Desert Palace Stairs Drop', 'Desert Palace Entrance (East)']),
|
create_cave_region('Bonk Rock Cave', ['Bonk Rock Cave']),
|
||||||
create_region('Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Return Rocks']),
|
create_cave_region('Library', ['Library']),
|
||||||
create_region('Desert Palace Main', ['Desert Palace - Big Chest', 'Desert Palace - Torch', 'Desert Palace - Map Chest'],
|
create_cave_region('Kakariko Gamble Game'),
|
||||||
['Desert Palace Exit (South)', 'Desert Palace Exit (West)', 'Desert Palace Exit (East)', 'Desert Palace East Wing']),
|
create_cave_region('Potion Shop', ['Potion Shop']),
|
||||||
create_region('Desert Palace East', ['Desert Palace - Compass Chest', 'Desert Palace - Big Key Chest']),
|
create_lw_region('Lake Hylia Island', ['Lake Hylia Island']),
|
||||||
create_region('Desert Palace North', ['Desert Palace - Lanmolas', 'Desert Palace - Prize'], ['Desert Palace Exit (North)']),
|
create_cave_region('Capacity Upgrade'),
|
||||||
create_region('Eastern Palace', ['Eastern Palace - Compass Chest', 'Eastern Palace - Big Chest', 'Eastern Palace - Cannonball Chest',
|
create_cave_region('Two Brothers House', None, ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)']),
|
||||||
'Eastern Palace - Big Key Chest', 'Eastern Palace - Map Chest', 'Eastern Palace - Armos Knights', 'Eastern Palace - Prize'], ['Eastern Palace Exit']),
|
create_lw_region('Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)']),
|
||||||
create_region('Master Sword Meadow', ['Master Sword Pedestal']),
|
create_cave_region('50 Rupee Cave'),
|
||||||
create_region('Lost Woods Gamble'),
|
create_lw_region('Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (West)']),
|
||||||
create_region('Hyrule Castle Courtyard', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Entrance (South)']),
|
create_lw_region('Desert Ledge (Northeast)', None, ['Checkerboard Cave']),
|
||||||
create_region('Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop']),
|
create_lw_region('Desert Palace Stairs', None, ['Desert Palace Entrance (South)']),
|
||||||
create_region('Hyrule Castle', ['Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest', 'Hyrule Castle - Zelda\'s Chest'],
|
create_lw_region('Desert Palace Lone Stairs', None, ['Desert Palace Stairs Drop', 'Desert Palace Entrance (East)']),
|
||||||
['Hyrule Castle Exit (East)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (South)', 'Throne Room']),
|
create_lw_region('Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Return Rocks']),
|
||||||
create_region('Sewer Drop', None, ['Sewer Drop']), # This exists only to be referenced for access checks
|
create_dungeon_region('Desert Palace Main (Outer)', ['Desert Palace - Big Chest', 'Desert Palace - Torch', 'Desert Palace - Map Chest'],
|
||||||
create_region('Sewers (Dark)', ['Sewers - Dark Cross'], ['Sewers Door']),
|
['Desert Palace Pots (Outer)', 'Desert Palace Exit (West)', 'Desert Palace Exit (East)', 'Desert Palace East Wing']),
|
||||||
create_region('Sewers', ['Sewers - Secret Room - Left', 'Sewers - Secret Room - Middle',
|
create_dungeon_region('Desert Palace Main (Inner)', None, ['Desert Palace Exit (South)', 'Desert Palace Pots (Inner)']),
|
||||||
'Sewers - Secret Room - Right'], ['Sanctuary Push Door', 'Sewers Back Door']),
|
create_dungeon_region('Desert Palace East', ['Desert Palace - Compass Chest', 'Desert Palace - Big Key Chest']),
|
||||||
create_region('Sanctuary', ['Sanctuary'], ['Sanctuary Exit']),
|
create_dungeon_region('Desert Palace North', ['Desert Palace - Lanmolas', 'Desert Palace - Prize'], ['Desert Palace Exit (North)']),
|
||||||
create_region('Agahnims Tower', ['Castle Tower - Room 03', 'Castle Tower - Dark Maze'], ['Agahnim 1', 'Agahnims Tower Exit']),
|
create_dungeon_region('Eastern Palace', ['Eastern Palace - Compass Chest', 'Eastern Palace - Big Chest', 'Eastern Palace - Cannonball Chest',
|
||||||
create_region('Agahnim 1', ['Agahnim 1'], None),
|
'Eastern Palace - Big Key Chest', 'Eastern Palace - Map Chest', 'Eastern Palace - Armos Knights', 'Eastern Palace - Prize'], ['Eastern Palace Exit']),
|
||||||
create_region('Old Man Cave', ['Old Man'], ['Old Man Cave Exit (East)', 'Old Man Cave Exit (West)']),
|
create_lw_region('Master Sword Meadow', ['Master Sword Pedestal']),
|
||||||
create_region('Old Man House', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']),
|
create_cave_region('Lost Woods Gamble'),
|
||||||
create_region('Old Man House Back', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']),
|
create_lw_region('Hyrule Castle Courtyard', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Entrance (South)']),
|
||||||
create_region('Death Mountain', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Broken Bridge (West)', 'Death Mountain Teleporter']),
|
create_lw_region('Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop']),
|
||||||
create_region('Death Mountain Return Cave', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)']),
|
create_dungeon_region('Hyrule Castle', ['Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest', 'Hyrule Castle - Zelda\'s Chest'],
|
||||||
create_region('Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)']),
|
['Hyrule Castle Exit (East)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (South)', 'Throne Room']),
|
||||||
create_region('Spectacle Rock Cave (Top)', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']),
|
create_dungeon_region('Sewer Drop', None, ['Sewer Drop']), # This exists only to be referenced for access checks
|
||||||
create_region('Spectacle Rock Cave (Bottom)', None, ['Spectacle Rock Cave Exit']),
|
create_dungeon_region('Sewers (Dark)', ['Sewers - Dark Cross'], ['Sewers Door']),
|
||||||
create_region('Spectacle Rock Cave (Peak)', None, ['Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Exit (Peak)']),
|
create_dungeon_region('Sewers', ['Sewers - Secret Room - Left', 'Sewers - Secret Room - Middle',
|
||||||
create_region('East Death Mountain (Bottom)', None, ['Broken Bridge (East)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'East Death Mountain Teleporter', 'Hookshot Fairy', 'Fairy Ascension Rocks', 'Spiral Cave (Bottom)']),
|
'Sewers - Secret Room - Right'], ['Sanctuary Push Door', 'Sewers Back Door']),
|
||||||
create_region('Hookshot Fairy'),
|
create_dungeon_region('Sanctuary', ['Sanctuary'], ['Sanctuary Exit']),
|
||||||
create_region('Paradox Cave Front', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)']),
|
create_dungeon_region('Agahnims Tower', ['Castle Tower - Room 03', 'Castle Tower - Dark Maze'], ['Agahnim 1', 'Agahnims Tower Exit']),
|
||||||
create_region('Paradox Cave Chest Area', ['Paradox Cave Lower - Far Left',
|
create_dungeon_region('Agahnim 1', ['Agahnim 1'], None),
|
||||||
'Paradox Cave Lower - Left',
|
create_cave_region('Old Man Cave', ['Old Man'], ['Old Man Cave Exit (East)', 'Old Man Cave Exit (West)']),
|
||||||
'Paradox Cave Lower - Right',
|
create_cave_region('Old Man House', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']),
|
||||||
'Paradox Cave Lower - Far Right',
|
create_cave_region('Old Man House Back', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']),
|
||||||
'Paradox Cave Lower - Middle',
|
create_lw_region('Death Mountain', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Broken Bridge (West)', 'Death Mountain Teleporter']),
|
||||||
'Paradox Cave Upper - Left',
|
create_cave_region('Death Mountain Return Cave', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)']),
|
||||||
'Paradox Cave Upper - Right'],
|
create_lw_region('Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)']),
|
||||||
['Paradox Cave Push Block', 'Paradox Cave Bomb Jump']),
|
create_cave_region('Spectacle Rock Cave (Top)', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']),
|
||||||
create_region('Paradox Cave', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']),
|
create_cave_region('Spectacle Rock Cave (Bottom)', None, ['Spectacle Rock Cave Exit']),
|
||||||
create_region('East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'Death Mountain (Top)', 'Spiral Cave Ledge Access', 'East Death Mountain Drop', 'Turtle Rock Teleporter', 'Fairy Ascension Ledge']),
|
create_cave_region('Spectacle Rock Cave (Peak)', None, ['Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Exit (Peak)']),
|
||||||
create_region('Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop']),
|
create_lw_region('East Death Mountain (Bottom)', None, ['Broken Bridge (East)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'East Death Mountain Teleporter', 'Hookshot Fairy', 'Fairy Ascension Rocks', 'Spiral Cave (Bottom)']),
|
||||||
create_region('Spiral Cave (Top)', ['Spiral Cave'], ['Spiral Cave (top to bottom)', 'Spiral Cave Exit (Top)']),
|
create_cave_region('Hookshot Fairy'),
|
||||||
create_region('Spiral Cave (Bottom)', None, ['Spiral Cave Exit']),
|
create_cave_region('Paradox Cave Front', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)']),
|
||||||
create_region('Fairy Ascension Plateau', None, ['Fairy Ascension Drop', 'Fairy Ascension Cave (Bottom)']),
|
create_cave_region('Paradox Cave Chest Area', ['Paradox Cave Lower - Far Left',
|
||||||
create_region('Fairy Ascension Cave', None, ['Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Cave Exit (Bottom)']),
|
'Paradox Cave Lower - Left',
|
||||||
create_region('Fairy Ascension Ledge', None, ['Fairy Ascension Ledge Drop', 'Fairy Ascension Cave (Top)']),
|
'Paradox Cave Lower - Right',
|
||||||
create_region('Death Mountain (Top)', ['Ether Tablet'], ['East Death Mountain (Top)', 'Tower of Hera', 'Death Mountain Drop']),
|
'Paradox Cave Lower - Far Right',
|
||||||
create_region('Spectacle Rock', ['Spectacle Rock'], ['Spectacle Rock Drop']),
|
'Paradox Cave Lower - Middle',
|
||||||
create_region('Tower of Hera (Bottom)', ['Tower of Hera - Basement Cage', 'Tower of Hera - Map Chest'], ['Tower of Hera Small Key Door', 'Tower of Hera Big Key Door', 'Tower of Hera Exit']),
|
'Paradox Cave Upper - Left',
|
||||||
create_region('Tower of Hera (Basement)', ['Tower of Hera - Big Key Chest']),
|
'Paradox Cave Upper - Right'],
|
||||||
create_region('Tower of Hera (Top)', ['Tower of Hera - Compass Chest', 'Tower of Hera - Big Chest', 'Tower of Hera - Moldorm', 'Tower of Hera - Prize']),
|
['Paradox Cave Push Block', 'Paradox Cave Bomb Jump']),
|
||||||
|
create_cave_region('Paradox Cave', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']),
|
||||||
|
create_lw_region('East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'Death Mountain (Top)', 'Spiral Cave Ledge Access', 'East Death Mountain Drop', 'Turtle Rock Teleporter', 'Fairy Ascension Ledge']),
|
||||||
|
create_lw_region('Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop']),
|
||||||
|
create_cave_region('Spiral Cave (Top)', ['Spiral Cave'], ['Spiral Cave (top to bottom)', 'Spiral Cave Exit (Top)']),
|
||||||
|
create_cave_region('Spiral Cave (Bottom)', None, ['Spiral Cave Exit']),
|
||||||
|
create_lw_region('Fairy Ascension Plateau', None, ['Fairy Ascension Drop', 'Fairy Ascension Cave (Bottom)']),
|
||||||
|
create_cave_region('Fairy Ascension Cave', None, ['Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Cave Exit (Bottom)']),
|
||||||
|
create_lw_region('Fairy Ascension Ledge', None, ['Fairy Ascension Ledge Drop', 'Fairy Ascension Cave (Top)']),
|
||||||
|
create_lw_region('Death Mountain (Top)', ['Ether Tablet'], ['East Death Mountain (Top)', 'Tower of Hera', 'Death Mountain Drop']),
|
||||||
|
create_lw_region('Spectacle Rock', ['Spectacle Rock'], ['Spectacle Rock Drop']),
|
||||||
|
create_dungeon_region('Tower of Hera (Bottom)', ['Tower of Hera - Basement Cage', 'Tower of Hera - Map Chest'], ['Tower of Hera Small Key Door', 'Tower of Hera Big Key Door', 'Tower of Hera Exit']),
|
||||||
|
create_dungeon_region('Tower of Hera (Basement)', ['Tower of Hera - Big Key Chest']),
|
||||||
|
create_dungeon_region('Tower of Hera (Top)', ['Tower of Hera - Compass Chest', 'Tower of Hera - Big Chest', 'Tower of Hera - Moldorm', 'Tower of Hera - Prize']),
|
||||||
|
|
||||||
create_region('East Dark World', ['Pyramid', 'Catfish'], ['Pyramid Fairy', 'South Dark World Bridge', 'West Dark World Gap', 'Palace of Darkness', 'Dark Lake Hylia Drop (East)', 'Dark Lake Hylia Teleporter',
|
create_dw_region('East Dark World', ['Pyramid'], ['Pyramid Fairy', 'South Dark World Bridge', 'Palace of Darkness', 'Dark Lake Hylia Drop (East)', 'Dark Lake Hylia Teleporter',
|
||||||
'Hyrule Castle Ledge Mirror Spot', 'Dark Lake Hylia Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Dark World Potion Shop', 'Pyramid Hole']),
|
'Hyrule Castle Ledge Mirror Spot', 'Dark Lake Hylia Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Pyramid Hole', 'Northeast Dark World Broken Bridge Pass']),
|
||||||
create_region('Palace of Darkness Hint'),
|
create_dw_region('Northeast Dark World', ['Catfish'], ['West Dark World Gap', 'Dark World Potion Shop', 'East Dark World Broken Bridge Pass']),
|
||||||
create_region('East Dark World Hint'),
|
create_cave_region('Palace of Darkness Hint'),
|
||||||
create_region('South Dark World', ['Stumpy', 'Digging Game', 'Bombos Tablet'], ['Dark Lake Hylia Drop (South)', 'Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock',
|
create_cave_region('East Dark World Hint'),
|
||||||
'Maze Race Mirror Spot', 'Cave 45 Mirror Spot', 'East Dark World Bridge', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Shop']),
|
create_dw_region('South Dark World', ['Stumpy', 'Digging Game', 'Bombos Tablet'], ['Dark Lake Hylia Drop (South)', 'Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock',
|
||||||
create_region('Big Bomb Shop'),
|
'Maze Race Mirror Spot', 'Cave 45 Mirror Spot', 'East Dark World Bridge', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Shop']),
|
||||||
create_region('Archery Game'),
|
create_cave_region('Big Bomb Shop'),
|
||||||
create_region('Dark Lake Hylia', None, ['Lake Hylia Island Mirror Spot', 'East Dark World Pier', 'Dark Lake Hylia Ledge']),
|
create_cave_region('Archery Game'),
|
||||||
create_region('Dark Lake Hylia Central Island', None, ['Ice Palace', 'Lake Hylia Central Island Mirror Spot']),
|
create_dw_region('Dark Lake Hylia', None, ['Lake Hylia Island Mirror Spot', 'East Dark World Pier', 'Dark Lake Hylia Ledge']),
|
||||||
create_region('Dark Lake Hylia Ledge', None, ['Dark Lake Hylia Ledge Drop', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave']),
|
create_dw_region('Dark Lake Hylia Central Island', None, ['Ice Palace', 'Lake Hylia Central Island Mirror Spot']),
|
||||||
create_region('Dark Lake Hylia Ledge Hint'),
|
create_dw_region('Dark Lake Hylia Ledge', None, ['Dark Lake Hylia Ledge Drop', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave']),
|
||||||
create_region('Dark Lake Hylia Ledge Spike Cave'),
|
create_cave_region('Dark Lake Hylia Ledge Hint'),
|
||||||
create_region('Hype Cave', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left',
|
create_cave_region('Dark Lake Hylia Ledge Spike Cave'),
|
||||||
'Hype Cave - Bottom', 'Hype Cave - Generous Guy']),
|
create_cave_region('Hype Cave', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left',
|
||||||
create_region('West Dark World', None, ['Village of Outcasts Drop', 'East Dark World River Pier', 'Brewery', 'C-Shaped House', 'Chest Game', 'Thieves Town', 'Graveyard Ledge Mirror Spot', 'Bumper Cave (Bottom)', 'Skull Woods Forest',
|
'Hype Cave - Bottom', 'Hype Cave - Generous Guy']),
|
||||||
'Bat Cave Drop Ledge Mirror Spot', 'Dark World Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Shop', 'Dark World Lumberjack Shop']),
|
create_dw_region('West Dark World', None, ['Village of Outcasts Drop', 'East Dark World River Pier', 'Brewery', 'C-Shaped House', 'Chest Game', 'Thieves Town', 'Graveyard Ledge Mirror Spot', 'Kings Grave Mirror Spot', 'Bumper Cave Entrance Rock',
|
||||||
create_region('Fortune Teller (Dark)'),
|
'Skull Woods Forest', 'Village of Outcasts Pegs', 'Village of Outcasts Eastern Rocks', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Lumberjack Shop']),
|
||||||
create_region('Dark World Shop'),
|
create_dw_region('Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop']),
|
||||||
create_region('Dark World Hammer Peg Cave', ['Peg Cave']),
|
create_dw_region('Hammer Peg Area', None, ['Bat Cave Drop Ledge Mirror Spot', 'Dark World Hammer Peg Cave', 'Peg Area Rocks']),
|
||||||
create_region('Pyramid Fairy', ['Pyramid Fairy - Left', 'Pyramid Fairy - Right']),
|
create_dw_region('Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance Drop']),
|
||||||
create_region('Brewery', ['Brewery']),
|
create_cave_region('Fortune Teller (Dark)'),
|
||||||
create_region('C-Shaped House', ['C-Shaped House']),
|
create_cave_region('Village of Outcasts Shop'),
|
||||||
create_region('Chest Game', ['Chest Game']),
|
create_cave_region('Dark Lake Hylia Shop'),
|
||||||
create_region('Red Shield Shop'),
|
create_cave_region('Dark World Lumberjack Shop'),
|
||||||
create_region('Dark Sanctuary Hint'),
|
create_cave_region('Dark World Potion Shop'),
|
||||||
create_region('Bumper Cave', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Exit (Top)']),
|
create_cave_region('Dark World Hammer Peg Cave', ['Peg Cave']),
|
||||||
create_region('Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Ledge Drop', 'Bumper Cave (Top)', 'Bumper Cave Ledge Mirror Spot']),
|
create_cave_region('Pyramid Fairy', ['Pyramid Fairy - Left', 'Pyramid Fairy - Right']),
|
||||||
create_region('Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods First Section Door',
|
create_cave_region('Brewery', ['Brewery']),
|
||||||
'Skull Woods Second Section Door (East)']),
|
create_cave_region('C-Shaped House', ['C-Shaped House']),
|
||||||
create_region('Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section']),
|
create_cave_region('Chest Game', ['Chest Game']),
|
||||||
create_region('Dark Desert', None, ['Misery Mire', 'Mire Shed', 'Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge Mirror Spot', 'Desert Palace Stairs Mirror Spot', 'Desert Palace Entrance (North) Mirror Spot',
|
create_cave_region('Red Shield Shop'),
|
||||||
'Dark Desert Hint', 'Dark Desert Fairy']),
|
create_cave_region('Dark Sanctuary Hint'),
|
||||||
create_region('Mire Shed', ['Mire Shed - Left', 'Mire Shed - Right']),
|
create_cave_region('Bumper Cave', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Exit (Top)']),
|
||||||
create_region('Dark Desert Hint'),
|
create_dw_region('Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Ledge Drop', 'Bumper Cave (Top)', 'Bumper Cave Ledge Mirror Spot']),
|
||||||
create_region('Dark Death Mountain (West Bottom)', None, ['Spike Cave', 'Spectacle Rock Mirror Spot', 'Dark Death Mountain Fairy']),
|
create_dw_region('Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods First Section Door',
|
||||||
create_region('Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (East)', 'Dark Death Mountain Drop (West)', 'Ganons Tower', 'Superbunny Cave (Top)', 'Hookshot Cave',
|
'Skull Woods Second Section Door (East)']),
|
||||||
'East Death Mountain (Top) Mirror Spot', 'Turtle Rock']),
|
create_dw_region('Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section']),
|
||||||
create_region('Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot']),
|
create_dw_region('Dark Desert', None, ['Misery Mire', 'Mire Shed', 'Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge Mirror Spot', 'Desert Palace Stairs Mirror Spot', 'Desert Palace Entrance (North) Mirror Spot',
|
||||||
create_region('Dark Death Mountain Isolated Ledge', None, ['Isolated Ledge Mirror Spot', 'Turtle Rock Isolated Ledge Entrance']),
|
'Dark Desert Hint', 'Dark Desert Fairy']),
|
||||||
create_region('Dark Death Mountain (East Bottom)', None, ['Superbunny Cave (Bottom)', 'Cave Shop (Dark Death Mountain)', 'Fairy Ascension Mirror Spot']),
|
create_cave_region('Mire Shed', ['Mire Shed - Left', 'Mire Shed - Right']),
|
||||||
create_region('Superbunny Cave', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'],
|
create_cave_region('Dark Desert Hint'),
|
||||||
['Superbunny Cave Exit (Top)', 'Superbunny Cave Exit (Bottom)']),
|
create_dw_region('Dark Death Mountain (West Bottom)', None, ['Spike Cave', 'Spectacle Rock Mirror Spot', 'Dark Death Mountain Fairy']),
|
||||||
create_region('Spike Cave', ['Spike Cave']),
|
create_dw_region('Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (East)', 'Dark Death Mountain Drop (West)', 'Ganons Tower', 'Superbunny Cave (Top)', 'Hookshot Cave',
|
||||||
create_region('Hookshot Cave', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'],
|
'East Death Mountain (Top) Mirror Spot', 'Turtle Rock']),
|
||||||
['Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)']),
|
create_dw_region('Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot']),
|
||||||
create_region('Death Mountain Floating Island (Dark World)', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance', 'Floating Island Mirror Spot']),
|
create_dw_region('Dark Death Mountain Isolated Ledge', None, ['Isolated Ledge Mirror Spot', 'Turtle Rock Isolated Ledge Entrance']),
|
||||||
create_region('Death Mountain Floating Island (Light World)', ['Floating Island']),
|
create_dw_region('Dark Death Mountain (East Bottom)', None, ['Superbunny Cave (Bottom)', 'Cave Shop (Dark Death Mountain)', 'Fairy Ascension Mirror Spot']),
|
||||||
create_region('Turtle Rock (Top)', None, ['Turtle Rock Drop']),
|
create_cave_region('Superbunny Cave', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'],
|
||||||
create_region('Mimic Cave Ledge', None, ['Mimic Cave']),
|
['Superbunny Cave Exit (Top)', 'Superbunny Cave Exit (Bottom)']),
|
||||||
create_region('Mimic Cave', ['Mimic Cave']),
|
create_cave_region('Spike Cave', ['Spike Cave']),
|
||||||
|
create_cave_region('Hookshot Cave', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'],
|
||||||
|
['Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)']),
|
||||||
|
create_dw_region('Death Mountain Floating Island (Dark World)', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance', 'Floating Island Mirror Spot']),
|
||||||
|
create_lw_region('Death Mountain Floating Island (Light World)', ['Floating Island']),
|
||||||
|
create_dw_region('Turtle Rock (Top)', None, ['Turtle Rock Drop']),
|
||||||
|
create_lw_region('Mimic Cave Ledge', None, ['Mimic Cave']),
|
||||||
|
create_cave_region('Mimic Cave', ['Mimic Cave']),
|
||||||
|
|
||||||
create_region('Swamp Palace (Entrance)', None, ['Swamp Palace Moat', 'Swamp Palace Exit']),
|
create_dungeon_region('Swamp Palace (Entrance)', None, ['Swamp Palace Moat', 'Swamp Palace Exit']),
|
||||||
create_region('Swamp Palace (First Room)', ['Swamp Palace - Entrance'], ['Swamp Palace Small Key Door']),
|
create_dungeon_region('Swamp Palace (First Room)', ['Swamp Palace - Entrance'], ['Swamp Palace Small Key Door']),
|
||||||
create_region('Swamp Palace (Starting Area)', ['Swamp Palace - Map Chest'], ['Swamp Palace (Center)']),
|
create_dungeon_region('Swamp Palace (Starting Area)', ['Swamp Palace - Map Chest'], ['Swamp Palace (Center)']),
|
||||||
create_region('Swamp Palace (Center)', ['Swamp Palace - Big Chest', 'Swamp Palace - Compass Chest',
|
create_dungeon_region('Swamp Palace (Center)', ['Swamp Palace - Big Chest', 'Swamp Palace - Compass Chest',
|
||||||
'Swamp Palace - Big Key Chest', 'Swamp Palace - West Chest'], ['Swamp Palace (North)']),
|
'Swamp Palace - Big Key Chest', 'Swamp Palace - West Chest'], ['Swamp Palace (North)']),
|
||||||
create_region('Swamp Palace (North)', ['Swamp Palace - Flooded Room - Left', 'Swamp Palace - Flooded Room - Right',
|
create_dungeon_region('Swamp Palace (North)', ['Swamp Palace - Flooded Room - Left', 'Swamp Palace - Flooded Room - Right',
|
||||||
'Swamp Palace - Waterfall Room', 'Swamp Palace - Arrghus', 'Swamp Palace - Prize']),
|
'Swamp Palace - Waterfall Room', 'Swamp Palace - Arrghus', 'Swamp Palace - Prize']),
|
||||||
create_region('Thieves Town (Entrance)', ['Thieves\' Town - Big Key Chest',
|
create_dungeon_region('Thieves Town (Entrance)', ['Thieves\' Town - Big Key Chest',
|
||||||
'Thieves\' Town - Map Chest',
|
'Thieves\' Town - Map Chest',
|
||||||
'Thieves\' Town - Compass Chest',
|
'Thieves\' Town - Compass Chest',
|
||||||
'Thieves\' Town - Ambush Chest'], ['Thieves Town Big Key Door', 'Thieves Town Exit']),
|
'Thieves\' Town - Ambush Chest'], ['Thieves Town Big Key Door', 'Thieves Town Exit']),
|
||||||
create_region('Thieves Town (Deep)', ['Thieves\' Town - Attic',
|
create_dungeon_region('Thieves Town (Deep)', ['Thieves\' Town - Attic',
|
||||||
'Thieves\' Town - Big Chest',
|
'Thieves\' Town - Big Chest',
|
||||||
'Thieves\' Town - Blind\'s Cell'], ['Blind Fight']),
|
'Thieves\' Town - Blind\'s Cell'], ['Blind Fight']),
|
||||||
create_region('Blind Fight', ['Thieves Town - Blind', 'Thieves Town - Prize']),
|
create_dungeon_region('Blind Fight', ['Thieves Town - Blind', 'Thieves Town - Prize']),
|
||||||
create_region('Skull Woods First Section', ['Skull Woods - Map Chest'], ['Skull Woods First Section Exit', 'Skull Woods First Section Bomb Jump', 'Skull Woods First Section South Door', 'Skull Woods First Section West Door']),
|
create_dungeon_region('Skull Woods First Section', ['Skull Woods - Map Chest'], ['Skull Woods First Section Exit', 'Skull Woods First Section Bomb Jump', 'Skull Woods First Section South Door', 'Skull Woods First Section West Door']),
|
||||||
create_region('Skull Woods First Section (Right)', ['Skull Woods - Pinball Room'], ['Skull Woods First Section (Right) North Door']),
|
create_dungeon_region('Skull Woods First Section (Right)', ['Skull Woods - Pinball Room'], ['Skull Woods First Section (Right) North Door']),
|
||||||
create_region('Skull Woods First Section (Left)', ['Skull Woods - Compass Chest', 'Skull Woods - Pot Prison'], ['Skull Woods First Section (Left) Door to Exit', 'Skull Woods First Section (Left) Door to Right']),
|
create_dungeon_region('Skull Woods First Section (Left)', ['Skull Woods - Compass Chest', 'Skull Woods - Pot Prison'], ['Skull Woods First Section (Left) Door to Exit', 'Skull Woods First Section (Left) Door to Right']),
|
||||||
create_region('Skull Woods First Section (Top)', ['Skull Woods - Big Chest'], ['Skull Woods First Section (Top) One-Way Path']),
|
create_dungeon_region('Skull Woods First Section (Top)', ['Skull Woods - Big Chest'], ['Skull Woods First Section (Top) One-Way Path']),
|
||||||
create_region('Skull Woods Second Section (Drop)', None, ['Skull Woods Second Section (Drop)']),
|
create_dungeon_region('Skull Woods Second Section (Drop)', None, ['Skull Woods Second Section (Drop)']),
|
||||||
create_region('Skull Woods Second Section', ['Skull Woods - Big Key Chest'], ['Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)']),
|
create_dungeon_region('Skull Woods Second Section', ['Skull Woods - Big Key Chest'], ['Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)']),
|
||||||
create_region('Skull Woods Final Section (Entrance)', ['Skull Woods - Bridge Room'], ['Skull Woods Torch Room', 'Skull Woods Final Section Exit']),
|
create_dungeon_region('Skull Woods Final Section (Entrance)', ['Skull Woods - Bridge Room'], ['Skull Woods Torch Room', 'Skull Woods Final Section Exit']),
|
||||||
create_region('Skull Woods Final Section (Mothula)', ['Skull Woods - Mothula', 'Skull Woods - Prize']),
|
create_dungeon_region('Skull Woods Final Section (Mothula)', ['Skull Woods - Mothula', 'Skull Woods - Prize']),
|
||||||
create_region('Ice Palace (Entrance)', None, ['Ice Palace Entrance Room', 'Ice Palace Exit']),
|
create_dungeon_region('Ice Palace (Entrance)', None, ['Ice Palace Entrance Room', 'Ice Palace Exit']),
|
||||||
create_region('Ice Palace (Main)', ['Ice Palace - Compass Chest', 'Ice Palace - Freezor Chest',
|
create_dungeon_region('Ice Palace (Main)', ['Ice Palace - Compass Chest', 'Ice Palace - Freezor Chest',
|
||||||
'Ice Palace - Big Chest', 'Ice Palace - Iced T Room'], ['Ice Palace (East)', 'Ice Palace (Kholdstare)']),
|
'Ice Palace - Big Chest', 'Ice Palace - Iced T Room'], ['Ice Palace (East)', 'Ice Palace (Kholdstare)']),
|
||||||
create_region('Ice Palace (East)', ['Ice Palace - Spike Room'], ['Ice Palace (East Top)']),
|
create_dungeon_region('Ice Palace (East)', ['Ice Palace - Spike Room'], ['Ice Palace (East Top)']),
|
||||||
create_region('Ice Palace (East Top)', ['Ice Palace - Big Key Chest', 'Ice Palace - Map Chest']),
|
create_dungeon_region('Ice Palace (East Top)', ['Ice Palace - Big Key Chest', 'Ice Palace - Map Chest']),
|
||||||
create_region('Ice Palace (Kholdstare)', ['Ice Palace - Kholdstare', 'Ice Palace - Prize']),
|
create_dungeon_region('Ice Palace (Kholdstare)', ['Ice Palace - Kholdstare', 'Ice Palace - Prize']),
|
||||||
create_region('Misery Mire (Entrance)', None, ['Misery Mire Entrance Gap', 'Misery Mire Exit']),
|
create_dungeon_region('Misery Mire (Entrance)', None, ['Misery Mire Entrance Gap', 'Misery Mire Exit']),
|
||||||
create_region('Misery Mire (Main)', ['Misery Mire - Big Chest', 'Misery Mire - Map Chest', 'Misery Mire - Main Lobby',
|
create_dungeon_region('Misery Mire (Main)', ['Misery Mire - Big Chest', 'Misery Mire - Map Chest', 'Misery Mire - Main Lobby',
|
||||||
'Misery Mire - Bridge Chest', 'Misery Mire - Spike Chest'], ['Misery Mire (West)', 'Misery Mire Big Key Door']),
|
'Misery Mire - Bridge Chest', 'Misery Mire - Spike Chest'], ['Misery Mire (West)', 'Misery Mire Big Key Door']),
|
||||||
create_region('Misery Mire (West)', ['Misery Mire - Compass Chest', 'Misery Mire - Big Key Chest']),
|
create_dungeon_region('Misery Mire (West)', ['Misery Mire - Compass Chest', 'Misery Mire - Big Key Chest']),
|
||||||
create_region('Misery Mire (Final Area)', None, ['Misery Mire (Vitreous)']),
|
create_dungeon_region('Misery Mire (Final Area)', None, ['Misery Mire (Vitreous)']),
|
||||||
create_region('Misery Mire (Vitreous)', ['Misery Mire - Vitreous', 'Misery Mire - Prize']),
|
create_dungeon_region('Misery Mire (Vitreous)', ['Misery Mire - Vitreous', 'Misery Mire - Prize']),
|
||||||
create_region('Turtle Rock (Entrance)', None, ['Turtle Rock Entrance Gap', 'Turtle Rock Exit (Front)']),
|
create_dungeon_region('Turtle Rock (Entrance)', None, ['Turtle Rock Entrance Gap', 'Turtle Rock Exit (Front)']),
|
||||||
create_region('Turtle Rock (First Section)', ['Turtle Rock - Compass Chest', 'Turtle Rock - Roller Room - Left',
|
create_dungeon_region('Turtle Rock (First Section)', ['Turtle Rock - Compass Chest', 'Turtle Rock - Roller Room - Left',
|
||||||
'Turtle Rock - Roller Room - Right'], ['Turtle Rock Pokey Room', 'Turtle Rock Entrance Gap Reverse']),
|
'Turtle Rock - Roller Room - Right'], ['Turtle Rock Pokey Room', 'Turtle Rock Entrance Gap Reverse']),
|
||||||
create_region('Turtle Rock (Chain Chomp Room)', ['Turtle Rock - Chain Chomps'], ['Turtle Rock (Chain Chomp Room) (North)', 'Turtle Rock (Chain Chomp Room) (South)']),
|
create_dungeon_region('Turtle Rock (Chain Chomp Room)', ['Turtle Rock - Chain Chomps'], ['Turtle Rock (Chain Chomp Room) (North)', 'Turtle Rock (Chain Chomp Room) (South)']),
|
||||||
create_region('Turtle Rock (Second Section)', ['Turtle Rock - Big Key Chest'], ['Turtle Rock Ledge Exit (West)', 'Turtle Rock Chain Chomp Staircase', 'Turtle Rock Big Key Door']),
|
create_dungeon_region('Turtle Rock (Second Section)', ['Turtle Rock - Big Key Chest'], ['Turtle Rock Ledge Exit (West)', 'Turtle Rock Chain Chomp Staircase', 'Turtle Rock Big Key Door']),
|
||||||
create_region('Turtle Rock (Big Chest)', ['Turtle Rock - Big Chest'], ['Turtle Rock (Big Chest) (North)', 'Turtle Rock Ledge Exit (East)']),
|
create_dungeon_region('Turtle Rock (Big Chest)', ['Turtle Rock - Big Chest'], ['Turtle Rock (Big Chest) (North)', 'Turtle Rock Ledge Exit (East)']),
|
||||||
create_region('Turtle Rock (Crystaroller Room)', ['Turtle Rock - Crystaroller Room'], ['Turtle Rock Dark Room Staircase', 'Turtle Rock Big Key Door Reverse']),
|
create_dungeon_region('Turtle Rock (Crystaroller Room)', ['Turtle Rock - Crystaroller Room'], ['Turtle Rock Dark Room Staircase', 'Turtle Rock Big Key Door Reverse']),
|
||||||
create_region('Turtle Rock (Dark Room)', None, ['Turtle Rock (Dark Room) (North)', 'Turtle Rock (Dark Room) (South)']),
|
create_dungeon_region('Turtle Rock (Dark Room)', None, ['Turtle Rock (Dark Room) (North)', 'Turtle Rock (Dark Room) (South)']),
|
||||||
create_region('Turtle Rock (Eye Bridge)', ['Turtle Rock - Eye Bridge - Bottom Left', 'Turtle Rock - Eye Bridge - Bottom Right',
|
create_dungeon_region('Turtle Rock (Eye Bridge)', ['Turtle Rock - Eye Bridge - Bottom Left', 'Turtle Rock - Eye Bridge - Bottom Right',
|
||||||
'Turtle Rock - Eye Bridge - Top Left', 'Turtle Rock - Eye Bridge - Top Right'],
|
'Turtle Rock - Eye Bridge - Top Left', 'Turtle Rock - Eye Bridge - Top Right'],
|
||||||
['Turtle Rock Dark Room (South)', 'Turtle Rock (Trinexx)', 'Turtle Rock Isolated Ledge Exit']),
|
['Turtle Rock Dark Room (South)', 'Turtle Rock (Trinexx)', 'Turtle Rock Isolated Ledge Exit']),
|
||||||
create_region('Turtle Rock (Trinexx)', ['Turtle Rock - Trinexx', 'Turtle Rock - Prize']),
|
create_dungeon_region('Turtle Rock (Trinexx)', ['Turtle Rock - Trinexx', 'Turtle Rock - Prize']),
|
||||||
create_region('Palace of Darkness (Entrance)', ['Palace of Darkness - Shooter Room'], ['Palace of Darkness Bridge Room', 'Palace of Darkness Bonk Wall', 'Palace of Darkness Exit']),
|
create_dungeon_region('Palace of Darkness (Entrance)', ['Palace of Darkness - Shooter Room'], ['Palace of Darkness Bridge Room', 'Palace of Darkness Bonk Wall', 'Palace of Darkness Exit']),
|
||||||
create_region('Palace of Darkness (Center)', ['Palace of Darkness - The Arena - Bridge', 'Palace of Darkness - Stalfos Basement'],
|
create_dungeon_region('Palace of Darkness (Center)', ['Palace of Darkness - The Arena - Bridge', 'Palace of Darkness - Stalfos Basement'],
|
||||||
['Palace of Darkness Big Key Chest Staircase', 'Palace of Darkness (North)', 'Palace of Darkness Big Key Door']),
|
['Palace of Darkness Big Key Chest Staircase', 'Palace of Darkness (North)', 'Palace of Darkness Big Key Door']),
|
||||||
create_region('Palace of Darkness (Big Key Chest)', ['Palace of Darkness - Big Key Chest']),
|
create_dungeon_region('Palace of Darkness (Big Key Chest)', ['Palace of Darkness - Big Key Chest']),
|
||||||
create_region('Palace of Darkness (Bonk Section)', ['Palace of Darkness - The Arena - Ledge', 'Palace of Darkness - Map Chest'], ['Palace of Darkness Hammer Peg Drop']),
|
create_dungeon_region('Palace of Darkness (Bonk Section)', ['Palace of Darkness - The Arena - Ledge', 'Palace of Darkness - Map Chest'], ['Palace of Darkness Hammer Peg Drop']),
|
||||||
create_region('Palace of Darkness (North)', ['Palace of Darkness - Compass Chest', 'Palace of Darkness - Dark Basement - Left', 'Palace of Darkness - Dark Basement - Right'],
|
create_dungeon_region('Palace of Darkness (North)', ['Palace of Darkness - Compass Chest', 'Palace of Darkness - Dark Basement - Left', 'Palace of Darkness - Dark Basement - Right'],
|
||||||
['Palace of Darkness Spike Statue Room Door', 'Palace of Darkness Maze Door']),
|
['Palace of Darkness Spike Statue Room Door', 'Palace of Darkness Maze Door']),
|
||||||
create_region('Palace of Darkness (Maze)', ['Palace of Darkness - Dark Maze - Top', 'Palace of Darkness - Dark Maze - Bottom', 'Palace of Darkness - Big Chest']),
|
create_dungeon_region('Palace of Darkness (Maze)', ['Palace of Darkness - Dark Maze - Top', 'Palace of Darkness - Dark Maze - Bottom', 'Palace of Darkness - Big Chest']),
|
||||||
create_region('Palace of Darkness (Harmless Hellway)', ['Palace of Darkness - Harmless Hellway']),
|
create_dungeon_region('Palace of Darkness (Harmless Hellway)', ['Palace of Darkness - Harmless Hellway']),
|
||||||
create_region('Palace of Darkness (Final Section)', ['Palace of Darkness - Helmasaur', 'Palace of Darkness - Prize']),
|
create_dungeon_region('Palace of Darkness (Final Section)', ['Palace of Darkness - Helmasaur', 'Palace of Darkness - Prize']),
|
||||||
create_region('Ganons Tower (Entrance)', ['Ganons Tower - Bob\'s Torch', 'Ganons Tower - Hope Room - Left', 'Ganons Tower - Hope Room - Right'],
|
create_dungeon_region('Ganons Tower (Entrance)', ['Ganons Tower - Bob\'s Torch', 'Ganons Tower - Hope Room - Left', 'Ganons Tower - Hope Room - Right'],
|
||||||
['Ganons Tower (Tile Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower Big Key Door', 'Ganons Tower Exit']),
|
['Ganons Tower (Tile Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower Big Key Door', 'Ganons Tower Exit']),
|
||||||
create_region('Ganons Tower (Tile Room)', ['Ganons Tower - Tile Room'], ['Ganons Tower (Tile Room) Key Door']),
|
create_dungeon_region('Ganons Tower (Tile Room)', ['Ganons Tower - Tile Room'], ['Ganons Tower (Tile Room) Key Door']),
|
||||||
create_region('Ganons Tower (Compass Room)', ['Ganons Tower - Compass Room - Top Left', 'Ganons Tower - Compass Room - Top Right',
|
create_dungeon_region('Ganons Tower (Compass Room)', ['Ganons Tower - Compass Room - Top Left', 'Ganons Tower - Compass Room - Top Right',
|
||||||
'Ganons Tower - Compass Room - Bottom Left', 'Ganons Tower - Compass Room - Bottom Right'],
|
'Ganons Tower - Compass Room - Bottom Left', 'Ganons Tower - Compass Room - Bottom Right'],
|
||||||
['Ganons Tower (Bottom) (East)']),
|
['Ganons Tower (Bottom) (East)']),
|
||||||
create_region('Ganons Tower (Hookshot Room)', ['Ganons Tower - DMs Room - Top Left', 'Ganons Tower - DMs Room - Top Right',
|
create_dungeon_region('Ganons Tower (Hookshot Room)', ['Ganons Tower - DMs Room - Top Left', 'Ganons Tower - DMs Room - Top Right',
|
||||||
'Ganons Tower - DMs Room - Bottom Left', 'Ganons Tower - DMs Room - Bottom Right'],
|
'Ganons Tower - DMs Room - Bottom Left', 'Ganons Tower - DMs Room - Bottom Right'],
|
||||||
['Ganons Tower (Map Room)', 'Ganons Tower (Double Switch Room)']),
|
['Ganons Tower (Map Room)', 'Ganons Tower (Double Switch Room)']),
|
||||||
create_region('Ganons Tower (Map Room)', ['Ganons Tower - Map Chest']),
|
create_dungeon_region('Ganons Tower (Map Room)', ['Ganons Tower - Map Chest']),
|
||||||
create_region('Ganons Tower (Firesnake Room)', ['Ganons Tower - Firesnake Room'], ['Ganons Tower (Firesnake Room)']),
|
create_dungeon_region('Ganons Tower (Firesnake Room)', ['Ganons Tower - Firesnake Room'], ['Ganons Tower (Firesnake Room)']),
|
||||||
create_region('Ganons Tower (Teleport Room)', ['Ganons Tower - Randomizer Room - Top Left', 'Ganons Tower - Randomizer Room - Top Right',
|
create_dungeon_region('Ganons Tower (Teleport Room)', ['Ganons Tower - Randomizer Room - Top Left', 'Ganons Tower - Randomizer Room - Top Right',
|
||||||
'Ganons Tower - Randomizer Room - Bottom Left', 'Ganons Tower - Randomizer Room - Bottom Right'],
|
'Ganons Tower - Randomizer Room - Bottom Left', 'Ganons Tower - Randomizer Room - Bottom Right'],
|
||||||
['Ganons Tower (Bottom) (West)']),
|
['Ganons Tower (Bottom) (West)']),
|
||||||
create_region('Ganons Tower (Bottom)', ['Ganons Tower - Bob\'s Chest', 'Ganons Tower - Big Chest', 'Ganons Tower - Big Key Room - Left',
|
create_dungeon_region('Ganons Tower (Bottom)', ['Ganons Tower - Bob\'s Chest', 'Ganons Tower - Big Chest', 'Ganons Tower - Big Key Room - Left',
|
||||||
'Ganons Tower - Big Key Room - Right', 'Ganons Tower - Big Key Chest']),
|
'Ganons Tower - Big Key Room - Right', 'Ganons Tower - Big Key Chest']),
|
||||||
create_region('Ganons Tower (Top)', None, ['Ganons Tower Torch Rooms']),
|
create_dungeon_region('Ganons Tower (Top)', None, ['Ganons Tower Torch Rooms']),
|
||||||
create_region('Ganons Tower (Before Moldorm)', ['Ganons Tower - Mini Helmasaur Room - Left', 'Ganons Tower - Mini Helmasaur Room - Right',
|
create_dungeon_region('Ganons Tower (Before Moldorm)', ['Ganons Tower - Mini Helmasaur Room - Left', 'Ganons Tower - Mini Helmasaur Room - Right',
|
||||||
'Ganons Tower - Pre-Moldorm Chest'], ['Ganons Tower Moldorm Door']),
|
'Ganons Tower - Pre-Moldorm Chest'], ['Ganons Tower Moldorm Door']),
|
||||||
create_region('Ganons Tower (Moldorm)', None, ['Ganons Tower Moldorm Gap']),
|
create_dungeon_region('Ganons Tower (Moldorm)', None, ['Ganons Tower Moldorm Gap']),
|
||||||
create_region('Agahnim 2', ['Ganons Tower - Validation Chest', 'Agahnim 2'], None),
|
create_dungeon_region('Agahnim 2', ['Ganons Tower - Validation Chest', 'Agahnim 2'], None),
|
||||||
create_region('Pyramid', ['Ganon'], ['Ganon Drop']),
|
create_cave_region('Pyramid', ['Ganon'], ['Ganon Drop']),
|
||||||
create_region('Bottom of Pyramid', None, ['Pyramid Exit']),
|
create_cave_region('Bottom of Pyramid', None, ['Pyramid Exit']),
|
||||||
create_region('Pyramid Ledge', None, ['Pyramid Entrance', 'Pyramid Drop'])
|
create_dw_region('Pyramid Ledge', None, ['Pyramid Entrance', 'Pyramid Drop'])
|
||||||
]
|
]
|
||||||
|
|
||||||
world.intialize_regions()
|
world.intialize_regions()
|
||||||
|
|
||||||
|
def create_lw_region(name, locations=None, exits=None):
|
||||||
|
return _create_region(name, RegionType.LightWorld, locations, exits)
|
||||||
|
|
||||||
def create_region(name, locations=None, exits=None):
|
def create_dw_region(name, locations=None, exits=None):
|
||||||
ret = Region(name)
|
return _create_region(name, RegionType.DarkWorld, locations, exits)
|
||||||
|
|
||||||
|
def create_cave_region(name, locations=None, exits=None):
|
||||||
|
return _create_region(name, RegionType.Cave, locations, exits)
|
||||||
|
|
||||||
|
def create_dungeon_region(name, locations=None, exits=None):
|
||||||
|
return _create_region(name, RegionType.Dungeon, locations, exits)
|
||||||
|
|
||||||
|
def _create_region(name, type, locations=None, exits=None):
|
||||||
|
ret = Region(name, type)
|
||||||
if locations is None:
|
if locations is None:
|
||||||
locations = []
|
locations = []
|
||||||
if exits is None:
|
if exits is None:
|
||||||
|
@ -287,22 +318,30 @@ def create_region(name, locations=None, exits=None):
|
||||||
ret.locations.append(Location(location, address, crystal, hint_text, ret))
|
ret.locations.append(Location(location, address, crystal, hint_text, ret))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def mark_light_world_regions(world):
|
def mark_light_world_regions(world):
|
||||||
# Note that in "inanity" shuffle this code may mark some dark world locations as being in light world. That is fine because this flag
|
# cross world caves may have some sections marked as both in_light_world, and in_dark_work.
|
||||||
# is only used for bunny logic, and you start with a Moon pearl immediately availible in Insanity shuffle.
|
# That is ok. the bunny logic will check for this case and incorporate special rules.
|
||||||
|
queue = collections.deque(region for region in world.regions if region.type == RegionType.LightWorld)
|
||||||
# Exclude entrances that represent connections from the light world to the dark world
|
|
||||||
excluded_entrances = set(['Top of Pyramid', 'Lake Hylia Central Island Teleporter', 'Dark Desert Teleporter', 'East Hyrule Teleporter', 'South Hyrule Teleporter', 'Kakariko Teleporter', 'Death Mountain Teleporter', 'East Death Mountain Teleporter', 'Turtle Rock Teleporter'])
|
|
||||||
|
|
||||||
starting_regions = ['Links House', 'Cave 45 Ledge', 'Graveyard Ledge', 'Mimic Cave Ledge', 'Death Mountain Floating Island (Light World)', 'Desert Ledge', 'Desert Ledge (Northeast)', 'Lake Hylia Island', 'Spectacle Rock', 'Death Mountain Return Ledge', 'Hyrule Castle Ledge','Maze Race Ledge']
|
|
||||||
queue = collections.deque([world.get_region(region) for region in starting_regions])
|
|
||||||
seen = set(queue)
|
seen = set(queue)
|
||||||
while queue:
|
while queue:
|
||||||
current = queue.popleft()
|
current = queue.popleft()
|
||||||
current.is_light_world = True
|
current.is_light_world = True
|
||||||
for exit in current.exits:
|
for exit in current.exits:
|
||||||
if exit.name in excluded_entrances:
|
if exit.connected_region.type == RegionType.DarkWorld:
|
||||||
|
# Don't venture into the dark world
|
||||||
|
continue
|
||||||
|
if exit.connected_region not in seen:
|
||||||
|
seen.add(exit.connected_region)
|
||||||
|
queue.append(exit.connected_region)
|
||||||
|
|
||||||
|
queue = collections.deque(region for region in world.regions if region.type == RegionType.DarkWorld)
|
||||||
|
seen = set(queue)
|
||||||
|
while queue:
|
||||||
|
current = queue.popleft()
|
||||||
|
current.is_dark_world = True
|
||||||
|
for exit in current.exits:
|
||||||
|
if exit.connected_region.type == RegionType.LightWorld:
|
||||||
|
# Don't venture into the light world
|
||||||
continue
|
continue
|
||||||
if exit.connected_region not in seen:
|
if exit.connected_region not in seen:
|
||||||
seen.add(exit.connected_region)
|
seen.add(exit.connected_region)
|
||||||
|
|
313
Rom.py
313
Rom.py
|
@ -15,7 +15,7 @@ from Items import ItemFactory
|
||||||
|
|
||||||
|
|
||||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||||
RANDOMIZERBASEHASH = '214e4b2a50cb65cd13a8194bc88cb030'
|
RANDOMIZERBASEHASH = 'dc5840f0d1ef7b51009c5625a054b3dd'
|
||||||
|
|
||||||
|
|
||||||
class JsonRom(object):
|
class JsonRom(object):
|
||||||
|
@ -44,7 +44,7 @@ class LocalRom(object):
|
||||||
|
|
||||||
def __init__(self, file, patch=True):
|
def __init__(self, file, patch=True):
|
||||||
with open(file, 'rb') as stream:
|
with open(file, 'rb') as stream:
|
||||||
self.buffer = bytearray(stream.read())
|
self.buffer = read_rom(stream)
|
||||||
if patch:
|
if patch:
|
||||||
self.patch_base_rom()
|
self.patch_base_rom()
|
||||||
|
|
||||||
|
@ -94,6 +94,13 @@ class LocalRom(object):
|
||||||
inv = crc ^ 0xFFFF
|
inv = crc ^ 0xFFFF
|
||||||
self.write_bytes(0x7FDC, [inv & 0xFF, (inv >> 8) & 0xFF, crc & 0xFF, (crc >> 8) & 0xFF])
|
self.write_bytes(0x7FDC, [inv & 0xFF, (inv >> 8) & 0xFF, crc & 0xFF, (crc >> 8) & 0xFF])
|
||||||
|
|
||||||
|
def read_rom(stream):
|
||||||
|
"Reads rom into bytearray and strips off any smc header"
|
||||||
|
buffer = bytearray(stream.read())
|
||||||
|
if len(buffer)%0x400 == 0x200:
|
||||||
|
buffer = buffer[0x200:]
|
||||||
|
return buffer
|
||||||
|
|
||||||
class Sprite(object):
|
class Sprite(object):
|
||||||
default_palette = [255, 127, 126, 35, 183, 17, 158, 54, 165, 20, 255, 1, 120, 16, 157,
|
default_palette = [255, 127, 126, 35, 183, 17, 158, 54, 165, 20, 255, 1, 120, 16, 157,
|
||||||
89, 71, 54, 104, 59, 74, 10, 239, 18, 92, 42, 113, 21, 24, 122,
|
89, 71, 54, 104, 59, 74, 10, 239, 18, 92, 42, 113, 21, 24, 122,
|
||||||
|
@ -261,7 +268,7 @@ def int32_as_bytes(value):
|
||||||
value = value & 0xFFFFFFFF
|
value = value & 0xFFFFFFFF
|
||||||
return [value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF, (value >> 24) & 0xFF]
|
return [value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF, (value >> 24) & 0xFF]
|
||||||
|
|
||||||
def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
|
||||||
# patch items
|
# patch items
|
||||||
for location in world.get_locations():
|
for location in world.get_locations():
|
||||||
itemid = location.item.code if location.item is not None else 0x5A
|
itemid = location.item.code if location.item is not None else 0x5A
|
||||||
|
@ -297,13 +304,57 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
if world.keysanity:
|
if world.keysanity:
|
||||||
rom.write_byte(0x155C9, random.choice([0x11, 0x16])) # Randomize GT music too in keysanity mode
|
rom.write_byte(0x155C9, random.choice([0x11, 0x16])) # Randomize GT music too in keysanity mode
|
||||||
|
|
||||||
# patch entrances
|
# patch entrance/exits/holes
|
||||||
for region in world.regions:
|
for region in world.regions:
|
||||||
for exit in region.exits:
|
for exit in region.exits:
|
||||||
if exit.target is not None:
|
if exit.target is not None:
|
||||||
addresses = [exit.addresses] if isinstance(exit.addresses, int) else exit.addresses
|
if isinstance(exit.addresses, tuple):
|
||||||
for address in addresses:
|
offset = exit.target
|
||||||
rom.write_byte(address, exit.target)
|
room_id, ow_area, vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x, unknown_1, unknown_2, door_1, door_2 = exit.addresses
|
||||||
|
#room id is deliberately not written
|
||||||
|
|
||||||
|
|
||||||
|
rom.write_byte(0x15B8C + offset, ow_area)
|
||||||
|
rom.write_int16_to_rom(0x15BDB + 2 * offset, vram_loc)
|
||||||
|
rom.write_int16_to_rom(0x15C79 + 2 * offset, scroll_y)
|
||||||
|
rom.write_int16_to_rom(0x15D17 + 2 * offset, scroll_x)
|
||||||
|
|
||||||
|
# for positioning fixups we abuse the roomid as a way of identifying which exit data we are appling
|
||||||
|
# Thanks to Zarby89 for originally finding these values
|
||||||
|
# todo fix screen scrolling
|
||||||
|
|
||||||
|
if world.shuffle not in ['insanity', 'insanity_legacy', 'madness_legacy'] and \
|
||||||
|
exit.name in ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', 'Skull Woods Final Section Exit', 'Ice Palace Exit', 'Misery Mire Exit',
|
||||||
|
'Palace of Darkness Exit', 'Swamp Palace Exit', 'Ganons Tower Exit', 'Desert Palace Exit (North)', 'Agahnims Tower Exit', 'Spiral Cave Exit (Top)',
|
||||||
|
'Superbunny Cave Exit (Bottom)', 'Turtle Rock Ledge Exit (East)']:
|
||||||
|
# For exits that connot be reached from another, no need to apply offset fixes.
|
||||||
|
rom.write_int16_to_rom(0x15DB5 + 2 * offset, link_y) # same as final else
|
||||||
|
elif room_id == 0x0059 and world.fix_skullwoods_exit:
|
||||||
|
rom.write_int16_to_rom(0x15DB5 + 2 * offset, 0x00F8)
|
||||||
|
elif room_id == 0x004a and world.fix_palaceofdarkness_exit:
|
||||||
|
rom.write_int16_to_rom(0x15DB5 + 2 * offset, 0x0640)
|
||||||
|
elif room_id == 0x00d6 and world.fix_trock_exit:
|
||||||
|
rom.write_int16_to_rom(0x15DB5 + 2 * offset, 0x0134)
|
||||||
|
elif room_id == 0x000c and world.fix_gtower_exit: # fix ganons tower exit point
|
||||||
|
rom.write_int16_to_rom(0x15DB5 + 2 * offset, 0x00A4)
|
||||||
|
else:
|
||||||
|
rom.write_int16_to_rom(0x15DB5 + 2 * offset, link_y)
|
||||||
|
|
||||||
|
rom.write_int16_to_rom(0x15E53 + 2 * offset, link_x)
|
||||||
|
rom.write_int16_to_rom(0x15EF1 + 2 * offset, camera_y)
|
||||||
|
rom.write_int16_to_rom(0x15F8F + 2 * offset, camera_x)
|
||||||
|
rom.write_byte(0x1602D + offset, unknown_1)
|
||||||
|
rom.write_byte(0x1607C + offset, unknown_2)
|
||||||
|
rom.write_int16_to_rom(0x160CB + 2 * offset, door_1)
|
||||||
|
rom.write_int16_to_rom(0x16169 + 2 * offset, door_2)
|
||||||
|
elif isinstance(exit.addresses, list):
|
||||||
|
# is hole
|
||||||
|
for address in exit.addresses:
|
||||||
|
rom.write_byte(address, exit.target)
|
||||||
|
else:
|
||||||
|
# patch door table
|
||||||
|
rom.write_byte(0xDBB73 + exit.addresses, exit.target)
|
||||||
|
|
||||||
|
|
||||||
# patch medallion requirements
|
# patch medallion requirements
|
||||||
if world.required_medallions[0] == 'Bombos':
|
if world.required_medallions[0] == 'Bombos':
|
||||||
|
@ -354,6 +405,7 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
TRIFORCE_PIECE = ItemFactory('Triforce Piece').code
|
TRIFORCE_PIECE = ItemFactory('Triforce Piece').code
|
||||||
GREEN_CLOCK = ItemFactory('Green Clock').code
|
GREEN_CLOCK = ItemFactory('Green Clock').code
|
||||||
|
|
||||||
|
rom.write_byte(0x18004F, 0x01) # Byrna Invulnerability: on
|
||||||
# handle difficulty
|
# handle difficulty
|
||||||
if world.difficulty == 'hard':
|
if world.difficulty == 'hard':
|
||||||
# Powdered Fairies Prize
|
# Powdered Fairies Prize
|
||||||
|
@ -364,13 +416,13 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
rom.write_byte(0x180085, 0x40) # Half Magic
|
rom.write_byte(0x180085, 0x40) # Half Magic
|
||||||
#Cape magic cost
|
#Cape magic cost
|
||||||
rom.write_bytes(0x3ADA7, [0x02, 0x02, 0x02])
|
rom.write_bytes(0x3ADA7, [0x02, 0x02, 0x02])
|
||||||
#Byrna residual magic cost
|
# Byrna Invulnerability: off
|
||||||
rom.write_bytes(0x45C42, [0x08, 0x08, 0x08])
|
rom.write_byte(0x18004F, 0x00)
|
||||||
#Disable catching fairies
|
#Disable catching fairies
|
||||||
rom.write_byte(0x34FD6, 0x80)
|
rom.write_byte(0x34FD6, 0x80)
|
||||||
overflow_replacement = GREEN_TWENTY_RUPEES
|
overflow_replacement = GREEN_TWENTY_RUPEES
|
||||||
# Rupoor negative value
|
# Rupoor negative value
|
||||||
rom.write_int16_to_rom(0x180036, 10)
|
rom.write_int16_to_rom(0x180036, world.rupoor_cost)
|
||||||
#Make Blue Shield more expensive
|
#Make Blue Shield more expensive
|
||||||
rom.write_bytes(0xF73D2, [0xFC, 0xFF])
|
rom.write_bytes(0xF73D2, [0xFC, 0xFF])
|
||||||
rom.write_bytes(0xF73DA, [0x04, 0x00])
|
rom.write_bytes(0xF73DA, [0x04, 0x00])
|
||||||
|
@ -398,8 +450,8 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
rom.write_byte(0x180085, 0x20) # Quarter Magic
|
rom.write_byte(0x180085, 0x20) # Quarter Magic
|
||||||
#Cape magic cost
|
#Cape magic cost
|
||||||
rom.write_bytes(0x3ADA7, [0x02, 0x02, 0x02])
|
rom.write_bytes(0x3ADA7, [0x02, 0x02, 0x02])
|
||||||
#Byrna residual magic cost
|
# Byrna Invulnerability: off
|
||||||
rom.write_bytes(0x45C42, [0x08, 0x08, 0x08])
|
rom.write_byte(0x18004F, 0x00)
|
||||||
#Disable catching fairies
|
#Disable catching fairies
|
||||||
rom.write_byte(0x34FD6, 0x80)
|
rom.write_byte(0x34FD6, 0x80)
|
||||||
overflow_replacement = GREEN_TWENTY_RUPEES
|
overflow_replacement = GREEN_TWENTY_RUPEES
|
||||||
|
@ -432,8 +484,8 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
rom.write_byte(0x180085, 0x00) # No healing
|
rom.write_byte(0x180085, 0x00) # No healing
|
||||||
#Cape magic cost
|
#Cape magic cost
|
||||||
rom.write_bytes(0x3ADA7, [0x02, 0x02, 0x02])
|
rom.write_bytes(0x3ADA7, [0x02, 0x02, 0x02])
|
||||||
#Byrna residual magic cost
|
# Byrna Invulnerability: off
|
||||||
rom.write_bytes(0x45C42, [0x08, 0x08, 0x08])
|
rom.write_byte(0x18004F, 0x00)
|
||||||
#Disable catching fairies
|
#Disable catching fairies
|
||||||
rom.write_byte(0x34FD6, 0x80)
|
rom.write_byte(0x34FD6, 0x80)
|
||||||
overflow_replacement = GREEN_TWENTY_RUPEES
|
overflow_replacement = GREEN_TWENTY_RUPEES
|
||||||
|
@ -466,8 +518,8 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
rom.write_byte(0x180085, 0x80) # full
|
rom.write_byte(0x180085, 0x80) # full
|
||||||
#Cape magic cost
|
#Cape magic cost
|
||||||
rom.write_bytes(0x3ADA7, [0x04, 0x08, 0x10])
|
rom.write_bytes(0x3ADA7, [0x04, 0x08, 0x10])
|
||||||
#Byrna residual magic cost
|
# Byrna Invulnerability: on
|
||||||
rom.write_bytes(0x45C42, [0x04, 0x02, 0x01])
|
rom.write_byte(0x18004F, 0x01)
|
||||||
#Enable catching fairies
|
#Enable catching fairies
|
||||||
rom.write_byte(0x34FD6, 0xF0)
|
rom.write_byte(0x34FD6, 0xF0)
|
||||||
#Set overflow items for progressive equipment
|
#Set overflow items for progressive equipment
|
||||||
|
@ -478,6 +530,9 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
else:
|
else:
|
||||||
overflow_replacement = GREEN_TWENTY_RUPEES
|
overflow_replacement = GREEN_TWENTY_RUPEES
|
||||||
|
|
||||||
|
#Byrna residual magic cost
|
||||||
|
rom.write_bytes(0x45C42, [0x04, 0x02, 0x01])
|
||||||
|
|
||||||
difficulty = world.difficulty_requirements
|
difficulty = world.difficulty_requirements
|
||||||
#Set overflow items for progressive equipment
|
#Set overflow items for progressive equipment
|
||||||
rom.write_bytes(0x180090,
|
rom.write_bytes(0x180090,
|
||||||
|
@ -548,6 +603,20 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
for prize, address in zip(bonk_prizes, bonk_addresses):
|
for prize, address in zip(bonk_prizes, bonk_addresses):
|
||||||
rom.write_byte(address, prize)
|
rom.write_byte(address, prize)
|
||||||
|
|
||||||
|
# Fill in item substitutions table
|
||||||
|
if world.difficulty in ['easy']:
|
||||||
|
rom.write_bytes(0x184000, [
|
||||||
|
# original_item, limit, replacement_item, filler
|
||||||
|
0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees
|
||||||
|
0x58, 0x01, 0x43, 0xFF, # silver arrows -> 1 arrow
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, # end of table sentinel
|
||||||
|
])
|
||||||
|
else:
|
||||||
|
rom.write_bytes(0x184000, [
|
||||||
|
# original_item, limit, replacement_item, filler
|
||||||
|
0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, # end of table sentinel
|
||||||
|
])
|
||||||
|
|
||||||
# set Fountain bottle exchange items
|
# set Fountain bottle exchange items
|
||||||
if world.difficulty in ['hard', 'expert', 'insane']:
|
if world.difficulty in ['hard', 'expert', 'insane']:
|
||||||
|
@ -637,11 +706,14 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
# TODO: a proper race rom mode should be implemented, that changes the following flag, and rummages the table (or uses the future encryption feature, etc)
|
# TODO: a proper race rom mode should be implemented, that changes the following flag, and rummages the table (or uses the future encryption feature, etc)
|
||||||
rom.write_bytes(0x180213, [0x00, 0x01]) # Not a Tournament Seed
|
rom.write_bytes(0x180213, [0x00, 0x01]) # Not a Tournament Seed
|
||||||
|
|
||||||
|
rom.write_byte(0x180211, 0x06) #Game type, we set the Entrance and item randomization flags
|
||||||
|
|
||||||
# assorted fixes
|
# assorted fixes
|
||||||
rom.write_byte(0x180030, 0x00) # Disable SRAM trace
|
rom.write_byte(0x180030, 0x00) # Disable SRAM trace
|
||||||
rom.write_byte(0x1800A2, 0x01) # remain in real dark world when dying in dark word dungion before killing aga1
|
rom.write_byte(0x1800A2, 0x01) # remain in real dark world when dying in dark word dungion before killing aga1
|
||||||
rom.write_byte(0x180169, 0x01 if world.lock_aga_door_in_escape else 0x00) # Lock or unlock aga tower door during escape sequence.
|
rom.write_byte(0x180169, 0x01 if world.lock_aga_door_in_escape else 0x00) # Lock or unlock aga tower door during escape sequence.
|
||||||
rom.write_byte(0x180171, 0x01 if world.ganon_at_pyramid else 0x00) # Enable respawning on pyramid after ganon death
|
rom.write_byte(0x180171, 0x01 if world.ganon_at_pyramid else 0x00) # Enable respawning on pyramid after ganon death
|
||||||
|
rom.write_byte(0x180173, 0x01) # Bob is enabled
|
||||||
rom.write_byte(0x180168, 0x08) # Spike Cave Damage
|
rom.write_byte(0x180168, 0x08) # Spike Cave Damage
|
||||||
rom.write_bytes(0x18016B, [0x04, 0x02, 0x01]) #Set spike cave and MM spike room Cape usage
|
rom.write_bytes(0x18016B, [0x04, 0x02, 0x01]) #Set spike cave and MM spike room Cape usage
|
||||||
rom.write_bytes(0x18016E, [0x04, 0x08, 0x10]) #Set spike cave and MM spike room Cape usage
|
rom.write_bytes(0x18016E, [0x04, 0x08, 0x10]) #Set spike cave and MM spike room Cape usage
|
||||||
|
@ -653,8 +725,26 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
rom.write_byte(0x180086, 0x00 if world.aga_randomness else 0x01) # set blue ball and ganon warp randomness
|
rom.write_byte(0x180086, 0x00 if world.aga_randomness else 0x01) # set blue ball and ganon warp randomness
|
||||||
rom.write_byte(0x1800A0, 0x01) # return to light world on s+q without mirror
|
rom.write_byte(0x1800A0, 0x01) # return to light world on s+q without mirror
|
||||||
rom.write_byte(0x1800A1, 0x01) # enable overworld screen transition draining for water level inside swamp
|
rom.write_byte(0x1800A1, 0x01) # enable overworld screen transition draining for water level inside swamp
|
||||||
|
rom.write_byte(0x180174, 0x01 if world.fix_fake_world else 0x00)
|
||||||
|
rom.write_byte(0x180175, 0x00) # Arrow mode: normal
|
||||||
|
rom.write_int16_to_rom(0x180176, 0) # Wood Arrow Cost (rupee arrow mode)
|
||||||
|
rom.write_int16_to_rom(0x180178, 0) # Silver Arrow Cost (rupee arrow mode)
|
||||||
rom.write_byte(0x180034, 0x0A) # starting max bombs
|
rom.write_byte(0x180034, 0x0A) # starting max bombs
|
||||||
rom.write_byte(0x180035, 30) # starting max bombs
|
rom.write_byte(0x180035, 30) # starting max arrows
|
||||||
|
for x in range(0x183000, 0x18304F):
|
||||||
|
rom.write_byte(x, 0) # Zero the initial equipment array
|
||||||
|
rom.write_byte(0x18302C, 0x18) # starting max health
|
||||||
|
rom.write_byte(0x18302D, 0x18) # starting current health
|
||||||
|
rom.write_byte(0x183039, 0x68) # starting abilities, bit array
|
||||||
|
rom.write_byte(0x18004A, 0x00) # Inverted mode (off)
|
||||||
|
rom.write_byte(0x2AF79, 0xD0) # vortexes: Normal (D0=light to dark, F0=dark to light, 42 = both)
|
||||||
|
rom.write_byte(0x3A943, 0xD0) # Mirror: Normal (D0=Dark to Light, F0=light to dark, 42 = both)
|
||||||
|
rom.write_byte(0x3A96D, 0xF0) # Residual Portal: Normal (F0= Light Side, D0=Dark Side, 42 = both (Darth Vader))
|
||||||
|
rom.write_byte(0x3A9A7, 0xD0) # Residual Portal: Normal (D0= Light Side, F0=Dark Side, 42 = both (Darth Vader))
|
||||||
|
|
||||||
|
rom.write_byte(0x18004D, 0x00) # Escape assist (off)
|
||||||
|
rom.write_byte(0x18004E, 0x00) # uncle Refill (off)
|
||||||
|
|
||||||
|
|
||||||
if world.goal in ['pedestal', 'triforcehunt']:
|
if world.goal in ['pedestal', 'triforcehunt']:
|
||||||
rom.write_byte(0x18003E, 0x01) # make ganon invincible
|
rom.write_byte(0x18003E, 0x01) # make ganon invincible
|
||||||
|
@ -694,10 +784,20 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
rom.write_bytes(0x6D2FB, [0x00, 0x00, 0xf7, 0xff, 0x02, 0x0E])
|
rom.write_bytes(0x6D2FB, [0x00, 0x00, 0xf7, 0xff, 0x02, 0x0E])
|
||||||
rom.write_bytes(0x6D313, [0x00, 0x00, 0xe4, 0xff, 0x08, 0x0E])
|
rom.write_bytes(0x6D313, [0x00, 0x00, 0xe4, 0xff, 0x08, 0x0E])
|
||||||
|
|
||||||
|
# Shop table
|
||||||
|
rom.write_bytes(0x184800, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])
|
||||||
|
|
||||||
# patch swamp: Need to enable permanent drain of water as dam or swamp were moved
|
# patch swamp: Need to enable permanent drain of water as dam or swamp were moved
|
||||||
rom.write_byte(0x18003D, 0x01 if world.swamp_patch_required else 0x00)
|
rom.write_byte(0x18003D, 0x01 if world.swamp_patch_required else 0x00)
|
||||||
|
|
||||||
|
# powder patch: remove the need to leave the scrren after powder, since it causes problems for potion shop at race game
|
||||||
|
# temporarally we are just nopping out this check we will conver this to a rom fix soon.
|
||||||
|
rom.write_bytes(0x02F539,[0xEA,0xEA,0xEA,0xEA,0xEA] if world.powder_patch_required else [0xAD, 0xBF, 0x0A, 0xF0, 0x4F])
|
||||||
|
|
||||||
|
# allow smith into multi-entrance caves in appropriate shuffles
|
||||||
|
if world.shuffle in ['restricted', 'full', 'crossed', 'insanity']:
|
||||||
|
rom.write_byte(0x18004C, 0x01)
|
||||||
|
|
||||||
# set correct flag for hera basement item
|
# set correct flag for hera basement item
|
||||||
if world.get_location('Tower of Hera - Basement Cage').item is not None and world.get_location('Tower of Hera - Basement Cage').item.name == 'Small Key (Tower of Hera)':
|
if world.get_location('Tower of Hera - Basement Cage').item is not None and world.get_location('Tower of Hera - Basement Cage').item.name == 'Small Key (Tower of Hera)':
|
||||||
rom.write_byte(0x4E3BB, 0xE4)
|
rom.write_byte(0x4E3BB, 0xE4)
|
||||||
|
@ -714,34 +814,20 @@ def patch_rom(world, rom, hashtable, beep='normal', sprite=None):
|
||||||
rom.write_byte(0xFED31, 0x2A) # preopen bombable exit
|
rom.write_byte(0xFED31, 0x2A) # preopen bombable exit
|
||||||
rom.write_byte(0xFEE41, 0x2A) # preopen bombable exit
|
rom.write_byte(0xFEE41, 0x2A) # preopen bombable exit
|
||||||
|
|
||||||
# Thanks to Zarby89 for finding these values
|
|
||||||
# fix skull woods exit point
|
|
||||||
rom.write_byte(0x15E0D, 0xF8 if world.fix_skullwoods_exit else 0xB8)
|
|
||||||
|
|
||||||
# fix palace of darkness exit point
|
|
||||||
rom.write_byte(0x15E03, 0x40 if world.fix_palaceofdarkness_exit else 0x28)
|
|
||||||
|
|
||||||
# fix turtle rock exit point
|
|
||||||
rom.write_byte(0x15E1D, 0x34 if world.fix_trock_exit else 0x28)
|
|
||||||
|
|
||||||
# fix ganons tower exit point
|
|
||||||
rom.write_byte(0x15E25, 0xA4 if world.fix_gtower_exit else 0x28)
|
|
||||||
# todo fix screen scrolling
|
|
||||||
|
|
||||||
write_strings(rom, world)
|
write_strings(rom, world)
|
||||||
|
|
||||||
# set rom name
|
# set rom name
|
||||||
# 21 bytes
|
# 21 bytes
|
||||||
rom.write_bytes(0x7FC0, bytearray('ER_052_%09d\0' % world.seed, 'utf8') + world.option_identifier.to_bytes(4, 'big'))
|
rom.write_bytes(0x7FC0, bytearray('ER_060_%09d\0' % world.seed, 'utf8') + world.option_identifier.to_bytes(4, 'big'))
|
||||||
|
|
||||||
# store hash table for main menu hash
|
# store hash table for main menu hash
|
||||||
rom.write_bytes(0x187F00, hashtable)
|
rom.write_bytes(0x187F00, hashtable)
|
||||||
|
|
||||||
apply_rom_settings(rom, beep, world.quickswap, world.fastmenu, world.disable_music, sprite)
|
apply_rom_settings(rom, beep, color, world.quickswap, world.fastmenu, world.disable_music, sprite)
|
||||||
|
|
||||||
return rom
|
return rom
|
||||||
|
|
||||||
def apply_rom_settings(rom, beep, quickswap, fastmenu, disable_music, sprite):
|
def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite):
|
||||||
|
|
||||||
# enable instant item menu
|
# enable instant item menu
|
||||||
if fastmenu == 'instant':
|
if fastmenu == 'instant':
|
||||||
|
@ -765,99 +851,92 @@ def apply_rom_settings(rom, beep, quickswap, fastmenu, disable_music, sprite):
|
||||||
else:
|
else:
|
||||||
rom.write_byte(0x180048, 0x08)
|
rom.write_byte(0x180048, 0x08)
|
||||||
|
|
||||||
# enable quick item swapping with L and R (ported by Amazing Ampharos)
|
rom.write_byte(0x18004B, 0x01 if quickswap else 0x00)
|
||||||
if quickswap:
|
|
||||||
rom.write_bytes(0x107fb, [0x22, 0x50, 0xFF, 0x1F])
|
|
||||||
rom.write_bytes(0x12451, [0x22, 0x50, 0xFF, 0x1F])
|
|
||||||
rom.write_bytes(0xfff50, [0x20, 0x58, 0xFF, 0xA5, 0xF6, 0x29, 0x40, 0x6B, 0xA5, 0xF6, 0x89, 0x10, 0xF0, 0x03, 0x4C, 0x69,
|
|
||||||
0xFF, 0x89, 0x20, 0xF0, 0x03, 0x4C, 0xAA, 0xFF, 0x60, 0xAD, 0x02, 0x02, 0xF0, 0x3B, 0xDA, 0xAA,
|
|
||||||
0xE0, 0x0F, 0xF0, 0x14, 0xE0, 0x10, 0xF0, 0x14, 0xE0, 0x14, 0xD0, 0x02, 0xA2, 0x00, 0xE8, 0xBF,
|
|
||||||
0x3F, 0xF3, 0x7E, 0xF0, 0xEB, 0x4C, 0xEB, 0xFF, 0xA2, 0x01, 0x80, 0x0A, 0xAF, 0x4F, 0xF3, 0x7E,
|
|
||||||
0xAA, 0xE0, 0x04, 0xF0, 0x10, 0xE8, 0xBF, 0x5B, 0xF3, 0x7E, 0xF0, 0xF5, 0x8A, 0x8F, 0x4F, 0xF3,
|
|
||||||
0x7E, 0xA2, 0x10, 0x80, 0xE0, 0xA2, 0x11, 0x80, 0xD6, 0x60, 0xAD, 0x02, 0x02, 0xF0, 0x3B, 0xDA,
|
|
||||||
0xAA, 0xE0, 0x11, 0xF0, 0x14, 0xE0, 0x10, 0xF0, 0x14, 0xE0, 0x01, 0xD0, 0x02, 0xA2, 0x15, 0xCA,
|
|
||||||
0xBF, 0x3F, 0xF3, 0x7E, 0xF0, 0xEB, 0x4C, 0xEB, 0xFF, 0xA2, 0x04, 0x80, 0x0A, 0xAF, 0x4F, 0xF3,
|
|
||||||
0x7E, 0xAA, 0xE0, 0x01, 0xF0, 0x10, 0xCA, 0xBF, 0x5B, 0xF3, 0x7E, 0xF0, 0xF5, 0x8A, 0x8F, 0x4F,
|
|
||||||
0xF3, 0x7E, 0xA2, 0x10, 0x80, 0xE0, 0xA2, 0x0F, 0x80, 0xD6, 0x60, 0xA9, 0x20, 0x8D, 0x2F, 0x01,
|
|
||||||
0x8E, 0x02, 0x02, 0x22, 0x7F, 0xDB, 0x0D, 0xFA, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])
|
|
||||||
else:
|
|
||||||
rom.write_bytes(0x107fb, [0xa5, 0xf6, 0x29, 0x40])
|
|
||||||
rom.write_bytes(0x12451, [0xa5, 0xf6, 0x29, 0x40])
|
|
||||||
rom.write_bytes(0xfff50, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])
|
|
||||||
|
|
||||||
music_volumes = [
|
music_volumes = [
|
||||||
(0x00, [0xD373B, 0xD375B, 0xD90F8]),
|
(0x00, [0xD373B, 0xD375B, 0xD90F8]),
|
||||||
(0x14, [0xDA710, 0xDA7A4, 0xDA7BB, 0xDA7D2]),
|
(0x14, [0xDA710, 0xDA7A4, 0xDA7BB, 0xDA7D2]),
|
||||||
(0x3C, [0xD5954, 0xD653B, 0xDA736, 0xDA752, 0xDA772, 0xDA792]),
|
(0x3C, [0xD5954, 0xD653B, 0xDA736, 0xDA752, 0xDA772, 0xDA792]),
|
||||||
(0x50, [0xD5B47, 0xD5B5E]),
|
(0x50, [0xD5B47, 0xD5B5E]),
|
||||||
(0x54, [0xD4306]),
|
(0x54, [0xD4306]),
|
||||||
(0x64, [0xD6878, 0xD6883, 0xD6E48, 0xD6E76, 0xD6EFB, 0xD6F2D, 0xDA211, 0xDA35B, 0xDA37B, 0xDA38E, 0xDA39F, 0xDA5C3, 0xDA691, 0xDA6A8, 0xDA6DF]),
|
(0x64, [0xD6878, 0xD6883, 0xD6E48, 0xD6E76, 0xD6EFB, 0xD6F2D, 0xDA211, 0xDA35B, 0xDA37B, 0xDA38E, 0xDA39F, 0xDA5C3, 0xDA691, 0xDA6A8, 0xDA6DF]),
|
||||||
(0x78, [0xD2349, 0xD3F45, 0xD42EB, 0xD48B9, 0xD48FF, 0xD543F, 0xD5817, 0xD5957, 0xD5ACB, 0xD5AE8, 0xD5B4A, 0xDA5DE, 0xDA608, 0xDA635,
|
(0x78, [0xD2349, 0xD3F45, 0xD42EB, 0xD48B9, 0xD48FF, 0xD543F, 0xD5817, 0xD5957, 0xD5ACB, 0xD5AE8, 0xD5B4A, 0xDA5DE, 0xDA608, 0xDA635,
|
||||||
0xDA662, 0xDA71F, 0xDA7AF, 0xDA7C6, 0xDA7DD]),
|
0xDA662, 0xDA71F, 0xDA7AF, 0xDA7C6, 0xDA7DD]),
|
||||||
(0x82, [0xD2F00, 0xDA3D5]),
|
(0x82, [0xD2F00, 0xDA3D5]),
|
||||||
(0xA0, [0xD249C, 0xD24CD, 0xD2C09, 0xD2C53, 0xD2CAF, 0xD2CEB, 0xD2D91, 0xD2EE6, 0xD38ED, 0xD3C91, 0xD3CD3, 0xD3CE8, 0xD3F0C,
|
(0xA0, [0xD249C, 0xD24CD, 0xD2C09, 0xD2C53, 0xD2CAF, 0xD2CEB, 0xD2D91, 0xD2EE6, 0xD38ED, 0xD3C91, 0xD3CD3, 0xD3CE8, 0xD3F0C,
|
||||||
0xD3F82, 0xD405F, 0xD4139, 0xD4198, 0xD41D5, 0xD41F6, 0xD422B, 0xD4270, 0xD42B1, 0xD4334, 0xD4371, 0xD43A6, 0xD43DB,
|
0xD3F82, 0xD405F, 0xD4139, 0xD4198, 0xD41D5, 0xD41F6, 0xD422B, 0xD4270, 0xD42B1, 0xD4334, 0xD4371, 0xD43A6, 0xD43DB,
|
||||||
0xD441E, 0xD4597, 0xD4B3C, 0xD4BAB, 0xD4C03, 0xD4C53, 0xD4C7F, 0xD4D9C, 0xD5424, 0xD65D2, 0xD664F, 0xD6698, 0xD66FF,
|
0xD441E, 0xD4597, 0xD4B3C, 0xD4BAB, 0xD4C03, 0xD4C53, 0xD4C7F, 0xD4D9C, 0xD5424, 0xD65D2, 0xD664F, 0xD6698, 0xD66FF,
|
||||||
0xD6985, 0xD6C5C, 0xD6C6F, 0xD6C8E, 0xD6CB4, 0xD6D7D, 0xD827D, 0xD960C, 0xD9828, 0xDA233, 0xDA3A2, 0xDA49E, 0xDA72B,
|
0xD6985, 0xD6C5C, 0xD6C6F, 0xD6C8E, 0xD6CB4, 0xD6D7D, 0xD827D, 0xD960C, 0xD9828, 0xDA233, 0xDA3A2, 0xDA49E, 0xDA72B,
|
||||||
0xDA745, 0xDA765, 0xDA785, 0xDABF6, 0xDAC0D, 0xDAEBE, 0xDAFAC]),
|
0xDA745, 0xDA765, 0xDA785, 0xDABF6, 0xDAC0D, 0xDAEBE, 0xDAFAC]),
|
||||||
(0xAA, [0xD9A02, 0xD9BD6]),
|
(0xAA, [0xD9A02, 0xD9BD6]),
|
||||||
(0xB4, [0xD21CD, 0xD2279, 0xD2E66, 0xD2E70, 0xD2EAB, 0xD3B97, 0xD3BAC, 0xD3BE8, 0xD3C0D, 0xD3C39, 0xD3C68, 0xD3C9F, 0xD3CBC,
|
(0xB4, [0xD21CD, 0xD2279, 0xD2E66, 0xD2E70, 0xD2EAB, 0xD3B97, 0xD3BAC, 0xD3BE8, 0xD3C0D, 0xD3C39, 0xD3C68, 0xD3C9F, 0xD3CBC,
|
||||||
0xD401E, 0xD4290, 0xD443E, 0xD456F, 0xD47D3, 0xD4D43, 0xD4DCC, 0xD4EBA, 0xD4F0B, 0xD4FE5, 0xD5012, 0xD54BC, 0xD54D5,
|
0xD401E, 0xD4290, 0xD443E, 0xD456F, 0xD47D3, 0xD4D43, 0xD4DCC, 0xD4EBA, 0xD4F0B, 0xD4FE5, 0xD5012, 0xD54BC, 0xD54D5,
|
||||||
0xD54F0, 0xD5509, 0xD57D8, 0xD59B9, 0xD5A2F, 0xD5AEB, 0xD5E5E, 0xD5FE9, 0xD658F, 0xD674A, 0xD6827, 0xD69D6, 0xD69F5,
|
0xD54F0, 0xD5509, 0xD57D8, 0xD59B9, 0xD5A2F, 0xD5AEB, 0xD5E5E, 0xD5FE9, 0xD658F, 0xD674A, 0xD6827, 0xD69D6, 0xD69F5,
|
||||||
0xD6A05, 0xD6AE9, 0xD6DCF, 0xD6E20, 0xD6ECB, 0xD71D4, 0xD71E6, 0xD7203, 0xD721E, 0xD8724, 0xD8732, 0xD9652, 0xD9698,
|
0xD6A05, 0xD6AE9, 0xD6DCF, 0xD6E20, 0xD6ECB, 0xD71D4, 0xD71E6, 0xD7203, 0xD721E, 0xD8724, 0xD8732, 0xD9652, 0xD9698,
|
||||||
0xD9CBC, 0xD9DC0, 0xD9E49, 0xDAA68, 0xDAA77, 0xDAA88, 0xDAA99, 0xDAF04]),
|
0xD9CBC, 0xD9DC0, 0xD9E49, 0xDAA68, 0xDAA77, 0xDAA88, 0xDAA99, 0xDAF04]),
|
||||||
(0x8c, [0xD1D28, 0xD1D41, 0xD1D5C, 0xD1D77, 0xD1EEE, 0xD311D, 0xD31D1, 0xD4148, 0xD5543, 0xD5B6F, 0xD65B3, 0xD6760, 0xD6B6B,
|
(0x8c, [0xD1D28, 0xD1D41, 0xD1D5C, 0xD1D77, 0xD1EEE, 0xD311D, 0xD31D1, 0xD4148, 0xD5543, 0xD5B6F, 0xD65B3, 0xD6760, 0xD6B6B,
|
||||||
0xD6DF6, 0xD6E0D, 0xD73A1, 0xD814C, 0xD825D, 0xD82BE, 0xD8340, 0xD8394, 0xD842C, 0xD8796, 0xD8903, 0xD892A, 0xD91E8,
|
0xD6DF6, 0xD6E0D, 0xD73A1, 0xD814C, 0xD825D, 0xD82BE, 0xD8340, 0xD8394, 0xD842C, 0xD8796, 0xD8903, 0xD892A, 0xD91E8,
|
||||||
0xD922B, 0xD92E0, 0xD937E, 0xD93C1, 0xDA958, 0xDA971, 0xDA98C, 0xDA9A7]),
|
0xD922B, 0xD92E0, 0xD937E, 0xD93C1, 0xDA958, 0xDA971, 0xDA98C, 0xDA9A7]),
|
||||||
(0xC8, [0xD1D92, 0xD1DBD, 0xD1DEB, 0xD1F5D, 0xD1F9F, 0xD1FBD, 0xD1FDC, 0xD1FEA, 0xD20CA, 0xD21BB, 0xD22C9, 0xD2754, 0xD284C,
|
(0xC8, [0xD1D92, 0xD1DBD, 0xD1DEB, 0xD1F5D, 0xD1F9F, 0xD1FBD, 0xD1FDC, 0xD1FEA, 0xD20CA, 0xD21BB, 0xD22C9, 0xD2754, 0xD284C,
|
||||||
0xD2866, 0xD2887, 0xD28A0, 0xD28BA, 0xD28DB, 0xD28F4, 0xD293E, 0xD2BF3, 0xD2C1F, 0xD2C69, 0xD2CA1, 0xD2CC5, 0xD2D05,
|
0xD2866, 0xD2887, 0xD28A0, 0xD28BA, 0xD28DB, 0xD28F4, 0xD293E, 0xD2BF3, 0xD2C1F, 0xD2C69, 0xD2CA1, 0xD2CC5, 0xD2D05,
|
||||||
0xD2D73, 0xD2DAF, 0xD2E3D, 0xD2F36, 0xD2F46, 0xD2F6F, 0xD2FCF, 0xD2FDF, 0xD302B, 0xD3086, 0xD3099, 0xD30A5, 0xD30CD,
|
0xD2D73, 0xD2DAF, 0xD2E3D, 0xD2F36, 0xD2F46, 0xD2F6F, 0xD2FCF, 0xD2FDF, 0xD302B, 0xD3086, 0xD3099, 0xD30A5, 0xD30CD,
|
||||||
0xD30F6, 0xD3154, 0xD3184, 0xD333A, 0xD33D9, 0xD349F, 0xD354A, 0xD35E5, 0xD3624, 0xD363C, 0xD3672, 0xD3691, 0xD36B4,
|
0xD30F6, 0xD3154, 0xD3184, 0xD333A, 0xD33D9, 0xD349F, 0xD354A, 0xD35E5, 0xD3624, 0xD363C, 0xD3672, 0xD3691, 0xD36B4,
|
||||||
0xD36C6, 0xD3724, 0xD3767, 0xD38CB, 0xD3B1D, 0xD3B2F, 0xD3B55, 0xD3B70, 0xD3B81, 0xD3BBF, 0xD3D34, 0xD3D55, 0xD3D6E,
|
0xD36C6, 0xD3724, 0xD3767, 0xD38CB, 0xD3B1D, 0xD3B2F, 0xD3B55, 0xD3B70, 0xD3B81, 0xD3BBF, 0xD3F65, 0xD3FA6, 0xD404F,
|
||||||
0xD3DC6, 0xD3E04, 0xD3E38, 0xD3F65, 0xD3FA6, 0xD404F, 0xD4087, 0xD417A, 0xD41A0, 0xD425C, 0xD4319, 0xD433C, 0xD43EF,
|
0xD4087, 0xD417A, 0xD41A0, 0xD425C, 0xD4319, 0xD433C, 0xD43EF, 0xD440C, 0xD4452, 0xD4494, 0xD44B5, 0xD4512, 0xD45D1,
|
||||||
0xD440C, 0xD4452, 0xD4494, 0xD44B5, 0xD4512, 0xD45D1, 0xD45EF, 0xD4682, 0xD46C3, 0xD483C, 0xD4848, 0xD4855, 0xD4862,
|
0xD45EF, 0xD4682, 0xD46C3, 0xD483C, 0xD4848, 0xD4855, 0xD4862, 0xD486F, 0xD487C, 0xD4A1C, 0xD4A3B, 0xD4A60, 0xD4B27,
|
||||||
0xD486F, 0xD487C, 0xD4A1C, 0xD4A3B, 0xD4A60, 0xD4B27, 0xD4C7A, 0xD4D12, 0xD4D81, 0xD4E90, 0xD4ED6, 0xD4EE2, 0xD5005,
|
0xD4C7A, 0xD4D12, 0xD4D81, 0xD4E90, 0xD4ED6, 0xD4EE2, 0xD5005, 0xD502E, 0xD503C, 0xD5081, 0xD51B1, 0xD51C7, 0xD51CF,
|
||||||
0xD502E, 0xD503C, 0xD5081, 0xD51B1, 0xD51C7, 0xD51CF, 0xD51EF, 0xD520C, 0xD5214, 0xD5231, 0xD5257, 0xD526D, 0xD5275,
|
0xD51EF, 0xD520C, 0xD5214, 0xD5231, 0xD5257, 0xD526D, 0xD5275, 0xD52AF, 0xD52BD, 0xD52CD, 0xD52DB, 0xD549C, 0xD5801,
|
||||||
0xD52AF, 0xD52BD, 0xD52CD, 0xD52DB, 0xD549C, 0xD5801, 0xD58A4, 0xD5A68, 0xD5A7F, 0xD5C12, 0xD5D71, 0xD5E10, 0xD5E9A,
|
0xD58A4, 0xD5A68, 0xD5A7F, 0xD5C12, 0xD5D71, 0xD5E10, 0xD5E9A, 0xD5F8B, 0xD5FA4, 0xD651A, 0xD6542, 0xD65ED, 0xD661D,
|
||||||
0xD5F8B, 0xD5FA4, 0xD651A, 0xD6542, 0xD65ED, 0xD661D, 0xD66D7, 0xD6776, 0xD68BD, 0xD68E5, 0xD6956, 0xD6973, 0xD69A8,
|
0xD66D7, 0xD6776, 0xD68BD, 0xD68E5, 0xD6956, 0xD6973, 0xD69A8, 0xD6A51, 0xD6A86, 0xD6B96, 0xD6C3E, 0xD6D4A, 0xD6E9C,
|
||||||
0xD6A51, 0xD6A86, 0xD6B96, 0xD6C3E, 0xD6D4A, 0xD6E9C, 0xD6F80, 0xD717E, 0xD7190, 0xD71B9, 0xD811D, 0xD8139, 0xD816B,
|
0xD6F80, 0xD717E, 0xD7190, 0xD71B9, 0xD811D, 0xD8139, 0xD816B, 0xD818A, 0xD819E, 0xD81BE, 0xD829C, 0xD82E1, 0xD8306,
|
||||||
0xD818A, 0xD819E, 0xD81BE, 0xD829C, 0xD82E1, 0xD8306, 0xD830E, 0xD835E, 0xD83AB, 0xD83CA, 0xD83F0, 0xD83F8, 0xD844B,
|
0xD830E, 0xD835E, 0xD83AB, 0xD83CA, 0xD83F0, 0xD83F8, 0xD844B, 0xD8479, 0xD849E, 0xD84CB, 0xD84EB, 0xD84F3, 0xD854A,
|
||||||
0xD8479, 0xD849E, 0xD84CB, 0xD84EB, 0xD84F3, 0xD854A, 0xD8573, 0xD859D, 0xD85B4, 0xD85CE, 0xD862A, 0xD8681, 0xD87E3,
|
0xD8573, 0xD859D, 0xD85B4, 0xD85CE, 0xD862A, 0xD8681, 0xD87E3, 0xD87FF, 0xD887B, 0xD88C6, 0xD88E3, 0xD8944, 0xD897B,
|
||||||
0xD87FF, 0xD887B, 0xD88C6, 0xD88E3, 0xD8944, 0xD897B, 0xD8C97, 0xD8CA4, 0xD8CB3, 0xD8CC2, 0xD8CD1, 0xD8D01, 0xD917B,
|
0xD8C97, 0xD8CA4, 0xD8CB3, 0xD8CC2, 0xD8CD1, 0xD8D01, 0xD917B, 0xD918C, 0xD919A, 0xD91B5, 0xD91D0, 0xD91DD, 0xD9220,
|
||||||
0xD918C, 0xD919A, 0xD91B5, 0xD91D0, 0xD91DD, 0xD9220, 0xD9273, 0xD9284, 0xD9292, 0xD92AD, 0xD92C8, 0xD92D5, 0xD9311,
|
0xD9273, 0xD9284, 0xD9292, 0xD92AD, 0xD92C8, 0xD92D5, 0xD9311, 0xD9322, 0xD9330, 0xD934B, 0xD9366, 0xD9373, 0xD93B6,
|
||||||
0xD9322, 0xD9330, 0xD934B, 0xD9366, 0xD9373, 0xD93B6, 0xD97A6, 0xD97C2, 0xD97DC, 0xD97FB, 0xD9811, 0xD98FF, 0xD996F,
|
0xD97A6, 0xD97C2, 0xD97DC, 0xD97FB, 0xD9811, 0xD98FF, 0xD996F, 0xD99A8, 0xD99D5, 0xD9A30, 0xD9A4E, 0xD9A6B, 0xD9A88,
|
||||||
0xD99A8, 0xD99D5, 0xD9A30, 0xD9A4E, 0xD9A6B, 0xD9A88, 0xD9AF7, 0xD9B1D, 0xD9B43, 0xD9B7C, 0xD9BA9, 0xD9C84, 0xD9C8D,
|
0xD9AF7, 0xD9B1D, 0xD9B43, 0xD9B7C, 0xD9BA9, 0xD9C84, 0xD9C8D, 0xD9CAC, 0xD9CE8, 0xD9CF3, 0xD9CFD, 0xD9D46, 0xDA35E,
|
||||||
0xD9CAC, 0xD9CE8, 0xD9CF3, 0xD9CFD, 0xD9D46, 0xDA35E, 0xDA37E, 0xDA391, 0xDA478, 0xDA4C3, 0xDA4D7, 0xDA4F6, 0xDA515,
|
0xDA37E, 0xDA391, 0xDA478, 0xDA4C3, 0xDA4D7, 0xDA4F6, 0xDA515, 0xDA6E2, 0xDA9C2, 0xDA9ED, 0xDAA1B, 0xDAA57, 0xDABAF,
|
||||||
0xDA6E2, 0xDA9C2, 0xDA9ED, 0xDAA1B, 0xDAA57, 0xDABAF, 0xDABC9, 0xDABE2, 0xDAC28, 0xDAC46, 0xDAC63, 0xDACB8, 0xDACEC,
|
0xDABC9, 0xDABE2, 0xDAC28, 0xDAC46, 0xDAC63, 0xDACB8, 0xDACEC, 0xDAD08, 0xDAD25, 0xDAD42, 0xDAD5F, 0xDAE17, 0xDAE34,
|
||||||
0xDAD08, 0xDAD25, 0xDAD42, 0xDAD5F, 0xDAE17, 0xDAE34, 0xDAE51, 0xDAF2E, 0xDAF55, 0xDAF6B, 0xDAF81, 0xDB14F, 0xDB16B,
|
0xDAE51, 0xDAF2E, 0xDAF55, 0xDAF6B, 0xDAF81, 0xDB14F, 0xDB16B, 0xDB180, 0xDB195, 0xDB1AA]),
|
||||||
0xDB180, 0xDB195, 0xDB1AA]),
|
(0xD2, [0xD2B88, 0xD364A, 0xD369F, 0xD3747]),
|
||||||
(0xD2, [0xD2B88, 0xD364A, 0xD369F, 0xD3747]),
|
(0xDC, [0xD213F, 0xD2174, 0xD229E, 0xD2426, 0xD4731, 0xD4753, 0xD4774, 0xD4795, 0xD47B6, 0xD4AA5, 0xD4AE4, 0xD4B96, 0xD4CA5,
|
||||||
(0xDC, [0xD213F, 0xD2174, 0xD229E, 0xD2426, 0xD4731, 0xD4753, 0xD4774, 0xD4795, 0xD47B6, 0xD4AA5, 0xD4AE4, 0xD4B96, 0xD4CA5,
|
0xD5477, 0xD5A3D, 0xD6566, 0xD672C, 0xD67C0, 0xD69B8, 0xD6AB1, 0xD6C05, 0xD6DB3, 0xD71AB, 0xD8E2D, 0xD8F0D, 0xD94E0,
|
||||||
0xD5477, 0xD5A3D, 0xD6566, 0xD672C, 0xD67C0, 0xD69B8, 0xD6AB1, 0xD6C05, 0xD6DB3, 0xD71AB, 0xD8E2D, 0xD8F0D, 0xD94E0,
|
0xD9544, 0xD95A8, 0xD9982, 0xD9B56, 0xDA694, 0xDA6AB, 0xDAE88, 0xDAEC8, 0xDAEE6, 0xDB1BF]),
|
||||||
0xD9544, 0xD95A8, 0xD9982, 0xD9B56, 0xDA694, 0xDA6AB, 0xDAE88, 0xDAEC8, 0xDAEE6, 0xDB1BF]),
|
(0xE6, [0xD210A, 0xD22DC, 0xD2447, 0xD5A4D, 0xD5DDC, 0xDA251, 0xDA26C]),
|
||||||
(0xE6, [0xD210A, 0xD22DC, 0xD2447, 0xD5A4D, 0xD5DDC, 0xDA251, 0xDA26C]),
|
(0xF0, [0xD945E, 0xD967D, 0xD96C2, 0xD9C95, 0xD9EE6, 0xDA5C6]),
|
||||||
(0xF0, [0xD945E, 0xD967D, 0xD96C2, 0xD9C95, 0xD9EE6, 0xDA5C6]),
|
(0xFA, [0xD2047, 0xD24C2, 0xD24EC, 0xD25A4, 0xD51A8, 0xD51E6, 0xD524E, 0xD529E, 0xD6045, 0xD81DE, 0xD821E, 0xD94AA, 0xD9A9E,
|
||||||
(0xFA, [0xD2047, 0xD24C2, 0xD24EC, 0xD25A4, 0xD3DAA, 0xD51A8, 0xD51E6, 0xD524E, 0xD529E, 0xD6045, 0xD81DE, 0xD821E, 0xD94AA,
|
0xD9AE4, 0xDA289]),
|
||||||
0xD9A9E, 0xD9AE4, 0xDA289]),
|
(0xFF, [0xD2085, 0xD21C5, 0xD5F28])
|
||||||
(0xFF, [0xD2085, 0xD21C5, 0xD5F28])
|
|
||||||
]
|
]
|
||||||
for volume, addresses in music_volumes:
|
for volume, addresses in music_volumes:
|
||||||
for address in addresses:
|
for address in addresses:
|
||||||
rom.write_byte(address, volume if not disable_music else 0x00)
|
rom.write_byte(address, volume if not disable_music else 0x00)
|
||||||
|
|
||||||
|
# restore Mirror sound effect volumes (for existing seeds that lack it)
|
||||||
|
rom.write_byte(0xD3E04, 0xC8)
|
||||||
|
rom.write_byte(0xD3DC6, 0xC8)
|
||||||
|
rom.write_byte(0xD3D6E, 0xC8)
|
||||||
|
rom.write_byte(0xD3D34, 0xC8)
|
||||||
|
rom.write_byte(0xD3D55, 0xC8)
|
||||||
|
rom.write_byte(0xD3E38, 0xC8)
|
||||||
|
rom.write_byte(0xD3DAA, 0xFA)
|
||||||
|
|
||||||
# set heart beep rate
|
# set heart beep rate
|
||||||
rom.write_byte(0x180033, {'off': 0x00, 'half': 0x40, 'quarter': 0x80, 'normal': 0x20}[beep])
|
rom.write_byte(0x180033, {'off': 0x00, 'half': 0x40, 'quarter': 0x80, 'normal': 0x20}[beep])
|
||||||
|
|
||||||
|
# set heart color
|
||||||
|
rom.write_byte(0x6FA1E, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
|
rom.write_byte(0x6FA20, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
|
rom.write_byte(0x6FA22, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
|
rom.write_byte(0x6FA24, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
|
rom.write_byte(0x6FA26, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
|
rom.write_byte(0x6FA28, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
|
rom.write_byte(0x6FA2A, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
|
rom.write_byte(0x6FA2C, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
|
rom.write_byte(0x6FA2E, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
|
rom.write_byte(0x6FA30, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
|
||||||
|
rom.write_byte(0x65561, {'red': 0x05, 'blue': 0x0D, 'green': 0x19, 'yellow': 0x09}[color])
|
||||||
|
|
||||||
# write link sprite if required
|
# write link sprite if required
|
||||||
if sprite is not None:
|
if sprite is not None:
|
||||||
write_sprite(rom, sprite)
|
write_sprite(rom, sprite)
|
||||||
|
|
316
Rules.py
316
Rules.py
|
@ -1,3 +1,4 @@
|
||||||
|
import collections
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ def add_rule(spot, rule, combine='and'):
|
||||||
|
|
||||||
|
|
||||||
def add_lamp_requirement(spot):
|
def add_lamp_requirement(spot):
|
||||||
add_rule(spot, lambda state: state.has('Lamp'))
|
add_rule(spot, lambda state: state.has('Lamp', state.world.lamps_needed_for_dark_rooms))
|
||||||
|
|
||||||
|
|
||||||
def forbid_item(location, item):
|
def forbid_item(location, item):
|
||||||
|
@ -86,7 +87,11 @@ def global_rules(world):
|
||||||
world.get_region('Old Man House').can_reach = lambda state: state.can_reach('Old Man', 'Location') or old_rule(state)
|
world.get_region('Old Man House').can_reach = lambda state: state.can_reach('Old Man', 'Location') or old_rule(state)
|
||||||
|
|
||||||
# overworld requirements
|
# overworld requirements
|
||||||
set_rule(world.get_entrance('Kings Grave'), lambda state: state.has_Boots() and (state.can_lift_heavy_rocks() or (state.has_Pearl() and state.has_Mirror() and state.can_reach('West Dark World'))))
|
set_rule(world.get_entrance('Kings Grave'), lambda state: state.has_Boots())
|
||||||
|
set_rule(world.get_entrance('Kings Grave Outer Rocks'), lambda state: state.can_lift_heavy_rocks())
|
||||||
|
set_rule(world.get_entrance('Kings Grave Inner Rocks'), lambda state: state.can_lift_heavy_rocks())
|
||||||
|
set_rule(world.get_entrance('Kings Grave Mirror Spot'), lambda state: state.has_Pearl() and state.has_Mirror())
|
||||||
|
# Caution: If king's grave is releaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it)
|
||||||
set_rule(world.get_entrance('Bonk Fairy (Light)'), lambda state: state.has_Boots())
|
set_rule(world.get_entrance('Bonk Fairy (Light)'), lambda state: state.has_Boots())
|
||||||
set_rule(world.get_location('Sunken Treasure'), lambda state: state.can_reach('Dam'))
|
set_rule(world.get_location('Sunken Treasure'), lambda state: state.can_reach('Dam'))
|
||||||
set_rule(world.get_entrance('Bat Cave Drop Ledge'), lambda state: state.has('Hammer'))
|
set_rule(world.get_entrance('Bat Cave Drop Ledge'), lambda state: state.has('Hammer'))
|
||||||
|
@ -96,7 +101,8 @@ def global_rules(world):
|
||||||
set_rule(world.get_entrance('Sanctuary Grave'), lambda state: state.can_lift_rocks())
|
set_rule(world.get_entrance('Sanctuary Grave'), lambda state: state.can_lift_rocks())
|
||||||
set_rule(world.get_entrance('20 Rupee Cave'), lambda state: state.can_lift_rocks())
|
set_rule(world.get_entrance('20 Rupee Cave'), lambda state: state.can_lift_rocks())
|
||||||
set_rule(world.get_entrance('50 Rupee Cave'), lambda state: state.can_lift_rocks())
|
set_rule(world.get_entrance('50 Rupee Cave'), lambda state: state.can_lift_rocks())
|
||||||
set_rule(world.get_entrance('Old Man Cave (West)'), lambda state: state.can_lift_rocks())
|
set_rule(world.get_entrance('Death Mountain Entrance Rock'), lambda state: state.can_lift_rocks())
|
||||||
|
set_rule(world.get_entrance('Bumper Cave Entrance Mirror Spot'), lambda state: state.has_Mirror())
|
||||||
set_rule(world.get_entrance('Flute Spot 1'), lambda state: state.has('Ocarina'))
|
set_rule(world.get_entrance('Flute Spot 1'), lambda state: state.has('Ocarina'))
|
||||||
set_rule(world.get_entrance('Lake Hylia Central Island Teleporter'), lambda state: state.can_lift_heavy_rocks())
|
set_rule(world.get_entrance('Lake Hylia Central Island Teleporter'), lambda state: state.can_lift_heavy_rocks())
|
||||||
set_rule(world.get_entrance('Dark Desert Teleporter'), lambda state: state.has('Ocarina') and state.can_lift_heavy_rocks())
|
set_rule(world.get_entrance('Dark Desert Teleporter'), lambda state: state.has('Ocarina') and state.can_lift_heavy_rocks())
|
||||||
|
@ -119,7 +125,6 @@ def global_rules(world):
|
||||||
set_rule(world.get_location('Master Sword Pedestal'), lambda state: state.has('Red Pendant') and state.has('Blue Pendant') and state.has('Green Pendant'))
|
set_rule(world.get_location('Master Sword Pedestal'), lambda state: state.has('Red Pendant') and state.has('Blue Pendant') and state.has('Green Pendant'))
|
||||||
set_rule(world.get_location('Sahasrahla'), lambda state: state.has('Green Pendant'))
|
set_rule(world.get_location('Sahasrahla'), lambda state: state.has('Green Pendant'))
|
||||||
set_rule(world.get_entrance('Agahnims Tower'), lambda state: state.has('Cape') or state.has_beam_sword() or state.has('Beat Agahnim 1')) # barrier gets removed after killing agahnim, relevant for entrance shuffle
|
set_rule(world.get_entrance('Agahnims Tower'), lambda state: state.has('Cape') or state.has_beam_sword() or state.has('Beat Agahnim 1')) # barrier gets removed after killing agahnim, relevant for entrance shuffle
|
||||||
# FIXME: VT has a can_kill_most_things(8) call on Aga Tower's entrance. I think this is supposed to reflect that a better weapon than 10 bombs is needed to reach the two chests in this tower
|
|
||||||
set_rule(world.get_entrance('Agahnim 1'), lambda state: state.has_sword() and state.has('Small Key (Agahnims Tower)', 2))
|
set_rule(world.get_entrance('Agahnim 1'), lambda state: state.has_sword() and state.has('Small Key (Agahnims Tower)', 2))
|
||||||
set_rule(world.get_location('Castle Tower - Dark Maze'), lambda state: state.has('Small Key (Agahnims Tower)'))
|
set_rule(world.get_location('Castle Tower - Dark Maze'), lambda state: state.has('Small Key (Agahnims Tower)'))
|
||||||
set_rule(world.get_entrance('Top of Pyramid'), lambda state: state.has('Beat Agahnim 1'))
|
set_rule(world.get_entrance('Top of Pyramid'), lambda state: state.has('Beat Agahnim 1'))
|
||||||
|
@ -135,10 +140,11 @@ def global_rules(world):
|
||||||
set_rule(world.get_entrance('East Death Mountain (Top)'), lambda state: state.has('Hammer'))
|
set_rule(world.get_entrance('East Death Mountain (Top)'), lambda state: state.has('Hammer'))
|
||||||
|
|
||||||
set_rule(world.get_location('Catfish'), lambda state: state.can_lift_rocks())
|
set_rule(world.get_location('Catfish'), lambda state: state.can_lift_rocks())
|
||||||
set_rule(world.get_entrance('Dark World Potion Shop'), lambda state: state.has_Pearl() and (state.can_lift_rocks() or state.has('Hammer') or state.has('Flippers')))
|
set_rule(world.get_entrance('Northeast Dark World Broken Bridge Pass'), lambda state: state.has_Pearl() and (state.can_lift_rocks() or state.has('Hammer') or state.has('Flippers')))
|
||||||
|
set_rule(world.get_entrance('East Dark World Broken Bridge Pass'), lambda state: state.has_Pearl() and (state.can_lift_rocks() or state.has('Hammer')))
|
||||||
set_rule(world.get_entrance('South Dark World Bridge'), lambda state: state.has('Hammer') and state.has_Pearl())
|
set_rule(world.get_entrance('South Dark World Bridge'), lambda state: state.has('Hammer') and state.has_Pearl())
|
||||||
set_rule(world.get_entrance('Bonk Fairy (Dark)'), lambda state: state.has_Pearl() and state.has_Boots())
|
set_rule(world.get_entrance('Bonk Fairy (Dark)'), lambda state: state.has_Pearl() and state.has_Boots())
|
||||||
set_rule(world.get_entrance('West Dark World Gap'), lambda state: state.has_Pearl() and state.has('Hookshot') and (state.has('Flippers') or state.has('Hammer') or state.can_lift_rocks()))
|
set_rule(world.get_entrance('West Dark World Gap'), lambda state: state.has_Pearl() and state.has('Hookshot'))
|
||||||
set_rule(world.get_entrance('Palace of Darkness'), lambda state: state.has_Pearl()) # kiki needs pearl
|
set_rule(world.get_entrance('Palace of Darkness'), lambda state: state.has_Pearl()) # kiki needs pearl
|
||||||
set_rule(world.get_entrance('Hyrule Castle Ledge Mirror Spot'), lambda state: state.has_Mirror())
|
set_rule(world.get_entrance('Hyrule Castle Ledge Mirror Spot'), lambda state: state.has_Mirror())
|
||||||
set_rule(world.get_entrance('Hyrule Castle Main Gate'), lambda state: state.has_Mirror())
|
set_rule(world.get_entrance('Hyrule Castle Main Gate'), lambda state: state.has_Mirror())
|
||||||
|
@ -153,6 +159,7 @@ def global_rules(world):
|
||||||
set_rule(world.get_entrance('Brewery'), lambda state: state.has_Pearl()) # bomb required
|
set_rule(world.get_entrance('Brewery'), lambda state: state.has_Pearl()) # bomb required
|
||||||
set_rule(world.get_entrance('Thieves Town'), lambda state: state.has_Pearl()) # bunny cannot pull
|
set_rule(world.get_entrance('Thieves Town'), lambda state: state.has_Pearl()) # bunny cannot pull
|
||||||
set_rule(world.get_entrance('Skull Woods First Section Hole (North)'), lambda state: state.has_Pearl()) # bunny cannot lift bush
|
set_rule(world.get_entrance('Skull Woods First Section Hole (North)'), lambda state: state.has_Pearl()) # bunny cannot lift bush
|
||||||
|
set_rule(world.get_entrance('Skull Woods Second Section Hole'), lambda state: state.has_Pearl()) # bunny cannot lift bush
|
||||||
set_rule(world.get_entrance('Maze Race Mirror Spot'), lambda state: state.has_Mirror())
|
set_rule(world.get_entrance('Maze Race Mirror Spot'), lambda state: state.has_Mirror())
|
||||||
set_rule(world.get_entrance('Cave 45 Mirror Spot'), lambda state: state.has_Mirror())
|
set_rule(world.get_entrance('Cave 45 Mirror Spot'), lambda state: state.has_Mirror())
|
||||||
set_rule(world.get_entrance('East Dark World Bridge'), lambda state: state.has_Pearl() and state.has('Hammer'))
|
set_rule(world.get_entrance('East Dark World Bridge'), lambda state: state.has_Pearl() and state.has('Hammer'))
|
||||||
|
@ -160,11 +167,14 @@ def global_rules(world):
|
||||||
set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot'), lambda state: state.has_Mirror())
|
set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot'), lambda state: state.has_Mirror())
|
||||||
set_rule(world.get_entrance('East Dark World River Pier'), lambda state: state.has_Pearl() and state.has('Flippers')) # ToDo any fake flipper set up?
|
set_rule(world.get_entrance('East Dark World River Pier'), lambda state: state.has_Pearl() and state.has('Flippers')) # ToDo any fake flipper set up?
|
||||||
set_rule(world.get_entrance('Graveyard Ledge Mirror Spot'), lambda state: state.has_Pearl() and state.has_Mirror())
|
set_rule(world.get_entrance('Graveyard Ledge Mirror Spot'), lambda state: state.has_Pearl() and state.has_Mirror())
|
||||||
set_rule(world.get_entrance('Bumper Cave (Bottom)'), lambda state: state.has_Pearl() and state.can_lift_rocks())
|
set_rule(world.get_entrance('Bumper Cave Entrance Rock'), lambda state: state.has_Pearl() and state.can_lift_rocks())
|
||||||
set_rule(world.get_entrance('Bumper Cave Ledge Mirror Spot'), lambda state: state.has_Mirror())
|
set_rule(world.get_entrance('Bumper Cave Ledge Mirror Spot'), lambda state: state.has_Mirror())
|
||||||
set_rule(world.get_entrance('Bat Cave Drop Ledge Mirror Spot'), lambda state: state.has_Pearl() and state.can_lift_heavy_rocks() and state.has_Mirror())
|
set_rule(world.get_entrance('Bat Cave Drop Ledge Mirror Spot'), lambda state: state.has_Mirror())
|
||||||
set_rule(world.get_entrance('Dark World Hammer Peg Cave'), lambda state: state.has_Pearl() and state.can_lift_heavy_rocks() and state.has('Hammer'))
|
set_rule(world.get_entrance('Dark World Hammer Peg Cave'), lambda state: state.has_Pearl() and state.has('Hammer'))
|
||||||
set_rule(world.get_entrance('Dark World Shop'), lambda state: state.has_Pearl() and state.has('Hammer'))
|
set_rule(world.get_entrance('Village of Outcasts Eastern Rocks'), lambda state: state.has_Pearl() and state.can_lift_heavy_rocks())
|
||||||
|
set_rule(world.get_entrance('Peg Area Rocks'), lambda state: state.has_Pearl() and state.can_lift_heavy_rocks())
|
||||||
|
set_rule(world.get_entrance('Village of Outcasts Pegs'), lambda state: state.has_Pearl() and state.has('Hammer'))
|
||||||
|
set_rule(world.get_entrance('Grassy Lawn Pegs'), lambda state: state.has_Pearl() and state.has('Hammer'))
|
||||||
set_rule(world.get_entrance('Bumper Cave Exit (Top)'), lambda state: state.has('Cape'))
|
set_rule(world.get_entrance('Bumper Cave Exit (Top)'), lambda state: state.has('Cape'))
|
||||||
set_rule(world.get_entrance('Bumper Cave Exit (Bottom)'), lambda state: state.has('Cape') or state.has('Hookshot'))
|
set_rule(world.get_entrance('Bumper Cave Exit (Bottom)'), lambda state: state.has('Cape') or state.has('Hookshot'))
|
||||||
|
|
||||||
|
@ -185,20 +195,13 @@ def global_rules(world):
|
||||||
set_rule(world.get_entrance('Fairy Ascension Mirror Spot'), lambda state: state.has_Mirror() and state.has_Pearl()) # need to lift flowers
|
set_rule(world.get_entrance('Fairy Ascension Mirror Spot'), lambda state: state.has_Mirror() and state.has_Pearl()) # need to lift flowers
|
||||||
set_rule(world.get_entrance('Isolated Ledge Mirror Spot'), lambda state: state.has_Mirror())
|
set_rule(world.get_entrance('Isolated Ledge Mirror Spot'), lambda state: state.has_Mirror())
|
||||||
set_rule(world.get_entrance('Superbunny Cave Exit (Bottom)'), lambda state: False) # Cannot get to bottom exit from top. Just exists for shuffling
|
set_rule(world.get_entrance('Superbunny Cave Exit (Bottom)'), lambda state: False) # Cannot get to bottom exit from top. Just exists for shuffling
|
||||||
|
|
||||||
set_rule(world.get_location('Spike Cave'), lambda state:
|
set_rule(world.get_location('Spike Cave'), lambda state:
|
||||||
state.has('Hammer') and state.can_lift_rocks() and
|
state.has('Hammer') and state.can_lift_rocks() and
|
||||||
(
|
((state.has('Cape') and state.can_extend_magic(16, True)) or
|
||||||
(
|
(state.has('Cane of Byrna') and
|
||||||
state.has('Cape')
|
(state.can_extend_magic(12, True) or
|
||||||
and (state.can_extend_magic(16)
|
(state.world.can_take_damage and (state.has_Boots() or state.has_hearts(4))))))
|
||||||
or (state.can_extend_magic(12) and (state.world.can_take_damage or state.has_Boots()))
|
|
||||||
or (state.can_extend_magic(10) and state.world.can_take_damage and state.has_Boots()))
|
|
||||||
) or (
|
|
||||||
state.has('Cane of Byrna')
|
|
||||||
and (state.can_extend_magic(12)
|
|
||||||
or (state.can_extend_magic(10) and (state.has_Boots() or state.world.can_take_damage))
|
|
||||||
or (state.world.can_take_damage and (state.has_Boots() or state.has_hearts(4)))))
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set_rule(world.get_location('Hookshot Cave - Top Right'), lambda state: state.has('Hookshot'))
|
set_rule(world.get_location('Hookshot Cave - Top Right'), lambda state: state.has('Hookshot'))
|
||||||
|
@ -257,7 +260,7 @@ def global_rules(world):
|
||||||
set_rule(world.get_entrance('Thieves Town Big Key Door'), lambda state: state.has('Big Key (Thieves Town)'))
|
set_rule(world.get_entrance('Thieves Town Big Key Door'), lambda state: state.has('Big Key (Thieves Town)'))
|
||||||
set_rule(world.get_entrance('Blind Fight'), lambda state: state.has('Small Key (Thieves Town)') and (state.has_blunt_weapon() or state.has('Cane of Somaria') or state.has('Cane of Byrna')))
|
set_rule(world.get_entrance('Blind Fight'), lambda state: state.has('Small Key (Thieves Town)') and (state.has_blunt_weapon() or state.has('Cane of Somaria') or state.has('Cane of Byrna')))
|
||||||
set_rule(world.get_location('Thieves\' Town - Big Chest'), lambda state: (state.has('Small Key (Thieves Town)') or item_name(state, 'Thieves\' Town - Big Chest') == 'Small Key (Thieves Town)') and state.has('Hammer'))
|
set_rule(world.get_location('Thieves\' Town - Big Chest'), lambda state: (state.has('Small Key (Thieves Town)') or item_name(state, 'Thieves\' Town - Big Chest') == 'Small Key (Thieves Town)') and state.has('Hammer'))
|
||||||
set_always_allow(world.get_location('Thieves\' Town - Big Chest'), lambda state, item: item.name == 'Small Key (Thieves Town)')
|
set_always_allow(world.get_location('Thieves\' Town - Big Chest'), lambda state, item: item.name == 'Small Key (Thieves Town)' and state.has('Hammer'))
|
||||||
set_rule(world.get_location('Thieves\' Town - Attic'), lambda state: state.has('Small Key (Thieves Town)'))
|
set_rule(world.get_location('Thieves\' Town - Attic'), lambda state: state.has('Small Key (Thieves Town)'))
|
||||||
for location in ['Thieves\' Town - Attic', 'Thieves\' Town - Big Chest', 'Thieves\' Town - Blind\'s Cell', 'Thieves Town - Blind']:
|
for location in ['Thieves\' Town - Attic', 'Thieves\' Town - Big Chest', 'Thieves\' Town - Blind\'s Cell', 'Thieves Town - Blind']:
|
||||||
forbid_item(world.get_location(location), 'Big Key (Thieves Town)')
|
forbid_item(world.get_location(location), 'Big Key (Thieves Town)')
|
||||||
|
@ -316,8 +319,8 @@ def global_rules(world):
|
||||||
set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Left'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield'))
|
set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Left'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield'))
|
||||||
set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Right'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield'))
|
set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Right'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield'))
|
||||||
set_rule(world.get_entrance('Turtle Rock (Trinexx)'), lambda state: state.has('Small Key (Turtle Rock)', 4) and state.has('Big Key (Turtle Rock)') and state.has('Cane of Somaria') and state.has('Fire Rod') and state.has('Ice Rod') and
|
set_rule(world.get_entrance('Turtle Rock (Trinexx)'), lambda state: state.has('Small Key (Turtle Rock)', 4) and state.has('Big Key (Turtle Rock)') and state.has('Cane of Somaria') and state.has('Fire Rod') and state.has('Ice Rod') and
|
||||||
(state.has('Hammer') or state.has_beam_sword() or (state.has_sword and state.can_extend_magic(32))))
|
(state.has('Hammer') or state.has_beam_sword() or (state.has_sword() and state.can_extend_magic(32))))
|
||||||
# TODO: Per VT, possibly allow a regular sword with 4x extended magic (ie. quater magic, or half magic+bottle or 3 bottles)
|
|
||||||
set_trock_key_rules(world)
|
set_trock_key_rules(world)
|
||||||
|
|
||||||
set_rule(world.get_entrance('Palace of Darkness Bonk Wall'), lambda state: state.has('Bow'))
|
set_rule(world.get_entrance('Palace of Darkness Bonk Wall'), lambda state: state.has('Bow'))
|
||||||
|
@ -434,9 +437,9 @@ def no_glitches_rules(world):
|
||||||
add_conditional_lamp('Eastern Palace - Prize', 'Eastern Palace', 'Location')
|
add_conditional_lamp('Eastern Palace - Prize', 'Eastern Palace', 'Location')
|
||||||
|
|
||||||
if not world.sewer_light_cone:
|
if not world.sewer_light_cone:
|
||||||
add_rule(world.get_location('Sewers - Dark Cross'), lambda state: state.has('Lamp'))
|
add_lamp_requirement(world.get_location('Sewers - Dark Cross'))
|
||||||
add_rule(world.get_entrance('Sewers Back Door'), lambda state: state.has('Lamp'))
|
add_lamp_requirement(world.get_entrance('Sewers Back Door'))
|
||||||
add_rule(world.get_entrance('Throne Room'), lambda state: state.has('Lamp'))
|
add_lamp_requirement(world.get_entrance('Throne Room'))
|
||||||
|
|
||||||
|
|
||||||
def open_rules(world):
|
def open_rules(world):
|
||||||
|
@ -450,7 +453,7 @@ def open_rules(world):
|
||||||
|
|
||||||
def swordless_rules(world):
|
def swordless_rules(world):
|
||||||
|
|
||||||
# for the time being swordless mode just inhierits all fixes from open mode.
|
# for the time being swordless mode just inherits all fixes from open mode.
|
||||||
# should there ever be fixes that apply to open mode but not swordless, this
|
# should there ever be fixes that apply to open mode but not swordless, this
|
||||||
# can be revisited.
|
# can be revisited.
|
||||||
open_rules(world)
|
open_rules(world)
|
||||||
|
@ -470,9 +473,12 @@ def swordless_rules(world):
|
||||||
|
|
||||||
|
|
||||||
def standard_rules(world):
|
def standard_rules(world):
|
||||||
|
for loc in ['Sanctuary','Sewers - Secret Room - Left', 'Sewers - Secret Room - Middle',
|
||||||
|
'Sewers - Secret Room - Right']:
|
||||||
|
add_rule(world.get_location(loc), lambda state: state.can_kill_most_things() and state.has('Small Key (Escape)'))
|
||||||
|
|
||||||
# easiest way to enforce key placement not relevant for open
|
# easiest way to enforce key placement not relevant for open
|
||||||
set_rule(world.get_location('Sewers - Dark Cross'), lambda state: state.can_kill_most_things())
|
set_rule(world.get_location('Sewers - Dark Cross'), lambda state: state.can_kill_most_things())
|
||||||
add_rule(world.get_entrance('Sewers Door'), lambda state: state.can_kill_most_things())
|
|
||||||
|
|
||||||
set_rule(world.get_location('Hyrule Castle - Boomerang Chest'), lambda state: state.can_kill_most_things())
|
set_rule(world.get_location('Hyrule Castle - Boomerang Chest'), lambda state: state.can_kill_most_things())
|
||||||
set_rule(world.get_location('Hyrule Castle - Zelda\'s Chest'), lambda state: state.can_kill_most_things())
|
set_rule(world.get_location('Hyrule Castle - Zelda\'s Chest'), lambda state: state.can_kill_most_things())
|
||||||
|
@ -545,7 +551,7 @@ def set_big_bomb_rules(world):
|
||||||
Normal_LW_entrances = ['Blinds Hideout',
|
Normal_LW_entrances = ['Blinds Hideout',
|
||||||
'Bonk Fairy (Light)',
|
'Bonk Fairy (Light)',
|
||||||
'Lake Hylia Fairy',
|
'Lake Hylia Fairy',
|
||||||
'Swamp Fairy',
|
'Light Hype Fairy',
|
||||||
'Desert Fairy',
|
'Desert Fairy',
|
||||||
'Chicken House',
|
'Chicken House',
|
||||||
'Aginahs Cave',
|
'Aginahs Cave',
|
||||||
|
@ -574,14 +580,26 @@ def set_big_bomb_rules(world):
|
||||||
'Dam',
|
'Dam',
|
||||||
'Lumberjack House',
|
'Lumberjack House',
|
||||||
'Lake Hylia Fortune Teller',
|
'Lake Hylia Fortune Teller',
|
||||||
'Kakariko Gamble Game']
|
'Eastern Palace',
|
||||||
|
'Kakariko Gamble Game',
|
||||||
|
'Kakariko Well Cave',
|
||||||
|
'Bat Cave Cave',
|
||||||
|
'Elder House (East)',
|
||||||
|
'Elder House (West)',
|
||||||
|
'North Fairy Cave',
|
||||||
|
'Lost Woods Hideout Stump',
|
||||||
|
'Lumberjack Tree Cave',
|
||||||
|
'Two Brothers House (East)',
|
||||||
|
'Sanctuary',
|
||||||
|
'Hyrule Castle Entrance (South)',
|
||||||
|
'Hyrule Castle Secret Entrance Stairs']
|
||||||
LW_walkable_entrances = ['Dark Lake Hylia Ledge Fairy',
|
LW_walkable_entrances = ['Dark Lake Hylia Ledge Fairy',
|
||||||
'Dark Lake Hylia Ledge Spike Cave',
|
'Dark Lake Hylia Ledge Spike Cave',
|
||||||
'Dark Lake Hylia Ledge Hint',
|
'Dark Lake Hylia Ledge Hint',
|
||||||
'Mire Shed',
|
'Mire Shed',
|
||||||
'Dark Desert Hint',
|
'Dark Desert Hint',
|
||||||
'Dark Desert Fairy',
|
'Dark Desert Fairy',
|
||||||
'Checkerboard Cave']
|
'Misery Mire']
|
||||||
Northern_DW_entrances = ['Brewery',
|
Northern_DW_entrances = ['Brewery',
|
||||||
'C-Shaped House',
|
'C-Shaped House',
|
||||||
'Chest Game',
|
'Chest Game',
|
||||||
|
@ -591,88 +609,238 @@ def set_big_bomb_rules(world):
|
||||||
'Fortune Teller (Dark)',
|
'Fortune Teller (Dark)',
|
||||||
'Dark World Shop',
|
'Dark World Shop',
|
||||||
'Dark World Lumberjack Shop',
|
'Dark World Lumberjack Shop',
|
||||||
'Graveyard Cave']
|
'Thieves Town',
|
||||||
|
'Skull Woods First Section Door',
|
||||||
|
'Skull Woods Second Section Door (East)']
|
||||||
Southern_DW_entrances = ['Hype Cave',
|
Southern_DW_entrances = ['Hype Cave',
|
||||||
'Bonk Fairy (Dark)',
|
'Bonk Fairy (Dark)',
|
||||||
'Archery Game',
|
'Archery Game',
|
||||||
'Big Bomb Shop',
|
'Big Bomb Shop',
|
||||||
'Dark Lake Hylia Shop',
|
'Dark Lake Hylia Shop',
|
||||||
'Cave 45']
|
'Swamp Palace']
|
||||||
Isolated_DW_entrances = ['Spike Cave',
|
Isolated_DW_entrances = ['Spike Cave',
|
||||||
'Cave Shop (Dark Death Mountain)',
|
'Cave Shop (Dark Death Mountain)',
|
||||||
'Dark Death Mountain Fairy',
|
'Dark Death Mountain Fairy',
|
||||||
'Mimic Cave']
|
'Mimic Cave',
|
||||||
|
'Skull Woods Second Section Door (West)',
|
||||||
|
'Skull Woods Final Section',
|
||||||
|
'Ice Palace',
|
||||||
|
'Turtle Rock',
|
||||||
|
'Dark Death Mountain Ledge (West)',
|
||||||
|
'Dark Death Mountain Ledge (East)',
|
||||||
|
'Bumper Cave (Top)',
|
||||||
|
'Superbunny Cave (Top)',
|
||||||
|
'Superbunny Cave (Bottom)',
|
||||||
|
'Hookshot Cave',
|
||||||
|
'Ganons Tower',
|
||||||
|
'Turtle Rock Isolated Ledge Entrance',
|
||||||
|
'Hookshot Cave Back Entrance']
|
||||||
Isolated_LW_entrances = ['Capacity Upgrade',
|
Isolated_LW_entrances = ['Capacity Upgrade',
|
||||||
'Hookshot Fairy']
|
'Tower of Hera',
|
||||||
|
'Death Mountain Return Cave (West)',
|
||||||
|
'Paradox Cave (Top)',
|
||||||
|
'Fairy Ascension Cave (Top)',
|
||||||
|
'Spiral Cave',
|
||||||
|
'Desert Palace Entrance (East)']
|
||||||
|
West_LW_DM_entrances = ['Old Man Cave (East)',
|
||||||
|
'Old Man House (Bottom)',
|
||||||
|
'Old Man House (Top)',
|
||||||
|
'Death Mountain Return Cave (East)',
|
||||||
|
'Spectacle Rock Cave Peak',
|
||||||
|
'Spectacle Rock Cave',
|
||||||
|
'Spectacle Rock Cave (Bottom)']
|
||||||
|
East_LW_DM_entrances = ['Paradox Cave (Bottom)',
|
||||||
|
'Paradox Cave (Middle)',
|
||||||
|
'Hookshot Fairy',
|
||||||
|
'Spiral Cave (Bottom)']
|
||||||
|
Mirror_from_SDW_entrances = ['Two Brothers House (West)',
|
||||||
|
'Cave 45']
|
||||||
|
Castle_ledge_entrances = ['Hyrule Castle Entrance (West)',
|
||||||
|
'Hyrule Castle Entrance (East)',
|
||||||
|
'Agahnims Tower']
|
||||||
|
Desert_mirrorable_ledge_entrances = ['Desert Palace Entrance (West)',
|
||||||
|
'Desert Palace Entrance (North)',
|
||||||
|
'Desert Palace Entrance (South)',
|
||||||
|
'Checkerboard Cave',]
|
||||||
|
|
||||||
set_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.can_reach('East Dark World', 'Region') and state.can_reach('Big Bomb Shop', 'Region') and state.has('Crystal 5') and state.has('Crystal 6'))
|
set_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.can_reach('East Dark World', 'Region') and state.can_reach('Big Bomb Shop', 'Region') and state.has('Crystal 5') and state.has('Crystal 6'))
|
||||||
|
|
||||||
|
#crossing peg bridge starting from the southern dark world
|
||||||
|
def cross_peg_bridge(state):
|
||||||
|
return state.has('Hammer') and state.has_Pearl()
|
||||||
|
|
||||||
|
# returning via the eastern and southern teleporters needs the same items, so we use the southern teleporter for out routing.
|
||||||
|
# crossing preg bridge already requires hammer so we just add the gloves to the requirement
|
||||||
|
def southern_teleporter(state):
|
||||||
|
return state.can_lift_rocks() and cross_peg_bridge(state)
|
||||||
|
|
||||||
|
# the basic routes assume you can reach eastern light world with the bomb.
|
||||||
|
# you can then use the southern teleporter, or (if you have beaten Aga1) the hyrule castle gate warp
|
||||||
|
def basic_routes(state):
|
||||||
|
return southern_teleporter(state) or state.can_reach('Top of Pyramid', 'Entrance')
|
||||||
|
|
||||||
|
# Key for below abbreviations:
|
||||||
|
# P = pearl
|
||||||
|
# A = Aga1
|
||||||
|
# H = hammer
|
||||||
|
# M = Mirror
|
||||||
|
# G = Glove
|
||||||
|
|
||||||
if bombshop_entrance.name in Normal_LW_entrances:
|
if bombshop_entrance.name in Normal_LW_entrances:
|
||||||
#1. Enter via gate: Needs Aga1
|
#1. basic routes
|
||||||
#2. south hyrule teleporter and cross peg bridge: Hammer and moon pearl
|
#2. Can reach Eastern dark world some other way, mirror, get bomb, return to mirror spot, walk to pyramid: Needs mirror
|
||||||
#3. Can reach Eastern dark world some other way, mirror, get bomb, return to mirror spot, walk to pyramid: Needs mirror
|
# -> M or BR
|
||||||
# -> A or (H and P)) or (M)
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: basic_routes(state) or state.has_Mirror())
|
||||||
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.can_reach('Top of Pyramid', 'Entrance') or (state.has('Hammer') and state.has_Pearl()) or state.has_Mirror())
|
|
||||||
elif bombshop_entrance.name in LW_walkable_entrances:
|
elif bombshop_entrance.name in LW_walkable_entrances:
|
||||||
#1. Mirror then gate: Needs mirror and Aga1
|
#1. Mirror then basic routes
|
||||||
#2. Mirror then go to south hyrule teleporter and cross peg bridge: Needs Mirror and Hammer and moon pearl
|
# -> M and BR
|
||||||
# -> M and (A or (H and P))
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has_Mirror() and basic_routes(state))
|
||||||
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has_Mirror() and (state.can_reach('Top of Pyramid', 'Entrance') or (state.has('Hammer') and state.has_Pearl())))
|
|
||||||
elif bombshop_entrance.name in Northern_DW_entrances:
|
elif bombshop_entrance.name in Northern_DW_entrances:
|
||||||
#1. Mirror and enter via gate: Need mirror and Aga1
|
#1. Mirror and basic routes
|
||||||
#2. Mirror and enter via south hyrule teleporter: Need mirror and hammer and moon pearl
|
#2. Go to south DW and then cross peg bridge: Need Mitts and hammer and moon pearl
|
||||||
|
# -> (Mitts and CPB) or (M and BR)
|
||||||
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: (state.can_lift_heavy_rocks() and cross_peg_bridge(state)) or (state.has_Mirror() and basic_routes(state)))
|
||||||
|
elif bombshop_entrance.name == 'Bumper Cave (Bottom)':
|
||||||
|
#1. Mirror and Lift rock and basic_routes
|
||||||
|
#2. Mirror and Flute and basic routes (can make difference if accessed via insanity or w/ mirror from connector, and then via hyrule castle gate, because no gloves are needed in that case)
|
||||||
#3. Go to south DW and then cross peg bridge: Need Mitts and hammer and moon pearl
|
#3. Go to south DW and then cross peg bridge: Need Mitts and hammer and moon pearl
|
||||||
# -> (Mitts and P and H) or (M and (A or (H and P)))
|
# -> (Mitts and CPB) or (((G or Flute) and M) and BR))
|
||||||
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: (state.can_lift_heavy_rocks() and state.has_Pearl() and state.has('Hammer')) or (state.has_Mirror() and (state.can_reach('Top of Pyramid', 'Entrance') or (state.has('Hammer') and state.has_Pearl()))))
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: (state.can_lift_heavy_rocks() and cross_peg_bridge(state)) or (((state.can_lift_rocks() or state.has('Ocarina')) and state.has_Mirror()) and basic_routes(state)))
|
||||||
elif bombshop_entrance.name in Southern_DW_entrances:
|
elif bombshop_entrance.name in Southern_DW_entrances:
|
||||||
#1. Mirror and enter via gate: Need mirror and Aga1
|
#1. Mirror and enter via gate: Need mirror and Aga1
|
||||||
#2. cross peg bridge: Need hammer and moon pearl
|
#2. cross peg bridge: Need hammer and moon pearl
|
||||||
# -> (H and P) or (M and A)
|
# -> CPB or (M and A)
|
||||||
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: (state.has('Hammer') and state.has_Pearl()) or (state.has_Mirror() and state.can_reach('Top of Pyramid', 'Entrance')))
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: cross_peg_bridge(state) or (state.has_Mirror() and state.can_reach('Top of Pyramid', 'Entrance')))
|
||||||
elif bombshop_entrance.name in Isolated_DW_entrances:
|
elif bombshop_entrance.name in Isolated_DW_entrances:
|
||||||
# 1. mirror then flute then enter via gate: Needs mirror and flute and Aga 1
|
# 1. mirror then flute then basic routes
|
||||||
# 2. mirror then flute then enter via south hyrule teleporter: Needs mirror and Flute and hammer and moon pearl
|
# -> M and Flute and BR
|
||||||
# -> M and Flute and (A or (H and P))
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has_Mirror() and state.has('Ocarina') and basic_routes(state))
|
||||||
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has_Mirror() and state.has('Ocarina') and (state.can_reach('Top of Pyramid', 'Entrance') or (state.has('Hammer') and state.has_Pearl())))
|
|
||||||
elif bombshop_entrance.name in Isolated_LW_entrances:
|
elif bombshop_entrance.name in Isolated_LW_entrances:
|
||||||
# 1. flute then enter via gate: Needs flute and Aga 1
|
# 1. flute then basic routes
|
||||||
# 2. flute then enter via south hyrule teleporter: Needs Flute and hammer and moon pearl
|
|
||||||
# Prexisting mirror spot is not permitted, because mirror might have been needed to reach these isolated locations.
|
# Prexisting mirror spot is not permitted, because mirror might have been needed to reach these isolated locations.
|
||||||
# -> Flute and (A or (H and P))
|
# -> Flute and BR
|
||||||
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has('Ocarina') and (state.can_reach('Top of Pyramid', 'Entrance') or (state.has('Hammer') and state.has_Pearl())))
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has('Ocarina') and basic_routes(state))
|
||||||
|
elif bombshop_entrance.name in West_LW_DM_entrances:
|
||||||
|
# 1. flute then basic routes or mirror
|
||||||
|
# Prexisting mirror spot is permitted, because flute can be used to reach west DM directly.
|
||||||
|
# -> Flute and (M or BR)
|
||||||
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has('Ocarina') and (state.has_Mirror() or basic_routes(state)))
|
||||||
|
elif bombshop_entrance.name in East_LW_DM_entrances:
|
||||||
|
# 1. flute then basic routes or mirror and hookshot
|
||||||
|
# Prexisting mirror spot is permitted, because flute can be used to reach west DM directly and then east DM via Hookshot
|
||||||
|
# -> Flute and ((M and Hookshot) or BR)
|
||||||
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has('Ocarina') and ((state.has_Mirror() and state.has('Hookshot')) or basic_routes(state)))
|
||||||
|
elif bombshop_entrance.name == 'Fairy Ascension Cave (Bottom)':
|
||||||
|
# Same as East_LW_DM_entrances except navigation without BR requires Mitts
|
||||||
|
# -> Flute and ((M and Hookshot and Mitts) or BR)
|
||||||
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has('Ocarina') and ((state.has_Mirror() and state.has('Hookshot') and state.can_lift_heavy_rocks()) or basic_routes(state)))
|
||||||
|
elif bombshop_entrance.name in Castle_ledge_entrances:
|
||||||
|
# 1. mirror on pyramid to castle ledge, grab bomb, return through mirror spot: Needs mirror
|
||||||
|
# 2. flute then basic routes
|
||||||
|
# -> M or (Flute and BR)
|
||||||
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has_Mirror() or (state.has('Ocarina') and basic_routes(state)))
|
||||||
|
elif bombshop_entrance.name in Desert_mirrorable_ledge_entrances:
|
||||||
|
# Cases when you have mire access: Mirror to reach locations, return via mirror spot, move to center of desert, mirror anagin and:
|
||||||
|
# 1. Have mire access, Mirror to reach locations, return via mirror spot, move to center of desert, mirror again and then basic routes
|
||||||
|
# 2. flute then basic routes
|
||||||
|
# -> (Mire access and M) or Flute) and BR
|
||||||
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: ((state.can_reach('Dark Desert', 'Region') and state.has_Mirror()) or state.has('Ocarina')) and basic_routes(state))
|
||||||
|
elif bombshop_entrance.name == 'Old Man Cave (West)':
|
||||||
|
# 1. Lift rock then basic_routes
|
||||||
|
# 2. flute then basic_routes
|
||||||
|
# -> (Flute or G) and BR
|
||||||
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: (state.has('Ocarina') or state.can_lift_rocks()) and basic_routes(state))
|
||||||
|
elif bombshop_entrance.name == 'Graveyard Cave':
|
||||||
|
# 1. flute then basic routes
|
||||||
|
# 2. (has west dark world access) use existing mirror spot (required Pearl), mirror again off ledge
|
||||||
|
# -> (Flute or (M and P and West Dark World access) and BR
|
||||||
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: (state.has('Ocarina') or (state.can_reach('West Dark World', 'Region') and state.has_Pearl() and state.has_Mirror())) and basic_routes(state))
|
||||||
|
elif bombshop_entrance.name in Mirror_from_SDW_entrances:
|
||||||
|
# 1. flute then basic routes
|
||||||
|
# 2. (has South dark world access) use existing mirror spot, mirror again off ledge
|
||||||
|
# -> (Flute or (M and South Dark World access) and BR
|
||||||
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: (state.has('Ocarina') or (state.can_reach('South Dark World', 'Region') and state.has_Mirror())) and basic_routes(state))
|
||||||
elif bombshop_entrance.name == 'Dark World Potion Shop':
|
elif bombshop_entrance.name == 'Dark World Potion Shop':
|
||||||
# 1. walk down by lifting rock: needs gloves and pearl`
|
# 1. walk down by lifting rock: needs gloves and pearl`
|
||||||
# 2. walk down by hammering peg: needs hammer and pearl
|
# 2. walk down by hammering peg: needs hammer and pearl
|
||||||
# 3. mirror and eneter via gate: needs Mirror and Aga1
|
# 3. mirror and basic routes
|
||||||
# (south hyrule teleporter would be redundant with #2)
|
# -> (P and (H or Gloves)) or (M and BR)
|
||||||
# -> P and (H or H) or (M and A)
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: (state.has_Pearl() and (state.has('Hammer') or state.can_lift_rocks())) or (state.has_Mirror() and basic_routes(state)))
|
||||||
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: (state.has_Pearl() and (state.has('Hammer') or state.can_lift_rocks())) or (state.has_Mirror() and state.can_reach('Top of Pyramid', 'Entrance')))
|
|
||||||
elif bombshop_entrance.name == 'Kings Grave':
|
elif bombshop_entrance.name == 'Kings Grave':
|
||||||
# same as the Normal_LW_entrances case except that the pre-existing mirror is only possible if you have mitts
|
# same as the Normal_LW_entrances case except that the pre-existing mirror is only possible if you have mitts
|
||||||
# (because otherwise mirror was used to reach the grave, so would cancel a pre-existing mirror spot)
|
# (because otherwise mirror was used to reach the grave, so would cancel a pre-existing mirror spot)
|
||||||
# -> A or (H and P) or (M and Mitts)
|
# to account for insanity, must consider a way to escape without a cave for basic_routes
|
||||||
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.can_reach('Top of Pyramid', 'Entrance') or (state.has('Hammer') and state.has_Pearl()) or (state.can_lift_heavy_rocks() and state.has_Mirror()))
|
# -> (M and Mitts) or ((Mitts or Flute or (M and P and West Dark World access)) and BR)
|
||||||
|
add_rule(world.get_entrance('Pyramid Fairy'), lambda state: (state.can_lift_heavy_rocks() and state.has_Mirror()) or ((state.can_lift_heavy_rocks() or state.has('Ocarina') or (state.can_reach('West Dark World', 'Region') and state.has_Pearl() and state.has_Mirror())) and basic_routes(state)))
|
||||||
|
|
||||||
def set_bunny_rules(world):
|
def set_bunny_rules(world):
|
||||||
|
|
||||||
# regions for the extis of multi-entrace caves/drops that bunny cannot pass
|
# regions for the exits of multi-entrace caves/drops that bunny cannot pass
|
||||||
# Note spiral cave may be technically passible, but it would be too absurd to require since OHKO mode is a thing.
|
# Note spiral cave may be technically passible, but it would be too absurd to require since OHKO mode is a thing.
|
||||||
bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)', 'Turtle Rock (Entrance)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Skull Woods Second Section (Drop)',
|
bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)', 'Turtle Rock (Entrance)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Skull Woods Second Section (Drop)',
|
||||||
'Turtle Rock (Eye Bridge)', 'Sewers', 'Pyramid', 'Spiral Cave (Top)']
|
'Turtle Rock (Eye Bridge)', 'Sewers', 'Pyramid', 'Spiral Cave (Top)', 'Desert Palace Main (Inner)']
|
||||||
|
|
||||||
bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge']
|
bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge']
|
||||||
|
|
||||||
# Add pearl requirements for bunny-impassible caves if they occur in the dark world
|
if world.get_region('Dam').is_dark_world:
|
||||||
|
# if Dam is is dark world, then it is required to have the pearl to get the sunken item
|
||||||
|
add_rule(world.get_location('Sunken Treasure'), lambda state: state.has_Pearl())
|
||||||
|
# similarly we need perl to get across the swamp palace moat
|
||||||
|
add_rule(world.get_entrance('Swamp Palace Moat'), lambda state: state.has_Pearl())
|
||||||
|
|
||||||
|
def path_to_access_rule(path, entrance):
|
||||||
|
return lambda state: state.can_reach(entrance) and all(rule(state) for rule in path)
|
||||||
|
|
||||||
|
def options_to_access_rule(options):
|
||||||
|
return lambda state: any(rule(state) for rule in options)
|
||||||
|
|
||||||
|
def get_rule_to_add(region):
|
||||||
|
if not region.is_light_world:
|
||||||
|
return lambda state: state.has_Pearl()
|
||||||
|
# in this case we are mixed region.
|
||||||
|
# we collect possible options.
|
||||||
|
|
||||||
|
# The base option is having the moon pearl
|
||||||
|
possible_options = [lambda state: state.has_Pearl()]
|
||||||
|
|
||||||
|
# We will search entrances recursively until we find
|
||||||
|
# one that leads to an exclusively light world region
|
||||||
|
# for each such entrance a new option ios aded that consist of:
|
||||||
|
# a) being able to reach it, and
|
||||||
|
# b) being able to access all entrances from there to `region`
|
||||||
|
seen = set([region])
|
||||||
|
queue = collections.deque([(region, [])])
|
||||||
|
while queue:
|
||||||
|
(current, path) = queue.popleft()
|
||||||
|
for entrance in current.entrances:
|
||||||
|
new_region = entrance.parent_region
|
||||||
|
if new_region in seen:
|
||||||
|
continue
|
||||||
|
new_path = path + [entrance.access_rule]
|
||||||
|
seen.add(new_region)
|
||||||
|
if not new_region.is_light_world:
|
||||||
|
continue # we don't care about pure dark world entrances
|
||||||
|
if new_region.is_dark_world:
|
||||||
|
queue.append((new_region, new_path))
|
||||||
|
else:
|
||||||
|
# we have reached pure light world, so we have a new possible option
|
||||||
|
possible_options.append(path_to_access_rule(new_path, entrance))
|
||||||
|
return options_to_access_rule(possible_options)
|
||||||
|
|
||||||
|
# Add requirements for bunny-impassible caves if they occur in the dark world
|
||||||
for region in [world.get_region(name) for name in bunny_impassable_caves]:
|
for region in [world.get_region(name) for name in bunny_impassable_caves]:
|
||||||
|
|
||||||
if region.is_light_world:
|
if not region.is_dark_world:
|
||||||
continue
|
continue
|
||||||
|
rule = get_rule_to_add(region)
|
||||||
for exit in region.exits:
|
for exit in region.exits:
|
||||||
add_rule(exit, lambda state: state.has_Pearl())
|
add_rule(exit, rule)
|
||||||
|
|
||||||
# Add a moon pearl requirement for all locations that are actually in the dark world, except those available to the bunny
|
# Add requirements for all locations that are actually in the dark world, except those available to the bunny
|
||||||
for location in world.get_locations():
|
for location in world.get_locations():
|
||||||
if not location.parent_region.is_light_world:
|
if location.parent_region.is_dark_world:
|
||||||
|
|
||||||
if location.name in bunny_accessible_locations:
|
if location.name in bunny_accessible_locations:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
add_rule(location, lambda state: state.has_Pearl())
|
add_rule(location, get_rule_to_add(location.parent_region))
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue