#include "editor.hpp" #include #include #include "button.hpp" #include "number_button.hpp" #include "pane.hpp" #include "select_button.hpp" #include "string_button.hpp" namespace dusk::ui { namespace { bool has_save_data() { return dComIfGs_getSaveData() != nullptr; } dSv_player_status_a_c* get_player_status() { if (!has_save_data()) { return nullptr; } return &dComIfGs_getSaveData()->getPlayer().getPlayerStatusA(); } Rml::String get_player_name() { if (!has_save_data()) { return ""; } return dComIfGs_getPlayerName(); } void set_player_name(Rml::String name) { dComIfGs_setPlayerName(name.c_str()); } Rml::String get_horse_name() { if (!has_save_data()) { return ""; } return dComIfGs_getHorseName(); } void set_horse_name(Rml::String name) { dComIfGs_setHorseName(name.c_str()); } Rml::String value_for_player_selection(const Rml::String& selection) { dSv_player_status_a_c* status = get_player_status(); if (selection == "get_horse_name") { return get_horse_name(); } if (status == nullptr) { return "?"; } if (selection == "max_health") { return fmt::format("{}", static_cast(status->mMaxLife)); } if (selection == "health") { return fmt::format("{}", static_cast(status->mLife)); } if (selection == "max_oil") { return fmt::format("{}", static_cast(status->mMaxOil)); } if (selection == "oil") { return fmt::format("{}", static_cast(status->mOil)); } return "Unknown"; } Rml::String make_select_row(std::string_view key, std::string_view label, const Rml::String& value, const Rml::String& activeSelection) { const char* selectedClass = key == activeSelection ? " selected" : ""; return fmt::format( "", selectedClass, key, label, value); } Rml::String make_numeric_detail( std::string_view label, std::string_view decAction, std::string_view incAction) { return fmt::format( "
" "
{0}
" "
" "" "" "
" "
", label, decAction, incAction); } template void adjust_u16(TValue& value, int delta, u16 minValue, u16 maxValue) { const int nextValue = std::clamp( static_cast(value) + delta, static_cast(minValue), static_cast(maxValue)); value = static_cast(nextValue); } void render_player_status_tab(Rml::Element* content, const Rml::String& activeSelection) { Rml::String leftPane = R"RML(
Player
)RML"; leftPane += make_select_row("player_name", "Player Name", get_player_name(), activeSelection); leftPane += make_select_row("horse_name", "Horse Name", get_horse_name(), activeSelection); leftPane += make_select_row( "max_health", "Max Health", value_for_player_selection("max_health"), activeSelection); leftPane += make_select_row("health", "Health", value_for_player_selection("health"), activeSelection); leftPane += make_select_row( "max_oil", "Max Oil", value_for_player_selection("max_oil"), activeSelection); leftPane += make_select_row("oil", "Oil", value_for_player_selection("oil"), activeSelection); leftPane += "
"; Rml::String rightPane; if (activeSelection == "max_health") { rightPane = make_numeric_detail("Max Health", "max_health.dec", "max_health.inc"); } else if (activeSelection == "health") { rightPane = make_numeric_detail("Health", "health.dec", "health.inc"); } else if (activeSelection == "max_oil") { rightPane = make_numeric_detail("Max Oil", "max_oil.dec", "max_oil.inc"); } else if (activeSelection == "oil") { rightPane = make_numeric_detail("Oil", "oil.dec", "oil.inc"); } Rml::Factory::InstanceElementText(content, leftPane + rightPane); } bool handle_editor_action(const Rml::VariantList& arguments) { if (arguments.empty() || !has_save_data()) { return true; } const Rml::String action = arguments[0].Get(); dSv_player_status_a_c* status = get_player_status(); if (status == nullptr) { return true; } if (action == "max_health.inc") { adjust_u16(status->mMaxLife, 1, 0, 0xFFFF); return true; } else if (action == "max_health.dec") { adjust_u16(status->mMaxLife, -1, 0, 0xFFFF); if (status->mLife > status->mMaxLife) { status->mLife = status->mMaxLife; } return true; } if (action == "health.inc") { adjust_u16(status->mLife, 1, 0, status->mMaxLife); return true; } else if (action == "health.dec") { adjust_u16(status->mLife, -1, 0, status->mMaxLife); return true; } if (action == "max_oil.inc") { adjust_u16(status->mMaxOil, 1, 0, 0xFFFF); return true; } else if (action == "max_oil.dec") { adjust_u16(status->mMaxOil, -1, 0, 0xFFFF); if (status->mOil > status->mMaxOil) { status->mOil = status->mMaxOil; } return true; } if (action == "oil.inc") { adjust_u16(status->mOil, 1, 0, status->mMaxOil); return true; } else if (action == "oil.dec") { adjust_u16(status->mOil, -1, 0, status->mMaxOil); return true; } return false; } } // namespace EditorWindow::EditorWindow() { add_tab("Player Status", [this](Rml::Element* content) { auto& leftPane = add_child(content, Pane::Direction::Vertical); auto& rightPane = add_child(content, Pane::Direction::Vertical); leftPane.add_section("Player"); leftPane.add_child(leftPane.root(), StringButton::Props{ .key = "Player Name", .getValue = get_player_name, .setValue = set_player_name, .maxLength = 16, }); leftPane.add_child(leftPane.root(), StringButton::Props{ .key = "Horse Name", .getValue = get_horse_name, .setValue = set_horse_name, .maxLength = 16, }); leftPane.add_child(leftPane.root(), NumberButton::Props{ .key = "Max Health", .getValue = [] { return get_player_status()->getMaxLife(); }, .setValue = [](int value) { return get_player_status()->setMaxLife(value); }, .max = UINT16_MAX, // TODO: actual max }); leftPane.add_child(leftPane.root(), NumberButton::Props{ .key = "Health", .getValue = [] { return get_player_status()->getLife(); }, .setValue = [](int value) { return get_player_status()->setLife(value); }, .max = UINT16_MAX, // TODO: actual max }); leftPane.add_child(leftPane.root(), NumberButton::Props{ .key = "Max Oil", .getValue = [] { return get_player_status()->getMaxOil(); }, .setValue = [](int value) { return get_player_status()->setMaxOil(value); }, .max = UINT16_MAX, // TODO: actual max }); leftPane.add_child(leftPane.root(), NumberButton::Props{ .key = "Oil", .getValue = [] { return get_player_status()->getOil(); }, .setValue = [](int value) { return get_player_status()->setOil(value); }, .max = UINT16_MAX, // TODO: actual max }); leftPane.add_section("Equipment"); leftPane.add_select_button({ .key = "Equip X", .value = "TODO", }); leftPane.add_select_button({ .key = "Equip Y", .value = "TODO", }); rightPane.add_button({ .text = "Hello, world!", }); }); add_tab("Location", [this](Rml::Element* content) { // TODO }); add_tab("Inventory", [this](Rml::Element* content) { // TODO }); add_tab("Collection", [this](Rml::Element* content) { // TODO }); add_tab("Flags", [this](Rml::Element* content) { // TODO }); add_tab("Minigame", [this](Rml::Element* content) { // TODO }); add_tab("Config", [this](Rml::Element* content) { // TODO }); } } // namespace dusk::ui