mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-23 22:23:24 -07:00
1.1
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from worlds.AutoWorld import World
|
||||
from .Types import HatDLC, HatType
|
||||
from .Types import HatDLC, HatType, hat_type_to_item
|
||||
from .Locations import get_total_locations
|
||||
from .Rules import get_difficulty, is_player_knowledgeable
|
||||
from typing import Optional, NamedTuple, List, Dict
|
||||
@@ -18,7 +18,7 @@ class HatInTimeItem(Item):
|
||||
|
||||
def create_itempool(world: World) -> List[Item]:
|
||||
itempool: List[Item] = []
|
||||
if not world.is_dw_only():
|
||||
if not world.is_dw_only() and world.multiworld.HatItems[world.player].value == 0:
|
||||
calculate_yarn_costs(world)
|
||||
yarn_pool: List[Item] = create_multiple_items(world, "Yarn",
|
||||
world.multiworld.YarnAvailable[world.player].value,
|
||||
@@ -36,6 +36,9 @@ def create_itempool(world: World) -> List[Item]:
|
||||
if not item_dlc_enabled(world, name):
|
||||
continue
|
||||
|
||||
if world.multiworld.HatItems[world.player].value == 0 and name in hat_type_to_item.values():
|
||||
continue
|
||||
|
||||
item_type: ItemClassification = item_table.get(name).classification
|
||||
|
||||
if world.is_dw_only():
|
||||
@@ -181,7 +184,13 @@ def create_junk_items(world: World, count: int) -> List[Item]:
|
||||
ahit_items = {
|
||||
"Yarn": ItemData(300001, ItemClassification.progression_skip_balancing),
|
||||
"Time Piece": ItemData(300002, ItemClassification.progression_skip_balancing),
|
||||
"Progressive Painting Unlock": ItemData(300003, ItemClassification.progression),
|
||||
|
||||
# for HatItems option
|
||||
"Sprint Hat": ItemData(300049, ItemClassification.progression),
|
||||
"Brewing Hat": ItemData(300050, ItemClassification.progression),
|
||||
"Ice Hat": ItemData(300051, ItemClassification.progression),
|
||||
"Dweller Mask": ItemData(300052, ItemClassification.progression),
|
||||
"Time Stop Hat": ItemData(300053, ItemClassification.progression),
|
||||
|
||||
# Relics
|
||||
"Relic (Burger Patty)": ItemData(300006, ItemClassification.progression),
|
||||
@@ -210,8 +219,9 @@ ahit_items = {
|
||||
"Camera Badge": ItemData(300042, ItemClassification.progression, HatDLC.death_wish),
|
||||
|
||||
# Other
|
||||
"Umbrella": ItemData(300033, ItemClassification.progression),
|
||||
"Badge Pin": ItemData(300043, ItemClassification.useful),
|
||||
"Umbrella": ItemData(300033, ItemClassification.progression),
|
||||
"Progressive Painting Unlock": ItemData(300003, ItemClassification.progression),
|
||||
|
||||
# Garbage items
|
||||
"25 Pons": ItemData(300034, ItemClassification.filler),
|
||||
|
||||
@@ -312,6 +312,12 @@ class MinExtraYarn(Range):
|
||||
default = 10
|
||||
|
||||
|
||||
class HatItems(Toggle):
|
||||
"""Removes all yarn from the pool and turns the hats into individual items instead."""
|
||||
display_name = "Hat Items"
|
||||
default = 0
|
||||
|
||||
|
||||
class MinPonCost(Range):
|
||||
"""The minimum amount of Pons that any shop item can cost."""
|
||||
display_name = "Minimum Shop Pon Cost"
|
||||
@@ -648,6 +654,7 @@ ahit_options: typing.Dict[str, type(Option)] = {
|
||||
"YarnCostMax": YarnCostMax,
|
||||
"YarnAvailable": YarnAvailable,
|
||||
"MinExtraYarn": MinExtraYarn,
|
||||
"HatItems": HatItems,
|
||||
|
||||
"MinPonCost": MinPonCost,
|
||||
"MaxPonCost": MaxPonCost,
|
||||
@@ -675,6 +682,7 @@ slot_data_options: typing.Dict[str, type(Option)] = {
|
||||
"ShuffleStorybookPages": ShuffleStorybookPages,
|
||||
"ShuffleActContracts": ShuffleActContracts,
|
||||
"ShuffleSubconPaintings": ShuffleSubconPaintings,
|
||||
"HatItems": HatItems,
|
||||
|
||||
"EnableDLC1": EnableDLC1,
|
||||
"Tasksanity": Tasksanity,
|
||||
|
||||
@@ -433,6 +433,11 @@ def create_rift_connections(world: World, region: Region):
|
||||
connect_regions(act_region, region, entrance_name, world.player)
|
||||
i += 1
|
||||
|
||||
# fix for some weird keyerror from tests
|
||||
if region.name == "Time Rift - Rumbi Factory":
|
||||
for entrance in region.entrances:
|
||||
world.multiworld.get_entrance(entrance.name, world.player)
|
||||
|
||||
|
||||
def create_tasksanity_locations(world: World):
|
||||
ship_shape: Region = world.multiworld.get_region("Ship Shape", world.player)
|
||||
@@ -873,11 +878,6 @@ def create_events(world: World) -> int:
|
||||
|
||||
event: Location = create_event(name, world.multiworld.get_region(data.region, world.player), world)
|
||||
event.show_in_spoiler = False
|
||||
|
||||
if data.act_complete_event:
|
||||
act_completion: str = f"Act Completion ({data.region})"
|
||||
event.access_rule = world.multiworld.get_location(act_completion, world.player).access_rule
|
||||
|
||||
count += 1
|
||||
|
||||
return count
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from worlds.AutoWorld import World, CollectionState
|
||||
from worlds.generic.Rules import add_rule, set_rule
|
||||
from .Locations import location_table, tihs_locations, zipline_unlocks, is_location_valid, contract_locations, \
|
||||
shop_locations
|
||||
from .Types import HatType, ChapterIndex
|
||||
shop_locations, event_locs
|
||||
from .Types import HatType, ChapterIndex, hat_type_to_item
|
||||
from BaseClasses import Location, Entrance, Region
|
||||
import typing
|
||||
|
||||
@@ -32,6 +32,9 @@ act_connections = {
|
||||
|
||||
|
||||
def can_use_hat(state: CollectionState, world: World, hat: HatType) -> bool:
|
||||
if world.multiworld.HatItems[world.player].value > 0:
|
||||
return state.has(hat_type_to_item[hat], world.player)
|
||||
|
||||
return state.count("Yarn", world.player) >= get_hat_cost(world, hat)
|
||||
|
||||
|
||||
@@ -257,8 +260,9 @@ def set_rules(world: World):
|
||||
if world.multiworld.ActRandomizer[world.player].value == 0:
|
||||
set_default_rift_rules(world)
|
||||
|
||||
table = location_table | event_locs
|
||||
location: Location
|
||||
for (key, data) in location_table.items():
|
||||
for (key, data) in table.items():
|
||||
if not is_location_valid(world, key):
|
||||
continue
|
||||
|
||||
@@ -340,6 +344,8 @@ def set_rules(world: World):
|
||||
for rules in access_rules:
|
||||
add_rule(e, rules)
|
||||
|
||||
set_event_rules(world)
|
||||
|
||||
for entrance in world.multiworld.get_region("Alpine Free Roam", world.player).entrances:
|
||||
add_rule(entrance, lambda state: can_use_hookshot(state, world))
|
||||
if world.multiworld.UmbrellaLogic[world.player].value > 0:
|
||||
@@ -851,6 +857,17 @@ def set_default_rift_rules(world: World):
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, world, "Necklace"))
|
||||
|
||||
|
||||
def set_event_rules(world: World):
|
||||
for (name, data) in event_locs.items():
|
||||
if not is_location_valid(world, name):
|
||||
continue
|
||||
|
||||
event: Location = world.multiworld.get_location(name, world.player)
|
||||
|
||||
if data.act_complete_event:
|
||||
add_rule(event, world.multiworld.get_location(f"Act Completion ({data.region})", world.player).access_rule)
|
||||
|
||||
|
||||
def connect_regions(start_region: Region, exit_region: Region, entrancename: str, player: int) -> Entrance:
|
||||
entrance = Entrance(player, entrancename, start_region)
|
||||
start_region.exits.append(entrance)
|
||||
|
||||
@@ -26,3 +26,12 @@ class ChapterIndex(IntEnum):
|
||||
FINALE = 5
|
||||
CRUISE = 6
|
||||
METRO = 7
|
||||
|
||||
|
||||
hat_type_to_item = {
|
||||
HatType.SPRINT: "Sprint Hat",
|
||||
HatType.BREWING: "Brewing Hat",
|
||||
HatType.ICE: "Ice Hat",
|
||||
HatType.DWELLER: "Dweller Mask",
|
||||
HatType.TIME_STOP: "Time Stop Hat",
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ 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] = {}
|
||||
badge_seller_count: Dict[int, int] = {}
|
||||
|
||||
|
||||
class AWebInTime(WebWorld):
|
||||
@@ -112,7 +111,7 @@ class HatInTimeWorld(World):
|
||||
hat_craft_order[self.player] = [HatType.SPRINT, HatType.BREWING, HatType.ICE,
|
||||
HatType.DWELLER, HatType.TIME_STOP]
|
||||
|
||||
if self.multiworld.RandomizeHatOrder[self.player].value > 0:
|
||||
if self.multiworld.HatItems[self.player].value == 0 and self.multiworld.RandomizeHatOrder[self.player].value > 0:
|
||||
self.random.shuffle(hat_craft_order[self.player])
|
||||
if self.multiworld.RandomizeHatOrder[self.player].value == 2:
|
||||
hat_craft_order[self.player].remove(HatType.TIME_STOP)
|
||||
@@ -165,26 +164,28 @@ class HatInTimeWorld(World):
|
||||
return create_item(self, name)
|
||||
|
||||
def fill_slot_data(self) -> dict:
|
||||
slot_data: dict = {"SprintYarnCost": hat_yarn_costs[self.player][HatType.SPRINT],
|
||||
"BrewingYarnCost": hat_yarn_costs[self.player][HatType.BREWING],
|
||||
"IceYarnCost": hat_yarn_costs[self.player][HatType.ICE],
|
||||
"DwellerYarnCost": hat_yarn_costs[self.player][HatType.DWELLER],
|
||||
"TimeStopYarnCost": hat_yarn_costs[self.player][HatType.TIME_STOP],
|
||||
"Chapter1Cost": chapter_timepiece_costs[self.player][ChapterIndex.MAFIA],
|
||||
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],
|
||||
"Hat1": int(hat_craft_order[self.player][0]),
|
||||
"Hat2": int(hat_craft_order[self.player][1]),
|
||||
"Hat3": int(hat_craft_order[self.player][2]),
|
||||
"Hat4": int(hat_craft_order[self.player][3]),
|
||||
"Hat5": int(hat_craft_order[self.player][4]),
|
||||
"BadgeSellerItemCount": badge_seller_count[self.player],
|
||||
"SeedNumber": self.multiworld.seed} # For shop prices
|
||||
|
||||
if self.multiworld.HatItems[self.player].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]))
|
||||
|
||||
if self.multiworld.ActRandomizer[self.player].value > 0:
|
||||
for name in self.act_connections.keys():
|
||||
slot_data[name] = self.act_connections[name]
|
||||
|
||||
24
worlds/ahit/test/TestActs.py
Normal file
24
worlds/ahit/test/TestActs.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from worlds.ahit.Regions import act_chapters
|
||||
from worlds.ahit.test.TestBase import HatInTimeTestBase
|
||||
|
||||
|
||||
class TestActs(HatInTimeTestBase):
|
||||
options = {
|
||||
"ActRandomizer": 2,
|
||||
"EnableDLC1": 1,
|
||||
"EnableDLC2": 1,
|
||||
}
|
||||
|
||||
def test_act_shuffle(self):
|
||||
for i in range(1000):
|
||||
self.world_setup()
|
||||
self.collect_all_but([""])
|
||||
|
||||
for name in act_chapters.keys():
|
||||
region = self.multiworld.get_region(name, 1)
|
||||
for entrance in region.entrances:
|
||||
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} "
|
||||
f"-> {entrance} -> {name}"
|
||||
f" (expected method of access)")
|
||||
5
worlds/ahit/test/TestBase.py
Normal file
5
worlds/ahit/test/TestBase.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from test.TestBase import WorldTestBase
|
||||
|
||||
|
||||
class HatInTimeTestBase(WorldTestBase):
|
||||
game = "A Hat in Time"
|
||||
0
worlds/ahit/test/__init__.py
Normal file
0
worlds/ahit/test/__init__.py
Normal file
Reference in New Issue
Block a user