11#include "imgui/imgui.h"
16using ImGui::BeginTable;
18using ImGui::Separator;
19using ImGui::TableNextColumn;
25 int& current_world,
int& current_map,
bool& current_map_lock,
26 bool& show_map_properties_panel,
bool& show_custom_bg_color_editor,
27 bool& show_overlay_editor,
bool& show_overlay_preview,
int& game_state,
29 (void)show_overlay_editor;
32 if (BeginTable(
"SimplifiedMapSettings", 9,
33 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit,
35 ImGui::TableSetupColumn(
"World", ImGuiTableColumnFlags_WidthFixed,
37 ImGui::TableSetupColumn(
"Map", ImGuiTableColumnFlags_WidthFixed,
39 ImGui::TableSetupColumn(
"Area Size", ImGuiTableColumnFlags_WidthFixed,
41 ImGui::TableSetupColumn(
"Lock", ImGuiTableColumnFlags_WidthFixed,
43 ImGui::TableSetupColumn(
"Graphics", ImGuiTableColumnFlags_WidthFixed,
45 ImGui::TableSetupColumn(
"Palettes", ImGuiTableColumnFlags_WidthFixed,
47 ImGui::TableSetupColumn(
"Properties", ImGuiTableColumnFlags_WidthFixed,
49 ImGui::TableSetupColumn(
"View", ImGuiTableColumnFlags_WidthFixed,
51 ImGui::TableSetupColumn(
"Quick", ImGuiTableColumnFlags_WidthFixed,
56 ImGui::Combo(
"##world", ¤t_world,
kWorldNames, 3);
59 ImGui::Text(
"%d (0x%02X)", current_map, current_map);
66 int current_area_size =
70 if (asm_version >= 3 && asm_version != 0xFF) {
72 if (ImGui::Combo(
"##AreaSize", ¤t_area_size,
kAreaSizeNames, 4)) {
83 const char* limited_names[] = {
"Small (1x1)",
"Large (2x2)"};
84 int limited_size = (current_area_size == 0 || current_area_size == 1) ? current_area_size : 0;
86 if (ImGui::Combo(
"##AreaSize", &limited_size, limited_names, 2)) {
97 if (asm_version == 0xFF || asm_version < 3) {
98 HOVER_HINT(
"Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
105 current_map_lock = !current_map_lock;
107 HOVER_HINT(current_map_lock ?
"Unlock Map" :
"Lock Map");
111 ImGui::OpenPopup(
"GraphicsPopup");
113 if (ImGui::IsItemHovered()) {
115 "Graphics Settings\n\n"
117 " • Area graphics (tileset)\n"
118 " • Sprite graphics sheets\n"
119 " • Animated graphics (v3+)\n"
120 " • Custom tile16 sheets (8 slots)");
126 ImGui::OpenPopup(
"PalettesPopup");
128 if (ImGui::IsItemHovered()) {
130 "Palette Settings\n\n"
132 " • Area palette (background colors)\n"
133 " • Main palette (v2+)\n"
134 " • Sprite palettes\n"
135 " • Custom background colors");
141 ImGui::OpenPopup(
"ConfigPopup");
143 if (ImGui::IsItemHovered()) {
145 "Area Configuration\n\n"
148 " • Game state settings\n"
149 " • Area size (v3+)\n"
150 " • Mosaic effects\n"
151 " • Visual effect overlays\n"
152 " • Map overlay info\n\n"
153 "Click 'Full Configuration Panel' for\n"
154 "comprehensive editing with all tabs.");
157 show_overlay_preview, game_state);
162 ImGui::OpenPopup(
"ViewPopup");
164 if (ImGui::IsItemHovered()) {
169 " • Toggle fullscreen\n"
177 ImGui::OpenPopup(
"QuickPopup");
179 if (ImGui::IsItemHovered()) {
181 "Quick Access Tools\n\n"
183 " • Tile16 editor (Ctrl+T)\n"
184 " • Copy current map\n"
185 " • Lock/unlock map (Ctrl+L)");
194 int current_map,
bool& show_map_properties_panel) {
195 (void)show_map_properties_panel;
197 Text(
"No overworld loaded");
203 Text(
"Current Map: %d (0x%02X)", current_map, current_map);
209 if (ImGui::BeginTabBar(
"MapPropertiesTabs",
210 ImGuiTabBarFlags_FittingPolicyScroll)) {
213 if (ImGui::BeginTabItem(
"Basic Properties")) {
219 if (ImGui::BeginTabItem(
"Sprite Properties")) {
225 uint8_t asm_version =
227 if (asm_version != 0xFF && ImGui::BeginTabItem(
"Custom Features")) {
233 if (ImGui::BeginTabItem(
"Tile Graphics")) {
239 if (ImGui::BeginTabItem(
"Music")) {
249 int current_map,
bool& show_custom_bg_color_editor) {
250 (void)show_custom_bg_color_editor;
252 Text(
"No overworld loaded");
256 uint8_t asm_version =
258 if (asm_version < 2) {
259 Text(
"Custom background colors require ZSCustomOverworld v2+");
263 Text(
"Custom Background Color Editor");
267 static bool use_area_specific_bg_color =
false;
268 if (ImGui::Checkbox(
"Use Area-Specific Background Color",
269 &use_area_specific_bg_color)) {
272 use_area_specific_bg_color ? 1 : 0;
275 if (use_area_specific_bg_color) {
277 uint16_t current_color =
284 if (ImGui::ColorPicker4(
285 "Background Color", (
float*)&color_vec,
286 ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHex)) {
290 ->set_area_specific_bg_color(new_snes_color.
snes());
295 (*rom_)[rom_address] = new_snes_color.
snes() & 0xFF;
296 (*rom_)[rom_address + 1] = (new_snes_color.
snes() >> 8) & 0xFF;
299 Text(
"SNES Color: 0x%04X", current_color);
304 bool& show_overlay_editor) {
305 (void)show_overlay_editor;
307 Text(
"No overworld loaded");
311 uint8_t asm_version =
314 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
316 ImGui::Text(
"Map: 0x%02X", current_map);
319 if (asm_version < 1) {
320 ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.4f, 1.0f),
324 "To use visual effect overlays, you need to upgrade your ROM to "
325 "ZSCustomOverworld. This feature allows you to add atmospheric effects "
326 "like fog, rain, forest canopy, and sky backgrounds to your maps.");
332 ImGuiTreeNodeFlags_DefaultOpen)) {
335 "Visual effects (subscreen overlays) are semi-transparent layers drawn "
336 "on top of or behind your map. They reference special area maps (0x80-0x9F) "
337 "for their tile16 graphics data.");
339 ImGui::Text(
"Common uses:");
340 ImGui::BulletText(
"Fog effects (Lost Woods, Skull Woods)");
341 ImGui::BulletText(
"Rain (Misery Mire)");
342 ImGui::BulletText(
"Forest canopy (Lost Woods)");
343 ImGui::BulletText(
"Sky backgrounds (Death Mountain)");
344 ImGui::BulletText(
"Under bridge views");
350 static bool use_subscreen_overlay =
false;
352 &use_subscreen_overlay)) {
355 use_subscreen_overlay ? 1 : 0;
357 if (ImGui::IsItemHovered()) {
358 ImGui::SetTooltip(
"Enable/disable visual effect overlay for this map area");
361 if (use_subscreen_overlay) {
363 uint16_t current_overlay =
368 ->set_subscreen_overlay(current_overlay);
373 (*rom_)[rom_address] = current_overlay & 0xFF;
374 (*rom_)[rom_address + 1] = (current_overlay >> 8) & 0xFF;
376 if (ImGui::IsItemHovered()) {
378 "ID of the special area map (0x80-0x9F) to use for\n"
379 "visual effects. That map's tile16 data will be drawn\n"
380 "as a semi-transparent layer on this area.");
385 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
391 ImGui::BulletText(
"0x0093 - Triforce Room Curtain");
392 ImGui::BulletText(
"0x0094 - Under the Bridge");
393 ImGui::BulletText(
"0x0095 - Sky Background (LW Death Mountain)");
394 ImGui::BulletText(
"0x0096 - Pyramid Background");
395 ImGui::BulletText(
"0x0097 - Fog Overlay (Master Sword Area)");
396 ImGui::BulletText(
"0x009C - Lava Background (DW Death Mountain)");
397 ImGui::BulletText(
"0x009D - Fog Overlay (Lost/Skull Woods)");
398 ImGui::BulletText(
"0x009E - Tree Canopy (Forest)");
399 ImGui::BulletText(
"0x009F - Rain Effect (Misery Mire)");
400 ImGui::BulletText(
"0x00FF - No Overlay (Disabled)");
405 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
411 gui::Canvas& canvas,
int current_map,
bool current_map_lock,
412 bool& show_map_properties_panel,
bool& show_custom_bg_color_editor,
413 bool& show_overlay_editor) {
420 lock_item.
label = current_map_lock ?
"Unlock Map" :
"Lock to This Map";
421 lock_item.
callback = [¤t_map_lock]() {
422 current_map_lock = !current_map_lock;
429 properties_item.
callback = [&show_map_properties_panel]() {
430 show_map_properties_panel =
true;
435 uint8_t asm_version =
437 if (asm_version >= 3 && asm_version != 0xFF) {
441 bg_color_item.
callback = [&show_custom_bg_color_editor]() {
442 show_custom_bg_color_editor =
true;
449 overlay_item.
callback = [&show_overlay_editor]() {
450 show_overlay_editor =
true;
458 reset_view_item.
callback = [&canvas]() {
466 zoom_in_item.
callback = [&canvas]() {
467 float scale = std::min(2.0f, canvas.
global_scale() + 0.25f);
474 zoom_out_item.
callback = [&canvas]() {
475 float scale = std::max(0.25f, canvas.
global_scale() - 0.25f);
486 if (ImGui::BeginPopup(
"GraphicsPopup")) {
487 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
489 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
492 ImGui::Text(
"Graphics Settings");
498 ->mutable_area_graphics(),
506 (*maps_bmp_)[current_map].set_modified(
true);
518 HOVER_HINT(
"Main tileset graphics for this map area");
525 ->mutable_sprite_graphics(game_state),
531 HOVER_HINT(
"Sprite graphics sheet for current game state");
533 uint8_t asm_version =
535 if (asm_version >= 3) {
538 ->mutable_animated_gfx(),
545 HOVER_HINT(
"Animated tile graphics (water, lava, etc.)");
549 if (asm_version >= 1 && asm_version != 0xFF) {
555 if (BeginTable(
"CustomTileGraphics", 2,
556 ImGuiTableFlags_SizingFixedFit)) {
557 for (
int i = 0; i < 8; i++) {
559 std::string label = absl::StrFormat(
ICON_MD_LAYERS " Sheet %d", i);
562 ->mutable_custom_tileset(i),
569 if (ImGui::IsItemHovered()) {
570 ImGui::SetTooltip(
"Custom graphics sheet %d (0x00-0xFF)", i);
575 }
else if (asm_version == 0xFF) {
577 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
580 "Custom tile graphics require ZSCustomOverworld v1+.\n"
581 "Upgrade your ROM to access 8 customizable graphics sheets.");
584 ImGui::PopStyleVar(2);
590 bool& show_custom_bg_color_editor) {
591 if (ImGui::BeginPopup(
"PalettesPopup")) {
592 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
594 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
597 ImGui::Text(
"Palette Settings");
603 ->mutable_area_palette(),
609 HOVER_HINT(
"Main color palette for background tiles");
613 if (asm_version >= 2) {
616 ->mutable_main_palette(),
622 HOVER_HINT(
"Extended main palette (ZSCustomOverworld v2+)");
630 ->mutable_sprite_palette(game_state),
635 HOVER_HINT(
"Color palette for sprites in current game state");
640 show_custom_bg_color_editor = !show_custom_bg_color_editor;
642 HOVER_HINT(
"Open custom background color editor (v2+)");
644 ImGui::PopStyleVar(2);
650 bool& show_map_properties_panel,
651 bool& show_overlay_preview,
653 if (ImGui::BeginPopup(
"ConfigPopup")) {
654 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
656 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
663 if (BeginTable(
"BasicProps", 2, ImGuiTableFlags_SizingFixedFit)) {
670 ->mutable_message_id(),
675 if (ImGui::IsItemHovered()) {
676 ImGui::SetTooltip(
"Message ID shown when entering this area");
688 if (ImGui::IsItemHovered()) {
689 ImGui::SetTooltip(
"Affects sprite graphics/palettes based on story progress");
701 uint8_t asm_version =
704 int current_area_size =
708 if (asm_version >= 3 && asm_version != 0xFF) {
719 HOVER_HINT(
"Map area size (1x1, 2x2, 2x1, 1x2 screens)");
722 const char* limited_names[] = {
"Small (1x1)",
"Large (2x2)"};
723 int limited_size = (current_area_size == 0 || current_area_size == 1) ? current_area_size : 0;
734 HOVER_HINT(
"Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
749 show_map_properties_panel =
true;
750 ImGui::CloseCurrentPopup();
752 HOVER_HINT(
"Open detailed area configuration with all settings tabs");
754 ImGui::PopStyleVar(2);
760 if (BeginTable(
"BasicProperties", 2,
761 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
762 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
763 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
770 ->mutable_area_graphics(),
774 (*maps_bmp_)[current_map].set_modified(
true);
780 if (ImGui::IsItemHovered()) {
781 ImGui::SetTooltip(
"Main tileset graphics for this map area");
789 ->mutable_area_palette(),
795 if (ImGui::IsItemHovered()) {
796 ImGui::SetTooltip(
"Color palette for background tiles");
804 ->mutable_message_id(),
809 if (ImGui::IsItemHovered()) {
810 ImGui::SetTooltip(
"Message displayed when entering this area");
822 if (ImGui::IsItemHovered()) {
823 ImGui::SetTooltip(
"Enable pixelated mosaic transition effect");
832 ->mutable_area_music(0),
836 if (ImGui::IsItemHovered()) {
837 ImGui::SetTooltip(
"Music track before rescuing Zelda");
845 ->mutable_area_music(1),
849 if (ImGui::IsItemHovered()) {
850 ImGui::SetTooltip(
"Music track after rescuing Zelda");
858 ->mutable_area_music(2),
862 if (ImGui::IsItemHovered()) {
863 ImGui::SetTooltip(
"Music track after obtaining Master Sword");
871 ->mutable_area_music(3),
875 if (ImGui::IsItemHovered()) {
876 ImGui::SetTooltip(
"Music track after defeating Agahnim (Dark World)");
884 if (BeginTable(
"SpriteProperties", 2,
885 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
886 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
887 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
892 static int game_state = 0;
893 ImGui::SetNextItemWidth(120.f);
898 if (ImGui::IsItemHovered()) {
899 ImGui::SetTooltip(
"Affects which sprite graphics/palettes are used");
907 ->mutable_sprite_graphics(1),
912 if (ImGui::IsItemHovered()) {
913 ImGui::SetTooltip(
"First sprite graphics sheet for Zelda rescued state");
921 ->mutable_sprite_graphics(2),
926 if (ImGui::IsItemHovered()) {
927 ImGui::SetTooltip(
"Second sprite graphics sheet for Master Sword obtained state");
935 ->mutable_sprite_palette(1),
940 if (ImGui::IsItemHovered()) {
941 ImGui::SetTooltip(
"Color palette for sprites - Zelda rescued state");
949 ->mutable_sprite_palette(2),
954 if (ImGui::IsItemHovered()) {
955 ImGui::SetTooltip(
"Color palette for sprites - Master Sword obtained state");
963 if (BeginTable(
"CustomFeatures", 2,
964 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
965 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
966 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
972 uint8_t asm_version =
975 int current_area_size =
977 ImGui::SetNextItemWidth(130.f);
979 if (asm_version >= 3 && asm_version != 0xFF) {
981 static const char* all_sizes[] = {
"Small (1x1)",
"Large (2x2)",
982 "Wide (2x1)",
"Tall (1x2)"};
983 if (ImGui::Combo(
"##AreaSize", ¤t_area_size, all_sizes, 4)) {
992 if (ImGui::IsItemHovered()) {
993 ImGui::SetTooltip(
"Map size: Small (1x1), Large (2x2), Wide (2x1), Tall (1x2)");
997 static const char* limited_sizes[] = {
"Small (1x1)",
"Large (2x2)"};
998 int limited_size = (current_area_size == 0 || current_area_size == 1) ? current_area_size : 0;
1000 if (ImGui::Combo(
"##AreaSize", &limited_size, limited_sizes, 2)) {
1009 if (ImGui::IsItemHovered()) {
1010 ImGui::SetTooltip(
"Map size: Small (1x1), Large (2x2). Wide/Tall require v3+");
1014 if (asm_version >= 2) {
1020 ->mutable_main_palette(),
1026 if (ImGui::IsItemHovered()) {
1027 ImGui::SetTooltip(
"Extended main palette (ZSCustomOverworld v2+)");
1031 if (asm_version >= 3) {
1037 ->mutable_animated_gfx(),
1042 if (ImGui::IsItemHovered()) {
1043 ImGui::SetTooltip(
"Animated tile graphics ID (water, lava, etc.)");
1051 ->mutable_subscreen_overlay(),
1056 if (ImGui::IsItemHovered()) {
1057 ImGui::SetTooltip(
"Visual effects overlay ID (fog, rain, backgrounds)");
1069 if (asm_version >= 1 && asm_version != 0xFF) {
1073 if (BeginTable(
"TileGraphics", 2,
1074 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1075 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
1076 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
1078 for (
int i = 0; i < 8; i++) {
1084 ->mutable_custom_tileset(i),
1093 if (ImGui::IsItemHovered()) {
1094 ImGui::SetTooltip(
"Custom graphics sheet %d (0x00-0xFF)", i);
1102 ImGui::TextWrapped(
"These 8 sheets allow custom tile graphics per map. "
1103 "Each sheet references a graphics ID loaded into VRAM.");
1106 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1110 "Custom tile graphics are not available in vanilla ROMs.\n\n"
1111 "To enable this feature, upgrade your ROM to ZSCustomOverworld v1+, "
1112 "which provides 8 customizable graphics sheets per map for advanced "
1113 "tileset customization.");
1121 if (BeginTable(
"MusicSettings", 2,
1122 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1123 ImGui::TableSetupColumn(
"Game State", ImGuiTableColumnFlags_WidthFixed,
1125 ImGui::TableSetupColumn(
"Music Track ID",
1126 ImGuiTableColumnFlags_WidthStretch);
1128 const char* music_state_names[] = {
1134 const char* music_descriptions[] = {
1135 "Music before rescuing Zelda from the castle",
1136 "Music after rescuing Zelda from Hyrule Castle",
1137 "Music after obtaining the Master Sword from the Lost Woods",
1138 "Music after defeating Agahnim (Dark World music)"};
1140 for (
int i = 0; i < 4; i++) {
1142 ImGui::Text(
"%s", music_state_names[i]);
1147 ->mutable_area_music(i),
1152 int music_address = 0;
1168 if (music_address > 0) {
1169 (*rom_)[music_address] =
1171 ->mutable_area_music(i);
1174 if (ImGui::IsItemHovered()) {
1175 ImGui::SetTooltip(
"%s", music_descriptions[i]);
1183 ImGui::TextWrapped(
"Music tracks control the background music for different "
1184 "game progression states on this overworld map.");
1189 ImGuiTreeNodeFlags_DefaultOpen)) {
1191 ImGui::BulletText(
"0x02 - Overworld Theme");
1192 ImGui::BulletText(
"0x05 - Kakariko Village");
1193 ImGui::BulletText(
"0x07 - Lost Woods");
1194 ImGui::BulletText(
"0x09 - Dark World Theme");
1195 ImGui::BulletText(
"0x0F - Ganon's Tower");
1196 ImGui::BulletText(
"0x11 - Death Mountain");
1217 return absl::OkStatus();
1224 return absl::OkStatus();
1243 int parent_id = map->parent();
1244 std::vector<int> siblings;
1246 switch (map->area_size()) {
1248 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1251 siblings = {parent_id, parent_id + 1};
1254 siblings = {parent_id, parent_id + 8};
1260 for (
int sibling : siblings) {
1263 if (sibling == map_index && !include_self) {
1268 (*maps_bmp_)[sibling].set_modified(
true);
1285 uint8_t asm_version =
1287 if (asm_version >= 2) {
1289 ImGui::Text(
"Mosaic Effects (per direction):");
1292 std::array<bool, 4> mosaic_expanded = current_map_ptr->mosaic_expanded();
1293 const char* direction_names[] = {
"North",
"South",
"East",
"West"};
1295 for (
int i = 0; i < 4; i++) {
1296 if (ImGui::Checkbox(direction_names[i], &mosaic_expanded[i])) {
1297 current_map_ptr->set_mosaic_expanded(i, mosaic_expanded[i]);
1303 if (ImGui::Checkbox(
1313 bool& show_overlay_preview) {
1314 uint8_t asm_version =
1318 bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
1320 if (is_special_overworld_map) {
1322 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
1323 ICON_MD_INFO " Special Area Map (0x%02X)", current_map);
1326 "This is a special area map (0x80-0x9F) used as a visual effect "
1327 "source. These maps provide the graphics data for subscreen overlays "
1328 "like fog, rain, forest canopy, and sky backgrounds that appear on "
1329 "normal maps (0x00-0x7F).");
1332 "You can edit the tile16 data here to customize how the visual effects "
1333 "appear when referenced by other maps.");
1338 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
1342 ImGui::OpenPopup(
"OverlayTypesHelp");
1345 if (ImGui::BeginPopup(
"OverlayTypesHelp")) {
1346 ImGui::Text(
ICON_MD_HELP " Understanding Overlay Types");
1349 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1352 ImGui::BulletText(
"Displayed as semi-transparent layers");
1353 ImGui::BulletText(
"Reference special area maps (0x80-0x9F)");
1354 ImGui::BulletText(
"Examples: fog, rain, forest canopy, sky");
1355 ImGui::BulletText(
"Purely visual - don't affect collision");
1359 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1362 ImGui::BulletText(
"Dynamic tile16 changes on the map");
1363 ImGui::BulletText(
"Used for bridges appearing, holes opening");
1364 ImGui::BulletText(
"Stored as tile16 ID arrays");
1365 ImGui::BulletText(
"Affect collision and interaction");
1366 ImGui::BulletText(
"Triggered by game events/progression");
1371 "Note: Subscreen overlays are what you configure here. "
1372 "Map overlays are event-driven and edited separately.");
1379 ImGui::Text(
ICON_MD_LAYERS " Subscreen Overlay (Visual Effects)");
1381 uint16_t current_overlay =
1386 ->set_subscreen_overlay(current_overlay);
1390 if (ImGui::IsItemHovered()) {
1392 "References a special area map (0x80-0x9F) for visual effects.\n"
1393 "The referenced map's tile16 data is drawn as a semi-transparent\n"
1394 "layer on top of or behind this area for atmospheric effects.");
1399 if (current_overlay == 0x00FF) {
1400 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1402 }
else if (current_overlay >= 0x80 && current_overlay < 0xA0) {
1403 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1406 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1413 &show_overlay_preview)) {
1416 if (ImGui::IsItemHovered()) {
1418 "Shows a semi-transparent preview of the visual effect overlay\n"
1419 "drawn on top of the current map in the editor canvas.\n\n"
1420 "This preview shows how the subscreen overlay will appear in-game.");
1426 if (asm_version == 0xFF) {
1427 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1431 ImGui::OpenPopup(
"InteractiveOverlayHelp");
1433 if (ImGui::BeginPopup(
"InteractiveOverlayHelp")) {
1434 ImGui::Text(
ICON_MD_HELP " Map Overlays (Interactive Tile Changes)");
1437 "Map overlays are different from visual effect overlays. "
1438 "They contain tile16 data that dynamically replaces tiles on "
1439 "the map based on game events or progression.");
1441 ImGui::Text(
"Common uses:");
1442 ImGui::BulletText(
"Bridges appearing over water");
1443 ImGui::BulletText(
"Holes revealing secret passages");
1444 ImGui::BulletText(
"Rocks/bushes being moved");
1445 ImGui::BulletText(
"Environmental changes from story events");
1448 "These are triggered by game code and stored as separate "
1449 "tile data arrays in the ROM. ZSCustomOverworld v3+ provides "
1450 "extended control over these features.");
1456 if (current_map_ptr->has_overlay()) {
1457 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1459 current_map_ptr->overlay_id());
1461 static_cast<int>(current_map_ptr->overlay_data().size()));
1462 ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.4f, 1.0f),
1465 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1472 if (asm_version == 0xFF) {
1473 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
1475 ImGui::BulletText(
"Visual effects use maps 0x80-0x9F");
1476 ImGui::BulletText(
"Map overlays are read-only");
1478 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1480 ImGui::BulletText(
"Enhanced visual effect control");
1481 if (asm_version >= 3) {
1482 ImGui::BulletText(
"Extended overlay system");
1483 ImGui::BulletText(
"Custom area sizes support");
1490 if (overlay_id == 0x0093) {
1491 return "Triforce Room Curtain";
1492 }
else if (overlay_id == 0x0094) {
1493 return "Under the Bridge";
1494 }
else if (overlay_id == 0x0095) {
1495 return "Sky Background (LW Death Mountain)";
1496 }
else if (overlay_id == 0x0096) {
1497 return "Pyramid Background";
1498 }
else if (overlay_id == 0x0097) {
1499 return "First Fog Overlay (Master Sword Area)";
1500 }
else if (overlay_id == 0x009C) {
1501 return "Lava Background (DW Death Mountain)";
1502 }
else if (overlay_id == 0x009D) {
1503 return "Second Fog Overlay (Lost Woods/Skull Woods)";
1504 }
else if (overlay_id == 0x009E) {
1505 return "Tree Canopy (Forest)";
1506 }
else if (overlay_id == 0x009F) {
1507 return "Rain Effect (Misery Mire)";
1508 }
else if (overlay_id == 0x00FF) {
1509 return "No Overlay";
1511 return "Custom overlay";
1517 bool show_overlay_preview) {
1524 uint16_t overlay_id = 0x00FF;
1525 bool has_subscreen_overlay =
false;
1527 uint8_t asm_version =
1529 bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
1531 if (is_special_overworld_map) {
1538 has_subscreen_overlay = (overlay_id != 0x00FF);
1540 if (!has_subscreen_overlay)
1544 int overlay_map_index = -1;
1545 if (overlay_id >= 0x80 && overlay_id < 0xA0) {
1546 overlay_map_index = overlay_id;
1553 const auto& overlay_bitmap = (*maps_bmp_)[overlay_map_index];
1554 if (!overlay_bitmap.is_active())
1558 int current_map_x = current_map % 8;
1559 int current_map_y = current_map / 8;
1560 if (current_world == 1) {
1561 current_map_x = (current_map - 0x40) % 8;
1562 current_map_y = (current_map - 0x40) / 8;
1563 }
else if (current_world == 2) {
1564 current_map_x = (current_map - 0x80) % 8;
1565 current_map_y = (current_map - 0x80) / 8;
1573 bool is_background_overlay =
1574 (overlay_id == 0x0095 || overlay_id == 0x0096 || overlay_id == 0x009C);
1577 ImU32 overlay_color =
1578 is_background_overlay ? IM_COL32(255, 255, 255, 128)
1580 IM_COL32(255, 255, 255,
1585 (ImTextureID)(intptr_t)overlay_bitmap.texture(), ImVec2(map_x, map_y),
1588 ImVec2(0, 0), ImVec2(1, 1), overlay_color);
1592 if (ImGui::BeginPopup(
"ViewPopup")) {
1593 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
1595 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
1598 ImGui::Text(
"View Controls");
1618 HOVER_HINT(
"Toggle fullscreen canvas (F11)");
1620 ImGui::PopStyleVar(2);
1626 if (ImGui::BeginPopup(
"QuickPopup")) {
1627 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
1629 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
1632 ImGui::Text(
"Quick Access");
1654 HOVER_HINT(
"Lock/unlock current map (Ctrl+L)");
1656 ImGui::PopStyleVar(2);
RefreshCallback refresh_overworld_map_
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp_
void RefreshMapProperties()
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()
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 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)
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 DrawSimplifiedMapSettings(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, int ¤t_mode)
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
Modern, robust canvas for drawing and manipulating graphics.
void set_scrolling(ImVec2 scroll)
auto global_scale() const
void ClearContextMenuItems()
void set_global_scale(float scale)
void AddContextMenuItem(const ContextMenuItem &item)
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_AUTO_FIX_HIGH
#define ICON_MD_MUSIC_NOTE
#define ICON_MD_ASPECT_RATIO
#define ICON_MD_ANIMATION
#define ICON_MD_HELP_OUTLINE
#define ICON_MD_EDIT_NOTE
#define ICON_MD_OPEN_IN_NEW
#define ICON_MD_CONTENT_COPY
#define ICON_MD_COLOR_LENS
#define HOVER_HINT(string)
constexpr const char * kAreaSizeNames[]
constexpr float kCompactItemSpacing
constexpr float kTableColumnView
constexpr unsigned int kOverworldMapSize
constexpr float kTableColumnQuick
constexpr float kTableColumnWorld
constexpr float kTableButtonView
constexpr float kTableColumnGraphics
constexpr const char * kWorldNames[]
constexpr float kHexByteInputWidth
constexpr float kTableButtonQuick
constexpr float kTableColumnPalettes
constexpr float kTableButtonProperties
constexpr float kComboWorldWidth
constexpr float kTableColumnMap
constexpr float kCompactFramePadding
constexpr float kTableColumnAreaSize
constexpr float kTableButtonPalettes
constexpr float kComboGameStateWidth
constexpr float kInputFieldSize
constexpr float kTableButtonGraphics
constexpr const char * kGameStateNames[]
constexpr float kIconButtonWidth
constexpr float kHexWordInputWidth
constexpr float kComboAreaSizeWidth
constexpr float kTableColumnLock
constexpr float kTableColumnProperties
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)
ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor &color)
bool InputHexWordCustom(const char *label, uint16_t *data, float input_width)
gfx::SnesColor ConvertImVec4ToSnesColor(const ImVec4 &color)
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
constexpr int OverworldCustomAreaSpecificBGEnabled
constexpr int kNumOverworldMaps
constexpr int kOverworldMusicBeginning
constexpr int OverworldCustomASMHasBeenApplied
constexpr int kOverworldMusicAgahnim
constexpr int kOverworldMusicMasterSword
constexpr int kOverworldMusicZelda
constexpr int OverworldCustomSubscreenOverlayEnabled
constexpr int OverworldCustomAreaSpecificBGPalette
constexpr int OverworldCustomSubscreenOverlayArray
Main namespace for the application.
SNES color in 15-bit RGB format (BGR555)