Merge branch 'DoorDev' into CrossGenWork

This commit is contained in:
aerinon
2020-01-29 13:01:29 -07:00
10 changed files with 97 additions and 76 deletions

View File

@@ -83,7 +83,7 @@ class World(object):
set_player_attr('ganonstower_vanilla', True) set_player_attr('ganonstower_vanilla', True)
set_player_attr('sewer_light_cone', self.mode[player] == 'standard') set_player_attr('sewer_light_cone', self.mode[player] == 'standard')
set_player_attr('fix_trock_doors', self.shuffle[player] != 'vanilla' or self.mode[player] == 'inverted') set_player_attr('fix_trock_doors', self.shuffle[player] != 'vanilla' or self.mode[player] == 'inverted')
set_player_attr('fix_skullwoods_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple']) set_player_attr('fix_skullwoods_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'] or self.doorShuffle[player] not in ['vanilla'])
set_player_attr('fix_palaceofdarkness_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple']) set_player_attr('fix_palaceofdarkness_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
set_player_attr('fix_trock_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple']) set_player_attr('fix_trock_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
set_player_attr('can_access_trock_eyebridge', None) set_player_attr('can_access_trock_eyebridge', None)
@@ -450,17 +450,17 @@ class CollectionState(object):
blocked.add(entrance.parent_region) blocked.add(entrance.parent_region)
if color_type: if color_type:
ccr[candidate] = color_type ccr[candidate] = color_type
for ext in candidate.exits: for ext in candidate.exits:
connect = ext.connected_region connect = ext.connected_region
if connect in rrp and connect in ccr: if connect in rrp and connect in ccr:
door = self.world.check_for_door(ext.name, player) door = self.world.check_for_door(ext.name, player)
if door is not None and not door.blocked: if door is not None and not door.blocked:
if ext.can_reach(self): if ext.can_reach(self):
new_color = ccr[connect] | (ccr[candidate] & (door.crystal or CrystalBarrier.Either)) new_color = ccr[connect] | (ccr[candidate] & (door.crystal or CrystalBarrier.Either))
if new_color != ccr[connect]: if new_color != ccr[connect]:
self.spread_crystal_access(candidate, new_color, rrp, ccr, player) self.spread_crystal_access(candidate, new_color, rrp, ccr, player)
else: else:
blocked.add(candidate) blocked.add(candidate)
new_regions = len(rrp) > reachable_regions_count new_regions = len(rrp) > reachable_regions_count
reachable_regions_count = len(rrp) reachable_regions_count = len(rrp)

View File

@@ -55,6 +55,9 @@ def link_doors(world, player):
cross_dungeon(world, player) cross_dungeon(world, player)
elif world.doorShuffle[player] == 'experimental': elif world.doorShuffle[player] == 'experimental':
experiment(world, player) experiment(world, player)
else:
logging.getLogger('').error('Invalid door shuffle setting: %s' % world.doorShuffle[player])
raise Exception('Invalid door shuffle setting: %s' % world.doorShuffle[player])
if world.doorShuffle[player] != 'vanilla': if world.doorShuffle[player] != 'vanilla':
create_door_spoiler(world, player) create_door_spoiler(world, player)
@@ -146,7 +149,8 @@ def vanilla_key_logic(world, player):
analyze_dungeon(key_layout, world, player) analyze_dungeon(key_layout, world, player)
world.key_logic[player][builder.name] = key_layout.key_logic world.key_logic[player][builder.name] = key_layout.key_logic
last_key = None last_key = None
validate_vanilla_key_logic(world, player) if world.shuffle[player] == 'vanilla':
validate_vanilla_key_logic(world, player)
# some useful functions # some useful functions
@@ -2023,18 +2027,19 @@ default_one_way_connections = [
] ]
# For crossed # For crossed
compass_data = { # offset from 0x122e17, sram storage, write offset from compass_w_addr, 0 = jmp or # of nops # offset from 0x122e17, sram storage, write offset from compass_w_addr, 0 = jmp or # of nops, dungeon_id
'Hyrule Castle': (0x1, 0xc0, 0x16, 0), compass_data = {
'Eastern Palace': (0x1C, 0xc1, 0x28, 0), 'Hyrule Castle': (0x1, 0xc0, 0x16, 0, 0x02),
'Desert Palace': (0x35, 0xc2, 0x4a, 0), 'Eastern Palace': (0x1C, 0xc1, 0x28, 0, 0x04),
'Agahnims Tower': (0x51, 0xc3, 0x5c, 0), 'Desert Palace': (0x35, 0xc2, 0x4a, 0, 0x06),
'Swamp Palace': (0x6A, 0xc4, 0x7e, 0), 'Agahnims Tower': (0x51, 0xc3, 0x5c, 0, 0x08),
'Palace of Darkness': (0x83, 0xc5, 0xa4, 0), 'Swamp Palace': (0x6A, 0xc4, 0x7e, 0, 0x0a),
'Misery Mire': (0x9C, 0xc6, 0xca, 0), 'Palace of Darkness': (0x83, 0xc5, 0xa4, 0, 0x0c),
'Skull Woods': (0xB5, 0xc7, 0xf0, 0), 'Misery Mire': (0x9C, 0xc6, 0xca, 0, 0x0e),
'Ice Palace': (0xD0, 0xc8, 0x102, 0), 'Skull Woods': (0xB5, 0xc7, 0xf0, 0, 0x10),
'Tower of Hera': (0xEB, 0xc9, 0x114, 0), 'Ice Palace': (0xD0, 0xc8, 0x102, 0, 0x12),
'Thieves Town': (0x106, 0xca, 0x138, 0), 'Tower of Hera': (0xEB, 0xc9, 0x114, 0, 0x14),
'Turtle Rock': (0x11F, 0xcb, 0x15e, 0), 'Thieves Town': (0x106, 0xca, 0x138, 0, 0x16),
'Ganons Tower': (0x13A, 0xcc, 0x170, 2) 'Turtle Rock': (0x11F, 0xcb, 0x15e, 0, 0x18),
'Ganons Tower': (0x13A, 0xcc, 0x170, 2, 0x1a)
} }

View File

@@ -218,8 +218,8 @@ def parse_arguments(argv, no_defaults=False):
Select the rate at which the menu opens and closes. Select the rate at which the menu opens and closes.
(default: %(default)s) (default: %(default)s)
''') ''')
parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true') parser.add_argument('--quickswap', default=defval(False), 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', default=defval(False), help='Disables game music.', action='store_true')
parser.add_argument('--mapshuffle', default=defval(False), help='Maps are no longer restricted to their dungeons, but can be anywhere', action='store_true') parser.add_argument('--mapshuffle', default=defval(False), help='Maps are no longer restricted to their dungeons, but can be anywhere', action='store_true')
parser.add_argument('--compassshuffle', default=defval(False), help='Compasses are no longer restricted to their dungeons, but can be anywhere', action='store_true') parser.add_argument('--compassshuffle', default=defval(False), help='Compasses are no longer restricted to their dungeons, but can be anywhere', action='store_true')
parser.add_argument('--keyshuffle', default=defval(False), help='Small Keys are no longer restricted to their dungeons, but can be anywhere', action='store_true') parser.add_argument('--keyshuffle', default=defval(False), help='Small Keys are no longer restricted to their dungeons, but can be anywhere', action='store_true')

View File

@@ -550,7 +550,7 @@ def link_entrances(world, player):
('North Fairy Cave Exit', 'North Fairy Cave'), ('North Fairy Cave Exit', 'North Fairy Cave'),
('Lost Woods Hideout Exit', 'Lost Woods Hideout (top)'), ('Lost Woods Hideout Exit', 'Lost Woods Hideout (top)'),
('Lumberjack Tree Exit', 'Lumberjack Tree (top)'), ('Lumberjack Tree Exit', 'Lumberjack Tree (top)'),
(('Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)'), 'Skull Woods Second Section (Drop)')] (('Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)'), 'Skull Back Drop')]
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
# cannot move uncle cave # cannot move uncle cave
@@ -587,7 +587,7 @@ def link_entrances(world, player):
else: else:
sw_hole_pool = dw_hole_entrances sw_hole_pool = dw_hole_entrances
mandatory_dark_world.append('Skull Woods First Section Exit') mandatory_dark_world.append('Skull Woods First Section Exit')
for target in ['Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']: for target in ['Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']:
connect_entrance(world, sw_hole_pool.pop(), target, player) connect_entrance(world, sw_hole_pool.pop(), target, player)
# sanctuary has to be in light world # sanctuary has to be in light world
@@ -786,8 +786,8 @@ def link_entrances(world, player):
hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave', hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave',
'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole'] 'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole']
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Woods Second Section (Drop)', hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop',
'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)'] 'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']
# tavern back door cannot be shuffled yet # tavern back door cannot be shuffled yet
connect_doors(world, ['Tavern North'], ['Tavern'], player) connect_doors(world, ['Tavern North'], ['Tavern'], player)
@@ -924,8 +924,8 @@ def link_entrances(world, player):
hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave', hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave',
'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole'] 'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole']
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Woods Second Section (Drop)', hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop',
'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)'] 'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
# cannot move uncle cave # cannot move uncle cave
@@ -1627,8 +1627,8 @@ def link_inverted_entrances(world, player):
hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave', hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave',
'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole'] 'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole']
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Woods Second Section (Drop)', hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop',
'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)'] 'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']
# tavern back door cannot be shuffled yet # tavern back door cannot be shuffled yet
connect_doors(world, ['Tavern North'], ['Tavern'], player) connect_doors(world, ['Tavern North'], ['Tavern'], player)
@@ -3780,8 +3780,8 @@ exit_ids = {'Links House Exit': (0x01, 0x00),
'Lost Woods Hideout (top)': 0x7A, 'Lost Woods Hideout (top)': 0x7A,
'Lumberjack Tree (top)': 0x7F, 'Lumberjack Tree (top)': 0x7F,
'Sewer Drop': 0x81, 'Sewer Drop': 0x81,
'Skull Woods Second Section (Drop)': 0x79, 'Skull Back Drop': 0x79,
'Skull Woods First Section (Left)': 0x77, 'Skull Left Drop': 0x77,
'Skull Woods First Section (Right)': 0x78, 'Skull Pinball': 0x78,
'Skull Woods First Section (Top)': 0x76, 'Skull Pot Circle': 0x76,
'Pyramid': 0x7B} 'Pyramid': 0x7B}

View File

@@ -864,7 +864,8 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa
def cnt_avail_small_locations(free_locations, key_only, state, world, player): def cnt_avail_small_locations(free_locations, key_only, state, world, player):
if not world.keyshuffle[player] and not world.retro[player]: if not world.keyshuffle[player] and not world.retro[player]:
avail_chest_keys = min(free_locations - state.used_locations + state.used_smalls, state.key_locations - key_only) bk_adj = 1 if state.big_key_opened and not state.big_key_special else 0
avail_chest_keys = min(free_locations - bk_adj, state.key_locations - key_only)
return max(0, avail_chest_keys + key_only - state.used_smalls) return max(0, avail_chest_keys + key_only - state.used_smalls)
return state.key_locations - state.used_smalls return state.key_locations - state.used_smalls
@@ -1146,20 +1147,22 @@ def val_mire(key_logic, world, player):
def val_turtle(key_logic, world, player): def val_turtle(key_logic, world, player):
val_rule(key_logic.door_rules['TR Hub NW'], 1) # todo: check vanilla key logic when TR back doors are accessible
val_rule(key_logic.door_rules['TR Pokey 1 NW'], 2) if world.shuffle[player] == 'vanilla' and world.mode[player] != 'inverted':
val_rule(key_logic.door_rules['TR Chain Chomps Down Stairs'], 3) val_rule(key_logic.door_rules['TR Hub NW'], 1)
val_rule(key_logic.door_rules['TR Pokey 2 ES'], 6, True, 'Turtle Rock - Big Key Chest', 4, {'Turtle Rock - Big Key Chest'}) val_rule(key_logic.door_rules['TR Pokey 1 NW'], 2)
val_rule(key_logic.door_rules['TR Crystaroller Down Stairs'], 5) val_rule(key_logic.door_rules['TR Chain Chomps Down Stairs'], 3)
val_rule(key_logic.door_rules['TR Dash Bridge WS'], 6) val_rule(key_logic.door_rules['TR Pokey 2 ES'], 6, True, 'Turtle Rock - Big Key Chest', 4, {'Turtle Rock - Big Key Chest'})
assert world.get_location('Turtle Rock - Eye Bridge - Bottom Right', player) in key_logic.bk_restricted val_rule(key_logic.door_rules['TR Crystaroller Down Stairs'], 5)
assert world.get_location('Turtle Rock - Eye Bridge - Top Left', player) in key_logic.bk_restricted val_rule(key_logic.door_rules['TR Dash Bridge WS'], 6)
assert world.get_location('Turtle Rock - Eye Bridge - Top Right', player) in key_logic.bk_restricted assert world.get_location('Turtle Rock - Eye Bridge - Bottom Right', player) in key_logic.bk_restricted
assert world.get_location('Turtle Rock - Eye Bridge - Bottom Left', player) in key_logic.bk_restricted assert world.get_location('Turtle Rock - Eye Bridge - Top Left', player) in key_logic.bk_restricted
assert world.get_location('Turtle Rock - Boss', player) in key_logic.bk_restricted assert world.get_location('Turtle Rock - Eye Bridge - Top Right', player) in key_logic.bk_restricted
assert world.get_location('Turtle Rock - Crystaroller Room', player) in key_logic.bk_restricted assert world.get_location('Turtle Rock - Eye Bridge - Bottom Left', player) in key_logic.bk_restricted
assert world.get_location('Turtle Rock - Big Chest', player) in key_logic.bk_restricted assert world.get_location('Turtle Rock - Boss', player) in key_logic.bk_restricted
assert len(key_logic.bk_restricted) == 7 assert world.get_location('Turtle Rock - Crystaroller Room', player) in key_logic.bk_restricted
assert world.get_location('Turtle Rock - Big Chest', player) in key_logic.bk_restricted
assert len(key_logic.bk_restricted) == 7
def val_ganons(key_logic, world, player): def val_ganons(key_logic, world, player):

View File

@@ -23,7 +23,8 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute
from ItemList import generate_itempool, difficulties, fill_prizes from ItemList import generate_itempool, difficulties, fill_prizes
from Utils import output_path, parse_player_names from Utils import output_path, parse_player_names
__version__ = '0.0.7-pre' __version__ = '0.0.9-pre'
def main(args, seed=None): def main(args, seed=None):
if args.outputpath: if args.outputpath:

View File

@@ -3,6 +3,7 @@ import logging
import random import random
import urllib.request import urllib.request
import urllib.parse import urllib.parse
import re
from DungeonRandomizer import parse_arguments from DungeonRandomizer import parse_arguments
from Main import main as DRMain from Main import main as DRMain
@@ -14,6 +15,7 @@ def parse_yaml(txt):
ret = {} ret = {}
indents = {len(txt) - len(txt.lstrip(' ')): ret} indents = {len(txt) - len(txt.lstrip(' ')): ret}
for line in txt.splitlines(): for line in txt.splitlines():
line = re.sub(r'#.*', '', line)
if not line: if not line:
continue continue
name, val = line.split(':', 1) name, val = line.split(':', 1)

31
Rom.py
View File

@@ -557,7 +557,7 @@ def patch_rom(world, rom, player, team, enemized):
# todo fix screen scrolling # todo fix screen scrolling
if world.shuffle[player] not in ['insanity', 'insanity_legacy', 'madness_legacy'] and \ if world.shuffle[player] not in ['insanity', 'insanity_legacy', 'madness_legacy'] and \
exit.name in ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', 'Skull Woods Final Section Exit', 'Ice Palace Exit', 'Misery Mire Exit', exit.name in ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', 'Ice Palace Exit', 'Misery Mire Exit',
'Palace of Darkness Exit', 'Swamp Palace Exit', 'Ganons Tower Exit', 'Desert Palace Exit (North)', 'Agahnims Tower Exit', 'Spiral Cave Exit (Top)', '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.
@@ -608,16 +608,10 @@ def patch_rom(world, rom, player, team, enemized):
for paired_door in world.paired_doors[player]: for paired_door in world.paired_doors[player]:
rom.write_bytes(paired_door.address_a(world, player), paired_door.rom_data_a(world, player)) rom.write_bytes(paired_door.address_a(world, player), paired_door.rom_data_a(world, player))
rom.write_bytes(paired_door.address_b(world, player), paired_door.rom_data_b(world, player)) rom.write_bytes(paired_door.address_b(world, player), paired_door.rom_data_b(world, player))
if world.fix_skullwoods_exit and world.shuffle in ['vanilla', 'simple', 'restricted', 'dungeonssimple']:
connect = world.get_entrance('Skull Woods Final Section', player).connected_region # fix skull woods exit, if not fixed during exit patching
exit_name = None if world.fix_skullwoods_exit[player] and world.shuffle[player] == 'vanilla':
for ext in connect.exits: write_int16(rom, 0x15DB5 + 2 * exit_ids['Skull Woods Final Section Exit'][1], 0x00F8)
if ext.connected_region.name == 'Skull Woods Forest (West)':
exit_name = ext.name
break
if exit_name is not None and exit_name == 'Skull Woods Final Section Exit':
rom.write_int16(0x15DB5 + 2 * exit_ids['Skull Woods Final Section Exit'][1], 0x00F8)
# todo: fix other exits if ER enabled and similar situation happens
write_custom_shops(rom, world, player) write_custom_shops(rom, world, player)
@@ -2102,8 +2096,19 @@ def compass_code_good(rom):
def update_compasses(rom, world, player): def update_compasses(rom, world, player):
layouts = world.dungeon_layouts[player] layouts = world.dungeon_layouts[player]
# cmp XX : bne escape
# cpy 32 : bne escape
# brl .itemCounts
# c9 02 d0 eastern
# nop #2
new_code = [0x07, 0xC0, 0x32, 0xD0, 0x03, 0x82, 0xB9, 0x01, 0xC9, 0x02, 0xD0, 0x10, 0xEA, 0xEA]
rom.write_bytes(compass_w_addr + 8, new_code)
# 05 06 07 08
# C9 00 D0 02 80 04 C9 02 D0 15 C0 32 D0 03 82 B3 01
# C9 XX D0 07 C0 32 D0 03 82 B9 01 C9 02 D0 10 EA EA
for name, builder in layouts.items(): for name, builder in layouts.items():
digit_offset, sram_byte, write_offset, jmp_nop_flag = compass_data[name] digit_offset, sram_byte, write_offset, jmp_nop_flag, dungeon_id = compass_data[name]
digit1 = builder.location_cnt // 10 digit1 = builder.location_cnt // 10
digit2 = builder.location_cnt % 10 digit2 = builder.location_cnt % 10
rom.write_byte(compass_r_addr+digit_offset, 0x90+digit1) rom.write_byte(compass_r_addr+digit_offset, 0x90+digit1)
@@ -2128,6 +2133,8 @@ def update_compasses(rom, world, player):
else: else:
for i in range(0, jmp_nop_flag): for i in range(0, jmp_nop_flag):
rom.write_byte(write_address+9+i, 0xea) # nop rom.write_byte(write_address+9+i, 0xea) # nop
if builder.bk_provided:
rom.write_byte(compass_w_addr+6, dungeon_id)
InconvenientDungeonEntrances = {'Turtle Rock': 'Turtle Rock Main', InconvenientDungeonEntrances = {'Turtle Rock': 'Turtle Rock Main',

View File

@@ -239,6 +239,8 @@ def create_rooms(world, player):
world.get_room(0x61, player).swap(5, 6) # puts the Incognito Entrance at the end, so it can be deleted world.get_room(0x61, player).swap(5, 6) # puts the Incognito Entrance at the end, so it can be deleted
world.get_room(0x62, player).swap(1, 4) # puts the exit at pos 1 - enables pos 3 world.get_room(0x62, player).swap(1, 4) # puts the exit at pos 1 - enables pos 3
world.get_room(0x77, player).swap(0, 1) # fixes Hera Lobby Key Stairs - entrance now at pos 0 world.get_room(0x77, player).swap(0, 1) # fixes Hera Lobby Key Stairs - entrance now at pos 0
if world.enemy_shuffle[player] != 'none':
world.get_room(0xc0, player).change(0, DoorKind.Normal) # fix this kill room if enemizer is on
class Room(object): class Room(object):

View File

@@ -131,12 +131,12 @@ def global_rules(world, player):
set_rule(world.get_location('Spike Cave', player), lambda state: set_rule(world.get_location('Spike Cave', player), lambda state:
state.has('Hammer', player) and state.can_lift_rocks(player) and state.has('Hammer', player) and state.can_lift_rocks(player) and
((state.has('Cape', player) and state.can_extend_magic(player, 16, True)) or ((state.has('Cape', player) and state.can_extend_magic(player, 16, True)) or
(state.has('Cane of Byrna', player) and (state.has('Cane of Byrna', player) and
(state.can_extend_magic(player, 12, True) or (state.can_extend_magic(player, 12, True) or
(state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4)))))) (state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4))))))
) )
set_rule(world.get_location('Hookshot Cave - Top Right', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_location('Hookshot Cave - Top Right', player), lambda state: state.has('Hookshot', player))
set_rule(world.get_location('Hookshot Cave - Top Left', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_location('Hookshot Cave - Top Left', player), lambda state: state.has('Hookshot', player))
@@ -217,6 +217,7 @@ def global_rules(world, player):
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Prize', player)) set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Prize', player))
# blind can't have the small key? - not necessarily true anymore - but likely still # blind can't have the small key? - not necessarily true anymore - but likely still
set_rule(world.get_location('Thieves\' Town - Big Chest', player), lambda state: state.has('Hammer', player))
for entrance in ['Thieves Basement Block Path', 'Thieves Blocked Entry Path', 'Thieves Conveyor Block Path', 'Thieves Conveyor Bridge Block Path']: for entrance in ['Thieves Basement Block Path', 'Thieves Blocked Entry Path', 'Thieves Conveyor Block Path', 'Thieves Conveyor Bridge Block Path']:
set_rule(world.get_entrance(entrance, player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance(entrance, player), lambda state: state.can_lift_rocks(player))
for location in ['Thieves\' Town - Blind\'s Cell', 'Thieves\' Town - Boss']: for location in ['Thieves\' Town - Blind\'s Cell', 'Thieves\' Town - Boss']:
@@ -363,7 +364,7 @@ def global_rules(world, player):
add_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player)) add_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player))
set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon[player], player) set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon[player], player)
and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times
set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player)) # need to damage ganon to get tiles to drop set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player)) # need to damage ganon to get tiles to drop