diff --git a/src/data/card.hpp b/src/data/card.hpp index c7372ea3..317b4c79 100644 --- a/src/data/card.hpp +++ b/src/data/card.hpp @@ -42,6 +42,18 @@ class Card { /** May return "" */ String identification() const; + /// Find a value in the data by name and type + template T& value(const String& name) { + for(IndexMap::iterator it = data.begin() ; it != data.end() ; ++it) { + if ((*it)->fieldP->name == name) { + T* ret = dynamic_cast(it->get()); + if (!ret) throw InternalError(_("Card field with name '")+name+_("' doesn't have the right type")); + return *ret; + } + } + throw InternalError(_("Expected a card field with name '")+name+_("'")); + } + DECLARE_REFLECTION(); }; diff --git a/src/data/field/choice.hpp b/src/data/field/choice.hpp index 0f99c81c..8c286582 100644 --- a/src/data/field/choice.hpp +++ b/src/data/field/choice.hpp @@ -139,7 +139,9 @@ class ChoiceValue : public Value { public: inline ChoiceValue(const ChoiceFieldP& field) : Value(field) - , value(field->initial, true) + , value(field->initial.empty() + ? field->choices->choiceName(0) // first choice + : field->initial, true) {} DECLARE_HAS_FIELD(Choice) diff --git a/src/data/format/formats.cpp b/src/data/format/formats.cpp index c0c9b761..e42a13d2 100644 --- a/src/data/format/formats.cpp +++ b/src/data/format/formats.cpp @@ -18,9 +18,9 @@ DECLARE_TYPEOF_COLLECTION(FileFormatP); vector file_formats; void init_file_formats() { - //file_formats.push_back(new_shared()); - //file_formats.push_back(new_shared()); - //file_formats.push_back(new_shared()); + file_formats.push_back(mse2_file_format()); + file_formats.push_back(mse1_file_format()); + file_formats.push_back(mtg_editor_file_format()); } String import_formats() { @@ -47,7 +47,7 @@ String export_formats(const Game& game) { return type_strings; } -void export_set(const Set& set, const String& filename, size_t format_type) { +void export_set(Set& set, const String& filename, size_t format_type) { FileFormatP format = file_formats.at(format_type); if (!format->canExport(*set.game)) { throw InternalError(_("File format doesn't apply to set")); @@ -67,4 +67,4 @@ SetP import_set(String name) { // default: use first format = MSE2 format assert(!file_formats.empty() && file_formats[0]->canImport()); return file_formats[0]->importSet(name); -} \ No newline at end of file +} diff --git a/src/data/format/formats.hpp b/src/data/format/formats.hpp index b0cf4890..a79e3b87 100644 --- a/src/data/format/formats.hpp +++ b/src/data/format/formats.hpp @@ -14,6 +14,7 @@ class Game; DECLARE_POINTER_TYPE(Set); +DECLARE_POINTER_TYPE(FileFormat); // ----------------------------------------------------------------------------- : FileFormat @@ -33,7 +34,7 @@ class FileFormat { throw InternalError(_("Import not supported by this file format")); } /// Export using this filter - virtual void exportSet(const Set& set, const String& filename) { + virtual void exportSet(Set& set, const String& filename) { throw InternalError(_("Export not supported by this file format")); } }; @@ -69,10 +70,13 @@ SetP import_set(String name); /// Save a set under the specified name. /** filterType specifies what format to use for saving, used as index in the list of file formats */ -void export_set(const Set& set, const String& filename, size_t format_type); +void export_set(Set& set, const String& filename, size_t format_type); -// ----------------------------------------------------------------------------- : Export +// ----------------------------------------------------------------------------- : The formats +FileFormatP mse1_file_format(); +FileFormatP mse2_file_format(); +FileFormatP mtg_editor_file_format(); // ----------------------------------------------------------------------------- : EOF #endif diff --git a/src/data/format/mse1.cpp b/src/data/format/mse1.cpp index 5e85f472..ac428295 100644 --- a/src/data/format/mse1.cpp +++ b/src/data/format/mse1.cpp @@ -7,5 +7,166 @@ // ----------------------------------------------------------------------------- : Includes #include +#include +#include +#include +#include +#include +#include +#include +#include -// ----------------------------------------------------------------------------- : +// ----------------------------------------------------------------------------- : MSE1FileFormat + +/// The file format of MSE1 files +class MSE1FileFormat : public FileFormat { + public: + virtual String extension() { return _("mse"); } + virtual String name() { return _("Magic Set Editor version 1 files (*.mse)"); } + virtual bool canImport() { return true; } + virtual bool canExport(const Game&) { return false; } + virtual SetP importSet(const String& filename); +}; + +FileFormatP mse1_file_format() { + return new_shared(); +} + +// ----------------------------------------------------------------------------- : Importing + +// read a card from a mse1 file, add to the set when done +void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file); + +SetP MSE1FileFormat::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); + set->game = Game::byName(_("magic")); + set->data.init(set->game->set_fields); + + // file version check + String format = file.ReadLine(); + if (format.substr(0,8) != _("MTG Set8")) { + throw ParseError(_("Expected MSE format version 8\nTo convert files made with older versions of Magic Set Editor:\n 1. Download the latest version 1 from http:;//magicsetedtitor.sourceforge.net\n 2. Open the set, then save the set\n 3. Try to open them again in this program.")); + } + // read general info + set->value(_("title")) .value = file.ReadLine(); + set->value(_("artist")) .value = file.ReadLine(); + set->value(_("copyright")).value = file.ReadLine(); + file.ReadLine(); // border color, ignored + String stylesheet = file.ReadLine(); + file.ReadLine(); // apprentice prefix ('MY'), ignored + file.ReadLine(); // 'formatN'?, not even used by MSE1 :S, ignored + file.ReadLine(); // 'formatS'?, same, ignored + file.ReadLine(); // symbol filename, ignored + file.ReadLine(); // use black symbol for all rarities, ignored + String desc, line; + while (!f.Eof()) { + line = file.ReadLine(); + if (line == _("\xFF")) break; + desc += line; + } + set->value(_("description")).value = desc; + + // load stylesheet + if (stylesheet.substr(0,3) == _("old")) { + try { + set->stylesheet = StyleSheet::byGameAndName(*set->game, _("old")); + } catch (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")); + } + + // read cards + CardP current_card; + while (!f.Eof()) { + read_mse1_card(*set, f, file); + } + + // done + return set; +} + +void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file) { + CardP card(new Card(*set.game)); + while (!f.Eof()) { + // read a line + String line = file.ReadLine(); + if (line.empty()) continue; + Char type = line.GetChar(0); + line = line.substr(1); + // interpret this line + switch (type) { + case 'A': { // done + set.cards.push_back(card); + return; + } case 'B': { // name + card->value(_("name")) .value.assign(line); + break; + } case 'C': case 'D': { // image filename + String image_file = set.newFileName(_("image"),_("")); // a new unique name in the package + if (wxCopyFile(line, set.nameOut(image_file), true)) { + card->value(_("image")) .filename = image_file; + } + break; + } case 'E': { // super type + card->value(_("super type")) .value.assign(line); + break; + } case 'F': { // sub type + card->value(_("sub type")) .value.assign(line); + break; + } case 'G': { // casting cost + card->value(_("casting cost")).value.assign(line); + break; + } case 'H': { // rarity + String rarity; + if (line == _("(U)")) rarity = _("uncommon"); + else if (line == _("(R)")) rarity = _("rare"); + else rarity = _("common"); + card->value(_("rarity")) .value.assign(rarity); + break; + } case 'I': { // power/thoughness + size_t pos = line.find_first_of(_('/')); + if (pos != String::npos) { + card->value(_("power")) .value.assign(line.substr(0, pos)); + card->value(_("toughness")) .value.assign(line.substr(pos+1)); + } + break; + } case 'J': { // rule text or part of text + Defaultable& text = card->value(_("rule text")).value; + if (!text().empty()) text.mutate() += _('\n'); + text.mutate() += line; + break; + } case 'K': { // flavor text or part of text + Defaultable& text = card->value(_("flavor text")).value; + if (!text().empty()) text.mutate() += _('\n'); + text.mutate() += line; + break; + } case 'L': { // card color (if not default) + // decode color + String color; + if (line == _("1")) color = _("white"); + else if (line == _("2")) color = _("blue"); + else if (line == _("3")) color = _("black"); + else if (line == _("4")) color = _("red"); + else if (line == _("5")) color = _("green"); + else if (line == _("6")) color = _("colorless"); + else if (line == _("7")) color = _("land"); + else if (line == _("9")) color = _("multicolor"); + else color = _("colorless"); + card->value(_("card color")).value.assign(color); + break; + } default: { + throw ParseError(_("Not a valid MSE1 file")); + } + } + } +} diff --git a/src/data/format/mse2.cpp b/src/data/format/mse2.cpp index 5e85f472..35b9f51a 100644 --- a/src/data/format/mse2.cpp +++ b/src/data/format/mse2.cpp @@ -7,5 +7,30 @@ // ----------------------------------------------------------------------------- : Includes #include +#include +#include -// ----------------------------------------------------------------------------- : +// ----------------------------------------------------------------------------- : MSE2FileFormat + +/// The file format of MSE2 files +class MSE2FileFormat : public FileFormat { + public: + virtual String extension() { return _("mse-set"); } + virtual String name() { return _("Magic Set Editor sets (*.mse-set)"); } + virtual bool canImport() { return true; } + virtual bool canExport(const Game&) { return true; } + virtual SetP importSet(const String& filename) { + settings.addRecentFile(filename); + SetP set(new Set); + set->open(filename); + return set; + } + virtual void exportSet(Set& set, const String& filename) { + set.saveAs(filename); + set.actions.setSavePoint();; + } +}; + +FileFormatP mse2_file_format() { + return new_shared(); +} diff --git a/src/data/format/mtg_editor.cpp b/src/data/format/mtg_editor.cpp index 5e85f472..15b2641c 100644 --- a/src/data/format/mtg_editor.cpp +++ b/src/data/format/mtg_editor.cpp @@ -8,4 +8,24 @@ #include -// ----------------------------------------------------------------------------- : +// ----------------------------------------------------------------------------- : 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); +}; + +FileFormatP mtg_editor_file_format() { + return new_shared(); +} + +// ----------------------------------------------------------------------------- : Importing + +SetP MtgEditorFileFormat::importSet(const String& filename) { + return SetP();//TODO +} diff --git a/src/data/set.hpp b/src/data/set.hpp index a72a898f..e708b30b 100644 --- a/src/data/set.hpp +++ b/src/data/set.hpp @@ -69,6 +69,18 @@ class Set : public Packaged { /// Styling information for a particular stylesheet IndexMap& stylingDataFor(const StyleSheet&); + /// Find a value in the data by name and type + template T& value(const String& name) { + for(IndexMap::iterator it = data.begin() ; it != data.end() ; ++it) { + if ((*it)->fieldP->name == name) { + T* ret = dynamic_cast(it->get()); + if (!ret) throw InternalError(_("Set field with name '")+name+_("' doesn't have the right type")); + return *ret; + } + } + throw InternalError(_("Expected a set field with name '")+name+_("'")); + } + protected: virtual String typeName() const; virtual void validate(Version); diff --git a/src/gui/set/window.cpp b/src/gui/set/window.cpp index c02fc306..a6dd97cf 100644 --- a/src/gui/set/window.cpp +++ b/src/gui/set/window.cpp @@ -351,14 +351,14 @@ void SetWindow::onFileNew(wxCommandEvent&) { if (!askSaveAndContinue()) return; // new set? SetP new_set = new_set_window(this); - if (new_set) set = new_set; + if (new_set) setSet(new_set); } void SetWindow::onFileOpen(wxCommandEvent&) { if (!askSaveAndContinue()) return; wxFileDialog dlg(this, _("Open a set"), _(""), _(""), import_formats(), wxOPEN); if (dlg.ShowModal() == wxID_OK) { - set = import_set(dlg.GetPath()); + setSet(import_set(dlg.GetPath())); } } diff --git a/src/render/value/color.cpp b/src/render/value/color.cpp index dbc670c6..085eb5f4 100644 --- a/src/render/value/color.cpp +++ b/src/render/value/color.cpp @@ -15,7 +15,7 @@ DECLARE_TYPEOF_COLLECTION(ColorField::ChoiceP); void ColorValueViewer::draw(RotatedDC& dc) { // draw in the value color dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(value().value.get()); + dc.SetBrush(value().value()); if (nativeLook()) { // native look // find name of color @@ -24,7 +24,7 @@ void ColorValueViewer::draw(RotatedDC& dc) { color_name = field().default_name; } else { FOR_EACH_CONST(c, field().choices) { - if (value().value.get() == c->color) { + if (value().value() == c->color) { color_name = capitalize(c->name); break; } diff --git a/src/script/scriptable.hpp b/src/script/scriptable.hpp index a14e1fe1..9da8c39f 100644 --- a/src/script/scriptable.hpp +++ b/src/script/scriptable.hpp @@ -87,7 +87,7 @@ class OptionalScript { }; template -inline ScriptValueP toScript(const Defaultable& v) { return toScript(v.get()); } +inline ScriptValueP toScript(const Defaultable& v) { return toScript(v()); } // ----------------------------------------------------------------------------- : StringScript diff --git a/src/util/defaultable.hpp b/src/util/defaultable.hpp index 4bdc04e4..f5e2eb48 100644 --- a/src/util/defaultable.hpp +++ b/src/util/defaultable.hpp @@ -40,12 +40,18 @@ class Defaultable { /// Get access to the value inline const T& operator () () const { return value; } - inline const T& get () const { return value; } + /// Get access to the value, for changing it + inline T& mutate () { + is_default = false; + return value; + } /// Is this value in the default state? inline bool isDefault() const { return is_default; } /// Set the defaultness to true inline void setDefault() { is_default = true; } + /// Set the defaultness to false + inline void unsetDefault() { is_default = false; } /// Compare the values, ignore defaultness /** used by scriptable to check for changes */