Big key door fix
Some generation fixes (need to look at pre-validate some more) Bumped up escape assist values in non-basic shuffles
This commit is contained in:
@@ -1018,7 +1018,8 @@ def main_dungeon_generation(dungeon_builders, recombinant_builders, connections_
|
|||||||
find_standard_origins(builder, recombinant_builders, origin_list)
|
find_standard_origins(builder, recombinant_builders, origin_list)
|
||||||
find_enabled_origins(builder.sectors, enabled_entrances, origin_list, entrances_map, name)
|
find_enabled_origins(builder.sectors, enabled_entrances, origin_list, entrances_map, name)
|
||||||
split_dungeon = treat_split_as_whole_dungeon(split_dungeon, name, origin_list, world, player)
|
split_dungeon = treat_split_as_whole_dungeon(split_dungeon, name, origin_list, world, player)
|
||||||
if len(origin_list) <= 0 or not pre_validate(builder, origin_list, split_dungeon, world, player):
|
# todo: figure out pre-validate, ensure all needed origins are enabled?
|
||||||
|
if len(origin_list) <= 0: # or not pre_validate(builder, origin_list, split_dungeon, world, player):
|
||||||
if last_key == builder.name or loops > 1000:
|
if last_key == builder.name or loops > 1000:
|
||||||
origin_name = world.get_region(origin_list[0], player).entrances[0].parent_region.name if len(origin_list) > 0 else 'no origin'
|
origin_name = world.get_region(origin_list[0], player).entrances[0].parent_region.name if len(origin_list) > 0 else 'no origin'
|
||||||
raise GenerationException(f'Infinite loop detected for "{builder.name}" located at {origin_name}')
|
raise GenerationException(f'Infinite loop detected for "{builder.name}" located at {origin_name}')
|
||||||
@@ -1068,14 +1069,14 @@ def determine_entrance_list(world, player):
|
|||||||
connections = {}
|
connections = {}
|
||||||
for key, portal_list in dungeon_portals.items():
|
for key, portal_list in dungeon_portals.items():
|
||||||
entrance_map[key] = []
|
entrance_map[key] = []
|
||||||
r_names = {}
|
r_names = []
|
||||||
if key in dungeon_drops.keys():
|
if key in dungeon_drops.keys():
|
||||||
for drop in dungeon_drops[key]:
|
for drop in dungeon_drops[key]:
|
||||||
r_names[drop] = None
|
r_names.append((drop, None))
|
||||||
for portal_name in portal_list:
|
for portal_name in portal_list:
|
||||||
portal = world.get_portal(portal_name, player)
|
portal = world.get_portal(portal_name, player)
|
||||||
r_names[portal.door.entrance.parent_region.name] = portal
|
r_names.append((portal.door.entrance.parent_region.name, portal))
|
||||||
for region_name, portal in r_names.items():
|
for region_name, portal in r_names:
|
||||||
if portal:
|
if portal:
|
||||||
region = world.get_region(portal.name + ' Portal', player)
|
region = world.get_region(portal.name + ' Portal', player)
|
||||||
else:
|
else:
|
||||||
@@ -2160,11 +2161,16 @@ def find_valid_trap_combination(builder, suggested, start_regions, paths, world,
|
|||||||
# eliminate start region if portal marked as destination
|
# eliminate start region if portal marked as destination
|
||||||
def filter_start_regions(builder, start_regions, world, player):
|
def filter_start_regions(builder, start_regions, world, player):
|
||||||
std_flag = world.mode[player] == 'standard' and builder.name == 'Hyrule Castle'
|
std_flag = world.mode[player] == 'standard' and builder.name == 'Hyrule Castle'
|
||||||
excluded = {}
|
excluded = {} # todo: drop lobbies, might be better to white list instead (two entrances per region)
|
||||||
for region in start_regions:
|
for region in start_regions:
|
||||||
portal = next((x for x in world.dungeon_portals[player] if x.door.entrance.parent_region == region), None)
|
portal = next((x for x in world.dungeon_portals[player] if x.door.entrance.parent_region == region), None)
|
||||||
if portal and portal.destination:
|
if portal and portal.destination:
|
||||||
excluded[region] = None
|
# make sure that a drop is not accessible for this "destination"
|
||||||
|
drop_region = next((x.parent_region for x in region.entrances
|
||||||
|
if x.parent_region.type in [RegionType.LightWorld, RegionType.DarkWorld]
|
||||||
|
or x.parent_region.name == 'Sewer Drop'), None)
|
||||||
|
if not drop_region:
|
||||||
|
excluded[region] = None
|
||||||
if std_flag and (not portal or portal.find_portal_entrance().parent_region.name != 'Hyrule Castle Courtyard'):
|
if std_flag and (not portal or portal.find_portal_entrance().parent_region.name != 'Hyrule Castle Courtyard'):
|
||||||
excluded[region] = None
|
excluded[region] = None
|
||||||
return [x for x in start_regions if x not in excluded.keys()]
|
return [x for x in start_regions if x not in excluded.keys()]
|
||||||
|
|||||||
@@ -1356,7 +1356,8 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge
|
|||||||
sanc_builder = random.choice(lw_builders)
|
sanc_builder = random.choice(lw_builders)
|
||||||
assign_sector(sanc, sanc_builder, candidate_sectors, global_pole)
|
assign_sector(sanc, sanc_builder, candidate_sectors, global_pole)
|
||||||
|
|
||||||
bow_sectors, retro_std_flag = {}, world.bow_mode[player].startswith('retro') and world.mode[player] == 'standard'
|
retro_std_flag = world.bow_mode[player].startswith('retro') and world.mode[player] == 'standard'
|
||||||
|
non_hc_sectors = {}
|
||||||
free_location_sectors = {}
|
free_location_sectors = {}
|
||||||
crystal_switches = {}
|
crystal_switches = {}
|
||||||
crystal_barriers = {}
|
crystal_barriers = {}
|
||||||
@@ -1364,7 +1365,9 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge
|
|||||||
neutral_sectors = {}
|
neutral_sectors = {}
|
||||||
for sector in candidate_sectors:
|
for sector in candidate_sectors:
|
||||||
if retro_std_flag and 'Bow' in sector.item_logic: # these need to be distributed outside of HC
|
if retro_std_flag and 'Bow' in sector.item_logic: # these need to be distributed outside of HC
|
||||||
bow_sectors[sector] = None
|
non_hc_sectors[sector] = None
|
||||||
|
elif world.mode[player] == 'standard' and 'Open Floodgate' in sector.item_logic:
|
||||||
|
non_hc_sectors[sector] = None
|
||||||
elif sector.chest_locations > 0:
|
elif sector.chest_locations > 0:
|
||||||
free_location_sectors[sector] = None
|
free_location_sectors[sector] = None
|
||||||
elif sector.c_switch:
|
elif sector.c_switch:
|
||||||
@@ -1375,8 +1378,8 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge
|
|||||||
neutral_sectors[sector] = None
|
neutral_sectors[sector] = None
|
||||||
else:
|
else:
|
||||||
polarized_sectors[sector] = None
|
polarized_sectors[sector] = None
|
||||||
if bow_sectors:
|
if non_hc_sectors:
|
||||||
assign_bow_sectors(dungeon_map, bow_sectors, global_pole)
|
assign_non_hc_sectors(dungeon_map, non_hc_sectors, global_pole)
|
||||||
leftover = assign_location_sectors_minimal(dungeon_map, free_location_sectors, global_pole, world, player)
|
leftover = assign_location_sectors_minimal(dungeon_map, free_location_sectors, global_pole, world, player)
|
||||||
free_location_sectors = scatter_extra_location_sectors(dungeon_map, leftover, global_pole)
|
free_location_sectors = scatter_extra_location_sectors(dungeon_map, leftover, global_pole)
|
||||||
for sector in free_location_sectors:
|
for sector in free_location_sectors:
|
||||||
@@ -1420,7 +1423,8 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge
|
|||||||
def standard_stair_check(dungeon_map, dungeon, candidate_sectors, global_pole):
|
def standard_stair_check(dungeon_map, dungeon, candidate_sectors, global_pole):
|
||||||
# this is because there must be at least one non-dead stairway in hc to get out
|
# this is because there must be at least one non-dead stairway in hc to get out
|
||||||
# this check may not be necessary
|
# this check may not be necessary
|
||||||
filtered_sectors = [x for x in candidate_sectors if any(y for y in x.outstanding_doors if not y.dead and y.type == DoorType.SpiralStairs)]
|
filtered_sectors = [x for x in candidate_sectors if 'Open Floodgate' not in x.item_logic and
|
||||||
|
any(y for y in x.outstanding_doors if not y.dead and y.type == DoorType.SpiralStairs)]
|
||||||
valid = False
|
valid = False
|
||||||
while not valid:
|
while not valid:
|
||||||
chosen_sector = random.choice(filtered_sectors)
|
chosen_sector = random.choice(filtered_sectors)
|
||||||
@@ -1550,7 +1554,7 @@ def define_sector_features(sectors):
|
|||||||
sector.bk_required = True
|
sector.bk_required = True
|
||||||
for ext in region.exits:
|
for ext in region.exits:
|
||||||
door = ext.door
|
door = ext.door
|
||||||
if door is not None:
|
if door is not None and not door.blocked:
|
||||||
if door.crystal == CrystalBarrier.Either:
|
if door.crystal == CrystalBarrier.Either:
|
||||||
sector.c_switch = True
|
sector.c_switch = True
|
||||||
elif door.crystal == CrystalBarrier.Orange:
|
elif door.crystal == CrystalBarrier.Orange:
|
||||||
@@ -1562,6 +1566,8 @@ def define_sector_features(sectors):
|
|||||||
if region.name in ['PoD Mimics 2', 'PoD Bow Statue Right', 'PoD Mimics 1', 'GT Mimics 1', 'GT Mimics 2',
|
if region.name in ['PoD Mimics 2', 'PoD Bow Statue Right', 'PoD Mimics 1', 'GT Mimics 1', 'GT Mimics 2',
|
||||||
'Eastern Single Eyegore', 'Eastern Duo Eyegores']:
|
'Eastern Single Eyegore', 'Eastern Duo Eyegores']:
|
||||||
sector.item_logic.add('Bow')
|
sector.item_logic.add('Bow')
|
||||||
|
if region.name in ['Swamp Lobby', 'Swamp Entrance']:
|
||||||
|
sector.item_logic.add('Open Floodgate')
|
||||||
|
|
||||||
|
|
||||||
def assign_sector(sector, dungeon, candidate_sectors, global_pole):
|
def assign_sector(sector, dungeon, candidate_sectors, global_pole):
|
||||||
@@ -1613,8 +1619,8 @@ def find_sector(r_name, sectors):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def assign_bow_sectors(dungeon_map, bow_sectors, global_pole):
|
def assign_non_hc_sectors(dungeon_map, non_hc_sectors, global_pole):
|
||||||
sector_list = list(bow_sectors)
|
sector_list = list(non_hc_sectors)
|
||||||
random.shuffle(sector_list)
|
random.shuffle(sector_list)
|
||||||
population = []
|
population = []
|
||||||
for name in dungeon_map:
|
for name in dungeon_map:
|
||||||
@@ -1623,7 +1629,7 @@ def assign_bow_sectors(dungeon_map, bow_sectors, global_pole):
|
|||||||
choices = random.choices(population, k=len(sector_list))
|
choices = random.choices(population, k=len(sector_list))
|
||||||
for i, choice in enumerate(choices):
|
for i, choice in enumerate(choices):
|
||||||
builder = dungeon_map[choice]
|
builder = dungeon_map[choice]
|
||||||
assign_sector(sector_list[i], builder, bow_sectors, global_pole)
|
assign_sector(sector_list[i], builder, non_hc_sectors, global_pole)
|
||||||
|
|
||||||
|
|
||||||
def scatter_extra_location_sectors(dungeon_map, free_location_sectors, global_pole):
|
def scatter_extra_location_sectors(dungeon_map, free_location_sectors, global_pole):
|
||||||
@@ -3511,7 +3517,8 @@ def check_for_valid_layout(builder, sector_list, builder_info):
|
|||||||
for portal in world.dungeon_portals[player]:
|
for portal in world.dungeon_portals[player]:
|
||||||
if not portal.destination and portal.name in dungeon_portals[builder.name]:
|
if not portal.destination and portal.name in dungeon_portals[builder.name]:
|
||||||
possible_regions.add(portal.door.entrance.parent_region.name)
|
possible_regions.add(portal.door.entrance.parent_region.name)
|
||||||
if builder.name in dungeon_drops.keys():
|
if builder.name in dungeon_drops.keys() and (builder.name != 'Hyrule Castle'
|
||||||
|
or world.mode[player] != 'standard'):
|
||||||
possible_regions.update(dungeon_drops[builder.name])
|
possible_regions.update(dungeon_drops[builder.name])
|
||||||
independents = find_independent_entrances(possible_regions, world, player)
|
independents = find_independent_entrances(possible_regions, world, player)
|
||||||
for name, split_build in builder.split_dungeon_map.items():
|
for name, split_build in builder.split_dungeon_map.items():
|
||||||
|
|||||||
2
Fill.py
2
Fill.py
@@ -289,7 +289,7 @@ def last_ditch_placement(item_to_place, locations, world, state, base_state, ite
|
|||||||
possible_swaps = [x for x in state.locations_checked if x.item.type == 'Crystal']
|
possible_swaps = [x for x in state.locations_checked if x.item.type == 'Crystal']
|
||||||
else:
|
else:
|
||||||
possible_swaps = [x for x in state.locations_checked
|
possible_swaps = [x for x in state.locations_checked
|
||||||
if x.item.type not in ['Event', 'Crystal'] and not x.forced_item]
|
if x.item.type not in ['Event', 'Crystal'] and not x.forced_item and not x.locked]
|
||||||
swap_locations = sorted(possible_swaps, key=location_preference)
|
swap_locations = sorted(possible_swaps, key=location_preference)
|
||||||
return try_possible_swaps(swap_locations, item_to_place, locations, world, base_state, itempool,
|
return try_possible_swaps(swap_locations, item_to_place, locations, world, base_state, itempool,
|
||||||
key_pool, single_player_placement)
|
key_pool, single_player_placement)
|
||||||
|
|||||||
8
Rom.py
8
Rom.py
@@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127
|
|||||||
|
|
||||||
|
|
||||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||||
RANDOMIZERBASEHASH = '61c296effe6180274721d570d2471e1c'
|
RANDOMIZERBASEHASH = '5639de3bfd500ba238d3f27ea78c19e1'
|
||||||
|
|
||||||
|
|
||||||
class JsonRom(object):
|
class JsonRom(object):
|
||||||
@@ -1492,8 +1492,10 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
|||||||
if world.doorShuffle[player] not in ['vanilla', 'basic']:
|
if world.doorShuffle[player] not in ['vanilla', 'basic']:
|
||||||
# Uncle respawn refills (magic, bombs, arrows)
|
# Uncle respawn refills (magic, bombs, arrows)
|
||||||
rom.write_bytes(0x180185, [max(0x20, magic_max), max(3, bomb_max), max(10, bow_max)])
|
rom.write_bytes(0x180185, [max(0x20, magic_max), max(3, bomb_max), max(10, bow_max)])
|
||||||
rom.write_bytes(0x180188, [0x20, 3, 10]) # Zelda respawn refills (magic, bombs, arrows)
|
# Zelda respawn refills (magic, bombs, arrows)
|
||||||
rom.write_bytes(0x18018B, [0x20, 3, 10]) # Mantle respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x180188, [max(0x20, magic_max), max(3, bomb_max), max(10, bow_max)])
|
||||||
|
# Mantle respawn refills (magic, bombs, arrows)
|
||||||
|
rom.write_bytes(0x18018B, [max(0x20, magic_max), max(3, bomb_max), max(10, bow_max)])
|
||||||
elif world.doorShuffle[player] == 'basic': # just in case a bomb is needed to get to a chest
|
elif world.doorShuffle[player] == 'basic': # just in case a bomb is needed to get to a chest
|
||||||
rom.write_bytes(0x180185, [max(0x00, magic_max), max(3, bomb_max), max(0, bow_max)])
|
rom.write_bytes(0x180185, [max(0x00, magic_max), max(3, bomb_max), max(0, bow_max)])
|
||||||
rom.write_bytes(0x180188, [magic_small, 3, bow_small]) # Zelda respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x180188, [magic_small, 3, bow_small]) # Zelda respawn refills (magic, bombs, arrows)
|
||||||
|
|||||||
Binary file not shown.
@@ -58,15 +58,17 @@ def generate_dungeon_find_proposal(builder, entrance_region_names, split_dungeon
|
|||||||
excluded[region] = None
|
excluded[region] = None
|
||||||
elif split_dungeon and builder.sewers_access and builder.sewers_access.entrance.parent_region == region:
|
elif split_dungeon and builder.sewers_access and builder.sewers_access.entrance.parent_region == region:
|
||||||
continue
|
continue
|
||||||
elif len(region.entrances) == 1: # for holes
|
drop_region = next((x.parent_region for x in region.entrances
|
||||||
access_region = next(x.parent_region for x in region.entrances
|
if x.parent_region.type in [RegionType.LightWorld, RegionType.DarkWorld]
|
||||||
if x.parent_region.type in [RegionType.LightWorld, RegionType.DarkWorld]
|
or x.parent_region.name == 'Sewer Drop'), None)
|
||||||
or x.parent_region.name == 'Sewer Drop')
|
if drop_region: # for holes
|
||||||
if access_region.name == 'Sewer Drop':
|
if drop_region.name == 'Sewer Drop':
|
||||||
access_region = next(x.parent_region for x in access_region.entrances)
|
drop_region = next(x.parent_region for x in drop_region.entrances)
|
||||||
if (access_region.name in world.inaccessible_regions[player] and
|
if (drop_region.name in world.inaccessible_regions[player] and
|
||||||
region.name not in world.enabled_entrances[player]):
|
region.name not in world.enabled_entrances[player]):
|
||||||
excluded[region] = None
|
excluded[region] = None
|
||||||
|
elif region in excluded:
|
||||||
|
del excluded[region]
|
||||||
entrance_regions = [x for x in entrance_regions if x not in excluded.keys()]
|
entrance_regions = [x for x in entrance_regions if x not in excluded.keys()]
|
||||||
doors_to_connect, idx = {}, 0
|
doors_to_connect, idx = {}, 0
|
||||||
all_regions = set()
|
all_regions = set()
|
||||||
@@ -315,9 +317,9 @@ def determine_paths_for_dungeon(world, player, all_regions, name):
|
|||||||
non_hole_portals.append(portal.door.entrance.parent_region.name)
|
non_hole_portals.append(portal.door.entrance.parent_region.name)
|
||||||
if portal.destination:
|
if portal.destination:
|
||||||
paths.append(portal.door.entrance.parent_region.name)
|
paths.append(portal.door.entrance.parent_region.name)
|
||||||
if world.mode[player] == 'standard' and name == 'Hyrule Castle':
|
if world.mode[player] == 'standard' and name == 'Hyrule Castle Dungeon':
|
||||||
paths.append('Hyrule Dungeon Cellblock')
|
paths.append('Hyrule Dungeon Cellblock')
|
||||||
paths.append(('Hyrule Dungeon Cellblock', 'Sanctuary'))
|
paths.append(('Hyrule Dungeon Cellblock', 'Hyrule Castle Throne Room'))
|
||||||
if world.doorShuffle[player] in ['basic'] and name == 'Thieves Town':
|
if world.doorShuffle[player] in ['basic'] and name == 'Thieves Town':
|
||||||
paths.append('Thieves Attic Window')
|
paths.append('Thieves Attic Window')
|
||||||
elif 'Thieves Attic Window' in all_r_names:
|
elif 'Thieves Attic Window' in all_r_names:
|
||||||
|
|||||||
Reference in New Issue
Block a user