493 lines
15 KiB
C++
493 lines
15 KiB
C++
#ifndef YAZE_APP_ZELDA3_DUNGEON_DUNGEON_EDITOR_SYSTEM_H
|
|
#define YAZE_APP_ZELDA3_DUNGEON_DUNGEON_EDITOR_SYSTEM_H
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
#include <functional>
|
|
#include <optional>
|
|
|
|
#include "absl/status/status.h"
|
|
#include "absl/status/statusor.h"
|
|
#include "app/core/window.h"
|
|
#include "app/gfx/bitmap.h"
|
|
#include "app/gfx/snes_palette.h"
|
|
#include "app/rom.h"
|
|
#include "zelda3/dungeon/room_object.h"
|
|
#include "zelda3/dungeon/room.h"
|
|
#include "zelda3/sprite/sprite.h"
|
|
#include "dungeon_object_editor.h"
|
|
|
|
namespace yaze {
|
|
namespace zelda3 {
|
|
|
|
/**
|
|
* @brief Comprehensive dungeon editing system
|
|
*
|
|
* This class provides a complete dungeon editing solution including:
|
|
* - Object editing (walls, floors, decorations)
|
|
* - Sprite management (enemies, NPCs, interactive elements)
|
|
* - Item placement and management
|
|
* - Entrance/exit data editing
|
|
* - Door configuration
|
|
* - Chest and treasure management
|
|
* - Room properties and metadata
|
|
* - Dungeon-wide settings
|
|
*/
|
|
class DungeonEditorSystem {
|
|
public:
|
|
// Editor modes
|
|
enum class EditorMode {
|
|
kObjects, // Object editing mode
|
|
kSprites, // Sprite editing mode
|
|
kItems, // Item placement mode
|
|
kEntrances, // Entrance/exit editing mode
|
|
kDoors, // Door configuration mode
|
|
kChests, // Chest management mode
|
|
kProperties, // Room properties mode
|
|
kGlobal // Dungeon-wide settings mode
|
|
};
|
|
|
|
// Sprite types and categories
|
|
enum class SpriteType {
|
|
kEnemy, // Hostile entities
|
|
kNPC, // Non-player characters
|
|
kInteractive, // Interactive objects
|
|
kDecoration, // Decorative sprites
|
|
kBoss, // Boss entities
|
|
kSpecial // Special purpose sprites
|
|
};
|
|
|
|
// Item types
|
|
enum class ItemType {
|
|
kWeapon, // Swords, bows, etc.
|
|
kTool, // Hookshot, bombs, etc.
|
|
kKey, // Keys and key items
|
|
kHeart, // Heart containers and pieces
|
|
kRupee, // Currency
|
|
kBottle, // Bottles and contents
|
|
kUpgrade, // Capacity upgrades
|
|
kSpecial // Special items
|
|
};
|
|
|
|
// Entrance/exit types
|
|
enum class EntranceType {
|
|
kNormal, // Standard room entrance
|
|
kStairs, // Staircase connection
|
|
kDoor, // Door connection
|
|
kCave, // Cave entrance
|
|
kWarp, // Warp/teleport
|
|
kBoss, // Boss room entrance
|
|
kSpecial // Special entrance type
|
|
};
|
|
|
|
// Editor state
|
|
struct EditorState {
|
|
EditorMode current_mode = EditorMode::kObjects;
|
|
int current_room_id = 0;
|
|
bool is_dirty = false; // Has unsaved changes
|
|
bool auto_save_enabled = true;
|
|
std::chrono::steady_clock::time_point last_save_time;
|
|
};
|
|
|
|
// Sprite editing data
|
|
struct SpriteData {
|
|
int sprite_id;
|
|
std::string name;
|
|
DungeonEditorSystem::SpriteType type;
|
|
int x, y;
|
|
int layer;
|
|
std::unordered_map<std::string, std::string> properties;
|
|
bool is_active = true;
|
|
};
|
|
|
|
// Item placement data
|
|
struct ItemData {
|
|
int item_id;
|
|
DungeonEditorSystem::ItemType type;
|
|
std::string name;
|
|
int x, y;
|
|
int room_id;
|
|
bool is_hidden = false;
|
|
std::unordered_map<std::string, std::string> properties;
|
|
};
|
|
|
|
// Entrance/exit data
|
|
struct EntranceData {
|
|
int entrance_id;
|
|
DungeonEditorSystem::EntranceType type;
|
|
std::string name;
|
|
int source_room_id;
|
|
int target_room_id;
|
|
int source_x, source_y;
|
|
int target_x, target_y;
|
|
bool is_bidirectional = true;
|
|
std::unordered_map<std::string, std::string> properties;
|
|
};
|
|
|
|
// Door configuration data
|
|
struct DoorData {
|
|
int door_id;
|
|
std::string name;
|
|
int room_id;
|
|
int x, y;
|
|
int direction; // 0=up, 1=right, 2=down, 3=left
|
|
int target_room_id;
|
|
int target_x, target_y;
|
|
bool requires_key = false;
|
|
int key_type = 0;
|
|
bool is_locked = false;
|
|
std::unordered_map<std::string, std::string> properties;
|
|
};
|
|
|
|
// Chest data
|
|
struct ChestData {
|
|
int chest_id;
|
|
int room_id;
|
|
int x, y;
|
|
bool is_big_chest = false;
|
|
int item_id;
|
|
int item_quantity = 1;
|
|
bool is_opened = false;
|
|
std::unordered_map<std::string, std::string> properties;
|
|
};
|
|
|
|
explicit DungeonEditorSystem(Rom* rom);
|
|
~DungeonEditorSystem() = default;
|
|
|
|
// System initialization and management
|
|
absl::Status Initialize();
|
|
absl::Status LoadDungeon(int dungeon_id);
|
|
absl::Status SaveDungeon();
|
|
absl::Status SaveRoom(int room_id);
|
|
absl::Status ReloadRoom(int room_id);
|
|
|
|
// Mode management
|
|
void SetEditorMode(EditorMode mode);
|
|
EditorMode GetEditorMode() const;
|
|
|
|
// Room management
|
|
absl::Status SetCurrentRoom(int room_id);
|
|
int GetCurrentRoom() const;
|
|
absl::StatusOr<Room> GetRoom(int room_id);
|
|
absl::Status CreateRoom(int room_id, const std::string& name = "");
|
|
absl::Status DeleteRoom(int room_id);
|
|
absl::Status DuplicateRoom(int source_room_id, int target_room_id);
|
|
|
|
// Object editing (delegated to DungeonObjectEditor)
|
|
std::shared_ptr<DungeonObjectEditor> GetObjectEditor();
|
|
absl::Status SetObjectEditorMode();
|
|
|
|
// Sprite management
|
|
absl::Status AddSprite(const SpriteData& sprite_data);
|
|
absl::Status RemoveSprite(int sprite_id);
|
|
absl::Status UpdateSprite(int sprite_id, const SpriteData& sprite_data);
|
|
absl::StatusOr<SpriteData> GetSprite(int sprite_id);
|
|
absl::StatusOr<std::vector<SpriteData>> GetSpritesByRoom(int room_id);
|
|
absl::StatusOr<std::vector<SpriteData>> GetSpritesByType(DungeonEditorSystem::SpriteType type);
|
|
absl::Status MoveSprite(int sprite_id, int new_x, int new_y);
|
|
absl::Status SetSpriteActive(int sprite_id, bool active);
|
|
|
|
// Item management
|
|
absl::Status AddItem(const ItemData& item_data);
|
|
absl::Status RemoveItem(int item_id);
|
|
absl::Status UpdateItem(int item_id, const ItemData& item_data);
|
|
absl::StatusOr<ItemData> GetItem(int item_id);
|
|
absl::StatusOr<std::vector<ItemData>> GetItemsByRoom(int room_id);
|
|
absl::StatusOr<std::vector<ItemData>> GetItemsByType(DungeonEditorSystem::ItemType type);
|
|
absl::Status MoveItem(int item_id, int new_x, int new_y);
|
|
absl::Status SetItemHidden(int item_id, bool hidden);
|
|
|
|
// Entrance/exit management
|
|
absl::Status AddEntrance(const EntranceData& entrance_data);
|
|
absl::Status RemoveEntrance(int entrance_id);
|
|
absl::Status UpdateEntrance(int entrance_id, const EntranceData& entrance_data);
|
|
absl::StatusOr<EntranceData> GetEntrance(int entrance_id);
|
|
absl::StatusOr<std::vector<EntranceData>> GetEntrancesByRoom(int room_id);
|
|
absl::StatusOr<std::vector<EntranceData>> GetEntrancesByType(DungeonEditorSystem::EntranceType type);
|
|
absl::Status ConnectRooms(int room1_id, int room2_id, int x1, int y1, int x2, int y2);
|
|
absl::Status DisconnectRooms(int room1_id, int room2_id);
|
|
|
|
// Door management
|
|
absl::Status AddDoor(const DoorData& door_data);
|
|
absl::Status RemoveDoor(int door_id);
|
|
absl::Status UpdateDoor(int door_id, const DoorData& door_data);
|
|
absl::StatusOr<DoorData> GetDoor(int door_id);
|
|
absl::StatusOr<std::vector<DoorData>> GetDoorsByRoom(int room_id);
|
|
absl::Status SetDoorLocked(int door_id, bool locked);
|
|
absl::Status SetDoorKeyRequirement(int door_id, bool requires_key, int key_type);
|
|
|
|
// Chest management
|
|
absl::Status AddChest(const ChestData& chest_data);
|
|
absl::Status RemoveChest(int chest_id);
|
|
absl::Status UpdateChest(int chest_id, const ChestData& chest_data);
|
|
absl::StatusOr<ChestData> GetChest(int chest_id);
|
|
absl::StatusOr<std::vector<ChestData>> GetChestsByRoom(int room_id);
|
|
absl::Status SetChestItem(int chest_id, int item_id, int quantity);
|
|
absl::Status SetChestOpened(int chest_id, bool opened);
|
|
|
|
// Room properties and metadata
|
|
struct RoomProperties {
|
|
int room_id;
|
|
std::string name;
|
|
std::string description;
|
|
int dungeon_id;
|
|
int floor_level;
|
|
bool is_boss_room = false;
|
|
bool is_save_room = false;
|
|
bool is_shop_room = false;
|
|
int music_id = 0;
|
|
int ambient_sound_id = 0;
|
|
std::unordered_map<std::string, std::string> custom_properties;
|
|
};
|
|
|
|
absl::Status SetRoomProperties(int room_id, const RoomProperties& properties);
|
|
absl::StatusOr<RoomProperties> GetRoomProperties(int room_id);
|
|
|
|
// Dungeon-wide settings
|
|
struct DungeonSettings {
|
|
int dungeon_id;
|
|
std::string name;
|
|
std::string description;
|
|
int total_rooms;
|
|
int starting_room_id;
|
|
int boss_room_id;
|
|
int music_theme_id;
|
|
int color_palette_id;
|
|
bool has_map = true;
|
|
bool has_compass = true;
|
|
bool has_big_key = true;
|
|
std::unordered_map<std::string, std::string> custom_settings;
|
|
};
|
|
|
|
absl::Status SetDungeonSettings(const DungeonSettings& settings);
|
|
absl::StatusOr<DungeonSettings> GetDungeonSettings();
|
|
|
|
// Validation and error checking
|
|
absl::Status ValidateRoom(int room_id);
|
|
absl::Status ValidateDungeon();
|
|
std::vector<std::string> GetValidationErrors(int room_id);
|
|
std::vector<std::string> GetDungeonValidationErrors();
|
|
|
|
// Rendering and preview
|
|
absl::StatusOr<gfx::Bitmap> RenderRoom(int room_id);
|
|
absl::StatusOr<gfx::Bitmap> RenderRoomPreview(int room_id, EditorMode mode);
|
|
absl::StatusOr<gfx::Bitmap> RenderDungeonMap();
|
|
|
|
// Import/Export functionality
|
|
absl::Status ImportRoomFromFile(const std::string& file_path, int room_id);
|
|
absl::Status ExportRoomToFile(int room_id, const std::string& file_path);
|
|
absl::Status ImportDungeonFromFile(const std::string& file_path);
|
|
absl::Status ExportDungeonToFile(const std::string& file_path);
|
|
|
|
// Undo/Redo system
|
|
absl::Status Undo();
|
|
absl::Status Redo();
|
|
bool CanUndo() const;
|
|
bool CanRedo() const;
|
|
void ClearHistory();
|
|
|
|
// Event callbacks
|
|
using RoomChangedCallback = std::function<void(int room_id)>;
|
|
using SpriteChangedCallback = std::function<void(int sprite_id)>;
|
|
using ItemChangedCallback = std::function<void(int item_id)>;
|
|
using EntranceChangedCallback = std::function<void(int entrance_id)>;
|
|
using DoorChangedCallback = std::function<void(int door_id)>;
|
|
using ChestChangedCallback = std::function<void(int chest_id)>;
|
|
using ModeChangedCallback = std::function<void(EditorMode mode)>;
|
|
using ValidationCallback = std::function<void(const std::vector<std::string>& errors)>;
|
|
|
|
void SetRoomChangedCallback(RoomChangedCallback callback);
|
|
void SetSpriteChangedCallback(SpriteChangedCallback callback);
|
|
void SetItemChangedCallback(ItemChangedCallback callback);
|
|
void SetEntranceChangedCallback(EntranceChangedCallback callback);
|
|
void SetDoorChangedCallback(DoorChangedCallback callback);
|
|
void SetChestChangedCallback(ChestChangedCallback callback);
|
|
void SetModeChangedCallback(ModeChangedCallback callback);
|
|
void SetValidationCallback(ValidationCallback callback);
|
|
|
|
// Getters
|
|
EditorState GetEditorState() const;
|
|
Rom* GetROM() const;
|
|
bool IsDirty() const;
|
|
bool HasUnsavedChanges() const;
|
|
|
|
// ROM management
|
|
void SetROM(Rom* rom);
|
|
|
|
private:
|
|
// Internal helper methods
|
|
absl::Status InitializeObjectEditor();
|
|
absl::Status InitializeSpriteSystem();
|
|
absl::Status InitializeItemSystem();
|
|
absl::Status InitializeEntranceSystem();
|
|
absl::Status InitializeDoorSystem();
|
|
absl::Status InitializeChestSystem();
|
|
|
|
// Data management
|
|
absl::Status LoadRoomData(int room_id);
|
|
absl::Status SaveRoomData(int room_id);
|
|
absl::Status LoadSpriteData();
|
|
absl::Status SaveSpriteData();
|
|
absl::Status LoadItemData();
|
|
absl::Status SaveItemData();
|
|
absl::Status LoadEntranceData();
|
|
absl::Status SaveEntranceData();
|
|
absl::Status LoadDoorData();
|
|
absl::Status SaveDoorData();
|
|
absl::Status LoadChestData();
|
|
absl::Status SaveChestData();
|
|
|
|
// Validation helpers
|
|
absl::Status ValidateSprite(const SpriteData& sprite);
|
|
absl::Status ValidateItem(const ItemData& item);
|
|
absl::Status ValidateEntrance(const EntranceData& entrance);
|
|
absl::Status ValidateDoor(const DoorData& door);
|
|
absl::Status ValidateChest(const ChestData& chest);
|
|
|
|
// ID generation
|
|
int GenerateSpriteId();
|
|
int GenerateItemId();
|
|
int GenerateEntranceId();
|
|
int GenerateDoorId();
|
|
int GenerateChestId();
|
|
|
|
// Member variables
|
|
Rom* rom_;
|
|
std::shared_ptr<DungeonObjectEditor> object_editor_;
|
|
|
|
EditorState editor_state_;
|
|
DungeonSettings dungeon_settings_;
|
|
|
|
// Data storage
|
|
std::unordered_map<int, Room> rooms_;
|
|
std::unordered_map<int, SpriteData> sprites_;
|
|
std::unordered_map<int, ItemData> items_;
|
|
std::unordered_map<int, EntranceData> entrances_;
|
|
std::unordered_map<int, DoorData> doors_;
|
|
std::unordered_map<int, ChestData> chests_;
|
|
std::unordered_map<int, RoomProperties> room_properties_;
|
|
|
|
// ID counters
|
|
int next_sprite_id_ = 1;
|
|
int next_item_id_ = 1;
|
|
int next_entrance_id_ = 1;
|
|
int next_door_id_ = 1;
|
|
int next_chest_id_ = 1;
|
|
|
|
// Event callbacks
|
|
RoomChangedCallback room_changed_callback_;
|
|
SpriteChangedCallback sprite_changed_callback_;
|
|
ItemChangedCallback item_changed_callback_;
|
|
EntranceChangedCallback entrance_changed_callback_;
|
|
DoorChangedCallback door_changed_callback_;
|
|
ChestChangedCallback chest_changed_callback_;
|
|
ModeChangedCallback mode_changed_callback_;
|
|
ValidationCallback validation_callback_;
|
|
|
|
// Undo/Redo system
|
|
struct UndoPoint {
|
|
EditorState state;
|
|
std::unordered_map<int, Room> rooms;
|
|
std::unordered_map<int, SpriteData> sprites;
|
|
std::unordered_map<int, ItemData> items;
|
|
std::unordered_map<int, EntranceData> entrances;
|
|
std::unordered_map<int, DoorData> doors;
|
|
std::unordered_map<int, ChestData> chests;
|
|
std::chrono::steady_clock::time_point timestamp;
|
|
};
|
|
|
|
std::vector<UndoPoint> undo_history_;
|
|
std::vector<UndoPoint> redo_history_;
|
|
static constexpr size_t kMaxUndoHistory = 100;
|
|
};
|
|
|
|
/**
|
|
* @brief Factory function to create dungeon editor system
|
|
*/
|
|
std::unique_ptr<DungeonEditorSystem> CreateDungeonEditorSystem(Rom* rom);
|
|
|
|
/**
|
|
* @brief Sprite type utilities
|
|
*/
|
|
namespace SpriteTypes {
|
|
|
|
/**
|
|
* @brief Get sprite information by ID
|
|
*/
|
|
struct SpriteInfo {
|
|
int id;
|
|
std::string name;
|
|
DungeonEditorSystem::SpriteType type;
|
|
std::string description;
|
|
int default_layer;
|
|
std::vector<std::pair<std::string, std::string>> default_properties;
|
|
bool is_interactive;
|
|
bool is_hostile;
|
|
int difficulty_rating;
|
|
};
|
|
|
|
absl::StatusOr<SpriteInfo> GetSpriteInfo(int sprite_id);
|
|
std::vector<SpriteInfo> GetAllSpriteInfos();
|
|
std::vector<SpriteInfo> GetSpritesByType(DungeonEditorSystem::SpriteType type);
|
|
absl::StatusOr<std::string> GetSpriteCategory(int sprite_id);
|
|
|
|
} // namespace SpriteTypes
|
|
|
|
/**
|
|
* @brief Item type utilities
|
|
*/
|
|
namespace ItemTypes {
|
|
|
|
/**
|
|
* @brief Get item information by ID
|
|
*/
|
|
struct ItemInfo {
|
|
int id;
|
|
std::string name;
|
|
DungeonEditorSystem::ItemType type;
|
|
std::string description;
|
|
int rarity;
|
|
int value;
|
|
std::vector<std::pair<std::string, std::string>> default_properties;
|
|
bool is_stackable;
|
|
int max_stack_size;
|
|
};
|
|
|
|
absl::StatusOr<ItemInfo> GetItemInfo(int item_id);
|
|
std::vector<ItemInfo> GetAllItemInfos();
|
|
std::vector<ItemInfo> GetItemsByType(DungeonEditorSystem::ItemType type);
|
|
absl::StatusOr<std::string> GetItemCategory(int item_id);
|
|
|
|
} // namespace ItemTypes
|
|
|
|
/**
|
|
* @brief Entrance type utilities
|
|
*/
|
|
namespace EntranceTypes {
|
|
|
|
/**
|
|
* @brief Get entrance information by ID
|
|
*/
|
|
struct EntranceInfo {
|
|
int id;
|
|
std::string name;
|
|
DungeonEditorSystem::EntranceType type;
|
|
std::string description;
|
|
std::vector<std::pair<std::string, std::string>> default_properties;
|
|
bool requires_key;
|
|
int key_type;
|
|
bool is_bidirectional;
|
|
};
|
|
|
|
absl::StatusOr<EntranceInfo> GetEntranceInfo(int entrance_id);
|
|
std::vector<EntranceInfo> GetAllEntranceInfos();
|
|
std::vector<EntranceInfo> GetEntrancesByType(DungeonEditorSystem::EntranceType type);
|
|
|
|
} // namespace EntranceTypes
|
|
|
|
} // namespace zelda3
|
|
} // namespace yaze
|
|
|
|
#endif // YAZE_APP_ZELDA3_DUNGEON_DUNGEON_EDITOR_SYSTEM_H
|