179 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			179 lines
		
	
	
		
			7.8 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 | ||
|  | 
 | ||
|  |     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" |