Add unit variation selection to the Create Unit dialog

Surprisingly, this involves quite a few API changes to enable the Create
Unit command to specify a unit variation id.
This commit is contained in:
Iris Morelle 2020-07-06 01:11:34 -04:00
parent c489ffab59
commit be4b927fd8
8 changed files with 120 additions and 19 deletions

View file

@ -201,10 +201,32 @@
[column]
grow_factor = 1
horizontal_grow = true
horizontal_alignment = "right"
[grid]
[row]
grow_factor=0
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
definition = "default"
label= _ "Variation:"
[/label]
[/column]
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
[menu_button]
id = "variation_box"
definition = "default"
[/menu_button]
[/column]
[column]
border = "all"
border_size = 5

View file

@ -24,6 +24,7 @@
#include "gui/widgets/image.hpp"
#include "gui/widgets/label.hpp"
#include "gui/widgets/grid.hpp"
#include "gui/widgets/menu_button.hpp"
#include "gui/widgets/text_box.hpp"
#include "gui/widgets/toggle_button.hpp"
#include "gui/widgets/unit_preview_pane.hpp"
@ -37,6 +38,7 @@
#include <boost/dynamic_bitset.hpp>
static std::string last_chosen_type_id = "";
static std::string last_variation = "";
static unit_race::GENDER last_gender = unit_race::MALE;
namespace gui2
@ -77,6 +79,7 @@ REGISTER_DIALOG(unit_create)
unit_create::unit_create()
: gender_(last_gender)
, choice_(last_chosen_type_id)
, variation_(last_variation)
, last_words_()
{
set_restore(true);
@ -97,6 +100,10 @@ void unit_create::pre_show(window& window)
gender_toggle.set_callback_on_value_change(
std::bind(&unit_create::gender_toggle_callback, this));
menu_button& var_box = find_widget<menu_button>(&window, "variation_box", false);
connect_signal_notify_modified(var_box, std::bind(&unit_create::variation_menu_callback, this));
listbox& list = find_widget<listbox>(&window, "unit_type_list", false);
text_box* filter
@ -175,6 +182,7 @@ void unit_create::post_show(window& window)
last_chosen_type_id = choice_ = units_[selected_row]->id();
last_gender = gender_;
last_variation = variation_;
}
void unit_create::update_displayed_type() const
@ -188,8 +196,17 @@ void unit_create::update_displayed_type() const
return;
}
find_widget<unit_preview_pane>(w, "unit_details", false)
.set_displayed_type(units_[selected_row]->get_gender_unit_type(gender_));
const unit_type* ut = &units_[selected_row]->get_gender_unit_type(gender_);
if(!variation_.empty()) {
const auto& variations = units_[selected_row]->variation_types();
auto vi = variations.find(variation_);
if(vi != variations.end()) {
ut = &vi->second.get_gender_unit_type(gender_);
}
}
find_widget<unit_preview_pane>(w, "unit_details", false).set_displayed_type(*ut);
}
void unit_create::list_item_clicked(window& window)
@ -206,6 +223,45 @@ void unit_create::list_item_clicked(window& window)
gender_toggle.set_members_enabled([&](const unit_race::GENDER& gender)->bool {
return units_[selected_row]->has_gender_variation(gender);
});
menu_button& var_box = find_widget<menu_button>(&window, "variation_box", false);
std::vector<config> var_box_values;
var_box_values.emplace_back("label", _("unit_variation^Default"), "variation_id", "");
const auto& ut = *units_[selected_row];
const auto& uvars = ut.variation_types();
var_box.set_active(!uvars.empty());
unsigned n = 0, selection = 0;
for(const auto& pair : uvars) {
++n;
const std::string& uv_id = pair.first;
const unit_type& uv = pair.second;
std::string uv_label;
if(!uv.type_name().empty() && uv.type_name() != ut.type_name()) {
uv_label = uv.type_name() + " (" + uv_id + ")";
} else {
uv_label = uv_id;
}
var_box_values.emplace_back("label", uv_label, "variation_id", uv_id);
if(uv_id == variation_) {
selection = n;
}
}
// If we didn't find the variation selection again then the new selected
// unit type doesn't have that variation id.
if(!selection) {
variation_.clear();
}
var_box.set_values(var_box_values, selection);
}
void unit_create::filter_text_changed(text_box_base* textbox, const std::string& text)
@ -262,5 +318,15 @@ void unit_create::gender_toggle_callback()
update_displayed_type();
}
void unit_create::variation_menu_callback()
{
window& window = *this->get_window();
menu_button& var_box = find_widget<menu_button>(&window, "variation_box", false);
variation_ = var_box.get_value_config()["variation_id"].str();
update_displayed_type();
}
} // namespace dialogs
} // namespace gui2

View file

@ -27,6 +27,7 @@ class unit_type;
namespace gui2
{
class menu_button;
class text_box_base;
namespace dialogs
@ -55,6 +56,12 @@ public:
return gender_;
}
/** Variation choice from the user. */
std::string variation() const
{
return variation_;
}
private:
std::vector<const unit_type*> units_;
@ -62,6 +69,8 @@ private:
std::string choice_;
std::string variation_;
std::vector<std::string> last_words_;
/** Inherited from modal_dialog, implemented by REGISTER_DIALOG. */
@ -77,6 +86,7 @@ private:
void list_item_clicked(window& window);
void filter_text_changed(text_box_base* textbox, const std::string& text);
void gender_toggle_callback();
void variation_menu_callback();
void update_displayed_type() const;

View file

@ -689,7 +689,7 @@ unit_map::iterator menu_handler::current_unit()
namespace
{
/// Allows a function to return both a type and a gender.
typedef std::pair<const unit_type*, unit_race::GENDER> type_and_gender;
typedef std::tuple<const unit_type*, unit_race::GENDER, std::string> type_gender_variation;
/**
* Allows the user to select a type of unit, using GUI2.
@ -698,7 +698,7 @@ typedef std::pair<const unit_type*, unit_race::GENDER> type_and_gender;
* @returns the selected type and gender. If this is canceled, the
* returned type is nullptr.
*/
type_and_gender choose_unit()
type_gender_variation choose_unit()
{
//
// The unit creation dialog makes sure unit types
@ -708,14 +708,14 @@ type_and_gender choose_unit()
create_dlg.show();
if(create_dlg.no_choice()) {
return type_and_gender(nullptr, unit_race::NUM_GENDERS);
return type_gender_variation(nullptr, unit_race::NUM_GENDERS, "");
}
const std::string& ut_id = create_dlg.choice();
const unit_type* utp = unit_types.find(ut_id);
if(!utp) {
ERR_NG << "Create unit dialog returned nonexistent or unusable unit_type id '" << ut_id << "'." << std::endl;
return type_and_gender(static_cast<const unit_type*>(nullptr), unit_race::NUM_GENDERS);
return type_gender_variation(static_cast<const unit_type*>(nullptr), unit_race::NUM_GENDERS, "");
}
const unit_type& ut = *utp;
@ -727,7 +727,7 @@ type_and_gender choose_unit()
gender = ut.genders().front();
}
return type_and_gender(utp, gender);
return type_gender_variation(utp, gender, create_dlg.variation());
}
/**
@ -739,7 +739,8 @@ void create_and_place(game_display&,
unit_map&,
const map_location& loc,
const unit_type& u_type,
unit_race::GENDER gender = unit_race::NUM_GENDERS)
unit_race::GENDER gender = unit_race::NUM_GENDERS,
const std::string& variation = "")
{
synced_context::run_and_throw("debug_create_unit",
config {
@ -747,6 +748,7 @@ void create_and_place(game_display&,
"y", loc.wml_y(),
"type", u_type.id(),
"gender", gender_string(gender),
"variation", variation,
}
);
}
@ -764,10 +766,10 @@ void menu_handler::create_unit(mouse_handler& mousehandler)
assert(gui_ != nullptr);
// Let the user select the kind of unit to create.
type_and_gender selection = choose_unit();
if(selection.first != nullptr) {
type_gender_variation selection = choose_unit();
if(std::get<0>(selection) != nullptr) {
// Make it so.
create_and_place(*gui_, map(), units(), destination, *selection.first, selection.second);
create_and_place(*gui_, map(), units(), destination, *std::get<0>(selection), std::get<1>(selection), std::get<2>(selection));
}
}

View file

@ -536,6 +536,7 @@ SYNCED_COMMAND_HANDLER_FUNCTION(debug_create_unit, child, use_undo, /*show*/, e
debug_notification(N_("A unit was created using debug mode during $players turn"));
map_location loc(child);
resources::whiteboard->on_kill_unit();
const std::string& variation = child["variation"].str();
const unit_race::GENDER gender = string_gender(child["gender"], unit_race::NUM_GENDERS);
const unit_type *u_type = unit_types.find(child["type"]);
if (!u_type) {
@ -547,7 +548,7 @@ SYNCED_COMMAND_HANDLER_FUNCTION(debug_create_unit, child, use_undo, /*show*/, e
? resources::controller->current_side() : 1;
// Create the unit.
unit_ptr created = unit::create(*u_type, side_num, true, gender);
unit_ptr created = unit::create(*u_type, side_num, true, gender, variation);
created->new_turn();
unit_map::unit_iterator unit_it;

View file

@ -308,7 +308,7 @@ private:
std::string debug_id_; /// A suffix for id_, used when logging messages.
std::string parent_id_; /// The id of the top ancestor of this unit_type.
/// from [base_unit]
std::string base_unit_id_;
std::string base_unit_id_;
t_string type_name_;
t_string description_;
std::vector<t_string> special_notes_;

View file

@ -725,11 +725,11 @@ void unit::clear_status_caches()
units_with_cache.clear();
}
void unit::init(const unit_type& u_type, int side, bool real_unit, unit_race::GENDER gender)
void unit::init(const unit_type& u_type, int side, bool real_unit, unit_race::GENDER gender, const std::string& variation)
{
type_ = &u_type;
race_ = &unit_race::null_race;
variation_ = type_->default_variation();
variation_ = variation.empty() ? type_->default_variation() : variation;
side_ = side;
gender_ = gender != unit_race::NUM_GENDERS ? gender : generate_gender(u_type, real_unit);
facing_ = static_cast<map_location::DIRECTION>(randomness::rng::default_instance().get_random_int(0, map_location::NDIRECTIONS-1));

View file

@ -140,7 +140,7 @@ public:
private:
void init(const config& cfg, bool use_traits = false, const vconfig* vcfg = nullptr);
void init(const unit_type& t, int side, bool real_unit, unit_race::GENDER gender = unit_race::NUM_GENDERS);
void init(const unit_type& t, int side, bool real_unit, unit_race::GENDER gender = unit_race::NUM_GENDERS, const std::string& variation = "");
// Copy constructor
unit(const unit& u);
@ -194,10 +194,10 @@ public:
*
* Only real_unit-s should have random traits, name and gender (to prevent OOS caused by RNG calls)
*/
static unit_ptr create(const unit_type& t, int side, bool real_unit, unit_race::GENDER gender = unit_race::NUM_GENDERS)
static unit_ptr create(const unit_type& t, int side, bool real_unit, unit_race::GENDER gender = unit_race::NUM_GENDERS, const std::string& variation = "")
{
unit_ptr res(new unit());
res->init(t, side, real_unit, gender);
res->init(t, side, real_unit, gender, variation);
return res;
}