6#define IM_PI 3.14159265358979323846f
22#include <unordered_map>
27#include "absl/status/status.h"
28#include "absl/strings/str_format.h"
29#include "imgui/imgui.h"
107 for (
size_t i = 0; i < lhs.
items.size(); ++i) {
148 const int clamped_world = std::clamp(current_world, 0, 2);
149 int normalized_map = current_map;
155 const int normalized_world = std::clamp(normalized_map / 0x40, 0, 2);
157 normalized_world != current_world || normalized_map != current_map;
158 current_world = normalized_world;
159 current_map = normalized_map;
168 "Gfx Groups: selection syncs with the Graphics editor for this ROM "
170 "(this surface uses its own preview canvases).");
181 std::make_unique<EntityMutationService>(
overworld_);
206 [
this](
int map_index,
bool respect_pin) {
214 [
this](
const std::vector<OverworldPropertyEdit>& edits,
215 const std::string& description) {
219 [
this](
const std::string&
type,
int id,
const std::string& label) {
232 toolbar_ = std::make_unique<OverworldToolbar>();
233 toolbar_->on_world_changed = [
this](
int world) {
236 toolbar_->on_refresh_graphics = [
this]() {
242 toolbar_->on_refresh_map = [
this]() {
246 toolbar_->on_save_to_scratch = [
this]() {
249 toolbar_->on_load_from_scratch = [
this]() {
252 toolbar_->on_upgrade_rom_version = [
this](int) {
253 ImGui::OpenPopup(
"UpgradeROMVersion");
258 toolbar_->on_rename_resource_label = [
this](
const std::string&
type,
int id,
259 const std::string& label) {
299 const int step = shift_held ? 16 : 1;
306 "overworld.entity_workbench"));
316 switch (entity->entity_type_) {
333 const size_t session_id =
348 const size_t session_id =
363 std::make_unique<OverworldInteractionCoordinator>(std::move(sink));
403 tile_painting_ = std::make_unique<TilePaintingManager>(deps, callbacks);
444 canvas_nav_ = std::make_unique<CanvasNavigationManager>();
470 LOG_DEBUG(
"OverworldEditor",
"Loading overworld.");
472 return absl::FailedPreconditionError(
"ROM not loaded");
497 [
this](
const std::vector<Tile16Commit>& commits) -> absl::Status {
499 for (
const auto& commit : commits) {
500 if (commit.tile_id >= 0 &&
501 commit.tile_id <
static_cast<int>(tiles16->size())) {
502 (*tiles16)[commit.tile_id] = commit.tile_data;
513 "Overworld editor refreshed after Tile16 changes");
514 return absl::OkStatus();
520 [
this](
const std::string& entity_type) {
536 [
this](
const std::string& group_name,
int palette_index) {
538 if (group_name ==
"ow_main" || group_name ==
"ow_animated" ||
539 group_name ==
"ow_aux" || group_name ==
"grass") {
541 "Palette change detected: %s, refreshing current map",
549 LOG_DEBUG(
"OverworldEditor",
"Registered as palette listener (ID: %d)",
556 if (!scratch_status.ok()) {
557 LOG_WARN(
"OverworldEditor",
"Failed to load scratch pad: %s",
558 std::string(scratch_status.message()).c_str());
567 return absl::OkStatus();
576 return absl::OkStatus();
581 return absl::OkStatus();
619 ImGui::SetNextWindowSize(ImVec2(400, 500), ImGuiCond_FirstUseEver);
633 ImGui::SetNextWindowSize(ImVec2(500, 450), ImGuiCond_FirstUseEver);
634 if (ImGui::Begin(
ICON_MD_LAYERS " Visual Effects Editor###OverlayEditor",
651 workbench->DrawPopups();
654 if (ImGui::BeginPopupModal(
"UpgradeROMVersion",
nullptr,
655 ImGuiWindowFlags_AlwaysAutoResize)) {
659 tr(
"This will apply the ZSCustomOverworld ASM patch to your ROM,\n"
660 "enabling advanced overworld features."));
663 const uint8_t current_version =
666 ImGui::Text(tr(
"Current Version: %s"),
667 current_version == 0xFF
669 : absl::StrFormat(
"v%d", current_version).c_str());
671 static int target_version = 3;
672 ImGui::RadioButton(tr(
"v2 (Basic features)"), &target_version, 2);
674 ImGui::RadioButton(tr(
"v3 (All features)"), &target_version, 3);
678 if (ImGui::Button(
ICON_MD_CHECK " Apply Upgrade", ImVec2(150.0f, 0.0f))) {
679 auto upgrade_status =
682 : absl::FailedPreconditionError(
"Upgrade system not initialized");
683 if (upgrade_status.ok()) {
689 ImGui::CloseCurrentPopup();
692 LOG_ERROR(
"OverworldEditor",
"Upgrade failed: %s",
693 upgrade_status.message().data());
697 if (ImGui::Button(
ICON_MD_CANCEL " Cancel", ImVec2(150.0f, 0.0f))) {
698 ImGui::CloseCurrentPopup();
713 return absl::OkStatus();
737 "Normalized stale overworld selection to world=%d map=%d",
777 map_texture_->PrimeWorldMaps(world, process_texture_queue);
783 const int clamped_world = std::clamp(world, 0, 2);
785 const int world_start = clamped_world * 0x40;
787 if (maps_remaining <= 0) {
827 "overworld.entity_workbench"));
841 "overworld.entity_workbench"));
853 "overworld.entity_workbench"));
869 workbench->SetActiveEntity(item);
892 *items = snapshot.
items;
895 auto* selected_item =
900 workbench->SetActiveEntity(selected_item);
916 std::string description) {
918 if (ItemSnapshotsEqual(before, after)) {
923 std::move(before), std::move(after),
927 std::move(description)));
932 if (!selected_item) {
935 "Select an overworld item first (Item Mode: key 5)",
945 *selected_item, offset_x, offset_y);
949 if (duplicate_or.ok()) {
950 duplicate_result.
entity = *duplicate_or;
951 duplicate_result.
status = absl::OkStatus();
953 duplicate_result.
status = duplicate_or.status();
955 "Failed to duplicate overworld item: " +
956 std::string(duplicate_or.status().message());
959 if (!duplicate_result.
ok()) {
963 ?
"Failed to duplicate overworld item"
970 auto* duplicated_item =
975 workbench->SetActiveEntity(duplicated_item);
978 absl::StrFormat(
"Duplicate overworld item 0x%02X",
979 static_cast<int>(duplicated_item->id_)));
983 absl::StrFormat(
"Duplicated item 0x%02X",
984 static_cast<int>(duplicated_item->id_)),
992 if (!selected_item) {
997 auto status =
NudgeItem(selected_item, delta_x, delta_y);
1009 workbench->SetActiveEntity(selected_item);
1012 std::move(before_snapshot),
1013 absl::StrFormat(
"Move overworld item 0x%02X (%+d,%+d)",
1014 static_cast<int>(selected_item->id_), delta_x, delta_y));
1021 if (!selected_item) {
1027 const uint8_t deleted_item_id = selected_identity.
id_;
1028 absl::Status remove_status =
1029 absl::FailedPreconditionError(
"Entity mutation service not initialized");
1036 if (!remove_status.ok()) {
1044 auto* nearest_item =
1052 workbench->SetActiveEntity(nearest_item);
1059 absl::StrFormat(
"Delete overworld item 0x%02X",
1060 static_cast<int>(deleted_item_id)));
1065 absl::StrFormat(
"Deleted item 0x%02X (selected nearest 0x%02X)",
1066 static_cast<int>(deleted_item_id),
1067 static_cast<int>(nearest_item->id_)),
1071 absl::StrFormat(
"Deleted overworld item 0x%02X",
1072 static_cast<int>(deleted_item_id)),
1085 return absl::FailedPreconditionError(
"Clipboard unavailable");
1090 std::vector<int> ids;
1095 static_cast<int>(std::floor(std::min(start.x, end.x) / 16.0f));
1097 static_cast<int>(std::floor(std::max(start.x, end.x) / 16.0f));
1099 static_cast<int>(std::floor(std::min(start.y, end.y) / 16.0f));
1101 static_cast<int>(std::floor(std::max(start.y, end.y) / 16.0f));
1102 const int width = end_x - start_x + 1;
1103 const int height = end_y - start_y + 1;
1104 ids.reserve(width * height);
1107 for (
int y = start_y; y <= end_y; ++y) {
1108 for (
int x = start_x; x <= end_x; ++x) {
1117 return absl::OkStatus();
1125 return absl::OkStatus();
1127 return absl::FailedPreconditionError(
"Nothing selected to copy");
1132 return absl::FailedPreconditionError(
"Clipboard unavailable");
1135 return absl::FailedPreconditionError(
"Clipboard empty");
1139 return absl::FailedPreconditionError(
"No paste target");
1148 const ImVec2 anchor =
1149 ImVec2(scaled_anchor.x / scale, scaled_anchor.y / scale);
1152 const int tile16_x =
1154 const int tile16_y =
1157 auto& selected_world =
1164 const int superY = local_map / 8;
1165 const int superX = local_map % 8;
1172 if (width * height !=
static_cast<int>(ids.size())) {
1173 return absl::InternalError(
"Clipboard dimensions mismatch");
1176 bool any_changed =
false;
1177 for (
int dy = 0; dy < height; ++dy) {
1178 for (
int dx = 0; dx < width; ++dx) {
1179 const int id = ids[dy * width + dx];
1180 const int gx = tile16_x + dx;
1181 const int gy = tile16_y + dy;
1183 const int global_x = superX * 32 + gx;
1184 const int global_y = superY * 32 + gy;
1185 if (global_x < 0 || global_x >= 256 || global_y < 0 || global_y >= 256)
1187 const int old_tile_id = selected_world[global_x][global_y];
1188 if (old_tile_id ==
id) {
1193 selected_world[global_x][global_y] = id;
1203 return absl::OkStatus();
1209 return absl::OkStatus();
1218 return absl::OkStatus();
1228 const bool saving_maps =
1240 manifest, write_policy, ranges,
"overworld maps",
"OverworldEditor",
1247 if (profile.has_expanded_tile32) {
1252 if (profile.has_expanded_tile16) {
1273 return absl::OkStatus();
1293 auto now = std::chrono::steady_clock::now();
1312 .tile_changes = {{{x, y}, old_tile_id}},
1326 std::vector<OverworldTileChange> changes;
1328 for (
const auto& [coords, old_tile_id] :
1330 auto [x, y] = coords;
1331 int new_tile_id = world_tiles[x][y];
1332 changes.push_back({x, y, old_tile_id, new_tile_id});
1334 auto action = std::make_unique<OverworldTilePaintAction>(
1336 std::move(changes), &
overworld_, [
this]() { RefreshOverworldMap(); });
1345 return absl::FailedPreconditionError(
"MapPropertiesSystem not initialized");
1357 before.
value = before_value;
1362 if (after_value == before_value) {
1363 return absl::OkStatus();
1367 after.
value = after_value;
1374 return absl::OkStatus();
1378 const std::vector<OverworldPropertyEdit>& edits,
1379 const std::string& description,
bool record_undo) {
1381 return absl::FailedPreconditionError(
"MapPropertiesSystem not initialized");
1383 if (edits.empty()) {
1384 return absl::OkStatus();
1388 for (
const auto& edit : edits) {
1391 return absl::OkStatus();
1396 std::vector<OverworldPropertyEdit> before_edits;
1397 std::vector<OverworldPropertyEdit> after_edits;
1398 before_edits.reserve(edits.size());
1399 after_edits.reserve(edits.size());
1401 for (
const auto& edit : edits) {
1407 if (!before_value.ok()) {
1408 for (
auto it = before_edits.rbegin(); it != before_edits.rend(); ++it) {
1411 return before_value.status();
1415 before.
value = *before_value;
1416 const absl::Status apply_status =
1418 if (!apply_status.ok()) {
1419 for (
auto it = before_edits.rbegin(); it != before_edits.rend(); ++it) {
1422 return apply_status;
1426 if (!after_value.ok()) {
1428 for (
auto it = before_edits.rbegin(); it != before_edits.rend(); ++it) {
1431 return after_value.status();
1433 if (*after_value == *before_value) {
1438 after.
value = *after_value;
1439 before_edits.push_back(std::move(before));
1440 after_edits.push_back(std::move(after));
1443 if (after_edits.empty()) {
1444 return absl::OkStatus();
1447 const std::string action_description =
1449 ? absl::StrFormat(
"Edit %d overworld map properties",
1450 static_cast<int>(after_edits.size()))
1453 before_edits, after_edits,
1457 action_description));
1458 return absl::OkStatus();
1462 const std::string& type,
int id,
const std::string& label) {
1464 return absl::FailedPreconditionError(
"No project is open");
1468 const std::string before =
1472 const std::string after =
1474 if (after == before) {
1475 return absl::OkStatus();
1480 [
this,
type,
id](
const std::string& value) {
1484 absl::StrFormat(
"Rename %s 0x%02X",
type,
id)));
1485 return absl::OkStatus();
1503 LOG_DEBUG(
"OverworldEditor",
"Loading overworld.");
1519 LOG_DEBUG(
"OverworldEditor",
"Loading overworld graphics (optimized).");
1533 "Loading overworld tileset (deferred textures).");
1546 LOG_DEBUG(
"OverworldEditor",
"Loading overworld tile16 graphics.");
1575 return absl::OkStatus();
1580 const int depth = 0x10;
1581 for (
int i = 0; i < 3; i++)
1583 int width = sprite.width();
1584 int height = sprite.height();
1585 if (width == 0 || height == 0) {
1592 *sprite.preview_graphics());
1598 return absl::OkStatus();
1621 map_texture_ = std::make_unique<OverworldMapTextureCoordinator>(ctx);
1644 map_refresh_ = std::make_unique<MapRefreshCoordinator>(ctx);
1675 LOG_WARN(
"OverworldEditor",
"Failed to refresh selected Tile16 %d: %s",
1676 tile_id, status.message().data());
1684 const size_t session_id =
1709 return absl::OkStatus();
1734 const char* mode_label =
"Draw";
1737 mode_label =
"Entrances";
1740 mode_label =
"Exits";
1743 mode_label =
"Items";
1746 mode_label =
"Sprites";
1749 mode_label =
"Transports";
1752 mode_label =
"Music";
1757 mode_label =
"Mouse";
1760 mode_label =
"Draw";
1763 mode_label =
"Fill";
void set_dirty(bool dirty)
bool loaded() const
Check if the manifest has been loaded.
UndoManager undo_manager_
EditorDependencies dependencies_
void SetHostSurfaceHint(std::string hint)
Main UI class for editing overworld maps in A Link to the Past.
std::unique_ptr< UsageStatisticsCard > usage_stats_card_
absl::Status Clear() override
std::unique_ptr< MapPropertiesSystem > map_properties_system_
std::unique_ptr< OverworldCanvasRenderer > canvas_renderer_
OverworldEntityWorkbench * GetWorkbench()
Resolve the entity workbench window content (may be null).
void HandleMapInteraction()
bool overworld_canvas_fullscreen_
bool map_blockset_loaded_
void InitMapTextureCoordinator()
zelda3::OverworldEntranceTileTypes entrance_tiletypes_
void HandleTile16Edit()
Handle tile16 editing from context menu (MOUSE mode) Gets the tile16 under the cursor and opens the T...
std::optional< OverworldUndoPoint > current_paint_operation_
void PushItemUndoAction(OverworldItemsSnapshot before, std::string description)
absl::Status CheckForCurrentMap()
Check for map changes and refresh if needed.
void CreateUndoPoint(int map_id, int world, int x, int y, int old_tile_id)
absl::Status LoadScratchToSelection()
void ForceRefreshGraphics(int map_index)
void RequestTile16Selection(int tile_id)
void RestoreItemUndoSnapshot(const OverworldItemsSnapshot &snapshot)
std::vector< int > selected_tile16_ids_
absl::Status ApplyOverworldPropertyEdit(const OverworldPropertyEdit &edit, bool record_undo=true)
gfx::Bitmap current_gfx_bmp_
gfx::Tilemap tile16_blockset_
void InitCanvasNavigationManager()
Initialize the canvas navigation manager (called during Initialize)
void InitMapRefreshCoordinator()
Initialize the map refresh coordinator (called during Initialize)
std::optional< zelda3::OverworldItem > selected_item_identity_
void CycleTileSelection(int delta)
Tile16Editor tile16_editor_
std::unique_ptr< zelda3::OverworldUpgradeSystem > upgrade_system_
gui::Canvas ow_map_canvas_
void NotifyEntityModified(zelda3::GameEntity *entity)
Notify that an entity has been modified, marking ROM as dirty.
void SwitchToWorld(int world)
absl::Status Undo() override
void HandleEntityInsertion(const std::string &entity_type)
Handle entity insertion from context menu.
std::unique_ptr< MapRefreshCoordinator > map_refresh_
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > maps_bmp_
std::unique_ptr< OverworldMapTextureCoordinator > map_texture_
static bool NormalizeMapSelection(int ¤t_world, int ¤t_map)
Clamp a possibly stale world/map selection back into a valid overworld range.
bool PickTile16FromHoveredCanvas()
bool show_map_properties_panel_
void RefreshOverworldMap()
void CheckForOverworldEdits()
Check for tile edits - delegates to TilePaintingManager.
void UpdateBlocksetWithPendingTileChanges()
void RefreshMapProperties()
void ContributeStatus(StatusBar *status_bar) override
~OverworldEditor() override
void RefreshSiblingMapGraphics(int map_index, bool include_self=false)
gui::Canvas scratch_canvas_
void PrimeWorldMaps(int world, bool process_texture_queue=false)
absl::Status ApplyOverworldPropertyEdits(const std::vector< OverworldPropertyEdit > &edits, const std::string &description, bool record_undo=true)
void RefreshOverworldMapOnDemand(int map_index)
gui::Canvas current_gfx_canvas_
void Initialize() override
bool show_overlay_editor_
std::unique_ptr< OverworldSidebar > sidebar_
absl::Status Redo() override
void SetupCanvasAutomation()
std::chrono::steady_clock::time_point last_paint_time_
void InvalidateGraphicsCache(int map_id=-1)
Invalidate cached graphics for a specific map or all maps.
std::optional< int > pending_tile16_selection_after_gfx_
absl::Status RenameProjectResourceLabelWithUndo(const std::string &type, int id, const std::string &label)
absl::Status SaveCurrentSelectionToScratch()
zelda3::OverworldItem * GetSelectedItem()
Resolve selected item identity to the current live item pointer.
bool NormalizeCurrentSelectionState()
Clamp and synchronize stale map/world selection before panels draw.
bool DuplicateSelectedItem(int offset_x=16, int offset_y=0)
Duplicate selected item with optional pixel offset.
absl::Status RefreshMapPalette()
void DrawOverworldCanvas()
Draw the main overworld canvas.
gui::Canvas blockset_canvas_
absl::Status RefreshTile16Blockset()
zelda3::Overworld & overworld()
Access the underlying Overworld data.
void SetCurrentEntity(zelda3::GameEntity *entity)
Set the currently active entity for editing.
absl::Status LoadScratchPad()
void UpdateBlocksetSelectorState()
void FinalizePaintOperation()
std::unique_ptr< OverworldEntityRenderer > entity_renderer_
auto & GetWorldTiles(int world)
absl::Status Load() override
absl::Status UpdateGfxGroupEditor()
void EnsureMapTexture(int map_index)
Ensure a specific map has its texture created.
std::vector< gfx::Bitmap > sprite_previews_
std::unique_ptr< CanvasNavigationManager > canvas_nav_
absl::Status Copy() override
bool NudgeSelectedItem(int delta_x, int delta_y)
Move selected item by signed pixel deltas.
EntityEditMode entity_edit_mode_
std::unique_ptr< OverworldToolbar > toolbar_
GfxGroupEditor gfx_group_editor_
void ProcessDeferredTextures()
Create textures for deferred map bitmaps on demand.
absl::Status Update() final
std::unique_ptr< gui::TileSelectorWidget > blockset_selector_
absl::Status Paste() override
void ScrollBlocksetCanvasToCurrentTile()
Scroll the blockset canvas to show the current selected tile16.
static constexpr auto kPaintBatchTimeout
bool DeleteSelectedItem()
Delete selected item and preserve nearest-item selection continuity.
std::unique_ptr< TilePaintingManager > tile_painting_
gui::Canvas graphics_bin_canvas_
gfx::BitmapTable current_graphics_set_
bool show_custom_bg_color_editor_
zelda3::Overworld overworld_
absl::Status LoadGraphics()
Load the Bitmap objects for each OverworldMap.
absl::Status LoadSpriteGraphics()
gfx::IRenderer * renderer_
OverworldItemsSnapshot CaptureItemUndoSnapshot() const
absl::Status Save() override
void InitInteractionCoordinator()
std::unique_ptr< DebugWindowCard > debug_window_card_
void SelectMapForEditing(int map_id, bool respect_pin=true)
std::unique_ptr< OverworldInteractionCoordinator > interaction_coordinator_
zelda3::GameEntity * current_entity_
void HandleKeyboardShortcuts()
Handle overworld keyboard shortcuts and edit-mode hotkeys.
gui::Canvas properties_canvas_
std::unique_ptr< EntityMutationService > entity_mutation_service_
gfx::SnesPalette palette_
gfx::Bitmap tile16_blockset_bmp_
void ClearSelectedItem()
Clear active item selection.
void InitTilePaintingManager()
Initialize the tile painting manager (called after graphics load)
bool SelectItemByIdentity(const zelda3::OverworldItem &item_identity)
Select an overworld item using value identity matching.
Authoritative component for entity editing state and UI.
void OpenContextMenuFor(zelda3::GameEntity *entity)
void SetActiveEntity(zelda3::GameEntity *entity)
A session-aware status bar displayed at the bottom of the application.
void SetCustomSegment(const std::string &key, const std::string &value)
Set a custom segment with key-value pair.
void SetEditorMode(const std::string &mode)
Set the current editor mode or tool.
int current_tile16() const
absl::Status SetCurrentTile(int id)
void set_on_changes_committed(std::function< absl::Status(const std::vector< Tile16Commit > &)> callback)
bool has_pending_changes() const
Check if any tiles have uncommitted changes.
void RequestTileSwitch(int target_tile_id)
absl::Status Initialize(gfx::Bitmap &tile16_blockset_bmp, gfx::Bitmap ¤t_gfx_bmp, std::array< uint8_t, 0x200 > &all_tiles_types)
bool is_tile_modified(int tile_id) const
Check if a specific tile has pending changes.
void set_palette(const gfx::SnesPalette &palette)
void set_on_current_tile_changed(std::function< void(int)> callback)
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
void Push(std::unique_ptr< UndoAction > action)
absl::Status Redo()
Redo the top action. Returns error if stack is empty.
absl::Status Undo()
Undo the top action. Returns error if stack is empty.
size_t GetActiveSessionId() const
bool OpenWindow(size_t session_id, const std::string &base_window_id)
WindowContent * GetWindowContent(const std::string &window_id)
Get a WindowContent instance by ID.
bool ToggleWindow(size_t session_id, const std::string &base_window_id)
void RegisterPanelAlias(const std::string &legacy_base_id, const std::string &canonical_base_id)
Register a legacy panel ID alias that resolves to a canonical ID.
void MarkWindowRecentlyUsed(const std::string &window_id)
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
int RegisterPaletteListener(PaletteChangeCallback callback)
Register a callback for palette change notifications.
void UnregisterPaletteListener(int listener_id)
Unregister a palette change listener.
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
SDL_Surface * surface() const
RAII timer for automatic timing management.
auto selected_tile_pos() const
auto global_scale() const
auto select_rect_active() const
void SetUsageMode(CanvasUsage usage)
auto drawn_tile_position() const
void ClearContextMenuItems()
bool IsMouseHovering() const
const ImVector< ImVec2 > & points() const
auto selected_points() const
Base class for all overworld and dungeon entities.
enum yaze::zelda3::GameEntity::EntityType entity_type_
Represents an overworld exit that transitions from dungeon to overworld.
absl::Status SaveMap32Expanded()
Save expanded tile32 definitions (v1+ ROMs)
void set_current_world(int world)
absl::Status Load(Rom *rom)
Load all overworld data from ROM.
const std::vector< uint8_t > & current_graphics() const
absl::Status SaveMapProperties()
Save per-area graphics, palettes, and messages.
std::vector< std::pair< uint32_t, uint32_t > > GetProjectedWriteRanges() const
Get the projected write ranges (PC offsets) for overworld map saves.
absl::Status SaveMap32Tiles()
Save tile32 definitions to ROM.
const gfx::SnesPalette & current_area_palette() const
absl::Status SaveMap16Tiles()
Save tile16 definitions to ROM.
absl::Status CreateTile32Tilemap()
Build tile32 tilemap from current tile16 data.
auto overworld_map(int i) const
const std::vector< uint8_t > & tile16_blockset_data() const
absl::Status SaveCustomOverworldData()
Save all v2/v3 property tables using the ROM's current feature flags.
void set_current_map(int i)
absl::Status SaveEntrances()
Save entrance warp points to ROM.
absl::Status SaveExits()
Save exit return points to ROM.
absl::Status EnsureMapBuilt(int map_index)
Build a map on-demand if it hasn't been built yet.
absl::Status SaveItems()
Save hidden overworld items to ROM.
uint16_t GetTile(int x, int y) const
absl::Status SaveOverworldMaps()
Save compressed map tile data to ROM.
auto mutable_all_tiles_types()
auto mutable_sprites(int state)
absl::Status SaveMap16Expanded()
Save expanded tile16 definitions (v1+ ROMs)
absl::Status SaveMusic()
Save per-area music IDs.
#define ICON_MD_FORMAT_COLOR_FILL
#define LOG_DEBUG(category, format,...)
#define LOG_ERROR(category, format,...)
#define LOG_WARN(category, format,...)
#define PRINT_IF_ERROR(expression)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
bool ItemIdentityMatchesForUndo(const zelda3::OverworldItem &lhs, const zelda3::OverworldItem &rhs)
bool ItemSnapshotsEqual(const OverworldItemsSnapshot &lhs, const OverworldItemsSnapshot &rhs)
Editors are the view controllers for the application.
absl::Status RenameProjectResourceLabel(project::YazeProject *project, const std::string &type, int id, const std::string &label)
absl::Status ValidateHackManifestSaveConflicts(const core::HackManifest &manifest, project::RomWritePolicy write_policy, const std::vector< std::pair< uint32_t, uint32_t > > &ranges, absl::string_view save_scope, const char *log_tag, ToastManager *toast_manager)
absl::Status RemoveItemByIdentity(zelda3::Overworld *overworld, const zelda3::OverworldItem &item_identity)
Remove an item by value identity instead of pointer identity.
constexpr unsigned int kOverworldMapSize
absl::Status NudgeItem(zelda3::OverworldItem *item, int delta_x, int delta_y)
Move an item by pixel deltas with overworld bounds clamping.
zelda3::OverworldItem * FindNearestItemForSelection(zelda3::Overworld *overworld, const zelda3::OverworldItem &anchor_identity)
Find the best next item to keep selection continuity after deletion.
zelda3::OverworldItem * FindItemByIdentity(zelda3::Overworld *overworld, const zelda3::OverworldItem &item_identity)
Find a live item by value identity.
std::string DescribeOverworldPropertyEdit(const OverworldPropertyEdit &edit)
constexpr int kTile16Size
int EffectiveOverworldHoverMap(int hovered_map, bool canvas_hovered)
std::string FormatOverworldMapStatusSegment(int current_map, int hovered_map)
std::string GetProjectResourceLabel(const project::YazeProject *project, const std::string &type, int id)
absl::StatusOr< zelda3::OverworldItem * > DuplicateItemByIdentity(zelda3::Overworld *overworld, const zelda3::OverworldItem &item_identity, int offset_x, int offset_y)
Duplicate an existing item by identity with a positional offset.
Tilemap CreateTilemap(IRenderer *renderer, const std::vector< uint8_t > &data, int width, int height, int tile_size, int num_tiles, const SnesPalette &palette)
EmptyStateOptions EmptyLoading(const char *what, bool compact)
bool DrawEmptyState(const EmptyStateOptions &options)
Draw a centered empty-state block.
EmptyStateOptions EmptyNoRom(bool compact)
constexpr int kNumTile16Individual
constexpr int kNumOverworldMaps
constexpr int OverworldCustomASMHasBeenApplied
OverworldRomProfile DetectOverworldRomProfile(const Rom &rom)
absl::StatusOr< OverworldEntranceTileTypes > LoadEntranceTileTypes(Rom *rom)
#define RETURN_IF_ERROR(expr)
struct yaze::core::FeatureFlags::Flags::Overworld overworld
Callbacks for operations that remain in the OverworldEditor.
std::function< void()> refresh_overworld_map
std::function< absl::Status()> refresh_tile16_blockset
std::function< void(int, bool)> select_map_for_editing
std::function< bool()> is_entity_hovered
Returns true if an entity is currently hovered (for pan suppression).
std::function< bool()> pick_tile16_from_hovered_canvas
std::function< void(int)> ensure_map_texture
Shared state pointers that the navigation manager reads/writes.
bool * show_map_properties_panel
std::unique_ptr< gui::TileSelectorWidget > * blockset_selector
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp
gui::Canvas * ow_map_canvas
zelda3::Overworld * overworld
bool * is_dragging_entity
gfx::Tilemap * tile16_blockset
EditingMode * current_mode
project::YazeProject * project
ToastManager * toast_manager
SharedClipboard * shared_clipboard
gfx::IRenderer * renderer
WorkspaceWindowManager * window_manager
std::string error_message
zelda3::GameEntity * entity
Context struct holding all data dependencies for map refresh operations. All pointers/references must...
gfx::Tilemap * tile16_blockset
gfx::SnesPalette * palette
zelda3::Overworld * overworld
std::function< void(int map_index)> ensure_map_texture
Callback to ensure a map texture is created (stays in OverworldEditor)
gfx::IRenderer * renderer
Tile16Editor * tile16_editor
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp
gfx::Bitmap * current_gfx_bmp
bool * map_blockset_loaded
gfx::BitmapTable * current_graphics_set
std::function< void(int map_index)> refresh_map_on_demand
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp
gfx::IRenderer * renderer
zelda3::Overworld * overworld
Sink for high-level commands emitted by the interaction coordinator.
std::function< void(zelda3::GameEntity *) on_entity_double_click)
std::function< void()> on_pick_tile_from_hover
std::function< void()> on_toggle_fullscreen
std::function< void(zelda3::GameEntity *) on_entity_context_menu)
std::function< bool()> can_edit_items
std::function< void()> on_toggle_tile16_editor
std::function< void()> on_toggle_brush
std::function< void()> on_duplicate_selected
std::function< void(int, int, bool)> on_nudge_selected
std::function< void()> on_undo
std::function< void(EditingMode)> on_set_editor_mode
std::function< void()> on_redo
std::function< void()> on_activate_fill
std::function< void(EntityEditMode)> on_set_entity_mode
std::function< void()> on_toggle_lock
std::function< void()> on_toggle_item_list
Snapshot of overworld item list + current item selection.
std::vector< zelda3::OverworldItem > items
std::optional< zelda3::OverworldItem > selected_item_identity
static constexpr const char * kItemList
static constexpr const char * kTile16Editor
std::vector< int > overworld_tile16_ids
bool has_overworld_tile16
Callbacks for undo integration and map refresh.
std::function< void(int tile_id)> request_tile16_selection
When set, eyedropper routes here (guarded RequestTileSwitch path).
std::function< void(int map_index)> refresh_overworld_map_on_demand
std::function< void()> scroll_blockset_to_current_tile
std::function< void()> finalize_paint_operation
std::function< void()> refresh_overworld_map
std::function< void(int map_id, int world, int x, int y, int old_tile_id)> create_undo_point
Shared state for the tile painting system.
Tile16Editor * tile16_editor
gui::Canvas * ow_map_canvas
zelda3::Overworld * overworld
std::vector< int > * selected_tile16_ids
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp
gfx::Tilemap * tile16_blockset
EditingMode * current_mode
Bitmap atlas
Master bitmap containing all tiles.
core::HackManifest hack_manifest