Allow Zelda escape to use TT Maiden Cell as checkpoint

This commit is contained in:
codemann8
2025-09-03 02:50:20 -05:00
parent 808daf224d
commit a5f14530cd
10 changed files with 60 additions and 21 deletions

View File

@@ -76,6 +76,7 @@ class World(object):
self.can_take_damage = True
self.hints = hints.copy()
self.prizes = {}
self.default_zelda_region = {}
self.dynamic_regions = []
self.dynamic_locations = []
self.spoiler_mode = spoiler_mode
@@ -185,6 +186,7 @@ class World(object):
set_player_attr('standardize_palettes', 'standardize')
set_player_attr('force_fix', {'gt': False, 'sw': False, 'pod': False, 'tr': False})
set_player_attr('prizes', {'dig;': [], 'pull': [0, 0, 0], 'crab': [0, 0], 'stun': 0, 'fish': 0, 'enemies': []})
set_player_attr('default_zelda_region', 'Hyrule Dungeon Cellblock')
set_player_attr('exp_cache', defaultdict(dict))
set_player_attr('enabled_entrances', {})

View File

@@ -1302,8 +1302,12 @@ def create_doors(world, player):
world.get_door('Swamp Flooded Room Ladder', player).event('Swamp Drain')
if world.mode[player] == 'standard' and 'Zelda Herself' not in [i.name for i in world.precollected_items if i.player == player]:
world.get_door('Hyrule Castle Throne Room Tapestry', player).event('Zelda Pickup')
world.get_door('Hyrule Castle Tapestry Backwards', player).event('Zelda Pickup')
if world.default_zelda_region[player] == 'Thieves Blind\'s Cell':
zelda_location = 'Suspicious Maiden'
else:
zelda_location = 'Zelda Pickup'
world.get_door('Hyrule Castle Throne Room Tapestry', player).event(zelda_location)
world.get_door('Hyrule Castle Tapestry Backwards', player).event(zelda_location)
# crystal switches and barriers
world.get_door('Hera Lobby Crystal Exit', player).c_switch()

View File

@@ -586,13 +586,13 @@ def determine_paths_for_dungeon(world, player, all_regions, name):
paths.append(portal.door.entrance.parent_region.name)
if world.mode[player] == 'standard':
if name == 'Hyrule Castle':
paths.append('Hyrule Dungeon Cellblock')
paths.append(('Hyrule Dungeon Cellblock', 'Sanctuary'))
paths.append(world.default_zelda_region[player])
paths.append((world.default_zelda_region[player], 'Sanctuary'))
if name == 'Hyrule Castle Sewers':
paths.append('Sanctuary')
if name == 'Hyrule Castle Dungeon':
paths.append('Hyrule Dungeon Cellblock')
paths.append(('Hyrule Dungeon Cellblock', 'Hyrule Castle Throne Room'))
paths.append(world.default_zelda_region[player])
paths.append((world.default_zelda_region[player], 'Hyrule Castle Throne Room'))
if world.doorShuffle[player] in ['basic'] and name == 'Thieves Town':
paths.append('Thieves Attic Window')
elif 'Thieves Attic Window' in all_r_names:
@@ -1322,7 +1322,7 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge
for r_name in dungeon_boss_sectors[key]:
assign_sector(find_sector(r_name, candidate_sectors), current_dungeon, candidate_sectors, global_pole)
if key == 'Hyrule Castle' and world.mode[player] == 'standard':
for r_name in ['Hyrule Dungeon Cellblock', 'Sanctuary', 'Hyrule Castle Throne Room']: # need to deliver zelda
for r_name in [world.default_zelda_region[player], 'Sanctuary', 'Hyrule Castle Throne Room']: # need to deliver zelda
assign_sector(find_sector(r_name, candidate_sectors), current_dungeon,
candidate_sectors, global_pole)
if key == 'Thieves Town' and (world.get_dungeon("Thieves Town", player).boss.enemizer_name == 'Blind'
@@ -3091,7 +3091,7 @@ def split_dungeon_builder(builder, split_list, builder_info):
if builder.name == 'Hyrule Castle':
assign_sector(find_sector('Hyrule Castle Throne Room', candidate_sectors),
dungeon_map['Hyrule Castle Dungeon'], candidate_sectors, global_pole)
assign_sector(find_sector('Hyrule Dungeon Cellblock', candidate_sectors),
assign_sector(find_sector(world.default_zelda_region[player], candidate_sectors),
dungeon_map['Hyrule Castle Dungeon'], candidate_sectors, global_pole)
dungeon_map['Hyrule Castle Dungeon'].throne_door = world.get_door('Hyrule Castle Throne Room N', player)
dungeon_map['Hyrule Castle Sewers'].sewers_access = builder.throne_door

View File

@@ -1676,7 +1676,7 @@ def set_event_item(world, player, location_name, item_name=None):
def shuffle_event_items(world, player):
if (world.shuffle_followers[player]):
if world.shuffle_followers[player]:
available_quests = follower_quests.copy()
available_pickups = [quests[0] for quests in available_quests.values()]
@@ -1688,11 +1688,14 @@ def shuffle_event_items(world, player):
available_pickups.remove(loc.item.name)
if world.mode[player] == 'standard':
if 'Zelda Herself' in available_pickups:
zelda_pickup = available_quests.pop('Zelda Pickup')[0]
available_pickups.remove(zelda_pickup)
set_event_item(world, player, 'Zelda Pickup', zelda_pickup)
if world.mode[player] == 'standard' and 'Zelda Herself' in available_pickups:
zelda_dropoff = 'Zelda Pickup'
if world.default_zelda_region[player] == 'Thieves Blind\'s Cell':
zelda_dropoff = 'Suspicious Maiden'
available_quests.pop(zelda_dropoff)
zelda_pickup = 'Zelda Herself'
available_pickups.remove(zelda_pickup)
set_event_item(world, player, zelda_dropoff, zelda_pickup)
random.shuffle(available_pickups)

View File

@@ -1805,7 +1805,10 @@ def imp_locations_factory(world, player):
return imp_locations
imp_locations = ['Agahnim 1', 'Agahnim 2', 'Attic Cracked Floor', 'Suspicious Maiden']
if world.mode[player] == 'standard':
imp_locations.append('Zelda Pickup')
if world.default_zelda_region[player] == 'Thieves Blinds\' Cell':
imp_locations.append('Suspicious Maiden')
else:
imp_locations.append('Zelda Pickup')
imp_locations.append('Zelda Drop Off')
return imp_locations

14
Rom.py
View File

@@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings
JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '93386b05ee4b5de6b9165941b9e14e97'
RANDOMIZERBASEHASH = '20e588b832011dcf15dbd31dff6955ce'
class JsonRom(object):
@@ -1581,6 +1581,18 @@ def patch_rom(world, rom, player, team, is_mystery=False):
rom.write_bytes(snes_to_pc(0x09A045), [0xEA, 0xEA]) # allow super bomb to follow into UW holes
rom.write_byte(snes_to_pc(0x09ACDF), 0x6B) # allow kiki/locksmith to follow after screen transition
if world.default_zelda_region[player] == 'Thieves Blind\'s Cell':
write_int16(rom, snes_to_pc(0x02D8D6), 0x45) # change zelda spawn point to maiden cell
rom.write_bytes(snes_to_pc(0x02D8F0), [0x08, 0x08, 0x08, 0x09, 0x0B, 0x0A, 0x0B, 0x0B])
write_int16(rom, snes_to_pc(0x02D91C), 0x0B00)
write_int16(rom, snes_to_pc(0x02D92A), 0x0800)
write_int16(rom, snes_to_pc(0x02D938), 0x0860)
write_int16(rom, snes_to_pc(0x02D946), 0x0B90)
write_int16(rom, snes_to_pc(0x02D954), 0x0078)
write_int16(rom, snes_to_pc(0x02D962), 0x017F)
rom.write_byte(snes_to_pc(0x02D975), 0x00)
rom.write_byte(snes_to_pc(0x02D98A), 0x02)
if world.enemy_shuffle[player] != 'none':
# informs zelda and maiden to draw over gfx slots that are guaranteed unused
rom.write_bytes(0x1802C1, world.data_tables[player].room_headers[0x80].free_gfx[0:2])

View File

@@ -1669,7 +1669,7 @@ def standard_rules(world, player):
def find_rules_for_zelda_delivery(world, player):
# path rules for backtracking
start_region = world.get_region('Hyrule Dungeon Cellblock', player)
start_region = world.get_region(world.default_zelda_region[player], player)
queue = deque([(start_region, [], [])])
visited = {start_region}
blank_state = CollectionState(world)

Binary file not shown.

View File

@@ -333,13 +333,13 @@ def determine_paths_for_dungeon(world, player, all_regions, name):
if portal.destination:
paths.append(portal.door.entrance.parent_region.name)
if world.mode[player] == 'standard' and name == 'Hyrule Castle Dungeon':
paths.append('Hyrule Dungeon Cellblock')
paths.append(('Hyrule Dungeon Cellblock', 'Hyrule Castle Throne Room'))
paths.append(world.default_zelda_region[player])
paths.append((world.default_zelda_region[player], 'Hyrule Castle Throne Room'))
entrance = next(x for x in world.dungeon_portals[player] if x.name == 'Hyrule Castle South')
# todo: in non-er, we can use the other portals too
paths.append(('Hyrule Dungeon Cellblock', entrance.door.entrance.parent_region.name))
paths.append((world.default_zelda_region[player], entrance.door.entrance.parent_region.name))
paths.append(('Hyrule Castle Throne Room', [entrance.door.entrance.parent_region.name,
'Hyrule Dungeon Cellblock']))
world.default_zelda_region[player]]))
if world.doorShuffle[player] in ['basic'] and name == 'Thieves Town':
paths.append('Thieves Attic Window')
elif 'Thieves Attic Window' in all_r_names:

View File

@@ -521,6 +521,21 @@ def randomize_enemies(world, player):
green_mail, blue_mail, red_mail = original_table[idx]
del original_table[idx]
world.data_tables[player].enemy_damage[i] = [green_mail, blue_mail, red_mail]
# determine default zelda follower location
if world.mode[player] == 'standard' and world.doorShuffle[player] == 'crossed' and world.shuffle_followers[player]:
def random_zelda():
world.default_zelda_region[player] = random.choice(['Hyrule Dungeon Cellblock', 'Thieves Blind\'s Cell'])
if world.customizer:
placements = world.customizer.get_placements()
if placements and player in placements and 'Zelda Herself' in placements[player].values():
location = [l for (l, item) in placements[player].items() if item == 'Zelda Herself'][0]
if location == 'Suspicious Maiden':
world.default_zelda_region[player] = 'Thieves Blind\'s Cell'
else:
random_zelda()
else:
random_zelda()
def write_enemy_shuffle_settings(world, player, rom):