diff --git a/worlds/shivers/Items.py b/worlds/shivers/Items.py index 3b403be5cb76..10d234d450bb 100644 --- a/worlds/shivers/Items.py +++ b/worlds/shivers/Items.py @@ -33,28 +33,38 @@ class ItemData(typing.NamedTuple): "Lightning Pot Top": ItemData(SHIVERS_ITEM_ID_OFFSET + 17, "pot"), "Sand Pot Top": ItemData(SHIVERS_ITEM_ID_OFFSET + 18, "pot"), "Metal Pot Top": ItemData(SHIVERS_ITEM_ID_OFFSET + 19, "pot"), + "Water Pot Complete": ItemData(SHIVERS_ITEM_ID_OFFSET + 20, "pot_type2"), + "Wax Pot Complete": ItemData(SHIVERS_ITEM_ID_OFFSET + 21, "pot_type2"), + "Ash Pot Complete": ItemData(SHIVERS_ITEM_ID_OFFSET + 22, "pot_type2"), + "Oil Pot Complete": ItemData(SHIVERS_ITEM_ID_OFFSET + 23, "pot_type2"), + "Cloth Pot Complete": ItemData(SHIVERS_ITEM_ID_OFFSET + 24, "pot_type2"), + "Wood Pot Complete": ItemData(SHIVERS_ITEM_ID_OFFSET + 25, "pot_type2"), + "Crystal Pot Complete": ItemData(SHIVERS_ITEM_ID_OFFSET + 26, "pot_type2"), + "Lightning Pot Complete": ItemData(SHIVERS_ITEM_ID_OFFSET + 27, "pot_type2"), + "Sand Pot Complete": ItemData(SHIVERS_ITEM_ID_OFFSET + 28, "pot_type2"), + "Metal Pot Complete": ItemData(SHIVERS_ITEM_ID_OFFSET + 29, "pot_type2"), #Keys - "Key for Office Elevator": ItemData(SHIVERS_ITEM_ID_OFFSET + 20, "key"), - "Key for Bedroom Elevator": ItemData(SHIVERS_ITEM_ID_OFFSET + 21, "key"), - "Key for Three Floor Elevator": ItemData(SHIVERS_ITEM_ID_OFFSET + 22, "key"), - "Key for Workshop": ItemData(SHIVERS_ITEM_ID_OFFSET + 23, "key"), - "Key for Office": ItemData(SHIVERS_ITEM_ID_OFFSET + 24, "key"), - "Key for Prehistoric Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 25, "key"), - "Key for Greenhouse Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 26, "key"), - "Key for Ocean Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 27, "key"), - "Key for Projector Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 28, "key"), - "Key for Generator Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 29, "key"), - "Key for Egypt Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 30, "key"), - "Key for Library Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 31, "key"), - "Key for Shaman Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 32, "key"), - "Key for UFO Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 33, "key"), - "Key for Torture Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 34, "key"), - "Key for Puzzle Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 35, "key"), - "Key for Bedroom": ItemData(SHIVERS_ITEM_ID_OFFSET + 36, "key"), - "Key for Underground Lake Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 37, "key"), - "Key for Janitor Closet": ItemData(SHIVERS_ITEM_ID_OFFSET + 38, "key"), - "Key for Front Door": ItemData(SHIVERS_ITEM_ID_OFFSET + 39, "key-optional"), + "Key for Office Elevator": ItemData(SHIVERS_ITEM_ID_OFFSET + 30, "key"), + "Key for Bedroom Elevator": ItemData(SHIVERS_ITEM_ID_OFFSET + 31, "key"), + "Key for Three Floor Elevator": ItemData(SHIVERS_ITEM_ID_OFFSET + 32, "key"), + "Key for Workshop": ItemData(SHIVERS_ITEM_ID_OFFSET + 33, "key"), + "Key for Office": ItemData(SHIVERS_ITEM_ID_OFFSET + 34, "key"), + "Key for Prehistoric Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 35, "key"), + "Key for Greenhouse Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 36, "key"), + "Key for Ocean Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 37, "key"), + "Key for Projector Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 38, "key"), + "Key for Generator Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 39, "key"), + "Key for Egypt Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 40, "key"), + "Key for Library Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 41, "key"), + "Key for Shaman Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 42, "key"), + "Key for UFO Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 43, "key"), + "Key for Torture Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 44, "key"), + "Key for Puzzle Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 45, "key"), + "Key for Bedroom": ItemData(SHIVERS_ITEM_ID_OFFSET + 46, "key"), + "Key for Underground Lake Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 47, "key"), + "Key for Janitor Closet": ItemData(SHIVERS_ITEM_ID_OFFSET + 48, "key"), + "Key for Front Door": ItemData(SHIVERS_ITEM_ID_OFFSET + 49, "key-optional"), #Abilities "Crawling": ItemData(SHIVERS_ITEM_ID_OFFSET + 50, "ability"), @@ -83,6 +93,16 @@ class ItemData(typing.NamedTuple): "Lightning Pot Top DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 87, "potduplicate"), "Sand Pot Top DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 88, "potduplicate"), "Metal Pot Top DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 89, "potduplicate"), + "Water Pot Complete DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 140, "potduplicate_type2"), + "Wax Pot Complete DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 141, "potduplicate_type2"), + "Ash Pot Complete DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 142, "potduplicate_type2"), + "Oil Pot Complete DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 143, "potduplicate_type2"), + "Cloth Pot Complete DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 144, "potduplicate_type2"), + "Wood Pot Complete DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 145, "potduplicate_type2"), + "Crystal Pot Complete DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 146, "potduplicate_type2"), + "Lightning Pot Complete DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 147, "potduplicate_type2"), + "Sand Pot Complete DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 148, "potduplicate_type2"), + "Metal Pot Complete DUPE": ItemData(SHIVERS_ITEM_ID_OFFSET + 149, "potduplicate_type2"), #Filler "Empty": ItemData(SHIVERS_ITEM_ID_OFFSET + 90, "filler"), diff --git a/worlds/shivers/Options.py b/worlds/shivers/Options.py index b70882f9a545..2f33eb18e5d1 100644 --- a/worlds/shivers/Options.py +++ b/worlds/shivers/Options.py @@ -1,21 +1,37 @@ -from Options import Choice, DefaultOnToggle, Toggle, PerGameCommonOptions +from Options import Choice, DefaultOnToggle, Toggle, PerGameCommonOptions, Range from dataclasses import dataclass +class IxupiCapturesNeeded(Range): + """ + Number of Ixupi Captures needed for goal condition. + """ + display_name = "Number of Ixupi Captures Needed" + range_start = 1 + range_end = 10 + default = 10 + class LobbyAccess(Choice): - """Chooses how keys needed to reach the lobby are placed. + """ + Chooses how keys needed to reach the lobby are placed. - Normal: Keys are placed anywhere - Early: Keys are placed early - - Local: Keys are placed locally""" + - Local: Keys are placed locally + """ display_name = "Lobby Access" option_normal = 0 option_early = 1 option_local = 2 + default = 1 class PuzzleHintsRequired(DefaultOnToggle): - """If turned on puzzle hints will be available before the corresponding puzzle is required. For example: The Shaman - Drums puzzle will be placed after access to the security cameras which give you the solution. Turning this off - allows for greater randomization.""" + """ + If turned on puzzle hints/solutions will be available before the corresponding puzzle is required. + + For example: The Red Door puzzle will be logically required only after access to the Beth's Address Book which gives you the solution. + + Turning this off allows for greater randomization. + """ display_name = "Puzzle Hints Required" class InformationPlaques(Toggle): @@ -26,7 +42,9 @@ class InformationPlaques(Toggle): display_name = "Include Information Plaques" class FrontDoorUsable(Toggle): - """Adds a key to unlock the front door of the museum.""" + """ + Adds a key to unlock the front door of the museum. + """ display_name = "Front Door Usable" class ElevatorsStaySolved(DefaultOnToggle): @@ -37,7 +55,9 @@ class ElevatorsStaySolved(DefaultOnToggle): display_name = "Elevators Stay Solved" class EarlyBeth(DefaultOnToggle): - """Beth's body is open at the start of the game. This allows any pot piece to be placed in the slide and early checks on the second half of the final riddle.""" + """ + Beth's body is open at the start of the game. This allows any pot piece to be placed in the slide and early checks on the second half of the final riddle. + """ display_name = "Early Beth" class EarlyLightning(Toggle): @@ -47,9 +67,34 @@ class EarlyLightning(Toggle): """ display_name = "Early Lightning" +class LocationPotPieces(Choice): + """ + Chooses where pot pieces will be located within the multiworld. + - Own World: Pot pieces will be located within your own world + - Different World: Pot pieces will be located in another world + - Any World: Pot pieces will be located in any world + """ + display_name = "Location of Pot Pieces" + option_own_world = 0 + option_different_world = 1 + option_any_world = 2 + +class FullPots(Choice): + """ + Chooses if pots will be in pieces or already completed + - Pieces: Only pot pieces will be added to the item pool + - Complete: Only completed pots will be added to the item pool + - Mixed: Each pot will be randomly chosen to be pieces or already completed. + """ + display_name = "Full Pots" + option_pieces = 0 + option_complete = 1 + option_mixed = 2 + @dataclass class ShiversOptions(PerGameCommonOptions): + ixupi_captures_needed: IxupiCapturesNeeded lobby_access: LobbyAccess puzzle_hints_required: PuzzleHintsRequired include_information_plaques: InformationPlaques @@ -57,3 +102,5 @@ class ShiversOptions(PerGameCommonOptions): elevators_stay_solved: ElevatorsStaySolved early_beth: EarlyBeth early_lightning: EarlyLightning + location_pot_pieces: LocationPotPieces + full_pots: FullPots diff --git a/worlds/shivers/Rules.py b/worlds/shivers/Rules.py index 3dc4f51c47a2..5288fa2c9c3f 100644 --- a/worlds/shivers/Rules.py +++ b/worlds/shivers/Rules.py @@ -8,58 +8,58 @@ def water_capturable(state: CollectionState, player: int) -> bool: - return (state.can_reach("Lobby", "Region", player) or (state.can_reach("Janitor Closet", "Region", player) and cloth_capturable(state, player))) \ - and state.has_all({"Water Pot Bottom", "Water Pot Top", "Water Pot Bottom DUPE", "Water Pot Top DUPE"}, player) + return state.has_all({"Water Pot Bottom", "Water Pot Top", "Water Pot Bottom DUPE", "Water Pot Top DUPE"}, player) or \ + state.has_all({"Water Pot Complete", "Water Pot Complete DUPE"}, player) def wax_capturable(state: CollectionState, player: int) -> bool: - return (state.can_reach("Library", "Region", player) or state.can_reach("Anansi", "Region", player)) \ - and state.has_all({"Wax Pot Bottom", "Wax Pot Top", "Wax Pot Bottom DUPE", "Wax Pot Top DUPE"}, player) + return state.has_all({"Wax Pot Bottom", "Wax Pot Top", "Wax Pot Bottom DUPE", "Wax Pot Top DUPE"}, player) or \ + state.has_all({"Wax Pot Complete", "Wax Pot Complete DUPE"}, player) def ash_capturable(state: CollectionState, player: int) -> bool: - return (state.can_reach("Office", "Region", player) or state.can_reach("Burial", "Region", player)) \ - and state.has_all({"Ash Pot Bottom", "Ash Pot Top", "Ash Pot Bottom DUPE", "Ash Pot Top DUPE"}, player) + return state.has_all({"Ash Pot Bottom", "Ash Pot Top", "Ash Pot Bottom DUPE", "Ash Pot Top DUPE"}, player) or \ + state.has_all({"Ash Pot Complete", "Ash Pot Complete DUPE"}, player) def oil_capturable(state: CollectionState, player: int) -> bool: - return (state.can_reach("Prehistoric", "Region", player) or state.can_reach("Tar River", "Region", player)) \ - and state.has_all({"Oil Pot Bottom", "Oil Pot Top", "Oil Pot Bottom DUPE", "Oil Pot Top DUPE"}, player) + return state.has_all({"Oil Pot Bottom", "Oil Pot Top", "Oil Pot Bottom DUPE", "Oil Pot Top DUPE"}, player) or \ + state.has_all({"Oil Pot Complete", "Oil Pot Complete DUPE"}, player) def cloth_capturable(state: CollectionState, player: int) -> bool: - return (state.can_reach("Egypt", "Region", player) or state.can_reach("Burial", "Region", player) or state.can_reach("Janitor Closet", "Region", player)) \ - and state.has_all({"Cloth Pot Bottom", "Cloth Pot Top", "Cloth Pot Bottom DUPE", "Cloth Pot Top DUPE"}, player) + return state.has_all({"Cloth Pot Bottom", "Cloth Pot Top", "Cloth Pot Bottom DUPE", "Cloth Pot Top DUPE"}, player) or \ + state.has_all({"Cloth Pot Complete", "Cloth Pot Complete DUPE"}, player) def wood_capturable(state: CollectionState, player: int) -> bool: - return (state.can_reach("Workshop", "Region", player) or state.can_reach("Blue Maze", "Region", player) or state.can_reach("Gods Room", "Region", player) or state.can_reach("Anansi", "Region", player)) \ - and state.has_all({"Wood Pot Bottom", "Wood Pot Top", "Wood Pot Bottom DUPE", "Wood Pot Top DUPE"}, player) + return state.has_all({"Wood Pot Bottom", "Wood Pot Top", "Wood Pot Bottom DUPE", "Wood Pot Top DUPE"}, player) or \ + state.has_all({"Wood Pot Complete", "Wood Pot Complete DUPE"}, player) def crystal_capturable(state: CollectionState, player: int) -> bool: - return (state.can_reach("Lobby", "Region", player) or state.can_reach("Ocean", "Region", player)) \ - and state.has_all({"Crystal Pot Bottom", "Crystal Pot Top", "Crystal Pot Bottom DUPE", "Crystal Pot Top DUPE"}, player) + return state.has_all({"Crystal Pot Bottom", "Crystal Pot Top", "Crystal Pot Bottom DUPE", "Crystal Pot Top DUPE"}, player) or \ + state.has_all({"Crystal Pot Complete", "Crystal Pot Complete DUPE"}, player) def sand_capturable(state: CollectionState, player: int) -> bool: - return (state.can_reach("Greenhouse", "Region", player) or state.can_reach("Ocean", "Region", player)) \ - and state.has_all({"Sand Pot Bottom", "Sand Pot Top", "Sand Pot Bottom DUPE", "Sand Pot Top DUPE"}, player) + return state.has_all({"Sand Pot Bottom", "Sand Pot Top", "Sand Pot Bottom DUPE", "Sand Pot Top DUPE"}, player) or \ + state.has_all({"Sand Pot Complete", "Sand Pot Complete DUPE"}, player) def metal_capturable(state: CollectionState, player: int) -> bool: - return (state.can_reach("Projector Room", "Region", player) or state.can_reach("Prehistoric", "Region", player) or state.can_reach("Bedroom", "Region", player)) \ - and state.has_all({"Metal Pot Bottom", "Metal Pot Top", "Metal Pot Bottom DUPE", "Metal Pot Top DUPE"}, player) + return state.has_all({"Metal Pot Bottom", "Metal Pot Top", "Metal Pot Bottom DUPE", "Metal Pot Top DUPE"}, player) or \ + state.has_all({"Metal Pot Complete", "Metal Pot Complete DUPE"}, player) def lightning_capturable(state: CollectionState, player: int) -> bool: - return (first_nine_ixupi_capturable or state.multiworld.early_lightning[player].value) \ - and state.can_reach("Generator", "Region", player) \ - and state.has_all({"Lightning Pot Bottom", "Lightning Pot Top", "Lightning Pot Bottom DUPE", "Lightning Pot Top DUPE"}, player) + return (first_nine_ixupi_capturable(state, player) or state.multiworld.worlds[player].options.early_lightning.value) \ + and (state.has_all({"Lightning Pot Bottom", "Lightning Pot Top", "Lightning Pot Bottom DUPE", "Lightning Pot Top DUPE"}, player) or \ + state.has_all({"Lightning Pot Complete", "Lightning Pot Complete DUPE"}, player)) def beths_body_available(state: CollectionState, player: int) -> bool: - return (first_nine_ixupi_capturable(state, player) or state.multiworld.early_beth[player].value) \ + return (first_nine_ixupi_capturable(state, player) or state.multiworld.worlds[player].options.early_beth.value) \ and state.can_reach("Generator", "Region", player) @@ -123,7 +123,8 @@ def get_rules_lookup(player: int): "To Burial From Egypt": lambda state: state.can_reach("Egypt", "Region", player), "To Gods Room From Anansi": lambda state: state.can_reach("Gods Room", "Region", player), "To Slide Room": lambda state: all_skull_dials_available(state, player), - "To Lobby From Slide Room": lambda state: (beths_body_available(state, player)) + "To Lobby From Slide Room": lambda state: beths_body_available(state, player), + "To Water Capture From Janitor Closet": lambda state: cloth_capturable(state, player) }, "locations_required": { "Puzzle Solved Anansi Musicbox": lambda state: state.can_reach("Clock Tower", "Region", player), @@ -207,8 +208,10 @@ def set_rules(world: "ShiversWorld") -> None: # forbid cloth in janitor closet and oil in tar river forbid_item(multiworld.get_location("Accessible: Storage: Janitor Closet", player), "Cloth Pot Bottom DUPE", player) forbid_item(multiworld.get_location("Accessible: Storage: Janitor Closet", player), "Cloth Pot Top DUPE", player) + forbid_item(multiworld.get_location("Accessible: Storage: Janitor Closet", player), "Cloth Pot Complete DUPE", player) forbid_item(multiworld.get_location("Accessible: Storage: Tar River", player), "Oil Pot Bottom DUPE", player) forbid_item(multiworld.get_location("Accessible: Storage: Tar River", player), "Oil Pot Top DUPE", player) + forbid_item(multiworld.get_location("Accessible: Storage: Tar River", player), "Oil Pot Complete DUPE", player) # Filler Item Forbids forbid_item(multiworld.get_location("Puzzle Solved Lyre", player), "Easier Lyre", player) @@ -234,4 +237,8 @@ def set_rules(world: "ShiversWorld") -> None: forbid_item(multiworld.get_location("Ixupi Captured Metal", player), "Metal Always Available in Prehistoric", player) # Set completion condition - multiworld.completion_condition[player] = lambda state: (first_nine_ixupi_capturable(state, player) and lightning_capturable(state, player)) + multiworld.completion_condition[player] = lambda state: (( + water_capturable(state, player) + wax_capturable(state, player) + ash_capturable(state, player) \ + + oil_capturable(state, player) + cloth_capturable(state, player) + wood_capturable(state, player) \ + + crystal_capturable(state, player) + sand_capturable(state, player) + metal_capturable(state, player) \ + + lightning_capturable(state, player)) >= world.options.ixupi_captures_needed.value) diff --git a/worlds/shivers/__init__.py b/worlds/shivers/__init__.py index e43e91fb5ae3..a2d7bc14644e 100644 --- a/worlds/shivers/__init__.py +++ b/worlds/shivers/__init__.py @@ -1,3 +1,4 @@ +from typing import List from .Items import item_table, ShiversItem from .Rules import set_rules from BaseClasses import Item, Tutorial, Region, Location @@ -22,7 +23,7 @@ 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" + game = "Shivers" topology_present = False web = ShiversWeb() options_dataclass = ShiversOptions @@ -30,7 +31,13 @@ class ShiversWorld(World): 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) @@ -78,9 +85,28 @@ 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"}: + 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)] @@ -88,7 +114,6 @@ def create_items(self) -> None: 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:")]) @@ -123,14 +148,14 @@ def create_items(self) -> None: self.multiworld.itempool += itempool #Lobby acess: - if self.options.lobby_access == 1: + 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 == 2: + 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 @@ -138,6 +163,12 @@ def create_items(self) -> None: 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 = [] @@ -149,7 +180,23 @@ def pre_fill(self) -> None: 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'] + #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) @@ -166,11 +213,13 @@ def pre_fill(self) -> None: 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}, + "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 } diff --git a/worlds/shivers/data/locations.json b/worlds/shivers/data/locations.json index 1d62f85d2d1c..64fe3647348d 100644 --- a/worlds/shivers/data/locations.json +++ b/worlds/shivers/data/locations.json @@ -81,7 +81,7 @@ "Information Plaque: (Ocean) Poseidon", "Information Plaque: (Ocean) Colossus of Rhodes", "Information Plaque: (Ocean) Poseidon's Temple", - "Information Plaque: (Underground Maze) Subterranean World", + "Information Plaque: (Underground Maze Staircase) Subterranean World", "Information Plaque: (Underground Maze) Dero", "Information Plaque: (Egypt) Tomb of the Ixupi", "Information Plaque: (Egypt) The Sphinx", @@ -119,16 +119,6 @@ "Outside": [ "Puzzle Solved Gears", "Puzzle Solved Stone Henge", - "Ixupi Captured Water", - "Ixupi Captured Wax", - "Ixupi Captured Ash", - "Ixupi Captured Oil", - "Ixupi Captured Cloth", - "Ixupi Captured Wood", - "Ixupi Captured Crystal", - "Ixupi Captured Sand", - "Ixupi Captured Metal", - "Ixupi Captured Lightning", "Puzzle Solved Office Elevator", "Puzzle Solved Three Floor Elevator", "Puzzle Hint Found: Combo Lock in Mailbox", @@ -182,7 +172,8 @@ "Accessible: Storage: Transforming Mask" ], "Generator": [ - "Final Riddle: Beth's Body Page 17" + "Final Riddle: Beth's Body Page 17", + "Ixupi Captured Lightning" ], "Theater Back Hallways": [ "Puzzle Solved Clock Tower Door" @@ -210,6 +201,7 @@ "Information Plaque: (Ocean) Poseidon's Temple" ], "Maze Staircase": [ + "Information Plaque: (Underground Maze Staircase) Subterranean World", "Puzzle Solved Maze Door" ], "Egypt": [ @@ -305,7 +297,6 @@ ], "Tar River": [ "Accessible: Storage: Tar River", - "Information Plaque: (Underground Maze) Subterranean World", "Information Plaque: (Underground Maze) Dero" ], "Theater": [ @@ -320,6 +311,33 @@ "Skull Dial Bridge": [ "Accessible: Storage: Skull Bridge", "Puzzle Solved Skull Dial Door" + ], + "Water Capture": [ + "Ixupi Captured Water" + ], + "Wax Capture": [ + "Ixupi Captured Wax" + ], + "Ash Capture": [ + "Ixupi Captured Ash" + ], + "Oil Capture": [ + "Ixupi Captured Oil" + ], + "Cloth Capture": [ + "Ixupi Captured Cloth" + ], + "Wood Capture": [ + "Ixupi Captured Wood" + ], + "Crystal Capture": [ + "Ixupi Captured Crystal" + ], + "Sand Capture": [ + "Ixupi Captured Sand" + ], + "Metal Capture": [ + "Ixupi Captured Metal" ] } -} +} diff --git a/worlds/shivers/data/regions.json b/worlds/shivers/data/regions.json index 963d100faddb..aeb5aa737366 100644 --- a/worlds/shivers/data/regions.json +++ b/worlds/shivers/data/regions.json @@ -7,35 +7,35 @@ ["Underground Lake", ["To Underground Tunnels From Underground Lake", "To Underground Blue Tunnels From Underground Lake"]], ["Underground Blue Tunnels", ["To Underground Lake From Underground Blue Tunnels", "To Office Elevator From Underground Blue Tunnels"]], ["Office Elevator", ["To Underground Blue Tunnels From Office Elevator","To Office From Office Elevator"]], - ["Office", ["To Office Elevator From Office", "To Workshop", "To Lobby From Office", "To Bedroom Elevator From Office"]], - ["Workshop", ["To Office From Workshop"]], + ["Office", ["To Office Elevator From Office", "To Workshop", "To Lobby From Office", "To Bedroom Elevator From Office", "To Ash Capture From Office"]], + ["Workshop", ["To Office From Workshop", "To Wood Capture From Workshop"]], ["Bedroom Elevator", ["To Office From Bedroom Elevator", "To Bedroom"]], - ["Bedroom", ["To Bedroom Elevator From Bedroom"]], - ["Lobby", ["To Office From Lobby", "To Library From Lobby", "To Theater From Lobby", "To Prehistoric From Lobby", "To Egypt From Lobby", "To Tar River From Lobby", "To Outside From Lobby"]], - ["Library", ["To Lobby From Library", "To Maintenance Tunnels From Library"]], + ["Bedroom", ["To Bedroom Elevator From Bedroom", "To Metal Capture From Bedroom"]], + ["Lobby", ["To Office From Lobby", "To Library From Lobby", "To Theater From Lobby", "To Prehistoric From Lobby", "To Egypt From Lobby", "To Tar River From Lobby", "To Outside From Lobby", "To Water Capture From Lobby", "To Crystal Capture From Lobby"]], + ["Library", ["To Lobby From Library", "To Maintenance Tunnels From Library", "To Wax Capture From Library"]], ["Maintenance Tunnels", ["To Library From Maintenance Tunnels", "To Three Floor Elevator From Maintenance Tunnels", "To Generator"]], ["Generator", ["To Maintenance Tunnels From Generator"]], ["Theater", ["To Lobby From Theater", "To Theater Back Hallways From Theater"]], ["Theater Back Hallways", ["To Theater From Theater Back Hallways", "To Clock Tower Staircase From Theater Back Hallways", "To Maintenance Tunnels From Theater Back Hallways", "To Projector Room"]], ["Clock Tower Staircase", ["To Theater Back Hallways From Clock Tower Staircase", "To Clock Tower"]], ["Clock Tower", ["To Clock Tower Staircase From Clock Tower"]], - ["Projector Room", ["To Theater Back Hallways From Projector Room"]], - ["Prehistoric", ["To Lobby From Prehistoric", "To Greenhouse", "To Ocean From Prehistoric"]], - ["Greenhouse", ["To Prehistoric From Greenhouse"]], - ["Ocean", ["To Prehistoric From Ocean", "To Maze Staircase From Ocean"]], + ["Projector Room", ["To Theater Back Hallways From Projector Room", "To Metal Capture From Projector Room"]], + ["Prehistoric", ["To Lobby From Prehistoric", "To Greenhouse", "To Ocean From Prehistoric", "To Oil Capture From Prehistoric", "To Metal Capture From Prehistoric"]], + ["Greenhouse", ["To Prehistoric From Greenhouse", "To Sand Capture From Greenhouse"]], + ["Ocean", ["To Prehistoric From Ocean", "To Maze Staircase From Ocean", "To Crystal Capture From Ocean", "To Sand Capture From Ocean"]], ["Maze Staircase", ["To Ocean From Maze Staircase", "To Maze From Maze Staircase"]], ["Maze", ["To Maze Staircase From Maze", "To Tar River"]], - ["Tar River", ["To Maze From Tar River", "To Lobby From Tar River"]], - ["Egypt", ["To Lobby From Egypt", "To Burial From Egypt", "To Blue Maze From Egypt"]], - ["Burial", ["To Egypt From Burial", "To Shaman From Burial"]], - ["Shaman", ["To Burial From Shaman", "To Gods Room"]], - ["Gods Room", ["To Shaman From Gods Room", "To Anansi From Gods Room"]], - ["Anansi", ["To Gods Room From Anansi", "To Werewolf From Anansi"]], + ["Tar River", ["To Maze From Tar River", "To Lobby From Tar River", "To Oil Capture From Tar River"]], + ["Egypt", ["To Lobby From Egypt", "To Burial From Egypt", "To Blue Maze From Egypt", "To Cloth Capture From Egypt"]], + ["Burial", ["To Egypt From Burial", "To Shaman From Burial", "To Ash Capture From Burial", "To Cloth Capture From Burial"]], + ["Shaman", ["To Burial From Shaman", "To Gods Room", "To Wax Capture From Shaman"]], + ["Gods Room", ["To Shaman From Gods Room", "To Anansi From Gods Room", "To Wood Capture From Gods Room"]], + ["Anansi", ["To Gods Room From Anansi", "To Werewolf From Anansi", "To Wax Capture From Anansi", "To Wood Capture From Anansi"]], ["Werewolf", ["To Anansi From Werewolf", "To Night Staircase From Werewolf"]], ["Night Staircase", ["To Werewolf From Night Staircase", "To Janitor Closet", "To UFO"]], - ["Janitor Closet", ["To Night Staircase From Janitor Closet"]], + ["Janitor Closet", ["To Night Staircase From Janitor Closet", "To Water Capture From Janitor Closet", "To Cloth Capture From Janitor Closet"]], ["UFO", ["To Night Staircase From UFO", "To Inventions From UFO"]], - ["Blue Maze", ["To Egypt From Blue Maze", "To Three Floor Elevator From Blue Maze Bottom", "To Three Floor Elevator From Blue Maze Top", "To Fortune Teller", "To Inventions From Blue Maze"]], + ["Blue Maze", ["To Egypt From Blue Maze", "To Three Floor Elevator From Blue Maze Bottom", "To Three Floor Elevator From Blue Maze Top", "To Fortune Teller", "To Inventions From Blue Maze", "To Wood Capture From Blue Maze"]], ["Three Floor Elevator", ["To Maintenance Tunnels From Three Floor Elevator", "To Blue Maze From Three Floor Elevator"]], ["Fortune Teller", ["To Blue Maze From Fortune Teller"]], ["Inventions", ["To Blue Maze From Inventions", "To UFO From Inventions", "To Torture From Inventions"]], @@ -43,7 +43,16 @@ ["Puzzle Room Mastermind", ["To Torture", "To Puzzle Room Marbles From Puzzle Room Mastermind"]], ["Puzzle Room Marbles", ["To Puzzle Room Mastermind From Puzzle Room Marbles", "To Skull Dial Bridge From Puzzle Room Marbles"]], ["Skull Dial Bridge", ["To Puzzle Room Marbles From Skull Dial Bridge", "To Slide Room"]], - ["Slide Room", ["To Skull Dial Bridge From Slide Room", "To Lobby From Slide Room"]] + ["Slide Room", ["To Skull Dial Bridge From Slide Room", "To Lobby From Slide Room"]], + ["Water Capture", []], + ["Wax Capture", []], + ["Ash Capture", []], + ["Oil Capture", []], + ["Cloth Capture", []], + ["Wood Capture", []], + ["Crystal Capture", []], + ["Sand Capture", []], + ["Metal Capture", []] ], "mandatory_connections": [ ["To Registry", "Registry"], @@ -140,6 +149,29 @@ ["To Puzzle Room Marbles From Skull Dial Bridge", "Puzzle Room Marbles"], ["To Skull Dial Bridge From Puzzle Room Marbles", "Skull Dial Bridge"], ["To Skull Dial Bridge From Slide Room", "Skull Dial Bridge"], - ["To Slide Room", "Slide Room"] + ["To Slide Room", "Slide Room"], + ["To Wax Capture From Library", "Wax Capture"], + ["To Wax Capture From Shaman", "Wax Capture"], + ["To Wax Capture From Anansi", "Wax Capture"], + ["To Water Capture From Lobby", "Water Capture"], + ["To Water Capture From Janitor Closet", "Water Capture"], + ["To Ash Capture From Office", "Ash Capture"], + ["To Ash Capture From Burial", "Ash Capture"], + ["To Oil Capture From Prehistoric", "Oil Capture"], + ["To Oil Capture From Tar River", "Oil Capture"], + ["To Cloth Capture From Egypt", "Cloth Capture"], + ["To Cloth Capture From Burial", "Cloth Capture"], + ["To Cloth Capture From Janitor Closet", "Cloth Capture"], + ["To Wood Capture From Workshop", "Wood Capture"], + ["To Wood Capture From Gods Room", "Wood Capture"], + ["To Wood Capture From Anansi", "Wood Capture"], + ["To Wood Capture From Blue Maze", "Wood Capture"], + ["To Crystal Capture From Lobby", "Crystal Capture"], + ["To Crystal Capture From Ocean", "Crystal Capture"], + ["To Sand Capture From Greenhouse", "Sand Capture"], + ["To Sand Capture From Ocean", "Sand Capture"], + ["To Metal Capture From Bedroom", "Metal Capture"], + ["To Metal Capture From Projector Room", "Metal Capture"], + ["To Metal Capture From Prehistoric", "Metal Capture"] ] -} \ No newline at end of file +} diff --git a/worlds/shivers/docs/en_Shivers.md b/worlds/shivers/docs/en_Shivers.md index a92f8a6b7911..2c56152a7a0c 100644 --- a/worlds/shivers/docs/en_Shivers.md +++ b/worlds/shivers/docs/en_Shivers.md @@ -12,8 +12,8 @@ these are randomized. Crawling has been added and is required to use any crawl s ## What is considered a location check in Shivers? -1. All puzzle solves are location checks excluding elevator puzzles. -2. All Ixupi captures are location checks excluding Lightning. +1. All puzzle solves are location checks. +2. All Ixupi captures are location checks. 3. Puzzle hints/solutions are location checks. For example, looking at the Atlantis map. 4. Optionally information plaques are location checks. @@ -23,9 +23,9 @@ If the player receives a key then the corresponding door will be unlocked. If th ## What is the victory condition? -Victory is achieved when the player captures Lightning in the generator room. +Victory is achieved when the player has captured the required number Ixupi set in their options. ## Encountered a bug? -Please contact GodlFire on Discord for bugs related to Shivers world generation.\ +Please contact GodlFire on Discord for bugs related to Shivers world generation.
Please contact GodlFire or mouse on Discord for bugs related to the Shivers Randomizer. diff --git a/worlds/shivers/docs/setup_en.md b/worlds/shivers/docs/setup_en.md index 187382ef643c..c53edcdf2b57 100644 --- a/worlds/shivers/docs/setup_en.md +++ b/worlds/shivers/docs/setup_en.md @@ -5,7 +5,7 @@ - [Shivers (GOG version)](https://www.gog.com/en/game/shivers) or original disc - [ScummVM](https://www.scummvm.org/downloads/) version 2.7.0 or later -- [Shivers Randomizer](https://www.speedrun.com/shivers/resources) +- [Shivers Randomizer](https://github.com/GodlFire/Shivers-Randomizer-CSharp/releases/latest) Latest release version ## Setup ScummVM for Shivers