| 
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 |  |  | from dataclasses import dataclass | 
					
						
							| 
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 |  |  | from schema import And, Optional, Or, Schema | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-22 08:40:50 -05:00
										 |  |  | from Options import ( | 
					
						
							|  |  |  |     Choice, DeathLinkMixin, DefaultOnToggle, ItemsAccessibility, OptionDict, OptionGroup, | 
					
						
							|  |  |  |     PerGameCommonOptions, | 
					
						
							|  |  |  |     PlandoConnections, Range, StartInventoryPool, Toggle, | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2025-03-10 10:16:09 -05:00
										 |  |  | from . import RANDOMIZED_CONNECTIONS | 
					
						
							| 
									
										
										
										
											2024-06-11 00:42:57 +02:00
										 |  |  | from .portals import CHECKPOINTS, PORTALS, SHOP_POINTS | 
					
						
							| 
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-31 05:13:14 -05:00
										 |  |  | class MessengerAccessibility(ItemsAccessibility): | 
					
						
							| 
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 |  |  |     # defaulting to locations accessibility since items makes certain items self-locking | 
					
						
							| 
									
										
										
										
											2024-07-31 05:13:14 -05:00
										 |  |  |     default = ItemsAccessibility.option_full | 
					
						
							|  |  |  |     __doc__ = ItemsAccessibility.__doc__ | 
					
						
							| 
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-01 06:34:41 -05:00
										 |  |  | class PortalPlando(PlandoConnections): | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2025-04-10 12:13:38 -05:00
										 |  |  |     Plando connections to be used with portal shuffle. | 
					
						
							|  |  |  |     Documentation on using this can be found in The Messenger plando guide. | 
					
						
							| 
									
										
										
										
											2024-06-01 06:34:41 -05:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2025-03-19 14:52:14 -05:00
										 |  |  |     display_name = "Portal Plando Connections" | 
					
						
							| 
									
										
										
										
											2024-06-01 06:34:41 -05:00
										 |  |  |     portals = [f"{portal} Portal" for portal in PORTALS] | 
					
						
							|  |  |  |     shop_points = [point for points in SHOP_POINTS.values() for point in points] | 
					
						
							|  |  |  |     checkpoints = [point for points in CHECKPOINTS.values() for point in points] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-10 10:16:09 -05:00
										 |  |  |     entrances = frozenset(PORTALS) | 
					
						
							|  |  |  |     exits = frozenset(portals + shop_points + checkpoints) | 
					
						
							| 
									
										
										
										
											2024-06-01 06:34:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-10 10:16:09 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TransitionPlando(PlandoConnections): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Plando connections to be used with transition shuffle. | 
					
						
							| 
									
										
										
										
											2025-04-10 12:13:38 -05:00
										 |  |  |     Documentation on using this can be found in The Messenger plando guide. | 
					
						
							| 
									
										
										
										
											2025-03-10 10:16:09 -05:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2025-03-19 14:52:14 -05:00
										 |  |  |     display_name = "Transition Plando Connections" | 
					
						
							| 
									
										
										
										
											2025-03-10 10:16:09 -05:00
										 |  |  |     entrances = frozenset(RANDOMIZED_CONNECTIONS.keys()) | 
					
						
							|  |  |  |     exits = frozenset(RANDOMIZED_CONNECTIONS.values()) | 
					
						
							| 
									
										
										
										
											2024-06-01 06:34:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-10 21:13:49 -05:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def can_connect(cls, entrance: str, exit: str) -> bool: | 
					
						
							|  |  |  |         if entrance != "Glacial Peak - Left" and entrance.lower() in cls.exits: | 
					
						
							|  |  |  |             return exit.lower() in cls.entrances | 
					
						
							|  |  |  |         return exit.lower() not in cls.entrances | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-01 06:34:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-21 15:21:27 -05:00
										 |  |  | class Logic(Choice): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     The level of logic to use when determining what locations in your world are accessible. | 
					
						
							| 
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-22 08:40:50 -05:00
										 |  |  |     **Normal:** Can require damage boosts, but otherwise approachable for someone who has beaten the game. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     **Hard:** Expects more knowledge and tighter execution. | 
					
						
							|  |  |  |     Has leashing, normal clips and much tighter d-boosting in logic. | 
					
						
							| 
									
										
										
										
											2023-03-21 15:21:27 -05:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     display_name = "Logic Level" | 
					
						
							|  |  |  |     option_normal = 0 | 
					
						
							|  |  |  |     option_hard = 1 | 
					
						
							| 
									
										
										
										
											2024-03-11 17:23:41 -05:00
										 |  |  |     alias_oob = 1 | 
					
						
							| 
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 |  |  |     alias_challenging = 1 | 
					
						
							| 
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-06 03:48:30 -05:00
										 |  |  | class MegaShards(Toggle): | 
					
						
							|  |  |  |     """Whether mega shards should be item locations.""" | 
					
						
							|  |  |  |     display_name = "Shuffle Mega Time Shards" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 17:23:41 -05:00
										 |  |  | class LimitedMovement(Toggle): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Removes either rope dart or wingsuit from the itempool. Forces logic to at least hard and accessibility to minimal. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     display_name = "Limited Movement" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class EarlyMed(Toggle): | 
					
						
							|  |  |  |     """Guarantees meditation will be found early""" | 
					
						
							|  |  |  |     display_name = "Early Meditation" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AvailablePortals(Range): | 
					
						
							| 
									
										
										
										
											2025-05-22 08:40:50 -05:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     Number of portals that are available from the start. Autumn Hills, Howling Grotto, and Glacial Peak are always | 
					
						
							|  |  |  |     available. If portal outputs are not randomized, Searing Crags will also be available. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2024-03-11 17:23:41 -05:00
										 |  |  |     display_name = "Available Starting Portals" | 
					
						
							|  |  |  |     range_start = 3 | 
					
						
							|  |  |  |     range_end = 6 | 
					
						
							|  |  |  |     default = 6 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ShufflePortals(Choice): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Whether the portals lead to random places. | 
					
						
							|  |  |  |     Entering a portal from its vanilla area will always lead to HQ, and will unlock it if relevant. | 
					
						
							|  |  |  |     Supports plando. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-22 08:40:50 -05:00
										 |  |  |     **None:** Portals will take you where they're supposed to. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     **Shops:** Portals can lead to any area except Music Box and Elemental Skylands, with each portal output guaranteed | 
					
						
							|  |  |  |     to not overlap with another portal's. Will only put you at a portal or a shop. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     **Checkpoints:** Like Shops except checkpoints without shops are also valid drop points. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     **Anywhere:** Like Checkpoints except it's possible for multiple portals to output to the same map. | 
					
						
							| 
									
										
										
										
											2024-03-11 17:23:41 -05:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     display_name = "Shuffle Portal Outputs" | 
					
						
							|  |  |  |     option_none = 0 | 
					
						
							|  |  |  |     alias_off = 0 | 
					
						
							|  |  |  |     option_shops = 1 | 
					
						
							|  |  |  |     option_checkpoints = 2 | 
					
						
							|  |  |  |     option_anywhere = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ShuffleTransitions(Choice): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Whether the transitions between the levels should be randomized. | 
					
						
							|  |  |  |     Supports plando. | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2025-05-22 08:40:50 -05:00
										 |  |  |     **None:** Level transitions lead where they should. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     **Coupled:** Returning through a transition will take you from whence you came. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     **Decoupled:** Any level transition can take you to any other level transition. | 
					
						
							| 
									
										
										
										
											2024-03-11 17:23:41 -05:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     display_name = "Shuffle Level Transitions" | 
					
						
							|  |  |  |     option_none = 0 | 
					
						
							|  |  |  |     alias_off = 0 | 
					
						
							|  |  |  |     option_coupled = 1 | 
					
						
							|  |  |  |     option_decoupled = 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 |  |  | class Goal(Choice): | 
					
						
							| 
									
										
										
										
											2025-05-22 08:40:50 -05:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     Requirement to finish the game. | 
					
						
							|  |  |  |     To win with the power seal hunt goal, you must enter the Music Box through the shop chest. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 |  |  |     display_name = "Goal" | 
					
						
							|  |  |  |     option_open_music_box = 0 | 
					
						
							|  |  |  |     option_power_seal_hunt = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MusicBox(DefaultOnToggle): | 
					
						
							|  |  |  |     """Whether the music box gauntlet needs to be done.""" | 
					
						
							|  |  |  |     display_name = "Music Box Gauntlet" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class NotesNeeded(Range): | 
					
						
							| 
									
										
										
										
											2025-04-10 12:03:05 -05:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2025-05-22 08:40:50 -05:00
										 |  |  |     How many notes need to be found in order to access the Music Box. | 
					
						
							|  |  |  |     6 are always needed to enter, so this places the others in your start inventory. | 
					
						
							| 
									
										
										
										
											2025-04-10 12:03:05 -05:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 |  |  |     display_name = "Notes Needed" | 
					
						
							|  |  |  |     range_start = 1 | 
					
						
							|  |  |  |     range_end = 6 | 
					
						
							|  |  |  |     default = range_end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AmountSeals(Range): | 
					
						
							|  |  |  |     """Number of power seals that exist in the item pool when power seal hunt is the goal.""" | 
					
						
							|  |  |  |     display_name = "Total Power Seals" | 
					
						
							|  |  |  |     range_start = 1 | 
					
						
							| 
									
										
										
										
											2023-04-06 03:48:30 -05:00
										 |  |  |     range_end = 85 | 
					
						
							|  |  |  |     default = 45 | 
					
						
							| 
									
										
										
										
											2023-03-12 09:05:50 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RequiredSeals(Range): | 
					
						
							|  |  |  |     """Percentage of total seals required to open the shop chest.""" | 
					
						
							|  |  |  |     display_name = "Percent Seals Required" | 
					
						
							|  |  |  |     range_start = 10 | 
					
						
							|  |  |  |     range_end = 100 | 
					
						
							|  |  |  |     default = range_end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-31 10:47:11 -05:00
										 |  |  | class Traps(Toggle): | 
					
						
							|  |  |  |     """Whether traps should be included in the itempool.""" | 
					
						
							|  |  |  |     display_name = "Include Traps" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 |  |  | class ShopPrices(Range): | 
					
						
							|  |  |  |     """Percentage modifier for shuffled item prices in shops""" | 
					
						
							|  |  |  |     display_name = "Shop Prices Modifier" | 
					
						
							|  |  |  |     range_start = 25 | 
					
						
							|  |  |  |     range_end = 400 | 
					
						
							|  |  |  |     default = 100 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-27 03:28:00 +01:00
										 |  |  | def planned_price(location: str) -> dict[Optional, Or]: | 
					
						
							| 
									
										
										
										
											2023-06-27 18:39:52 -05:00
										 |  |  |     return { | 
					
						
							|  |  |  |         Optional(location): Or( | 
					
						
							|  |  |  |             And(int, lambda n: n >= 0), | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 Optional(And(int, lambda n: n >= 0)): And(int, lambda n: n >= 0) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PlannedShopPrices(OptionDict): | 
					
						
							|  |  |  |     """Plan specific prices on shop slots. Supports weighting""" | 
					
						
							|  |  |  |     display_name = "Shop Price Plando" | 
					
						
							|  |  |  |     schema = Schema({ | 
					
						
							|  |  |  |         **planned_price("Karuta Plates"), | 
					
						
							|  |  |  |         **planned_price("Serendipitous Bodies"), | 
					
						
							|  |  |  |         **planned_price("Path of Resilience"), | 
					
						
							|  |  |  |         **planned_price("Kusari Jacket"), | 
					
						
							|  |  |  |         **planned_price("Energy Shuriken"), | 
					
						
							|  |  |  |         **planned_price("Serendipitous Minds"), | 
					
						
							|  |  |  |         **planned_price("Prepared Mind"), | 
					
						
							|  |  |  |         **planned_price("Meditation"), | 
					
						
							|  |  |  |         **planned_price("Rejuvenative Spirit"), | 
					
						
							|  |  |  |         **planned_price("Centered Mind"), | 
					
						
							|  |  |  |         **planned_price("Strike of the Ninja"), | 
					
						
							|  |  |  |         **planned_price("Second Wind"), | 
					
						
							|  |  |  |         **planned_price("Currents Master"), | 
					
						
							|  |  |  |         **planned_price("Aerobatics Warrior"), | 
					
						
							|  |  |  |         **planned_price("Demon's Bane"), | 
					
						
							|  |  |  |         **planned_price("Devil's Due"), | 
					
						
							|  |  |  |         **planned_price("Time Sense"), | 
					
						
							|  |  |  |         **planned_price("Power Sense"), | 
					
						
							|  |  |  |         **planned_price("Focused Power Sense"), | 
					
						
							|  |  |  |         **planned_price("Green Kappa Figurine"), | 
					
						
							|  |  |  |         **planned_price("Blue Kappa Figurine"), | 
					
						
							|  |  |  |         **planned_price("Ountarde Figurine"), | 
					
						
							|  |  |  |         **planned_price("Red Kappa Figurine"), | 
					
						
							|  |  |  |         **planned_price("Demon King Figurine"), | 
					
						
							|  |  |  |         **planned_price("Quillshroom Figurine"), | 
					
						
							|  |  |  |         **planned_price("Jumping Quillshroom Figurine"), | 
					
						
							|  |  |  |         **planned_price("Scurubu Figurine"), | 
					
						
							|  |  |  |         **planned_price("Jumping Scurubu Figurine"), | 
					
						
							|  |  |  |         **planned_price("Wallaxer Figurine"), | 
					
						
							|  |  |  |         **planned_price("Barmath'azel Figurine"), | 
					
						
							|  |  |  |         **planned_price("Queen of Quills Figurine"), | 
					
						
							|  |  |  |         **planned_price("Demon Hive Figurine"), | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 |  |  | @dataclass | 
					
						
							| 
									
										
										
										
											2024-03-03 07:11:44 -06:00
										 |  |  | class MessengerOptions(DeathLinkMixin, PerGameCommonOptions): | 
					
						
							| 
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 |  |  |     accessibility: MessengerAccessibility | 
					
						
							|  |  |  |     start_inventory: StartInventoryPool | 
					
						
							|  |  |  |     logic_level: Logic | 
					
						
							|  |  |  |     shuffle_shards: MegaShards | 
					
						
							| 
									
										
										
										
											2024-03-11 17:23:41 -05:00
										 |  |  |     limited_movement: LimitedMovement | 
					
						
							|  |  |  |     early_meditation: EarlyMed | 
					
						
							|  |  |  |     available_portals: AvailablePortals | 
					
						
							|  |  |  |     shuffle_portals: ShufflePortals | 
					
						
							| 
									
										
										
										
											2025-03-10 10:16:09 -05:00
										 |  |  |     shuffle_transitions: ShuffleTransitions | 
					
						
							| 
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 |  |  |     goal: Goal | 
					
						
							|  |  |  |     music_box: MusicBox | 
					
						
							|  |  |  |     notes_needed: NotesNeeded | 
					
						
							|  |  |  |     total_seals: AmountSeals | 
					
						
							|  |  |  |     percent_seals_required: RequiredSeals | 
					
						
							| 
									
										
										
										
											2024-04-18 11:59:30 -05:00
										 |  |  |     traps: Traps | 
					
						
							| 
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 |  |  |     shop_price: ShopPrices | 
					
						
							|  |  |  |     shop_price_plan: PlannedShopPrices | 
					
						
							| 
									
										
										
										
											2024-06-01 06:34:41 -05:00
										 |  |  |     portal_plando: PortalPlando | 
					
						
							| 
									
										
										
										
											2025-03-10 10:16:09 -05:00
										 |  |  |     plando_connections: TransitionPlando | 
					
						
							| 
									
										
										
										
											2025-05-22 08:40:50 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | option_groups = [ | 
					
						
							|  |  |  |     OptionGroup( | 
					
						
							|  |  |  |         "Difficulty", | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             EarlyMed, | 
					
						
							|  |  |  |             Logic, | 
					
						
							|  |  |  |             LimitedMovement, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     OptionGroup( | 
					
						
							|  |  |  |         "Goal", | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             Goal, | 
					
						
							|  |  |  |             MusicBox, | 
					
						
							|  |  |  |             NotesNeeded, | 
					
						
							|  |  |  |             AmountSeals, | 
					
						
							|  |  |  |             RequiredSeals, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     OptionGroup( | 
					
						
							|  |  |  |         "Entrances", | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             AvailablePortals, | 
					
						
							|  |  |  |             ShufflePortals, | 
					
						
							|  |  |  |             ShuffleTransitions, | 
					
						
							|  |  |  |             PortalPlando, | 
					
						
							|  |  |  |             TransitionPlando, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  | ] |