Skip to content

Commit

Permalink
Migrate remaining internal code changes
Browse files Browse the repository at this point in the history
  • Loading branch information
fenhl committed Nov 1, 2023
1 parent 3eb69b7 commit 38e1c66
Showing 4 changed files with 24 additions and 14 deletions.
28 changes: 18 additions & 10 deletions EntranceShuffle.py
Original file line number Diff line number Diff line change
@@ -891,7 +891,7 @@ def shuffle_random_entrances(worlds: list[World]) -> None:
try:
validate_world(world, worlds, None, locations_to_ensure_reachable, complete_itempool, placed_one_way_entrances=placed_one_way_entrances)
except EntranceShuffleError as error:
raise EntranceShuffleError('Worlds are not valid after shuffling entrances, Reason: %s' % error)
raise EntranceShuffleError('Worlds are not valid after shuffling entrances, Reason: %s' % error) from error


def shuffle_one_way_priority_entrances(worlds: list[World], world: World, one_way_priorities: dict[str, tuple[list[str], list[str]]],
@@ -916,12 +916,13 @@ def shuffle_one_way_priority_entrances(worlds: list[World], world: World, one_wa
restore_connections(entrance, target)
logging.getLogger('').info('Failed to place all priority one-way entrances for world %d. Will retry %d more times', world.id, retry_count)
logging.getLogger('').info('\t%s' % error)
last_error = error

if world.settings.custom_seed:
raise EntranceShuffleError('Entrance placement attempt count exceeded for world %d. Ensure the \"Seed\" field is empty and retry a few times.' % world.id)
raise EntranceShuffleError('Entrance placement attempt count exceeded for world %d. Ensure the \"Seed\" field is empty and retry a few times.' % world.id) from last_error
if world.settings.distribution_file:
raise EntranceShuffleError('Entrance placement attempt count exceeded for world %d. Some entrances in the Plandomizer File may have to be changed to create a valid seed. Reach out to Support on Discord for help.' % world.id)
raise EntranceShuffleError('Entrance placement attempt count exceeded for world %d. Retry a few times or reach out to Support on Discord for help.' % world.id)
raise EntranceShuffleError('Entrance placement attempt count exceeded for world %d. Some entrances in the Plandomizer File may have to be changed to create a valid seed. Reach out to Support on Discord for help.' % world.id) from last_error
raise EntranceShuffleError('Entrance placement attempt count exceeded for world %d. Retry a few times or reach out to Support on Discord for help.' % world.id) from last_error


# Shuffle all entrances within a provided pool
@@ -1013,14 +1014,13 @@ def replace_entrance(worlds: list[World], entrance: Entrance, target: Entrance,
change_connections(entrance, target)
validate_world(entrance.world, worlds, entrance, locations_to_ensure_reachable, itempool, placed_one_way_entrances=placed_one_way_entrances)
rollbacks.append((entrance, target))
return True
except EntranceShuffleError as error:
# If the entrance can't be placed there, log a debug message and change the connections back to what they were previously
logging.getLogger('').debug('Failed to connect %s To %s (Reason: %s) [World %d]',
entrance, entrance.connected_region or target.connected_region, error, entrance.world.id)
if entrance.connected_region:
restore_connections(entrance, target)
return False
raise


# Connect one random entrance from entrance pools to one random target in the respective target pool.
@@ -1052,10 +1052,14 @@ def place_one_way_priority_entrance(worlds: list[World], world: World, priority_
continue
for target in one_way_target_entrance_pools[entrance.type]:
if target.connected_region and target.connected_region.name in allowed_regions:
if replace_entrance(worlds, entrance, target, rollbacks, locations_to_ensure_reachable, complete_itempool):
try:
replace_entrance(worlds, entrance, target, rollbacks, locations_to_ensure_reachable, complete_itempool)
except EntranceShuffleError as error:
last_error = error
else:
logging.getLogger('').debug(f'Priority placement for {priority_name}: placing {entrance} as {target}')
return
raise EntranceShuffleError(f'Unable to place priority one-way entrance for {priority_name} [World {world.id}].')
raise EntranceShuffleError(f'Unable to place priority one-way entrance for {priority_name} [World {world.id}].') from last_error


# Shuffle entrances by placing them instead of entrances in the provided target entrances list
@@ -1079,11 +1083,15 @@ def shuffle_entrances(worlds: list[World], entrances: list[Entrance], target_ent
if target.connected_region is None:
continue

if replace_entrance(worlds, entrance, target, rollbacks, locations_to_ensure_reachable, complete_itempool, placed_one_way_entrances=placed_one_way_entrances):
try:
replace_entrance(worlds, entrance, target, rollbacks, locations_to_ensure_reachable, complete_itempool, placed_one_way_entrances=placed_one_way_entrances)
except EntranceShuffleError as error:
last_error = error
else:
break

if entrance.connected_region is None:
raise EntranceShuffleError('No more valid entrances to replace with %s in world %d' % (entrance, entrance.world.id))
raise EntranceShuffleError('No more valid entrances to replace with %s in world %d' % (entrance, entrance.world.id)) from last_error


# Check and validate that an entrance is compatible to replace a specific target
1 change: 1 addition & 0 deletions Plandomizer.py
Original file line number Diff line number Diff line change
@@ -1226,6 +1226,7 @@ def configure_triforce_hunt(self, worlds: list[World]) -> None:
for triforce_piece in triforce_pieces:
if triforce_piece in world.settings.starting_items:
total_starting_count += world.settings.starting_items[triforce_piece].count
#TODO add starting pieces from other skipped checks (Links Pocket, pre-completed dungeons)
if world.skip_child_zelda and 'Song from Impa' in world.distribution.locations and world.distribution.locations['Song from Impa'].item == triforce_piece:
total_starting_count += 1
total_count += world.triforce_count
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -60,6 +60,7 @@ Differences between `dev-fenhl` and [`Dev-R`](https://github.com/Roman971/OoT-Ra
* “Triforce Blitz S2” is a fast-paced game mode with very powerful hints used for [a tournament](https://midos.house/event/tfb/2), taken from [Elagatua's `Dev` branch](https://github.com/Elagatua/OoT-Randomizer/tree/Dev). Note that the tournament itself was played on that branch, not this one. See [the official website](https://www.triforceblitz.com/) for details.
* Other changes:
* Plandos can specify different settings for each world ([#2055](https://github.com/OoTRandomizer/OoT-Randomizer/pull/2055))
* The text box no longer shows the player's own gold skulltula token count when finding a token for another player (part of [#2055](https://github.com/OoTRandomizer/OoT-Randomizer/pull/2055))
* Some settings have been renamed for clarity ([#1560](https://github.com/OoTRandomizer/OoT-Randomizer/pull/1560))
* The conditions for forcing one-way entrances that lead to the Bolero, Nocturne, and Requiem warp pads have been adjusted to increase variety with some settings, such as “Guarantee Reachable Locations” set to “All Goals”, “Shuffle Dungeon Rewards”, or “Mix Entrance Pools” (based on [#1440](https://github.com/OoTRandomizer/OoT-Randomizer/pull/1440))
* Gold skulltula tokens can be on excluded locations if there are no checks requiring them (such as in SAWS)
8 changes: 4 additions & 4 deletions RuleParser.py
Original file line number Diff line number Diff line change
@@ -389,7 +389,7 @@ def create_delayed_rules(self) -> None:

self.current_spot = event
# This could, in theory, create further subrules.
access_rule = self.make_access_rule(self.visit(node))
access_rule = self.make_access_rule(self.visit(node), 'create_delayed_rules')
if access_rule is self.rule_cache.get('NameConstant(False)') or access_rule is self.rule_cache.get('Constant(False)'):
event.access_rule = None
event.never = True
@@ -404,13 +404,13 @@ def create_delayed_rules(self) -> None:
# Safeguard in case this is called multiple times per world
self.delayed_rules.clear()

def make_access_rule(self, body: ast.AST) -> AccessRule:
def make_access_rule(self, body: ast.AST, filename: str = 'make_access_rule') -> AccessRule:
rule_str = ast.dump(body, False)
if rule_str not in self.rule_cache:
# requires consistent iteration on dicts
kwargs = [ast.arg(arg=k) for k in kwarg_defaults.keys()]
kwd = list(map(ast.Constant, kwarg_defaults.values()))
name = f'<{self.current_spot and self.current_spot.name}: {rule_str}>'
name = f'<{self.current_spot.name if self.current_spot else filename}: {rule_str}>'
try:
self.rule_cache[rule_str] = eval(compile(
ast.fix_missing_locations(
@@ -477,7 +477,7 @@ def at_night(self, node: ast.Call) -> ast.expr:
# If spot is None, here() rules won't work.
def parse_rule(self, rule_string: str, spot: Optional[Location | Entrance] = None) -> AccessRule:
self.current_spot = spot
return self.make_access_rule(self.visit(ast.parse(rule_string, mode='eval').body))
return self.make_access_rule(self.visit(ast.parse(rule_string, mode='eval').body), str(spot or 'parse_rule'))

def parse_spot_rule(self, spot: Location | Entrance) -> None:
rule = spot.rule_string.split('#', 1)[0].strip()

0 comments on commit 38e1c66

Please sign in to comment.