From a1c78edda5574a6f81c04ef573d8fc4382f8c39e Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sun, 15 Sep 2024 00:37:21 -0400 Subject: [PATCH] Lua API: Enable plugins to play a campaign This also fixes some issues that can prevent a plugin from working with the GUI (that is, only working in headless mode). Plugins should work in both headless and GUI mode. --- src/game_launcher.cpp | 16 +++++++--- src/game_launcher.hpp | 1 + src/gui/dialogs/campaign_selection.cpp | 39 ++++++++++++++++++++++++ src/gui/dialogs/campaign_selection.hpp | 18 ++--------- src/gui/dialogs/loading_screen.cpp | 1 + src/gui/dialogs/modal_dialog.cpp | 17 +++++++---- src/gui/dialogs/sp_options_configure.cpp | 5 +++ src/wesnoth.cpp | 2 ++ 8 files changed, 73 insertions(+), 26 deletions(-) diff --git a/src/game_launcher.cpp b/src/game_launcher.cpp index cf239e83f9d..f73ce3f447d 100644 --- a/src/game_launcher.cpp +++ b/src/game_launcher.cpp @@ -751,14 +751,20 @@ std::string game_launcher::jump_to_campaign_id() const return jump_to_campaign_.campaign_id; } +bool game_launcher::play_campaign() { + if(new_campaign()) { + state_.set_skip_story(jump_to_campaign_.skip_story); + jump_to_campaign_.jump = false; + launch_game(reload_mode::NO_RELOAD_DATA); + return true; + } + return false; +} + bool game_launcher::goto_campaign() { if(jump_to_campaign_.jump) { - if(new_campaign()) { - state_.set_skip_story(jump_to_campaign_.skip_story); - jump_to_campaign_.jump = false; - launch_game(reload_mode::NO_RELOAD_DATA); - } else { + if(!play_campaign()) { jump_to_campaign_.jump = false; return false; } diff --git a/src/game_launcher.hpp b/src/game_launcher.hpp index ba81700268e..1c43d66722f 100644 --- a/src/game_launcher.hpp +++ b/src/game_launcher.hpp @@ -102,6 +102,7 @@ public: void select_mp_server(const std::string& server) { multiplayer_server_ = server; } bool play_multiplayer(mp_mode mode); bool play_multiplayer_commandline(); + bool play_campaign(); bool change_language(); void launch_game(reload_mode reload = reload_mode::RELOAD_DATA); diff --git a/src/gui/dialogs/campaign_selection.cpp b/src/gui/dialogs/campaign_selection.cpp index 31dab2227ea..26e8836903f 100644 --- a/src/gui/dialogs/campaign_selection.cpp +++ b/src/gui/dialogs/campaign_selection.cpp @@ -39,6 +39,23 @@ namespace gui2::dialogs REGISTER_DIALOG(campaign_selection) +campaign_selection::campaign_selection(ng::create_engine& eng) + : modal_dialog(window_id()) + , engine_(eng) + , choice_(-1) + , rng_mode_(RNG_DEFAULT) + , mod_states_() + , page_ids_() + , difficulties_() + , current_difficulty_() + , current_sorting_(RANK) + , currently_sorted_asc_(true) + , mod_ids_() +{ + set_show_even_without_video(true); + set_allow_plugin_skip(false); +} + void campaign_selection::campaign_selected() { tree_view& tree = find_widget("campaign_tree"); @@ -425,6 +442,28 @@ void campaign_selection::pre_show() connect_signal_notify_modified(diff_menu, std::bind(&campaign_selection::difficulty_selected, this)); campaign_selected(); + + plugins_context_.reset(new plugins_context("Campaign Selection")); + plugins_context_->set_callback("create", [this](const config&) { set_retval(retval::OK); }, false); + plugins_context_->set_callback("quit", [this](const config&) { set_retval(retval::CANCEL); }, false); + + plugins_context_->set_accessor("find_level", [this](const config& cfg) { + const std::string id = cfg["id"].str(); + auto result = engine_.find_level_by_id(id); + return config { + "index", result.second, + "type", level_type::get_string(result.first), + }; + }); + + plugins_context_->set_accessor_int("find_mod", [this](const config& cfg) { + return engine_.find_extra_by_id(ng::create_engine::MOD, cfg["id"]); + }); + + plugins_context_->set_callback("select_level", [this](const config& cfg) { + choice_ = cfg["index"].to_int(); + engine_.set_current_level(choice_); + }, true); } void campaign_selection::add_campaign_to_tree(const config& campaign) diff --git a/src/gui/dialogs/campaign_selection.hpp b/src/gui/dialogs/campaign_selection.hpp index 234e73e5f08..eeefc65af1e 100644 --- a/src/gui/dialogs/campaign_selection.hpp +++ b/src/gui/dialogs/campaign_selection.hpp @@ -18,13 +18,14 @@ #include "gui/dialogs/modal_dialog.hpp" #include "game_initialization/create_engine.hpp" +#include "gui/dialogs/multiplayer/plugin_executor.hpp" #include namespace gui2::dialogs { -class campaign_selection : public modal_dialog +class campaign_selection : public modal_dialog, private plugin_executor { enum CAMPAIGN_ORDER {RANK, DATE, NAME}; public: @@ -41,20 +42,7 @@ public: RNG_BIASED, }; - explicit campaign_selection(ng::create_engine& eng) - : modal_dialog(window_id()) - , engine_(eng) - , choice_(-1) - , rng_mode_(RNG_DEFAULT) - , mod_states_() - , page_ids_() - , difficulties_() - , current_difficulty_() - , current_sorting_(RANK) - , currently_sorted_asc_(true) - , mod_ids_() - { - } + explicit campaign_selection(ng::create_engine& eng); /***** ***** ***** setters / getters for members ***** ****** *****/ diff --git a/src/gui/dialogs/loading_screen.cpp b/src/gui/dialogs/loading_screen.cpp index d28f140e655..076e1eb2ce7 100644 --- a/src/gui/dialogs/loading_screen.cpp +++ b/src/gui/dialogs/loading_screen.cpp @@ -93,6 +93,7 @@ loading_screen::loading_screen(std::function f) current_visible_stage_ = visible_stages_.end(); singleton_ = this; + set_allow_plugin_skip(false); } void loading_screen::pre_show() diff --git a/src/gui/dialogs/modal_dialog.cpp b/src/gui/dialogs/modal_dialog.cpp index 7a2d6844640..c3e3baeb82d 100644 --- a/src/gui/dialogs/modal_dialog.cpp +++ b/src/gui/dialogs/modal_dialog.cpp @@ -66,20 +66,25 @@ bool modal_dialog::show(const unsigned auto_close_time) { if(video::headless() && !show_even_without_video_) { DBG_DP << "modal_dialog::show denied"; - if(!allow_plugin_skip_) { - return false; - } + return false; + } + if(allow_plugin_skip_) { + bool skipped = false; plugins_manager* pm = plugins_manager::get(); if (pm && pm->any_running()) { plugins_context pc("Dialog"); - pc.set_callback("skip_dialog", [this](config) { retval_ = retval::OK; }, false); - pc.set_callback("quit", [](config) {}, false); + pc.set_callback("skip_dialog", [this, &skipped](config) { retval_ = retval::OK; skipped = true; }, false); + pc.set_callback("quit", [this, &skipped](config) { retval_ = retval::CANCEL; skipped = true; }, false); + pc.set_callback("select", [this, &skipped](config c) { retval_ = c["retval"].to_int(); skipped = true; }, false); + pc.set_accessor_string("id", [this](config) { return window_id(); }); pc.play_slice(); } - return false; + if(skipped) { + return false; + } } init_fields(); diff --git a/src/gui/dialogs/sp_options_configure.cpp b/src/gui/dialogs/sp_options_configure.cpp index 78b2f4101b3..bbc378f41a4 100644 --- a/src/gui/dialogs/sp_options_configure.cpp +++ b/src/gui/dialogs/sp_options_configure.cpp @@ -28,12 +28,17 @@ sp_options_configure::sp_options_configure(ng::create_engine& create_engine, ng: , config_engine_(config_engine) , options_manager_() { + set_show_even_without_video(true); + set_allow_plugin_skip(false); } void sp_options_configure::pre_show() { options_manager_.reset(new mp_options_helper(*this, create_engine_)); options_manager_->update_all_options(); + + plugins_context_.reset(new plugins_context("Campaign Configure")); + plugins_context_->set_callback("launch", [this](const config&) { set_retval(retval::OK); }, false); } void sp_options_configure::post_show() diff --git a/src/wesnoth.cpp b/src/wesnoth.cpp index 064ac751030..41c46422709 100644 --- a/src/wesnoth.cpp +++ b/src/wesnoth.cpp @@ -762,6 +762,8 @@ static int do_gameloop(commandline_options& cmdline_opts) const plugins_context::reg_vec callbacks { {"play_multiplayer", std::bind(&game_launcher::play_multiplayer, game.get(), game_launcher::mp_mode::CONNECT)}, + {"play_local", std::bind(&game_launcher::play_multiplayer, game.get(), game_launcher::mp_mode::LOCAL)}, + {"play_campaign", std::bind(&game_launcher::play_campaign, game.get())}, }; const plugins_context::areg_vec accessors {