yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
object_selector_content.cc
Go to the documentation of this file.
1// Related header
3#include <algorithm>
4#include <cstddef>
5#include <cstdint>
6#include <memory>
7#include <vector>
8
9// Third-party library headers
10#include "absl/strings/str_format.h"
13#include "imgui/imgui.h"
14
15// Project headers
19#include "app/gui/core/icons.h"
23#include "rom/rom.h"
31
32namespace yaze {
33namespace editor {
34
36 gfx::IRenderer* renderer, Rom* rom, DungeonCanvasViewer* canvas_viewer,
37 std::shared_ptr<zelda3::DungeonObjectEditor> object_editor)
38 : renderer_(renderer),
39 rom_(rom),
40 canvas_viewer_(canvas_viewer),
41 object_selector_(rom),
42 object_editor_(object_editor) {
43 // Initialize object parser for static editor info lookup
44 if (rom) {
45 object_parser_ = std::make_unique<zelda3::ObjectParser>(rom);
46 }
47
48 // Wire up object selector callback
50 [this](const zelda3::RoomObject& obj) {
51 preview_object_ = obj;
53 if (canvas_viewer_) {
56 }
57
58 // Sync with backend editor if available
59 if (object_editor_) {
61 object_editor_->SetCurrentObjectType(obj.id_);
62 }
63 });
64
65 // Wire up double-click callback for static object editor
67 [this](int obj_id) { OpenStaticObjectEditor(obj_id); });
68}
69
76
77void ObjectSelectorContent::Draw(bool* p_open) {
78 (void)p_open;
80
81 const auto& theme = AgentUI::GetTheme();
82 const int max_objects = static_cast<int>(zelda3::kMaxTileObjects);
83 const int max_sprites = static_cast<int>(zelda3::kMaxTotalSprites);
84 const int max_doors = static_cast<int>(zelda3::kMaxDoors);
85
86 // Check if placement was blocked by ROM limits
87 if (canvas_viewer_) {
88 auto& coordinator =
90
91 auto& tile_handler = coordinator.tile_handler();
92 if (tile_handler.was_placement_blocked()) {
93 const auto reason = tile_handler.placement_block_reason();
94 tile_handler.clear_placement_blocked();
95 switch (reason) {
97 SetPlacementError(absl::StrFormat(
98 "Object limit reached (%d max) - placement blocked",
99 max_objects));
100 break;
102 SetPlacementError("Invalid room target - placement blocked");
103 break;
105 default:
106 SetPlacementError("Object placement blocked");
107 break;
108 }
109 }
110
111 auto& sprite_handler = coordinator.sprite_handler();
112 if (sprite_handler.was_placement_blocked()) {
113 const auto reason = sprite_handler.placement_block_reason();
114 sprite_handler.clear_placement_blocked();
115 switch (reason) {
117 SetPlacementError(absl::StrFormat(
118 "Sprite limit reached (%d max) - placement blocked",
119 max_sprites));
120 break;
122 SetPlacementError("Invalid room target - sprite placement blocked");
123 break;
125 default:
126 SetPlacementError("Sprite placement blocked");
127 break;
128 }
129 }
130
131 auto& door_handler = coordinator.door_handler();
132 if (door_handler.was_placement_blocked()) {
133 const auto reason = door_handler.placement_block_reason();
134 door_handler.clear_placement_blocked();
135 switch (reason) {
137 SetPlacementError(absl::StrFormat(
138 "Door limit reached (%d max) - placement blocked", max_doors));
139 break;
141 SetPlacementError("Invalid door position - must be near a wall");
142 break;
144 SetPlacementError("Invalid room target - door placement blocked");
145 break;
147 default:
148 SetPlacementError("Door placement blocked");
149 break;
150 }
151 }
152 }
153
156
157 float available_height = ImGui::GetContentRegionAvail().y;
158 float browser_height =
159 std::max(220.0f, available_height - (static_editor_open_ ? 260.0f : 0.0f));
160
161 gui::SectionHeader(ICON_MD_CATEGORY, "Object Selector", theme.text_info);
162 ImGui::TextColored(
163 theme.text_secondary_gray,
164 "Choose an object to place. Double-click an entry to inspect its draw "
165 "routine or open the tile editor.");
166 ImGui::BeginChild("ObjectBrowserRegion", ImVec2(0, browser_height), true);
168 ImGui::EndChild();
169
171 ImGui::Spacing();
173 }
174}
175
179
181 // In agent mode, we might force tabs open or change layout
182 (void)enabled;
183}
184
185void ObjectSelectorContent::SetPlacementError(const std::string& message) {
186 // Avoid refreshing the timer for repeated identical errors; keeps the
187 // message stable during rapid blocked clicks.
188 if (message == last_placement_error_ && placement_error_time_ >= 0.0) {
189 double elapsed = ImGui::GetTime() - placement_error_time_;
190 if (elapsed < kPlacementErrorDuration) {
191 return;
192 }
193 }
194 last_placement_error_ = message;
195 placement_error_time_ = ImGui::GetTime();
196}
197
199 // Delegate to the DungeonObjectSelector component
201}
202
204 const auto& theme = AgentUI::GetTheme();
205 auto* viewer = ResolveCanvasViewer();
206 const size_t selection_count =
207 viewer ? viewer->object_interaction().GetSelectionCount() : 0;
208
209 gui::SectionHeader(ICON_MD_TOUCH_APP, "Interaction", theme.text_info);
210
211 bool is_placing = has_preview_object_ && canvas_viewer_ &&
213 if (!is_placing && has_preview_object_) {
214 has_preview_object_ = false;
215 }
216
217 if (is_placing) {
218 ImGui::TextColored(theme.status_warning,
219 ICON_MD_ADD_CIRCLE " Placement ready: 0x%03X %s",
222 ImGui::SameLine();
223 if (ImGui::SmallButton(ICON_MD_CANCEL " Cancel")) {
225 }
226 } else if (selection_count == 1) {
227 ImGui::TextColored(theme.status_success,
228 ICON_MD_CHECK_CIRCLE " 1 room object selected");
230 ImGui::SameLine();
231 if (ImGui::SmallButton(ICON_MD_OPEN_IN_NEW " Open Object Editor")) {
233 }
234 }
235 } else if (selection_count > 1) {
236 ImGui::TextColored(theme.status_success,
237 ICON_MD_SELECT_ALL " %zu room objects selected",
238 selection_count);
240 ImGui::SameLine();
241 if (ImGui::SmallButton(ICON_MD_OPEN_IN_NEW " Open Object Editor")) {
243 }
244 }
245 } else {
246 ImGui::TextColored(theme.text_secondary_gray,
248 " Browse objects below to place them. Click room "
249 "objects to edit them in the Object Editor.");
250 }
251
252 if (!last_placement_error_.empty()) {
253 double elapsed = ImGui::GetTime() - placement_error_time_;
254 if (elapsed < kPlacementErrorDuration) {
255 ImGui::TextColored(theme.status_error, ICON_MD_ERROR " %s",
256 last_placement_error_.c_str());
257 } else {
258 last_placement_error_.clear();
259 }
260 }
261}
262
263// =============================================================================
264// Static Object Editor (opened via double-click)
265// =============================================================================
266
268 static_editor_open_ = true;
269 static_editor_object_id_ = object_id;
271
272 // Sync with object selector for visual indicator
274
275 // Fetch draw routine info for this object
276 if (object_parser_) {
277 static_editor_draw_info_ = object_parser_->GetObjectDrawInfo(object_id);
278 }
279
280 // Render the object preview using ObjectDrawer
281 auto* rooms = object_selector_.get_rooms();
282 if (rom_ && rom_->is_loaded() && rooms && current_room_id_ >= 0 &&
283 current_room_id_ < static_cast<int>(rooms->size())) {
284 auto& room = (*rooms)[current_room_id_];
285
286 // Ensure room graphics are loaded
287 if (!room.IsLoaded()) {
288 room.LoadRoomGraphics(room.blockset());
289 }
290
291 // Clear preview buffer and initialize bitmap
294
295 // Create a preview object at top-left of canvas (tile 2,2 = pixel 16,16)
296 // to fit within the 128x128 preview area with some margin
297 zelda3::RoomObject preview_obj(object_id, 2, 2, 0x12, 0);
298 preview_obj.SetRom(rom_);
299 preview_obj.EnsureTilesLoaded();
300
301 if (preview_obj.tiles().empty()) {
302 return; // No tiles to draw
303 }
304
305 // Get room graphics data
306 const uint8_t* gfx_data = room.get_gfx_buffer().data();
307
308 // Apply palette to bitmap
309 auto& bitmap = static_preview_buffer_.bitmap();
310 gfx::PaletteGroup palette_group;
311 auto* game_data = object_selector_.game_data();
312 if (game_data && !game_data->palette_groups.dungeon_main.empty()) {
313 // Use the entire dungeon_main palette group
314 palette_group = game_data->palette_groups.dungeon_main;
315
316 std::vector<SDL_Color> colors(256);
317 size_t color_index = 0;
318 for (size_t pal_idx = 0;
319 pal_idx < palette_group.size() && color_index < 256; ++pal_idx) {
320 const auto& pal = palette_group[pal_idx];
321 for (size_t i = 0; i < pal.size() && color_index < 256; ++i) {
322 ImVec4 rgb = pal[i].rgb();
323 colors[color_index++] = {static_cast<Uint8>(rgb.x),
324 static_cast<Uint8>(rgb.y),
325 static_cast<Uint8>(rgb.z), 255};
326 }
327 }
328 colors[255] = {0, 0, 0, 0}; // Transparent
329 bitmap.SetPalette(colors);
330 if (bitmap.surface()) {
331 SDL_SetColorKey(bitmap.surface(), SDL_TRUE, 255);
332 SDL_SetSurfaceBlendMode(bitmap.surface(), SDL_BLENDMODE_BLEND);
333 }
334 }
335
336 // Create drawer with room's graphics data
337 zelda3::ObjectDrawer drawer(rom_, current_room_id_, gfx_data);
338 drawer.InitializeDrawRoutines();
339
340 auto status = drawer.DrawObject(preview_obj, static_preview_buffer_,
341 static_preview_buffer_, palette_group);
342 if (status.ok()) {
343 // Sync bitmap data to SDL surface
344 if (bitmap.modified() && bitmap.surface() &&
345 bitmap.mutable_data().size() > 0) {
346 SDL_LockSurface(bitmap.surface());
347 size_t surface_size = bitmap.surface()->h * bitmap.surface()->pitch;
348 size_t data_size = bitmap.mutable_data().size();
349 if (surface_size >= data_size) {
350 memcpy(bitmap.surface()->pixels, bitmap.mutable_data().data(),
351 data_size);
352 }
353 SDL_UnlockSurface(bitmap.surface());
354 }
355
356 // Create texture
360
361 static_preview_rendered_ = bitmap.texture() != nullptr;
362 }
363 }
364}
365
367 static_editor_open_ = false;
369
370 // Clear the visual indicator in object selector
372}
373
375 const auto& theme = AgentUI::GetTheme();
376
377 gui::StyleColorGuard header_colors({
378 {ImGuiCol_Header, ImVec4(0.15f, 0.25f, 0.35f, 1.0f)},
379 {ImGuiCol_HeaderHovered, ImVec4(0.20f, 0.30f, 0.40f, 1.0f)},
380 });
381
382 bool header_open = ImGui::CollapsingHeader(
383 absl::StrFormat(ICON_MD_CONSTRUCTION " Object 0x%02X - %s",
386 .c_str(),
387 ImGuiTreeNodeFlags_DefaultOpen);
388
389 if (header_open) {
390 gui::StyleVarGuard frame_pad_guard(ImGuiStyleVar_FramePadding,
391 ImVec2(8, 6));
392
393 // Two-column layout: Info | Preview
394 if (ImGui::BeginTable("StaticEditorLayout", 2,
395 ImGuiTableFlags_BordersInnerV)) {
396 ImGui::TableSetupColumn("Info", ImGuiTableColumnFlags_WidthFixed, 200);
397 ImGui::TableSetupColumn("Preview", ImGuiTableColumnFlags_WidthStretch);
398
399 ImGui::TableNextRow();
400
401 // Left column: Object information
402 ImGui::TableNextColumn();
403 {
404 // Object ID with hex/decimal display
405 ImGui::TextColored(theme.text_info, ICON_MD_TAG " Object ID");
406 ImGui::SameLine();
407 ImGui::Text("0x%02X (%d)", static_editor_object_id_,
409
410 ImGui::Spacing();
411
412 // Draw routine info
413 ImGui::TextColored(theme.text_info, ICON_MD_BRUSH " Draw Routine");
414 ImGui::Indent();
415 ImGui::Text("ID: %d", static_editor_draw_info_.draw_routine_id);
416 ImGui::Text("Name: %s", static_editor_draw_info_.routine_name.c_str());
417 ImGui::Unindent();
418
419 ImGui::Spacing();
420
421 // Tile and size info
422 ImGui::TextColored(theme.text_info, ICON_MD_GRID_VIEW " Tile Info");
423 ImGui::Indent();
424 ImGui::Text("Tile Count: %d", static_editor_draw_info_.tile_count);
425 ImGui::Text("Orientation: %s",
428 : "Both");
430 ImGui::TextColored(theme.status_warning, ICON_MD_LAYERS " Both BG");
431 }
432 ImGui::Unindent();
433
434 ImGui::Spacing();
435 ImGui::Separator();
436 ImGui::Spacing();
437
438 // Action buttons (vertical layout)
439 if (ImGui::Button(ICON_MD_CONTENT_COPY " Copy ID", ImVec2(-1, 0))) {
440 ImGui::SetClipboardText(
441 absl::StrFormat("0x%02X", static_editor_object_id_).c_str());
442 }
443 if (ImGui::IsItemHovered()) {
444 ImGui::SetTooltip("Copy object ID to clipboard");
445 }
446
447 if (ImGui::Button(ICON_MD_CODE " Export ASM", ImVec2(-1, 0))) {
448 const std::string asm_preview = absl::StrFormat(
449 "; Object 0x%02X (%s)\n"
450 "; Auto-generated preview stub\n"
451 "org $000000\n"
452 "dw $%02X ; object id\n"
453 "; draw_routine=%d tile_count=%d\n",
458 ImGui::SetClipboardText(asm_preview.c_str());
459 }
460 if (ImGui::IsItemHovered()) {
461 ImGui::SetTooltip("Copy ASM preview stub to clipboard");
462 }
463
464 if (ImGui::Button(ICON_MD_GRID_ON " Edit Tiles", ImVec2(-1, 0))) {
467 static_cast<int16_t>(static_editor_object_id_));
468 }
469 }
470 if (ImGui::IsItemHovered()) {
471 ImGui::SetTooltip("Open tile editor to rearrange 8x8 tiles");
472 }
473
474 ImGui::Spacing();
475
476 // Close button at bottom
477 if (gui::DangerButton(ICON_MD_CLOSE " Close", ImVec2(-1, 0))) {
479 }
480 }
481
482 // Right column: Preview canvas
483 ImGui::TableNextColumn();
484 {
485 ImGui::TextColored(theme.text_secondary_gray, "Preview:");
486
487 gui::PreviewPanelOpts preview_opts;
488 preview_opts.canvas_size = ImVec2(128, 128);
489 preview_opts.render_popups = false;
490 preview_opts.grid_step = 0.0f;
491 preview_opts.ensure_texture = true;
492
493 gui::CanvasFrameOptions frame_opts;
494 frame_opts.canvas_size = preview_opts.canvas_size;
495 frame_opts.draw_context_menu = false;
496 frame_opts.draw_grid = preview_opts.grid_step > 0.0f;
497 if (preview_opts.grid_step > 0.0f) {
498 frame_opts.grid_step = preview_opts.grid_step;
499 }
500 frame_opts.draw_overlay = true;
501 frame_opts.render_popups = preview_opts.render_popups;
502
503 auto rt = gui::BeginCanvas(static_preview_canvas_, frame_opts);
504
506 auto& bitmap = static_preview_buffer_.bitmap();
507 gui::RenderPreviewPanel(rt, bitmap, preview_opts);
508 } else {
510 preview_opts);
512 ImVec2(24, 56), "No preview available",
513 ImGui::GetColorU32(theme.text_secondary_gray));
514 }
515 gui::EndCanvas(static_preview_canvas_, rt, frame_opts);
516
517 // Usage hint
518 ImGui::Spacing();
519 ImGui::TextColored(theme.text_secondary_gray, ICON_MD_INFO
520 " Double-click objects in browser\n"
521 "to view their draw routine info.");
522 }
523
524 ImGui::EndTable();
525 }
526 }
527}
528
529// =============================================================================
530// Room Validation Bar
531// =============================================================================
532
534 auto* rooms = object_selector_.get_rooms();
535 if (!rooms || current_room_id_ < 0 ||
537 return;
538 }
539
540 const auto& theme = AgentUI::GetTheme();
541 const auto& room = (*rooms)[current_room_id_];
542
543 // Gather counts
544 size_t object_count = room.GetTileObjects().size();
545 size_t sprite_count = room.GetSprites().size();
546 size_t door_count = room.GetDoors().size();
547
548 // Count chests (objects in 0xF9-0xFD range)
549 int chest_count = 0;
550 for (const auto& obj : room.GetTileObjects()) {
551 if (obj.id_ >= 0xF9 && obj.id_ <= 0xFD) {
552 chest_count++;
553 }
554 }
555
556 // Canonical limits shared across handlers/validator.
557 const int kMaxObjects = static_cast<int>(zelda3::kMaxTileObjects);
558 const int kMaxSprites = static_cast<int>(zelda3::kMaxTotalSprites);
559 const int kMaxDoors = static_cast<int>(zelda3::kMaxDoors);
560 const int kMaxChests = static_cast<int>(zelda3::kMaxChests);
561
562 // Helper to pick color based on usage ratio
563 auto usage_color = [&](size_t count, int max_val) -> ImVec4 {
564 float ratio = static_cast<float>(count) / static_cast<float>(max_val);
565 if (ratio >= 1.0f) {
566 return theme.status_error;
567 }
568 if (ratio >= 0.75f) {
569 return theme.status_warning;
570 }
571 return theme.text_secondary_gray;
572 };
573
574 // Compact inline counters
575 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 2));
576
577 ImGui::TextColored(usage_color(object_count, kMaxObjects),
578 ICON_MD_WIDGETS " %zu/%d", object_count, kMaxObjects);
579 if (ImGui::IsItemHovered()) {
580 ImGui::SetTooltip("Objects: %zu of %d maximum", object_count, kMaxObjects);
581 }
582
583 ImGui::SameLine();
584 ImGui::TextColored(usage_color(sprite_count, kMaxSprites),
585 ICON_MD_PEST_CONTROL " %zu/%d", sprite_count, kMaxSprites);
586 if (ImGui::IsItemHovered()) {
587 ImGui::SetTooltip("Sprites: %zu of %d maximum", sprite_count, kMaxSprites);
588 }
589
590 ImGui::SameLine();
591 ImGui::TextColored(usage_color(door_count, kMaxDoors),
592 ICON_MD_DOOR_FRONT " %zu/%d", door_count, kMaxDoors);
593 if (ImGui::IsItemHovered()) {
594 ImGui::SetTooltip("Doors: %zu of %d maximum", door_count, kMaxDoors);
595 }
596
597 ImGui::SameLine();
598 ImGui::TextColored(usage_color(chest_count, kMaxChests),
599 ICON_MD_INVENTORY_2 " %d/%d", chest_count, kMaxChests);
600 if (ImGui::IsItemHovered()) {
601 ImGui::SetTooltip("Chests: %d of %d maximum", chest_count, kMaxChests);
602 }
603
604 ImGui::PopStyleVar();
605
606 // Run full validation and show warnings/errors inline
607 zelda3::DungeonValidator validator;
608 auto result = validator.ValidateRoom(room);
609 if (!result.errors.empty() || !result.warnings.empty()) {
610 for (const auto& err : result.errors) {
611 ImGui::TextColored(theme.status_error, ICON_MD_ERROR " %s", err.c_str());
612 }
613 for (const auto& warn : result.warnings) {
614 ImGui::TextColored(theme.status_warning, ICON_MD_WARNING " %s",
615 warn.c_str());
616 }
617 }
618
619 ImGui::Separator();
620}
621
629
630} // namespace editor
631} // 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:28
bool is_loaded() const
Definition rom.h:132
DungeonObjectInteraction & object_interaction()
void SetPreviewObject(const zelda3::RoomObject &object)
InteractionCoordinator & entity_coordinator()
Get the interaction coordinator for entity handling.
void SetObjectDoubleClickCallback(std::function< void(int)> callback)
void SelectObject(int obj_id, int subtype=-1)
void SetObjectSelectedCallback(std::function< void(const zelda3::RoomObject &)> callback)
void SetPlacementError(const std::string &message)
std::function< DungeonCanvasViewer *()> canvas_viewer_provider_
std::shared_ptr< zelda3::DungeonObjectEditor > object_editor_
ObjectSelectorContent(gfx::IRenderer *renderer, Rom *rom, DungeonCanvasViewer *canvas_viewer, std::shared_ptr< zelda3::DungeonObjectEditor > object_editor=nullptr)
void Draw(bool *p_open) override
Draw the panel content.
std::unique_ptr< zelda3::ObjectParser > object_parser_
PlacementBlockReason placement_block_reason() const
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Definition arena.cc:36
void ProcessTextureQueue(IRenderer *renderer)
Definition arena.cc:116
static Arena & Get()
Definition arena.cc:21
Defines an abstract interface for all rendering operations.
Definition irenderer.h:60
void AddTextAt(ImVec2 local_pos, const std::string &text, uint32_t color)
Definition canvas.cc:2507
RAII guard for ImGui style colors.
Definition style_guard.h:27
RAII guard for ImGui style vars.
Definition style_guard.h:68
ValidationResult ValidateRoom(const Room &room)
Draws dungeon objects to background buffers using game patterns.
void InitializeDrawRoutines()
Initialize draw routine registry Must be called before drawing objects.
absl::Status DrawObject(const RoomObject &object, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const gfx::PaletteGroup &palette_group, const DungeonState *state=nullptr, gfx::BackgroundBuffer *layout_bg1=nullptr)
Draw a room object to background buffers.
const std::vector< gfx::TileInfo > & tiles() const
void SetRom(Rom *rom)
Definition room_object.h:79
#define ICON_MD_GRID_VIEW
Definition icons.h:897
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_CANCEL
Definition icons.h:364
#define ICON_MD_WARNING
Definition icons.h:2123
#define ICON_MD_CONSTRUCTION
Definition icons.h:458
#define ICON_MD_BRUSH
Definition icons.h:325
#define ICON_MD_CODE
Definition icons.h:434
#define ICON_MD_WIDGETS
Definition icons.h:2156
#define ICON_MD_ERROR
Definition icons.h:686
#define ICON_MD_GRID_ON
Definition icons.h:896
#define ICON_MD_LAYERS
Definition icons.h:1068
#define ICON_MD_DOOR_FRONT
Definition icons.h:613
#define ICON_MD_CHECK_CIRCLE
Definition icons.h:400
#define ICON_MD_PEST_CONTROL
Definition icons.h:1429
#define ICON_MD_TOUCH_APP
Definition icons.h:2000
#define ICON_MD_MOUSE
Definition icons.h:1251
#define ICON_MD_SELECT_ALL
Definition icons.h:1680
#define ICON_MD_OPEN_IN_NEW
Definition icons.h:1354
#define ICON_MD_CONTENT_COPY
Definition icons.h:465
#define ICON_MD_INVENTORY_2
Definition icons.h:1012
#define ICON_MD_CLOSE
Definition icons.h:418
#define ICON_MD_CATEGORY
Definition icons.h:382
#define ICON_MD_TAG
Definition icons.h:1940
#define ICON_MD_ADD_CIRCLE
Definition icons.h:95
const AgentUITheme & GetTheme()
void EndCanvas(Canvas &canvas)
Definition canvas.cc:1591
void BeginCanvas(Canvas &canvas, ImVec2 child_size)
Definition canvas.cc:1568
bool DangerButton(const char *label, const ImVec2 &size, const char *panel_id, const char *anim_id)
Draw a danger action button (error color).
void SectionHeader(const char *icon, const char *label, const ImVec4 &color)
bool RenderPreviewPanel(const CanvasRuntime &rt, gfx::Bitmap &bmp, const PreviewPanelOpts &opts)
Definition canvas.cc:2238
constexpr size_t kMaxTileObjects
constexpr size_t kMaxDoors
std::string GetObjectName(int object_id)
constexpr int kNumberOfRooms
constexpr size_t kMaxChests
constexpr size_t kMaxTotalSprites
Represents a group of palettes.
std::optional< float > grid_step
Definition canvas.h:70
gfx::PaletteGroupMap palette_groups
Definition game_data.h:91