13#define IM_PI 3.14159265358979323846f
30#include <unordered_map>
35#include "absl/status/status.h"
36#include "absl/strings/str_format.h"
37#include "imgui/imgui.h"
107 std::function<absl::Status(uint16_t)> apply)
108 : before_(before), after_(after), apply_(std::move(apply)) {}
109 absl::Status
Undo()
override {
return apply_(before_); }
110 absl::Status
Redo()
override {
return apply_(after_); }
111 std::string
Description()
const override {
return "Paint Lyra A0 terrain"; }
117 std::function<absl::Status(uint16_t)>
apply_;
132 for (
size_t i = 0; i < lhs.
items.size(); ++i) {
182 int& current_map,
int map_count) {
184 const int clamped_world = std::clamp(current_world, 0, 2);
185 int normalized_map = current_map;
186 if (normalized_map < 0 || normalized_map >= map_count) {
187 normalized_map = std::min(clamped_world * 0x40, map_count - 1);
190 const int normalized_world = std::clamp(normalized_map / 0x40, 0, 2);
192 normalized_world != current_world || normalized_map != current_map;
193 current_world = normalized_world;
194 current_map = normalized_map;
203 "Gfx Groups: selection syncs with the Graphics editor for this ROM "
205 "(this surface uses its own preview canvases).");
216 std::make_unique<EntityMutationService>(
overworld_);
237 [
this](
int map_id) -> absl::Status {
243 [
this](
int map_index,
bool respect_pin) {
251 [
this](
const std::vector<OverworldPropertyEdit>& edits,
252 const std::string& description) {
256 [
this](
const std::string&
type,
int id,
const std::string& label) {
269 [
this](
const std::string&
type,
int id,
const std::string& label) {
275 toolbar_ = std::make_unique<OverworldToolbar>();
276 toolbar_->on_story_changed = [
this](
int state) {
280 sidebar_->draw_project_tools = [
this](
int map_id,
int& state) {
286 toolbar_->on_world_changed = [
this](
int world) {
295 toolbar_->on_insert_item = [
this]() {
298 toolbar_->on_open_map_properties = [
this]() {
301 toolbar_->on_toggle_overlay_preview = [
this]() {
304 toolbar_->is_overlay_preview_enabled = [
this]() {
307 toolbar_->on_toggle_grid = [
this]() {
310 toolbar_->is_grid_visible = [
this]() {
313 toolbar_->on_toggle_entities = [
this]() {
316 toolbar_->are_entities_visible = [
this]() {
328 toolbar_->on_center_map = [
this]() {
334 toolbar_->on_toggle_overlay_preview = [
this]() {
337 toolbar_->is_overlay_preview_enabled = [
this]() {
340 toolbar_->on_upgrade_rom_version = [
this](int) {
341 ImGui::OpenPopup(
"UpgradeROMVersion");
361 [
this](
int map_id) {
JumpToMap(map_id); });
363 [
this](
const char* name) -> std::string {
389 const int step = shift_held ? 16 : 1;
396 "overworld.entity_workbench"));
406 switch (entity->entity_type_) {
437 std::make_unique<OverworldInteractionCoordinator>(std::move(sink));
484 int y) -> absl::StatusOr<uint16_t> {
486 return absl::FailedPreconditionError(
"Lyra terrain is unavailable");
490 int width,
int height,
506 tile_painting_ = std::make_unique<TilePaintingManager>(deps, callbacks);
555 canvas_nav_ = std::make_unique<CanvasNavigationManager>();
579 const Rom& replacement)
const {
586 return absl::OkStatus();
588 return absl::FailedPreconditionError(
589 "Lyra canvas session replacement requires a fresh editor session");
595 return absl::FailedPreconditionError(
596 "Publish project graphics before reloading overworld data");
598 LOG_DEBUG(
"OverworldEditor",
"Loading overworld.");
600 return absl::FailedPreconditionError(
"ROM not loaded");
603 return absl::FailedPreconditionError(
604 "Save the Lyra terrain draft before reloading overworld data");
608 return absl::FailedPreconditionError(
609 "Invalid Lyra descriptor; overworld loading refused");
617 return absl::OkStatus();
622 return absl::FailedPreconditionError(
623 "Lyra canvas session replacement requires a fresh editor session");
648 return absl::OkStatus();
652 FinishScratchEdit(
"Edit scratch layout");
653 lyra_canvas_.FinishStroke(undo_manager_);
654 FinalizePaintOperation();
661 if (collision_types.ok()) {
664 LOG_WARN(
"OverworldEditor",
"Collision labels unavailable: %s",
665 collision_types.status().ToString().c_str());
674 [
this](
int tile16_id,
int quadrant) {
682 return absl::StrFormat(
"Placed %d times (%s)", count,
687 [
this](
const std::vector<Tile16Commit>&) {
698 [
this](
const std::string& entity_type,
723 [
this](
const std::string& group_name,
int palette_index) {
729 map_refresh_->RefreshPaletteUsers(group_name, palette_index);
731 LOG_DEBUG(
"OverworldEditor",
"Registered as palette listener (ID: %d)",
748 if (!scratch_status.ok()) {
749 LOG_WARN(
"OverworldEditor",
"Failed to load scratch pad: %s",
750 std::string(scratch_status.message()).c_str());
759 return absl::OkStatus();
763 state = std::clamp(state, 0, 2);
774 map->set_game_state(state);
786 bool refresh_selection =
false;
789 if (overworld_map !=
nullptr) {
790 overworld_map->set_game_state(std::clamp(
game_state_, 0, 2));
795 if (overworld_map !=
nullptr && !
maps_bmp_[map].modified() &&
796 overworld_map->SourceSheetsChanged()) {
801 if (refresh_selection) {
815 return absl::OkStatus();
820 return absl::OkStatus();
864 ImGui::SetNextWindowSize(ImVec2(400, 500), ImGuiCond_FirstUseEver);
878 ImGui::SetNextWindowSize(ImVec2(500, 450), ImGuiCond_FirstUseEver);
879 if (ImGui::Begin(
ICON_MD_LAYERS " Visual Effects Editor###OverlayEditor",
895 workbench->DrawPopups();
898 if (ImGui::BeginPopupModal(
"UpgradeROMVersion",
nullptr,
899 ImGuiWindowFlags_AlwaysAutoResize)) {
903 tr(
"This will apply the ZSCustomOverworld ASM patch to your ROM,\n"
904 "enabling advanced overworld features."));
907 const uint8_t current_version =
910 ImGui::Text(tr(
"Current Version: %s"),
911 current_version == 0xFF
913 : absl::StrFormat(
"v%d", current_version).c_str());
915 static int target_version = 3;
916 ImGui::RadioButton(tr(
"v2 (Basic features)"), &target_version, 2);
918 ImGui::RadioButton(tr(
"v3 (All features)"), &target_version, 3);
922 if (ImGui::Button(
ICON_MD_CHECK " Apply Upgrade", ImVec2(150.0f, 0.0f))) {
923 auto upgrade_status =
926 : absl::FailedPreconditionError(
"Upgrade system not initialized");
927 if (upgrade_status.ok()) {
933 ImGui::CloseCurrentPopup();
936 LOG_ERROR(
"OverworldEditor",
"Upgrade failed: %s",
937 upgrade_status.message().data());
941 if (ImGui::Button(
ICON_MD_CANCEL " Cancel", ImVec2(150.0f, 0.0f))) {
942 ImGui::CloseCurrentPopup();
957 return absl::OkStatus();
970 return absl::FailedPreconditionError(
971 "Publish project graphics before Save Project");
985 return absl::OkStatus();
995 return absl::OkStatus();
1001 return absl::FailedPreconditionError(
1002 "Publish project graphics before Save Project As");
1017 bool changed =
false;
1019 const int normalized =
1021 const int world = normalized / 0x40;
1042 "Normalized stale overworld selection to world=%d map=%d",
1057 if (!project_terrain && !map) {
1075 const bool tracking_paint = respect_pin &&
1079 if (!tracking_paint) {
1082 if (!tracking_paint || !project_terrain) {
1088 if (project_terrain) {
1114 map_texture_->PrimeWorldMaps(world, process_texture_queue);
1121 const int clamped_world = std::clamp(world, 0, 2);
1123 const int world_start = clamped_world * 0x40;
1125 if (maps_remaining <= 0) {
1166 "overworld.entity_workbench"));
1180 "overworld.entity_workbench"));
1195 "overworld.entity_workbench"));
1211 workbench->SetActiveEntity(item);
1234 *items = snapshot.
items;
1237 auto* selected_item =
1239 if (selected_item) {
1242 workbench->SetActiveEntity(selected_item);
1258 std::string description) {
1260 if (ItemSnapshotsEqual(before, after)) {
1265 std::move(before), std::move(after),
1269 std::move(description)));
1274 if (!selected_item) {
1277 "Select an overworld item first (click one, or Items mode: 5)",
1287 *selected_item, offset_x, offset_y);
1290 offset_x, offset_y);
1291 if (duplicate_or.ok()) {
1292 duplicate_result.
entity = *duplicate_or;
1293 duplicate_result.
status = absl::OkStatus();
1295 duplicate_result.
status = duplicate_or.status();
1297 "Failed to duplicate overworld item: " +
1298 std::string(duplicate_or.status().message());
1301 if (!duplicate_result.
ok()) {
1305 ?
"Failed to duplicate overworld item"
1312 auto* duplicated_item =
1317 workbench->SetActiveEntity(duplicated_item);
1320 absl::StrFormat(
"Duplicate overworld item 0x%02X",
1321 static_cast<int>(duplicated_item->id_)));
1325 absl::StrFormat(
"Duplicated item 0x%02X",
1326 static_cast<int>(duplicated_item->id_)),
1334 if (!selected_item) {
1339 auto status =
NudgeItem(selected_item, delta_x, delta_y);
1351 workbench->SetActiveEntity(selected_item);
1354 std::move(before_snapshot),
1355 absl::StrFormat(
"Move overworld item 0x%02X (%+d,%+d)",
1356 static_cast<int>(selected_item->id_), delta_x, delta_y));
1363 if (!selected_item) {
1369 const uint8_t deleted_item_id = selected_identity.
id_;
1370 absl::Status remove_status =
1371 absl::FailedPreconditionError(
"Entity mutation service not initialized");
1378 if (!remove_status.ok()) {
1386 auto* nearest_item =
1394 workbench->SetActiveEntity(nearest_item);
1401 absl::StrFormat(
"Delete overworld item 0x%02X",
1402 static_cast<int>(deleted_item_id)));
1407 absl::StrFormat(
"Deleted item 0x%02X (selected nearest 0x%02X)",
1408 static_cast<int>(deleted_item_id),
1409 static_cast<int>(nearest_item->id_)),
1413 absl::StrFormat(
"Deleted overworld item 0x%02X",
1414 static_cast<int>(deleted_item_id)),
1433 return absl::FailedPreconditionError(
"Clipboard unavailable");
1441 return absl::OkStatus();
1450 return absl::OkStatus();
1452 return absl::FailedPreconditionError(
"Nothing selected to copy");
1457 return absl::FailedPreconditionError(
"Lyra preview is read-only");
1460 return absl::FailedPreconditionError(
"Clipboard unavailable");
1463 return absl::FailedPreconditionError(
"Clipboard empty");
1466 return absl::FailedPreconditionError(
"Tile painting is unavailable");
1470 clipboard.overworld_height,
1471 clipboard.overworld_tile16_ids});
1475 int map_id,
const std::vector<GuardedTileCell>& cells) {
1477 return absl::FailedPreconditionError(
"Lyra preview is read-only");
1480 return absl::FailedPreconditionError(
"Overworld is not loaded");
1484 return absl::OutOfRangeError(
"Stencil map must be a ROM overworld map");
1488 return absl::FailedPreconditionError(
"Stencil map could not be selected");
1496 return absl::OkStatus();
1501 ImGui::TextDisabled(
"Lyra preview: graphics editing unavailable");
1502 return absl::OkStatus();
1509 return absl::OkStatus();
1519 return absl::FailedPreconditionError(
1520 "Overworld save transaction is already active");
1524 return absl::OkStatus();
1545 return absl::FailedPreconditionError(
1546 "Publish project graphics before Save ROM (Edit / Import Project "
1550 if (
rom_ ==
nullptr) {
1551 return absl::FailedPreconditionError(
"No ROM for overworld sprites");
1560 const bool saving_sprites =
1563 if (saving_sprites) {
1568 std::vector<std::pair<uint32_t, uint32_t>> ranges;
1569 for (
const auto& write : sprite_plan) {
1570 ranges.emplace_back(write.address, write.address + write.bytes.size());
1580 const bool saving_maps =
1592 manifest, write_policy, ranges,
"overworld maps",
"OverworldEditor",
1599 if (profile.has_expanded_tile32) {
1604 if (profile.has_expanded_tile16) {
1625 if (saving_sprites) {
1628 save_transaction.
Commit();
1629 return absl::OkStatus();
1636 return absl::FailedPreconditionError(
"Only Lyra A0 terrain is writable");
1639 auto apply = [
this, x, y](uint16_t value) -> absl::Status {
1644 return absl::OkStatus();
1648 if (before == tile) {
1649 return absl::OkStatus();
1653 std::make_unique<LyraTerrainPaintAction>(before, tile, std::move(apply)));
1654 return absl::OkStatus();
1659 return absl::FailedPreconditionError(
"Lyra A0 terrain writer unavailable");
1662 const std::vector<std::pair<uint32_t, uint32_t>> ranges = {
1665 {0x14701C, 0x147020},
1666 {0x14724C, 0x147250},
1667 {0x14725C, 0x147260}};
1676 return absl::OkStatus();
1696 auto now = std::chrono::steady_clock::now();
1713 .tile_changes = {{{x, y}, old_tile_id}},
1725 std::vector<OverworldTileChange> changes;
1727 for (
const auto& [coords, old_tile_id] :
1729 auto [x, y] = coords;
1730 int new_tile_id = world_tiles[x][y];
1731 changes.push_back({x, y, old_tile_id, new_tile_id});
1733 auto action = std::make_unique<OverworldTilePaintAction>(
1735 std::move(changes), &
overworld_, std::function<
void()>{},
1736 [
this](
int map_id) {
1737 maps_bmp_[map_id].set_modified(true);
1738 RefreshOverworldMapOnDemand(map_id);
1749 return absl::FailedPreconditionError(
"Lyra preview is read-only");
1752 return absl::FailedPreconditionError(
"MapPropertiesSystem not initialized");
1764 before.
value = before_value;
1769 if (after_value == before_value) {
1770 return absl::OkStatus();
1774 after.
value = after_value;
1781 return absl::OkStatus();
1785 const std::vector<OverworldPropertyEdit>& edits,
1786 const std::string& description,
bool record_undo) {
1788 return absl::FailedPreconditionError(
"Lyra preview is read-only");
1791 return absl::FailedPreconditionError(
"MapPropertiesSystem not initialized");
1793 if (edits.empty()) {
1794 return absl::OkStatus();
1798 for (
const auto& edit : edits) {
1801 return absl::OkStatus();
1806 std::vector<OverworldPropertyEdit> before_edits;
1807 std::vector<OverworldPropertyEdit> after_edits;
1808 before_edits.reserve(edits.size());
1809 after_edits.reserve(edits.size());
1811 for (
const auto& edit : edits) {
1817 if (!before_value.ok()) {
1818 for (
auto it = before_edits.rbegin(); it != before_edits.rend(); ++it) {
1821 return before_value.status();
1825 before.
value = *before_value;
1826 const absl::Status apply_status =
1828 if (!apply_status.ok()) {
1829 for (
auto it = before_edits.rbegin(); it != before_edits.rend(); ++it) {
1832 return apply_status;
1836 if (!after_value.ok()) {
1838 for (
auto it = before_edits.rbegin(); it != before_edits.rend(); ++it) {
1841 return after_value.status();
1843 if (*after_value == *before_value) {
1848 after.
value = *after_value;
1849 before_edits.push_back(std::move(before));
1850 after_edits.push_back(std::move(after));
1853 if (after_edits.empty()) {
1854 return absl::OkStatus();
1857 const std::string action_description =
1859 ? absl::StrFormat(
"Edit %d overworld map properties",
1860 static_cast<int>(after_edits.size()))
1863 before_edits, after_edits,
1867 action_description));
1868 return absl::OkStatus();
1872 const std::string& type,
int id,
const std::string& label) {
1874 return absl::FailedPreconditionError(
"Lyra preview is read-only");
1877 return absl::FailedPreconditionError(
"No project is open");
1881 const std::string before =
1885 const std::string after =
1887 if (after == before) {
1888 return absl::OkStatus();
1893 [
this,
type,
id](
const std::string& value) {
1897 absl::StrFormat(
"Rename %s 0x%02X",
type,
id)));
1898 return absl::OkStatus();
1905 return absl::FailedPreconditionError(
"Lyra preview is read-only");
1916 return absl::FailedPreconditionError(
"Lyra preview is read-only");
1927 return absl::OkStatus();
1941 LOG_DEBUG(
"OverworldEditor",
"Loading overworld.");
1958 return absl::OkStatus();
1977 LOG_DEBUG(
"OverworldEditor",
"Loading overworld graphics (optimized).");
1991 "Loading overworld tileset (deferred textures).");
2004 LOG_DEBUG(
"OverworldEditor",
"Loading overworld tile16 graphics.");
2033 return absl::OkStatus();
2038 const int depth = 0x10;
2039 for (
int i = 0; i < 3; i++)
2041 int width = sprite.width();
2042 int height = sprite.height();
2043 if (width == 0 || height == 0) {
2050 *sprite.preview_graphics());
2056 return absl::OkStatus();
2088 map_texture_ = std::make_unique<OverworldMapTextureCoordinator>(ctx);
2111 map_refresh_ = std::make_unique<MapRefreshCoordinator>(ctx);
2128 return absl::FailedPreconditionError(
"Overworld ROM session is not loaded");
2130 if (tile16_id < 0 ||
2132 return absl::InvalidArgumentError(
"Selected Tile16 is unavailable");
2135 if (manager ==
nullptr) {
2136 return absl::FailedPreconditionError(
"Graphics editor is unavailable");
2143 if (map ==
nullptr || !map->is_built()) {
2144 return absl::FailedPreconditionError(
"Selected overworld map is not built");
2146 if (map->HasGraphicsPreview()) {
2147 return absl::UnimplementedError(
2148 "Project graphics overrides need an explicit editable source map");
2158 auto preview_map = std::make_shared<zelda3::OverworldMap>(*map);
2160 context->resolve_live_source = [
this, owner, source_map_id, tile16_id,
2164 return absl::FailedPreconditionError(
"Overworld source session changed");
2169 if (!live || live->HasGraphicsPreview()) {
2170 return absl::UnimplementedError(
2171 "Project graphics overrides have no writable source");
2173 live->LoadAreaGraphics();
2178 return resolved.status();
2179 fresh = std::move(*resolved);
2180 return absl::OkStatus();
2182 context->limitation +=
" Palette colors follow live edits.";
2183 context->refresh_palettes = [
this, preview_map, owner, tile16_id, quadrant](
2187 return absl::FailedPreconditionError(
"Overworld source session changed");
2193 if (!refreshed.ok())
2194 return refreshed.status();
2197 context->preview_revision = [
this, owner,
2198 source_map_id]() -> absl::StatusOr<uint64_t> {
2200 return absl::FailedPreconditionError(
"Overworld source session changed");
2201 constexpr uint64_t kPrime = 1099511628211ULL;
2202 uint64_t hash = 1469598103934665603ULL;
2203 auto add = [&](uint64_t value) {
2204 hash = (hash ^ value) * kPrime;
2207 for (
const auto& quadrant : tile.tiles_info)
2209 const auto& placements =
2213 const int x0 = (local % 8) * 32;
2214 const int y0 = (local / 8) * 32;
2215 for (
int x = x0; x < x0 + 32; ++x) {
2216 if (x >=
static_cast<int>(placements.size()) ||
2217 y0 + 32 >
static_cast<int>(placements[x].size()))
2218 return absl::FailedPreconditionError(
"Overworld source grid changed");
2219 for (
int y = y0; y < y0 + 32; ++y)
2220 add(placements[x][y]);
2225 [
this, preview_map, owner,
2226 source_map_id]() -> absl::StatusOr<usage_preview::PreviewImage> {
2228 return absl::FailedPreconditionError(
2229 "Overworld graphics source session has changed");
2231 std::set<uint16_t> ids;
2232 for (
int slot = 0; slot < 8; ++slot) {
2233 ids.insert(preview_map->static_graphics(slot));
2235 ids.insert(preview_map->animated_sheet());
2236 preview_map->SetGraphicsSheetOverrides(
2247 image.
pixels = preview_map->bitmap_data();
2249 const auto& palette = preview_map->current_palette();
2250 for (
size_t i = 0; i < palette.size() && i < image.
colors.size(); ++i) {
2251 const auto rgb = palette[i].rgb();
2253 SDL_Color{
static_cast<uint8_t
>(rgb.x),
static_cast<uint8_t
>(rgb.y),
2254 static_cast<uint8_t
>(rgb.z), 255};
2258 context->return_to_source = [
this, manager, source_map_id, tile16_id]() {
2267 auto* editor_set = manager->GetCurrentEditorSet();
2268 if (editor_set ==
nullptr || editor_set->GetGraphicsEditor() ==
nullptr) {
2269 return absl::FailedPreconditionError(
"Graphics editor is unavailable");
2273 editor_set->GetGraphicsEditor()->OpenInContext(std::move(*
context)));
2275 return absl::OkStatus();
2296 LOG_WARN(
"OverworldEditor",
"Failed to refresh selected Tile16 %d: %s",
2297 tile_id, status.message().data());
2333 return absl::OkStatus();
2377 const int x = local % 8 + dx;
2378 const int y = local / 8 + dy;
2379 if (x < 0 || x >= 8 || y < 0 || y >= rows) {
2382 const int target = world * 0x40 + y * 8 + x;
2403 const int world = std::clamp(map_id / 0x40, 0, 2);
2461 if (!window_manager) {
2465 if (window_manager->IsWindowOpen(session_id,
2469 window_manager->OpenWindowFloating(session_id,
2472 const std::string window_name = window_manager->GetWorkspaceWindowName(
2474 if (!window_name.empty()) {
2475 ImGui::SetWindowFocus(window_name.c_str());
2482 const size_t session_id =
2485 const bool properties_open =
2486 window_manager && window_manager->IsWindowOpen(
2488 if (ImGui::MenuItem(
"Map Properties...",
"M", properties_open)) {
2494 if (ImGui::BeginMenu(
"Scratch Workspace")) {
2497 int current_page_idx = 0;
2498 for (
size_t i = 0; i < pages.size(); ++i) {
2500 current_page_idx =
static_cast<int>(i);
2504 if (ImGui::MenuItem(
"Previous Layout",
nullptr,
false,
2505 current_page_idx > 0)) {
2511 if (ImGui::MenuItem(
2512 "Next Layout",
nullptr,
false,
2513 current_page_idx <
static_cast<int>(pages.size()) - 1)) {
2519 if (ImGui::MenuItem(
"New Layout",
nullptr,
false,
2526 if (ImGui::MenuItem(
"Duplicate Layout",
nullptr,
false,
2533 if (ImGui::MenuItem(
"Clear Layout")) {
2536 if (ImGui::MenuItem(
"Delete Layout",
nullptr,
false, pages.size() > 1)) {
2544 const bool can_capture = (active_brush && active_brush->valid());
2545 if (ImGui::MenuItem(
2546 "Capture Selection to Scratch",
nullptr,
false,
2550 if (ImGui::MenuItem(
"Copy Layout as Brush",
nullptr,
false, page.in_use)) {
2553 if (ImGui::MenuItem(
"Refresh Preview")) {
2561 if (ImGui::BeginMenu(
"Entities")) {
2564 if (ImGui::MenuItem(
"All Entities (Select Mode)",
nullptr,
2568 if (ImGui::MenuItem(
"Entrances Mode",
nullptr,
2572 if (ImGui::MenuItem(
"Exits Mode",
nullptr,
2576 if (ImGui::MenuItem(
"Items Mode",
nullptr,
2580 if (ImGui::MenuItem(
"Sprites Mode",
nullptr,
2587 if (ImGui::BeginMenu(
"Tiles & Graphics")) {
2588 if (ImGui::MenuItem(
"Tile16 Editor",
nullptr,
false)) {
2591 if (ImGui::MenuItem(
"Item List",
nullptr,
false)) {
2604 if (ImGui::BeginMenu(
"Diagnostics")) {
2605 if (ImGui::MenuItem(
"Usage Statistics",
nullptr,
false)) {
2606 if (window_manager) {
2610 if (ImGui::MenuItem(
"Debug Window",
nullptr,
false)) {
2611 if (window_manager) {
2623 ImGui::EndDisabled();
2631 window_manager->IsWindowOpen(window_manager->GetActiveSessionId(),
2650 const int tx =
static_cast<int>(mouse.x / (16.0f * scale)) % 32;
2651 const int ty =
static_cast<int>(mouse.y / (16.0f * scale)) % 32;
2657 const char* mode_label;
2660 mode_label =
"Entrances";
2663 mode_label =
"Exits";
2666 mode_label =
"Items";
2669 mode_label =
"Sprites";
2672 mode_label =
"Transports";
2675 mode_label =
"Music";
2680 mode_label =
"Mouse";
2683 mode_label =
"Draw";
2686 mode_label =
"Fill";
2689 mode_label =
"Draw";
2694 mode_label =
"Draw";
2706 snapshot.
title =
"Overworld";
2707 snapshot.
subtitle =
"Load a ROM to inspect map context";
2717 {.id =
"map", .label =
"Map", .value = map.
map_id_label},
2718 {.id =
"parent", .label =
"Parent", .value = map.
parent_label},
2722 {.id =
"graphics", .label =
"Graphics", .value = map.
area_gfx_label},
2727 const auto belongs_to_area = [owner_map](
const auto& entity) {
2728 return static_cast<int>(entity.map_id_) == owner_map;
2736 .value = std::to_string(std::count_if(
2737 sprites.begin(), sprites.end(),
2739 return static_cast<int>(sprite.map_id()) == owner_map;
2743 .value = std::to_string(
2744 std::count_if(items.begin(), items.end(), belongs_to_area))},
2746 .label =
"Entrances",
2752 .value = exits ? std::to_string(std::count_if(
2753 exits->begin(), exits->end(), belongs_to_area))
2764 .message =
"Map context is pinned; cursor hover will not replace it.",
2769 .id =
"tile_selection",
2771 .message = absl::StrFormat(
"%zu Tile16 cells selected",
2777 "overworld.properties",
2778 "overworld.entities",
2782 {.id =
"open_properties",
2783 .label =
"Map Properties",
2784 .target =
"overworld.properties"},
2785 {.id =
"open_entities",
2786 .label =
"Entity Workbench",
2787 .target =
"overworld.entity_workbench"},
2788 {.id =
"open_tile16",
2789 .label =
"Tile16 Selector",
2790 .target =
"overworld.tile16_selector"},
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
absl::Status CheckLayoutWritable() const
absl::Status AttachLyraPrivateReservation(const core::HackManifest &manifest)
rom::LyraLayoutInspection InspectLyraLayout() const
void set_dirty(bool dirty)
absl::Status SaveLyraA0TerrainAs(const std::array< uint16_t, 256 > &tiles, const std::string &filename)
bool loaded() const
Check if the manifest has been loaded.
static constexpr int kFirstMap
absl::StatusOr< uint16_t > tile(int global_x, int global_y) const
The EditorManager controls the main editor window and manages the various editor classes.
EditorContext context() const
UndoManager undo_manager_
project::YazeProject * project() const
EditorDependencies dependencies_
void SetHostSurfaceHint(std::string hint)
void DrawProperties(int map_id, int &state, zelda3::Overworld &overworld, UndoManager &history)
absl::Status PaintPattern(const TileBrush &brush, int x, int y, int width, int height, bool finalize, UndoManager &history)
absl::Status SaveAs(project::YazeProject *project, const std::string &project_path, zelda3::Overworld &overworld)
bool entity_placement_active() const
gfx::Bitmap & MapAtlas(int map_id)
absl::Status Create(project::YazeProject *project, zelda3::Overworld &overworld)
const core::LyraTerrainDocument * document() const
absl::Status Load(project::YazeProject *project, zelda3::Overworld &overworld)
absl::Status Save(project::YazeProject *project, zelda3::Overworld &overworld)
void FinishStroke(UndoManager &history)
absl::Status Open(project::YazeProject *project, const std::string &path, zelda3::Overworld &overworld)
Main UI class for editing overworld maps in A Link to the Past.
void ToggleItemListWindow()
bool IsProjectTerrainMap(int map_id) const
bool grid_visible() const
void LocateOverworldTile(int map_id, int world_x, int world_y)
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 DrawEditorMenu() override
int DisplayedMapCount() const
void InitMapTextureCoordinator()
zelda3::OverworldEntranceTileTypes entrance_tiletypes_
absl::Status SaveProjectTerrainAs(project::YazeProject *project, const std::string &project_path)
void CenterOverworldView()
std::array< gfx::Bitmap, zelda3::kExpandedMapCount > maps_bmp_
EditorContextSnapshot BuildContextSnapshot() const override
std::string graphics_import_pack_
std::optional< OverworldUndoPoint > current_paint_operation_
absl::Status BeginSaveTransaction() override
void PushItemUndoAction(OverworldItemsSnapshot before, std::string description)
absl::Status CheckForCurrentMap()
Check for map changes and refresh if needed.
absl::Status PrepareProjectSave()
void CreateUndoPoint(int map_id, int world, int x, int y, int old_tile_id)
absl::StatusOr< int > ApplyTile16Stencil(int map_id, const std::vector< GuardedTileCell > &cells)
Select map_id and apply a guarded stencil as one undoable paint.
void ClearSelectionBrush()
void CommitSaveTransaction() override
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)
zelda3::GameData * game_data_
gfx::Bitmap current_gfx_bmp_
gfx::Tilemap tile16_blockset_
absl::Status ClearScratchSpace()
void InitCanvasNavigationManager()
Initialize the canvas navigation manager (called during Initialize)
zelda3::OverworldGraphicsPreview graphics_preview_baseline_
void JumpToMap(int map_id)
void InitMapRefreshCoordinator()
Initialize the map refresh coordinator (called during Initialize)
ScratchWorkspace scratch_workspace_
void RequestItemInsertPopup(const std::optional< OverworldContextTarget > &target)
std::string ProjectGraphicsPath() const
std::optional< zelda3::OverworldItem > selected_item_identity_
void CycleTileSelection(int delta)
void SetSelectionBrush(TileBrush brush)
absl::Status RefreshMapPalette(int map_id=-1)
void ResetOverworldView()
absl::Status PaintLyraA0Terrain(int map_id, int x, int y, uint16_t tile)
void OpenMapPropertiesWindow()
Tile16Editor tile16_editor_
std::unique_ptr< zelda3::OverworldUpgradeSystem > upgrade_system_
void RequestJumpToEntrance(int entrance_id)
Trigger a jump to a dungeon entrance.
gui::Canvas ow_map_canvas_
bool Tile16MenuEnabled() const
absl::Status SyncProjectGraphicsPreview(bool force=false)
void HandleEntityInsertion(const std::string &entity_type, const OverworldContextTarget &target)
Handle entity insertion from context menu.
void NotifyEntityModified(zelda3::GameEntity *entity)
Notify that an entity has been modified, marking ROM as dirty.
void SwitchToWorld(int world)
absl::Status CheckRomReplacement(const Rom &replacement) const
absl::Status OpenLyraTerrain(const std::string &path)
absl::Status Undo() override
void ToggleTile16EditorWindow()
void SetPreviewStoryState(int state)
std::unique_ptr< MapRefreshCoordinator > map_refresh_
void MarkScratchSpaceDirty()
void SelectAdjacentMap(int dx, int dy)
Alt+Arrow: select the neighbouring screen in the world grid and center it.
std::unique_ptr< OverworldMapTextureCoordinator > map_texture_
bool is_lyra_preview() const
bool PickTile16FromHoveredCanvas()
void RefreshOverworldMap()
void CheckForOverworldEdits()
Check for tile edits - delegates to TilePaintingManager.
void DrawEditMenuItems() override
void ContributeStatus(StatusBar *status_bar) override
~OverworldEditor() override
gui::Canvas scratch_canvas_
void PrimeWorldMaps(int world, bool process_texture_queue=false)
absl::Status FlushScratchPadIfDirty()
bool SampleContextTile16(const OverworldContextTarget &target)
absl::Status ApplyOverworldPropertyEdits(const std::vector< OverworldPropertyEdit > &edits, const std::string &description, bool record_undo=true)
void set_current_map(int map_id)
Set the current map for editing (also updates world)
void RefreshOverworldMapOnDemand(int map_index)
void RefreshMapsForSheetEdits()
Mark maps for a graphics rebuild when a sheet they use changed in the session's sheet store (an unsav...
gui::Canvas current_gfx_canvas_
absl::Status RefreshPendingProjectGraphics()
void Initialize() override
bool show_overlay_editor_
std::unique_ptr< OverworldSidebar > sidebar_
absl::Status Redo() override
void SetupCanvasAutomation()
int GetTile16UsageCount(int tile_id) const
const TileBrush * selection_brush() const
void FinishScratchEdit(const std::string &description)
void DrawProjectGraphicsSource()
std::optional< int > pending_tile16_selection_after_gfx_
void HandleTile16Edit(const OverworldContextTarget &target)
Handle tile16 editing from context menu (MOUSE mode) Opens the Tile16 captured at menu-open through t...
static bool NormalizeMapSelection(int ¤t_world, int ¤t_map, int map_count=zelda3::kNumOverworldMaps)
Clamp a possibly stale world/map selection back into a valid overworld range.
void SetEditingMode(EditingMode mode)
Tool change from the toolbar or keys 1/2: also leaves entity modes.
LyraTerrainCanvas lyra_canvas_
bool graphics_import_applied_
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()
Handle overworld keyboard shortcuts and edit-mode hotkeys.
bool DuplicateSelectedItem(int offset_x=16, int offset_y=0)
Duplicate selected item with optional pixel offset.
void DrawOverworldCanvas()
Draw the main overworld canvas.
gui::Canvas blockset_canvas_
absl::Status RefreshTile16Blockset()
void ToggleCanvasFullscreen()
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 RollbackSaveTransaction() override
std::string GetTile16ScopeLabel() const
void FinalizePaintOperation()
std::unique_ptr< OverworldEntityRenderer > entity_renderer_
auto & GetWorldTiles(int world)
std::optional< OverworldEntityInsertionRequest > pending_entity_insertion_
absl::Status Load() override
absl::Status UpdateGfxGroupEditor()
absl::Status RebuildScratchBitmapFromTileData()
void EnsureMapTexture(int map_index)
Ensure a specific map has its texture created.
std::vector< gfx::Bitmap > sprite_previews_
absl::Status OpenGraphicsForTile16Quadrant(int tile16_id, int quadrant)
std::shared_ptr< ProjectGraphicsSource > graphics_source_
std::unique_ptr< CanvasNavigationManager > canvas_nav_
absl::Status SaveLyraA0TerrainAs(const std::string &filename)
absl::Status Copy() override
bool NudgeSelectedItem(int delta_x, int delta_y)
Move selected item by signed pixel deltas.
EntityEditMode entity_edit_mode_
const project::YazeProject * graphics_source_project_
bool graphics_source_open_
const gfx::Bitmap * AreaScreenBitmap(int map_id)
std::unique_ptr< OverworldToolbar > toolbar_
GfxGroupEditor gfx_group_editor_
void ProcessDeferredTextures()
Create textures for deferred map bitmaps on demand.
absl::Status OpenGraphicsForContextTile16(const OverworldContextTarget &target)
absl::Status Update() final
std::unique_ptr< gui::TileSelectorWidget > blockset_selector_
bool show_overlay_preview_
bool entities_visible() const
project::YazeProject * TerrainProject() const
void RefreshMapProperties(int map_id=-1)
absl::Status CreateLyraTerrain()
void ToggleEntityVisibility()
absl::Status Paste() override
void ScrollBlocksetCanvasToCurrentTile()
Scroll the blockset canvas to show the current selected tile16.
std::optional< ProjectGraphicsImportPlan > graphics_import_plan_
bool DeleteSelectedItem()
Delete selected item and preserve nearest-item selection continuity.
std::unique_ptr< TilePaintingManager > tile_painting_
absl::Status lyra_canvas_status_
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 SetEntityEditMode(EntityEditMode mode)
Entity focus (entrances/exits/items/sprites); NONE = all entities.
bool lyra_a0_terrain_writable() const
gui::Canvas properties_canvas_
std::optional< ProjectGraphicsImportAsset > graphics_import_asset_
std::unique_ptr< EntityMutationService > entity_mutation_service_
gfx::SnesPalette palette_
gfx::Bitmap tile16_blockset_bmp_
std::string graphics_preview_config_path_
bool map_tile_save_transaction_open_
void ClearSelectedItem()
Clear active item selection.
std::string lyra_loaded_rom_sha1_
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)
const ScratchWorkspaceState & state() const
absl::Status DeletePage()
static constexpr size_t kMaxPages
absl::Status AddPage(bool duplicate=false)
std::string GetDisplayString(const std::string &name) const
Live, platform-formatted binding for a shortcut name.
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.
void ClearCustomSegment(const std::string &key)
Remove a custom segment.
int current_tile16() const
void SetCollisionTypes(const std::array< uint8_t, 0x200 > &types)
absl::Status SetCurrentTile(int id)
void SetHoverDetailProvider(std::function< std::string(int)> provider)
void BindDocument(std::vector< gfx::Tile16 > *definitions, UndoManager *history, std::function< void()> before_edit={})
void SetOpenGraphicsForQuadrant(std::function< absl::Status(int, int)> callback)
void DrawOverworldMenuItems()
void ClearCollisionTypes()
void set_on_document_changed(std::function< void(const std::vector< Tile16Commit > &)> callback)
void RequestTileSwitch(int target_tile_id)
bool blockset_loaded() const
absl::Status Initialize(gfx::Bitmap &tile16_blockset_bmp, gfx::Bitmap ¤t_gfx_bmp, std::array< uint8_t, 0x200 > &all_tiles_types)
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, std::string action_label={}, std::function< void()> on_action=nullptr)
Abstract base for all undoable actions (Command pattern)
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.
LyraTerrainPaintAction(uint16_t before, uint16_t after, std::function< absl::Status(uint16_t)> apply)
absl::Status Redo() override
size_t MemoryUsage() const override
Approximate memory footprint for budget enforcement.
std::function< absl::Status(uint16_t)> apply_
absl::Status Undo() override
std::string Description() const override
Human-readable description (e.g., "Paint 12 tiles on map 5")
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.
Represents a bitmap image optimized for SNES ROM hacking.
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
TextureHandle texture() const
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
SDL_Surface * surface() const
static PaletteManager & Get()
Get the singleton instance.
RAII timer for automatic timing management.
auto global_scale() const
void SetUsageMode(CanvasUsage usage)
auto hover_mouse_pos() const
void ApplyConfigSnapshot(const CanvasConfig &snapshot)
void ClearContextMenuItems()
CanvasConfig & GetConfig()
bool IsMouseHovering() 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.
void SyncAreaProperties(int map_index)
Copy the area parent's render settings (main palette, animated GFX, tile GFX groups,...
absl::Status SetLyraA0Tile32(int x, int y, uint16_t tile)
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 ValidatePrivateNativeTerrainSave() const
absl::Status SaveMap32Tiles()
Save tile32 definitions to ROM.
const gfx::SnesPalette & current_area_palette() const
absl::Status SaveMap16Tiles()
Save tile16 definitions to ROM.
auto sprites(int state) const
const std::vector< gfx::Tile16 > & tiles16() const
bool is_lyra_preview() const
int inspected_map_count() const
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
void SetGraphicsPreview(OverworldGraphicsPreview preview)
absl::Status SaveCustomOverworldData()
Save all v2/v3 property tables using the ROM's current feature flags.
void set_current_map(int i)
absl::StatusOr< OverworldSpriteSavePlan > PrepareSpriteSave() const
auto mutable_overworld_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.
void RollbackSavedMapTiles()
absl::Status SaveItems()
Save hidden overworld items to ROM.
void CommitSavedMapTiles()
absl::Status LoadLyraTerrainPreview(Rom *rom)
absl::Status SaveOverworldMaps()
Save compressed map tile data to ROM.
auto mutable_all_tiles_types()
auto mutable_sprites(int state)
void set_game_state(int state)
const std::array< uint16_t, 256 > & lyra_a0_tiles() const
const std::vector< OverworldEntrance > & entrances() const
absl::Status SaveMap16Expanded()
Save expanded tile16 definitions (v1+ ROMs)
absl::StatusOr< std::array< uint8_t, kNumTileTypes > > GetTile8CollisionTypes(int map_id) const
OverworldBlockset & GetMapTiles(int world_type)
absl::Status SaveMusic()
Save per-area music IDs.
A class for managing sprites in the overworld and underworld.
#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)
absl::StatusOr< zelda3::OverworldGraphicsPreview > LoadOverworldGraphicsPreview(const std::string &filename)
bool ItemIdentityMatchesForUndo(const zelda3::OverworldItem &lhs, const zelda3::OverworldItem &rhs)
bool ItemSnapshotsEqual(const OverworldItemsSnapshot &lhs, const OverworldItemsSnapshot &rhs)
SheetPixels SnapshotSessionSheets(const std::set< uint16_t > &ids, const zelda3::GameData *game_data)
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.
absl::Status UpdateGraphicsContextPalettes(GraphicsEditContext &context, GraphicsEditContext refreshed)
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)
void AppendResolvedGraphicsContext(EditorContextSnapshot &snapshot, const zelda3::ResolvedGraphicsContext &context)
constexpr int kTile16Size
absl::StatusOr< GraphicsEditContext > MakeOverworldGraphicsEditContext(const zelda3::OverworldMap &map, const gfx::Tile16 &tile16, int tile16_id, int quadrant, const zelda3::GameData *owner)
OverworldMapMetadata BuildOverworldMapMetadata(const zelda3::Overworld &overworld, const Rom *rom, const project::YazeProject *project, int map_id, int game_state)
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)
uint16_t TileInfoToWord(TileInfo tile_info)
EmptyStateOptions EmptyLoading(const char *what, bool compact)
bool DrawEmptyState(const EmptyStateOptions &options)
Draw a centered empty-state block.
EmptyStateOptions EmptyNoRom(bool compact)
constexpr uint32_t kLyraA0LowStreamPc
constexpr uint32_t kLyraA0HighStreamPc
std::string ComputeSha1Hex(const uint8_t *data, size_t size)
Compute SHA-1 hash of data, return lowercase hex string (40 chars).
constexpr int kNumTile16Individual
constexpr int kNumOverworldMaps
absl::Status ApplyOverworldSpriteSave(Rom &rom, const OverworldSpriteSavePlan &plan)
constexpr int OverworldCustomASMHasBeenApplied
OverworldRomProfile DetectOverworldRomProfile(const Rom &rom)
absl::StatusOr< OverworldEntranceTileTypes > LoadEntranceTileTypes(Rom *rom)
int WorldForOverworldMap(int map_index)
constexpr int kExpandedMapCount
ResolvedGraphicsContext DescribeOverworldGraphicsContext(const OverworldMap &map, const GraphicsContextIdentity &identity)
std::vector< OverworldSpriteWrite > OverworldSpriteSavePlan
#define RETURN_IF_ERROR(expr)
bool kSaveOverworldSprites
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< int()> displayed_map_count
std::function< bool()> pick_tile16_from_hovered_canvas
std::function< bool(int)> is_project_terrain_map
std::function< void(int)> ensure_map_texture
std::function< void()> open_map_properties
Opens (and focuses) the Map Properties window. Double-click target.
Shared state pointers that the navigation manager reads/writes.
std::array< gfx::Bitmap, zelda3::kExpandedMapCount > * maps_bmp
std::unique_ptr< gui::TileSelectorWidget > * blockset_selector
gui::Canvas * ow_map_canvas
zelda3::Overworld * overworld
bool * is_dragging_entity
gfx::Tilemap * tile16_blockset
EditingMode * current_mode
std::vector< EditorContextValue > counts
std::string pending_label
std::vector< EditorContextAction > actions
std::vector< EditorContextDiagnostic > diagnostics
std::string semantic_owner
std::vector< EditorContextValue > metadata
std::vector< std::string > capabilities
project::YazeProject * project
ToastManager * toast_manager
SharedClipboard * shared_clipboard
gfx::IRenderer * renderer
ShortcutManager * shortcut_manager
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::array< gfx::Bitmap, zelda3::kExpandedMapCount > * maps_bmp
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
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::kExpandedMapCount > * 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(zelda3::GameEntity *) on_entity_context_menu)
std::function< bool()> can_edit_items
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(EntityEditMode)> on_set_entity_mode
Snapshot of overworld item list + current item selection.
std::vector< zelda3::OverworldItem > items
std::optional< zelda3::OverworldItem > selected_item_identity
static constexpr const char * kMapProperties
static constexpr const char * kItemList
static constexpr const char * kTile16Editor
static constexpr const char * kDebugWindow
static constexpr const char * kUsageStats
std::vector< ScratchPage > pages
std::vector< int > overworld_tile16_ids
bool has_overworld_tile16
std::vector< int > tile_ids
Callbacks for undo integration and map refresh.
std::function< absl::Status(const TileBrush &, int x, int y, int width, int height, bool finalize) paint_project_pattern)
std::function< void(int tile_id)> request_tile16_selection
When set, eyedropper routes here (guarded RequestTileSwitch path).
std::function< absl::StatusOr< uint16_t >(int world, int x, int y)> read_project_tile
std::function< void(int map_index)> refresh_overworld_map_on_demand
std::function< void()> scroll_blockset_to_current_tile
std::function< int(int world)> allocated_rows
std::function< void()> finalize_paint_operation
std::function< void(int map_id)> select_map_for_editing
std::function< bool(int world, int x, int y)> is_project_tile
std::function< void()> finalize_project_paint
std::function< const gfx::Bitmap *(int map_id)> project_tile_atlas
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
std::array< gfx::Bitmap, zelda3::kExpandedMapCount > * maps_bmp
gui::Canvas * ow_map_canvas
zelda3::Overworld * overworld
std::vector< int > * selected_tile16_ids
gfx::Tilemap * tile16_blockset
EditingMode * current_mode
std::array< SDL_Color, 256 > colors
std::vector< uint8_t > pixels
Bitmap atlas
Master bitmap containing all tiles.
Modern project structure with comprehensive settings consolidation.
core::HackManifest hack_manifest
LyraLayoutPresence presence