From 3b415b3f5f182238da9ed83e0b2b07fb07044e04 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Fri, 6 Feb 2026 13:03:32 -0500 Subject: Annotated RTE rooms for most maps --- data/ids.yaml | 59 +++++++++++++++++++++++++++++++ data/maps/control_center/metadata.txtpb | 1 + data/maps/daedalus/metadata.txtpb | 1 + data/maps/demo/metadata.txtpb | 2 ++ data/maps/four_rooms/metadata.txtpb | 1 + data/maps/icarus/metadata.txtpb | 1 + data/maps/the_advanced/metadata.txtpb | 1 + data/maps/the_ancient/metadata.txtpb | 1 + data/maps/the_bearer/metadata.txtpb | 1 + data/maps/the_between/metadata.txtpb | 1 + data/maps/the_butterfly/metadata.txtpb | 1 + data/maps/the_charismatic/metadata.txtpb | 1 + data/maps/the_colorful/metadata.txtpb | 1 + data/maps/the_congruent/metadata.txtpb | 1 + data/maps/the_crystalline/metadata.txtpb | 1 + data/maps/the_darkroom/metadata.txtpb | 1 + data/maps/the_digital/metadata.txtpb | 1 + data/maps/the_door/metadata.txtpb | 1 + data/maps/the_double_sided/metadata.txtpb | 1 + data/maps/the_entry/metadata.txtpb | 2 ++ data/maps/the_extravagant/metadata.txtpb | 1 + data/maps/the_fuzzy/metadata.txtpb | 1 + data/maps/the_gallery/metadata.txtpb | 1 + data/maps/the_gold/metadata.txtpb | 1 + data/maps/the_graveyard/metadata.txtpb | 1 + data/maps/the_great/metadata.txtpb | 1 + data/maps/the_hinterlands/metadata.txtpb | 2 ++ data/maps/the_hive/metadata.txtpb | 1 + data/maps/the_impressive/metadata.txtpb | 1 + data/maps/the_invisible/metadata.txtpb | 1 + data/maps/the_jubilant/metadata.txtpb | 1 + data/maps/the_keen/metadata.txtpb | 1 + data/maps/the_liberated/metadata.txtpb | 1 + data/maps/the_linear/metadata.txtpb | 1 + data/maps/the_lionized/metadata.txtpb | 1 + data/maps/the_literate/metadata.txtpb | 1 + data/maps/the_lively/metadata.txtpb | 1 + data/maps/the_nuanced/metadata.txtpb | 1 + data/maps/the_orb/metadata.txtpb | 1 + data/maps/the_owl/metadata.txtpb | 1 + data/maps/the_parthenon/metadata.txtpb | 1 + data/maps/the_partial/metadata.txtpb | 1 + data/maps/the_perceptive/metadata.txtpb | 1 + data/maps/the_plaza/metadata.txtpb | 1 + data/maps/the_quiet/metadata.txtpb | 1 + data/maps/the_relentless/metadata.txtpb | 1 + data/maps/the_repetitive/metadata.txtpb | 1 + data/maps/the_revitalized/metadata.txtpb | 1 + data/maps/the_shop/metadata.txtpb | 1 + data/maps/the_sirenic/metadata.txtpb | 1 + data/maps/the_stellar/metadata.txtpb | 1 + data/maps/the_stormy/metadata.txtpb | 1 + data/maps/the_sturdy/metadata.txtpb | 1 + data/maps/the_sun_temple/metadata.txtpb | 1 + data/maps/the_sweet/metadata.txtpb | 1 + data/maps/the_symbolic/metadata.txtpb | 1 + data/maps/the_talented/metadata.txtpb | 1 + data/maps/the_tenacious/metadata.txtpb | 1 + data/maps/the_three_doors/metadata.txtpb | 1 + data/maps/the_tower/metadata.txtpb | 1 + data/maps/the_tree/metadata.txtpb | 1 + data/maps/the_unkempt/metadata.txtpb | 1 + data/maps/the_unyielding/metadata.txtpb | 1 + data/maps/the_wise/metadata.txtpb | 1 + data/maps/the_wondrous/metadata.txtpb | 1 + data/maps/the_words/metadata.txtpb | 1 + proto/data.proto | 1 + proto/human.proto | 2 ++ tools/assign_ids/main.cpp | 35 ++++++++++++++++-- tools/datapacker/main.cpp | 5 +++ tools/util/ids_yaml_format.cpp | 8 +++++ tools/validator/human_processor.cpp | 16 +++++++++ tools/validator/main.cpp | 4 ++- tools/validator/structs.h | 4 +++ tools/validator/validator.cpp | 21 +++++++++++ 75 files changed, 219 insertions(+), 4 deletions(-) diff --git a/data/ids.yaml b/data/ids.yaml index 0042899..f9c59aa 100644 --- a/data/ids.yaml +++ b/data/ids.yaml @@ -86,6 +86,7 @@ maps: Unkempt Door: 2712 Unyielding Door: 2720 X1 Door: 2711 + rte: 3385 daedalus: rooms: After Bee Room: @@ -1228,6 +1229,7 @@ maps: Zoo Prize Door: 1599 Zoo South Entrance: 1596 Zoo West Entrance: 1594 + rte: 3376 demo: rooms: Backside Area: @@ -1370,6 +1372,7 @@ maps: Keyholder Door: 5 Synonyms Door: 2 Time Door: 3 + rte: 3415 icarus: rooms: Above Trans Rights: @@ -1499,6 +1502,7 @@ maps: These Door: 2874 Troupe Door: 2867 Woman Door: 2859 + rte: 3416 the_advanced: rooms: CBA: @@ -1543,6 +1547,7 @@ maps: MASTERY: 2969 doors: Side Room Puzzles: 2934 + rte: 3380 the_ancient: rooms: Inside: @@ -1554,6 +1559,7 @@ maps: doors: Front Door: 41 Lavender Cubes: 43 + rte: 3412 the_bearer: rooms: Back Area: @@ -1641,6 +1647,7 @@ maps: Control Center Color Panel: 3303 Exit Door: 47 Overlook Door: 46 + rte: 3373 the_between: rooms: Control Center Side: @@ -1696,6 +1703,7 @@ maps: Purple Puzzles: 87 Red Puzzles: 81 Yellow Puzzles: 82 + rte: 3408 the_butterfly: rooms: Main Area: @@ -1723,6 +1731,7 @@ maps: Mastery: masteries: MASTERY: 140 + rte: 3395 the_charismatic: rooms: Latitude Middle: @@ -1760,6 +1769,7 @@ maps: Mastery: masteries: MASTERY: 2988 + rte: 3396 the_colorful: rooms: Black Room: @@ -1826,6 +1836,7 @@ maps: White Door: 141 Window Door: 152 Yellow Door: 146 + rte: 3365 the_congruent: rooms: Flipped Magenta Room: @@ -1885,6 +1896,7 @@ maps: Obverse Magenta Door: 173 Obverse Yellow Door: 178 Obverse Yellow Puzzles: 179 + rte: 3369 the_crystalline: rooms: Flip Area: @@ -1902,6 +1914,7 @@ maps: MASTERY: 2993 doors: Checkpoint Panels: 3307 + rte: 3367 the_darkroom: rooms: Congruent Entrance: @@ -1956,6 +1969,7 @@ maps: Double Sided Entrance: 224 Second Room Entrance: 219 Third Room Entrance: 220 + rte: 3409 the_digital: rooms: Chamber: @@ -1995,6 +2009,7 @@ maps: Control Center Blue Panel: 3308 Gallery Entrance: 245 Tree Entrance: 247 + rte: 3403 the_door: rooms: Main Area: @@ -2062,6 +2077,7 @@ maps: 10 Panels: 3310 15 Panels: 3311 5 Panels: 3309 + rte: 3384 the_entry: rooms: Blue Alcove: @@ -2312,6 +2328,7 @@ maps: panels: CACTUS: 410 TAIL: 411 + rte: 3397 the_fuzzy: rooms: Main Area: @@ -2339,6 +2356,7 @@ maps: doors: Black Panels: 3021 Green Panels: 3321 + rte: 3420 the_gallery: rooms: Back Room: @@ -2373,6 +2391,7 @@ maps: Wise Painting: 416 Wondrous Painting: 422 Words Painting: 424 + rte: 3394 the_gold: rooms: The Whole Thing: @@ -2391,6 +2410,7 @@ maps: SEVERE: 437 doors: Remember Panel: 3323 + rte: 3370 the_great: rooms: Back Area: @@ -2698,6 +2718,7 @@ maps: West/East Divider: 443 Why Is It Not Red: 3325 Zero Room Panels: 470 + rte: 3405 the_hinterlands: rooms: Main Area: @@ -2764,6 +2785,7 @@ maps: WILDFLOWER: 670 doors: Room 8 Door: 627 + rte: 3401 the_impressive: rooms: Green Eye: @@ -2793,6 +2815,7 @@ maps: Front Door: 671 Green Eye Panels: 3337 Side Door: 672 + rte: 3386 the_invisible: rooms: Entrance: @@ -2807,6 +2830,7 @@ maps: ENTRY: 3215 doors: Maze Entrance: 684 + rte: 3410 the_jubilant: rooms: Main Area: @@ -2838,6 +2862,7 @@ maps: doors: Side Door: 687 Side Room Puzzles: 3339 + rte: 3411 the_keen: rooms: Main Area: @@ -2855,6 +2880,7 @@ maps: GREAT: 3217 doors: All Panels: 707 + rte: 3402 the_liberated: rooms: Puzzle Room: @@ -2871,6 +2897,7 @@ maps: ENTRY: 3218 doors: Door: 718 + rte: 3422 the_linear: rooms: Room: @@ -2887,6 +2914,7 @@ maps: GREAT: 3219 doors: Behind The Keen Gravestone: 727 + rte: 3393 the_lionized: rooms: Puzzle Room: @@ -2901,6 +2929,7 @@ maps: ROCK: 740 ports: ENTRY: 3220 + rte: 3404 the_literate: rooms: Puzzle Room: @@ -2917,6 +2946,7 @@ maps: ENTRY: 3221 doors: Door: 745 + rte: 3382 the_lively: rooms: Puzzle Room: @@ -2931,6 +2961,7 @@ maps: SOPRANO: 757 ports: BETWEEN: 3222 + rte: 3383 the_nuanced: rooms: Back Room: @@ -2968,6 +2999,7 @@ maps: Green Side Puzzles: 764 Main Room Door: 2750 Stores Panel: 3340 + rte: 3398 the_orb: rooms: B Room: @@ -2992,6 +3024,7 @@ maps: Middle Room: ports: MID: 3226 + rte: 3381 the_owl: rooms: Blue Room: @@ -3075,6 +3108,7 @@ maps: Sky Owl: 813 Sky Top Doors: 805 White Owl: 816 + rte: 3414 the_parthenon: rooms: Lavender Area: @@ -3100,6 +3134,7 @@ maps: doors: K2 Door: 852 Lavender Area Puzzles: 3351 + rte: 3418 the_partial: rooms: Control Center Entrance: @@ -3139,11 +3174,13 @@ maps: L Entered: 2843 Main Room Puzzles: 863 P Door: 864 + rte: 3407 the_perceptive: rooms: Main Area: ports: CC: 3235 + rte: 3374 the_plaza: rooms: Bottom Left Room: @@ -3263,6 +3300,7 @@ maps: Southwest Puzzles: 898 Symbolic Entrance: 889 Turtle Entrance: 891 + rte: 3390 the_quiet: rooms: Keyholder Room: @@ -3286,6 +3324,7 @@ maps: DAEDALUS: 3242 doors: Side Door: 970 + rte: 3419 the_relentless: rooms: All: @@ -3481,6 +3520,7 @@ maps: Magenta Puzzles: 1033 Yellow Door: 1030 Yellow Puzzles: 1034 + rte: 3377 the_revitalized: rooms: Bye Room: @@ -3508,6 +3548,7 @@ maps: WON: 1135 doors: Return Panel: 1128 + rte: 3378 the_shop: rooms: Main Area: @@ -3542,6 +3583,7 @@ maps: Books Puzzles: 1136 Games Puzzles: 1137 N Entered: 2971 + rte: 3421 the_sirenic: rooms: Mastery: @@ -3572,6 +3614,7 @@ maps: PLAZA: 3248 doors: Entrance: 1161 + rte: 3389 the_stellar: rooms: Blue Panel: @@ -3624,6 +3667,7 @@ maps: Entrance: 2995 Question Panels: 3017 Welcome Back Panels: 3359 + rte: 3387 the_stormy: rooms: Center: @@ -3654,6 +3698,7 @@ maps: panels: RAIN: 1191 SNOW: 1190 + rte: 3368 the_sturdy: rooms: Main Area: @@ -3672,6 +3717,7 @@ maps: S2 Area: panels: COLORS: 1201 + rte: 3391 the_sun_temple: rooms: Entrance: @@ -3693,6 +3739,7 @@ maps: LAWN: 1215 doors: Entrance: 1210 + rte: 3375 the_sweet: rooms: Main Area: @@ -3728,6 +3775,7 @@ maps: ports: EXIT1: 3254 EXIT2: 3255 + rte: 3400 the_symbolic: rooms: Black Room: @@ -3924,6 +3972,7 @@ maps: Tutorial Door: 2754 Tutorial Panels: 2283 Whirred Room Panels: 2284 + rte: 3379 the_talented: rooms: Back Room: @@ -3961,6 +4010,7 @@ maps: Brown Side Panels: 2428 Keyholder Hint Panel: 3360 Main Room Door: 2429 + rte: 3388 the_tenacious: rooms: Color Room: @@ -3989,6 +4039,7 @@ maps: doors: K Entered: 2844 Paintings Door: 2453 + rte: 3399 the_three_doors: rooms: Dead End Room: @@ -4032,6 +4083,7 @@ maps: NEXT: 3266 doors: The Three Doors Gravestone: 2460 + rte: 3392 the_tower: rooms: First Floor: @@ -4111,6 +4163,7 @@ maps: Fourth Floor Puzzles: 2481 Second Floor Puzzles: 2479 Third Floor Puzzles: 2480 + rte: 3413 the_tree: rooms: Bearer Entrance: @@ -4156,6 +4209,7 @@ maps: doors: Control Center Brown Door: 2548 The Tree Gravestone: 2549 + rte: 3371 the_unkempt: rooms: Control Center Entrance: @@ -4277,6 +4331,7 @@ maps: Near Teal Door Panels: 3361 Routine Out Chute: 2584 W2 Room Door: 2581 + rte: 3417 the_unyielding: rooms: Bearer Entrance: @@ -4539,6 +4594,7 @@ maps: Southwest Corner Behind: 1254 Southwest Room: 1431 Yellow Room Puzzles: 1250 + rte: 3366 the_wise: rooms: Entry: @@ -4571,6 +4627,7 @@ maps: WORDS: 2688 doors: Front Door: 2666 + rte: 3372 the_wondrous: rooms: Entry: @@ -4593,6 +4650,7 @@ maps: SHRINK: 2699 doors: Shrink Door: 2689 + rte: 3406 the_words: rooms: Main Area: @@ -4607,6 +4665,7 @@ maps: TREE: 2705 ports: ENTRY: 3283 + rte: 3423 letters: a1: 596 a2: 6 diff --git a/data/maps/control_center/metadata.txtpb b/data/maps/control_center/metadata.txtpb index bf89670..e56f7a9 100644 --- a/data/maps/control_center/metadata.txtpb +++ b/data/maps/control_center/metadata.txtpb @@ -1 +1,2 @@ display_name: "Control Center" +rte_room: "Main Area" diff --git a/data/maps/daedalus/metadata.txtpb b/data/maps/daedalus/metadata.txtpb index 6ad90e1..2f3da90 100644 --- a/data/maps/daedalus/metadata.txtpb +++ b/data/maps/daedalus/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "Daedalus" +rte_room: "Starting Room" daedalus_only_mode: DAED_ONLY_ALLOW # These paintings can't be shuffled because they are behind panels. excluded_nodes: "Components/Paintings/Group3/mouse" diff --git a/data/maps/demo/metadata.txtpb b/data/maps/demo/metadata.txtpb index 4f61386..acaf461 100644 --- a/data/maps/demo/metadata.txtpb +++ b/data/maps/demo/metadata.txtpb @@ -1,5 +1,7 @@ display_name: "Demo" type: DEMO +# No RTE because this is a secret map. + # This painting is above a panel and can't be entered. excluded_nodes: "Meshes/owl" # The map's mastery is created at runtime. diff --git a/data/maps/four_rooms/metadata.txtpb b/data/maps/four_rooms/metadata.txtpb index ac4631d..ba66847 100644 --- a/data/maps/four_rooms/metadata.txtpb +++ b/data/maps/four_rooms/metadata.txtpb @@ -1 +1,2 @@ display_name: "Four Rooms" +rte_room: "Synonyms Room" diff --git a/data/maps/icarus/metadata.txtpb b/data/maps/icarus/metadata.txtpb index 8512d8e..c2a3656 100644 --- a/data/maps/icarus/metadata.txtpb +++ b/data/maps/icarus/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "Icarus" type: ICARUS +rte_room: "Welcome Spine (Obverse)" # The map's mastery is created at runtime. custom_nodes: "Components/Collectables/collectable" diff --git a/data/maps/the_advanced/metadata.txtpb b/data/maps/the_advanced/metadata.txtpb index cee10b6..71d3925 100644 --- a/data/maps/the_advanced/metadata.txtpb +++ b/data/maps/the_advanced/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Advanced" type: GIFT_MAP +rte_room: "Main Area" # The map's mastery is created at runtime. custom_nodes: "Components/Collectables/collectable" diff --git a/data/maps/the_ancient/metadata.txtpb b/data/maps/the_ancient/metadata.txtpb index cf6bce3..0f321dd 100644 --- a/data/maps/the_ancient/metadata.txtpb +++ b/data/maps/the_ancient/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Ancient" +rte_room: "Outside" diff --git a/data/maps/the_bearer/metadata.txtpb b/data/maps/the_bearer/metadata.txtpb index 584c71e..003473a 100644 --- a/data/maps/the_bearer/metadata.txtpb +++ b/data/maps/the_bearer/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Bearer" +rte_room: "Entry" diff --git a/data/maps/the_between/metadata.txtpb b/data/maps/the_between/metadata.txtpb index 33f96a1..6134447 100644 --- a/data/maps/the_between/metadata.txtpb +++ b/data/maps/the_between/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Between" +rte_room: "Main Area" diff --git a/data/maps/the_butterfly/metadata.txtpb b/data/maps/the_butterfly/metadata.txtpb index 5206dfe..5933359 100644 --- a/data/maps/the_butterfly/metadata.txtpb +++ b/data/maps/the_butterfly/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Butterfly" +rte_room: "Main Area" diff --git a/data/maps/the_charismatic/metadata.txtpb b/data/maps/the_charismatic/metadata.txtpb index 8d26105..740c04a 100644 --- a/data/maps/the_charismatic/metadata.txtpb +++ b/data/maps/the_charismatic/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Charismatic" type: GIFT_MAP +rte_room: "Main Area" # The map's mastery is created at runtime. custom_nodes: "Components/Collectables/collectable" diff --git a/data/maps/the_colorful/metadata.txtpb b/data/maps/the_colorful/metadata.txtpb index 5e67428..1300c79 100644 --- a/data/maps/the_colorful/metadata.txtpb +++ b/data/maps/the_colorful/metadata.txtpb @@ -1,3 +1,4 @@ display_name: "The Colorful" +rte_room: "White Room" # This has something to do with the FISH/FISHES proxy. excluded_nodes: "Components/panel_fake" diff --git a/data/maps/the_congruent/metadata.txtpb b/data/maps/the_congruent/metadata.txtpb index 6260ed4..038bbd6 100644 --- a/data/maps/the_congruent/metadata.txtpb +++ b/data/maps/the_congruent/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Congruent" +rte_room: "Main Area" worldport_entrance { room: "Main Area" name: "DARKROOM" diff --git a/data/maps/the_crystalline/metadata.txtpb b/data/maps/the_crystalline/metadata.txtpb index 09b0f1d..2447af6 100644 --- a/data/maps/the_crystalline/metadata.txtpb +++ b/data/maps/the_crystalline/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Crystalline" type: GIFT_MAP +rte_room: "Main Area" # The map's mastery is created at runtime. custom_nodes: "Components/Collectables/collectable" diff --git a/data/maps/the_darkroom/metadata.txtpb b/data/maps/the_darkroom/metadata.txtpb index e4a1290..0b122e9 100644 --- a/data/maps/the_darkroom/metadata.txtpb +++ b/data/maps/the_darkroom/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Darkroom" +rte_room: "First Room" diff --git a/data/maps/the_digital/metadata.txtpb b/data/maps/the_digital/metadata.txtpb index e505dcf..ce2f2c5 100644 --- a/data/maps/the_digital/metadata.txtpb +++ b/data/maps/the_digital/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Digital" +rte_room: "Main Area" diff --git a/data/maps/the_door/metadata.txtpb b/data/maps/the_door/metadata.txtpb index 85dc340..a253d9f 100644 --- a/data/maps/the_door/metadata.txtpb +++ b/data/maps/the_door/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Door" +# No RTE because it would make The Wondrous pointless. diff --git a/data/maps/the_double_sided/metadata.txtpb b/data/maps/the_double_sided/metadata.txtpb index 6f56c63..1bcf6ac 100644 --- a/data/maps/the_double_sided/metadata.txtpb +++ b/data/maps/the_double_sided/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Double Sided" +rte_room: "Start" worldport_entrance { room: "Start" name: "DARKROOM" diff --git a/data/maps/the_entry/metadata.txtpb b/data/maps/the_entry/metadata.txtpb index da2194b..d20137c 100644 --- a/data/maps/the_entry/metadata.txtpb +++ b/data/maps/the_entry/metadata.txtpb @@ -1,4 +1,6 @@ display_name: "The Entry" +# No RTE because this map is always an RTE. + # This is a debug warp to The Ancient and as far as I can tell there is no way # to access it. excluded_nodes: "Components/Warps/worldport-test" diff --git a/data/maps/the_extravagant/metadata.txtpb b/data/maps/the_extravagant/metadata.txtpb index 0a35c90..77d3b4b 100644 --- a/data/maps/the_extravagant/metadata.txtpb +++ b/data/maps/the_extravagant/metadata.txtpb @@ -1,3 +1,4 @@ display_name: "The Extravagant" +rte_room: "Y Minus First Floor" # This appears to be completely inaccessible. excluded_nodes: "Components/Warps/worldport" diff --git a/data/maps/the_fuzzy/metadata.txtpb b/data/maps/the_fuzzy/metadata.txtpb index b4178c7..ded955b 100644 --- a/data/maps/the_fuzzy/metadata.txtpb +++ b/data/maps/the_fuzzy/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Fuzzy" type: GIFT_MAP +rte_room: "Main Area" # The map's mastery is created at runtime. custom_nodes: "Components/Collectables/collectable" diff --git a/data/maps/the_gallery/metadata.txtpb b/data/maps/the_gallery/metadata.txtpb index 9d02a11..a1bbe25 100644 --- a/data/maps/the_gallery/metadata.txtpb +++ b/data/maps/the_gallery/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Gallery" +rte_room: "Main Area" daedalus_only_mode: DAED_ONLY_PARTIAL # These are the eyes in the foyer, and aren't normal paintings. excluded_nodes: "Components/Paintings/Starting/eye" diff --git a/data/maps/the_gold/metadata.txtpb b/data/maps/the_gold/metadata.txtpb index c4a8b3b..7c20bae 100644 --- a/data/maps/the_gold/metadata.txtpb +++ b/data/maps/the_gold/metadata.txtpb @@ -1,2 +1,3 @@ display_name: "The Gold" daedalus_only_mode: DAED_ONLY_ALLOW +# No RTE because it would trivialize Gold Ending. diff --git a/data/maps/the_graveyard/metadata.txtpb b/data/maps/the_graveyard/metadata.txtpb index 0bac222..47a48e0 100644 --- a/data/maps/the_graveyard/metadata.txtpb +++ b/data/maps/the_graveyard/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Graveyard" +rte_room: "Outside" # These really shouldn't be shuffled because it would make Black Ending trivial. excluded_nodes: "Components/Paintings/grave" excluded_nodes: "Components/Paintings/grave2" diff --git a/data/maps/the_great/metadata.txtpb b/data/maps/the_great/metadata.txtpb index b01faf7..7bbecd4 100644 --- a/data/maps/the_great/metadata.txtpb +++ b/data/maps/the_great/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Great" +rte_room: "Main Area" # This can't be shuffled because it is tilted. excluded_nodes: "Components/Paintings/u" # This can't be shuffled because it is on the ground. diff --git a/data/maps/the_hinterlands/metadata.txtpb b/data/maps/the_hinterlands/metadata.txtpb index dd1e627..8148c2a 100644 --- a/data/maps/the_hinterlands/metadata.txtpb +++ b/data/maps/the_hinterlands/metadata.txtpb @@ -1,4 +1,6 @@ display_name: "The Hinterlands" +# No RTE because the map is not randomized. + # I'm not currently planning on shuffling anything in here. excluded_nodes: "Components/Paintings/C" excluded_nodes: "Components/Paintings/E" diff --git a/data/maps/the_hive/metadata.txtpb b/data/maps/the_hive/metadata.txtpb index 8f3894c..7be7b9e 100644 --- a/data/maps/the_hive/metadata.txtpb +++ b/data/maps/the_hive/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Hive" +rte_room: "Main Area" diff --git a/data/maps/the_impressive/metadata.txtpb b/data/maps/the_impressive/metadata.txtpb index 63929cb..7a0a052 100644 --- a/data/maps/the_impressive/metadata.txtpb +++ b/data/maps/the_impressive/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Impressive" +rte_room: "Lobby" # These are apparently little eyes on the Green Eye panel pedestals? I don't # think they're ever visible in gameplay. excluded_nodes: "Meshes/eye" diff --git a/data/maps/the_invisible/metadata.txtpb b/data/maps/the_invisible/metadata.txtpb index 967bf19..e980466 100644 --- a/data/maps/the_invisible/metadata.txtpb +++ b/data/maps/the_invisible/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Invisible" +rte_room: "Entrance" diff --git a/data/maps/the_jubilant/metadata.txtpb b/data/maps/the_jubilant/metadata.txtpb index 4af1874..019b0b2 100644 --- a/data/maps/the_jubilant/metadata.txtpb +++ b/data/maps/the_jubilant/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Jubilant" +rte_room: "Main Area" worldport_entrance { room: "Main Area" name: "GREAT" diff --git a/data/maps/the_keen/metadata.txtpb b/data/maps/the_keen/metadata.txtpb index 909f420..8417c2e 100644 --- a/data/maps/the_keen/metadata.txtpb +++ b/data/maps/the_keen/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Keen" +rte_room: "Main Area" worldport_entrance { room: "Main Area" name: "GREAT" diff --git a/data/maps/the_liberated/metadata.txtpb b/data/maps/the_liberated/metadata.txtpb index b9b4321..ebedbec 100644 --- a/data/maps/the_liberated/metadata.txtpb +++ b/data/maps/the_liberated/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Liberated" +rte_room: "Puzzle Room" worldport_entrance { room: "Puzzle Room" name: "ENTRY" diff --git a/data/maps/the_linear/metadata.txtpb b/data/maps/the_linear/metadata.txtpb index 838bb2b..cc9b4ce 100644 --- a/data/maps/the_linear/metadata.txtpb +++ b/data/maps/the_linear/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Linear" +rte_room: "Room" worldport_entrance { room: "Room" name: "GREAT" diff --git a/data/maps/the_lionized/metadata.txtpb b/data/maps/the_lionized/metadata.txtpb index 8d6168d..587143d 100644 --- a/data/maps/the_lionized/metadata.txtpb +++ b/data/maps/the_lionized/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Lionized" +rte_room: "Puzzle Room" worldport_entrance { room: "Puzzle Room" name: "ENTRY" diff --git a/data/maps/the_literate/metadata.txtpb b/data/maps/the_literate/metadata.txtpb index 0e04306..28f5ccd 100644 --- a/data/maps/the_literate/metadata.txtpb +++ b/data/maps/the_literate/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Literate" +rte_room: "Puzzle Room" worldport_entrance { room: "Puzzle Room" name: "ENTRY" diff --git a/data/maps/the_lively/metadata.txtpb b/data/maps/the_lively/metadata.txtpb index acd1177..c088afe 100644 --- a/data/maps/the_lively/metadata.txtpb +++ b/data/maps/the_lively/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Lively" +rte_room: "Puzzle Room" worldport_entrance { room: "Puzzle Room" name: "BETWEEN" diff --git a/data/maps/the_nuanced/metadata.txtpb b/data/maps/the_nuanced/metadata.txtpb index 4ac9b13..a3405ff 100644 --- a/data/maps/the_nuanced/metadata.txtpb +++ b/data/maps/the_nuanced/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Nuanced" +rte_room: "Main Room" worldport_entrance { room: "Main Room" name: "UNYIELDING" diff --git a/data/maps/the_orb/metadata.txtpb b/data/maps/the_orb/metadata.txtpb index 0b25353..a33dbf6 100644 --- a/data/maps/the_orb/metadata.txtpb +++ b/data/maps/the_orb/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Orb" +rte_room: "Main Area" # These are inaccessible, and were probably just copy pasted from the other # rooms. excluded_nodes: "Components/Warps/worldport2" diff --git a/data/maps/the_owl/metadata.txtpb b/data/maps/the_owl/metadata.txtpb index a2004f8..11d79b0 100644 --- a/data/maps/the_owl/metadata.txtpb +++ b/data/maps/the_owl/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Owl" +rte_room: "R2C2 Bottom" diff --git a/data/maps/the_parthenon/metadata.txtpb b/data/maps/the_parthenon/metadata.txtpb index 8696c33..203d712 100644 --- a/data/maps/the_parthenon/metadata.txtpb +++ b/data/maps/the_parthenon/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Parthenon" +rte_room: "Main Area" diff --git a/data/maps/the_partial/metadata.txtpb b/data/maps/the_partial/metadata.txtpb index 48e9f42..9d5ad4a 100644 --- a/data/maps/the_partial/metadata.txtpb +++ b/data/maps/the_partial/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Partial" +rte_room: "Obverse Side" diff --git a/data/maps/the_perceptive/metadata.txtpb b/data/maps/the_perceptive/metadata.txtpb index 6942cab..22eb1d5 100644 --- a/data/maps/the_perceptive/metadata.txtpb +++ b/data/maps/the_perceptive/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Perceptive" +rte_room: "Main Area" worldport_entrance { room: "Main Area" name: "CC" diff --git a/data/maps/the_plaza/metadata.txtpb b/data/maps/the_plaza/metadata.txtpb index 262fe99..6ff2e83 100644 --- a/data/maps/the_plaza/metadata.txtpb +++ b/data/maps/the_plaza/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Plaza" +rte_room: "Main Area" diff --git a/data/maps/the_quiet/metadata.txtpb b/data/maps/the_quiet/metadata.txtpb index d7fd0eb..9056fac 100644 --- a/data/maps/the_quiet/metadata.txtpb +++ b/data/maps/the_quiet/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Quiet" +rte_room: "Main Area" worldport_entrance { room: "Main Area" name: "DAEDALUS" diff --git a/data/maps/the_relentless/metadata.txtpb b/data/maps/the_relentless/metadata.txtpb index 9515145..313420d 100644 --- a/data/maps/the_relentless/metadata.txtpb +++ b/data/maps/the_relentless/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Relentless" +# No RTE in order to preserve the gimmick of the map. diff --git a/data/maps/the_repetitive/metadata.txtpb b/data/maps/the_repetitive/metadata.txtpb index 76a0f50..4924048 100644 --- a/data/maps/the_repetitive/metadata.txtpb +++ b/data/maps/the_repetitive/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Repetitive" +rte_room: "Main Room" # These paintings are directly above/behind panels and thus can't be entered. excluded_nodes: "Meshes/eyeRed3" excluded_nodes: "Meshes/eyeRed4" diff --git a/data/maps/the_revitalized/metadata.txtpb b/data/maps/the_revitalized/metadata.txtpb index 7c4bf46..ab64625 100644 --- a/data/maps/the_revitalized/metadata.txtpb +++ b/data/maps/the_revitalized/metadata.txtpb @@ -1,3 +1,4 @@ display_name: "The Revitalized" +rte_room: "Bye Room" # Let's not include the demo (for now). excluded_nodes: "Components/panel_demo" diff --git a/data/maps/the_shop/metadata.txtpb b/data/maps/the_shop/metadata.txtpb index 06f7fed..4a17985 100644 --- a/data/maps/the_shop/metadata.txtpb +++ b/data/maps/the_shop/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Shop" +rte_room: "Main Area" diff --git a/data/maps/the_sirenic/metadata.txtpb b/data/maps/the_sirenic/metadata.txtpb index 80b1783..9e1e5e7 100644 --- a/data/maps/the_sirenic/metadata.txtpb +++ b/data/maps/the_sirenic/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Sirenic" +rte_room: "Start" worldport_entrance { room: "Start" name: "PLAZA" diff --git a/data/maps/the_stellar/metadata.txtpb b/data/maps/the_stellar/metadata.txtpb index aaf6631..30b5ece 100644 --- a/data/maps/the_stellar/metadata.txtpb +++ b/data/maps/the_stellar/metadata.txtpb @@ -1,5 +1,6 @@ display_name: "The Stellar" type: GIFT_MAP +rte_room: "Starting Room" # This panel does not appear to be accessible without sniping. excluded_nodes: "Panels/Room_1/panel_2" # The map's mastery is created at runtime. diff --git a/data/maps/the_stormy/metadata.txtpb b/data/maps/the_stormy/metadata.txtpb index 42b1814..098218b 100644 --- a/data/maps/the_stormy/metadata.txtpb +++ b/data/maps/the_stormy/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Stormy" +rte_room: "Center" diff --git a/data/maps/the_sturdy/metadata.txtpb b/data/maps/the_sturdy/metadata.txtpb index bdc5a94..e6d997f 100644 --- a/data/maps/the_sturdy/metadata.txtpb +++ b/data/maps/the_sturdy/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Sturdy" +rte_room: "Main Area" # Let's ignore the second half of the rainbows for now. #excluded_nodes: "Components/Doors/Rainbow2/Hinge/rainbowMirrored" #excluded_nodes: "Components/Doors/Rainbow/Hinge/rainbowMirrored" diff --git a/data/maps/the_sun_temple/metadata.txtpb b/data/maps/the_sun_temple/metadata.txtpb index 25ed636..c64162e 100644 --- a/data/maps/the_sun_temple/metadata.txtpb +++ b/data/maps/the_sun_temple/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Sun Temple" +rte_room: "Entrance" worldport_entrance { room: "Entrance" name: "UNKEMPT" diff --git a/data/maps/the_sweet/metadata.txtpb b/data/maps/the_sweet/metadata.txtpb index 95f2209..9c3e7f5 100644 --- a/data/maps/the_sweet/metadata.txtpb +++ b/data/maps/the_sweet/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Sweet" +rte_room: "Main Area" diff --git a/data/maps/the_symbolic/metadata.txtpb b/data/maps/the_symbolic/metadata.txtpb index 2b37985..d57fca2 100644 --- a/data/maps/the_symbolic/metadata.txtpb +++ b/data/maps/the_symbolic/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Symbolic" +rte_room: "White Room" worldport_entrance { room: "White Room" name: "PLAZA" diff --git a/data/maps/the_talented/metadata.txtpb b/data/maps/the_talented/metadata.txtpb index 943bc69..0e68b9e 100644 --- a/data/maps/the_talented/metadata.txtpb +++ b/data/maps/the_talented/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Talented" +rte_room: "Main Area" worldport_entrance { room: "Main Area" name: "GREAT" diff --git a/data/maps/the_tenacious/metadata.txtpb b/data/maps/the_tenacious/metadata.txtpb index 58b3919..86ed1c5 100644 --- a/data/maps/the_tenacious/metadata.txtpb +++ b/data/maps/the_tenacious/metadata.txtpb @@ -1,2 +1,3 @@ display_name: "The Tenacious" +rte_room: "Control Center Entrance" daedalus_only_mode: DAED_ONLY_ALLOW diff --git a/data/maps/the_three_doors/metadata.txtpb b/data/maps/the_three_doors/metadata.txtpb index 0c6052a..bed023f 100644 --- a/data/maps/the_three_doors/metadata.txtpb +++ b/data/maps/the_three_doors/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Three Doors" +rte_room: "First Second Room" diff --git a/data/maps/the_tower/metadata.txtpb b/data/maps/the_tower/metadata.txtpb index 3876206..9d4fe0b 100644 --- a/data/maps/the_tower/metadata.txtpb +++ b/data/maps/the_tower/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Tower" +rte_room: "First Floor" worldport_entrance { room: "First Floor" name: "GREAT" diff --git a/data/maps/the_tree/metadata.txtpb b/data/maps/the_tree/metadata.txtpb index 6090384..c52b946 100644 --- a/data/maps/the_tree/metadata.txtpb +++ b/data/maps/the_tree/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Tree" +rte_room: "Main Area" diff --git a/data/maps/the_unkempt/metadata.txtpb b/data/maps/the_unkempt/metadata.txtpb index f2862bc..eaa821f 100644 --- a/data/maps/the_unkempt/metadata.txtpb +++ b/data/maps/the_unkempt/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Unkempt" +rte_room: "Main Area" diff --git a/data/maps/the_unyielding/metadata.txtpb b/data/maps/the_unyielding/metadata.txtpb index d674150..311a966 100644 --- a/data/maps/the_unyielding/metadata.txtpb +++ b/data/maps/the_unyielding/metadata.txtpb @@ -1 +1,2 @@ display_name: "The Unyielding" +rte_room: "Digital Entrance" diff --git a/data/maps/the_wise/metadata.txtpb b/data/maps/the_wise/metadata.txtpb index 91af34e..282ebe9 100644 --- a/data/maps/the_wise/metadata.txtpb +++ b/data/maps/the_wise/metadata.txtpb @@ -1,3 +1,4 @@ display_name: "The Wise" +rte_room: "Entry" # This port is out of bounds. excluded_nodes: "Components/Warps/worldport" diff --git a/data/maps/the_wondrous/metadata.txtpb b/data/maps/the_wondrous/metadata.txtpb index 1c8e04c..88ca318 100644 --- a/data/maps/the_wondrous/metadata.txtpb +++ b/data/maps/the_wondrous/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Wondrous" +rte_room: "Entry" worldport_entrance { room: "Entry" name: "DAEDALUS" diff --git a/data/maps/the_words/metadata.txtpb b/data/maps/the_words/metadata.txtpb index 2dadcae..b016db0 100644 --- a/data/maps/the_words/metadata.txtpb +++ b/data/maps/the_words/metadata.txtpb @@ -1,4 +1,5 @@ display_name: "The Words" +rte_room: "Main Area" # These are old proxies of the main room's panels that are not linked up # anymore. excluded_nodes: "Panels/Proxies/panel_3" diff --git a/proto/data.proto b/proto/data.proto index d7538da..6c846a3 100644 --- a/proto/data.proto +++ b/proto/data.proto @@ -287,6 +287,7 @@ message Map { optional string display_name = 3; optional DaedalusOnlyMode daedalus_only_mode = 6; optional uint64 worldport_entrance = 4; + optional uint64 rte_room = 7; optional MapType type = 5; } diff --git a/proto/human.proto b/proto/human.proto index 39625d5..484369e 100644 --- a/proto/human.proto +++ b/proto/human.proto @@ -238,6 +238,7 @@ message HumanMap { optional DaedalusOnlyMode daedalus_only_mode = 6; optional PortIdentifier worldport_entrance = 3; + optional string rte_room = 7; // These two fields are used by the validator and nothing else. excluded_nodes // are objects in the tscn that are intentionally not mentioned in the txtpb. @@ -286,6 +287,7 @@ message IdMappings { message MapIds { map doors = 1; map rooms = 2; + optional uint64 rte = 3; } map maps = 1; diff --git a/tools/assign_ids/main.cpp b/tools/assign_ids/main.cpp index 4cf7c3f..4a48b86 100644 --- a/tools/assign_ids/main.cpp +++ b/tools/assign_ids/main.cpp @@ -67,6 +67,10 @@ class AssignIds { UpdateNextId(room.keyholders()); UpdateNextId(room.ports()); } + + if (map.has_rte()) { + UpdateNextId(map.rte()); + } } UpdateNextId(id_mappings_.special()); @@ -93,10 +97,31 @@ class AssignIds { void ProcessMap(std::filesystem::path path) { std::string map_name = path.filename().string(); + ProcessMapMetadata(path / "metadata.txtpb", map_name); ProcessDoorsFile(path / "doors.txtpb", map_name); ProcessRooms(path / "rooms", map_name); } + void ProcessMapMetadata(std::filesystem::path path, + const std::string& current_map_name) { + if (!std::filesystem::exists(path)) { + return; + } + + auto metadata = ReadMessageFromFile(path.string()); + auto& maps = *output_.mutable_maps(); + + if (metadata.has_rte_room()) { + if (!id_mappings_.maps().contains(current_map_name) || + !id_mappings_.maps().at(current_map_name).has_rte()) { + maps[current_map_name].set_rte(next_id_++); + } else { + maps[current_map_name].set_rte( + id_mappings_.maps().at(current_map_name).rte()); + } + } + } + void ProcessDoorsFile(std::filesystem::path path, const std::string& current_map_name) { if (!std::filesystem::exists(path)) { @@ -342,9 +367,13 @@ class AssignIds { private: void UpdateNextId(const google::protobuf::Map& ids) { for (const auto& [_, id] : ids) { - if (id > next_id_) { - next_id_ = id; - } + UpdateNextId(id); + } + } + + void UpdateNextId(uint64_t id) { + if (id > next_id_) { + next_id_ = id; } } diff --git a/tools/datapacker/main.cpp b/tools/datapacker/main.cpp index 953821f..4b74217 100644 --- a/tools/datapacker/main.cpp +++ b/tools/datapacker/main.cpp @@ -100,6 +100,11 @@ class DataPacker { map_name, metadata.worldport_entrance().room(), metadata.worldport_entrance().name(), std::nullopt, std::nullopt)); } + + if (metadata.has_rte_room()) { + map.set_rte_room(container_.FindOrAddRoom(map_name, metadata.rte_room(), + std::nullopt)); + } } void ProcessRooms(std::filesystem::path path, diff --git a/tools/util/ids_yaml_format.cpp b/tools/util/ids_yaml_format.cpp index 5b9113b..c23c66b 100644 --- a/tools/util/ids_yaml_format.cpp +++ b/tools/util/ids_yaml_format.cpp @@ -80,6 +80,10 @@ IdMappings ReadIdsFromYaml(const std::string& filename) { door_it.second.as(); } } + + if (map_it.second["rte"]) { + map_ids.set_rte(map_it.second["rte"].as()); + } } } @@ -168,6 +172,10 @@ void WriteIdsAsYaml(const IdMappings& ids, const std::string& filename) { map_node["doors"][door_name] = door_id; }); + if (map_ids.has_rte()) { + map_node["rte"] = map_ids.rte(); + } + result["maps"][map_name] = std::move(map_node); }); diff --git a/tools/validator/human_processor.cpp b/tools/validator/human_processor.cpp index ffa9765..d6fcfa6 100644 --- a/tools/validator/human_processor.cpp +++ b/tools/validator/human_processor.cpp @@ -74,6 +74,8 @@ class HumanProcessor { MapInfo& map_info = info_.maps[current_map_name]; auto metadata = ReadMessageFromFile(path.string()); + map_info.definitions.push_back(metadata); + for (const std::string& path : metadata.excluded_nodes()) { map_info.game_nodes[path].uses++; } @@ -92,6 +94,15 @@ class HumanProcessor { map_info.malformed_worldport_entrance = metadata.worldport_entrance(); } } + + if (metadata.has_rte_room()) { + RoomIdentifier room_identifier; + room_identifier.set_map(current_map_name); + room_identifier.set_name(metadata.rte_room()); + + RoomInfo& room_info = info_.rooms[room_identifier]; + room_info.map_rtes_referenced_by.push_back(current_map_name); + } } void ProcessRooms(std::filesystem::path path, @@ -617,6 +628,11 @@ class HumanProcessor { port_info.has_id = true; } } + + if (map.has_rte()) { + MapInfo& map_info = info_.maps[map_name]; + map_info.has_rte_id = true; + } } for (const auto& [tag, id] : ids.special()) { diff --git a/tools/validator/main.cpp b/tools/validator/main.cpp index 1a72e9a..6139e95 100644 --- a/tools/validator/main.cpp +++ b/tools/validator/main.cpp @@ -21,7 +21,9 @@ void Run(const std::string& mapdir, const std::string& repodir) { int main(int argc, char** argv) { if (argc != 3) { std::cout << "Incorrect argument count." << std::endl; - std::cout << "Usage: validator [path to map directory] [path to Lingo 2 repository]" << std::endl; + std::cout << "Usage: validator [path to map directory] [path to Lingo 2 " + "repository]" + << std::endl; return 1; } diff --git a/tools/validator/structs.h b/tools/validator/structs.h index 62974a8..81a0e8f 100644 --- a/tools/validator/structs.h +++ b/tools/validator/structs.h @@ -28,6 +28,9 @@ struct GameNodeInfo { struct MapInfo { std::map game_nodes; + std::vector definitions; + bool has_rte_id = false; + std::optional malformed_worldport_entrance; }; @@ -37,6 +40,7 @@ struct RoomInfo { std::vector doors_referenced_by; std::vector panels_referenced_by; std::vector connections_referenced_by; + std::vector map_rtes_referenced_by; }; struct DoorInfo { diff --git a/tools/validator/validator.cpp b/tools/validator/validator.cpp index fe36be7..e9fbb74 100644 --- a/tools/validator/validator.cpp +++ b/tools/validator/validator.cpp @@ -1,5 +1,6 @@ #include "validator.h" +#include #include #include "proto/human.pb.h" @@ -74,6 +75,22 @@ class Validator { std::cout << "The worldport entrance for map " << map_name << " is malformed." << std::endl; } + + if (map_info.has_rte_id) { + if (!std::any_of( + map_info.definitions.begin(), map_info.definitions.end(), + [](const HumanMap& h_map) { return h_map.has_rte_room(); })) { + std::cout << "Map " << map_name << " has an RTE ID but no RTE room." + << std::endl; + } + } else { + if (std::any_of( + map_info.definitions.begin(), map_info.definitions.end(), + [](const HumanMap& h_map) { return h_map.has_rte_room(); })) { + std::cout << "Map " << map_name << " has an RTE room but no RTE ID." + << std::endl; + } + } } void ValidateRoom(const RoomIdentifier& room_identifier, @@ -99,6 +116,10 @@ class Validator { std::cout << " CONNECTION " << connection.ShortDebugString() << std::endl; } + + for (const std::string& map_name : room_info.map_rtes_referenced_by) { + std::cout << " MAP RTE " << map_name << std::endl; + } } else if (room_info.definitions.size() > 1) { std::cout << "Room " << room_identifier.ShortDebugString() << " was defined multiple times." << std::endl; -- cgit 1.4.1 From 225a6dba793386f36e72b432c8374e1978cee72a Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Fri, 6 Feb 2026 13:24:35 -0500 Subject: Add RTE AP ID to compiled datafile --- proto/data.proto | 4 +++- tools/datapacker/main.cpp | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/proto/data.proto b/proto/data.proto index 6c846a3..3330666 100644 --- a/proto/data.proto +++ b/proto/data.proto @@ -287,8 +287,10 @@ message Map { optional string display_name = 3; optional DaedalusOnlyMode daedalus_only_mode = 6; optional uint64 worldport_entrance = 4; - optional uint64 rte_room = 7; optional MapType type = 5; + + optional uint64 rte_room = 7; + optional uint64 rte_ap_id = 8; } message Progressive { diff --git a/tools/datapacker/main.cpp b/tools/datapacker/main.cpp index 4b74217..f1ef10e 100644 --- a/tools/datapacker/main.cpp +++ b/tools/datapacker/main.cpp @@ -716,6 +716,11 @@ class DataPacker { container_.all_objects().mutable_ports(port_id)->set_ap_id(ap_id); } } + + if (map.has_rte()) { + uint64_t map_id = container_.FindOrAddMap(map_name); + container_.all_objects().mutable_maps(map_id)->set_rte_ap_id(map.rte()); + } } auto& specials = *container_.all_objects().mutable_special_ids(); -- cgit 1.4.1 From 2a3916c1c58e033b06042d5d5413ea85cd94babf Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Fri, 6 Feb 2026 13:43:45 -0500 Subject: Add shuffle_fast_travel and fast_travel_access to apworld --- apworld/__init__.py | 2 ++ apworld/options.py | 23 +++++++++++++++++++++++ apworld/player_logic.py | 16 +++++++++++++++- apworld/regions.py | 18 ++++++++++++++++++ apworld/static_logic.py | 12 ++++++++++++ 5 files changed, 70 insertions(+), 1 deletion(-) diff --git a/apworld/__init__.py b/apworld/__init__.py index 5bad63e..ff1da66 100644 --- a/apworld/__init__.py +++ b/apworld/__init__.py @@ -140,6 +140,7 @@ class Lingo2World(World): "enable_gift_maps", "enable_icarus", "endings_requirement", + "fast_travel_access", "keyholder_sanity", "masteries_requirement", "shuffle_control_center_colors", @@ -155,6 +156,7 @@ class Lingo2World(World): slot_data: dict[str, object] = { **self.options.as_dict(*slot_options), + "rte": [self.static_logic.objects.maps[map_id].name for map_id in self.player_logic.rte_mapping], "version": self.static_logic.get_data_version(), } diff --git a/apworld/options.py b/apworld/options.py index 5661351..063af21 100644 --- a/apworld/options.py +++ b/apworld/options.py @@ -91,6 +91,27 @@ class CyanDoorBehavior(Choice): option_item = 2 +class ShuffleFastTravel(Toggle): + """If enabled, the list of maps you can fast travel to is randomized, except for The Entry, which is always + accessible.""" + display_name = "Shuffle Fast Travel" + + +class FastTravelAccess(Choice): + """ + Controls how the fast travel buttons on the pause menu work. + + - **Vanilla**: You can only fast travel to maps once you have been to them and stepped foot in the general area that + the warp would place you. This option means that fast travel has no impact on logic. + - **Unlocked**: All five fast travel maps will be available from the start. + - **Items**: Only The Entry is available from the start. The other fast travel buttons are locked behind items. + """ + display_name = "Fast Travel Access" + option_vanilla = 0 + option_unlocked = 1 + option_items = 2 + + class EnableIcarus(Toggle): """ Controls whether Icarus is randomized. If disabled, which is the default, no locations or items will be created for @@ -234,6 +255,8 @@ class Lingo2Options(PerGameCommonOptions): shuffle_worldports: ShuffleWorldports keyholder_sanity: KeyholderSanity cyan_door_behavior: CyanDoorBehavior + shuffle_fast_travel: ShuffleFastTravel + fast_travel_access: FastTravelAccess enable_icarus: EnableIcarus enable_gift_maps: EnableGiftMaps daedalus_only: DaedalusOnly diff --git a/apworld/player_logic.py b/apworld/player_logic.py index b946296..a02856e 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py @@ -5,7 +5,7 @@ from .generated import data_pb2 as data_pb2 from .items import SYMBOL_ITEMS from typing import TYPE_CHECKING, NamedTuple -from .options import ShuffleLetters, CyanDoorBehavior, VictoryCondition +from .options import ShuffleLetters, CyanDoorBehavior, VictoryCondition, FastTravelAccess if TYPE_CHECKING: from . import Lingo2World @@ -221,6 +221,7 @@ class Lingo2PlayerLogic: double_letter_amount: dict[str, int] goal_room_id: int + rte_mapping: list[int] def __init__(self, world: "Lingo2World"): self.world = world @@ -304,6 +305,19 @@ class Lingo2PlayerLogic: if "The Fuzzy" in world.options.enable_gift_maps.value: self.real_items.append("Numbers") + if world.options.shuffle_fast_travel: + travelable_maps = [map_id for map_id in self.shuffled_maps + if world.static_logic.objects.maps[map_id].HasField("rte_room")] + self.rte_mapping = world.random.sample(travelable_maps, 4) + else: + canonical_rtes = ["the_plaza", "the_gallery", "daedalus", "control_center"] + self.rte_mapping = [world.static_logic.map_id_by_name[map_name] for map_name in canonical_rtes + if world.static_logic.map_id_by_name[map_name] in self.shuffled_maps] + + if world.options.fast_travel_access == FastTravelAccess.option_items: + for rte_map in self.rte_mapping: + self.real_items.append(world.static_logic.get_map_rte_item_name(rte_map)) + if self.world.options.shuffle_doors: for progressive in world.static_logic.objects.progressives: for i in range(0, len(progressive.doors)): diff --git a/apworld/regions.py b/apworld/regions.py index 2f9b571..500139f 100644 --- a/apworld/regions.py +++ b/apworld/regions.py @@ -5,6 +5,7 @@ from BaseClasses import Region, ItemClassification, Entrance from entrance_rando import randomize_entrances from .items import Lingo2Item from .locations import Lingo2Location +from .options import FastTravelAccess from .player_logic import AccessRequirements from .rules import make_location_lambda @@ -153,6 +154,23 @@ def create_regions(world: "Lingo2World"): for region in reqs.get_referenced_rooms(): world.multiworld.register_indirect_condition(regions[region], connection) + if world.options.fast_travel_access != FastTravelAccess.option_vanilla: + for rte_map_id in world.player_logic.rte_mapping: + rte_map = world.static_logic.objects.maps[rte_map_id] + to_region = world.static_logic.get_room_region_name(rte_map.rte_room) + + if to_region not in regions: + continue + + connection_name = f"Return to {to_region}" + + reqs = AccessRequirements() + + if world.options.fast_travel_access == FastTravelAccess.option_items: + reqs.items.add(world.static_logic.get_map_rte_item_name(rte_map_id)) + + regions["Menu"].connect(regions[to_region], connection_name, make_location_lambda(reqs, world, None)) + world.multiworld.regions += regions.values() diff --git a/apworld/static_logic.py b/apworld/static_logic.py index 715178e..672ae5a 100644 --- a/apworld/static_logic.py +++ b/apworld/static_logic.py @@ -18,6 +18,8 @@ class Lingo2StaticLogic: door_id_by_ap_id: dict[int, int] port_id_by_ap_id: dict[int, int] + map_id_by_name: dict[str, int] + def __init__(self): self.item_id_to_name = {} self.location_id_to_name = {} @@ -79,6 +81,10 @@ class Lingo2StaticLogic: for trap_name in ANTI_COLLECTABLE_TRAPS: self.item_id_to_name[self.objects.special_ids[trap_name]] = trap_name + for game_map in self.objects.maps: + if game_map.HasField("rte_room"): + self.item_id_to_name[game_map.rte_ap_id] = self.get_map_rte_item_name(game_map.id) + self.item_name_to_id = {name: ap_id for ap_id, name in self.item_id_to_name.items()} self.location_name_to_id = {name: ap_id for ap_id, name in self.location_id_to_name.items()} @@ -90,6 +96,8 @@ class Lingo2StaticLogic: self.door_id_by_ap_id = {door.ap_id: door.id for door in self.objects.doors if door.HasField("ap_id")} self.port_id_by_ap_id = {port.ap_id: port.id for port in self.objects.ports if port.HasField("ap_id")} + self.map_id_by_name = {game_map.name: game_map.id for game_map in self.objects.maps} + def get_door_item_name(self, door: data_pb2.Door) -> str: return f"{self.get_map_object_map_name(door)} - {door.name}" @@ -177,6 +185,10 @@ class Lingo2StaticLogic: def get_room_object_map_id(self, obj) -> int: return self.objects.rooms[obj.room_id].map_id + def get_map_rte_item_name(self, map_id: int) -> str: + game_map = self.objects.maps[map_id] + return f"Return to {game_map.display_name}" + def get_data_version(self) -> list[int]: version = self.objects.version return [version.major, version.minor, version.patch] -- cgit 1.4.1