yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_editor_system.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <chrono>
5
6#include "absl/strings/str_format.h"
7
8namespace yaze {
9namespace zelda3 {
10
12 : rom_(rom), game_data_(game_data) {}
13
15 if (rom_ == nullptr) {
16 return absl::InvalidArgumentError("ROM is null");
17 }
18
19 // Initialize default dungeon settings
21 dungeon_settings_.name = "Default Dungeon";
22 dungeon_settings_.description = "A dungeon created with the editor";
31
32 // Initialize object editor
33 object_editor_ = std::make_shared<DungeonObjectEditor>(rom_);
34 RETURN_IF_ERROR(object_editor_->InitializeEditor());
35
36 return absl::OkStatus();
37}
38
39absl::Status DungeonEditorSystem::LoadDungeon(int dungeon_id) {
40 // TODO: Implement actual dungeon loading from ROM
42 editor_state_.is_dirty = false;
44 editor_state_.last_save_time = std::chrono::steady_clock::now();
45
46 return absl::OkStatus();
47}
48
50 if (!rom_) return absl::InvalidArgumentError("ROM is null");
51
52 // Iterate through all rooms to ensure global data (like sprites) is saved
53 for (int i = 0; i < NumberOfRooms; ++i) {
54 auto status = SaveRoomData(i);
55 if (!status.ok()) {
56 return status;
57 }
58 }
59
60 editor_state_.is_dirty = false;
61 editor_state_.last_save_time = std::chrono::steady_clock::now();
62
63 return absl::OkStatus();
64}
65
66absl::Status DungeonEditorSystem::SaveRoom(int room_id) {
67 return SaveRoomData(room_id);
68}
69
70absl::Status DungeonEditorSystem::ReloadRoom(int room_id) {
71 return LoadRoomData(room_id);
72}
73
77
81
82absl::Status DungeonEditorSystem::SetCurrentRoom(int room_id) {
83 if (room_id < 0 || room_id >= NumberOfRooms) {
84 return absl::InvalidArgumentError("Invalid room ID");
85 }
86
88 return absl::OkStatus();
89}
90
94
95absl::StatusOr<Room> DungeonEditorSystem::GetRoom(int room_id) {
96 if (room_id < 0 || room_id >= NumberOfRooms) {
97 return absl::InvalidArgumentError("Invalid room ID");
98 }
99
100 // TODO: Load room from ROM or return cached room
101 return Room(room_id, rom_, game_data_);
102}
103
104absl::Status DungeonEditorSystem::CreateRoom(int room_id,
105 const std::string& name) {
106 // TODO: Implement room creation
107 return absl::OkStatus();
108}
109
110absl::Status DungeonEditorSystem::DeleteRoom(int room_id) {
111 // TODO: Implement room deletion
112 return absl::OkStatus();
113}
114
115absl::Status DungeonEditorSystem::DuplicateRoom(int source_room_id,
116 int target_room_id) {
117 // TODO: Implement room duplication
118 return absl::OkStatus();
119}
120
121std::shared_ptr<DungeonObjectEditor> DungeonEditorSystem::GetObjectEditor() {
122 if (!object_editor_) {
123 object_editor_ = std::make_shared<DungeonObjectEditor>(rom_);
124 }
125 return object_editor_;
126}
127
130 return absl::OkStatus();
131}
132
133// Sprite management
134absl::Status DungeonEditorSystem::AddSprite(const SpriteData& sprite_data) {
135 int sprite_id = GenerateSpriteId();
136 sprites_[sprite_id] = sprite_data;
137 sprites_[sprite_id].sprite_id = sprite_id;
138
140 sprite_changed_callback_(sprite_id);
141 }
142
143 return absl::OkStatus();
144}
145
146absl::Status DungeonEditorSystem::RemoveSprite(int sprite_id) {
147 auto it = sprites_.find(sprite_id);
148 if (it == sprites_.end()) {
149 return absl::NotFoundError("Sprite not found");
150 }
151
152 sprites_.erase(it);
153 return absl::OkStatus();
154}
155
156absl::Status DungeonEditorSystem::UpdateSprite(int sprite_id,
157 const SpriteData& sprite_data) {
158 auto it = sprites_.find(sprite_id);
159 if (it == sprites_.end()) {
160 return absl::NotFoundError("Sprite not found");
161 }
162
163 it->second = sprite_data;
164 it->second.sprite_id = sprite_id;
165
167 sprite_changed_callback_(sprite_id);
168 }
169
170 return absl::OkStatus();
171}
172
173absl::StatusOr<DungeonEditorSystem::SpriteData> DungeonEditorSystem::GetSprite(
174 int sprite_id) {
175 auto it = sprites_.find(sprite_id);
176 if (it == sprites_.end()) {
177 return absl::NotFoundError("Sprite not found");
178 }
179
180 return it->second;
181}
182
183absl::StatusOr<std::vector<DungeonEditorSystem::SpriteData>>
185 std::vector<SpriteData> room_sprites;
186
187 for (const auto& [id, sprite] : sprites_) {
188 if (sprite.x >= 0 && sprite.y >= 0) { // Simple room assignment logic
189 room_sprites.push_back(sprite);
190 }
191 }
192
193 return room_sprites;
194}
195
196absl::StatusOr<std::vector<DungeonEditorSystem::SpriteData>>
198 std::vector<SpriteData> typed_sprites;
199
200 for (const auto& [id, sprite] : sprites_) {
201 if (sprite.type == type) {
202 typed_sprites.push_back(sprite);
203 }
204 }
205
206 return typed_sprites;
207}
208
209absl::Status DungeonEditorSystem::MoveSprite(int sprite_id, int new_x,
210 int new_y) {
211 auto it = sprites_.find(sprite_id);
212 if (it == sprites_.end()) {
213 return absl::NotFoundError("Sprite not found");
214 }
215
216 it->second.x = new_x;
217 it->second.y = new_y;
218
220 sprite_changed_callback_(sprite_id);
221 }
222
223 return absl::OkStatus();
224}
225
226absl::Status DungeonEditorSystem::SetSpriteActive(int sprite_id, bool active) {
227 auto it = sprites_.find(sprite_id);
228 if (it == sprites_.end()) {
229 return absl::NotFoundError("Sprite not found");
230 }
231
232 it->second.is_active = active;
233
235 sprite_changed_callback_(sprite_id);
236 }
237
238 return absl::OkStatus();
239}
240
241// Item management
242absl::Status DungeonEditorSystem::AddItem(const ItemData& item_data) {
243 int item_id = GenerateItemId();
244 items_[item_id] = item_data;
245 items_[item_id].item_id = item_id;
246
248 item_changed_callback_(item_id);
249 }
250
251 return absl::OkStatus();
252}
253
254absl::Status DungeonEditorSystem::RemoveItem(int item_id) {
255 auto it = items_.find(item_id);
256 if (it == items_.end()) {
257 return absl::NotFoundError("Item not found");
258 }
259
260 items_.erase(it);
261 return absl::OkStatus();
262}
263
264absl::Status DungeonEditorSystem::UpdateItem(int item_id,
265 const ItemData& item_data) {
266 auto it = items_.find(item_id);
267 if (it == items_.end()) {
268 return absl::NotFoundError("Item not found");
269 }
270
271 it->second = item_data;
272 it->second.item_id = item_id;
273
275 item_changed_callback_(item_id);
276 }
277
278 return absl::OkStatus();
279}
280
281absl::StatusOr<DungeonEditorSystem::ItemData> DungeonEditorSystem::GetItem(
282 int item_id) {
283 auto it = items_.find(item_id);
284 if (it == items_.end()) {
285 return absl::NotFoundError("Item not found");
286 }
287
288 return it->second;
289}
290
291absl::StatusOr<std::vector<DungeonEditorSystem::ItemData>>
293 std::vector<ItemData> room_items;
294
295 for (const auto& [id, item] : items_) {
296 if (item.room_id == room_id) {
297 room_items.push_back(item);
298 }
299 }
300
301 return room_items;
302}
303
304absl::StatusOr<std::vector<DungeonEditorSystem::ItemData>>
306 std::vector<ItemData> typed_items;
307
308 for (const auto& [id, item] : items_) {
309 if (item.type == type) {
310 typed_items.push_back(item);
311 }
312 }
313
314 return typed_items;
315}
316
317absl::Status DungeonEditorSystem::MoveItem(int item_id, int new_x, int new_y) {
318 auto it = items_.find(item_id);
319 if (it == items_.end()) {
320 return absl::NotFoundError("Item not found");
321 }
322
323 it->second.x = new_x;
324 it->second.y = new_y;
325
327 item_changed_callback_(item_id);
328 }
329
330 return absl::OkStatus();
331}
332
333absl::Status DungeonEditorSystem::SetItemHidden(int item_id, bool hidden) {
334 auto it = items_.find(item_id);
335 if (it == items_.end()) {
336 return absl::NotFoundError("Item not found");
337 }
338
339 it->second.is_hidden = hidden;
340
342 item_changed_callback_(item_id);
343 }
344
345 return absl::OkStatus();
346}
347
348// Entrance/exit management
350 const EntranceData& entrance_data) {
351 int entrance_id = GenerateEntranceId();
352 entrances_[entrance_id] = entrance_data;
353 entrances_[entrance_id].entrance_id = entrance_id;
354
356 entrance_changed_callback_(entrance_id);
357 }
358
359 return absl::OkStatus();
360}
361
362absl::Status DungeonEditorSystem::RemoveEntrance(int entrance_id) {
363 auto it = entrances_.find(entrance_id);
364 if (it == entrances_.end()) {
365 return absl::NotFoundError("Entrance not found");
366 }
367
368 entrances_.erase(it);
369 return absl::OkStatus();
370}
371
373 int entrance_id, const EntranceData& entrance_data) {
374 auto it = entrances_.find(entrance_id);
375 if (it == entrances_.end()) {
376 return absl::NotFoundError("Entrance not found");
377 }
378
379 it->second = entrance_data;
380 it->second.entrance_id = entrance_id;
381
383 entrance_changed_callback_(entrance_id);
384 }
385
386 return absl::OkStatus();
387}
388
389absl::StatusOr<DungeonEditorSystem::EntranceData>
391 auto it = entrances_.find(entrance_id);
392 if (it == entrances_.end()) {
393 return absl::NotFoundError("Entrance not found");
394 }
395
396 return it->second;
397}
398
399absl::StatusOr<std::vector<DungeonEditorSystem::EntranceData>>
401 std::vector<EntranceData> room_entrances;
402
403 for (const auto& [id, entrance] : entrances_) {
404 if (entrance.source_room_id == room_id ||
405 entrance.target_room_id == room_id) {
406 room_entrances.push_back(entrance);
407 }
408 }
409
410 return room_entrances;
411}
412
413absl::StatusOr<std::vector<DungeonEditorSystem::EntranceData>>
415 std::vector<EntranceData> typed_entrances;
416
417 for (const auto& [id, entrance] : entrances_) {
418 if (entrance.type == type) {
419 typed_entrances.push_back(entrance);
420 }
421 }
422
423 return typed_entrances;
424}
425
426absl::Status DungeonEditorSystem::ConnectRooms(int room1_id, int room2_id,
427 int x1, int y1, int x2, int y2) {
428 EntranceData entrance_data;
429 entrance_data.source_room_id = room1_id;
430 entrance_data.target_room_id = room2_id;
431 entrance_data.source_x = x1;
432 entrance_data.source_y = y1;
433 entrance_data.target_x = x2;
434 entrance_data.target_y = y2;
435 entrance_data.type = EntranceType::kNormal;
436 entrance_data.is_bidirectional = true;
437
438 return AddEntrance(entrance_data);
439}
440
441absl::Status DungeonEditorSystem::DisconnectRooms(int room1_id, int room2_id) {
442 // Find and remove entrance between rooms
443 for (auto it = entrances_.begin(); it != entrances_.end();) {
444 const auto& entrance = it->second;
445 if ((entrance.source_room_id == room1_id &&
446 entrance.target_room_id == room2_id) ||
447 (entrance.source_room_id == room2_id &&
448 entrance.target_room_id == room1_id)) {
449 it = entrances_.erase(it);
450 } else {
451 ++it;
452 }
453 }
454
455 return absl::OkStatus();
456}
457
458// Door management
459absl::Status DungeonEditorSystem::AddDoor(const DoorData& door_data) {
460 int door_id = GenerateDoorId();
461 doors_[door_id] = door_data;
462 doors_[door_id].door_id = door_id;
463
465 door_changed_callback_(door_id);
466 }
467
468 return absl::OkStatus();
469}
470
471absl::Status DungeonEditorSystem::RemoveDoor(int door_id) {
472 auto it = doors_.find(door_id);
473 if (it == doors_.end()) {
474 return absl::NotFoundError("Door not found");
475 }
476
477 doors_.erase(it);
478 return absl::OkStatus();
479}
480
481absl::Status DungeonEditorSystem::UpdateDoor(int door_id,
482 const DoorData& door_data) {
483 auto it = doors_.find(door_id);
484 if (it == doors_.end()) {
485 return absl::NotFoundError("Door not found");
486 }
487
488 it->second = door_data;
489 it->second.door_id = door_id;
490
492 door_changed_callback_(door_id);
493 }
494
495 return absl::OkStatus();
496}
497
498absl::StatusOr<DungeonEditorSystem::DoorData> DungeonEditorSystem::GetDoor(
499 int door_id) {
500 auto it = doors_.find(door_id);
501 if (it == doors_.end()) {
502 return absl::NotFoundError("Door not found");
503 }
504
505 return it->second;
506}
507
508absl::StatusOr<std::vector<DungeonEditorSystem::DoorData>>
510 std::vector<DoorData> room_doors;
511
512 for (const auto& [id, door] : doors_) {
513 if (door.room_id == room_id) {
514 room_doors.push_back(door);
515 }
516 }
517
518 return room_doors;
519}
520
521absl::Status DungeonEditorSystem::SetDoorLocked(int door_id, bool locked) {
522 auto it = doors_.find(door_id);
523 if (it == doors_.end()) {
524 return absl::NotFoundError("Door not found");
525 }
526
527 it->second.is_locked = locked;
528
530 door_changed_callback_(door_id);
531 }
532
533 return absl::OkStatus();
534}
535
537 bool requires_key,
538 int key_type) {
539 auto it = doors_.find(door_id);
540 if (it == doors_.end()) {
541 return absl::NotFoundError("Door not found");
542 }
543
544 it->second.requires_key = requires_key;
545 it->second.key_type = key_type;
546
548 door_changed_callback_(door_id);
549 }
550
551 return absl::OkStatus();
552}
553
554// Chest management
556 int chest_id = GenerateChestId();
557 chests_[chest_id] = chest_data;
558 chests_[chest_id].chest_id = chest_id;
559
561 chest_changed_callback_(chest_id);
562 }
563
564 return absl::OkStatus();
565}
566
567absl::Status DungeonEditorSystem::RemoveChest(int chest_id) {
568 auto it = chests_.find(chest_id);
569 if (it == chests_.end()) {
570 return absl::NotFoundError("Chest not found");
571 }
572
573 chests_.erase(it);
574 return absl::OkStatus();
575}
576
577absl::Status DungeonEditorSystem::UpdateChest(int chest_id,
578 const ChestData& chest_data) {
579 auto it = chests_.find(chest_id);
580 if (it == chests_.end()) {
581 return absl::NotFoundError("Chest not found");
582 }
583
584 it->second = chest_data;
585 it->second.chest_id = chest_id;
586
588 chest_changed_callback_(chest_id);
589 }
590
591 return absl::OkStatus();
592}
593
594absl::StatusOr<DungeonEditorSystem::ChestData> DungeonEditorSystem::GetChest(
595 int chest_id) {
596 auto it = chests_.find(chest_id);
597 if (it == chests_.end()) {
598 return absl::NotFoundError("Chest not found");
599 }
600
601 return it->second;
602}
603
604absl::StatusOr<std::vector<DungeonEditorSystem::ChestData>>
606 std::vector<ChestData> room_chests;
607
608 for (const auto& [id, chest] : chests_) {
609 if (chest.room_id == room_id) {
610 room_chests.push_back(chest);
611 }
612 }
613
614 return room_chests;
615}
616
617absl::Status DungeonEditorSystem::SetChestItem(int chest_id, int item_id,
618 int quantity) {
619 auto it = chests_.find(chest_id);
620 if (it == chests_.end()) {
621 return absl::NotFoundError("Chest not found");
622 }
623
624 it->second.item_id = item_id;
625 it->second.item_quantity = quantity;
626
628 chest_changed_callback_(chest_id);
629 }
630
631 return absl::OkStatus();
632}
633
634absl::Status DungeonEditorSystem::SetChestOpened(int chest_id, bool opened) {
635 auto it = chests_.find(chest_id);
636 if (it == chests_.end()) {
637 return absl::NotFoundError("Chest not found");
638 }
639
640 it->second.is_opened = opened;
641
643 chest_changed_callback_(chest_id);
644 }
645
646 return absl::OkStatus();
647}
648
649// Room properties and metadata
651 int room_id, const RoomProperties& properties) {
652 room_properties_[room_id] = properties;
653
655 room_changed_callback_(room_id);
656 }
657
658 return absl::OkStatus();
659}
660
661absl::StatusOr<DungeonEditorSystem::RoomProperties>
663 auto it = room_properties_.find(room_id);
664 if (it == room_properties_.end()) {
665 // Return default properties
666 RoomProperties default_properties;
667 default_properties.room_id = room_id;
668 default_properties.name = absl::StrFormat("Room %d", room_id);
669 default_properties.description = "";
670 default_properties.dungeon_id = 0;
671 default_properties.floor_level = 0;
672 default_properties.is_boss_room = false;
673 default_properties.is_save_room = false;
674 default_properties.is_shop_room = false;
675 default_properties.music_id = 0;
676 default_properties.ambient_sound_id = 0;
677 return default_properties;
678 }
679
680 return it->second;
681}
682
683// Dungeon-wide settings
685 const DungeonSettings& settings) {
686 dungeon_settings_ = settings;
687 return absl::OkStatus();
688}
689
690absl::StatusOr<DungeonEditorSystem::DungeonSettings>
694
695// Validation and error checking
696absl::Status DungeonEditorSystem::ValidateRoom(int room_id) {
697 // TODO: Implement room validation
698 return absl::OkStatus();
699}
700
702 // TODO: Implement dungeon validation
703 return absl::OkStatus();
704}
705
706std::vector<std::string> DungeonEditorSystem::GetValidationErrors(int room_id) {
707 // TODO: Implement validation error collection
708 return {};
709}
710
712 // TODO: Implement dungeon validation error collection
713 return {};
714}
715
716// Rendering and preview
717absl::StatusOr<gfx::Bitmap> DungeonEditorSystem::RenderRoom(int room_id) {
718 // TODO: Implement room rendering
719 return gfx::Bitmap();
720}
721
722absl::StatusOr<gfx::Bitmap> DungeonEditorSystem::RenderRoomPreview(
723 int room_id, EditorMode mode) {
724 // TODO: Implement room preview rendering
725 return gfx::Bitmap();
726}
727
728absl::StatusOr<gfx::Bitmap> DungeonEditorSystem::RenderDungeonMap() {
729 // TODO: Implement dungeon map rendering
730 return gfx::Bitmap();
731}
732
733// Import/Export functionality
735 const std::string& file_path, int room_id) {
736 // TODO: Implement room import
737 return absl::OkStatus();
738}
739
741 int room_id, const std::string& file_path) {
742 // TODO: Implement room export
743 return absl::OkStatus();
744}
745
747 const std::string& file_path) {
748 // TODO: Implement dungeon import
749 return absl::OkStatus();
750}
751
753 const std::string& file_path) {
754 // TODO: Implement dungeon export
755 return absl::OkStatus();
756}
757
758// Undo/Redo system
761 if (object_editor_) {
762 return object_editor_->Undo();
763 }
764 }
765
766 if (!CanUndo()) {
767 return absl::FailedPreconditionError("Nothing to undo");
768 }
769
770 // TODO: Implement undo functionality for other modes
771 return absl::OkStatus();
772}
773
776 if (object_editor_) {
777 return object_editor_->Redo();
778 }
779 }
780
781 if (!CanRedo()) {
782 return absl::FailedPreconditionError("Nothing to redo");
783 }
784
785 // TODO: Implement redo functionality for other modes
786 return absl::OkStatus();
787}
788
790 return !undo_history_.empty();
791}
792
794 return !redo_history_.empty();
795}
796
798 undo_history_.clear();
799 redo_history_.clear();
800}
801
802// Event callbacks
806
811
815
820
824
829
833
837
838// Helper methods
842
846
850
854
858
860 return rom_;
861}
862
866
868 rom_ = rom;
869 // Update object editor with new ROM if it exists
870 if (object_editor_) {
871 object_editor_->SetROM(rom);
872 }
873}
874
875// Data management
876absl::Status DungeonEditorSystem::LoadRoomData(int room_id) {
877 if (!rom_) return absl::InvalidArgumentError("ROM is null");
878
879 // Load the room from ROM to get current data
880 Room room = LoadRoomFromRom(rom_, room_id);
881
882 // 1. Load Sprites
883 // Clear existing sprites for this room to avoid duplicates on reload
884 for (auto it = sprites_.begin(); it != sprites_.end();) {
885 if (it->second.properties.count("room_id") && std::stoi(it->second.properties.at("room_id")) == room_id) {
886 it = sprites_.erase(it);
887 } else {
888 ++it;
889 }
890 }
891
892 const auto& room_sprites = room.GetSprites();
893 for (const auto& spr : room_sprites) {
894 SpriteData data;
896 data.x = spr.x();
897 data.y = spr.y();
898 data.layer = spr.layer();
899 data.type = SpriteType::kEnemy; // Default, should map from spr.id()
900 data.name = absl::StrFormat("Sprite %02X", spr.id());
901 data.properties["id"] = absl::StrFormat("%d", spr.id());
902 data.properties["subtype"] = absl::StrFormat("%d", spr.subtype());
903 data.properties["room_id"] = absl::StrFormat("%d", room_id);
904
905 sprites_[data.sprite_id] = data;
906 }
907
908 // 2. Load Chests
909 // Clear existing chests for this room
910 for (auto it = chests_.begin(); it != chests_.end();) {
911 if (it->second.room_id == room_id) {
912 it = chests_.erase(it);
913 } else {
914 ++it;
915 }
916 }
917
918 const auto& room_chests = room.GetChests();
919 for (const auto& chest : room_chests) {
920 ChestData data;
921 data.chest_id = GenerateChestId();
922 data.room_id = room_id;
923 data.item_id = chest.id; // Raw item ID
924 data.is_big_chest = chest.size;
925 chests_[data.chest_id] = data;
926 }
927
928 return absl::OkStatus();
929}
930
931absl::Status DungeonEditorSystem::SaveRoomData(int room_id) {
932 if (!rom_) return absl::InvalidArgumentError("ROM is null");
933
934 // Check if this is the currently edited room in the ObjectEditor
935 bool is_current_editor_room = false;
936 if (object_editor_ && object_editor_->GetRoom().id() == room_id) {
937 is_current_editor_room = true;
938 }
939
940 // If it's the current room, we MUST use the editor's room object
941 // because it contains the unsaved object/tile changes.
942 // If it's not, we load from ROM (assuming objects haven't changed).
943
944 std::unique_ptr<Room> room_ptr;
945 Room* room = nullptr;
946
947 if (is_current_editor_room) {
948 room = object_editor_->GetMutableRoom();
949 } else {
950 room_ptr = std::make_unique<Room>(LoadRoomFromRom(rom_, room_id));
951 room = room_ptr.get();
952 }
953
954 if (!room) return absl::InternalError("Failed to get Room object");
955
956 // 1. Sync Sprites from DungeonEditorSystem to Room
957 // We rebuild the room's sprite list from the system's source of truth
958 room->GetSprites().clear();
959 for (const auto& [id, sprite_data] : sprites_) {
960 auto room_id_it = sprite_data.properties.find("room_id");
961 if (room_id_it != sprite_data.properties.end()) {
962 if (std::stoi(room_id_it->second) != room_id) continue;
963 } else {
964 continue;
965 }
966
967 int raw_id = 0;
968 int subtype = 0;
969 if (sprite_data.properties.count("id")) raw_id = std::stoi(sprite_data.properties.at("id"));
970 if (sprite_data.properties.count("subtype")) subtype = std::stoi(sprite_data.properties.at("subtype"));
971
972 zelda3::Sprite z3_sprite(raw_id, sprite_data.x, sprite_data.y, subtype, sprite_data.layer);
973 room->GetSprites().push_back(z3_sprite);
974 }
975
976 // 2. Save Sprites
977 auto status = room->SaveSprites();
978 if (!status.ok()) return status;
979
980 // 3. Save Objects (Tiles)
981 // Only save objects if it's the current room (where we might have changes)
982 // or if we want to enforce a rewrite. For now, saving only if current
983 // avoids unnecessary ROM writes for unmodified rooms.
984 if (is_current_editor_room) {
985 status = room->SaveObjects();
986 if (!status.ok()) return status;
987 }
988
989 return absl::OkStatus();
990}
991
993 return absl::OkStatus();
994}
995
997 return absl::OkStatus();
998}
999
1001 return absl::OkStatus();
1002}
1003
1005 return absl::OkStatus();
1006}
1007
1009 return absl::OkStatus();
1010}
1011
1013 return absl::OkStatus();
1014}
1015
1017 return absl::OkStatus();
1018}
1019
1021 return absl::OkStatus();
1022}
1023
1025 return absl::OkStatus();
1026}
1027
1029 return absl::OkStatus();
1030}
1031
1033 if (object_editor_) {
1034 object_editor_->SetExternalRoom(room);
1035 }
1036}
1037
1038// Factory function
1039std::unique_ptr<DungeonEditorSystem> CreateDungeonEditorSystem(Rom* rom,
1040 GameData* game_data) {
1041 return std::make_unique<DungeonEditorSystem>(rom);
1042}
1043
1044} // namespace zelda3
1045} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:24
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:67
absl::StatusOr< DungeonSettings > GetDungeonSettings()
void SetSpriteChangedCallback(SpriteChangedCallback callback)
absl::Status UpdateItem(int item_id, const ItemData &item_data)
absl::Status DuplicateRoom(int source_room_id, int target_room_id)
absl::Status UpdateDoor(int door_id, const DoorData &door_data)
absl::StatusOr< EntranceData > GetEntrance(int entrance_id)
std::unordered_map< int, DoorData > doors_
absl::Status ExportRoomToFile(int room_id, const std::string &file_path)
std::function< void(const std::vector< std::string > &errors)> ValidationCallback
std::unordered_map< int, EntranceData > entrances_
absl::StatusOr< std::vector< SpriteData > > GetSpritesByType(DungeonEditorSystem::SpriteType type)
absl::Status SetRoomProperties(int room_id, const RoomProperties &properties)
absl::Status RemoveEntrance(int entrance_id)
absl::Status SetChestOpened(int chest_id, bool opened)
std::function< void(int sprite_id)> SpriteChangedCallback
std::unordered_map< int, SpriteData > sprites_
absl::StatusOr< std::vector< DoorData > > GetDoorsByRoom(int room_id)
std::function< void(int door_id)> DoorChangedCallback
absl::StatusOr< SpriteData > GetSprite(int sprite_id)
absl::Status MoveSprite(int sprite_id, int new_x, int new_y)
EntranceChangedCallback entrance_changed_callback_
absl::Status SetDoorKeyRequirement(int door_id, bool requires_key, int key_type)
void SetRoomChangedCallback(RoomChangedCallback callback)
void SetEntranceChangedCallback(EntranceChangedCallback callback)
std::vector< std::string > GetValidationErrors(int room_id)
absl::StatusOr< RoomProperties > GetRoomProperties(int room_id)
std::shared_ptr< DungeonObjectEditor > object_editor_
absl::Status AddSprite(const SpriteData &sprite_data)
DungeonEditorSystem(Rom *rom, GameData *game_data=nullptr)
std::shared_ptr< DungeonObjectEditor > GetObjectEditor()
absl::Status SetSpriteActive(int sprite_id, bool active)
void SetChestChangedCallback(ChestChangedCallback callback)
absl::Status SetCurrentRoom(int room_id)
absl::StatusOr< std::vector< ItemData > > GetItemsByType(DungeonEditorSystem::ItemType type)
absl::Status ConnectRooms(int room1_id, int room2_id, int x1, int y1, int x2, int y2)
absl::StatusOr< gfx::Bitmap > RenderRoomPreview(int room_id, EditorMode mode)
std::vector< std::string > GetDungeonValidationErrors()
std::unordered_map< int, ChestData > chests_
std::unordered_map< int, ItemData > items_
absl::Status AddDoor(const DoorData &door_data)
std::function< void(int item_id)> ItemChangedCallback
absl::StatusOr< std::vector< EntranceData > > GetEntrancesByRoom(int room_id)
absl::Status SetDungeonSettings(const DungeonSettings &settings)
absl::Status ImportDungeonFromFile(const std::string &file_path)
absl::StatusOr< gfx::Bitmap > RenderRoom(int room_id)
absl::Status UpdateEntrance(int entrance_id, const EntranceData &entrance_data)
void SetModeChangedCallback(ModeChangedCallback callback)
absl::StatusOr< gfx::Bitmap > RenderDungeonMap()
absl::Status DisconnectRooms(int room1_id, int room2_id)
std::unordered_map< int, RoomProperties > room_properties_
absl::Status ExportDungeonToFile(const std::string &file_path)
std::function< void(EditorMode mode)> ModeChangedCallback
absl::Status RemoveSprite(int sprite_id)
absl::StatusOr< std::vector< ChestData > > GetChestsByRoom(int room_id)
absl::Status LoadDungeon(int dungeon_id)
absl::StatusOr< std::vector< ItemData > > GetItemsByRoom(int room_id)
std::function< void(int room_id)> RoomChangedCallback
absl::Status MoveItem(int item_id, int new_x, int new_y)
absl::StatusOr< ChestData > GetChest(int chest_id)
absl::StatusOr< DoorData > GetDoor(int door_id)
absl::Status SetChestItem(int chest_id, int item_id, int quantity)
absl::StatusOr< std::vector< SpriteData > > GetSpritesByRoom(int room_id)
absl::Status UpdateChest(int chest_id, const ChestData &chest_data)
void SetDoorChangedCallback(DoorChangedCallback callback)
std::function< void(int chest_id)> ChestChangedCallback
absl::Status UpdateSprite(int sprite_id, const SpriteData &sprite_data)
absl::StatusOr< std::vector< EntranceData > > GetEntrancesByType(DungeonEditorSystem::EntranceType type)
absl::Status SetItemHidden(int item_id, bool hidden)
void SetItemChangedCallback(ItemChangedCallback callback)
absl::Status CreateRoom(int room_id, const std::string &name="")
absl::Status AddEntrance(const EntranceData &entrance_data)
absl::Status ImportRoomFromFile(const std::string &file_path, int room_id)
absl::StatusOr< ItemData > GetItem(int item_id)
absl::Status AddChest(const ChestData &chest_data)
absl::StatusOr< Room > GetRoom(int room_id)
absl::Status SetDoorLocked(int door_id, bool locked)
void SetValidationCallback(ValidationCallback callback)
std::function< void(int entrance_id)> EntranceChangedCallback
absl::Status AddItem(const ItemData &item_data)
const std::vector< chest_data > & GetChests() const
Definition room.h:250
absl::Status SaveObjects()
Definition room.cc:1376
const std::vector< zelda3::Sprite > & GetSprites() const
Definition room.h:246
absl::Status SaveSprites()
Definition room.cc:1430
A class for managing sprites in the overworld and underworld.
Definition sprite.h:35
struct chest_data chest_data
Legacy chest data structure.
constexpr int NumberOfRooms
Definition room.h:70
Room LoadRoomFromRom(Rom *rom, int room_id)
Definition room.cc:177
std::unique_ptr< DungeonEditorSystem > CreateDungeonEditorSystem(Rom *rom, GameData *game_data)
Factory function to create dungeon editor system.
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
Legacy chest data structure.
Definition zelda.h:438
Treasure chest.
Definition zelda.h:425
std::chrono::steady_clock::time_point last_save_time
std::unordered_map< std::string, std::string > properties