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('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_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_trock_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
set_player_attr('can_access_trock_eyebridge', None)

View File

@@ -55,6 +55,9 @@ def link_doors(world, player):
cross_dungeon(world, player)
elif world.doorShuffle[player] == 'experimental':
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':
create_door_spoiler(world, player)
@@ -146,6 +149,7 @@ def vanilla_key_logic(world, player):
analyze_dungeon(key_layout, world, player)
world.key_logic[player][builder.name] = key_layout.key_logic
last_key = None
if world.shuffle[player] == 'vanilla':
validate_vanilla_key_logic(world, player)
@@ -2023,18 +2027,19 @@ default_one_way_connections = [
]
# For crossed
compass_data = { # offset from 0x122e17, sram storage, write offset from compass_w_addr, 0 = jmp or # of nops
'Hyrule Castle': (0x1, 0xc0, 0x16, 0),
'Eastern Palace': (0x1C, 0xc1, 0x28, 0),
'Desert Palace': (0x35, 0xc2, 0x4a, 0),
'Agahnims Tower': (0x51, 0xc3, 0x5c, 0),
'Swamp Palace': (0x6A, 0xc4, 0x7e, 0),
'Palace of Darkness': (0x83, 0xc5, 0xa4, 0),
'Misery Mire': (0x9C, 0xc6, 0xca, 0),
'Skull Woods': (0xB5, 0xc7, 0xf0, 0),
'Ice Palace': (0xD0, 0xc8, 0x102, 0),
'Tower of Hera': (0xEB, 0xc9, 0x114, 0),
'Thieves Town': (0x106, 0xca, 0x138, 0),
'Turtle Rock': (0x11F, 0xcb, 0x15e, 0),
'Ganons Tower': (0x13A, 0xcc, 0x170, 2)
# offset from 0x122e17, sram storage, write offset from compass_w_addr, 0 = jmp or # of nops, dungeon_id
compass_data = {
'Hyrule Castle': (0x1, 0xc0, 0x16, 0, 0x02),
'Eastern Palace': (0x1C, 0xc1, 0x28, 0, 0x04),
'Desert Palace': (0x35, 0xc2, 0x4a, 0, 0x06),
'Agahnims Tower': (0x51, 0xc3, 0x5c, 0, 0x08),
'Swamp Palace': (0x6A, 0xc4, 0x7e, 0, 0x0a),
'Palace of Darkness': (0x83, 0xc5, 0xa4, 0, 0x0c),
'Misery Mire': (0x9C, 0xc6, 0xca, 0, 0x0e),
'Skull Woods': (0xB5, 0xc7, 0xf0, 0, 0x10),
'Ice Palace': (0xD0, 0xc8, 0x102, 0, 0x12),
'Tower of Hera': (0xEB, 0xc9, 0x114, 0, 0x14),
'Thieves Town': (0x106, 0xca, 0x138, 0, 0x16),
'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.
(default: %(default)s)
''')
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('--quickswap', default=defval(False), help='Enable quick item swapping with L and R.', 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('--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')

View File

@@ -550,7 +550,7 @@ def link_entrances(world, player):
('North Fairy Cave Exit', 'North Fairy Cave'),
('Lost Woods Hideout Exit', 'Lost Woods Hideout (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':
# cannot move uncle cave
@@ -587,7 +587,7 @@ def link_entrances(world, player):
else:
sw_hole_pool = dw_hole_entrances
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)
# 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',
'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)',
'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop',
'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']
# tavern back door cannot be shuffled yet
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',
'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)',
'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop',
'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']
if world.mode[player] == 'standard':
# 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',
'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)',
'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop',
'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']
# tavern back door cannot be shuffled yet
connect_doors(world, ['Tavern North'], ['Tavern'], player)
@@ -3780,8 +3780,8 @@ exit_ids = {'Links House Exit': (0x01, 0x00),
'Lost Woods Hideout (top)': 0x7A,
'Lumberjack Tree (top)': 0x7F,
'Sewer Drop': 0x81,
'Skull Woods Second Section (Drop)': 0x79,
'Skull Woods First Section (Left)': 0x77,
'Skull Woods First Section (Right)': 0x78,
'Skull Woods First Section (Top)': 0x76,
'Skull Back Drop': 0x79,
'Skull Left Drop': 0x77,
'Skull Pinball': 0x78,
'Skull Pot Circle': 0x76,
'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):
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 state.key_locations - state.used_smalls
@@ -1146,6 +1147,8 @@ def val_mire(key_logic, world, player):
def val_turtle(key_logic, world, player):
# todo: check vanilla key logic when TR back doors are accessible
if world.shuffle[player] == 'vanilla' and world.mode[player] != 'inverted':
val_rule(key_logic.door_rules['TR Hub NW'], 1)
val_rule(key_logic.door_rules['TR Pokey 1 NW'], 2)
val_rule(key_logic.door_rules['TR Chain Chomps Down Stairs'], 3)

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 Utils import output_path, parse_player_names
__version__ = '0.0.7-pre'
__version__ = '0.0.9-pre'
def main(args, seed=None):
if args.outputpath:

View File

@@ -3,6 +3,7 @@ import logging
import random
import urllib.request
import urllib.parse
import re
from DungeonRandomizer import parse_arguments
from Main import main as DRMain
@@ -14,6 +15,7 @@ def parse_yaml(txt):
ret = {}
indents = {len(txt) - len(txt.lstrip(' ')): ret}
for line in txt.splitlines():
line = re.sub(r'#.*', '', line)
if not line:
continue
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
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)',
'Superbunny Cave Exit (Bottom)', 'Turtle Rock Ledge Exit (East)']:
# 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]:
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))
if world.fix_skullwoods_exit and world.shuffle in ['vanilla', 'simple', 'restricted', 'dungeonssimple']:
connect = world.get_entrance('Skull Woods Final Section', player).connected_region
exit_name = None
for ext in connect.exits:
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
# fix skull woods exit, if not fixed during exit patching
if world.fix_skullwoods_exit[player] and world.shuffle[player] == 'vanilla':
write_int16(rom, 0x15DB5 + 2 * exit_ids['Skull Woods Final Section Exit'][1], 0x00F8)
write_custom_shops(rom, world, player)
@@ -2102,8 +2096,19 @@ def compass_code_good(rom):
def update_compasses(rom, world, 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():
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
digit2 = builder.location_cnt % 10
rom.write_byte(compass_r_addr+digit_offset, 0x90+digit1)
@@ -2128,6 +2133,8 @@ def update_compasses(rom, world, player):
else:
for i in range(0, jmp_nop_flag):
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',

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(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
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):

View File

@@ -217,6 +217,7 @@ def global_rules(world, 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
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']:
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']: