diff --git a/src/game_definition.cc b/src/game_definition.cc index feeb830..def382c 100644 --- a/src/game_definition.cc +++ b/src/game_definition.cc @@ -89,6 +89,13 @@ GameDefinitions::GameDefinitions() { option.default_value.set_values[game_items.GetId(default_value)] = true; } + } else if (option_data["type"] == "items-dict") { + option.type = kDictOption; + option.set_type = kItemSet; + + for (const auto& default_value : option_data["defaultValue"]) { + option.default_value.dict_values[game_items.GetId(default_value)] = 1; + } } else if (option_data["type"] == "locations-set") { option.type = kSetOption; option.set_type = kLocationSet; @@ -147,11 +154,13 @@ GameDefinitions::GameDefinitions() { option.description = "Forces these items to be outside their native world."; } else if (option.name == "start_inventory") { - option.type = kUNKNOWN_OPTION_TYPE; + option.type = kDictOption; + option.set_type = kItemSet; option.display_name = "Start Inventory"; option.description = "Start with these items."; } else if (option.name == "start_inventory_from_pool") { - option.type = kUNKNOWN_OPTION_TYPE; + option.type = kDictOption; + option.set_type = kItemSet; option.display_name = "Start Inventory from Pool"; option.description = "Start with these items and don't place them in the world.\nThe " diff --git a/src/game_definition.h b/src/game_definition.h index 6495d0b..44e4ec3 100644 --- a/src/game_definition.h +++ b/src/game_definition.h @@ -16,6 +16,7 @@ enum OptionType { kRangeOption, kSelectOption, kSetOption, + kDictOption, }; enum SetType { @@ -38,6 +39,7 @@ struct OptionValue { std::string string_value; int int_value = 0; std::vector set_values; + std::map dict_values; int weight = 50; std::vector weighting; diff --git a/src/option_set_dialog.cc b/src/option_set_dialog.cc index 7808abe..85329f4 100644 --- a/src/option_set_dialog.cc +++ b/src/option_set_dialog.cc @@ -66,20 +66,54 @@ OptionSetDialog::OptionSetDialog(const Game* game, // Set up the chosen list chosen_list_ = new wxDataViewListCtrl(lists_sizer->GetStaticBox(), wxID_ANY); - chosen_list_->AppendTextColumn("Value"); + + if (option_definition_->type == kDictOption) { + chosen_list_->AppendTextColumn("Value", wxDATAVIEW_CELL_INERT, + wxCOL_WIDTH_AUTOSIZE); + +#ifdef __WXMAC__ + chosen_list_->AppendTextColumn("Amount", wxDATAVIEW_CELL_INERT, + wxCOL_WIDTH_AUTOSIZE); +#else + wxDataViewSpinRenderer* amount_renderer = + new wxDataViewSpinRenderer(1, 1000); + chosen_list_->AppendColumn(new wxDataViewColumn("Amount", amount_renderer, + 1, wxCOL_WIDTH_AUTOSIZE), + "long"); +#endif + } else { + chosen_list_->AppendTextColumn("Value"); + } const DoubleMap& option_set = GetOptionSetElements(*game_, option_name); - for (int i = 0; i < option_value.set_values.size(); i++) { - if (option_value.set_values.at(i)) { - std::string str_val = option_set.GetValue(i); + if (option_definition_->type == kDictOption) { + for (const auto& [id, amount] : option_value.dict_values) { + std::string str_val = option_set.GetValue(id); wxVector data; data.push_back(wxVariant(str_val)); +#ifdef __WXMAC__ + data.push_back(wxVariant(std::to_string(amount))); +#else + data.push_back(wxVariant(amount)); +#endif chosen_list_->AppendItem(data); picked_.insert(str_val); } + } else if (option_definition_->type == kSetOption) { + for (int i = 0; i < option_value.set_values.size(); i++) { + if (option_value.set_values.at(i)) { + std::string str_val = option_set.GetValue(i); + + wxVector data; + data.push_back(wxVariant(str_val)); + chosen_list_->AppendItem(data); + + picked_.insert(str_val); + } + } } wxButton* remove_btn = @@ -122,10 +156,32 @@ OptionValue OptionSetDialog::GetOptionValue() const { GetOptionSetElements(*game_, option_definition_->name); OptionValue option_value; - option_value.set_values.resize(option_set.size()); - for (const std::string& name : picked_) { - option_value.set_values[option_set.GetId(name)] = true; + if (option_definition_->type == kDictOption) { + for (int i = 0; i < chosen_list_->GetItemCount(); i++) { + wxString str_sel = chosen_list_->GetTextValue(i, 0); + +#ifdef __WXMAC__ + wxString str_amount = chosen_list_->GetTextValue(i, 1); + + long amount_value; + if (str_amount.ToLong(&amount_value)) { +#else + wxVariant amount_variant; + chosen_list_->GetValue(amount_variant, i, 1); + long amount_value = amount_variant.GetLong(); + { +#endif + option_value.dict_values[option_set.GetId(str_sel.ToStdString())] = + amount_value; + } + } + } else if (option_definition_->type == kSetOption) { + option_value.set_values.resize(option_set.size()); + + for (const std::string& name : picked_) { + option_value.set_values[option_set.GetId(name)] = true; + } } return option_value; @@ -169,6 +225,13 @@ void OptionSetDialog::OnAddClicked(wxCommandEvent& event) { wxVector data; data.push_back(wxVariant(selected_text)); + if (option_definition_->type == kDictOption) { +#ifdef __WXMAC__ + data.push_back(wxVariant("1")); +#else + data.push_back(wxVariant(1)); +#endif + } chosen_list_->AppendItem(data); picked_.insert(selected_text.ToStdString()); diff --git a/src/wizard_editor.cc b/src/wizard_editor.cc index 8adfb02..edf0eac 100644 --- a/src/wizard_editor.cc +++ b/src/wizard_editor.cc @@ -236,8 +236,9 @@ FormOption::FormOption(WizardEditor* parent, wxWindow* container, sizer->Add(final_sizer, wxSizerFlags().Expand()); randomizable = true; - } else if (game_option.type == kSetOption) { - if (game_option.set_type == kCustomSet && + } else if (game_option.type == kSetOption || + game_option.type == kDictOption) { + if (game_option.type == kSetOption && game_option.set_type == kCustomSet && game_option.custom_set.size() <= 15) { list_box_ = new wxCheckListBox(container, wxID_ANY); @@ -334,7 +335,8 @@ void FormOption::PopulateFromWorld() { combo_box_->Enable(); } } - } else if (game_option.type == kSetOption) { + } else if (game_option.type == kSetOption || + game_option.type == kDictOption) { if (list_box_ != nullptr) { if (ov.error) { list_box_->Disable(); @@ -516,8 +518,10 @@ void FormOption::SaveToWorld() { } else if (game_option.type == kRangeOption) { new_value.int_value = slider_->GetValue(); } else if (game_option.type == kSetOption) { - for (int i = 0; i < list_box_->GetCount(); i++) { - new_value.set_values.push_back(list_box_->IsChecked(i)); + if (list_box_ != nullptr) { + for (int i = 0; i < list_box_->GetCount(); i++) { + new_value.set_values.push_back(list_box_->IsChecked(i)); + } } } diff --git a/src/world.cc b/src/world.cc index f80841c..b73a3ef 100644 --- a/src/world.cc +++ b/src/world.cc @@ -171,7 +171,19 @@ void World::SetOption(const std::string& option_name, } if (!any_set) { + yaml_[*game_][option_name] = YAML::Load("[]"); + } + } else if (option.type == kDictOption) { + yaml_[*game_].remove(option_name); + + const DoubleMap& option_set = + GetOptionSetElements(game, option_name); + if (option_value.dict_values.empty()) { yaml_[*game_][option_name] = YAML::Load("{}"); + } else { + for (const auto& [id, amount] : option_value.dict_values) { + yaml_[*game_][option_name][option_set.GetValue(id)] = amount; + } } } @@ -263,6 +275,21 @@ void World::PopulateFromYaml() { } else { option_value.error = "Option value should be a list."; } + } else if (option.type == kDictOption) { + const DoubleMap& option_set = + GetOptionSetElements(game, option.name); + + if (game_node[option.name].IsMap()) { + for (YAML::const_iterator it = game_node[option.name].begin(); + it != game_node[option.name].end(); it++) { + std::string str_val = it->first.as(); + int int_val = it->second.as(); + + option_value.dict_values[option_set.GetId(str_val)] = int_val; + } + } else { + option_value.error = "Option value should be a map."; + } } options_[option.name] = std::move(option_value);