The Messenger: Fix precollected notes not being removed from the itempool (#3066)
* The Messenger: fix precollected notes not being properly removed from pool * The Messenger: bump required client version
This commit is contained in:
		
							parent
							
								
									72c53513f8
								
							
						
					
					
						commit
						4e3d396394
					
				|  | @ -1,4 +1,5 @@ | ||||||
| import logging | import logging | ||||||
|  | from datetime import date | ||||||
| from typing import Any, ClassVar, Dict, List, Optional, TextIO | from typing import Any, ClassVar, Dict, List, Optional, TextIO | ||||||
| 
 | 
 | ||||||
| from BaseClasses import CollectionState, Entrance, Item, ItemClassification, MultiWorld, Tutorial | from BaseClasses import CollectionState, Entrance, Item, ItemClassification, MultiWorld, Tutorial | ||||||
|  | @ -9,7 +10,8 @@ from worlds.AutoWorld import WebWorld, World | ||||||
| from worlds.LauncherComponents import Component, Type, components | from worlds.LauncherComponents import Component, Type, components | ||||||
| from .client_setup import launch_game | from .client_setup import launch_game | ||||||
| from .connections import CONNECTIONS, RANDOMIZED_CONNECTIONS, TRANSITIONS | from .connections import CONNECTIONS, RANDOMIZED_CONNECTIONS, TRANSITIONS | ||||||
| from .constants import ALL_ITEMS, ALWAYS_LOCATIONS, BOSS_LOCATIONS, FILLER, NOTES, PHOBEKINS, PROG_ITEMS, USEFUL_ITEMS | from .constants import ALL_ITEMS, ALWAYS_LOCATIONS, BOSS_LOCATIONS, FILLER, NOTES, PHOBEKINS, PROG_ITEMS, TRAPS, \ | ||||||
|  |     USEFUL_ITEMS | ||||||
| from .options import AvailablePortals, Goal, Logic, MessengerOptions, NotesNeeded, ShuffleTransitions | from .options import AvailablePortals, Goal, Logic, MessengerOptions, NotesNeeded, ShuffleTransitions | ||||||
| from .portals import PORTALS, add_closed_portal_reqs, disconnect_portals, shuffle_portals, validate_portals | from .portals import PORTALS, add_closed_portal_reqs, disconnect_portals, shuffle_portals, validate_portals | ||||||
| from .regions import LEVELS, MEGA_SHARDS, LOCATIONS, REGION_CONNECTIONS | from .regions import LEVELS, MEGA_SHARDS, LOCATIONS, REGION_CONNECTIONS | ||||||
|  | @ -110,7 +112,7 @@ class MessengerWorld(World): | ||||||
|         }, |         }, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     required_client_version = (0, 4, 3) |     required_client_version = (0, 4, 4) | ||||||
| 
 | 
 | ||||||
|     web = MessengerWeb() |     web = MessengerWeb() | ||||||
| 
 | 
 | ||||||
|  | @ -127,6 +129,7 @@ class MessengerWorld(World): | ||||||
|     portal_mapping: List[int] |     portal_mapping: List[int] | ||||||
|     transitions: List[Entrance] |     transitions: List[Entrance] | ||||||
|     reachable_locs: int = 0 |     reachable_locs: int = 0 | ||||||
|  |     filler: Dict[str, int] | ||||||
| 
 | 
 | ||||||
|     def generate_early(self) -> None: |     def generate_early(self) -> None: | ||||||
|         if self.options.goal == Goal.option_power_seal_hunt: |         if self.options.goal == Goal.option_power_seal_hunt: | ||||||
|  | @ -146,8 +149,9 @@ class MessengerWorld(World): | ||||||
|         self.starting_portals = [f"{portal} Portal" |         self.starting_portals = [f"{portal} Portal" | ||||||
|                                  for portal in starting_portals[:3] + |                                  for portal in starting_portals[:3] + | ||||||
|                                  self.random.sample(starting_portals[3:], k=self.options.available_portals - 3)] |                                  self.random.sample(starting_portals[3:], k=self.options.available_portals - 3)] | ||||||
|  | 
 | ||||||
|         # super complicated method for adding searing crags to starting portals if it wasn't chosen |         # super complicated method for adding searing crags to starting portals if it wasn't chosen | ||||||
|         # need to add a check for transition shuffle when that gets added back in |         # TODO add a check for transition shuffle when that gets added back in | ||||||
|         if not self.options.shuffle_portals and "Searing Crags Portal" not in self.starting_portals: |         if not self.options.shuffle_portals and "Searing Crags Portal" not in self.starting_portals: | ||||||
|             self.starting_portals.append("Searing Crags Portal") |             self.starting_portals.append("Searing Crags Portal") | ||||||
|             if len(self.starting_portals) > 4: |             if len(self.starting_portals) > 4: | ||||||
|  | @ -155,6 +159,10 @@ class MessengerWorld(World): | ||||||
|                                     if portal in self.starting_portals] |                                     if portal in self.starting_portals] | ||||||
|                 self.starting_portals.remove(self.random.choice(portals_to_strip)) |                 self.starting_portals.remove(self.random.choice(portals_to_strip)) | ||||||
| 
 | 
 | ||||||
|  |         self.filler = FILLER.copy() | ||||||
|  |         if (not hasattr(self.options, "traps") and date.today() < date(2024, 4, 2)) or self.options.traps: | ||||||
|  |             self.filler.update(TRAPS) | ||||||
|  | 
 | ||||||
|         self.plando_portals = [] |         self.plando_portals = [] | ||||||
|         self.portal_mapping = [] |         self.portal_mapping = [] | ||||||
|         self.spoiler_portal_mapping = {} |         self.spoiler_portal_mapping = {} | ||||||
|  | @ -182,12 +190,13 @@ class MessengerWorld(World): | ||||||
|     def create_items(self) -> None: |     def create_items(self) -> None: | ||||||
|         # create items that are always in the item pool |         # create items that are always in the item pool | ||||||
|         main_movement_items = ["Rope Dart", "Wingsuit"] |         main_movement_items = ["Rope Dart", "Wingsuit"] | ||||||
|  |         precollected_names = [item.name for item in self.multiworld.precollected_items[self.player]] | ||||||
|         itempool: List[MessengerItem] = [ |         itempool: List[MessengerItem] = [ | ||||||
|             self.create_item(item) |             self.create_item(item) | ||||||
|             for item in self.item_name_to_id |             for item in self.item_name_to_id | ||||||
|             if "Time Shard" not in item and item not in { |             if item not in { | ||||||
|                 "Power Seal", *NOTES, *FIGURINES, *main_movement_items, |                 "Power Seal", *NOTES, *FIGURINES, *main_movement_items, | ||||||
|                 *{collected_item.name for collected_item in self.multiworld.precollected_items[self.player]}, |                 *precollected_names, *FILLER, *TRAPS, | ||||||
|             } |             } | ||||||
|         ] |         ] | ||||||
| 
 | 
 | ||||||
|  | @ -199,7 +208,7 @@ class MessengerWorld(World): | ||||||
|         if self.options.goal == Goal.option_open_music_box: |         if self.options.goal == Goal.option_open_music_box: | ||||||
|             # make a list of all notes except those in the player's defined starting inventory, and adjust the |             # make a list of all notes except those in the player's defined starting inventory, and adjust the | ||||||
|             # amount we need to put in the itempool and precollect based on that |             # amount we need to put in the itempool and precollect based on that | ||||||
|             notes = [note for note in NOTES if note not in self.multiworld.precollected_items[self.player]] |             notes = [note for note in NOTES if note not in precollected_names] | ||||||
|             self.random.shuffle(notes) |             self.random.shuffle(notes) | ||||||
|             precollected_notes_amount = NotesNeeded.range_end - \ |             precollected_notes_amount = NotesNeeded.range_end - \ | ||||||
|                                         self.options.notes_needed - \ |                                         self.options.notes_needed - \ | ||||||
|  | @ -228,8 +237,8 @@ class MessengerWorld(World): | ||||||
|         remaining_fill = len(self.multiworld.get_unfilled_locations(self.player)) - len(itempool) |         remaining_fill = len(self.multiworld.get_unfilled_locations(self.player)) - len(itempool) | ||||||
|         if remaining_fill < 10: |         if remaining_fill < 10: | ||||||
|             self._filler_items = self.random.choices( |             self._filler_items = self.random.choices( | ||||||
|                 list(FILLER)[2:], |                 list(self.filler)[2:], | ||||||
|                 weights=list(FILLER.values())[2:], |                 weights=list(self.filler.values())[2:], | ||||||
|                 k=remaining_fill |                 k=remaining_fill | ||||||
|             ) |             ) | ||||||
|         filler = [self.create_filler() for _ in range(remaining_fill)] |         filler = [self.create_filler() for _ in range(remaining_fill)] | ||||||
|  | @ -300,8 +309,8 @@ class MessengerWorld(World): | ||||||
|     def get_filler_item_name(self) -> str: |     def get_filler_item_name(self) -> str: | ||||||
|         if not getattr(self, "_filler_items", None): |         if not getattr(self, "_filler_items", None): | ||||||
|             self._filler_items = [name for name in self.random.choices( |             self._filler_items = [name for name in self.random.choices( | ||||||
|                 list(FILLER), |                 list(self.filler), | ||||||
|                 weights=list(FILLER.values()), |                 weights=list(self.filler.values()), | ||||||
|                 k=20 |                 k=20 | ||||||
|             )] |             )] | ||||||
|         return self._filler_items.pop(0) |         return self._filler_items.pop(0) | ||||||
|  | @ -336,6 +345,9 @@ class MessengerWorld(World): | ||||||
|         if name in {*USEFUL_ITEMS, *USEFUL_SHOP_ITEMS}: |         if name in {*USEFUL_ITEMS, *USEFUL_SHOP_ITEMS}: | ||||||
|             return ItemClassification.useful |             return ItemClassification.useful | ||||||
|          |          | ||||||
|  |         if name in TRAPS: | ||||||
|  |             return ItemClassification.trap | ||||||
|  | 
 | ||||||
|         return ItemClassification.filler |         return ItemClassification.filler | ||||||
| 
 | 
 | ||||||
|     def collect(self, state: "CollectionState", item: "Item") -> bool: |     def collect(self, state: "CollectionState", item: "Item") -> bool: | ||||||
|  |  | ||||||
|  | @ -48,6 +48,11 @@ FILLER = { | ||||||
|     "Time Shard (500)": 5, |     "Time Shard (500)": 5, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | TRAPS = { | ||||||
|  |     "Teleport Trap": 5, | ||||||
|  |     "Prophecy Trap": 10, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| # item_name_to_id needs to be deterministic and match upstream | # item_name_to_id needs to be deterministic and match upstream | ||||||
| ALL_ITEMS = [ | ALL_ITEMS = [ | ||||||
|     *NOTES, |     *NOTES, | ||||||
|  | @ -71,6 +76,8 @@ ALL_ITEMS = [ | ||||||
|     *SHOP_ITEMS, |     *SHOP_ITEMS, | ||||||
|     *FIGURINES, |     *FIGURINES, | ||||||
|     "Money Wrench", |     "Money Wrench", | ||||||
|  |     "Teleport Trap", | ||||||
|  |     "Prophecy Trap", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| # locations | # locations | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| from dataclasses import dataclass | from dataclasses import dataclass | ||||||
|  | from datetime import date | ||||||
| from typing import Dict | from typing import Dict | ||||||
| 
 | 
 | ||||||
| from schema import And, Optional, Or, Schema | from schema import And, Optional, Or, Schema | ||||||
|  | @ -123,6 +124,11 @@ class RequiredSeals(Range): | ||||||
|     default = range_end |     default = range_end | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class Traps(Toggle): | ||||||
|  |     """Whether traps should be included in the itempool.""" | ||||||
|  |     display_name = "Include Traps" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class ShopPrices(Range): | class ShopPrices(Range): | ||||||
|     """Percentage modifier for shuffled item prices in shops""" |     """Percentage modifier for shuffled item prices in shops""" | ||||||
|     display_name = "Shop Prices Modifier" |     display_name = "Shop Prices Modifier" | ||||||
|  | @ -199,3 +205,6 @@ class MessengerOptions(DeathLinkMixin, PerGameCommonOptions): | ||||||
|     percent_seals_required: RequiredSeals |     percent_seals_required: RequiredSeals | ||||||
|     shop_price: ShopPrices |     shop_price: ShopPrices | ||||||
|     shop_price_plan: PlannedShopPrices |     shop_price_plan: PlannedShopPrices | ||||||
|  | 
 | ||||||
|  |     if date.today() > date(2024, 4, 1): | ||||||
|  |         traps: Traps | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue