2023-07-24 19:41:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from functools import cached_property
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from typing import Optional, TYPE_CHECKING, cast
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-24 19:41:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from BaseClasses import CollectionState, Item, ItemClassification, Location, Region
							 | 
						
					
						
							
								
									
										
										
										
											2023-10-08 07:33:39 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from .constants import NOTES, PHOBEKINS, PROG_ITEMS, USEFUL_ITEMS
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from .options import Goal
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from .regions import MEGA_SHARDS, REGIONS, SEALS
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from .shop import FIGURINES, PROG_SHOP_ITEMS, SHOP_ITEMS, USEFUL_SHOP_ITEMS
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								if TYPE_CHECKING:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    from . import MessengerWorld
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								class MessengerRegion(Region):
							 | 
						
					
						
							
								
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def __init__(self, name: str, world: "MessengerWorld") -> None:
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        super().__init__(name, world.player, world.multiworld)
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-22 00:45:46 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        locations = [loc for loc in REGIONS[self.name]]
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if self.name == "The Shop":
							 | 
						
					
						
							
								
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if world.options.goal > Goal.option_open_music_box:
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-22 00:45:46 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                locations.append("Shop Chest")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            shop_locations = {f"The Shop - {shop_loc}": world.location_name_to_id[f"The Shop - {shop_loc}"]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                              for shop_loc in SHOP_ITEMS}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            shop_locations.update(**{figurine: world.location_name_to_id[figurine] for figurine in FIGURINES})
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.add_locations(shop_locations, MessengerShopLocation)
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        elif self.name == "Tower HQ":
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-22 00:45:46 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            locations.append("Money Wrench")
							 | 
						
					
						
							
								
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if world.options.shuffle_seals and self.name in SEALS:
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-22 00:45:46 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            locations += [seal_loc for seal_loc in SEALS[self.name]]
							 | 
						
					
						
							
								
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if world.options.shuffle_shards and self.name in MEGA_SHARDS:
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-22 00:45:46 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            locations += [shard for shard in MEGA_SHARDS[self.name]]
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-24 19:41:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        loc_dict = {loc: world.location_name_to_id[loc] if loc in world.location_name_to_id else None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    for loc in locations}
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-22 00:45:46 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.add_locations(loc_dict, MessengerLocation)
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								class MessengerLocation(Location):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    game = "The Messenger"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-22 00:45:46 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def __init__(self, player: int, name: str, loc_id: Optional[int], parent: MessengerRegion) -> None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        super().__init__(player, name, loc_id, parent)
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if loc_id is None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.place_locked_item(MessengerItem(name, parent.player, None))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								class MessengerShopLocation(MessengerLocation):
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-24 19:41:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    @cached_property
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def cost(self) -> int:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        name = self.name.replace("The Shop - ", "")  # TODO use `remove_prefix` when 3.8 finally gets dropped
							 | 
						
					
						
							
								
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        world = cast("MessengerWorld", self.parent_region.multiworld.worlds[self.player])
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-24 19:41:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # short circuit figurines which all require demon's bane be purchased, but nothing else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if "Figurine" in name:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return world.figurine_prices[name] +\
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                cast(MessengerShopLocation, world.multiworld.get_location("The Shop - Demon's Bane", self.player)).cost
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        shop_data = SHOP_ITEMS[name]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if shop_data.prerequisite:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            prereq_cost = 0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if isinstance(shop_data.prerequisite, set):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                for prereq in shop_data.prerequisite:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    prereq_cost +=\
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        cast(MessengerShopLocation,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                             world.multiworld.get_location(prereq, self.player)).cost
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                prereq_cost +=\
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    cast(MessengerShopLocation,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                         world.multiworld.get_location(shop_data.prerequisite, self.player)).cost
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return world.shop_prices[name] + prereq_cost
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return world.shop_prices[name]
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def can_afford(self, state: CollectionState) -> bool:
							 | 
						
					
						
							
								
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        world = cast("MessengerWorld", state.multiworld.worlds[self.player])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        can_afford = state.has("Shards", self.player, min(self.cost, world.total_shards))
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if "Figurine" in self.name:
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-24 19:41:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            can_afford = state.has("Money Wrench", self.player) and can_afford\
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-18 22:01:44 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                and state.can_reach("Money Wrench", "Location", self.player)
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return can_afford
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								class MessengerItem(Item):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    game = "The Messenger"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def __init__(self, name: str, player: int, item_id: Optional[int] = None, override_progression: bool = False,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                 count: int = 0) -> None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if count:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            item_class = ItemClassification.progression_skip_balancing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elif item_id is None or override_progression or name in {*NOTES, *PROG_ITEMS, *PHOBEKINS, *PROG_SHOP_ITEMS}:
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            item_class = ItemClassification.progression
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        elif name in {*USEFUL_ITEMS, *USEFUL_SHOP_ITEMS}:
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            item_class = ItemClassification.useful
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            item_class = ItemClassification.filler
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        super().__init__(name, item_class, item_id, player)
							 |