3#include "absl/strings/str_format.h"
14#include "imgui/imgui.h"
21using ImGui::BeginTable;
23using ImGui::Separator;
24using ImGui::TableNextColumn;
30 int& current_world,
int& current_map,
bool& current_map_lock,
31 bool& show_map_properties_panel,
bool& show_custom_bg_color_editor,
32 bool& show_overlay_editor,
bool& show_overlay_preview,
int& game_state,
34 (void)show_overlay_editor;
35 (void)show_custom_bg_color_editor;
37 (void)show_overlay_preview;
40 if (BeginTable(
"CanvasToolbar", 7,
41 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit,
43 ImGui::TableSetupColumn(
"World", ImGuiTableColumnFlags_WidthFixed,
45 ImGui::TableSetupColumn(
"Map", ImGuiTableColumnFlags_WidthFixed,
47 ImGui::TableSetupColumn(
"Area Size", ImGuiTableColumnFlags_WidthFixed,
49 ImGui::TableSetupColumn(
"Lock", ImGuiTableColumnFlags_WidthFixed,
51 ImGui::TableSetupColumn(
"Mode", ImGuiTableColumnFlags_WidthFixed,
53 ImGui::TableSetupColumn(
54 "Entity", ImGuiTableColumnFlags_WidthStretch);
55 ImGui::TableSetupColumn(
"Sidebar", ImGuiTableColumnFlags_WidthFixed, 40.0f);
59 ImGui::Combo(
"##world", ¤t_world,
kWorldNames, 3);
62 ImGui::Text(
"%d (0x%02X)", current_map, current_map);
69 int current_area_size =
75 if (ImGui::Combo(
"##AreaSize", ¤t_area_size,
kAreaSizeNames, 4)) {
85 const char* limited_names[] = {
"Small (1x1)",
"Large (2x2)"};
86 int limited_size = (current_area_size == 0 || current_area_size == 1)
90 if (ImGui::Combo(
"##AreaSize", &limited_size, limited_names, 2)) {
103 HOVER_HINT(
"Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
110 current_map_lock = !current_map_lock;
112 HOVER_HINT(current_map_lock ?
"Unlock Map" :
"Lock Map");
116 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
122 HOVER_HINT(
"Mouse Mode (1)\nNavigate, pan, and manage entities");
130 HOVER_HINT(
"Tile Paint Mode (2)\nDraw tiles on the map");
131 ImGui::PopStyleVar();
136 const char* entity_icon =
"";
137 const char* entity_label =
"";
138 switch (entity_edit_mode) {
141 entity_label =
"Entrances";
145 entity_label =
"Exits";
149 entity_label =
"Items";
153 entity_label =
"Sprites";
157 entity_label =
"Transports";
161 entity_label =
"Music";
166 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
"%s %s", entity_icon,
173 show_map_properties_panel = !show_map_properties_panel;
182 int current_map,
bool& show_map_properties_panel) {
183 (void)show_map_properties_panel;
185 Text(
"No overworld loaded");
191 Text(
"Current Map: %d (0x%02X)", current_map, current_map);
197 if (ImGui::BeginTabBar(
"MapPropertiesTabs",
198 ImGuiTabBarFlags_FittingPolicyScroll)) {
200 if (ImGui::BeginTabItem(
"Basic Properties")) {
206 if (ImGui::BeginTabItem(
"Sprite Properties")) {
214 ImGui::BeginTabItem(
"Custom Features")) {
220 if (ImGui::BeginTabItem(
"Tile Graphics")) {
226 if (ImGui::BeginTabItem(
"Music")) {
236 int current_map,
bool& show_custom_bg_color_editor) {
237 (void)show_custom_bg_color_editor;
239 Text(
"No overworld loaded");
245 Text(
"Custom background colors require ZSCustomOverworld v2+");
249 Text(
"Custom Background Color Editor");
253 bool use_area_specific_bg_color =
255 if (ImGui::Checkbox(
"Use Area-Specific Background Color",
256 &use_area_specific_bg_color)) {
259 use_area_specific_bg_color ? 0x01 : 0x00;
262 if (use_area_specific_bg_color) {
264 uint16_t current_color =
271 if (ImGui::ColorPicker4(
272 "Background Color", (
float*)&color_vec,
273 ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHex)) {
277 ->set_area_specific_bg_color(new_snes_color.
snes());
282 (*rom_)[rom_address] = new_snes_color.
snes() & 0xFF;
283 (*rom_)[rom_address + 1] = (new_snes_color.
snes() >> 8) & 0xFF;
286 Text(
"SNES Color: 0x%04X", current_color);
291 bool& show_overlay_editor) {
292 (void)show_overlay_editor;
294 Text(
"No overworld loaded");
300 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
302 ImGui::Text(
"Map: 0x%02X", current_map);
308 " Enhanced overlay editing requires ZSCustomOverworld v1+");
311 "Subscreen overlays are a vanilla feature used for atmospheric effects "
312 "like fog, rain, and forest canopy. ZSCustomOverworld expands this by "
313 "allowing per-area overlay configuration and additional "
320 ImGuiTreeNodeFlags_DefaultOpen)) {
323 "Visual effects (subscreen overlays) are semi-transparent layers drawn "
324 "on top of or behind your map. They reference special area maps "
326 "for their tile16 graphics data.");
328 ImGui::Text(
"Common uses:");
329 ImGui::BulletText(
"Fog effects (Lost Woods, Skull Woods)");
330 ImGui::BulletText(
"Rain (Misery Mire)");
331 ImGui::BulletText(
"Forest canopy (Lost Woods)");
332 ImGui::BulletText(
"Sky backgrounds (Death Mountain)");
333 ImGui::BulletText(
"Under bridge views");
339 bool use_subscreen_overlay =
342 &use_subscreen_overlay)) {
345 use_subscreen_overlay ? 0x01 : 0x00;
347 if (ImGui::IsItemHovered()) {
348 ImGui::SetTooltip(
"Enable/disable visual effect overlay for this map area");
351 if (use_subscreen_overlay) {
353 uint16_t current_overlay =
358 ->set_subscreen_overlay(current_overlay);
363 (*rom_)[rom_address] = current_overlay & 0xFF;
364 (*rom_)[rom_address + 1] = (current_overlay >> 8) & 0xFF;
366 if (ImGui::IsItemHovered()) {
368 "ID of the special area map (0x80-0x9F) to use for\n"
369 "visual effects. That map's tile16 data will be drawn\n"
370 "as a semi-transparent layer on this area.");
375 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
ICON_MD_INFO " %s",
376 overlay_desc.c_str());
380 " Common Visual Effect IDs")) {
382 ImGui::BulletText(
"0x0093 - Triforce Room Curtain");
383 ImGui::BulletText(
"0x0094 - Under the Bridge");
384 ImGui::BulletText(
"0x0095 - Sky Background (LW Death Mountain)");
385 ImGui::BulletText(
"0x0096 - Pyramid Background");
386 ImGui::BulletText(
"0x0097 - Fog Overlay (Master Sword Area)");
387 ImGui::BulletText(
"0x009C - Lava Background (DW Death Mountain)");
388 ImGui::BulletText(
"0x009D - Fog Overlay (Lost/Skull Woods)");
389 ImGui::BulletText(
"0x009E - Tree Canopy (Forest)");
390 ImGui::BulletText(
"0x009F - Rain Effect (Misery Mire)");
391 ImGui::BulletText(
"0x00FF - No Overlay (Disabled)");
396 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
ICON_MD_BLOCK
397 " No visual effects enabled for this area");
402 gui::Canvas& canvas,
int current_map,
bool current_map_lock,
403 bool& show_map_properties_panel,
bool& show_custom_bg_color_editor,
404 bool& show_overlay_editor,
int current_mode) {
422 entity_menu.
subitems.push_back(entrance_item);
432 entity_menu.
subitems.push_back(hole_item);
442 entity_menu.
subitems.push_back(exit_item);
452 entity_menu.
subitems.push_back(item_item);
462 entity_menu.
subitems.push_back(sprite_item);
470 tile16_edit_item.
callback = [
this]() {
481 lock_item.
label = current_map_lock ?
"Unlock Map" :
"Lock to This Map";
482 lock_item.
callback = [¤t_map_lock]() {
483 current_map_lock = !current_map_lock;
490 properties_item.
callback = [&show_map_properties_panel]() {
491 show_map_properties_panel =
true;
501 bg_color_item.
callback = [&show_custom_bg_color_editor]() {
502 show_custom_bg_color_editor =
true;
509 overlay_item.
callback = [&show_overlay_editor]() {
510 show_overlay_editor =
true;
518 reset_view_item.
callback = [&canvas]() {
526 zoom_in_item.
callback = [&canvas]() {
535 zoom_out_item.
callback = [&canvas]() {
548 ImGui::PushID(
"GraphicsPopup");
553 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
554 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
556 ImGui::Text(
"Graphics Settings");
562 ->mutable_area_graphics(),
571 (*maps_bmp_)[current_map].set_modified(
true);
583 HOVER_HINT(
"Main tileset graphics for this map area");
590 ->mutable_sprite_graphics(game_state),
596 HOVER_HINT(
"Sprite graphics sheet for current game state");
602 ->mutable_animated_gfx(),
609 HOVER_HINT(
"Animated tile graphics (water, lava, etc.)");
620 if (BeginTable(
"CustomTileGraphics", 2, ImGuiTableFlags_SizingFixedFit)) {
621 for (
int i = 0; i < 8; i++) {
623 std::string label = absl::StrFormat(
ICON_MD_LAYERS " Sheet %d", i);
626 ->mutable_custom_tileset(i),
633 if (ImGui::IsItemHovered()) {
634 ImGui::SetTooltip(
"Custom graphics sheet %d (0x00-0xFF)", i);
641 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
644 "Custom tile graphics require ZSCustomOverworld v1+.\n"
645 "Upgrade your ROM to access 8 customizable graphics sheets.");
648 ImGui::PopStyleVar(2);
655 bool& show_custom_bg_color_editor) {
659 ImGui::PushID(
"PalettesPopup");
664 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
665 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
667 ImGui::Text(
"Palette Settings");
673 ->mutable_area_palette(),
679 HOVER_HINT(
"Main color palette for background tiles");
687 ->mutable_main_palette(),
693 HOVER_HINT(
"Extended main palette (ZSCustomOverworld v2+)");
701 ->mutable_sprite_palette(game_state),
706 HOVER_HINT(
"Color palette for sprites in current game state");
711 show_custom_bg_color_editor = !show_custom_bg_color_editor;
713 HOVER_HINT(
"Open custom background color editor (v2+)");
715 ImGui::PopStyleVar(2);
722 bool& show_map_properties_panel,
723 bool& show_overlay_preview,
728 ImGui::PushID(
"ConfigPopup");
733 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
734 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
740 if (BeginTable(
"BasicProps", 2, ImGuiTableFlags_SizingFixedFit)) {
747 ->mutable_message_id(),
752 if (ImGui::IsItemHovered()) {
753 ImGui::SetTooltip(
"Message ID shown when entering this area");
765 if (ImGui::IsItemHovered()) {
767 "Affects sprite graphics/palettes based on story progress");
781 int current_area_size =
785 if (asm_version >= 3 && asm_version != 0xFF) {
796 HOVER_HINT(
"Map area size (1x1, 2x2, 2x1, 1x2 screens)");
799 const char* limited_names[] = {
"Small (1x1)",
"Large (2x2)"};
800 int limited_size = (current_area_size == 0 || current_area_size == 1)
814 HOVER_HINT(
"Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
829 show_map_properties_panel =
true;
830 ImGui::CloseCurrentPopup();
832 HOVER_HINT(
"Open detailed area configuration with all settings tabs");
834 ImGui::PopStyleVar(2);
841 if (BeginTable(
"BasicProperties", 2,
842 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
843 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
844 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
851 ->mutable_area_graphics(),
855 (*maps_bmp_)[current_map].set_modified(
true);
861 if (ImGui::IsItemHovered()) {
862 ImGui::SetTooltip(
"Main tileset graphics for this map area");
870 ->mutable_area_palette(),
876 if (ImGui::IsItemHovered()) {
877 ImGui::SetTooltip(
"Color palette for background tiles");
885 ->mutable_message_id(),
890 if (ImGui::IsItemHovered()) {
891 ImGui::SetTooltip(
"Message displayed when entering this area");
903 if (ImGui::IsItemHovered()) {
904 ImGui::SetTooltip(
"Enable pixelated mosaic transition effect");
913 ->mutable_area_music(0),
917 if (ImGui::IsItemHovered()) {
918 ImGui::SetTooltip(
"Music track before rescuing Zelda");
926 ->mutable_area_music(1),
930 if (ImGui::IsItemHovered()) {
931 ImGui::SetTooltip(
"Music track after rescuing Zelda");
939 ->mutable_area_music(2),
943 if (ImGui::IsItemHovered()) {
944 ImGui::SetTooltip(
"Music track after obtaining Master Sword");
952 ->mutable_area_music(3),
956 if (ImGui::IsItemHovered()) {
957 ImGui::SetTooltip(
"Music track after defeating Agahnim (Dark World)");
965 if (BeginTable(
"SpriteProperties", 2,
966 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
967 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
968 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
973 static int game_state = 0;
974 ImGui::SetNextItemWidth(120.f);
979 if (ImGui::IsItemHovered()) {
980 ImGui::SetTooltip(
"Affects which sprite graphics/palettes are used");
988 ->mutable_sprite_graphics(1),
993 if (ImGui::IsItemHovered()) {
994 ImGui::SetTooltip(
"First sprite graphics sheet for Zelda rescued state");
1002 ->mutable_sprite_graphics(2),
1007 if (ImGui::IsItemHovered()) {
1009 "Second sprite graphics sheet for Master Sword obtained state");
1017 ->mutable_sprite_palette(1),
1022 if (ImGui::IsItemHovered()) {
1023 ImGui::SetTooltip(
"Color palette for sprites - Zelda rescued state");
1031 ->mutable_sprite_palette(2),
1036 if (ImGui::IsItemHovered()) {
1038 "Color palette for sprites - Master Sword obtained state");
1046 if (BeginTable(
"CustomFeatures", 2,
1047 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1048 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
1049 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
1057 int current_area_size =
1059 ImGui::SetNextItemWidth(130.f);
1063 static const char* all_sizes[] = {
"Small (1x1)",
"Large (2x2)",
1064 "Wide (2x1)",
"Tall (1x2)"};
1065 if (ImGui::Combo(
"##AreaSize", ¤t_area_size, all_sizes, 4)) {
1073 if (ImGui::IsItemHovered()) {
1075 "Map size: Small (1x1), Large (2x2), Wide (2x1), Tall (1x2)");
1079 static const char* limited_sizes[] = {
"Small (1x1)",
"Large (2x2)"};
1080 int limited_size = (current_area_size == 0 || current_area_size == 1)
1084 if (ImGui::Combo(
"##AreaSize", &limited_size, limited_sizes, 2)) {
1093 if (ImGui::IsItemHovered()) {
1095 "Map size: Small (1x1), Large (2x2). Wide/Tall require v3+");
1100 rom_version_basic)) {
1106 ->mutable_main_palette(),
1112 if (ImGui::IsItemHovered()) {
1113 ImGui::SetTooltip(
"Extended main palette (ZSCustomOverworld v2+)");
1118 rom_version_basic)) {
1124 ->mutable_animated_gfx(),
1129 if (ImGui::IsItemHovered()) {
1130 ImGui::SetTooltip(
"Animated tile graphics ID (water, lava, etc.)");
1138 ->mutable_subscreen_overlay(),
1143 if (ImGui::IsItemHovered()) {
1144 ImGui::SetTooltip(
"Visual effects overlay ID (fog, rain, backgrounds)");
1160 if (BeginTable(
"TileGraphics", 2,
1161 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1162 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed,
1164 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
1166 for (
int i = 0; i < 8; i++) {
1172 ->mutable_custom_tileset(i),
1181 if (ImGui::IsItemHovered()) {
1182 ImGui::SetTooltip(
"Custom graphics sheet %d (0x00-0xFF)", i);
1191 "These 8 sheets allow custom tile graphics per map. "
1192 "Each sheet references a graphics ID loaded into VRAM.");
1195 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1199 "Custom tile graphics are not available in vanilla ROMs.\n\n"
1200 "To enable this feature, upgrade your ROM to ZSCustomOverworld v1+, "
1201 "which provides 8 customizable graphics sheets per map for advanced "
1202 "tileset customization.");
1210 if (BeginTable(
"MusicSettings", 2,
1211 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1212 ImGui::TableSetupColumn(
"Game State", ImGuiTableColumnFlags_WidthFixed,
1214 ImGui::TableSetupColumn(
"Music Track ID",
1215 ImGuiTableColumnFlags_WidthStretch);
1217 const char* music_state_names[] = {
1223 const char* music_descriptions[] = {
1224 "Music before rescuing Zelda from the castle",
1225 "Music after rescuing Zelda from Hyrule Castle",
1226 "Music after obtaining the Master Sword from the Lost Woods",
1227 "Music after defeating Agahnim (Dark World music)"};
1229 for (
int i = 0; i < 4; i++) {
1231 ImGui::Text(
"%s", music_state_names[i]);
1236 ->mutable_area_music(i),
1241 int music_address = 0;
1257 if (music_address > 0) {
1258 (*rom_)[music_address] =
1260 ->mutable_area_music(i);
1263 if (ImGui::IsItemHovered()) {
1264 ImGui::SetTooltip(
"%s", music_descriptions[i]);
1273 "Music tracks control the background music for different "
1274 "game progression states on this overworld map.");
1279 ImGuiTreeNodeFlags_DefaultOpen)) {
1281 ImGui::BulletText(
"0x02 - Overworld Theme");
1282 ImGui::BulletText(
"0x05 - Kakariko Village");
1283 ImGui::BulletText(
"0x07 - Lost Woods");
1284 ImGui::BulletText(
"0x09 - Dark World Theme");
1285 ImGui::BulletText(
"0x0F - Ganon's Tower");
1286 ImGui::BulletText(
"0x11 - Death Mountain");
1307 return absl::OkStatus();
1314 return absl::OkStatus();
1324 bool include_self) {
1335 int parent_id = map->parent();
1336 std::vector<int> siblings;
1338 switch (map->area_size()) {
1340 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1343 siblings = {parent_id, parent_id + 1};
1346 siblings = {parent_id, parent_id + 8};
1352 for (
int sibling : siblings) {
1355 if (sibling == map_index && !include_self) {
1360 (*maps_bmp_)[sibling].set_modified(
true);
1381 ImGui::Text(
"Mosaic Effects (per direction):");
1384 std::array<bool, 4> mosaic_expanded = current_map_ptr->mosaic_expanded();
1385 const char* direction_names[] = {
"North",
"South",
"East",
"West"};
1387 for (
int i = 0; i < 4; i++) {
1388 if (ImGui::Checkbox(direction_names[i], &mosaic_expanded[i])) {
1389 current_map_ptr->set_mosaic_expanded(i, mosaic_expanded[i]);
1395 if (ImGui::Checkbox(
1405 bool& show_overlay_preview) {
1409 bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
1411 if (is_special_overworld_map) {
1413 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
1414 ICON_MD_INFO " Special Area Map (0x%02X)", current_map);
1417 "This is a special area map (0x80-0x9F) used as a visual effect "
1418 "source. These maps provide the graphics data for subscreen overlays "
1419 "like fog, rain, forest canopy, and sky backgrounds that appear on "
1420 "normal maps (0x00-0x7F).");
1423 "You can edit the tile16 data here to customize how the visual effects "
1424 "appear when referenced by other maps.");
1430 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
1442 ImGui::Text(
ICON_MD_HELP " Understanding Overlay Types");
1445 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
ICON_MD_LAYERS
1446 " 1. Subscreen Overlays (Visual Effects)");
1448 ImGui::BulletText(
"Displayed as semi-transparent layers");
1449 ImGui::BulletText(
"Reference special area maps (0x80-0x9F)");
1450 ImGui::BulletText(
"Examples: fog, rain, forest canopy, sky");
1451 ImGui::BulletText(
"Purely visual - don't affect collision");
1455 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1458 ImGui::BulletText(
"Dynamic tile16 changes on the map");
1459 ImGui::BulletText(
"Used for bridges appearing, holes opening");
1460 ImGui::BulletText(
"Stored as tile16 ID arrays");
1461 ImGui::BulletText(
"Affect collision and interaction");
1462 ImGui::BulletText(
"Triggered by game events/progression");
1467 "Note: Subscreen overlays are what you configure here. "
1468 "Map overlays are event-driven and edited separately.");
1475 ImGui::Text(
ICON_MD_LAYERS " Subscreen Overlay (Visual Effects)");
1477 uint16_t current_overlay =
1482 ->set_subscreen_overlay(current_overlay);
1486 if (ImGui::IsItemHovered()) {
1488 "References a special area map (0x80-0x9F) for visual effects.\n"
1489 "The referenced map's tile16 data is drawn as a semi-transparent\n"
1490 "layer on top of or behind this area for atmospheric effects.");
1495 if (current_overlay == 0x00FF) {
1496 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
ICON_MD_CHECK " %s",
1497 overlay_desc.c_str());
1498 }
else if (current_overlay >= 0x80 && current_overlay < 0xA0) {
1499 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1502 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1509 &show_overlay_preview)) {
1512 if (ImGui::IsItemHovered()) {
1514 "Shows a semi-transparent preview of the visual effect overlay\n"
1515 "drawn on top of the current map in the editor canvas.\n\n"
1516 "This preview shows how the subscreen overlay will appear in-game.");
1523 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1532 if (ImGui::BeginPopup(
1536 ImGui::Text(
ICON_MD_HELP " Map Overlays (Interactive Tile Changes)");
1539 "Map overlays are different from visual effect overlays. "
1540 "They contain tile16 data that dynamically replaces tiles on "
1541 "the map based on game events or progression.");
1543 ImGui::Text(
"Common uses:");
1544 ImGui::BulletText(
"Bridges appearing over water");
1545 ImGui::BulletText(
"Holes revealing secret passages");
1546 ImGui::BulletText(
"Rocks/bushes being moved");
1547 ImGui::BulletText(
"Environmental changes from story events");
1550 "These are triggered by game code and stored as separate "
1551 "tile data arrays in the ROM. ZSCustomOverworld v3+ provides "
1552 "extended control over these features.");
1558 if (current_map_ptr->has_overlay()) {
1559 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1561 current_map_ptr->overlay_id());
1563 static_cast<int>(current_map_ptr->overlay_data().size()));
1564 ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.4f, 1.0f),
1567 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1575 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
1577 ImGui::BulletText(
"Visual effects use maps 0x80-0x9F");
1578 ImGui::BulletText(
"Map overlays are read-only");
1580 const char* version_name =
1582 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
ICON_MD_UPGRADE " %s",
1584 ImGui::BulletText(
"Enhanced visual effect control");
1586 ImGui::BulletText(
"Extended overlay system");
1587 ImGui::BulletText(
"Custom area sizes support");
1594 if (overlay_id == 0x0093) {
1595 return "Triforce Room Curtain";
1596 }
else if (overlay_id == 0x0094) {
1597 return "Under the Bridge";
1598 }
else if (overlay_id == 0x0095) {
1599 return "Sky Background (LW Death Mountain)";
1600 }
else if (overlay_id == 0x0096) {
1601 return "Pyramid Background";
1602 }
else if (overlay_id == 0x0097) {
1603 return "First Fog Overlay (Master Sword Area)";
1604 }
else if (overlay_id == 0x009C) {
1605 return "Lava Background (DW Death Mountain)";
1606 }
else if (overlay_id == 0x009D) {
1607 return "Second Fog Overlay (Lost Woods/Skull Woods)";
1608 }
else if (overlay_id == 0x009E) {
1609 return "Tree Canopy (Forest)";
1610 }
else if (overlay_id == 0x009F) {
1611 return "Rain Effect (Misery Mire)";
1612 }
else if (overlay_id == 0x00FF) {
1613 return "No Overlay";
1615 return "Custom overlay";
1621 bool show_overlay_preview) {
1628 uint16_t overlay_id = 0x00FF;
1629 bool has_subscreen_overlay =
false;
1631 bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
1633 if (is_special_overworld_map) {
1641 has_subscreen_overlay = (overlay_id != 0x00FF);
1643 if (!has_subscreen_overlay)
1647 int overlay_map_index = -1;
1648 if (overlay_id >= 0x80 && overlay_id < 0xA0) {
1649 overlay_map_index = overlay_id;
1656 const auto& overlay_bitmap = (*maps_bmp_)[overlay_map_index];
1657 if (!overlay_bitmap.is_active() || !overlay_bitmap.texture())
1661 int current_map_x = current_map % 8;
1662 int current_map_y = current_map / 8;
1663 if (current_world == 1) {
1664 current_map_x = (current_map - 0x40) % 8;
1665 current_map_y = (current_map - 0x40) / 8;
1666 }
else if (current_world == 2) {
1667 current_map_x = (current_map - 0x80) % 8;
1668 current_map_y = (current_map - 0x80) / 8;
1676 bool is_background_overlay =
1677 (overlay_id == 0x0095 || overlay_id == 0x0096 || overlay_id == 0x009C);
1680 ImU32 overlay_color =
1681 is_background_overlay ? IM_COL32(255, 255, 255, 128)
1683 IM_COL32(255, 255, 255,
1688 (ImTextureID)(intptr_t)overlay_bitmap.texture(), ImVec2(map_x, map_y),
1691 ImVec2(0, 0), ImVec2(1, 1), overlay_color);
1698 ImGui::PushID(
"ViewPopup");
1703 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
1704 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
1706 ImGui::Text(
"View Controls");
1729 ImGui::PopStyleVar(2);
1739 ImGui::PushID(
"QuickPopup");
1744 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
1745 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
1747 ImGui::Text(
"Quick Access");
1769 HOVER_HINT(
"Lock/unlock current map (Ctrl+L)");
1771 ImGui::PopStyleVar(2);
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()
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)
struct snes_color snes_color
SNES color in 15-bit RGB format (BGR555)
#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 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)