0.6.2 Release

0.6.2 Release
This commit is contained in:
AmazingAmpharos 2019-04-30 18:17:36 -05:00 committed by GitHub
commit 390bd1f561
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 2711 additions and 842 deletions

11
.gitignore vendored
View File

@ -1,9 +1,10 @@
*.pyc
dist
build
.idea .idea
*.sfc .vscode
*_Spoiler.txt *_Spoiler.txt
bundle/components.wxs *.pyc
*.sfc
*.wixobj *.wixobj
build
bundle/components.wxs
dist
README.html README.html

View File

@ -24,12 +24,12 @@ def main():
''') ''')
parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true') parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true')
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=['double', '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'], parser.add_argument('--heartcolor', default='red', const='red', nargs='?', choices=['red', 'blue', 'green', 'yellow', 'random'],
help='Select the color of Link\'s heart meter. (default: %(default)s)') 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

View File

@ -7,7 +7,7 @@ from Utils import int16_as_bytes
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, retro, custom, customitemarray): def __init__(self, shuffle, logic, mode, difficulty, timer, progressive, goal, algorithm, place_dungeon_items, check_beatable_only, shuffle_ganon, quickswap, fastmenu, disable_music, keysanity, retro, custom, customitemarray, boss_shuffle, hints):
self.shuffle = shuffle self.shuffle = shuffle
self.logic = logic self.logic = logic
self.mode = mode self.mode = mode
@ -23,6 +23,7 @@ class World(object):
self.seed = None self.seed = None
self.state = CollectionState(self) self.state = CollectionState(self)
self.required_medallions = ['Ether', 'Quake'] self.required_medallions = ['Ether', 'Quake']
self._cached_entrances = None
self._cached_locations = None self._cached_locations = None
self._entrance_cache = {} self._entrance_cache = {}
self._region_cache = {} self._region_cache = {}
@ -45,7 +46,7 @@ class World(object):
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'
self.save_and_quit_from_boss = False self.save_and_quit_from_boss = True
self.check_beatable_only = check_beatable_only self.check_beatable_only = check_beatable_only
self.fix_skullwoods_exit = self.shuffle not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'] self.fix_skullwoods_exit = self.shuffle not in ['vanilla', 'simple', 'restricted', 'dungeonssimple']
self.fix_palaceofdarkness_exit = self.shuffle not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'] self.fix_palaceofdarkness_exit = self.shuffle not in ['vanilla', 'simple', 'restricted', 'dungeonssimple']
@ -53,6 +54,9 @@ class World(object):
self.shuffle_ganon = shuffle_ganon self.shuffle_ganon = shuffle_ganon
self.fix_gtower_exit = self.shuffle_ganon self.fix_gtower_exit = self.shuffle_ganon
self.can_access_trock_eyebridge = None self.can_access_trock_eyebridge = None
self.can_access_trock_front = None
self.can_access_trock_big_chest = None
self.can_access_trock_middle = None
self.quickswap = quickswap self.quickswap = quickswap
self.fastmenu = fastmenu self.fastmenu = fastmenu
self.disable_music = disable_music self.disable_music = disable_music
@ -63,6 +67,8 @@ class World(object):
self.can_take_damage = True self.can_take_damage = True
self.difficulty_requirements = None self.difficulty_requirements = None
self.fix_fake_world = True self.fix_fake_world = True
self.boss_shuffle = boss_shuffle
self.hints = hints
self.dynamic_regions = [] self.dynamic_regions = []
self.dynamic_locations = [] self.dynamic_locations = []
self.spoiler = Spoiler(self) self.spoiler = Spoiler(self)
@ -110,6 +116,15 @@ class World(object):
return r_location return r_location
raise RuntimeError('No such location %s' % location) raise RuntimeError('No such location %s' % location)
def get_dungeon(self, dungeonname):
if isinstance(dungeonname, Dungeon):
return dungeonname
for dungeon in self.dungeons:
if dungeon.name == dungeonname:
return dungeon
raise RuntimeError('No such dungeon %s' % dungeonname)
def get_all_state(self, keys=False): def get_all_state(self, keys=False):
ret = CollectionState(self) ret = CollectionState(self)
@ -180,6 +195,16 @@ class World(object):
else: else:
raise RuntimeError('Cannot assign item %s to location %s.' % (item, location)) raise RuntimeError('Cannot assign item %s to location %s.' % (item, location))
def get_entrances(self):
if self._cached_entrances is None:
self._cached_entrances = []
for region in self.regions:
self._cached_entrances.extend(region.entrances)
return self._cached_entrances
def clear_entrance_cache(self):
self._cached_entrances = None
def get_locations(self): def get_locations(self):
if self._cached_locations is None: if self._cached_locations is None:
self._cached_locations = [] self._cached_locations = []
@ -409,11 +434,11 @@ class CollectionState(object):
return len([pritem for pritem in self.prog_items if pritem.startswith('Bottle')]) return len([pritem for pritem in self.prog_items if pritem.startswith('Bottle')])
def has_hearts(self, count): def has_hearts(self, count):
# Warning: This oncly considers items that are marked as advancement items # Warning: This only considers items that are marked as advancement items
return self.heart_count() >= count return self.heart_count() >= count
def heart_count(self): def heart_count(self):
# Warning: This oncly considers items that are marked as advancement items # Warning: This only considers items that are marked as advancement items
return ( return (
self.item_count('Boss Heart Container') self.item_count('Boss Heart Container')
+ self.item_count('Sanctuary Heart Container') + self.item_count('Sanctuary Heart Container')
@ -424,26 +449,27 @@ 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, fullrefill=False): #This reflects the total magic Link has, not the total extra he has. def can_extend_magic(self, smallmagic=16, 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' and not fullrefill: if self.can_buy_unlimited('Green Potion') or self.can_buy_unlimited('Blue Potion'):
basemagic = basemagic + int(basemagic * 0.5 * self.bottle_count()) if self.world.difficulty == 'hard' and not fullrefill:
elif self.world.difficulty == 'expert' and not fullrefill: basemagic = basemagic + int(basemagic * 0.5 * self.bottle_count())
basemagic = basemagic + int(basemagic * 0.25 * self.bottle_count()) elif self.world.difficulty == 'expert' and not fullrefill:
elif self.world.difficulty == 'insane' and not fullrefill: basemagic = basemagic + int(basemagic * 0.25 * self.bottle_count())
basemagic = basemagic elif self.world.difficulty == 'insane' and not fullrefill:
elif self.can_buy_unlimited('Green Potion') or self.can_buy_unlimited('Red Potion'): basemagic = basemagic
basemagic = basemagic + basemagic * self.bottle_count() else:
basemagic = basemagic + basemagic * self.bottle_count()
return basemagic >= smallmagic return basemagic >= smallmagic
def can_kill_most_things(self, enemies=5): def can_kill_most_things(self, enemies=5):
return (self.has_blunt_weapon() return (self.has_blunt_weapon()
or self.has('Cane of Somaria') or self.has('Cane of Somaria')
or (self.has('Cane of Byrna') and (enemies < 6 or self.can_extend_Magic())) or (self.has('Cane of Byrna') and (enemies < 6 or self.can_extend_magic()))
or self.can_shoot_arrows() or self.can_shoot_arrows()
or self.has('Fire Rod') or self.has('Fire Rod')
) )
@ -455,6 +481,16 @@ class CollectionState(object):
return self.has('Bow') and (self.has('Silver Arrows') or self.can_buy_unlimited('Single Arrow')) return self.has('Bow') and (self.has('Silver Arrows') or self.can_buy_unlimited('Single Arrow'))
return self.has('Bow') return self.has('Bow')
def can_get_good_bee(self):
cave = self.world.get_region('Good Bee Cave')
return (
self.has_bottle() and
self.has('Bug Catching Net') and
(self.has_Boots() or (self.has_sword() and self.has('Quake'))) and
cave.can_reach(self) and
(cave.is_light_world or self.has_Pearl())
)
def has_sword(self): def has_sword(self):
return self.has('Fighter Sword') or self.has('Master Sword') or self.has('Tempered Sword') or self.has('Golden Sword') return self.has('Fighter Sword') or self.has('Master Sword') or self.has('Tempered Sword') or self.has('Golden Sword')
@ -595,7 +631,7 @@ class RegionType(Enum):
class Region(object): class Region(object):
def __init__(self, name, type): def __init__(self, name, type, hint):
self.name = name self.name = name
self.type = type self.type = type
self.entrances = [] self.entrances = []
@ -607,7 +643,7 @@ class Region(object):
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.is_dark_world = False
self.spot_type = 'Region' self.spot_type = 'Region'
self.hint_text = 'Hyrule' self.hint_text = hint
self.recursion_count = 0 self.recursion_count = 0
def can_reach(self, state): def can_reach(self, state):
@ -676,6 +712,15 @@ class Dungeon(object):
self.big_key = big_key self.big_key = big_key
self.small_keys = small_keys self.small_keys = small_keys
self.dungeon_items = dungeon_items self.dungeon_items = dungeon_items
self.bosses = dict()
@property
def boss(self):
return self.bosses.get(None, None)
@boss.setter
def boss(self, value):
self.bosses[None] = value
@property @property
def keys(self): def keys(self):
@ -694,9 +739,16 @@ class Dungeon(object):
def __unicode__(self): def __unicode__(self):
return '%s' % self.name return '%s' % self.name
class Boss(object):
def __init__(self, name, enemizer_name, defeat_rule):
self.name = name
self.enemizer_name = enemizer_name
self.defeat_rule = defeat_rule
def can_defeat(self, state):
return self.defeat_rule(state)
class Location(object): class Location(object):
def __init__(self, name='', address=None, crystal=False, hint_text=None, parent=None): def __init__(self, name='', address=None, crystal=False, hint_text=None, parent=None):
self.name = name self.name = name
self.parent_region = parent self.parent_region = parent
@ -713,7 +765,7 @@ class Location(object):
self.item_rule = lambda item: True self.item_rule = lambda item: True
def can_fill(self, state, item, check_access=True): def can_fill(self, state, item, check_access=True):
return self.always_allow(item, self) or (self.parent_region.can_fill(item) and self.item_rule(item) and (not check_access or self.can_reach(state))) return self.always_allow(state, item) or (self.parent_region.can_fill(item) and self.item_rule(item) and (not check_access or self.can_reach(state)))
def can_reach(self, state): def can_reach(self, state):
if self.access_rule(state) and state.can_reach(self.parent_region): if self.access_rule(state) and state.can_reach(self.parent_region):
@ -729,7 +781,7 @@ class Location(object):
class Item(object): class Item(object):
def __init__(self, name='', advancement=False, priority=False, type=None, code=None, pedestal_hint=None, pedestal_credit=None, sickkid_credit=None, zora_credit=None, witch_credit=None, fluteboy_credit=None): def __init__(self, name='', advancement=False, priority=False, type=None, code=None, pedestal_hint=None, pedestal_credit=None, sickkid_credit=None, zora_credit=None, witch_credit=None, fluteboy_credit=None, hint_text=None):
self.name = name self.name = name
self.advancement = advancement self.advancement = advancement
self.priority = priority self.priority = priority
@ -740,6 +792,7 @@ class Item(object):
self.zora_credit_text = zora_credit self.zora_credit_text = zora_credit
self.magicshop_credit_text = witch_credit self.magicshop_credit_text = witch_credit
self.fluteboy_credit_text = fluteboy_credit self.fluteboy_credit_text = fluteboy_credit
self.hint_text = hint_text
self.code = code self.code = code
self.location = None self.location = None
@ -774,6 +827,7 @@ class Crystal(Item):
class ShopType(Enum): class ShopType(Enum):
Shop = 0 Shop = 0
TakeAny = 1 TakeAny = 1
UpgradeShop = 2
class Shop(object): class Shop(object):
def __init__(self, region, room_id, type, shopkeeper_config, replaceable): def __init__(self, region, room_id, type, shopkeeper_config, replaceable):
@ -803,6 +857,8 @@ class Shop(object):
config |= 0x40 # ignore door id config |= 0x40 # ignore door id
if self.type == ShopType.TakeAny: if self.type == ShopType.TakeAny:
config |= 0x80 config |= 0x80
if self.type == ShopType.UpgradeShop:
config |= 0x10 # Alt. VRAM
return [0x00]+int16_as_bytes(self.room_id)+[door_id, 0x00, config, self.shopkeeper_config, 0x00] return [0x00]+int16_as_bytes(self.room_id)+[door_id, 0x00, config, self.shopkeeper_config, 0x00]
def has_unlimited(self, item): def has_unlimited(self, item):
@ -840,6 +896,7 @@ class Spoiler(object):
self.paths = {} self.paths = {}
self.metadata = {} self.metadata = {}
self.shops = [] self.shops = []
self.bosses = OrderedDict()
def set_entrance(self, entrance, exit, direction): def set_entrance(self, entrance, exit, direction):
self.entrances[(entrance, direction)] = OrderedDict([('entrance', entrance), ('exit', exit), ('direction', direction)]) self.entrances[(entrance, direction)] = OrderedDict([('entrance', entrance), ('exit', exit), ('direction', direction)])
@ -884,6 +941,23 @@ class Spoiler(object):
shopdata['item_{}'.format(index)] = "{}{}".format(item['item'], item['price']) if item['price'] else item['item'] shopdata['item_{}'.format(index)] = "{}{}".format(item['item'], item['price']) if item['price'] else item['item']
self.shops.append(shopdata) self.shops.append(shopdata)
self.bosses["Eastern Palace"] = self.world.get_dungeon("Eastern Palace").boss.name
self.bosses["Desert Palace"] = self.world.get_dungeon("Desert Palace").boss.name
self.bosses["Tower Of Hera"] = self.world.get_dungeon("Tower of Hera").boss.name
self.bosses["Hyrule Castle"] = "Agahnim"
self.bosses["Palace Of Darkness"] = self.world.get_dungeon("Palace of Darkness").boss.name
self.bosses["Swamp Palace"] = self.world.get_dungeon("Swamp Palace").boss.name
self.bosses["Skull Woods"] = self.world.get_dungeon("Skull Woods").boss.name
self.bosses["Thieves Town"] = self.world.get_dungeon("Thieves Town").boss.name
self.bosses["Ice Palace"] = self.world.get_dungeon("Ice Palace").boss.name
self.bosses["Misery Mire"] = self.world.get_dungeon("Misery Mire").boss.name
self.bosses["Turtle Rock"] = self.world.get_dungeon("Turtle Rock").boss.name
self.bosses["Ganons Tower Basement"] = self.world.get_dungeon('Ganons Tower').bosses['bottom'].name
self.bosses["Ganons Tower Middle"] = self.world.get_dungeon('Ganons Tower').bosses['middle'].name
self.bosses["Ganons Tower Top"] = self.world.get_dungeon('Ganons Tower').bosses['top'].name
self.bosses["Ganons Tower"] = "Agahnim 2"
self.bosses["Ganon"] = "Ganon"
from Main import __version__ as ERVersion from Main import __version__ as ERVersion
self.metadata = {'version': ERVersion, self.metadata = {'version': ERVersion,
@ -913,7 +987,10 @@ class Spoiler(object):
out['Shops'] = self.shops out['Shops'] = self.shops
out['playthrough'] = self.playthrough out['playthrough'] = self.playthrough
out['paths'] = self.paths out['paths'] = self.paths
if self.world.boss_shuffle != 'none':
out['Bosses'] = self.bosses
out['meta'] = self.metadata out['meta'] = self.metadata
return json.dumps(out) return json.dumps(out)
def to_file(self, filename): def to_file(self, filename):

196
Bosses.py Normal file
View File

@ -0,0 +1,196 @@
import logging
import random
from BaseClasses import Boss
from Fill import FillError
def BossFactory(boss):
if boss is None:
return None
if boss in boss_table:
enemizer_name, defeat_rule = boss_table[boss]
return Boss(boss, enemizer_name, defeat_rule)
logging.getLogger('').error('Unknown Boss: %s', boss)
return None
def ArmosKnightsDefeatRule(state):
# Magic amounts are probably a bit overkill
return (
state.has_blunt_weapon() or
(state.has('Cane of Somaria') and state.can_extend_magic(10)) or
(state.has('Cane of Byrna') and state.can_extend_magic(16)) or
(state.has('Ice Rod') and state.can_extend_magic(32)) or
(state.has('Fire Rod') and state.can_extend_magic(32)) or
state.has('Blue Boomerang') or
state.has('Red Boomerang'))
def LanmolasDefeatRule(state):
# TODO: Allow the canes here?
return (
state.has_blunt_weapon() or
state.has('Fire Rod') or
state.has('Ice Rod') or
state.can_shoot_arrows())
def MoldormDefeatRule(state):
return state.has_blunt_weapon()
def HelmasaurKingDefeatRule(state):
return state.has_blunt_weapon() or state.can_shoot_arrows()
def ArrghusDefeatRule(state):
if not state.has('Hookshot'):
return False
# TODO: ideally we would have a check for bow and silvers, which combined with the
# hookshot is enough. This is not coded yet because the silvers that only work in pyramid feature
# makes this complicated
if state.has_blunt_weapon():
return True
return ((state.has('Fire Rod') and (state.can_shoot_arrows() or state.can_extend_magic(12))) or #assuming mostly gitting two puff with one shot
(state.has('Ice Rod') and (state.can_shoot_arrows() or state.can_extend_magic(16))))
def MothulaDefeatRule(state):
return (
state.has_blunt_weapon() or
(state.has('Fire Rod') and state.can_extend_magic(10)) or
# TODO: Not sure how much (if any) extend magic is needed for these two, since they only apply
# to non-vanilla locations, so are harder to test, so sticking with what VT has for now:
(state.has('Cane of Somaria') and state.can_extend_magic(16)) or
(state.has('Cane of Byrna') and state.can_extend_magic(16)) or
state.can_get_good_bee()
)
def BlindDefeatRule(state):
return state.has_blunt_weapon() or state.has('Cane of Somaria') or state.has('Cane of Byrna')
def KholdstareDefeatRule(state):
return (
(
state.has('Fire Rod') or
(
state.has('Bombos') and
# FIXME: the following only actually works for the vanilla location for swordless mode
(state.has_sword() or state.world.mode == 'swordless')
)
) and
(
state.has_blunt_weapon() or
(state.has('Fire Rod') and state.can_extend_magic(20)) or
# FIXME: this actually only works for the vanilla location for swordless mode
(
state.has('Fire Rod') and
state.has('Bombos') and
state.world.mode == 'swordless' and
state.can_extend_magic(16)
)
)
)
def VitreousDefeatRule(state):
return state.can_shoot_arrows() or state.has_blunt_weapon()
def TrinexxDefeatRule(state):
if not (state.has('Fire Rod') and state.has('Ice Rod')):
return False
return state.has('Hammer') or state.has_beam_sword() or (state.has_sword() and state.can_extend_magic(32))
def AgahnimDefeatRule(state):
return state.has_sword() or state.has('Hammer') or state.has('Bug Catching Net')
boss_table = {
'Armos Knights': ('Armos', ArmosKnightsDefeatRule),
'Lanmolas': ('Lanmola', LanmolasDefeatRule),
'Moldorm': ('Moldorm', MoldormDefeatRule),
'Helmasaur King': ('Helmasaur', HelmasaurKingDefeatRule),
'Arrghus': ('Arrghus', ArrghusDefeatRule),
'Mothula': ('Mothula', MothulaDefeatRule),
'Blind': ('Blind', BlindDefeatRule),
'Kholdstare': ('Kholdstare', KholdstareDefeatRule),
'Vitreous': ('Vitreous', VitreousDefeatRule),
'Trinexx': ('Trinexx', TrinexxDefeatRule),
'Agahnim': ('Agahnim', AgahnimDefeatRule),
'Agahnim2': ('Agahnim2', AgahnimDefeatRule)
}
def can_place_boss(world, boss, dungeon_name, level=None):
if world.mode in ['swordless'] and boss == 'Kholdstare' and dungeon_name != 'Ice Palace':
return False
if dungeon_name == 'Ganons Tower' and level == 'top':
if boss in ["Armos Knights", "Arrghus", "Blind", "Trinexx", "Lanmolas"]:
return False
if dungeon_name == 'Ganons Tower' and level == 'middle':
if boss in ["Blind"]:
return False
if dungeon_name == 'Tower of Hera' and boss in ["Armos Knights", "Arrghus", "Blind", "Trinexx", "Lanmolas"]:
return False
if dungeon_name == 'Skull Woods' and boss in ["Trinexx"]:
return False
if boss in ["Agahnim", "Agahnim2", "Ganon"]:
return False
return True
def place_bosses(world):
if world.boss_shuffle == 'none':
return
# Most to least restrictive order
boss_locations = [
['Ganons Tower', 'top'],
['Tower of Hera', None],
['Skull Woods', None],
['Ganons Tower', 'middle'],
['Eastern Palace', None],
['Desert Palace', None],
['Palace of Darkness', None],
['Swamp Palace', None],
['Thieves Town', None],
['Ice Palace', None],
['Misery Mire', None],
['Turtle Rock', None],
['Ganons Tower', 'bottom'],
]
all_bosses = sorted(boss_table.keys()) #s orted to be deterministic on older pythons
placeable_bosses = [boss for boss in all_bosses if boss not in ['Agahnim', 'Agahnim2', 'Ganon']]
if world.boss_shuffle in ["basic", "normal"]:
# temporary hack for swordless kholdstare:
if world.mode == 'swordless':
world.get_dungeon('Ice Palace').boss = BossFactory('Kholdstare')
logging.getLogger('').debug('Placing boss Kholdstare at Ice Palace')
boss_locations.remove(['Ice Palace', None])
placeable_bosses.remove('Kholdstare')
if world.boss_shuffle == "basic": # vanilla bosses shuffled
bosses = placeable_bosses + ['Armos Knights', 'Lanmolas', 'Moldorm']
else: # all bosses present, the three duplicates chosen at random
bosses = all_bosses + [random.choice(placeable_bosses) for _ in range(3)]
logging.getLogger('').debug('Bosses chosen %s', bosses)
random.shuffle(bosses)
for [loc, level] in boss_locations:
loc_text = loc + (' ('+level+')' if level else '')
boss = next((b for b in bosses if can_place_boss(world, b, loc, level)), None)
if not boss:
raise FillError('Could not place boss for location %s' % loc_text)
bosses.remove(boss)
logging.getLogger('').debug('Placing boss %s at %s', boss, loc_text)
world.get_dungeon(loc).bosses[level] = BossFactory(boss)
elif world.boss_shuffle == "chaos": #all bosses chosen at random
for [loc, level] in boss_locations:
loc_text = loc + (' ('+level+')' if level else '')
try:
boss = random.choice([b for b in placeable_bosses if can_place_boss(world, b, loc, level)])
except IndexError:
raise FillError('Could not place boss for location %s' % loc_text)
logging.getLogger('').debug('Placing boss %s at %s', boss, loc_text)
world.get_dungeon(loc).bosses[level] = BossFactory(boss)

View File

@ -1,34 +1,39 @@
import random import random
from BaseClasses import Dungeon from BaseClasses import Dungeon
from Bosses import BossFactory
from Fill import fill_restrictive from Fill import fill_restrictive
from Items import ItemFactory from Items import ItemFactory
def create_dungeons(world): def create_dungeons(world):
def make_dungeon(name, dungeon_regions, big_key, small_keys, dungeon_items): def make_dungeon(name, default_boss, dungeon_regions, big_key, small_keys, dungeon_items):
dungeon = Dungeon(name, dungeon_regions, big_key, [] if world.retro else small_keys, dungeon_items) dungeon = Dungeon(name, dungeon_regions, big_key, [] if world.retro else small_keys, dungeon_items)
dungeon.boss = BossFactory(default_boss)
for region in dungeon.regions: for region in dungeon.regions:
world.get_region(region).dungeon = dungeon world.get_region(region).dungeon = dungeon
return dungeon return dungeon
ES = make_dungeon('Hyrule Castle', ['Hyrule Castle', 'Sewers', 'Sewer Drop', 'Sewers (Dark)', 'Sanctuary'], None, [ItemFactory('Small Key (Escape)')], [ItemFactory('Map (Escape)')]) ES = make_dungeon('Hyrule Castle', None, ['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', 'Armos Knights', ['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 (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)'])) DP = make_dungeon('Desert Palace', 'Lanmolas', ['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', 'Moldorm', ['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', 'Agahnim', ['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', 'Helmasaur King', ['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)']))
TT = make_dungeon('Thieves Town', ['Thieves Town (Entrance)', 'Thieves Town (Deep)', 'Blind Fight'], ItemFactory('Big Key (Thieves Town)'), [ItemFactory('Small Key (Thieves Town)')], ItemFactory(['Map (Thieves Town)', 'Compass (Thieves Town)'])) TT = make_dungeon('Thieves Town', 'Blind', ['Thieves Town (Entrance)', 'Thieves Town (Deep)', 'Blind Fight'], ItemFactory('Big Key (Thieves Town)'), [ItemFactory('Small Key (Thieves Town)')], ItemFactory(['Map (Thieves Town)', 'Compass (Thieves Town)']))
SW = make_dungeon('Skull Woods', ['Skull Woods Final Section (Entrance)', 'Skull Woods First Section', 'Skull Woods Second Section', 'Skull Woods Second Section (Drop)', 'Skull Woods Final Section (Mothula)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)'], ItemFactory('Big Key (Skull Woods)'), ItemFactory(['Small Key (Skull Woods)'] * 2), ItemFactory(['Map (Skull Woods)', 'Compass (Skull Woods)'])) SW = make_dungeon('Skull Woods', 'Mothula', ['Skull Woods Final Section (Entrance)', 'Skull Woods First Section', 'Skull Woods Second Section', 'Skull Woods Second Section (Drop)', 'Skull Woods Final Section (Mothula)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)'], ItemFactory('Big Key (Skull Woods)'), ItemFactory(['Small Key (Skull Woods)'] * 2), ItemFactory(['Map (Skull Woods)', 'Compass (Skull Woods)']))
SP = make_dungeon('Swamp Palace', ['Swamp Palace (Entrance)', 'Swamp Palace (First Room)', 'Swamp Palace (Starting Area)', 'Swamp Palace (Center)', 'Swamp Palace (North)'], ItemFactory('Big Key (Swamp Palace)'), [ItemFactory('Small Key (Swamp Palace)')], ItemFactory(['Map (Swamp Palace)', 'Compass (Swamp Palace)'])) SP = make_dungeon('Swamp Palace', 'Arrghus', ['Swamp Palace (Entrance)', 'Swamp Palace (First Room)', 'Swamp Palace (Starting Area)', 'Swamp Palace (Center)', 'Swamp Palace (North)'], ItemFactory('Big Key (Swamp Palace)'), [ItemFactory('Small Key (Swamp Palace)')], ItemFactory(['Map (Swamp Palace)', 'Compass (Swamp Palace)']))
IP = make_dungeon('Ice Palace', ['Ice Palace (Entrance)', 'Ice Palace (Main)', 'Ice Palace (East)', 'Ice Palace (East Top)', 'Ice Palace (Kholdstare)'], ItemFactory('Big Key (Ice Palace)'), ItemFactory(['Small Key (Ice Palace)'] * 2), ItemFactory(['Map (Ice Palace)', 'Compass (Ice Palace)'])) IP = make_dungeon('Ice Palace', 'Kholdstare', ['Ice Palace (Entrance)', 'Ice Palace (Main)', 'Ice Palace (East)', 'Ice Palace (East Top)', 'Ice Palace (Kholdstare)'], ItemFactory('Big Key (Ice Palace)'), ItemFactory(['Small Key (Ice Palace)'] * 2), ItemFactory(['Map (Ice Palace)', 'Compass (Ice Palace)']))
MM = make_dungeon('Misery Mire', ['Misery Mire (Entrance)', 'Misery Mire (Main)', 'Misery Mire (West)', 'Misery Mire (Final Area)', 'Misery Mire (Vitreous)'], ItemFactory('Big Key (Misery Mire)'), ItemFactory(['Small Key (Misery Mire)'] * 3), ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)'])) MM = make_dungeon('Misery Mire', 'Vitreous', ['Misery Mire (Entrance)', 'Misery Mire (Main)', 'Misery Mire (West)', 'Misery Mire (Final Area)', 'Misery Mire (Vitreous)'], ItemFactory('Big Key (Misery Mire)'), ItemFactory(['Small Key (Misery Mire)'] * 3), ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)']))
TR = make_dungeon('Turtle Rock', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller Room)', 'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], ItemFactory('Big Key (Turtle Rock)'), ItemFactory(['Small Key (Turtle Rock)'] * 4), ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'])) TR = make_dungeon('Turtle Rock', 'Trinexx', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller Room)', 'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], ItemFactory('Big Key (Turtle Rock)'), ItemFactory(['Small Key (Turtle Rock)'] * 4), ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)']))
GT = make_dungeon('Ganons Tower', ['Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', 'Ganons Tower (Compass Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', 'Ganons Tower (Firesnake Room)', 'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', 'Ganons Tower (Top)', 'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', 'Agahnim 2'], ItemFactory('Big Key (Ganons Tower)'), ItemFactory(['Small Key (Ganons Tower)'] * 4), ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'])) GT = make_dungeon('Ganons Tower', 'Agahnim2', ['Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', 'Ganons Tower (Compass Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', 'Ganons Tower (Firesnake Room)', 'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', 'Ganons Tower (Top)', 'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', 'Agahnim 2'], ItemFactory('Big Key (Ganons Tower)'), ItemFactory(['Small Key (Ganons Tower)'] * 4), ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)']))
GT.bosses['bottom'] = BossFactory('Armos Knights')
GT.bosses['middle'] = BossFactory('Lanmolas')
GT.bosses['top'] = BossFactory('Moldorm')
world.dungeons = [ES, EP, DP, ToH, AT, PoD, TT, SW, SP, IP, MM, TR, GT] world.dungeons = [ES, EP, DP, ToH, AT, PoD, TT, SW, SP, IP, MM, TR, GT]
def fill_dungeons(world): def fill_dungeons(world):
freebes = ['Ganons Tower - Map Chest', 'Palace of Darkness - Harmless Hellway', 'Palace of Darkness - Big Key Chest', 'Turtle Rock - Big Key Chest'] freebes = ['Ganons Tower - Map Chest', 'Palace of Darkness - Harmless Hellway', 'Palace of Darkness - Big Key Chest', 'Turtle Rock - Big Key Chest']
@ -145,7 +150,7 @@ dungeon_music_addresses = {'Eastern Palace - Prize': [0x1559A],
'Tower of Hera - Prize': [0x155C5, 0x1107A, 0x10B8C], 'Tower of Hera - Prize': [0x155C5, 0x1107A, 0x10B8C],
'Palace of Darkness - Prize': [0x155B8], 'Palace of Darkness - Prize': [0x155B8],
'Swamp Palace - Prize': [0x155B7], 'Swamp Palace - Prize': [0x155B7],
'Thieves Town - Prize': [0x155C6], 'Thieves\' Town - Prize': [0x155C6],
'Skull Woods - Prize': [0x155BA, 0x155BB, 0x155BC, 0x155BD, 0x15608, 0x15609, 0x1560A, 0x1560B], 'Skull Woods - Prize': [0x155BA, 0x155BB, 0x155BC, 0x155BD, 0x15608, 0x15609, 0x1560A, 0x1560B],
'Ice Palace - Prize': [0x155BF], 'Ice Palace - Prize': [0x155BF],
'Misery Mire - Prize': [0x155B9], 'Misery Mire - Prize': [0x155B9],

339
ER_hint_reference.txt Normal file
View File

@ -0,0 +1,339 @@
Hint description:
Hints will appear in the following ratios across the 15 telepathic tiles that have hints and the five storyteller locations:
4 hints for inconvenient entrances.
4 hints for random entrances (this can by coincidence pick inconvenient entrances that aren't used for the first set of hints).
3 hints for inconvenient item locations.
5 hints for valuable items.
4 junk hints.
These hints will use the following format:
Entrance hints go "[Entrance on overworld] leads to [interior]".
Inconvenient item locations are a little more custom but amount to "[Location] has [item name]". The item name is literal and will specify which dungeon the dungeon specific items hail from (small key/big key/map/compass).
The valuable items are of the format "[item name] can be found [location]". The item name is again literal, and the location text is taken from Ganon's silver arrow hints. Note that the way it works is that every unique valuable item that exists is considered independently, and you won't get multiple hints for the EXACT same item (so you can only get one hint for Progressive Sword no matter how many swords exist in the seed, but if swords are not progressive, you could get hints for both Master Sword and Tempered Sword). More copies of an item existing does not increase the probability of getting a hint for that particular item (you are equally likely to get a hint for a Progressive Sword as for the Hammer). Unlike the IR, item names are never obfuscated by "something unique", and there is no special bias for hints for GT Big Key or Pegasus Boots.
Hint Locations:
Eastern Palace room before Big Chest
Desert Palace bonk torch room
Tower of Hera entrance room
Tower of Hera Big Chest room
Castle Tower after dark rooms
Palace of Darkness before Bow section
Swamp Palace entryway
Thieves' Town upstairs
Ice Palace entrance
Ice Palace after first drop
Ice Palace tall ice floor room
Misery Mire cutscene room
Turtle Rock entrance
Spectacle Rock cave
Spiky Hint cave
PoD Bdlg NPC
Near PoD Storyteller (bug near bomb wall)
Dark Sanctuary Storyteller (long room with tables)
Near Mire Storyteller (feather duster in winding cave)
SE DW Storyteller (owl in winding cave)
Inconvenient entrance list:
Skull Woods Final
Ice Palace
Misery Mire
Turtle Rock
Ganon's Tower
Mimic Ledge
SW DM Foothills Cave (mirror from upper Bumper ledge)
Hammer Pegs (near purple chest)
Super Bomb cracked wall
Inconvenient location list:
Swamp left (two chests)
Mire left (two chests)
Hera basement
Eastern Palace Big Key chest (protected by anti-fairies)
Thieves' Town Big Chest
Ice Palace Big Chest
Ganon's Tower Big Chest
Purple Chest
Spike Cave
Magic Bat
Sahasrahla (Green Pendant)
Valuable Items are simply all items that are shown on the pause subscreen (Y, B, or A sections) minus Silver Arrows and plus Triforce Pieces, Magic Upgrades (1/2 or 1/4), and the Single Arrow. If keysanity is being used, you can additionally get hints for Small Keys or Big Keys but not hints for Maps or Compasses.
While the exact verbage of location names and item names can be found in the source code, here's a copy for reference:
Overworld Entrance naming:
Turtle Rock: Turtle Rock Main
Misery Mire: Misery Mire
Ice Palace: Ice Palace
Skull Woods Final Section: The back of Skull Woods
Death Mountain Return Cave (West): The SW DM Foothills Cave
Mimic Cave: Mimic Ledge
Dark World Hammer Peg Cave: The rows of pegs
Pyramid Fairy: The crack on the pyramid
Eastern Palace: Eastern Palace
Elder House (East): Elder House
Elder House (West): Elder House
Two Brothers House (East): Eastern Quarreling Brothers' house
Old Man Cave (West): The lower DM entrance
Hyrule Castle Entrance (South): The ground level castle door
Thieves Town: Thieves' Town
Bumper Cave (Bottom): The lower Bumper Cave
Swamp Palace: Swamp Palace
Dark Death Mountain Ledge (West): The East dark DM connector ledge
Dark Death Mountain Ledge (East): The East dark DM connector ledge
Superbunny Cave (Top): The summit of dark DM cave
Superbunny Cave (Bottom): The base of east dark DM
Hookshot Cave: The rock on dark DM
Desert Palace Entrance (South): The book sealed passage
Tower of Hera: The Tower of Hera
Two Brothers House (West): The door near the race game
Old Man Cave (East): The SW-most cave on west DM
Old Man House (Bottom): A cave with a door on west DM
Old Man House (Top): The eastmost cave on west DM
Death Mountain Return Cave (East): The westmost cave on west DM
Spectacle Rock Cave Peak: The highest cave on west DM
Spectacle Rock Cave: The right ledge on west DM
Spectacle Rock Cave (Bottom): The left ledge on west DM
Paradox Cave (Bottom): The southmost cave on east DM
Paradox Cave (Middle): The right paired cave on east DM
Paradox Cave (Top): The east DM summit cave
Fairy Ascension Cave (Bottom): The east DM cave behind rocks
Fairy Ascension Cave (Top): The central ledge on east DM
Spiral Cave: The left ledge on east DM
Spiral Cave (Bottom): The SWmost cave on east DM
Palace of Darkness: Palace of Darkness
Hyrule Castle Entrance (West): The left castle door
Hyrule Castle Entrance (East): The right castle door
Agahnims Tower: The sealed castle door
Desert Palace Entrance (West): The westmost building in the desert
Desert Palace Entrance (North): The northmost cave in the desert
Blinds Hideout: Blind's old house
Lake Hylia Fairy: A cave NE of Lake Hylia
Light Hype Fairy: The cave south of your house
Desert Fairy: The cave near the desert
Chicken House: The chicken lady's house
Aginahs Cave: The open desert cave
Sahasrahlas Hut: The house near armos
Cave Shop (Lake Hylia): The cave NW Lake Hylia
Blacksmiths Hut: The old smithery
Sick Kids House: The central house in Kakariko
Lost Woods Gamble: A tree trunk door
Fortune Teller (Light): A building NE of Kakariko
Snitch Lady (East): A house guarded by a snitch
Snitch Lady (West): A house guarded by a snitch
Bush Covered House: A house with an uncut lawn
Tavern (Front): A building with a backdoor
Light World Bomb Hut: A Kakariko building with no door
Kakariko Shop: The old Kakariko shop
Mini Moldorm Cave: The cave south of Lake Hylia
Long Fairy Cave: The eastmost portal cave
Good Bee Cave: The open cave SE Lake Hylia
20 Rupee Cave: The rock SE Lake Hylia
50 Rupee Cave: The rock near the desert
Ice Rod Cave: The sealed cave SE Lake Hylia
Library: The old library
Potion Shop: The witch's building
Dam: The old dam
Lumberjack House: The lumberjack house
Lake Hylia Fortune Teller: The building NW Lake Hylia
Kakariko Gamble Game: The old Kakariko gambling den
Waterfall of Wishing: Going behind the waterfall
Capacity Upgrade: The cave on the island
Bonk Rock Cave: The rock pile near Sanctuary
Graveyard Cave: The graveyard ledge
Checkerboard Cave: The NE desert ledge
Cave 45: The ledge south of haunted grove
Kings Grave: The northeastmost grave
Bonk Fairy (Light): The rock pile near your home
Hookshot Fairy: A cave on east DM
Bonk Fairy (Dark): The rock pile near the old bomb shop
Dark Sanctuary Hint: The dark sanctuary cave
Dark Lake Hylia Fairy: The cave NE dark Lake Hylia
C-Shaped House: The NE house in Village of Outcasts
Big Bomb Shop: The old bomb shop
Dark Death Mountain Fairy: The SW cave on dark DM
Dark Lake Hylia Shop: The building NW dark Lake Hylia
Dark World Shop: The hammer sealed building
Red Shield Shop: The fenced in building
Mire Shed: The western hut in the mire
East Dark World Hint: The dark cave near the eastmost portal
Dark Desert Hint: The cave east of the mire
Spike Cave: The ledge cave on west dark DM
Palace of Darkness Hint: The building south of Kiki
Dark Lake Hylia Ledge Spike Cave: The rock SE dark Lake Hylia
Cave Shop (Dark Death Mountain): The base of east dark DM
Dark World Potion Shop: The building near the catfish
Archery Game: The old archery game
Dark World Lumberjack Shop: The northmost Dark World building
Hype Cave: The cave south of the old bomb shop
Brewery: The Village of Outcasts building with no door
Dark Lake Hylia Ledge Hint: The open cave SE dark Lake Hylia
Chest Game: The westmost building in the Village of Outcasts
Dark Desert Fairy: The eastern hut in the mire
Dark Lake Hylia Ledge Fairy: The sealed cave SE dark Lake Hylia
Fortune Teller (Dark): The building NE the Village of Outcasts
Sanctuary: Sanctuary
Lumberjack Tree Cave: The cave Behind Lumberjacks
Lost Woods Hideout Stump: The stump in Lost Woods
North Fairy Cave: The cave East of Graveyard
Bat Cave Cave: The cave in eastern Kakariko
Kakariko Well Cave: The cave in northern Kakariko
Hyrule Castle Secret Entrance Stairs: The tunnel near the castle
Skull Woods First Section Door: The southeastmost skull
Skull Woods Second Section Door (East): The central open skull
Skull Woods Second Section Door (West): The westmost open skull
Desert Palace Entrance (East): The eastern building in the desert
Turtle Rock Isolated Ledge Entrance: The isolated ledge on east dark DM
Bumper Cave (Top): The upper Bumper Cave
Hookshot Cave Back Entrance: The stairs on the floating island
Destination Entrance Naming:
Hyrule Castle: Hyrule Castle (all three entrances)
Eastern Palace: Eastern Palace
Desert Palace: Desert Palace (all four entrances, including final)
Tower of Hera: Tower of Hera
Palace of Darkness: Palace of Darkness
Swamp Palace: Swamp Palace
Skull Woods: Skull Woods (any entrance including final)
Thieves' Town: Thieves' Town
Ice Palace: Ice Palace
Misery Mire: Misery Mire
Turtle Rock: Turtle Rock (all four entrances)
Ganon's Tower: Ganon's Tower
Castle Tower: Agahnim's Tower
A connector: Paradox Cave, Spectacle Rock Cave, Hookshot Cave, Superbunny Cave, Spiral Cave, Old Man Fetch Cave, Old Man House, Elder House, Quarreling Brothers' House, Bumper Cave, DM Fairy Ascent Cave, DM Exit Cave
A bounty of five items: Mini-moldorm cave, Hype Cave, Blind's Hideout
Sahasrahla: Sahasrahla
A cave with two items: Mire hut, Waterfall Fairy, Pyramid Fairy
A fairy fountain: Any healer fairy cave, either bonk cave with four fairies, the "long fairy" cave
A common shop: Any shop that sells bombs by default
The rare shop: The shop that sells the Red Shield by default
The potion shop: Potion Shop
The bomb shop: Bomb Shop
A fortune teller: Any of the three fortune tellers
A house with a chest: Chicken Lady's house, C-House, Brewery
A cave with an item: Checkerboard cave, Hammer Pegs cave, Cave 45, Graveyard Ledge cave
A cave with a chest: Sanc Bonk Rock Cave, Cape Grave Cave, Ice Rod Cave, Aginah's Cave
The dam: Watergate
The sick kid: Sick Kid
The library: Library
Mimic Cave: Mimic Cave
Spike Cave: Spike Cave
A game of 16 chests: VoO chest game (for the item)
A storyteller: The four DW NPCs who charge 20 rupees for a hint as well as the PoD Bdlg guy who gives a free hint
A cave with some cash: 20 rupee cave, 50 rupee cave (both have thieves and some pots)
A game of chance: Gambling game (just for cash, no items)
A game of skill: Archery minigame
The queen of fairies: Capacity Upgrade Fairy
A drop's exit: Sanctuary, LW Thieves' Hideout, Kakariko Well, Magic Bat, Useless Fairy, Uncle Tunnel, Ganon drop exit
A restock room: The Kakariko bomb/arrow restock room
The tavern: The Kakariko tavern
The grass man: The Kakariko man with many beds
A cold bee: The "wrong side" of Ice Rod cave where you can get a Good Bee
Fairies deep in a cave: Hookshot Fairy
Location naming reference:
Mushroom: in the woods
Master Sword Pedestal: at the pedestal
Bottle Merchant: with a merchant
Stumpy: with tree boy
Flute Spot: underground
Digging Game: underground
Lake Hylia Island: on an island
Floating Island: on an island
Bumper Cave Ledge: on a ledge
Spectacle Rock: atop a rock
Maze Race: at the race
Desert Ledge: in the desert
Pyramid: on the pyramid
Catfish: with a catfish
Ether Tablet: at a monument
Bombos Tablet: at a monument
Hobo: with the hobo
Zora's Ledge: near Zora
King Zora: at a high price
Sunken Treasure: underwater
Floodgate Chest: in the dam
Blacksmith: with the smith
Purple Chest: from a box
Old Man: with the old man
Link's Uncle: with your uncle
Secret Passage: near your uncle
Kakariko Well (5 items): in a well
Lost Woods Hideout: near a thief
Lumberjack Tree: in a hole
Magic Bat: with the bat
Paradox Cave (7 items): in a cave with seven chests
Blind's Hideout (5 items): in a basement
Mini Moldorm Cave (5 items): near Moldorms
Hype Cave (4 back chests): near a bat-like man
Hype Cave - Generous Guy: with a bat-like man
Hookshot Cave (4 items): across pits
Sahasrahla's Hut (chests in back): near the elder
Sahasrahla: with the elder
Waterfall Fairy (2 items): near a fairy
Pyramid Fairy (2 items): near a fairy
Mire Shed (2 items): near sparks
Superbunny Cave (2 items): in a connection
Spiral Cave: in spiral cave
Kakariko Tavern: in the bar
Link's House: in your home
Sick Kid: with the sick
Library: near books
Potion Shop: near potions
Spike Cave: beyond spikes
Mimic Cave: in a cave of mimicry
Chest Game: as a prize
Chicken House: near poultry
Aginah's Cave: with Aginah
Ice Rod Cave: in a frozen cave
Brewery: alone in a home
C-Shaped House: alone in a home
Spectacle Rock Cave: alone in a cave
King's Tomb: alone in a cave
Cave 45: alone in a cave
Graveyard Cave: alone in a cave
Checkerboard Cave: alone in a cave
Bonk Rock Cave: alone in a cave
Peg Cave: alone in a cave
Sanctuary: in Sanctuary
Hyrule Castle - Boomerang Chest: in Hyrule Castle
Hyrule Castle - Map Chest: in Hyrule Castle
Hyrule Castle - Zelda's Chest: in Hyrule Castle
Sewers - Dark Cross: in the sewers
Sewers - Secret Room (3 items): in the sewers
Eastern Palace - Boss: with the Armos
Eastern Palace (otherwise, 5 items): in Eastern Palace
Desert Palace - Boss: with Lanmolas
Desert Palace (otherwise, 5 items): in Desert Palace
Tower of Hera - Boss: with Moldorm
Tower of Hera (otherwise, 5 items): in Tower of Hera
Castle Tower (2 items): in Castle Tower
Palace of Darkness - Boss: with Helmasaur King
Palace of Darkness (otherwise, 13 items): in Palace of Darkness
Swamp Palace - Boss: with Arrghus
Swamp Palace (otherwise, 9 items): in Swamp Palace
Skull Woods - Bridge Room: near Mothula
Skull Woods - Boss: with Mothula
Skull Woods (otherwise, 6 items): in Skull Woods
Thieves' Town - Boss: with Blind
Thieves' Town (otherwise, 7 items): in Thieves' Town
Ice Palace - Boss: with Kholdstare
Ice Palace (otherwise, 7 items): in Ice Palace
Misery Mire - Boss: with Vitreous
Misery Mire (otherwise, 7 items): in Misery Mire
Turtle Rock - Boss: with Trinexx
Turtle Rock (otherwise, 11 items): in Turtle Rock
Ganons Tower (after climb, 4 items): atop Ganon's Tower
Ganon's Tower (otherwise, 23 items): in Ganon's Tower

View File

@ -182,18 +182,21 @@ 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('--hints', help='''\
Make telepathic tiles and storytellers give helpful hints.
''', action='store_true')
# included for backwards compatibility # included for backwards compatibility
parser.add_argument('--shuffleganon', help=argparse.SUPPRESS, action='store_true', default=True) parser.add_argument('--shuffleganon', help=argparse.SUPPRESS, action='store_true', default=True)
parser.add_argument('--no-shuffleganon', help='''\ parser.add_argument('--no-shuffleganon', help='''\
If set, the Pyramid Hole and Ganon's Tower are not If set, the Pyramid Hole and Ganon's Tower are not
included entrance shuffle pool. included entrance shuffle pool.
''', action='store_false', dest='shuffleganon') ''', 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=['double', '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'], parser.add_argument('--heartcolor', default='red', const='red', nargs='?', choices=['red', 'blue', 'green', 'yellow', 'random'],
help='Select the color of Link\'s heart meter. (default: %(default)s)') 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
@ -204,6 +207,8 @@ def start():
''') ''')
parser.add_argument('--suppress_rom', help='Do not create an output rom file.', action='store_true') parser.add_argument('--suppress_rom', help='Do not create an output rom file.', action='store_true')
parser.add_argument('--gui', help='Launch the GUI', action='store_true') parser.add_argument('--gui', help='Launch the GUI', action='store_true')
# Deliberately not documented, only useful for vt site integration right now:
parser.add_argument('--shufflebosses', help=argparse.SUPPRESS, default='none', const='none', nargs='?', choices=['none', 'basic', 'normal', 'chaos'])
parser.add_argument('--jsonout', action='store_true', help='''\ parser.add_argument('--jsonout', action='store_true', help='''\
Output .json patch to stdout instead of a patched rom. Used Output .json patch to stdout instead of a patched rom. Used
for VT site integration, do not use otherwise. for VT site integration, do not use otherwise.

View File

@ -7,6 +7,13 @@ def link_entrances(world):
connect_two_way(world, 'Links House', 'Links House Exit') # unshuffled. For now connect_two_way(world, 'Links House', 'Links House Exit') # unshuffled. For now
connect_exit(world, 'Chris Houlihan Room Exit', 'Links House') # should always match link's house, except for plandos connect_exit(world, 'Chris Houlihan Room Exit', 'Links House') # should always match link's house, except for plandos
Dungeon_Exits = Dungeon_Exits_Base.copy()
Cave_Exits = Cave_Exits_Base.copy()
Old_Man_House = Old_Man_House_Base.copy()
Cave_Three_Exits = Cave_Three_Exits_Base.copy()
unbias_some_entrances(Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits)
# setup mandatory connections # setup mandatory connections
for exitname, regionname in mandatory_connections: for exitname, regionname in mandatory_connections:
connect_simple(world, exitname, regionname) connect_simple(world, exitname, regionname)
@ -96,8 +103,8 @@ def link_entrances(world):
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)') connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)')
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)') connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)')
# add old man house to ensure it is alwayxs somewhere on light death mountain # add old man house to ensure it is always somewhere on light death mountain
caves.append(('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)')) caves.extend(list(Old_Man_House))
caves.extend(list(three_exit_caves)) caves.extend(list(three_exit_caves))
# connect rest # connect rest
@ -181,7 +188,8 @@ def link_entrances(world):
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)') connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)')
# place Old Man House in Light World # place Old Man House in Light World
connect_caves(world, lw_entrances, [], [('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)')]) connect_caves(world, lw_entrances, [], list(Old_Man_House)) #for multiple seeds
# now scramble the rest # now scramble the rest
connect_caves(world, lw_entrances, dw_entrances, caves) connect_caves(world, lw_entrances, dw_entrances, caves)
@ -223,7 +231,7 @@ def link_entrances(world):
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)') connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)')
# place Old Man House in Light World # place Old Man House in Light World
connect_caves(world, lw_entrances, [], [('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)')]) connect_caves(world, lw_entrances, [], Old_Man_House)
# connect rest. There's 2 dw entrances remaining, so we will not run into parity issue placing caves # connect rest. There's 2 dw entrances remaining, so we will not run into parity issue placing caves
connect_caves(world, lw_entrances, dw_entrances, caves) connect_caves(world, lw_entrances, dw_entrances, caves)
@ -260,6 +268,7 @@ def link_entrances(world):
bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors) bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors)
blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors)
door_targets = list(Single_Cave_Targets) door_targets = list(Single_Cave_Targets)
old_man_house = list(Old_Man_House)
# tavern back door cannot be shuffled yet # tavern back door cannot be shuffled yet
connect_doors(world, ['Tavern North'], ['Tavern']) connect_doors(world, ['Tavern North'], ['Tavern'])
@ -268,7 +277,7 @@ def link_entrances(world):
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)') connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)')
else: else:
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3)))
lw_entrances.append('Hyrule Castle Entrance (South)') lw_entrances.append('Hyrule Castle Entrance (South)')
if not world.shuffle_ganon: if not world.shuffle_ganon:
@ -276,14 +285,30 @@ def link_entrances(world):
else: else:
dw_entrances.append('Ganons Tower') dw_entrances.append('Ganons Tower')
caves.append('Ganons Tower Exit') caves.append('Ganons Tower Exit')
# we randomize which world requirements we fulfill first so we get better dungeon distribution # we randomize which world requirements we fulfill first so we get better dungeon distribution
#we also places the Old Man House at this time to make sure he can be connected to the desert one way
if random.randint(0, 1) == 0: if random.randint(0, 1) == 0:
caves += old_man_house
connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits) connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits)
try:
caves.remove(old_man_house[0])
except ValueError:
pass
else: #if the cave wasn't placed we get here
connect_caves(world, lw_entrances, [], old_man_house)
connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits) connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits)
else: else:
connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits) connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits)
caves += old_man_house
connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits) connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits)
try:
caves.remove(old_man_house[0])
except ValueError:
pass
else: #if the cave wasn't placed we get here
connect_caves(world, lw_entrances, [], old_man_house)
if world.mode == 'standard': if world.mode == 'standard':
# rest of hyrule castle must be in light world # rest of hyrule castle must be in light world
connect_caves(world, lw_entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')]) connect_caves(world, lw_entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')])
@ -322,12 +347,9 @@ def link_entrances(world):
dw_entrances.remove(bomb_shop) dw_entrances.remove(bomb_shop)
# place the old man cave's entrance somewhere in the light world # place the old man cave's entrance somewhere in the light world
random.shuffle(lw_entrances)
old_man_entrance = lw_entrances.pop() old_man_entrance = lw_entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)') connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)')
# place Old Man House in Light World
connect_caves(world, lw_entrances, [], [('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)')])
# now scramble the rest # now scramble the rest
connect_caves(world, lw_entrances, dw_entrances, caves) connect_caves(world, lw_entrances, dw_entrances, caves)
@ -346,7 +368,7 @@ def link_entrances(world):
must_exits = list(DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + LW_Dungeon_Entrances_Must_Exit) must_exits = list(DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + LW_Dungeon_Entrances_Must_Exit)
old_man_entrances = list(Old_Man_Entrances + ['Tower of Hera']) old_man_entrances = list(Old_Man_Entrances + ['Tower of Hera'])
caves = list(Cave_Exits + Dungeon_Exits + Cave_Three_Exits) # don't need to consider three exit caves, have one exit caves to avoid parity issues caves = list(Cave_Exits + Dungeon_Exits + Cave_Three_Exits + Old_Man_House) # don't need to consider three exit caves, have one exit caves to avoid parity issues
bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors) bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors)
blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors)
door_targets = list(Single_Cave_Targets) door_targets = list(Single_Cave_Targets)
@ -358,7 +380,7 @@ def link_entrances(world):
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)') connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)')
else: else:
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3)))
entrances.append('Hyrule Castle Entrance (South)') entrances.append('Hyrule Castle Entrance (South)')
if not world.shuffle_ganon: if not world.shuffle_ganon:
@ -367,6 +389,7 @@ def link_entrances(world):
entrances.append('Ganons Tower') entrances.append('Ganons Tower')
caves.append('Ganons Tower Exit') caves.append('Ganons Tower Exit')
#place must-exit caves
connect_mandatory_exits(world, entrances, caves, must_exits) connect_mandatory_exits(world, entrances, caves, must_exits)
if world.mode == 'standard': if world.mode == 'standard':
@ -405,8 +428,6 @@ def link_entrances(world):
old_man_entrance = entrances.pop() old_man_entrance = entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)') connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)')
# place Old Man House
connect_caves(world, entrances, [], [('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)')])
# now scramble the rest # now scramble the rest
connect_caves(world, entrances, [], caves) connect_caves(world, entrances, [], caves)
@ -434,7 +455,7 @@ def link_entrances(world):
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)') connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)')
else: else:
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3)))
lw_entrances.append('Hyrule Castle Entrance (South)') lw_entrances.append('Hyrule Castle Entrance (South)')
if not world.shuffle_ganon: if not world.shuffle_ganon:
@ -467,7 +488,7 @@ def link_entrances(world):
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)') connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)')
# place Old Man House in Light World # place Old Man House in Light World
connect_caves(world, lw_entrances, [], [('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)')]) connect_caves(world, lw_entrances, [], list(Old_Man_House)) #need this to avoid badness with multiple seeds
# now scramble the rest # now scramble the rest
connect_caves(world, lw_entrances, dw_entrances, caves) connect_caves(world, lw_entrances, dw_entrances, caves)
@ -1152,6 +1173,7 @@ def connect_mandatory_exits(world, entrances, caves, must_be_exits):
"""This works inplace""" """This works inplace"""
random.shuffle(entrances) random.shuffle(entrances)
random.shuffle(caves) random.shuffle(caves)
used_caves = []
while must_be_exits: while must_be_exits:
exit = must_be_exits.pop() exit = must_be_exits.pop()
# find multi exit cave # find multi exit cave
@ -1163,20 +1185,30 @@ def connect_mandatory_exits(world, entrances, caves, must_be_exits):
if cave is None: if cave is None:
raise RuntimeError('No more caves left. Should not happen!') raise RuntimeError('No more caves left. Should not happen!')
else:
caves.remove(cave)
# all caves are sorted so that the last exit is always reachable
for i in range(len(cave) - 1):
entrance = entrances.pop()
# ToDo Better solution, this is a hot fix. Do not connect both sides of trock ledge to each other # all caves are sorted so that the last exit is always reachable
connect_two_way(world, exit, cave[-1])
if len(cave) == 2:
entrance = entrances.pop()
# ToDo Better solution, this is a hot fix. Do not connect both sides of trock ledge only to each other
if entrance == 'Dark Death Mountain Ledge (West)': if entrance == 'Dark Death Mountain Ledge (West)':
new_entrance = entrances.pop() new_entrance = entrances.pop()
entrances.append(entrance) entrances.append(entrance)
entrance = new_entrance entrance = new_entrance
connect_two_way(world, entrance, cave[0])
connect_two_way(world, entrance, cave[i]) elif cave[-1] == 'Spectacle Rock Cave Exit': #Spectacle rock only has one exit
connect_two_way(world, exit, cave[-1]) for exit in cave[:-1]:
connect_two_way(world,entrances.pop(),exit)
else:#save for later so we can connect to multiple exits
caves.append(cave[0:-1])
random.shuffle(caves)
used_caves.append(cave[0:-1])
caves.remove(cave)
for cave in used_caves:
if cave in caves: #check if we placed multiple entrances from this 3 or 4 exit
for exit in cave:
connect_two_way(world, entrances.pop(), exit)
caves.remove(cave)
def connect_caves(world, lw_entrances, dw_entrances, caves): def connect_caves(world, lw_entrances, dw_entrances, caves):
@ -1302,6 +1334,45 @@ def simple_shuffle_dungeons(world):
connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Turtle Rock Ledge Exit (West)') connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Turtle Rock Ledge Exit (West)')
connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Turtle Rock Ledge Exit (East)') connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Turtle Rock Ledge Exit (East)')
def unbias_some_entrances(Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits):
def shuffle_lists_in_list(ls):
for i, item in enumerate(ls):
if isinstance(item, list):
ls[i] = random.sample(item, len(item))
def tuplize_lists_in_list(ls):
for i, item in enumerate(ls):
if isinstance(item, list):
ls[i] = tuple(item)
shuffle_lists_in_list(Dungeon_Exits)
shuffle_lists_in_list(Cave_Exits)
shuffle_lists_in_list(Old_Man_House)
shuffle_lists_in_list(Cave_Three_Exits)
# paradox fixup
if Cave_Three_Exits[1][0] == "Paradox Cave Exit (Bottom)":
i = random.randint(1,2)
Cave_Three_Exits[1][0] = Cave_Three_Exits[1][i]
Cave_Three_Exits[1][i] = "Paradox Cave Exit (Bottom)"
# TR fixup
tr_fixup = False
for i, item in enumerate(Dungeon_Exits[-1]):
if 'Turtle Rock Ledge Exit (East)' == item:
tr_fixup = True
if 0 != i:
Dungeon_Exits[-1][i] = Dungeon_Exits[-1][0]
Dungeon_Exits[-1][0] = 'Turtle Rock Ledge Exit (East)'
break
if not tr_fixup: raise RuntimeError("TR entrance shuffle fixup didn't happen")
tuplize_lists_in_list(Dungeon_Exits)
tuplize_lists_in_list(Cave_Exits)
tuplize_lists_in_list(Old_Man_House)
tuplize_lists_in_list(Cave_Three_Exits)
LW_Dungeon_Entrances = ['Desert Palace Entrance (South)', LW_Dungeon_Entrances = ['Desert Palace Entrance (South)',
'Desert Palace Entrance (West)', 'Desert Palace Entrance (West)',
@ -1326,7 +1397,7 @@ DW_Dungeon_Entrances = ['Thieves Town',
DW_Dungeon_Entrances_Must_Exit = ['Dark Death Mountain Ledge (East)', DW_Dungeon_Entrances_Must_Exit = ['Dark Death Mountain Ledge (East)',
'Turtle Rock Isolated Ledge Entrance'] 'Turtle Rock Isolated Ledge Entrance']
Dungeon_Exits = [('Desert Palace Exit (South)', 'Desert Palace Exit (West)', 'Desert Palace Exit (East)'), Dungeon_Exits_Base = [['Desert Palace Exit (South)', 'Desert Palace Exit (West)', 'Desert Palace Exit (East)'],
'Desert Palace Exit (North)', 'Desert Palace Exit (North)',
'Eastern Palace Exit', 'Eastern Palace Exit',
'Tower of Hera Exit', 'Tower of Hera Exit',
@ -1337,7 +1408,8 @@ Dungeon_Exits = [('Desert Palace Exit (South)', 'Desert Palace Exit (West)', 'De
'Palace of Darkness Exit', 'Palace of Darkness Exit',
'Swamp Palace Exit', 'Swamp Palace Exit',
'Agahnims Tower Exit', 'Agahnims Tower Exit',
('Turtle Rock Exit (Front)', 'Turtle Rock Ledge Exit (East)', 'Turtle Rock Ledge Exit (West)', 'Turtle Rock Isolated Ledge Exit')] ['Turtle Rock Ledge Exit (East)',
'Turtle Rock Exit (Front)', 'Turtle Rock Ledge Exit (West)', 'Turtle Rock Isolated Ledge Exit']]
DW_Entrances_Must_Exit = ['Bumper Cave (Top)', 'Hookshot Cave Back Entrance'] DW_Entrances_Must_Exit = ['Bumper Cave (Top)', 'Hookshot Cave Back Entrance']
@ -1355,17 +1427,23 @@ Old_Man_Entrances = ['Old Man Cave (East)',
'Spectacle Rock Cave Peak', 'Spectacle Rock Cave Peak',
'Spectacle Rock Cave (Bottom)'] 'Spectacle Rock Cave (Bottom)']
Cave_Exits = [('Elder House Exit (East)', 'Elder House Exit (West)'), Old_Man_House_Base = [['Old Man House Exit (Bottom)', 'Old Man House Exit (Top)']]
('Two Brothers House Exit (East)', 'Two Brothers House Exit (West)'),
('Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)'), Cave_Exits_Base = [['Elder House Exit (East)', 'Elder House Exit (West)'],
('Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Cave Exit (Top)'), ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)'],
('Spiral Cave Exit (Top)', 'Spiral Cave Exit'), ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)'],
('Bumper Cave Exit (Top)', 'Bumper Cave Exit (Bottom)'), ['Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Cave Exit (Top)'],
('Superbunny Cave Exit (Bottom)', 'Superbunny Cave Exit (Top)'), ['Bumper Cave Exit (Top)', 'Bumper Cave Exit (Bottom)'],
('Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)')] ['Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)']]
Cave_Exits_Base += [('Superbunny Cave Exit (Bottom)', 'Superbunny Cave Exit (Top)'),
('Spiral Cave Exit (Top)', 'Spiral Cave Exit')]
Cave_Three_Exits_Base = [('Spectacle Rock Cave Exit (Peak)', 'Spectacle Rock Cave Exit (Top)',
'Spectacle Rock Cave Exit'),
['Paradox Cave Exit (Top)', 'Paradox Cave Exit (Middle)','Paradox Cave Exit (Bottom)']]
Cave_Three_Exits = [('Spectacle Rock Cave Exit (Peak)', 'Spectacle Rock Cave Exit (Top)', 'Spectacle Rock Cave Exit'),
('Paradox Cave Exit (Top)', 'Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Bottom)')]
LW_Entrances = ['Elder House (East)', LW_Entrances = ['Elder House (East)',
'Elder House (West)', 'Elder House (West)',
@ -1750,6 +1828,9 @@ mandatory_connections = [('Lake Hylia Central Island Pier', 'Lake Hylia Central
('Fairy Ascension Drop', 'East Death Mountain (Bottom)'), ('Fairy Ascension Drop', 'East Death Mountain (Bottom)'),
('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'),
('Fairy Ascension Ledge', 'Fairy Ascension Ledge'), ('Fairy Ascension Ledge', 'Fairy Ascension Ledge'),
('Fairy Ascension Cave Climb', 'Fairy Ascension Cave (Top)'),
('Fairy Ascension Cave Pots', 'Fairy Ascension Cave (Bottom)'),
('Fairy Ascension Cave Drop', 'Fairy Ascension Cave (Drop)'),
('Spectacle Rock Mirror Spot', 'Spectacle Rock'), ('Spectacle Rock Mirror Spot', 'Spectacle Rock'),
('Dark Death Mountain Drop (East)', 'Dark Death Mountain (East Bottom)'), ('Dark Death Mountain Drop (East)', 'Dark Death Mountain (East Bottom)'),
('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'),
@ -1924,8 +2005,8 @@ default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'),
('Paradox Cave Exit (Middle)', 'East Death Mountain (Bottom)'), ('Paradox Cave Exit (Middle)', 'East Death Mountain (Bottom)'),
('Paradox Cave Exit (Top)', 'East Death Mountain (Top)'), ('Paradox Cave Exit (Top)', 'East Death Mountain (Top)'),
('Hookshot Fairy', 'Hookshot Fairy'), ('Hookshot Fairy', 'Hookshot Fairy'),
('Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave'), ('Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Bottom)'),
('Fairy Ascension Cave (Top)', 'Fairy Ascension Cave'), ('Fairy Ascension Cave (Top)', 'Fairy Ascension Cave (Top)'),
('Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Plateau'), ('Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Plateau'),
('Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Ledge'), ('Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Ledge'),
('Spiral Cave', 'Spiral Cave (Top)'), ('Spiral Cave', 'Spiral Cave (Top)'),

21
Gui.py
View File

@ -73,6 +73,9 @@ def guiMain(args=None):
shuffleGanonVar = IntVar() shuffleGanonVar = IntVar()
shuffleGanonVar.set(1) #set default 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)
hintsVar = IntVar()
hintsVar.set(1) #set default
hintsCheckbutton = Checkbutton(checkBoxFrame, text="Include Helpful Hints", variable=hintsVar)
customVar = IntVar() customVar = IntVar()
customCheckbutton = Checkbutton(checkBoxFrame, text="Use custom item pool", variable=customVar) customCheckbutton = Checkbutton(checkBoxFrame, text="Use custom item pool", variable=customVar)
@ -85,6 +88,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)
hintsCheckbutton.pack(expand=True, anchor=W)
customCheckbutton.pack(expand=True, anchor=W) customCheckbutton.pack(expand=True, anchor=W)
fileDialogFrame = Frame(rightHalfFrame) fileDialogFrame = Frame(rightHalfFrame)
@ -205,7 +209,7 @@ def guiMain(args=None):
heartbeepFrame = Frame(drowDownFrame) heartbeepFrame = Frame(drowDownFrame)
heartbeepVar = StringVar() heartbeepVar = StringVar()
heartbeepVar.set('normal') heartbeepVar.set('normal')
heartbeepOptionMenu = OptionMenu(heartbeepFrame, heartbeepVar, 'normal', 'half', 'quarter', 'off') heartbeepOptionMenu = OptionMenu(heartbeepFrame, heartbeepVar, 'double', 'normal', 'half', 'quarter', 'off')
heartbeepOptionMenu.pack(side=RIGHT) heartbeepOptionMenu.pack(side=RIGHT)
heartbeepLabel = Label(heartbeepFrame, text='Heartbeep sound rate') heartbeepLabel = Label(heartbeepFrame, text='Heartbeep sound rate')
heartbeepLabel.pack(side=LEFT) heartbeepLabel.pack(side=LEFT)
@ -213,7 +217,7 @@ def guiMain(args=None):
heartcolorFrame = Frame(drowDownFrame) heartcolorFrame = Frame(drowDownFrame)
heartcolorVar = StringVar() heartcolorVar = StringVar()
heartcolorVar.set('red') heartcolorVar.set('red')
heartcolorOptionMenu = OptionMenu(heartcolorFrame, heartcolorVar, 'red', 'blue', 'green', 'yellow') heartcolorOptionMenu = OptionMenu(heartcolorFrame, heartcolorVar, 'red', 'blue', 'green', 'yellow', 'random')
heartcolorOptionMenu.pack(side=RIGHT) heartcolorOptionMenu.pack(side=RIGHT)
heartcolorLabel = Label(heartcolorFrame, text='Heart color') heartcolorLabel = Label(heartcolorFrame, text='Heart color')
heartcolorLabel.pack(side=LEFT) heartcolorLabel.pack(side=LEFT)
@ -271,6 +275,7 @@ 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.hints = bool(hintsVar.get())
guiargs.custom = bool(customVar.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()), 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(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()),
@ -281,6 +286,7 @@ def guiMain(args=None):
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(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(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()), int(universalkeyVar.get())] int(triforceVar.get()), int(rupoorcostVar.get()), int(universalkeyVar.get())]
guiargs.shufflebosses = None
guiargs.rom = romVar.get() guiargs.rom = romVar.get()
guiargs.jsonout = None guiargs.jsonout = None
guiargs.sprite = sprite guiargs.sprite = sprite
@ -361,13 +367,13 @@ def guiMain(args=None):
drowDownFrame2 = Frame(topFrame2) drowDownFrame2 = Frame(topFrame2)
heartbeepFrame2 = Frame(drowDownFrame2) heartbeepFrame2 = Frame(drowDownFrame2)
heartbeepOptionMenu2 = OptionMenu(heartbeepFrame2, heartbeepVar, 'normal', 'half', 'quarter', 'off') heartbeepOptionMenu2 = OptionMenu(heartbeepFrame2, heartbeepVar, 'double', 'normal', 'half', 'quarter', 'off')
heartbeepOptionMenu2.pack(side=RIGHT) heartbeepOptionMenu2.pack(side=RIGHT)
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) heartcolorFrame2 = Frame(drowDownFrame2)
heartcolorOptionMenu2 = OptionMenu(heartcolorFrame2, heartcolorVar, 'red', 'blue', 'green', 'yellow') heartcolorOptionMenu2 = OptionMenu(heartcolorFrame2, heartcolorVar, 'red', 'blue', 'green', 'yellow', 'random')
heartcolorOptionMenu2.pack(side=RIGHT) heartcolorOptionMenu2.pack(side=RIGHT)
heartcolorLabel2 = Label(heartcolorFrame2, text='Heart color') heartcolorLabel2 = Label(heartcolorFrame2, text='Heart color')
heartcolorLabel2.pack(side=LEFT) heartcolorLabel2.pack(side=LEFT)
@ -1012,6 +1018,7 @@ def guiMain(args=None):
logicVar.set(args.logic) logicVar.set(args.logic)
romVar.set(args.rom) romVar.set(args.rom)
shuffleGanonVar.set(args.shuffleganon) shuffleGanonVar.set(args.shuffleganon)
hintsVar.set(args.hints)
if args.sprite is not None: if args.sprite is not None:
set_sprite(Sprite(args.sprite)) set_sprite(Sprite(args.sprite))
@ -1077,7 +1084,7 @@ class SpriteSelector(object):
for file in glob(output_path(path)): for file in glob(output_path(path)):
sprites.append(Sprite(file)) sprites.append(Sprite(file))
sprites.sort(key=lambda s: str.lower(s.name or "")) sprites.sort(key=lambda s: str.lower(s.name or "").strip())
i = 0 i = 0
for sprite in sprites: for sprite in sprites:
@ -1114,7 +1121,7 @@ class SpriteSelector(object):
try: try:
task.update_status("Downloading official sprites list") task.update_status("Downloading official sprites list")
with urlopen('http://vt.alttp.run/sprites') as response: with urlopen('https://alttpr.com/sprites') as response:
sprites_arr = json.loads(response.read().decode("utf-8")) sprites_arr = json.loads(response.read().decode("utf-8"))
except Exception as e: except Exception as e:
resultmessage = "Error getting list of official sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e) resultmessage = "Error getting list of official sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e)
@ -1161,7 +1168,7 @@ class SpriteSelector(object):
deleted += 1 deleted += 1
if successful: if successful:
resultmessage = "official sprites updated sucessfully" resultmessage = "official sprites updated successfully"
task.queue_event(finished) task.queue_event(finished)

View File

@ -3,6 +3,7 @@ import logging
import random import random
from BaseClasses import Region, RegionType, Shop, ShopType, Location from BaseClasses import Region, RegionType, Shop, ShopType, Location
from Bosses import place_bosses
from Dungeons import get_dungeon_item_pool from Dungeons import get_dungeon_item_pool
from EntranceShuffle import connect_entrance from EntranceShuffle import connect_entrance
from Fill import FillError, fill_restrictive from Fill import FillError, fill_restrictive
@ -20,9 +21,9 @@ basicgloves = ['Power Glove', 'Titans Mitts']
normalbottles = ['Bottle', 'Bottle (Red Potion)', 'Bottle (Green Potion)', 'Bottle (Blue Potion)', 'Bottle (Fairy)', 'Bottle (Bee)', 'Bottle (Good Bee)'] normalbottles = ['Bottle', 'Bottle (Red Potion)', 'Bottle (Green Potion)', 'Bottle (Blue Potion)', 'Bottle (Fairy)', 'Bottle (Bee)', 'Bottle (Good Bee)']
hardbottles = ['Bottle', 'Bottle (Red Potion)', 'Bottle (Green Potion)', 'Bottle (Blue Potion)', 'Bottle (Bee)', 'Bottle (Good Bee)'] hardbottles = ['Bottle', 'Bottle (Red Potion)', 'Bottle (Green Potion)', 'Bottle (Blue Potion)', 'Bottle (Bee)', 'Bottle (Good Bee)']
normalbaseitems = (['Silver Arrows', 'Magic Upgrade (1/2)', 'Single Arrow', 'Sanctuary Heart Container', 'Arrow Upgrade (+10)', 'Bomb Upgrade (+10)'] + normalbaseitems = (['Silver Arrows', 'Magic Upgrade (1/2)', 'Single Arrow', 'Sanctuary Heart Container', 'Arrows (10)', 'Bombs (3)'] +
['Rupees (300)'] * 4 + ['Boss Heart Container'] * 10 + ['Piece of Heart'] * 24) ['Rupees (300)'] * 4 + ['Boss Heart Container'] * 10 + ['Piece of Heart'] * 24)
normalfirst15extra = ['Rupees (100)', 'Rupees (300)', 'Rupees (50)'] + ['Arrow Upgrade (+5)'] * 6 + ['Bomb Upgrade (+5)'] * 6 normalfirst15extra = ['Rupees (100)', 'Rupees (300)', 'Rupees (50)'] + ['Arrows (10)'] * 6 + ['Bombs (3)'] * 6
normalsecond15extra = ['Bombs (3)'] * 9 + ['Rupees (50)'] * 2 + ['Arrows (10)'] * 2 + ['Rupee (1)'] + ['Bombs (10)'] normalsecond15extra = ['Bombs (3)'] * 9 + ['Rupees (50)'] * 2 + ['Arrows (10)'] * 2 + ['Rupee (1)'] + ['Bombs (10)']
normalthird10extra = ['Rupees (50)'] * 4 + ['Rupees (20)'] * 3 + ['Arrows (10)', 'Rupee (1)', 'Rupees (5)'] normalthird10extra = ['Rupees (50)'] * 4 + ['Rupees (20)'] * 3 + ['Arrows (10)', 'Rupee (1)', 'Rupees (5)']
normalfourth5extra = ['Arrows (10)'] * 2 + ['Rupees (20)'] * 2 + ['Rupees (5)'] normalfourth5extra = ['Arrows (10)'] * 2 + ['Rupees (20)'] * 2 + ['Rupees (5)']
@ -33,7 +34,7 @@ easybaseitems = (['Sanctuary Heart Container'] + ['Rupees (300)'] * 4 + ['Magic
['Boss Heart Container'] * 10 + ['Piece of Heart'] * 12) ['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)'] + ['Arrows (10)'] * 7 + ['Bombs (3)'] * 7
easysecond10extra = ['Bombs (3)'] * 7 + ['Rupee (1)', 'Rupees (50)', 'Bombs (10)'] easysecond10extra = ['Bombs (3)'] * 7 + ['Rupee (1)', 'Rupees (50)', 'Bombs (10)']
easythird5extra = ['Rupees (50)'] * 2 + ['Bombs (3)'] * 2 + ['Arrows (10)'] 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
@ -265,6 +266,7 @@ def generate_itempool(world):
tr_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)] tr_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)]
world.required_medallions = (mm_medallion, tr_medallion) world.required_medallions = (mm_medallion, tr_medallion)
place_bosses(world)
set_up_shops(world) set_up_shops(world)
if world.retro: if world.retro:
@ -272,9 +274,6 @@ def generate_itempool(world):
create_dynamic_shop_locations(world) create_dynamic_shop_locations(world)
# distribute crystals
fill_prizes(world)
take_any_locations = [ take_any_locations = [
'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', 'Light World Bomb Hut', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', 'Light World Bomb Hut',
'Fortune Teller (Light)', 'Lake Hylia Fortune Teller', 'Lumberjack House', 'Bonk Fairy (Light)', 'Fortune Teller (Light)', 'Lake Hylia Fortune Teller', 'Lumberjack House', 'Bonk Fairy (Light)',
@ -288,7 +287,7 @@ take_any_locations = [
def set_up_take_anys(world): def set_up_take_anys(world):
regions = random.sample(take_any_locations, 5) regions = random.sample(take_any_locations, 5)
old_man_take_any = Region("Old Man Sword Cave", RegionType.Cave) old_man_take_any = Region("Old Man Sword Cave", RegionType.Cave, 'the sword cave')
world.regions.append(old_man_take_any) world.regions.append(old_man_take_any)
world.dynamic_regions.append(old_man_take_any) world.dynamic_regions.append(old_man_take_any)
@ -310,7 +309,7 @@ def set_up_take_anys(world):
old_man_take_any.shop.add_inventory(0, 'Rupees (300)', 0, 0) old_man_take_any.shop.add_inventory(0, 'Rupees (300)', 0, 0)
for num in range(4): for num in range(4):
take_any = Region("Take-Any #{}".format(num+1), RegionType.Cave) take_any = Region("Take-Any #{}".format(num+1), RegionType.Cave, 'a cave of choice')
world.regions.append(take_any) world.regions.append(take_any)
world.dynamic_regions.append(take_any) world.dynamic_regions.append(take_any)
@ -346,7 +345,7 @@ def create_dynamic_shop_locations(world):
def fill_prizes(world, attempts=15): 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] 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] unplaced_prizes = [crystal for crystal in crystals if crystal.name not in placed_prizes]
@ -374,6 +373,9 @@ def set_up_shops(world):
# Changes to basic Shops # Changes to basic Shops
# TODO: move hard+ mode changes for sheilds here, utilizing the new shops # TODO: move hard+ mode changes for sheilds here, utilizing the new shops
for shop in world.shops:
shop.active = True
if world.retro: if world.retro:
rss = world.get_region('Red Shield Shop').shop rss = world.get_region('Red Shield Shop').shop
rss.active = True rss.active = True

302
Items.py
View File

@ -11,8 +11,8 @@ def ItemFactory(items):
singleton = True singleton = True
for item in items: for item in items:
if item in item_table: if item in item_table:
advancement, priority, type, code, pedestal_hint, pedestal_credit, sickkid_credit, zora_credit, witch_credit, fluteboy_credit = item_table[item] advancement, priority, type, code, pedestal_hint, pedestal_credit, sickkid_credit, zora_credit, witch_credit, fluteboy_credit, hint_text = item_table[item]
ret.append(Item(item, advancement, priority, type, code, pedestal_hint, pedestal_credit, sickkid_credit, zora_credit, witch_credit, fluteboy_credit)) ret.append(Item(item, advancement, priority, type, code, pedestal_hint, pedestal_credit, sickkid_credit, zora_credit, witch_credit, fluteboy_credit, hint_text))
else: else:
logging.getLogger('').warning('Unknown Item: %s', item) logging.getLogger('').warning('Unknown Item: %s', item)
return None return None
@ -22,153 +22,153 @@ def ItemFactory(items):
return ret return ret
# Format: Name: (Advancement, Priority, Type, ItemCode, Pedestal Hint Text, Pedestal Credit Text, Sick Kid Credit Text, Zora Credit Text, Witch Credit Text, Flute Boy Credit Text) # Format: Name: (Advancement, Priority, Type, ItemCode, Pedestal Hint Text, Pedestal Credit Text, Sick Kid Credit Text, Zora Credit Text, Witch Credit Text, Flute Boy Credit Text, Hint Text)
item_table = {'Bow': (True, False, None, 0x0B, 'You have\nchosen the\narcher class.', 'the stick and twine', 'arrow-slinging kid', 'arrow sling for sale', 'witch and robin hood', 'archer boy shoots again'), item_table = {'Bow': (True, False, None, 0x0B, 'You have\nchosen the\narcher class.', 'the stick and twine', 'arrow-slinging kid', 'arrow sling for sale', 'witch and robin hood', 'archer boy shoots again', 'the Bow'),
'Book of Mudora': (True, False, None, 0x1D, 'This is a\nparadox?!', 'and the story book', 'the scholarly kid', 'moon runes for sale', 'drugs for literacy', 'book-worm boy can read again'), 'Book of Mudora': (True, False, None, 0x1D, 'This is a\nparadox?!', 'and the story book', 'the scholarly kid', 'moon runes for sale', 'drugs for literacy', 'book-worm boy can read again', 'the Book'),
'Hammer': (True, False, None, 0x09, 'stop\nhammer time!', 'and m c hammer', 'hammer-smashing kid', 'm c hammer for sale', 'stop... hammer time', 'stop, hammer time'), 'Hammer': (True, False, None, 0x09, 'stop\nhammer time!', 'and m c hammer', 'hammer-smashing kid', 'm c hammer for sale', 'stop... hammer time', 'stop, hammer time', 'the hammer'),
'Hookshot': (True, False, None, 0x0A, 'BOING!!!\nBOING!!!\nBOING!!!', 'and the tickle beam', 'tickle-monster kid', 'tickle beam for sale', 'witch and tickle boy', 'beam boy tickles again'), 'Hookshot': (True, False, None, 0x0A, 'BOING!!!\nBOING!!!\nBOING!!!', 'and the tickle beam', 'tickle-monster kid', 'tickle beam for sale', 'witch and tickle boy', 'beam boy tickles again', 'the Hookshot'),
'Magic Mirror': (True, False, None, 0x1A, 'Isn\'t your\nreflection so\npretty?', 'the face reflector', 'the narcissistic kid', 'your face for sale', 'trades looking-glass', 'narcissistic boy is happy again'), 'Magic Mirror': (True, False, None, 0x1A, 'Isn\'t your\nreflection so\npretty?', 'the face reflector', 'the narcissistic kid', 'your face for sale', 'trades looking-glass', 'narcissistic boy is happy again', 'the Mirror'),
'Ocarina': (True, False, None, 0x14, 'Save the duck\nand fly to\nfreedom!', 'and the duck call', 'the duck-call kid', 'duck call for sale', 'duck-calls for trade', 'ocarina boy plays again'), 'Ocarina': (True, False, None, 0x14, 'Save the duck\nand fly to\nfreedom!', 'and the duck call', 'the duck-call kid', 'duck call for sale', 'duck-calls for trade', 'ocarina boy plays again', 'the Flute'),
'Pegasus Boots': (True, False, None, 0x4B, 'Gotta go fast!', 'and the sprint shoes', 'the running-man kid', 'sprint shoe for sale', 'shrooms for speed', 'gotta-go-fast boy runs again'), 'Pegasus Boots': (True, False, None, 0x4B, 'Gotta go fast!', 'and the sprint shoes', 'the running-man kid', 'sprint shoe for sale', 'shrooms for speed', 'gotta-go-fast boy runs again', 'the Boots'),
'Power Glove': (True, False, None, 0x1B, 'Now you can\nlift weak\nstuff!', 'and the grey mittens', 'body-building kid', 'lift glove for sale', 'fungus for gloves', 'body-building boy lifts again'), 'Power Glove': (True, False, None, 0x1B, 'Now you can\nlift weak\nstuff!', 'and the grey mittens', 'body-building kid', 'lift glove for sale', 'fungus for gloves', 'body-building boy lifts again', 'the glove'),
'Cape': (True, False, None, 0x19, 'Wear this to\nbecome\ninvisible!', 'the camouflage cape', 'red riding-hood kid', 'red hood for sale', 'hood from a hood', 'dapper boy hides again'), 'Cape': (True, False, None, 0x19, 'Wear this to\nbecome\ninvisible!', 'the camouflage cape', 'red riding-hood kid', 'red hood for sale', 'hood from a hood', 'dapper boy hides again', 'the cape'),
'Mushroom': (True, False, None, 0x29, 'I\'m a fun guy!\n\nI\'m a funghi!', 'and the legal drugs', 'the drug-dealing kid', 'legal drugs for sale', 'shroom swap', 'shroom boy sells drugs again'), 'Mushroom': (True, False, None, 0x29, 'I\'m a fun guy!\n\nI\'m a funghi!', 'and the legal drugs', 'the drug-dealing kid', 'legal drugs for sale', 'shroom swap', 'shroom boy sells drugs again', 'the mushroom'),
'Shovel': (True, False, None, 0x13, 'Can\n You\n Dig it?', 'and the fetch quest', 'archaeologist kid', 'dirt spade for sale', 'can you dig it', 'shovel boy digs again'), 'Shovel': (True, False, None, 0x13, 'Can\n You\n Dig it?', 'and the spade', 'archaeologist kid', 'dirt spade for sale', 'can you dig it', 'shovel boy digs again', 'the shovel'),
'Lamp': (True, False, None, 0x12, 'Baby, baby,\nbaby.\nLight my way!', 'and the flashlight', 'light-shining kid', 'flashlight for sale', 'fungus for illumination', 'illuminated boy can see again'), 'Lamp': (True, False, None, 0x12, 'Baby, baby,\nbaby.\nLight my way!', 'and the flashlight', 'light-shining kid', 'flashlight for sale', 'fungus for illumination', 'illuminated boy can see again', 'the lamp'),
'Magic Powder': (True, False, None, 0x0D, 'you can turn\nanti-faeries\ninto faeries', 'and the magic sack', 'the sack-holding kid', 'magic sack for sale', 'the witch and assistant', 'magic boy plays marbles again'), 'Magic Powder': (True, False, None, 0x0D, 'you can turn\nanti-faeries\ninto faeries', 'and the magic sack', 'the sack-holding kid', 'magic sack for sale', 'the witch and assistant', 'magic boy plays marbles again', 'the powder'),
'Moon Pearl': (True, False, None, 0x1F, ' Bunny Link\n be\n gone!', 'and the jaw breaker', 'fortune-telling kid', 'lunar orb for sale', 'shrooms for moon rock', 'moon boy plays ball again'), 'Moon Pearl': (True, False, None, 0x1F, ' Bunny Link\n be\n gone!', 'and the jaw breaker', 'fortune-telling kid', 'lunar orb for sale', 'shrooms for moon rock', 'moon boy plays ball again', 'the moon pearl'),
'Cane of Somaria': (True, False, None, 0x15, 'I make blocks\nto hold down\nswitches!', 'and the red blocks', 'the block-making kid', 'block stick for sale', 'block stick for trade', 'cane boy makes blocks again'), 'Cane of Somaria': (True, False, None, 0x15, 'I make blocks\nto hold down\nswitches!', 'and the red blocks', 'the block-making kid', 'block stick for sale', 'block stick for trade', 'cane boy makes blocks again', 'the red cane'),
'Fire Rod': (True, False, None, 0x07, 'I\'m the hot\nrod. I make\nthings burn!', 'and the flamethrower', 'fire-starting kid', 'rage rod for sale', 'fungus for rage-rod', 'firestarter boy burns again'), 'Fire Rod': (True, False, None, 0x07, 'I\'m the hot\nrod. I make\nthings burn!', 'and the flamethrower', 'fire-starting kid', 'rage rod for sale', 'fungus for rage-rod', 'firestarter boy burns again', 'the fire rod'),
'Flippers': (True, False, None, 0x1E, 'fancy a swim?', 'and the toewebs', 'the swimming kid', 'finger webs for sale', 'shrooms let you swim', 'swimming boy swims agai'), 'Flippers': (True, False, None, 0x1E, 'fancy a swim?', 'and the toewebs', 'the swimming kid', 'finger webs for sale', 'shrooms let you swim', 'swimming boy swims again', 'the flippers'),
'Ice Rod': (True, False, None, 0x08, 'I\'m the cold\nrod. I make\nthings freeze!', 'and the freeze ray', 'the ice-bending kid', 'freeze ray for sale', 'fungus for ice-rod', 'ice-cube boy freezes again'), 'Ice Rod': (True, False, None, 0x08, 'I\'m the cold\nrod. I make\nthings freeze!', 'and the freeze ray', 'the ice-bending kid', 'freeze ray for sale', 'fungus for ice-rod', 'ice-cube boy freezes again', 'the ice rod'),
'Titans Mitts': (True, False, None, 0x1C, 'Now you can\nlift heavy\nstuff!', 'and the golden glove', 'body-building kid', 'carry glove for sale', 'fungus for bling-gloves', 'body-building boy has gold again'), 'Titans Mitts': (True, False, None, 0x1C, 'Now you can\nlift heavy\nstuff!', 'and the golden glove', 'body-building kid', 'carry glove for sale', 'fungus for bling-gloves', 'body-building boy has gold again', 'the mitts'),
'Ether': (True, False, None, 0x10, 'This magic\ncoin freezes\neverything!', 'and the bolt coin', 'coin-collecting kid', 'bolt coin for sale', 'shrooms for bolt-coin', 'medallion boy sees floor again'), 'Ether': (True, False, None, 0x10, 'This magic\ncoin freezes\neverything!', 'and the bolt coin', 'coin-collecting kid', 'bolt coin for sale', 'shrooms for bolt-coin', 'medallion boy sees floor again', 'Ether'),
'Bombos': (True, False, None, 0x0F, 'Burn, baby,\nburn! Fear my\nring of fire!', 'and the swirly coin', 'coin-collecting kid', 'swirly coin for sale', 'shrooms for swirly-coin', 'medallion boy melts room again'), 'Bombos': (True, False, None, 0x0F, 'Burn, baby,\nburn! Fear my\nring of fire!', 'and the swirly coin', 'coin-collecting kid', 'swirly coin for sale', 'shrooms for swirly-coin', 'medallion boy melts room again', 'Bombos'),
'Quake': (True, False, None, 0x11, 'Maxing out the\nRichter scale\nis what I do!', 'and the wavy coin', 'coin-collecting kid', 'wavy coin for sale', 'shrooms for wavy-coin', 'medallion boy shakes dirt again'), 'Quake': (True, False, None, 0x11, 'Maxing out the\nRichter scale\nis what I do!', 'and the wavy coin', 'coin-collecting kid', 'wavy coin for sale', 'shrooms for wavy-coin', 'medallion boy shakes dirt again', 'Quake'),
'Bottle': (True, False, None, 0x16, 'Now you can\nstore potions\nand stuff!', 'and the terrarium', 'the terrarium kid', 'terrarium for sale', 'special promotion', 'bottle boy has terrarium again'), 'Bottle': (True, False, None, 0x16, 'Now you can\nstore potions\nand stuff!', 'and the terrarium', 'the terrarium kid', 'terrarium for sale', 'special promotion', 'bottle boy has terrarium again', 'a Bottle'),
'Bottle (Red Potion)': (True, False, None, 0x2B, 'Hearty red goop!', 'and the red goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has red goo again'), 'Bottle (Red Potion)': (True, False, None, 0x2B, 'Hearty red goop!', 'and the red goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has red goo again', 'a Bottle'),
'Bottle (Green Potion)': (True, False, None, 0x2C, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again'), 'Bottle (Green Potion)': (True, False, None, 0x2C, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again', 'a Bottle'),
'Bottle (Blue Potion)': (True, False, None, 0x2D, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again'), 'Bottle (Blue Potion)': (True, False, None, 0x2D, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again', 'a Bottle'),
'Bottle (Fairy)': (True, False, None, 0x3D, 'Save me and I will revive you', 'and the captive', 'the tingle kid', 'hostage for sale', 'fairy dust and shrooms', 'bottle boy has friend again'), 'Bottle (Fairy)': (True, False, None, 0x3D, 'Save me and I will revive you', 'and the captive', 'the tingle kid', 'hostage for sale', 'fairy dust and shrooms', 'bottle boy has friend again', 'a Bottle'),
'Bottle (Bee)': (True, False, None, 0x3C, 'I will sting your foes a few times', 'and the sting buddy', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has mad bee again'), 'Bottle (Bee)': (True, False, None, 0x3C, 'I will sting your foes a few times', 'and the sting buddy', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has mad bee again', 'a Bottle'),
'Bottle (Good Bee)': (True, False, None, 0x48, 'I will sting your foes a whole lot!', 'and the sparkle sting', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has beetor again'), 'Bottle (Good Bee)': (True, False, None, 0x48, 'I will sting your foes a whole lot!', 'and the sparkle sting', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has beetor again', 'a Bottle'),
'Master Sword': (True, False, 'Sword', 0x50, 'I beat barries and pigs alike', 'and the master sword', 'sword-wielding kid', 'glow sword for sale', 'fungus for blue slasher', 'sword boy fights again'), 'Master Sword': (True, False, 'Sword', 0x50, 'I beat barries and pigs alike', 'and the master sword', 'sword-wielding kid', 'glow sword for sale', 'fungus for blue slasher', 'sword boy fights again', 'the Master Sword'),
'Tempered Sword': (True, False, 'Sword', 0x02, 'I stole the\nblacksmith\'s\njob!', 'the tempered sword', 'sword-wielding kid', 'flame sword for sale', 'fungus for red slasher', 'sword boy fights again'), 'Tempered Sword': (True, False, 'Sword', 0x02, 'I stole the\nblacksmith\'s\njob!', 'the tempered sword', 'sword-wielding kid', 'flame sword for sale', 'fungus for red slasher', 'sword boy fights again', 'the Tempered Sword'),
'Fighter Sword': (True, False, 'Sword', 0x49, 'A pathetic\nsword rests\nhere!', 'the tiny sword', 'sword-wielding kid', 'tiny sword for sale', 'fungus for tiny slasher', 'sword boy fights again'), 'Fighter Sword': (True, False, 'Sword', 0x49, 'A pathetic\nsword rests\nhere!', 'the tiny sword', 'sword-wielding kid', 'tiny sword for sale', 'fungus for tiny slasher', 'sword boy fights again', 'the small sword'),
'Golden Sword': (True, False, 'Sword', 0x03, 'The butter\nsword rests\nhere!', 'and the butter sword', 'sword-wielding kid', 'butter for sale', 'cap churned to butter', 'sword boy fights again'), 'Golden Sword': (True, False, 'Sword', 0x03, 'The butter\nsword rests\nhere!', 'and the butter sword', 'sword-wielding kid', 'butter for sale', 'cap churned to butter', 'sword boy fights again', 'the Golden Sword'),
'Progressive Sword': (True, False, 'Sword', 0x5E, 'a better copy\nof your sword\nfor your time', 'the unknown sword', 'sword-wielding kid', 'sword for sale', 'fungus for some slasher', 'sword boy fights again'), 'Progressive Sword': (True, False, 'Sword', 0x5E, 'a better copy\nof your sword\nfor your time', 'the unknown sword', 'sword-wielding kid', 'sword for sale', 'fungus for some slasher', 'sword boy fights again', 'a sword'),
'Progressive Glove': (True, False, None, 0x61, 'a way to lift\nheavier things', 'and the lift upgrade', 'body-building kid', 'some glove for sale', 'fungus for gloves', 'body-building boy lifts again'), 'Progressive Glove': (True, False, None, 0x61, 'a way to lift\nheavier things', 'and the lift upgrade', 'body-building kid', 'some glove for sale', 'fungus for gloves', 'body-building boy lifts again', 'a glove'),
'Silver Arrows': (True, False, None, 0x58, 'Do you fancy\nsilver tipped\narrows?', 'and the ganonsbane', 'ganon-killing kid', 'ganon doom for sale', 'fungus for pork', 'archer boy shines again'), 'Silver Arrows': (True, False, None, 0x58, 'Do you fancy\nsilver tipped\narrows?', 'and the ganonsbane', 'ganon-killing kid', 'ganon doom for sale', 'fungus for pork', 'archer boy shines again', 'the silver arrows'),
'Green Pendant': (True, False, 'Crystal', [0x04, 0x38, 0x62, 0x00, 0x69, 0x01], None, None, None, None, None, None), 'Green Pendant': (True, False, 'Crystal', [0x04, 0x38, 0x62, 0x00, 0x69, 0x01], None, None, None, None, None, None, None),
'Red Pendant': (True, False, 'Crystal', [0x02, 0x34, 0x60, 0x00, 0x69, 0x02], None, None, None, None, None, None), 'Red Pendant': (True, False, 'Crystal', [0x02, 0x34, 0x60, 0x00, 0x69, 0x02], None, None, None, None, None, None, None),
'Blue Pendant': (True, False, 'Crystal', [0x01, 0x32, 0x60, 0x00, 0x69, 0x03], None, None, None, None, None, None), 'Blue Pendant': (True, False, 'Crystal', [0x01, 0x32, 0x60, 0x00, 0x69, 0x03], None, None, None, None, None, None, None),
'Triforce': (True, False, None, 0x6A, '\n YOU WIN!', 'and the triforce', 'victorious kid', 'victory for sale', 'fungus for the win', 'greedy boy wins game again'), 'Triforce': (True, False, None, 0x6A, '\n YOU WIN!', 'and the triforce', 'victorious kid', 'victory for sale', 'fungus for the win', 'greedy boy wins game again', 'the Triforce'),
'Power Star': (True, False, None, 0x6B, 'a small victory', 'and the power star', 'star-struck kid', 'star for sale', 'see stars with shroom', 'mario powers up again'), 'Power Star': (True, False, None, 0x6B, 'a small victory', 'and the power star', 'star-struck kid', 'star for sale', 'see stars with shroom', 'mario powers up again', 'a Power Star'),
'Triforce Piece': (True, False, None, 0x6C, 'a small victory', 'and the thirdforce', 'triangular kid', 'triangle for sale', 'fungus for triangle', 'wise boy has triangle again'), 'Triforce Piece': (True, False, None, 0x6C, 'a small victory', 'and the thirdforce', 'triangular kid', 'triangle for sale', 'fungus for triangle', 'wise boy has triangle again', 'a Triforce Piece'),
'Crystal 1': (True, False, 'Crystal', [0x02, 0x34, 0x64, 0x40, 0x7F, 0x06], None, None, None, None, None, None), 'Crystal 1': (True, False, 'Crystal', [0x02, 0x34, 0x64, 0x40, 0x7F, 0x06], None, None, None, None, None, None, None),
'Crystal 2': (True, False, 'Crystal', [0x10, 0x34, 0x64, 0x40, 0x79, 0x06], None, None, None, None, None, None), 'Crystal 2': (True, False, 'Crystal', [0x10, 0x34, 0x64, 0x40, 0x79, 0x06], None, None, None, None, None, None, None),
'Crystal 3': (True, False, 'Crystal', [0x40, 0x34, 0x64, 0x40, 0x6C, 0x06], None, None, None, None, None, None), 'Crystal 3': (True, False, 'Crystal', [0x40, 0x34, 0x64, 0x40, 0x6C, 0x06], None, None, None, None, None, None, None),
'Crystal 4': (True, False, 'Crystal', [0x20, 0x34, 0x64, 0x40, 0x6D, 0x06], None, None, None, None, None, None), 'Crystal 4': (True, False, 'Crystal', [0x20, 0x34, 0x64, 0x40, 0x6D, 0x06], None, None, None, None, None, None, None),
'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, 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, 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, None),
'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'), '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', 'an arrow'),
'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', 'ten arrows'),
'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 capacity'),
'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', 'arrow capacity'),
'Single Bomb': (False, False, None, 0x27, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again'), 'Single Bomb': (False, False, None, 0x27, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'),
'Bombs (3)': (False, False, None, 0x28, 'I make things\ngo triple\nBOOM!!!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again'), 'Bombs (3)': (False, False, None, 0x28, 'I make things\ngo triple\nBOOM!!!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'three bombs'),
'Bombs (10)': (False, False, None, 0x31, 'I make things\ngo BOOM! Ten\ntimes!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again'), 'Bombs (10)': (False, False, None, 0x31, 'I make things\ngo BOOM! Ten\ntimes!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'ten bombs'),
'Bomb Upgrade (+10)': (False, False, None, 0x52, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again'), 'Bomb Upgrade (+10)': (False, False, None, 0x52, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'),
'Bomb Upgrade (+5)': (False, False, None, 0x51, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again'), 'Bomb Upgrade (+5)': (False, False, None, 0x51, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'),
'Blue Mail': (False, True, None, 0x22, 'Now you\'re a\nblue elf!', 'and the banana hat', 'the protected kid', 'banana hat for sale', 'the clothing store', 'tailor boy banana hatted again'), 'Blue Mail': (False, True, None, 0x22, 'Now you\'re a\nblue elf!', 'and the banana hat', 'the protected kid', 'banana hat for sale', 'the clothing store', 'tailor boy banana hatted again', 'the blue mail'),
'Red Mail': (False, True, None, 0x23, 'Now you\'re a\nred elf!', 'and the eggplant hat', 'well-protected kid', 'purple hat for sale', 'the nice clothing store', 'tailor boy fears nothing again'), 'Red Mail': (False, True, None, 0x23, 'Now you\'re a\nred elf!', 'and the eggplant hat', 'well-protected kid', 'purple hat for sale', 'the nice clothing store', 'tailor boy fears nothing again', 'the red mail'),
'Progressive Armor': (False, True, None, 0x60, 'time for a\nchange of\nclothes?', 'and the unknown hat', 'the protected kid', 'new hat for sale', 'the clothing store', 'tailor boy has threads again'), 'Progressive Armor': (False, True, None, 0x60, 'time for a\nchange of\nclothes?', 'and the unknown hat', 'the protected kid', 'new hat for sale', 'the clothing store', 'tailor boy has threads again', 'some armor'),
'Blue Boomerang': (False, True, None, 0x0C, 'No matter what\nyou do, blue\nreturns to you', 'and the bluemarang', 'the bat-throwing kid', 'bent stick for sale', 'fungus for puma-stick', 'throwing boy plays fetch again'), 'Blue Boomerang': (True, False, None, 0x0C, 'No matter what\nyou do, blue\nreturns to you', 'and the bluemarang', 'the bat-throwing kid', 'bent stick for sale', 'fungus for puma-stick', 'throwing boy plays fetch again', 'the blue boomerang'),
'Red Boomerang': (False, True, None, 0x2A, 'No matter what\nyou do, red\nreturns to you', 'and the badmarang', 'the bat-throwing kid', 'air foil for sale', 'fungus for return-stick', 'magical boy plays fetch again'), 'Red Boomerang': (True, False, None, 0x2A, 'No matter what\nyou do, red\nreturns to you', 'and the badmarang', 'the bat-throwing kid', 'air foil for sale', 'fungus for return-stick', 'magical boy plays fetch again', 'the red boomerang'),
'Blue Shield': (False, True, None, 0x04, 'Now you can\ndefend against\npebbles!', 'and the stone blocker', 'shield-wielding kid', 'shield for sale', 'fungus for shield', 'shield boy defends again'), 'Blue Shield': (False, True, None, 0x04, 'Now you can\ndefend against\npebbles!', 'and the stone blocker', 'shield-wielding kid', 'shield for sale', 'fungus for shield', 'shield boy defends again', 'the blue shield'),
'Red Shield': (False, True, None, 0x05, 'Now you can\ndefend against\nfireballs!', 'and the shot blocker', 'shield-wielding kid', 'fire shield for sale', 'fungus for fire shield', 'shield boy defends again'), 'Red Shield': (False, True, None, 0x05, 'Now you can\ndefend against\nfireballs!', 'and the shot blocker', 'shield-wielding kid', 'fire shield for sale', 'fungus for fire shield', 'shield boy defends again', 'the red shield'),
'Mirror Shield': (True, False, None, 0x06, 'Now you can\ndefend against\nlasers!', 'and the laser blocker', 'shield-wielding kid', 'face shield for sale', 'fungus for face shield', 'shield boy defends again'), 'Mirror Shield': (True, False, None, 0x06, 'Now you can\ndefend against\nlasers!', 'and the laser blocker', 'shield-wielding kid', 'face shield for sale', 'fungus for face shield', 'shield boy defends again', 'the mirror shield'),
'Progressive Shield': (True, False, None, 0x5F, 'have a better\nblocker in\nfront of you', 'and the new shield', 'shield-wielding kid', 'shield for sale', 'fungus for shield', 'shield boy defends again'), 'Progressive Shield': (True, False, None, 0x5F, 'have a better\nblocker in\nfront of you', 'and the new shield', 'shield-wielding kid', 'shield for sale', 'fungus for shield', 'shield boy defends again', 'a shield'),
'Bug Catching Net': (True, False, None, 0x21, 'Let\'s catch\nsome bees and\nfaeries!', 'and the bee catcher', 'the bug-catching kid', 'stick web for sale', 'fungus for butterflies', 'wrong boy catches bees again'), 'Bug Catching Net': (True, False, None, 0x21, 'Let\'s catch\nsome bees and\nfaeries!', 'and the bee catcher', 'the bug-catching kid', 'stick web for sale', 'fungus for butterflies', 'wrong boy catches bees again', 'the bug net'),
'Cane of Byrna': (True, False, None, 0x18, 'Use this to\nbecome\ninvincible!', 'and the bad cane', 'the spark-making kid', 'spark stick for sale', 'spark-stick for trade', 'cane boy encircles again'), 'Cane of Byrna': (True, False, None, 0x18, 'Use this to\nbecome\ninvincible!', 'and the bad cane', 'the spark-making kid', 'spark stick for sale', 'spark-stick for trade', 'cane boy encircles again', 'the blue cane'),
'Boss Heart Container': (False, False, None, 0x3E, 'Maximum health\nincreased!\nYeah!', 'and the full heart', 'the life-giving kid', 'love for sale', 'fungus for life', 'life boy feels love again'), 'Boss Heart Container': (False, False, None, 0x3E, 'Maximum health\nincreased!\nYeah!', 'and the full heart', 'the life-giving kid', 'love for sale', 'fungus for life', 'life boy feels love again', 'a heart'),
'Sanctuary Heart Container': (False, False, None, 0x3F, 'Maximum health\nincreased!\nYeah!', 'and the full heart', 'the life-giving kid', 'love for sale', 'fungus for life', 'life boy feels love again'), 'Sanctuary Heart Container': (False, False, None, 0x3F, 'Maximum health\nincreased!\nYeah!', 'and the full heart', 'the life-giving kid', 'love for sale', 'fungus for life', 'life boy feels love again', 'a heart'),
'Piece of Heart': (False, False, None, 0x17, 'Just a little\npiece of love!', 'and the broken heart', 'the life-giving kid', 'little love for sale', 'fungus for life', 'life boy feels some love again"'), 'Piece of Heart': (False, False, None, 0x17, 'Just a little\npiece of love!', 'and the broken heart', 'the life-giving kid', 'little love for sale', 'fungus for life', 'life boy feels some love again', 'a heart piece'),
'Rupee (1)': (False, False, None, 0x34, 'Just pocket\nchange. Move\nright along.', 'the pocket change', 'poverty-struck kid', 'life lesson for sale', 'buying cheap drugs', 'destitute boy has snack again'), 'Rupee (1)': (False, False, None, 0x34, 'Just pocket\nchange. Move\nright along.', 'the pocket change', 'poverty-struck kid', 'life lesson for sale', 'buying cheap drugs', 'destitute boy has snack again', 'a green rupee'),
'Rupees (5)': (False, False, None, 0x35, 'Just pocket\nchange. Move\nright along.', 'the pocket change', 'poverty-struck kid', 'life lesson for sale', 'buying cheap drugs', 'destitute boy has snack again'), 'Rupees (5)': (False, False, None, 0x35, 'Just pocket\nchange. Move\nright along.', 'the pocket change', 'poverty-struck kid', 'life lesson for sale', 'buying cheap drugs', 'destitute boy has snack again', 'a blue rupee'),
'Rupees (20)': (False, False, None, 0x36, 'Just couch\ncash. Move\nright along.', 'and the couch cash', 'the piggy-bank kid', 'life lesson for sale', 'the witch buying drugs', 'destitute boy has lunch again'), 'Rupees (20)': (False, False, None, 0x36, 'Just couch\ncash. Move\nright along.', 'and the couch cash', 'the piggy-bank kid', 'life lesson for sale', 'the witch buying drugs', 'destitute boy has lunch again', 'a red rupee'),
'Rupees (50)': (False, False, None, 0x41, 'A rupee pile!\nOkay?', 'and the rupee pile', 'the well-off kid', 'life lesson for sale', 'buying okay drugs', 'destitute boy has dinner again'), 'Rupees (50)': (False, False, None, 0x41, 'A rupee pile!\nOkay?', 'and the rupee pile', 'the well-off kid', 'life lesson for sale', 'buying okay drugs', 'destitute boy has dinner again', 'fifty rupees'),
'Rupees (100)': (False, False, None, 0x40, 'A rupee stash!\nHell yeah!', 'and the rupee stash', 'the kind-of-rich kid', 'life lesson for sale', 'buying good drugs', 'affluent boy goes drinking again'), 'Rupees (100)': (False, False, None, 0x40, 'A rupee stash!\nHell yeah!', 'and the rupee stash', 'the kind-of-rich kid', 'life lesson for sale', 'buying good drugs', 'affluent boy goes drinking again', 'one hundred rupees'),
'Rupees (300)': (False, False, None, 0x46, 'A rupee hoard!\nHell yeah!', 'and the rupee hoard', 'the really-rich kid', 'life lesson for sale', 'buying the best drugs', 'fat-cat boy is rich again'), 'Rupees (300)': (False, False, None, 0x46, 'A rupee hoard!\nHell yeah!', 'and the rupee hoard', 'the really-rich kid', 'life lesson for sale', 'buying the best drugs', 'fat-cat boy is rich again', 'three hundred rupees'),
'Rupoor': (False, False, None, 0x59, 'a debt collector', 'and the toll-booth', 'the toll-booth kid', 'double loss for sale', 'witch stole your rupees', 'affluent boy steals rupees'), 'Rupoor': (False, False, None, 0x59, 'a debt collector', 'and the toll-booth', 'the toll-booth kid', 'double loss for sale', 'witch stole your rupees', 'affluent boy steals rupees', 'a rupoor'),
'Red Clock': (False, True, None, 0x5B, 'a waste of time', 'the ruby clock', 'the ruby-time kid', 'red time for sale', 'for ruby time', 'moment boy travels time again'), 'Red Clock': (False, True, None, 0x5B, 'a waste of time', 'the ruby clock', 'the ruby-time kid', 'red time for sale', 'for ruby time', 'moment boy travels time again', 'a red clock'),
'Blue Clock': (False, True, None, 0x5C, 'a bit of time', 'the sapphire clock', 'sapphire-time kid', 'blue time for sale', 'for sapphire time', 'moment boy time travels again'), 'Blue Clock': (False, True, None, 0x5C, 'a bit of time', 'the sapphire clock', 'sapphire-time kid', 'blue time for sale', 'for sapphire time', 'moment boy time travels again', 'a blue clock'),
'Green Clock': (False, True, None, 0x5D, 'a lot of time', 'the emerald clock', 'the emerald-time kid', 'green time for sale', 'for emerald time', 'moment boy adjusts time again'), 'Green Clock': (False, True, None, 0x5D, 'a lot of time', 'the emerald clock', 'the emerald-time kid', 'green time for sale', 'for emerald time', 'moment boy adjusts time again', 'a red clock'),
'Single RNG': (False, True, None, 0x62, 'something you don\'t yet have', None, None, None, None, 'unknown boy somethings again'), 'Single RNG': (False, True, None, 0x62, 'something you don\'t yet have', None, None, None, None, 'unknown boy somethings again', 'a new mystery'),
'Multi RNG': (False, True, None, 0x63, 'something you may already have', None, None, None, None, 'unknown boy somethings again'), 'Multi RNG': (False, True, None, 0x63, 'something you may already have', None, None, None, None, 'unknown boy somethings again', 'a total mystery'),
'Magic Upgrade (1/2)': (True, False, None, 0x4E, 'Your magic\npower has been\ndoubled!', 'and the spell power', 'the magic-saving kid', 'wizardry for sale', 'mekalekahi mekahiney ho', 'magic boy saves magic again'), # can be required to beat mothula in an open seed in very very rare circumstance 'Magic Upgrade (1/2)': (True, False, None, 0x4E, 'Your magic\npower has been\ndoubled!', 'and the spell power', 'the magic-saving kid', 'wizardry for sale', 'mekalekahi mekahiney ho', 'magic boy saves magic again', 'half magic'), # can be required to beat mothula in an open seed in very very rare circumstance
'Magic Upgrade (1/4)': (True, False, None, 0x4F, 'Your magic\npower has been\nquadrupled!', 'and the spell power', 'the magic-saving kid', 'wizardry for sale', 'mekalekahi mekahiney ho', 'magic boy saves magic again'), # can be required to beat mothula in an open seed in very very rare circumstance 'Magic Upgrade (1/4)': (True, False, None, 0x4F, 'Your magic\npower has been\nquadrupled!', 'and the spell power', 'the magic-saving kid', 'wizardry for sale', 'mekalekahi mekahiney ho', 'magic boy saves magic again', 'quarter magic'), # can be required to beat mothula in an open seed in very very rare circumstance
'Small Key (Eastern Palace)': (False, False, 'SmallKey', 0xA2, 'A small key to Armos Knights', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Eastern Palace)': (False, False, 'SmallKey', 0xA2, 'A small key to Armos Knights', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Eastern Palace'),
'Big Key (Eastern Palace)': (False, False, 'BigKey', 0x9D, 'A big key to Armos Knights', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Eastern Palace)': (False, False, 'BigKey', 0x9D, 'A big key to Armos Knights', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Eastern Palace'),
'Compass (Eastern Palace)': (False, True, 'Compass', 0x8D, 'Now you can find the Armos Knights!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Eastern Palace)': (False, True, 'Compass', 0x8D, 'Now you can find the Armos Knights!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Eastern Palace'),
'Map (Eastern Palace)': (False, True, 'Map', 0x7D, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Eastern Palace)': (False, True, 'Map', 0x7D, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Eastern Palace'),
'Small Key (Desert Palace)': (False, False, 'SmallKey', 0xA3, 'A small key to the desert', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Desert Palace)': (False, False, 'SmallKey', 0xA3, 'A small key to the desert', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Desert Palace'),
'Big Key (Desert Palace)': (False, False, 'BigKey', 0x9C, 'A big key to the desert', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Desert Palace)': (False, False, 'BigKey', 0x9C, 'A big key to the desert', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Desert Palace'),
'Compass (Desert Palace)': (False, True, 'Compass', 0x8C, 'Now you can find Lanmolas!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Desert Palace)': (False, True, 'Compass', 0x8C, 'Now you can find Lanmolas!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Desert Palace'),
'Map (Desert Palace)': (False, True, 'Map', 0x7C, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Desert Palace)': (False, True, 'Map', 0x7C, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Desert Palace'),
'Small Key (Tower of Hera)': (False, False, 'SmallKey', 0xAA, 'A small key to Hera', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Tower of Hera)': (False, False, 'SmallKey', 0xAA, 'A small key to Hera', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Tower of Hera'),
'Big Key (Tower of Hera)': (False, False, 'BigKey', 0x95, 'A big key to Hera', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Tower of Hera)': (False, False, 'BigKey', 0x95, 'A big key to Hera', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Tower of Hera'),
'Compass (Tower of Hera)': (False, True, 'Compass', 0x85, 'Now you can find Moldorm!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Tower of Hera)': (False, True, 'Compass', 0x85, 'Now you can find Moldorm!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Tower of Hera'),
'Map (Tower of Hera)': (False, True, 'Map', 0x75, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Tower of Hera)': (False, True, 'Map', 0x75, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Tower of Hera'),
'Small Key (Escape)': (False, False, 'SmallKey', 0xA0, 'A small key to the castle', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Escape)': (False, False, 'SmallKey', 0xA0, 'A small key to the castle', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Hyrule Castle'),
'Big Key (Escape)': (False, False, 'BigKey', 0x9F, 'A big key to the castle', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Escape)': (False, False, 'BigKey', 0x9F, 'A big key to the castle', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Hyrule Castle'),
'Compass (Escape)': (False, True, 'Compass', 0x8F, 'Now you can find no boss!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Escape)': (False, True, 'Compass', 0x8F, 'Now you can find no boss!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Hyrule Castle'),
'Map (Escape)': (False, True, 'Map', 0x7F, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Escape)': (False, True, 'Map', 0x7F, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Hyrule Castle'),
'Small Key (Agahnims Tower)': (False, False, 'SmallKey', 0xA4, 'A small key to Agahnim', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Agahnims Tower)': (False, False, 'SmallKey', 0xA4, 'A small key to Agahnim', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Castle Tower'),
'Small Key (Palace of Darkness)': (False, False, 'SmallKey', 0xA6, 'A small key to darkness', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Palace of Darkness)': (False, False, 'SmallKey', 0xA6, 'A small key to darkness', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Palace of Darkness'),
'Big Key (Palace of Darkness)': (False, False, 'BigKey', 0x99, 'A big key to darkness', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Palace of Darkness)': (False, False, 'BigKey', 0x99, 'A big key to darkness', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Palace of Darkness'),
'Compass (Palace of Darkness)': (False, True, 'Compass', 0x89, 'Now you can find Helmasaur King!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Palace of Darkness)': (False, True, 'Compass', 0x89, 'Now you can find Helmasaur King!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Palace of Darkness'),
'Map (Palace of Darkness)': (False, True, 'Map', 0x79, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Palace of Darkness)': (False, True, 'Map', 0x79, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Palace of Darkness'),
'Small Key (Thieves Town)': (False, False, 'SmallKey', 0xAB, 'A small key to thievery', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Thieves Town)': (False, False, 'SmallKey', 0xAB, 'A small key to thievery', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Thieves\' Town'),
'Big Key (Thieves Town)': (False, False, 'BigKey', 0x94, 'A big key to thievery', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Thieves Town)': (False, False, 'BigKey', 0x94, 'A big key to thievery', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Thieves\' Town'),
'Compass (Thieves Town)': (False, True, 'Compass', 0x84, 'Now you can find Blind!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Thieves Town)': (False, True, 'Compass', 0x84, 'Now you can find Blind!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Thieves\' Town'),
'Map (Thieves Town)': (False, True, 'Map', 0x74, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Thieves Town)': (False, True, 'Map', 0x74, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Thieves\' Town'),
'Small Key (Skull Woods)': (False, False, 'SmallKey', 0xA8, 'A small key to the woods', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Skull Woods)': (False, False, 'SmallKey', 0xA8, 'A small key to the woods', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Skull Woods'),
'Big Key (Skull Woods)': (False, False, 'BigKey', 0x97, 'A big key to the woods', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Skull Woods)': (False, False, 'BigKey', 0x97, 'A big key to the woods', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Skull Woods'),
'Compass (Skull Woods)': (False, True, 'Compass', 0x87, 'Now you can find Mothula!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Skull Woods)': (False, True, 'Compass', 0x87, 'Now you can find Mothula!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Skull Woods'),
'Map (Skull Woods)': (False, True, 'Map', 0x77, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Skull Woods)': (False, True, 'Map', 0x77, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Skull Woods'),
'Small Key (Swamp Palace)': (False, False, 'SmallKey', 0xA5, 'A small key to the swamp', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Swamp Palace)': (False, False, 'SmallKey', 0xA5, 'A small key to the swamp', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Swamp Palace'),
'Big Key (Swamp Palace)': (False, False, 'BigKey', 0x9A, 'A big key to the swamp', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Swamp Palace)': (False, False, 'BigKey', 0x9A, 'A big key to the swamp', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Swamp Palace'),
'Compass (Swamp Palace)': (False, True, 'Compass', 0x8A, 'Now you can find Arrghus!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Swamp Palace)': (False, True, 'Compass', 0x8A, 'Now you can find Arrghus!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Swamp Palace'),
'Map (Swamp Palace)': (False, True, 'Map', 0x7A, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Swamp Palace)': (False, True, 'Map', 0x7A, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Swamp Palace'),
'Small Key (Ice Palace)': (False, False, 'SmallKey', 0xA9, 'A small key to the iceberg', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Ice Palace)': (False, False, 'SmallKey', 0xA9, 'A small key to the iceberg', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Ice Palace'),
'Big Key (Ice Palace)': (False, False, 'BigKey', 0x96, 'A big key to the iceberg', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Ice Palace)': (False, False, 'BigKey', 0x96, 'A big key to the iceberg', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Ice Palace'),
'Compass (Ice Palace)': (False, True, 'Compass', 0x86, 'Now you can find Kholdstare!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Ice Palace)': (False, True, 'Compass', 0x86, 'Now you can find Kholdstare!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Ice Palace'),
'Map (Ice Palace)': (False, True, 'Map', 0x76, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Ice Palace)': (False, True, 'Map', 0x76, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Ice Palace'),
'Small Key (Misery Mire)': (False, False, 'SmallKey', 0xA7, 'A small key to the mire', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Misery Mire)': (False, False, 'SmallKey', 0xA7, 'A small key to the mire', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Misery Mire'),
'Big Key (Misery Mire)': (False, False, 'BigKey', 0x98, 'A big key to the mire', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Misery Mire)': (False, False, 'BigKey', 0x98, 'A big key to the mire', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Misery Mire'),
'Compass (Misery Mire)': (False, True, 'Compass', 0x88, 'Now you can find Vitreous!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Misery Mire)': (False, True, 'Compass', 0x88, 'Now you can find Vitreous!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Misery Mire'),
'Map (Misery Mire)': (False, True, 'Map', 0x78, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Misery Mire)': (False, True, 'Map', 0x78, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Misery Mire'),
'Small Key (Turtle Rock)': (False, False, 'SmallKey', 0xAC, 'A small key to the pipe maze', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Turtle Rock)': (False, False, 'SmallKey', 0xAC, 'A small key to the pipe maze', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Turtle Rock'),
'Big Key (Turtle Rock)': (False, False, 'BigKey', 0x93, 'A big key to the pipe maze', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Turtle Rock)': (False, False, 'BigKey', 0x93, 'A big key to the pipe maze', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Turtle Rock'),
'Compass (Turtle Rock)': (False, True, 'Compass', 0x83, 'Now you can find Trinexx!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Turtle Rock)': (False, True, 'Compass', 0x83, 'Now you can find Trinexx!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Turtle Rock'),
'Map (Turtle Rock)': (False, True, 'Map', 0x73, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Turtle Rock)': (False, True, 'Map', 0x73, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Turtle Rock'),
'Small Key (Ganons Tower)': (False, False, 'SmallKey', 0xAD, 'A small key to the evil tower', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Ganons Tower)': (False, False, 'SmallKey', 0xAD, 'A small key to the evil tower', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Ganon\'s Tower'),
'Big Key (Ganons Tower)': (False, False, 'BigKey', 0x92, 'A big key to the evil tower', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again'), 'Big Key (Ganons Tower)': (False, False, 'BigKey', 0x92, 'A big key to the evil tower', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Ganon\'s Tower'),
'Compass (Ganons Tower)': (False, True, 'Compass', 0x82, 'Now you can find Agahnim!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again'), 'Compass (Ganons Tower)': (False, True, 'Compass', 0x82, 'Now you can find Agahnim!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a comapss to Ganon\'s Tower'),
'Map (Ganons Tower)': (False, True, 'Map', 0x72, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again'), 'Map (Ganons Tower)': (False, True, 'Map', 0x72, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Ganon\'s Tower'),
'Small Key (Universal)': (False, True, None, 0xAF, 'A small key for any door', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again'), 'Small Key (Universal)': (False, True, None, 0xAF, 'A small key for any door', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key'),
'Nothing': (False, False, None, 0x5A, 'Some Hot Air', 'and the Nothing', 'the zen kid', 'outright theft', 'shroom theft', 'empty boy is bored again'), 'Nothing': (False, False, None, 0x5A, 'Some Hot Air', 'and the Nothing', 'the zen kid', 'outright theft', 'shroom theft', 'empty boy is bored again', 'nothing'),
'Red Potion': (False, False, None, 0x2E, None, None, None, None, None, None), 'Red Potion': (False, False, None, 0x2E, None, None, None, None, None, None, None),
'Green Potion': (False, False, None, 0x2F, None, None, None, None, None, None), 'Green Potion': (False, False, None, 0x2F, None, None, None, None, None, None, None),
'Blue Potion': (False, False, None, 0x30, None, None, None, None, None, None), 'Blue Potion': (False, False, None, 0x30, None, None, None, None, None, None, None),
'Bee': (False, False, None, 0x0E, None, None, None, None, None, None), 'Bee': (False, False, None, 0x0E, None, None, None, None, None, None, None),
'Small Heart': (False, False, None, 0x42, None, None, None, None, None, None), 'Small Heart': (False, False, None, 0x42, None, None, None, None, None, None, None),
'Beat Agahnim 1': (True, False, 'Event', None, None, None, None, None, None, None), 'Beat Agahnim 1': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Beat Agahnim 2': (True, False, 'Event', None, None, None, None, None, None, None), 'Beat Agahnim 2': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Get Frog': (True, False, 'Event', None, None, None, None, None, None, None), 'Get Frog': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Return Smith': (True, False, 'Event', None, None, None, None, None, None, None), 'Return Smith': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Pick Up Purple Chest': (True, False, 'Event', None, None, None, None, None, None, None), 'Pick Up Purple Chest': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Open Floodgate': (True, False, 'Event', None, None, None, None, None, None, None), 'Open Floodgate': (True, False, 'Event', None, None, None, None, None, None, None, None),
} }

65
Main.py
View File

@ -6,41 +6,41 @@ import logging
import random import random
import time import time
from BaseClasses import World, CollectionState, Item, Region, Location, Entrance, Shop from BaseClasses import World, CollectionState, Item, Region, Location, Shop
from Regions import create_regions, mark_light_world_regions from Regions import create_regions, mark_light_world_regions
from EntranceShuffle import link_entrances from EntranceShuffle import link_entrances
from Rom import patch_rom, Sprite, LocalRom, JsonRom from Rom import patch_rom, Sprite, LocalRom, JsonRom
from Rules import set_rules from Rules import set_rules
from Dungeons import create_dungeons, fill_dungeons, fill_dungeons_restrictive from Dungeons import create_dungeons, fill_dungeons, fill_dungeons_restrictive
from Fill import distribute_items_cutoff, distribute_items_staleness, distribute_items_restrictive, flood_items from Fill import distribute_items_cutoff, distribute_items_staleness, distribute_items_restrictive, flood_items
from ItemList import generate_itempool, difficulties from ItemList import generate_itempool, difficulties, fill_prizes
from Utils import output_path from Utils import output_path
__version__ = '0.6.1' __version__ = '0.6.2'
logic_hash = [215, 244, 99, 97, 253, 98, 31, 150, 207, 70, 50, 78, 59, 73, 221, 191, logic_hash = [134, 166, 181, 191, 228, 89, 188, 200, 5, 157, 217, 139, 180, 198, 106, 104,
21, 34, 200, 116, 77, 234, 89, 27, 228, 96, 16, 249, 56, 148, 3, 176, 88, 223, 138, 28, 54, 18, 216, 129, 248, 19, 109, 220, 159, 75, 238, 57,
17, 227, 24, 20, 238, 67, 37, 219, 62, 223, 60, 123, 246, 92, 164, 177, 231, 183, 143, 167, 114, 176, 82, 169, 179, 94, 115, 193, 252, 222, 52, 245,
211, 15, 245, 23, 75, 33, 190, 124, 144, 100, 87, 57, 86, 108, 80, 181, 33, 208, 39, 122, 177, 136, 29, 161, 210, 165, 6, 125, 146, 212, 101, 185,
6, 28, 2, 71, 182, 155, 222, 229, 90, 91, 32, 126, 25, 226, 133, 41, 65, 247, 253, 85, 171, 147, 71, 148, 203, 202, 230, 1, 13, 64, 254, 141,
132, 122, 10, 30, 53, 239, 112, 49, 104, 76, 209, 247, 139, 13, 173, 113, 32, 93, 152, 4, 92, 16, 195, 204, 246, 201, 11, 7, 189, 97, 9, 91,
159, 69, 145, 161, 11, 102, 149, 143, 129, 178, 45, 217, 196, 232, 208, 119, 237, 215, 163, 131, 142, 34, 111, 196, 120, 127, 168, 211, 227, 61, 187, 110,
94, 19, 35, 65, 170, 103, 55, 109, 5, 43, 118, 194, 180, 12, 206, 241, 190, 162, 59, 80, 225, 186, 37, 154, 76, 72, 27, 17, 79, 206, 207, 243,
8, 105, 210, 231, 179, 83, 137, 18, 212, 236, 225, 66, 63, 142, 138, 131, 184, 197, 153, 48, 119, 99, 2, 151, 51, 67, 121, 175, 38, 224, 87, 242,
192, 160, 1, 198, 153, 128, 106, 165, 39, 248, 167, 22, 74, 163, 140, 157, 45, 22, 155, 244, 209, 117, 214, 213, 194, 126, 236, 73, 133, 70, 49, 140,
214, 84, 154, 127, 195, 172, 136, 168, 68, 134, 152, 95, 111, 235, 26, 42, 229, 108, 156, 124, 105, 226, 44, 23, 112, 102, 173, 219, 14, 116, 58, 103,
135, 186, 250, 7, 72, 58, 4, 9, 193, 101, 52, 44, 187, 183, 171, 184, 55, 10, 95, 251, 84, 118, 160, 78, 63, 250, 31, 41, 35, 255, 170, 25,
197, 130, 47, 189, 81, 203, 51, 110, 146, 175, 213, 88, 79, 93, 64, 107, 66, 172, 98, 249, 68, 8, 113, 21, 46, 24, 137, 149, 81, 130, 42, 164,
121, 237, 0, 46, 120, 141, 199, 158, 174, 114, 205, 201, 151, 185, 242, 29, 50, 12, 158, 15, 47, 182, 30, 40, 36, 83, 77, 205, 20, 241, 3, 132,
162, 117, 85, 54, 14, 202, 216, 169, 230, 252, 188, 251, 36, 233, 147, 82, 0, 60, 96, 62, 74, 178, 53, 56, 135, 174, 145, 86, 107, 233, 218, 221,
115, 61, 255, 38, 220, 218, 40, 224, 48, 125, 204, 156, 240, 254, 166, 243] 43, 150, 100, 69, 235, 26, 234, 192, 199, 144, 232, 128, 239, 123, 240, 90]
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, args.retro, args.custom, args.customitemarray) 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.retro, args.custom, args.customitemarray, args.shufflebosses, args.hints)
logger = logging.getLogger('') logger = logging.getLogger('')
if seed is None: if seed is None:
random.seed(None) random.seed(None)
@ -62,13 +62,17 @@ def main(args, seed=None):
link_entrances(world) link_entrances(world)
mark_light_world_regions(world) mark_light_world_regions(world)
logger.info('Generating Item Pool.')
generate_itempool(world)
logger.info('Calculating Access Rules.') logger.info('Calculating Access Rules.')
set_rules(world) set_rules(world)
logger.info('Generating Item Pool.') logger.info('Placing Dungeon Prizes.')
generate_itempool(world) fill_prizes(world)
logger.info('Placing Dungeon Items.') logger.info('Placing Dungeon Items.')
@ -112,7 +116,7 @@ def main(args, seed=None):
else: else:
sprite = None sprite = None
outfilebase = 'ER_%s_%s-%s-%s%s_%s-%s%s%s%s_%s' % (world.logic, world.difficulty, world.mode, world.goal, "" if world.timer in ['none', 'display'] else "-" + world.timer, world.shuffle, world.algorithm, "-keysanity" if world.keysanity else "", "-retro" if world.retro else "", "-prog_" + world.progressive if world.progressive in ['off', 'random'] else "", world.seed) outfilebase = 'ER_%s_%s-%s-%s%s_%s-%s%s%s%s%s_%s' % (world.logic, world.difficulty, world.mode, world.goal, "" if world.timer in ['none', 'display'] else "-" + world.timer, world.shuffle, world.algorithm, "-keysanity" if world.keysanity else "", "-retro" if world.retro else "", "-prog_" + world.progressive if world.progressive in ['off', 'random'] else "", "-nohints" if not world.hints else "", world.seed)
if not args.suppress_rom: if not args.suppress_rom:
if args.jsonout: if args.jsonout:
@ -140,7 +144,7 @@ def gt_filler(world):
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, world.retro, world.custom, world.customitemarray) 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.retro, world.custom, world.customitemarray, world.boss_shuffle, world.hints)
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
@ -151,6 +155,9 @@ def copy_world(world):
ret.dark_world_light_cone = world.dark_world_light_cone ret.dark_world_light_cone = world.dark_world_light_cone
ret.seed = world.seed ret.seed = world.seed
ret.can_access_trock_eyebridge = world.can_access_trock_eyebridge ret.can_access_trock_eyebridge = world.can_access_trock_eyebridge
ret.can_access_trock_front = world.can_access_trock_front
ret.can_access_trock_big_chest = world.can_access_trock_big_chest
ret.can_access_trock_middle = world.can_access_trock_middle
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.fix_fake_world = world.fix_fake_world
@ -160,6 +167,11 @@ def copy_world(world):
copy_dynamic_regions_and_locations(world, ret) copy_dynamic_regions_and_locations(world, ret)
# copy bosses
for dungeon in world.dungeons:
for level, boss in dungeon.bosses.items():
ret.get_dungeon(dungeon.name).bosses[level] = boss
for shop in world.shops: for shop in world.shops:
copied_shop = ret.get_region(shop.region.name).shop copied_shop = ret.get_region(shop.region.name).shop
copied_shop.active = shop.active copied_shop.active = shop.active
@ -195,7 +207,7 @@ def copy_world(world):
def copy_dynamic_regions_and_locations(world, ret): def copy_dynamic_regions_and_locations(world, ret):
for region in world.dynamic_regions: for region in world.dynamic_regions:
new_reg = Region(region.name, region.type) new_reg = Region(region.name, region.type, region.hint_text)
ret.regions.append(new_reg) ret.regions.append(new_reg)
ret.dynamic_regions.append(new_reg) ret.dynamic_regions.append(new_reg)
@ -266,7 +278,8 @@ def create_playthrough(world):
old_item = location.item old_item = location.item
location.item = None location.item = None
state.remove(old_item) state.remove(old_item)
if world.can_beat_game(state_cache[num]): ##if world.can_beat_game(state_cache[num]):
if world.can_beat_game():
to_delete.append(location) to_delete.append(location)
else: else:
# still required, got to keep it around # still required, got to keep it around

View File

@ -71,14 +71,14 @@ Desert Palace - Torch: Small Key (Desert Palace)
Desert Palace - Map Chest: Nothing Desert Palace - Map Chest: Nothing
Desert Palace - Compass Chest: Nothing Desert Palace - Compass Chest: Nothing
Desert Palace - Big Key Chest: Big Key (Desert Palace) Desert Palace - Big Key Chest: Big Key (Desert Palace)
Desert Palace - Lanmolas: Nothing Desert Palace - Boss: Nothing
Desert Palace - Prize: Blue Pendant Desert Palace - Prize: Blue Pendant
Eastern Palace - Compass Chest: Nothing Eastern Palace - Compass Chest: Nothing
Eastern Palace - Big Chest: Bow Eastern Palace - Big Chest: Bow
Eastern Palace - Cannonball Chest: Nothing Eastern Palace - Cannonball Chest: Nothing
Eastern Palace - Big Key Chest: Big Key (Eastern Palace) Eastern Palace - Big Key Chest: Big Key (Eastern Palace)
Eastern Palace - Map Chest: Nothing Eastern Palace - Map Chest: Nothing
Eastern Palace - Armos Knights: Nothing Eastern Palace - Boss: Nothing
Eastern Palace - Prize: Green Pendant Eastern Palace - Prize: Green Pendant
Master Sword Pedestal: Master Sword Master Sword Pedestal: Master Sword
Hyrule Castle - Boomerang Chest: Nothing Hyrule Castle - Boomerang Chest: Nothing
@ -108,7 +108,7 @@ Tower of Hera - Map Chest: Nothing
Tower of Hera - Big Key Chest: Big Key (Tower of Hera) Tower of Hera - Big Key Chest: Big Key (Tower of Hera)
Tower of Hera - Compass Chest: Nothing Tower of Hera - Compass Chest: Nothing
Tower of Hera - Big Chest: Moon Pearl Tower of Hera - Big Chest: Moon Pearl
Tower of Hera - Moldorm: Nothing Tower of Hera - Boss: Nothing
Tower of Hera - Prize: Red Pendant Tower of Hera - Prize: Red Pendant
Pyramid: Nothing Pyramid: Nothing
Catfish: Quake Catfish: Quake
@ -147,7 +147,7 @@ Swamp Palace - West Chest: Nothing
Swamp Palace - Flooded Room - Left: Nothing Swamp Palace - Flooded Room - Left: Nothing
Swamp Palace - Flooded Room - Right: Nothing Swamp Palace - Flooded Room - Right: Nothing
Swamp Palace - Waterfall Room: Nothing Swamp Palace - Waterfall Room: Nothing
Swamp Palace - Arrghus: Nothing Swamp Palace - Boss: Nothing
Swamp Palace - Prize: Crystal 2 Swamp Palace - Prize: Crystal 2
Thieves' Town - Big Key Chest: Big Key (Thieves Town) Thieves' Town - Big Key Chest: Big Key (Thieves Town)
Thieves' Town - Map Chest: Nothing Thieves' Town - Map Chest: Nothing
@ -156,8 +156,8 @@ Thieves' Town - Ambush Chest: Nothing
Thieves' Town - Attic: Nothing Thieves' Town - Attic: Nothing
Thieves' Town - Big Chest: Titans Mitts Thieves' Town - Big Chest: Titans Mitts
Thieves' Town - Blind's Cell: Small Key (Thieves Town) Thieves' Town - Blind's Cell: Small Key (Thieves Town)
Thieves Town - Blind: Nothing Thieves' Town - Boss: Nothing
Thieves Town - Prize: Crystal 4 Thieves' Town - Prize: Crystal 4
Skull Woods - Compass Chest: Nothing Skull Woods - Compass Chest: Nothing
Skull Woods - Map Chest: Nothing Skull Woods - Map Chest: Nothing
Skull Woods - Big Chest: Fire Rod Skull Woods - Big Chest: Fire Rod
@ -165,7 +165,7 @@ Skull Woods - Pot Prison: Small Key (Skull Woods)
Skull Woods - Pinball Room: Small Key (Skull Woods) Skull Woods - Pinball Room: Small Key (Skull Woods)
Skull Woods - Big Key Chest: Big Key (Skull Woods) Skull Woods - Big Key Chest: Big Key (Skull Woods)
Skull Woods - Bridge Room: Small Key (Skull Woods) Skull Woods - Bridge Room: Small Key (Skull Woods)
Skull Woods - Mothula: Nothing Skull Woods - Boss: Nothing
Skull Woods - Prize: Crystal 3 Skull Woods - Prize: Crystal 3
Ice Palace - Compass Chest: Nothing Ice Palace - Compass Chest: Nothing
Ice Palace - Freezor Chest: Nothing Ice Palace - Freezor Chest: Nothing
@ -174,7 +174,7 @@ Ice Palace - Iced T Room: Small Key (Ice Palace)
Ice Palace - Spike Room: Small Key (Ice Palace) Ice Palace - Spike Room: Small Key (Ice Palace)
Ice Palace - Big Key Chest: Big Key (Ice Palace) Ice Palace - Big Key Chest: Big Key (Ice Palace)
Ice Palace - Map Chest: Nothing Ice Palace - Map Chest: Nothing
Ice Palace - Kholdstare: Nothing Ice Palace - Boss: Nothing
Ice Palace - Prize: Crystal 5 Ice Palace - Prize: Crystal 5
Misery Mire - Big Chest: Cane of Somaria Misery Mire - Big Chest: Cane of Somaria
Misery Mire - Map Chest: Nothing Misery Mire - Map Chest: Nothing
@ -183,7 +183,7 @@ Misery Mire - Bridge Chest: Small Key (Misery Mire)
Misery Mire - Spike Chest: Small Key (Misery Mire) Misery Mire - Spike Chest: Small Key (Misery Mire)
Misery Mire - Compass Chest: Nothing Misery Mire - Compass Chest: Nothing
Misery Mire - Big Key Chest: Big Key (Misery Mire) Misery Mire - Big Key Chest: Big Key (Misery Mire)
Misery Mire - Vitreous: Nothing Misery Mire - Boss: Nothing
Misery Mire - Prize: Crystal 6 Misery Mire - Prize: Crystal 6
Turtle Rock - Compass Chest: Nothing Turtle Rock - Compass Chest: Nothing
Turtle Rock - Roller Room - Left: Nothing Turtle Rock - Roller Room - Left: Nothing
@ -196,7 +196,7 @@ Turtle Rock - Eye Bridge - Bottom Left: Small Key (Turtle Rock)
Turtle Rock - Eye Bridge - Bottom Right: Nothing Turtle Rock - Eye Bridge - Bottom Right: Nothing
Turtle Rock - Eye Bridge - Top Left: Nothing Turtle Rock - Eye Bridge - Top Left: Nothing
Turtle Rock - Eye Bridge - Top Right: Nothing Turtle Rock - Eye Bridge - Top Right: Nothing
Turtle Rock - Trinexx: Nothing Turtle Rock - Boss: Nothing
Turtle Rock - Prize: Crystal 7 Turtle Rock - Prize: Crystal 7
Palace of Darkness - Shooter Room: Small Key (Palace of Darkness) Palace of Darkness - Shooter Room: Small Key (Palace of Darkness)
Palace of Darkness - The Arena - Bridge: Small Key (Palace of Darkness) Palace of Darkness - The Arena - Bridge: Small Key (Palace of Darkness)
@ -212,7 +212,7 @@ Palace of Darkness - Dark Maze - Top: Nothing
Palace of Darkness - Dark Maze - Bottom: Nothing Palace of Darkness - Dark Maze - Bottom: Nothing
Palace of Darkness - Big Chest: Hammer Palace of Darkness - Big Chest: Hammer
Palace of Darkness - Harmless Hellway: Nothing Palace of Darkness - Harmless Hellway: Nothing
Palace of Darkness - Helmasaur: Nothing Palace of Darkness - Boss: Nothing
Palace of Darkness - Prize: Crystal 1 Palace of Darkness - Prize: Crystal 1
Ganons Tower - Bob's Torch: Small Key (Ganons Tower) Ganons Tower - Bob's Torch: Small Key (Ganons Tower)
Ganons Tower - Hope Room - Left: Nothing Ganons Tower - Hope Room - Left: Nothing

View File

@ -1,7 +1,7 @@
# ALttPEntranceRandomizer # ALttPEntranceRandomizer
This is a entrance randomizer for _The Legend of Zelda: A Link to the Past_ for the SNES. This is a entrance randomizer for _The Legend of Zelda: A Link to the Past_ for the SNES.
See http://vt.alttp.run for more details on the normal randomizer. See https://alttpr.com/ for more details on the normal randomizer.
# Installation # Installation
@ -297,6 +297,11 @@ If set, will only ensure the goal can be achieved, but not necessarily that all
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. 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. This setting removes any bias against Ganon's Tower that some algorithms may have.
## Include Helpful Hints
If set, the 15 telepathic tiles and 5 storytellers scattered about Hyrule will give helpful hints about various items and entrances. An exact breakdown of the hint
distribution is provided as an included text file.
## Use Custom Item Pool ## 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 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
@ -441,7 +446,7 @@ This may lead to different amount of itempool items being placed in a dungeon th
Select frequency of beeps when on low health. (default: normal) Select frequency of beeps when on low health. (default: normal)
``` ```
--heartcolor [{red,blue,green,yellow}] --heartcolor [{red,blue,green,yellow,random}]
``` ```
Select the color of Link\'s heart meter. (default: red) Select the color of Link\'s heart meter. (default: red)
@ -458,6 +463,12 @@ 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)
```
--hints
```
Enables helpful hints from storytellers and telepathic tiles (default: False)
``` ```
--no-shuffleganon --no-shuffleganon
``` ```

View File

@ -17,277 +17,279 @@ def create_regions(world):
'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']), '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_lw_region('Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop']), create_lw_region('Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop']),
create_lw_region('Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Teleporter']), create_lw_region('Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Teleporter']),
create_cave_region('Blinds Hideout', ["Blind\'s Hideout - Top", create_cave_region('Blinds Hideout', 'a bounty of five items', ["Blind\'s Hideout - Top",
"Blind\'s Hideout - Left", "Blind\'s Hideout - Left",
"Blind\'s Hideout - Right", "Blind\'s Hideout - Right",
"Blind\'s Hideout - Far Left", "Blind\'s Hideout - Far Left",
"Blind\'s Hideout - Far Right"]), "Blind\'s Hideout - Far Right"]),
create_cave_region('Hyrule Castle Secret Entrance', ['Link\'s Uncle', 'Secret Passage'], ['Hyrule Castle Secret Entrance Exit']), create_cave_region('Hyrule Castle Secret Entrance', 'a drop\'s exit', ['Link\'s Uncle', 'Secret Passage'], ['Hyrule Castle Secret Entrance Exit']),
create_lw_region('Zoras River', ['King Zora', 'Zora\'s Ledge']), create_lw_region('Zoras River', ['King Zora', 'Zora\'s Ledge']),
create_cave_region('Waterfall of Wishing', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']), create_cave_region('Waterfall of Wishing', 'a cave with two chests', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']),
create_lw_region('Kings Grave Area', None, ['Kings Grave', 'Kings Grave Inner Rocks']), create_lw_region('Kings Grave Area', None, ['Kings Grave', 'Kings Grave Inner Rocks']),
create_cave_region('Kings Grave', ['King\'s Tomb']), create_cave_region('Kings Grave', 'a cave with a chest', ['King\'s Tomb']),
create_cave_region('North Fairy Cave', None, ['North Fairy Cave Exit']), create_cave_region('North Fairy Cave', 'a drop\'s exit', None, ['North Fairy Cave Exit']),
create_cave_region('Dam', ['Floodgate', 'Floodgate Chest']), create_cave_region('Dam', 'the dam', ['Floodgate', 'Floodgate Chest']),
create_cave_region('Links House', ['Link\'s House'], ['Links House Exit']), create_cave_region('Links House', 'your house', ['Link\'s House'], ['Links House Exit']),
create_cave_region('Chris Houlihan Room', None, ['Chris Houlihan Room Exit']), create_cave_region('Chris Houlihan Room', 'I AM ERROR', None, ['Chris Houlihan Room Exit']),
create_cave_region('Tavern', ['Kakariko Tavern']), create_cave_region('Tavern', 'the tavern', ['Kakariko Tavern']),
create_cave_region('Elder House', None, ['Elder House Exit (East)', 'Elder House Exit (West)']), create_cave_region('Elder House', 'a connector', None, ['Elder House Exit (East)', 'Elder House Exit (West)']),
create_cave_region('Snitch Lady (East)'), create_cave_region('Snitch Lady (East)', 'a boring house'),
create_cave_region('Snitch Lady (West)'), create_cave_region('Snitch Lady (West)', 'a boring house'),
create_cave_region('Bush Covered House'), create_cave_region('Bush Covered House', 'the grass man'),
create_cave_region('Tavern (Front)'), create_cave_region('Tavern (Front)', 'the tavern'),
create_cave_region('Light World Bomb Hut'), create_cave_region('Light World Bomb Hut', 'a restock room'),
create_cave_region('Kakariko Shop'), create_cave_region('Kakariko Shop', 'a common shop'),
create_cave_region('Fortune Teller (Light)'), create_cave_region('Fortune Teller (Light)', 'a fortune teller'),
create_cave_region('Lake Hylia Fortune Teller'), create_cave_region('Lake Hylia Fortune Teller', 'a fortune teller'),
create_cave_region('Lumberjack House'), create_cave_region('Lumberjack House', 'a boring house'),
create_cave_region('Bonk Fairy (Light)'), create_cave_region('Bonk Fairy (Light)', 'a fairy fountain'),
create_cave_region('Bonk Fairy (Dark)'), create_cave_region('Bonk Fairy (Dark)', 'a fairy fountain'),
create_cave_region('Lake Hylia Healer Fairy'), create_cave_region('Lake Hylia Healer Fairy', 'a fairy fountain'),
create_cave_region('Swamp Healer Fairy'), create_cave_region('Swamp Healer Fairy', 'a fairy fountain'),
create_cave_region('Desert Healer Fairy'), create_cave_region('Desert Healer Fairy', 'a fairy fountain'),
create_cave_region('Dark Lake Hylia Healer Fairy'), create_cave_region('Dark Lake Hylia Healer Fairy', 'a fairy fountain'),
create_cave_region('Dark Lake Hylia Ledge Healer Fairy'), create_cave_region('Dark Lake Hylia Ledge Healer Fairy', 'a fairy fountain'),
create_cave_region('Dark Desert Healer Fairy'), create_cave_region('Dark Desert Healer Fairy', 'a fairy fountain'),
create_cave_region('Dark Death Mountain Healer Fairy'), create_cave_region('Dark Death Mountain Healer Fairy', 'a fairy fountain'),
create_cave_region('Chicken House', ['Chicken House']), create_cave_region('Chicken House', 'a house with a chest', ['Chicken House']),
create_cave_region('Aginahs Cave', ['Aginah\'s Cave']), create_cave_region('Aginahs Cave', 'a cave with a chest', ['Aginah\'s Cave']),
create_cave_region('Sahasrahlas Hut', ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla']), create_cave_region('Sahasrahlas Hut', 'Sahasrahla', ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla']),
create_cave_region('Kakariko Well (top)', ['Kakariko Well - Top', 'Kakariko Well - Left', 'Kakariko Well - Middle', create_cave_region('Kakariko Well (top)', 'a drop\'s exit', ['Kakariko Well - Top', 'Kakariko Well - Left', 'Kakariko Well - Middle',
'Kakariko Well - Right', 'Kakariko Well - Bottom'], ['Kakariko Well (top to bottom)']), 'Kakariko Well - Right', 'Kakariko Well - Bottom'], ['Kakariko Well (top to bottom)']),
create_cave_region('Kakariko Well (bottom)', None, ['Kakariko Well Exit']), create_cave_region('Kakariko Well (bottom)', 'a drop\'s exit', None, ['Kakariko Well Exit']),
create_cave_region('Blacksmiths Hut', ['Blacksmith', 'Missing Smith']), create_cave_region('Blacksmiths Hut', 'the smith', ['Blacksmith', 'Missing Smith']),
create_lw_region('Bat Cave Drop Ledge', None, ['Bat Cave Drop']), create_lw_region('Bat Cave Drop Ledge', None, ['Bat Cave Drop']),
create_cave_region('Bat Cave (right)', ['Magic Bat'], ['Bat Cave Door']), create_cave_region('Bat Cave (right)', 'a drop\'s exit', ['Magic Bat'], ['Bat Cave Door']),
create_cave_region('Bat Cave (left)', None, ['Bat Cave Exit']), create_cave_region('Bat Cave (left)', 'a drop\'s exit', None, ['Bat Cave Exit']),
create_cave_region('Sick Kids House', ['Sick Kid']), create_cave_region('Sick Kids House', 'the sick kid', ['Sick Kid']),
create_lw_region('Hobo Bridge', ['Hobo']), create_lw_region('Hobo Bridge', ['Hobo']),
create_cave_region('Lost Woods Hideout (top)', ['Lost Woods Hideout'], ['Lost Woods Hideout (top to bottom)']), create_cave_region('Lost Woods Hideout (top)', 'a drop\'s exit', ['Lost Woods Hideout'], ['Lost Woods Hideout (top to bottom)']),
create_cave_region('Lost Woods Hideout (bottom)', None, ['Lost Woods Hideout Exit']), create_cave_region('Lost Woods Hideout (bottom)', 'a drop\'s exit', None, ['Lost Woods Hideout Exit']),
create_cave_region('Lumberjack Tree (top)', ['Lumberjack Tree'], ['Lumberjack Tree (top to bottom)']), create_cave_region('Lumberjack Tree (top)', 'a drop\'s exit', ['Lumberjack Tree'], ['Lumberjack Tree (top to bottom)']),
create_cave_region('Lumberjack Tree (bottom)', None, ['Lumberjack Tree Exit']), create_cave_region('Lumberjack Tree (bottom)', 'a drop\'s exit', None, ['Lumberjack Tree Exit']),
create_lw_region('Cave 45 Ledge', None, ['Cave 45']), create_lw_region('Cave 45 Ledge', None, ['Cave 45']),
create_cave_region('Cave 45', ['Cave 45']), create_cave_region('Cave 45', 'a cave with an item', ['Cave 45']),
create_lw_region('Graveyard Ledge', None, ['Graveyard Cave']), create_lw_region('Graveyard Ledge', None, ['Graveyard Cave']),
create_cave_region('Graveyard Cave', ['Graveyard Cave']), create_cave_region('Graveyard Cave', 'a cave with an item', ['Graveyard Cave']),
create_cave_region('Checkerboard Cave', ['Checkerboard Cave']), create_cave_region('Checkerboard Cave', 'a cave with an item', ['Checkerboard Cave']),
create_cave_region('Long Fairy Cave'), create_cave_region('Long Fairy Cave', 'a fairy fountain'),
create_cave_region('Mini Moldorm Cave', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', create_cave_region('Mini Moldorm Cave', 'a bounty of five items', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right',
'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']), 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']),
create_cave_region('Ice Rod Cave', ['Ice Rod Cave']), create_cave_region('Ice Rod Cave', 'a cave with a chest', ['Ice Rod Cave']),
create_cave_region('Good Bee Cave'), create_cave_region('Good Bee Cave', 'a cold bee'),
create_cave_region('20 Rupee Cave'), create_cave_region('20 Rupee Cave', 'a cave with some cash'),
create_cave_region('Cave Shop (Lake Hylia)'), create_cave_region('Cave Shop (Lake Hylia)', 'a common shop'),
create_cave_region('Cave Shop (Dark Death Mountain)'), create_cave_region('Cave Shop (Dark Death Mountain)', 'a common shop'),
create_cave_region('Bonk Rock Cave', ['Bonk Rock Cave']), create_cave_region('Bonk Rock Cave', 'a cave with a chest', ['Bonk Rock Cave']),
create_cave_region('Library', ['Library']), create_cave_region('Library', 'the library', ['Library']),
create_cave_region('Kakariko Gamble Game'), create_cave_region('Kakariko Gamble Game', 'a game of chance'),
create_cave_region('Potion Shop', ['Potion Shop']), create_cave_region('Potion Shop', 'the potion shop', ['Potion Shop']),
create_lw_region('Lake Hylia Island', ['Lake Hylia Island']), create_lw_region('Lake Hylia Island', ['Lake Hylia Island']),
create_cave_region('Capacity Upgrade'), create_cave_region('Capacity Upgrade', 'the queen of fairies'),
create_cave_region('Two Brothers House', None, ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)']), create_cave_region('Two Brothers House', 'a connector', None, ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)']),
create_lw_region('Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)']), create_lw_region('Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)']),
create_cave_region('50 Rupee Cave'), create_cave_region('50 Rupee Cave', 'a cave with some cash'),
create_lw_region('Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (West)']), create_lw_region('Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (West)']),
create_lw_region('Desert Ledge (Northeast)', None, ['Checkerboard Cave']), create_lw_region('Desert Ledge (Northeast)', None, ['Checkerboard Cave']),
create_lw_region('Desert Palace Stairs', None, ['Desert Palace Entrance (South)']), create_lw_region('Desert Palace Stairs', None, ['Desert Palace Entrance (South)']),
create_lw_region('Desert Palace Lone Stairs', None, ['Desert Palace Stairs Drop', 'Desert Palace Entrance (East)']), create_lw_region('Desert Palace Lone Stairs', None, ['Desert Palace Stairs Drop', 'Desert Palace Entrance (East)']),
create_lw_region('Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Return Rocks']), create_lw_region('Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Return Rocks']),
create_dungeon_region('Desert Palace Main (Outer)', ['Desert Palace - Big Chest', 'Desert Palace - Torch', 'Desert Palace - Map Chest'], create_dungeon_region('Desert Palace Main (Outer)', 'Desert Palace', ['Desert Palace - Big Chest', 'Desert Palace - Torch', 'Desert Palace - Map Chest'],
['Desert Palace Pots (Outer)', 'Desert Palace Exit (West)', 'Desert Palace Exit (East)', 'Desert Palace East Wing']), ['Desert Palace Pots (Outer)', 'Desert Palace Exit (West)', 'Desert Palace Exit (East)', 'Desert Palace East Wing']),
create_dungeon_region('Desert Palace Main (Inner)', None, ['Desert Palace Exit (South)', 'Desert Palace Pots (Inner)']), create_dungeon_region('Desert Palace Main (Inner)', 'Desert Palace', None, ['Desert Palace Exit (South)', 'Desert Palace Pots (Inner)']),
create_dungeon_region('Desert Palace East', ['Desert Palace - Compass Chest', 'Desert Palace - Big Key Chest']), create_dungeon_region('Desert Palace East', 'Desert Palace', ['Desert Palace - Compass Chest', 'Desert Palace - Big Key Chest']),
create_dungeon_region('Desert Palace North', ['Desert Palace - Lanmolas', 'Desert Palace - Prize'], ['Desert Palace Exit (North)']), create_dungeon_region('Desert Palace North', 'Desert Palace', ['Desert Palace - Boss', 'Desert Palace - Prize'], ['Desert Palace Exit (North)']),
create_dungeon_region('Eastern Palace', ['Eastern Palace - Compass Chest', 'Eastern Palace - Big Chest', 'Eastern Palace - Cannonball Chest', create_dungeon_region('Eastern Palace', 'Eastern Palace', ['Eastern Palace - Compass Chest', 'Eastern Palace - Big Chest', 'Eastern Palace - Cannonball Chest',
'Eastern Palace - Big Key Chest', 'Eastern Palace - Map Chest', 'Eastern Palace - Armos Knights', 'Eastern Palace - Prize'], ['Eastern Palace Exit']), 'Eastern Palace - Big Key Chest', 'Eastern Palace - Map Chest', 'Eastern Palace - Boss', 'Eastern Palace - Prize'], ['Eastern Palace Exit']),
create_lw_region('Master Sword Meadow', ['Master Sword Pedestal']), create_lw_region('Master Sword Meadow', ['Master Sword Pedestal']),
create_cave_region('Lost Woods Gamble'), create_cave_region('Lost Woods Gamble', 'a game of chance'),
create_lw_region('Hyrule Castle Courtyard', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Entrance (South)']), create_lw_region('Hyrule Castle Courtyard', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Entrance (South)']),
create_lw_region('Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop']), create_lw_region('Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop']),
create_dungeon_region('Hyrule Castle', ['Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest', 'Hyrule Castle - Zelda\'s Chest'], create_dungeon_region('Hyrule Castle', 'Hyrule Castle', ['Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest', 'Hyrule Castle - Zelda\'s Chest'],
['Hyrule Castle Exit (East)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (South)', 'Throne Room']), ['Hyrule Castle Exit (East)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (South)', 'Throne Room']),
create_dungeon_region('Sewer Drop', None, ['Sewer Drop']), # This exists only to be referenced for access checks create_dungeon_region('Sewer Drop', 'a drop\'s exit', None, ['Sewer Drop']), # This exists only to be referenced for access checks
create_dungeon_region('Sewers (Dark)', ['Sewers - Dark Cross'], ['Sewers Door']), create_dungeon_region('Sewers (Dark)', 'a drop\'s exit', ['Sewers - Dark Cross'], ['Sewers Door']),
create_dungeon_region('Sewers', ['Sewers - Secret Room - Left', 'Sewers - Secret Room - Middle', create_dungeon_region('Sewers', 'a drop\'s exit', ['Sewers - Secret Room - Left', 'Sewers - Secret Room - Middle',
'Sewers - Secret Room - Right'], ['Sanctuary Push Door', 'Sewers Back Door']), 'Sewers - Secret Room - Right'], ['Sanctuary Push Door', 'Sewers Back Door']),
create_dungeon_region('Sanctuary', ['Sanctuary'], ['Sanctuary Exit']), create_dungeon_region('Sanctuary', 'a drop\'s exit', ['Sanctuary'], ['Sanctuary Exit']),
create_dungeon_region('Agahnims Tower', ['Castle Tower - Room 03', 'Castle Tower - Dark Maze'], ['Agahnim 1', 'Agahnims Tower Exit']), create_dungeon_region('Agahnims Tower', 'Castle Tower', ['Castle Tower - Room 03', 'Castle Tower - Dark Maze'], ['Agahnim 1', 'Agahnims Tower Exit']),
create_dungeon_region('Agahnim 1', ['Agahnim 1'], None), create_dungeon_region('Agahnim 1', 'Castle Tower', ['Agahnim 1'], None),
create_cave_region('Old Man Cave', ['Old Man'], ['Old Man Cave Exit (East)', 'Old Man Cave Exit (West)']), create_cave_region('Old Man Cave', 'a connector', ['Old Man'], ['Old Man Cave Exit (East)', 'Old Man Cave Exit (West)']),
create_cave_region('Old Man House', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']), create_cave_region('Old Man House', 'a connector', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']),
create_cave_region('Old Man House Back', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']), create_cave_region('Old Man House Back', 'a connector', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']),
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']), 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']),
create_cave_region('Death Mountain Return Cave', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)']), create_cave_region('Death Mountain Return Cave', 'a connector', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)']),
create_lw_region('Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)']), create_lw_region('Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)']),
create_cave_region('Spectacle Rock Cave (Top)', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']), create_cave_region('Spectacle Rock Cave (Top)', 'a connector', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']),
create_cave_region('Spectacle Rock Cave (Bottom)', None, ['Spectacle Rock Cave Exit']), create_cave_region('Spectacle Rock Cave (Bottom)', 'a connector', None, ['Spectacle Rock Cave Exit']),
create_cave_region('Spectacle Rock Cave (Peak)', None, ['Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Exit (Peak)']), create_cave_region('Spectacle Rock Cave (Peak)', 'a connector', None, ['Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Exit (Peak)']),
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_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_cave_region('Hookshot Fairy'), create_cave_region('Hookshot Fairy', 'fairies deep in a cave'),
create_cave_region('Paradox Cave Front', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)', 'Light World Death Mountain Shop']), create_cave_region('Paradox Cave Front', 'a connector', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)', 'Light World Death Mountain Shop']),
create_cave_region('Paradox Cave Chest Area', ['Paradox Cave Lower - Far Left', create_cave_region('Paradox Cave Chest Area', 'a connector', ['Paradox Cave Lower - Far Left',
'Paradox Cave Lower - Left', 'Paradox Cave Lower - Left',
'Paradox Cave Lower - Right', 'Paradox Cave Lower - Right',
'Paradox Cave Lower - Far Right', 'Paradox Cave Lower - Far Right',
'Paradox Cave Lower - Middle', 'Paradox Cave Lower - Middle',
'Paradox Cave Upper - Left', 'Paradox Cave Upper - Left',
'Paradox Cave Upper - Right'], 'Paradox Cave Upper - Right'],
['Paradox Cave Push Block', 'Paradox Cave Bomb Jump']), ['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_cave_region('Paradox Cave', 'a connector', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']),
create_cave_region('Light World Death Mountain Shop'), create_cave_region('Light World Death Mountain Shop', 'a common shop'),
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('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_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 (Top)', 'a connector', ['Spiral Cave'], ['Spiral Cave (top to bottom)', 'Spiral Cave Exit (Top)']),
create_cave_region('Spiral Cave (Bottom)', None, ['Spiral Cave Exit']), create_cave_region('Spiral Cave (Bottom)', 'a connector', None, ['Spiral Cave Exit']),
create_lw_region('Fairy Ascension Plateau', None, ['Fairy Ascension Drop', 'Fairy Ascension Cave (Bottom)']), 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_cave_region('Fairy Ascension Cave (Bottom)', 'a connector', None, ['Fairy Ascension Cave Climb', 'Fairy Ascension Cave Exit (Bottom)']),
create_cave_region('Fairy Ascension Cave (Drop)', 'a connector', None, ['Fairy Ascension Cave Pots']),
create_cave_region('Fairy Ascension Cave (Top)', 'a connector', None, ['Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Cave Drop']),
create_lw_region('Fairy Ascension Ledge', None, ['Fairy Ascension Ledge Drop', 'Fairy Ascension Cave (Top)']), 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('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_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 (Bottom)', 'Tower of Hera', ['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 (Basement)', 'Tower of Hera', ['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_dungeon_region('Tower of Hera (Top)', 'Tower of Hera', ['Tower of Hera - Compass Chest', 'Tower of Hera - Big Chest', 'Tower of Hera - Boss', 'Tower of Hera - Prize']),
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', 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', 'Pyramid Hole', 'Northeast Dark World Broken Bridge Pass']), '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_dw_region('Northeast Dark World', ['Catfish'], ['West Dark World Gap', 'Dark World Potion Shop', 'East Dark World Broken Bridge Pass']), create_dw_region('Northeast Dark World', ['Catfish'], ['West Dark World Gap', 'Dark World Potion Shop', 'East Dark World Broken Bridge Pass']),
create_cave_region('Palace of Darkness Hint'), create_cave_region('Palace of Darkness Hint', 'a storyteller'),
create_cave_region('East Dark World Hint'), create_cave_region('East Dark World Hint', 'a storyteller'),
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_dw_region('South Dark World', ['Stumpy', 'Digging Game', 'Bombos Tablet'], ['Dark Lake Hylia Drop (South)', 'Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'Maze Race Mirror Spot',
'Maze Race Mirror Spot', 'Cave 45 Mirror Spot', 'East Dark World Bridge', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Shop']), 'Cave 45 Mirror Spot', 'East Dark World Bridge', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Shop']),
create_cave_region('Big Bomb Shop'), create_cave_region('Big Bomb Shop', 'the bomb shop'),
create_cave_region('Archery Game'), create_cave_region('Archery Game', 'a game of skill'),
create_dw_region('Dark Lake Hylia', None, ['Lake Hylia Island Mirror Spot', 'East Dark World Pier', 'Dark Lake Hylia Ledge']), create_dw_region('Dark Lake Hylia', None, ['Lake Hylia Island Mirror Spot', 'East Dark World Pier', 'Dark Lake Hylia Ledge']),
create_dw_region('Dark Lake Hylia Central Island', None, ['Ice Palace', 'Lake Hylia Central Island Mirror Spot']), create_dw_region('Dark Lake Hylia Central Island', None, ['Ice Palace', 'Lake Hylia Central Island Mirror Spot']),
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_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_cave_region('Dark Lake Hylia Ledge Hint'), create_cave_region('Dark Lake Hylia Ledge Hint', 'a storyteller'),
create_cave_region('Dark Lake Hylia Ledge Spike Cave'), create_cave_region('Dark Lake Hylia Ledge Spike Cave', 'a spiky hint'),
create_cave_region('Hype Cave', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', create_cave_region('Hype Cave', 'a bounty of five items', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left',
'Hype Cave - Bottom', 'Hype Cave - Generous Guy']), 'Hype Cave - Bottom', 'Hype Cave - Generous Guy']),
create_dw_region('West Dark World', ['Frog'], ['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_dw_region('West Dark World', ['Frog'], ['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',
'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']), '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_dw_region('Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop']), create_dw_region('Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop']),
create_dw_region('Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Bat Cave Drop Ledge Mirror Spot', 'Dark World Hammer Peg Cave', 'Peg Area Rocks']), create_dw_region('Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Bat Cave Drop Ledge Mirror Spot', 'Dark World Hammer Peg Cave', 'Peg Area Rocks']),
create_dw_region('Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance Drop']), create_dw_region('Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance Drop']),
create_cave_region('Fortune Teller (Dark)'), create_cave_region('Fortune Teller (Dark)', 'a fortune teller'),
create_cave_region('Village of Outcasts Shop'), create_cave_region('Village of Outcasts Shop', 'a common shop'),
create_cave_region('Dark Lake Hylia Shop'), create_cave_region('Dark Lake Hylia Shop', 'a common shop'),
create_cave_region('Dark World Lumberjack Shop'), create_cave_region('Dark World Lumberjack Shop', 'a common shop'),
create_cave_region('Dark World Potion Shop'), create_cave_region('Dark World Potion Shop', 'a common shop'),
create_cave_region('Dark World Hammer Peg Cave', ['Peg Cave']), create_cave_region('Dark World Hammer Peg Cave', 'a cave with an item', ['Peg Cave']),
create_cave_region('Pyramid Fairy', ['Pyramid Fairy - Left', 'Pyramid Fairy - Right']), create_cave_region('Pyramid Fairy', 'a cave with two chests', ['Pyramid Fairy - Left', 'Pyramid Fairy - Right']),
create_cave_region('Brewery', ['Brewery']), create_cave_region('Brewery', 'a house with a chest', ['Brewery']),
create_cave_region('C-Shaped House', ['C-Shaped House']), create_cave_region('C-Shaped House', 'a house with a chest', ['C-Shaped House']),
create_cave_region('Chest Game', ['Chest Game']), create_cave_region('Chest Game', 'a game of 16 chests', ['Chest Game']),
create_cave_region('Red Shield Shop'), create_cave_region('Red Shield Shop', 'the rare shop'),
create_cave_region('Dark Sanctuary Hint'), create_cave_region('Dark Sanctuary Hint', 'a storyteller'),
create_cave_region('Bumper Cave', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Exit (Top)']), create_cave_region('Bumper Cave', 'a connector', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Exit (Top)']),
create_dw_region('Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Ledge Drop', 'Bumper Cave (Top)', 'Bumper Cave Ledge Mirror Spot']), create_dw_region('Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Ledge Drop', 'Bumper Cave (Top)', 'Bumper Cave Ledge Mirror Spot']),
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_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 Second Section Door (East)']), 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']),
create_dw_region('Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section']), create_dw_region('Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section']),
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_dw_region('Dark Desert', None, ['Misery Mire', 'Mire Shed', 'Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge Mirror Spot', 'Desert Palace Stairs Mirror Spot',
'Dark Desert Hint', 'Dark Desert Fairy']), 'Desert Palace Entrance (North) Mirror Spot', 'Dark Desert Hint', 'Dark Desert Fairy']),
create_cave_region('Mire Shed', ['Mire Shed - Left', 'Mire Shed - Right']), create_cave_region('Mire Shed', 'a cave with two chests', ['Mire Shed - Left', 'Mire Shed - Right']),
create_cave_region('Dark Desert Hint'), create_cave_region('Dark Desert Hint', 'a storyteller'),
create_dw_region('Dark Death Mountain (West Bottom)', None, ['Spike Cave', 'Spectacle Rock Mirror Spot', 'Dark Death Mountain Fairy']), create_dw_region('Dark Death Mountain (West Bottom)', None, ['Spike Cave', 'Spectacle Rock Mirror Spot', 'Dark Death Mountain Fairy']),
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_dw_region('Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (East)', 'Dark Death Mountain Drop (West)', 'Ganons Tower', 'Superbunny Cave (Top)',
'East Death Mountain (Top) Mirror Spot', 'Turtle Rock']), 'Hookshot Cave', 'East Death Mountain (Top) Mirror Spot', 'Turtle Rock']),
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_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_dw_region('Dark Death Mountain Isolated Ledge', None, ['Isolated Ledge Mirror Spot', 'Turtle Rock Isolated Ledge Entrance']), create_dw_region('Dark Death Mountain Isolated Ledge', None, ['Isolated Ledge Mirror Spot', 'Turtle Rock Isolated Ledge Entrance']),
create_dw_region('Dark Death Mountain (East Bottom)', None, ['Superbunny Cave (Bottom)', 'Cave Shop (Dark Death Mountain)', 'Fairy Ascension Mirror Spot']), create_dw_region('Dark Death Mountain (East Bottom)', None, ['Superbunny Cave (Bottom)', 'Cave Shop (Dark Death Mountain)', 'Fairy Ascension Mirror Spot']),
create_cave_region('Superbunny Cave', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'], create_cave_region('Superbunny Cave', 'a connector', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'],
['Superbunny Cave Exit (Top)', 'Superbunny Cave Exit (Bottom)']), ['Superbunny Cave Exit (Top)', 'Superbunny Cave Exit (Bottom)']),
create_cave_region('Spike Cave', ['Spike Cave']), create_cave_region('Spike Cave', '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'], create_cave_region('Hookshot Cave', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'],
['Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)']), ['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_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_lw_region('Death Mountain Floating Island (Light World)', ['Floating Island']),
create_dw_region('Turtle Rock (Top)', None, ['Turtle Rock Drop']), create_dw_region('Turtle Rock (Top)', None, ['Turtle Rock Drop']),
create_lw_region('Mimic Cave Ledge', None, ['Mimic Cave']), create_lw_region('Mimic Cave Ledge', None, ['Mimic Cave']),
create_cave_region('Mimic Cave', ['Mimic Cave']), create_cave_region('Mimic Cave', 'Mimic Cave', ['Mimic Cave']),
create_dungeon_region('Swamp Palace (Entrance)', None, ['Swamp Palace Moat', 'Swamp Palace Exit']), create_dungeon_region('Swamp Palace (Entrance)', 'Swamp Palace', None, ['Swamp Palace Moat', 'Swamp Palace Exit']),
create_dungeon_region('Swamp Palace (First Room)', ['Swamp Palace - Entrance'], ['Swamp Palace Small Key Door']), create_dungeon_region('Swamp Palace (First Room)', 'Swamp Palace', ['Swamp Palace - Entrance'], ['Swamp Palace Small Key Door']),
create_dungeon_region('Swamp Palace (Starting Area)', ['Swamp Palace - Map Chest'], ['Swamp Palace (Center)']), create_dungeon_region('Swamp Palace (Starting Area)', 'Swamp Palace', ['Swamp Palace - Map Chest'], ['Swamp Palace (Center)']),
create_dungeon_region('Swamp Palace (Center)', ['Swamp Palace - Big Chest', 'Swamp Palace - Compass Chest', create_dungeon_region('Swamp Palace (Center)', 'Swamp Palace', ['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_dungeon_region('Swamp Palace (North)', ['Swamp Palace - Flooded Room - Left', 'Swamp Palace - Flooded Room - Right', create_dungeon_region('Swamp Palace (North)', 'Swamp Palace', ['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 - Boss', 'Swamp Palace - Prize']),
create_dungeon_region('Thieves Town (Entrance)', ['Thieves\' Town - Big Key Chest', create_dungeon_region('Thieves Town (Entrance)', 'Thieves\' Town', ['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_dungeon_region('Thieves Town (Deep)', ['Thieves\' Town - Attic', create_dungeon_region('Thieves Town (Deep)', 'Thieves\' Town', ['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_dungeon_region('Blind Fight', ['Thieves Town - Blind', 'Thieves Town - Prize']), create_dungeon_region('Blind Fight', 'Thieves\' Town', ['Thieves\' Town - Boss', 'Thieves\' Town - Prize']),
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_dungeon_region('Skull Woods First Section', 'Skull Woods', ['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 (Right)', ['Skull Woods - Pinball Room'], ['Skull Woods First Section (Right) North Door']), create_dungeon_region('Skull Woods First Section (Right)', 'Skull Woods', ['Skull Woods - Pinball Room'], ['Skull Woods First Section (Right) North Door']),
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_dungeon_region('Skull Woods First Section (Left)', 'Skull Woods', ['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 (Top)', ['Skull Woods - Big Chest'], ['Skull Woods First Section (Top) One-Way Path']), create_dungeon_region('Skull Woods First Section (Top)', 'Skull Woods', ['Skull Woods - Big Chest'], ['Skull Woods First Section (Top) One-Way Path']),
create_dungeon_region('Skull Woods Second Section (Drop)', None, ['Skull Woods Second Section (Drop)']), create_dungeon_region('Skull Woods Second Section (Drop)', 'Skull Woods', None, ['Skull Woods Second Section (Drop)']),
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_dungeon_region('Skull Woods Second Section', 'Skull Woods', ['Skull Woods - Big Key Chest'], ['Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)']),
create_dungeon_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', ['Skull Woods - Bridge Room'], ['Skull Woods Torch Room', 'Skull Woods Final Section Exit']),
create_dungeon_region('Skull Woods Final Section (Mothula)', ['Skull Woods - Mothula', 'Skull Woods - Prize']), create_dungeon_region('Skull Woods Final Section (Mothula)', 'Skull Woods', ['Skull Woods - Boss', 'Skull Woods - Prize']),
create_dungeon_region('Ice Palace (Entrance)', None, ['Ice Palace Entrance Room', 'Ice Palace Exit']), create_dungeon_region('Ice Palace (Entrance)', 'Ice Palace', None, ['Ice Palace Entrance Room', 'Ice Palace Exit']),
create_dungeon_region('Ice Palace (Main)', ['Ice Palace - Compass Chest', 'Ice Palace - Freezor Chest', create_dungeon_region('Ice Palace (Main)', 'Ice Palace', ['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_dungeon_region('Ice Palace (East)', ['Ice Palace - Spike Room'], ['Ice Palace (East Top)']), create_dungeon_region('Ice Palace (East)', 'Ice Palace', ['Ice Palace - Spike Room'], ['Ice Palace (East Top)']),
create_dungeon_region('Ice Palace (East Top)', ['Ice Palace - Big Key Chest', 'Ice Palace - Map Chest']), create_dungeon_region('Ice Palace (East Top)', 'Ice Palace', ['Ice Palace - Big Key Chest', 'Ice Palace - Map Chest']),
create_dungeon_region('Ice Palace (Kholdstare)', ['Ice Palace - Kholdstare', 'Ice Palace - Prize']), create_dungeon_region('Ice Palace (Kholdstare)', 'Ice Palace', ['Ice Palace - Boss', 'Ice Palace - Prize']),
create_dungeon_region('Misery Mire (Entrance)', None, ['Misery Mire Entrance Gap', 'Misery Mire Exit']), create_dungeon_region('Misery Mire (Entrance)', 'Misery Mire', None, ['Misery Mire Entrance Gap', 'Misery Mire Exit']),
create_dungeon_region('Misery Mire (Main)', ['Misery Mire - Big Chest', 'Misery Mire - Map Chest', 'Misery Mire - Main Lobby', create_dungeon_region('Misery Mire (Main)', 'Misery Mire', ['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_dungeon_region('Misery Mire (West)', ['Misery Mire - Compass Chest', 'Misery Mire - Big Key Chest']), create_dungeon_region('Misery Mire (West)', 'Misery Mire', ['Misery Mire - Compass Chest', 'Misery Mire - Big Key Chest']),
create_dungeon_region('Misery Mire (Final Area)', None, ['Misery Mire (Vitreous)']), create_dungeon_region('Misery Mire (Final Area)', 'Misery Mire', None, ['Misery Mire (Vitreous)']),
create_dungeon_region('Misery Mire (Vitreous)', ['Misery Mire - Vitreous', 'Misery Mire - Prize']), create_dungeon_region('Misery Mire (Vitreous)', 'Misery Mire', ['Misery Mire - Boss', 'Misery Mire - Prize']),
create_dungeon_region('Turtle Rock (Entrance)', None, ['Turtle Rock Entrance Gap', 'Turtle Rock Exit (Front)']), create_dungeon_region('Turtle Rock (Entrance)', 'Turtle Rock', None, ['Turtle Rock Entrance Gap', 'Turtle Rock Exit (Front)']),
create_dungeon_region('Turtle Rock (First Section)', ['Turtle Rock - Compass Chest', 'Turtle Rock - Roller Room - Left', create_dungeon_region('Turtle Rock (First Section)', 'Turtle Rock', ['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_dungeon_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', ['Turtle Rock - Chain Chomps'], ['Turtle Rock (Chain Chomp Room) (North)', 'Turtle Rock (Chain Chomp Room) (South)']),
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_dungeon_region('Turtle Rock (Second Section)', 'Turtle Rock', ['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 (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', ['Turtle Rock - Big Chest'], ['Turtle Rock (Big Chest) (North)', 'Turtle Rock Ledge Exit (East)']),
create_dungeon_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', ['Turtle Rock - Crystaroller Room'], ['Turtle Rock Dark Room Staircase', 'Turtle Rock Big Key Door Reverse']),
create_dungeon_region('Turtle Rock (Dark Room)', None, ['Turtle Rock (Dark Room) (North)', 'Turtle Rock (Dark Room) (South)']), create_dungeon_region('Turtle Rock (Dark Room)', 'Turtle Rock', None, ['Turtle Rock (Dark Room) (North)', 'Turtle Rock (Dark Room) (South)']),
create_dungeon_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', ['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_dungeon_region('Turtle Rock (Trinexx)', ['Turtle Rock - Trinexx', 'Turtle Rock - Prize']), create_dungeon_region('Turtle Rock (Trinexx)', 'Turtle Rock', ['Turtle Rock - Boss', 'Turtle Rock - Prize']),
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_dungeon_region('Palace of Darkness (Entrance)', 'Palace of Darkness', ['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 (Center)', ['Palace of Darkness - The Arena - Bridge', 'Palace of Darkness - Stalfos Basement'], create_dungeon_region('Palace of Darkness (Center)', 'Palace of Darkness', ['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_dungeon_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', ['Palace of Darkness - Big Key Chest']),
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_dungeon_region('Palace of Darkness (Bonk Section)', 'Palace of Darkness', ['Palace of Darkness - The Arena - Ledge', 'Palace of Darkness - Map Chest'], ['Palace of Darkness Hammer Peg Drop']),
create_dungeon_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', ['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_dungeon_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', ['Palace of Darkness - Dark Maze - Top', 'Palace of Darkness - Dark Maze - Bottom', 'Palace of Darkness - Big Chest']),
create_dungeon_region('Palace of Darkness (Harmless Hellway)', ['Palace of Darkness - Harmless Hellway']), create_dungeon_region('Palace of Darkness (Harmless Hellway)', 'Palace of Darkness', ['Palace of Darkness - Harmless Hellway']),
create_dungeon_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', ['Palace of Darkness - Boss', 'Palace of Darkness - Prize']),
create_dungeon_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)', 'Ganon\'s Tower', ['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_dungeon_region('Ganons Tower (Tile Room)', ['Ganons Tower - Tile Room'], ['Ganons Tower (Tile Room) Key Door']), create_dungeon_region('Ganons Tower (Tile Room)', 'Ganon\'s Tower', ['Ganons Tower - Tile Room'], ['Ganons Tower (Tile Room) Key Door']),
create_dungeon_region('Ganons Tower (Compass Room)', ['Ganons Tower - Compass Room - Top Left', 'Ganons Tower - Compass Room - Top Right', create_dungeon_region('Ganons Tower (Compass Room)', 'Ganon\'s Tower', ['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_dungeon_region('Ganons Tower (Hookshot Room)', ['Ganons Tower - DMs Room - Top Left', 'Ganons Tower - DMs Room - Top Right', create_dungeon_region('Ganons Tower (Hookshot Room)', 'Ganon\'s Tower', ['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_dungeon_region('Ganons Tower (Map Room)', ['Ganons Tower - Map Chest']), create_dungeon_region('Ganons Tower (Map Room)', 'Ganon\'s Tower', ['Ganons Tower - Map Chest']),
create_dungeon_region('Ganons Tower (Firesnake Room)', ['Ganons Tower - Firesnake Room'], ['Ganons Tower (Firesnake Room)']), create_dungeon_region('Ganons Tower (Firesnake Room)', 'Ganon\'s Tower', ['Ganons Tower - Firesnake Room'], ['Ganons Tower (Firesnake Room)']),
create_dungeon_region('Ganons Tower (Teleport Room)', ['Ganons Tower - Randomizer Room - Top Left', 'Ganons Tower - Randomizer Room - Top Right', create_dungeon_region('Ganons Tower (Teleport Room)', 'Ganon\'s Tower', ['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_dungeon_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)', 'Ganon\'s Tower', ['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_dungeon_region('Ganons Tower (Top)', None, ['Ganons Tower Torch Rooms']), create_dungeon_region('Ganons Tower (Top)', 'Ganon\'s Tower', None, ['Ganons Tower Torch Rooms']),
create_dungeon_region('Ganons Tower (Before Moldorm)', ['Ganons Tower - Mini Helmasaur Room - Left', 'Ganons Tower - Mini Helmasaur Room - Right', create_dungeon_region('Ganons Tower (Before Moldorm)', 'Ganon\'s Tower', ['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_dungeon_region('Ganons Tower (Moldorm)', None, ['Ganons Tower Moldorm Gap']), create_dungeon_region('Ganons Tower (Moldorm)', 'Ganon\'s Tower', None, ['Ganons Tower Moldorm Gap']),
create_dungeon_region('Agahnim 2', ['Ganons Tower - Validation Chest', 'Agahnim 2'], None), create_dungeon_region('Agahnim 2', 'Ganon\'s Tower', ['Ganons Tower - Validation Chest', 'Agahnim 2'], None),
create_cave_region('Pyramid', ['Ganon'], ['Ganon Drop']), create_cave_region('Pyramid', 'a drop\'s exit', ['Ganon'], ['Ganon Drop']),
create_cave_region('Bottom of Pyramid', None, ['Pyramid Exit']), create_cave_region('Bottom of Pyramid', 'a drop\'s exit', None, ['Pyramid Exit']),
create_dw_region('Pyramid Ledge', None, ['Pyramid Entrance', 'Pyramid Drop']) create_dw_region('Pyramid Ledge', None, ['Pyramid Entrance', 'Pyramid Drop'])
] ]
@ -299,22 +301,28 @@ def create_regions(world):
for index, (item, price) in enumerate(default_shop_contents[region_name]): for index, (item, price) in enumerate(default_shop_contents[region_name]):
shop.add_inventory(index, item, price) shop.add_inventory(index, item, price)
region = world.get_region('Capacity Upgrade')
shop = Shop(region, 0x0115, ShopType.UpgradeShop, 0x04, True)
region.shop = shop
world.shops.append(shop)
shop.add_inventory(0, 'Bomb Upgrade (+5)', 100, 7)
shop.add_inventory(1, 'Arrow Upgrade (+5)', 100, 7)
world.intialize_regions() world.intialize_regions()
def create_lw_region(name, locations=None, exits=None): def create_lw_region(name, locations=None, exits=None):
return _create_region(name, RegionType.LightWorld, locations, exits) return _create_region(name, RegionType.LightWorld, 'Light World', locations, exits)
def create_dw_region(name, locations=None, exits=None): def create_dw_region(name, locations=None, exits=None):
return _create_region(name, RegionType.DarkWorld, locations, exits) return _create_region(name, RegionType.DarkWorld, 'Dark World', locations, exits)
def create_cave_region(name, locations=None, exits=None): def create_cave_region(name, hint='Hyrule', locations=None, exits=None):
return _create_region(name, RegionType.Cave, locations, exits) return _create_region(name, RegionType.Cave, hint, locations, exits)
def create_dungeon_region(name, locations=None, exits=None): def create_dungeon_region(name, hint='Hyrule', locations=None, exits=None):
return _create_region(name, RegionType.Dungeon, locations, exits) return _create_region(name, RegionType.Dungeon, hint, locations, exits)
def _create_region(name, type, locations=None, exits=None): def _create_region(name, type, hint='Hyrule', locations=None, exits=None):
ret = Region(name, type) ret = Region(name, type, hint)
if locations is None: if locations is None:
locations = [] locations = []
if exits is None: if exits is None:
@ -358,15 +366,15 @@ def mark_light_world_regions(world):
# (room_id, shopkeeper, replaceable) # (room_id, shopkeeper, replaceable)
shop_table = { shop_table = {
'Cave Shop (Dark Death Mountain)': (0x0112, 0x51, True), 'Cave Shop (Dark Death Mountain)': (0x0112, 0xC1, True),
'Red Shield Shop': (0x0110, 0x51, True), 'Red Shield Shop': (0x0110, 0xC1, True),
'Dark Lake Hylia Shop': (0x010F, 0x51, True), 'Dark Lake Hylia Shop': (0x010F, 0xC1, True),
'Dark World Lumberjack Shop': (0x010F, 0x51, True), 'Dark World Lumberjack Shop': (0x010F, 0xC1, True),
'Village of Outcasts Shop': (0x010F, 0x51, True), 'Village of Outcasts Shop': (0x010F, 0xC1, True),
'Dark World Potion Shop': (0x010F, 0x51, True), 'Dark World Potion Shop': (0x010F, 0xC1, True),
'Light World Death Mountain Shop': (0x00FF, 0x51, True), 'Light World Death Mountain Shop': (0x00FF, 0xA0, True),
'Kakariko Shop': (0x011F, 0x51, True), 'Kakariko Shop': (0x011F, 0xA0, True),
'Cave Shop (Lake Hylia)': (0x0112, 0x51, True), 'Cave Shop (Lake Hylia)': (0x0112, 0xA0, True),
'Potion Shop': (0x0109, 0xFF, False), 'Potion Shop': (0x0109, 0xFF, False),
# Bomb Shop not currently modeled as a shop, due to special nature of items # Bomb Shop not currently modeled as a shop, due to special nature of items
} }
@ -422,7 +430,7 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Kakariko Well - Bottom': (0xEA9A, False, 'in a well'), 'Kakariko Well - Bottom': (0xEA9A, False, 'in a well'),
'Blacksmith': (0x18002A, False, 'with the smith'), 'Blacksmith': (0x18002A, False, 'with the smith'),
'Magic Bat': (0x180015, False, 'with the bat'), 'Magic Bat': (0x180015, False, 'with the bat'),
'Sick Kid': (0x339CF, False, 'with the ill'), 'Sick Kid': (0x339CF, False, 'with the sick'),
'Hobo': (0x33E7D, False, 'with the hobo'), 'Hobo': (0x33E7D, False, 'with the hobo'),
'Lost Woods Hideout': (0x180000, False, 'near a thief'), 'Lost Woods Hideout': (0x180000, False, 'near a thief'),
'Lumberjack Tree': (0x180001, False, 'in a hole'), 'Lumberjack Tree': (0x180001, False, 'in a hole'),
@ -434,7 +442,7 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Mini Moldorm Cave - Right': (0xEB48, False, 'near Moldorms'), 'Mini Moldorm Cave - Right': (0xEB48, False, 'near Moldorms'),
'Mini Moldorm Cave - Far Right': (0xEB4B, False, 'near Moldorms'), 'Mini Moldorm Cave - Far Right': (0xEB4B, False, 'near Moldorms'),
'Mini Moldorm Cave - Generous Guy': (0x180010, False, 'near Moldorms'), 'Mini Moldorm Cave - Generous Guy': (0x180010, False, 'near Moldorms'),
'Ice Rod Cave': (0xEB4E, False, 'on ice'), 'Ice Rod Cave': (0xEB4E, False, 'in a frozen cave'),
'Bonk Rock Cave': (0xEB3F, False, 'alone in a cave'), 'Bonk Rock Cave': (0xEB3F, False, 'alone in a cave'),
'Library': (0x180012, False, 'near books'), 'Library': (0x180012, False, 'near books'),
'Potion Shop': (0x180014, False, 'near potions'), 'Potion Shop': (0x180014, False, 'near potions'),
@ -446,13 +454,13 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Desert Palace - Map Chest': (0xE9B6, False, 'in Desert Palace'), 'Desert Palace - Map Chest': (0xE9B6, False, 'in Desert Palace'),
'Desert Palace - Compass Chest': (0xE9CB, False, 'in Desert Palace'), 'Desert Palace - Compass Chest': (0xE9CB, False, 'in Desert Palace'),
'Desert Palace - Big Key Chest': (0xE9C2, False, 'in Desert Palace'), 'Desert Palace - Big Key Chest': (0xE9C2, False, 'in Desert Palace'),
'Desert Palace - Lanmolas': (0x180151, False, 'with Lanmolas'), 'Desert Palace - Boss': (0x180151, False, 'with Lanmolas'),
'Eastern Palace - Compass Chest': (0xE977, False, 'in Eastern Palace'), 'Eastern Palace - Compass Chest': (0xE977, False, 'in Eastern Palace'),
'Eastern Palace - Big Chest': (0xE97D, False, 'in Eastern Palace'), 'Eastern Palace - Big Chest': (0xE97D, False, 'in Eastern Palace'),
'Eastern Palace - Cannonball Chest': (0xE9B3, False, 'in Eastern Palace'), 'Eastern Palace - Cannonball Chest': (0xE9B3, False, 'in Eastern Palace'),
'Eastern Palace - Big Key Chest': (0xE9B9, False, 'in Eastern Palace'), 'Eastern Palace - Big Key Chest': (0xE9B9, False, 'in Eastern Palace'),
'Eastern Palace - Map Chest': (0xE9F5, False, 'in Eastern Palace'), 'Eastern Palace - Map Chest': (0xE9F5, False, 'in Eastern Palace'),
'Eastern Palace - Armos Knights': (0x180150, False, 'with the Armos'), 'Eastern Palace - Boss': (0x180150, False, 'with the Armos'),
'Master Sword Pedestal': (0x289B0, False, 'at the pedestal'), 'Master Sword Pedestal': (0x289B0, False, 'at the pedestal'),
'Hyrule Castle - Boomerang Chest': (0xE974, False, 'in Hyrule Castle'), 'Hyrule Castle - Boomerang Chest': (0xE974, False, 'in Hyrule Castle'),
'Hyrule Castle - Map Chest': (0xEB0C, False, 'in Hyrule Castle'), 'Hyrule Castle - Map Chest': (0xEB0C, False, 'in Hyrule Castle'),
@ -462,36 +470,36 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Sewers - Secret Room - Middle': (0xEB60, False, 'in the sewers'), 'Sewers - Secret Room - Middle': (0xEB60, False, 'in the sewers'),
'Sewers - Secret Room - Right': (0xEB63, False, 'in the sewers'), 'Sewers - Secret Room - Right': (0xEB63, False, 'in the sewers'),
'Sanctuary': (0xEA79, False, 'in Sanctuary'), 'Sanctuary': (0xEA79, False, 'in Sanctuary'),
'Castle Tower - Room 03': (0xEAB5, False, 'in Hyrule Castle'), 'Castle Tower - Room 03': (0xEAB5, False, 'in Castle Tower'),
'Castle Tower - Dark Maze': (0xEAB2, False, 'in Hyrule Castle'), 'Castle Tower - Dark Maze': (0xEAB2, False, 'in Castle Tower'),
'Old Man': (0xF69FA, False, 'with the old man'), 'Old Man': (0xF69FA, False, 'with the old man'),
'Spectacle Rock Cave': (0x180002, False, 'alone in a cave'), 'Spectacle Rock Cave': (0x180002, False, 'alone in a cave'),
'Paradox Cave Lower - Far Left': (0xEB2A, False, 'in paradox cave'), 'Paradox Cave Lower - Far Left': (0xEB2A, False, 'in a cave with seven chests'),
'Paradox Cave Lower - Left': (0xEB2D, False, 'in paradox cave'), 'Paradox Cave Lower - Left': (0xEB2D, False, 'in a cave with seven chests'),
'Paradox Cave Lower - Right': (0xEB30, False, 'in paradox cave'), 'Paradox Cave Lower - Right': (0xEB30, False, 'in a cave with seven chests'),
'Paradox Cave Lower - Far Right': (0xEB33, False, 'in paradox cave'), 'Paradox Cave Lower - Far Right': (0xEB33, False, 'in a cave with seven chests'),
'Paradox Cave Lower - Middle': (0xEB36, False, 'in paradox cave'), 'Paradox Cave Lower - Middle': (0xEB36, False, 'in a cave with seven chests'),
'Paradox Cave Upper - Left': (0xEB39, False, 'in paradox cave'), 'Paradox Cave Upper - Left': (0xEB39, False, 'in a cave with seven chests'),
'Paradox Cave Upper - Right': (0xEB3C, False, 'in paradox cave'), 'Paradox Cave Upper - Right': (0xEB3C, False, 'in a cave with seven chests'),
'Spiral Cave': (0xE9BF, False, 'in spiral cave'), 'Spiral Cave': (0xE9BF, False, 'in spiral cave'),
'Ether Tablet': (0x180016, False, 'at a monument'), 'Ether Tablet': (0x180016, False, 'at a monolith'),
'Spectacle Rock': (0x180140, False, 'atop a rock'), 'Spectacle Rock': (0x180140, False, 'atop a rock'),
'Tower of Hera - Basement Cage': (0x180162, False, 'in Tower of Hera'), 'Tower of Hera - Basement Cage': (0x180162, False, 'in Tower of Hera'),
'Tower of Hera - Map Chest': (0xE9AD, False, 'in Tower of Hera'), 'Tower of Hera - Map Chest': (0xE9AD, False, 'in Tower of Hera'),
'Tower of Hera - Big Key Chest': (0xE9E6, False, 'in Tower of Hera'), 'Tower of Hera - Big Key Chest': (0xE9E6, False, 'in Tower of Hera'),
'Tower of Hera - Compass Chest': (0xE9FB, False, 'in Tower of Hera'), 'Tower of Hera - Compass Chest': (0xE9FB, False, 'in Tower of Hera'),
'Tower of Hera - Big Chest': (0xE9F8, False, 'in Tower of Hera'), 'Tower of Hera - Big Chest': (0xE9F8, False, 'in Tower of Hera'),
'Tower of Hera - Moldorm': (0x180152, False, 'with Moldorm'), 'Tower of Hera - Boss': (0x180152, False, 'with Moldorm'),
'Pyramid': (0x180147, False, 'on the pyramid'), 'Pyramid': (0x180147, False, 'on the pyramid'),
'Catfish': (0xEE185, False, 'with a fish'), 'Catfish': (0xEE185, False, 'with a catfish'),
'Stumpy': (0x330C7, False, 'with tree boy'), 'Stumpy': (0x330C7, False, 'with tree boy'),
'Digging Game': (0x180148, False, 'underground'), 'Digging Game': (0x180148, False, 'underground'),
'Bombos Tablet': (0x180017, False, 'at a monument'), 'Bombos Tablet': (0x180017, False, 'at a monolith'),
'Hype Cave - Top': (0xEB1E, False, 'near batman'), 'Hype Cave - Top': (0xEB1E, False, 'near a bat-like man'),
'Hype Cave - Middle Right': (0xEB21, False, 'near batman'), 'Hype Cave - Middle Right': (0xEB21, False, 'near a bat-like man'),
'Hype Cave - Middle Left': (0xEB24, False, 'near batman'), 'Hype Cave - Middle Left': (0xEB24, False, 'near a bat-like man'),
'Hype Cave - Bottom': (0xEB27, False, 'near batman'), 'Hype Cave - Bottom': (0xEB27, False, 'near a bat-like man'),
'Hype Cave - Generous Guy': (0x180011, False, 'with batman'), 'Hype Cave - Generous Guy': (0x180011, False, 'with a bat-like man'),
'Peg Cave': (0x180006, False, 'alone in a cave'), 'Peg Cave': (0x180006, False, 'alone in a cave'),
'Pyramid Fairy - Left': (0xE980, False, 'near a fairy'), 'Pyramid Fairy - Left': (0xE980, False, 'near a fairy'),
'Pyramid Fairy - Right': (0xE983, False, 'near a fairy'), 'Pyramid Fairy - Right': (0xE983, False, 'near a fairy'),
@ -499,8 +507,8 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'C-Shaped House': (0xE9EF, False, 'alone in a home'), 'C-Shaped House': (0xE9EF, False, 'alone in a home'),
'Chest Game': (0xEDA8, False, 'as a prize'), 'Chest Game': (0xEDA8, False, 'as a prize'),
'Bumper Cave Ledge': (0x180146, False, 'on a ledge'), 'Bumper Cave Ledge': (0x180146, False, 'on a ledge'),
'Mire Shed - Left': (0xEA73, False, 'near a spark'), 'Mire Shed - Left': (0xEA73, False, 'near sparks'),
'Mire Shed - Right': (0xEA76, False, 'near a spark'), 'Mire Shed - Right': (0xEA76, False, 'near sparks'),
'Superbunny Cave - Top': (0xEA7C, False, 'in a connection'), 'Superbunny Cave - Top': (0xEA7C, False, 'in a connection'),
'Superbunny Cave - Bottom': (0xEA7F, False, 'in a connection'), 'Superbunny Cave - Bottom': (0xEA7F, False, 'in a connection'),
'Spike Cave': (0xEA8B, False, 'beyond spikes'), 'Spike Cave': (0xEA8B, False, 'beyond spikes'),
@ -509,7 +517,7 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Hookshot Cave - Bottom Right': (0xEB5A, False, 'across pits'), 'Hookshot Cave - Bottom Right': (0xEB5A, False, 'across pits'),
'Hookshot Cave - Bottom Left': (0xEB57, False, 'across pits'), 'Hookshot Cave - Bottom Left': (0xEB57, False, 'across pits'),
'Floating Island': (0x180141, False, 'on an island'), 'Floating Island': (0x180141, False, 'on an island'),
'Mimic Cave': (0xE9C5, False, 'beyond Goriyas'), 'Mimic Cave': (0xE9C5, False, 'in a cave of mimicry'),
'Swamp Palace - Entrance': (0xEA9D, False, 'in Swamp Palace'), 'Swamp Palace - Entrance': (0xEA9D, False, 'in Swamp Palace'),
'Swamp Palace - Map Chest': (0xE986, False, 'in Swamp Palace'), 'Swamp Palace - Map Chest': (0xE986, False, 'in Swamp Palace'),
'Swamp Palace - Big Chest': (0xE989, False, 'in Swamp Palace'), 'Swamp Palace - Big Chest': (0xE989, False, 'in Swamp Palace'),
@ -519,7 +527,7 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Swamp Palace - Flooded Room - Left': (0xEAA9, False, 'in Swamp Palace'), 'Swamp Palace - Flooded Room - Left': (0xEAA9, False, 'in Swamp Palace'),
'Swamp Palace - Flooded Room - Right': (0xEAAC, False, 'in Swamp Palace'), 'Swamp Palace - Flooded Room - Right': (0xEAAC, False, 'in Swamp Palace'),
'Swamp Palace - Waterfall Room': (0xEAAF, False, 'in Swamp Palace'), 'Swamp Palace - Waterfall Room': (0xEAAF, False, 'in Swamp Palace'),
'Swamp Palace - Arrghus': (0x180154, False, 'with Arrghus'), 'Swamp Palace - Boss': (0x180154, False, 'with Arrghus'),
'Thieves\' Town - Big Key Chest': (0xEA04, False, 'in Thieves\' Town'), 'Thieves\' Town - Big Key Chest': (0xEA04, False, 'in Thieves\' Town'),
'Thieves\' Town - Map Chest': (0xEA01, False, 'in Thieves\' Town'), 'Thieves\' Town - Map Chest': (0xEA01, False, 'in Thieves\' Town'),
'Thieves\' Town - Compass Chest': (0xEA07, False, 'in Thieves\' Town'), 'Thieves\' Town - Compass Chest': (0xEA07, False, 'in Thieves\' Town'),
@ -527,7 +535,7 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Thieves\' Town - Attic': (0xEA0D, False, 'in Thieves\' Town'), 'Thieves\' Town - Attic': (0xEA0D, False, 'in Thieves\' Town'),
'Thieves\' Town - Big Chest': (0xEA10, False, 'in Thieves\' Town'), 'Thieves\' Town - Big Chest': (0xEA10, False, 'in Thieves\' Town'),
'Thieves\' Town - Blind\'s Cell': (0xEA13, False, 'in Thieves\' Town'), 'Thieves\' Town - Blind\'s Cell': (0xEA13, False, 'in Thieves\' Town'),
'Thieves Town - Blind': (0x180156, False, 'with Blind'), 'Thieves\' Town - Boss': (0x180156, False, 'with Blind'),
'Skull Woods - Compass Chest': (0xE992, False, 'in Skull Woods'), 'Skull Woods - Compass Chest': (0xE992, False, 'in Skull Woods'),
'Skull Woods - Map Chest': (0xE99B, False, 'in Skull Woods'), 'Skull Woods - Map Chest': (0xE99B, False, 'in Skull Woods'),
'Skull Woods - Big Chest': (0xE998, False, 'in Skull Woods'), 'Skull Woods - Big Chest': (0xE998, False, 'in Skull Woods'),
@ -535,7 +543,7 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Skull Woods - Pinball Room': (0xE9C8, False, 'in Skull Woods'), 'Skull Woods - Pinball Room': (0xE9C8, False, 'in Skull Woods'),
'Skull Woods - Big Key Chest': (0xE99E, False, 'in Skull Woods'), 'Skull Woods - Big Key Chest': (0xE99E, False, 'in Skull Woods'),
'Skull Woods - Bridge Room': (0xE9FE, False, 'near Mothula'), 'Skull Woods - Bridge Room': (0xE9FE, False, 'near Mothula'),
'Skull Woods - Mothula': (0x180155, False, 'with Mothula'), 'Skull Woods - Boss': (0x180155, False, 'with Mothula'),
'Ice Palace - Compass Chest': (0xE9D4, False, 'in Ice Palace'), 'Ice Palace - Compass Chest': (0xE9D4, False, 'in Ice Palace'),
'Ice Palace - Freezor Chest': (0xE995, False, 'in Ice Palace'), 'Ice Palace - Freezor Chest': (0xE995, False, 'in Ice Palace'),
'Ice Palace - Big Chest': (0xE9AA, False, 'in Ice Palace'), 'Ice Palace - Big Chest': (0xE9AA, False, 'in Ice Palace'),
@ -543,7 +551,7 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Ice Palace - Spike Room': (0xE9E0, False, 'in Ice Palace'), 'Ice Palace - Spike Room': (0xE9E0, False, 'in Ice Palace'),
'Ice Palace - Big Key Chest': (0xE9A4, False, 'in Ice Palace'), 'Ice Palace - Big Key Chest': (0xE9A4, False, 'in Ice Palace'),
'Ice Palace - Map Chest': (0xE9DD, False, 'in Ice Palace'), 'Ice Palace - Map Chest': (0xE9DD, False, 'in Ice Palace'),
'Ice Palace - Kholdstare': (0x180157, False, 'with Kholdstare'), 'Ice Palace - Boss': (0x180157, False, 'with Kholdstare'),
'Misery Mire - Big Chest': (0xEA67, False, 'in Misery Mire'), 'Misery Mire - Big Chest': (0xEA67, False, 'in Misery Mire'),
'Misery Mire - Map Chest': (0xEA6A, False, 'in Misery Mire'), 'Misery Mire - Map Chest': (0xEA6A, False, 'in Misery Mire'),
'Misery Mire - Main Lobby': (0xEA5E, False, 'in Misery Mire'), 'Misery Mire - Main Lobby': (0xEA5E, False, 'in Misery Mire'),
@ -551,7 +559,7 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Misery Mire - Spike Chest': (0xE9DA, False, 'in Misery Mire'), 'Misery Mire - Spike Chest': (0xE9DA, False, 'in Misery Mire'),
'Misery Mire - Compass Chest': (0xEA64, False, 'in Misery Mire'), 'Misery Mire - Compass Chest': (0xEA64, False, 'in Misery Mire'),
'Misery Mire - Big Key Chest': (0xEA6D, False, 'in Misery Mire'), 'Misery Mire - Big Key Chest': (0xEA6D, False, 'in Misery Mire'),
'Misery Mire - Vitreous': (0x180158, False, 'with Vitreous'), 'Misery Mire - Boss': (0x180158, False, 'with Vitreous'),
'Turtle Rock - Compass Chest': (0xEA22, False, 'in Turtle Rock'), 'Turtle Rock - Compass Chest': (0xEA22, False, 'in Turtle Rock'),
'Turtle Rock - Roller Room - Left': (0xEA1C, False, 'in Turtle Rock'), 'Turtle Rock - Roller Room - Left': (0xEA1C, False, 'in Turtle Rock'),
'Turtle Rock - Roller Room - Right': (0xEA1F, False, 'in Turtle Rock'), 'Turtle Rock - Roller Room - Right': (0xEA1F, False, 'in Turtle Rock'),
@ -563,7 +571,7 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Turtle Rock - Eye Bridge - Bottom Right': (0xEA2E, False, 'in Turtle Rock'), 'Turtle Rock - Eye Bridge - Bottom Right': (0xEA2E, False, 'in Turtle Rock'),
'Turtle Rock - Eye Bridge - Top Left': (0xEA2B, False, 'in Turtle Rock'), 'Turtle Rock - Eye Bridge - Top Left': (0xEA2B, False, 'in Turtle Rock'),
'Turtle Rock - Eye Bridge - Top Right': (0xEA28, False, 'in Turtle Rock'), 'Turtle Rock - Eye Bridge - Top Right': (0xEA28, False, 'in Turtle Rock'),
'Turtle Rock - Trinexx': (0x180159, False, 'with Trinexx'), 'Turtle Rock - Boss': (0x180159, False, 'with Trinexx'),
'Palace of Darkness - Shooter Room': (0xEA5B, False, 'in Palace of Darkness'), 'Palace of Darkness - Shooter Room': (0xEA5B, False, 'in Palace of Darkness'),
'Palace of Darkness - The Arena - Bridge': (0xEA3D, False, 'in Palace of Darkness'), 'Palace of Darkness - The Arena - Bridge': (0xEA3D, False, 'in Palace of Darkness'),
'Palace of Darkness - Stalfos Basement': (0xEA49, False, 'in Palace of Darkness'), 'Palace of Darkness - Stalfos Basement': (0xEA49, False, 'in Palace of Darkness'),
@ -577,37 +585,37 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Palace of Darkness - Dark Maze - Bottom': (0xEA58, False, 'in Palace of Darkness'), 'Palace of Darkness - Dark Maze - Bottom': (0xEA58, False, 'in Palace of Darkness'),
'Palace of Darkness - Big Chest': (0xEA40, False, 'in Palace of Darkness'), 'Palace of Darkness - Big Chest': (0xEA40, False, 'in Palace of Darkness'),
'Palace of Darkness - Harmless Hellway': (0xEA46, False, 'in Palace of Darkness'), 'Palace of Darkness - Harmless Hellway': (0xEA46, False, 'in Palace of Darkness'),
'Palace of Darkness - Helmasaur': (0x180153, False, 'with Helmasaur King'), 'Palace of Darkness - Boss': (0x180153, False, 'with Helmasaur King'),
'Ganons Tower - Bob\'s Torch': (0x180161, False, 'on my torch'), 'Ganons Tower - Bob\'s Torch': (0x180161, False, 'in Ganon\'s Tower'),
'Ganons Tower - Hope Room - Left': (0xEAD9, False, 'in My Tower'), 'Ganons Tower - Hope Room - Left': (0xEAD9, False, 'in Ganon\'s Tower'),
'Ganons Tower - Hope Room - Right': (0xEADC, False, 'in My Tower'), 'Ganons Tower - Hope Room - Right': (0xEADC, False, 'in Ganon\'s Tower'),
'Ganons Tower - Tile Room': (0xEAE2, False, 'with my tiles'), 'Ganons Tower - Tile Room': (0xEAE2, False, 'in Ganon\'s Tower'),
'Ganons Tower - Compass Room - Top Left': (0xEAE5, False, 'in My Tower'), 'Ganons Tower - Compass Room - Top Left': (0xEAE5, False, 'in Ganon\'s Tower'),
'Ganons Tower - Compass Room - Top Right': (0xEAE8, False, 'in My Tower'), 'Ganons Tower - Compass Room - Top Right': (0xEAE8, False, 'in Ganon\'s Tower'),
'Ganons Tower - Compass Room - Bottom Left': (0xEAEB, False, 'in My Tower'), 'Ganons Tower - Compass Room - Bottom Left': (0xEAEB, False, 'in Ganon\'s Tower'),
'Ganons Tower - Compass Room - Bottom Right': (0xEAEE, False, 'in My Tower'), 'Ganons Tower - Compass Room - Bottom Right': (0xEAEE, False, 'in Ganon\'s Tower'),
'Ganons Tower - DMs Room - Top Left': (0xEAB8, False, 'in My Tower'), 'Ganons Tower - DMs Room - Top Left': (0xEAB8, False, 'in Ganon\'s Tower'),
'Ganons Tower - DMs Room - Top Right': (0xEABB, False, 'in My Tower'), 'Ganons Tower - DMs Room - Top Right': (0xEABB, False, 'in Ganon\'s Tower'),
'Ganons Tower - DMs Room - Bottom Left': (0xEABE, False, 'in My Tower'), 'Ganons Tower - DMs Room - Bottom Left': (0xEABE, False, 'in Ganon\'s Tower'),
'Ganons Tower - DMs Room - Bottom Right': (0xEAC1, False, 'in My Tower'), 'Ganons Tower - DMs Room - Bottom Right': (0xEAC1, False, 'in Ganon\'s Tower'),
'Ganons Tower - Map Chest': (0xEAD3, False, 'in My Tower'), 'Ganons Tower - Map Chest': (0xEAD3, False, 'in Ganon\'s Tower'),
'Ganons Tower - Firesnake Room': (0xEAD0, False, 'in My Tower'), 'Ganons Tower - Firesnake Room': (0xEAD0, False, 'in Ganon\'s Tower'),
'Ganons Tower - Randomizer Room - Top Left': (0xEAC4, False, 'in My Tower'), 'Ganons Tower - Randomizer Room - Top Left': (0xEAC4, False, 'in Ganon\'s Tower'),
'Ganons Tower - Randomizer Room - Top Right': (0xEAC7, False, 'in My Tower'), 'Ganons Tower - Randomizer Room - Top Right': (0xEAC7, False, 'in Ganon\'s Tower'),
'Ganons Tower - Randomizer Room - Bottom Left': (0xEACA, False, 'in My Tower'), 'Ganons Tower - Randomizer Room - Bottom Left': (0xEACA, False, 'in Ganon\'s Tower'),
'Ganons Tower - Randomizer Room - Bottom Right': (0xEACD, False, 'in My Tower'), 'Ganons Tower - Randomizer Room - Bottom Right': (0xEACD, False, 'in Ganon\'s Tower'),
'Ganons Tower - Bob\'s Chest': (0xEADF, False, 'in My Tower'), 'Ganons Tower - Bob\'s Chest': (0xEADF, False, 'in Ganon\'s Tower'),
'Ganons Tower - Big Chest': (0xEAD6, False, 'in my big chest'), 'Ganons Tower - Big Chest': (0xEAD6, False, 'in Ganon\'s Tower'),
'Ganons Tower - Big Key Room - Left': (0xEAF4, False, 'beyond my Armos'), 'Ganons Tower - Big Key Room - Left': (0xEAF4, False, 'in Ganon\'s Tower'),
'Ganons Tower - Big Key Room - Right': (0xEAF7, False, 'beyond my Armos'), 'Ganons Tower - Big Key Room - Right': (0xEAF7, False, 'in Ganon\'s Tower'),
'Ganons Tower - Big Key Chest': (0xEAF1, False, 'beyond my Armos'), 'Ganons Tower - Big Key Chest': (0xEAF1, False, 'in Ganon\'s Tower'),
'Ganons Tower - Mini Helmasaur Room - Left': (0xEAFD, False, 'atop My Tower'), 'Ganons Tower - Mini Helmasaur Room - Left': (0xEAFD, False, 'atop Ganon\'s Tower'),
'Ganons Tower - Mini Helmasaur Room - Right': (0xEB00, False, 'atop My Tower'), 'Ganons Tower - Mini Helmasaur Room - Right': (0xEB00, False, 'atop Ganon\'s Tower'),
'Ganons Tower - Pre-Moldorm Chest': (0xEB03, False, 'atop My Tower'), 'Ganons Tower - Pre-Moldorm Chest': (0xEB03, False, 'atop Ganon\'s Tower'),
'Ganons Tower - Validation Chest': (0xEB06, False, 'atop My Tower'), 'Ganons Tower - Validation Chest': (0xEB06, False, 'atop Ganon\'s Tower'),
'Ganon': (None, False, 'from me'), 'Ganon': (None, False, 'from me'),
'Agahnim 1': (None, False, 'from my wizardry form'), 'Agahnim 1': (None, False, 'from Ganon\'s wizardry form'),
'Agahnim 2': (None, False, 'from my wizardry form'), 'Agahnim 2': (None, False, 'from Ganon\'s wizardry form'),
'Floodgate': (None, False, None), 'Floodgate': (None, False, None),
'Frog': (None, False, None), 'Frog': (None, False, None),
'Missing Smith': (None, False, None), 'Missing Smith': (None, False, None),
@ -617,7 +625,7 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Tower of Hera - Prize': ([0x120A5, 0x53F0A, 0x53F0B, 0x18005A, 0x18007A, 0xC706], True, 'Tower of Hera'), 'Tower of Hera - Prize': ([0x120A5, 0x53F0A, 0x53F0B, 0x18005A, 0x18007A, 0xC706], True, 'Tower of Hera'),
'Palace of Darkness - Prize': ([0x120A1, 0x53F00, 0x53F01, 0x180056, 0x18007D, 0xC702], True, 'Palace of Darkness'), 'Palace of Darkness - Prize': ([0x120A1, 0x53F00, 0x53F01, 0x180056, 0x18007D, 0xC702], True, 'Palace of Darkness'),
'Swamp Palace - Prize': ([0x120A0, 0x53F6C, 0x53F6D, 0x180055, 0x180071, 0xC701], True, 'Swamp Palace'), 'Swamp Palace - Prize': ([0x120A0, 0x53F6C, 0x53F6D, 0x180055, 0x180071, 0xC701], True, 'Swamp Palace'),
'Thieves Town - Prize': ([0x120A6, 0x53F36, 0x53F37, 0x18005B, 0x180077, 0xC707], True, 'Thieves\' Town'), 'Thieves\' Town - Prize': ([0x120A6, 0x53F36, 0x53F37, 0x18005B, 0x180077, 0xC707], True, 'Thieves\' Town'),
'Skull Woods - Prize': ([0x120A3, 0x53F12, 0x53F13, 0x180058, 0x18007B, 0xC704], True, 'Skull Woods'), 'Skull Woods - Prize': ([0x120A3, 0x53F12, 0x53F13, 0x180058, 0x18007B, 0xC704], True, 'Skull Woods'),
'Ice Palace - Prize': ([0x120A4, 0x53F5A, 0x53F5B, 0x180059, 0x180073, 0xC705], True, 'Ice Palace'), 'Ice Palace - Prize': ([0x120A4, 0x53F5A, 0x53F5B, 0x180059, 0x180073, 0xC705], True, 'Ice Palace'),
'Misery Mire - Prize': ([0x120A2, 0x53F48, 0x53F49, 0x180057, 0x180075, 0xC703], True, 'Misery Mire'), 'Misery Mire - Prize': ([0x120A2, 0x53F48, 0x53F49, 0x180057, 0x180075, 0xC703], True, 'Misery Mire'),

608
Rom.py
View File

@ -8,15 +8,15 @@ import random
from BaseClasses import ShopType from BaseClasses import ShopType
from Dungeons import dungeon_music_addresses from Dungeons import dungeon_music_addresses
from Text import MultiByteTextMapper, text_addresses, Credits from Text import MultiByteTextMapper, text_addresses, Credits, TextTable
from Text import Uncle_texts, Ganon1_texts, PyramidFairy_texts, TavernMan_texts, Sahasrahla2_texts, Triforce_texts, Blind_texts, BombShop2_texts from Text import Uncle_texts, Ganon1_texts, TavernMan_texts, Sahasrahla2_texts, Triforce_texts, Blind_texts, BombShop2_texts, junk_texts
from Text import KingsReturn_texts, Sanctuary_texts, Kakariko_texts, Blacksmiths_texts, DeathMountain_texts, LostWoods_texts, WishingWell_texts, DesertPalace_texts, MountainTower_texts, LinksHouse_texts, Lumberjacks_texts, SickKid_texts, FluteBoy_texts, Zora_texts, MagicShop_texts, Sahasrahla_names from Text import KingsReturn_texts, Sanctuary_texts, Kakariko_texts, Blacksmiths_texts, DeathMountain_texts, LostWoods_texts, WishingWell_texts, DesertPalace_texts, MountainTower_texts, LinksHouse_texts, Lumberjacks_texts, SickKid_texts, FluteBoy_texts, Zora_texts, MagicShop_texts, Sahasrahla_names
from Utils import local_path, int16_as_bytes, int32_as_bytes from Utils import local_path, int16_as_bytes, int32_as_bytes
from Items import ItemFactory from Items import ItemFactory
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '354bad0d01b6284c89f05c9b414d48c1' RANDOMIZERBASEHASH = 'cb560220b7b1b8202e92381aee19cd36'
class JsonRom(object): class JsonRom(object):
@ -28,18 +28,26 @@ class JsonRom(object):
self.patches[str(address)] = [value] self.patches[str(address)] = [value]
def write_bytes(self, startaddress, values): def write_bytes(self, startaddress, values):
if not values:
return
self.patches[str(startaddress)] = list(values) self.patches[str(startaddress)] = list(values)
def write_int16_to_rom(self, address, value): def write_int16(self, address, value):
self.write_bytes(address, int16_as_bytes(value)) self.write_bytes(address, int16_as_bytes(value))
def write_int32_to_rom(self, address, value): def write_int32(self, address, value):
self.write_bytes(address, int32_as_bytes(value)) self.write_bytes(address, int32_as_bytes(value))
def write_to_file(self, file): def write_to_file(self, file):
with open(file, 'w') as stream: with open(file, 'w') as stream:
json.dump([self.patches], stream) json.dump([self.patches], stream)
def get_hash(self):
h = hashlib.md5()
h.update(json.dumps([self.patches]).encode('utf-8'))
return h.hexdigest()
class LocalRom(object): class LocalRom(object):
@ -56,10 +64,10 @@ class LocalRom(object):
for i, value in enumerate(values): for i, value in enumerate(values):
self.write_byte(startaddress + i, value) self.write_byte(startaddress + i, value)
def write_int16_to_rom(self, address, value): def write_int16(self, address, value):
self.write_bytes(address, int16_as_bytes(value)) self.write_bytes(address, int16_as_bytes(value))
def write_int32_to_rom(self, address, value): def write_int32(self, address, value):
self.write_bytes(address, int32_as_bytes(value)) self.write_bytes(address, int32_as_bytes(value))
def write_to_file(self, file): def write_to_file(self, file):
@ -95,6 +103,11 @@ 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 get_hash(self):
h = hashlib.md5()
h.update(self.buffer)
return h.hexdigest()
def read_rom(stream): def read_rom(stream):
"Reads rom into bytearray and strips off any smc header" "Reads rom into bytearray and strips off any smc header"
buffer = bytearray(stream.read()) buffer = bytearray(stream.read())
@ -307,9 +320,9 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
rom.write_byte(0x15B8C + offset, ow_area) rom.write_byte(0x15B8C + offset, ow_area)
rom.write_int16_to_rom(0x15BDB + 2 * offset, vram_loc) rom.write_int16(0x15BDB + 2 * offset, vram_loc)
rom.write_int16_to_rom(0x15C79 + 2 * offset, scroll_y) rom.write_int16(0x15C79 + 2 * offset, scroll_y)
rom.write_int16_to_rom(0x15D17 + 2 * offset, scroll_x) rom.write_int16(0x15D17 + 2 * offset, scroll_x)
# for positioning fixups we abuse the roomid as a way of identifying which exit data we are appling # 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 # Thanks to Zarby89 for originally finding these values
@ -320,25 +333,25 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
'Palace of Darkness Exit', 'Swamp Palace Exit', 'Ganons Tower Exit', 'Desert Palace Exit (North)', 'Agahnims Tower Exit', 'Spiral Cave Exit (Top)', '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)']: 'Superbunny Cave Exit (Bottom)', 'Turtle Rock Ledge Exit (East)']:
# For exits that connot be reached from another, no need to apply offset fixes. # 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 rom.write_int16(0x15DB5 + 2 * offset, link_y) # same as final else
elif room_id == 0x0059 and world.fix_skullwoods_exit: elif room_id == 0x0059 and world.fix_skullwoods_exit:
rom.write_int16_to_rom(0x15DB5 + 2 * offset, 0x00F8) rom.write_int16(0x15DB5 + 2 * offset, 0x00F8)
elif room_id == 0x004a and world.fix_palaceofdarkness_exit: elif room_id == 0x004a and world.fix_palaceofdarkness_exit:
rom.write_int16_to_rom(0x15DB5 + 2 * offset, 0x0640) rom.write_int16(0x15DB5 + 2 * offset, 0x0640)
elif room_id == 0x00d6 and world.fix_trock_exit: elif room_id == 0x00d6 and world.fix_trock_exit:
rom.write_int16_to_rom(0x15DB5 + 2 * offset, 0x0134) rom.write_int16(0x15DB5 + 2 * offset, 0x0134)
elif room_id == 0x000c and world.fix_gtower_exit: # fix ganons tower exit point elif room_id == 0x000c and world.fix_gtower_exit: # fix ganons tower exit point
rom.write_int16_to_rom(0x15DB5 + 2 * offset, 0x00A4) rom.write_int16(0x15DB5 + 2 * offset, 0x00A4)
else: else:
rom.write_int16_to_rom(0x15DB5 + 2 * offset, link_y) rom.write_int16(0x15DB5 + 2 * offset, link_y)
rom.write_int16_to_rom(0x15E53 + 2 * offset, link_x) rom.write_int16(0x15E53 + 2 * offset, link_x)
rom.write_int16_to_rom(0x15EF1 + 2 * offset, camera_y) rom.write_int16(0x15EF1 + 2 * offset, camera_y)
rom.write_int16_to_rom(0x15F8F + 2 * offset, camera_x) rom.write_int16(0x15F8F + 2 * offset, camera_x)
rom.write_byte(0x1602D + offset, unknown_1) rom.write_byte(0x1602D + offset, unknown_1)
rom.write_byte(0x1607C + offset, unknown_2) rom.write_byte(0x1607C + offset, unknown_2)
rom.write_int16_to_rom(0x160CB + 2 * offset, door_1) rom.write_int16(0x160CB + 2 * offset, door_1)
rom.write_int16_to_rom(0x16169 + 2 * offset, door_2) rom.write_int16(0x16169 + 2 * offset, door_2)
elif isinstance(exit.addresses, list): elif isinstance(exit.addresses, list):
# is hole # is hole
for address in exit.addresses: for address in exit.addresses:
@ -415,29 +428,11 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
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, world.rupoor_cost) rom.write_int16(0x180036, world.rupoor_cost)
# Set stun items # Set stun items
rom.write_byte(0x180180, 0x02) # Hookshot only rom.write_byte(0x180180, 0x02) # Hookshot only
# Make silver arrows only usable against Ganon # Make silver arrows only usable against Ganon
rom.write_byte(0x180181, 0x01) rom.write_byte(0x180181, 0x01)
#Make Blue Shield more expensive
rom.write_bytes(0xF73D2, [0xFC, 0xFF])
rom.write_bytes(0xF73DA, [0x04, 0x00])
rom.write_bytes(0xF73E2, [0x0C, 0x00])
rom.write_byte(0xF73D6, 0x31)
rom.write_byte(0xF73DE, 0x30)
rom.write_byte(0xF73E6, 0x30)
rom.write_byte(0xF7201, 0x00)
rom.write_byte(0xF71FF, 0x64)
#Make Red Shield more expensive
rom.write_bytes(0xF73FA, [0xFC, 0xFF])
rom.write_bytes(0xF7402, [0x04, 0x00])
rom.write_bytes(0xF740A, [0x0C, 0x00])
rom.write_byte(0xF73FE, 0x33)
rom.write_byte(0xF7406, 0x33)
rom.write_byte(0xF740E, 0x33)
rom.write_byte(0xF7241, 0x03)
rom.write_byte(0xF723F, 0xE7)
elif world.difficulty == 'expert': elif world.difficulty == 'expert':
# Powdered Fairies Prize # Powdered Fairies Prize
rom.write_byte(0x36DD0, 0xD8) # One Heart rom.write_byte(0x36DD0, 0xD8) # One Heart
@ -453,29 +448,11 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
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, world.rupoor_cost) rom.write_int16(0x180036, world.rupoor_cost)
# Set stun items # Set stun items
rom.write_byte(0x180180, 0x00) # Nothing rom.write_byte(0x180180, 0x00) # Nothing
# Make silver arrows only usable against Ganon # Make silver arrows only usable against Ganon
rom.write_byte(0x180181, 0x01) rom.write_byte(0x180181, 0x01)
#Make Blue Shield more expensive
rom.write_bytes(0xF73D2, [0xFC, 0xFF])
rom.write_bytes(0xF73DA, [0x04, 0x00])
rom.write_bytes(0xF73E2, [0x0C, 0x00])
rom.write_byte(0xF73D6, 0x3C)
rom.write_byte(0xF73DE, 0x3C)
rom.write_byte(0xF73E6, 0x3C)
rom.write_byte(0xF7201, 0x27)
rom.write_byte(0xF71FF, 0x06)
#Make Red Shield more expensive
rom.write_bytes(0xF73FA, [0xFC, 0xFF])
rom.write_bytes(0xF7402, [0x04, 0x00])
rom.write_bytes(0xF740A, [0x0C, 0x00])
rom.write_byte(0xF73FE, 0x3C)
rom.write_byte(0xF7406, 0x3C)
rom.write_byte(0xF740E, 0x3C)
rom.write_byte(0xF7241, 0x27)
rom.write_byte(0xF723F, 0x06)
elif world.difficulty == 'insane': elif world.difficulty == 'insane':
# Powdered Fairies Prize # Powdered Fairies Prize
rom.write_byte(0x36DD0, 0x79) # Bees rom.write_byte(0x36DD0, 0x79) # Bees
@ -491,29 +468,11 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
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, world.rupoor_cost) rom.write_int16(0x180036, world.rupoor_cost)
# Set stun items # Set stun items
rom.write_byte(0x180180, 0x00) # Nothing rom.write_byte(0x180180, 0x00) # Nothing
# Make silver arrows only usable against Ganon # Make silver arrows only usable against Ganon
rom.write_byte(0x180181, 0x01) rom.write_byte(0x180181, 0x01)
#Make Blue Shield more expensive
rom.write_bytes(0xF73D2, [0xFC, 0xFF])
rom.write_bytes(0xF73DA, [0x04, 0x00])
rom.write_bytes(0xF73E2, [0x0C, 0x00])
rom.write_byte(0xF73D6, 0x3C)
rom.write_byte(0xF73DE, 0x3C)
rom.write_byte(0xF73E6, 0x3C)
rom.write_byte(0xF7201, 0x27)
rom.write_byte(0xF71FF, 0x10)
#Make Red Shield more expensive
rom.write_bytes(0xF73FA, [0xFC, 0xFF])
rom.write_bytes(0xF7402, [0x04, 0x00])
rom.write_bytes(0xF740A, [0x0C, 0x00])
rom.write_byte(0xF73FE, 0x3C)
rom.write_byte(0xF7406, 0x3C)
rom.write_byte(0xF740E, 0x3C)
rom.write_byte(0xF7241, 0x27)
rom.write_byte(0xF723F, 0x10)
else: else:
# Powdered Fairies Prize # Powdered Fairies Prize
rom.write_byte(0x36DD0, 0xE3) # fairy rom.write_byte(0x36DD0, 0xE3) # fairy
@ -528,7 +487,7 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
#Enable catching fairies #Enable catching fairies
rom.write_byte(0x34FD6, 0xF0) rom.write_byte(0x34FD6, 0xF0)
# Rupoor negative value # Rupoor negative value
rom.write_int16_to_rom(0x180036, world.rupoor_cost) rom.write_int16(0x180036, world.rupoor_cost)
# Set stun items # Set stun items
rom.write_byte(0x180180, 0x03) # All standard items rom.write_byte(0x180180, 0x03) # All standard items
# Make silver arrows freely usable # Make silver arrows freely usable
@ -541,7 +500,7 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
if world.difficulty in ['easy']: if world.difficulty in ['easy']:
rom.write_byte(0x180182, 0x03) # auto equip silvers on pickup and at ganon rom.write_byte(0x180182, 0x03) # auto equip silvers on pickup and at ganon
elif world.retro and world.difficulty in ['hard','expert', 'insane']: #FIXME: this is temporary for v29 baserom elif world.retro and world.difficulty in ['hard', 'expert', 'insane']: #FIXME: this is temporary for v29 baserom (perhaps no so temporary?)
rom.write_byte(0x180182, 0x03) # auto equip silvers on pickup and at ganon rom.write_byte(0x180182, 0x03) # auto equip silvers on pickup and at ganon
else: else:
rom.write_byte(0x180182, 0x01) # auto equip silvers on pickup rom.write_byte(0x180182, 0x01) # auto equip silvers on pickup
@ -572,11 +531,17 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2,
0xE3, 0xE3, 0xE3, 0xE3, 0xE3] 0xE3, 0xE3, 0xE3, 0xE3, 0xE3]
if world.difficulty in ['hard', 'expert', 'insane']:
prize_replacements = {0xE0: 0xDF, # Fairy -> heart
0xE3: 0xD8} # Big magic -> small magic
prizes = [prize_replacements.get(prize, prize) for prize in prizes]
dig_prizes = [prize_replacements.get(prize, prize) for prize in dig_prizes]
if world.retro: if world.retro:
prize_replacements = {0xE1: 0xDA, #5 Arrows -> Blue Rupee prize_replacements = {0xE1: 0xDA, #5 Arrows -> Blue Rupee
0xE2: 0xDB} #10 Arrows -> Red Rupee 0xE2: 0xDB} #10 Arrows -> Red Rupee
prizes = [prize_replacements.get(prize,prize) for prize in prizes] prizes = [prize_replacements.get(prize, prize) for prize in prizes]
dig_prizes = [prize_replacements.get(prize,prize) for prize in dig_prizes] dig_prizes = [prize_replacements.get(prize, prize) for prize in dig_prizes]
rom.write_bytes(0x180100, dig_prizes) rom.write_bytes(0x180100, dig_prizes)
random.shuffle(prizes) random.shuffle(prizes)
@ -638,12 +603,16 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
# original_item, limit, replacement_item, filler # original_item, limit, replacement_item, filler
0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees 0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees
0x58, 0x01, 0x43, 0xFF, # silver arrows -> 1 arrow 0x58, 0x01, 0x43, 0xFF, # silver arrows -> 1 arrow
0x51, 0x06, 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade
0x53, 0x06, 0x54, 0xFF, # 6 +5 arrow upgrades -> +10 arrow upgrade
0xFF, 0xFF, 0xFF, 0xFF, # end of table sentinel 0xFF, 0xFF, 0xFF, 0xFF, # end of table sentinel
]) ])
else: else:
rom.write_bytes(0x184000, [ rom.write_bytes(0x184000, [
# original_item, limit, replacement_item, filler # original_item, limit, replacement_item, filler
0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees 0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees
0x51, 0x06, 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade
0x53, 0x06, 0x54, 0xFF, # 6 +5 arrow upgrades -> +10 arrow upgrade
0xFF, 0xFF, 0xFF, 0xFF, # end of table sentinel 0xFF, 0xFF, 0xFF, 0xFF, # end of table sentinel
]) ])
@ -674,6 +643,10 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
rom.write_byte(0x348DB, 0x3A) # Red Boomerang becomes Red Boomerang rom.write_byte(0x348DB, 0x3A) # Red Boomerang becomes Red Boomerang
rom.write_byte(0x348EB, 0x05) # Blue Shield becomes Blue Shield rom.write_byte(0x348EB, 0x05) # Blue Shield becomes Blue Shield
# Remove Statues for upgrade fairy
rom.write_bytes(0x01F810, [0x1A, 0x1E, 0x01, 0x1A, 0x1E, 0x01])
rom.write_byte(0x180029, 0x01) # Smithy quick item give rom.write_byte(0x180029, 0x01) # Smithy quick item give
# set swordless mode settings # set swordless mode settings
@ -694,39 +667,39 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
ERtimeincrease = ERtimeincrease + 15 ERtimeincrease = ERtimeincrease + 15
if world.clock_mode == 'off': if world.clock_mode == 'off':
rom.write_bytes(0x180190, [0x00, 0x00, 0x00]) # turn off clock mode rom.write_bytes(0x180190, [0x00, 0x00, 0x00]) # turn off clock mode
rom.write_int32_to_rom(0x180200, 0) # red clock adjustment time (in frames, sint32) rom.write_int32(0x180200, 0) # red clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x180204, 0) # blue clock adjustment time (in frames, sint32) rom.write_int32(0x180204, 0) # blue clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x180208, 0) # green clock adjustment time (in frames, sint32) rom.write_int32(0x180208, 0) # green clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x18020C, 0) # starting time (in frames, sint32) rom.write_int32(0x18020C, 0) # starting time (in frames, sint32)
elif world.clock_mode == 'ohko': elif world.clock_mode == 'ohko':
rom.write_bytes(0x180190, [0x01, 0x02, 0x01]) # ohko timer with resetable timer functionality rom.write_bytes(0x180190, [0x01, 0x02, 0x01]) # ohko timer with resetable timer functionality
rom.write_int32_to_rom(0x180200, 0) # red clock adjustment time (in frames, sint32) rom.write_int32(0x180200, 0) # red clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x180204, 0) # blue clock adjustment time (in frames, sint32) rom.write_int32(0x180204, 0) # blue clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x180208, 0) # green clock adjustment time (in frames, sint32) rom.write_int32(0x180208, 0) # green clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x18020C, 0) # starting time (in frames, sint32) rom.write_int32(0x18020C, 0) # starting time (in frames, sint32)
elif world.clock_mode == 'countdown-ohko': elif world.clock_mode == 'countdown-ohko':
rom.write_bytes(0x180190, [0x01, 0x02, 0x01]) # ohko timer with resetable timer functionality rom.write_bytes(0x180190, [0x01, 0x02, 0x01]) # ohko timer with resetable timer functionality
rom.write_int32_to_rom(0x180200, -100 * 60 * 60 * 60) # red clock adjustment time (in frames, sint32) rom.write_int32(0x180200, -100 * 60 * 60 * 60) # red clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) rom.write_int32(0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) rom.write_int32(0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32)
if world.difficulty == 'easy': if world.difficulty == 'easy':
rom.write_int32_to_rom(0x18020C, (20 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32) rom.write_int32(0x18020C, (20 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32)
elif world.difficulty == 'normal': elif world.difficulty == 'normal':
rom.write_int32_to_rom(0x18020C, (10 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32) rom.write_int32(0x18020C, (10 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32)
else: else:
rom.write_int32_to_rom(0x18020C, int((5 + ERtimeincrease / 2) * 60 * 60)) # starting time (in frames, sint32) rom.write_int32(0x18020C, int((5 + ERtimeincrease / 2) * 60 * 60)) # starting time (in frames, sint32)
if world.clock_mode == 'stopwatch': if world.clock_mode == 'stopwatch':
rom.write_bytes(0x180190, [0x02, 0x01, 0x00]) # set stopwatch mode rom.write_bytes(0x180190, [0x02, 0x01, 0x00]) # set stopwatch mode
rom.write_int32_to_rom(0x180200, -2 * 60 * 60) # red clock adjustment time (in frames, sint32) rom.write_int32(0x180200, -2 * 60 * 60) # red clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) rom.write_int32(0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) rom.write_int32(0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x18020C, 0) # starting time (in frames, sint32) rom.write_int32(0x18020C, 0) # starting time (in frames, sint32)
if world.clock_mode == 'countdown': if world.clock_mode == 'countdown':
rom.write_bytes(0x180190, [0x01, 0x01, 0x00]) # set countdown, with no reset available rom.write_bytes(0x180190, [0x01, 0x01, 0x00]) # set countdown, with no reset available
rom.write_int32_to_rom(0x180200, -2 * 60 * 60) # red clock adjustment time (in frames, sint32) rom.write_int32(0x180200, -2 * 60 * 60) # red clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) rom.write_int32(0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) rom.write_int32(0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32)
rom.write_int32_to_rom(0x18020C, (40 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32) rom.write_int32(0x18020C, (40 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32)
# set up goals for treasure hunt # set up goals for treasure hunt
rom.write_bytes(0x180165, [0x0E, 0x28] if world.treasure_hunt_icon == 'Triforce Piece' else [0x0D, 0x28]) rom.write_bytes(0x180165, [0x0E, 0x28] if world.treasure_hunt_icon == 'Triforce Piece' else [0x0D, 0x28])
@ -738,7 +711,6 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
rom.write_byte(0x180211, 0x06) #Game type, we set the Entrance and item randomization flags 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(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
@ -764,13 +736,20 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
rom.write_byte(0x18302D, 0x18) # starting current health rom.write_byte(0x18302D, 0x18) # starting current health
rom.write_byte(0x183039, 0x68) # starting abilities, bit array rom.write_byte(0x183039, 0x68) # starting abilities, bit array
rom.write_byte(0x18004A, 0x00) # Inverted mode (off) rom.write_byte(0x18004A, 0x00) # Inverted mode (off)
rom.write_byte(0x18005D, 0x00) # Hammer always breaks barrier
rom.write_byte(0x2AF79, 0xD0) # vortexes: Normal (D0=light to dark, F0=dark to light, 42 = both) 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(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(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(0x3A9A7, 0xD0) # Residual Portal: Normal (D0= Light Side, F0=Dark Side, 42 = both (Darth Vader))
rom.write_bytes(0x180080, [50, 50, 70, 70]) # values to fill for Capacity Upgrades (Bomb5, Bomb10, Arrow5, Arrow10)
rom.write_byte(0x18004D, 0x00) # Escape assist (off) rom.write_byte(0x18004D, 0x00) # Escape assist (off)
rom.write_byte(0x18004E, 0x00) # uncle Refill (off) rom.write_byte(0x18004E, 0x00) # escape fills
rom.write_int16(0x180183, 0) # rupee fill (for bow if rupee arrows enabled)
rom.write_bytes(0x180185, [0x00, 0x00, 0x00]) # uncle item refills
rom.write_bytes(0x180188, [0x00, 0x00, 0x00]) # zelda item refills
rom.write_bytes(0x18018B, [0x00, 0x00, 0x00]) # uncle item refills
if world.goal in ['pedestal', 'triforcehunt']: if world.goal in ['pedestal', 'triforcehunt']:
@ -809,6 +788,7 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
rom.write_byte(0x180020, digging_game_rng) rom.write_byte(0x180020, digging_game_rng)
rom.write_byte(0xEFD95, digging_game_rng) rom.write_byte(0xEFD95, digging_game_rng)
rom.write_byte(0x1800A3, 0x01) # enable correct world setting behaviour after agahnim kills rom.write_byte(0x1800A3, 0x01) # enable correct world setting behaviour after agahnim kills
rom.write_byte(0x1800A4, 0x01 if world.logic != 'nologic' else 0x00) # enable POD EG fix
rom.write_byte(0x180042, 0x01 if world.save_and_quit_from_boss else 0x00) # Allow Save and Quit after boss kill rom.write_byte(0x180042, 0x01 if world.save_and_quit_from_boss else 0x00) # Allow Save and Quit after boss kill
# remove shield from uncle # remove shield from uncle
@ -851,10 +831,18 @@ def patch_rom(world, rom, hashtable, beep='normal', color='red', sprite=None):
# set rom name # set rom name
# 21 bytes # 21 bytes
rom.write_bytes(0x7FC0, bytearray('ER_060_%09d\0' % world.seed, 'utf8') + world.option_identifier.to_bytes(4, 'big')) rom.write_bytes(0x7FC0, bytearray('ER_062_%09d\0' % world.seed, 'utf8') + world.option_identifier.to_bytes(4, 'big'))
# store hash table for main menu hash # Write title screen Code
rom.write_bytes(0x187F00, hashtable) hashint = int(rom.get_hash(), 16)
code = [
(hashint >> 20) & 0x1F,
(hashint >> 15) & 0x1F,
(hashint >> 10) & 0x1F,
(hashint >> 5) & 0x1F,
hashint & 0x1F,
]
rom.write_bytes(0x180215, code)
apply_rom_settings(rom, beep, color, world.quickswap, world.fastmenu, world.disable_music, sprite) apply_rom_settings(rom, beep, color, world.quickswap, world.fastmenu, world.disable_music, sprite)
@ -987,9 +975,11 @@ def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, spr
rom.write_byte(0xD3DAA, 0xFA) 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, 'double': 0x10}[beep])
# set heart color # set heart color
if color == 'random':
color = random.choice(['red', 'blue', 'green', 'yellow'])
rom.write_byte(0x6FA1E, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[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(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(0x6FA22, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
@ -1024,43 +1014,159 @@ def write_string_to_rom(rom, target, string):
def write_strings(rom, world): def write_strings(rom, world):
tt = TextTable()
tt.removeUnwantedText()
# Let's keep this guy's text accurate to the shuffle setting.
if world.shuffle in ['vanilla', 'dungeonsfull', 'dungeonssimple']:
tt['kakariko_flophouse_man_no_flippers'] = 'I really hate mowing my yard.\n{PAGEBREAK}\nI should move.'
tt['kakariko_flophouse_man'] = 'I really hate mowing my yard.\n{PAGEBREAK}\nI should move.'
# For hints, first we write hints about entrances, some from the inconvenient list others from all reasonable entrances.
if world.hints:
tt['sign_north_of_links_house'] = '> Randomizer The telepathic tiles can have hints!'
entrances_to_hint = {}
entrances_to_hint.update(InconvenientEntrances)
if world.shuffle_ganon:
entrances_to_hint.update({'Ganons Tower': 'Ganon\'s Tower'})
hint_locations = HintLocations.copy()
random.shuffle(hint_locations)
all_entrances = world.get_entrances()
random.shuffle(all_entrances)
hint_count = 4
for entrance in all_entrances:
if entrance.name in entrances_to_hint:
this_hint = entrances_to_hint[entrance.name] + ' leads to ' + entrance.connected_region.hint_text + '.'
tt[hint_locations.pop(0)] = this_hint
entrances_to_hint.pop(entrance.name)
hint_count -= 1
if hint_count < 1:
break
entrances_to_hint.update(OtherEntrances)
if world.shuffle in ['insanity', 'madness_legacy', 'insanity_legacy']:
entrances_to_hint.update(InsanityEntrances)
if world.shuffle_ganon:
entrances_to_hint.update({'Pyramid Ledge': 'The pyramid ledge'})
hint_count = 4
for entrance in all_entrances:
if entrance.name in entrances_to_hint:
this_hint = entrances_to_hint[entrance.name] + ' leads to ' + entrance.connected_region.hint_text + '.'
tt[hint_locations.pop(0)] = this_hint
entrances_to_hint.pop(entrance.name)
hint_count -= 1
if hint_count < 1:
break
# Next we write a few hints for specific inconvenient locations. We don't make many because in entrance this is highly unpredictable.
locations_to_hint = InconvenientLocations.copy()
random.shuffle(locations_to_hint)
hint_count = 3
del locations_to_hint[hint_count:]
for location in locations_to_hint:
if location == 'Swamp Left':
if random.randint(0, 1) == 0:
first_item = world.get_location('Swamp Palace - West Chest').item.hint_text
second_item = world.get_location('Swamp Palace - Big Key Chest').item.hint_text
else:
second_item = world.get_location('Swamp Palace - West Chest').item.hint_text
first_item = world.get_location('Swamp Palace - Big Key Chest').item.hint_text
this_hint = ('The westmost chests in Swamp Palace contain ' + first_item + ' and ' + second_item + '.')
tt[hint_locations.pop(0)] = this_hint
elif location == 'Mire Left':
if random.randint(0, 1) == 0:
first_item = world.get_location('Misery Mire - Compass Chest').item.hint_text
second_item = world.get_location('Misery Mire - Big Key Chest').item.hint_text
else:
second_item = world.get_location('Misery Mire - Compass Chest').item.hint_text
first_item = world.get_location('Misery Mire - Big Key Chest').item.hint_text
this_hint = ('The westmost chests in Misery Mire contain ' + first_item + ' and ' + second_item + '.')
tt[hint_locations.pop(0)] = this_hint
elif location == 'Tower of Hera - Big Key Chest':
this_hint = 'Waiting in the Tower of Hera basement leads to ' + world.get_location(location).item.hint_text + '.'
tt[hint_locations.pop(0)] = this_hint
elif location == 'Ganons Tower - Big Chest':
this_hint = 'The big chest in Ganon\'s Tower contains ' + world.get_location(location).item.hint_text + '.'
tt[hint_locations.pop(0)] = this_hint
elif location == 'Thieves\' Town - Big Chest':
this_hint = 'The big chest in Thieves\' Town contains ' + world.get_location(location).item.hint_text + '.'
tt[hint_locations.pop(0)] = this_hint
elif location == 'Ice Palace - Big Chest':
this_hint = 'The big chest in Ice Palace contains ' + world.get_location(location).item.hint_text + '.'
tt[hint_locations.pop(0)] = this_hint
elif location == 'Eastern Palace - Big Key Chest':
this_hint = 'The antifairy guarded chest in Eastern Palace contains ' + world.get_location(location).item.hint_text + '.'
tt[hint_locations.pop(0)] = this_hint
else:
this_hint = location + ' leads to ' + world.get_location(location).item.hint_text + '.'
tt[hint_locations.pop(0)] = this_hint
# Lastly we write hints to show where certain interesting items are. It is done the way it is to re-use the silver code and also to give one hint per each type of item regardless of how many exist. This supports many settings well.
items_to_hint = RelevantItems.copy()
if world.keysanity:
items_to_hint.extend(KeysanityItems)
random.shuffle(items_to_hint)
hint_count = 5
while(hint_count > 0):
this_item = items_to_hint.pop(0)
this_location = world.find_items(this_item)
random.shuffle(this_location)
if this_location:
this_hint = this_location[0].item.hint_text + ' can be found ' + this_location[0].hint_text + '.'
tt[hint_locations.pop(0)] = this_hint
hint_count -= 1
else:
continue
# All remaining hint slots are filled with junk hints. It is done this way to ensure the same junk hint isn't selected twice.
junk_hints = junk_texts.copy()
random.shuffle(junk_hints)
for location in hint_locations:
tt[location] = junk_hints.pop(0)
# We still need the older hints of course. Those are done here.
silverarrows = world.find_items('Silver Arrows') silverarrows = world.find_items('Silver Arrows')
silverarrow_hint = (' %s?' % silverarrows[0].hint_text) if silverarrows else '?\nI think not!' random.shuffle(silverarrows)
write_string_to_rom(rom, 'Ganon2', 'Did you find the silver arrows%s' % silverarrow_hint) silverarrow_hint = (' %s?' % silverarrows[0].hint_text.replace('Ganon\'s', 'my')) if silverarrows else '?\nI think not!'
tt['ganon_phase_3'] = 'Did you find the silver arrows%s' % silverarrow_hint
crystal5 = world.find_items('Crystal 5')[0] crystal5 = world.find_items('Crystal 5')[0]
crystal6 = world.find_items('Crystal 6')[0] crystal6 = world.find_items('Crystal 6')[0]
write_string_to_rom(rom, 'BombShop1', 'Big Bomb?\nMy supply is blocked until you clear %s and %s.' % (crystal5.hint_text, crystal6.hint_text)) tt['bomb_shop'] = 'Big Bomb?\nMy supply is blocked until you clear %s and %s.' % (crystal5.hint_text, crystal6.hint_text)
greenpendant = world.find_items('Green Pendant')[0] greenpendant = world.find_items('Green Pendant')[0]
write_string_to_rom(rom, 'Sahasrahla1', 'I lost my family heirloom in %s' % greenpendant.hint_text) tt['sahasrahla_bring_courage'] = 'I lost my family heirloom in %s' % greenpendant.hint_text
tt['uncle_leaving_text'] = Uncle_texts[random.randint(0, len(Uncle_texts) - 1)]
tt['end_triforce'] = "{NOBORDER}\n" + Triforce_texts[random.randint(0, len(Triforce_texts) - 1)]
tt['bomb_shop_big_bomb'] = BombShop2_texts[random.randint(0, len(BombShop2_texts) - 1)]
# this is what shows after getting the green pendant item in rando
tt['sahasrahla_quest_have_master_sword'] = Sahasrahla2_texts[random.randint(0, len(Sahasrahla2_texts) - 1)]
tt['blind_by_the_light'] = Blind_texts[random.randint(0, len(Blind_texts) - 1)]
write_string_to_rom(rom, 'Uncle', Uncle_texts[random.randint(0, len(Uncle_texts) - 1)])
write_string_to_rom(rom, 'Triforce', Triforce_texts[random.randint(0, len(Triforce_texts) - 1)])
write_string_to_rom(rom, 'BombShop2', BombShop2_texts[random.randint(0, len(BombShop2_texts) - 1)])
write_string_to_rom(rom, 'PyramidFairy', PyramidFairy_texts[random.randint(0, len(PyramidFairy_texts) - 1)])
write_string_to_rom(rom, 'Sahasrahla2', Sahasrahla2_texts[random.randint(0, len(Sahasrahla2_texts) - 1)])
write_string_to_rom(rom, 'Blind', Blind_texts[random.randint(0, len(Blind_texts) - 1)])
if world.goal in ['pedestal', 'triforcehunt']: if world.goal in ['pedestal', 'triforcehunt']:
write_string_to_rom(rom, 'Ganon1Invincible', 'Why are you even here?\n You can\'t even hurt me!') tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me!'
write_string_to_rom(rom, 'Ganon2Invincible', 'Seriously? Go Away, I will not Die.') tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.'
else: else:
write_string_to_rom(rom, 'Ganon1', Ganon1_texts[random.randint(0, len(Ganon1_texts) - 1)]) tt['ganon_fall_in'] = Ganon1_texts[random.randint(0, len(Ganon1_texts) - 1)]
write_string_to_rom(rom, 'Ganon1Invincible', 'You cannot defeat me until you finish your goal!') tt['ganon_fall_in_alt'] = 'You cannot defeat me until you finish your goal!'
write_string_to_rom(rom, 'Ganon2Invincible', 'Got wax in\nyour ears?\nI can not die!') tt['ganon_phase_3_alt'] = 'Got wax in\nyour ears?\nI can not die!'
write_string_to_rom(rom, 'TavernMan', TavernMan_texts[random.randint(0, len(TavernMan_texts) - 1)]) tt['kakariko_tavern_fisherman'] = TavernMan_texts[random.randint(0, len(TavernMan_texts) - 1)]
pedestalitem = world.get_location('Master Sword Pedestal').item pedestalitem = world.get_location('Master Sword Pedestal').item
pedestal_text = 'Some Hot Air' if pedestalitem is None else pedestalitem.pedestal_hint_text if pedestalitem.pedestal_hint_text is not None else 'Unknown Item' pedestal_text = 'Some Hot Air' if pedestalitem is None else pedestalitem.pedestal_hint_text if pedestalitem.pedestal_hint_text is not None else 'Unknown Item'
write_string_to_rom(rom, 'Pedestal', pedestal_text) tt['mastersword_pedestal_translated'] = pedestal_text
pedestal_credit_text = 'and the Hot Air' if pedestalitem is None else pedestalitem.pedestal_credit_text if pedestalitem.pedestal_credit_text is not None else 'and the Unknown Item' pedestal_credit_text = 'and the Hot Air' if pedestalitem is None else pedestalitem.pedestal_credit_text if pedestalitem.pedestal_credit_text is not None else 'and the Unknown Item'
etheritem = world.get_location('Ether Tablet').item etheritem = world.get_location('Ether Tablet').item
ether_text = 'Some Hot Air' if etheritem is None else etheritem.pedestal_hint_text if etheritem.pedestal_hint_text is not None else 'Unknown Item' ether_text = 'Some Hot Air' if etheritem is None else etheritem.pedestal_hint_text if etheritem.pedestal_hint_text is not None else 'Unknown Item'
write_string_to_rom(rom, 'EtherTablet', ether_text) tt['tablet_ether_book'] = ether_text
bombositem = world.get_location('Bombos Tablet').item bombositem = world.get_location('Bombos Tablet').item
bombos_text = 'Some Hot Air' if bombositem is None else bombositem.pedestal_hint_text if bombositem.pedestal_hint_text is not None else 'Unknown Item' bombos_text = 'Some Hot Air' if bombositem is None else bombositem.pedestal_hint_text if bombositem.pedestal_hint_text is not None else 'Unknown Item'
write_string_to_rom(rom, 'BombosTablet', bombos_text) tt['tablet_bombos_book'] = bombos_text
rom.write_bytes(0xE0000, tt.getBytes())
credits = Credits() credits = Credits()
@ -1077,7 +1183,7 @@ def write_strings(rom, world):
fluteboyitem_text = random.choice(FluteBoy_texts) if fluteboyitem is None or fluteboyitem.fluteboy_credit_text is None else fluteboyitem.fluteboy_credit_text fluteboyitem_text = random.choice(FluteBoy_texts) if fluteboyitem is None or fluteboyitem.fluteboy_credit_text is None else fluteboyitem.fluteboy_credit_text
credits.update_credits_line('castle', 0, random.choice(KingsReturn_texts)) credits.update_credits_line('castle', 0, random.choice(KingsReturn_texts))
credits.update_credits_line('sancturary', 0, random.choice(Sanctuary_texts)) credits.update_credits_line('sanctuary', 0, random.choice(Sanctuary_texts))
credits.update_credits_line('kakariko', 0, random.choice(Kakariko_texts).format(random.choice(Sahasrahla_names))) credits.update_credits_line('kakariko', 0, random.choice(Kakariko_texts).format(random.choice(Sahasrahla_names)))
credits.update_credits_line('desert', 0, random.choice(DesertPalace_texts)) credits.update_credits_line('desert', 0, random.choice(DesertPalace_texts))
@ -1097,3 +1203,245 @@ def write_strings(rom, world):
(pointers, data) = credits.get_bytes() (pointers, data) = credits.get_bytes()
rom.write_bytes(0x181500, data) rom.write_bytes(0x181500, data)
rom.write_bytes(0x76CC0, [byte for p in pointers for byte in [p & 0xFF, p >> 8 & 0xFF]]) rom.write_bytes(0x76CC0, [byte for p in pointers for byte in [p & 0xFF, p >> 8 & 0xFF]])
InconvenientEntrances = {'Turtle Rock': 'Turtle Rock Main',
'Misery Mire': 'Misery Mire',
'Ice Palace': 'Ice Palace',
'Skull Woods Final Section': 'The back of Skull Woods',
'Death Mountain Return Cave (West)': 'The SW DM foothills cave',
'Mimic Cave': 'Mimic Ledge',
'Dark World Hammer Peg Cave': 'The rows of pegs',
'Pyramid Fairy': 'The crack on the pyramid'
}
OtherEntrances = {'Eastern Palace': 'Eastern Palace',
'Elder House (East)': 'Elder House',
'Elder House (West)': 'Elder House',
'Two Brothers House (East)': 'Eastern Quarreling Brothers\' house',
'Old Man Cave (West)': 'The lower DM entrance',
'Hyrule Castle Entrance (South)': 'The ground level castle door',
'Thieves Town': 'Thieves\' Town',
'Bumper Cave (Bottom)': 'The lower Bumper Cave',
'Swamp Palace': 'Swamp Palace',
'Dark Death Mountain Ledge (West)': 'The East dark DM connector ledge',
'Dark Death Mountain Ledge (East)': 'The East dark DM connector ledge',
'Superbunny Cave (Top)': 'The summit of dark DM cave',
'Superbunny Cave (Bottom)': 'The base of east dark DM',
'Hookshot Cave': 'The rock on dark DM',
'Desert Palace Entrance (South)': 'The book sealed passage',
'Tower of Hera': 'The Tower of Hera',
'Two Brothers House (West)': 'The door near the race game',
'Old Man Cave (East)': 'The SW-most cave on west DM',
'Old Man House (Bottom)': 'A cave with a door on west DM',
'Old Man House (Top)': 'The eastmost cave on west DM',
'Death Mountain Return Cave (East)': 'The westmost cave on west DM',
'Spectacle Rock Cave Peak': 'The highest cave on west DM',
'Spectacle Rock Cave': 'The right ledge on west DM',
'Spectacle Rock Cave (Bottom)': 'The left ledge on west DM',
'Paradox Cave (Bottom)': 'The southmost cave on east DM',
'Paradox Cave (Middle)': 'The right paired cave on east DM',
'Paradox Cave (Top)': 'The east DM summit cave',
'Fairy Ascension Cave (Bottom)': 'The east DM cave behind rocks',
'Fairy Ascension Cave (Top)': 'The central ledge on east DM',
'Spiral Cave': 'The left ledge on east DM',
'Spiral Cave (Bottom)': 'The SWmost cave on east DM',
'Palace of Darkness': 'Palace of Darkness',
'Hyrule Castle Entrance (West)': 'The left castle door',
'Hyrule Castle Entrance (East)': 'The right castle door',
'Agahnims Tower': 'The sealed castle door',
'Desert Palace Entrance (West)': 'The westmost building in the desert',
'Desert Palace Entrance (North)': 'The northmost cave in the desert',
'Blinds Hideout': 'Blind\'s old house',
'Lake Hylia Fairy': 'A cave NE of Lake Hylia',
'Light Hype Fairy': 'The cave south of your house',
'Desert Fairy': 'The cave near the desert',
'Chicken House': 'The chicken lady\'s house',
'Aginahs Cave': 'The open desert cave',
'Sahasrahlas Hut': 'The house near armos',
'Cave Shop (Lake Hylia)': 'The cave NW Lake Hylia',
'Blacksmiths Hut': 'The old smithery',
'Sick Kids House': 'The central house in Kakariko',
'Lost Woods Gamble': 'A tree trunk door',
'Fortune Teller (Light)': 'A building NE of Kakariko',
'Snitch Lady (East)': 'A house guarded by a snitch',
'Snitch Lady (West)': 'A house guarded by a snitch',
'Bush Covered House': 'A house with an uncut lawn',
'Tavern (Front)': 'A building with a backdoor',
'Light World Bomb Hut': 'A Kakariko building with no door',
'Kakariko Shop': 'The old Kakariko shop',
'Mini Moldorm Cave': 'The cave south of Lake Hylia',
'Long Fairy Cave': 'The eastmost portal cave',
'Good Bee Cave': 'The open cave SE Lake Hylia',
'20 Rupee Cave': 'The rock SE Lake Hylia',
'50 Rupee Cave': 'The rock near the desert',
'Ice Rod Cave': 'The sealed cave SE Lake Hylia',
'Library': 'The old library',
'Potion Shop': 'The witch\'s building',
'Dam': 'The old dam',
'Lumberjack House': 'The lumberjack house',
'Lake Hylia Fortune Teller': 'The building NW Lake Hylia',
'Kakariko Gamble Game': 'The old Kakariko gambling den',
'Waterfall of Wishing': 'Going behind the waterfall',
'Capacity Upgrade': 'The cave on the island',
'Bonk Rock Cave': 'The rock pile near Sanctuary',
'Graveyard Cave': 'The graveyard ledge',
'Checkerboard Cave': 'The NE desert ledge',
'Cave 45': 'The ledge south of haunted grove',
'Kings Grave': 'The northeastmost grave',
'Bonk Fairy (Light)': 'The rock pile near your home',
'Hookshot Fairy': 'The left paired cave on east DM',
'Bonk Fairy (Dark)': 'The rock pile near the old bomb shop',
'Dark Sanctuary Hint': 'The dark sanctuary cave',
'Dark Lake Hylia Fairy': 'The cave NE dark Lake Hylia',
'C-Shaped House': 'The NE house in Village of Outcasts',
'Big Bomb Shop': 'The old bomb shop',
'Dark Death Mountain Fairy': 'The SW cave on dark DM',
'Dark Lake Hylia Shop': 'The building NW dark Lake Hylia',
'Dark World Shop': 'The hammer sealed building',
'Red Shield Shop': 'The fenced in building',
'Mire Shed': 'The western hut in the mire',
'East Dark World Hint': 'The dark cave near the eastmost portal',
'Dark Desert Hint': 'The cave east of the mire',
'Spike Cave': 'The ledge cave on west dark DM',
'Palace of Darkness Hint': 'The building south of Kiki',
'Dark Lake Hylia Ledge Spike Cave': 'The rock SE dark Lake Hylia',
'Cave Shop (Dark Death Mountain)': 'The base of east dark DM',
'Dark World Potion Shop': 'The building near the catfish',
'Archery Game': 'The old archery game',
'Dark World Lumberjack Shop': 'The northmost Dark World building',
'Hype Cave': 'The cave south of the old bomb shop',
'Brewery': 'The Village of Outcasts building with no door',
'Dark Lake Hylia Ledge Hint': 'The open cave SE dark Lake Hylia',
'Chest Game': 'The westmost building in the Village of Outcasts',
'Dark Desert Fairy': 'The eastern hut in the mire',
'Dark Lake Hylia Ledge Fairy': 'The sealed cave SE dark Lake Hylia',
'Fortune Teller (Dark)': 'The building NE the Village of Outcasts'
}
InsanityEntrances = {'Sanctuary': 'Sanctuary',
'Lumberjack Tree Cave': 'The cave Behind Lumberjacks',
'Lost Woods Hideout Stump': 'The stump in Lost Woods',
'North Fairy Cave': 'The cave East of Graveyard',
'Bat Cave Cave': 'The cave in eastern Kakariko',
'Kakariko Well Cave': 'The cave in northern Kakariko',
'Hyrule Castle Secret Entrance Stairs': 'The tunnel near the castle',
'Skull Woods First Section Door': 'The southeastmost skull',
'Skull Woods Second Section Door (East)': 'The central open skull',
'Skull Woods Second Section Door (West)': 'The westmost open skull',
'Desert Palace Entrance (East)': 'The eastern building in the desert',
'Turtle Rock Isolated Ledge Entrance': 'The isolated ledge on east dark DM',
'Bumper Cave (Top)': 'The upper Bumper Cave',
'Hookshot Cave Back Entrance': 'The stairs on the floating island'
}
HintLocations = ['telepathic_tile_eastern_palace',
'telepathic_tile_tower_of_hera_floor_4',
'telepathic_tile_spectacle_rock',
'telepathic_tile_swamp_entrance',
'telepathic_tile_thieves_town_upstairs',
'telepathic_tile_misery_mire',
'telepathic_tile_palace_of_darkness',
'telepathic_tile_desert_bonk_torch_room',
'telepathic_tile_castle_tower',
'telepathic_tile_ice_large_room',
'telepathic_tile_turtle_rock',
'telepathic_tile_ice_entrace',
'telepathic_tile_ice_stalfos_knights_room',
'telepathic_tile_tower_of_hera_entrance',
'telepathic_tile_south_east_darkworld_cave',
'dark_palace_tree_dude',
'dark_sanctuary_hint_0',
'dark_sanctuary_hint_1',
'dark_sanctuary_yes',
'dark_sanctuary_hint_2']
InconvenientLocations = ['Spike Cave',
'Sahasrahla',
'Purple Chest',
'Swamp Left',
'Mire Left',
'Tower of Hera - Big Key Chest',
'Eastern Palace - Big Key Chest',
'Thieves\' Town - Big Chest',
'Ice Palace - Big Chest',
'Ganons Tower - Big Chest',
'Magic Bat']
RelevantItems = ['Bow',
'Book of Mudora',
'Hammer',
'Hookshot',
'Magic Mirror',
'Ocarina',
'Pegasus Boots',
'Power Glove',
'Cape',
'Mushroom',
'Shovel',
'Lamp',
'Magic Powder',
'Moon Pearl',
'Cane of Somaria',
'Fire Rod',
'Flippers',
'Ice Rod',
'Titans Mitts',
'Ether',
'Bombos',
'Quake',
'Bottle',
'Bottle (Red Potion)',
'Bottle (Green Potion)',
'Bottle (Blue Potion)',
'Bottle (Fairy)',
'Bottle (Bee)',
'Bottle (Good Bee)',
'Master Sword',
'Tempered Sword',
'Fighter Sword',
'Golden Sword',
'Progressive Sword',
'Progressive Glove',
'Master Sword',
'Power Star',
'Triforce Piece',
'Single Arrow',
'Blue Mail',
'Red Mail',
'Progressive Armor',
'Blue Boomerang',
'Red Boomerang',
'Blue Shield',
'Red Shield',
'Mirror Shield',
'Progressive Shield',
'Bug Catching Net',
'Cane of Byrna',
'Magic Upgrade (1/2)',
'Magic Upgrade (1/4)'
]
KeysanityItems = ['Small Key (Eastern Palace)',
'Big Key (Eastern Palace)',
'Small Key (Escape)',
'Small Key (Desert Palace)',
'Big Key (Desert Palace)',
'Small Key (Tower of Hera)',
'Big Key (Tower of Hera)',
'Small Key (Agahnims Tower)',
'Small Key (Palace of Darkness)',
'Big Key (Palace of Darkness)',
'Small Key (Thieves Town)',
'Big Key (Thieves Town)',
'Small Key (Swamp Palace)',
'Big Key (Swamp Palace)',
'Small Key (Skull Woods)',
'Big Key (Skull Woods)',
'Small Key (Ice Palace)',
'Big Key (Ice Palace)',
'Small Key (Misery Mire)',
'Big Key (Misery Mire)',
'Small Key (Turtle Rock)',
'Big Key (Turtle Rock)',
'Small Key (Ganons Tower)',
'Big Key (Ganons Tower)'
]

190
Rules.py
View File

@ -49,10 +49,13 @@ def set_rules(world):
def set_rule(spot, rule): def set_rule(spot, rule):
spot.access_rule = rule spot.access_rule = rule
def set_defeat_dungeon_boss_rule(location):
# Lambda required to defer evaluation of dungeon.boss since it will change later if boos shuffle is used
set_rule(location, lambda state: location.parent_region.dungeon.boss.can_defeat(state))
def set_always_allow(spot, rule): def set_always_allow(spot, rule):
spot.always_allow = rule spot.always_allow = rule
def add_rule(spot, rule, combine='and'): def add_rule(spot, rule, combine='and'):
old_rule = spot.access_rule old_rule = spot.access_rule
if combine == 'or': if combine == 'or':
@ -138,6 +141,7 @@ def global_rules(world):
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
set_rule(world.get_entrance('Agahnim 1'), lambda state: state.has_sword() and state.has_key('Small Key (Agahnims Tower)', 2)) set_rule(world.get_entrance('Agahnim 1'), lambda state: state.has_sword() and state.has_key('Small Key (Agahnims Tower)', 2))
set_defeat_dungeon_boss_rule(world.get_location('Agahnim 1'))
set_rule(world.get_location('Castle Tower - Dark Maze'), lambda state: state.has_key('Small Key (Agahnims Tower)')) set_rule(world.get_location('Castle Tower - Dark Maze'), lambda state: state.has_key('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'))
set_rule(world.get_entrance('Old Man Cave Exit (West)'), lambda state: False) # drop cannot be climbed up set_rule(world.get_entrance('Old Man Cave Exit (West)'), lambda state: False) # drop cannot be climbed up
@ -198,7 +202,6 @@ def global_rules(world):
set_rule(world.get_entrance('Desert Palace Stairs Mirror Spot'), lambda state: state.has_Mirror()) set_rule(world.get_entrance('Desert Palace Stairs Mirror Spot'), lambda state: state.has_Mirror())
set_rule(world.get_entrance('Desert Palace Entrance (North) Mirror Spot'), lambda state: state.has_Mirror()) set_rule(world.get_entrance('Desert Palace Entrance (North) Mirror Spot'), lambda state: state.has_Mirror())
set_rule(world.get_entrance('Spectacle Rock Mirror Spot'), lambda state: state.has_Mirror()) set_rule(world.get_entrance('Spectacle Rock Mirror Spot'), lambda state: state.has_Mirror())
set_rule(world.get_entrance('Ganons Tower'), lambda state: state.has('Crystal 1') and state.has('Crystal 2') and state.has('Crystal 3') and state.has('Crystal 4') and state.has('Crystal 5') and state.has('Crystal 6') and state.has('Crystal 7'))
set_rule(world.get_entrance('Hookshot Cave'), lambda state: state.can_lift_rocks() and state.has_Pearl()) set_rule(world.get_entrance('Hookshot Cave'), lambda state: state.can_lift_rocks() and state.has_Pearl())
set_rule(world.get_entrance('East Death Mountain (Top) Mirror Spot'), lambda state: state.has_Mirror()) set_rule(world.get_entrance('East Death Mountain (Top) Mirror Spot'), lambda state: state.has_Mirror())
@ -228,22 +231,20 @@ def global_rules(world):
set_rule(world.get_entrance('Sewers Back Door'), lambda state: state.has_key('Small Key (Escape)')) set_rule(world.get_entrance('Sewers Back Door'), lambda state: state.has_key('Small Key (Escape)'))
set_rule(world.get_location('Eastern Palace - Big Chest'), lambda state: state.has('Big Key (Eastern Palace)')) set_rule(world.get_location('Eastern Palace - Big Chest'), lambda state: state.has('Big Key (Eastern Palace)'))
set_rule(world.get_location('Eastern Palace - Armos Knights'), lambda state: state.can_shoot_arrows() and state.has('Big Key (Eastern Palace)')) set_rule(world.get_location('Eastern Palace - Boss'), lambda state: state.can_shoot_arrows() and state.has('Big Key (Eastern Palace)') and world.get_location('Eastern Palace - Boss').parent_region.dungeon.boss.can_defeat(state))
set_rule(world.get_location('Eastern Palace - Prize'), lambda state: state.can_shoot_arrows() and state.has('Big Key (Eastern Palace)')) set_rule(world.get_location('Eastern Palace - Prize'), lambda state: state.can_shoot_arrows() and state.has('Big Key (Eastern Palace)') and world.get_location('Eastern Palace - Prize').parent_region.dungeon.boss.can_defeat(state))
for location in ['Eastern Palace - Armos Knights', 'Eastern Palace - Big Chest']: for location in ['Eastern Palace - Boss', 'Eastern Palace - Big Chest']:
forbid_item(world.get_location(location), 'Big Key (Eastern Palace)') forbid_item(world.get_location(location), 'Big Key (Eastern Palace)')
set_rule(world.get_location('Desert Palace - Big Chest'), lambda state: state.has('Big Key (Desert Palace)')) set_rule(world.get_location('Desert Palace - Big Chest'), lambda state: state.has('Big Key (Desert Palace)'))
set_rule(world.get_location('Desert Palace - Torch'), lambda state: state.has_Boots()) set_rule(world.get_location('Desert Palace - Torch'), lambda state: state.has_Boots())
set_rule(world.get_entrance('Desert Palace East Wing'), lambda state: state.has_key('Small Key (Desert Palace)')) set_rule(world.get_entrance('Desert Palace East Wing'), lambda state: state.has_key('Small Key (Desert Palace)'))
set_rule(world.get_location('Desert Palace - Prize'), lambda state: state.has_key('Small Key (Desert Palace)') and state.has('Big Key (Desert Palace)') and state.has_fire_source() and set_rule(world.get_location('Desert Palace - Prize'), lambda state: state.has_key('Small Key (Desert Palace)') and state.has('Big Key (Desert Palace)') and state.has_fire_source() and world.get_location('Desert Palace - Prize').parent_region.dungeon.boss.can_defeat(state))
(state.has_blunt_weapon() or state.has('Fire Rod') or state.has('Ice Rod') or state.can_shoot_arrows())) set_rule(world.get_location('Desert Palace - Boss'), lambda state: state.has_key('Small Key (Desert Palace)') and state.has('Big Key (Desert Palace)') and state.has_fire_source() and world.get_location('Desert Palace - Boss').parent_region.dungeon.boss.can_defeat(state))
set_rule(world.get_location('Desert Palace - Lanmolas'), lambda state: state.has_key('Small Key (Desert Palace)') and state.has('Big Key (Desert Palace)') and state.has_fire_source() and for location in ['Desert Palace - Boss', 'Desert Palace - Big Chest']:
(state.has_blunt_weapon() or state.has('Fire Rod') or state.has('Ice Rod') or state.can_shoot_arrows()))
for location in ['Desert Palace - Lanmolas', 'Desert Palace - Big Chest']:
forbid_item(world.get_location(location), 'Big Key (Desert Palace)') forbid_item(world.get_location(location), 'Big Key (Desert Palace)')
for location in ['Desert Palace - Lanmolas', 'Desert Palace - Big Key Chest', 'Desert Palace - Compass Chest']: for location in ['Desert Palace - Boss', 'Desert Palace - Big Key Chest', 'Desert Palace - Compass Chest']:
forbid_item(world.get_location(location), 'Small Key (Desert Palace)') forbid_item(world.get_location(location), 'Small Key (Desert Palace)')
set_rule(world.get_entrance('Tower of Hera Small Key Door'), lambda state: state.has_key('Small Key (Tower of Hera)') or item_name(state, 'Tower of Hera - Big Key Chest') == 'Small Key (Tower of Hera)') set_rule(world.get_entrance('Tower of Hera Small Key Door'), lambda state: state.has_key('Small Key (Tower of Hera)') or item_name(state, 'Tower of Hera - Big Key Chest') == 'Small Key (Tower of Hera)')
@ -251,9 +252,9 @@ def global_rules(world):
set_rule(world.get_location('Tower of Hera - Big Chest'), lambda state: state.has('Big Key (Tower of Hera)')) set_rule(world.get_location('Tower of Hera - Big Chest'), lambda state: state.has('Big Key (Tower of Hera)'))
set_rule(world.get_location('Tower of Hera - Big Key Chest'), lambda state: state.has_fire_source()) set_rule(world.get_location('Tower of Hera - Big Key Chest'), lambda state: state.has_fire_source())
set_always_allow(world.get_location('Tower of Hera - Big Key Chest'), lambda state, item: item.name == 'Small Key (Tower of Hera)') set_always_allow(world.get_location('Tower of Hera - Big Key Chest'), lambda state, item: item.name == 'Small Key (Tower of Hera)')
set_rule(world.get_location('Tower of Hera - Moldorm'), lambda state: state.has_blunt_weapon()) set_defeat_dungeon_boss_rule(world.get_location('Tower of Hera - Boss'))
set_rule(world.get_location('Tower of Hera - Prize'), lambda state: state.has_blunt_weapon()) set_defeat_dungeon_boss_rule(world.get_location('Tower of Hera - Prize'))
for location in ['Tower of Hera - Moldorm', 'Tower of Hera - Big Chest', 'Tower of Hera - Compass Chest']: for location in ['Tower of Hera - Boss', 'Tower of Hera - Big Chest', 'Tower of Hera - Compass Chest']:
forbid_item(world.get_location(location), 'Big Key (Tower of Hera)') forbid_item(world.get_location(location), 'Big Key (Tower of Hera)')
# for location in ['Tower of Hera - Big Key Chest']: # for location in ['Tower of Hera - Big Key Chest']:
# forbid_item(world.get_location(location), 'Small Key (Tower of Hera)') # forbid_item(world.get_location(location), 'Small Key (Tower of Hera)')
@ -266,19 +267,21 @@ def global_rules(world):
set_rule(world.get_location('Swamp Palace - Big Chest'), lambda state: state.has('Big Key (Swamp Palace)') or item_name(state, 'Swamp Palace - Big Chest') == 'Big Key (Swamp Palace)') set_rule(world.get_location('Swamp Palace - Big Chest'), lambda state: state.has('Big Key (Swamp Palace)') or item_name(state, 'Swamp Palace - Big Chest') == 'Big Key (Swamp Palace)')
set_always_allow(world.get_location('Swamp Palace - Big Chest'), lambda state, item: item.name == 'Big Key (Swamp Palace)') set_always_allow(world.get_location('Swamp Palace - Big Chest'), lambda state, item: item.name == 'Big Key (Swamp Palace)')
set_rule(world.get_entrance('Swamp Palace (North)'), lambda state: state.has('Hookshot')) set_rule(world.get_entrance('Swamp Palace (North)'), lambda state: state.has('Hookshot'))
set_rule(world.get_location('Swamp Palace - Arrghus'), lambda state: state.has_blunt_weapon()) set_defeat_dungeon_boss_rule(world.get_location('Swamp Palace - Boss'))
set_rule(world.get_location('Swamp Palace - Prize'), lambda state: state.has_blunt_weapon()) set_defeat_dungeon_boss_rule(world.get_location('Swamp Palace - Prize'))
for location in ['Swamp Palace - Entrance']: for location in ['Swamp Palace - Entrance']:
forbid_item(world.get_location(location), 'Big Key (Swamp Palace)') forbid_item(world.get_location(location), 'Big Key (Swamp Palace)')
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_key('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_key('Small Key (Thieves Town)'))
set_defeat_dungeon_boss_rule(world.get_location('Thieves\' Town - Boss'))
set_defeat_dungeon_boss_rule(world.get_location('Thieves\' Town - Prize'))
set_rule(world.get_location('Thieves\' Town - Big Chest'), lambda state: (state.has_key('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_key('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)' and state.has('Hammer')) 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_key('Small Key (Thieves Town)')) set_rule(world.get_location('Thieves\' Town - Attic'), lambda state: state.has_key('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 - Boss']:
forbid_item(world.get_location(location), 'Big Key (Thieves Town)') forbid_item(world.get_location(location), 'Big Key (Thieves Town)')
for location in ['Thieves\' Town - Attic', 'Thieves Town - Blind']: for location in ['Thieves\' Town - Attic', 'Thieves\' Town - Boss']:
forbid_item(world.get_location(location), 'Small Key (Thieves Town)') forbid_item(world.get_location(location), 'Small Key (Thieves Town)')
set_rule(world.get_entrance('Skull Woods First Section South Door'), lambda state: state.has_key('Small Key (Skull Woods)')) set_rule(world.get_entrance('Skull Woods First Section South Door'), lambda state: state.has_key('Small Key (Skull Woods)'))
@ -288,15 +291,20 @@ def global_rules(world):
set_rule(world.get_location('Skull Woods - Big Chest'), lambda state: state.has('Big Key (Skull Woods)') or item_name(state, 'Skull Woods - Big Chest') == 'Big Key (Skull Woods)') set_rule(world.get_location('Skull Woods - Big Chest'), lambda state: state.has('Big Key (Skull Woods)') or item_name(state, 'Skull Woods - Big Chest') == 'Big Key (Skull Woods)')
set_always_allow(world.get_location('Skull Woods - Big Chest'), lambda state, item: item.name == 'Big Key (Skull Woods)') set_always_allow(world.get_location('Skull Woods - Big Chest'), lambda state, item: item.name == 'Big Key (Skull Woods)')
set_rule(world.get_entrance('Skull Woods Torch Room'), lambda state: state.has_key('Small Key (Skull Woods)', 3) and state.has('Fire Rod') and state.has_sword()) # sword required for curtain set_rule(world.get_entrance('Skull Woods Torch Room'), lambda state: state.has_key('Small Key (Skull Woods)', 3) and state.has('Fire Rod') and state.has_sword()) # sword required for curtain
for location in ['Skull Woods - Mothula']: set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Boss'))
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Prize'))
for location in ['Skull Woods - Boss']:
forbid_item(world.get_location(location), 'Small Key (Skull Woods)') forbid_item(world.get_location(location), 'Small Key (Skull Woods)')
set_rule(world.get_entrance('Ice Palace Entrance Room'), lambda state: state.has('Fire Rod') or (state.has('Bombos') and state.has_sword())) set_rule(world.get_entrance('Ice Palace Entrance Room'), lambda state: state.has('Fire Rod') or (state.has('Bombos') and state.has_sword()))
set_rule(world.get_location('Ice Palace - Big Chest'), lambda state: state.has('Big Key (Ice Palace)')) set_rule(world.get_location('Ice Palace - Big Chest'), lambda state: state.has('Big Key (Ice Palace)'))
set_rule(world.get_entrance('Ice Palace (Kholdstare)'), lambda state: state.can_lift_rocks() and state.has('Hammer') and state.has('Big Key (Ice Palace)') and (state.has_key('Small Key (Ice Palace)', 2) or (state.has('Cane of Somaria') and state.has_key('Small Key (Ice Palace)', 1)))) set_rule(world.get_entrance('Ice Palace (Kholdstare)'), lambda state: state.can_lift_rocks() and state.has('Hammer') and state.has('Big Key (Ice Palace)') and (state.has_key('Small Key (Ice Palace)', 2) or (state.has('Cane of Somaria') and state.has_key('Small Key (Ice Palace)', 1))))
# TODO: investigate change from VT. Changed to hookshot or 2 keys (no checking for big key in specific chests)
set_rule(world.get_entrance('Ice Palace (East)'), lambda state: (state.has('Hookshot') or (item_in_locations(state, 'Big Key (Ice Palace)', ['Ice Palace - Spike Room', 'Ice Palace - Big Key Chest', 'Ice Palace - Map Chest']) and state.has_key('Small Key (Ice Palace)'))) and (state.world.can_take_damage or state.has('Hookshot') or state.has('Cape') or state.has('Cane of Byrna'))) set_rule(world.get_entrance('Ice Palace (East)'), lambda state: (state.has('Hookshot') or (item_in_locations(state, 'Big Key (Ice Palace)', ['Ice Palace - Spike Room', 'Ice Palace - Big Key Chest', 'Ice Palace - Map Chest']) and state.has_key('Small Key (Ice Palace)'))) and (state.world.can_take_damage or state.has('Hookshot') or state.has('Cape') or state.has('Cane of Byrna')))
set_rule(world.get_entrance('Ice Palace (East Top)'), lambda state: state.can_lift_rocks() and state.has('Hammer')) set_rule(world.get_entrance('Ice Palace (East Top)'), lambda state: state.can_lift_rocks() and state.has('Hammer'))
for location in ['Ice Palace - Big Chest', 'Ice Palace - Kholdstare']: set_defeat_dungeon_boss_rule(world.get_location('Ice Palace - Boss'))
set_defeat_dungeon_boss_rule(world.get_location('Ice Palace - Prize'))
for location in ['Ice Palace - Big Chest', 'Ice Palace - Boss']:
forbid_item(world.get_location(location), 'Big Key (Ice Palace)') forbid_item(world.get_location(location), 'Big Key (Ice Palace)')
set_rule(world.get_entrance('Misery Mire Entrance Gap'), lambda state: (state.has_Boots() or state.has('Hookshot')) and (state.has_sword() or state.has('Fire Rod') or state.has('Ice Rod') or state.has('Hammer') or state.has('Cane of Somaria') or state.can_shoot_arrows())) # need to defeat wizzrobes, bombs don't work ... set_rule(world.get_entrance('Misery Mire Entrance Gap'), lambda state: (state.has_Boots() or state.has('Hookshot')) and (state.has_sword() or state.has('Fire Rod') or state.has('Ice Rod') or state.has('Hammer') or state.has('Cane of Somaria') or state.can_shoot_arrows())) # need to defeat wizzrobes, bombs don't work ...
@ -313,8 +321,10 @@ def global_rules(world):
(item_name(state, 'Misery Mire - Big Key Chest') in ['Big Key (Misery Mire)'])) else state.has_key('Small Key (Misery Mire)', 3)) (item_name(state, 'Misery Mire - Big Key Chest') in ['Big Key (Misery Mire)'])) else state.has_key('Small Key (Misery Mire)', 3))
set_rule(world.get_location('Misery Mire - Compass Chest'), lambda state: state.has_fire_source()) set_rule(world.get_location('Misery Mire - Compass Chest'), lambda state: state.has_fire_source())
set_rule(world.get_location('Misery Mire - Big Key Chest'), lambda state: state.has_fire_source()) set_rule(world.get_location('Misery Mire - Big Key Chest'), lambda state: state.has_fire_source())
set_rule(world.get_entrance('Misery Mire (Vitreous)'), lambda state: state.has('Cane of Somaria') and (state.can_shoot_arrows() or state.has_blunt_weapon())) set_rule(world.get_entrance('Misery Mire (Vitreous)'), lambda state: state.has('Cane of Somaria'))
for location in ['Misery Mire - Big Chest', 'Misery Mire - Vitreous']: set_defeat_dungeon_boss_rule(world.get_location('Misery Mire - Boss'))
set_defeat_dungeon_boss_rule(world.get_location('Misery Mire - Prize'))
for location in ['Misery Mire - Big Chest', 'Misery Mire - Boss']:
forbid_item(world.get_location(location), 'Big Key (Misery Mire)') forbid_item(world.get_location(location), 'Big Key (Misery Mire)')
set_rule(world.get_entrance('Turtle Rock Entrance Gap'), lambda state: state.has('Cane of Somaria')) set_rule(world.get_entrance('Turtle Rock Entrance Gap'), lambda state: state.has('Cane of Somaria'))
@ -325,17 +335,15 @@ def global_rules(world):
set_rule(world.get_location('Turtle Rock - Big Chest'), lambda state: state.has('Big Key (Turtle Rock)') and (state.has('Cane of Somaria') or state.has('Hookshot'))) set_rule(world.get_location('Turtle Rock - Big Chest'), lambda state: state.has('Big Key (Turtle Rock)') and (state.has('Cane of Somaria') or state.has('Hookshot')))
set_rule(world.get_entrance('Turtle Rock (Big Chest) (North)'), lambda state: state.has('Cane of Somaria') or state.has('Hookshot')) set_rule(world.get_entrance('Turtle Rock (Big Chest) (North)'), lambda state: state.has('Cane of Somaria') or state.has('Hookshot'))
set_rule(world.get_entrance('Turtle Rock Big Key Door'), lambda state: state.has('Big Key (Turtle Rock)')) set_rule(world.get_entrance('Turtle Rock Big Key Door'), lambda state: state.has('Big Key (Turtle Rock)'))
set_rule(world.get_entrance('Turtle Rock Dark Room Staircase'), lambda state: state.has_key('Small Key (Turtle Rock)', 3))
set_rule(world.get_entrance('Turtle Rock (Dark Room) (North)'), lambda state: state.has('Cane of Somaria')) set_rule(world.get_entrance('Turtle Rock (Dark Room) (North)'), lambda state: state.has('Cane of Somaria'))
set_rule(world.get_entrance('Turtle Rock (Dark Room) (South)'), lambda state: state.has('Cane of Somaria')) set_rule(world.get_entrance('Turtle Rock (Dark Room) (South)'), lambda state: state.has('Cane of Somaria'))
set_rule(world.get_location('Turtle Rock - Eye Bridge - Bottom 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 - Bottom 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 - Bottom 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 - Bottom 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 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_key('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_key('Small Key (Turtle Rock)', 4) and state.has('Big Key (Turtle Rock)') and state.has('Cane of Somaria'))
(state.has('Hammer') or state.has_beam_sword() or (state.has_sword() and state.can_extend_magic(32)))) set_defeat_dungeon_boss_rule(world.get_location('Turtle Rock - Boss'))
set_defeat_dungeon_boss_rule(world.get_location('Turtle Rock - Prize'))
set_trock_key_rules(world)
set_rule(world.get_entrance('Palace of Darkness Bonk Wall'), lambda state: state.can_shoot_arrows()) set_rule(world.get_entrance('Palace of Darkness Bonk Wall'), lambda state: state.can_shoot_arrows())
set_rule(world.get_entrance('Palace of Darkness Hammer Peg Drop'), lambda state: state.has('Hammer')) set_rule(world.get_entrance('Palace of Darkness Hammer Peg Drop'), lambda state: state.has('Hammer'))
@ -350,6 +358,8 @@ def global_rules(world):
set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door'), lambda state: state.has_key('Small Key (Palace of Darkness)', 6) or (item_name(state, 'Palace of Darkness - Harmless Hellway') in ['Small Key (Palace of Darkness)'] and state.has_key('Small Key (Palace of Darkness)', 4))) set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door'), lambda state: state.has_key('Small Key (Palace of Darkness)', 6) or (item_name(state, 'Palace of Darkness - Harmless Hellway') in ['Small Key (Palace of Darkness)'] and state.has_key('Small Key (Palace of Darkness)', 4)))
set_always_allow(world.get_location('Palace of Darkness - Harmless Hellway'), lambda state, item: item.name == 'Small Key (Palace of Darkness)' and state.has_key('Small Key (Palace of Darkness)', 5)) set_always_allow(world.get_location('Palace of Darkness - Harmless Hellway'), lambda state, item: item.name == 'Small Key (Palace of Darkness)' and state.has_key('Small Key (Palace of Darkness)', 5))
set_rule(world.get_entrance('Palace of Darkness Maze Door'), lambda state: state.has_key('Small Key (Palace of Darkness)', 6)) set_rule(world.get_entrance('Palace of Darkness Maze Door'), lambda state: state.has_key('Small Key (Palace of Darkness)', 6))
set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Boss'))
set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Prize'))
# these key rules are conservative, you might be able to get away with more lenient rules # these key rules are conservative, you might be able to get away with more lenient rules
randomizer_room_chests = ['Ganons Tower - Randomizer Room - Top Left', 'Ganons Tower - Randomizer Room - Top Right', 'Ganons Tower - Randomizer Room - Bottom Left', 'Ganons Tower - Randomizer Room - Bottom Right'] randomizer_room_chests = ['Ganons Tower - Randomizer Room - Top Left', 'Ganons Tower - Randomizer Room - Top Right', 'Ganons Tower - Randomizer Room - Bottom Left', 'Ganons Tower - Randomizer Room - Bottom Right']
@ -380,15 +390,17 @@ def global_rules(world):
set_rule(world.get_location(location), lambda state: state.has('Fire Rod') and (state.has_key('Small Key (Ganons Tower)', 4) or (item_in_locations(state, 'Big Key (Ganons Tower)', compass_room_chests) and state.has_key('Small Key (Ganons Tower)', 3)))) set_rule(world.get_location(location), lambda state: state.has('Fire Rod') and (state.has_key('Small Key (Ganons Tower)', 4) or (item_in_locations(state, 'Big Key (Ganons Tower)', compass_room_chests) and state.has_key('Small Key (Ganons Tower)', 3))))
set_rule(world.get_location('Ganons Tower - Big Chest'), lambda state: state.has('Big Key (Ganons Tower)')) set_rule(world.get_location('Ganons Tower - Big Chest'), lambda state: state.has('Big Key (Ganons Tower)'))
set_rule(world.get_location('Ganons Tower - Big Key Room - Left'), lambda state: state.can_shoot_arrows() or state.has_blunt_weapon())
set_rule(world.get_location('Ganons Tower - Big Key Chest'), lambda state: state.can_shoot_arrows() or state.has_blunt_weapon()) set_rule(world.get_location('Ganons Tower - Big Key Room - Left'), lambda state: world.get_location('Ganons Tower - Big Key Room - Left').parent_region.dungeon.bosses['bottom'].can_defeat(state))
set_rule(world.get_location('Ganons Tower - Big Key Room - Right'), lambda state: state.can_shoot_arrows() or state.has_blunt_weapon()) set_rule(world.get_location('Ganons Tower - Big Key Chest'), lambda state: world.get_location('Ganons Tower - Big Key Chest').parent_region.dungeon.bosses['bottom'].can_defeat(state))
set_rule(world.get_location('Ganons Tower - Big Key Room - Right'), lambda state: world.get_location('Ganons Tower - Big Key Room - Right').parent_region.dungeon.bosses['bottom'].can_defeat(state))
set_rule(world.get_entrance('Ganons Tower Big Key Door'), lambda state: state.has('Big Key (Ganons Tower)') and state.can_shoot_arrows()) set_rule(world.get_entrance('Ganons Tower Big Key Door'), lambda state: state.has('Big Key (Ganons Tower)') and state.can_shoot_arrows())
set_rule(world.get_entrance('Ganons Tower Torch Rooms'), lambda state: state.has_fire_source()) set_rule(world.get_entrance('Ganons Tower Torch Rooms'), lambda state: state.has_fire_source() and world.get_entrance('Ganons Tower Torch Rooms').parent_region.dungeon.bosses['middle'].can_defeat(state))
set_rule(world.get_location('Ganons Tower - Pre-Moldorm Chest'), lambda state: state.has_key('Small Key (Ganons Tower)', 3)) set_rule(world.get_location('Ganons Tower - Pre-Moldorm Chest'), lambda state: state.has_key('Small Key (Ganons Tower)', 3))
set_rule(world.get_entrance('Ganons Tower Moldorm Door'), lambda state: state.has_key('Small Key (Ganons Tower)', 4)) set_rule(world.get_entrance('Ganons Tower Moldorm Door'), lambda state: state.has_key('Small Key (Ganons Tower)', 4))
set_rule(world.get_entrance('Ganons Tower Moldorm Gap'), lambda state: state.has('Hookshot') and state.has_blunt_weapon()) set_rule(world.get_entrance('Ganons Tower Moldorm Gap'), lambda state: state.has('Hookshot') and world.get_entrance('Ganons Tower Moldorm Gap').parent_region.dungeon.bosses['top'].can_defeat(state))
set_rule(world.get_location('Agahnim 2'), lambda state: state.has_sword() or state.has('Hammer') or state.has('Bug Catching Net')) set_defeat_dungeon_boss_rule(world.get_location('Agahnim 2'))
set_rule(world.get_entrance('Pyramid Hole'), lambda state: state.has('Beat Agahnim 2')) set_rule(world.get_entrance('Pyramid Hole'), lambda state: state.has('Beat Agahnim 2'))
for location in ['Ganons Tower - Big Chest', 'Ganons Tower - Mini Helmasaur Room - Left', 'Ganons Tower - Mini Helmasaur Room - Right', for location in ['Ganons Tower - Big Chest', 'Ganons Tower - Mini Helmasaur Room - Left', 'Ganons Tower - Mini Helmasaur Room - Right',
'Ganons Tower - Pre-Moldorm Chest', 'Ganons Tower - Validation Chest']: 'Ganons Tower - Pre-Moldorm Chest', 'Ganons Tower - Validation Chest']:
@ -399,6 +411,12 @@ def global_rules(world):
and (state.has('Tempered Sword') or state.has('Golden Sword') or (state.has('Silver Arrows') and state.can_shoot_arrows()) or state.has('Lamp') or state.can_extend_magic(12))) # need to light torch a sufficient amount of times and (state.has('Tempered Sword') or state.has('Golden Sword') or (state.has('Silver Arrows') and state.can_shoot_arrows()) or state.has('Lamp') or state.can_extend_magic(12))) # need to light torch a sufficient amount of times
set_rule(world.get_entrance('Ganon Drop'), lambda state: state.has_beam_sword()) # need to damage ganon to get tiles to drop set_rule(world.get_entrance('Ganon Drop'), lambda state: state.has_beam_sword()) # need to damage ganon to get tiles to drop
set_rule(world.get_entrance('Ganons Tower'), lambda state: False) # This is a safety for the TR function below to not require GT entrance in its key logic.
set_trock_key_rules(world)
set_rule(world.get_entrance('Ganons Tower'), lambda state: state.has('Crystal 1') and state.has('Crystal 2') and state.has('Crystal 3') and state.has('Crystal 4') and state.has('Crystal 5') and state.has('Crystal 6') and state.has('Crystal 7'))
def no_glitches_rules(world): def no_glitches_rules(world):
set_rule(world.get_entrance('Zoras River'), lambda state: state.has('Flippers') or state.can_lift_rocks()) set_rule(world.get_entrance('Zoras River'), lambda state: state.has('Flippers') or state.can_lift_rocks())
@ -407,7 +425,11 @@ def no_glitches_rules(world):
set_rule(world.get_entrance('Dark Lake Hylia Drop (East)'), lambda state: state.has_Pearl() and state.has('Flippers')) set_rule(world.get_entrance('Dark Lake Hylia Drop (East)'), lambda state: state.has_Pearl() and state.has('Flippers'))
set_rule(world.get_entrance('Dark Lake Hylia Teleporter'), lambda state: state.has_Pearl() and state.has('Flippers') and (state.has('Hammer') or state.can_lift_rocks())) set_rule(world.get_entrance('Dark Lake Hylia Teleporter'), lambda state: state.has_Pearl() and state.has('Flippers') and (state.has('Hammer') or state.can_lift_rocks()))
set_rule(world.get_entrance('Dark Lake Hylia Ledge Drop'), lambda state: state.has_Pearl() and state.has('Flippers')) set_rule(world.get_entrance('Dark Lake Hylia Ledge Drop'), lambda state: state.has_Pearl() and state.has('Flippers'))
add_rule(world.get_entrance('Ganons Tower (Hookshot Room)'), lambda state: state.has('Hookshot')) add_rule(world.get_entrance('Ganons Tower (Hookshot Room)'), lambda state: state.has('Hookshot') or state.has_Boots())
add_rule(world.get_entrance('Ganons Tower (Double Switch Room)'), lambda state: state.has('Hookshot'))
DMs_room_chests = ['Ganons Tower - DMs Room - Top Left', 'Ganons Tower - DMs Room - Top Right', 'Ganons Tower - DMs Room - Bottom Left', 'Ganons Tower - DMs Room - Bottom Right']
for location in DMs_room_chests:
add_rule(world.get_location(location), lambda state: state.has('Hookshot'))
set_rule(world.get_entrance('Paradox Cave Push Block Reverse'), lambda state: False) # no glitches does not require block override set_rule(world.get_entrance('Paradox Cave Push Block Reverse'), lambda state: False) # no glitches does not require block override
set_rule(world.get_entrance('Paradox Cave Bomb Jump'), lambda state: False) set_rule(world.get_entrance('Paradox Cave Bomb Jump'), lambda state: False)
set_rule(world.get_entrance('Skull Woods First Section Bomb Jump'), lambda state: False) set_rule(world.get_entrance('Skull Woods First Section Bomb Jump'), lambda state: False)
@ -447,7 +469,7 @@ def no_glitches_rules(world):
add_conditional_lamp('Old Man House Front to Back', 'Old Man House', 'Entrance') add_conditional_lamp('Old Man House Front to Back', 'Old Man House', 'Entrance')
add_conditional_lamp('Old Man House Back to Front', 'Old Man House', 'Entrance') add_conditional_lamp('Old Man House Back to Front', 'Old Man House', 'Entrance')
add_conditional_lamp('Eastern Palace - Big Key Chest', 'Eastern Palace', 'Location') add_conditional_lamp('Eastern Palace - Big Key Chest', 'Eastern Palace', 'Location')
add_conditional_lamp('Eastern Palace - Armos Knights', 'Eastern Palace', 'Location') add_conditional_lamp('Eastern Palace - Boss', 'Eastern Palace', 'Location')
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:
@ -473,14 +495,13 @@ def swordless_rules(world):
open_rules(world) open_rules(world)
set_rule(world.get_entrance('Agahnims Tower'), lambda state: state.has('Cape') or state.has('Hammer') 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('Hammer') or state.has('Beat Agahnim 1')) # barrier gets removed after killing agahnim, relevant for entrance shuffle
set_rule(world.get_entrance('Agahnim 1'), lambda state: (state.has('Hammer') or (state.has('Bug Catching Net') and (state.has('Fire Rod') or state.can_shoot_arrows() or state.has('Cane of Somaria')))) and state.has_key('Small Key (Agahnims Tower)', 2)) set_rule(world.get_entrance('Agahnim 1'), lambda state: (state.has('Hammer') or state.has('Fire Rod') or state.can_shoot_arrows() or state.has('Cane of Somaria')) and state.has_key('Small Key (Agahnims Tower)', 2))
set_rule(world.get_location('Ether Tablet'), lambda state: state.has('Book of Mudora') and state.has('Hammer')) set_rule(world.get_location('Ether Tablet'), lambda state: state.has('Book of Mudora') and state.has('Hammer'))
set_rule(world.get_location('Bombos Tablet'), lambda state: state.has('Book of Mudora') and state.has('Hammer') and state.has_Mirror()) set_rule(world.get_location('Bombos Tablet'), lambda state: state.has('Book of Mudora') and state.has('Hammer') and state.has_Mirror())
set_rule(world.get_entrance('Misery Mire'), lambda state: state.has_Pearl() and state.has_misery_mire_medallion()) # sword not required to use medallion for opening in swordless (!) set_rule(world.get_entrance('Misery Mire'), lambda state: state.has_Pearl() and state.has_misery_mire_medallion()) # sword not required to use medallion for opening in swordless (!)
set_rule(world.get_entrance('Turtle Rock'), lambda state: state.has_Pearl() and state.has_turtle_rock_medallion() and state.can_reach('Turtle Rock (Top)', 'Region')) # sword not required to use medallion for opening in swordless (!) set_rule(world.get_entrance('Turtle Rock'), lambda state: state.has_Pearl() and state.has_turtle_rock_medallion() and state.can_reach('Turtle Rock (Top)', 'Region')) # sword not required to use medallion for opening in swordless (!)
set_rule(world.get_entrance('Skull Woods Torch Room'), lambda state: state.has_key('Small Key (Skull Woods)', 3) and state.has('Fire Rod') and (state.has('Hammer') or state.can_extend_magic(10))) # no curtain set_rule(world.get_entrance('Skull Woods Torch Room'), lambda state: state.has_key('Small Key (Skull Woods)', 3) and state.has('Fire Rod')) # no curtain
set_rule(world.get_entrance('Ice Palace Entrance Room'), lambda state: state.has('Fire Rod') or state.has('Bombos')) #in swordless mode bombos pads are present in the relevant parts of ice palace set_rule(world.get_entrance('Ice Palace Entrance Room'), lambda state: state.has('Fire Rod') or state.has('Bombos')) #in swordless mode bombos pads are present in the relevant parts of ice palace
set_rule(world.get_location('Agahnim 2'), lambda state: state.has('Hammer') or state.has('Bug Catching Net'))
set_rule(world.get_location('Ganon'), lambda state: state.has('Hammer') and state.has_fire_source() and state.has('Silver Arrows') and state.can_shoot_arrows() and state.has('Crystal 1') and state.has('Crystal 2') set_rule(world.get_location('Ganon'), lambda state: state.has('Hammer') and state.has_fire_source() and state.has('Silver Arrows') and state.can_shoot_arrows() and state.has('Crystal 1') and state.has('Crystal 2')
and state.has('Crystal 3') and state.has('Crystal 4') and state.has('Crystal 5') and state.has('Crystal 6') and state.has('Crystal 7')) and state.has('Crystal 3') and state.has('Crystal 4') and state.has('Crystal 5') and state.has('Crystal 6') and state.has('Crystal 7'))
set_rule(world.get_entrance('Ganon Drop'), lambda state: state.has('Hammer')) # need to damage ganon to get tiles to drop set_rule(world.get_entrance('Ganon Drop'), lambda state: state.has('Hammer')) # need to damage ganon to get tiles to drop
@ -501,61 +522,88 @@ def standard_rules(world):
def set_trock_key_rules(world): def set_trock_key_rules(world):
# ToDo If only second section entrance is available, we may very well run out of valid key locations currently.
# this is good enough to allow even key distribution but may still prevent certain valid item combinations from being placed all_state = world.get_all_state(True)
all_state = world.get_all_state() # First set all relevant locked doors to impassible.
for entrance in ['Turtle Rock Dark Room Staircase', 'Turtle Rock (Chain Chomp Room) (North)', 'Turtle Rock (Chain Chomp Room) (South)', 'Turtle Rock Pokey Room']:
set_rule(world.get_entrance(entrance), lambda state: False)
# check if the back entrance into trock can be accessed. As no small keys are placed yet, the rule on the dark room staircase door # Check if each of the four main regions of the dungoen can be reached. The previous code section prevents key-costing moves within the dungeon.
# prevents us from reach the eye bridge from within the dungeon (!)
can_reach_back = all_state.can_reach(world.get_region('Turtle Rock (Eye Bridge)')) if world.can_access_trock_eyebridge is None else world.can_access_trock_eyebridge can_reach_back = all_state.can_reach(world.get_region('Turtle Rock (Eye Bridge)')) if world.can_access_trock_eyebridge is None else world.can_access_trock_eyebridge
world.can_access_trock_eyebridge = can_reach_back world.can_access_trock_eyebridge = can_reach_back
can_reach_front = all_state.can_reach(world.get_region('Turtle Rock (Entrance)')) if world.can_access_trock_front is None else world.can_access_trock_front
world.can_access_trock_front = can_reach_front
can_reach_big_chest = all_state.can_reach(world.get_region('Turtle Rock (Big Chest)')) if world.can_access_trock_big_chest is None else world.can_access_trock_big_chest
world.can_access_trock_big_chest = can_reach_big_chest
can_reach_middle = all_state.can_reach(world.get_region('Turtle Rock (Second Section)')) if world.can_access_trock_middle is None else world.can_access_trock_middle
world.can_access_trock_middle = can_reach_middle
# if we have backdoor access we can waste a key on the trinexx door, then have no lamp to reverse traverse the maze room. We simply require an additional key just to be super safe then. The backdoor access to the chest is otherwise free # No matter what, the key requirement for going from the middle to the bottom should be three keys.
if not can_reach_back: set_rule(world.get_entrance('Turtle Rock Dark Room Staircase'), lambda state: state.has_key('Small Key (Turtle Rock)', 3))
set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has_key('Small Key (Turtle Rock)', 1))
else:
set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has_key('Small Key (Turtle Rock)', 2))
# if we have front access this transition is useless. If we don't, it's a dead end so cannot hold any small keys # The following represent the most common and most restrictive key rules. These are overwritten later as needed.
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (South)'), lambda state: state.has_key('Small Key (Turtle Rock)', 4)) set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (South)'), lambda state: state.has_key('Small Key (Turtle Rock)', 4))
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)'), lambda state: state.has_key('Small Key (Turtle Rock)', 4))
set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has_key('Small Key (Turtle Rock)', 4))
# this is just the pokey room with one more key # No matter what, the Big Key cannot be in the Big Chest or held by Trinexx.
if not can_reach_back: non_big_key_locations = ['Turtle Rock - Big Chest', 'Turtle Rock - Boss']
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)'), lambda state: state.has_key('Small Key (Turtle Rock)', 2))
else:
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)'), lambda state: state.has_key('Small Key (Turtle Rock)', 3))
# the most complicated one
def tr_big_key_chest_keys_needed(state): def tr_big_key_chest_keys_needed(state):
# This function handles the key requirements for the TR Big Chest in the situations it having the Big Key should logically require 2 keys, small key
# should logically require no keys, and anything else should logically require 4 keys.
item = item_name(state, 'Turtle Rock - Big Key Chest') item = item_name(state, 'Turtle Rock - Big Key Chest')
# handle key for a key situation in the usual way (by letting us logically open the door using the key locked inside it)
if item in ['Small Key (Turtle Rock)']: if item in ['Small Key (Turtle Rock)']:
return 3 return 0
# if we lack backdoor access and cannot reach the back before opening this chest because it contains the big key if item in ['Big Key (Turtle Rock)']:
# then that means there are two doors left that we cannot have spent a key on, (crystalroller and trinexx) so we only need
# two keys
if item in ['Big Key (Turtle Rock)'] and not can_reach_back:
return 2 return 2
# otherwise we could potentially have opened every other door already, so we need all 4 keys.
return 4 return 4
set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has_key('Small Key (Turtle Rock)', tr_big_key_chest_keys_needed(state))) # Now we need to set rules based on which entrances we have access to. The most important point is whether we have back access. If we have back access, we
set_always_allow(world.get_location('Turtle Rock - Big Key Chest'), lambda state, item: item.name == 'Small Key (Turtle Rock)' and state.has_key('Small Key (Turtle Rock)', 3)) # might open all the locked doors in any order so we need maximally restrictive rules.
if can_reach_back:
# set big key restrictions set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: (state.has_key('Small Key (Turtle Rock)', 4) or item_name(state, 'Turtle Rock - Big Key Chest') == 'Small Key (Turtle Rock)'))
non_big_key_locations = ['Turtle Rock - Big Chest', 'Turtle Rock - Trinexx'] set_always_allow(world.get_location('Turtle Rock - Big Key Chest'), lambda state, item: item.name == 'Small Key (Turtle Rock)')
if not can_reach_back: elif can_reach_front and can_reach_middle:
set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has_key('Small Key (Turtle Rock)', tr_big_key_chest_keys_needed(state)))
set_always_allow(world.get_location('Turtle Rock - Big Key Chest'), lambda state, item: item.name == 'Small Key (Turtle Rock)')
non_big_key_locations += ['Turtle Rock - Crystaroller Room', 'Turtle Rock - Eye Bridge - Bottom Left', non_big_key_locations += ['Turtle Rock - Crystaroller Room', 'Turtle Rock - Eye Bridge - Bottom Left',
'Turtle Rock - Eye Bridge - Bottom Right', 'Turtle Rock - Eye Bridge - Top Left', 'Turtle Rock - Eye Bridge - Bottom Right', 'Turtle Rock - Eye Bridge - Top Left',
'Turtle Rock - Eye Bridge - Top Right'] 'Turtle Rock - Eye Bridge - Top Right']
elif can_reach_front:
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)'), lambda state: state.has_key('Small Key (Turtle Rock)', 2))
set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has_key('Small Key (Turtle Rock)', 1))
set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has_key('Small Key (Turtle Rock)', tr_big_key_chest_keys_needed(state)))
set_always_allow(world.get_location('Turtle Rock - Big Key Chest'), lambda state, item: item.name == 'Small Key (Turtle Rock)' and state.has_key('Small Key (Turtle Rock)', 2))
non_big_key_locations += ['Turtle Rock - Crystaroller Room', 'Turtle Rock - Eye Bridge - Bottom Left',
'Turtle Rock - Eye Bridge - Bottom Right', 'Turtle Rock - Eye Bridge - Top Left',
'Turtle Rock - Eye Bridge - Top Right']
elif can_reach_big_chest:
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (South)'), lambda state: state.has_key('Small Key (Turtle Rock)', 2) if item_in_locations(state, 'Big Key (Turtle Rock)', ['Turtle Rock - Compass Chest', 'Turtle Rock - Roller Room - Left', 'Turtle Rock - Roller Room - Right']) else state.has_key('Small Key (Turtle Rock)', 4))
set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: (state.has_key('Small Key (Turtle Rock)', 4) or item_name(state, 'Turtle Rock - Big Key Chest') == 'Small Key (Turtle Rock)'))
set_always_allow(world.get_location('Turtle Rock - Big Key Chest'), lambda state, item: item.name == 'Small Key (Turtle Rock)')
non_big_key_locations += ['Turtle Rock - Crystaroller Room', 'Turtle Rock - Eye Bridge - Bottom Left',
'Turtle Rock - Eye Bridge - Bottom Right', 'Turtle Rock - Eye Bridge - Top Left',
'Turtle Rock - Eye Bridge - Top Right']
if not world.keysanity:
non_big_key_locations += ['Turtle Rock - Big Key Chest']
else:
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (South)'), lambda state: state.has_key('Small Key (Turtle Rock)', 2) if item_in_locations(state, 'Big Key (Turtle Rock)', ['Turtle Rock - Compass Chest', 'Turtle Rock - Roller Room - Left', 'Turtle Rock - Roller Room - Right']) else state.has_key('Small Key (Turtle Rock)', 4))
set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: (state.has_key('Small Key (Turtle Rock)', 4) or item_name(state, 'Turtle Rock - Big Key Chest') == 'Small Key (Turtle Rock)'))
set_always_allow(world.get_location('Turtle Rock - Big Key Chest'), lambda state, item: item.name == 'Small Key (Turtle Rock)')
non_big_key_locations += ['Turtle Rock - Crystaroller Room', 'Turtle Rock - Eye Bridge - Bottom Left',
'Turtle Rock - Eye Bridge - Bottom Right', 'Turtle Rock - Eye Bridge - Top Left',
'Turtle Rock - Eye Bridge - Top Right']
if not world.keysanity:
non_big_key_locations += ['Turtle Rock - Big Key Chest', 'Turtle Rock - Chain Chomps']
# set big key restrictions
for location in non_big_key_locations: for location in non_big_key_locations:
forbid_item(world.get_location(location), 'Big Key (Turtle Rock)') forbid_item(world.get_location(location), 'Big Key (Turtle Rock)')
# small key restriction # small key restriction
for location in ['Turtle Rock - Trinexx']: for location in ['Turtle Rock - Boss']:
forbid_item(world.get_location(location), 'Small Key (Turtle Rock)') forbid_item(world.get_location(location), 'Small Key (Turtle Rock)')
@ -792,7 +840,7 @@ def set_bunny_rules(world):
# regions for the exits 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)', 'Desert Palace Main (Inner)'] 'Turtle Rock (Eye Bridge)', 'Sewers', 'Pyramid', 'Spiral Cave (Top)', 'Desert Palace Main (Inner)', 'Fairy Ascension Cave (Drop)']
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', 'Dark Blacksmith Ruins'] 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', 'Dark Blacksmith Ruins']

848
Text.py

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,12 @@ 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 pc_to_snes(value):
return ((value<<1) & 0x7F0000)|(value & 0x7FFF)|0x8000
def snes_to_pc(value):
return ((value & 0x7F0000)>>1)|(value & 0x7FFF)
def is_bundled(): def is_bundled():
return getattr(sys, 'frozen', False) return getattr(sys, 'frozen', False)

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.