3#include "absl/strings/str_format.h"
16#include "imgui/imgui.h"
23using ImGui::BeginTable;
25using ImGui::Separator;
26using ImGui::TableNextColumn;
32 int& current_world,
int& current_map,
bool& current_map_lock,
33 bool& show_map_properties_panel,
bool& show_custom_bg_color_editor,
34 bool& show_overlay_editor,
bool& show_overlay_preview,
int& game_state,
36 (void)show_overlay_editor;
37 (void)show_custom_bg_color_editor;
39 (void)show_overlay_preview;
42 if (BeginTable(
"CanvasToolbar", 7,
43 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit,
45 ImGui::TableSetupColumn(
"World", ImGuiTableColumnFlags_WidthFixed,
47 ImGui::TableSetupColumn(
"Map", ImGuiTableColumnFlags_WidthFixed,
49 ImGui::TableSetupColumn(
"Area Size", ImGuiTableColumnFlags_WidthFixed,
51 ImGui::TableSetupColumn(
"Lock", ImGuiTableColumnFlags_WidthFixed,
53 ImGui::TableSetupColumn(
"Mode", ImGuiTableColumnFlags_WidthFixed,
55 ImGui::TableSetupColumn(
56 "Entity", ImGuiTableColumnFlags_WidthStretch);
57 ImGui::TableSetupColumn(
"Sidebar", ImGuiTableColumnFlags_WidthFixed, 40.0f);
61 ImGui::Combo(
"##world", ¤t_world,
kWorldNames, 3);
64 ImGui::Text(
"%d (0x%02X)", current_map, current_map);
71 int current_area_size =
77 if (ImGui::Combo(
"##AreaSize", ¤t_area_size,
kAreaSizeNames, 4)) {
87 const char* limited_names[] = {
"Small (1x1)",
"Large (2x2)"};
88 int limited_size = (current_area_size == 0 || current_area_size == 1)
92 if (ImGui::Combo(
"##AreaSize", &limited_size, limited_names, 2)) {
105 HOVER_HINT(
"Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
112 current_map_lock = !current_map_lock;
114 HOVER_HINT(current_map_lock ?
"Unlock Map" :
"Lock Map");
125 HOVER_HINT(
"Mouse Mode (1)\nNavigate, pan, and manage entities");
134 HOVER_HINT(
"Tile Paint Mode (2)\nDraw tiles on the map");
140 const char* entity_icon =
"";
141 const char* entity_label =
"";
142 switch (entity_edit_mode) {
145 entity_label =
"Entrances";
149 entity_label =
"Exits";
153 entity_label =
"Items";
157 entity_label =
"Sprites";
161 entity_label =
"Transports";
165 entity_label =
"Music";
170 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
"%s %s", entity_icon,
177 show_map_properties_panel = !show_map_properties_panel;
186 int current_map,
bool& show_map_properties_panel) {
187 (void)show_map_properties_panel;
189 Text(
"No overworld loaded");
195 Text(
"Current Map: %d (0x%02X)", current_map, current_map);
202 ImGuiTabBarFlags_FittingPolicyScroll)) {
204 if (ImGui::BeginTabItem(
"Basic Properties")) {
210 if (ImGui::BeginTabItem(
"Sprite Properties")) {
218 ImGui::BeginTabItem(
"Custom Features")) {
224 if (ImGui::BeginTabItem(
"Tile Graphics")) {
230 if (ImGui::BeginTabItem(
"Music")) {
240 int current_map,
bool& show_custom_bg_color_editor) {
241 (void)show_custom_bg_color_editor;
243 Text(
"No overworld loaded");
249 Text(
"Custom background colors require ZSCustomOverworld v2+");
253 Text(
"Custom Background Color Editor");
257 bool use_area_specific_bg_color =
259 if (ImGui::Checkbox(
"Use Area-Specific Background Color",
260 &use_area_specific_bg_color)) {
263 use_area_specific_bg_color ? 0x01 : 0x00;
266 if (use_area_specific_bg_color) {
268 uint16_t current_color =
275 if (ImGui::ColorPicker4(
276 "Background Color", (
float*)&color_vec,
277 ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHex)) {
281 ->set_area_specific_bg_color(new_snes_color.
snes());
286 (*rom_)[rom_address] = new_snes_color.
snes() & 0xFF;
287 (*rom_)[rom_address + 1] = (new_snes_color.
snes() >> 8) & 0xFF;
290 Text(
"SNES Color: 0x%04X", current_color);
295 bool& show_overlay_editor) {
296 (void)show_overlay_editor;
298 Text(
"No overworld loaded");
304 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
306 ImGui::Text(
"Map: 0x%02X", current_map);
312 " Enhanced overlay editing requires ZSCustomOverworld v1+");
315 "Subscreen overlays are a vanilla feature used for atmospheric effects "
316 "like fog, rain, and forest canopy. ZSCustomOverworld expands this by "
317 "allowing per-area overlay configuration and additional "
324 ImGuiTreeNodeFlags_DefaultOpen)) {
327 "Visual effects (subscreen overlays) are semi-transparent layers drawn "
328 "on top of or behind your map. They reference special area maps "
330 "for their tile16 graphics data.");
332 ImGui::Text(
"Common uses:");
333 ImGui::BulletText(
"Fog effects (Lost Woods, Skull Woods)");
334 ImGui::BulletText(
"Rain (Misery Mire)");
335 ImGui::BulletText(
"Forest canopy (Lost Woods)");
336 ImGui::BulletText(
"Sky backgrounds (Death Mountain)");
337 ImGui::BulletText(
"Under bridge views");
343 bool use_subscreen_overlay =
346 &use_subscreen_overlay)) {
349 use_subscreen_overlay ? 0x01 : 0x00;
351 if (ImGui::IsItemHovered()) {
352 ImGui::SetTooltip(
"Enable/disable visual effect overlay for this map area");
355 if (use_subscreen_overlay) {
357 uint16_t current_overlay =
362 ->set_subscreen_overlay(current_overlay);
367 (*rom_)[rom_address] = current_overlay & 0xFF;
368 (*rom_)[rom_address + 1] = (current_overlay >> 8) & 0xFF;
370 if (ImGui::IsItemHovered()) {
372 "ID of the special area map (0x80-0x9F) to use for\n"
373 "visual effects. That map's tile16 data will be drawn\n"
374 "as a semi-transparent layer on this area.");
379 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
ICON_MD_INFO " %s",
380 overlay_desc.c_str());
384 " Common Visual Effect IDs")) {
386 ImGui::BulletText(
"0x0093 - Triforce Room Curtain");
387 ImGui::BulletText(
"0x0094 - Under the Bridge");
388 ImGui::BulletText(
"0x0095 - Sky Background (LW Death Mountain)");
389 ImGui::BulletText(
"0x0096 - Pyramid Background");
390 ImGui::BulletText(
"0x0097 - Fog Overlay (Master Sword Area)");
391 ImGui::BulletText(
"0x009C - Lava Background (DW Death Mountain)");
392 ImGui::BulletText(
"0x009D - Fog Overlay (Lost/Skull Woods)");
393 ImGui::BulletText(
"0x009E - Tree Canopy (Forest)");
394 ImGui::BulletText(
"0x009F - Rain Effect (Misery Mire)");
395 ImGui::BulletText(
"0x00FF - No Overlay (Disabled)");
400 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
ICON_MD_BLOCK
401 " No visual effects enabled for this area");
406 gui::Canvas& canvas,
int current_map,
bool current_map_lock,
407 bool& show_map_properties_panel,
bool& show_custom_bg_color_editor,
408 bool& show_overlay_editor,
int current_mode) {
426 entity_menu.
subitems.push_back(entrance_item);
436 entity_menu.
subitems.push_back(hole_item);
446 entity_menu.
subitems.push_back(exit_item);
456 entity_menu.
subitems.push_back(item_item);
466 entity_menu.
subitems.push_back(sprite_item);
474 tile16_edit_item.
callback = [
this]() {
485 lock_item.
label = current_map_lock ?
"Unlock Map" :
"Lock to This Map";
486 lock_item.
callback = [¤t_map_lock]() {
487 current_map_lock = !current_map_lock;
494 properties_item.
callback = [&show_map_properties_panel]() {
495 show_map_properties_panel =
true;
505 bg_color_item.
callback = [&show_custom_bg_color_editor]() {
506 show_custom_bg_color_editor =
true;
513 overlay_item.
callback = [&show_overlay_editor]() {
514 show_overlay_editor =
true;
522 reset_view_item.
callback = [&canvas]() {
530 zoom_in_item.
callback = [&canvas]() {
539 zoom_out_item.
callback = [&canvas]() {
552 ImGui::PushID(
"GraphicsPopup");
558 {{ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)},
559 {ImGuiStyleVar_FramePadding, ImVec2(padding, padding)}});
561 ImGui::Text(
"Graphics Settings");
567 ->mutable_area_graphics(),
576 (*maps_bmp_)[current_map].set_modified(
true);
588 HOVER_HINT(
"Main tileset graphics for this map area");
595 ->mutable_sprite_graphics(game_state),
601 HOVER_HINT(
"Sprite graphics sheet for current game state");
607 ->mutable_animated_gfx(),
614 HOVER_HINT(
"Animated tile graphics (water, lava, etc.)");
625 if (BeginTable(
"CustomTileGraphics", 2, ImGuiTableFlags_SizingFixedFit)) {
626 for (
int i = 0; i < 8; i++) {
628 std::string label = absl::StrFormat(
ICON_MD_LAYERS " Sheet %d", i);
631 ->mutable_custom_tileset(i),
638 if (ImGui::IsItemHovered()) {
639 ImGui::SetTooltip(
"Custom graphics sheet %d (0x00-0xFF)", i);
646 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
649 "Custom tile graphics require ZSCustomOverworld v1+.\n"
650 "Upgrade your ROM to access 8 customizable graphics sheets.");
658 bool& show_custom_bg_color_editor) {
662 ImGui::PushID(
"PalettesPopup");
668 {{ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)},
669 {ImGuiStyleVar_FramePadding, ImVec2(padding, padding)}});
671 ImGui::Text(
"Palette Settings");
677 ->mutable_area_palette(),
683 HOVER_HINT(
"Main color palette for background tiles");
691 ->mutable_main_palette(),
697 HOVER_HINT(
"Extended main palette (ZSCustomOverworld v2+)");
705 ->mutable_sprite_palette(game_state),
710 HOVER_HINT(
"Color palette for sprites in current game state");
715 show_custom_bg_color_editor = !show_custom_bg_color_editor;
717 HOVER_HINT(
"Open custom background color editor (v2+)");
724 bool& show_map_properties_panel,
725 bool& show_overlay_preview,
730 ImGui::PushID(
"ConfigPopup");
736 {{ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)},
737 {ImGuiStyleVar_FramePadding, ImVec2(padding, padding)}});
743 if (BeginTable(
"BasicProps", 2, ImGuiTableFlags_SizingFixedFit)) {
750 ->mutable_message_id(),
755 if (ImGui::IsItemHovered()) {
756 ImGui::SetTooltip(
"Message ID shown when entering this area");
768 if (ImGui::IsItemHovered()) {
770 "Affects sprite graphics/palettes based on story progress");
784 int current_area_size =
788 if (asm_version >= 3 && asm_version != 0xFF) {
799 HOVER_HINT(
"Map area size (1x1, 2x2, 2x1, 1x2 screens)");
802 const char* limited_names[] = {
"Small (1x1)",
"Large (2x2)"};
803 int limited_size = (current_area_size == 0 || current_area_size == 1)
817 HOVER_HINT(
"Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
832 show_map_properties_panel =
true;
833 ImGui::CloseCurrentPopup();
835 HOVER_HINT(
"Open detailed area configuration with all settings tabs");
843 if (BeginTable(
"BasicProperties", 2,
844 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
845 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
846 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
853 ->mutable_area_graphics(),
857 (*maps_bmp_)[current_map].set_modified(
true);
863 if (ImGui::IsItemHovered()) {
864 ImGui::SetTooltip(
"Main tileset graphics for this map area");
872 ->mutable_area_palette(),
878 if (ImGui::IsItemHovered()) {
879 ImGui::SetTooltip(
"Color palette for background tiles");
887 ->mutable_message_id(),
892 if (ImGui::IsItemHovered()) {
893 ImGui::SetTooltip(
"Message displayed when entering this area");
905 if (ImGui::IsItemHovered()) {
906 ImGui::SetTooltip(
"Enable pixelated mosaic transition effect");
915 ->mutable_area_music(0),
919 if (ImGui::IsItemHovered()) {
920 ImGui::SetTooltip(
"Music track before rescuing Zelda");
928 ->mutable_area_music(1),
932 if (ImGui::IsItemHovered()) {
933 ImGui::SetTooltip(
"Music track after rescuing Zelda");
941 ->mutable_area_music(2),
945 if (ImGui::IsItemHovered()) {
946 ImGui::SetTooltip(
"Music track after obtaining Master Sword");
954 ->mutable_area_music(3),
958 if (ImGui::IsItemHovered()) {
959 ImGui::SetTooltip(
"Music track after defeating Agahnim (Dark World)");
967 if (BeginTable(
"SpriteProperties", 2,
968 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
969 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
970 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
975 static int game_state = 0;
976 ImGui::SetNextItemWidth(120.f);
981 if (ImGui::IsItemHovered()) {
982 ImGui::SetTooltip(
"Affects which sprite graphics/palettes are used");
990 ->mutable_sprite_graphics(1),
995 if (ImGui::IsItemHovered()) {
996 ImGui::SetTooltip(
"First sprite graphics sheet for Zelda rescued state");
1004 ->mutable_sprite_graphics(2),
1009 if (ImGui::IsItemHovered()) {
1011 "Second sprite graphics sheet for Master Sword obtained state");
1019 ->mutable_sprite_palette(1),
1024 if (ImGui::IsItemHovered()) {
1025 ImGui::SetTooltip(
"Color palette for sprites - Zelda rescued state");
1033 ->mutable_sprite_palette(2),
1038 if (ImGui::IsItemHovered()) {
1040 "Color palette for sprites - Master Sword obtained state");
1048 if (BeginTable(
"CustomFeatures", 2,
1049 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1050 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
1051 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
1059 int current_area_size =
1061 ImGui::SetNextItemWidth(130.f);
1065 static const char* all_sizes[] = {
"Small (1x1)",
"Large (2x2)",
1066 "Wide (2x1)",
"Tall (1x2)"};
1067 if (ImGui::Combo(
"##AreaSize", ¤t_area_size, all_sizes, 4)) {
1075 if (ImGui::IsItemHovered()) {
1077 "Map size: Small (1x1), Large (2x2), Wide (2x1), Tall (1x2)");
1081 static const char* limited_sizes[] = {
"Small (1x1)",
"Large (2x2)"};
1082 int limited_size = (current_area_size == 0 || current_area_size == 1)
1086 if (ImGui::Combo(
"##AreaSize", &limited_size, limited_sizes, 2)) {
1095 if (ImGui::IsItemHovered()) {
1097 "Map size: Small (1x1), Large (2x2). Wide/Tall require v3+");
1102 rom_version_basic)) {
1108 ->mutable_main_palette(),
1114 if (ImGui::IsItemHovered()) {
1115 ImGui::SetTooltip(
"Extended main palette (ZSCustomOverworld v2+)");
1120 rom_version_basic)) {
1126 ->mutable_animated_gfx(),
1131 if (ImGui::IsItemHovered()) {
1132 ImGui::SetTooltip(
"Animated tile graphics ID (water, lava, etc.)");
1140 ->mutable_subscreen_overlay(),
1145 if (ImGui::IsItemHovered()) {
1146 ImGui::SetTooltip(
"Visual effects overlay ID (fog, rain, backgrounds)");
1162 if (BeginTable(
"TileGraphics", 2,
1163 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1164 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed,
1166 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
1168 for (
int i = 0; i < 8; i++) {
1174 ->mutable_custom_tileset(i),
1183 if (ImGui::IsItemHovered()) {
1184 ImGui::SetTooltip(
"Custom graphics sheet %d (0x00-0xFF)", i);
1193 "These 8 sheets allow custom tile graphics per map. "
1194 "Each sheet references a graphics ID loaded into VRAM.");
1197 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1201 "Custom tile graphics are not available in vanilla ROMs.\n\n"
1202 "To enable this feature, upgrade your ROM to ZSCustomOverworld v1+, "
1203 "which provides 8 customizable graphics sheets per map for advanced "
1204 "tileset customization.");
1212 if (BeginTable(
"MusicSettings", 2,
1213 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1214 ImGui::TableSetupColumn(
"Game State", ImGuiTableColumnFlags_WidthFixed,
1216 ImGui::TableSetupColumn(
"Music Track ID",
1217 ImGuiTableColumnFlags_WidthStretch);
1219 const char* music_state_names[] = {
1225 const char* music_descriptions[] = {
1226 "Music before rescuing Zelda from the castle",
1227 "Music after rescuing Zelda from Hyrule Castle",
1228 "Music after obtaining the Master Sword from the Lost Woods",
1229 "Music after defeating Agahnim (Dark World music)"};
1231 for (
int i = 0; i < 4; i++) {
1233 ImGui::Text(
"%s", music_state_names[i]);
1238 ->mutable_area_music(i),
1243 int music_address = 0;
1259 if (music_address > 0) {
1260 (*rom_)[music_address] =
1262 ->mutable_area_music(i);
1265 if (ImGui::IsItemHovered()) {
1266 ImGui::SetTooltip(
"%s", music_descriptions[i]);
1275 "Music tracks control the background music for different "
1276 "game progression states on this overworld map.");
1281 ImGuiTreeNodeFlags_DefaultOpen)) {
1283 ImGui::BulletText(
"0x02 - Overworld Theme");
1284 ImGui::BulletText(
"0x05 - Kakariko Village");
1285 ImGui::BulletText(
"0x07 - Lost Woods");
1286 ImGui::BulletText(
"0x09 - Dark World Theme");
1287 ImGui::BulletText(
"0x0F - Ganon's Tower");
1288 ImGui::BulletText(
"0x11 - Death Mountain");
1309 return absl::OkStatus();
1316 return absl::OkStatus();
1326 bool include_self) {
1337 int parent_id = map->parent();
1338 std::vector<int> siblings;
1340 switch (map->area_size()) {
1342 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1345 siblings = {parent_id, parent_id + 1};
1348 siblings = {parent_id, parent_id + 8};
1354 for (
int sibling : siblings) {
1357 if (sibling == map_index && !include_self) {
1362 (*maps_bmp_)[sibling].set_modified(
true);
1383 ImGui::Text(
"Mosaic Effects (per direction):");
1386 std::array<bool, 4> mosaic_expanded = current_map_ptr->mosaic_expanded();
1387 const char* direction_names[] = {
"North",
"South",
"East",
"West"};
1389 for (
int i = 0; i < 4; i++) {
1390 if (ImGui::Checkbox(direction_names[i], &mosaic_expanded[i])) {
1391 current_map_ptr->set_mosaic_expanded(i, mosaic_expanded[i]);
1397 if (ImGui::Checkbox(
1407 bool& show_overlay_preview) {
1411 bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
1413 if (is_special_overworld_map) {
1415 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
1416 ICON_MD_INFO " Special Area Map (0x%02X)", current_map);
1419 "This is a special area map (0x80-0x9F) used as a visual effect "
1420 "source. These maps provide the graphics data for subscreen overlays "
1421 "like fog, rain, forest canopy, and sky backgrounds that appear on "
1422 "normal maps (0x00-0x7F).");
1425 "You can edit the tile16 data here to customize how the visual effects "
1426 "appear when referenced by other maps.");
1432 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
1444 ImGui::Text(
ICON_MD_HELP " Understanding Overlay Types");
1447 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
ICON_MD_LAYERS
1448 " 1. Subscreen Overlays (Visual Effects)");
1450 ImGui::BulletText(
"Displayed as semi-transparent layers");
1451 ImGui::BulletText(
"Reference special area maps (0x80-0x9F)");
1452 ImGui::BulletText(
"Examples: fog, rain, forest canopy, sky");
1453 ImGui::BulletText(
"Purely visual - don't affect collision");
1457 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1460 ImGui::BulletText(
"Dynamic tile16 changes on the map");
1461 ImGui::BulletText(
"Used for bridges appearing, holes opening");
1462 ImGui::BulletText(
"Stored as tile16 ID arrays");
1463 ImGui::BulletText(
"Affect collision and interaction");
1464 ImGui::BulletText(
"Triggered by game events/progression");
1469 "Note: Subscreen overlays are what you configure here. "
1470 "Map overlays are event-driven and edited separately.");
1477 ImGui::Text(
ICON_MD_LAYERS " Subscreen Overlay (Visual Effects)");
1479 uint16_t current_overlay =
1484 ->set_subscreen_overlay(current_overlay);
1488 if (ImGui::IsItemHovered()) {
1490 "References a special area map (0x80-0x9F) for visual effects.\n"
1491 "The referenced map's tile16 data is drawn as a semi-transparent\n"
1492 "layer on top of or behind this area for atmospheric effects.");
1497 if (current_overlay == 0x00FF) {
1498 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
ICON_MD_CHECK " %s",
1499 overlay_desc.c_str());
1500 }
else if (current_overlay >= 0x80 && current_overlay < 0xA0) {
1501 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1504 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1511 &show_overlay_preview)) {
1514 if (ImGui::IsItemHovered()) {
1516 "Shows a semi-transparent preview of the visual effect overlay\n"
1517 "drawn on top of the current map in the editor canvas.\n\n"
1518 "This preview shows how the subscreen overlay will appear in-game.");
1525 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1534 if (ImGui::BeginPopup(
1538 ImGui::Text(
ICON_MD_HELP " Map Overlays (Interactive Tile Changes)");
1541 "Map overlays are different from visual effect overlays. "
1542 "They contain tile16 data that dynamically replaces tiles on "
1543 "the map based on game events or progression.");
1545 ImGui::Text(
"Common uses:");
1546 ImGui::BulletText(
"Bridges appearing over water");
1547 ImGui::BulletText(
"Holes revealing secret passages");
1548 ImGui::BulletText(
"Rocks/bushes being moved");
1549 ImGui::BulletText(
"Environmental changes from story events");
1552 "These are triggered by game code and stored as separate "
1553 "tile data arrays in the ROM. ZSCustomOverworld v3+ provides "
1554 "extended control over these features.");
1560 if (current_map_ptr->has_overlay()) {
1561 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1563 current_map_ptr->overlay_id());
1565 static_cast<int>(current_map_ptr->overlay_data().size()));
1566 ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.4f, 1.0f),
1569 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1577 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
1579 ImGui::BulletText(
"Visual effects use maps 0x80-0x9F");
1580 ImGui::BulletText(
"Map overlays are read-only");
1582 const char* version_name =
1584 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
ICON_MD_UPGRADE " %s",
1586 ImGui::BulletText(
"Enhanced visual effect control");
1588 ImGui::BulletText(
"Extended overlay system");
1589 ImGui::BulletText(
"Custom area sizes support");
1596 if (overlay_id == 0x0093) {
1597 return "Triforce Room Curtain";
1598 }
else if (overlay_id == 0x0094) {
1599 return "Under the Bridge";
1600 }
else if (overlay_id == 0x0095) {
1601 return "Sky Background (LW Death Mountain)";
1602 }
else if (overlay_id == 0x0096) {
1603 return "Pyramid Background";
1604 }
else if (overlay_id == 0x0097) {
1605 return "First Fog Overlay (Master Sword Area)";
1606 }
else if (overlay_id == 0x009C) {
1607 return "Lava Background (DW Death Mountain)";
1608 }
else if (overlay_id == 0x009D) {
1609 return "Second Fog Overlay (Lost Woods/Skull Woods)";
1610 }
else if (overlay_id == 0x009E) {
1611 return "Tree Canopy (Forest)";
1612 }
else if (overlay_id == 0x009F) {
1613 return "Rain Effect (Misery Mire)";
1614 }
else if (overlay_id == 0x00FF) {
1615 return "No Overlay";
1617 return "Custom overlay";
1623 bool show_overlay_preview) {
1630 uint16_t overlay_id = 0x00FF;
1631 bool has_subscreen_overlay =
false;
1633 bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
1635 if (is_special_overworld_map) {
1643 has_subscreen_overlay = (overlay_id != 0x00FF);
1645 if (!has_subscreen_overlay)
1649 int overlay_map_index = -1;
1650 if (overlay_id >= 0x80 && overlay_id < 0xA0) {
1651 overlay_map_index = overlay_id;
1658 const auto& overlay_bitmap = (*maps_bmp_)[overlay_map_index];
1659 if (!overlay_bitmap.is_active() || !overlay_bitmap.texture())
1663 int current_map_x = current_map % 8;
1664 int current_map_y = current_map / 8;
1665 if (current_world == 1) {
1666 current_map_x = (current_map - 0x40) % 8;
1667 current_map_y = (current_map - 0x40) / 8;
1668 }
else if (current_world == 2) {
1669 current_map_x = (current_map - 0x80) % 8;
1670 current_map_y = (current_map - 0x80) / 8;
1678 bool is_background_overlay =
1679 (overlay_id == 0x0095 || overlay_id == 0x0096 || overlay_id == 0x009C);
1682 ImU32 overlay_color =
1683 is_background_overlay ? IM_COL32(255, 255, 255, 128)
1685 IM_COL32(255, 255, 255,
1690 (ImTextureID)(intptr_t)overlay_bitmap.texture(), ImVec2(map_x, map_y),
1693 ImVec2(0, 0), ImVec2(1, 1), overlay_color);
1700 ImGui::PushID(
"ViewPopup");
1706 {{ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)},
1707 {ImGuiStyleVar_FramePadding, ImVec2(padding, padding)}});
1709 ImGui::Text(
"View Controls");
1741 ImGui::PushID(
"QuickPopup");
1747 {{ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)},
1748 {ImGuiStyleVar_FramePadding, ImVec2(padding, padding)}});
1750 ImGui::Text(
"Quick Access");
1772 HOVER_HINT(
"Lock/unlock current map (Ctrl+L)");
RefreshCallback refresh_overworld_map_
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp_
std::function< void()> edit_tile16_callback_
void RefreshMapProperties()
void SetupCanvasContextMenu(gui::Canvas &canvas, int current_map, bool current_map_lock, bool &show_map_properties_panel, bool &show_custom_bg_color_editor, bool &show_overlay_editor, int current_mode=0)
void DrawOverlayEditor(int current_map, bool &show_overlay_editor)
void DrawPropertiesPopup(int current_map, bool &show_map_properties_panel, bool &show_overlay_preview, int &game_state)
RefreshCallback refresh_map_properties_
void RefreshOverworldMap()
RefreshPaletteCallback refresh_tile16_blockset_
void DrawOverlayPreviewOnMap(int current_map, int current_world, bool show_overlay_preview)
void DrawMosaicControls(int current_map)
void DrawMapPropertiesPanel(int current_map, bool &show_map_properties_panel)
absl::Status RefreshTile16Blockset()
std::function< void(const std::string &) entity_insert_callback_)
void DrawSpritePropertiesTab(int current_map)
RefreshPaletteCallback refresh_map_palette_
void DrawMusicTab(int current_map)
void DrawBasicPropertiesTab(int current_map)
void DrawCustomFeaturesTab(int current_map)
void DrawPalettesPopup(int current_map, int game_state, bool &show_custom_bg_color_editor)
void DrawCustomBackgroundColorEditor(int current_map, bool &show_custom_bg_color_editor)
void DrawCanvasToolbar(int ¤t_world, int ¤t_map, bool ¤t_map_lock, bool &show_map_properties_panel, bool &show_custom_bg_color_editor, bool &show_overlay_editor, bool &show_overlay_preview, int &game_state, EditingMode ¤t_mode, EntityEditMode &entity_edit_mode)
zelda3::Overworld * overworld_
void ForceRefreshGraphics(int map_index)
void RefreshSiblingMapGraphics(int map_index, bool include_self=false)
void DrawTileGraphicsTab(int current_map)
ForceRefreshGraphicsCallback force_refresh_graphics_
void DrawQuickAccessPopup()
std::string GetOverlayDescription(uint16_t overlay_id)
void DrawOverlayControls(int current_map, bool &show_overlay_preview)
absl::Status RefreshMapPalette()
void DrawGraphicsPopup(int current_map, int game_state)
RAII timer for automatic timing management.
constexpr uint16_t snes() const
Get SNES 15-bit color.
Modern, robust canvas for drawing and manipulating graphics.
void set_scrolling(ImVec2 scroll)
auto global_scale() const
void SetUsageMode(CanvasUsage usage)
void ClearContextMenuItems()
void AddContextMenuItem(const gui::CanvasMenuItem &item)
void set_global_scale(float scale)
static float GetButtonPadding()
static float GetStandardSpacing()
RAII guard for ImGui style vars.
static bool SupportsCustomBGColors(OverworldVersion version)
Check if ROM supports custom background colors per area (v2+)
static OverworldVersion GetVersion(const Rom &rom)
Detect ROM version from ASM marker byte.
static bool SupportsAreaEnum(OverworldVersion version)
Check if ROM supports area enum system (v3+ only)
static bool SupportsAnimatedGFX(OverworldVersion version)
Check if ROM supports animated GFX selection (v3+)
static bool SupportsExpandedSpace(OverworldVersion version)
Check if ROM uses expanded ROM space for overworld data.
static const char * GetVersionName(OverworldVersion version)
Get human-readable version name for display/logging.
auto overworld_map(int i) const
auto mutable_overworld_map(int i)
absl::Status ConfigureMultiAreaMap(int parent_index, AreaSizeEnum size)
Configure a multi-area map structure (Large/Wide/Tall)
#define ICON_MD_GRID_VIEW
#define ICON_MD_LOCK_OPEN
#define ICON_MD_LIGHTBULB
#define ICON_MD_PHOTO_SIZE_SELECT_LARGE
#define ICON_MD_OFFLINE_BOLT
#define ICON_MD_PLAY_ARROW
#define ICON_MD_OPEN_IN_FULL
#define ICON_MD_VISIBILITY
#define ICON_MD_FORMAT_COLOR_FILL
#define ICON_MD_DOOR_BACK
#define ICON_MD_AUTO_FIX_HIGH
#define ICON_MD_MUSIC_NOTE
#define ICON_MD_ASPECT_RATIO
#define ICON_MD_ANIMATION
#define ICON_MD_DOOR_FRONT
#define ICON_MD_HELP_OUTLINE
#define ICON_MD_ADD_LOCATION
#define ICON_MD_EDIT_NOTE
#define ICON_MD_OPEN_IN_NEW
#define ICON_MD_PEST_CONTROL_RODENT
#define ICON_MD_CONTENT_COPY
#define ICON_MD_COLOR_LENS
#define HOVER_HINT(string)
constexpr const char * kAreaSizeNames[]
constexpr unsigned int kOverworldMapSize
constexpr float kOverworldMaxZoom
constexpr float kTableColumnWorld
constexpr float kOverworldMinZoom
constexpr const char * kWorldNames[]
constexpr float kHexByteInputWidth
constexpr float kComboWorldWidth
constexpr float kTableColumnMap
constexpr float kTableColumnAreaSize
constexpr float kOverworldZoomStep
constexpr float kComboGameStateWidth
constexpr float kInputFieldSize
constexpr const char * kGameStateNames[]
constexpr float kIconButtonWidth
constexpr float kHexWordInputWidth
constexpr float kComboAreaSizeWidth
constexpr float kTableColumnLock
constexpr const char * kOverworld
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)
bool BeginThemedTabBar(const char *id, ImGuiTabBarFlags flags)
A stylized tab bar with "Mission Control" branding.
bool ToggleButton(const char *label, bool active, const ImVec2 &size)
ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor &color)
Convert SnesColor to standard ImVec4 for display.
bool InputHexWordCustom(const char *label, uint16_t *data, float input_width)
std::string MakePopupId(size_t session_id, const std::string &editor_name, const std::string &popup_name)
Generate session-aware popup IDs to prevent conflicts in multi-editor layouts.
gfx::SnesColor ConvertImVec4ToSnesColor(const ImVec4 &color)
Convert standard ImVec4 to SnesColor.
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
constexpr int OverworldCustomAreaSpecificBGEnabled
constexpr int kNumOverworldMaps
constexpr int kOverworldMusicBeginning
AreaSizeEnum
Area size enumeration for v3+ ROMs.
constexpr int OverworldCustomASMHasBeenApplied
constexpr int kOverworldMusicAgahnim
@ kVanilla
0xFF in ROM, no ZScream ASM applied
constexpr int kOverworldMusicMasterSword
constexpr int kOverworldMusicZelda
constexpr int OverworldCustomSubscreenOverlayEnabled
constexpr int OverworldCustomAreaSpecificBGPalette
constexpr int OverworldCustomSubscreenOverlayArray
SNES color in 15-bit RGB format (BGR555)
struct snes_color snes_color
SNES color in 15-bit RGB format (BGR555)