about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-09-07 15:42:00 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2025-09-07 15:42:00 -0400
commitd79984b099c3f762b95d3b4257bef113d3a8d6ee (patch)
treebcb647c4734b9ddecb465f818e06efc899482f4e
parent8ab6132f99e9a033c170310b2d88a7312e46a153 (diff)
downloadlingo2-archipelago-d79984b099c3f762b95d3b4257bef113d3a8d6ee.tar.gz
lingo2-archipelago-d79984b099c3f762b95d3b4257bef113d3a8d6ee.tar.bz2
lingo2-archipelago-d79984b099c3f762b95d3b4257bef113d3a8d6ee.zip
Added door groups
-rw-r--r--apworld/options.py9
-rw-r--r--apworld/player_logic.py35
-rw-r--r--apworld/static_logic.py3
-rw-r--r--data/door_groups.txtpb84
-rw-r--r--data/ids.yaml12
-rw-r--r--data/maps/daedalus/doors.txtpb4
-rw-r--r--data/maps/the_entry/connections.txtpb2
-rw-r--r--data/maps/the_entry/doors.txtpb2
-rw-r--r--data/maps/the_repetitive/connections.txtpb2
-rw-r--r--data/maps/the_repetitive/doors.txtpb2
-rw-r--r--proto/data.proto23
-rw-r--r--proto/human.proto11
-rw-r--r--tools/assign_ids/main.cpp20
-rw-r--r--tools/datapacker/container.cpp17
-rw-r--r--tools/datapacker/container.h3
-rw-r--r--tools/datapacker/main.cpp31
-rw-r--r--tools/util/ids_yaml_format.cpp12
-rw-r--r--tools/validator/human_processor.cpp33
-rw-r--r--tools/validator/structs.h9
-rw-r--r--tools/validator/validator.cpp28
20 files changed, 326 insertions, 16 deletions
diff --git a/apworld/options.py b/apworld/options.py index f7dc5bd..dbf09e7 100644 --- a/apworld/options.py +++ b/apworld/options.py
@@ -8,6 +8,14 @@ class ShuffleDoors(Toggle):
8 display_name = "Shuffle Doors" 8 display_name = "Shuffle Doors"
9 9
10 10
11class ShuffleControlCenterColors(Toggle):
12 """
13 Some doors open after solving the COLOR panel in the Control Center. If this option is enabled, these doors will
14 instead open upon receiving an item.
15 """
16 display_name = "Shuffle Control Center Colors"
17
18
11class ShuffleLetters(Choice): 19class ShuffleLetters(Choice):
12 """ 20 """
13 Controls how letter unlocks are handled. Note that H1, I1, N1, and T1 will always be present at their vanilla 21 Controls how letter unlocks are handled. Note that H1, I1, N1, and T1 will always be present at their vanilla
@@ -71,6 +79,7 @@ class VictoryCondition(Choice):
71@dataclass 79@dataclass
72class Lingo2Options(PerGameCommonOptions): 80class Lingo2Options(PerGameCommonOptions):
73 shuffle_doors: ShuffleDoors 81 shuffle_doors: ShuffleDoors
82 shuffle_control_center_colors: ShuffleControlCenterColors
74 shuffle_letters: ShuffleLetters 83 shuffle_letters: ShuffleLetters
75 keyholder_sanity: KeyholderSanity 84 keyholder_sanity: KeyholderSanity
76 daedalus_roof_access: DaedalusRoofAccess 85 daedalus_roof_access: DaedalusRoofAccess
diff --git a/apworld/player_logic.py b/apworld/player_logic.py index 5cb9011..ce9a4e5 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py
@@ -123,16 +123,39 @@ class Lingo2PlayerLogic:
123 self.item_by_door[progressive.doors[i]] = (progressive.name, i + 1) 123 self.item_by_door[progressive.doors[i]] = (progressive.name, i + 1)
124 self.real_items.append(progressive.name) 124 self.real_items.append(progressive.name)
125 125
126 for door_group in world.static_logic.objects.door_groups:
127 if door_group.type == data_pb2.DoorGroupType.CONNECTOR and not self.world.options.shuffle_doors:
128 continue
129
130 if (door_group.type == data_pb2.DoorGroupType.COLOR_CONNECTOR and
131 not self.world.options.shuffle_control_center_colors):
132 continue
133
134 for door in door_group.doors:
135 self.item_by_door[door] = (door_group.name, 1)
136
137 self.real_items.append(door_group.name)
138
126 # We iterate through the doors in two parts because it is essential that we determine which doors are shuffled 139 # We iterate through the doors in two parts because it is essential that we determine which doors are shuffled
127 # before we calculate any access requirements. 140 # before we calculate any access requirements.
128 for door in world.static_logic.objects.doors: 141 for door in world.static_logic.objects.doors:
129 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.ITEM_ONLY] and self.world.options.shuffle_doors: 142 if door.type in [data_pb2.DoorType.EVENT, data_pb2.DoorType.LOCATION_ONLY, data_pb2.DoorType.GRAVESTONE]:
130 if door.id in self.item_by_door: 143 continue
131 continue 144
145 if door.id in self.item_by_door:
146 continue
147
148 if (door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.ITEM_ONLY] and
149 not self.world.options.shuffle_doors):
150 continue
151
152 if (door.type == data_pb2.DoorType.CONTROL_CENTER_COLOR and
153 not self.world.options.shuffle_control_center_colors):
154 continue
132 155
133 door_item_name = self.world.static_logic.get_door_item_name(door) 156 door_item_name = self.world.static_logic.get_door_item_name(door)
134 self.item_by_door[door.id] = (door_item_name, 1) 157 self.item_by_door[door.id] = (door_item_name, 1)
135 self.real_items.append(door_item_name) 158 self.real_items.append(door_item_name)
136 159
137 for door in world.static_logic.objects.doors: 160 for door in world.static_logic.objects.doors:
138 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.LOCATION_ONLY, data_pb2.DoorType.GRAVESTONE]: 161 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.LOCATION_ONLY, data_pb2.DoorType.GRAVESTONE]:
diff --git a/apworld/static_logic.py b/apworld/static_logic.py index b699d59..3f6cdea 100644 --- a/apworld/static_logic.py +++ b/apworld/static_logic.py
@@ -44,6 +44,9 @@ class Lingo2StaticLogic:
44 for progressive in self.objects.progressives: 44 for progressive in self.objects.progressives:
45 self.item_id_to_name[progressive.ap_id] = progressive.name 45 self.item_id_to_name[progressive.ap_id] = progressive.name
46 46
47 for door_group in self.objects.door_groups:
48 self.item_id_to_name[door_group.ap_id] = door_group.name
49
47 for keyholder in self.objects.keyholders: 50 for keyholder in self.objects.keyholders:
48 if keyholder.HasField("key"): 51 if keyholder.HasField("key"):
49 location_name = f"{self.get_room_object_location_prefix(keyholder)} - {keyholder.key.upper()} Keyholder" 52 location_name = f"{self.get_room_object_location_prefix(keyholder)} - {keyholder.key.upper()} Keyholder"
diff --git a/data/door_groups.txtpb b/data/door_groups.txtpb new file mode 100644 index 0000000..ca8ce54 --- /dev/null +++ b/data/door_groups.txtpb
@@ -0,0 +1,84 @@
1door_groups {
2 name: "The Entry - Repetitive Entrance"
3 type: CONNECTOR
4 doors {
5 map: "the_entry"
6 name: "Starting Room West Wall North Door"
7 }
8 doors {
9 map: "the_repetitive"
10 name: "Entry Entrance"
11 }
12}
13door_groups {
14 name: "The Repetitive - Plaza Entrance"
15 type: CONNECTOR
16 doors {
17 map: "the_repetitive"
18 name: "Black Hallway"
19 }
20 doors {
21 map: "the_plaza"
22 name: "Repetitive Entrance"
23 }
24}
25door_groups {
26 name: "Control Center White Doors"
27 type: COLOR_CONNECTOR
28 doors {
29 map: "daedalus"
30 name: "White Hallway From Entry"
31 }
32 doors {
33 map: "the_entry"
34 name: "Control Center White Door"
35 }
36}
37door_groups {
38 name: "Control Center Purple Doors"
39 type: COLOR_CONNECTOR
40 doors {
41 map: "daedalus"
42 name: "Purple Hallway From Great"
43 }
44 doors {
45 map: "the_great"
46 name: "Control Center Purple Door"
47 }
48}
49door_groups {
50 name: "Control Center Orange Doors"
51 type: COLOR_CONNECTOR
52 doors {
53 map: "daedalus"
54 name: "Control Center Orange Door"
55 }
56 doors {
57 map: "the_unkempt"
58 name: "Control Center Orange Door"
59 }
60}
61door_groups {
62 name: "Control Center Brown Doors"
63 type: COLOR_CONNECTOR
64 doors {
65 map: "the_bearer"
66 name: "Control Center Brown Door"
67 }
68 doors {
69 map: "the_tree"
70 name: "Control Center Brown Door"
71 }
72}
73door_groups {
74 name: "Control Center Blue Doors"
75 type: COLOR_CONNECTOR
76 doors {
77 map: "the_digital"
78 name: "Control Center Blue Door"
79 }
80 doors {
81 map: "the_unyielding"
82 name: "Digital Entrance"
83 }
84}
diff --git a/data/ids.yaml b/data/ids.yaml index 6498619..bd6cbc1 100644 --- a/data/ids.yaml +++ b/data/ids.yaml
@@ -1743,13 +1743,13 @@ maps:
1743 Red Blue Area Left Door: 302 1743 Red Blue Area Left Door: 302
1744 Red Blue Area Right Door: 303 1744 Red Blue Area Right Door: 303
1745 Red Room Painting: 323 1745 Red Room Painting: 323
1746 Repetitive Entrance: 312
1747 Revitalized Entrance: 306 1746 Revitalized Entrance: 306
1748 Right Eye Entrance: 301 1747 Right Eye Entrance: 301
1749 Scarf Door: 296 1748 Scarf Door: 296
1750 Second Room Left Door: 298 1749 Second Room Left Door: 298
1751 Second Room Right Door: 290 1750 Second Room Right Door: 290
1752 Shop Entrance: 313 1751 Shop Entrance: 313
1752 Starting Room West Wall North Door: 2781
1753 Third Eye Painting: 324 1753 Third Eye Painting: 324
1754 Trick Door: 287 1754 Trick Door: 287
1755 Trick To Shop Door: 289 1755 Trick To Shop Door: 289
@@ -2760,6 +2760,7 @@ maps:
2760 ZEROING: 1118 2760 ZEROING: 1118
2761 doors: 2761 doors:
2762 Anti-Collectable Room: 1025 2762 Anti-Collectable Room: 1025
2763 Black Hallway: 2780
2763 Cyan Door: 1028 2764 Cyan Door: 1028
2764 Cyan Puzzles: 1032 2765 Cyan Puzzles: 1032
2765 Dot Area Entrance: 1026 2766 Dot Area Entrance: 1026
@@ -2768,7 +2769,6 @@ maps:
2768 Lime Puzzles: 1031 2769 Lime Puzzles: 1031
2769 Magenta Door: 1029 2770 Magenta Door: 1029
2770 Magenta Puzzles: 1033 2771 Magenta Puzzles: 1033
2771 Plaza Entrance: 1024
2772 Yellow Door: 1030 2772 Yellow Door: 1030
2773 Yellow Puzzles: 1034 2773 Yellow Puzzles: 1034
2774 the_revitalized: 2774 the_revitalized:
@@ -3840,3 +3840,11 @@ special:
3840 A Job Well Done: 1160 3840 A Job Well Done: 1160
3841progressives: 3841progressives:
3842 Progressive Gold Ending: 2753 3842 Progressive Gold Ending: 2753
3843door_groups:
3844 Control Center Blue Doors: 2788
3845 Control Center Brown Doors: 2787
3846 Control Center Orange Doors: 2786
3847 Control Center Purple Doors: 2785
3848 Control Center White Doors: 2784
3849 The Entry - Repetitive Entrance: 2782
3850 The Repetitive - Plaza Entrance: 2783
diff --git a/data/maps/daedalus/doors.txtpb b/data/maps/daedalus/doors.txtpb index 7359c5e..d6c33f4 100644 --- a/data/maps/daedalus/doors.txtpb +++ b/data/maps/daedalus/doors.txtpb
@@ -892,16 +892,12 @@ doors {
892} 892}
893doors { 893doors {
894 name: "White Hallway From Entry" 894 name: "White Hallway From Entry"
895 # TODO: This should be combined with the corresponding door in the_entry, at
896 # least when connections are not shuffled.
897 type: CONTROL_CENTER_COLOR 895 type: CONTROL_CENTER_COLOR
898 receivers: "Components/Doors/Halls/froom_6" 896 receivers: "Components/Doors/Halls/froom_6"
899 control_center_color: "white" 897 control_center_color: "white"
900} 898}
901doors { 899doors {
902 name: "Purple Hallway From Great" 900 name: "Purple Hallway From Great"
903 # TODO: This should be combined with the corresponding door in the_great, at
904 # least when connections are not shuffled.
905 type: CONTROL_CENTER_COLOR 901 type: CONTROL_CENTER_COLOR
906 receivers: "Components/Doors/Halls/froom_7" 902 receivers: "Components/Doors/Halls/froom_7"
907 control_center_color: "purple" 903 control_center_color: "purple"
diff --git a/data/maps/the_entry/connections.txtpb b/data/maps/the_entry/connections.txtpb index 6f847da..a2e325a 100644 --- a/data/maps/the_entry/connections.txtpb +++ b/data/maps/the_entry/connections.txtpb
@@ -192,7 +192,7 @@ connections {
192connections { 192connections {
193 from_room: "Starting Room" 193 from_room: "Starting Room"
194 to_room: "Repetitive Entrance" 194 to_room: "Repetitive Entrance"
195 door { name: "Repetitive Entrance" } 195 door { name: "Starting Room West Wall North Door" }
196} 196}
197connections { 197connections {
198 from_room: "Lime Room" 198 from_room: "Lime Room"
diff --git a/data/maps/the_entry/doors.txtpb b/data/maps/the_entry/doors.txtpb index 78ffa52..6bef160 100644 --- a/data/maps/the_entry/doors.txtpb +++ b/data/maps/the_entry/doors.txtpb
@@ -193,7 +193,7 @@ doors {
193 location_room: "Starting Room" 193 location_room: "Starting Room"
194} 194}
195doors { 195doors {
196 name: "Repetitive Entrance" 196 name: "Starting Room West Wall North Door"
197 type: ITEM_ONLY 197 type: ITEM_ONLY
198 receivers: "Components/Doors/Entry/entry_proxied_9" 198 receivers: "Components/Doors/Entry/entry_proxied_9"
199 double_letters: true 199 double_letters: true
diff --git a/data/maps/the_repetitive/connections.txtpb b/data/maps/the_repetitive/connections.txtpb index 2b115a9..0afe72d 100644 --- a/data/maps/the_repetitive/connections.txtpb +++ b/data/maps/the_repetitive/connections.txtpb
@@ -6,7 +6,7 @@ connections {
6connections { 6connections {
7 from_room: "Main Room" 7 from_room: "Main Room"
8 to_room: "Plaza Connector" 8 to_room: "Plaza Connector"
9 door { name: "Plaza Entrance" } 9 door { name: "Black Hallway" }
10 oneway: true 10 oneway: true
11} 11}
12connections { 12connections {
diff --git a/data/maps/the_repetitive/doors.txtpb b/data/maps/the_repetitive/doors.txtpb index 9e63c1d..8171dc4 100644 --- a/data/maps/the_repetitive/doors.txtpb +++ b/data/maps/the_repetitive/doors.txtpb
@@ -6,7 +6,7 @@ doors {
6 location_room: "Main Room" 6 location_room: "Main Room"
7} 7}
8doors { 8doors {
9 name: "Plaza Entrance" 9 name: "Black Hallway"
10 type: STANDARD 10 type: STANDARD
11 receivers: "Components/Doors/Door12" 11 receivers: "Components/Doors/Door12"
12 panels { room: "Main Room" name: "I" } 12 panels { room: "Main Room" name: "I" }
diff --git a/proto/data.proto b/proto/data.proto index 855c28c..84d14ef 100644 --- a/proto/data.proto +++ b/proto/data.proto
@@ -29,6 +29,20 @@ enum DoorType {
29 GRAVESTONE = 6; 29 GRAVESTONE = 6;
30} 30}
31 31
32enum DoorGroupType {
33 DOOR_GROUP_TYPE_UNKNOWN = 0;
34
35 // These doors border a worldport. They should be grouped when connections are
36 // not shuffled.
37 CONNECTOR = 1;
38
39 // Similar to CONNECTOR, but these doors are also ordinarily opened by solving
40 // the COLOR panel in the Control Center. These should be grouped when
41 // connections are not shuffled, but are not items at all when control center
42 // colors are not shuffled.
43 COLOR_CONNECTOR = 2;
44}
45
32enum AxisDirection { 46enum AxisDirection {
33 AXIS_DIRECTION_UNKNOWN = 0; 47 AXIS_DIRECTION_UNKNOWN = 0;
34 48
@@ -232,6 +246,14 @@ message Progressive {
232 repeated uint64 doors = 4; 246 repeated uint64 doors = 4;
233} 247}
234 248
249message DoorGroup {
250 optional uint64 id = 1;
251 optional string name = 2;
252 optional uint64 ap_id = 3;
253 optional DoorGroupType type = 4;
254 repeated uint64 doors = 5;
255}
256
235message AllObjects { 257message AllObjects {
236 repeated Map maps = 7; 258 repeated Map maps = 7;
237 repeated Room rooms = 1; 259 repeated Room rooms = 1;
@@ -245,5 +267,6 @@ message AllObjects {
245 repeated Ending endings = 12; 267 repeated Ending endings = 12;
246 repeated Connection connections = 6; 268 repeated Connection connections = 6;
247 repeated Progressive progressives = 13; 269 repeated Progressive progressives = 13;
270 repeated DoorGroup door_groups = 14;
248 map<string, uint64> special_ids = 8; 271 map<string, uint64> special_ids = 8;
249} 272}
diff --git a/proto/human.proto b/proto/human.proto index 205b867..89fd076 100644 --- a/proto/human.proto +++ b/proto/human.proto
@@ -203,6 +203,16 @@ message HumanProgressives {
203 repeated HumanProgressive progressives = 1; 203 repeated HumanProgressive progressives = 1;
204} 204}
205 205
206message HumanDoorGroup {
207 optional string name = 1;
208 optional DoorGroupType type = 2;
209 repeated DoorIdentifier doors = 3;
210}
211
212message HumanDoorGroups {
213 repeated HumanDoorGroup door_groups = 1;
214}
215
206message IdMappings { 216message IdMappings {
207 message RoomIds { 217 message RoomIds {
208 map<string, uint64> panels = 1; 218 map<string, uint64> panels = 1;
@@ -220,4 +230,5 @@ message IdMappings {
220 map<string, uint64> letters = 3; 230 map<string, uint64> letters = 3;
221 map<string, uint64> endings = 4; 231 map<string, uint64> endings = 4;
222 map<string, uint64> progressives = 5; 232 map<string, uint64> progressives = 5;
233 map<string, uint64> door_groups = 6;
223} 234}
diff --git a/tools/assign_ids/main.cpp b/tools/assign_ids/main.cpp index e3add66..d212767 100644 --- a/tools/assign_ids/main.cpp +++ b/tools/assign_ids/main.cpp
@@ -42,6 +42,7 @@ class AssignIds {
42 ProcessMaps(datadir_path); 42 ProcessMaps(datadir_path);
43 ProcessSpecialIds(); 43 ProcessSpecialIds();
44 ProcessProgressivesFile(datadir_path / "progressives.txtpb"); 44 ProcessProgressivesFile(datadir_path / "progressives.txtpb");
45 ProcessDoorGroupsFile(datadir_path / "door_groups.txtpb");
45 46
46 WriteIds(ids_path); 47 WriteIds(ids_path);
47 48
@@ -61,6 +62,7 @@ class AssignIds {
61 for (const auto& [_, room] : map.rooms()) { 62 for (const auto& [_, room] : map.rooms()) {
62 UpdateNextId(room.panels()); 63 UpdateNextId(room.panels());
63 UpdateNextId(room.masteries()); 64 UpdateNextId(room.masteries());
65 UpdateNextId(room.keyholders());
64 } 66 }
65 } 67 }
66 68
@@ -68,6 +70,7 @@ class AssignIds {
68 UpdateNextId(id_mappings_.letters()); 70 UpdateNextId(id_mappings_.letters());
69 UpdateNextId(id_mappings_.endings()); 71 UpdateNextId(id_mappings_.endings());
70 UpdateNextId(id_mappings_.progressives()); 72 UpdateNextId(id_mappings_.progressives());
73 UpdateNextId(id_mappings_.door_groups());
71 74
72 next_id_++; 75 next_id_++;
73 } 76 }
@@ -267,6 +270,23 @@ class AssignIds {
267 } 270 }
268 } 271 }
269 272
273 void ProcessDoorGroupsFile(std::filesystem::path path) {
274 if (!std::filesystem::exists(path)) {
275 return;
276 }
277
278 auto h_groups = ReadMessageFromFile<HumanDoorGroups>(path.string());
279 auto& groups = *output_.mutable_door_groups();
280
281 for (const HumanDoorGroup& h_group : h_groups.door_groups()) {
282 if (!id_mappings_.door_groups().contains(h_group.name())) {
283 groups[h_group.name()] = next_id_++;
284 } else {
285 groups[h_group.name()] = id_mappings_.door_groups().at(h_group.name());
286 }
287 }
288 }
289
270 private: 290 private:
271 void UpdateNextId(const google::protobuf::Map<std::string, uint64_t>& ids) { 291 void UpdateNextId(const google::protobuf::Map<std::string, uint64_t>& ids) {
272 for (const auto& [_, id] : ids) { 292 for (const auto& [_, id] : ids) {
diff --git a/tools/datapacker/container.cpp b/tools/datapacker/container.cpp index 624caf8..4a656b3 100644 --- a/tools/datapacker/container.cpp +++ b/tools/datapacker/container.cpp
@@ -348,6 +348,23 @@ uint64_t Container::FindOrAddProgressive(std::string prog_name) {
348 } 348 }
349} 349}
350 350
351uint64_t Container::FindOrAddDoorGroup(std::string group_name) {
352 auto it = door_group_id_by_name_.find(group_name);
353
354 if (it == door_group_id_by_name_.end()) {
355 uint64_t new_id = all_objects_.door_groups_size();
356 DoorGroup* door_group = all_objects_.add_door_groups();
357 door_group->set_id(new_id);
358 door_group->set_name(group_name);
359
360 door_group_id_by_name_[group_name] = new_id;
361
362 return new_id;
363 } else {
364 return it->second;
365 }
366}
367
351void Container::AddConnection(const Connection& connection) { 368void Container::AddConnection(const Connection& connection) {
352 *all_objects_.add_connections() = connection; 369 *all_objects_.add_connections() = connection;
353} 370}
diff --git a/tools/datapacker/container.h b/tools/datapacker/container.h index 8cec560..bc02ba4 100644 --- a/tools/datapacker/container.h +++ b/tools/datapacker/container.h
@@ -62,6 +62,8 @@ class Container {
62 62
63 uint64_t FindOrAddProgressive(std::string prog_name); 63 uint64_t FindOrAddProgressive(std::string prog_name);
64 64
65 uint64_t FindOrAddDoorGroup(std::string group_name);
66
65 AllObjects& all_objects() { return all_objects_; } 67 AllObjects& all_objects() { return all_objects_; }
66 68
67 private: 69 private:
@@ -85,6 +87,7 @@ class Container {
85 door_id_by_map_door_names_; 87 door_id_by_map_door_names_;
86 std::map<std::string, uint64_t> ending_id_by_name_; 88 std::map<std::string, uint64_t> ending_id_by_name_;
87 std::map<std::string, uint64_t> progressive_id_by_name_; 89 std::map<std::string, uint64_t> progressive_id_by_name_;
90 std::map<std::string, uint64_t> door_group_id_by_name_;
88}; 91};
89 92
90} // namespace com::fourisland::lingo2_archipelago 93} // namespace com::fourisland::lingo2_archipelago
diff --git a/tools/datapacker/main.cpp b/tools/datapacker/main.cpp index 595647d..c72462d 100644 --- a/tools/datapacker/main.cpp +++ b/tools/datapacker/main.cpp
@@ -44,6 +44,7 @@ class DataPacker {
44 ProcessConnectionsFile(datadir_path / "connections.txtpb", std::nullopt); 44 ProcessConnectionsFile(datadir_path / "connections.txtpb", std::nullopt);
45 ProcessMaps(datadir_path); 45 ProcessMaps(datadir_path);
46 ProcessProgressivesFile(datadir_path / "progressives.txtpb"); 46 ProcessProgressivesFile(datadir_path / "progressives.txtpb");
47 ProcessDoorGroupsFile(datadir_path / "door_groups.txtpb");
47 ProcessIdsFile(datadir_path / "ids.yaml"); 48 ProcessIdsFile(datadir_path / "ids.yaml");
48 49
49 { 50 {
@@ -577,6 +578,31 @@ class DataPacker {
577 } 578 }
578 } 579 }
579 580
581 void ProcessDoorGroupsFile(std::filesystem::path path) {
582 if (!std::filesystem::exists(path)) {
583 return;
584 }
585
586 auto h_groups = ReadMessageFromFile<HumanDoorGroups>(path.string());
587
588 for (const HumanDoorGroup& h_group : h_groups.door_groups()) {
589 ProcessDoorGroup(h_group);
590 }
591 }
592
593 void ProcessDoorGroup(const HumanDoorGroup& h_group) {
594 uint64_t group_id = container_.FindOrAddDoorGroup(h_group.name());
595 DoorGroup& group = *container_.all_objects().mutable_door_groups(group_id);
596
597 group.set_type(h_group.type());
598
599 for (const DoorIdentifier& di : h_group.doors()) {
600 uint64_t door_id =
601 container_.FindOrAddDoor(di.map(), di.name(), std::nullopt);
602 group.add_doors(door_id);
603 }
604 }
605
580 void ProcessIdsFile(std::filesystem::path path) { 606 void ProcessIdsFile(std::filesystem::path path) {
581 auto ids = ReadIdsFromYaml(path.string()); 607 auto ids = ReadIdsFromYaml(path.string());
582 608
@@ -631,6 +657,11 @@ class DataPacker {
631 uint64_t prog_id = container_.FindOrAddProgressive(prog_name); 657 uint64_t prog_id = container_.FindOrAddProgressive(prog_name);
632 container_.all_objects().mutable_progressives(prog_id)->set_ap_id(ap_id); 658 container_.all_objects().mutable_progressives(prog_id)->set_ap_id(ap_id);
633 } 659 }
660
661 for (const auto& [group_name, ap_id] : ids.door_groups()) {
662 uint64_t group_id = container_.FindOrAddDoorGroup(group_name);
663 container_.all_objects().mutable_door_groups(group_id)->set_ap_id(ap_id);
664 }
634 } 665 }
635 666
636 std::string mapdir_; 667 std::string mapdir_;
diff --git a/tools/util/ids_yaml_format.cpp b/tools/util/ids_yaml_format.cpp index 67c21d6..71bfd63 100644 --- a/tools/util/ids_yaml_format.cpp +++ b/tools/util/ids_yaml_format.cpp
@@ -104,6 +104,13 @@ IdMappings ReadIdsFromYaml(const std::string& filename) {
104 } 104 }
105 } 105 }
106 106
107 if (document["door_groups"]) {
108 for (const auto& group_it : document["door_groups"]) {
109 (*result.mutable_door_groups())[group_it.first.as<std::string>()] =
110 group_it.second.as<uint64_t>();
111 }
112 }
113
107 return result; 114 return result;
108} 115}
109 116
@@ -171,6 +178,11 @@ void WriteIdsAsYaml(const IdMappings& ids, const std::string& filename) {
171 result["progressives"][prog_name] = prog_id; 178 result["progressives"][prog_name] = prog_id;
172 }); 179 });
173 180
181 OperateOnSortedMap(ids.door_groups(), [&result](const std::string& group_name,
182 uint64_t group_id) {
183 result["door_groups"][group_name] = group_id;
184 });
185
174 std::ofstream output_stream(filename); 186 std::ofstream output_stream(filename);
175 output_stream << result << std::endl; 187 output_stream << result << std::endl;
176} 188}
diff --git a/tools/validator/human_processor.cpp b/tools/validator/human_processor.cpp index 5720ba9..561225e 100644 --- a/tools/validator/human_processor.cpp +++ b/tools/validator/human_processor.cpp
@@ -43,6 +43,7 @@ class HumanProcessor {
43 ProcessConnectionsFile(datadir_path / "connections.txtpb", std::nullopt); 43 ProcessConnectionsFile(datadir_path / "connections.txtpb", std::nullopt);
44 ProcessMaps(datadir_path); 44 ProcessMaps(datadir_path);
45 ProcessProgressivesFile(datadir_path / "progressives.txtpb"); 45 ProcessProgressivesFile(datadir_path / "progressives.txtpb");
46 ProcessDoorGroupsFile(datadir_path / "door_groups.txtpb");
46 ProcessIdsFile(datadir_path / "ids.yaml"); 47 ProcessIdsFile(datadir_path / "ids.yaml");
47 } 48 }
48 49
@@ -510,6 +511,33 @@ class HumanProcessor {
510 } 511 }
511 } 512 }
512 513
514 void ProcessDoorGroupsFile(std::filesystem::path path) {
515 if (!std::filesystem::exists(path)) {
516 return;
517 }
518
519 auto h_groups = ReadMessageFromFile<HumanDoorGroups>(path.string());
520
521 for (const HumanDoorGroup& h_group : h_groups.door_groups()) {
522 ProcessDoorGroup(h_group);
523 }
524 }
525
526 void ProcessDoorGroup(const HumanDoorGroup& h_group) {
527 DoorGroupInfo& group_info = info_.door_groups[h_group.name()];
528 group_info.definitions.push_back(h_group);
529
530 for (const DoorIdentifier& di : h_group.doors()) {
531 if (!di.has_map()) {
532 group_info.malformed_doors.push_back(di);
533 continue;
534 }
535
536 DoorInfo& door_info = info_.doors[di];
537 door_info.door_groups_referenced_by.push_back(h_group.name());
538 }
539 }
540
513 void ProcessIdsFile(std::filesystem::path path) { 541 void ProcessIdsFile(std::filesystem::path path) {
514 auto ids = ReadIdsFromYaml(path.string()); 542 auto ids = ReadIdsFromYaml(path.string());
515 543
@@ -573,6 +601,11 @@ class HumanProcessor {
573 ProgressiveInfo& prog_info = info_.progressives[prog_name]; 601 ProgressiveInfo& prog_info = info_.progressives[prog_name];
574 prog_info.has_id = true; 602 prog_info.has_id = true;
575 } 603 }
604
605 for (const auto& [group_name, ap_id] : ids.door_groups()) {
606 DoorGroupInfo& group_info = info_.door_groups[group_name];
607 group_info.has_id = true;
608 }
576 } 609 }
577 610
578 std::string mapdir_; 611 std::string mapdir_;
diff --git a/tools/validator/structs.h b/tools/validator/structs.h index e24ed3d..17ed33a 100644 --- a/tools/validator/structs.h +++ b/tools/validator/structs.h
@@ -47,6 +47,7 @@ struct DoorInfo {
47 std::vector<PaintingIdentifier> paintings_referenced_by; 47 std::vector<PaintingIdentifier> paintings_referenced_by;
48 std::vector<PortIdentifier> ports_referenced_by; 48 std::vector<PortIdentifier> ports_referenced_by;
49 std::vector<std::string> progressives_referenced_by; 49 std::vector<std::string> progressives_referenced_by;
50 std::vector<std::string> door_groups_referenced_by;
50 51
51 MalformedIdentifiers malformed_identifiers; 52 MalformedIdentifiers malformed_identifiers;
52}; 53};
@@ -115,6 +116,13 @@ struct ProgressiveInfo {
115 std::vector<DoorIdentifier> malformed_doors; 116 std::vector<DoorIdentifier> malformed_doors;
116}; 117};
117 118
119struct DoorGroupInfo {
120 std::vector<HumanDoorGroup> definitions;
121 bool has_id = false;
122
123 std::vector<DoorIdentifier> malformed_doors;
124};
125
118struct CollectedInfo { 126struct CollectedInfo {
119 std::map<std::string, MapInfo> maps; 127 std::map<std::string, MapInfo> maps;
120 std::map<RoomIdentifier, RoomInfo, RoomIdentifierLess> rooms; 128 std::map<RoomIdentifier, RoomInfo, RoomIdentifierLess> rooms;
@@ -128,6 +136,7 @@ struct CollectedInfo {
128 std::map<std::string, EndingInfo> endings; 136 std::map<std::string, EndingInfo> endings;
129 std::map<std::string, PanelNameInfo> panel_names; 137 std::map<std::string, PanelNameInfo> panel_names;
130 std::map<std::string, ProgressiveInfo> progressives; 138 std::map<std::string, ProgressiveInfo> progressives;
139 std::map<std::string, DoorGroupInfo> door_groups;
131}; 140};
132 141
133} // namespace com::fourisland::lingo2_archipelago 142} // namespace com::fourisland::lingo2_archipelago
diff --git a/tools/validator/validator.cpp b/tools/validator/validator.cpp index ab1612e..4149caa 100644 --- a/tools/validator/validator.cpp +++ b/tools/validator/validator.cpp
@@ -48,6 +48,9 @@ class Validator {
48 for (const auto& [prog_name, prog_info] : info_.progressives) { 48 for (const auto& [prog_name, prog_info] : info_.progressives) {
49 ValidateProgressive(prog_name, prog_info); 49 ValidateProgressive(prog_name, prog_info);
50 } 50 }
51 for (const auto& [group_name, group_info] : info_.door_groups) {
52 ValidateDoorGroup(group_name, group_info);
53 }
51 } 54 }
52 55
53 private: 56 private:
@@ -173,6 +176,11 @@ class Validator {
173 std::cout << " PROGRESSIVE " << prog_name << std::endl; 176 std::cout << " PROGRESSIVE " << prog_name << std::endl;
174 } 177 }
175 178
179 for (const std::string& group_name :
180 door_info.door_groups_referenced_by) {
181 std::cout << " DOOR GROUP " << group_name << std::endl;
182 }
183
176 if (door_info.has_id) { 184 if (door_info.has_id) {
177 std::cout << " An AP ID is present." << std::endl; 185 std::cout << " An AP ID is present." << std::endl;
178 } 186 }
@@ -460,6 +468,26 @@ class Validator {
460 } 468 }
461 } 469 }
462 470
471 void ValidateDoorGroup(const std::string& group_name,
472 const DoorGroupInfo& group_info) const {
473 if (group_info.definitions.empty()) {
474 std::cout << "Door group \"" << group_name
475 << "\" has no definition, but was referenced:" << std::endl;
476
477 if (group_info.has_id) {
478 std::cout << " An AP ID is present." << std::endl;
479 }
480 } else if (group_info.definitions.size() > 1) {
481 std::cout << "Door group \"" << group_name
482 << "\" has multiple definitions." << std::endl;
483 }
484
485 if (!group_info.has_id) {
486 std::cout << "Door group \"" << group_name << "\" is missing an AP ID."
487 << std::endl;
488 }
489 }
490
463 const CollectedInfo& info_; 491 const CollectedInfo& info_;
464}; 492};
465 493