Skip to content

Commit

Permalink
Add unit variation selection to the Create Unit dialog
Browse files Browse the repository at this point in the history
Surprisingly, this involves quite a few API changes to enable the Create
Unit command to specify a unit variation id.
  • Loading branch information
irydacea committed Jul 9, 2020
1 parent c489ffa commit be4b927
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 19 deletions.
24 changes: 23 additions & 1 deletion data/gui/window/unit_create.cfg
Expand Up @@ -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
Expand Down
70 changes: 68 additions & 2 deletions src/gui/dialogs/unit_create.cpp
Expand Up @@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
10 changes: 10 additions & 0 deletions src/gui/dialogs/unit_create.hpp
Expand Up @@ -27,6 +27,7 @@ class unit_type;
namespace gui2
{

class menu_button;
class text_box_base;

namespace dialogs
Expand Down Expand Up @@ -55,13 +56,21 @@ class unit_create : public modal_dialog
return gender_;
}

/** Variation choice from the user. */
std::string variation() const
{
return variation_;
}

private:
std::vector<const unit_type*> units_;

unit_race::GENDER gender_;

std::string choice_;

std::string variation_;

std::vector<std::string> last_words_;

/** Inherited from modal_dialog, implemented by REGISTER_DIALOG. */
Expand All @@ -77,6 +86,7 @@ class unit_create : public modal_dialog
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;

Expand Down
20 changes: 11 additions & 9 deletions src/menu_events.cpp
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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;

Expand All @@ -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());
}

/**
Expand All @@ -739,14 +739,16 @@ 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 {
"x", loc.wml_x(),
"y", loc.wml_y(),
"type", u_type.id(),
"gender", gender_string(gender),
"variation", variation,
}
);
}
Expand All @@ -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));
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/synced_commands.cpp
Expand Up @@ -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 $player’s 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) {
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/units/types.hpp
Expand Up @@ -308,7 +308,7 @@ class unit_type
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_;
Expand Down
4 changes: 2 additions & 2 deletions src/units/unit.cpp
Expand Up @@ -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));
Expand Down
6 changes: 3 additions & 3 deletions src/units/unit.hpp
Expand Up @@ -140,7 +140,7 @@ class unit
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);
Expand Down Expand Up @@ -194,10 +194,10 @@ class unit
*
* 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;
}

Expand Down

0 comments on commit be4b927

Please sign in to comment.