summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-09-01 12:54:46 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2025-09-01 12:54:46 -0400
commita3972a65b9b443a6085a6ac40b153442e190f382 (patch)
tree8291258115a066f99c972005557208cb9dbd8899
parentd142ae3408d3e26e12d7dfaa6a7ccbcf56042957 (diff)
downloadlingo2-archipelago-a3972a65b9b443a6085a6ac40b153442e190f382.tar.gz
lingo2-archipelago-a3972a65b9b443a6085a6ac40b153442e190f382.tar.bz2
lingo2-archipelago-a3972a65b9b443a6085a6ac40b153442e190f382.zip
Added progressive doors
-rw-r--r--apworld/player_logic.py27
-rw-r--r--apworld/rules.py3
-rw-r--r--apworld/static_logic.py3
-rw-r--r--data/ids.yaml3
-rw-r--r--data/progressives.txtpb22
-rw-r--r--proto/data.proto8
-rw-r--r--proto/human.proto10
-rw-r--r--tools/assign_ids/main.cpp64
-rw-r--r--tools/datapacker/container.cpp17
-rw-r--r--tools/datapacker/container.h3
-rw-r--r--tools/datapacker/main.cpp33
-rw-r--r--tools/util/ids_yaml_format.cpp12
-rw-r--r--tools/validator/human_processor.cpp28
-rw-r--r--tools/validator/structs.h8
-rw-r--r--tools/validator/validator.cpp16
15 files changed, 219 insertions, 38 deletions
diff --git a/apworld/player_logic.py b/apworld/player_logic.py index c6465f6..e08f644 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py
@@ -23,6 +23,7 @@ def calculate_letter_histogram(solution: str) -> dict[str, int]:
23 23
24class AccessRequirements: 24class AccessRequirements:
25 items: set[str] 25 items: set[str]
26 progressives: dict[str, int]
26 rooms: set[str] 27 rooms: set[str]
27 symbols: set[str] 28 symbols: set[str]
28 letters: dict[str, int] 29 letters: dict[str, int]
@@ -32,6 +33,7 @@ class AccessRequirements:
32 33
33 def __init__(self): 34 def __init__(self):
34 self.items = set() 35 self.items = set()
36 self.progressives = dict()
35 self.rooms = set() 37 self.rooms = set()
36 self.symbols = set() 38 self.symbols = set()
37 self.letters = dict() 39 self.letters = dict()
@@ -47,6 +49,9 @@ class AccessRequirements:
47 for item in other.items: 49 for item in other.items:
48 self.items.add(item) 50 self.items.add(item)
49 51
52 for item, amount in other.progressives.items():
53 self.progressives[item] = max(amount, self.progressives.get(item, 0))
54
50 for room in other.rooms: 55 for room in other.rooms:
51 self.rooms.add(room) 56 self.rooms.add(room)
52 57
@@ -63,6 +68,8 @@ class AccessRequirements:
63 parts = [] 68 parts = []
64 if len(self.items) > 0: 69 if len(self.items) > 0:
65 parts.append(f"items={self.items}") 70 parts.append(f"items={self.items}")
71 if len(self.progressives) > 0:
72 parts.append(f"progressives={self.progressives}")
66 if len(self.rooms) > 0: 73 if len(self.rooms) > 0:
67 parts.append(f"rooms={self.rooms}") 74 parts.append(f"rooms={self.rooms}")
68 if len(self.symbols) > 0: 75 if len(self.symbols) > 0:
@@ -85,7 +92,7 @@ class Lingo2PlayerLogic:
85 locations_by_room: dict[int, list[PlayerLocation]] 92 locations_by_room: dict[int, list[PlayerLocation]]
86 event_loc_item_by_room: dict[int, dict[str, str]] 93 event_loc_item_by_room: dict[int, dict[str, str]]
87 94
88 item_by_door: dict[int, str] 95 item_by_door: dict[int, tuple[str, int]]
89 96
90 panel_reqs: dict[int, AccessRequirements] 97 panel_reqs: dict[int, AccessRequirements]
91 proxy_reqs: dict[int, dict[str, AccessRequirements]] 98 proxy_reqs: dict[int, dict[str, AccessRequirements]]
@@ -103,12 +110,21 @@ class Lingo2PlayerLogic:
103 self.door_reqs = dict() 110 self.door_reqs = dict()
104 self.real_items = list() 111 self.real_items = list()
105 112
113 if self.world.options.shuffle_doors:
114 for progressive in world.static_logic.objects.progressives:
115 for i in range(0, len(progressive.doors)):
116 self.item_by_door[progressive.doors[i]] = (progressive.name, i + 1)
117 self.real_items.append(progressive.name)
118
106 # We iterate through the doors in two parts because it is essential that we determine which doors are shuffled 119 # We iterate through the doors in two parts because it is essential that we determine which doors are shuffled
107 # before we calculate any access requirements. 120 # before we calculate any access requirements.
108 for door in world.static_logic.objects.doors: 121 for door in world.static_logic.objects.doors:
109 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.ITEM_ONLY] and self.world.options.shuffle_doors: 122 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.ITEM_ONLY] and self.world.options.shuffle_doors:
123 if door.id in self.item_by_door:
124 continue
125
110 door_item_name = self.world.static_logic.get_door_item_name(door) 126 door_item_name = self.world.static_logic.get_door_item_name(door)
111 self.item_by_door[door.id] = door_item_name 127 self.item_by_door[door.id] = (door_item_name, 1)
112 self.real_items.append(door_item_name) 128 self.real_items.append(door_item_name)
113 129
114 for door in world.static_logic.objects.doors: 130 for door in world.static_logic.objects.doors:
@@ -261,7 +277,12 @@ class Lingo2PlayerLogic:
261 def get_door_open_reqs(self, door_id: int) -> AccessRequirements: 277 def get_door_open_reqs(self, door_id: int) -> AccessRequirements:
262 if door_id in self.item_by_door: 278 if door_id in self.item_by_door:
263 reqs = AccessRequirements() 279 reqs = AccessRequirements()
264 reqs.items.add(self.item_by_door.get(door_id)) 280
281 item_name, amount = self.item_by_door.get(door_id)
282 if amount == 1:
283 reqs.items.add(item_name)
284 else:
285 reqs.progressives[item_name] = amount
265 286
266 return reqs 287 return reqs
267 else: 288 else:
diff --git a/apworld/rules.py b/apworld/rules.py index 4a84acf..5e20de5 100644 --- a/apworld/rules.py +++ b/apworld/rules.py
@@ -12,6 +12,9 @@ def lingo2_can_satisfy_requirements(state: CollectionState, reqs: AccessRequirem
12 if not all(state.has(item, world.player) for item in reqs.items): 12 if not all(state.has(item, world.player) for item in reqs.items):
13 return False 13 return False
14 14
15 if not all(state.has(item, world.player, amount) for item, amount in reqs.progressives.items()):
16 return False
17
15 if not all(state.can_reach_region(region_name, world.player) for region_name in reqs.rooms): 18 if not all(state.can_reach_region(region_name, world.player) for region_name in reqs.rooms):
16 return False 19 return False
17 20
diff --git a/apworld/static_logic.py b/apworld/static_logic.py index ff1f17d..0613474 100644 --- a/apworld/static_logic.py +++ b/apworld/static_logic.py
@@ -41,6 +41,9 @@ class Lingo2StaticLogic:
41 location_name = f"{self.get_room_object_map_name(ending)} - {ending.name.title()} Ending" 41 location_name = f"{self.get_room_object_map_name(ending)} - {ending.name.title()} Ending"
42 self.location_id_to_name[ending.ap_id] = location_name 42 self.location_id_to_name[ending.ap_id] = location_name
43 43
44 for progressive in self.objects.progressives:
45 self.item_id_to_name[progressive.ap_id] = progressive.name
46
44 self.item_id_to_name[self.objects.special_ids["Nothing"]] = "Nothing" 47 self.item_id_to_name[self.objects.special_ids["Nothing"]] = "Nothing"
45 48
46 self.item_name_to_id = {name: ap_id for ap_id, name in self.item_id_to_name.items()} 49 self.item_name_to_id = {name: ap_id for ap_id, name in self.item_id_to_name.items()}
diff --git a/data/ids.yaml b/data/ids.yaml index 1184bfd..3aff6ea 100644 --- a/data/ids.yaml +++ b/data/ids.yaml
@@ -3800,3 +3800,6 @@ endings:
3800 YELLOW: 1206 3800 YELLOW: 1206
3801special: 3801special:
3802 Nothing: 1160 3802 Nothing: 1160
3803progressives:
3804 Progressive Gold Ending: 2753
3805 Progressive Symbolic Entrance: 2752
diff --git a/data/progressives.txtpb b/data/progressives.txtpb new file mode 100644 index 0000000..cacb968 --- /dev/null +++ b/data/progressives.txtpb
@@ -0,0 +1,22 @@
1progressives {
2 name: "Progressive Symbolic Entrance"
3 doors { map: "the_symbolic" name: "White Door" }
4 doors { map: "the_symbolic" name: "Black Door" }
5 doors { map: "the_symbolic" name: "Red Door" }
6 doors { map: "the_symbolic" name: "Blue Door" }
7 doors { map: "the_symbolic" name: "Green Door" }
8 doors { map: "the_symbolic" name: "Yellow Door" }
9 doors { map: "the_symbolic" name: "Purple Door" }
10 doors { map: "the_symbolic" name: "Orange Door" }
11}
12progressives {
13 name: "Progressive Gold Ending"
14 doors { map: "daedalus" name: "Red Rainbow Room" }
15 doors { map: "daedalus" name: "Orange Rainbow Room" }
16 doors { map: "daedalus" name: "Yellow Rainbow Room" }
17 doors { map: "daedalus" name: "Green Rainbow Room" }
18 doors { map: "daedalus" name: "Blue Rainbow Room" }
19 doors { map: "daedalus" name: "Purple Rainbow Room" }
20 doors { map: "daedalus" name: "Cyan Rainbow Room" }
21 doors { map: "daedalus" name: "Brown Rainbow Room" }
22}
diff --git a/proto/data.proto b/proto/data.proto index 60b603b..b627e83 100644 --- a/proto/data.proto +++ b/proto/data.proto
@@ -221,6 +221,13 @@ message Map {
221 optional string display_name = 3; 221 optional string display_name = 3;
222} 222}
223 223
224message Progressive {
225 optional uint64 id = 1;
226 optional string name = 2;
227 optional uint64 ap_id = 3;
228 repeated uint64 doors = 4;
229}
230
224message AllObjects { 231message AllObjects {
225 repeated Map maps = 7; 232 repeated Map maps = 7;
226 repeated Room rooms = 1; 233 repeated Room rooms = 1;
@@ -233,5 +240,6 @@ message AllObjects {
233 repeated Mastery masteries = 10; 240 repeated Mastery masteries = 10;
234 repeated Ending endings = 12; 241 repeated Ending endings = 12;
235 repeated Connection connections = 6; 242 repeated Connection connections = 6;
243 repeated Progressive progressives = 13;
236 map<string, uint64> special_ids = 8; 244 map<string, uint64> special_ids = 8;
237} 245}
diff --git a/proto/human.proto b/proto/human.proto index c7e2f5d..8d882da 100644 --- a/proto/human.proto +++ b/proto/human.proto
@@ -183,6 +183,15 @@ message HumanMap {
183 repeated string excluded_nodes = 2; 183 repeated string excluded_nodes = 2;
184} 184}
185 185
186message HumanProgressive {
187 optional string name = 1;
188 repeated DoorIdentifier doors = 2;
189}
190
191message HumanProgressives {
192 repeated HumanProgressive progressives = 1;
193}
194
186message IdMappings { 195message IdMappings {
187 message RoomIds { 196 message RoomIds {
188 map<string, uint64> panels = 1; 197 map<string, uint64> panels = 1;
@@ -198,4 +207,5 @@ message IdMappings {
198 map<string, uint64> special = 2; 207 map<string, uint64> special = 2;
199 map<string, uint64> letters = 3; 208 map<string, uint64> letters = 3;
200 map<string, uint64> endings = 4; 209 map<string, uint64> endings = 4;
210 map<string, uint64> progressives = 5;
201} 211}
diff --git a/tools/assign_ids/main.cpp b/tools/assign_ids/main.cpp index e65e5e4..3a2f347 100644 --- a/tools/assign_ids/main.cpp +++ b/tools/assign_ids/main.cpp
@@ -40,6 +40,7 @@ class AssignIds {
40 ReadIds(ids_path); 40 ReadIds(ids_path);
41 41
42 ProcessMaps(datadir_path); 42 ProcessMaps(datadir_path);
43 ProcessProgressivesFile(datadir_path / "progressives.txtpb");
43 44
44 WriteIds(ids_path); 45 WriteIds(ids_path);
45 46
@@ -54,44 +55,18 @@ class AssignIds {
54 id_mappings_ = ReadIdsFromYaml(path.string()); 55 id_mappings_ = ReadIdsFromYaml(path.string());
55 56
56 for (const auto& [_, map] : id_mappings_.maps()) { 57 for (const auto& [_, map] : id_mappings_.maps()) {
57 for (const auto& [_, id] : map.doors()) { 58 UpdateNextId(map.doors());
58 if (id > next_id_) {
59 next_id_ = id;
60 }
61 }
62 59
63 for (const auto& [_, room] : map.rooms()) { 60 for (const auto& [_, room] : map.rooms()) {
64 for (const auto& [_, id] : room.panels()) { 61 UpdateNextId(room.panels());
65 if (id > next_id_) { 62 UpdateNextId(room.masteries());
66 next_id_ = id;
67 }
68 }
69
70 for (const auto& [_, id] : room.masteries()) {
71 if (id > next_id_) {
72 next_id_ = id;
73 }
74 }
75 }
76 }
77
78 for (const auto& [_, id] : id_mappings_.special()) {
79 if (id > next_id_) {
80 next_id_ = id;
81 } 63 }
82 } 64 }
83 65
84 for (const auto& [_, id] : id_mappings_.letters()) { 66 UpdateNextId(id_mappings_.special());
85 if (id > next_id_) { 67 UpdateNextId(id_mappings_.letters());
86 next_id_ = id; 68 UpdateNextId(id_mappings_.endings());
87 } 69 UpdateNextId(id_mappings_.progressives());
88 }
89
90 for (const auto& [_, id] : id_mappings_.endings()) {
91 if (id > next_id_) {
92 next_id_ = id;
93 }
94 }
95 70
96 next_id_++; 71 next_id_++;
97 } 72 }
@@ -210,7 +185,30 @@ class AssignIds {
210 } 185 }
211 } 186 }
212 187
188 void ProcessProgressivesFile(std::filesystem::path path) {
189 if (!std::filesystem::exists(path)) {
190 return;
191 }
192
193 auto h_progs = ReadMessageFromFile<HumanProgressives>(path.string());
194 auto& progs = *id_mappings_.mutable_progressives();
195
196 for (const HumanProgressive& h_prog : h_progs.progressives()) {
197 if (!progs.contains(h_prog.name())) {
198 progs[h_prog.name()] = next_id_++;
199 }
200 }
201 }
202
213 private: 203 private:
204 void UpdateNextId(const google::protobuf::Map<std::string, uint64_t>& ids) {
205 for (const auto& [_, id] : ids) {
206 if (id > next_id_) {
207 next_id_ = id;
208 }
209 }
210 }
211
214 std::string mapdir_; 212 std::string mapdir_;
215 213
216 uint64_t next_id_ = 1; 214 uint64_t next_id_ = 1;
diff --git a/tools/datapacker/container.cpp b/tools/datapacker/container.cpp index 2c68552..624caf8 100644 --- a/tools/datapacker/container.cpp +++ b/tools/datapacker/container.cpp
@@ -331,6 +331,23 @@ uint64_t Container::FindOrAddDoor(std::optional<std::string> map_name,
331 } 331 }
332} 332}
333 333
334uint64_t Container::FindOrAddProgressive(std::string prog_name) {
335 auto it = progressive_id_by_name_.find(prog_name);
336
337 if (it == progressive_id_by_name_.end()) {
338 uint64_t new_id = all_objects_.progressives_size();
339 Progressive* progressive = all_objects_.add_progressives();
340 progressive->set_id(new_id);
341 progressive->set_name(prog_name);
342
343 progressive_id_by_name_[prog_name] = new_id;
344
345 return new_id;
346 } else {
347 return it->second;
348 }
349}
350
334void Container::AddConnection(const Connection& connection) { 351void Container::AddConnection(const Connection& connection) {
335 *all_objects_.add_connections() = connection; 352 *all_objects_.add_connections() = connection;
336} 353}
diff --git a/tools/datapacker/container.h b/tools/datapacker/container.h index 68f5875..8cec560 100644 --- a/tools/datapacker/container.h +++ b/tools/datapacker/container.h
@@ -60,6 +60,8 @@ class Container {
60 60
61 void AddConnection(const Connection& connection); 61 void AddConnection(const Connection& connection);
62 62
63 uint64_t FindOrAddProgressive(std::string prog_name);
64
63 AllObjects& all_objects() { return all_objects_; } 65 AllObjects& all_objects() { return all_objects_; }
64 66
65 private: 67 private:
@@ -82,6 +84,7 @@ class Container {
82 std::map<std::string, std::map<std::string, uint64_t>> 84 std::map<std::string, std::map<std::string, uint64_t>>
83 door_id_by_map_door_names_; 85 door_id_by_map_door_names_;
84 std::map<std::string, uint64_t> ending_id_by_name_; 86 std::map<std::string, uint64_t> ending_id_by_name_;
87 std::map<std::string, uint64_t> progressive_id_by_name_;
85}; 88};
86 89
87} // namespace com::fourisland::lingo2_archipelago 90} // namespace com::fourisland::lingo2_archipelago
diff --git a/tools/datapacker/main.cpp b/tools/datapacker/main.cpp index 4923fce..5ed82cc 100644 --- a/tools/datapacker/main.cpp +++ b/tools/datapacker/main.cpp
@@ -43,6 +43,7 @@ class DataPacker {
43 43
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 ProcessIdsFile(datadir_path / "ids.yaml"); 47 ProcessIdsFile(datadir_path / "ids.yaml");
47 48
48 { 49 {
@@ -104,7 +105,7 @@ class DataPacker {
104 container_.FindOrAddRoom(current_map_name, h_room.name(), std::nullopt); 105 container_.FindOrAddRoom(current_map_name, h_room.name(), std::nullopt);
105 Room& room = *container_.all_objects().mutable_rooms(room_id); 106 Room& room = *container_.all_objects().mutable_rooms(room_id);
106 107
107 //room.set_display_name(h_room.display_name()); 108 // room.set_display_name(h_room.display_name());
108 109
109 if (h_room.has_panel_display_name()) { 110 if (h_room.has_panel_display_name()) {
110 room.set_panel_display_name(h_room.panel_display_name()); 111 room.set_panel_display_name(h_room.panel_display_name());
@@ -388,7 +389,7 @@ class DataPacker {
388 door.add_doors( 389 door.add_doors(
389 container_.FindOrAddDoor(map_name, di.name(), current_map_name)); 390 container_.FindOrAddDoor(map_name, di.name(), current_map_name));
390 } 391 }
391 392
392 for (const std::string& ending_name : h_door.endings()) { 393 for (const std::string& ending_name : h_door.endings()) {
393 door.add_endings(container_.FindOrAddEnding(ending_name)); 394 door.add_endings(container_.FindOrAddEnding(ending_name));
394 } 395 }
@@ -544,6 +545,29 @@ class DataPacker {
544 } 545 }
545 } 546 }
546 547
548 void ProcessProgressivesFile(std::filesystem::path path) {
549 if (!std::filesystem::exists(path)) {
550 return;
551 }
552
553 auto h_progs = ReadMessageFromFile<HumanProgressives>(path.string());
554
555 for (const HumanProgressive& h_prog : h_progs.progressives()) {
556 ProcessProgressive(h_prog);
557 }
558 }
559
560 void ProcessProgressive(const HumanProgressive& h_prog) {
561 uint64_t prog_id = container_.FindOrAddProgressive(h_prog.name());
562 Progressive& prog = *container_.all_objects().mutable_progressives(prog_id);
563
564 for (const DoorIdentifier& di : h_prog.doors()) {
565 uint64_t door_id =
566 container_.FindOrAddDoor(di.map(), di.name(), std::nullopt);
567 prog.add_doors(door_id);
568 }
569 }
570
547 void ProcessIdsFile(std::filesystem::path path) { 571 void ProcessIdsFile(std::filesystem::path path) {
548 auto ids = ReadIdsFromYaml(path.string()); 572 auto ids = ReadIdsFromYaml(path.string());
549 573
@@ -585,6 +609,11 @@ class DataPacker {
585 uint64_t ending_id = container_.FindOrAddEnding(ending_name); 609 uint64_t ending_id = container_.FindOrAddEnding(ending_name);
586 container_.all_objects().mutable_endings(ending_id)->set_ap_id(ap_id); 610 container_.all_objects().mutable_endings(ending_id)->set_ap_id(ap_id);
587 } 611 }
612
613 for (const auto& [prog_name, ap_id] : ids.progressives()) {
614 uint64_t prog_id = container_.FindOrAddProgressive(prog_name);
615 container_.all_objects().mutable_progressives(prog_id)->set_ap_id(ap_id);
616 }
588 } 617 }
589 618
590 std::string mapdir_; 619 std::string mapdir_;
diff --git a/tools/util/ids_yaml_format.cpp b/tools/util/ids_yaml_format.cpp index f72f60e..ae62073 100644 --- a/tools/util/ids_yaml_format.cpp +++ b/tools/util/ids_yaml_format.cpp
@@ -89,6 +89,13 @@ IdMappings ReadIdsFromYaml(const std::string& filename) {
89 } 89 }
90 } 90 }
91 91
92 if (document["progressives"]) {
93 for (const auto& prog_it : document["progressives"]) {
94 (*result.mutable_progressives())[prog_it.first.as<std::string>()] =
95 prog_it.second.as<uint64_t>();
96 }
97 }
98
92 return result; 99 return result;
93} 100}
94 101
@@ -144,6 +151,11 @@ void WriteIdsAsYaml(const IdMappings& ids, const std::string& filename) {
144 result["special"][special_name] = special_id; 151 result["special"][special_name] = special_id;
145 }); 152 });
146 153
154 OperateOnSortedMap(ids.progressives(),
155 [&result](const std::string& prog_name, uint64_t prog_id) {
156 result["progressives"][prog_name] = prog_id;
157 });
158
147 std::ofstream output_stream(filename); 159 std::ofstream output_stream(filename);
148 output_stream << result << std::endl; 160 output_stream << result << std::endl;
149} 161}
diff --git a/tools/validator/human_processor.cpp b/tools/validator/human_processor.cpp index 0f63936..49e7578 100644 --- a/tools/validator/human_processor.cpp +++ b/tools/validator/human_processor.cpp
@@ -41,6 +41,7 @@ class HumanProcessor {
41 41
42 ProcessConnectionsFile(datadir_path / "connections.txtpb", std::nullopt); 42 ProcessConnectionsFile(datadir_path / "connections.txtpb", std::nullopt);
43 ProcessMaps(datadir_path); 43 ProcessMaps(datadir_path);
44 ProcessProgressivesFile(datadir_path / "progressives.txtpb");
44 ProcessIdsFile(datadir_path / "ids.txtpb"); 45 ProcessIdsFile(datadir_path / "ids.txtpb");
45 } 46 }
46 47
@@ -481,6 +482,33 @@ class HumanProcessor {
481 } 482 }
482 } 483 }
483 484
485 void ProcessProgressivesFile(std::filesystem::path path) {
486 if (!std::filesystem::exists(path)) {
487 return;
488 }
489
490 auto h_progs = ReadMessageFromFile<HumanProgressives>(path.string());
491
492 for (const HumanProgressive& h_prog : h_progs.progressives()) {
493 ProcessProgressive(h_prog);
494 }
495 }
496
497 void ProcessProgressive(const HumanProgressive& h_prog) {
498 ProgressiveInfo& prog_info = info_.progressives[h_prog.name()];
499 prog_info.definitions.push_back(h_prog);
500
501 for (const DoorIdentifier& di : h_prog.doors()) {
502 if (!di.has_map()) {
503 prog_info.malformed_doors.push_back(di);
504 continue;
505 }
506
507 DoorInfo& door_info = info_.doors[di];
508 door_info.progressives_referenced_by.push_back(h_prog.name());
509 }
510 }
511
484 void ProcessIdsFile(std::filesystem::path path) { 512 void ProcessIdsFile(std::filesystem::path path) {
485 // Ignore this for now. 513 // Ignore this for now.
486 } 514 }
diff --git a/tools/validator/structs.h b/tools/validator/structs.h index 0ca96fe..717fccf 100644 --- a/tools/validator/structs.h +++ b/tools/validator/structs.h
@@ -45,6 +45,7 @@ struct DoorInfo {
45 std::vector<PanelIdentifier> panels_referenced_by; 45 std::vector<PanelIdentifier> panels_referenced_by;
46 std::vector<PaintingIdentifier> paintings_referenced_by; 46 std::vector<PaintingIdentifier> paintings_referenced_by;
47 std::vector<PortIdentifier> ports_referenced_by; 47 std::vector<PortIdentifier> ports_referenced_by;
48 std::vector<std::string> progressives_referenced_by;
48 49
49 MalformedIdentifiers malformed_identifiers; 50 MalformedIdentifiers malformed_identifiers;
50}; 51};
@@ -102,6 +103,12 @@ struct PanelNameInfo {
102 std::vector<PanelIdentifier> panels_used_by; 103 std::vector<PanelIdentifier> panels_used_by;
103}; 104};
104 105
106struct ProgressiveInfo {
107 std::vector<HumanProgressive> definitions;
108
109 std::vector<DoorIdentifier> malformed_doors;
110};
111
105struct CollectedInfo { 112struct CollectedInfo {
106 std::map<std::string, MapInfo> maps; 113 std::map<std::string, MapInfo> maps;
107 std::map<RoomIdentifier, RoomInfo, RoomIdentifierLess> rooms; 114 std::map<RoomIdentifier, RoomInfo, RoomIdentifierLess> rooms;
@@ -114,6 +121,7 @@ struct CollectedInfo {
114 std::map<LetterIdentifier, LetterInfo> letters; 121 std::map<LetterIdentifier, LetterInfo> letters;
115 std::map<std::string, EndingInfo> endings; 122 std::map<std::string, EndingInfo> endings;
116 std::map<std::string, PanelNameInfo> panel_names; 123 std::map<std::string, PanelNameInfo> panel_names;
124 std::map<std::string, ProgressiveInfo> progressives;
117}; 125};
118 126
119} // namespace com::fourisland::lingo2_archipelago 127} // namespace com::fourisland::lingo2_archipelago
diff --git a/tools/validator/validator.cpp b/tools/validator/validator.cpp index 9c66e09..fd004d7 100644 --- a/tools/validator/validator.cpp +++ b/tools/validator/validator.cpp
@@ -45,6 +45,9 @@ class Validator {
45 for (const auto& [panel_name, panel_info] : info_.panel_names) { 45 for (const auto& [panel_name, panel_info] : info_.panel_names) {
46 ValidatePanelName(panel_name, panel_info); 46 ValidatePanelName(panel_name, panel_info);
47 } 47 }
48 for (const auto& [prog_name, prog_info] : info_.progressives) {
49 ValidateProgressive(prog_name, prog_info);
50 }
48 } 51 }
49 52
50 private: 53 private:
@@ -164,6 +167,11 @@ class Validator {
164 std::cout << " CONNECTION " << connection.ShortDebugString() 167 std::cout << " CONNECTION " << connection.ShortDebugString()
165 << std::endl; 168 << std::endl;
166 } 169 }
170
171 for (const std::string& prog_name :
172 door_info.progressives_referenced_by) {
173 std::cout << " PROGRESSIVE " << prog_name << std::endl;
174 }
167 } else if (door_info.definitions.size() > 1) { 175 } else if (door_info.definitions.size() > 1) {
168 std::cout << "Door " << door_identifier.ShortDebugString() 176 std::cout << "Door " << door_identifier.ShortDebugString()
169 << " was defined multiple times." << std::endl; 177 << " was defined multiple times." << std::endl;
@@ -369,6 +377,14 @@ class Validator {
369 } 377 }
370 } 378 }
371 379
380 void ValidateProgressive(const std::string& prog_name,
381 const ProgressiveInfo& prog_info) const {
382 if (prog_info.definitions.size() > 1) {
383 std::cout << "Progressive \"" << prog_name
384 << "\" has multiple definitions." << std::endl;
385 }
386 }
387
372 const CollectedInfo& info_; 388 const CollectedInfo& info_;
373}; 389};
374 390