diff --git a/BaseClasses.py b/BaseClasses.py index b8955500..8d641b0b 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1115,13 +1115,15 @@ class Location: self.parent_region = parent def can_fill(self, state: CollectionState, item: Item, check_access=True) -> bool: - return self.always_allow(state, item) or (self.item_rule(item) and (not check_access or self.can_reach(state))) + return (self.always_allow(state, item) + or ((self.progress_type != LocationProgressType.EXCLUDED or not (item.advancement or item.useful)) + and self.item_rule(item) + and (not check_access or self.can_reach(state)))) def can_reach(self, state: CollectionState) -> bool: # self.access_rule computes faster on average, so placing it first for faster abort - if self.access_rule(state) and self.parent_region.can_reach(state): - return True - return False + assert self.parent_region, "Can't reach location without region" + return self.access_rule(state) and self.parent_region.can_reach(state) def place_locked_item(self, item: Item): if self.item: diff --git a/docs/world api.md b/docs/world api.md index a43d61e5..d95627dd 100644 --- a/docs/world api.md +++ b/docs/world api.md @@ -102,7 +102,7 @@ Locations are places where items can be located in your game. This may be chests or boss drops for RPG-like games but could also be progress in a research tree. Each location has a `name` and an `id` (a.k.a. "code" or "address"), is placed -in a Region and has access rules. +in a Region, has access rules and a classification. The name needs to be unique in each game and must not be numeric (has to contain least 1 letter or symbol). The ID needs to be unique across all games and is best in the same range as the item IDs. @@ -110,6 +110,10 @@ World-specific IDs are 1 to 253-1, IDs ≤ 0 are global and reserved. Special locations with ID `None` can hold events. +Classification is one of `LocationProgressType.DEFAULT`, `PRIORITY` or `EXCLUDED`. +The Fill algorithm will fill priority first, giving higher chance of it being +required, and not place progression or useful items in excluded locations. + ### Items Items are all things that can "drop" for your game. This may be RPG items like diff --git a/worlds/generic/Rules.py b/worlds/generic/Rules.py index 865dc395..98fb560a 100644 --- a/worlds/generic/Rules.py +++ b/worlds/generic/Rules.py @@ -89,7 +89,6 @@ def exclusion_rules(world: MultiWorld, player: int, exclude_locations: typing.Se if loc_name not in world.worlds[player].location_name_to_id: raise Exception(f"Unable to exclude location {loc_name} in player {player}'s world.") from e else: - add_item_rule(location, lambda i: not (i.advancement or i.useful)) location.progress_type = LocationProgressType.EXCLUDED diff --git a/worlds/pokemon_rb/regions.py b/worlds/pokemon_rb/regions.py index 5141f06c..9640e0a8 100644 --- a/worlds/pokemon_rb/regions.py +++ b/worlds/pokemon_rb/regions.py @@ -14,7 +14,6 @@ def create_region(world: MultiWorld, player: int, name: str, locations_per_regio ret.locations.append(location) if world.randomize_hidden_items[player].value == 2 and "Hidden" in location.name: location.progress_type = LocationProgressType.EXCLUDED - add_item_rule(location, lambda i: not (i.advancement or i.useful)) if exits: for exit in exits: ret.exits.append(Entrance(player, exit, ret)) diff --git a/worlds/soe/__init__.py b/worlds/soe/__init__.py index 864d2daa..f45508bf 100644 --- a/worlds/soe/__init__.py +++ b/worlds/soe/__init__.py @@ -242,7 +242,6 @@ class SoEWorld(World): for location in self.multiworld.random.sample(spheres[trash_sphere][typ], count): assert location.name != "Energy Core #285", "Error in sphere generation" location.progress_type = LocationProgressType.EXCLUDED - # TODO: do we need to set an item rule? def sphere1_blocked_items_rule(item): if isinstance(item, SoEItem):