mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-30 02:43:25 -07:00
1.3.6
This commit is contained in:
@@ -197,6 +197,7 @@ def create_dw_regions(world: World):
|
||||
if i == 0:
|
||||
connect_regions(dw_map, dw, f"-> {name}", world.player)
|
||||
else:
|
||||
# noinspection PyUnboundLocalVariable
|
||||
connect_regions(prev_dw, dw, f"{prev_dw.name} -> {name}", world.player)
|
||||
|
||||
loc_id = death_wishes[name]
|
||||
|
||||
@@ -283,7 +283,7 @@ ahit_locations = {
|
||||
# Alpine Skyline
|
||||
"Alpine Skyline - Goat Village: Below Hookpoint": LocData(2000334856, "Alpine Skyline Area (TIHS)"),
|
||||
"Alpine Skyline - Goat Village: Hidden Branch": LocData(2000334855, "Alpine Skyline Area (TIHS)"),
|
||||
"Alpine Skyline - Goat Refinery": LocData(2000333635, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - Goat Refinery": LocData(2000333635, "Alpine Skyline Area (TIHS)"),
|
||||
"Alpine Skyline - Bird Pass Fork": LocData(2000335911, "Alpine Skyline Area (TIHS)"),
|
||||
|
||||
"Alpine Skyline - Yellow Band Hills": LocData(2000335756, "Alpine Skyline Area (TIHS)",
|
||||
@@ -900,6 +900,8 @@ event_locs = {
|
||||
"HUMT Access": LocData(0, "Heating Up Mafia Town"),
|
||||
"TOD Access": LocData(0, "Toilet of Doom"),
|
||||
"YCHE Access": LocData(0, "Your Contract has Expired"),
|
||||
"AFR Access": LocData(0, "Alpine Free Roam"),
|
||||
"TIHS Access": LocData(0, "The Illness has Spread"),
|
||||
|
||||
"Birdhouse Cleared": LocData(0, "The Birdhouse", act_event=True),
|
||||
"Lava Cake Cleared": LocData(0, "The Lava Cake", act_event=True),
|
||||
|
||||
@@ -458,6 +458,15 @@ class NyakuzaThugMaxShopItems(Range):
|
||||
default = 4
|
||||
|
||||
|
||||
class NoTicketSkips(Choice):
|
||||
"""Prevent metro gate skips from being in logic on higher difficulties.
|
||||
Rush Hour option will only consider the ticket skips for Rush Hour in logic."""
|
||||
display_name = "No Ticket Skips"
|
||||
option_false = 0
|
||||
option_true = 1
|
||||
option_rush_hour = 2
|
||||
|
||||
|
||||
class BaseballBat(Toggle):
|
||||
"""Replace the Umbrella with the baseball bat from Nyakuza Metro.
|
||||
DLC2 content does not have to be shuffled for this option but Nyakuza Metro still needs to be installed."""
|
||||
@@ -656,6 +665,7 @@ ahit_options: typing.Dict[str, type(Option)] = {
|
||||
"MetroMaxPonCost": MetroMaxPonCost,
|
||||
"NyakuzaThugMinShopItems": NyakuzaThugMinShopItems,
|
||||
"NyakuzaThugMaxShopItems": NyakuzaThugMaxShopItems,
|
||||
"NoTicketSkips": NoTicketSkips,
|
||||
|
||||
"LowestChapterCost": LowestChapterCost,
|
||||
"HighestChapterCost": HighestChapterCost,
|
||||
@@ -720,6 +730,7 @@ slot_data_options: typing.Dict[str, type(Option)] = {
|
||||
"MetroMinPonCost": MetroMinPonCost,
|
||||
"MetroMaxPonCost": MetroMaxPonCost,
|
||||
"BaseballBat": BaseballBat,
|
||||
"NoTicketSkips": NoTicketSkips,
|
||||
|
||||
"MinPonCost": MinPonCost,
|
||||
"MaxPonCost": MaxPonCost,
|
||||
|
||||
@@ -309,10 +309,10 @@ def create_regions(world: World):
|
||||
|
||||
# Items near the Dead Bird Studio elevator can be reached from the basement act, and beyond in Expert
|
||||
ev_area = create_region_and_connect(w, "Dead Bird Studio - Elevator Area", "DBS -> Elevator Area", dbs)
|
||||
post_ev_area = create_region_and_connect(w, "Dead Bird Studio - Post Elevator Area", "DBS -> Post Elevator Area", dbs)
|
||||
post_ev = create_region_and_connect(w, "Dead Bird Studio - Post Elevator Area", "DBS -> Post Elevator Area", dbs)
|
||||
connect_regions(basement, ev_area, "DBS Basement -> Elevator Area", p)
|
||||
if world.multiworld.LogicDifficulty[world.player].value >= int(Difficulty.EXPERT):
|
||||
connect_regions(basement, post_ev_area, "DBS Basement -> Post Elevator Area", p)
|
||||
connect_regions(basement, post_ev, "DBS Basement -> Post Elevator Area", p)
|
||||
|
||||
# ------------------------------------------- SUBCON FOREST --------------------------------------- #
|
||||
subcon_forest = create_region_and_connect(w, "Subcon Forest", "Telescope -> Subcon Forest", spaceship)
|
||||
@@ -501,12 +501,12 @@ def randomize_act_entrances(world: World):
|
||||
region_list.append(region)
|
||||
|
||||
for region in region_list.copy():
|
||||
if "Time Rift" in region.name:
|
||||
if region.name in chapter_finales:
|
||||
region_list.remove(region)
|
||||
region_list.append(region)
|
||||
|
||||
for region in region_list.copy():
|
||||
if region.name in chapter_finales:
|
||||
if "Time Rift" in region.name:
|
||||
region_list.remove(region)
|
||||
region_list.append(region)
|
||||
|
||||
@@ -631,8 +631,8 @@ def randomize_act_entrances(world: World):
|
||||
candidate = c
|
||||
break
|
||||
|
||||
# noinspection PyUnboundLocalVariable
|
||||
shuffled_list.append(candidate)
|
||||
# print(region, candidate)
|
||||
|
||||
# Vanilla
|
||||
if candidate.name == region.name:
|
||||
|
||||
@@ -317,9 +317,24 @@ def set_rules(world: World):
|
||||
for loc in world.multiworld.get_region("Alpine Skyline Area (TIHS)", world.player).locations:
|
||||
if "Goat Village" in loc.name:
|
||||
continue
|
||||
# This needs some special handling
|
||||
if loc.name == "Alpine Skyline - Goat Refinery":
|
||||
add_rule(loc, lambda state: state.has("AFR Access", world.player)
|
||||
and can_use_hookshot(state, world)
|
||||
and can_hit(state, world, True))
|
||||
|
||||
difficulty: Difficulty = Difficulty(world.multiworld.LogicDifficulty[world.player].value)
|
||||
if difficulty >= Difficulty.MODERATE:
|
||||
add_rule(loc, lambda state: state.has("TIHS Access", world.player)
|
||||
and can_use_hat(state, world, HatType.SPRINT), "or")
|
||||
elif difficulty >= Difficulty.HARD:
|
||||
add_rule(loc, lambda state: state.has("TIHS Access", world.player, "or"))
|
||||
|
||||
continue
|
||||
|
||||
add_rule(loc, lambda state: can_use_hookshot(state, world))
|
||||
|
||||
dummy_entrances: typing.List[Entrance] = []
|
||||
for (key, acts) in act_connections.items():
|
||||
if "Arctic Cruise" in key and not world.is_dlc1():
|
||||
continue
|
||||
@@ -328,7 +343,7 @@ def set_rules(world: World):
|
||||
entrance: Entrance = world.multiworld.get_entrance(key, world.player)
|
||||
region: Region = entrance.connected_region
|
||||
access_rules: typing.List[typing.Callable[[CollectionState], bool]] = []
|
||||
entrance.parent_region.exits.remove(entrance)
|
||||
dummy_entrances.append(entrance)
|
||||
|
||||
# Entrances to this act that we have to set access_rules on
|
||||
entrances: typing.List[Entrance] = []
|
||||
@@ -354,6 +369,9 @@ def set_rules(world: World):
|
||||
for rules in access_rules:
|
||||
add_rule(e, rules)
|
||||
|
||||
for e in dummy_entrances:
|
||||
set_rule(e, lambda state: False)
|
||||
|
||||
set_event_rules(world)
|
||||
|
||||
if world.multiworld.EndGoal[world.player].value == 1:
|
||||
@@ -448,13 +466,12 @@ def set_moderate_rules(world: World):
|
||||
# There is a glitched fall damage volume near the Yellow Overpass time piece that warps the player to Pink Paw.
|
||||
# Yellow Overpass time piece can also be reached without Hookshot quite easily.
|
||||
if world.is_dlc2():
|
||||
set_rule(world.multiworld.get_entrance("-> Pink Paw Station", world.player), lambda state: True)
|
||||
# No Hookshot
|
||||
set_rule(world.multiworld.get_location("Act Completion (Yellow Overpass Station)", world.player),
|
||||
lambda state: True)
|
||||
|
||||
# No Dweller, Hookshot, or Time Stop for these
|
||||
set_rule(world.multiworld.get_location("Pink Paw Station - Cat Vacuum", world.player), lambda state: True)
|
||||
|
||||
# The player can quite literally walk past the fan from the side without Time Stop.
|
||||
set_rule(world.multiworld.get_location("Pink Paw Station - Behind Fan", world.player), lambda state: True)
|
||||
|
||||
# Moderate: clear Rush Hour without Hookshot
|
||||
@@ -465,8 +482,10 @@ def set_moderate_rules(world: World):
|
||||
and can_use_hat(state, world, HatType.ICE)
|
||||
and can_use_hat(state, world, HatType.BREWING))
|
||||
|
||||
# Moderate: Bluefin Tunnel without tickets
|
||||
set_rule(world.multiworld.get_entrance("-> Bluefin Tunnel", world.player), lambda state: True)
|
||||
# Moderate: Bluefin Tunnel + Pink Paw Station without tickets
|
||||
if world.multiworld.NoTicketSkips[world.player].value == 0:
|
||||
set_rule(world.multiworld.get_entrance("-> Pink Paw Station", world.player), lambda state: True)
|
||||
set_rule(world.multiworld.get_entrance("-> Bluefin Tunnel", world.player), lambda state: True)
|
||||
|
||||
|
||||
def set_hard_rules(world: World):
|
||||
@@ -483,6 +502,13 @@ def set_hard_rules(world: World):
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player),
|
||||
lambda state: has_paintings(state, world, 1, False) or state.has("YCHE Access", world.player))
|
||||
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Noose Treehouse", world.player),
|
||||
lambda state: has_paintings(state, world, 2, True))
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Long Tree Climb Chest", world.player),
|
||||
lambda state: has_paintings(state, world, 2, True))
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Tall Tree Hookshot Swing", world.player),
|
||||
lambda state: has_paintings(state, world, 3, True))
|
||||
|
||||
# SDJ
|
||||
add_rule(world.multiworld.get_location("Subcon Forest - Long Tree Climb Chest", world.player),
|
||||
lambda state: can_sdj(state, world) and has_paintings(state, world, 2), "or")
|
||||
@@ -508,8 +534,15 @@ def set_hard_rules(world: World):
|
||||
lambda state: can_use_hat(state, world, HatType.ICE))
|
||||
|
||||
# Hard: clear Rush Hour with Brewing Hat only
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.BREWING))
|
||||
if world.multiworld.NoTicketSkips[world.player].value != 1:
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.BREWING))
|
||||
else:
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.BREWING)
|
||||
and state.has("Metro Ticket - Yellow", world.player)
|
||||
and state.has("Metro Ticket - Blue", world.player)
|
||||
and state.has("Metro Ticket - Pink", world.player))
|
||||
|
||||
|
||||
def set_expert_rules(world: World):
|
||||
@@ -517,8 +550,10 @@ def set_expert_rules(world: World):
|
||||
set_rule(world.multiworld.get_entrance("Telescope -> Time's End", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.FINALE)))
|
||||
|
||||
# Expert: Mafia Town - Above Boats with nothing
|
||||
# Expert: Mafia Town - Above Boats, Top of Lighthouse, and Hot Air Balloon with nothing
|
||||
set_rule(world.multiworld.get_location("Mafia Town - Above Boats", world.player), lambda state: True)
|
||||
set_rule(world.multiworld.get_location("Mafia Town - Top of Lighthouse", world.player), lambda state: True)
|
||||
set_rule(world.multiworld.get_location("Mafia Town - Hot Air Balloon", world.player), lambda state: True)
|
||||
|
||||
# Expert: Clear Dead Bird Studio with nothing
|
||||
for loc in world.multiworld.get_region("Dead Bird Studio - Post Elevator Area", world.player).locations:
|
||||
@@ -561,13 +596,9 @@ def set_expert_rules(world: World):
|
||||
# Set painting rules only. Skipping paintings is determined in has_paintings
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player),
|
||||
lambda state: has_paintings(state, world, 1, True))
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Noose Treehouse", world.player),
|
||||
lambda state: has_paintings(state, world, 2, True))
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Long Tree Climb Chest", world.player),
|
||||
lambda state: has_paintings(state, world, 2, True))
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Dweller Platforming Tree B", world.player),
|
||||
lambda state: has_paintings(state, world, 3, True))
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Tall Tree Hookshot Swing", world.player),
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Magnet Badge Bush", world.player),
|
||||
lambda state: has_paintings(state, world, 3, True))
|
||||
|
||||
# You can cherry hover to Snatcher's post-fight cutscene, which completes the level without having to fight him
|
||||
@@ -579,7 +610,13 @@ def set_expert_rules(world: World):
|
||||
|
||||
if world.is_dlc2():
|
||||
# Expert: clear Rush Hour with nothing
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player), lambda state: True)
|
||||
if world.multiworld.NoTicketSkips[world.player].value == 0:
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player), lambda state: True)
|
||||
else:
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player),
|
||||
lambda state: state.has("Metro Ticket - Yellow", world.player)
|
||||
and state.has("Metro Ticket - Blue", world.player)
|
||||
and state.has("Metro Ticket - Pink", world.player))
|
||||
|
||||
|
||||
def set_mafia_town_rules(world: World):
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from BaseClasses import Item, ItemClassification, Tutorial
|
||||
from .Items import item_table, create_item, relic_groups, act_contracts, create_itempool
|
||||
from .Regions import create_regions, randomize_act_entrances, chapter_act_info, create_events, get_shuffled_region
|
||||
from .Locations import location_table, contract_locations, is_location_valid, get_location_names, TASKSANITY_START_ID
|
||||
from .Locations import location_table, contract_locations, is_location_valid, get_location_names, TASKSANITY_START_ID, \
|
||||
get_total_locations
|
||||
from .Rules import set_rules
|
||||
from .Options import ahit_options, slot_data_options, adjust_options
|
||||
from .Types import HatType, ChapterIndex, HatInTimeItem
|
||||
@@ -173,7 +174,8 @@ class HatInTimeWorld(World):
|
||||
"Chapter7Cost": chapter_timepiece_costs[self.player][ChapterIndex.METRO],
|
||||
"BadgeSellerItemCount": badge_seller_count[self.player],
|
||||
"SeedNumber": str(self.multiworld.seed), # For shop prices
|
||||
"SeedName": self.multiworld.seed_name}
|
||||
"SeedName": self.multiworld.seed_name,
|
||||
"TotalLocations": get_total_locations(self)}
|
||||
|
||||
if self.multiworld.HatItems[self.player].value == 0:
|
||||
slot_data.setdefault("SprintYarnCost", hat_yarn_costs[self.player][HatType.SPRINT])
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from worlds.ahit.Regions import act_chapters
|
||||
from worlds.ahit.Rules import act_connections
|
||||
from worlds.ahit.test.TestBase import HatInTimeTestBase
|
||||
|
||||
|
||||
@@ -6,9 +7,6 @@ class TestActs(HatInTimeTestBase):
|
||||
def run_default_tests(self) -> bool:
|
||||
return False
|
||||
|
||||
def testAllStateCanReachEverything(self):
|
||||
pass
|
||||
|
||||
options = {
|
||||
"ActRandomizer": 2,
|
||||
"EnableDLC1": 1,
|
||||
@@ -24,6 +22,9 @@ class TestActs(HatInTimeTestBase):
|
||||
for name in act_chapters.keys():
|
||||
region = self.multiworld.get_region(name, 1)
|
||||
for entrance in region.entrances:
|
||||
if entrance.name in act_connections.keys():
|
||||
continue
|
||||
|
||||
self.assertTrue(self.can_reach_entrance(entrance.name),
|
||||
f"Can't reach {name} from {entrance}\n"
|
||||
f"{entrance.parent_region.entrances[0]} -> {entrance.parent_region} "
|
||||
|
||||
Reference in New Issue
Block a user