mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-27 14:53:22 -07:00
More stuff from review
This commit is contained in:
@@ -149,21 +149,21 @@ dw_classes = {
|
||||
def create_dw_regions(world: "HatInTimeWorld"):
|
||||
if world.options.DWExcludeAnnoyingContracts.value > 0:
|
||||
for name in annoying_dws:
|
||||
world.get_excluded_dws().append(name)
|
||||
world.excluded_dws.append(name)
|
||||
|
||||
if world.options.DWEnableBonus.value == 0 \
|
||||
or world.options.DWAutoCompleteBonuses.value > 0:
|
||||
for name in death_wishes:
|
||||
world.get_excluded_bonuses().append(name)
|
||||
world.excluded_bonuses.append(name)
|
||||
elif world.options.DWExcludeAnnoyingBonuses.value > 0:
|
||||
for name in annoying_bonuses:
|
||||
world.get_excluded_bonuses().append(name)
|
||||
world.excluded_bonuses.append(name)
|
||||
|
||||
if world.options.DWExcludeCandles.value > 0:
|
||||
for name in dw_candles:
|
||||
if name in world.get_excluded_dws():
|
||||
if name in world.excluded_dws:
|
||||
continue
|
||||
world.get_excluded_dws().append(name)
|
||||
world.excluded_dws.append(name)
|
||||
|
||||
spaceship = world.multiworld.get_region("Spaceship", world.player)
|
||||
dw_map: Region = create_region(world, "Death Wish Map")
|
||||
@@ -193,7 +193,7 @@ def create_dw_regions(world: "HatInTimeWorld"):
|
||||
|
||||
dw_shuffle.append("Seal the Deal")
|
||||
|
||||
world.set_dw_shuffle(dw_shuffle)
|
||||
world.dw_shuffle = dw_shuffle
|
||||
prev_dw: Region
|
||||
for i in range(len(dw_shuffle)):
|
||||
name = dw_shuffle[i]
|
||||
@@ -220,7 +220,7 @@ def create_dw_regions(world: "HatInTimeWorld"):
|
||||
bonus_stamps.place_locked_item(HatInTimeItem(f"2 Stamps - {name}",
|
||||
ItemClassification.progression, None, world.player))
|
||||
|
||||
if name in world.get_excluded_dws():
|
||||
if name in world.excluded_dws:
|
||||
main_objective.progress_type = LocationProgressType.EXCLUDED
|
||||
full_clear.progress_type = LocationProgressType.EXCLUDED
|
||||
elif world.is_bonus_excluded(name):
|
||||
@@ -232,7 +232,7 @@ def create_dw_regions(world: "HatInTimeWorld"):
|
||||
else:
|
||||
for key, loc_id in death_wishes.items():
|
||||
if key == "Snatcher Coins in Nyakuza Metro" and not world.is_dlc2():
|
||||
world.get_excluded_dws().append(key)
|
||||
world.excluded_dws.append(key)
|
||||
continue
|
||||
|
||||
dw = create_region(world, key)
|
||||
@@ -258,7 +258,7 @@ def create_dw_regions(world: "HatInTimeWorld"):
|
||||
bonus_stamps.place_locked_item(HatInTimeItem(f"2 Stamps - {key}",
|
||||
ItemClassification.progression, None, world.player))
|
||||
|
||||
if key in world.get_excluded_dws():
|
||||
if key in world.excluded_dws:
|
||||
main_objective.progress_type = LocationProgressType.EXCLUDED
|
||||
full_clear.progress_type = LocationProgressType.EXCLUDED
|
||||
elif world.is_bonus_excluded(key):
|
||||
|
||||
@@ -103,13 +103,13 @@ required_snatcher_coins = {
|
||||
|
||||
|
||||
def set_dw_rules(world: "HatInTimeWorld"):
|
||||
if "Snatcher's Hit List" not in world.get_excluded_dws() \
|
||||
or "Camera Tourist" not in world.get_excluded_dws():
|
||||
if "Snatcher's Hit List" not in world.excluded_dws \
|
||||
or "Camera Tourist" not in world.excluded_dws:
|
||||
set_enemy_rules(world)
|
||||
|
||||
dw_list: List[str] = []
|
||||
if world.options.DWShuffle.value > 0:
|
||||
dw_list = world.get_dw_shuffle()
|
||||
dw_list = world.dw_shuffle
|
||||
else:
|
||||
for name in death_wishes.keys():
|
||||
dw_list.append(name)
|
||||
@@ -196,13 +196,12 @@ def set_dw_rules(world: "HatInTimeWorld"):
|
||||
add_rule(bonus_stamps, loc.access_rule)
|
||||
|
||||
if world.options.DWShuffle.value > 0:
|
||||
dw_shuffle = world.get_dw_shuffle()
|
||||
for i in range(len(dw_shuffle)):
|
||||
for i in range(len(world.dw_shuffle)):
|
||||
if i == 0:
|
||||
continue
|
||||
|
||||
name = dw_shuffle[i]
|
||||
prev_dw = world.multiworld.get_region(dw_shuffle[i-1], world.player)
|
||||
name = world.dw_shuffle[i]
|
||||
prev_dw = world.multiworld.get_region(world.dw_shuffle[i-1], world.player)
|
||||
entrance = world.multiworld.get_entrance(f"{prev_dw.name} -> {name}", world.player)
|
||||
add_rule(entrance, lambda state, n=prev_dw.name: state.has(f"1 Stamp - {n}", world.player))
|
||||
else:
|
||||
@@ -330,10 +329,16 @@ def set_candle_dw_rules(name: str, world: "HatInTimeWorld"):
|
||||
and state.has("Triple Enemy Picture", world.player))
|
||||
|
||||
elif "Snatcher Coins" in name:
|
||||
coins: List[str] = []
|
||||
for coin in required_snatcher_coins[name]:
|
||||
add_rule(main_objective, lambda state: state.has(coin, world.player), "or")
|
||||
coins.append(coin)
|
||||
add_rule(full_clear, lambda state: state.has(coin, world.player))
|
||||
|
||||
# any coin works for the main objective
|
||||
add_rule(main_objective, lambda state: state.has(coins[0], world.player)
|
||||
or state.has(coins[1], world.player)
|
||||
or state.has(coins[2], world.player))
|
||||
|
||||
|
||||
def get_zero_jump_clear_count(state: CollectionState, world: "HatInTimeWorld") -> int:
|
||||
total = 0
|
||||
@@ -378,7 +383,7 @@ def can_reach_all_bosses(state: CollectionState, world: "HatInTimeWorld") -> boo
|
||||
|
||||
|
||||
def create_enemy_events(world: "HatInTimeWorld"):
|
||||
no_tourist = "Camera Tourist" in world.get_excluded_dws() or "Camera Tourist" in world.get_excluded_bonuses()
|
||||
no_tourist = "Camera Tourist" in world.excluded_dws or "Camera Tourist" in world.excluded_bonuses
|
||||
|
||||
for enemy, regions in hit_list.items():
|
||||
if no_tourist and enemy in bosses:
|
||||
@@ -395,7 +400,7 @@ def create_enemy_events(world: "HatInTimeWorld"):
|
||||
if area == "Bluefin Tunnel" and not world.is_dlc2():
|
||||
continue
|
||||
if world.options.DWShuffle.value > 0 and area in death_wishes.keys() \
|
||||
and area not in world.get_dw_shuffle():
|
||||
and area not in world.dw_shuffle:
|
||||
continue
|
||||
|
||||
region = world.multiworld.get_region(area, world.player)
|
||||
@@ -409,7 +414,7 @@ def create_enemy_events(world: "HatInTimeWorld"):
|
||||
continue
|
||||
|
||||
if world.options.DWShuffle.value > 0 and name in death_wishes.keys() \
|
||||
and name not in world.get_dw_shuffle():
|
||||
and name not in world.dw_shuffle:
|
||||
continue
|
||||
|
||||
region = world.multiworld.get_region(name, world.player)
|
||||
@@ -422,7 +427,7 @@ def create_enemy_events(world: "HatInTimeWorld"):
|
||||
|
||||
|
||||
def set_enemy_rules(world: "HatInTimeWorld"):
|
||||
no_tourist = "Camera Tourist" in world.get_excluded_dws() or "Camera Tourist" in world.get_excluded_bonuses()
|
||||
no_tourist = "Camera Tourist" in world.excluded_dws or "Camera Tourist" in world.excluded_bonuses
|
||||
|
||||
for enemy, regions in hit_list.items():
|
||||
if no_tourist and enemy in bosses:
|
||||
@@ -440,7 +445,7 @@ def set_enemy_rules(world: "HatInTimeWorld"):
|
||||
continue
|
||||
|
||||
if world.options.DWShuffle.value > 0 and area in death_wishes \
|
||||
and area not in world.get_dw_shuffle():
|
||||
and area not in world.dw_shuffle:
|
||||
continue
|
||||
|
||||
event = world.multiworld.get_location(f"{enemy} - {area}", world.player)
|
||||
|
||||
@@ -97,7 +97,7 @@ def calculate_yarn_costs(world: "HatInTimeWorld"):
|
||||
max_cost = 0
|
||||
for i in range(5):
|
||||
cost: int = mw.random.randint(min(min_yarn_cost, max_yarn_cost), max(max_yarn_cost, min_yarn_cost))
|
||||
world.get_hat_yarn_costs()[HatType(i)] = cost
|
||||
world.hat_yarn_costs[HatType(i)] = cost
|
||||
max_cost += cost
|
||||
|
||||
available_yarn: int = world.options.YarnAvailable.value
|
||||
|
||||
@@ -12,7 +12,7 @@ def get_total_locations(world: "HatInTimeWorld") -> int:
|
||||
total = 0
|
||||
|
||||
if not world.is_dw_only():
|
||||
for (name) in location_table.keys():
|
||||
for name in location_table.keys():
|
||||
if is_location_valid(world, name):
|
||||
total += 1
|
||||
|
||||
@@ -21,9 +21,9 @@ def get_total_locations(world: "HatInTimeWorld") -> int:
|
||||
|
||||
if world.is_dw():
|
||||
if world.options.DWShuffle.value > 0:
|
||||
total += len(world.get_dw_shuffle())
|
||||
total += len(world.dw_shuffle)
|
||||
if world.options.DWEnableBonus.value > 0:
|
||||
total += len(world.get_dw_shuffle())
|
||||
total += len(world.dw_shuffle)
|
||||
else:
|
||||
total += 37
|
||||
if world.is_dlc2():
|
||||
@@ -81,11 +81,11 @@ def is_location_valid(world: "HatInTimeWorld", location: str) -> bool:
|
||||
return False
|
||||
|
||||
if world.options.DWShuffle.value > 0 \
|
||||
and data.region in death_wishes and data.region not in world.get_dw_shuffle():
|
||||
and data.region in death_wishes and data.region not in world.dw_shuffle:
|
||||
return False
|
||||
|
||||
if location in zero_jumps:
|
||||
if world.options.DWShuffle.value > 0 and "Zero Jumps" not in world.get_dw_shuffle():
|
||||
if world.options.DWShuffle.value > 0 and "Zero Jumps" not in world.dw_shuffle:
|
||||
return False
|
||||
|
||||
difficulty: int = world.options.LogicDifficulty.value
|
||||
@@ -298,10 +298,10 @@ 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 (TIHS)"),
|
||||
"Alpine Skyline - Bird Pass Fork": LocData(2000335911, "Alpine Skyline Area (TIHS)"),
|
||||
"Alpine Skyline - Goat Refinery": LocData(2000333635, "Alpine Skyline Area (TIHS)", hookshot=True),
|
||||
"Alpine Skyline - Bird Pass Fork": LocData(2000335911, "Alpine Skyline Area (TIHS)", hookshot=True),
|
||||
|
||||
"Alpine Skyline - Yellow Band Hills": LocData(2000335756, "Alpine Skyline Area (TIHS)",
|
||||
"Alpine Skyline - Yellow Band Hills": LocData(2000335756, "Alpine Skyline Area (TIHS)", hookshot=True,
|
||||
required_hats=[HatType.BREWING]),
|
||||
|
||||
"Alpine Skyline - The Purrloined Village: Horned Stone": LocData(2000335561, "Alpine Skyline Area"),
|
||||
@@ -318,7 +318,7 @@ ahit_locations = {
|
||||
|
||||
"Alpine Skyline - Mystifying Time Mesa: Zipline": LocData(2000337058, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - Mystifying Time Mesa: Gate Puzzle": LocData(2000336052, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - Ember Summit": LocData(2000336311, "Alpine Skyline Area (TIHS)"),
|
||||
"Alpine Skyline - Ember Summit": LocData(2000336311, "Alpine Skyline Area (TIHS)", hookshot=True),
|
||||
"Alpine Skyline - The Lava Cake: Center Fence Cage": LocData(2000335448, "The Lava Cake"),
|
||||
"Alpine Skyline - The Lava Cake: Outer Island Chest": LocData(2000334291, "The Lava Cake"),
|
||||
"Alpine Skyline - The Lava Cake: Dweller Pillars": LocData(2000335417, "The Lava Cake"),
|
||||
@@ -327,7 +327,7 @@ ahit_locations = {
|
||||
"Alpine Skyline - The Twilight Bell: Wide Purple Platform": LocData(2000336478, "The Twilight Bell"),
|
||||
"Alpine Skyline - The Twilight Bell: Ice Platform": LocData(2000335826, "The Twilight Bell"),
|
||||
"Alpine Skyline - Goat Outpost Horn": LocData(2000334760, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - Windy Passage": LocData(2000334776, "Alpine Skyline Area (TIHS)"),
|
||||
"Alpine Skyline - Windy Passage": LocData(2000334776, "Alpine Skyline Area (TIHS)", hookshot=True),
|
||||
"Alpine Skyline - The Windmill: Inside Pon Cluster": LocData(2000336395, "The Windmill"),
|
||||
"Alpine Skyline - The Windmill: Entrance": LocData(2000335783, "The Windmill"),
|
||||
"Alpine Skyline - The Windmill: Dropdown": LocData(2000335815, "The Windmill"),
|
||||
@@ -867,54 +867,112 @@ zero_jumps = {
|
||||
dlc_flags=HatDLC.dlc2_dw),
|
||||
}
|
||||
|
||||
# noinspection PyDictDuplicateKeys
|
||||
snatcher_coins = {
|
||||
"Snatcher Coin - Top of HQ": LocData(0, "Down with the Mafia!", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of HQ": LocData(0, "Cheating the Race", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of HQ (DWTM)": LocData(0, "Down with the Mafia!", snatcher_coin="Snatcher Coin - Top of HQ",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Top of HQ": LocData(0, "Heating Up Mafia Town",
|
||||
hit_type=HitType.umbrella, dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of HQ (CTR)": LocData(0, "Cheating the Race", snatcher_coin="Snatcher Coin - Top of HQ",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Top of HQ": LocData(0, "The Golden Vault", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of HQ": LocData(0, "Beat the Heat", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of HQ (HUMT)": LocData(0, "Heating Up Mafia Town", snatcher_coin="Snatcher Coin - Top of HQ",
|
||||
hit_type=HitType.umbrella, dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Top of Tower": LocData(0, "Mafia Town Area (HUMT)", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of Tower": LocData(0, "Beat the Heat", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of Tower": LocData(0, "Collect-a-thon", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of Tower": LocData(0, "She Speedran from Outer Space", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of Tower": LocData(0, "Mafia's Jumps", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Under Ruined Tower": LocData(0, "Mafia Town Area", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Under Ruined Tower": LocData(0, "Collect-a-thon", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Under Ruined Tower": LocData(0, "She Speedran from Outer Space", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of HQ (TGV)": LocData(0, "The Golden Vault", snatcher_coin="Snatcher Coin - Top of HQ",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Top of Red House": LocData(0, "Dead Bird Studio - Elevator Area", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of Red House": LocData(0, "Security Breach", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Train Rush": LocData(0, "Train Rush", hookshot=True, dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Top of HQ (DW: BTH)": LocData(0, "Beat the Heat", snatcher_coin="Snatcher Coin - Top of HQ",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Train Rush": LocData(0, "10 Seconds until Self-Destruct", hookshot=True,
|
||||
"Snatcher Coin - Top of Tower": LocData(0, "Mafia Town Area (HUMT)", snatcher_coin="Snatcher Coin - Top of Tower",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Top of Tower (DW: BTH)": LocData(0, "Beat the Heat", snatcher_coin="Snatcher Coin - Top of Tower",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Top of Tower (DW: CAT)": LocData(0, "Collect-a-thon", snatcher_coin="Snatcher Coin - Top of Tower",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Top of Tower (SSFOS)": LocData(0, "She Speedran from Outer Space",
|
||||
snatcher_coin="Snatcher Coin - Top of Tower",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Top of Tower (DW: MJ)": LocData(0, "Mafia's Jumps", snatcher_coin="Snatcher Coin - Top of Tower",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Under Ruined Tower": LocData(0, "Mafia Town Area",
|
||||
snatcher_coin="Snatcher Coin - Under Ruined Tower",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Under Ruined Tower (DW: CAT)": LocData(0, "Collect-a-thon",
|
||||
snatcher_coin="Snatcher Coin - Under Ruined Tower",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Under Ruined Tower (DW: SSFOS)": LocData(0, "She Speedran from Outer Space",
|
||||
snatcher_coin="Snatcher Coin - Under Ruined Tower",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Top of Red House (DBS)": LocData(0, "Dead Bird Studio - Elevator Area",
|
||||
snatcher_coin="Snatcher Coin - Top of Red House",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Top of Red House (DW: SB)": LocData(0, "Security Breach",
|
||||
snatcher_coin="Snatcher Coin - Top of Red House",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Train Rush": LocData(0, "Train Rush", snatcher_coin="Snatcher Coin - Train Rush",
|
||||
hookshot=True, dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Train Rush (10 Seconds)": LocData(0, "10 Seconds until Self-Destruct",
|
||||
snatcher_coin="Snatcher Coin - Train Rush",
|
||||
hookshot=True, dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Picture Perfect": LocData(0, "Picture Perfect", snatcher_coin="Snatcher Coin - Picture Perfect",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Swamp Tree": LocData(0, "Subcon Forest Area", snatcher_coin="Snatcher Coin - Swamp Tree",
|
||||
hookshot=True, paintings=1,
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Picture Perfect": LocData(0, "Picture Perfect", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Swamp Tree (Speedrun Well)": LocData(0, "Speedrun Well",
|
||||
snatcher_coin="Snatcher Coin - Swamp Tree",
|
||||
hookshot=True, dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Swamp Tree": LocData(0, "Subcon Forest Area", hookshot=True, paintings=1,
|
||||
"Snatcher Coin - Manor Roof": LocData(0, "Subcon Forest Area", snatcher_coin="Snatcher Coin - Manor Roof",
|
||||
hit_type=HitType.dweller_bell, paintings=1,
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Swamp Tree": LocData(0, "Speedrun Well", hookshot=True, dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Giant Time Piece": LocData(0, "Subcon Forest Area",
|
||||
snatcher_coin="Snatcher Coin - Giant Time Piece",
|
||||
paintings=3, dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Manor Roof": LocData(0, "Subcon Forest Area", hit_type=HitType.dweller_bell, paintings=1,
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Goat Village Top": LocData(0, "Alpine Skyline Area (TIHS)",
|
||||
snatcher_coin="Snatcher Coin - Goat Village Top",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Giant Time Piece": LocData(0, "Subcon Forest Area", paintings=3, dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Goat Village Top (Illness Speedrun)": LocData(0, "The Illness has Speedrun",
|
||||
snatcher_coin="Snatcher Coin - Goat Village Top",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Goat Village Top": LocData(0, "Alpine Skyline Area (TIHS)", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Goat Village Top": LocData(0, "The Illness has Speedrun", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Lava Cake": LocData(0, "The Lava Cake", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Windmill": LocData(0, "The Windmill", dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Windmill": LocData(0, "Wound-Up Windmill", hookshot=True, dlc_flags=HatDLC.death_wish),
|
||||
"Snatcher Coin - Lava Cake": LocData(0, "The Lava Cake", snatcher_coin="Snatcher Coin - Lava Cake",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Green Clean Tower": LocData(0, "Green Clean Station", dlc_flags=HatDLC.dlc2_dw),
|
||||
"Snatcher Coin - Bluefin Cat Train": LocData(0, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2_dw),
|
||||
"Snatcher Coin - Pink Paw Fence": LocData(0, "Pink Paw Station", dlc_flags=HatDLC.dlc2_dw),
|
||||
"Snatcher Coin - Windmill": LocData(0, "The Windmill", snatcher_coin="Snatcher Coin - Windmill",
|
||||
dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Windmill (DW: WUW)": LocData(0, "Wound-Up Windmill", snatcher_coin="Snatcher Coin - Windmill",
|
||||
hookshot=True, dlc_flags=HatDLC.death_wish),
|
||||
|
||||
"Snatcher Coin - Green Clean Tower": LocData(0, "Green Clean Station",
|
||||
snatcher_coin="Snatcher Coin - Green Clean Tower",
|
||||
dlc_flags=HatDLC.dlc2_dw),
|
||||
|
||||
"Snatcher Coin - Bluefin Cat Train": LocData(0, "Bluefin Tunnel",
|
||||
snatcher_coin="Snatcher Coin - Bluefin Tunnel",
|
||||
dlc_flags=HatDLC.dlc2_dw),
|
||||
|
||||
"Snatcher Coin - Pink Paw Fence": LocData(0, "Pink Paw Station",
|
||||
snatcher_coin="Snatcher Coin - Pink Paw Fence",
|
||||
dlc_flags=HatDLC.dlc2_dw),
|
||||
}
|
||||
|
||||
event_locs = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from typing import List, TYPE_CHECKING
|
||||
from schema import Schema
|
||||
from schema import Schema, Optional
|
||||
from dataclasses import dataclass
|
||||
from worlds.AutoWorld import PerGameCommonOptions
|
||||
from Options import Range, Toggle, DeathLink, Choice, OptionDict, DefaultOnToggle
|
||||
@@ -128,7 +128,7 @@ class ActPlando(OptionDict):
|
||||
"""Plando acts onto other acts. For example, \"Train Rush\": \"Alpine Free Roam\""""
|
||||
display_name = "Act Plando"
|
||||
schema = Schema({
|
||||
str: str
|
||||
Optional(str): str
|
||||
})
|
||||
|
||||
|
||||
@@ -516,7 +516,8 @@ class DWShuffleCountMax(Range):
|
||||
|
||||
|
||||
class DWEnableBonus(Toggle):
|
||||
"""In Death Wish, add a location for completing all of a DW contract's bonuses, in addition to the location for completing the DW contract normally.
|
||||
"""In Death Wish, add a location for completing all of a DW contract's bonuses,
|
||||
in addition to the location for completing the DW contract normally.
|
||||
WARNING!! Only for the brave! This option can create VERY DIFFICULT SEEDS!
|
||||
ONLY turn this on if you know what you are doing to yourself and everyone else in the multiworld!
|
||||
Using Peace and Tranquility to auto-complete the bonuses will NOT count!"""
|
||||
|
||||
@@ -788,7 +788,7 @@ def create_badge_seller(world: "HatInTimeWorld") -> Region:
|
||||
world.options.BadgeSellerMaxItems.value)
|
||||
|
||||
if max_items <= 0:
|
||||
world.set_badge_seller_count(0)
|
||||
world.badge_seller_count = 0
|
||||
return badge_seller
|
||||
|
||||
for (key, data) in shop_locations.items():
|
||||
@@ -803,7 +803,7 @@ def create_badge_seller(world: "HatInTimeWorld") -> Region:
|
||||
if count >= max_items:
|
||||
break
|
||||
|
||||
world.set_badge_seller_count(max_items)
|
||||
world.badge_seller_count = max_items
|
||||
return badge_seller
|
||||
|
||||
|
||||
@@ -867,9 +867,9 @@ def update_chapter_act_info(world: "HatInTimeWorld", original_region: Region, ne
|
||||
world.act_connections[original_act_info] = new_act_info
|
||||
|
||||
|
||||
def get_shuffled_region(self, region: str) -> str:
|
||||
def get_shuffled_region(world: "HatInTimeWorld", region: str) -> str:
|
||||
ci: str = chapter_act_info[region]
|
||||
for key, val in self.act_connections.items():
|
||||
for key, val in world.act_connections.items():
|
||||
if val == ci:
|
||||
for name in chapter_act_info.keys():
|
||||
if chapter_act_info[name] == key:
|
||||
@@ -882,7 +882,6 @@ def create_thug_shops(world: "HatInTimeWorld"):
|
||||
count = -1
|
||||
step = 0
|
||||
old_name = ""
|
||||
thug_items = world.get_nyakuza_thug_items()
|
||||
|
||||
for key, data in shop_locations.items():
|
||||
if data.nyakuza_thug == "":
|
||||
@@ -892,14 +891,14 @@ def create_thug_shops(world: "HatInTimeWorld"):
|
||||
continue
|
||||
|
||||
try:
|
||||
if thug_items[data.nyakuza_thug] <= 0:
|
||||
if world.nyakuza_thug_items[data.nyakuza_thug] <= 0:
|
||||
continue
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if count == -1:
|
||||
count = world.random.randint(min_items, max_items)
|
||||
thug_items.setdefault(data.nyakuza_thug, count)
|
||||
world.nyakuza_thug_items.setdefault(data.nyakuza_thug, count)
|
||||
if count <= 0:
|
||||
continue
|
||||
|
||||
@@ -915,8 +914,6 @@ def create_thug_shops(world: "HatInTimeWorld"):
|
||||
step = 0
|
||||
count = -1
|
||||
|
||||
world.set_nyakuza_thug_items(thug_items)
|
||||
|
||||
|
||||
def create_events(world: "HatInTimeWorld") -> int:
|
||||
count = 0
|
||||
@@ -928,7 +925,7 @@ def create_events(world: "HatInTimeWorld") -> int:
|
||||
item_name: str = name
|
||||
if world.is_dw():
|
||||
if name in snatcher_coins.keys():
|
||||
name = f"{name} ({data.region})"
|
||||
item_name = data.snatcher_coin
|
||||
elif name in zero_jumps:
|
||||
if get_difficulty(world) < Difficulty.HARD and name in zero_jumps_hard:
|
||||
continue
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from worlds.AutoWorld import CollectionState
|
||||
from worlds.generic.Rules import add_rule, set_rule
|
||||
from .Locations import location_table, zipline_unlocks, is_location_valid, contract_locations, \
|
||||
shop_locations, event_locs, snatcher_coins
|
||||
from .Types import HatType, ChapterIndex, hat_type_to_item, Difficulty, HatDLC, HitType
|
||||
shop_locations, event_locs
|
||||
from .Types import HatType, ChapterIndex, hat_type_to_item, Difficulty, HitType
|
||||
from BaseClasses import Location, Entrance, Region
|
||||
from typing import TYPE_CHECKING, List, Callable, Union, Dict
|
||||
|
||||
@@ -43,9 +43,8 @@ def can_use_hat(state: CollectionState, world: "HatInTimeWorld", hat: HatType) -
|
||||
|
||||
def get_hat_cost(world: "HatInTimeWorld", hat: HatType) -> int:
|
||||
cost = 0
|
||||
costs = world.get_hat_yarn_costs()
|
||||
for h in world.get_hat_craft_order():
|
||||
cost += costs[h]
|
||||
for h in world.hat_craft_order:
|
||||
cost += world.hat_yarn_costs[h]
|
||||
if h == hat:
|
||||
break
|
||||
|
||||
@@ -136,7 +135,7 @@ def can_clear_metro(state: CollectionState, world: "HatInTimeWorld") -> bool:
|
||||
def set_rules(world: "HatInTimeWorld"):
|
||||
# First, chapter access
|
||||
starting_chapter = ChapterIndex(world.options.StartingChapter.value)
|
||||
world.set_chapter_cost(starting_chapter, 0)
|
||||
world.chapter_timepiece_costs[starting_chapter] = 0
|
||||
|
||||
# Chapter costs increase progressively. Randomly decide the chapter order, except for Finale
|
||||
chapter_list: List[ChapterIndex] = [ChapterIndex.MAFIA, ChapterIndex.BIRDS,
|
||||
@@ -160,8 +159,8 @@ def set_rules(world: "HatInTimeWorld"):
|
||||
world.random.shuffle(chapter_list)
|
||||
|
||||
if starting_chapter is not ChapterIndex.ALPINE and (world.is_dlc1() or world.is_dlc2()):
|
||||
index1: int = 69
|
||||
index2: int = 69
|
||||
index1 = 69
|
||||
index2 = 69
|
||||
pos: int
|
||||
lowest_index: int
|
||||
chapter_list.remove(ChapterIndex.ALPINE)
|
||||
@@ -180,75 +179,63 @@ def set_rules(world: "HatInTimeWorld"):
|
||||
|
||||
chapter_list.insert(pos, ChapterIndex.ALPINE)
|
||||
|
||||
if world.is_dlc1() and world.is_dlc2() and final_chapter is not ChapterIndex.METRO:
|
||||
chapter_list.remove(ChapterIndex.METRO)
|
||||
index = chapter_list.index(ChapterIndex.CRUISE)
|
||||
if index >= len(chapter_list):
|
||||
chapter_list.append(ChapterIndex.METRO)
|
||||
else:
|
||||
chapter_list.insert(world.random.randint(index+1, len(chapter_list)), ChapterIndex.METRO)
|
||||
|
||||
lowest_cost: int = world.options.LowestChapterCost.value
|
||||
highest_cost: int = world.options.HighestChapterCost.value
|
||||
cost_increment: int = world.options.ChapterCostIncrement.value
|
||||
min_difference: int = world.options.ChapterCostMinDifference.value
|
||||
last_cost = 0
|
||||
loop_count = 0
|
||||
|
||||
for chapter in chapter_list:
|
||||
min_range: int = lowest_cost + (cost_increment * loop_count)
|
||||
for i, chapter in enumerate(chapter_list):
|
||||
min_range: int = lowest_cost + (cost_increment * i)
|
||||
if min_range >= highest_cost:
|
||||
min_range = highest_cost-1
|
||||
|
||||
value: int = world.random.randint(min_range, min(highest_cost, max(lowest_cost, last_cost + cost_increment)))
|
||||
|
||||
cost = world.random.randint(value, min(value + cost_increment, highest_cost))
|
||||
if loop_count >= 1:
|
||||
if i >= 1:
|
||||
if last_cost + min_difference > cost:
|
||||
cost = last_cost + min_difference
|
||||
|
||||
cost = min(cost, highest_cost)
|
||||
world.set_chapter_cost(chapter, cost)
|
||||
world.chapter_timepiece_costs[chapter] = cost
|
||||
last_cost = cost
|
||||
loop_count += 1
|
||||
|
||||
if final_chapter is not None:
|
||||
world.set_chapter_cost(final_chapter, world.random.randint(
|
||||
world.chapter_timepiece_costs[final_chapter] = world.random.randint(
|
||||
world.options.FinalChapterMinCost.value,
|
||||
world.options.FinalChapterMaxCost.value))
|
||||
world.options.FinalChapterMaxCost.value)
|
||||
|
||||
add_rule(world.multiworld.get_entrance("Telescope -> Mafia Town", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.MAFIA)))
|
||||
lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.MAFIA]))
|
||||
|
||||
add_rule(world.multiworld.get_entrance("Telescope -> Battle of the Birds", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS)))
|
||||
lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.BIRDS]))
|
||||
|
||||
add_rule(world.multiworld.get_entrance("Telescope -> Subcon Forest", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.SUBCON)))
|
||||
lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.SUBCON]))
|
||||
|
||||
add_rule(world.multiworld.get_entrance("Telescope -> Alpine Skyline", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE)))
|
||||
lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.ALPINE]))
|
||||
|
||||
add_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))
|
||||
lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.FINALE])
|
||||
and can_use_hat(state, world, HatType.BREWING) and can_use_hat(state, world, HatType.DWELLER))
|
||||
|
||||
if world.is_dlc1():
|
||||
add_rule(world.multiworld.get_entrance("Telescope -> The Arctic Cruise", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE))
|
||||
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.CRUISE)))
|
||||
lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.ALPINE])
|
||||
and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.CRUISE]))
|
||||
|
||||
if world.is_dlc2():
|
||||
add_rule(world.multiworld.get_entrance("Telescope -> Nyakuza Metro", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE))
|
||||
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.METRO))
|
||||
lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.ALPINE])
|
||||
and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.METRO])
|
||||
and can_use_hat(state, world, HatType.DWELLER) and can_use_hat(state, world, HatType.ICE))
|
||||
|
||||
if world.options.ActRandomizer.value == 0:
|
||||
set_default_rift_rules(world)
|
||||
|
||||
table = {**location_table, **event_locs}
|
||||
loc: Location
|
||||
for (key, data) in table.items():
|
||||
if not is_location_valid(world, key):
|
||||
continue
|
||||
@@ -256,9 +243,6 @@ def set_rules(world: "HatInTimeWorld"):
|
||||
if key in contract_locations.keys():
|
||||
continue
|
||||
|
||||
if data.dlc_flags & HatDLC.death_wish and key in snatcher_coins.keys():
|
||||
key = f"{key} ({data.region})"
|
||||
|
||||
loc = world.multiworld.get_location(key, world.player)
|
||||
|
||||
for hat in data.required_hats:
|
||||
@@ -319,33 +303,12 @@ def set_rules(world: "HatInTimeWorld"):
|
||||
add_rule(world.multiworld.get_location(loc, world.player),
|
||||
lambda state, z=zipline: state.has(z, world.player))
|
||||
|
||||
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.options.LogicDifficulty.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: List[Entrance] = []
|
||||
|
||||
for (key, acts) in act_connections.items():
|
||||
if "Arctic Cruise" in key and not world.is_dlc1():
|
||||
continue
|
||||
|
||||
i: int = 1
|
||||
entrance: Entrance = world.multiworld.get_entrance(key, world.player)
|
||||
region: Region = entrance.connected_region
|
||||
access_rules: List[Callable[[CollectionState], bool]] = []
|
||||
@@ -354,7 +317,7 @@ def set_rules(world: "HatInTimeWorld"):
|
||||
# Entrances to this act that we have to set access_rules on
|
||||
entrances: List[Entrance] = []
|
||||
|
||||
for act in acts:
|
||||
for i, act in enumerate(acts, start=1):
|
||||
act_entrance: Entrance = world.multiworld.get_entrance(act, world.player)
|
||||
access_rules.append(act_entrance.access_rule)
|
||||
required_region = act_entrance.connected_region
|
||||
@@ -369,8 +332,6 @@ def set_rules(world: "HatInTimeWorld"):
|
||||
rule = world.multiworld.get_location(name, world.player).access_rule
|
||||
access_rules.append(rule)
|
||||
|
||||
i += 1
|
||||
|
||||
for e in entrances:
|
||||
for rules in access_rules:
|
||||
add_rule(e, rules)
|
||||
@@ -389,7 +350,7 @@ def set_rules(world: "HatInTimeWorld"):
|
||||
def set_specific_rules(world: "HatInTimeWorld"):
|
||||
add_rule(world.multiworld.get_location("Mafia Boss Shop Item", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, 12)
|
||||
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS)))
|
||||
and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.BIRDS]))
|
||||
|
||||
add_rule(world.multiworld.get_location("Spaceship - Rumbi Abuse", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, 4))
|
||||
@@ -457,6 +418,11 @@ def set_moderate_rules(world: "HatInTimeWorld"):
|
||||
set_rule(world.multiworld.get_location("Alpine Skyline - Mystifying Time Mesa: Zipline", world.player),
|
||||
lambda state: can_use_hookshot(state, world))
|
||||
|
||||
# Moderate: Goat Refinery from TIHS with Sprint only
|
||||
add_rule(world.multiworld.get_location("Alpine Skyline - Goat Refinery", world.player),
|
||||
lambda state: state.has("TIHS Access", world.player)
|
||||
and can_use_hat(state, world, HatType.SPRINT), "or")
|
||||
|
||||
# Moderate: Finale without Hookshot
|
||||
set_rule(world.multiworld.get_location("Act Completion (The Finale)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.DWELLER))
|
||||
@@ -530,6 +496,10 @@ def set_hard_rules(world: "HatInTimeWorld"):
|
||||
add_rule(world.multiworld.get_entrance("Telescope -> Time's End", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.ICE), "or")
|
||||
|
||||
# Hard: Goat Refinery from TIHS with nothing
|
||||
add_rule(world.multiworld.get_location("Alpine Skyline - Goat Refinery", world.player),
|
||||
lambda state: state.has("TIHS Access", world.player, "or"))
|
||||
|
||||
if world.is_dlc1():
|
||||
# Hard: clear Deep Sea without Dweller Mask
|
||||
set_rule(world.multiworld.get_location("Act Completion (Time Rift - Deep Sea)", world.player),
|
||||
@@ -555,7 +525,7 @@ def set_hard_rules(world: "HatInTimeWorld"):
|
||||
def set_expert_rules(world: "HatInTimeWorld"):
|
||||
# Finale Telescope with no hats
|
||||
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)))
|
||||
lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.FINALE]))
|
||||
|
||||
# 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)
|
||||
@@ -753,6 +723,11 @@ def set_alps_rules(world: "HatInTimeWorld"):
|
||||
add_rule(world.multiworld.get_entrance("Alpine Skyline - Finale", world.player),
|
||||
lambda state: can_clear_alpine(state, world))
|
||||
|
||||
add_rule(world.multiworld.get_location("Alpine Skyline - Goat Refinery", world.player),
|
||||
lambda state: state.has("AFR Access", world.player)
|
||||
and can_use_hookshot(state, world)
|
||||
and can_hit(state, world, True))
|
||||
|
||||
|
||||
def set_dlc1_rules(world: "HatInTimeWorld"):
|
||||
add_rule(world.multiworld.get_entrance("Cruise Ship Entrance BV", world.player),
|
||||
@@ -810,11 +785,11 @@ def set_rift_rules(world: "HatInTimeWorld", regions: Dict[str, Region]):
|
||||
# This is accessing the regions in place of these time rifts, so we can set the rules on all the entrances.
|
||||
for entrance in regions["Time Rift - Gallery"].entrances:
|
||||
add_rule(entrance, lambda state: can_use_hat(state, world, HatType.BREWING)
|
||||
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS)))
|
||||
and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.BIRDS]))
|
||||
|
||||
for entrance in regions["Time Rift - The Lab"].entrances:
|
||||
add_rule(entrance, lambda state: can_use_hat(state, world, HatType.DWELLER)
|
||||
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE)))
|
||||
and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.ALPINE]))
|
||||
|
||||
for entrance in regions["Time Rift - Sewers"].entrances:
|
||||
add_rule(entrance, lambda state: can_clear_act(state, world, "Mafia Town - Act 4"))
|
||||
@@ -895,11 +870,11 @@ def set_default_rift_rules(world: "HatInTimeWorld"):
|
||||
|
||||
for entrance in world.multiworld.get_region("Time Rift - Gallery", world.player).entrances:
|
||||
add_rule(entrance, lambda state: can_use_hat(state, world, HatType.BREWING)
|
||||
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS)))
|
||||
and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.BIRDS]))
|
||||
|
||||
for entrance in world.multiworld.get_region("Time Rift - The Lab", world.player).entrances:
|
||||
add_rule(entrance, lambda state: can_use_hat(state, world, HatType.DWELLER)
|
||||
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE)))
|
||||
and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.ALPINE]))
|
||||
|
||||
for entrance in world.multiworld.get_region("Time Rift - Sewers", world.player).entrances:
|
||||
add_rule(entrance, lambda state: can_clear_act(state, world, "Mafia Town - Act 4"))
|
||||
@@ -970,9 +945,6 @@ def set_event_rules(world: "HatInTimeWorld"):
|
||||
if not is_location_valid(world, name):
|
||||
continue
|
||||
|
||||
if data.dlc_flags & HatDLC.death_wish and name in snatcher_coins.keys():
|
||||
name = f"{name} ({data.region})"
|
||||
|
||||
event: Location = world.multiworld.get_location(name, world.player)
|
||||
|
||||
if data.act_event:
|
||||
|
||||
@@ -69,6 +69,7 @@ class LocData(NamedTuple):
|
||||
# Other
|
||||
act_event: Optional[bool] = False # Only used for event locations. Copy access rule from act completion
|
||||
nyakuza_thug: Optional[str] = "" # Name of Nyakuza thug NPC (for metro shops)
|
||||
snatcher_coin: Optional[str] = "" # Only for Snatcher Coin event locations, name of the Snatcher Coin item
|
||||
|
||||
|
||||
class ItemData(NamedTuple):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from BaseClasses import Item, ItemClassification, Tutorial, Location
|
||||
from BaseClasses import Item, ItemClassification, Tutorial, Location, MultiWorld
|
||||
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, \
|
||||
@@ -24,15 +24,6 @@ components.append(Component("A Hat in Time Client", "AHITClient", func=launch_cl
|
||||
|
||||
icon_paths['yatta'] = local_path('data', 'yatta.png')
|
||||
|
||||
hat_craft_order: Dict[int, List[HatType]] = {}
|
||||
hat_yarn_costs: Dict[int, Dict[HatType, int]] = {}
|
||||
chapter_timepiece_costs: Dict[int, Dict[ChapterIndex, int]] = {}
|
||||
excluded_dws: Dict[int, List[str]] = {}
|
||||
excluded_bonuses: Dict[int, List[str]] = {}
|
||||
dw_shuffle: Dict[int, List[str]] = {}
|
||||
nyakuza_thug_items: Dict[int, Dict[str, int]] = {}
|
||||
badge_seller_count: Dict[int, int] = {}
|
||||
|
||||
|
||||
class AWebInTime(WebWorld):
|
||||
theme = "partyTime"
|
||||
@@ -60,11 +51,33 @@ class HatInTimeWorld(World):
|
||||
|
||||
options_dataclass = AHITOptions
|
||||
options: AHITOptions
|
||||
act_connections: Dict[str, str] = {}
|
||||
shop_locs: List[str] = []
|
||||
item_name_groups = relic_groups
|
||||
web = AWebInTime()
|
||||
|
||||
def __init__(self, multiworld: "MultiWorld", player: int):
|
||||
super().__init__(multiworld, player)
|
||||
self.act_connections: Dict[str, str] = {}
|
||||
self.shop_locs: List[str] = []
|
||||
|
||||
self.hat_craft_order: List[HatType] = [HatType.SPRINT, HatType.BREWING, HatType.ICE,
|
||||
HatType.DWELLER, HatType.TIME_STOP]
|
||||
|
||||
self.hat_yarn_costs: Dict[HatType, int] = {HatType.SPRINT: -1, HatType.BREWING: -1, HatType.ICE: -1,
|
||||
HatType.DWELLER: -1, HatType.TIME_STOP: -1}
|
||||
|
||||
self.chapter_timepiece_costs: Dict[ChapterIndex, int] = {ChapterIndex.MAFIA: -1,
|
||||
ChapterIndex.BIRDS: -1,
|
||||
ChapterIndex.SUBCON: -1,
|
||||
ChapterIndex.ALPINE: -1,
|
||||
ChapterIndex.FINALE: -1,
|
||||
ChapterIndex.CRUISE: -1,
|
||||
ChapterIndex.METRO: -1}
|
||||
self.excluded_dws: List[str] = []
|
||||
self.excluded_bonuses: List[str] = []
|
||||
self.dw_shuffle: List[str] = []
|
||||
self.nyakuza_thug_items: Dict[str, int] = {}
|
||||
self.badge_seller_count: int = 0
|
||||
|
||||
def generate_early(self):
|
||||
adjust_options(self)
|
||||
|
||||
@@ -87,12 +100,6 @@ class HatInTimeWorld(World):
|
||||
self.multiworld.push_precollected(self.create_item("Progressive Painting Unlock"))
|
||||
|
||||
def create_regions(self):
|
||||
excluded_dws[self.player] = []
|
||||
excluded_bonuses[self.player] = []
|
||||
dw_shuffle[self.player] = []
|
||||
nyakuza_thug_items[self.player] = {}
|
||||
badge_seller_count[self.player] = 0
|
||||
self.shop_locs = []
|
||||
# noinspection PyClassVar
|
||||
self.topology_present = bool(self.options.ActRandomizer.value)
|
||||
|
||||
@@ -105,8 +112,8 @@ class HatInTimeWorld(World):
|
||||
|
||||
create_events(self)
|
||||
if self.is_dw():
|
||||
if "Snatcher's Hit List" not in self.get_excluded_dws() \
|
||||
or "Camera Tourist" not in self.get_excluded_dws():
|
||||
if "Snatcher's Hit List" not in self.excluded_dws \
|
||||
or "Camera Tourist" not in self.excluded_dws:
|
||||
create_enemy_events(self)
|
||||
|
||||
# place vanilla contract locations if contract shuffle is off
|
||||
@@ -115,30 +122,15 @@ class HatInTimeWorld(World):
|
||||
self.multiworld.get_location(name, self.player).place_locked_item(create_item(self, name))
|
||||
|
||||
def create_items(self):
|
||||
hat_yarn_costs[self.player] = {HatType.SPRINT: -1, HatType.BREWING: -1, HatType.ICE: -1,
|
||||
HatType.DWELLER: -1, HatType.TIME_STOP: -1}
|
||||
|
||||
hat_craft_order[self.player] = [HatType.SPRINT, HatType.BREWING, HatType.ICE,
|
||||
HatType.DWELLER, HatType.TIME_STOP]
|
||||
|
||||
if self.options.HatItems.value == 0 and self.options.RandomizeHatOrder.value > 0:
|
||||
self.random.shuffle(hat_craft_order[self.player])
|
||||
self.random.shuffle(self.hat_craft_order)
|
||||
if self.options.RandomizeHatOrder.value == 2:
|
||||
hat_craft_order[self.player].remove(HatType.TIME_STOP)
|
||||
hat_craft_order[self.player].append(HatType.TIME_STOP)
|
||||
self.hat_craft_order.remove(HatType.TIME_STOP)
|
||||
self.hat_craft_order.append(HatType.TIME_STOP)
|
||||
|
||||
self.multiworld.itempool += create_itempool(self)
|
||||
|
||||
def set_rules(self):
|
||||
self.act_connections = {}
|
||||
chapter_timepiece_costs[self.player] = {ChapterIndex.MAFIA: -1,
|
||||
ChapterIndex.BIRDS: -1,
|
||||
ChapterIndex.SUBCON: -1,
|
||||
ChapterIndex.ALPINE: -1,
|
||||
ChapterIndex.FINALE: -1,
|
||||
ChapterIndex.CRUISE: -1,
|
||||
ChapterIndex.METRO: -1}
|
||||
|
||||
if self.is_dw_only():
|
||||
# we already have all items if this is the case, no need for rules
|
||||
self.multiworld.push_precollected(HatInTimeItem("Death Wish Only Mode", ItemClassification.progression,
|
||||
@@ -152,7 +144,7 @@ class HatInTimeWorld(World):
|
||||
if name == "Snatcher Coins in Nyakuza Metro" and not self.is_dlc2():
|
||||
continue
|
||||
|
||||
if self.options.DWShuffle.value > 0 and name not in self.get_dw_shuffle():
|
||||
if self.options.DWShuffle.value > 0 and name not in self.dw_shuffle:
|
||||
continue
|
||||
|
||||
full_clear = self.multiworld.get_location(f"{name} - All Clear", self.player)
|
||||
@@ -174,41 +166,41 @@ class HatInTimeWorld(World):
|
||||
return create_item(self, name)
|
||||
|
||||
def fill_slot_data(self) -> dict:
|
||||
slot_data: dict = {"Chapter1Cost": chapter_timepiece_costs[self.player][ChapterIndex.MAFIA],
|
||||
"Chapter2Cost": chapter_timepiece_costs[self.player][ChapterIndex.BIRDS],
|
||||
"Chapter3Cost": chapter_timepiece_costs[self.player][ChapterIndex.SUBCON],
|
||||
"Chapter4Cost": chapter_timepiece_costs[self.player][ChapterIndex.ALPINE],
|
||||
"Chapter5Cost": chapter_timepiece_costs[self.player][ChapterIndex.FINALE],
|
||||
"Chapter6Cost": chapter_timepiece_costs[self.player][ChapterIndex.CRUISE],
|
||||
"Chapter7Cost": chapter_timepiece_costs[self.player][ChapterIndex.METRO],
|
||||
"BadgeSellerItemCount": badge_seller_count[self.player],
|
||||
slot_data: dict = {"Chapter1Cost": self.chapter_timepiece_costs[ChapterIndex.MAFIA],
|
||||
"Chapter2Cost": self.chapter_timepiece_costs[ChapterIndex.BIRDS],
|
||||
"Chapter3Cost": self.chapter_timepiece_costs[ChapterIndex.SUBCON],
|
||||
"Chapter4Cost": self.chapter_timepiece_costs[ChapterIndex.ALPINE],
|
||||
"Chapter5Cost": self.chapter_timepiece_costs[ChapterIndex.FINALE],
|
||||
"Chapter6Cost": self.chapter_timepiece_costs[ChapterIndex.CRUISE],
|
||||
"Chapter7Cost": self.chapter_timepiece_costs[ChapterIndex.METRO],
|
||||
"BadgeSellerItemCount": self.badge_seller_count,
|
||||
"SeedNumber": str(self.multiworld.seed), # For shop prices
|
||||
"SeedName": self.multiworld.seed_name,
|
||||
"TotalLocations": get_total_locations(self)}
|
||||
|
||||
if self.options.HatItems.value == 0:
|
||||
slot_data.setdefault("SprintYarnCost", hat_yarn_costs[self.player][HatType.SPRINT])
|
||||
slot_data.setdefault("BrewingYarnCost", hat_yarn_costs[self.player][HatType.BREWING])
|
||||
slot_data.setdefault("IceYarnCost", hat_yarn_costs[self.player][HatType.ICE])
|
||||
slot_data.setdefault("DwellerYarnCost", hat_yarn_costs[self.player][HatType.DWELLER])
|
||||
slot_data.setdefault("TimeStopYarnCost", hat_yarn_costs[self.player][HatType.TIME_STOP])
|
||||
slot_data.setdefault("Hat1", int(hat_craft_order[self.player][0]))
|
||||
slot_data.setdefault("Hat2", int(hat_craft_order[self.player][1]))
|
||||
slot_data.setdefault("Hat3", int(hat_craft_order[self.player][2]))
|
||||
slot_data.setdefault("Hat4", int(hat_craft_order[self.player][3]))
|
||||
slot_data.setdefault("Hat5", int(hat_craft_order[self.player][4]))
|
||||
slot_data.setdefault("SprintYarnCost", self.hat_yarn_costs[HatType.SPRINT])
|
||||
slot_data.setdefault("BrewingYarnCost", self.hat_yarn_costs[HatType.BREWING])
|
||||
slot_data.setdefault("IceYarnCost", self.hat_yarn_costs[HatType.ICE])
|
||||
slot_data.setdefault("DwellerYarnCost", self.hat_yarn_costs[HatType.DWELLER])
|
||||
slot_data.setdefault("TimeStopYarnCost", self.hat_yarn_costs[HatType.TIME_STOP])
|
||||
slot_data.setdefault("Hat1", int(self.hat_craft_order[0]))
|
||||
slot_data.setdefault("Hat2", int(self.hat_craft_order[1]))
|
||||
slot_data.setdefault("Hat3", int(self.hat_craft_order[2]))
|
||||
slot_data.setdefault("Hat4", int(self.hat_craft_order[3]))
|
||||
slot_data.setdefault("Hat5", int(self.hat_craft_order[4]))
|
||||
|
||||
if self.options.ActRandomizer.value > 0:
|
||||
for name in self.act_connections.keys():
|
||||
slot_data[name] = self.act_connections[name]
|
||||
|
||||
if self.is_dlc2() and not self.is_dw_only():
|
||||
for name in nyakuza_thug_items[self.player].keys():
|
||||
slot_data[name] = nyakuza_thug_items[self.player][name]
|
||||
for name in self.nyakuza_thug_items.keys():
|
||||
slot_data[name] = self.nyakuza_thug_items[name]
|
||||
|
||||
if self.is_dw():
|
||||
i = 0
|
||||
for name in excluded_dws[self.player]:
|
||||
for name in self.excluded_dws:
|
||||
if self.options.EndGoal.value == 3 and name == "Seal the Deal":
|
||||
continue
|
||||
|
||||
@@ -217,15 +209,15 @@ class HatInTimeWorld(World):
|
||||
|
||||
i = 0
|
||||
if self.options.DWAutoCompleteBonuses.value == 0:
|
||||
for name in excluded_bonuses[self.player]:
|
||||
if name in excluded_dws[self.player]:
|
||||
for name in self.excluded_bonuses:
|
||||
if name in self.excluded_dws:
|
||||
continue
|
||||
|
||||
slot_data[f"excluded_bonus{i}"] = dw_classes[name]
|
||||
i += 1
|
||||
|
||||
if self.options.DWShuffle.value > 0:
|
||||
shuffled_dws = self.get_dw_shuffle()
|
||||
shuffled_dws = self.dw_shuffle
|
||||
for i in range(len(shuffled_dws)):
|
||||
slot_data[f"dw_{i}"] = dw_classes[shuffled_dws[i]]
|
||||
|
||||
@@ -281,26 +273,11 @@ class HatInTimeWorld(World):
|
||||
hint_data[self.player] = new_hint_data
|
||||
|
||||
def write_spoiler_header(self, spoiler_handle: TextIO):
|
||||
for i in self.get_chapter_costs():
|
||||
spoiler_handle.write("Chapter %i Cost: %i\n" % (i, self.get_chapter_costs()[ChapterIndex(i)]))
|
||||
for i in self.chapter_timepiece_costs:
|
||||
spoiler_handle.write("Chapter %i Cost: %i\n" % (i, self.chapter_timepiece_costs[ChapterIndex(i)]))
|
||||
|
||||
for hat in hat_craft_order[self.player]:
|
||||
spoiler_handle.write("Hat Cost: %s: %i\n" % (hat, hat_yarn_costs[self.player][hat]))
|
||||
|
||||
def set_chapter_cost(self, chapter: ChapterIndex, cost: int):
|
||||
chapter_timepiece_costs[self.player][chapter] = cost
|
||||
|
||||
def get_chapter_cost(self, chapter: ChapterIndex) -> int:
|
||||
return chapter_timepiece_costs[self.player][chapter]
|
||||
|
||||
def get_hat_craft_order(self):
|
||||
return hat_craft_order[self.player]
|
||||
|
||||
def get_hat_yarn_costs(self):
|
||||
return hat_yarn_costs[self.player]
|
||||
|
||||
def get_chapter_costs(self):
|
||||
return chapter_timepiece_costs[self.player]
|
||||
for hat in self.hat_craft_order:
|
||||
spoiler_handle.write("Hat Cost: %s: %i\n" % (hat, self.hat_yarn_costs[hat]))
|
||||
|
||||
def is_dlc1(self) -> bool:
|
||||
return self.options.EnableDLC1.value > 0
|
||||
@@ -314,43 +291,19 @@ class HatInTimeWorld(World):
|
||||
def is_dw_only(self) -> bool:
|
||||
return self.is_dw() and self.options.DeathWishOnly.value > 0
|
||||
|
||||
def get_excluded_dws(self):
|
||||
return excluded_dws[self.player]
|
||||
|
||||
def get_excluded_bonuses(self):
|
||||
return excluded_bonuses[self.player]
|
||||
|
||||
def is_dw_excluded(self, name: str) -> bool:
|
||||
# don't exclude Seal the Deal if it's our goal
|
||||
if self.options.EndGoal.value == 3 and name == "Seal the Deal" \
|
||||
and f"{name} - Main Objective" not in self.options.exclude_locations:
|
||||
return False
|
||||
|
||||
if name in excluded_dws[self.player]:
|
||||
if name in self.excluded_dws:
|
||||
return True
|
||||
|
||||
return f"{name} - Main Objective" in self.options.exclude_locations
|
||||
|
||||
def is_bonus_excluded(self, name: str) -> bool:
|
||||
if self.is_dw_excluded(name) or name in excluded_bonuses[self.player]:
|
||||
if self.is_dw_excluded(name) or name in self.excluded_bonuses:
|
||||
return True
|
||||
|
||||
return f"{name} - All Clear" in self.options.exclude_locations
|
||||
|
||||
def get_dw_shuffle(self):
|
||||
return dw_shuffle[self.player]
|
||||
|
||||
def set_dw_shuffle(self, shuffle: List[str]):
|
||||
dw_shuffle[self.player] = shuffle
|
||||
|
||||
def get_badge_seller_count(self) -> int:
|
||||
return badge_seller_count[self.player]
|
||||
|
||||
def set_badge_seller_count(self, value: int):
|
||||
badge_seller_count[self.player] = value
|
||||
|
||||
def get_nyakuza_thug_items(self):
|
||||
return nyakuza_thug_items[self.player]
|
||||
|
||||
def set_nyakuza_thug_items(self, items: Dict[str, int]):
|
||||
nyakuza_thug_items[self.player] = items
|
||||
|
||||
Reference in New Issue
Block a user