/* * Copyright 2007-2008 Ben Boeckel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ // Header include #include "Sigmod.h" // Sigmod includes #include "Ability.h" #include "Author.h" #include "Badge.h" #include "CoinList.h" #include "EggGroup.h" #include "GlobalScript.h" #include "Item.h" #include "ItemType.h" #include "Macros.h" #include "Map.h" #include "Move.h" #include "Nature.h" #include "Rules.h" #include "Skin.h" #include "Sound.h" #include "Species.h" #include "Sprite.h" #include "Status.h" #include "Store.h" #include "Tile.h" #include "Time.h" #include "Trainer.h" #include "Type.h" #include "Weather.h" // Qt includes #include Sigmod::Sigmod::Sigmod() : Object(NULL, 0), m_title(""), m_version(""), m_description(""), m_singlePlayer(true), m_startMap(INT_MAX), m_startWarp(INT_MAX), m_typechart(0, 0), m_rules(new Rules(this)) { } Sigmod::Sigmod::Sigmod(const Sigmod& sigmod) : Object(NULL, 0), m_rules(new Rules(this)) { *this = sigmod; } Sigmod::Sigmod::Sigmod(const QDomElement& xml) : Object(NULL, 0), m_rules(new Rules(this)) { load(xml); } Sigmod::Sigmod::~Sigmod() { delete m_rules; clear(); } void Sigmod::Sigmod::validate() { TEST_BEGIN(); if (m_title.isEmpty()) emit(error("Title is empty")); if (m_version.isEmpty()) emit(error("Version is empty")); if (m_description.isEmpty()) emit(warning("Description is empty")); if (m_singlePlayer) { const Map* map = mapById(m_startMap); if (!map) emit(error("Invalid starting map")); else if (!map->warpById(m_startWarp)) emit(error("Invalid starting warp")); } if ((m_typechart.width() != typeCount()) || (m_typechart.height() != typeCount())) emit(error("Type chart is invalid")); TEST_CHILD(m_rules); QSet idChecker; QSet nameChecker; QSet timeChecker; if (abilityCount() < m_rules->maxAbilities()) emit(error("There are too few abilities")); TEST_SUB_BEGIN(Ability, abilities); TEST_SUB("ability", id); TEST_SUB("ability", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!authorCount()) emit(error("There are no authors")); TEST_SUB_BEGIN(Author, authors); TEST_SUB("author", id); TEST_SUB("author", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!badgeCount()) emit(error("There are no badges")); TEST_SUB_BEGIN(Badge, badges); TEST_SUB("badge", id); TEST_SUB("badge", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!coinListCount()) emit(warning("There are no coin lists")); TEST_SUB_BEGIN(CoinList, coinLists); TEST_SUB("coin list", id); TEST_SUB("coin list", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (m_rules->breedingAllowed()) { if (!eggGroupCount()) emit(error("There are no egg groups")); TEST_SUB_BEGIN(EggGroup, eggGroups); TEST_SUB("egg group", id); TEST_SUB("egg group", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); } if (!globalScriptCount()) emit(warning("There are no global scripts")); TEST_SUB_BEGIN(GlobalScript, globalScripts); TEST_SUB("global script", id); TEST_SUB("global script", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!itemCount()) emit(warning("There are no items")); TEST_SUB_BEGIN(Item, items); TEST_SUB("item", id); TEST_SUB("item", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!itemTypeCount() && itemCount()) emit(error("There are no item types")); TEST_SUB_BEGIN(ItemType, itemTypes); TEST_SUB("item type", id); TEST_SUB("item type", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!mapCount()) emit(error("There are no maps")); TEST_SUB_BEGIN(Map, maps); TEST_SUB("map", id); TEST_SUB("map", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!moveCount()) emit(error("There are no moves")); TEST_SUB_BEGIN(Move, moves); TEST_SUB("move", id); TEST_SUB("move", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (natureCount() < m_rules->maxNatures()) emit(error("There are too few natures")); TEST_SUB_BEGIN(Nature, natures); TEST_SUB("nature", id); TEST_SUB("nature", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); TEST_SUB_BEGIN(Skin, skins); TEST_SUB("skin", id); TEST_SUB("skin", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!soundCount()) emit(warning("There are no sounds")); TEST_SUB_BEGIN(Sound, sounds); TEST_SUB("sound", id); TEST_SUB("sound", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!speciesCount()) emit(error("There are no species")); TEST_SUB_BEGIN(Species, species); TEST_SUB("species", id); TEST_SUB("species", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!statusCount()) emit(error("There are no status effects")); TEST_SUB_BEGIN(Status, status); TEST_SUB("status", id); TEST_SUB("status", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!storeCount()) emit(warning("There are no stores")); TEST_SUB_BEGIN(Store, stores); TEST_SUB("store", id); TEST_SUB("store", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!tileCount()) emit(error("There are no tiles")); TEST_SUB_BEGIN(Tile, tiles); TEST_SUB("tile", id); TEST_SUB("tile", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!trainerCount()) emit(warning("There are no trainers")); TEST_SUB_BEGIN(Trainer, trainers); TEST_SUB("trainer", id); TEST_SUB("trainer", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!timeCount()) emit(error("There are no times")); TEST_SUB_BEGIN(Time, times); TEST_SUB("time", id); TEST_SUB("time", name); if (timeChecker.contains((60 * object->hour()) + object->minute())) emit(error(subclass("time", QString("%1:%2").arg(object->hour(), object->minute())))); timeChecker.insert((60 * object->hour()) + object->minute()); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!typeCount()) emit(error("There are no types")); TEST_SUB_BEGIN(Type, types); TEST_SUB("type", id); TEST_SUB("type", name); TEST_SUB_END(); idChecker.clear(); nameChecker.clear(); if (!weatherCount()) emit(warning("There are no weathers")); TEST_SUB_BEGIN(Weather, weathers); TEST_SUB("weather", id); TEST_SUB("weather", name); TEST_SUB_END(); TEST_END(); } void Sigmod::Sigmod::load(const QDomElement& xml) { LOAD_BEGIN(); LOAD(title); LOAD(version); LOAD(description); LOAD(singlePlayer); LOAD(startMap); LOAD(startWarp); m_rules->load(xml.firstChildElement("Rules")); LOAD_SUB(newAbility, Ability); LOAD_SUB(newAuthor, Author); LOAD_SUB(newBadge, Badge); LOAD_SUB(newCoinList, CoinList); LOAD_SUB(newEggGroup, EggGroup); LOAD_SUB(newGlobalScript, GlobalScript); LOAD_SUB(newItem, Item); LOAD_SUB(newItemType, ItemType); LOAD_SUB(newMap, Map); LOAD_SUB(newMove, Move); LOAD_SUB(newNature, Nature); LOAD_SUB(newSkin, Skin); LOAD_SUB(newSound, Sound); LOAD_SUB(newSpecies, Species); LOAD_SUB(newSprite, Sprite); LOAD_SUB(newStatus, Status); LOAD_SUB(newStore, Store); LOAD_SUB(newTile, Tile); LOAD_SUB(newTime, Time); LOAD_SUB(newTrainer, Trainer); LOAD_SUB(newType, Type); LOAD_SUB(newWeather, Weather); LOAD_MATRIX(typechart); m_typechart.resize(typeCount(), typeCount()); } QDomElement Sigmod::Sigmod::save() const { QDomElement xml = QDomDocument().createElement(className()); SAVE(title); SAVE(version); SAVE(description); SAVE(singlePlayer); SAVE(startMap); SAVE(startWarp); SAVE_Rules(rules); SAVE_MATRIX(typechart); SAVE_SUB(Ability, abilities); SAVE_SUB(Author, authors); SAVE_SUB(Badge, badges); SAVE_SUB(CoinList, coinLists); SAVE_SUB(EggGroup, eggGroups); SAVE_SUB(GlobalScript, globalScripts); SAVE_SUB(Item, items); SAVE_SUB(ItemType, itemTypes); SAVE_SUB(Map, maps); SAVE_SUB(Move, moves); SAVE_SUB(Nature, natures); SAVE_SUB(Skin, skins); SAVE_SUB(Sound, sounds); SAVE_SUB(Species, species); SAVE_SUB(Sprite, sprites); SAVE_SUB(Status, status); SAVE_SUB(Store, stores); SAVE_SUB(Tile, tiles); SAVE_SUB(Time, times); SAVE_SUB(Trainer, trainers); SAVE_SUB(Type, types); SAVE_SUB(Weather, weathers); return xml; } SETTER(Sigmod, QString&, Title, title) SETTER(Sigmod, QString&, Version, version) SETTER(Sigmod, QString&, Description, description) SETTER(Sigmod, bool, SinglePlayer, singlePlayer) SETTER(Sigmod, int, StartMap, startMap) SETTER(Sigmod, int, StartWarp, startWarp) SETTER_MATRIX(Sigmod, Sigcore::Fraction&, Typechart, typechart, multiplier) void Sigmod::Sigmod::setRules(const Rules& rules) { *m_rules = rules; } void Sigmod::Sigmod::setRules(const QDomElement& xml) { m_rules->load(xml); } GETTER(Sigmod, QString, title) GETTER(Sigmod, QString, version) GETTER(Sigmod, QString, description) GETTER(Sigmod, bool, singlePlayer) GETTER(Sigmod, int, startMap) GETTER(Sigmod, int, startWarp) const Sigcore::Matrix* Sigmod::Sigmod::typechart() const { return &m_typechart; } Sigcore::Matrix* Sigmod::Sigmod::typechart() { return &m_typechart; } Sigcore::Fraction Sigmod::Sigmod::typechart(const int attack, const int defense) const { return m_typechart(attack, defense); } const Sigmod::Rules* Sigmod::Sigmod::rules() const { return m_rules; } Sigmod::Rules* Sigmod::Sigmod::rules() { return m_rules; } CHECK(Sigmod, QString&, title) CHECK(Sigmod, QString&, version) CHECK(Sigmod, QString&, description) CHECK(Sigmod, bool, singlePlayer) CHECK_BEGIN(Sigmod, int, startMap) if (!m_singlePlayer) { emit(error(unused("startMap"))); return false; } if (!mapById(startMap)) EBOUNDS_IDX(startMap); CHECK_END() CHECK_BEGIN(Sigmod, int, startWarp) if (!m_singlePlayer) { emit(error(unused("startWarp"))); return false; } const Map* map = mapById(m_startMap); if (!map) EBOUNDS_IDX(m_startMap); IBOUNDS(startWarp, map, warp); CHECK_END() CHECK_BOUNDS(Sigmod, Sigcore::Fraction&, typechart, 0, INT_MAX) SSUBCLASS(Sigmod, Ability, ability, abilities) SSUBCLASS(Sigmod, Author, author, authors) SSUBCLASS(Sigmod, Badge, badge, badges) SSUBCLASS(Sigmod, CoinList, coinList, coinLists) SSUBCLASS(Sigmod, EggGroup, eggGroup, eggGroups) SSUBCLASS(Sigmod, GlobalScript, globalScript, globalScripts) SSUBCLASS(Sigmod, Item, item, items) SSUBCLASS(Sigmod, ItemType, itemType, itemTypes) SSUBCLASS(Sigmod, Map, map, maps) SSUBCLASS(Sigmod, Move, move, moves) SSUBCLASS(Sigmod, Nature, nature, natures) SSUBCLASS(Sigmod, Skin, skin, skins) SSUBCLASS(Sigmod, Sound, sound, sounds) SSUBCLASS(Sigmod, Species, species, species) SSUBCLASS(Sigmod, Sprite, sprite, sprites) SSUBCLASS(Sigmod, Status, status, status) SSUBCLASS(Sigmod, Store, store, stores) SSUBCLASS(Sigmod, Tile, tile, tiles) SSUBCLASS(Sigmod, Time, time, times) SSUBCLASS(Sigmod, Trainer, trainer, trainers) const Sigmod::Type* Sigmod::Sigmod::type(const int index) const { if (index < typeCount()) return m_types.at(index); return NULL; } Sigmod::Type* Sigmod::Sigmod::type(const int index) { if (index < typeCount()) return m_types[index]; return NULL; } const Sigmod::Type* Sigmod::Sigmod::typeById(const int id) const { return type(typeIndex(id)); } Sigmod::Type* Sigmod::Sigmod::typeById(const int id) { return type(typeIndex(id)); } int Sigmod::Sigmod::typeIndex(const int id) const { for (int i = 0; i < typeCount(); ++i) { if (m_types[i]->id() == id) return i; } return INT_MAX; } int Sigmod::Sigmod::typeCount() const { return m_types.size(); } Sigmod::Type* Sigmod::Sigmod::newType() { return newType(new Type(this, newTypeId())); } Sigmod::Type* Sigmod::Sigmod::newType(const QDomElement& xml) { return newType(new Type(xml, this, newTypeId())); } Sigmod::Type* Sigmod::Sigmod::newType(const Type& type) { return newType(new Type(type, this, newTypeId())); } Sigmod::Type* Sigmod::Sigmod::newType(Type* type) { m_types.append(type); m_typechart.resize(typeCount(), typeCount(), Sigcore::Fraction(1, 1)); return type; } void Sigmod::Sigmod::deleteType(const int index) { if (index < typeCount()) { delete m_types[index]; m_types.removeAt(index); m_typechart.resize(typeCount(), typeCount(), Sigcore::Fraction(1, 1)); } } void Sigmod::Sigmod::deleteTypeById(const int id) { deleteType(typeIndex(id)); } int Sigmod::Sigmod::newTypeId() const { int i = 0; while ((i < typeCount()) && (typeIndex(i) != INT_MAX)) ++i; return i; } SSUBCLASS(Sigmod, Weather, weather, weathers) Sigmod::Sigmod& Sigmod::Sigmod::operator=(const Sigmod& rhs) { if (this == &rhs) return *this; clear(); COPY(title); COPY(version); COPY(description); COPY(singlePlayer); COPY(startMap); COPY(startWarp); COPY(typechart); COPY_Rules(rules); COPY_SUB(Ability, abilities); COPY_SUB(Author, authors); COPY_SUB(Badge, badges); COPY_SUB(CoinList, coinLists); COPY_SUB(EggGroup, eggGroups); COPY_SUB(GlobalScript, globalScripts); COPY_SUB(Item, items); COPY_SUB(ItemType, itemTypes); COPY_SUB(Map, maps); COPY_SUB(Move, moves); COPY_SUB(Nature, natures); COPY_SUB(Skin, skins); COPY_SUB(Sound, sounds); COPY_SUB(Species, species); COPY_SUB(Sprite, sprites); COPY_SUB(Status, status); COPY_SUB(Store, stores); COPY_SUB(Tile, tiles); COPY_SUB(Time, times); COPY_SUB(Trainer, trainers); COPY_SUB(Type, types); COPY_SUB(Weather, weathers); m_typechart.resize(typeCount(), typeCount()); return *this; } void Sigmod::Sigmod::clear() { SUBCLASS_CLEAR(abilities); SUBCLASS_CLEAR(badges); SUBCLASS_CLEAR(coinLists); SUBCLASS_CLEAR(eggGroups); SUBCLASS_CLEAR(globalScripts); SUBCLASS_CLEAR(items); SUBCLASS_CLEAR(maps); SUBCLASS_CLEAR(moves); SUBCLASS_CLEAR(natures); SUBCLASS_CLEAR(skins); SUBCLASS_CLEAR(sounds); SUBCLASS_CLEAR(species); SUBCLASS_CLEAR(sprites); SUBCLASS_CLEAR(status); SUBCLASS_CLEAR(stores); SUBCLASS_CLEAR(tiles); SUBCLASS_CLEAR(trainers); SUBCLASS_CLEAR(types); SUBCLASS_CLEAR(weathers); }