diff options
Diffstat (limited to 'player_logic.py')
-rw-r--r-- | player_logic.py | 106 |
1 files changed, 60 insertions, 46 deletions
diff --git a/player_logic.py b/player_logic.py index 966f5a1..96e9869 100644 --- a/player_logic.py +++ b/player_logic.py | |||
@@ -1,12 +1,13 @@ | |||
1 | from enum import Enum | 1 | from enum import Enum |
2 | from typing import Dict, List, NamedTuple, Optional, Set, Tuple, TYPE_CHECKING | 2 | from typing import Dict, List, NamedTuple, Optional, Set, Tuple, TYPE_CHECKING |
3 | 3 | ||
4 | from .datatypes import Door, RoomAndDoor, RoomAndPanel | 4 | from .datatypes import Door, DoorType, RoomAndDoor, RoomAndPanel |
5 | from .items import ALL_ITEM_TABLE, ItemData | 5 | from .items import ALL_ITEM_TABLE, ItemType |
6 | from .locations import ALL_LOCATION_TABLE, LocationClassification | 6 | from .locations import ALL_LOCATION_TABLE, LocationClassification |
7 | from .options import LocationChecks, ShuffleDoors, VictoryCondition | 7 | from .options import LocationChecks, ShuffleDoors, SunwarpAccess, VictoryCondition |
8 | from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \ | 8 | from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \ |
9 | PANELS_BY_ROOM, PROGRESSION_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS | 9 | PANELS_BY_ROOM, PROGRESSION_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS, \ |
10 | SUNWARP_ENTRANCES, SUNWARP_EXITS | ||
10 | 11 | ||
11 | if TYPE_CHECKING: | 12 | if TYPE_CHECKING: |
12 | from . import LingoWorld | 13 | from . import LingoWorld |
@@ -58,21 +59,6 @@ def should_split_progression(progression_name: str, world: "LingoWorld") -> Prog | |||
58 | return ProgressiveItemBehavior.PROGRESSIVE | 59 | return ProgressiveItemBehavior.PROGRESSIVE |
59 | 60 | ||
60 | 61 | ||
61 | def should_include_item(item: ItemData, world: "LingoWorld") -> bool: | ||
62 | if item.mode == "colors": | ||
63 | return world.options.shuffle_colors > 0 | ||
64 | elif item.mode == "doors": | ||
65 | return world.options.shuffle_doors != ShuffleDoors.option_none | ||
66 | elif item.mode == "complex door": | ||
67 | return world.options.shuffle_doors == ShuffleDoors.option_complex | ||
68 | elif item.mode == "door group": | ||
69 | return world.options.shuffle_doors == ShuffleDoors.option_simple | ||
70 | elif item.mode == "special": | ||
71 | return False | ||
72 | else: | ||
73 | return True | ||
74 | |||
75 | |||
76 | class LingoPlayerLogic: | 62 | class LingoPlayerLogic: |
77 | """ | 63 | """ |
78 | Defines logic after a player's options have been applied | 64 | Defines logic after a player's options have been applied |
@@ -99,6 +85,10 @@ class LingoPlayerLogic: | |||
99 | mastery_reqs: List[AccessRequirements] | 85 | mastery_reqs: List[AccessRequirements] |
100 | counting_panel_reqs: Dict[str, List[Tuple[AccessRequirements, int]]] | 86 | counting_panel_reqs: Dict[str, List[Tuple[AccessRequirements, int]]] |
101 | 87 | ||
88 | sunwarp_mapping: List[int] | ||
89 | sunwarp_entrances: List[str] | ||
90 | sunwarp_exits: List[str] | ||
91 | |||
102 | def add_location(self, room: str, name: str, code: Optional[int], panels: List[RoomAndPanel], world: "LingoWorld"): | 92 | def add_location(self, room: str, name: str, code: Optional[int], panels: List[RoomAndPanel], world: "LingoWorld"): |
103 | """ | 93 | """ |
104 | Creates a location. This function determines the access requirements for the location by combining and | 94 | Creates a location. This function determines the access requirements for the location by combining and |
@@ -132,6 +122,7 @@ class LingoPlayerLogic: | |||
132 | self.real_items.append(progressive_item_name) | 122 | self.real_items.append(progressive_item_name) |
133 | else: | 123 | else: |
134 | self.set_door_item(room_name, door_data.name, door_data.item_name) | 124 | self.set_door_item(room_name, door_data.name, door_data.item_name) |
125 | self.real_items.append(door_data.item_name) | ||
135 | 126 | ||
136 | def __init__(self, world: "LingoWorld"): | 127 | def __init__(self, world: "LingoWorld"): |
137 | self.item_by_door = {} | 128 | self.item_by_door = {} |
@@ -148,6 +139,7 @@ class LingoPlayerLogic: | |||
148 | self.door_reqs = {} | 139 | self.door_reqs = {} |
149 | self.mastery_reqs = [] | 140 | self.mastery_reqs = [] |
150 | self.counting_panel_reqs = {} | 141 | self.counting_panel_reqs = {} |
142 | self.sunwarp_mapping = [] | ||
151 | 143 | ||
152 | door_shuffle = world.options.shuffle_doors | 144 | door_shuffle = world.options.shuffle_doors |
153 | color_shuffle = world.options.shuffle_colors | 145 | color_shuffle = world.options.shuffle_colors |
@@ -161,15 +153,37 @@ class LingoPlayerLogic: | |||
161 | "be enough locations for all of the door items.") | 153 | "be enough locations for all of the door items.") |
162 | 154 | ||
163 | # Create door items, where needed. | 155 | # Create door items, where needed. |
164 | if door_shuffle != ShuffleDoors.option_none: | 156 | door_groups: Set[str] = set() |
165 | for room_name, room_data in DOORS_BY_ROOM.items(): | 157 | for room_name, room_data in DOORS_BY_ROOM.items(): |
166 | for door_name, door_data in room_data.items(): | 158 | for door_name, door_data in room_data.items(): |
167 | if door_data.skip_item is False and door_data.event is False: | 159 | if door_data.skip_item is False and door_data.event is False: |
160 | if door_data.type == DoorType.NORMAL and door_shuffle != ShuffleDoors.option_none: | ||
168 | if door_data.door_group is not None and door_shuffle == ShuffleDoors.option_simple: | 161 | if door_data.door_group is not None and door_shuffle == ShuffleDoors.option_simple: |
169 | # Grouped doors are handled differently if shuffle doors is on simple. | 162 | # Grouped doors are handled differently if shuffle doors is on simple. |
170 | self.set_door_item(room_name, door_name, door_data.door_group) | 163 | self.set_door_item(room_name, door_name, door_data.door_group) |
164 | door_groups.add(door_data.door_group) | ||
171 | else: | 165 | else: |
172 | self.handle_non_grouped_door(room_name, door_data, world) | 166 | self.handle_non_grouped_door(room_name, door_data, world) |
167 | elif door_data.type == DoorType.SUNWARP: | ||
168 | if world.options.sunwarp_access == SunwarpAccess.option_unlock: | ||
169 | self.set_door_item(room_name, door_name, "Sunwarps") | ||
170 | door_groups.add("Sunwarps") | ||
171 | elif world.options.sunwarp_access == SunwarpAccess.option_individual: | ||
172 | self.set_door_item(room_name, door_name, door_data.item_name) | ||
173 | self.real_items.append(door_data.item_name) | ||
174 | elif world.options.sunwarp_access == SunwarpAccess.option_progressive: | ||
175 | self.set_door_item(room_name, door_name, "Progressive Pilgrimage") | ||
176 | self.real_items.append("Progressive Pilgrimage") | ||
177 | elif door_data.type == DoorType.SUN_PAINTING: | ||
178 | if not world.options.enable_pilgrimage: | ||
179 | self.set_door_item(room_name, door_name, door_data.item_name) | ||
180 | self.real_items.append(door_data.item_name) | ||
181 | |||
182 | self.real_items += door_groups | ||
183 | |||
184 | # Create color items, if needed. | ||
185 | if color_shuffle: | ||
186 | self.real_items += [name for name, item in ALL_ITEM_TABLE.items() if item.type == ItemType.COLOR] | ||
173 | 187 | ||
174 | # Create events for each achievement panel, so that we can determine when THE MASTER is accessible. | 188 | # Create events for each achievement panel, so that we can determine when THE MASTER is accessible. |
175 | for room_name, room_data in PANELS_BY_ROOM.items(): | 189 | for room_name, room_data in PANELS_BY_ROOM.items(): |
@@ -206,6 +220,11 @@ class LingoPlayerLogic: | |||
206 | 220 | ||
207 | if world.options.level_2_requirement == 1: | 221 | if world.options.level_2_requirement == 1: |
208 | raise Exception("The Level 2 requirement must be at least 2 when LEVEL 2 is the victory condition.") | 222 | raise Exception("The Level 2 requirement must be at least 2 when LEVEL 2 is the victory condition.") |
223 | elif victory_condition == VictoryCondition.option_pilgrimage: | ||
224 | self.victory_condition = "Pilgrim Antechamber - PILGRIM" | ||
225 | self.add_location("Pilgrim Antechamber", "PILGRIM (Solved)", None, | ||
226 | [RoomAndPanel("Pilgrim Antechamber", "PILGRIM")], world) | ||
227 | self.event_loc_to_item["PILGRIM (Solved)"] = "Victory" | ||
209 | 228 | ||
210 | # Create groups of counting panel access requirements for the LEVEL 2 check. | 229 | # Create groups of counting panel access requirements for the LEVEL 2 check. |
211 | self.create_panel_hunt_events(world) | 230 | self.create_panel_hunt_events(world) |
@@ -225,28 +244,22 @@ class LingoPlayerLogic: | |||
225 | self.add_location(location_data.room, location_name, location_data.code, location_data.panels, world) | 244 | self.add_location(location_data.room, location_name, location_data.code, location_data.panels, world) |
226 | self.real_locations.append(location_name) | 245 | self.real_locations.append(location_name) |
227 | 246 | ||
228 | # Instantiate all real items. | 247 | if world.options.enable_pilgrimage and world.options.sunwarp_access == SunwarpAccess.option_disabled: |
229 | for name, item in ALL_ITEM_TABLE.items(): | 248 | raise Exception("Sunwarps cannot be disabled when pilgrimage is enabled.") |
230 | if should_include_item(item, world): | 249 | |
231 | self.real_items.append(name) | 250 | if world.options.shuffle_sunwarps: |
232 | 251 | if world.options.sunwarp_access == SunwarpAccess.option_disabled: | |
233 | # Calculate the requirements for the fake pilgrimage. | 252 | raise Exception("Sunwarps cannot be shuffled if they are disabled.") |
234 | fake_pilgrimage = [ | 253 | |
235 | ["Second Room", "Exit Door"], ["Crossroads", "Tower Entrance"], | 254 | self.sunwarp_mapping = list(range(0, 12)) |
236 | ["Orange Tower Fourth Floor", "Hot Crusts Door"], ["Outside The Initiated", "Shortcut to Hub Room"], | 255 | world.random.shuffle(self.sunwarp_mapping) |
237 | ["Orange Tower First Floor", "Shortcut to Hub Room"], ["Directional Gallery", "Shortcut to The Undeterred"], | 256 | |
238 | ["Orange Tower First Floor", "Salt Pepper Door"], ["Hub Room", "Crossroads Entrance"], | 257 | sunwarp_rooms = SUNWARP_ENTRANCES + SUNWARP_EXITS |
239 | ["Color Hunt", "Shortcut to The Steady"], ["The Bearer", "Entrance"], ["Art Gallery", "Exit"], | 258 | self.sunwarp_entrances = [sunwarp_rooms[i] for i in self.sunwarp_mapping[0:6]] |
240 | ["The Tenacious", "Shortcut to Hub Room"], ["Outside The Agreeable", "Tenacious Entrance"] | 259 | self.sunwarp_exits = [sunwarp_rooms[i] for i in self.sunwarp_mapping[6:12]] |
241 | ] | 260 | else: |
242 | pilgrimage_reqs = AccessRequirements() | 261 | self.sunwarp_entrances = SUNWARP_ENTRANCES |
243 | for door in fake_pilgrimage: | 262 | self.sunwarp_exits = SUNWARP_EXITS |
244 | door_object = DOORS_BY_ROOM[door[0]][door[1]] | ||
245 | if door_object.event or world.options.shuffle_doors == ShuffleDoors.option_none: | ||
246 | pilgrimage_reqs.merge(self.calculate_door_requirements(door[0], door[1], world)) | ||
247 | else: | ||
248 | pilgrimage_reqs.doors.add(RoomAndDoor(door[0], door[1])) | ||
249 | self.door_reqs.setdefault("Pilgrim Antechamber", {})["Pilgrimage"] = pilgrimage_reqs | ||
250 | 263 | ||
251 | # Create the paintings mapping, if painting shuffle is on. | 264 | # Create the paintings mapping, if painting shuffle is on. |
252 | if painting_shuffle: | 265 | if painting_shuffle: |
@@ -277,10 +290,11 @@ class LingoPlayerLogic: | |||
277 | # Starting Room - Exit Door gives access to OPEN and TRACE. | 290 | # Starting Room - Exit Door gives access to OPEN and TRACE. |
278 | good_item_options: List[str] = ["Starting Room - Back Right Door", "Second Room - Exit Door"] | 291 | good_item_options: List[str] = ["Starting Room - Back Right Door", "Second Room - Exit Door"] |
279 | 292 | ||
280 | if not color_shuffle: | 293 | if not color_shuffle and not world.options.enable_pilgrimage: |
281 | # HOT CRUST and THIS. | 294 | # HOT CRUST and THIS. |
282 | good_item_options.append("Pilgrim Room - Sun Painting") | 295 | good_item_options.append("Pilgrim Room - Sun Painting") |
283 | 296 | ||
297 | if not color_shuffle: | ||
284 | if door_shuffle == ShuffleDoors.option_simple: | 298 | if door_shuffle == ShuffleDoors.option_simple: |
285 | # WELCOME BACK, CLOCKWISE, and DRAWL + RUNS. | 299 | # WELCOME BACK, CLOCKWISE, and DRAWL + RUNS. |
286 | good_item_options.append("Welcome Back Doors") | 300 | good_item_options.append("Welcome Back Doors") |