Skip to content

Commit

Permalink
Fail early if there is no check at the start of the game
Browse files Browse the repository at this point in the history
Catch some cases where the item randomizer won't be able to place the
first item and error out early with an actionable error message

This is not comprehensive, and might have false positives with
extra starting items due to the fairly static safety entrance
algorithm
  • Loading branch information
Aelire committed Jun 19, 2024
1 parent 8b31c76 commit 0fe7a62
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 3 deletions.
10 changes: 9 additions & 1 deletion randomizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,15 @@ def __init__(self, seed, clean_iso_path, randomized_output_folder, options: Opti
else:
self.dungeons_and_caves_only_start = False
self.logic.update_entrance_connection_macros() # Reset the entrance macros.


if self.dungeons_and_caves_only_start and not self.entrances.can_assign_safety_entrance():
msg = "No guaranteed accessible locations at the beginning of the game.\n"
if self.dungeons_only_start and not self.options.open_drc:
msg += 'Consider enabling more progression settings, adding starting items or enabling "Open DRC"'
else:
msg += "Consider enabling more progression settings or adding starting items"
raise TooFewProgressionLocationsError(msg)

self.fully_initialized = True

def get_max_progress_length(self) -> int:
Expand Down
19 changes: 17 additions & 2 deletions randomizers/entrances.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def __post_init__(self):


DUNGEON_ENTRANCE_NAMES_WITH_NO_REQUIREMENTS = [
"Dungeon Entrance on Dragon Roost Island",
"Dungeon Entrance on Dragon Roost Island", # Conditional on the "Open DRC" option
]
SECRET_CAVE_ENTRANCE_NAMES_WITH_NO_REQUIREMENTS = [
"Secret Cave Entrance on Pawprint Isle",
Expand Down Expand Up @@ -464,7 +464,8 @@ def randomize_one_set_of_entrances(self, relevant_entrances: list[ZoneEntrance],
e for e in relevant_entrances
if e.entrance_name in self.entrance_names_with_no_requirements
]
self.safety_entrance = self.rng.choice(possible_safety_entrances)
if possible_safety_entrances:
self.safety_entrance = self.rng.choice(possible_safety_entrances)

# We calculate which exits are terminal (the end of a nested chain) per-set instead of for all
# entrances. This is so that, for example, Ice Ring Isle counts as terminal when its inner cave
Expand Down Expand Up @@ -1130,4 +1131,18 @@ def get_entrance_zone_for_boss(self, boss_name: str) -> str:
zone_exit = ZoneExit.all[boss_arena_name]
outermost_entrance = self.get_outermost_entrance_for_exit(zone_exit)
return outermost_entrance.island_name

def can_assign_safety_entrance(self) -> bool:
# We need to be able to assign at least one safety entrance with progression
# in one of the sets of entrances to be randomized
if not self.is_enabled():
return True
for entrances, exits in self.get_all_entrance_sets_to_be_randomized():
if (
any(entr.entrance_name in self.entrance_names_with_no_requirements for entr in entrances)
and any(ex.unique_name in self.exit_names_with_no_requirements for ex in exits)
):
return True
return False

#endregion

0 comments on commit 0fe7a62

Please sign in to comment.