diff options
| -rw-r--r-- | __init__.py | 3 | ||||
| -rw-r--r-- | data/LL1.yaml | 694 | ||||
| -rw-r--r-- | data/generated.dat | bin | 136563 -> 148903 bytes | |||
| -rw-r--r-- | data/ids.yaml | 142 | ||||
| -rw-r--r-- | datatypes.py | 11 | ||||
| -rw-r--r-- | items.py | 17 | ||||
| -rw-r--r-- | options.py | 29 | ||||
| -rw-r--r-- | player_logic.py | 121 | ||||
| -rw-r--r-- | rules.py | 10 | ||||
| -rw-r--r-- | static_logic.py | 32 | ||||
| -rw-r--r-- | test/TestDoors.py | 56 | ||||
| -rw-r--r-- | test/TestOptions.py | 17 | ||||
| -rw-r--r-- | test/TestOrangeTower.py | 2 | ||||
| -rw-r--r-- | test/TestPanelsanity.py | 2 | ||||
| -rw-r--r-- | test/TestPilgrimage.py | 8 | ||||
| -rw-r--r-- | test/TestProgressive.py | 7 | ||||
| -rw-r--r-- | test/TestSunwarps.py | 21 | ||||
| -rw-r--r-- | utils/assign_ids.rb | 40 | ||||
| -rw-r--r-- | utils/pickle_static_data.py | 124 | ||||
| -rw-r--r-- | utils/validate_config.rb | 88 | 
20 files changed, 1274 insertions, 150 deletions
| diff --git a/__init__.py b/__init__.py index a1b8b7c..9853be7 100644 --- a/__init__.py +++ b/__init__.py | |||
| @@ -170,7 +170,8 @@ class LingoWorld(World): | |||
| 170 | slot_options = [ | 170 | slot_options = [ | 
| 171 | "death_link", "victory_condition", "shuffle_colors", "shuffle_doors", "shuffle_paintings", "shuffle_panels", | 171 | "death_link", "victory_condition", "shuffle_colors", "shuffle_doors", "shuffle_paintings", "shuffle_panels", | 
| 172 | "enable_pilgrimage", "sunwarp_access", "mastery_achievements", "level_2_requirement", "location_checks", | 172 | "enable_pilgrimage", "sunwarp_access", "mastery_achievements", "level_2_requirement", "location_checks", | 
| 173 | "early_color_hallways", "pilgrimage_allows_roof_access", "pilgrimage_allows_paintings", "shuffle_sunwarps" | 173 | "early_color_hallways", "pilgrimage_allows_roof_access", "pilgrimage_allows_paintings", "shuffle_sunwarps", | 
| 174 | "group_doors" | ||
| 174 | ] | 175 | ] | 
| 175 | 176 | ||
| 176 | slot_data = { | 177 | slot_data = { | 
| diff --git a/data/LL1.yaml b/data/LL1.yaml index 3035446..1c9f4e5 100644 --- a/data/LL1.yaml +++ b/data/LL1.yaml | |||
| @@ -1,6 +1,13 @@ | |||
| 1 | --- | 1 | --- | 
| 2 | # This file is an associative array where the keys are region names. Rooms | 2 | # This file is an associative array where the keys are region names. Rooms | 
| 3 | # have four properties: entrances, panels, doors, and paintings. | 3 | # have a number of properties: | 
| 4 | # - entrances | ||
| 5 | # - panels | ||
| 6 | # - doors | ||
| 7 | # - panel_doors | ||
| 8 | # - paintings | ||
| 9 | # - progression | ||
| 10 | # - sunwarps | ||
| 4 | # | 11 | # | 
| 5 | # entrances is an array of regions from which this room can be accessed. The | 12 | # entrances is an array of regions from which this room can be accessed. The | 
| 6 | # key of each entry is the room that can access this one. The value is a list | 13 | # key of each entry is the room that can access this one. The value is a list | 
| @@ -13,7 +20,7 @@ | |||
| 13 | # room that the door is in. The room name may be omitted if the door is | 20 | # room that the door is in. The room name may be omitted if the door is | 
| 14 | # located in the current room. | 21 | # located in the current room. | 
| 15 | # | 22 | # | 
| 16 | # panels is an array of panels in the room. The key of the array is an | 23 | # panels is a named array of panels in the room. The key of the array is an | 
| 17 | # arbitrary name for the panel. Panels can have the following fields: | 24 | # arbitrary name for the panel. Panels can have the following fields: | 
| 18 | # - id: The internal ID of the panel in the LINGO map | 25 | # - id: The internal ID of the panel in the LINGO map | 
| 19 | # - required_room: In addition to having access to this room, the player must | 26 | # - required_room: In addition to having access to this room, the player must | 
| @@ -45,7 +52,7 @@ | |||
| 45 | # - hunt: If True, the tracker will show this panel even when it is | 52 | # - hunt: If True, the tracker will show this panel even when it is | 
| 46 | # not a check. Used for hunts like the Number Hunt. | 53 | # not a check. Used for hunts like the Number Hunt. | 
| 47 | # | 54 | # | 
| 48 | # doors is an array of doors associated with this room. When door | 55 | # doors is a named array of doors associated with this room. When door | 
| 49 | # randomization is enabled, each of these is an item. The key is a name that | 56 | # randomization is enabled, each of these is an item. The key is a name that | 
| 50 | # will be displayed as part of the item's name. Doors can have the following | 57 | # will be displayed as part of the item's name. Doors can have the following | 
| 51 | # fields: | 58 | # fields: | 
| @@ -78,6 +85,18 @@ | |||
| 78 | # - event: Denotes that the door is event only. This is similar to | 85 | # - event: Denotes that the door is event only. This is similar to | 
| 79 | # setting both skip_location and skip_item. | 86 | # setting both skip_location and skip_item. | 
| 80 | # | 87 | # | 
| 88 | # panel_doors is a named array of "panel doors" associated with this room. | ||
| 89 | # When panel door shuffle is enabled, each of these becomes an item, and those | ||
| 90 | # items block access to the listed panels. The key is a name for internal | ||
| 91 | # reference only. Panel doors can have the following fields: | ||
| 92 | # - panels: Required. This is the set of panels that are blocked by this | ||
| 93 | # panel door. | ||
| 94 | # - item_name: Overrides the name of the item generated for this panel | ||
| 95 | # door. If not specified, the item name will be generated from | ||
| 96 | # the room name and the name(s) of the panel(s). | ||
| 97 | # - panel_group: When region grouping is enabled, all panel doors with the | ||
| 98 | # same group will be covered by a single item. | ||
| 99 | # | ||
| 81 | # paintings is an array of paintings in the room. This is used for painting | 100 | # paintings is an array of paintings in the room. This is used for painting | 
| 82 | # shuffling. | 101 | # shuffling. | 
| 83 | # - id: The internal painting ID from the LINGO map. | 102 | # - id: The internal painting ID from the LINGO map. | 
| @@ -105,6 +124,14 @@ | |||
| 105 | # fine in door shuffle mode. | 124 | # fine in door shuffle mode. | 
| 106 | # - move: Denotes that the painting is able to move. | 125 | # - move: Denotes that the painting is able to move. | 
| 107 | # | 126 | # | 
| 127 | # progression is a named array of items that define an ordered set of items. | ||
| 128 | # progression items do not have any true connection to the rooms that they | ||
| 129 | # are defined in, but it is best to place them in a thematically appropriate | ||
| 130 | # room. The key for a progression entry is the name of the item that will be | ||
| 131 | # created. A progression entry is a dictionary with one or both of a "doors" | ||
| 132 | # key and a "panel_doors" key. These fields should be lists of doors or | ||
| 133 | # panel doors that will be contained in this progressive item. | ||
| 134 | # | ||
| 108 | # sunwarps is an array of sunwarps in the room. This is used for sunwarp | 135 | # sunwarps is an array of sunwarps in the room. This is used for sunwarp | 
| 109 | # shuffling. | 136 | # shuffling. | 
| 110 | # - dots: The number of dots on this sunwarp. | 137 | # - dots: The number of dots on this sunwarp. | 
| @@ -193,6 +220,10 @@ | |||
| 193 | panel: RACECAR (Black) | 220 | panel: RACECAR (Black) | 
| 194 | - room: The Tenacious | 221 | - room: The Tenacious | 
| 195 | panel: SOLOS (Black) | 222 | panel: SOLOS (Black) | 
| 223 | panel_doors: | ||
| 224 | HIDDEN: | ||
| 225 | panels: | ||
| 226 | - HIDDEN | ||
| 196 | paintings: | 227 | paintings: | 
| 197 | - id: arrows_painting | 228 | - id: arrows_painting | 
| 198 | exit_only: True | 229 | exit_only: True | 
| @@ -303,6 +334,10 @@ | |||
| 303 | panel: SOLOS (Black) | 334 | panel: SOLOS (Black) | 
| 304 | - room: Hub Room | 335 | - room: Hub Room | 
| 305 | panel: RAT | 336 | panel: RAT | 
| 337 | panel_doors: | ||
| 338 | OPEN: | ||
| 339 | panels: | ||
| 340 | - OPEN | ||
| 306 | paintings: | 341 | paintings: | 
| 307 | - id: owl_painting | 342 | - id: owl_painting | 
| 308 | orientation: north | 343 | orientation: north | 
| @@ -317,7 +352,13 @@ | |||
| 317 | panels: | 352 | panels: | 
| 318 | Achievement: | 353 | Achievement: | 
| 319 | id: Countdown Panels/Panel_seeker_seeker | 354 | id: Countdown Panels/Panel_seeker_seeker | 
| 320 | required_room: Hidden Room | 355 | # The Seeker uniquely has the property that 1) it can be entered (through the Pilgrim Room) without opening the | 
| 356 | # front door in panels mode door shuffle, and 2) the front door panel is part of the CDP. This necessitates this | ||
| 357 | # required_panel clause, because the entrance panel needs to be solvable for the achievement even if an | ||
| 358 | # alternate entrance to the room is used. | ||
| 359 | required_panel: | ||
| 360 | room: Hidden Room | ||
| 361 | panel: OPEN | ||
| 321 | tag: forbid | 362 | tag: forbid | 
| 322 | check: True | 363 | check: True | 
| 323 | achievement: The Seeker | 364 | achievement: The Seeker | 
| @@ -537,6 +578,23 @@ | |||
| 537 | item_group: Achievement Room Entrances | 578 | item_group: Achievement Room Entrances | 
| 538 | panels: | 579 | panels: | 
| 539 | - OPEN | 580 | - OPEN | 
| 581 | panel_doors: | ||
| 582 | ORDER: | ||
| 583 | panels: | ||
| 584 | - ORDER | ||
| 585 | SLAUGHTER: | ||
| 586 | panel_group: Tenacious Entrance Panels | ||
| 587 | panels: | ||
| 588 | - SLAUGHTER | ||
| 589 | TRACE: | ||
| 590 | panels: | ||
| 591 | - TRACE | ||
| 592 | RAT: | ||
| 593 | panels: | ||
| 594 | - RAT | ||
| 595 | OPEN: | ||
| 596 | panels: | ||
| 597 | - OPEN | ||
| 540 | paintings: | 598 | paintings: | 
| 541 | - id: maze_painting | 599 | - id: maze_painting | 
| 542 | orientation: west | 600 | orientation: west | 
| @@ -608,12 +666,13 @@ | |||
| 608 | item_name: "6 Sunwarp" | 666 | item_name: "6 Sunwarp" | 
| 609 | progression: | 667 | progression: | 
| 610 | Progressive Pilgrimage: | 668 | Progressive Pilgrimage: | 
| 611 | - 1 Sunwarp | 669 | doors: | 
| 612 | - 2 Sunwarp | 670 | - 1 Sunwarp | 
| 613 | - 3 Sunwarp | 671 | - 2 Sunwarp | 
| 614 | - 4 Sunwarp | 672 | - 3 Sunwarp | 
| 615 | - 5 Sunwarp | 673 | - 4 Sunwarp | 
| 616 | - 6 Sunwarp | 674 | - 5 Sunwarp | 
| 675 | - 6 Sunwarp | ||
| 617 | Pilgrim Antechamber: | 676 | Pilgrim Antechamber: | 
| 618 | # The entrances to this room are special. When pilgrimage is enabled, we use a special access rule to determine | 677 | # The entrances to this room are special. When pilgrimage is enabled, we use a special access rule to determine | 
| 619 | # whether a pilgrimage can succeed. When pilgrimage is disabled, the sun painting will be added to the pool. | 678 | # whether a pilgrimage can succeed. When pilgrimage is disabled, the sun painting will be added to the pool. | 
| @@ -881,6 +940,24 @@ | |||
| 881 | panel: READS + RUST | 940 | panel: READS + RUST | 
| 882 | - room: Ending Area | 941 | - room: Ending Area | 
| 883 | panel: THE END | 942 | panel: THE END | 
| 943 | panel_doors: | ||
| 944 | DECAY: | ||
| 945 | panel_group: Tenacious Entrance Panels | ||
| 946 | panels: | ||
| 947 | - DECAY | ||
| 948 | NOPE: | ||
| 949 | panels: | ||
| 950 | - NOPE | ||
| 951 | WE ROT: | ||
| 952 | panels: | ||
| 953 | - WE ROT | ||
| 954 | WORDS SWORD: | ||
| 955 | panels: | ||
| 956 | - WORDS | ||
| 957 | - SWORD | ||
| 958 | BEND HI: | ||
| 959 | panels: | ||
| 960 | - BEND HI | ||
| 884 | paintings: | 961 | paintings: | 
| 885 | - id: eye_painting | 962 | - id: eye_painting | 
| 886 | disable: True | 963 | disable: True | 
| @@ -895,6 +972,14 @@ | |||
| 895 | direction: exit | 972 | direction: exit | 
| 896 | entrance_indicator_pos: [ -17, 2.5, -41.01 ] | 973 | entrance_indicator_pos: [ -17, 2.5, -41.01 ] | 
| 897 | orientation: north | 974 | orientation: north | 
| 975 | progression: | ||
| 976 | Progressive Suits Area: | ||
| 977 | panel_doors: | ||
| 978 | - WORDS SWORD | ||
| 979 | - room: Lost Area | ||
| 980 | panel_door: LOST | ||
| 981 | - room: Amen Name Area | ||
| 982 | panel_door: AMEN NAME | ||
| 898 | Lost Area: | 983 | Lost Area: | 
| 899 | entrances: | 984 | entrances: | 
| 900 | Outside The Agreeable: | 985 | Outside The Agreeable: | 
| @@ -920,6 +1005,11 @@ | |||
| 920 | panels: | 1005 | panels: | 
| 921 | - LOST (1) | 1006 | - LOST (1) | 
| 922 | - LOST (2) | 1007 | - LOST (2) | 
| 1008 | panel_doors: | ||
| 1009 | LOST: | ||
| 1010 | panels: | ||
| 1011 | - LOST (1) | ||
| 1012 | - LOST (2) | ||
| 923 | Amen Name Area: | 1013 | Amen Name Area: | 
| 924 | entrances: | 1014 | entrances: | 
| 925 | Crossroads: | 1015 | Crossroads: | 
| @@ -953,6 +1043,11 @@ | |||
| 953 | panels: | 1043 | panels: | 
| 954 | - AMEN | 1044 | - AMEN | 
| 955 | - NAME | 1045 | - NAME | 
| 1046 | panel_doors: | ||
| 1047 | AMEN NAME: | ||
| 1048 | panels: | ||
| 1049 | - AMEN | ||
| 1050 | - NAME | ||
| 956 | Suits Area: | 1051 | Suits Area: | 
| 957 | entrances: | 1052 | entrances: | 
| 958 | Amen Name Area: | 1053 | Amen Name Area: | 
| @@ -1056,6 +1151,13 @@ | |||
| 1056 | - LEVEL (White) | 1151 | - LEVEL (White) | 
| 1057 | - RACECAR (White) | 1152 | - RACECAR (White) | 
| 1058 | - SOLOS (White) | 1153 | - SOLOS (White) | 
| 1154 | panel_doors: | ||
| 1155 | Black Palindromes: | ||
| 1156 | item_name: The Tenacious - Black Palindromes (Panels) | ||
| 1157 | panels: | ||
| 1158 | - LEVEL (Black) | ||
| 1159 | - RACECAR (Black) | ||
| 1160 | - SOLOS (Black) | ||
| 1059 | Near Far Area: | 1161 | Near Far Area: | 
| 1060 | entrances: | 1162 | entrances: | 
| 1061 | Hub Room: True | 1163 | Hub Room: True | 
| @@ -1081,6 +1183,21 @@ | |||
| 1081 | panels: | 1183 | panels: | 
| 1082 | - NEAR | 1184 | - NEAR | 
| 1083 | - FAR | 1185 | - FAR | 
| 1186 | panel_doors: | ||
| 1187 | NEAR FAR: | ||
| 1188 | item_name: Symmetry Room - NEAR, FAR (Panels) | ||
| 1189 | panel_group: Symmetry Room Panels | ||
| 1190 | panels: | ||
| 1191 | - NEAR | ||
| 1192 | - FAR | ||
| 1193 | progression: | ||
| 1194 | Progressive Symmetry Room: | ||
| 1195 | panel_doors: | ||
| 1196 | - NEAR FAR | ||
| 1197 | - room: Warts Straw Area | ||
| 1198 | panel_door: WARTS STRAW | ||
| 1199 | - room: Leaf Feel Area | ||
| 1200 | panel_door: LEAF FEEL | ||
| 1084 | Warts Straw Area: | 1201 | Warts Straw Area: | 
| 1085 | entrances: | 1202 | entrances: | 
| 1086 | Near Far Area: | 1203 | Near Far Area: | 
| @@ -1108,6 +1225,13 @@ | |||
| 1108 | panels: | 1225 | panels: | 
| 1109 | - WARTS | 1226 | - WARTS | 
| 1110 | - STRAW | 1227 | - STRAW | 
| 1228 | panel_doors: | ||
| 1229 | WARTS STRAW: | ||
| 1230 | item_name: Symmetry Room - WARTS, STRAW (Panels) | ||
| 1231 | panel_group: Symmetry Room Panels | ||
| 1232 | panels: | ||
| 1233 | - WARTS | ||
| 1234 | - STRAW | ||
| 1111 | Leaf Feel Area: | 1235 | Leaf Feel Area: | 
| 1112 | entrances: | 1236 | entrances: | 
| 1113 | Warts Straw Area: | 1237 | Warts Straw Area: | 
| @@ -1135,6 +1259,13 @@ | |||
| 1135 | panels: | 1259 | panels: | 
| 1136 | - LEAF | 1260 | - LEAF | 
| 1137 | - FEEL | 1261 | - FEEL | 
| 1262 | panel_doors: | ||
| 1263 | LEAF FEEL: | ||
| 1264 | item_name: Symmetry Room - LEAF, FEEL (Panels) | ||
| 1265 | panel_group: Symmetry Room Panels | ||
| 1266 | panels: | ||
| 1267 | - LEAF | ||
| 1268 | - FEEL | ||
| 1138 | Outside The Agreeable: | 1269 | Outside The Agreeable: | 
| 1139 | entrances: | 1270 | entrances: | 
| 1140 | Crossroads: | 1271 | Crossroads: | 
| @@ -1243,6 +1374,20 @@ | |||
| 1243 | panels: | 1374 | panels: | 
| 1244 | - room: Color Hunt | 1375 | - room: Color Hunt | 
| 1245 | panel: PURPLE | 1376 | panel: PURPLE | 
| 1377 | panel_doors: | ||
| 1378 | MASSACRED: | ||
| 1379 | panel_group: Tenacious Entrance Panels | ||
| 1380 | panels: | ||
| 1381 | - MASSACRED | ||
| 1382 | BLACK: | ||
| 1383 | panels: | ||
| 1384 | - BLACK | ||
| 1385 | CLOSE: | ||
| 1386 | panels: | ||
| 1387 | - CLOSE | ||
| 1388 | RIGHT: | ||
| 1389 | panels: | ||
| 1390 | - RIGHT | ||
| 1246 | paintings: | 1391 | paintings: | 
| 1247 | - id: eyes_yellow_painting | 1392 | - id: eyes_yellow_painting | 
| 1248 | orientation: east | 1393 | orientation: east | 
| @@ -1294,6 +1439,14 @@ | |||
| 1294 | - WINTER | 1439 | - WINTER | 
| 1295 | - DIAMONDS | 1440 | - DIAMONDS | 
| 1296 | - FIRE | 1441 | - FIRE | 
| 1442 | panel_doors: | ||
| 1443 | Lookout: | ||
| 1444 | item_name: Compass Room Panels | ||
| 1445 | panels: | ||
| 1446 | - NORTH | ||
| 1447 | - WINTER | ||
| 1448 | - DIAMONDS | ||
| 1449 | - FIRE | ||
| 1297 | paintings: | 1450 | paintings: | 
| 1298 | - id: pencil_painting7 | 1451 | - id: pencil_painting7 | 
| 1299 | orientation: north | 1452 | orientation: north | 
| @@ -1510,6 +1663,10 @@ | |||
| 1510 | - HIDE (3) | 1663 | - HIDE (3) | 
| 1511 | - room: Outside The Agreeable | 1664 | - room: Outside The Agreeable | 
| 1512 | panel: HIDE | 1665 | panel: HIDE | 
| 1666 | panel_doors: | ||
| 1667 | DOWN: | ||
| 1668 | panels: | ||
| 1669 | - DOWN | ||
| 1513 | The Perceptive: | 1670 | The Perceptive: | 
| 1514 | entrances: | 1671 | entrances: | 
| 1515 | Starting Room: | 1672 | Starting Room: | 
| @@ -1531,6 +1688,10 @@ | |||
| 1531 | check: True | 1688 | check: True | 
| 1532 | exclude_reduce: True | 1689 | exclude_reduce: True | 
| 1533 | tag: botwhite | 1690 | tag: botwhite | 
| 1691 | panel_doors: | ||
| 1692 | GAZE: | ||
| 1693 | panels: | ||
| 1694 | - GAZE | ||
| 1534 | paintings: | 1695 | paintings: | 
| 1535 | - id: garden_painting_tower | 1696 | - id: garden_painting_tower | 
| 1536 | orientation: north | 1697 | orientation: north | 
| @@ -1572,9 +1733,10 @@ | |||
| 1572 | - EAT | 1733 | - EAT | 
| 1573 | progression: | 1734 | progression: | 
| 1574 | Progressive Fearless: | 1735 | Progressive Fearless: | 
| 1575 | - Second Floor | 1736 | doors: | 
| 1576 | - room: The Fearless (Second Floor) | 1737 | - Second Floor | 
| 1577 | door: Third Floor | 1738 | - room: The Fearless (Second Floor) | 
| 1739 | door: Third Floor | ||
| 1578 | The Fearless (Second Floor): | 1740 | The Fearless (Second Floor): | 
| 1579 | entrances: | 1741 | entrances: | 
| 1580 | The Fearless (First Floor): | 1742 | The Fearless (First Floor): | 
| @@ -1669,6 +1831,10 @@ | |||
| 1669 | tag: forbid | 1831 | tag: forbid | 
| 1670 | required_door: | 1832 | required_door: | 
| 1671 | door: Stairs | 1833 | door: Stairs | 
| 1834 | required_panel: | ||
| 1835 | - panel: FOUR (1) | ||
| 1836 | - panel: FOUR (2) | ||
| 1837 | - panel: SIX | ||
| 1672 | achievement: The Observant | 1838 | achievement: The Observant | 
| 1673 | FOUR (1): | 1839 | FOUR (1): | 
| 1674 | id: Look Room/Panel_four_back | 1840 | id: Look Room/Panel_four_back | 
| @@ -1782,6 +1948,16 @@ | |||
| 1782 | door_group: Observant Doors | 1948 | door_group: Observant Doors | 
| 1783 | panels: | 1949 | panels: | 
| 1784 | - SIX | 1950 | - SIX | 
| 1951 | panel_doors: | ||
| 1952 | BACKSIDE: | ||
| 1953 | item_name: The Observant - Backside Entrance Panels | ||
| 1954 | panel_group: Backside Entrance Panels | ||
| 1955 | panels: | ||
| 1956 | - FOUR (1) | ||
| 1957 | - FOUR (2) | ||
| 1958 | STAIRS: | ||
| 1959 | panels: | ||
| 1960 | - SIX | ||
| 1785 | The Incomparable: | 1961 | The Incomparable: | 
| 1786 | entrances: | 1962 | entrances: | 
| 1787 | The Observant: | 1963 | The Observant: | 
| @@ -1798,9 +1974,12 @@ | |||
| 1798 | check: True | 1974 | check: True | 
| 1799 | tag: forbid | 1975 | tag: forbid | 
| 1800 | required_room: | 1976 | required_room: | 
| 1801 | - Elements Area | ||
| 1802 | - Courtyard | ||
| 1803 | - Eight Room | 1977 | - Eight Room | 
| 1978 | required_panel: | ||
| 1979 | - room: Courtyard | ||
| 1980 | panel: I | ||
| 1981 | - room: Elements Area | ||
| 1982 | panel: A | ||
| 1804 | achievement: The Incomparable | 1983 | achievement: The Incomparable | 
| 1805 | A (One): | 1984 | A (One): | 
| 1806 | id: Strand Room/Panel_blank_a | 1985 | id: Strand Room/Panel_blank_a | 
| @@ -1865,6 +2044,15 @@ | |||
| 1865 | panel: I | 2044 | panel: I | 
| 1866 | - room: Elements Area | 2045 | - room: Elements Area | 
| 1867 | panel: A | 2046 | panel: A | 
| 2047 | panel_doors: | ||
| 2048 | Giant Sevens: | ||
| 2049 | item_name: Giant Seven Panels | ||
| 2050 | panels: | ||
| 2051 | - I (Seven) | ||
| 2052 | - room: Courtyard | ||
| 2053 | panel: I | ||
| 2054 | - room: Elements Area | ||
| 2055 | panel: A | ||
| 1868 | paintings: | 2056 | paintings: | 
| 1869 | - id: crown_painting | 2057 | - id: crown_painting | 
| 1870 | orientation: east | 2058 | orientation: east | 
| @@ -1972,14 +2160,31 @@ | |||
| 1972 | panel: DRAWL + RUNS | 2160 | panel: DRAWL + RUNS | 
| 1973 | - room: Owl Hallway | 2161 | - room: Owl Hallway | 
| 1974 | panel: READS + RUST | 2162 | panel: READS + RUST | 
| 2163 | panel_doors: | ||
| 2164 | Access: | ||
| 2165 | item_name: Orange Tower Panels | ||
| 2166 | panels: | ||
| 2167 | - room: Orange Tower First Floor | ||
| 2168 | panel: DADS + ALE | ||
| 2169 | - room: Outside The Undeterred | ||
| 2170 | panel: ART + ART | ||
| 2171 | - room: Orange Tower Third Floor | ||
| 2172 | panel: DEER + WREN | ||
| 2173 | - room: Orange Tower Fourth Floor | ||
| 2174 | panel: LEARNS + UNSEW | ||
| 2175 | - room: Orange Tower Fifth Floor | ||
| 2176 | panel: DRAWL + RUNS | ||
| 2177 | - room: Owl Hallway | ||
| 2178 | panel: READS + RUST | ||
| 1975 | progression: | 2179 | progression: | 
| 1976 | Progressive Orange Tower: | 2180 | Progressive Orange Tower: | 
| 1977 | - Second Floor | 2181 | doors: | 
| 1978 | - Third Floor | 2182 | - Second Floor | 
| 1979 | - Fourth Floor | 2183 | - Third Floor | 
| 1980 | - Fifth Floor | 2184 | - Fourth Floor | 
| 1981 | - Sixth Floor | 2185 | - Fifth Floor | 
| 1982 | - Seventh Floor | 2186 | - Sixth Floor | 
| 2187 | - Seventh Floor | ||
| 1983 | Orange Tower First Floor: | 2188 | Orange Tower First Floor: | 
| 1984 | entrances: | 2189 | entrances: | 
| 1985 | Hub Room: | 2190 | Hub Room: | 
| @@ -2022,6 +2227,10 @@ | |||
| 2022 | - SALT | 2227 | - SALT | 
| 2023 | - room: Directional Gallery | 2228 | - room: Directional Gallery | 
| 2024 | panel: PEPPER | 2229 | panel: PEPPER | 
| 2230 | panel_doors: | ||
| 2231 | SECRET: | ||
| 2232 | panels: | ||
| 2233 | - SECRET | ||
| 2025 | sunwarps: | 2234 | sunwarps: | 
| 2026 | - dots: 4 | 2235 | - dots: 4 | 
| 2027 | direction: enter | 2236 | direction: enter | 
| @@ -2174,6 +2383,10 @@ | |||
| 2174 | id: Shuffle Room Area Doors/Door_hotcrust_shortcuts | 2383 | id: Shuffle Room Area Doors/Door_hotcrust_shortcuts | 
| 2175 | panels: | 2384 | panels: | 
| 2176 | - HOT CRUSTS | 2385 | - HOT CRUSTS | 
| 2386 | panel_doors: | ||
| 2387 | HOT CRUSTS: | ||
| 2388 | panels: | ||
| 2389 | - HOT CRUSTS | ||
| 2177 | sunwarps: | 2390 | sunwarps: | 
| 2178 | - dots: 5 | 2391 | - dots: 5 | 
| 2179 | direction: enter | 2392 | direction: enter | 
| @@ -2288,6 +2501,12 @@ | |||
| 2288 | panels: | 2501 | panels: | 
| 2289 | - SIZE (Small) | 2502 | - SIZE (Small) | 
| 2290 | - SIZE (Big) | 2503 | - SIZE (Big) | 
| 2504 | panel_doors: | ||
| 2505 | SIZE: | ||
| 2506 | item_name: Orange Tower Fifth Floor - SIZE Panels | ||
| 2507 | panels: | ||
| 2508 | - SIZE (Small) | ||
| 2509 | - SIZE (Big) | ||
| 2291 | paintings: | 2510 | paintings: | 
| 2292 | - id: hi_solved_painting3 | 2511 | - id: hi_solved_painting3 | 
| 2293 | orientation: south | 2512 | orientation: south | 
| @@ -2631,6 +2850,15 @@ | |||
| 2631 | - SECOND | 2850 | - SECOND | 
| 2632 | - THIRD | 2851 | - THIRD | 
| 2633 | - FOURTH | 2852 | - FOURTH | 
| 2853 | panel_doors: | ||
| 2854 | FIRST SECOND THIRD FOURTH: | ||
| 2855 | item_name: Courtyard - Ordinal Panels | ||
| 2856 | panel_group: Backside Entrance Panels | ||
| 2857 | panels: | ||
| 2858 | - FIRST | ||
| 2859 | - SECOND | ||
| 2860 | - THIRD | ||
| 2861 | - FOURTH | ||
| 2634 | The Colorful (White): | 2862 | The Colorful (White): | 
| 2635 | entrances: | 2863 | entrances: | 
| 2636 | Courtyard: True | 2864 | Courtyard: True | 
| @@ -2648,6 +2876,12 @@ | |||
| 2648 | location_name: The Colorful - White | 2876 | location_name: The Colorful - White | 
| 2649 | panels: | 2877 | panels: | 
| 2650 | - BEGIN | 2878 | - BEGIN | 
| 2879 | panel_doors: | ||
| 2880 | BEGIN: | ||
| 2881 | item_name: The Colorful - BEGIN (Panel) | ||
| 2882 | panel_group: Colorful Panels | ||
| 2883 | panels: | ||
| 2884 | - BEGIN | ||
| 2651 | The Colorful (Black): | 2885 | The Colorful (Black): | 
| 2652 | entrances: | 2886 | entrances: | 
| 2653 | The Colorful (White): | 2887 | The Colorful (White): | 
| @@ -2668,6 +2902,12 @@ | |||
| 2668 | door_group: Colorful Doors | 2902 | door_group: Colorful Doors | 
| 2669 | panels: | 2903 | panels: | 
| 2670 | - FOUND | 2904 | - FOUND | 
| 2905 | panel_doors: | ||
| 2906 | FOUND: | ||
| 2907 | item_name: The Colorful - FOUND (Panel) | ||
| 2908 | panel_group: Colorful Panels | ||
| 2909 | panels: | ||
| 2910 | - FOUND | ||
| 2671 | The Colorful (Red): | 2911 | The Colorful (Red): | 
| 2672 | entrances: | 2912 | entrances: | 
| 2673 | The Colorful (Black): | 2913 | The Colorful (Black): | 
| @@ -2688,6 +2928,12 @@ | |||
| 2688 | door_group: Colorful Doors | 2928 | door_group: Colorful Doors | 
| 2689 | panels: | 2929 | panels: | 
| 2690 | - LOAF | 2930 | - LOAF | 
| 2931 | panel_doors: | ||
| 2932 | LOAF: | ||
| 2933 | item_name: The Colorful - LOAF (Panel) | ||
| 2934 | panel_group: Colorful Panels | ||
| 2935 | panels: | ||
| 2936 | - LOAF | ||
| 2691 | The Colorful (Yellow): | 2937 | The Colorful (Yellow): | 
| 2692 | entrances: | 2938 | entrances: | 
| 2693 | The Colorful (Red): | 2939 | The Colorful (Red): | 
| @@ -2708,6 +2954,12 @@ | |||
| 2708 | door_group: Colorful Doors | 2954 | door_group: Colorful Doors | 
| 2709 | panels: | 2955 | panels: | 
| 2710 | - CREAM | 2956 | - CREAM | 
| 2957 | panel_doors: | ||
| 2958 | CREAM: | ||
| 2959 | item_name: The Colorful - CREAM (Panel) | ||
| 2960 | panel_group: Colorful Panels | ||
| 2961 | panels: | ||
| 2962 | - CREAM | ||
| 2711 | The Colorful (Blue): | 2963 | The Colorful (Blue): | 
| 2712 | entrances: | 2964 | entrances: | 
| 2713 | The Colorful (Yellow): | 2965 | The Colorful (Yellow): | 
| @@ -2728,6 +2980,12 @@ | |||
| 2728 | door_group: Colorful Doors | 2980 | door_group: Colorful Doors | 
| 2729 | panels: | 2981 | panels: | 
| 2730 | - SUN | 2982 | - SUN | 
| 2983 | panel_doors: | ||
| 2984 | SUN: | ||
| 2985 | item_name: The Colorful - SUN (Panel) | ||
| 2986 | panel_group: Colorful Panels | ||
| 2987 | panels: | ||
| 2988 | - SUN | ||
| 2731 | The Colorful (Purple): | 2989 | The Colorful (Purple): | 
| 2732 | entrances: | 2990 | entrances: | 
| 2733 | The Colorful (Blue): | 2991 | The Colorful (Blue): | 
| @@ -2748,6 +3006,12 @@ | |||
| 2748 | door_group: Colorful Doors | 3006 | door_group: Colorful Doors | 
| 2749 | panels: | 3007 | panels: | 
| 2750 | - SPOON | 3008 | - SPOON | 
| 3009 | panel_doors: | ||
| 3010 | SPOON: | ||
| 3011 | item_name: The Colorful - SPOON (Panel) | ||
| 3012 | panel_group: Colorful Panels | ||
| 3013 | panels: | ||
| 3014 | - SPOON | ||
| 2751 | The Colorful (Orange): | 3015 | The Colorful (Orange): | 
| 2752 | entrances: | 3016 | entrances: | 
| 2753 | The Colorful (Purple): | 3017 | The Colorful (Purple): | 
| @@ -2768,6 +3032,12 @@ | |||
| 2768 | door_group: Colorful Doors | 3032 | door_group: Colorful Doors | 
| 2769 | panels: | 3033 | panels: | 
| 2770 | - LETTERS | 3034 | - LETTERS | 
| 3035 | panel_doors: | ||
| 3036 | LETTERS: | ||
| 3037 | item_name: The Colorful - LETTERS (Panel) | ||
| 3038 | panel_group: Colorful Panels | ||
| 3039 | panels: | ||
| 3040 | - LETTERS | ||
| 2771 | The Colorful (Green): | 3041 | The Colorful (Green): | 
| 2772 | entrances: | 3042 | entrances: | 
| 2773 | The Colorful (Orange): | 3043 | The Colorful (Orange): | 
| @@ -2788,6 +3058,12 @@ | |||
| 2788 | door_group: Colorful Doors | 3058 | door_group: Colorful Doors | 
| 2789 | panels: | 3059 | panels: | 
| 2790 | - WALLS | 3060 | - WALLS | 
| 3061 | panel_doors: | ||
| 3062 | WALLS: | ||
| 3063 | item_name: The Colorful - WALLS (Panel) | ||
| 3064 | panel_group: Colorful Panels | ||
| 3065 | panels: | ||
| 3066 | - WALLS | ||
| 2791 | The Colorful (Brown): | 3067 | The Colorful (Brown): | 
| 2792 | entrances: | 3068 | entrances: | 
| 2793 | The Colorful (Green): | 3069 | The Colorful (Green): | 
| @@ -2808,6 +3084,12 @@ | |||
| 2808 | door_group: Colorful Doors | 3084 | door_group: Colorful Doors | 
| 2809 | panels: | 3085 | panels: | 
| 2810 | - IRON | 3086 | - IRON | 
| 3087 | panel_doors: | ||
| 3088 | IRON: | ||
| 3089 | item_name: The Colorful - IRON (Panel) | ||
| 3090 | panel_group: Colorful Panels | ||
| 3091 | panels: | ||
| 3092 | - IRON | ||
| 2811 | The Colorful (Gray): | 3093 | The Colorful (Gray): | 
| 2812 | entrances: | 3094 | entrances: | 
| 2813 | The Colorful (Brown): | 3095 | The Colorful (Brown): | 
| @@ -2828,6 +3110,12 @@ | |||
| 2828 | door_group: Colorful Doors | 3110 | door_group: Colorful Doors | 
| 2829 | panels: | 3111 | panels: | 
| 2830 | - OBSTACLE | 3112 | - OBSTACLE | 
| 3113 | panel_doors: | ||
| 3114 | OBSTACLE: | ||
| 3115 | item_name: The Colorful - OBSTACLE (Panel) | ||
| 3116 | panel_group: Colorful Panels | ||
| 3117 | panels: | ||
| 3118 | - OBSTACLE | ||
| 2831 | The Colorful: | 3119 | The Colorful: | 
| 2832 | entrances: | 3120 | entrances: | 
| 2833 | The Colorful (Gray): | 3121 | The Colorful (Gray): | 
| @@ -2866,26 +3154,48 @@ | |||
| 2866 | orientation: north | 3154 | orientation: north | 
| 2867 | progression: | 3155 | progression: | 
| 2868 | Progressive Colorful: | 3156 | Progressive Colorful: | 
| 2869 | - room: The Colorful (White) | 3157 | doors: | 
| 2870 | door: Progress Door | 3158 | - room: The Colorful (White) | 
| 2871 | - room: The Colorful (Black) | 3159 | door: Progress Door | 
| 2872 | door: Progress Door | 3160 | - room: The Colorful (Black) | 
| 2873 | - room: The Colorful (Red) | 3161 | door: Progress Door | 
| 2874 | door: Progress Door | 3162 | - room: The Colorful (Red) | 
| 2875 | - room: The Colorful (Yellow) | 3163 | door: Progress Door | 
| 2876 | door: Progress Door | 3164 | - room: The Colorful (Yellow) | 
| 2877 | - room: The Colorful (Blue) | 3165 | door: Progress Door | 
| 2878 | door: Progress Door | 3166 | - room: The Colorful (Blue) | 
| 2879 | - room: The Colorful (Purple) | 3167 | door: Progress Door | 
| 2880 | door: Progress Door | 3168 | - room: The Colorful (Purple) | 
| 2881 | - room: The Colorful (Orange) | 3169 | door: Progress Door | 
| 2882 | door: Progress Door | 3170 | - room: The Colorful (Orange) | 
| 2883 | - room: The Colorful (Green) | 3171 | door: Progress Door | 
| 2884 | door: Progress Door | 3172 | - room: The Colorful (Green) | 
| 2885 | - room: The Colorful (Brown) | 3173 | door: Progress Door | 
| 2886 | door: Progress Door | 3174 | - room: The Colorful (Brown) | 
| 2887 | - room: The Colorful (Gray) | 3175 | door: Progress Door | 
| 2888 | door: Progress Door | 3176 | - room: The Colorful (Gray) | 
| 3177 | door: Progress Door | ||
| 3178 | panel_doors: | ||
| 3179 | - room: The Colorful (White) | ||
| 3180 | panel_door: BEGIN | ||
| 3181 | - room: The Colorful (Black) | ||
| 3182 | panel_door: FOUND | ||
| 3183 | - room: The Colorful (Red) | ||
| 3184 | panel_door: LOAF | ||
| 3185 | - room: The Colorful (Yellow) | ||
| 3186 | panel_door: CREAM | ||
| 3187 | - room: The Colorful (Blue) | ||
| 3188 | panel_door: SUN | ||
| 3189 | - room: The Colorful (Purple) | ||
| 3190 | panel_door: SPOON | ||
| 3191 | - room: The Colorful (Orange) | ||
| 3192 | panel_door: LETTERS | ||
| 3193 | - room: The Colorful (Green) | ||
| 3194 | panel_door: WALLS | ||
| 3195 | - room: The Colorful (Brown) | ||
| 3196 | panel_door: IRON | ||
| 3197 | - room: The Colorful (Gray) | ||
| 3198 | panel_door: OBSTACLE | ||
| 2889 | Welcome Back Area: | 3199 | Welcome Back Area: | 
| 2890 | entrances: | 3200 | entrances: | 
| 2891 | Starting Room: | 3201 | Starting Room: | 
| @@ -2958,6 +3268,10 @@ | |||
| 2958 | door_group: Hedge Maze Doors | 3268 | door_group: Hedge Maze Doors | 
| 2959 | panels: | 3269 | panels: | 
| 2960 | - STRAYS | 3270 | - STRAYS | 
| 3271 | panel_doors: | ||
| 3272 | STRAYS: | ||
| 3273 | panels: | ||
| 3274 | - STRAYS | ||
| 2961 | paintings: | 3275 | paintings: | 
| 2962 | - id: arrows_painting_8 | 3276 | - id: arrows_painting_8 | 
| 2963 | orientation: south | 3277 | orientation: south | 
| @@ -3155,6 +3469,13 @@ | |||
| 3155 | panel: I | 3469 | panel: I | 
| 3156 | - room: Elements Area | 3470 | - room: Elements Area | 
| 3157 | panel: A | 3471 | panel: A | 
| 3472 | panel_doors: | ||
| 3473 | UNCOVER: | ||
| 3474 | panels: | ||
| 3475 | - UNCOVER | ||
| 3476 | OXEN: | ||
| 3477 | panels: | ||
| 3478 | - OXEN | ||
| 3158 | paintings: | 3479 | paintings: | 
| 3159 | - id: clock_painting_5 | 3480 | - id: clock_painting_5 | 
| 3160 | orientation: east | 3481 | orientation: east | 
| @@ -3524,6 +3845,13 @@ | |||
| 3524 | - RISE (Sunrise) | 3845 | - RISE (Sunrise) | 
| 3525 | - ZEN | 3846 | - ZEN | 
| 3526 | - SON | 3847 | - SON | 
| 3848 | panel_doors: | ||
| 3849 | UNOPEN: | ||
| 3850 | panels: | ||
| 3851 | - UNOPEN | ||
| 3852 | BEGIN: | ||
| 3853 | panels: | ||
| 3854 | - BEGIN | ||
| 3527 | paintings: | 3855 | paintings: | 
| 3528 | - id: pencil_painting2 | 3856 | - id: pencil_painting2 | 
| 3529 | orientation: west | 3857 | orientation: west | 
| @@ -3819,6 +4147,34 @@ | |||
| 3819 | item_group: Achievement Room Entrances | 4147 | item_group: Achievement Room Entrances | 
| 3820 | panels: | 4148 | panels: | 
| 3821 | - ZERO | 4149 | - ZERO | 
| 4150 | panel_doors: | ||
| 4151 | ZERO: | ||
| 4152 | panels: | ||
| 4153 | - ZERO | ||
| 4154 | PEN: | ||
| 4155 | panels: | ||
| 4156 | - PEN | ||
| 4157 | TWO: | ||
| 4158 | item_name: Two Panels | ||
| 4159 | panels: | ||
| 4160 | - TWO (1) | ||
| 4161 | - TWO (2) | ||
| 4162 | THREE: | ||
| 4163 | item_name: Three Panels | ||
| 4164 | panels: | ||
| 4165 | - THREE (1) | ||
| 4166 | - THREE (2) | ||
| 4167 | - THREE (3) | ||
| 4168 | FOUR: | ||
| 4169 | item_name: Four Panels | ||
| 4170 | panels: | ||
| 4171 | - FOUR | ||
| 4172 | - room: Hub Room | ||
| 4173 | panel: FOUR | ||
| 4174 | - room: Dead End Area | ||
| 4175 | panel: FOUR | ||
| 4176 | - room: The Traveled | ||
| 4177 | panel: FOUR | ||
| 3822 | paintings: | 4178 | paintings: | 
| 3823 | - id: maze_painting_3 | 4179 | - id: maze_painting_3 | 
| 3824 | enter_only: True | 4180 | enter_only: True | 
| @@ -3994,6 +4350,10 @@ | |||
| 3994 | panel: FIVE (1) | 4350 | panel: FIVE (1) | 
| 3995 | - room: Directional Gallery | 4351 | - room: Directional Gallery | 
| 3996 | panel: FIVE (2) | 4352 | panel: FIVE (2) | 
| 4353 | First Six: | ||
| 4354 | event: True | ||
| 4355 | panels: | ||
| 4356 | - SIX | ||
| 3997 | Sevens: | 4357 | Sevens: | 
| 3998 | id: | 4358 | id: | 
| 3999 | - Count Up Room Area Doors/Door_seven_hider | 4359 | - Count Up Room Area Doors/Door_seven_hider | 
| @@ -4102,12 +4462,109 @@ | |||
| 4102 | panel: NINE | 4462 | panel: NINE | 
| 4103 | - room: Elements Area | 4463 | - room: Elements Area | 
| 4104 | panel: NINE | 4464 | panel: NINE | 
| 4465 | panel_doors: | ||
| 4466 | FIVE: | ||
| 4467 | item_name: Five Panels | ||
| 4468 | panels: | ||
| 4469 | - FIVE | ||
| 4470 | - room: Outside The Agreeable | ||
| 4471 | panel: FIVE (1) | ||
| 4472 | - room: Outside The Agreeable | ||
| 4473 | panel: FIVE (2) | ||
| 4474 | - room: Directional Gallery | ||
| 4475 | panel: FIVE (1) | ||
| 4476 | - room: Directional Gallery | ||
| 4477 | panel: FIVE (2) | ||
| 4478 | SIX: | ||
| 4479 | item_name: Six Panels | ||
| 4480 | panels: | ||
| 4481 | - SIX | ||
| 4482 | - room: Outside The Bold | ||
| 4483 | panel: SIX | ||
| 4484 | - room: Directional Gallery | ||
| 4485 | panel: SIX (1) | ||
| 4486 | - room: Directional Gallery | ||
| 4487 | panel: SIX (2) | ||
| 4488 | - room: The Bearer (East) | ||
| 4489 | panel: SIX | ||
| 4490 | - room: The Bearer (South) | ||
| 4491 | panel: SIX | ||
| 4492 | SEVEN: | ||
| 4493 | item_name: Seven Panels | ||
| 4494 | panels: | ||
| 4495 | - SEVEN | ||
| 4496 | - room: Directional Gallery | ||
| 4497 | panel: SEVEN | ||
| 4498 | - room: Knight Night Exit | ||
| 4499 | panel: SEVEN (1) | ||
| 4500 | - room: Knight Night Exit | ||
| 4501 | panel: SEVEN (2) | ||
| 4502 | - room: Knight Night Exit | ||
| 4503 | panel: SEVEN (3) | ||
| 4504 | - room: Outside The Initiated | ||
| 4505 | panel: SEVEN (1) | ||
| 4506 | - room: Outside The Initiated | ||
| 4507 | panel: SEVEN (2) | ||
| 4508 | EIGHT: | ||
| 4509 | item_name: Eight Panels | ||
| 4510 | panels: | ||
| 4511 | - EIGHT | ||
| 4512 | - room: Directional Gallery | ||
| 4513 | panel: EIGHT | ||
| 4514 | - room: The Eyes They See | ||
| 4515 | panel: EIGHT | ||
| 4516 | - room: Dead End Area | ||
| 4517 | panel: EIGHT | ||
| 4518 | - room: Crossroads | ||
| 4519 | panel: EIGHT | ||
| 4520 | - room: Hot Crusts Area | ||
| 4521 | panel: EIGHT | ||
| 4522 | - room: Art Gallery | ||
| 4523 | panel: EIGHT | ||
| 4524 | - room: Outside The Initiated | ||
| 4525 | panel: EIGHT | ||
| 4526 | NINE: | ||
| 4527 | item_name: Nine Panels | ||
| 4528 | panels: | ||
| 4529 | - NINE | ||
| 4530 | - room: Directional Gallery | ||
| 4531 | panel: NINE | ||
| 4532 | - room: Amen Name Area | ||
| 4533 | panel: NINE | ||
| 4534 | - room: Yellow Backside Area | ||
| 4535 | panel: NINE | ||
| 4536 | - room: Outside The Initiated | ||
| 4537 | panel: NINE | ||
| 4538 | - room: Outside The Bold | ||
| 4539 | panel: NINE | ||
| 4540 | - room: Rhyme Room (Cross) | ||
| 4541 | panel: NINE | ||
| 4542 | - room: Orange Tower Fifth Floor | ||
| 4543 | panel: NINE | ||
| 4544 | - room: Elements Area | ||
| 4545 | panel: NINE | ||
| 4105 | paintings: | 4546 | paintings: | 
| 4106 | - id: smile_painting_5 | 4547 | - id: smile_painting_5 | 
| 4107 | enter_only: True | 4548 | enter_only: True | 
| 4108 | orientation: east | 4549 | orientation: east | 
| 4109 | required_door: | 4550 | required_door: | 
| 4110 | door: Eights | 4551 | door: Eights | 
| 4552 | progression: | ||
| 4553 | Progressive Number Hunt: | ||
| 4554 | panel_doors: | ||
| 4555 | - room: Outside The Undeterred | ||
| 4556 | panel_door: TWO | ||
| 4557 | - room: Outside The Undeterred | ||
| 4558 | panel_door: THREE | ||
| 4559 | - room: Outside The Undeterred | ||
| 4560 | panel_door: FOUR | ||
| 4561 | - FIVE | ||
| 4562 | - SIX | ||
| 4563 | - SEVEN | ||
| 4564 | - EIGHT | ||
| 4565 | - NINE | ||
| 4566 | - room: Outside The Undeterred | ||
| 4567 | panel_door: ZERO | ||
| 4111 | Directional Gallery: | 4568 | Directional Gallery: | 
| 4112 | entrances: | 4569 | entrances: | 
| 4113 | Outside The Agreeable: | 4570 | Outside The Agreeable: | 
| @@ -4195,7 +4652,7 @@ | |||
| 4195 | tag: midorange | 4652 | tag: midorange | 
| 4196 | required_door: | 4653 | required_door: | 
| 4197 | room: Number Hunt | 4654 | room: Number Hunt | 
| 4198 | door: Sixes | 4655 | door: First Six | 
| 4199 | PARANOID: | 4656 | PARANOID: | 
| 4200 | id: Backside Room/Panel_paranoid_paranoid | 4657 | id: Backside Room/Panel_paranoid_paranoid | 
| 4201 | tag: midwhite | 4658 | tag: midwhite | 
| @@ -4203,7 +4660,7 @@ | |||
| 4203 | exclude_reduce: True | 4660 | exclude_reduce: True | 
| 4204 | required_door: | 4661 | required_door: | 
| 4205 | room: Number Hunt | 4662 | room: Number Hunt | 
| 4206 | door: Sixes | 4663 | door: First Six | 
| 4207 | YELLOW: | 4664 | YELLOW: | 
| 4208 | id: Color Arrow Room/Panel_yellow_afar | 4665 | id: Color Arrow Room/Panel_yellow_afar | 
| 4209 | tag: midwhite | 4666 | tag: midwhite | 
| @@ -4266,6 +4723,11 @@ | |||
| 4266 | panels: | 4723 | panels: | 
| 4267 | - room: Color Hunt | 4724 | - room: Color Hunt | 
| 4268 | panel: YELLOW | 4725 | panel: YELLOW | 
| 4726 | panel_doors: | ||
| 4727 | TURN LEARN: | ||
| 4728 | panels: | ||
| 4729 | - TURN | ||
| 4730 | - LEARN | ||
| 4269 | paintings: | 4731 | paintings: | 
| 4270 | - id: smile_painting_7 | 4732 | - id: smile_painting_7 | 
| 4271 | orientation: south | 4733 | orientation: south | 
| @@ -4277,7 +4739,7 @@ | |||
| 4277 | move: True | 4739 | move: True | 
| 4278 | required_door: | 4740 | required_door: | 
| 4279 | room: Number Hunt | 4741 | room: Number Hunt | 
| 4280 | door: Sixes | 4742 | door: First Six | 
| 4281 | - id: boxes_painting | 4743 | - id: boxes_painting | 
| 4282 | orientation: south | 4744 | orientation: south | 
| 4283 | - id: cherry_painting | 4745 | - id: cherry_painting | 
| @@ -4344,6 +4806,34 @@ | |||
| 4344 | id: Rock Room Doors/Door_hint | 4806 | id: Rock Room Doors/Door_hint | 
| 4345 | panels: | 4807 | panels: | 
| 4346 | - EXIT | 4808 | - EXIT | 
| 4809 | panel_doors: | ||
| 4810 | EXIT: | ||
| 4811 | panels: | ||
| 4812 | - EXIT | ||
| 4813 | RED: | ||
| 4814 | panel_group: Color Hunt Panels | ||
| 4815 | panels: | ||
| 4816 | - RED | ||
| 4817 | BLUE: | ||
| 4818 | panel_group: Color Hunt Panels | ||
| 4819 | panels: | ||
| 4820 | - BLUE | ||
| 4821 | YELLOW: | ||
| 4822 | panel_group: Color Hunt Panels | ||
| 4823 | panels: | ||
| 4824 | - YELLOW | ||
| 4825 | ORANGE: | ||
| 4826 | panel_group: Color Hunt Panels | ||
| 4827 | panels: | ||
| 4828 | - ORANGE | ||
| 4829 | PURPLE: | ||
| 4830 | panel_group: Color Hunt Panels | ||
| 4831 | panels: | ||
| 4832 | - PURPLE | ||
| 4833 | GREEN: | ||
| 4834 | panel_group: Color Hunt Panels | ||
| 4835 | panels: | ||
| 4836 | - GREEN | ||
| 4347 | paintings: | 4837 | paintings: | 
| 4348 | - id: arrows_painting_7 | 4838 | - id: arrows_painting_7 | 
| 4349 | orientation: east | 4839 | orientation: east | 
| @@ -4481,6 +4971,14 @@ | |||
| 4481 | event: True | 4971 | event: True | 
| 4482 | panels: | 4972 | panels: | 
| 4483 | - HEART | 4973 | - HEART | 
| 4974 | panel_doors: | ||
| 4975 | FARTHER: | ||
| 4976 | panel_group: Backside Entrance Panels | ||
| 4977 | panels: | ||
| 4978 | - FARTHER | ||
| 4979 | MIDDLE: | ||
| 4980 | panels: | ||
| 4981 | - MIDDLE | ||
| 4484 | The Bearer (East): | 4982 | The Bearer (East): | 
| 4485 | entrances: | 4983 | entrances: | 
| 4486 | Cross Tower (East): True | 4984 | Cross Tower (East): True | 
| @@ -5333,6 +5831,11 @@ | |||
| 5333 | item_name: Knight Night Room - Exit | 5831 | item_name: Knight Night Room - Exit | 
| 5334 | panels: | 5832 | panels: | 
| 5335 | - TRUSTED | 5833 | - TRUSTED | 
| 5834 | panel_doors: | ||
| 5835 | TRUSTED: | ||
| 5836 | item_name: Knight Night Room - TRUSTED (Panel) | ||
| 5837 | panels: | ||
| 5838 | - TRUSTED | ||
| 5336 | Knight Night Exit: | 5839 | Knight Night Exit: | 
| 5337 | entrances: | 5840 | entrances: | 
| 5338 | Knight Night (Outer Ring): | 5841 | Knight Night (Outer Ring): | 
| @@ -6017,6 +6520,10 @@ | |||
| 6017 | item_group: Achievement Room Entrances | 6520 | item_group: Achievement Room Entrances | 
| 6018 | panels: | 6521 | panels: | 
| 6019 | - SHRINK | 6522 | - SHRINK | 
| 6523 | panel_doors: | ||
| 6524 | SHRINK: | ||
| 6525 | panels: | ||
| 6526 | - SHRINK | ||
| 6020 | The Wondrous (Doorknob): | 6527 | The Wondrous (Doorknob): | 
| 6021 | entrances: | 6528 | entrances: | 
| 6022 | Outside The Wondrous: | 6529 | Outside The Wondrous: | 
| @@ -6228,18 +6735,36 @@ | |||
| 6228 | - KEEP | 6735 | - KEEP | 
| 6229 | - BAILEY | 6736 | - BAILEY | 
| 6230 | - TOWER | 6737 | - TOWER | 
| 6738 | panel_doors: | ||
| 6739 | CASTLE: | ||
| 6740 | item_name: Hallway Room - First Room Panels | ||
| 6741 | panel_group: Hallway Room Panels | ||
| 6742 | panels: | ||
| 6743 | - WALL | ||
| 6744 | - KEEP | ||
| 6745 | - BAILEY | ||
| 6746 | - TOWER | ||
| 6231 | paintings: | 6747 | paintings: | 
| 6232 | - id: panda_painting | 6748 | - id: panda_painting | 
| 6233 | orientation: south | 6749 | orientation: south | 
| 6234 | progression: | 6750 | progression: | 
| 6235 | Progressive Hallway Room: | 6751 | Progressive Hallway Room: | 
| 6236 | - Exit | 6752 | doors: | 
| 6237 | - room: Hallway Room (2) | 6753 | - Exit | 
| 6238 | door: Exit | 6754 | - room: Hallway Room (2) | 
| 6239 | - room: Hallway Room (3) | 6755 | door: Exit | 
| 6240 | door: Exit | 6756 | - room: Hallway Room (3) | 
| 6241 | - room: Hallway Room (4) | 6757 | door: Exit | 
| 6242 | door: Exit | 6758 | - room: Hallway Room (4) | 
| 6759 | door: Exit | ||
| 6760 | panel_doors: | ||
| 6761 | - CASTLE | ||
| 6762 | - room: Hallway Room (2) | ||
| 6763 | panel_door: COUNTERCLOCKWISE | ||
| 6764 | - room: Hallway Room (3) | ||
| 6765 | panel_door: TRANSFORMATION | ||
| 6766 | - room: Hallway Room (4) | ||
| 6767 | panel_door: WHEELBARROW | ||
| 6243 | Hallway Room (2): | 6768 | Hallway Room (2): | 
| 6244 | entrances: | 6769 | entrances: | 
| 6245 | Hallway Room (1): | 6770 | Hallway Room (1): | 
| @@ -6278,6 +6803,15 @@ | |||
| 6278 | - CLOCK | 6803 | - CLOCK | 
| 6279 | - ER | 6804 | - ER | 
| 6280 | - COUNT | 6805 | - COUNT | 
| 6806 | panel_doors: | ||
| 6807 | COUNTERCLOCKWISE: | ||
| 6808 | item_name: Hallway Room - Second Room Panels | ||
| 6809 | panel_group: Hallway Room Panels | ||
| 6810 | panels: | ||
| 6811 | - WISE | ||
| 6812 | - CLOCK | ||
| 6813 | - ER | ||
| 6814 | - COUNT | ||
| 6281 | Hallway Room (3): | 6815 | Hallway Room (3): | 
| 6282 | entrances: | 6816 | entrances: | 
| 6283 | Hallway Room (2): | 6817 | Hallway Room (2): | 
| @@ -6316,6 +6850,15 @@ | |||
| 6316 | - FORM | 6850 | - FORM | 
| 6317 | - A | 6851 | - A | 
| 6318 | - SHUN | 6852 | - SHUN | 
| 6853 | panel_doors: | ||
| 6854 | TRANSFORMATION: | ||
| 6855 | item_name: Hallway Room - Third Room Panels | ||
| 6856 | panel_group: Hallway Room Panels | ||
| 6857 | panels: | ||
| 6858 | - TRANCE | ||
| 6859 | - FORM | ||
| 6860 | - A | ||
| 6861 | - SHUN | ||
| 6319 | Hallway Room (4): | 6862 | Hallway Room (4): | 
| 6320 | entrances: | 6863 | entrances: | 
| 6321 | Hallway Room (3): | 6864 | Hallway Room (3): | 
| @@ -6338,6 +6881,12 @@ | |||
| 6338 | panels: | 6881 | panels: | 
| 6339 | - WHEEL | 6882 | - WHEEL | 
| 6340 | include_reduce: True | 6883 | include_reduce: True | 
| 6884 | panel_doors: | ||
| 6885 | WHEELBARROW: | ||
| 6886 | item_name: Hallway Room - WHEEL | ||
| 6887 | panel_group: Hallway Room Panels | ||
| 6888 | panels: | ||
| 6889 | - WHEEL | ||
| 6341 | Elements Area: | 6890 | Elements Area: | 
| 6342 | entrances: | 6891 | entrances: | 
| 6343 | Roof: True | 6892 | Roof: True | 
| @@ -6412,6 +6961,10 @@ | |||
| 6412 | panels: | 6961 | panels: | 
| 6413 | - room: The Wanderer | 6962 | - room: The Wanderer | 
| 6414 | panel: Achievement | 6963 | panel: Achievement | 
| 6964 | panel_doors: | ||
| 6965 | WANDERLUST: | ||
| 6966 | panels: | ||
| 6967 | - WANDERLUST | ||
| 6415 | The Wanderer: | 6968 | The Wanderer: | 
| 6416 | entrances: | 6969 | entrances: | 
| 6417 | Outside The Wanderer: | 6970 | Outside The Wanderer: | 
| @@ -6553,6 +7106,10 @@ | |||
| 6553 | item_group: Achievement Room Entrances | 7106 | item_group: Achievement Room Entrances | 
| 6554 | panels: | 7107 | panels: | 
| 6555 | - ORDER | 7108 | - ORDER | 
| 7109 | panel_doors: | ||
| 7110 | ORDER: | ||
| 7111 | panels: | ||
| 7112 | - ORDER | ||
| 6556 | paintings: | 7113 | paintings: | 
| 6557 | - id: smile_painting_3 | 7114 | - id: smile_painting_3 | 
| 6558 | orientation: west | 7115 | orientation: west | 
| @@ -6566,10 +7123,11 @@ | |||
| 6566 | orientation: south | 7123 | orientation: south | 
| 6567 | progression: | 7124 | progression: | 
| 6568 | Progressive Art Gallery: | 7125 | Progressive Art Gallery: | 
| 6569 | - Second Floor | 7126 | doors: | 
| 6570 | - Third Floor | 7127 | - Second Floor | 
| 6571 | - Fourth Floor | 7128 | - Third Floor | 
| 6572 | - Fifth Floor | 7129 | - Fourth Floor | 
| 7130 | - Fifth Floor | ||
| 6573 | Art Gallery (Second Floor): | 7131 | Art Gallery (Second Floor): | 
| 6574 | entrances: | 7132 | entrances: | 
| 6575 | Art Gallery: | 7133 | Art Gallery: | 
| @@ -7281,8 +7839,8 @@ | |||
| 7281 | id: Panel Room/Panel_broomed_bedroom | 7839 | id: Panel Room/Panel_broomed_bedroom | 
| 7282 | colors: yellow | 7840 | colors: yellow | 
| 7283 | tag: midyellow | 7841 | tag: midyellow | 
| 7284 | required_door: | 7842 | required_panel: | 
| 7285 | door: Excavation | 7843 | panel: WALL (1) | 
| 7286 | LAYS: | 7844 | LAYS: | 
| 7287 | id: Panel Room/Panel_lays_maze | 7845 | id: Panel Room/Panel_lays_maze | 
| 7288 | colors: purple | 7846 | colors: purple | 
| @@ -7309,13 +7867,24 @@ | |||
| 7309 | Excavation: | 7867 | Excavation: | 
| 7310 | event: True | 7868 | event: True | 
| 7311 | panels: | 7869 | panels: | 
| 7312 | - WALL (1) | 7870 | - STAIRS | 
| 7313 | Cellar Exit: | 7871 | Cellar Exit: | 
| 7314 | id: | 7872 | id: | 
| 7315 | - Tower Room Area Doors/Door_panel_basement | 7873 | - Tower Room Area Doors/Door_panel_basement | 
| 7316 | - Tower Room Area Doors/Door_panel_basement2 | 7874 | - Tower Room Area Doors/Door_panel_basement2 | 
| 7317 | panels: | 7875 | panels: | 
| 7318 | - BASE | 7876 | - BASE | 
| 7877 | panel_doors: | ||
| 7878 | STAIRS: | ||
| 7879 | panel_group: Room Room Panels | ||
| 7880 | panels: | ||
| 7881 | - STAIRS | ||
| 7882 | Colors: | ||
| 7883 | panel_group: Room Room Panels | ||
| 7884 | panels: | ||
| 7885 | - BROOMED | ||
| 7886 | - LAYS | ||
| 7887 | - BASE | ||
| 7319 | Cellar: | 7888 | Cellar: | 
| 7320 | entrances: | 7889 | entrances: | 
| 7321 | Room Room: | 7890 | Room Room: | 
| @@ -7354,6 +7923,11 @@ | |||
| 7354 | panels: | 7923 | panels: | 
| 7355 | - KITTEN | 7924 | - KITTEN | 
| 7356 | - CAT | 7925 | - CAT | 
| 7926 | panel_doors: | ||
| 7927 | KITTEN CAT: | ||
| 7928 | panels: | ||
| 7929 | - KITTEN | ||
| 7930 | - CAT | ||
| 7357 | paintings: | 7931 | paintings: | 
| 7358 | - id: arrows_painting_2 | 7932 | - id: arrows_painting_2 | 
| 7359 | orientation: east | 7933 | orientation: east | 
| @@ -7608,6 +8182,10 @@ | |||
| 7608 | item_group: Achievement Room Entrances | 8182 | item_group: Achievement Room Entrances | 
| 7609 | panels: | 8183 | panels: | 
| 7610 | - OPEN | 8184 | - OPEN | 
| 8185 | panel_doors: | ||
| 8186 | OPEN: | ||
| 8187 | panels: | ||
| 8188 | - OPEN | ||
| 7611 | The Scientific: | 8189 | The Scientific: | 
| 7612 | entrances: | 8190 | entrances: | 
| 7613 | Outside The Scientific: | 8191 | Outside The Scientific: | 
| diff --git a/data/generated.dat b/data/generated.dat index 4a751b2..d221b81 100644 --- a/data/generated.dat +++ b/data/generated.dat | |||
| Binary files differ | |||
| diff --git a/data/ids.yaml b/data/ids.yaml index c49a8df..b46f1d3 100644 --- a/data/ids.yaml +++ b/data/ids.yaml | |||
| @@ -1478,3 +1478,145 @@ progression: | |||
| 1478 | Progressive Art Gallery: 444563 | 1478 | Progressive Art Gallery: 444563 | 
| 1479 | Progressive Colorful: 444580 | 1479 | Progressive Colorful: 444580 | 
| 1480 | Progressive Pilgrimage: 444583 | 1480 | Progressive Pilgrimage: 444583 | 
| 1481 | Progressive Suits Area: 444602 | ||
| 1482 | Progressive Symmetry Room: 444608 | ||
| 1483 | Progressive Number Hunt: 444654 | ||
| 1484 | panel_doors: | ||
| 1485 | Starting Room: | ||
| 1486 | HIDDEN: 444589 | ||
| 1487 | Hidden Room: | ||
| 1488 | OPEN: 444590 | ||
| 1489 | Hub Room: | ||
| 1490 | ORDER: 444591 | ||
| 1491 | SLAUGHTER: 444592 | ||
| 1492 | TRACE: 444594 | ||
| 1493 | RAT: 444595 | ||
| 1494 | OPEN: 444596 | ||
| 1495 | Crossroads: | ||
| 1496 | DECAY: 444597 | ||
| 1497 | NOPE: 444598 | ||
| 1498 | WE ROT: 444599 | ||
| 1499 | WORDS SWORD: 444600 | ||
| 1500 | BEND HI: 444601 | ||
| 1501 | Lost Area: | ||
| 1502 | LOST: 444603 | ||
| 1503 | Amen Name Area: | ||
| 1504 | AMEN NAME: 444604 | ||
| 1505 | The Tenacious: | ||
| 1506 | Black Palindromes: 444605 | ||
| 1507 | Near Far Area: | ||
| 1508 | NEAR FAR: 444606 | ||
| 1509 | Warts Straw Area: | ||
| 1510 | WARTS STRAW: 444609 | ||
| 1511 | Leaf Feel Area: | ||
| 1512 | LEAF FEEL: 444610 | ||
| 1513 | Outside The Agreeable: | ||
| 1514 | MASSACRED: 444611 | ||
| 1515 | BLACK: 444612 | ||
| 1516 | CLOSE: 444613 | ||
| 1517 | RIGHT: 444614 | ||
| 1518 | Compass Room: | ||
| 1519 | Lookout: 444615 | ||
| 1520 | Hedge Maze: | ||
| 1521 | DOWN: 444617 | ||
| 1522 | The Perceptive: | ||
| 1523 | GAZE: 444618 | ||
| 1524 | The Observant: | ||
| 1525 | BACKSIDE: 444619 | ||
| 1526 | STAIRS: 444621 | ||
| 1527 | The Incomparable: | ||
| 1528 | Giant Sevens: 444622 | ||
| 1529 | Orange Tower: | ||
| 1530 | Access: 444623 | ||
| 1531 | Orange Tower First Floor: | ||
| 1532 | SECRET: 444624 | ||
| 1533 | Orange Tower Fourth Floor: | ||
| 1534 | HOT CRUSTS: 444625 | ||
| 1535 | Orange Tower Fifth Floor: | ||
| 1536 | SIZE: 444626 | ||
| 1537 | First Second Third Fourth: | ||
| 1538 | FIRST SECOND THIRD FOURTH: 444627 | ||
| 1539 | The Colorful (White): | ||
| 1540 | BEGIN: 444628 | ||
| 1541 | The Colorful (Black): | ||
| 1542 | FOUND: 444630 | ||
| 1543 | The Colorful (Red): | ||
| 1544 | LOAF: 444631 | ||
| 1545 | The Colorful (Yellow): | ||
| 1546 | CREAM: 444632 | ||
| 1547 | The Colorful (Blue): | ||
| 1548 | SUN: 444633 | ||
| 1549 | The Colorful (Purple): | ||
| 1550 | SPOON: 444634 | ||
| 1551 | The Colorful (Orange): | ||
| 1552 | LETTERS: 444635 | ||
| 1553 | The Colorful (Green): | ||
| 1554 | WALLS: 444636 | ||
| 1555 | The Colorful (Brown): | ||
| 1556 | IRON: 444637 | ||
| 1557 | The Colorful (Gray): | ||
| 1558 | OBSTACLE: 444638 | ||
| 1559 | Owl Hallway: | ||
| 1560 | STRAYS: 444639 | ||
| 1561 | Outside The Initiated: | ||
| 1562 | UNCOVER: 444640 | ||
| 1563 | OXEN: 444641 | ||
| 1564 | Outside The Bold: | ||
| 1565 | UNOPEN: 444642 | ||
| 1566 | BEGIN: 444643 | ||
| 1567 | Outside The Undeterred: | ||
| 1568 | ZERO: 444644 | ||
| 1569 | PEN: 444645 | ||
| 1570 | TWO: 444646 | ||
| 1571 | THREE: 444647 | ||
| 1572 | FOUR: 444648 | ||
| 1573 | Number Hunt: | ||
| 1574 | FIVE: 444649 | ||
| 1575 | SIX: 444650 | ||
| 1576 | SEVEN: 444651 | ||
| 1577 | EIGHT: 444652 | ||
| 1578 | NINE: 444653 | ||
| 1579 | Color Hunt: | ||
| 1580 | EXIT: 444655 | ||
| 1581 | RED: 444656 | ||
| 1582 | BLUE: 444658 | ||
| 1583 | YELLOW: 444659 | ||
| 1584 | ORANGE: 444660 | ||
| 1585 | PURPLE: 444661 | ||
| 1586 | GREEN: 444662 | ||
| 1587 | The Bearer: | ||
| 1588 | FARTHER: 444663 | ||
| 1589 | MIDDLE: 444664 | ||
| 1590 | Knight Night (Final): | ||
| 1591 | TRUSTED: 444665 | ||
| 1592 | Outside The Wondrous: | ||
| 1593 | SHRINK: 444666 | ||
| 1594 | Hallway Room (1): | ||
| 1595 | CASTLE: 444667 | ||
| 1596 | Hallway Room (2): | ||
| 1597 | COUNTERCLOCKWISE: 444669 | ||
| 1598 | Hallway Room (3): | ||
| 1599 | TRANSFORMATION: 444670 | ||
| 1600 | Hallway Room (4): | ||
| 1601 | WHEELBARROW: 444671 | ||
| 1602 | Outside The Wanderer: | ||
| 1603 | WANDERLUST: 444672 | ||
| 1604 | Art Gallery: | ||
| 1605 | ORDER: 444673 | ||
| 1606 | Room Room: | ||
| 1607 | STAIRS: 444674 | ||
| 1608 | Colors: 444676 | ||
| 1609 | Outside The Wise: | ||
| 1610 | KITTEN CAT: 444677 | ||
| 1611 | Outside The Scientific: | ||
| 1612 | OPEN: 444678 | ||
| 1613 | Directional Gallery: | ||
| 1614 | TURN LEARN: 444679 | ||
| 1615 | panel_groups: | ||
| 1616 | Tenacious Entrance Panels: 444593 | ||
| 1617 | Symmetry Room Panels: 444607 | ||
| 1618 | Backside Entrance Panels: 444620 | ||
| 1619 | Colorful Panels: 444629 | ||
| 1620 | Color Hunt Panels: 444657 | ||
| 1621 | Hallway Room Panels: 444668 | ||
| 1622 | Room Room Panels: 444675 | ||
| diff --git a/datatypes.py b/datatypes.py index 36141da..9521422 100644 --- a/datatypes.py +++ b/datatypes.py | |||
| @@ -12,6 +12,11 @@ class RoomAndPanel(NamedTuple): | |||
| 12 | panel: str | 12 | panel: str | 
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | class RoomAndPanelDoor(NamedTuple): | ||
| 16 | room: Optional[str] | ||
| 17 | panel_door: str | ||
| 18 | |||
| 19 | |||
| 15 | class EntranceType(Flag): | 20 | class EntranceType(Flag): | 
| 16 | NORMAL = auto() | 21 | NORMAL = auto() | 
| 17 | PAINTING = auto() | 22 | PAINTING = auto() | 
| @@ -63,9 +68,15 @@ class Panel(NamedTuple): | |||
| 63 | exclude_reduce: bool | 68 | exclude_reduce: bool | 
| 64 | achievement: bool | 69 | achievement: bool | 
| 65 | non_counting: bool | 70 | non_counting: bool | 
| 71 | panel_door: Optional[RoomAndPanelDoor] # This will always be fully specified. | ||
| 66 | location_name: Optional[str] | 72 | location_name: Optional[str] | 
| 67 | 73 | ||
| 68 | 74 | ||
| 75 | class PanelDoor(NamedTuple): | ||
| 76 | item_name: str | ||
| 77 | panel_group: Optional[str] | ||
| 78 | |||
| 79 | |||
| 69 | class Painting(NamedTuple): | 80 | class Painting(NamedTuple): | 
| 70 | id: str | 81 | id: str | 
| 71 | room: str | 82 | room: str | 
| diff --git a/items.py b/items.py index 67eacea..78b288e 100644 --- a/items.py +++ b/items.py | |||
| @@ -3,7 +3,7 @@ from typing import Dict, List, NamedTuple, Set | |||
| 3 | 3 | ||
| 4 | from BaseClasses import Item, ItemClassification | 4 | from BaseClasses import Item, ItemClassification | 
| 5 | from .static_logic import DOORS_BY_ROOM, PROGRESSIVE_ITEMS, get_door_group_item_id, get_door_item_id, \ | 5 | from .static_logic import DOORS_BY_ROOM, PROGRESSIVE_ITEMS, get_door_group_item_id, get_door_item_id, \ | 
| 6 | get_progressive_item_id, get_special_item_id | 6 | get_progressive_item_id, get_special_item_id, PANEL_DOORS_BY_ROOM, get_panel_door_item_id, get_panel_group_item_id | 
| 7 | 7 | ||
| 8 | 8 | ||
| 9 | class ItemType(Enum): | 9 | class ItemType(Enum): | 
| @@ -65,6 +65,21 @@ def load_item_data(): | |||
| 65 | ItemClassification.progression, ItemType.NORMAL, True, []) | 65 | ItemClassification.progression, ItemType.NORMAL, True, []) | 
| 66 | ITEMS_BY_GROUP.setdefault("Doors", []).append(group) | 66 | ITEMS_BY_GROUP.setdefault("Doors", []).append(group) | 
| 67 | 67 | ||
| 68 | panel_groups: Set[str] = set() | ||
| 69 | for room_name, panel_doors in PANEL_DOORS_BY_ROOM.items(): | ||
| 70 | for panel_door_name, panel_door in panel_doors.items(): | ||
| 71 | if panel_door.panel_group is not None: | ||
| 72 | panel_groups.add(panel_door.panel_group) | ||
| 73 | |||
| 74 | ALL_ITEM_TABLE[panel_door.item_name] = ItemData(get_panel_door_item_id(room_name, panel_door_name), | ||
| 75 | ItemClassification.progression, ItemType.NORMAL, False, []) | ||
| 76 | ITEMS_BY_GROUP.setdefault("Panels", []).append(panel_door.item_name) | ||
| 77 | |||
| 78 | for group in panel_groups: | ||
| 79 | ALL_ITEM_TABLE[group] = ItemData(get_panel_group_item_id(group), ItemClassification.progression, | ||
| 80 | ItemType.NORMAL, False, []) | ||
| 81 | ITEMS_BY_GROUP.setdefault("Panels", []).append(group) | ||
| 82 | |||
| 68 | special_items: Dict[str, ItemClassification] = { | 83 | special_items: Dict[str, ItemClassification] = { | 
| 69 | ":)": ItemClassification.filler, | 84 | ":)": ItemClassification.filler, | 
| 70 | "The Feeling of Being Lost": ItemClassification.filler, | 85 | "The Feeling of Being Lost": ItemClassification.filler, | 
| diff --git a/options.py b/options.py index 5a076e5..2fd57ff 100644 --- a/options.py +++ b/options.py | |||
| @@ -8,21 +8,31 @@ from .items import TRAP_ITEMS | |||
| 8 | 8 | ||
| 9 | 9 | ||
| 10 | class ShuffleDoors(Choice): | 10 | class ShuffleDoors(Choice): | 
| 11 | """If on, opening doors will require their respective "keys". | 11 | """This option specifies how doors open. | 
| 12 | 12 | ||
| 13 | - **Simple:** Doors are sorted into logical groups, which are all opened by | 13 | - **None:** Doors in the game will open the way they do in vanilla. | 
| 14 | receiving an item. | 14 | - **Panels:** Doors still open as in vanilla, but the panels that open the | 
| 15 | - **Complex:** The items are much more granular, and will usually only open | 15 | doors will be locked, and an item will be required to unlock the panels. | 
| 16 | a single door each. | 16 | - **Doors:** the doors themselves are locked behind items, and will open | 
| 17 | automatically without needing to solve a panel once the key is obtained. | ||
| 17 | """ | 18 | """ | 
| 18 | display_name = "Shuffle Doors" | 19 | display_name = "Shuffle Doors" | 
| 19 | option_none = 0 | 20 | option_none = 0 | 
| 20 | option_simple = 1 | 21 | option_panels = 1 | 
| 21 | option_complex = 2 | 22 | option_doors = 2 | 
| 23 | alias_simple = 2 | ||
| 24 | alias_complex = 2 | ||
| 25 | |||
| 26 | |||
| 27 | class GroupDoors(Toggle): | ||
| 28 | """By default, door shuffle in either panels or doors mode will create individual keys for every panel or door to be locked. | ||
| 29 | |||
| 30 | When group doors is on, some panels and doors are sorted into logical groups, which are opened together by receiving an item.""" | ||
| 31 | display_name = "Group Doors" | ||
| 22 | 32 | ||
| 23 | 33 | ||
| 24 | class ProgressiveOrangeTower(DefaultOnToggle): | 34 | class ProgressiveOrangeTower(DefaultOnToggle): | 
| 25 | """When "Shuffle Doors" is on, this setting governs the manner in which the Orange Tower floors open up. | 35 | """When "Shuffle Doors" is on doors mode, this setting governs the manner in which the Orange Tower floors open up. | 
| 26 | 36 | ||
| 27 | - **Off:** There is an item for each floor of the tower, and each floor's | 37 | - **Off:** There is an item for each floor of the tower, and each floor's | 
| 28 | item is the only one needed to access that floor. | 38 | item is the only one needed to access that floor. | 
| @@ -33,7 +43,7 @@ class ProgressiveOrangeTower(DefaultOnToggle): | |||
| 33 | 43 | ||
| 34 | 44 | ||
| 35 | class ProgressiveColorful(DefaultOnToggle): | 45 | class ProgressiveColorful(DefaultOnToggle): | 
| 36 | """When "Shuffle Doors" is on "complex", this setting governs the manner in which The Colorful opens up. | 46 | """When "Shuffle Doors" is on either panels or doors mode and "Group Doors" is off, this setting governs the manner in which The Colorful opens up. | 
| 37 | 47 | ||
| 38 | - **Off:** There is an item for each room of The Colorful, meaning that | 48 | - **Off:** There is an item for each room of The Colorful, meaning that | 
| 39 | random rooms in the middle of the sequence can open up without giving you | 49 | random rooms in the middle of the sequence can open up without giving you | 
| @@ -253,6 +263,7 @@ lingo_option_groups = [ | |||
| 253 | @dataclass | 263 | @dataclass | 
| 254 | class LingoOptions(PerGameCommonOptions): | 264 | class LingoOptions(PerGameCommonOptions): | 
| 255 | shuffle_doors: ShuffleDoors | 265 | shuffle_doors: ShuffleDoors | 
| 266 | group_doors: GroupDoors | ||
| 256 | progressive_orange_tower: ProgressiveOrangeTower | 267 | progressive_orange_tower: ProgressiveOrangeTower | 
| 257 | progressive_colorful: ProgressiveColorful | 268 | progressive_colorful: ProgressiveColorful | 
| 258 | location_checks: LocationChecks | 269 | location_checks: LocationChecks | 
| diff --git a/player_logic.py b/player_logic.py index 35080ac..b21735c 100644 --- a/player_logic.py +++ b/player_logic.py | |||
| @@ -7,8 +7,8 @@ from .items import ALL_ITEM_TABLE, ItemType | |||
| 7 | from .locations import ALL_LOCATION_TABLE, LocationClassification | 7 | from .locations import ALL_LOCATION_TABLE, LocationClassification | 
| 8 | from .options import LocationChecks, ShuffleDoors, SunwarpAccess, VictoryCondition | 8 | from .options import LocationChecks, ShuffleDoors, SunwarpAccess, VictoryCondition | 
| 9 | from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \ | 9 | from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \ | 
| 10 | PANELS_BY_ROOM, PROGRESSION_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS, \ | 10 | PANELS_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS, PROGRESSIVE_DOORS_BY_ROOM, \ | 
| 11 | SUNWARP_ENTRANCES, SUNWARP_EXITS | 11 | PANEL_DOORS_BY_ROOM, PROGRESSIVE_PANELS_BY_ROOM, SUNWARP_ENTRANCES, SUNWARP_EXITS | 
| 12 | 12 | ||
| 13 | if TYPE_CHECKING: | 13 | if TYPE_CHECKING: | 
| 14 | from . import LingoWorld | 14 | from . import LingoWorld | 
| @@ -18,6 +18,8 @@ class AccessRequirements: | |||
| 18 | rooms: Set[str] | 18 | rooms: Set[str] | 
| 19 | doors: Set[RoomAndDoor] | 19 | doors: Set[RoomAndDoor] | 
| 20 | colors: Set[str] | 20 | colors: Set[str] | 
| 21 | items: Set[str] | ||
| 22 | progression: Dict[str, int] | ||
| 21 | the_master: bool | 23 | the_master: bool | 
| 22 | postgame: bool | 24 | postgame: bool | 
| 23 | 25 | ||
| @@ -25,6 +27,8 @@ class AccessRequirements: | |||
| 25 | self.rooms = set() | 27 | self.rooms = set() | 
| 26 | self.doors = set() | 28 | self.doors = set() | 
| 27 | self.colors = set() | 29 | self.colors = set() | 
| 30 | self.items = set() | ||
| 31 | self.progression = dict() | ||
| 28 | self.the_master = False | 32 | self.the_master = False | 
| 29 | self.postgame = False | 33 | self.postgame = False | 
| 30 | 34 | ||
| @@ -32,12 +36,17 @@ class AccessRequirements: | |||
| 32 | self.rooms |= other.rooms | 36 | self.rooms |= other.rooms | 
| 33 | self.doors |= other.doors | 37 | self.doors |= other.doors | 
| 34 | self.colors |= other.colors | 38 | self.colors |= other.colors | 
| 39 | self.items |= other.items | ||
| 35 | self.the_master |= other.the_master | 40 | self.the_master |= other.the_master | 
| 36 | self.postgame |= other.postgame | 41 | self.postgame |= other.postgame | 
| 37 | 42 | ||
| 43 | for progression, index in other.progression.items(): | ||
| 44 | if progression not in self.progression or index > self.progression[progression]: | ||
| 45 | self.progression[progression] = index | ||
| 46 | |||
| 38 | def __str__(self): | 47 | def __str__(self): | 
| 39 | return f"AccessRequirements(rooms={self.rooms}, doors={self.doors}, colors={self.colors}," \ | 48 | return f"AccessRequirements(rooms={self.rooms}, doors={self.doors}, colors={self.colors}, items={self.items}," \ | 
| 40 | f" the_master={self.the_master}, postgame={self.postgame})" | 49 | f" progression={self.progression}), the_master={self.the_master}, postgame={self.postgame}" | 
| 41 | 50 | ||
| 42 | 51 | ||
| 43 | class PlayerLocation(NamedTuple): | 52 | class PlayerLocation(NamedTuple): | 
| @@ -117,15 +126,15 @@ class LingoPlayerLogic: | |||
| 117 | self.item_by_door.setdefault(room, {})[door] = item | 126 | self.item_by_door.setdefault(room, {})[door] = item | 
| 118 | 127 | ||
| 119 | def handle_non_grouped_door(self, room_name: str, door_data: Door, world: "LingoWorld"): | 128 | def handle_non_grouped_door(self, room_name: str, door_data: Door, world: "LingoWorld"): | 
| 120 | if room_name in PROGRESSION_BY_ROOM and door_data.name in PROGRESSION_BY_ROOM[room_name]: | 129 | if room_name in PROGRESSIVE_DOORS_BY_ROOM and door_data.name in PROGRESSIVE_DOORS_BY_ROOM[room_name]: | 
| 121 | progression_name = PROGRESSION_BY_ROOM[room_name][door_data.name].item_name | 130 | progression_name = PROGRESSIVE_DOORS_BY_ROOM[room_name][door_data.name].item_name | 
| 122 | progression_handling = should_split_progression(progression_name, world) | 131 | progression_handling = should_split_progression(progression_name, world) | 
| 123 | 132 | ||
| 124 | if progression_handling == ProgressiveItemBehavior.SPLIT: | 133 | if progression_handling == ProgressiveItemBehavior.SPLIT: | 
| 125 | self.set_door_item(room_name, door_data.name, door_data.item_name) | 134 | self.set_door_item(room_name, door_data.name, door_data.item_name) | 
| 126 | self.real_items.append(door_data.item_name) | 135 | self.real_items.append(door_data.item_name) | 
| 127 | elif progression_handling == ProgressiveItemBehavior.PROGRESSIVE: | 136 | elif progression_handling == ProgressiveItemBehavior.PROGRESSIVE: | 
| 128 | progressive_item_name = PROGRESSION_BY_ROOM[room_name][door_data.name].item_name | 137 | progressive_item_name = PROGRESSIVE_DOORS_BY_ROOM[room_name][door_data.name].item_name | 
| 129 | self.set_door_item(room_name, door_data.name, progressive_item_name) | 138 | self.set_door_item(room_name, door_data.name, progressive_item_name) | 
| 130 | self.real_items.append(progressive_item_name) | 139 | self.real_items.append(progressive_item_name) | 
| 131 | else: | 140 | else: | 
| @@ -156,17 +165,31 @@ class LingoPlayerLogic: | |||
| 156 | victory_condition = world.options.victory_condition | 165 | victory_condition = world.options.victory_condition | 
| 157 | early_color_hallways = world.options.early_color_hallways | 166 | early_color_hallways = world.options.early_color_hallways | 
| 158 | 167 | ||
| 159 | if location_checks == LocationChecks.option_reduced and door_shuffle != ShuffleDoors.option_none: | 168 | if location_checks == LocationChecks.option_reduced: | 
| 160 | raise OptionError("You cannot have reduced location checks when door shuffle is on, because there would not" | 169 | if door_shuffle == ShuffleDoors.option_doors: | 
| 161 | " be enough locations for all of the door items.") | 170 | raise OptionError(f"Slot \"{world.player_name}\" cannot have reduced location checks when door shuffle" | 
| 171 | f" is on, because there would not be enough locations for all of the door items.") | ||
| 172 | if door_shuffle == ShuffleDoors.option_panels: | ||
| 173 | if not world.options.group_doors: | ||
| 174 | raise OptionError(f"Slot \"{world.player_name}\" cannot have reduced location checks when ungrouped" | ||
| 175 | f" panels mode door shuffle is on, because there would not be enough locations for" | ||
| 176 | f" all of the panel items.") | ||
| 177 | if color_shuffle: | ||
| 178 | raise OptionError(f"Slot \"{world.player_name}\" cannot have reduced location checks with both" | ||
| 179 | f" panels mode door shuffle and color shuffle because there would not be enough" | ||
| 180 | f" locations for all of the items.") | ||
| 181 | if world.options.sunwarp_access >= SunwarpAccess.option_individual: | ||
| 182 | raise OptionError(f"Slot \"{world.player_name}\" cannot have reduced location checks with both" | ||
| 183 | f" panels mode door shuffle and individual or progressive sunwarp access because" | ||
| 184 | f" there would not be enough locations for all of the items.") | ||
| 162 | 185 | ||
| 163 | # Create door items, where needed. | 186 | # Create door items, where needed. | 
| 164 | door_groups: Set[str] = set() | 187 | door_groups: Set[str] = set() | 
| 165 | for room_name, room_data in DOORS_BY_ROOM.items(): | 188 | for room_name, room_data in DOORS_BY_ROOM.items(): | 
| 166 | for door_name, door_data in room_data.items(): | 189 | for door_name, door_data in room_data.items(): | 
| 167 | if door_data.skip_item is False and door_data.event is False: | 190 | if door_data.skip_item is False and door_data.event is False: | 
| 168 | if door_data.type == DoorType.NORMAL and door_shuffle != ShuffleDoors.option_none: | 191 | if door_data.type == DoorType.NORMAL and door_shuffle == ShuffleDoors.option_doors: | 
| 169 | if door_data.door_group is not None and door_shuffle == ShuffleDoors.option_simple: | 192 | if door_data.door_group is not None and world.options.group_doors: | 
| 170 | # Grouped doors are handled differently if shuffle doors is on simple. | 193 | # Grouped doors are handled differently if shuffle doors is on simple. | 
| 171 | self.set_door_item(room_name, door_name, door_data.door_group) | 194 | self.set_door_item(room_name, door_name, door_data.door_group) | 
| 172 | door_groups.add(door_data.door_group) | 195 | door_groups.add(door_data.door_group) | 
| @@ -188,7 +211,29 @@ class LingoPlayerLogic: | |||
| 188 | self.real_items.append(door_data.item_name) | 211 | self.real_items.append(door_data.item_name) | 
| 189 | 212 | ||
| 190 | self.real_items += door_groups | 213 | self.real_items += door_groups | 
| 191 | 214 | ||
| 215 | # Create panel items, where needed. | ||
| 216 | if world.options.shuffle_doors == ShuffleDoors.option_panels: | ||
| 217 | panel_groups: Set[str] = set() | ||
| 218 | |||
| 219 | for room_name, room_data in PANEL_DOORS_BY_ROOM.items(): | ||
| 220 | for panel_door_name, panel_door_data in room_data.items(): | ||
| 221 | if panel_door_data.panel_group is not None and world.options.group_doors: | ||
| 222 | panel_groups.add(panel_door_data.panel_group) | ||
| 223 | elif room_name in PROGRESSIVE_PANELS_BY_ROOM \ | ||
| 224 | and panel_door_name in PROGRESSIVE_PANELS_BY_ROOM[room_name]: | ||
| 225 | progression_obj = PROGRESSIVE_PANELS_BY_ROOM[room_name][panel_door_name] | ||
| 226 | progression_handling = should_split_progression(progression_obj.item_name, world) | ||
| 227 | |||
| 228 | if progression_handling == ProgressiveItemBehavior.SPLIT: | ||
| 229 | self.real_items.append(panel_door_data.item_name) | ||
| 230 | elif progression_handling == ProgressiveItemBehavior.PROGRESSIVE: | ||
| 231 | self.real_items.append(progression_obj.item_name) | ||
| 232 | else: | ||
| 233 | self.real_items.append(panel_door_data.item_name) | ||
| 234 | |||
| 235 | self.real_items += panel_groups | ||
| 236 | |||
| 192 | # Create color items, if needed. | 237 | # Create color items, if needed. | 
| 193 | if color_shuffle: | 238 | if color_shuffle: | 
| 194 | self.real_items += [name for name, item in ALL_ITEM_TABLE.items() if item.type == ItemType.COLOR] | 239 | self.real_items += [name for name, item in ALL_ITEM_TABLE.items() if item.type == ItemType.COLOR] | 
| @@ -244,7 +289,7 @@ class LingoPlayerLogic: | |||
| 244 | elif location_checks == LocationChecks.option_insanity: | 289 | elif location_checks == LocationChecks.option_insanity: | 
| 245 | location_classification = LocationClassification.insanity | 290 | location_classification = LocationClassification.insanity | 
| 246 | 291 | ||
| 247 | if door_shuffle != ShuffleDoors.option_none and not early_color_hallways: | 292 | if door_shuffle == ShuffleDoors.option_doors and not early_color_hallways: | 
| 248 | location_classification |= LocationClassification.small_sphere_one | 293 | location_classification |= LocationClassification.small_sphere_one | 
| 249 | 294 | ||
| 250 | for location_name, location_data in ALL_LOCATION_TABLE.items(): | 295 | for location_name, location_data in ALL_LOCATION_TABLE.items(): | 
| @@ -286,7 +331,7 @@ class LingoPlayerLogic: | |||
| 286 | "iterations. This is very unlikely to happen on its own, and probably indicates some " | 331 | "iterations. This is very unlikely to happen on its own, and probably indicates some " | 
| 287 | "kind of logic error.") | 332 | "kind of logic error.") | 
| 288 | 333 | ||
| 289 | if door_shuffle != ShuffleDoors.option_none and location_checks != LocationChecks.option_insanity \ | 334 | if door_shuffle == ShuffleDoors.option_doors and location_checks != LocationChecks.option_insanity \ | 
| 290 | and not early_color_hallways and world.multiworld.players > 1: | 335 | and not early_color_hallways and world.multiworld.players > 1: | 
| 291 | # Under the combination of door shuffle, normal location checks, and no early color hallways, sphere 1 is | 336 | # Under the combination of door shuffle, normal location checks, and no early color hallways, sphere 1 is | 
| 292 | # only three checks. In a multiplayer situation, this can be frustrating for the player because they are | 337 | # only three checks. In a multiplayer situation, this can be frustrating for the player because they are | 
| @@ -301,19 +346,19 @@ class LingoPlayerLogic: | |||
| 301 | # Starting Room - Exit Door gives access to OPEN and TRACE. | 346 | # Starting Room - Exit Door gives access to OPEN and TRACE. | 
| 302 | good_item_options: List[str] = ["Starting Room - Back Right Door", "Second Room - Exit Door"] | 347 | good_item_options: List[str] = ["Starting Room - Back Right Door", "Second Room - Exit Door"] | 
| 303 | 348 | ||
| 304 | if not color_shuffle and not world.options.enable_pilgrimage: | ||
| 305 | # HOT CRUST and THIS. | ||
| 306 | good_item_options.append("Pilgrim Room - Sun Painting") | ||
| 307 | |||
| 308 | if not color_shuffle: | 349 | if not color_shuffle: | 
| 309 | if door_shuffle == ShuffleDoors.option_simple: | 350 | if not world.options.enable_pilgrimage: | 
| 351 | # HOT CRUST and THIS. | ||
| 352 | good_item_options.append("Pilgrim Room - Sun Painting") | ||
| 353 | |||
| 354 | if world.options.group_doors: | ||
| 310 | # WELCOME BACK, CLOCKWISE, and DRAWL + RUNS. | 355 | # WELCOME BACK, CLOCKWISE, and DRAWL + RUNS. | 
| 311 | good_item_options.append("Welcome Back Doors") | 356 | good_item_options.append("Welcome Back Doors") | 
| 312 | else: | 357 | else: | 
| 313 | # WELCOME BACK and CLOCKWISE. | 358 | # WELCOME BACK and CLOCKWISE. | 
| 314 | good_item_options.append("Welcome Back Area - Shortcut to Starting Room") | 359 | good_item_options.append("Welcome Back Area - Shortcut to Starting Room") | 
| 315 | 360 | ||
| 316 | if door_shuffle == ShuffleDoors.option_simple: | 361 | if world.options.group_doors: | 
| 317 | # Color hallways access (NOTE: reconsider when sunwarp shuffling exists). | 362 | # Color hallways access (NOTE: reconsider when sunwarp shuffling exists). | 
| 318 | good_item_options.append("Rhyme Room Doors") | 363 | good_item_options.append("Rhyme Room Doors") | 
| 319 | 364 | ||
| @@ -359,13 +404,11 @@ class LingoPlayerLogic: | |||
| 359 | def randomize_paintings(self, world: "LingoWorld") -> bool: | 404 | def randomize_paintings(self, world: "LingoWorld") -> bool: | 
| 360 | self.painting_mapping.clear() | 405 | self.painting_mapping.clear() | 
| 361 | 406 | ||
| 362 | door_shuffle = world.options.shuffle_doors | ||
| 363 | |||
| 364 | # First, assign mappings to the required-exit paintings. We ensure that req-blocked paintings do not lead to | 407 | # First, assign mappings to the required-exit paintings. We ensure that req-blocked paintings do not lead to | 
| 365 | # required paintings. | 408 | # required paintings. | 
| 366 | req_exits = [] | 409 | req_exits = [] | 
| 367 | required_painting_rooms = REQUIRED_PAINTING_ROOMS | 410 | required_painting_rooms = REQUIRED_PAINTING_ROOMS | 
| 368 | if door_shuffle == ShuffleDoors.option_none: | 411 | if world.options.shuffle_doors != ShuffleDoors.option_doors: | 
| 369 | required_painting_rooms += REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS | 412 | required_painting_rooms += REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS | 
| 370 | req_exits = [painting_id for painting_id, painting in PAINTINGS.items() if painting.required_when_no_doors] | 413 | req_exits = [painting_id for painting_id, painting in PAINTINGS.items() if painting.required_when_no_doors] | 
| 371 | 414 | ||
| @@ -432,7 +475,7 @@ class LingoPlayerLogic: | |||
| 432 | for painting_id, painting in PAINTINGS.items(): | 475 | for painting_id, painting in PAINTINGS.items(): | 
| 433 | if painting_id not in self.painting_mapping.values() \ | 476 | if painting_id not in self.painting_mapping.values() \ | 
| 434 | and (painting.required or (painting.required_when_no_doors and | 477 | and (painting.required or (painting.required_when_no_doors and | 
| 435 | door_shuffle == ShuffleDoors.option_none)): | 478 | world.options.shuffle_doors != ShuffleDoors.option_doors)): | 
| 436 | return False | 479 | return False | 
| 437 | 480 | ||
| 438 | return True | 481 | return True | 
| @@ -447,12 +490,31 @@ class LingoPlayerLogic: | |||
| 447 | access_reqs = AccessRequirements() | 490 | access_reqs = AccessRequirements() | 
| 448 | panel_object = PANELS_BY_ROOM[room][panel] | 491 | panel_object = PANELS_BY_ROOM[room][panel] | 
| 449 | 492 | ||
| 493 | if world.options.shuffle_doors == ShuffleDoors.option_panels and panel_object.panel_door is not None: | ||
| 494 | panel_door_room = panel_object.panel_door.room | ||
| 495 | panel_door_name = panel_object.panel_door.panel_door | ||
| 496 | panel_door = PANEL_DOORS_BY_ROOM[panel_door_room][panel_door_name] | ||
| 497 | |||
| 498 | if panel_door.panel_group is not None and world.options.group_doors: | ||
| 499 | access_reqs.items.add(panel_door.panel_group) | ||
| 500 | elif panel_door_room in PROGRESSIVE_PANELS_BY_ROOM\ | ||
| 501 | and panel_door_name in PROGRESSIVE_PANELS_BY_ROOM[panel_door_room]: | ||
| 502 | progression_obj = PROGRESSIVE_PANELS_BY_ROOM[panel_door_room][panel_door_name] | ||
| 503 | progression_handling = should_split_progression(progression_obj.item_name, world) | ||
| 504 | |||
| 505 | if progression_handling == ProgressiveItemBehavior.SPLIT: | ||
| 506 | access_reqs.items.add(panel_door.item_name) | ||
| 507 | elif progression_handling == ProgressiveItemBehavior.PROGRESSIVE: | ||
| 508 | access_reqs.progression[progression_obj.item_name] = progression_obj.index | ||
| 509 | else: | ||
| 510 | access_reqs.items.add(panel_door.item_name) | ||
| 511 | |||
| 450 | for req_room in panel_object.required_rooms: | 512 | for req_room in panel_object.required_rooms: | 
| 451 | access_reqs.rooms.add(req_room) | 513 | access_reqs.rooms.add(req_room) | 
| 452 | 514 | ||
| 453 | for req_door in panel_object.required_doors: | 515 | for req_door in panel_object.required_doors: | 
| 454 | door_object = DOORS_BY_ROOM[room if req_door.room is None else req_door.room][req_door.door] | 516 | door_object = DOORS_BY_ROOM[room if req_door.room is None else req_door.room][req_door.door] | 
| 455 | if door_object.event or world.options.shuffle_doors == ShuffleDoors.option_none: | 517 | if door_object.event or world.options.shuffle_doors != ShuffleDoors.option_doors: | 
| 456 | sub_access_reqs = self.calculate_door_requirements( | 518 | sub_access_reqs = self.calculate_door_requirements( | 
| 457 | room if req_door.room is None else req_door.room, req_door.door, world) | 519 | room if req_door.room is None else req_door.room, req_door.door, world) | 
| 458 | access_reqs.merge(sub_access_reqs) | 520 | access_reqs.merge(sub_access_reqs) | 
| @@ -522,11 +584,14 @@ class LingoPlayerLogic: | |||
| 522 | continue | 584 | continue | 
| 523 | 585 | ||
| 524 | # We won't coalesce any panels that have requirements beyond colors. To simplify things for now, we will | 586 | # We won't coalesce any panels that have requirements beyond colors. To simplify things for now, we will | 
| 525 | # only coalesce single-color panels. Chains/stacks/combo puzzles will be separate. THE MASTER has | 587 | # only coalesce single-color panels. Chains/stacks/combo puzzles will be separate. Panel door locked | 
| 526 | # special access rules and is handled separately. | 588 | # puzzles will be separate if panels mode is on. THE MASTER has special access rules and is handled | 
| 589 | # separately. | ||
| 527 | if len(panel_data.required_panels) > 0 or len(panel_data.required_doors) > 0\ | 590 | if len(panel_data.required_panels) > 0 or len(panel_data.required_doors) > 0\ | 
| 528 | or len(panel_data.required_rooms) > 0\ | 591 | or len(panel_data.required_rooms) > 0\ | 
| 529 | or (world.options.shuffle_colors and len(panel_data.colors) > 1)\ | 592 | or (world.options.shuffle_colors and len(panel_data.colors) > 1)\ | 
| 593 | or (world.options.shuffle_doors == ShuffleDoors.option_panels | ||
| 594 | and panel_data.panel_door is not None)\ | ||
| 530 | or panel_name == "THE MASTER": | 595 | or panel_name == "THE MASTER": | 
| 531 | self.counting_panel_reqs.setdefault(room_name, []).append( | 596 | self.counting_panel_reqs.setdefault(room_name, []).append( | 
| 532 | (self.calculate_panel_requirements(room_name, panel_name, world), 1)) | 597 | (self.calculate_panel_requirements(room_name, panel_name, world), 1)) | 
| diff --git a/rules.py b/rules.py index ed84c56..e0bb08f 100644 --- a/rules.py +++ b/rules.py | |||
| @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING | |||
| 3 | from BaseClasses import CollectionState | 3 | from BaseClasses import CollectionState | 
| 4 | from .datatypes import RoomAndDoor | 4 | from .datatypes import RoomAndDoor | 
| 5 | from .player_logic import AccessRequirements, PlayerLocation | 5 | from .player_logic import AccessRequirements, PlayerLocation | 
| 6 | from .static_logic import PROGRESSION_BY_ROOM, PROGRESSIVE_ITEMS | 6 | from .static_logic import PROGRESSIVE_DOORS_BY_ROOM, PROGRESSIVE_ITEMS | 
| 7 | 7 | ||
| 8 | if TYPE_CHECKING: | 8 | if TYPE_CHECKING: | 
| 9 | from . import LingoWorld | 9 | from . import LingoWorld | 
| @@ -59,6 +59,12 @@ def _lingo_can_satisfy_requirements(state: CollectionState, access: AccessRequir | |||
| 59 | if not state.has(color.capitalize(), world.player): | 59 | if not state.has(color.capitalize(), world.player): | 
| 60 | return False | 60 | return False | 
| 61 | 61 | ||
| 62 | if not all(state.has(item, world.player) for item in access.items): | ||
| 63 | return False | ||
| 64 | |||
| 65 | if not all(state.has(item, world.player, index) for item, index in access.progression.items()): | ||
| 66 | return False | ||
| 67 | |||
| 62 | if access.the_master and not lingo_can_use_mastery_location(state, world): | 68 | if access.the_master and not lingo_can_use_mastery_location(state, world): | 
| 63 | return False | 69 | return False | 
| 64 | 70 | ||
| @@ -77,7 +83,7 @@ def _lingo_can_open_door(state: CollectionState, room: str, door: str, world: "L | |||
| 77 | 83 | ||
| 78 | item_name = world.player_logic.item_by_door[room][door] | 84 | item_name = world.player_logic.item_by_door[room][door] | 
| 79 | if item_name in PROGRESSIVE_ITEMS: | 85 | if item_name in PROGRESSIVE_ITEMS: | 
| 80 | progression = PROGRESSION_BY_ROOM[room][door] | 86 | progression = PROGRESSIVE_DOORS_BY_ROOM[room][door] | 
| 81 | return state.has(item_name, world.player, progression.index) | 87 | return state.has(item_name, world.player, progression.index) | 
| 82 | 88 | ||
| 83 | return state.has(item_name, world.player) | 89 | return state.has(item_name, world.player) | 
| diff --git a/static_logic.py b/static_logic.py index ff820dd..74eea44 100644 --- a/static_logic.py +++ b/static_logic.py | |||
| @@ -4,15 +4,17 @@ import pickle | |||
| 4 | from io import BytesIO | 4 | from io import BytesIO | 
| 5 | from typing import Dict, List, Set | 5 | from typing import Dict, List, Set | 
| 6 | 6 | ||
| 7 | from .datatypes import Door, Painting, Panel, Progression, Room | 7 | from .datatypes import Door, Painting, Panel, PanelDoor, Progression, Room | 
| 8 | 8 | ||
| 9 | ALL_ROOMS: List[Room] = [] | 9 | ALL_ROOMS: List[Room] = [] | 
| 10 | DOORS_BY_ROOM: Dict[str, Dict[str, Door]] = {} | 10 | DOORS_BY_ROOM: Dict[str, Dict[str, Door]] = {} | 
| 11 | PANELS_BY_ROOM: Dict[str, Dict[str, Panel]] = {} | 11 | PANELS_BY_ROOM: Dict[str, Dict[str, Panel]] = {} | 
| 12 | PANEL_DOORS_BY_ROOM: Dict[str, Dict[str, PanelDoor]] = {} | ||
| 12 | PAINTINGS: Dict[str, Painting] = {} | 13 | PAINTINGS: Dict[str, Painting] = {} | 
| 13 | 14 | ||
| 14 | PROGRESSIVE_ITEMS: List[str] = [] | 15 | PROGRESSIVE_ITEMS: Set[str] = set() | 
| 15 | PROGRESSION_BY_ROOM: Dict[str, Dict[str, Progression]] = {} | 16 | PROGRESSIVE_DOORS_BY_ROOM: Dict[str, Dict[str, Progression]] = {} | 
| 17 | PROGRESSIVE_PANELS_BY_ROOM: Dict[str, Dict[str, Progression]] = {} | ||
| 16 | 18 | ||
| 17 | PAINTING_ENTRANCES: int = 0 | 19 | PAINTING_ENTRANCES: int = 0 | 
| 18 | PAINTING_EXIT_ROOMS: Set[str] = set() | 20 | PAINTING_EXIT_ROOMS: Set[str] = set() | 
| @@ -28,6 +30,8 @@ PANEL_LOCATION_IDS: Dict[str, Dict[str, int]] = {} | |||
| 28 | DOOR_LOCATION_IDS: Dict[str, Dict[str, int]] = {} | 30 | DOOR_LOCATION_IDS: Dict[str, Dict[str, int]] = {} | 
| 29 | DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {} | 31 | DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {} | 
| 30 | DOOR_GROUP_ITEM_IDS: Dict[str, int] = {} | 32 | DOOR_GROUP_ITEM_IDS: Dict[str, int] = {} | 
| 33 | PANEL_DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {} | ||
| 34 | PANEL_GROUP_ITEM_IDS: Dict[str, int] = {} | ||
| 31 | PROGRESSIVE_ITEM_IDS: Dict[str, int] = {} | 35 | PROGRESSIVE_ITEM_IDS: Dict[str, int] = {} | 
| 32 | 36 | ||
| 33 | HASHES: Dict[str, str] = {} | 37 | HASHES: Dict[str, str] = {} | 
| @@ -68,6 +72,20 @@ def get_door_group_item_id(name: str): | |||
| 68 | return DOOR_GROUP_ITEM_IDS[name] | 72 | return DOOR_GROUP_ITEM_IDS[name] | 
| 69 | 73 | ||
| 70 | 74 | ||
| 75 | def get_panel_door_item_id(room: str, name: str): | ||
| 76 | if room not in PANEL_DOOR_ITEM_IDS or name not in PANEL_DOOR_ITEM_IDS[room]: | ||
| 77 | raise Exception(f"Item ID for panel door {room} - {name} not found in ids.yaml.") | ||
| 78 | |||
| 79 | return PANEL_DOOR_ITEM_IDS[room][name] | ||
| 80 | |||
| 81 | |||
| 82 | def get_panel_group_item_id(name: str): | ||
| 83 | if name not in PANEL_GROUP_ITEM_IDS: | ||
| 84 | raise Exception(f"Item ID for panel group {name} not found in ids.yaml.") | ||
| 85 | |||
| 86 | return PANEL_GROUP_ITEM_IDS[name] | ||
| 87 | |||
| 88 | |||
| 71 | def get_progressive_item_id(name: str): | 89 | def get_progressive_item_id(name: str): | 
| 72 | if name not in PROGRESSIVE_ITEM_IDS: | 90 | if name not in PROGRESSIVE_ITEM_IDS: | 
| 73 | raise Exception(f"Item ID for progressive item {name} not found in ids.yaml.") | 91 | raise Exception(f"Item ID for progressive item {name} not found in ids.yaml.") | 
| @@ -97,8 +115,10 @@ def load_static_data_from_file(): | |||
| 97 | ALL_ROOMS.extend(pickdata["ALL_ROOMS"]) | 115 | ALL_ROOMS.extend(pickdata["ALL_ROOMS"]) | 
| 98 | DOORS_BY_ROOM.update(pickdata["DOORS_BY_ROOM"]) | 116 | DOORS_BY_ROOM.update(pickdata["DOORS_BY_ROOM"]) | 
| 99 | PANELS_BY_ROOM.update(pickdata["PANELS_BY_ROOM"]) | 117 | PANELS_BY_ROOM.update(pickdata["PANELS_BY_ROOM"]) | 
| 100 | PROGRESSIVE_ITEMS.extend(pickdata["PROGRESSIVE_ITEMS"]) | 118 | PANEL_DOORS_BY_ROOM.update(pickdata["PANEL_DOORS_BY_ROOM"]) | 
| 101 | PROGRESSION_BY_ROOM.update(pickdata["PROGRESSION_BY_ROOM"]) | 119 | PROGRESSIVE_ITEMS.update(pickdata["PROGRESSIVE_ITEMS"]) | 
| 120 | PROGRESSIVE_DOORS_BY_ROOM.update(pickdata["PROGRESSIVE_DOORS_BY_ROOM"]) | ||
| 121 | PROGRESSIVE_PANELS_BY_ROOM.update(pickdata["PROGRESSIVE_PANELS_BY_ROOM"]) | ||
| 102 | PAINTING_ENTRANCES = pickdata["PAINTING_ENTRANCES"] | 122 | PAINTING_ENTRANCES = pickdata["PAINTING_ENTRANCES"] | 
| 103 | PAINTING_EXIT_ROOMS.update(pickdata["PAINTING_EXIT_ROOMS"]) | 123 | PAINTING_EXIT_ROOMS.update(pickdata["PAINTING_EXIT_ROOMS"]) | 
| 104 | PAINTING_EXITS = pickdata["PAINTING_EXITS"] | 124 | PAINTING_EXITS = pickdata["PAINTING_EXITS"] | 
| @@ -111,6 +131,8 @@ def load_static_data_from_file(): | |||
| 111 | DOOR_LOCATION_IDS.update(pickdata["DOOR_LOCATION_IDS"]) | 131 | DOOR_LOCATION_IDS.update(pickdata["DOOR_LOCATION_IDS"]) | 
| 112 | DOOR_ITEM_IDS.update(pickdata["DOOR_ITEM_IDS"]) | 132 | DOOR_ITEM_IDS.update(pickdata["DOOR_ITEM_IDS"]) | 
| 113 | DOOR_GROUP_ITEM_IDS.update(pickdata["DOOR_GROUP_ITEM_IDS"]) | 133 | DOOR_GROUP_ITEM_IDS.update(pickdata["DOOR_GROUP_ITEM_IDS"]) | 
| 134 | PANEL_DOOR_ITEM_IDS.update(pickdata["PANEL_DOOR_ITEM_IDS"]) | ||
| 135 | PANEL_GROUP_ITEM_IDS.update(pickdata["PANEL_GROUP_ITEM_IDS"]) | ||
| 114 | PROGRESSIVE_ITEM_IDS.update(pickdata["PROGRESSIVE_ITEM_IDS"]) | 136 | PROGRESSIVE_ITEM_IDS.update(pickdata["PROGRESSIVE_ITEM_IDS"]) | 
| 115 | 137 | ||
| 116 | 138 | ||
| diff --git a/test/TestDoors.py b/test/TestDoors.py index f496c5f..cfbd7f3 100644 --- a/test/TestDoors.py +++ b/test/TestDoors.py | |||
| @@ -3,7 +3,7 @@ from . import LingoTestBase | |||
| 3 | 3 | ||
| 4 | class TestRequiredRoomLogic(LingoTestBase): | 4 | class TestRequiredRoomLogic(LingoTestBase): | 
| 5 | options = { | 5 | options = { | 
| 6 | "shuffle_doors": "complex", | 6 | "shuffle_doors": "doors", | 
| 7 | "shuffle_colors": "false", | 7 | "shuffle_colors": "false", | 
| 8 | } | 8 | } | 
| 9 | 9 | ||
| @@ -50,7 +50,7 @@ class TestRequiredRoomLogic(LingoTestBase): | |||
| 50 | 50 | ||
| 51 | class TestRequiredDoorLogic(LingoTestBase): | 51 | class TestRequiredDoorLogic(LingoTestBase): | 
| 52 | options = { | 52 | options = { | 
| 53 | "shuffle_doors": "complex", | 53 | "shuffle_doors": "doors", | 
| 54 | "shuffle_colors": "false", | 54 | "shuffle_colors": "false", | 
| 55 | } | 55 | } | 
| 56 | 56 | ||
| @@ -78,7 +78,8 @@ class TestRequiredDoorLogic(LingoTestBase): | |||
| 78 | 78 | ||
| 79 | class TestSimpleDoors(LingoTestBase): | 79 | class TestSimpleDoors(LingoTestBase): | 
| 80 | options = { | 80 | options = { | 
| 81 | "shuffle_doors": "simple", | 81 | "shuffle_doors": "doors", | 
| 82 | "group_doors": "true", | ||
| 82 | "shuffle_colors": "false", | 83 | "shuffle_colors": "false", | 
| 83 | } | 84 | } | 
| 84 | 85 | ||
| @@ -90,3 +91,52 @@ class TestSimpleDoors(LingoTestBase): | |||
| 90 | self.assertTrue(self.multiworld.state.can_reach("Outside The Wanderer", "Region", self.player)) | 91 | self.assertTrue(self.multiworld.state.can_reach("Outside The Wanderer", "Region", self.player)) | 
| 91 | self.assertTrue(self.multiworld.state.can_reach("Orange Tower Third Floor", "Region", self.player)) | 92 | self.assertTrue(self.multiworld.state.can_reach("Orange Tower Third Floor", "Region", self.player)) | 
| 92 | 93 | ||
| 94 | |||
| 95 | class TestPanels(LingoTestBase): | ||
| 96 | options = { | ||
| 97 | "shuffle_doors": "panels" | ||
| 98 | } | ||
| 99 | |||
| 100 | def test_requirement(self): | ||
| 101 | self.assertFalse(self.can_reach_location("Starting Room - HIDDEN")) | ||
| 102 | self.assertFalse(self.can_reach_location("Hidden Room - OPEN")) | ||
| 103 | self.assertFalse(self.can_reach_location("The Seeker - Achievement")) | ||
| 104 | |||
| 105 | self.collect_by_name("Starting Room - HIDDEN (Panel)") | ||
| 106 | self.assertTrue(self.can_reach_location("Starting Room - HIDDEN")) | ||
| 107 | self.assertFalse(self.can_reach_location("Hidden Room - OPEN")) | ||
| 108 | self.assertFalse(self.can_reach_location("The Seeker - Achievement")) | ||
| 109 | |||
| 110 | self.collect_by_name("Hidden Room - OPEN (Panel)") | ||
| 111 | self.assertTrue(self.can_reach_location("Starting Room - HIDDEN")) | ||
| 112 | self.assertTrue(self.can_reach_location("Hidden Room - OPEN")) | ||
| 113 | self.assertTrue(self.can_reach_location("The Seeker - Achievement")) | ||
| 114 | |||
| 115 | |||
| 116 | class TestGroupedPanels(LingoTestBase): | ||
| 117 | options = { | ||
| 118 | "shuffle_doors": "panels", | ||
| 119 | "group_doors": "true", | ||
| 120 | "shuffle_colors": "false", | ||
| 121 | } | ||
| 122 | |||
| 123 | def test_requirement(self): | ||
| 124 | self.assertFalse(self.can_reach_location("Hub Room - SLAUGHTER")) | ||
| 125 | self.assertFalse(self.can_reach_location("Dread Hallway - DREAD")) | ||
| 126 | self.assertFalse(self.can_reach_location("The Tenacious - Achievement")) | ||
| 127 | |||
| 128 | self.collect_by_name("Tenacious Entrance Panels") | ||
| 129 | self.assertTrue(self.can_reach_location("Hub Room - SLAUGHTER")) | ||
| 130 | self.assertFalse(self.can_reach_location("Dread Hallway - DREAD")) | ||
| 131 | self.assertFalse(self.can_reach_location("The Tenacious - Achievement")) | ||
| 132 | |||
| 133 | self.collect_by_name("Outside The Agreeable - BLACK (Panel)") | ||
| 134 | self.assertTrue(self.can_reach_location("Hub Room - SLAUGHTER")) | ||
| 135 | self.assertTrue(self.can_reach_location("Dread Hallway - DREAD")) | ||
| 136 | self.assertFalse(self.can_reach_location("The Tenacious - Achievement")) | ||
| 137 | |||
| 138 | self.collect_by_name("The Tenacious - Black Palindromes (Panels)") | ||
| 139 | self.assertTrue(self.can_reach_location("Hub Room - SLAUGHTER")) | ||
| 140 | self.assertTrue(self.can_reach_location("Dread Hallway - DREAD")) | ||
| 141 | self.assertTrue(self.can_reach_location("The Tenacious - Achievement")) | ||
| 142 | |||
| diff --git a/test/TestOptions.py b/test/TestOptions.py index fce0743..bd8ed81 100644 --- a/test/TestOptions.py +++ b/test/TestOptions.py | |||
| @@ -3,7 +3,7 @@ from . import LingoTestBase | |||
| 3 | 3 | ||
| 4 | class TestMultiShuffleOptions(LingoTestBase): | 4 | class TestMultiShuffleOptions(LingoTestBase): | 
| 5 | options = { | 5 | options = { | 
| 6 | "shuffle_doors": "complex", | 6 | "shuffle_doors": "doors", | 
| 7 | "progressive_orange_tower": "true", | 7 | "progressive_orange_tower": "true", | 
| 8 | "shuffle_colors": "true", | 8 | "shuffle_colors": "true", | 
| 9 | "shuffle_paintings": "true", | 9 | "shuffle_paintings": "true", | 
| @@ -13,7 +13,7 @@ class TestMultiShuffleOptions(LingoTestBase): | |||
| 13 | 13 | ||
| 14 | class TestPanelsanity(LingoTestBase): | 14 | class TestPanelsanity(LingoTestBase): | 
| 15 | options = { | 15 | options = { | 
| 16 | "shuffle_doors": "complex", | 16 | "shuffle_doors": "doors", | 
| 17 | "progressive_orange_tower": "true", | 17 | "progressive_orange_tower": "true", | 
| 18 | "location_checks": "insanity", | 18 | "location_checks": "insanity", | 
| 19 | "shuffle_colors": "true" | 19 | "shuffle_colors": "true" | 
| @@ -22,7 +22,18 @@ class TestPanelsanity(LingoTestBase): | |||
| 22 | 22 | ||
| 23 | class TestAllPanelHunt(LingoTestBase): | 23 | class TestAllPanelHunt(LingoTestBase): | 
| 24 | options = { | 24 | options = { | 
| 25 | "shuffle_doors": "complex", | 25 | "shuffle_doors": "doors", | 
| 26 | "progressive_orange_tower": "true", | ||
| 27 | "shuffle_colors": "true", | ||
| 28 | "victory_condition": "level_2", | ||
| 29 | "level_2_requirement": "800", | ||
| 30 | "early_color_hallways": "true" | ||
| 31 | } | ||
| 32 | |||
| 33 | |||
| 34 | class TestAllPanelHuntPanelsMode(LingoTestBase): | ||
| 35 | options = { | ||
| 36 | "shuffle_doors": "panels", | ||
| 26 | "progressive_orange_tower": "true", | 37 | "progressive_orange_tower": "true", | 
| 27 | "shuffle_colors": "true", | 38 | "shuffle_colors": "true", | 
| 28 | "victory_condition": "level_2", | 39 | "victory_condition": "level_2", | 
| diff --git a/test/TestOrangeTower.py b/test/TestOrangeTower.py index 7b0c3bb..444264a 100644 --- a/test/TestOrangeTower.py +++ b/test/TestOrangeTower.py | |||
| @@ -3,7 +3,7 @@ from . import LingoTestBase | |||
| 3 | 3 | ||
| 4 | class TestProgressiveOrangeTower(LingoTestBase): | 4 | class TestProgressiveOrangeTower(LingoTestBase): | 
| 5 | options = { | 5 | options = { | 
| 6 | "shuffle_doors": "complex", | 6 | "shuffle_doors": "doors", | 
| 7 | "progressive_orange_tower": "true" | 7 | "progressive_orange_tower": "true" | 
| 8 | } | 8 | } | 
| 9 | 9 | ||
| diff --git a/test/TestPanelsanity.py b/test/TestPanelsanity.py index 34c1b38..f8330ae 100644 --- a/test/TestPanelsanity.py +++ b/test/TestPanelsanity.py | |||
| @@ -3,7 +3,7 @@ from . import LingoTestBase | |||
| 3 | 3 | ||
| 4 | class TestPanelHunt(LingoTestBase): | 4 | class TestPanelHunt(LingoTestBase): | 
| 5 | options = { | 5 | options = { | 
| 6 | "shuffle_doors": "complex", | 6 | "shuffle_doors": "doors", | 
| 7 | "location_checks": "insanity", | 7 | "location_checks": "insanity", | 
| 8 | "victory_condition": "level_2", | 8 | "victory_condition": "level_2", | 
| 9 | "level_2_requirement": "15" | 9 | "level_2_requirement": "15" | 
| diff --git a/test/TestPilgrimage.py b/test/TestPilgrimage.py index 4c5e259..328156d 100644 --- a/test/TestPilgrimage.py +++ b/test/TestPilgrimage.py | |||
| @@ -18,7 +18,7 @@ class TestPilgrimageWithRoofAndPaintings(LingoTestBase): | |||
| 18 | options = { | 18 | options = { | 
| 19 | "enable_pilgrimage": "true", | 19 | "enable_pilgrimage": "true", | 
| 20 | "shuffle_colors": "false", | 20 | "shuffle_colors": "false", | 
| 21 | "shuffle_doors": "complex", | 21 | "shuffle_doors": "doors", | 
| 22 | "pilgrimage_allows_roof_access": "true", | 22 | "pilgrimage_allows_roof_access": "true", | 
| 23 | "pilgrimage_allows_paintings": "true", | 23 | "pilgrimage_allows_paintings": "true", | 
| 24 | "early_color_hallways": "false" | 24 | "early_color_hallways": "false" | 
| @@ -39,7 +39,7 @@ class TestPilgrimageNoRoofYesPaintings(LingoTestBase): | |||
| 39 | options = { | 39 | options = { | 
| 40 | "enable_pilgrimage": "true", | 40 | "enable_pilgrimage": "true", | 
| 41 | "shuffle_colors": "false", | 41 | "shuffle_colors": "false", | 
| 42 | "shuffle_doors": "complex", | 42 | "shuffle_doors": "doors", | 
| 43 | "pilgrimage_allows_roof_access": "false", | 43 | "pilgrimage_allows_roof_access": "false", | 
| 44 | "pilgrimage_allows_paintings": "true", | 44 | "pilgrimage_allows_paintings": "true", | 
| 45 | "early_color_hallways": "false" | 45 | "early_color_hallways": "false" | 
| @@ -62,7 +62,7 @@ class TestPilgrimageNoRoofNoPaintings(LingoTestBase): | |||
| 62 | options = { | 62 | options = { | 
| 63 | "enable_pilgrimage": "true", | 63 | "enable_pilgrimage": "true", | 
| 64 | "shuffle_colors": "false", | 64 | "shuffle_colors": "false", | 
| 65 | "shuffle_doors": "complex", | 65 | "shuffle_doors": "doors", | 
| 66 | "pilgrimage_allows_roof_access": "false", | 66 | "pilgrimage_allows_roof_access": "false", | 
| 67 | "pilgrimage_allows_paintings": "false", | 67 | "pilgrimage_allows_paintings": "false", | 
| 68 | "early_color_hallways": "false" | 68 | "early_color_hallways": "false" | 
| @@ -117,7 +117,7 @@ class TestPilgrimageYesRoofNoPaintings(LingoTestBase): | |||
| 117 | options = { | 117 | options = { | 
| 118 | "enable_pilgrimage": "true", | 118 | "enable_pilgrimage": "true", | 
| 119 | "shuffle_colors": "false", | 119 | "shuffle_colors": "false", | 
| 120 | "shuffle_doors": "complex", | 120 | "shuffle_doors": "doors", | 
| 121 | "pilgrimage_allows_roof_access": "true", | 121 | "pilgrimage_allows_roof_access": "true", | 
| 122 | "pilgrimage_allows_paintings": "false", | 122 | "pilgrimage_allows_paintings": "false", | 
| 123 | "early_color_hallways": "false" | 123 | "early_color_hallways": "false" | 
| diff --git a/test/TestProgressive.py b/test/TestProgressive.py index e79fd6b..2c837f5 100644 --- a/test/TestProgressive.py +++ b/test/TestProgressive.py | |||
| @@ -3,7 +3,7 @@ from . import LingoTestBase | |||
| 3 | 3 | ||
| 4 | class TestComplexProgressiveHallwayRoom(LingoTestBase): | 4 | class TestComplexProgressiveHallwayRoom(LingoTestBase): | 
| 5 | options = { | 5 | options = { | 
| 6 | "shuffle_doors": "complex" | 6 | "shuffle_doors": "doors" | 
| 7 | } | 7 | } | 
| 8 | 8 | ||
| 9 | def test_item(self): | 9 | def test_item(self): | 
| @@ -54,7 +54,8 @@ class TestComplexProgressiveHallwayRoom(LingoTestBase): | |||
| 54 | 54 | ||
| 55 | class TestSimpleHallwayRoom(LingoTestBase): | 55 | class TestSimpleHallwayRoom(LingoTestBase): | 
| 56 | options = { | 56 | options = { | 
| 57 | "shuffle_doors": "simple" | 57 | "shuffle_doors": "doors", | 
| 58 | "group_doors": "true", | ||
| 58 | } | 59 | } | 
| 59 | 60 | ||
| 60 | def test_item(self): | 61 | def test_item(self): | 
| @@ -81,7 +82,7 @@ class TestSimpleHallwayRoom(LingoTestBase): | |||
| 81 | 82 | ||
| 82 | class TestProgressiveArtGallery(LingoTestBase): | 83 | class TestProgressiveArtGallery(LingoTestBase): | 
| 83 | options = { | 84 | options = { | 
| 84 | "shuffle_doors": "complex", | 85 | "shuffle_doors": "doors", | 
| 85 | "shuffle_colors": "false", | 86 | "shuffle_colors": "false", | 
| 86 | } | 87 | } | 
| 87 | 88 | ||
| diff --git a/test/TestSunwarps.py b/test/TestSunwarps.py index e8e913c..66ba3af 100644 --- a/test/TestSunwarps.py +++ b/test/TestSunwarps.py | |||
| @@ -19,7 +19,8 @@ class TestVanillaDoorsNormalSunwarps(LingoTestBase): | |||
| 19 | 19 | ||
| 20 | class TestSimpleDoorsNormalSunwarps(LingoTestBase): | 20 | class TestSimpleDoorsNormalSunwarps(LingoTestBase): | 
| 21 | options = { | 21 | options = { | 
| 22 | "shuffle_doors": "simple", | 22 | "shuffle_doors": "doors", | 
| 23 | "group_doors": "true", | ||
| 23 | "sunwarp_access": "normal" | 24 | "sunwarp_access": "normal" | 
| 24 | } | 25 | } | 
| 25 | 26 | ||
| @@ -37,7 +38,8 @@ class TestSimpleDoorsNormalSunwarps(LingoTestBase): | |||
| 37 | 38 | ||
| 38 | class TestSimpleDoorsDisabledSunwarps(LingoTestBase): | 39 | class TestSimpleDoorsDisabledSunwarps(LingoTestBase): | 
| 39 | options = { | 40 | options = { | 
| 40 | "shuffle_doors": "simple", | 41 | "shuffle_doors": "doors", | 
| 42 | "group_doors": "true", | ||
| 41 | "sunwarp_access": "disabled" | 43 | "sunwarp_access": "disabled" | 
| 42 | } | 44 | } | 
| 43 | 45 | ||
| @@ -56,7 +58,8 @@ class TestSimpleDoorsDisabledSunwarps(LingoTestBase): | |||
| 56 | 58 | ||
| 57 | class TestSimpleDoorsUnlockSunwarps(LingoTestBase): | 59 | class TestSimpleDoorsUnlockSunwarps(LingoTestBase): | 
| 58 | options = { | 60 | options = { | 
| 59 | "shuffle_doors": "simple", | 61 | "shuffle_doors": "doors", | 
| 62 | "group_doors": "true", | ||
| 60 | "sunwarp_access": "unlock" | 63 | "sunwarp_access": "unlock" | 
| 61 | } | 64 | } | 
| 62 | 65 | ||
| @@ -78,7 +81,8 @@ class TestSimpleDoorsUnlockSunwarps(LingoTestBase): | |||
| 78 | 81 | ||
| 79 | class TestComplexDoorsNormalSunwarps(LingoTestBase): | 82 | class TestComplexDoorsNormalSunwarps(LingoTestBase): | 
| 80 | options = { | 83 | options = { | 
| 81 | "shuffle_doors": "complex", | 84 | "shuffle_doors": "doors", | 
| 85 | "group_doors": "false", | ||
| 82 | "sunwarp_access": "normal" | 86 | "sunwarp_access": "normal" | 
| 83 | } | 87 | } | 
| 84 | 88 | ||
| @@ -96,7 +100,8 @@ class TestComplexDoorsNormalSunwarps(LingoTestBase): | |||
| 96 | 100 | ||
| 97 | class TestComplexDoorsDisabledSunwarps(LingoTestBase): | 101 | class TestComplexDoorsDisabledSunwarps(LingoTestBase): | 
| 98 | options = { | 102 | options = { | 
| 99 | "shuffle_doors": "complex", | 103 | "shuffle_doors": "doors", | 
| 104 | "group_doors": "false", | ||
| 100 | "sunwarp_access": "disabled" | 105 | "sunwarp_access": "disabled" | 
| 101 | } | 106 | } | 
| 102 | 107 | ||
| @@ -115,7 +120,8 @@ class TestComplexDoorsDisabledSunwarps(LingoTestBase): | |||
| 115 | 120 | ||
| 116 | class TestComplexDoorsIndividualSunwarps(LingoTestBase): | 121 | class TestComplexDoorsIndividualSunwarps(LingoTestBase): | 
| 117 | options = { | 122 | options = { | 
| 118 | "shuffle_doors": "complex", | 123 | "shuffle_doors": "doors", | 
| 124 | "group_doors": "false", | ||
| 119 | "sunwarp_access": "individual" | 125 | "sunwarp_access": "individual" | 
| 120 | } | 126 | } | 
| 121 | 127 | ||
| @@ -142,7 +148,8 @@ class TestComplexDoorsIndividualSunwarps(LingoTestBase): | |||
| 142 | 148 | ||
| 143 | class TestComplexDoorsProgressiveSunwarps(LingoTestBase): | 149 | class TestComplexDoorsProgressiveSunwarps(LingoTestBase): | 
| 144 | options = { | 150 | options = { | 
| 145 | "shuffle_doors": "complex", | 151 | "shuffle_doors": "doors", | 
| 152 | "group_doors": "false", | ||
| 146 | "sunwarp_access": "progressive" | 153 | "sunwarp_access": "progressive" | 
| 147 | } | 154 | } | 
| 148 | 155 | ||
| diff --git a/utils/assign_ids.rb b/utils/assign_ids.rb index 9e1ce67..f7de3d0 100644 --- a/utils/assign_ids.rb +++ b/utils/assign_ids.rb | |||
| @@ -73,6 +73,22 @@ if old_generated.include? "door_groups" then | |||
| 73 | end | 73 | end | 
| 74 | end | 74 | end | 
| 75 | end | 75 | end | 
| 76 | if old_generated.include? "panel_doors" then | ||
| 77 | old_generated["panel_doors"].each do |room, panel_doors| | ||
| 78 | panel_doors.each do |name, id| | ||
| 79 | if id >= next_item_id then | ||
| 80 | next_item_id = id + 1 | ||
| 81 | end | ||
| 82 | end | ||
| 83 | end | ||
| 84 | end | ||
| 85 | if old_generated.include? "panel_groups" then | ||
| 86 | old_generated["panel_groups"].each do |name, id| | ||
| 87 | if id >= next_item_id then | ||
| 88 | next_item_id = id + 1 | ||
| 89 | end | ||
| 90 | end | ||
| 91 | end | ||
| 76 | if old_generated.include? "progression" then | 92 | if old_generated.include? "progression" then | 
| 77 | old_generated["progression"].each do |name, id| | 93 | old_generated["progression"].each do |name, id| | 
| 78 | if id >= next_item_id then | 94 | if id >= next_item_id then | 
| @@ -82,6 +98,7 @@ if old_generated.include? "progression" then | |||
| 82 | end | 98 | end | 
| 83 | 99 | ||
| 84 | door_groups = Set[] | 100 | door_groups = Set[] | 
| 101 | panel_groups = Set[] | ||
| 85 | 102 | ||
| 86 | config = YAML.load_file(configpath) | 103 | config = YAML.load_file(configpath) | 
| 87 | config.each do |room_name, room_data| | 104 | config.each do |room_name, room_data| | 
| @@ -163,6 +180,29 @@ config.each do |room_name, room_data| | |||
| 163 | end | 180 | end | 
| 164 | end | 181 | end | 
| 165 | 182 | ||
| 183 | if room_data.include? "panel_doors" | ||
| 184 | room_data["panel_doors"].each do |panel_door_name, panel_door| | ||
| 185 | unless old_generated.include? "panel_doors" and old_generated["panel_doors"].include? room_name and old_generated["panel_doors"][room_name].include? panel_door_name then | ||
| 186 | old_generated["panel_doors"] ||= {} | ||
| 187 | old_generated["panel_doors"][room_name] ||= {} | ||
| 188 | old_generated["panel_doors"][room_name][panel_door_name] = next_item_id | ||
| 189 | |||
| 190 | next_item_id += 1 | ||
| 191 | end | ||
| 192 | |||
| 193 | if panel_door.include? "panel_group" and not panel_groups.include? panel_door["panel_group"] then | ||
| 194 | panel_groups.add(panel_door["panel_group"]) | ||
| 195 | |||
| 196 | unless old_generated.include? "panel_groups" and old_generated["panel_groups"].include? panel_door["panel_group"] then | ||
| 197 | old_generated["panel_groups"] ||= {} | ||
| 198 | old_generated["panel_groups"][panel_door["panel_group"]] = next_item_id | ||
| 199 | |||
| 200 | next_item_id += 1 | ||
| 201 | end | ||
| 202 | end | ||
| 203 | end | ||
| 204 | end | ||
| 205 | |||
| 166 | if room_data.include? "progression" | 206 | if room_data.include? "progression" | 
| 167 | room_data["progression"].each do |progression_name, pdata| | 207 | room_data["progression"].each do |progression_name, pdata| | 
| 168 | unless old_generated.include? "progression" and old_generated["progression"].include? progression_name then | 208 | unless old_generated.include? "progression" and old_generated["progression"].include? progression_name then | 
| diff --git a/utils/pickle_static_data.py b/utils/pickle_static_data.py index e40c21c..92bcb7a 100644 --- a/utils/pickle_static_data.py +++ b/utils/pickle_static_data.py | |||
| @@ -6,8 +6,8 @@ import sys | |||
| 6 | sys.path.append(os.path.join("worlds", "lingo")) | 6 | sys.path.append(os.path.join("worlds", "lingo")) | 
| 7 | sys.path.append(".") | 7 | sys.path.append(".") | 
| 8 | sys.path.append("..") | 8 | sys.path.append("..") | 
| 9 | from datatypes import Door, DoorType, EntranceType, Painting, Panel, Progression, Room, RoomAndDoor, RoomAndPanel,\ | 9 | from datatypes import Door, DoorType, EntranceType, Painting, Panel, PanelDoor, Progression, Room, RoomAndDoor,\ | 
| 10 | RoomEntrance | 10 | RoomAndPanel, RoomAndPanelDoor, RoomEntrance | 
| 11 | 11 | ||
| 12 | import hashlib | 12 | import hashlib | 
| 13 | import pickle | 13 | import pickle | 
| @@ -18,10 +18,12 @@ import Utils | |||
| 18 | ALL_ROOMS: List[Room] = [] | 18 | ALL_ROOMS: List[Room] = [] | 
| 19 | DOORS_BY_ROOM: Dict[str, Dict[str, Door]] = {} | 19 | DOORS_BY_ROOM: Dict[str, Dict[str, Door]] = {} | 
| 20 | PANELS_BY_ROOM: Dict[str, Dict[str, Panel]] = {} | 20 | PANELS_BY_ROOM: Dict[str, Dict[str, Panel]] = {} | 
| 21 | PANEL_DOORS_BY_ROOM: Dict[str, Dict[str, PanelDoor]] = {} | ||
| 21 | PAINTINGS: Dict[str, Painting] = {} | 22 | PAINTINGS: Dict[str, Painting] = {} | 
| 22 | 23 | ||
| 23 | PROGRESSIVE_ITEMS: List[str] = [] | 24 | PROGRESSIVE_ITEMS: Set[str] = set() | 
| 24 | PROGRESSION_BY_ROOM: Dict[str, Dict[str, Progression]] = {} | 25 | PROGRESSIVE_DOORS_BY_ROOM: Dict[str, Dict[str, Progression]] = {} | 
| 26 | PROGRESSIVE_PANELS_BY_ROOM: Dict[str, Dict[str, Progression]] = {} | ||
| 25 | 27 | ||
| 26 | PAINTING_ENTRANCES: int = 0 | 28 | PAINTING_ENTRANCES: int = 0 | 
| 27 | PAINTING_EXIT_ROOMS: Set[str] = set() | 29 | PAINTING_EXIT_ROOMS: Set[str] = set() | 
| @@ -37,8 +39,13 @@ PANEL_LOCATION_IDS: Dict[str, Dict[str, int]] = {} | |||
| 37 | DOOR_LOCATION_IDS: Dict[str, Dict[str, int]] = {} | 39 | DOOR_LOCATION_IDS: Dict[str, Dict[str, int]] = {} | 
| 38 | DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {} | 40 | DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {} | 
| 39 | DOOR_GROUP_ITEM_IDS: Dict[str, int] = {} | 41 | DOOR_GROUP_ITEM_IDS: Dict[str, int] = {} | 
| 42 | PANEL_DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {} | ||
| 43 | PANEL_GROUP_ITEM_IDS: Dict[str, int] = {} | ||
| 40 | PROGRESSIVE_ITEM_IDS: Dict[str, int] = {} | 44 | PROGRESSIVE_ITEM_IDS: Dict[str, int] = {} | 
| 41 | 45 | ||
| 46 | # This doesn't need to be stored in the datafile. | ||
| 47 | PANEL_DOOR_BY_PANEL_BY_ROOM: Dict[str, Dict[str, str]] = {} | ||
| 48 | |||
| 42 | 49 | ||
| 43 | def hash_file(path): | 50 | def hash_file(path): | 
| 44 | md5 = hashlib.md5() | 51 | md5 = hashlib.md5() | 
| @@ -53,7 +60,7 @@ def hash_file(path): | |||
| 53 | 60 | ||
| 54 | def load_static_data(ll1_path, ids_path): | 61 | def load_static_data(ll1_path, ids_path): | 
| 55 | global PAINTING_EXITS, SPECIAL_ITEM_IDS, PANEL_LOCATION_IDS, DOOR_LOCATION_IDS, DOOR_ITEM_IDS, \ | 62 | global PAINTING_EXITS, SPECIAL_ITEM_IDS, PANEL_LOCATION_IDS, DOOR_LOCATION_IDS, DOOR_ITEM_IDS, \ | 
| 56 | DOOR_GROUP_ITEM_IDS, PROGRESSIVE_ITEM_IDS | 63 | DOOR_GROUP_ITEM_IDS, PROGRESSIVE_ITEM_IDS, PANEL_DOOR_ITEM_IDS, PANEL_GROUP_ITEM_IDS | 
| 57 | 64 | ||
| 58 | # Load in all item and location IDs. These are broken up into groups based on the type of item/location. | 65 | # Load in all item and location IDs. These are broken up into groups based on the type of item/location. | 
| 59 | with open(ids_path, "r") as file: | 66 | with open(ids_path, "r") as file: | 
| @@ -86,6 +93,17 @@ def load_static_data(ll1_path, ids_path): | |||
| 86 | for item_name, item_id in config["door_groups"].items(): | 93 | for item_name, item_id in config["door_groups"].items(): | 
| 87 | DOOR_GROUP_ITEM_IDS[item_name] = item_id | 94 | DOOR_GROUP_ITEM_IDS[item_name] = item_id | 
| 88 | 95 | ||
| 96 | if "panel_doors" in config: | ||
| 97 | for room_name, panel_doors in config["panel_doors"].items(): | ||
| 98 | PANEL_DOOR_ITEM_IDS[room_name] = {} | ||
| 99 | |||
| 100 | for panel_door, item_id in panel_doors.items(): | ||
| 101 | PANEL_DOOR_ITEM_IDS[room_name][panel_door] = item_id | ||
| 102 | |||
| 103 | if "panel_groups" in config: | ||
| 104 | for item_name, item_id in config["panel_groups"].items(): | ||
| 105 | PANEL_GROUP_ITEM_IDS[item_name] = item_id | ||
| 106 | |||
| 89 | if "progression" in config: | 107 | if "progression" in config: | 
| 90 | for item_name, item_id in config["progression"].items(): | 108 | for item_name, item_id in config["progression"].items(): | 
| 91 | PROGRESSIVE_ITEM_IDS[item_name] = item_id | 109 | PROGRESSIVE_ITEM_IDS[item_name] = item_id | 
| @@ -147,6 +165,46 @@ def process_entrance(source_room, doors, room_obj): | |||
| 147 | room_obj.entrances.append(RoomEntrance(source_room, door, entrance_type)) | 165 | room_obj.entrances.append(RoomEntrance(source_room, door, entrance_type)) | 
| 148 | 166 | ||
| 149 | 167 | ||
| 168 | def process_panel_door(room_name, panel_door_name, panel_door_data): | ||
| 169 | global PANEL_DOORS_BY_ROOM, PANEL_DOOR_BY_PANEL_BY_ROOM | ||
| 170 | |||
| 171 | panels: List[RoomAndPanel] = list() | ||
| 172 | for panel in panel_door_data["panels"]: | ||
| 173 | if isinstance(panel, dict): | ||
| 174 | panels.append(RoomAndPanel(panel["room"], panel["panel"])) | ||
| 175 | else: | ||
| 176 | panels.append(RoomAndPanel(room_name, panel)) | ||
| 177 | |||
| 178 | for panel in panels: | ||
| 179 | PANEL_DOOR_BY_PANEL_BY_ROOM.setdefault(panel.room, {})[panel.panel] = RoomAndPanelDoor(room_name, | ||
| 180 | panel_door_name) | ||
| 181 | |||
| 182 | if "item_name" in panel_door_data: | ||
| 183 | item_name = panel_door_data["item_name"] | ||
| 184 | else: | ||
| 185 | panel_per_room = dict() | ||
| 186 | for panel in panels: | ||
| 187 | panel_room_name = room_name if panel.room is None else panel.room | ||
| 188 | panel_per_room.setdefault(panel_room_name, []).append(panel.panel) | ||
| 189 | |||
| 190 | room_strs = list() | ||
| 191 | for door_room_str, door_panels_str in panel_per_room.items(): | ||
| 192 | room_strs.append(door_room_str + " - " + ", ".join(door_panels_str)) | ||
| 193 | |||
| 194 | if len(panels) == 1: | ||
| 195 | item_name = f"{room_strs[0]} (Panel)" | ||
| 196 | else: | ||
| 197 | item_name = " and ".join(room_strs) + " (Panels)" | ||
| 198 | |||
| 199 | if "panel_group" in panel_door_data: | ||
| 200 | panel_group = panel_door_data["panel_group"] | ||
| 201 | else: | ||
| 202 | panel_group = None | ||
| 203 | |||
| 204 | panel_door_obj = PanelDoor(item_name, panel_group) | ||
| 205 | PANEL_DOORS_BY_ROOM[room_name][panel_door_name] = panel_door_obj | ||
| 206 | |||
| 207 | |||
| 150 | def process_panel(room_name, panel_name, panel_data): | 208 | def process_panel(room_name, panel_name, panel_data): | 
| 151 | global PANELS_BY_ROOM | 209 | global PANELS_BY_ROOM | 
| 152 | 210 | ||
| @@ -227,13 +285,18 @@ def process_panel(room_name, panel_name, panel_data): | |||
| 227 | else: | 285 | else: | 
| 228 | non_counting = False | 286 | non_counting = False | 
| 229 | 287 | ||
| 288 | if room_name in PANEL_DOOR_BY_PANEL_BY_ROOM and panel_name in PANEL_DOOR_BY_PANEL_BY_ROOM[room_name]: | ||
| 289 | panel_door = PANEL_DOOR_BY_PANEL_BY_ROOM[room_name][panel_name] | ||
| 290 | else: | ||
| 291 | panel_door = None | ||
| 292 | |||
| 230 | if "location_name" in panel_data: | 293 | if "location_name" in panel_data: | 
| 231 | location_name = panel_data["location_name"] | 294 | location_name = panel_data["location_name"] | 
| 232 | else: | 295 | else: | 
| 233 | location_name = None | 296 | location_name = None | 
| 234 | 297 | ||
| 235 | panel_obj = Panel(required_rooms, required_doors, required_panels, colors, check, event, exclude_reduce, | 298 | panel_obj = Panel(required_rooms, required_doors, required_panels, colors, check, event, exclude_reduce, | 
| 236 | achievement, non_counting, location_name) | 299 | achievement, non_counting, panel_door, location_name) | 
| 237 | PANELS_BY_ROOM[room_name][panel_name] = panel_obj | 300 | PANELS_BY_ROOM[room_name][panel_name] = panel_obj | 
| 238 | 301 | ||
| 239 | 302 | ||
| @@ -325,7 +388,7 @@ def process_door(room_name, door_name, door_data): | |||
| 325 | painting_ids = [] | 388 | painting_ids = [] | 
| 326 | 389 | ||
| 327 | door_type = DoorType.NORMAL | 390 | door_type = DoorType.NORMAL | 
| 328 | if door_name.endswith(" Sunwarp"): | 391 | if room_name == "Sunwarps": | 
| 329 | door_type = DoorType.SUNWARP | 392 | door_type = DoorType.SUNWARP | 
| 330 | elif room_name == "Pilgrim Antechamber" and door_name == "Sun Painting": | 393 | elif room_name == "Pilgrim Antechamber" and door_name == "Sun Painting": | 
| 331 | door_type = DoorType.SUN_PAINTING | 394 | door_type = DoorType.SUN_PAINTING | 
| @@ -404,11 +467,11 @@ def process_sunwarp(room_name, sunwarp_data): | |||
| 404 | SUNWARP_EXITS[sunwarp_data["dots"] - 1] = room_name | 467 | SUNWARP_EXITS[sunwarp_data["dots"] - 1] = room_name | 
| 405 | 468 | ||
| 406 | 469 | ||
| 407 | def process_progression(room_name, progression_name, progression_doors): | 470 | def process_progressive_door(room_name, progression_name, progression_doors): | 
| 408 | global PROGRESSIVE_ITEMS, PROGRESSION_BY_ROOM | 471 | global PROGRESSIVE_ITEMS, PROGRESSIVE_DOORS_BY_ROOM | 
| 409 | 472 | ||
| 410 | # Progressive items are configured as a list of doors. | 473 | # Progressive items are configured as a list of doors. | 
| 411 | PROGRESSIVE_ITEMS.append(progression_name) | 474 | PROGRESSIVE_ITEMS.add(progression_name) | 
| 412 | 475 | ||
| 413 | progression_index = 1 | 476 | progression_index = 1 | 
| 414 | for door in progression_doors: | 477 | for door in progression_doors: | 
| @@ -419,11 +482,31 @@ def process_progression(room_name, progression_name, progression_doors): | |||
| 419 | door_room = room_name | 482 | door_room = room_name | 
| 420 | door_door = door | 483 | door_door = door | 
| 421 | 484 | ||
| 422 | room_progressions = PROGRESSION_BY_ROOM.setdefault(door_room, {}) | 485 | room_progressions = PROGRESSIVE_DOORS_BY_ROOM.setdefault(door_room, {}) | 
| 423 | room_progressions[door_door] = Progression(progression_name, progression_index) | 486 | room_progressions[door_door] = Progression(progression_name, progression_index) | 
| 424 | progression_index += 1 | 487 | progression_index += 1 | 
| 425 | 488 | ||
| 426 | 489 | ||
| 490 | def process_progressive_panel(room_name, progression_name, progression_panel_doors): | ||
| 491 | global PROGRESSIVE_ITEMS, PROGRESSIVE_PANELS_BY_ROOM | ||
| 492 | |||
| 493 | # Progressive items are configured as a list of panel doors. | ||
| 494 | PROGRESSIVE_ITEMS.add(progression_name) | ||
| 495 | |||
| 496 | progression_index = 1 | ||
| 497 | for panel_door in progression_panel_doors: | ||
| 498 | if isinstance(panel_door, Dict): | ||
| 499 | panel_door_room = panel_door["room"] | ||
| 500 | panel_door_door = panel_door["panel_door"] | ||
| 501 | else: | ||
| 502 | panel_door_room = room_name | ||
| 503 | panel_door_door = panel_door | ||
| 504 | |||
| 505 | room_progressions = PROGRESSIVE_PANELS_BY_ROOM.setdefault(panel_door_room, {}) | ||
| 506 | room_progressions[panel_door_door] = Progression(progression_name, progression_index) | ||
| 507 | progression_index += 1 | ||
| 508 | |||
| 509 | |||
| 427 | def process_room(room_name, room_data): | 510 | def process_room(room_name, room_data): | 
| 428 | global ALL_ROOMS | 511 | global ALL_ROOMS | 
| 429 | 512 | ||
| @@ -433,6 +516,12 @@ def process_room(room_name, room_data): | |||
| 433 | for source_room, doors in room_data["entrances"].items(): | 516 | for source_room, doors in room_data["entrances"].items(): | 
| 434 | process_entrance(source_room, doors, room_obj) | 517 | process_entrance(source_room, doors, room_obj) | 
| 435 | 518 | ||
| 519 | if "panel_doors" in room_data: | ||
| 520 | PANEL_DOORS_BY_ROOM[room_name] = dict() | ||
| 521 | |||
| 522 | for panel_door_name, panel_door_data in room_data["panel_doors"].items(): | ||
| 523 | process_panel_door(room_name, panel_door_name, panel_door_data) | ||
| 524 | |||
| 436 | if "panels" in room_data: | 525 | if "panels" in room_data: | 
| 437 | PANELS_BY_ROOM[room_name] = dict() | 526 | PANELS_BY_ROOM[room_name] = dict() | 
| 438 | 527 | ||
| @@ -454,8 +543,11 @@ def process_room(room_name, room_data): | |||
| 454 | process_sunwarp(room_name, sunwarp_data) | 543 | process_sunwarp(room_name, sunwarp_data) | 
| 455 | 544 | ||
| 456 | if "progression" in room_data: | 545 | if "progression" in room_data: | 
| 457 | for progression_name, progression_doors in room_data["progression"].items(): | 546 | for progression_name, pdata in room_data["progression"].items(): | 
| 458 | process_progression(room_name, progression_name, progression_doors) | 547 | if "doors" in pdata: | 
| 548 | process_progressive_door(room_name, progression_name, pdata["doors"]) | ||
| 549 | if "panel_doors" in pdata: | ||
| 550 | process_progressive_panel(room_name, progression_name, pdata["panel_doors"]) | ||
| 459 | 551 | ||
| 460 | ALL_ROOMS.append(room_obj) | 552 | ALL_ROOMS.append(room_obj) | 
| 461 | 553 | ||
| @@ -492,8 +584,10 @@ if __name__ == '__main__': | |||
| 492 | "ALL_ROOMS": ALL_ROOMS, | 584 | "ALL_ROOMS": ALL_ROOMS, | 
| 493 | "DOORS_BY_ROOM": DOORS_BY_ROOM, | 585 | "DOORS_BY_ROOM": DOORS_BY_ROOM, | 
| 494 | "PANELS_BY_ROOM": PANELS_BY_ROOM, | 586 | "PANELS_BY_ROOM": PANELS_BY_ROOM, | 
| 587 | "PANEL_DOORS_BY_ROOM": PANEL_DOORS_BY_ROOM, | ||
| 495 | "PROGRESSIVE_ITEMS": PROGRESSIVE_ITEMS, | 588 | "PROGRESSIVE_ITEMS": PROGRESSIVE_ITEMS, | 
| 496 | "PROGRESSION_BY_ROOM": PROGRESSION_BY_ROOM, | 589 | "PROGRESSIVE_DOORS_BY_ROOM": PROGRESSIVE_DOORS_BY_ROOM, | 
| 590 | "PROGRESSIVE_PANELS_BY_ROOM": PROGRESSIVE_PANELS_BY_ROOM, | ||
| 497 | "PAINTING_ENTRANCES": PAINTING_ENTRANCES, | 591 | "PAINTING_ENTRANCES": PAINTING_ENTRANCES, | 
| 498 | "PAINTING_EXIT_ROOMS": PAINTING_EXIT_ROOMS, | 592 | "PAINTING_EXIT_ROOMS": PAINTING_EXIT_ROOMS, | 
| 499 | "PAINTING_EXITS": PAINTING_EXITS, | 593 | "PAINTING_EXITS": PAINTING_EXITS, | 
| @@ -506,6 +600,8 @@ if __name__ == '__main__': | |||
| 506 | "DOOR_LOCATION_IDS": DOOR_LOCATION_IDS, | 600 | "DOOR_LOCATION_IDS": DOOR_LOCATION_IDS, | 
| 507 | "DOOR_ITEM_IDS": DOOR_ITEM_IDS, | 601 | "DOOR_ITEM_IDS": DOOR_ITEM_IDS, | 
| 508 | "DOOR_GROUP_ITEM_IDS": DOOR_GROUP_ITEM_IDS, | 602 | "DOOR_GROUP_ITEM_IDS": DOOR_GROUP_ITEM_IDS, | 
| 603 | "PANEL_DOOR_ITEM_IDS": PANEL_DOOR_ITEM_IDS, | ||
| 604 | "PANEL_GROUP_ITEM_IDS": PANEL_GROUP_ITEM_IDS, | ||
| 509 | "PROGRESSIVE_ITEM_IDS": PROGRESSIVE_ITEM_IDS, | 605 | "PROGRESSIVE_ITEM_IDS": PROGRESSIVE_ITEM_IDS, | 
| 510 | } | 606 | } | 
| 511 | 607 | ||
| diff --git a/utils/validate_config.rb b/utils/validate_config.rb index 498980b..70f7fc2 100644 --- a/utils/validate_config.rb +++ b/utils/validate_config.rb | |||
| @@ -33,19 +33,23 @@ end | |||
| 33 | configured_rooms = Set["Menu"] | 33 | configured_rooms = Set["Menu"] | 
| 34 | configured_doors = Set[] | 34 | configured_doors = Set[] | 
| 35 | configured_panels = Set[] | 35 | configured_panels = Set[] | 
| 36 | configured_panel_doors = Set[] | ||
| 36 | 37 | ||
| 37 | mentioned_rooms = Set[] | 38 | mentioned_rooms = Set[] | 
| 38 | mentioned_doors = Set[] | 39 | mentioned_doors = Set[] | 
| 39 | mentioned_panels = Set[] | 40 | mentioned_panels = Set[] | 
| 41 | mentioned_panel_doors = Set[] | ||
| 40 | mentioned_sunwarp_entrances = Set[] | 42 | mentioned_sunwarp_entrances = Set[] | 
| 41 | mentioned_sunwarp_exits = Set[] | 43 | mentioned_sunwarp_exits = Set[] | 
| 42 | mentioned_paintings = Set[] | 44 | mentioned_paintings = Set[] | 
| 43 | 45 | ||
| 44 | door_groups = {} | 46 | door_groups = {} | 
| 47 | panel_groups = {} | ||
| 45 | 48 | ||
| 46 | directives = Set["entrances", "panels", "doors", "paintings", "sunwarps", "progression"] | 49 | directives = Set["entrances", "panels", "doors", "panel_doors", "paintings", "sunwarps", "progression"] | 
| 47 | panel_directives = Set["id", "required_room", "required_door", "required_panel", "colors", "check", "exclude_reduce", "tag", "link", "subtag", "achievement", "copy_to_sign", "non_counting", "hunt", "location_name"] | 50 | panel_directives = Set["id", "required_room", "required_door", "required_panel", "colors", "check", "exclude_reduce", "tag", "link", "subtag", "achievement", "copy_to_sign", "non_counting", "hunt", "location_name"] | 
| 48 | door_directives = Set["id", "painting_id", "panels", "item_name", "item_group", "location_name", "skip_location", "skip_item", "door_group", "include_reduce", "event", "warp_id"] | 51 | door_directives = Set["id", "painting_id", "panels", "item_name", "item_group", "location_name", "skip_location", "skip_item", "door_group", "include_reduce", "event", "warp_id"] | 
| 52 | panel_door_directives = Set["panels", "item_name", "panel_group"] | ||
| 49 | painting_directives = Set["id", "enter_only", "exit_only", "orientation", "required_door", "required", "required_when_no_doors", "move", "req_blocked", "req_blocked_when_no_doors"] | 53 | painting_directives = Set["id", "enter_only", "exit_only", "orientation", "required_door", "required", "required_when_no_doors", "move", "req_blocked", "req_blocked_when_no_doors"] | 
| 50 | 54 | ||
| 51 | non_counting = 0 | 55 | non_counting = 0 | 
| @@ -253,6 +257,43 @@ config.each do |room_name, room| | |||
| 253 | end | 257 | end | 
| 254 | end | 258 | end | 
| 255 | 259 | ||
| 260 | (room["panel_doors"] || {}).each do |panel_door_name, panel_door| | ||
| 261 | configured_panel_doors.add("#{room_name} - #{panel_door_name}") | ||
| 262 | |||
| 263 | if panel_door.include?("panels") | ||
| 264 | panel_door["panels"].each do |panel| | ||
| 265 | if panel.kind_of? Hash then | ||
| 266 | other_room = panel.include?("room") ? panel["room"] : room_name | ||
| 267 | mentioned_panels.add("#{other_room} - #{panel["panel"]}") | ||
| 268 | else | ||
| 269 | other_room = panel.include?("room") ? panel["room"] : room_name | ||
| 270 | mentioned_panels.add("#{room_name} - #{panel}") | ||
| 271 | end | ||
| 272 | end | ||
| 273 | else | ||
| 274 | puts "#{room_name} - #{panel_door_name} :::: Missing panels field" | ||
| 275 | end | ||
| 276 | |||
| 277 | if panel_door.include?("panel_group") | ||
| 278 | panel_groups[panel_door["panel_group"]] ||= 0 | ||
| 279 | panel_groups[panel_door["panel_group"]] += 1 | ||
| 280 | end | ||
| 281 | |||
| 282 | bad_subdirectives = [] | ||
| 283 | panel_door.keys.each do |key| | ||
| 284 | unless panel_door_directives.include?(key) then | ||
| 285 | bad_subdirectives << key | ||
| 286 | end | ||
| 287 | end | ||
| 288 | unless bad_subdirectives.empty? then | ||
| 289 | puts "#{room_name} - #{panel_door_name} :::: Panel door has the following invalid subdirectives: #{bad_subdirectives.join(", ")}" | ||
| 290 | end | ||
| 291 | |||
| 292 | unless ids.include?("panel_doors") and ids["panel_doors"].include?(room_name) and ids["panel_doors"][room_name].include?(panel_door_name) | ||
| 293 | puts "#{room_name} - #{panel_door_name} :::: Panel door is missing an item ID" | ||
| 294 | end | ||
| 295 | end | ||
| 296 | |||
| 256 | (room["paintings"] || []).each do |painting| | 297 | (room["paintings"] || []).each do |painting| | 
| 257 | if painting.include?("id") and painting["id"].kind_of? String then | 298 | if painting.include?("id") and painting["id"].kind_of? String then | 
| 258 | unless paintings.include? painting["id"] then | 299 | unless paintings.include? painting["id"] then | 
| @@ -327,12 +368,24 @@ config.each do |room_name, room| | |||
| 327 | end | 368 | end | 
| 328 | end | 369 | end | 
| 329 | 370 | ||
| 330 | (room["progression"] || {}).each do |progression_name, door_list| | 371 | (room["progression"] || {}).each do |progression_name, pdata| | 
| 331 | door_list.each do |door| | 372 | if pdata.include? "doors" then | 
| 332 | if door.kind_of? Hash then | 373 | pdata["doors"].each do |door| | 
| 333 | mentioned_doors.add("#{door["room"]} - #{door["door"]}") | 374 | if door.kind_of? Hash then | 
| 334 | else | 375 | mentioned_doors.add("#{door["room"]} - #{door["door"]}") | 
| 335 | mentioned_doors.add("#{room_name} - #{door}") | 376 | else | 
| 377 | mentioned_doors.add("#{room_name} - #{door}") | ||
| 378 | end | ||
| 379 | end | ||
| 380 | end | ||
| 381 | |||
| 382 | if pdata.include? "panel_doors" then | ||
| 383 | pdata["panel_doors"].each do |panel_door| | ||
| 384 | if panel_door.kind_of? Hash then | ||
| 385 | mentioned_panel_doors.add("#{panel_door["room"]} - #{panel_door["panel_door"]}") | ||
| 386 | else | ||
| 387 | mentioned_panel_doors.add("#{room_name} - #{panel_door}") | ||
| 388 | end | ||
| 336 | end | 389 | end | 
| 337 | end | 390 | end | 
| 338 | 391 | ||
| @@ -344,17 +397,22 @@ end | |||
| 344 | 397 | ||
| 345 | errored_rooms = mentioned_rooms - configured_rooms | 398 | errored_rooms = mentioned_rooms - configured_rooms | 
| 346 | unless errored_rooms.empty? then | 399 | unless errored_rooms.empty? then | 
| 347 | puts "The folloring rooms are mentioned but do not exist: " + errored_rooms.to_s | 400 | puts "The following rooms are mentioned but do not exist: " + errored_rooms.to_s | 
| 348 | end | 401 | end | 
| 349 | 402 | ||
| 350 | errored_panels = mentioned_panels - configured_panels | 403 | errored_panels = mentioned_panels - configured_panels | 
| 351 | unless errored_panels.empty? then | 404 | unless errored_panels.empty? then | 
| 352 | puts "The folloring panels are mentioned but do not exist: " + errored_panels.to_s | 405 | puts "The following panels are mentioned but do not exist: " + errored_panels.to_s | 
| 353 | end | 406 | end | 
| 354 | 407 | ||
| 355 | errored_doors = mentioned_doors - configured_doors | 408 | errored_doors = mentioned_doors - configured_doors | 
| 356 | unless errored_doors.empty? then | 409 | unless errored_doors.empty? then | 
| 357 | puts "The folloring doors are mentioned but do not exist: " + errored_doors.to_s | 410 | puts "The following doors are mentioned but do not exist: " + errored_doors.to_s | 
| 411 | end | ||
| 412 | |||
| 413 | errored_panel_doors = mentioned_panel_doors - configured_panel_doors | ||
| 414 | unless errored_panel_doors.empty? then | ||
| 415 | puts "The following panel doors are mentioned but do not exist: " + errored_panel_doors.to_s | ||
| 358 | end | 416 | end | 
| 359 | 417 | ||
| 360 | door_groups.each do |group,num| | 418 | door_groups.each do |group,num| | 
| @@ -367,6 +425,16 @@ door_groups.each do |group,num| | |||
| 367 | end | 425 | end | 
| 368 | end | 426 | end | 
| 369 | 427 | ||
| 428 | panel_groups.each do |group,num| | ||
| 429 | if num == 1 then | ||
| 430 | puts "Panel group \"#{group}\" only has one panel in it" | ||
| 431 | end | ||
| 432 | |||
| 433 | unless ids.include?("panel_groups") and ids["panel_groups"].include?(group) | ||
| 434 | puts "#{group} :::: Panel group is missing an item ID" | ||
| 435 | end | ||
| 436 | end | ||
| 437 | |||
| 370 | slashed_rooms = configured_rooms.select do |room| | 438 | slashed_rooms = configured_rooms.select do |room| | 
| 371 | room.include? "/" | 439 | room.include? "/" | 
| 372 | end | 440 | end | 
