TUNIC: The Big Refactor (#5195)
* Make it actually return false if it gets to the backup lists and fails them * Fix stuff after merge * Add outlet regions, create new regions as needed for them * Put together part of decoupled and direction pairs * make direction pairs work * Make decoupled work * Make fixed shop work again * Fix a few minor bugs * Fix a few minor bugs * Fix plando * god i love programming * Reorder portal list * Update portal sorter for variable shops * Add missing parameter * Some cleanup of prints and functions * Fix typo * it's aliiiiiive * Make seed groups not sync decoupled * Add test with full-shop plando * Fix bug with vanilla portals * Handle plando connections and direction pair errors * Update plando checking for decoupled * Fix typo * Fix exception text to be shorter * Add some more comments * Add todo note * Remove unused safety thing * Remove extra plando connections definition in options * Make seed groups in decoupled with overlapping but not fully overlapped plando connections interact nicely without messing with what the entrances look like in the spoiler log * Fix weird edge case that is technically user error * Add note to fixed shop * Fix parsing shop names in UT * Remove debug print * Actually make UT work * multiworld. to world. * Fix typo from merge * Make it so the shops show up in the entrance hints * Fix bug in ladder storage rules * Remove blank line * # Conflicts: # worlds/tunic/__init__.py # worlds/tunic/er_data.py # worlds/tunic/er_rules.py # worlds/tunic/er_scripts.py # worlds/tunic/rules.py # worlds/tunic/test/test_access.py * Fix issues after merge * Update plando connections stuff in docs * Make early bushes only contain grass * Fix library mistake * Backport changes to grass rando (#20) * Backport changes to grass rando * add_rule instead of set_rule for the special cases, add special cases for back of swamp laurels area cause I should've made a new region for the swamp upper entrance * Remove item name group for grass * Update grass rando option descriptions - Also ignore grass fill for single player games * Ignore grass fill option for solo rando * Update er_rules.py * Fix pre fill issue * Remove duplicate option * Add excluded grass locations back * Hide grass fill option from simple ui options page * Check for start with sword before setting grass rules * Update worlds/tunic/options.py Co-authored-by: Scipio Wright <scipiowright@gmail.com> * has_stick -> has_melee * has_stick -> has_melee * Add a failsafe for direction pairing * Fix playthrough crash bug * Remove init from logicmixin * Updates per code review (thanks hesto) * has_stick to has_melee in newer update * has_stick to has_melee in newer update * Exclude grass from get_filler_item_name - non-grass rando games were accidentally seeing grass items get shuffled in as filler, which is funny but probably shouldn't happen * Update worlds/tunic/__init__.py Co-authored-by: Scipio Wright <scipiowright@gmail.com> * Apply suggestions from code review Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: Scipio Wright <scipiowright@gmail.com> * change the rest of grass_fill to local_fill * Filter out grass from filler_items * remove -> discard * Update worlds/tunic/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Starting out * Rules for breakable regions * # Conflicts: # worlds/tunic/__init__.py # worlds/tunic/combat_logic.py # worlds/tunic/er_data.py # worlds/tunic/er_rules.py # worlds/tunic/er_scripts.py * Cleanup more stuff after merge * Revert "Cleanup more stuff after merge" This reverts commit a6ee9a93da8f2fcc4413de6df6927b246017889d. * Revert "# Conflicts:" This reverts commit c74ccd74a45b6ad6b9abe6e339d115a0c98baf30. * Cleanup more stuff after merge * change has_stick to has_melee * Update grass list with combat logic regions * More fixes from combat logic merge * Fix some dumb stuff (#21) * Reorganize pre fill for grass * make the rest of it work, it's pr ready, boom * Make it work in not pot shuffle * Merge grass rando * multiworld -> world get_location, use has_any * Swap out region for West Garden Before Terry grass * Adjust west garden rules to add west combat region * Adjust grass regions for south checkpoint grass * Adjust grass regions for after terry grass * Adjust grass regions for west combat grass * Adjust grass regions for dagger house grass * Adjust grass regions for south checkpoint grass, adjust regions and rules for some related locations * Finish the remainder of the west garden grass, reformat ruined atoll a little * More hex quest updates - Implement page ability shuffle for hex quest - Fix keys behind bosses if hex goal is less than 3 - Added check to fix conflicting hex quest options - Add option to slot data * Change option comparison * Change option checking and fix some stuff - also keep prayer first on low hex counts * Update option defaulting * Update option checking * Fix option assignment again * Merge in hex hunt * Merge in changes * Clean up imports * Add ability type to UT stuff * merge it all * Make local fill work across pot and grass (to be adjusted later) * Make separate pools for the grass and non-grass fills * Fix id overlap * Update option description * Fix default * Reorder localfill option desc * Load the purgatory ones in * Adjustments after merge * Fully remove logicrules * Fix UT support with fixed shop option * Add breakable shuffle to the ut stuff * Make it load in a specific number of locations * Add Silent's spoiler log ability thing * Fix for groups * Fix for groups * Fix typo * Fix hex quest UT support * Use .get * UT fixes, classification fixes * Rename some locations * Adjust guard house names * Adjust guard house names * Rework create_item * Fix for plando connections * Rename, add new breakables * Rename more stuff * Time to rename them again * Fix issue with fixed shop + decoupled * Put in an exception to catch that error in the future * Update create_item to match main * Update spoiler log lines for hex abilities * Burn the signs down * Bring over the combat logic fix * Merge in combat logic fix * Silly static method thing * Move a few areas to before well instead of east forest * Add an all_random hidden option for dev stuff * Port over changes from main * Fix west courtyard pot regions * Remove debug prints * Fix fortress courtyard and beneath the fortress loc groups again * Add exception handling to deal with duplicate apworlds * Fix typo * More missing loc group conversions * Initial fuse shuffle stuff * Fix gun missing from combat_items, add new for combat logic cache, very slight refactor of check_combat_reqs to let it do the changeover in a less complicated fashion, fix area being a boss area rather than non-boss area for a check * Add fuse shuffle logic * reorder atoll statue rule * Update traversal reqs * Remove fuse shuffle from temple door * Combine rules and option checking * Add bell shuffle; fix fuse location groups * Fix portal rules not requiring prayer * Merge the grass laurels exit grass PR * Merge in fortress bridge PR * Do a little clean up * Fix a regression * Update after merge * Some more stuff * More Silent changes * Update more info section in game info page * Fix rules for atoll and swamp fuses * Precollect cathedral fuse in ER * actually just make the fuse useful instead of progression * Add it to the swamp and cath rules too * Fix cath fuse name * Minor fixes and edits * Some UT stuff * Fix a couple more groups * Move a bunch of UT stuff to its own file * Fix up a couple UT things * Couple minor ER fixes * Formatting change * UT poptracker stuff enabled since it's optional in one of the releases * Add author string to world class * Adjust local fill option name * Update ut_stuff to match the PR * Add exception handling for UT with old apworld * Fix missing tracker_world * Remove extra entrance from cath main -> elevator Entry <-> Elev exists, Entry <-> Main exists So no connection is needed between Main and Elev * Fix so that decoupled doesn't incorrectly use get_portal_info and get_paired_portal * Fix so that decoupled doesn't incorrectly use get_portal_info and get_paired_portal * Update for breakables poptracker * Backup and warnings instead * Update typing * Delete old regions and rules, move stuff to logic_helpers and constants * Delete now much less useful tests * Fix breakables map tracking * Add more comments to init * Add todo to grass.py * Fix up tests * Pull out fuse and bell shuffle * Pull out fuse and bell shuffle * Update worlds/tunic/options.py Co-authored-by: qwint <qwint.42@gmail.com> * Update worlds/tunic/logic_helpers.py Co-authored-by: qwint <qwint.42@gmail.com> * {} -> () in state functions * {} -> () in state functions * Change {} -> () in state functions, use constant for gun * Remove floating constants in er_data * Finish hard deprecating FixedShop * Finish hard deprecating FixedShop * Fix zig skip showing up in decoupled fixed shop --------- Co-authored-by: silent-destroyer <osilentdestroyer@gmail.com> Co-authored-by: Silent <110704408+silent-destroyer@users.noreply.github.com> Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: qwint <qwint.42@gmail.com>
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
from typing import Dict, List, Set, Tuple, TYPE_CHECKING
|
||||
from copy import deepcopy
|
||||
from random import Random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from BaseClasses import Region, ItemClassification, Item, Location
|
||||
from .locations import all_locations
|
||||
from Options import PlandoConnection
|
||||
|
||||
from .breakables import create_breakable_exclusive_regions, set_breakable_location_rules
|
||||
from .er_data import (Portal, portal_mapping, traversal_requirements, DeadEnd, Direction, RegionInfo,
|
||||
get_portal_outlet_region)
|
||||
from .er_rules import set_er_region_rules
|
||||
from .breakables import create_breakable_exclusive_regions, set_breakable_location_rules
|
||||
from Options import PlandoConnection
|
||||
from .locations import all_locations
|
||||
from .options import EntranceRando, EntranceLayout
|
||||
from random import Random
|
||||
from copy import deepcopy
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import TunicWorld
|
||||
@@ -22,8 +24,8 @@ class TunicERLocation(Location):
|
||||
game: str = "TUNIC"
|
||||
|
||||
|
||||
def create_er_regions(world: "TunicWorld") -> Dict[Portal, Portal]:
|
||||
regions: Dict[str, Region] = {}
|
||||
def create_er_regions(world: "TunicWorld") -> dict[Portal, Portal]:
|
||||
regions: dict[str, Region] = {}
|
||||
world.used_shop_numbers = set()
|
||||
|
||||
for region_name, region_data in world.er_regions.items():
|
||||
@@ -83,7 +85,7 @@ def create_er_regions(world: "TunicWorld") -> Dict[Portal, Portal]:
|
||||
|
||||
|
||||
# keys are event names, values are event regions
|
||||
tunic_events: Dict[str, str] = {
|
||||
tunic_events: dict[str, str] = {
|
||||
"Eastern Bell": "Forest Belltower Upper",
|
||||
"Western Bell": "Overworld Belltower at Bell",
|
||||
"Furnace Fuse": "Furnace Fuse",
|
||||
@@ -101,7 +103,7 @@ tunic_events: Dict[str, str] = {
|
||||
}
|
||||
|
||||
|
||||
def place_event_items(world: "TunicWorld", regions: Dict[str, Region]) -> None:
|
||||
def place_event_items(world: "TunicWorld", regions: dict[str, Region]) -> None:
|
||||
for event_name, region_name in tunic_events.items():
|
||||
region = regions[region_name]
|
||||
location = TunicERLocation(world.player, event_name, None, region)
|
||||
@@ -111,9 +113,13 @@ def place_event_items(world: "TunicWorld", regions: Dict[str, Region]) -> None:
|
||||
location.place_locked_item(
|
||||
TunicERItem("Unseal the Heir", ItemClassification.progression, None, world.player))
|
||||
elif event_name.endswith("Bell"):
|
||||
# if world.options.shuffle_bells:
|
||||
# continue
|
||||
location.place_locked_item(
|
||||
TunicERItem("Ring " + event_name, ItemClassification.progression, None, world.player))
|
||||
else:
|
||||
elif event_name.endswith("Fuse") or event_name.endswith("Fuses"):
|
||||
# if world.options.shuffle_fuses:
|
||||
# continue
|
||||
location.place_locked_item(
|
||||
TunicERItem("Activate " + event_name, ItemClassification.progression, None, world.player))
|
||||
region.locations.append(location)
|
||||
@@ -135,7 +141,7 @@ def get_shop_num(world: "TunicWorld") -> int:
|
||||
|
||||
# all shops are the same shop. however, you cannot get to all shops from the same shop entrance.
|
||||
# so, we need a bunch of shop regions that connect to the actual shop, but the actual shop cannot connect back
|
||||
def create_shop_region(world: "TunicWorld", regions: Dict[str, Region], portal_num) -> None:
|
||||
def create_shop_region(world: "TunicWorld", regions: dict[str, Region], portal_num) -> None:
|
||||
new_shop_name = f"Shop {portal_num}"
|
||||
world.er_regions[new_shop_name] = RegionInfo("Shop", dead_end=DeadEnd.all_cats)
|
||||
new_shop_region = Region(new_shop_name, world.player, world.multiworld)
|
||||
@@ -144,8 +150,8 @@ def create_shop_region(world: "TunicWorld", regions: Dict[str, Region], portal_n
|
||||
|
||||
|
||||
# for non-ER that uses the ER rules, we create a vanilla set of portal pairs
|
||||
def vanilla_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal, Portal]:
|
||||
portal_pairs: Dict[Portal, Portal] = {}
|
||||
def vanilla_portals(world: "TunicWorld", regions: dict[str, Region]) -> dict[Portal, Portal]:
|
||||
portal_pairs: dict[Portal, Portal] = {}
|
||||
# we don't want the zig skip exit for vanilla portals, since it shouldn't be considered for logic here
|
||||
portal_map = [portal for portal in portal_mapping if portal.name not in
|
||||
["Ziggurat Lower Falling Entrance", "Purgatory Bottom Exit", "Purgatory Top Exit"]]
|
||||
@@ -182,10 +188,10 @@ def vanilla_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Por
|
||||
# repeat this phase until all regions are reachable
|
||||
# second phase: randomly pair dead ends to random two_plus
|
||||
# third phase: randomly pair the remaining two_plus to each other
|
||||
def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal, Portal]:
|
||||
portal_pairs: Dict[Portal, Portal] = {}
|
||||
dead_ends: List[Portal] = []
|
||||
two_plus: List[Portal] = []
|
||||
def pair_portals(world: "TunicWorld", regions: dict[str, Region]) -> dict[Portal, Portal]:
|
||||
portal_pairs: dict[Portal, Portal] = {}
|
||||
dead_ends: list[Portal] = []
|
||||
two_plus: list[Portal] = []
|
||||
player_name = world.player_name
|
||||
portal_map = portal_mapping.copy()
|
||||
laurels_zips = world.options.laurels_zips.value
|
||||
@@ -194,6 +200,10 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
entrance_layout = world.options.entrance_layout
|
||||
laurels_location = world.options.laurels_location
|
||||
decoupled = world.options.decoupled
|
||||
# shuffle_fuses = bool(world.options.shuffle_fuses.value)
|
||||
# shuffle_bells = bool(world.options.shuffle_bells.value)
|
||||
shuffle_fuses = False
|
||||
shuffle_bells = False
|
||||
traversal_reqs = deepcopy(traversal_requirements)
|
||||
has_laurels = True
|
||||
waterfall_plando = False
|
||||
@@ -207,7 +217,7 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
entrance_layout = seed_group["entrance_layout"]
|
||||
laurels_location = "10_fairies" if seed_group["laurels_at_10_fairies"] is True else False
|
||||
|
||||
logic_tricks: Tuple[bool, int, int] = (laurels_zips, ice_grappling, ladder_storage)
|
||||
logic_tricks: tuple[bool, int, int] = (laurels_zips, ice_grappling, ladder_storage)
|
||||
|
||||
# marking that you don't immediately have laurels
|
||||
if laurels_location == "10_fairies" and not world.using_ut:
|
||||
@@ -215,8 +225,8 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
|
||||
# for the direction pairs option with decoupled off
|
||||
# tracks how many portals are in each direction in each list
|
||||
two_plus_direction_tracker: Dict[int, int] = {direction: 0 for direction in range(8)}
|
||||
dead_end_direction_tracker: Dict[int, int] = {direction: 0 for direction in range(8)}
|
||||
two_plus_direction_tracker: dict[int, int] = {direction: 0 for direction in range(8)}
|
||||
dead_end_direction_tracker: dict[int, int] = {direction: 0 for direction in range(8)}
|
||||
|
||||
# for ensuring we have enough entrances in directions left that we don't leave dead ends without any
|
||||
def too_few_portals_for_direction_pairs(direction: int, offset: int) -> bool:
|
||||
@@ -226,10 +236,6 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
return False
|
||||
return True
|
||||
|
||||
# If using Universal Tracker, restore portal_map. Could be cleaner, but it does not matter for UT even a little bit
|
||||
if world.using_ut:
|
||||
portal_map = portal_mapping.copy()
|
||||
|
||||
# create separate lists for dead ends and non-dead ends
|
||||
for portal in portal_map:
|
||||
dead_end_status = world.er_regions[portal.region].dead_end
|
||||
@@ -291,11 +297,12 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
dead_ends.append(shop_portal)
|
||||
dead_end_direction_tracker[shop_portal.direction] += 1
|
||||
|
||||
connected_regions: Set[str] = set()
|
||||
connected_regions: set[str] = set()
|
||||
# make better start region stuff when/if implementing random start
|
||||
start_region = "Overworld"
|
||||
connected_regions.add(start_region)
|
||||
connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic_tricks)
|
||||
connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic_tricks,
|
||||
shuffle_fuses, shuffle_bells)
|
||||
|
||||
if world.options.entrance_rando.value in EntranceRando.options.values():
|
||||
plando_connections = world.options.plando_connections.value
|
||||
@@ -371,8 +378,8 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
else:
|
||||
modified_plando_connections = plando_connections
|
||||
|
||||
connected_shop_portal1s: Set[int] = set()
|
||||
connected_shop_portal2s: Set[int] = set()
|
||||
connected_shop_portal1s: set[int] = set()
|
||||
connected_shop_portal2s: set[int] = set()
|
||||
for connection in modified_plando_connections:
|
||||
p_entrance = connection.entrance
|
||||
p_exit = connection.exit
|
||||
@@ -419,7 +426,15 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
break
|
||||
else:
|
||||
if p_entrance.startswith("Shop Portal "):
|
||||
portal_num = int(p_entrance.split("Shop Portal ")[-1])
|
||||
try:
|
||||
portal_num = int(p_entrance.split("Shop Portal ")[-1])
|
||||
except ValueError:
|
||||
if "Previous Region" in p_entrance:
|
||||
raise Exception("TUNIC: APWorld used for generation is incompatible with newer APWorld. "
|
||||
"Please use the APWorld from Archipelago 0.6.1 instead.")
|
||||
else:
|
||||
raise Exception("TUNIC: Unknown error occurred in UT entrance setup, please contact "
|
||||
"the TUNIC APWorld devs.")
|
||||
# shops 1-6 are south, 7 and 8 are east, and after that it just breaks direction pairs
|
||||
if portal_num <= 6:
|
||||
pdir = Direction.south
|
||||
@@ -452,7 +467,15 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
else:
|
||||
if not portal2:
|
||||
if p_exit.startswith("Shop Portal "):
|
||||
portal_num = int(p_exit.split("Shop Portal ")[-1])
|
||||
try:
|
||||
portal_num = int(p_exit.split("Shop Portal ")[-1])
|
||||
except ValueError:
|
||||
if "Previous Region" in p_exit:
|
||||
raise Exception("TUNIC: APWorld used for generation is incompatible with newer APWorld. "
|
||||
"Please use the APWorld from Archipelago 0.6.1 instead.")
|
||||
else:
|
||||
raise Exception("TUNIC: Unknown error occurred in UT entrance setup, please contact "
|
||||
"the TUNIC APWorld devs.")
|
||||
if portal_num <= 6:
|
||||
pdir = Direction.south
|
||||
elif portal_num in [7, 8]:
|
||||
@@ -510,13 +533,15 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
dead_end_direction_tracker[portal1.direction] -= 1
|
||||
else:
|
||||
two_plus_direction_tracker[portal1.direction] -= 1
|
||||
|
||||
if portal2_dead_end:
|
||||
dead_end_direction_tracker[portal2.direction] -= 1
|
||||
else:
|
||||
two_plus_direction_tracker[portal2.direction] -= 1
|
||||
|
||||
# if we have plando connections, our connected regions may change somewhat
|
||||
connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic_tricks)
|
||||
connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic_tricks,
|
||||
shuffle_fuses, shuffle_bells)
|
||||
|
||||
# if there are an odd number of shops after plando, add another one, except in decoupled where it doesn't matter
|
||||
if not decoupled and len(world.used_shop_numbers) % 2 == 1:
|
||||
@@ -599,7 +624,6 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
connected_regions = backup_connected_regions.copy()
|
||||
rare_failure_count += 1
|
||||
fail_count = 0
|
||||
|
||||
if rare_failure_count > 100:
|
||||
raise Exception(f"Failed to pair regions due to rare pairing issues for {player_name}. "
|
||||
f"Unconnected regions: {non_dead_end_regions - connected_regions}.\n"
|
||||
@@ -633,7 +657,9 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
if waterfall_plando:
|
||||
cr = connected_regions.copy()
|
||||
cr.add(portal.region)
|
||||
if "Secret Gathering Place" not in update_reachable_regions(cr, traversal_reqs, has_laurels, logic_tricks):
|
||||
if "Secret Gathering Place" not in update_reachable_regions(cr, traversal_reqs, has_laurels,
|
||||
logic_tricks, shuffle_fuses,
|
||||
shuffle_bells):
|
||||
continue
|
||||
# if not waterfall_plando, then we just want to pair secret gathering place now
|
||||
elif portal.region != "Secret Gathering Place":
|
||||
@@ -682,8 +708,8 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
# once we have both portals, connect them and add the new region(s) to connected_regions
|
||||
if not has_laurels and "Secret Gathering Place" in connected_regions:
|
||||
has_laurels = True
|
||||
connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic_tricks)
|
||||
|
||||
connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic_tricks,
|
||||
shuffle_fuses, shuffle_bells)
|
||||
portal_pairs[portal1] = portal2
|
||||
two_plus_direction_tracker[portal1.direction] -= 1
|
||||
two_plus_direction_tracker[portal2.direction] -= 1
|
||||
@@ -745,7 +771,7 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
||||
|
||||
|
||||
# loop through our list of paired portals and make two-way connections
|
||||
def create_randomized_entrances(world: "TunicWorld", portal_pairs: Dict[Portal, Portal], regions: Dict[str, Region]) -> None:
|
||||
def create_randomized_entrances(world: "TunicWorld", portal_pairs: dict[Portal, Portal], regions: dict[str, Region]) -> None:
|
||||
for portal1, portal2 in portal_pairs.items():
|
||||
# connect to the outlet region if there is one, if not connect to the actual region
|
||||
regions[portal1.region].connect(
|
||||
@@ -757,8 +783,9 @@ def create_randomized_entrances(world: "TunicWorld", portal_pairs: Dict[Portal,
|
||||
name=portal2.name)
|
||||
|
||||
|
||||
def update_reachable_regions(connected_regions: Set[str], traversal_reqs: Dict[str, Dict[str, List[List[str]]]],
|
||||
has_laurels: bool, logic: Tuple[bool, int, int]) -> Set[str]:
|
||||
def update_reachable_regions(connected_regions: set[str], traversal_reqs: dict[str, dict[str, list[list[str]]]],
|
||||
has_laurels: bool, logic: tuple[bool, int, int], shuffle_fuses: bool,
|
||||
shuffle_bells: bool) -> set[str]:
|
||||
zips, ice_grapples, ls = logic
|
||||
# starting count, so we can run it again if this changes
|
||||
region_count = len(connected_regions)
|
||||
@@ -790,6 +817,12 @@ def update_reachable_regions(connected_regions: Set[str], traversal_reqs: Dict[s
|
||||
break
|
||||
elif req not in connected_regions:
|
||||
break
|
||||
elif req == "Fuse Shuffle":
|
||||
if not shuffle_fuses:
|
||||
break
|
||||
elif req == "Bell Shuffle":
|
||||
if not shuffle_bells:
|
||||
break
|
||||
else:
|
||||
met_traversal_reqs = True
|
||||
break
|
||||
@@ -798,13 +831,14 @@ def update_reachable_regions(connected_regions: Set[str], traversal_reqs: Dict[s
|
||||
|
||||
# if the length of connected_regions changed, we got new regions, so we want to check those new origins
|
||||
if region_count != len(connected_regions):
|
||||
connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic)
|
||||
connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic,
|
||||
shuffle_fuses, shuffle_bells)
|
||||
|
||||
return connected_regions
|
||||
|
||||
|
||||
# which directions are opposites
|
||||
direction_pairs: Dict[int, int] = {
|
||||
direction_pairs: dict[int, int] = {
|
||||
Direction.north: Direction.south,
|
||||
Direction.south: Direction.north,
|
||||
Direction.east: Direction.west,
|
||||
@@ -848,9 +882,9 @@ def verify_plando_directions(connection: PlandoConnection) -> bool:
|
||||
|
||||
|
||||
# sort the portal dict by the name of the first portal, referring to the portal order in the master portal list
|
||||
def sort_portals(portal_pairs: Dict[Portal, Portal], world: "TunicWorld") -> Dict[str, str]:
|
||||
sorted_pairs: Dict[str, str] = {}
|
||||
reference_list: List[str] = [portal.name for portal in portal_mapping]
|
||||
def sort_portals(portal_pairs: dict[Portal, Portal], world: "TunicWorld") -> dict[str, str]:
|
||||
sorted_pairs: dict[str, str] = {}
|
||||
reference_list: list[str] = [portal.name for portal in portal_mapping]
|
||||
|
||||
# due to plando, there can be a variable number of shops
|
||||
largest_shop_number = max(world.used_shop_numbers)
|
||||
|
||||
Reference in New Issue
Block a user