* Add collect behavior option. * Add comma Co-authored-by: Scipio Wright <scipiowright@gmail.com> --------- Co-authored-by: Scipio Wright <scipiowright@gmail.com>
		
			
				
	
	
		
			229 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from typing import List
 | 
						|
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 = "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
 | 
						|
    shivers_item_id_offset = 27000
 | 
						|
    pot_completed_list: List[int]
 | 
						|
 | 
						|
 | 
						|
    def generate_early(self):
 | 
						|
        self.pot_completed_list = []
 | 
						|
 | 
						|
    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 {"key", "ability", "filler2"}:
 | 
						|
                itempool.append(self.create_item(name))
 | 
						|
 | 
						|
        # Pot pieces/Completed/Mixed:
 | 
						|
        for i in range(10):
 | 
						|
            if self.options.full_pots == "pieces":
 | 
						|
                itempool.append(self.create_item(self.item_id_to_name[self.shivers_item_id_offset + i]))
 | 
						|
                itempool.append(self.create_item(self.item_id_to_name[self.shivers_item_id_offset + 10 + i]))
 | 
						|
            elif self.options.full_pots == "complete":
 | 
						|
                itempool.append(self.create_item(self.item_id_to_name[self.shivers_item_id_offset + 20 + i]))
 | 
						|
            else:
 | 
						|
                # Roll for if pieces or a complete pot will be used.
 | 
						|
                # Pot Pieces
 | 
						|
                if self.random.randint(0, 1) == 0:
 | 
						|
                    self.pot_completed_list.append(0)
 | 
						|
                    itempool.append(self.create_item(self.item_id_to_name[self.shivers_item_id_offset + i]))
 | 
						|
                    itempool.append(self.create_item(self.item_id_to_name[self.shivers_item_id_offset + 10 + i]))
 | 
						|
                # Completed Pot
 | 
						|
                else:
 | 
						|
                    self.pot_completed_list.append(1)
 | 
						|
                    itempool.append(self.create_item(self.item_id_to_name[self.shivers_item_id_offset + 20 + i]))
 | 
						|
 | 
						|
        #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 == "early":
 | 
						|
            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 == "local":
 | 
						|
            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 == "own_world":
 | 
						|
            self.options.local_items.value |= {name for name, data in item_table.items() if data.type == "pot" or data.type == "pot_type2"}
 | 
						|
        if self.options.location_pot_pieces == "different_world":
 | 
						|
            self.options.non_local_items.value |= {name for name, data in item_table.items() if data.type == "pot" or data.type == "pot_type2"}
 | 
						|
 | 
						|
    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))
 | 
						|
 | 
						|
        #Pot pieces/Completed/Mixed:
 | 
						|
        if self.options.full_pots == "pieces":
 | 
						|
            storageitems += [self.create_item(name) for name, data in item_table.items() if data.type == 'potduplicate']
 | 
						|
        elif self.options.full_pots == "complete":
 | 
						|
            storageitems += [self.create_item(name) for name, data in item_table.items() if data.type == 'potduplicate_type2']
 | 
						|
            storageitems += [self.create_item("Empty") for i in range(10)]
 | 
						|
        else:
 | 
						|
            for i in range(10):
 | 
						|
                #Pieces
 | 
						|
                if self.pot_completed_list[i] == 0:
 | 
						|
                    storageitems += [self.create_item(self.item_id_to_name[self.shivers_item_id_offset + 70 + i])]
 | 
						|
                    storageitems += [self.create_item(self.item_id_to_name[self.shivers_item_id_offset + 80 + i])]
 | 
						|
                #Complete
 | 
						|
                else:
 | 
						|
                    storageitems += [self.create_item(self.item_id_to_name[self.shivers_item_id_offset + 140 + i])]
 | 
						|
                    storageitems += [self.create_item("Empty")]
 | 
						|
 | 
						|
        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": list(self.options.exclude_locations.value),
 | 
						|
            "IxupiCapturesNeeded": self.options.ixupi_captures_needed.value,
 | 
						|
            "ElevatorsStaySolved": self.options.elevators_stay_solved.value,
 | 
						|
            "EarlyBeth": self.options.early_beth.value,
 | 
						|
            "EarlyLightning": self.options.early_lightning.value,
 | 
						|
            "FrontDoorUsable": self.options.front_door_usable.value,
 | 
						|
            "PuzzleCollectBehavior": self.options.puzzle_collect_behavior.value,
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
class ShiversLocation(Location):
 | 
						|
    game = "Shivers"
 |