//+----------------------------------------------------------------------------+ //| Description: Magic Set Editor - Program to make card games | //| Copyright: (C) Twan van Laarhoven and the other MSE developers | //| License: GNU General Public License 2 or later (see file COPYING) | //+----------------------------------------------------------------------------+ #pragma once // ----------------------------------------------------------------------------- : Includes #include #include #include #include #include #include #include #include #include #include #include #include // ----------------------------------------------------------------------------- : Helper functions inline static Value* get_card_field_container(Game& game, IndexMap& map, String& key_name, bool ignore_field_not_found) { // find value container to update IndexMap::const_iterator it = map.find(key_name); if (it == map.end()) { // look among alternate names std::map::iterator alt_name_it = game.card_fields_alt_names.find(unified_form(key_name)); if (alt_name_it != game.card_fields_alt_names.end()) { it = map.find(alt_name_it->second); } } if (it == map.end()) { if (ignore_field_not_found) return nullptr; throw ScriptError(_ERROR_2_("no field with name", _TYPE_("card"), key_name)); } return it->get(); } inline static Value* get_container(IndexMap& map, const String& type, const String& key_name, bool ignore_field_not_found) { // find value container to update IndexMap::const_iterator it = map.find(key_name); if (it == map.end()) { it = map.find(key_name.Lower()); if (it == map.end()) { if (ignore_field_not_found) return nullptr; throw ScriptError(_ERROR_2_("no field with name", _TYPE_V_(type), key_name)); } } return it->get(); } inline static void set_container(Value* container, ScriptValueP& value, String key_name) { // set the given value into the container if (TextValue* tvalue = dynamic_cast(container)) { tvalue->value = value->toString(); } else if (ChoiceValue* cvalue = dynamic_cast(container)) { cvalue->value = value->toString(); } else if (PackageChoiceValue* pvalue = dynamic_cast(container)) { String package_name = value->toString(); while (package_name.starts_with(_("/"))) package_name = package_name.substr(1); pvalue->package_name = package_name; } else if (ColorValue* cvalue = dynamic_cast(container)) { cvalue->value = value->toColor(); } else if (ImageValue* ivalue = dynamic_cast(container)) { if (ExternalImage* img = dynamic_cast(value.get())) { ivalue->filename = LocalFileName::fromReadString(img->toString(), ""); } else if (value->type() == SCRIPT_STRING) { ivalue->filename = LocalFileName::fromReadString(value->toString(), ""); } else { throw ScriptError(_ERROR_1_("cant set image value", key_name)); } } else if (SymbolValue* svalue = dynamic_cast(container)) { if (value->type() == SCRIPT_STRING) { svalue->filename = LocalFileName::fromReadString(value->toString(), ""); } else { throw ScriptError(_ERROR_1_("cant set symbol value", key_name)); } } else { throw ScriptError(_ERROR_1_("cant set value", key_name)); } } inline static bool set_stylesheet_container(const Game& game, CardP& card, ScriptValueP& value, String key_name, bool ignore_field_not_found) { // check if the given value is for a stylesheet, if found set it and return true key_name = unified_form(key_name); if (key_name == _("style") || key_name == _("stylesheet") || key_name == _("template")) { if (!trim(value->toString()).empty()) { card->stylesheet = StyleSheet::byGameAndName(game, value->toString()); if (card->stylesheet) { card->styling_data.init(card->stylesheet->styling_fields); card->extraDataFor(*card->stylesheet).init(card->stylesheet->extra_card_fields); } } return true; } return false; } inline static bool set_builtin_container(const Game& game, CardP& card, ScriptValueP& value, String key_name, bool ignore_field_not_found) { // check if the given value is for a built-in field, if found set it and return true key_name = unified_form(key_name); if (key_name == _("style") || key_name == _("stylesheet") || key_name == _("template")) { return true; // we already took care of this } else if (key_name == _("style_version") || key_name == _("stylesheet_version") || key_name == _("template_version")) { card->stylesheet_version = Version::fromString(value->toString()); return true; } else if (key_name == _("card_notes") || key_name == _("notes") || key_name == _("note")) { card->notes = value->toString(); return true; } else if (key_name == _("id") || key_name == _("uid") || key_name == _("uuid")) { card->uid = value->toString(); return true; } else if (key_name == _("linked_card_1") || key_name == _("linked_card")) { card->linked_card_1 = value->toString(); return true; } else if (key_name == _("linked_card_2")) { card->linked_card_2 = value->toString(); return true; } else if (key_name == _("linked_card_3")) { card->linked_card_3 = value->toString(); return true; } else if (key_name == _("linked_card_4")) { card->linked_card_4 = value->toString(); return true; } else if (key_name == _("linked_relation_1") || key_name == _("linked_relation")) { card->linked_relation_1 = value->toString(); return true; } else if (key_name == _("linked_relation_2")) { card->linked_relation_2 = value->toString(); return true; } else if (key_name == _("linked_relation_3")) { card->linked_relation_3 = value->toString(); return true; } else if (key_name == _("linked_relation_4")) { card->linked_relation_4 = value->toString(); return true; } else if (key_name == _("styling_data") || key_name == _("style_data") || key_name == _("stylesheet_data") || key_name == _("template_data") || key_name == _("styling") || key_name == _("styling_fields") || key_name == _("style_fields") || key_name == _("stylesheet_fields") || key_name == _("template_fields") || key_name == _("extra_data") || key_name == _("extra_fields") || key_name == _("extra_card_data") || key_name == _("extra_card_fields")) { bool is_extra = key_name == _("extra_data") || key_name == _("extra_fields") || key_name == _("extra_card_data") || key_name == _("extra_card_fields"); String type = is_extra ? _("extra") : _("styling"); if (value->type() != SCRIPT_COLLECTION) { throw ScriptError(_ERROR_1_("styling data not map", type)); } if (!card->stylesheet) { throw ScriptError(_ERROR_1_("styling data without stylesheet", type)); } IndexMap& data = is_extra ? card->extraDataFor(*card->stylesheet) : card->styling_data; ScriptValueP it = value->makeIterator(); ScriptValueP key; while (ScriptValueP value = it->next(&key)) { assert(key); if (key == script_nil || value == script_nil) continue; String key_name = key->toString(); Value* container = get_container(data, type, key_name, ignore_field_not_found); set_container(container, value, key_name); if (!is_extra) card->has_styling = true; } return true; } return false; } inline static bool check_table_headers(GameP& game, std::vector& headers, const String& file_extension, String& missing_fields_out) { if (headers.empty()) { queue_message(MESSAGE_ERROR, _("Empty headers given")); return false; } for (int x = 0; x < headers.size(); ++x) { String key_name = headers[x]; if ( game->card_fields_alt_names.find(unified_form(key_name)) == game->card_fields_alt_names.end() || key_name == _("notes") || key_name == _("note") || key_name == _("style") || key_name == _("stylesheet") || key_name == _("template") || key_name == _("id") || key_name == _("uid") || key_name == _("multiverse_id") || key_name == _("linked_card") || key_name == _("linked_card_1") || key_name == _("linked_card_2") || key_name == _("linked_card_3") || key_name == _("linked_card_4") || key_name == _("linked_relation") || key_name == _("linked_relation_1") || key_name == _("linked_relation_2") || key_name == _("linked_relation_3") || key_name == _("linked_relation_4") || key_name == _("link_relation") || key_name == _("link_relation_1") || key_name == _("link_relation_2") || key_name == _("link_relation_3") || key_name == _("link_relation_4") ) { missing_fields_out += _("\n ") + key_name; } } return true; } inline static bool cards_from_table(SetP& set, vector& headers, std::vector>& table, bool ignore_field_not_found, const String& file_extension, vector& cards_out) { // ensure table is square int count = headers.size(); for (int y = 0; y < table.size(); ++y) { if (table[y].size() != count) { queue_message(MESSAGE_ERROR, _ERROR_1_("add card csv file malformed", wxString::Format(wxT("%i"), y+1))); return false; } } // produce cards from table Context& ctx = set->getContext(); ScriptValueP new_card_function = ctx.getVariable("new_card"); ScriptValueP ctx_input = ctx.getVariableOpt(SCRIPT_VAR_input); ScriptValueP ctx_ignore = ctx.getVariableOpt("ignore_field_not_found"); ctx.setVariable("ignore_field_not_found", to_script(ignore_field_not_found)); for (int y = 0; y < table.size(); ++y) { ScriptCustomCollectionP field_map = make_intrusive(); for (int x = 0; x < count; ++x) { // check if value is worth writing if (table[y][x] != script_nil) { field_map->key_value[headers[x]] = table[y][x]; } } ctx.setVariable(SCRIPT_VAR_input, field_map); CardP card = from_script(new_card_function->eval(ctx)); // is this a new card? if (contains(set->cards, card) || contains(cards_out, card)) { // make copy card = make_intrusive(set.get(), card); } cards_out.push_back(card); } if (ctx_input) ctx.setVariable(SCRIPT_VAR_input, ctx_input); if (ctx_ignore) ctx.setVariable("ignore_field_not_found", ctx_ignore); return true; }