diff --git a/worlds/dark_souls_3/__init__.py b/worlds/dark_souls_3/__init__.py index 0f30b50541a..10d1f1fb9f7 100644 --- a/worlds/dark_souls_3/__init__.py +++ b/worlds/dark_souls_3/__init__.py @@ -106,12 +106,11 @@ def generate_early(self): not self.options.late_basin_of_vows ) ): - self.multiworld.early_items[self.player]['Storm Ruler'] = 1 - self.options.local_items.value.add('Storm Ruler') + self.multiworld.early_items[self.player]["Storm Ruler"] = 1 + self.options.local_items.value.add("Storm Ruler") else: self.yhorm_location = default_yhorm_location - def _allow_boss_for_yhorm(self, boss: DS3BossInfo) -> bool: """Returns whether boss is a valid location for Yhorm in this seed.""" @@ -141,7 +140,6 @@ def _allow_boss_for_yhorm(self, boss: DS3BossInfo) -> bool: for location in location_tables["Cemetery of Ash"] ) - def create_regions(self): # Create Vanilla Regions regions: Dict[str, Region] = {"Menu": self.create_region("Menu", {})} @@ -228,7 +226,6 @@ def create_connection(from_region: str, to_region: str): create_connection("Painted World of Ariandel (After Contraption)", "Dreg Heap") create_connection("Dreg Heap", "Ringed City") - # For each region, add the associated locations retrieved from the corresponding location_table def create_region(self, region_name, location_table) -> Region: new_region = Region(region_name, self.player, self.multiworld) @@ -277,7 +274,6 @@ def create_region(self, region_name, location_table) -> Region: self.multiworld.regions.append(new_region) return new_region - def create_items(self): # Just used to efficiently deduplicate items item_set: Set[str] = set() @@ -315,7 +311,6 @@ def create_items(self): self._fill_local_items() - def _create_injectable_items(self, num_required_extra_items: int) -> List[Item]: """Returns a list of items to inject into the multiworld instead of skipped items. @@ -365,7 +360,6 @@ def _create_injectable_items(self, num_required_extra_items: int) -> List[Item]: return [self.create_item(item) for item in items] - def create_item(self, item: Union[str, DS3ItemData]) -> Item: data = item if isinstance(item, DS3ItemData) else item_dictionary[item] classification = None @@ -407,7 +401,6 @@ def create_item(self, item: Union[str, DS3ItemData]) -> Item: return DarkSouls3Item(self.player, data, classification=classification) - def _fill_local_items(self) -> None: """Removes certain items from the item pool and manually places them in the local world. @@ -416,7 +409,7 @@ def _fill_local_items(self) -> None: # If Yhorm is at Iudex Gundyr, Storm Ruler must be randomized, so it can always be moved. # Fill this manually so that, if very few slots are available in Cemetery of Ash, this # doesn't get locked out by bad rolls on the next two fills. - if self.yhorm_location.name == 'Iudex Gundyr': + if self.yhorm_location.name == "Iudex Gundyr": self._fill_local_item("Storm Ruler", ["Cemetery of Ash"], lambda location: location.name != "CA: Coiled Sword - boss drop") @@ -438,7 +431,6 @@ def _fill_local_items(self) -> None: "High Wall of Lothric" ]) - def _fill_local_item( self, name: str, regions: List[str], @@ -497,11 +489,9 @@ def _replace_with_filler(self, location: DarkSouls3Location) -> None: location.item = candidate return - def get_filler_item_name(self) -> str: return self.random.choice(filler_item_names) - def set_rules(self) -> None: randomized_items = {item.name for item in self.local_itempool} @@ -574,7 +564,7 @@ def set_rules(self) -> None: and self._has_any_scroll(state) )) - if self.options.late_basin_of_vows > 1: # After Small Doll + if self.options.late_basin_of_vows > 1: # After Small Doll self._add_entrance_rule("Lothric Castle", "Small Doll") # DLC Access Rules Below @@ -595,7 +585,7 @@ def set_rules(self) -> None: "Painted World of Ariandel (Before Contraption)", lambda state: state.has("Small Doll", self.player) and self._has_any_scroll(state)) - if self.options.late_dlc > 1: # After Basin + if self.options.late_dlc > 1: # After Basin self._add_entrance_rule("Painted World of Ariandel (Before Contraption)", "Basin of Vows") # Define the access rules to some specific locations @@ -643,7 +633,7 @@ def set_rules(self) -> None: and self._has_any_scroll(state) )) - if self.options.late_basin_of_vows > 1: # After Small Doll + if self.options.late_basin_of_vows > 1: # After Small Doll self._add_location_rule("HWL: Soul of the Dancer", "Small Doll") self._add_location_rule([ @@ -721,7 +711,6 @@ def set_rules(self) -> None: state.has("Cinders of a Lord - Aldrich", self.player) and \ state.has("Cinders of a Lord - Lothric Prince", self.player) - def _add_shop_rules(self) -> None: """Adds rules for items unlocked in shops.""" @@ -804,7 +793,6 @@ def _add_shop_rules(self) -> None: self._add_location_rule( [f"FS: {item} - {shop} for {key_name}" for item in items], key) - def _add_npc_rules(self) -> None: """Adds rules for items accessible via NPC quests. @@ -1102,7 +1090,6 @@ def _add_npc_rules(self) -> None: self._can_get(state, "AL: Soul of Aldrich") )) - def _add_transposition_rules(self) -> None: """Adds rules for items obtainable from Ludleth by soul transposition.""" @@ -1166,7 +1153,6 @@ def _add_transposition_rules(self) -> None: state.has(s, self.player) and state.has("Transposing Kiln", self.player) )) - def _add_crow_rules(self) -> None: """Adds rules for items obtainable by trading items to the crow on Firelink roof.""" @@ -1199,7 +1185,6 @@ def _add_crow_rules(self) -> None: and not item.data.is_upgraded )) - def _add_unnecessary_location_rules(self) -> None: """Adds rules for locations that can contain useful but not necessary items. @@ -1230,27 +1215,25 @@ def _add_unnecessary_location_rules(self) -> None: if self.options.excluded_locations == "unnecessary": self.options.exclude_locations.value.clear() - def _add_early_item_rules(self, randomized_items: Set[str]) -> None: """Adds rules to make sure specific items are available early.""" - if 'Pyromancy Flame' in randomized_items: + if "Pyromancy Flame" in randomized_items: # Make this available early because so many items are useless without it. self._add_entrance_rule("Road of Sacrifices", "Pyromancy Flame") self._add_entrance_rule("Consumed King's Garden", "Pyromancy Flame") self._add_entrance_rule("Grand Archives", "Pyromancy Flame") - if 'Transposing Kiln' in randomized_items: + if "Transposing Kiln" in randomized_items: # Make this available early so players can make use of their boss souls. self._add_entrance_rule("Road of Sacrifices", "Transposing Kiln") self._add_entrance_rule("Consumed King's Garden", "Transposing Kiln") self._add_entrance_rule("Grand Archives", "Transposing Kiln") # Make this available pretty early - if 'Small Lothric Banner' in randomized_items: + if "Small Lothric Banner" in randomized_items: if self.options.early_banner == "early_global": - self.multiworld.early_items[self.player]['Small Lothric Banner'] = 1 + self.multiworld.early_items[self.player]["Small Lothric Banner"] = 1 elif self.options.early_banner == "early_local": - self.multiworld.local_early_items[self.player]['Small Lothric Banner'] = 1 - + self.multiworld.local_early_items[self.player]["Small Lothric Banner"] = 1 def _has_any_scroll(self, state: CollectionState) -> bool: """Returns whether the given state has any scroll item.""" @@ -1261,7 +1244,6 @@ def _has_any_scroll(self, state: CollectionState) -> bool: or state.has("Crystal Scroll", self.player) ) - def _add_location_rule(self, location: Union[str, List[str]], rule: Union[CollectionRule, str]) -> None: """Sets a rule for the given location if it that location is randomized. @@ -1279,7 +1261,6 @@ def _add_location_rule(self, location: Union[str, List[str]], rule: Union[Collec rule = lambda state, item=rule: state.has(item, self.player) add_rule(self.multiworld.get_location(location, self.player), rule) - def _add_entrance_rule(self, region: str, rule: Union[CollectionRule, str]) -> None: """Sets a rule for the entrance to the given region.""" assert region in location_tables @@ -1290,23 +1271,19 @@ def _add_entrance_rule(self, region: str, rule: Union[CollectionRule, str]) -> N rule = lambda state, item=rule: state.has(item, self.player) add_rule(self.multiworld.get_entrance("Go To " + region, self.player), rule) - def _add_item_rule(self, location: str, rule: ItemRule) -> None: """Sets a rule for what items are allowed in a given location.""" if not self._is_location_available(location): return add_item_rule(self.multiworld.get_location(location, self.player), rule) - def _can_go_to(self, state, region) -> None: """Returns whether state can access the given region name.""" return state.can_reach(f"Go To {region}", "Entrance", self.player) - def _can_get(self, state, location) -> None: """Returns whether state can access the given location name.""" return state.can_reach(location, "Location", self.player) - def _is_location_available( self, location: Union[str, DS3LocationData, DarkSouls3Location] @@ -1333,14 +1310,12 @@ def _is_location_available( ) ) - def write_spoiler(self, spoiler_handle: TextIO) -> None: if self.yhorm_location != default_yhorm_location: spoiler_handle.write( f"Yhorm takes the place of {self.yhorm_location.name} in " + f"{self.multiworld.get_player_name(self.player)}'s world\n") - def post_fill(self): """If item smoothing is enabled, rearrange items so they scale up smoothly through the run. @@ -1455,14 +1430,12 @@ def smooth_items(item_order: List[Union[DS3ItemData, DarkSouls3Item]]) -> None: upgraded_weapons.sort(key=lambda item: item.level) smooth_items(upgraded_weapons) - def _shuffle(self, seq: Sequence) -> List: """Returns a shuffled copy of a sequence.""" copy = list(seq) self.random.shuffle(copy) return copy - def _pop_item( self, location: Location, @@ -1481,7 +1454,6 @@ def _pop_item( # If we can't find a suitable item, give up and assign an unsuitable one. return items.pop(0) - def fill_slot_data(self) -> Dict[str, object]: slot_data: Dict[str, object] = {}