Merged in DR v1.2.0.22

This commit is contained in:
codemann8
2023-11-18 17:49:41 -06:00
5 changed files with 94 additions and 76 deletions

View File

@@ -1800,7 +1800,7 @@ def imp_locations_factory(world, player):
imp_locations = ['Agahnim 1', 'Agahnim 2', 'Attic Cracked Floor', 'Suspicious Maiden'] imp_locations = ['Agahnim 1', 'Agahnim 2', 'Attic Cracked Floor', 'Suspicious Maiden']
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
imp_locations.append('Zelda Pickup') imp_locations.append('Zelda Pickup')
imp_locations.append('Zelda Dropoff') imp_locations.append('Zelda Drop Off')
return imp_locations return imp_locations

View File

@@ -36,7 +36,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new
from source.tools.BPS import create_bps_from_data from source.tools.BPS import create_bps_from_data
from source.classes.CustomSettings import CustomSettings from source.classes.CustomSettings import CustomSettings
version_number = '1.2.0.21' version_number = '1.2.0.22'
version_branch = '-u' version_branch = '-u'
__version__ = f'{version_number}{version_branch}' __version__ = f'{version_number}{version_branch}'

View File

@@ -109,6 +109,13 @@ These are now independent of retro mode and have three options: None, Random, an
# Bug Fixes and Notes # Bug Fixes and Notes
* 1.2.0.22u
* Flute can't be activated in rain state (except glitched modes) (Thanks codemann!)
* ER: Minor fix for Link's House on DM in Insanity (escape cave should not be re-used)
* Logic issues:
* Self-locking key not allowed in Sanctuary in standard (typo fixed)
* More advanced bunny-walking logic in dungeons (multiple paths considred)
* MSU: GTBK song fix for DR (Thanks codemann!)
* 1.2.0.21u * 1.2.0.21u
* Fix that should force items needed for leaving Zelda's cell to before the throne room, so S&Q isn't mandatory * Fix that should force items needed for leaving Zelda's cell to before the throne room, so S&Q isn't mandatory
* Small fix for Tavern Shuffle (thanks Catobat) * Small fix for Tavern Shuffle (thanks Catobat)

View File

@@ -128,9 +128,11 @@ def mirrorless_path_to_castle_courtyard(world, player):
queue.append((entrance.connected_region, new_path)) queue.append((entrance.connected_region, new_path))
seen.add(entrance.connected_region) seen.add(entrance.connected_region)
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): 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 # 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)) set_rule(location, lambda state: location.parent_region.dungeon.boss.can_defeat(state))
@@ -139,6 +141,7 @@ def set_defeat_dungeon_boss_rule(location):
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':
@@ -167,22 +170,26 @@ def forbid_item(location, item, player):
old_rule = location.item_rule old_rule = location.item_rule
location.item_rule = lambda i: (i.name != item or i.player != player) and old_rule(i) location.item_rule = lambda i: (i.name != item or i.player != player) and old_rule(i)
def add_item_rule(location, rule): def add_item_rule(location, rule):
old_rule = location.item_rule old_rule = location.item_rule
location.item_rule = lambda item: rule(item) and old_rule(item) location.item_rule = lambda item: rule(item) and old_rule(item)
def item_in_locations(state, item, player, locations): def item_in_locations(state, item, player, locations):
for location in locations: for location in locations:
if item_name(state, location[0], location[1]) == (item, player): if item_name(state, location[0], location[1]) == (item, player):
return True return True
return False return False
def item_name(state, location, player): def item_name(state, location, player):
location = state.world.get_location(location, player) location = state.world.get_location(location, player)
if location.item is None: if location.item is None:
return None return None
return (location.item.name, location.item.player) return (location.item.name, location.item.player)
def global_rules(world, player): def global_rules(world, player):
# ganon can only carry triforce # ganon can only carry triforce
add_item_rule(world.get_location('Ganon', player), lambda item: item.name == 'Triforce' and item.player == player) add_item_rule(world.get_location('Ganon', player), lambda item: item.name == 'Triforce' and item.player == player)
@@ -1378,6 +1385,7 @@ def forbid_bomb_jump_requirements(world, player):
set_rule(world.get_entrance('Paradox Cave Bomb Jump', player), lambda state: False) set_rule(world.get_entrance('Paradox Cave Bomb Jump', player), lambda state: False)
set_rule(world.get_entrance('Ice Lake Iceberg Bomb Jump', player), lambda state: False) set_rule(world.get_entrance('Ice Lake Iceberg Bomb Jump', player), lambda state: False)
def add_conditional_lamps(world, player): def add_conditional_lamps(world, player):
def add_conditional_lamp(spot, spottype='Location'): def add_conditional_lamp(spot, spottype='Location'):
if spottype == 'Location': if spottype == 'Location':
@@ -1519,6 +1527,7 @@ std_kill_doors_if_trapped = {
# 'Ice Lobby S' # can melt rule is sufficient # 'Ice Lobby S' # can melt rule is sufficient
} }
def add_connection(parent_name, target_name, entrance_name, world, player): def add_connection(parent_name, target_name, entrance_name, world, player):
parent = world.get_region(parent_name, player) parent = world.get_region(parent_name, player)
target = world.get_region(target_name, player) target = world.get_region(target_name, player)
@@ -1581,6 +1590,7 @@ def standard_rules(world, player):
def check_rule_list(state, r_list): def check_rule_list(state, r_list):
return True if len(r_list) <= 0 else r_list[0](state) and check_rule_list(state, r_list[1:]) return True if len(r_list) <= 0 else r_list[0](state) and check_rule_list(state, r_list[1:])
rule_list, debug_path = find_rules_for_zelda_delivery(world, player) rule_list, debug_path = find_rules_for_zelda_delivery(world, player)
set_rule(world.get_entrance('Hyrule Castle Throne Room Tapestry', player), set_rule(world.get_entrance('Hyrule Castle Throne Room Tapestry', player),
lambda state: state.has('Zelda Herself', player) and check_rule_list(state, rule_list)) lambda state: state.has('Zelda Herself', player) and check_rule_list(state, rule_list))
@@ -1619,16 +1629,15 @@ def find_rules_for_zelda_delivery(world, player):
if not rule(blank_state): if not rule(blank_state):
rule_list.append(rule) rule_list.append(rule)
next_path.append(ext.name) next_path.append(ext.name)
if connect.name == 'Sanctuary': if connect.name == 'Hyrule Castle Throne Room':
return rule_list, next_path return rule_list, next_path
else: else:
visited.add(connect) visited.add(connect)
queue.append((connect, rule_list, next_path)) queue.append((connect, rule_list, next_path))
raise Exception('No path to Sanctuary found') raise Exception('No path to Throne Room found')
def set_bunny_rules(world, player, inverted): def set_bunny_rules(world, player, inverted):
# 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 (top)', 'Bumper Cave (bottom)', 'Two Brothers House', bunny_impassable_caves = ['Bumper Cave (top)', 'Bumper Cave (bottom)', 'Two Brothers House',
@@ -1668,6 +1677,7 @@ def set_bunny_rules(world, player, inverted):
return region.is_light_world return region.is_light_world
else: else:
return region.is_dark_world return region.is_dark_world
def is_link(region): def is_link(region):
if inverted: if inverted:
return region.is_dark_world return region.is_dark_world
@@ -1697,16 +1707,15 @@ def set_bunny_rules(world, player, inverted):
# for each such entrance a new option is added that consist of: # for each such entrance a new option is added that consist of:
# a) being able to reach it, and # a) being able to reach it, and
# b) being able to access all entrances from there to `region` # b) being able to access all entrances from there to `region`
seen = {region} queue = deque([(region, [], {region})])
queue = deque([(region, [])])
while queue: while queue:
(current, path) = queue.popleft() (current, path, seen) = queue.popleft()
for entrance in current.entrances: for entrance in current.entrances:
new_region = entrance.parent_region new_region = entrance.parent_region
if new_region.type in (RegionType.Cave, RegionType.Dungeon) and new_region in seen: if new_region.type in (RegionType.Cave, RegionType.Dungeon) and new_region in seen:
continue continue
new_path = path + [entrance.access_rule] new_path = path + [entrance.access_rule]
seen.add(new_region) new_seen = seen.union({new_region})
if not is_link(new_region): if not is_link(new_region):
if world.logic[player] == 'owglitches': if world.logic[player] == 'owglitches':
if region.type == RegionType.Dungeon and new_region.type != RegionType.Dungeon: if region.type == RegionType.Dungeon and new_region.type != RegionType.Dungeon:
@@ -1743,7 +1752,7 @@ def set_bunny_rules(world, player, inverted):
else: else:
continue continue
if is_bunny(new_region): if is_bunny(new_region):
queue.append((new_region, new_path)) queue.append((new_region, new_path, new_seen))
else: else:
# we have reached pure light world, so we have a new possible option # we have reached pure light world, so we have a new possible option
possible_options.append(path_to_access_rule(new_path, entrance)) possible_options.append(path_to_access_rule(new_path, entrance))
@@ -1795,7 +1804,6 @@ drop_dungeon_entrances = {
"Skull Back Drop" "Skull Back Drop"
} }
bunny_revivable_entrances = { bunny_revivable_entrances = {
"Sewers Pull Switch", "TR Dash Room", "Swamp Boss", "Hera Boss", "Sewers Pull Switch", "TR Dash Room", "Swamp Boss", "Hera Boss",
"Tower Agahnim 1", "Ice Lobby", "Sewers Rat Path", "PoD Falling Bridge", "Tower Agahnim 1", "Ice Lobby", "Sewers Rat Path", "PoD Falling Bridge",

View File

@@ -711,7 +711,10 @@ def do_links_house(entrances, exits, avail, cross_world):
connect_entrance(chosen_dm_escape, chosen_exit_start, avail) connect_entrance(chosen_dm_escape, chosen_exit_start, avail)
connect_exit(chosen_exit_end, chosen_landing, avail) connect_exit(chosen_exit_end, chosen_landing, avail)
entrances.remove(chosen_dm_escape) entrances.remove(chosen_dm_escape)
avail.decoupled_exits.remove(chosen_exit_start)
avail.decoupled_entrances.remove(chosen_landing) avail.decoupled_entrances.remove(chosen_landing)
# chosen cave has already been removed from exits
exits.add(chosen_exit_start) # this needs to be added back in
if len(chosen_cave): if len(chosen_cave):
exits.update([x for x in chosen_cave]) exits.update([x for x in chosen_cave])
exits.update([x for item in multi_exit_caves for x in item]) exits.update([x for item in multi_exit_caves for x in item])