Update overworld map properties and overlay functionality
- Changed the included assembly file for custom overworld to version 3 for improved features. - Enhanced documentation in the overworld loading guide to clarify overlay effects and configurations. - Refactored MapPropertiesSystem to support overlay previews and improved mosaic controls. - Added functionality for loading vanilla overlays and displaying overlay descriptions in the editor. - Updated UI components in OverworldEditor to integrate new overlay settings and preview options.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
#include "app/editor/overworld/map_properties.h"
|
||||
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/color.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/gui/style.h"
|
||||
#include "app/zelda3/overworld/overworld_map.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
@@ -11,11 +11,7 @@ namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
using ImGui::BeginTable;
|
||||
using ImGui::Button;
|
||||
using ImGui::Checkbox;
|
||||
using ImGui::EndTable;
|
||||
// HOVER_HINT is defined in util/macro.h
|
||||
using ImGui::SameLine;
|
||||
using ImGui::Separator;
|
||||
using ImGui::TableNextColumn;
|
||||
using ImGui::Text;
|
||||
@@ -26,7 +22,8 @@ constexpr const char* kGamePartComboString[] = {"Light World", "Dark World", "Sp
|
||||
|
||||
void MapPropertiesSystem::DrawSimplifiedMapSettings(int& current_world, int& current_map,
|
||||
bool& current_map_lock, bool& show_map_properties_panel,
|
||||
bool& show_custom_bg_color_editor, bool& show_overlay_editor) {
|
||||
bool& show_custom_bg_color_editor, bool& show_overlay_editor,
|
||||
bool& show_overlay_preview, int& game_state) {
|
||||
// Enhanced settings table with popup buttons for quick access
|
||||
if (BeginTable("SimplifiedMapSettings", 8, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit, ImVec2(0, 0), -1)) {
|
||||
ImGui::TableSetupColumn("World", ImGuiTableColumnFlags_WidthFixed, 100);
|
||||
@@ -90,19 +87,14 @@ void MapPropertiesSystem::DrawSimplifiedMapSettings(int& current_world, int& cur
|
||||
HOVER_HINT("Palette Settings");
|
||||
DrawPalettesPopup(current_map, show_custom_bg_color_editor);
|
||||
|
||||
TableNextColumn();
|
||||
if (ImGui::Button("Overlays", ImVec2(80, 0))) {
|
||||
ImGui::OpenPopup("OverlaysPopup");
|
||||
}
|
||||
HOVER_HINT("Overlay Settings");
|
||||
DrawOverlaysPopup(current_map, show_overlay_editor);
|
||||
// Overlays are now integrated into Properties popup
|
||||
|
||||
TableNextColumn();
|
||||
if (ImGui::Button("Properties", ImVec2(90, 0))) {
|
||||
ImGui::OpenPopup("PropertiesPopup");
|
||||
}
|
||||
HOVER_HINT("Map Properties");
|
||||
DrawPropertiesPopup(current_map, show_map_properties_panel);
|
||||
DrawPropertiesPopup(current_map, show_map_properties_panel, show_overlay_preview, game_state);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
@@ -336,8 +328,17 @@ void MapPropertiesSystem::DrawGraphicsPopup(int current_map) {
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::Button("Tile Graphics (8 sheets)")) {
|
||||
// This would open the full properties panel
|
||||
ImGui::Text("Custom Tile Graphics (8 sheets):");
|
||||
|
||||
// Show the 8 custom graphics IDs in a more accessible way
|
||||
for (int i = 0; i < 8; i++) {
|
||||
std::string label = absl::StrFormat("Sheet %d", i);
|
||||
if (gui::InputHexByte(label.c_str(),
|
||||
overworld_->mutable_overworld_map(current_map)->mutable_custom_tileset(i),
|
||||
80.f)) {
|
||||
RefreshMapProperties();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
@@ -353,7 +354,7 @@ void MapPropertiesSystem::DrawPalettesPopup(int current_map, bool& show_custom_b
|
||||
overworld_->mutable_overworld_map(current_map)->mutable_area_palette(),
|
||||
kInputFieldSize)) {
|
||||
RefreshMapProperties();
|
||||
RefreshMapPalette();
|
||||
auto status = RefreshMapPalette();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
|
||||
@@ -363,7 +364,7 @@ void MapPropertiesSystem::DrawPalettesPopup(int current_map, bool& show_custom_b
|
||||
overworld_->mutable_overworld_map(current_map)->mutable_main_palette(),
|
||||
kInputFieldSize)) {
|
||||
RefreshMapProperties();
|
||||
RefreshMapPalette();
|
||||
auto status = RefreshMapPalette();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
}
|
||||
@@ -391,73 +392,56 @@ void MapPropertiesSystem::DrawPalettesPopup(int current_map, bool& show_custom_b
|
||||
}
|
||||
}
|
||||
|
||||
void MapPropertiesSystem::DrawOverlaysPopup(int current_map, bool& show_overlay_editor) {
|
||||
if (ImGui::BeginPopup("OverlaysPopup")) {
|
||||
ImGui::Text("Overlay Settings");
|
||||
ImGui::Separator();
|
||||
|
||||
static uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
|
||||
if (asm_version >= 3) {
|
||||
if (gui::InputHexWord("Subscreen Overlay",
|
||||
overworld_->mutable_overworld_map(current_map)->mutable_subscreen_overlay(),
|
||||
kInputFieldSize + 20)) {
|
||||
RefreshMapProperties();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::Button("Overlay Settings")) {
|
||||
show_overlay_editor = !show_overlay_editor;
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("Overlays require ZSCustomOverworld v3+");
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void MapPropertiesSystem::DrawPropertiesPopup(int current_map, bool& show_map_properties_panel) {
|
||||
void MapPropertiesSystem::DrawPropertiesPopup(int current_map, bool& show_map_properties_panel,
|
||||
bool& show_overlay_preview, int& game_state) {
|
||||
if (ImGui::BeginPopup("PropertiesPopup")) {
|
||||
ImGui::Text("Map Properties");
|
||||
ImGui::Text("Map Properties & Overlays");
|
||||
ImGui::Separator();
|
||||
|
||||
if (gui::InputHexWord("Message ID",
|
||||
overworld_->mutable_overworld_map(current_map)->mutable_message_id(),
|
||||
|
||||
// Basic properties
|
||||
if (gui::InputHexWord("Message ID",
|
||||
overworld_->mutable_overworld_map(current_map)
|
||||
->mutable_message_id(),
|
||||
kInputFieldSize + 20)) {
|
||||
RefreshMapProperties();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Mosaic Effect",
|
||||
overworld_->mutable_overworld_map(current_map)->mutable_mosaic())) {
|
||||
RefreshMapProperties();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
|
||||
static int game_state = 0; // This should be passed in or stored
|
||||
|
||||
// Mosaic controls with directional support for v2+
|
||||
DrawMosaicControls(current_map);
|
||||
|
||||
// Overlay controls - always accessible, behavior changes by version
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Overlay Settings:");
|
||||
DrawOverlayControls(current_map, show_overlay_preview);
|
||||
|
||||
ImGui::SetNextItemWidth(100.f);
|
||||
if (ImGui::Combo("Game State", &game_state, kGamePartComboString, 3)) {
|
||||
RefreshMapProperties();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
|
||||
|
||||
static uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
|
||||
if (asm_version != 0xFF) {
|
||||
static const char *area_size_names[] = {"Small (1x1)", "Large (2x2)", "Wide (2x1)", "Tall (1x2)"};
|
||||
int current_area_size = static_cast<int>(overworld_->overworld_map(current_map)->area_size());
|
||||
static const char *area_size_names[] = {"Small (1x1)", "Large (2x2)",
|
||||
"Wide (2x1)", "Tall (1x2)"};
|
||||
int current_area_size = static_cast<int>(
|
||||
overworld_->overworld_map(current_map)->area_size());
|
||||
ImGui::SetNextItemWidth(120.f);
|
||||
if (ImGui::Combo("Area Size", ¤t_area_size, area_size_names, 4)) {
|
||||
overworld_->mutable_overworld_map(current_map)->SetAreaSize(static_cast<zelda3::AreaSizeEnum>(current_area_size));
|
||||
overworld_->mutable_overworld_map(current_map)
|
||||
->SetAreaSize(
|
||||
static_cast<zelda3::AreaSizeEnum>(current_area_size));
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::Button("Full Properties Panel")) {
|
||||
show_map_properties_panel = true;
|
||||
}
|
||||
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
@@ -482,7 +466,7 @@ void MapPropertiesSystem::DrawBasicPropertiesTab(int current_map) {
|
||||
overworld_->mutable_overworld_map(current_map)->mutable_area_palette(),
|
||||
kInputFieldSize)) {
|
||||
RefreshMapProperties();
|
||||
RefreshMapPalette();
|
||||
auto status = RefreshMapPalette();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
|
||||
@@ -585,7 +569,7 @@ void MapPropertiesSystem::DrawCustomFeaturesTab(int current_map) {
|
||||
overworld_->mutable_overworld_map(current_map)->mutable_main_palette(),
|
||||
kInputFieldSize)) {
|
||||
RefreshMapProperties();
|
||||
RefreshMapPalette();
|
||||
auto status = RefreshMapPalette();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
}
|
||||
@@ -663,5 +647,187 @@ absl::Status MapPropertiesSystem::RefreshMapPalette() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void MapPropertiesSystem::DrawMosaicControls(int current_map) {
|
||||
static uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
|
||||
if (asm_version >= 2) {
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Mosaic Effects (per direction):");
|
||||
|
||||
auto* current_map_ptr = overworld_->mutable_overworld_map(current_map);
|
||||
std::array<bool, 4> mosaic_expanded = current_map_ptr->mosaic_expanded();
|
||||
const char* direction_names[] = {"North", "South", "East", "West"};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (ImGui::Checkbox(direction_names[i], &mosaic_expanded[i])) {
|
||||
current_map_ptr->set_mosaic_expanded(i, mosaic_expanded[i]);
|
||||
RefreshMapProperties();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ImGui::Checkbox("Mosaic Effect",
|
||||
overworld_->mutable_overworld_map(current_map)
|
||||
->mutable_mosaic())) {
|
||||
RefreshMapProperties();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MapPropertiesSystem::DrawOverlayControls(int current_map, bool& show_overlay_preview) {
|
||||
static uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
|
||||
|
||||
// Determine if this is a special overworld map (0x80-0x9F)
|
||||
bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
|
||||
|
||||
if (asm_version == 0xFF) {
|
||||
// Vanilla ROM - read-only overlay info
|
||||
auto *current_map_ptr = overworld_->overworld_map(current_map);
|
||||
if (current_map_ptr->has_vanilla_overlay()) {
|
||||
ImGui::Text("Vanilla Overlay: 0x%04X", current_map_ptr->vanilla_overlay_id());
|
||||
|
||||
// Show overlay description
|
||||
uint16_t overlay_id = current_map_ptr->vanilla_overlay_id();
|
||||
std::string overlay_desc = GetOverlayDescription(overlay_id);
|
||||
ImGui::Text("Description: %s", overlay_desc.c_str());
|
||||
|
||||
// Preview checkbox for vanilla
|
||||
if (ImGui::Checkbox("Preview Overlay on Map", &show_overlay_preview)) {
|
||||
// Toggle overlay preview
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("No vanilla overlay for this map");
|
||||
}
|
||||
} else if (is_special_overworld_map && asm_version < 3) {
|
||||
// Special overworld maps (0x80-0x9F) require ZSCustomOverworld v3+
|
||||
ImGui::Text("Special overworld maps require ZSCustomOverworld v3+");
|
||||
ImGui::Text("Current version: v%d", asm_version);
|
||||
ImGui::Text("Map 0x%02X is a special overworld map", current_map);
|
||||
} else {
|
||||
// Light World (0x00-0x3F) and Dark World (0x40-0x7F) maps always support overlays
|
||||
// Special overworld maps (0x80-0x9F) support overlays with v3+
|
||||
uint16_t current_overlay = overworld_->mutable_overworld_map(current_map)->subscreen_overlay();
|
||||
if (gui::InputHexWord("Subscreen Overlay", ¤t_overlay, kInputFieldSize + 20)) {
|
||||
overworld_->mutable_overworld_map(current_map)->set_subscreen_overlay(current_overlay);
|
||||
RefreshMapProperties();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
|
||||
// Show overlay description
|
||||
std::string overlay_desc = GetOverlayDescription(current_overlay);
|
||||
ImGui::Text("Description: %s", overlay_desc.c_str());
|
||||
|
||||
// Preview checkbox
|
||||
if (ImGui::Checkbox("Preview Overlay on Map", &show_overlay_preview)) {
|
||||
// Toggle overlay preview
|
||||
}
|
||||
|
||||
// Show version info for special maps
|
||||
if (is_special_overworld_map) {
|
||||
ImGui::Text("Special overworld map (v%d)", asm_version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string MapPropertiesSystem::GetOverlayDescription(uint16_t overlay_id) {
|
||||
if (overlay_id == 0x0093) {
|
||||
return "Triforce Room Curtain";
|
||||
} else if (overlay_id == 0x0094) {
|
||||
return "Under the Bridge";
|
||||
} else if (overlay_id == 0x0095) {
|
||||
return "Sky Background (LW Death Mountain)";
|
||||
} else if (overlay_id == 0x0096) {
|
||||
return "Pyramid Background";
|
||||
} else if (overlay_id == 0x0097) {
|
||||
return "First Fog Overlay (Master Sword Area)";
|
||||
} else if (overlay_id == 0x009C) {
|
||||
return "Lava Background (DW Death Mountain)";
|
||||
} else if (overlay_id == 0x009D) {
|
||||
return "Second Fog Overlay (Lost Woods/Skull Woods)";
|
||||
} else if (overlay_id == 0x009E) {
|
||||
return "Tree Canopy (Forest)";
|
||||
} else if (overlay_id == 0x009F) {
|
||||
return "Rain Effect (Misery Mire)";
|
||||
} else if (overlay_id == 0x00FF) {
|
||||
return "No Overlay";
|
||||
} else {
|
||||
return "Custom overlay";
|
||||
}
|
||||
}
|
||||
|
||||
void MapPropertiesSystem::DrawOverlayPreviewOnMap(int current_map, int current_world, bool show_overlay_preview) {
|
||||
if (!show_overlay_preview || !maps_bmp_ || !canvas_) return;
|
||||
|
||||
// Get overlay information based on ROM version and map type
|
||||
uint16_t overlay_id = 0x00FF;
|
||||
bool has_overlay = false;
|
||||
|
||||
static uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
|
||||
bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
|
||||
|
||||
if (asm_version == 0xFF) {
|
||||
// Vanilla ROM - use vanilla overlay
|
||||
auto *current_map_ptr = overworld_->overworld_map(current_map);
|
||||
if (current_map_ptr->has_vanilla_overlay()) {
|
||||
overlay_id = current_map_ptr->vanilla_overlay_id();
|
||||
has_overlay = true;
|
||||
}
|
||||
} else if (is_special_overworld_map && asm_version < 3) {
|
||||
// Special overworld maps require v3+ - no overlay support
|
||||
return;
|
||||
} else {
|
||||
// Light World (0x00-0x3F) and Dark World (0x40-0x7F) maps always support overlays
|
||||
// Special overworld maps (0x80-0x9F) support overlays with v3+
|
||||
overlay_id = overworld_->overworld_map(current_map)->subscreen_overlay();
|
||||
has_overlay = (overlay_id != 0x00FF);
|
||||
}
|
||||
|
||||
if (!has_overlay) return;
|
||||
|
||||
// Map overlay ID to special area map for bitmap
|
||||
int overlay_map_index = -1;
|
||||
if (overlay_id >= 0x80 && overlay_id < 0xA0) {
|
||||
overlay_map_index = overlay_id;
|
||||
}
|
||||
|
||||
if (overlay_map_index < 0 || overlay_map_index >= zelda3::kNumOverworldMaps) return;
|
||||
|
||||
// Get the overlay map's bitmap
|
||||
const auto &overlay_bitmap = (*maps_bmp_)[overlay_map_index];
|
||||
if (!overlay_bitmap.is_active()) return;
|
||||
|
||||
// Calculate position for overlay preview on the current map
|
||||
int current_map_x = current_map % 8;
|
||||
int current_map_y = current_map / 8;
|
||||
if (current_world == 1) {
|
||||
current_map_x = (current_map - 0x40) % 8;
|
||||
current_map_y = (current_map - 0x40) / 8;
|
||||
} else if (current_world == 2) {
|
||||
current_map_x = (current_map - 0x80) % 8;
|
||||
current_map_y = (current_map - 0x80) / 8;
|
||||
}
|
||||
|
||||
int scale = static_cast<int>(canvas_->global_scale());
|
||||
int map_x = current_map_x * kOverworldMapSize * scale;
|
||||
int map_y = current_map_y * kOverworldMapSize * scale;
|
||||
|
||||
// Determine if this is a background or foreground overlay
|
||||
bool is_background_overlay = (overlay_id == 0x0095 || overlay_id == 0x0096 || overlay_id == 0x009C);
|
||||
|
||||
// Set alpha for semi-transparent preview
|
||||
ImU32 overlay_color = is_background_overlay ?
|
||||
IM_COL32(255, 255, 255, 128) : // Background overlays - lighter
|
||||
IM_COL32(255, 255, 255, 180); // Foreground overlays - more opaque
|
||||
|
||||
// Draw the overlay bitmap with semi-transparency
|
||||
canvas_->draw_list()->AddImage(
|
||||
(ImTextureID)(intptr_t)overlay_bitmap.texture(),
|
||||
ImVec2(map_x, map_y),
|
||||
ImVec2(map_x + kOverworldMapSize * scale, map_y + kOverworldMapSize * scale),
|
||||
ImVec2(0, 0),
|
||||
ImVec2(1, 1),
|
||||
overlay_color);
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
@@ -4,20 +4,22 @@
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
class MapPropertiesSystem {
|
||||
public:
|
||||
explicit MapPropertiesSystem(zelda3::Overworld* overworld, Rom* rom)
|
||||
: overworld_(overworld), rom_(rom) {}
|
||||
explicit MapPropertiesSystem(zelda3::Overworld* overworld, Rom* rom,
|
||||
std::array<gfx::Bitmap, zelda3::kNumOverworldMaps>* maps_bmp = nullptr,
|
||||
gui::Canvas* canvas = nullptr)
|
||||
: overworld_(overworld), rom_(rom), maps_bmp_(maps_bmp), canvas_(canvas) {}
|
||||
|
||||
// Main interface methods
|
||||
void DrawSimplifiedMapSettings(int& current_world, int& current_map,
|
||||
bool& current_map_lock, bool& show_map_properties_panel,
|
||||
bool& show_custom_bg_color_editor, bool& show_overlay_editor);
|
||||
bool& show_custom_bg_color_editor, bool& show_overlay_editor,
|
||||
bool& show_overlay_preview, int& game_state);
|
||||
|
||||
void DrawMapPropertiesPanel(int current_map, bool& show_map_properties_panel);
|
||||
|
||||
@@ -25,6 +27,9 @@ class MapPropertiesSystem {
|
||||
|
||||
void DrawOverlayEditor(int current_map, bool& show_overlay_editor);
|
||||
|
||||
// Overlay preview functionality
|
||||
void DrawOverlayPreviewOnMap(int current_map, int current_world, bool show_overlay_preview);
|
||||
|
||||
// Context menu integration
|
||||
void SetupCanvasContextMenu(gui::Canvas& canvas, int current_map, bool current_map_lock,
|
||||
bool& show_map_properties_panel, bool& show_custom_bg_color_editor,
|
||||
@@ -34,8 +39,13 @@ class MapPropertiesSystem {
|
||||
// Property category drawers
|
||||
void DrawGraphicsPopup(int current_map);
|
||||
void DrawPalettesPopup(int current_map, bool& show_custom_bg_color_editor);
|
||||
void DrawOverlaysPopup(int current_map, bool& show_overlay_editor);
|
||||
void DrawPropertiesPopup(int current_map, bool& show_map_properties_panel);
|
||||
void DrawPropertiesPopup(int current_map, bool& show_map_properties_panel,
|
||||
bool& show_overlay_preview, int& game_state);
|
||||
|
||||
// Overlay and mosaic functionality
|
||||
void DrawMosaicControls(int current_map);
|
||||
void DrawOverlayControls(int current_map, bool& show_overlay_preview);
|
||||
std::string GetOverlayDescription(uint16_t overlay_id);
|
||||
|
||||
// Tab content drawers
|
||||
void DrawBasicPropertiesTab(int current_map);
|
||||
@@ -50,6 +60,8 @@ class MapPropertiesSystem {
|
||||
|
||||
zelda3::Overworld* overworld_;
|
||||
Rom* rom_;
|
||||
std::array<gfx::Bitmap, zelda3::kNumOverworldMaps>* maps_bmp_;
|
||||
gui::Canvas* canvas_;
|
||||
|
||||
// Static constants
|
||||
static constexpr float kInputFieldSize = 30.f;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@
|
||||
#include "app/editor/graphics/gfx_group_editor.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/editor/overworld/tile16_editor.h"
|
||||
#include "app/editor/overworld/map_properties.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/tilemap.h"
|
||||
@@ -77,6 +78,7 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
|
||||
explicit OverworldEditor(Rom* rom) : rom_(rom) {
|
||||
type_ = EditorType::kOverworld;
|
||||
gfx_group_editor_.set_rom(rom);
|
||||
// MapPropertiesSystem will be initialized after maps_bmp_ and canvas are ready
|
||||
}
|
||||
|
||||
void Initialize() override;
|
||||
@@ -161,6 +163,8 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
|
||||
void DrawCustomBackgroundColorEditor();
|
||||
void DrawOverlayEditor();
|
||||
void DrawMapLockControls();
|
||||
void DrawOverlayPreview();
|
||||
void DrawOverlayPreviewOnMap();
|
||||
void DrawOverworldContextMenu();
|
||||
void DrawSimplifiedMapSettings();
|
||||
void DrawMapPropertiesPanel();
|
||||
@@ -227,6 +231,10 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
|
||||
bool show_overlay_editor_ = false;
|
||||
bool use_area_specific_bg_color_ = false;
|
||||
bool show_map_properties_panel_ = false;
|
||||
bool show_overlay_preview_ = false;
|
||||
|
||||
// Map properties system for UI organization
|
||||
std::unique_ptr<MapPropertiesSystem> map_properties_system_;
|
||||
|
||||
gfx::Tilemap tile16_blockset_;
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ absl::Status OverworldMap::BuildMap(int count, int game_state, int world,
|
||||
RETURN_IF_ERROR(BuildTileset())
|
||||
RETURN_IF_ERROR(BuildTiles16Gfx(tiles16, count))
|
||||
RETURN_IF_ERROR(LoadPalette());
|
||||
RETURN_IF_ERROR(LoadVanillaOverlay());
|
||||
RETURN_IF_ERROR(BuildBitmap(world_blockset))
|
||||
built_ = true;
|
||||
return absl::OkStatus();
|
||||
@@ -824,6 +825,138 @@ absl::Status OverworldMap::LoadPalette() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status OverworldMap::LoadVanillaOverlay() {
|
||||
uint8_t asm_version = (*rom_)[OverworldCustomASMHasBeenApplied];
|
||||
|
||||
// Only load vanilla overlays if this is a vanilla ROM (asm_version == 0xFF)
|
||||
if (asm_version != 0xFF) {
|
||||
has_vanilla_overlay_ = false;
|
||||
vanilla_overlay_id_ = 0;
|
||||
vanilla_overlay_data_.clear();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Load vanilla overlay for this map
|
||||
int address = (kOverlayPointersBank << 16) +
|
||||
((*rom_)[kOverlayPointers + (index_ * 2) + 1] << 8) +
|
||||
(*rom_)[kOverlayPointers + (index_ * 2)];
|
||||
|
||||
// Convert SNES address to PC address
|
||||
address = ((address & 0x7F0000) >> 1) | (address & 0x7FFF);
|
||||
|
||||
// Check if custom overlay code is present
|
||||
if ((*rom_)[kOverlayData1] == 0x6B) {
|
||||
// Use custom overlay data pointer
|
||||
address = ((*rom_)[kOverlayData2 + 2 + (index_ * 3)] << 16) +
|
||||
((*rom_)[kOverlayData2 + 1 + (index_ * 3)] << 8) +
|
||||
(*rom_)[kOverlayData2 + (index_ * 3)];
|
||||
address = ((address & 0x7F0000) >> 1) | (address & 0x7FFF);
|
||||
}
|
||||
|
||||
// Validate address
|
||||
if (address >= rom_->size()) {
|
||||
has_vanilla_overlay_ = false;
|
||||
vanilla_overlay_id_ = 0;
|
||||
vanilla_overlay_data_.clear();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Parse overlay data
|
||||
vanilla_overlay_data_.clear();
|
||||
uint8_t b = (*rom_)[address];
|
||||
|
||||
// Parse overlay commands until we hit END (0x60)
|
||||
while (b != 0x60 && address < rom_->size()) {
|
||||
vanilla_overlay_data_.push_back(b);
|
||||
|
||||
// Handle different overlay commands
|
||||
switch (b) {
|
||||
case 0xA9: // LDA #$
|
||||
if (address + 2 < rom_->size()) {
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 1]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 2]);
|
||||
address += 3;
|
||||
} else {
|
||||
address++;
|
||||
}
|
||||
break;
|
||||
case 0xA2: // LDX #$
|
||||
if (address + 2 < rom_->size()) {
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 1]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 2]);
|
||||
address += 3;
|
||||
} else {
|
||||
address++;
|
||||
}
|
||||
break;
|
||||
case 0x8D: // STA $xxxx
|
||||
if (address + 3 < rom_->size()) {
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 1]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 2]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 3]);
|
||||
address += 4;
|
||||
} else {
|
||||
address++;
|
||||
}
|
||||
break;
|
||||
case 0x9D: // STA $xxxx,x
|
||||
if (address + 3 < rom_->size()) {
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 1]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 2]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 3]);
|
||||
address += 4;
|
||||
} else {
|
||||
address++;
|
||||
}
|
||||
break;
|
||||
case 0x8F: // STA $xxxxxx
|
||||
if (address + 4 < rom_->size()) {
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 1]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 2]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 3]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 4]);
|
||||
address += 5;
|
||||
} else {
|
||||
address++;
|
||||
}
|
||||
break;
|
||||
case 0x1A: // INC A
|
||||
address++;
|
||||
break;
|
||||
case 0x4C: // JMP
|
||||
if (address + 3 < rom_->size()) {
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 1]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 2]);
|
||||
vanilla_overlay_data_.push_back((*rom_)[address + 3]);
|
||||
address += 4;
|
||||
} else {
|
||||
address++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
address++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (address < rom_->size()) {
|
||||
b = (*rom_)[address];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the END command if we found it
|
||||
if (b == 0x60) {
|
||||
vanilla_overlay_data_.push_back(0x60);
|
||||
}
|
||||
|
||||
// Set overlay ID based on map index (simplified)
|
||||
vanilla_overlay_id_ = index_;
|
||||
has_vanilla_overlay_ = !vanilla_overlay_data_.empty();
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void OverworldMap::ProcessGraphicsBuffer(int index, int static_graphics_offset,
|
||||
int size, uint8_t *all_gfx) {
|
||||
// Ensure we don't go out of bounds
|
||||
|
||||
@@ -36,6 +36,13 @@ constexpr int OverworldCustomTileGFXGroupEnabled = 0x140148; // 1 byte, not 0 i
|
||||
constexpr int OverworldCustomMosaicArray = 0x140200; // 1 byte for each overworld area (0xA0)
|
||||
constexpr int OverworldCustomMosaicEnabled = 0x140142; // 1 byte, not 0 if enabled
|
||||
|
||||
// Vanilla overlay constants
|
||||
constexpr int kOverlayPointers = 0x77664; // 2 bytes for each overworld area (0x100)
|
||||
constexpr int kOverlayPointersBank = 0x0E; // Bank for overlay pointers
|
||||
constexpr int kOverlayData1 = 0x77676; // Check for custom overlay code
|
||||
constexpr int kOverlayData2 = 0x77677; // Custom overlay data pointer
|
||||
constexpr int kOverlayCodeStart = 0x77657; // Start of overlay code
|
||||
|
||||
// 1 byte for each overworld area (0xA0)
|
||||
constexpr int OverworldCustomMainPaletteArray = 0x140160;
|
||||
// 1 byte, not 0 if enabled
|
||||
@@ -98,6 +105,7 @@ class OverworldMap : public gfx::GfxContext {
|
||||
|
||||
void LoadAreaGraphics();
|
||||
absl::Status LoadPalette();
|
||||
absl::Status LoadVanillaOverlay();
|
||||
absl::Status BuildTileset();
|
||||
absl::Status BuildTiles16Gfx(std::vector<gfx::Tile16>& tiles16, int count);
|
||||
absl::Status BuildBitmap(OverworldBlockset& world_blockset);
|
||||
@@ -139,6 +147,15 @@ class OverworldMap : public gfx::GfxContext {
|
||||
void set_animated_gfx(uint8_t gfx) { animated_gfx_ = gfx; }
|
||||
|
||||
auto custom_tileset(int index) const { return custom_gfx_ids_[index]; }
|
||||
|
||||
// Vanilla overlay accessors
|
||||
auto vanilla_overlay_id() const { return vanilla_overlay_id_; }
|
||||
auto has_vanilla_overlay() const { return has_vanilla_overlay_; }
|
||||
const auto& vanilla_overlay_data() const { return vanilla_overlay_data_; }
|
||||
|
||||
// Mosaic expanded accessors
|
||||
const std::array<bool, 4>& mosaic_expanded() const { return mosaic_expanded_; }
|
||||
void set_mosaic_expanded(int index, bool value) { mosaic_expanded_[index] = value; }
|
||||
void set_custom_tileset(int index, uint8_t value) { custom_gfx_ids_[index] = value; }
|
||||
|
||||
auto mutable_current_graphics() { return ¤t_gfx_; }
|
||||
@@ -216,6 +233,9 @@ class OverworldMap : public gfx::GfxContext {
|
||||
static_graphics_.fill(0);
|
||||
mosaic_expanded_.fill(false);
|
||||
area_size_ = AreaSizeEnum::SmallArea;
|
||||
vanilla_overlay_id_ = 0;
|
||||
has_vanilla_overlay_ = false;
|
||||
vanilla_overlay_data_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -267,6 +287,11 @@ class OverworldMap : public gfx::GfxContext {
|
||||
|
||||
std::array<bool, 4> mosaic_expanded_;
|
||||
|
||||
// Vanilla overlay support
|
||||
uint16_t vanilla_overlay_id_ = 0;
|
||||
bool has_vanilla_overlay_ = false;
|
||||
std::vector<uint8_t> vanilla_overlay_data_;
|
||||
|
||||
std::vector<uint8_t> current_blockset_;
|
||||
std::vector<uint8_t> current_gfx_;
|
||||
std::vector<uint8_t> bitmap_data_;
|
||||
|
||||
Reference in New Issue
Block a user