Files
Archipelago/worlds/shivers/__init__.py
T
GodlFire 5a9bc60a25 Adds an option to have pot pieces placed local/non-local/anywhere
Shivers nearly always finishes last in multiworld games due to the fact you need all 20 pot pieces to win and the pot pieces open very few location checks. This option allows the pieces to be placed locally. This should allow Shivers to be finished earlier.
2024-01-01 12:00:41 -07:00

185 lines
8.2 KiB
Python

from .Items import item_table, ShiversItem
from .Rules import set_rules
from BaseClasses import Item, Tutorial, Region, Location
from Fill import fill_restrictive
from worlds.AutoWorld import WebWorld, World
from . import Constants, Rules
from .Options import ShiversOptions
class ShiversWeb(WebWorld):
tutorials = [Tutorial(
"Shivers Setup Guide",
"A guide to setting up Shivers for Multiworld.",
"English",
"setup_en.md",
"setup/en",
["GodlFire", "Mathx2"]
)]
class ShiversWorld(World):
"""
Shivers is a horror themed point and click adventure. Explore the mysteries of Windlenot's Museum of the Strange and Unusual.
"""
game: str = "Shivers"
topology_present = False
web = ShiversWeb()
options_dataclass = ShiversOptions
options: ShiversOptions
item_name_to_id = {name: data.code for name, data in item_table.items()}
location_name_to_id = Constants.location_name_to_id
def create_item(self, name: str) -> Item:
data = item_table[name]
return ShiversItem(name, data.classification, data.code, self.player)
def create_event(self, region_name: str, event_name: str) -> None:
region = self.multiworld.get_region(region_name, self.player)
loc = ShiversLocation(self.player, event_name, None, region)
loc.place_locked_item(self.create_event_item(event_name))
region.locations.append(loc)
def create_regions(self) -> None:
# Create regions
for region_name, exits in Constants.region_info["regions"]:
r = Region(region_name, self.player, self.multiworld)
self.multiworld.regions.append(r)
for exit_name in exits:
r.create_exit(exit_name)
# Bind mandatory connections
for entr_name, region_name in Constants.region_info["mandatory_connections"]:
e = self.multiworld.get_entrance(entr_name, self.player)
r = self.multiworld.get_region(region_name, self.player)
e.connect(r)
# Locations
# Build exclusion list
self.removed_locations = set()
if not self.options.include_information_plaques:
self.removed_locations.update(Constants.exclusion_info["plaques"])
if not self.options.elevators_stay_solved:
self.removed_locations.update(Constants.exclusion_info["elevators"])
if not self.options.early_lightning:
self.removed_locations.update(Constants.exclusion_info["lightning"])
# Add locations
for region_name, locations in Constants.location_info["locations_by_region"].items():
region = self.multiworld.get_region(region_name, self.player)
for loc_name in locations:
if loc_name not in self.removed_locations:
loc = ShiversLocation(self.player, loc_name, self.location_name_to_id.get(loc_name, None), region)
region.locations.append(loc)
def create_items(self) -> None:
#Add items to item pool
itempool = []
for name, data in item_table.items():
if data.type in {"pot", "key", "ability", "filler2"}:
itempool.append(self.create_item(name))
#Add Filler
itempool += [self.create_item("Easier Lyre") for i in range(9)]
#Extra filler is random between Heals and Easier Lyre. Heals weighted 95%.
filler_needed = len(self.multiworld.get_unfilled_locations(self.player)) - 24 - len(itempool)
itempool += [self.random.choices([self.create_item("Heal"), self.create_item("Easier Lyre")], weights=[95, 5])[0] for i in range(filler_needed)]
#Place library escape items. Choose a location to place the escape item
library_region = self.multiworld.get_region("Library", self.player)
librarylocation = self.random.choice([loc for loc in library_region.locations if not loc.name.startswith("Accessible:")])
#Roll for which escape items will be placed in the Library
library_random = self.random.randint(1, 3)
if library_random == 1:
librarylocation.place_locked_item(self.create_item("Crawling"))
itempool = [item for item in itempool if item.name != "Crawling"]
elif library_random == 2:
librarylocation.place_locked_item(self.create_item("Key for Library Room"))
itempool = [item for item in itempool if item.name != "Key for Library Room"]
elif library_random == 3:
librarylocation.place_locked_item(self.create_item("Key for Three Floor Elevator"))
librarylocationkeytwo = self.random.choice([loc for loc in library_region.locations if not loc.name.startswith("Accessible:") and loc != librarylocation])
librarylocationkeytwo.place_locked_item(self.create_item("Key for Egypt Room"))
itempool = [item for item in itempool if item.name not in ["Key for Three Floor Elevator", "Key for Egypt Room"]]
#If front door option is on, determine which set of keys will be used for lobby access and add front door key to item pool
lobby_access_keys = 1
if self.options.front_door_usable:
lobby_access_keys = self.random.randint(1, 2)
itempool += [self.create_item("Key for Front Door")]
else:
itempool += [self.create_item("Heal")]
self.multiworld.itempool += itempool
#Lobby acess:
if self.options.lobby_access == 1:
if lobby_access_keys == 1:
self.multiworld.early_items[self.player]["Key for Underground Lake Room"] = 1
self.multiworld.early_items[self.player]["Key for Office Elevator"] = 1
self.multiworld.early_items[self.player]["Key for Office"] = 1
elif lobby_access_keys == 2:
self.multiworld.early_items[self.player]["Key for Front Door"] = 1
if self.options.lobby_access == 2:
if lobby_access_keys == 1:
self.multiworld.local_early_items[self.player]["Key for Underground Lake Room"] = 1
self.multiworld.local_early_items[self.player]["Key for Office Elevator"] = 1
self.multiworld.local_early_items[self.player]["Key for Office"] = 1
elif lobby_access_keys == 2:
self.multiworld.local_early_items[self.player]["Key for Front Door"] = 1
#Pot piece shuffle location:
if self.options.location_pot_pieces == 0:
self.multiworld.local_items[self.player].value.update({name for name, data in item_table.items() if data.type == "pot"})
if self.options.location_pot_pieces == 1:
self.multiworld.non_local_items[self.player].value.update({name for name, data in item_table.items() if data.type == "pot"})
def pre_fill(self) -> None:
# Prefills event storage locations with duplicate pots
storagelocs = []
storageitems = []
self.storage_placements = []
for locations in Constants.location_info["locations_by_region"].values():
for loc_name in locations:
if loc_name.startswith("Accessible: "):
storagelocs.append(self.multiworld.get_location(loc_name, self.player))
storageitems += [self.create_item(name) for name, data in item_table.items() if data.type == 'potduplicate']
storageitems += [self.create_item("Empty") for i in range(3)]
state = self.multiworld.get_all_state(True)
self.random.shuffle(storagelocs)
self.random.shuffle(storageitems)
fill_restrictive(self.multiworld, state, storagelocs.copy(), storageitems, True, True)
self.storage_placements = {location.name: location.item.name for location in storagelocs}
set_rules = set_rules
def fill_slot_data(self) -> dict:
return {
"storageplacements": self.storage_placements,
"excludedlocations": {str(excluded_location).replace('ExcludeLocations(', '').replace(')', '') for excluded_location in self.multiworld.exclude_locations.values()},
"elevatorsstaysolved": {self.options.elevators_stay_solved.value},
"earlybeth": {self.options.early_beth.value},
"earlylightning": {self.options.early_lightning.value},
}
class ShiversLocation(Location):
game = "Shivers"