Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: CollectionState - Never pick up advancements #3786

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
29 changes: 16 additions & 13 deletions BaseClasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,11 +436,11 @@ def get_all_state(self, use_cache: bool) -> CollectionState:
ret = CollectionState(self)

for item in self.itempool:
self.worlds[item.player].collect(ret, item)
ret.collect(item, prevent_sweep=True)
for player in self.player_ids:
subworld = self.worlds[player]
for item in subworld.get_pre_fill_items():
subworld.collect(ret, item)
ret.collect(item, prevent_sweep=True)
ret.sweep_for_advancements()

if use_cache:
Expand Down Expand Up @@ -909,26 +909,29 @@ def count_group_unique(self, item_name_group: str, player: int) -> int:
)

# Item related
def collect(self, item: Item, prevent_sweep: bool = False, location: Optional[Location] = None) -> bool:
def collect(self, item: Item, prevent_sweep: bool = False, location: Optional[Location] = None):
if location:
self.locations_checked.add(location)

changed = self.multiworld.worlds[item.player].collect(self, item)
if not item.advancement:
return

self.multiworld.worlds[item.player].collect(self, item)
self.stale[item.player] = True

if changed and not prevent_sweep:
if not prevent_sweep:
self.sweep_for_advancements()

return changed

def remove(self, item: Item):
changed = self.multiworld.worlds[item.player].remove(self, item)
if changed:
# invalidate caches, nothing can be trusted anymore now
self.reachable_regions[item.player] = set()
self.blocked_connections[item.player] = set()
self.stale[item.player] = True
if not item.advancement:
return

self.multiworld.worlds[item.player].remove(self, item)

# invalidate caches, nothing can be trusted anymore now
self.reachable_regions[item.player] = set()
self.blocked_connections[item.player] = set()
self.stale[item.player] = True


class Entrance:
Expand Down
31 changes: 14 additions & 17 deletions worlds/AutoWorld.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,18 +484,15 @@ def create_group(cls, multiworld: "MultiWorld", new_player_id: int, players: Set

return group

# decent place to implement progressive items, in most cases can stay as-is
def collect_item(self, state: "CollectionState", item: "Item", remove: bool = False) -> Optional[str]:
def collect_item(self, state: "CollectionState", item: "Item", remove: bool = False) -> str:
"""
Collect an item name into state. For speed reasons items that aren't logically useful get skipped.
Collect None to skip item.
Collect an item name into state.
Decent place to implement progressive items, i.e. convert "Progressive Sword" into "Fighter's Sword"
:param state: CollectionState to collect into
:param item: Item to decide on if it should be collected into state
:param remove: indicate if this is meant to remove from state instead of adding.
"""
if item.advancement:
return item.name
return None
return item.name

def get_pre_fill_items(self) -> List["Item"]:
"""
Expand All @@ -506,22 +503,22 @@ def get_pre_fill_items(self) -> List["Item"]:

# these two methods can be extended for pseudo-items on state
def collect(self, state: "CollectionState", item: "Item") -> bool:
assert item.advancement, "Collect should no longer be called with non-advancements."

NewSoupVi marked this conversation as resolved.
Show resolved Hide resolved
"""Called when an item is collected in to state. Useful for things such as progressive items or currency."""
name = self.collect_item(state, item)
if name:
state.prog_items[self.player][name] += 1
return True
return False
state.prog_items[self.player][name] += 1
return True # Backwards compatibility, this used to denote whether a progression item was picked up

def remove(self, state: "CollectionState", item: "Item") -> bool:
assert item.advancement, "Remove should no longer be called with non-advancements."

"""Called when an item is removed from to state. Useful for things such as progressive items or currency."""
name = self.collect_item(state, item, True)
if name:
state.prog_items[self.player][name] -= 1
if state.prog_items[self.player][name] < 1:
del (state.prog_items[self.player][name])
return True
return False
state.prog_items[self.player][name] -= 1
if state.prog_items[self.player][name] < 1:
del (state.prog_items[self.player][name])
Comment on lines +519 to +520
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3.10 should mean this is fine now?

Suggested change
if state.prog_items[self.player][name] < 1:
del (state.prog_items[self.player][name])

return True # Backwards compatibility, this used to denote whether a progression item was removed

# following methods should not need to be overridden.
def create_filler(self) -> "Item":
Expand Down
2 changes: 1 addition & 1 deletion worlds/alttp/Dungeons.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ def fill_dungeons_restrictive(multiworld: MultiWorld):
in_dungeon_player_ids = {item.player for item in in_dungeon_items}
all_state_base = CollectionState(multiworld)
for item in multiworld.itempool:
multiworld.worlds[item.player].collect(all_state_base, item)
all_state_base.collect(item, prevent_sweep=True)
pre_fill_items = []
for player in in_dungeon_player_ids:
pre_fill_items += multiworld.worlds[player].get_pre_fill_items()
Expand Down
2 changes: 1 addition & 1 deletion worlds/factorio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ def generate_basic(self):
start_location_hints.add(loc.name)

def collect_item(self, state, item, remove=False):
if item.advancement and item.name in progressive_technology_table:
if item.name in progressive_technology_table:
prog_table = progressive_technology_table[item.name].progressive
if remove:
for item_name in reversed(prog_table):
Expand Down
6 changes: 3 additions & 3 deletions worlds/oot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ def pre_fill(self):
def prefill_state(base_state):
state = base_state.copy()
for item in self.get_pre_fill_items():
self.collect(state, item)
state.collect(item, prevent_sweep=True)
state.sweep_for_advancements(locations=self.get_locations())
return state

Expand All @@ -892,7 +892,7 @@ def prefill_state(base_state):
# Set up initial state
state = CollectionState(self.multiworld)
for item in self.itempool:
self.collect(state, item)
state.collect(item, prevent_sweep=True)
state.sweep_for_advancements(locations=self.get_locations())

# Place dungeon items
Expand Down Expand Up @@ -1382,7 +1382,7 @@ def is_major_item(self, item: OOTItem):
def get_state_with_complete_itempool(self):
all_state = CollectionState(self.multiworld)
for item in self.itempool + self.pre_fill_items:
self.multiworld.worlds[item.player].collect(all_state, item)
all_state.collect(item, prevent_sweep=True)
# If free_scarecrow give Scarecrow Song
if self.free_scarecrow:
all_state.collect(self.create_item("Scarecrow Song"), prevent_sweep=True)
Expand Down
2 changes: 0 additions & 2 deletions worlds/raft/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,6 @@ def create_resourcePack(self, rpName: str) -> Item:
return RaftItem(rpName, ItemClassification.filler, self.item_name_to_id[rpName], player=self.player)

def collect_item(self, state, item, remove=False):
if item.advancement is False:
return None
if item.name in progressive_item_list:
prog_table = progressive_item_list[item.name]
if remove:
Expand Down
2 changes: 1 addition & 1 deletion worlds/smz3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def create_items(self):
# Dungeons items here are not in the itempool and will be prefilled locally so they must stay local
self.options.non_local_items.value -= frozenset(item_name for item_name in self.item_names if TotalSMZ3Item.Item.IsNameDungeonItem(item_name))
for item in self.keyCardsItems:
self.multiworld.push_precollected(SMZ3Item(item.Type.name, ItemClassification.filler, item.Type, self.item_name_to_id[item.Type.name], self.player, item))
self.multiworld.push_precollected(SMZ3Item(item.Type.name, ItemClassification.progression, item.Type, self.item_name_to_id[item.Type.name], self.player, item))

itemPool = [SMZ3Item(item.Type.name, ItemClassification.progression, item.Type, self.item_name_to_id[item.Type.name], self.player, item) for item in progressionItems] + \
[SMZ3Item(item.Type.name, ItemClassification.useful, item.Type, self.item_name_to_id[item.Type.name], self.player, item) for item in niceItems] + \
Expand Down
Loading