//+----------------------------------------------------------------------------+ //| Description: Magic Set Editor - Program to make Magic (tm) cards | //| Copyright: (C) 2001 - 2006 Twan van Laarhoven | //| License: GNU General Public License 2 or later (see file COPYING) | //+----------------------------------------------------------------------------+ // ----------------------------------------------------------------------------- : Includes #include #include #include #include #include #include #include #include #include #include DECLARE_TYPEOF_COLLECTION(CardP); // ----------------------------------------------------------------------------- : MtgEditorFileFormat /// The file format of Mtg Editor files class MtgEditorFileFormat : public FileFormat { public: virtual String extension() { return _("set"); } virtual String name() { return _("Mtg Editor files (*.set)"); } virtual bool canImport() { return true; } virtual bool canExport(const Game&) { return false; } virtual SetP importSet(const String& filename); private: // Filter: se filename -> image directory // based on MtgEditor's: CardSet.getImageFolder String filter1(const String& str); // Filter: card name -> image name // based on MtgEditor's: Tools::purgeSpecialChars String filter2(const String& str); // Remove mtg editor tags void untag(const CardP& card, const String& field); // Translate all tags, mana tags get converted to , other tags are removed void translateTags(String& value); }; FileFormatP mtg_editor_file_format() { return new_shared(); } // ----------------------------------------------------------------------------- : Importing SetP MtgEditorFileFormat::importSet(const String& filename) { wxFileInputStream f(filename); #ifdef UNICODE wxTextInputStream file(f, _('\n'), wxConvLibc); #else wxTextInputStream file(f); #endif // create set SetP set(new Set(Game::byName(_("magic")))); // parsing state CardP current_card; Defaultable* target = nullptr; // value we are currently reading String layout = _("8e"); String set_date, card_date; bool first = true; // read file while (!f.Eof()) { // read a line if (!current_card) current_card = new_shared1(*set->game); String line = file.ReadLine(); if (line == _("#SET###########")) { // set.title target = &set->value(_("title")).value; } else if (line == _("#SETDATE#######")) { // date // remember date for generation of illustration filename target = nullptr; set_date = file.ReadLine(); } else if (line == _("#SHOWRARITY####") || line == _("#FONTS#########") || line == _("#COUNT#########")) { // ignore target = nullptr; file.ReadLine(); } else if (line == _("#LAYOUT########")) { // layout type target = nullptr; layout = file.ReadLine(); } else if (line == _("#CARD##########") || line == _("#EOF###########")) { // begin/end of card if (!first) { // First [CARD##] indicates only the start of a card, subsequent ones also the end of the previous // card. We only care about the latter // remove all tags from all text values untag(current_card, _("name")); untag(current_card, _("super type")); untag(current_card, _("sub type")); untag(current_card, _("casting cost")); untag(current_card, _("flavor text")); untag(current_card, _("illustrator")); untag(current_card, _("copyright")); untag(current_card, _("power")); untag(current_card, _("toughness")); // translate mtg editor tags to mse2 tags translateTags(current_card->value(_("rule text")).value.mutate()); // add the card to the set set->cards.push_back(current_card); } first = false; current_card = new_shared1(*set->game); target = ¤t_card->value(_("name")).value; } else if (line == _("#DATE##########")) { // date // remember date for generation of illustration filename target = nullptr; card_date = file.ReadLine(); } else if (line == _("#TYPE##########")) { // super type target = ¤t_card->value(_("super type")).value; } else if (line == _("#SUBTYPE#######")) { // sub type target = ¤t_card->value(_("sub type")).value; } else if (line == _("#COST##########")) { // casting cost target = ¤t_card->value(_("casting cost")).value; } else if (line == _("#RARITY########") || line == _("#FREQUENCY#####")) { // rarity target = 0; line = file.ReadLine(); if (line == _("0")) current_card->value(_("rarity")).value.assign(_("common")); else if (line == _("1")) current_card->value(_("rarity")).value.assign(_("uncommon")); else current_card->value(_("rarity")).value.assign(_("rare")); } else if (line == _("#COLOR#########")) { // card color target = 0; line = file.ReadLine(); current_card->value(_("card color")).value.assign(line); } else if (line == _("#AUTOBG########")) { // card color.isDefault target = 0; line = file.ReadLine(); if (line == _("TRUE")) { current_card->value(_("card color")).value.makeDefault(); } } else if (line == _("#RULETEXT######")) { // rule text target = ¤t_card->value(_("rule text")).value; } else if (line == _("#FLAVORTEXT####")) { // flavor text target = ¤t_card->value(_("flavor text")).value; } else if (line == _("#ARTIST########")) { // illustrator target = ¤t_card->value(_("illustrator")).value; } else if (line == _("#COPYRIGHT#####")) { // copyright target = ¤t_card->value(_("copyright")).value; } else if (line == _("#POWER#########")) { // power target = ¤t_card->value(_("power")).value; } else if (line == _("#TOUGHNESS#####")) { // toughness target = ¤t_card->value(_("toughness")).value; } else if (line == _("#ILLUSTRATION##") || line == _("#ILLUSTRATION8#")) { // image target = 0; line = file.ReadLine(); if (!wxFileExists(line)) { // based on card name and date line = filter1(filename) + set_date + _("/") + filter2(current_card->value(_("name")).value()) + card_date + _(".jpg"); } // copy image into set if (wxFileExists(line)) { String image_file = set->newFileName(_("image"),_("")); if (wxCopyFile(line, set->nameOut(image_file), true)) { current_card->value(_("image")).filename = image_file; } } } else if (line == _("#TOMBSTONE#####")) { // tombstone target = 0; line = file.ReadLine(); current_card->value(_("card symbol")).value.assign( line==_("TRUE") ? _("tombstone") : _("none") ); } else { // normal text if (target != 0) { // value of a text field if (!target->isDefault()) target->mutate() += _("\n"); target->mutate() += line; } else { throw ParseError(_("Error in Mtg Editor file, unexpected text:\n") + line); } } } // set defaults for artist and copyright to that of the first card if (!set->cards.empty()) { String artist = set->cards[0]->value(_("illustrator")).value(); String copyright = set->cards[0]->value(_("copyright")) .value(); set->value(_("artist")) .value.assign(artist); set->value(_("copyright")).value.assign(copyright); // which cards have this value? FOR_EACH(card, set->cards) { Defaultable& card_artist = card->value(_("illustrator")).value; Defaultable& card_copyright = card->value(_("copyright")) .value; if (card_artist() == artist) card_artist.makeDefault(); if (card_copyright() == copyright) card_copyright.makeDefault(); } } // Load stylesheet if (layout != _("8e")) { try { set->stylesheet = StyleSheet::byGameAndName(*set->game, _("old")); } catch (const Error&) { // If old style doesn't work try the new one set->stylesheet = StyleSheet::byGameAndName(*set->game, _("new")); } } else { set->stylesheet = StyleSheet::byGameAndName(*set->game, _("new")); } return set; } // ----------------------------------------------------------------------------- : Filtering String MtgEditorFileFormat::filter1(const String& str) { String before, after, ret; // split path name size_t pos = str.find_last_of(_("/\\")); if (pos == String::npos) { before = _(""); after = str; } else { before = str.substr(0, pos + 1); after = str.substr(pos + 1); } // filter FOR_EACH(c, after) { if (isAlnum(c)) ret += c; else ret += _('_'); } return before + ret; } String MtgEditorFileFormat::filter2(const String& str) { String ret; FOR_EACH_CONST(c, str) { if (isAlnum(c)) ret += c; else if (c==_(' ') || c==_('-')) ret += _('_'); } return ret; } void MtgEditorFileFormat::untag(const CardP& card, const String& field) { Defaultable& value = card->value(field).value; value.assignDontChangeDefault(untag_no_escape(value())); } void MtgEditorFileFormat::translateTags(String& value) { // Translate tags String ret; size_t pos = 0; while (pos < value.size()) { Char c = value.GetChar(pos); ++pos; if (c == _('<')) { String tag; while (pos < value.size()) { c = value.GetChar(pos); ++pos; if (c == _('>')) break; else tag += c; } tag.MakeUpper(); unsigned long number; if (tag==_("W") || tag==_("U") || tag==_("B") || tag==_("R") || tag==_("G") || tag==_("X") || tag==_("Y") || tag==_("Z")) { ret += _("") + tag + _(""); } else if (tag.ToULong(&number)) { ret += _("") + tag + _(""); } else if (tag==_("T") || tag==_("TAP")) { ret += _("T"); } else if (tag==_("THIS")) { ret += _("~"); } } else { ret += c; } } // Join adjecent symbol sections value = replace_all(ret, _(""), _("")); }