diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index d267dc39c0..3c128ef8c5 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -729,6 +729,16 @@ tunic_er_regions: Dict[str, RegionInfo] = { } +# this is essentially a pared down version of the region connections in rules.py, with some minor differences +# the main purpose of this is to make it so that you can access every region +# most items are excluded from the rules here, since we can assume Archipelago will properly place them +# laurels (hyperdash) can be locked at 10 fairies, requiring access to secret gathering place +# so until secret gathering place has been paired, you do not have hyperdash, so you cannot use hyperdash entrances +# Zip means you need the laurels zips option enabled +# IG# refers to ice grappling difficulties +# LS# refers to ladder storage difficulties +# LS rules are used for region connections here regardless of whether you have being knocked out of the air in logic +# this is because it just means you can reach the entrances in that region via ladder storage traversal_requirements: Dict[str, Dict[str, List[List[str]]]] = { "Overworld": { "Overworld Beach": @@ -1231,8 +1241,6 @@ traversal_requirements: Dict[str, Dict[str, List[List[str]]]] = { [], "Fortress Courtyard Upper": [["LS2"]], - "Fortress Exterior near cave": - [["LS1"]], "Fortress Courtyard": [["LS1"]], }, @@ -1354,7 +1362,7 @@ traversal_requirements: Dict[str, Dict[str, List[List[str]]]] = { "Quarry": [], "Monastery Rope": - [["LS2"]] + [["LS2"]], }, "Quarry Portal": { "Quarry Entry": diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 5e354707dd..5d0f9f3505 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1034,17 +1034,17 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ # connect the applicable overworld regions to the ls elevation regions for origin_region, ladders in region_ladders.items(): for ladder_region, region_info in ow_ladder_groups.items(): - common_ladders: FrozenSet[str] = frozenset(ladders.intersection(region_info.ladders)) # checking if that region has a ladder or ladders for that elevation + common_ladders: FrozenSet[str] = frozenset(ladders.intersection(region_info.ladders)) if common_ladders: if options.shuffle_ladders: regions[origin_region].connect( - ladder_regions[ladder_region], + connecting_region=ladder_regions[ladder_region], rule=lambda state, lads=common_ladders: state.has_any(lads, player) and can_ladder_storage(state, world)) else: regions[origin_region].connect( - ladder_regions[ladder_region], + connecting_region=ladder_regions[ladder_region], rule=lambda state: can_ladder_storage(state, world)) # connect ls elevation regions to the region on the other side of the portals @@ -1072,14 +1072,24 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ # connect the non-overworld ones for ls_info in non_ow_ls_list: + # for places where the destination is a region (so you have to get knocked down) if ls_info.dest_is_region: - regions[ls_info.origin].connect( - connecting_region=regions[ls_info.destination], - name=ls_info.destination + " (LS) " + ls_info.origin, - rule=lambda state: can_ladder_storage(state, world)) + # none of the non-ow ones have multiple ladders that can be used, so don't need has_any + if options.shuffle_ladders and ls_info.ladders_req: + regions[ls_info.origin].connect( + connecting_region=regions[ls_info.destination], + name=ls_info.destination + " (LS) " + ls_info.origin, + rule=lambda state, lad=ls_info.ladders_req: can_ladder_storage(state, world) + and state.has(lad, player)) + else: + regions[ls_info.origin].connect( + connecting_region=regions[ls_info.destination], + name=ls_info.destination + " (LS) " + ls_info.origin, + rule=lambda state: can_ladder_storage(state, world)) continue portal_name, dest_region = get_portal_info(ls_info.destination) + # these two are special cases if ls_info.destination == "Atoll Redux, Frog Stairs_mouth": regions[ls_info.origin].connect( connecting_region=regions[dest_region], @@ -1095,13 +1105,20 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ regions[ls_info.origin].connect( connecting_region=regions[dest_region], name=portal_name + " (LS) " + ls_info.origin, - rule=lambda state: can_ladder_storage(state, world) and has_ability(prayer, state, world) - and (state.has(ls_info.ladders_req, player) or not options.shuffle_ladders)) + rule=lambda state: can_ladder_storage(state, world) and has_ability(holy_cross, state, world) + and (state.has("Ladders in Swamp", player) or not options.shuffle_ladders)) else: regions[ls_info.origin].connect( connecting_region=regions[dest_region], name=portal_name + " (LS) " + ls_info.origin, - rule=lambda state: can_ladder_storage(state, world) and has_ability(prayer, state, world)) + rule=lambda state: can_ladder_storage(state, world) and has_ability(holy_cross, state, world)) + + elif options.shuffle_ladders and ls_info.ladders_req: + regions[ls_info.origin].connect( + connecting_region=regions[dest_region], + name=portal_name + " (LS) " + ls_info.origin, + rule=lambda state, lad=ls_info.ladders_req: can_ladder_storage(state, world) + and state.has(lad, player)) else: regions[ls_info.origin].connect( connecting_region=regions[dest_region], diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 5f7a739f8c..85e876fe94 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -51,7 +51,7 @@ def create_er_regions(world: "TunicWorld") -> Dict[Portal, Portal]: victory_region = regions["Spirit Arena Victory"] victory_location = TunicERLocation(world.player, "The Heir", None, victory_region) victory_location.place_locked_item(TunicERItem("Victory", ItemClassification.progression, None, world.player)) - world.multiworld.completion_condition[world.player] = lambda state: state.has("Victory", world.player) + world.multiworld.completion_condition[world.player] = lambda state: True # state.has("Victory", world.player) victory_region.locations.append(victory_location) return portal_pairs diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index f470ea540d..a646a6663d 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -167,6 +167,7 @@ item_table: Dict[str, TunicItemData] = { "Ladders in Swamp": TunicItemData(ItemClassification.progression, 0, 150, "Ladders"), } +# items to be replaced by fool traps fool_tiers: List[List[str]] = [ [], ["Money x1", "Money x10", "Money x15", "Money x16"], @@ -174,6 +175,7 @@ fool_tiers: List[List[str]] = [ ["Money x1", "Money x10", "Money x15", "Money x16", "Money x20", "Money x25", "Money x30"], ] +# items we'll want the location of in slot data, for generating in-game hints slot_data_item_names = [ "Stick", "Sword", diff --git a/worlds/tunic/ladder_storage_data.py b/worlds/tunic/ladder_storage_data.py index 40bc624f7a..4875bb2519 100644 --- a/worlds/tunic/ladder_storage_data.py +++ b/worlds/tunic/ladder_storage_data.py @@ -13,7 +13,7 @@ ow_ladder_groups: Dict[str, OWLadderInfo] = { # lowest elevation "LS Elev 0": OWLadderInfo({"Ladders in Overworld Town", "Ladder to Ruined Atoll", "Ladder to Swamp"}, ["Swamp Redux 2_conduit", "Overworld Cave_", "Atoll Redux_lower", "Maze Room_", - "Town Basement_beach", "Archipelagos Redux_lowest"], + "Town Basement_beach", "Archipelagos Redux_lower", "Archipelagos Redux_lowest"], ["Overworld Beach"]), # also the east filigree room "LS Elev 1": OWLadderInfo({"Ladders near Weathervane", "Ladders in Overworld Town", "Ladder to Swamp"}, @@ -21,7 +21,7 @@ ow_ladder_groups: Dict[str, OWLadderInfo] = { ["Overworld Tunnel Turret"]), # also the fountain filigree room and ruined passage door "LS Elev 2": OWLadderInfo({"Ladders near Weathervane", "Ladders to West Bell"}, - ["Archipelagos Redux_lower", "Ruins Passage_east"], + ["Archipelagos Redux_upper", "Ruins Passage_east"], ["After Ruined Passage"]), # also old house door "LS Elev 3": OWLadderInfo({"Ladders near Weathervane", "Ladder to Quarry", "Ladders to West Bell", @@ -89,7 +89,6 @@ easy_ls: List[LadderInfo] = [ # East Forest # Entrance by the dancing fox holy cross spot LadderInfo("East Forest", "East Forest Redux, East Forest Redux Laddercave_upper"), - LadderInfo("East Forest", "East Forest Dance Fox Spot", dest_is_region=True), # From the west side of Guard House 1 to the east side LadderInfo("Guard House 1 West", "East Forest Redux Laddercave, East Forest Redux_gate"), @@ -101,14 +100,12 @@ easy_ls: List[LadderInfo] = [ # Fortress main entry and grave path lower entry, ls at the ladder by the telescope LadderInfo("Fortress Exterior from Overworld", "Fortress Courtyard, Fortress Main_Big Door"), LadderInfo("Fortress Exterior from Overworld", "Fortress Courtyard, Fortress Reliquary_Lower"), - LadderInfo("Fortress Exterior from Overworld", "Fortress Courtyard", dest_is_region=True), # same as above, except from the east side of the area LadderInfo("Fortress Exterior from East Forest", "Fortress Courtyard, Overworld Redux_"), LadderInfo("Fortress Exterior from East Forest", "Fortress Courtyard, Shop_"), LadderInfo("Fortress Exterior from East Forest", "Fortress Courtyard, Fortress Main_Big Door"), LadderInfo("Fortress Exterior from East Forest", "Fortress Courtyard, Fortress Reliquary_Lower"), - LadderInfo("Fortress Exterior from East Forest", "Fortress Courtyard", dest_is_region=True), # same as above, except from the Beneath the Vault entrance ladder LadderInfo("Fortress Exterior near cave", "Fortress Courtyard, Overworld Redux_", "Ladder to Beneath the Vault"), @@ -116,7 +113,6 @@ easy_ls: List[LadderInfo] = [ "Ladder to Beneath the Vault"), LadderInfo("Fortress Exterior near cave", "Fortress Courtyard, Fortress Reliquary_Lower", "Ladder to Beneath the Vault"), - LadderInfo("Fortress Exterior near cave", "Fortress Courtyard", "Ladder to Beneath the Vault", dest_is_region=True), # Swamp to Gauntlet LadderInfo("Swamp Mid", "Swamp Redux 2, Cathedral Arena_", "Ladders in Swamp"), @@ -124,12 +120,18 @@ easy_ls: List[LadderInfo] = [ # Ladder by the hero grave LadderInfo("Back of Swamp", "Swamp Redux 2, Overworld Redux_conduit"), LadderInfo("Back of Swamp", "Swamp Redux 2, Shop_"), - LadderInfo("Back of Swamp", "Swamp Mid", dest_is_region=True), - LadderInfo("Back of Swamp", "Swamp Front", dest_is_region=True), ] -# if we can gain elevation, add the harder ones +# if we can gain elevation or get knocked down, add the harder ones medium_ls: List[LadderInfo] = [ + # region-destination versions of easy ls spots + LadderInfo("East Forest", "East Forest Dance Fox Spot", dest_is_region=True), + LadderInfo("Fortress Exterior from Overworld", "Fortress Courtyard", dest_is_region=True), + LadderInfo("Fortress Exterior from East Forest", "Fortress Courtyard", dest_is_region=True), + LadderInfo("Fortress Exterior near cave", "Fortress Courtyard", "Ladder to Beneath the Vault", dest_is_region=True), + LadderInfo("Back of Swamp", "Swamp Mid", dest_is_region=True), + LadderInfo("Back of Swamp", "Swamp Front", dest_is_region=True), + # gain height off the northeast fuse ramp LadderInfo("Ruined Atoll", "Atoll Redux, Frog Stairs_eye"), @@ -153,6 +155,7 @@ medium_ls: List[LadderInfo] = [ LadderInfo("Lower Mountain", "Mountain, Mountaintop_"), # Where the rope is behind Monastery + LadderInfo("Quarry Entry", "Quarry Redux, Monastery_back"), LadderInfo("Quarry Monastery Entry", "Quarry Redux, Monastery_back"), LadderInfo("Quarry Back", "Quarry Redux, Monastery_back"), diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index c88997292a..cb613f9e03 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -150,8 +150,8 @@ class ShuffleLadders(Toggle): """ internal_name = "shuffle_ladders" display_name = "Shuffle Ladders" - - + + class TunicPlandoConnections(PlandoConnections): entrances = {*(portal.name for portal in portal_mapping), "Shop", "Shop Portal"} exits = {*(portal.name for portal in portal_mapping), "Shop", "Shop Portal"} @@ -230,14 +230,14 @@ class TunicOptions(PerGameCommonOptions): hexagon_quest: HexagonQuest hexagon_goal: HexagonGoal extra_hexagon_percentage: ExtraHexagonPercentage + laurels_location: LaurelsLocation lanternless: Lanternless maskless: Maskless - laurels_location: LaurelsLocation - plando_connections: TunicPlandoConnections laurels_zips: LaurelsZips ice_grappling: IceGrappling ladder_storage: LadderStorage ladder_storage_without_items: LadderStorageWithoutItems + plando_connections: TunicPlandoConnections logic_rules: Removed