7#include <unordered_map>
9#include "absl/strings/numbers.h"
10#include "absl/strings/str_cat.h"
11#include "absl/strings/str_format.h"
12#include "absl/strings/str_split.h"
13#include "absl/strings/string_view.h"
19#include "imgui/imgui.h"
27 "Vanilla ROM Hack",
"ZSCustomOverworld v2",
28 "ZSCustomOverworld v3 (Recommended)",
"Randomizer Compatible"};
31 "Standard ROM editing without custom ASM. Limited to vanilla features.",
32 "Basic overworld expansion: custom BG colors, main palettes, parent "
34 "Full overworld expansion: wide/tall areas, animated GFX, overlays, all "
36 "Compatible with ALttP Randomizer. Minimal custom features."};
53 {
"custom", &LoadOptions::enable_custom_overworld},
54 {
"tail", &LoadOptions::enable_tail_expansion},
55 {
"ow_maps", &LoadOptions::save_overworld_maps},
56 {
"ow_entrances", &LoadOptions::save_overworld_entrances},
57 {
"ow_exits", &LoadOptions::save_overworld_exits},
58 {
"ow_items", &LoadOptions::save_overworld_items},
59 {
"ow_sprites", &LoadOptions::save_overworld_sprites},
60 {
"dungeon_maps", &LoadOptions::save_dungeon_maps},
61 {
"palettes", &LoadOptions::save_all_palettes},
62 {
"gfx_groups", &LoadOptions::save_gfx_groups},
97 bool suggest_project_creation) {
131 std::string base_name;
132 if (last_slash != std::string::npos) {
137 if (last_dot != std::string::npos && last_dot > last_slash) {
138 base_name = base_name.substr(0, base_name.find_last_of(
'.'));
166 const std::string& preset_name,
bool remembered) {
182 for (
const auto& flag : kRememberedFlags) {
183 options_.*flag.member = current.*flag.member;
196 ImGui::SetNextWindowSize(ImVec2(600, 500), ImGuiCond_FirstUseEver);
197 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
198 ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
200 ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse;
211 "%s", tr(
"These are the options this session uses now. Apply "
212 "changes what the next save writes."));
263 const char* version_name =
266 ImVec4 version_color;
288 ImGui::TextWrapped(tr(
"%s To apply ZSCustomOverworld, use Upgrade in the "
289 "Overworld toolbar. This dialog never changes the "
299 ImGui::Checkbox(tr(
"Enable custom overworld features in editor"),
301 if (ImGui::IsItemHovered()) {
303 "%s", tr(
"On a vanilla ROM, gives each area the ZSCustomOverworld "
304 "fields (main palette, mosaic, animated GFX, overlay),\n"
305 "filled with the values the vanilla game uses.\n"
306 "A ZSCustomOverworld ROM always loads its own values, so "
307 "this has no effect there."));
310 ImGui::Checkbox(tr(
"Enable special world tail (0xA0-0xBF)"),
312 if (ImGui::IsItemHovered()) {
314 "%s", tr(
"Builds special world maps 0xA0-0xBF when the ROM has the "
315 "TailMapExpansion patch.\n"
316 "Without the patch, those maps stay blank."));
322 ImGui::TextWrapped(tr(
"%s The open overworld loaded with different "
323 "choices. Reopen the ROM to apply these."),
327 ImGui::TextWrapped(tr(
"%s Both are read when the overworld loads. Reopen "
328 "the ROM to apply a change."),
338 if (ImGui::BeginCombo(
"##PresetCombo",
347 if (ImGui::IsItemHovered()) {
352 ImGui::SetItemDefaultFocus();
365 : tr(
"Show Advanced Options"))) {
375 if (ImGui::TreeNodeEx(
"Overworld", ImGuiTreeNodeFlags_DefaultOpen)) {
385 if (ImGui::TreeNodeEx(
"Dungeon")) {
391 if (ImGui::TreeNodeEx(
"Graphics")) {
402 ImGui::Checkbox(tr(
"Create associated project file"),
408 ImGui::Text(tr(
"Project Name:"));
409 ImGui::SetNextItemWidth(-1);
416 tr(
"Project file stores settings, labels, and preferences."));
424 if (ImGui::IsItemHovered()) {
427 tr(
"Skip this dialog the next time this file opens.\n"
428 "Change it later with ROM Load Options… in the command palette.\n"
429 "Forgotten when the ROM's ZSCustomOverworld version changes."));
433 const float button_width = 120.0f;
434 const float spacing = 10.0f;
435 float total_width = button_width * 2 + spacing;
438 float avail = ImGui::GetContentRegionAvail().x;
439 ImGui::SetCursorPosX((avail - total_width) * 0.5f + ImGui::GetCursorPosX());
442 if (ImGui::Button(tr(
"Cancel"), ImVec2(button_width, 0))) {
447 ImGui::SameLine(0, spacing);
455 {{ImGuiCol_Button, accent},
456 {ImGuiCol_ButtonHovered,
457 ImVec4(accent.x * 1.1f, accent.y * 1.1f, accent.z * 1.1f, accent.w)},
458 {ImGuiCol_ButtonActive, ImVec4(accent.x * 0.9f, accent.y * 0.9f,
459 accent.z * 0.9f, accent.w)}});
462 const std::string confirm_label =
465 if (ImGui::Button(confirm_label.c_str(), ImVec2(button_width, 0))) {
486 if (preset_name ==
"Vanilla ROM Hack") {
496 }
else if (preset_name ==
"ZSCustomOverworld v2") {
506 }
else if (preset_name ==
"ZSCustomOverworld v3 (Recommended)") {
516 }
else if (preset_name ==
"Randomizer Compatible") {
564 const LoadOptions& options,
int zso_version_byte) {
565 std::string encoded =
567 for (
const auto& flag : kRememberedFlags) {
568 absl::StrAppend(&encoded,
";", flag.key,
"=",
569 options.*flag.member ?
"1" :
"0");
575 preset.erase(std::remove_if(preset.begin(), preset.end(),
577 return c ==
';' || c ==
'\t' || c ==
'\r' ||
581 if (!preset.empty()) {
582 absl::StrAppend(&encoded,
";preset=", preset);
587std::optional<RomLoadOptionsDialog::RememberedChoice>
589 const auto as_absl_view = [](std::string_view view) {
590 return absl::string_view(view.data(), view.size());
592 std::unordered_map<std::string_view, std::string_view> fields;
593 for (absl::string_view absl_part :
594 absl::StrSplit(as_absl_view(encoded),
';', absl::SkipEmpty())) {
595 const std::string_view part(absl_part.data(), absl_part.size());
596 const size_t eq = part.find(
'=');
597 if (eq == std::string_view::npos) {
600 fields[part.substr(0, eq)] = part.substr(eq + 1);
604 auto it = fields.find(
"v");
605 if (it == fields.end() ||
606 !absl::SimpleAtoi(as_absl_view(it->second), &version) ||
607 version != kRememberedChoiceVersion) {
612 it = fields.find(
"zso");
613 if (it == fields.end() ||
619 for (
const auto& flag : kRememberedFlags) {
620 it = fields.find(flag.key);
621 if (it == fields.end() || (it->second !=
"0" && it->second !=
"1")) {
624 choice.
options.*flag.member = it->second ==
"1";
627 it = fields.find(
"preset");
628 if (it != fields.end()) {
635 if (rom_path.empty()) {
638 std::filesystem::path path(rom_path);
639 if (path.is_relative()) {
641 auto absolute = std::filesystem::absolute(path, ec);
643 path = std::move(absolute);
646 return path.lexically_normal().string();
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
const std::string & rom_filename() const
std::function< void(const LoadOptions &) confirm_callback_)
void ApplyPreset(const std::string &preset_name)
std::function< bool()> apply_guard_
void Open(Rom *rom, const std::string &rom_filename)
Open the dialog after ROM detection.
int selected_preset_index_
static const char * kPresetNames[kNumPresets]
void OpenForReview(Rom *rom, const core::FeatureFlags::Flags &active, const std::string &preset_name, bool remembered)
Reopen the dialog for a ROM that is already loaded.
bool OverworldLoadOptionsChanged() const
bool loaded_custom_overworld_
zelda3::OverworldVersion detected_version_
char project_name_buffer_[256]
static LoadOptions OptionsFromFeatureFlags(const core::FeatureFlags::Flags &flags)
static std::optional< RememberedChoice > DecodeRememberedChoice(std::string_view encoded)
void DrawFeatureFlagDetails()
static std::string RomChoiceKey(const std::string &rom_path)
bool Show(bool *p_open)
Show the dialog.
static void ApplyToFeatureFlags(const LoadOptions &options, core::FeatureFlags::Flags &flags)
static std::string EncodeRememberedChoice(const LoadOptions &options, int zso_version_byte)
void DrawOverworldOptions()
void DrawFeatureFlagPresets()
bool loaded_tail_expansion_
void DrawProjectOptions()
static const char * kPresetDescriptions[kNumPresets]
std::string rom_filename_
static constexpr int kNumPresets
void ApplyOptionsToFeatureFlags()
std::function< void()> cancel_callback_
int zso_version_byte() const
void Draw(bool *p_open)
Draw the dialog (wrapper around Show)
RAII guard for ImGui style colors.
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
static OverworldVersion GetVersion(const Rom &rom)
Detect ROM version from ASM marker byte.
static uint8_t GetAsmVersion(const Rom &rom)
Get raw ASM version byte from ROM.
static const char * GetVersionName(OverworldVersion version)
Get human-readable version name for display/logging.
#define ICON_MD_AUTO_FIX_HIGH
constexpr RememberedFlag kRememberedFlags[]
constexpr int kRememberedChoiceVersion
ImVec4 ConvertColorToImVec4(const Color &color)
ImVec4 GetTextSecondaryVec4()
@ kZSCustomV2
Parent system, BG colors, main palettes.
@ kZSCustomV1
Basic features, expanded pointers.
@ kVanilla
0xFF in ROM, no ZScream ASM applied
@ kZSCustomV3
Area enum, wide/tall areas, all features.
bool kEnableSpecialWorldExpansion
bool kSaveOverworldSprites
bool kLoadCustomOverworld
bool kSaveOverworldEntrances
struct yaze::core::FeatureFlags::Flags::Overworld overworld
bool enable_tail_expansion
bool save_overworld_items
std::string selected_preset
bool save_overworld_exits
bool enable_custom_overworld
bool save_overworld_sprites
bool save_overworld_entrances
bool LoadOptions::* member