/* * Copyright 2007-2009 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 "Game.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 "Specie.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 using namespace Sigcore; using namespace Sigmod; Game::Game() : Object(NULL, 0), m_title(""), m_version(""), m_description(""), m_singlePlayer(true), m_startScript("", ""), m_typechart(0, 0), m_rules(new Rules(this)), m_abilities(this), m_authors(this), m_badges(this), m_coinLists(this), m_eggGroups(this), m_globalScripts(this), m_items(this), m_itemTypes(this), m_maps(this), m_moves(this), m_natures(this), m_skins(this), m_sounds(this), m_species(this), m_sprites(this), m_statuses(this), m_stores(this), m_tiles(this, &Game::typeAdded, &Game::typeRemoved), m_times(this), m_trainers(this), m_types(this), m_weathers(this) { } Game::Game(const Game& game) : Object(NULL, 0), m_rules(new Rules(this)), m_abilities(this), m_authors(this), m_badges(this), m_coinLists(this), m_eggGroups(this), m_globalScripts(this), m_items(this), m_itemTypes(this), m_maps(this), m_moves(this), m_natures(this), m_skins(this), m_sounds(this), m_species(this), m_sprites(this), m_statuses(this), m_stores(this), m_tiles(this, &Game::typeAdded, &Game::typeRemoved), m_times(this), m_trainers(this), m_types(this), m_weathers(this) { *this = game; } Game::Game(const QDomElement& xml) : Object(NULL, 0), m_rules(new Rules(this)), m_abilities(this), m_authors(this), m_badges(this), m_coinLists(this), m_eggGroups(this), m_globalScripts(this), m_items(this), m_itemTypes(this), m_maps(this), m_moves(this), m_natures(this), m_skins(this), m_sounds(this), m_species(this), m_sprites(this), m_statuses(this), m_stores(this), m_tiles(this, &Game::typeAdded, &Game::typeRemoved), m_times(this), m_trainers(this), m_types(this), m_weathers(this) { load(xml); } Game::~Game() { delete m_rules; } void Game::validate() { testBegin(); 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")); // TODO: check map positioning if ((m_typechart.width() != m_types.count()) || (m_typechart.height() != m_types.count())) emit(error("Type chart is invalid")); connect(m_rules, SIGNAL(valMessage(QString)), this, SIGNAL(valMessage(QString))); connect(m_rules, SIGNAL(valWarning(QString)), this, SIGNAL(valWarning(QString))); connect(m_rules, SIGNAL(valError(QString)), this, SIGNAL(valError(QString))); m_rules->validate(); \ disconnect(m_rules, SIGNAL(valMessage(QString)), this, SIGNAL(valMessage(QString))); disconnect(m_rules, SIGNAL(valWarning(QString)), this, SIGNAL(valWarning(QString))); disconnect(m_rules, SIGNAL(valError(QString)), this, SIGNAL(valError(QString))); QSet idChecker; QSet nameChecker; QSet timeChecker; if (m_abilities.count() < m_rules->maxAbilities()) emit(error("There are too few abilities")); m_abilities.validate(); for (int i = 0; i < m_abilities.count(); ++i) { Ability* ability = m_abilities.at(i); testSubclassValue(ability, ability->id(), "ID value", &idChecker); testSubclassValue(ability, ability->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_authors.count()) emit(error("There are no authors")); m_authors.validate(); for (int i = 0; i < m_authors.count(); ++i) { Author* author = m_authors.at(i); testSubclassValue(author, author->id(), "ID value", &idChecker); testSubclassValue(author, author->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_badges.count()) emit(error("There are no badges")); m_badges.validate(); for (int i = 0; i < m_badges.count(); ++i) { Badge* badge = m_badges.at(i); testSubclassValue(badge, badge->id(), "ID value", &idChecker); testSubclassValue(badge, badge->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_coinLists.count()) emit(warning("There are no coin lists")); m_coinLists.validate(); for (int i = 0; i < m_coinLists.count(); ++i) { CoinList* coinList = m_coinLists.at(i); testSubclassValue(coinList, coinList->id(), "ID value", &idChecker); testSubclassValue(coinList, coinList->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (m_rules->breedingAllowed()) { if (!m_eggGroups.count()) emit(error("There are no egg groups")); m_eggGroups.validate(); for (int i = 0; i < m_eggGroups.count(); ++i) { EggGroup* eggGroup = m_eggGroups.at(i); testSubclassValue(eggGroup, eggGroup->id(), "ID value", &idChecker); testSubclassValue(eggGroup, eggGroup->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); } if (!m_globalScripts.count()) emit(warning("There are no global scripts")); m_globalScripts.validate(); for (int i = 0; i < m_globalScripts.count(); ++i) { GlobalScript* globalScript = m_globalScripts.at(i); testSubclassValue(globalScript, globalScript->id(), "ID value", &idChecker); testSubclassValue(globalScript, globalScript->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_items.count()) emit(warning("There are no items")); m_items.validate(); for (int i = 0; i < m_items.count(); ++i) { Item* item = m_items.at(i); testSubclassValue(item, item->id(), "ID value", &idChecker); testSubclassValue(item, item->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_itemTypes.count() && m_items.count()) emit(error("There are no item types")); m_itemTypes.validate(); for (int i = 0; i < m_itemTypes.count(); ++i) { ItemType* itemType = m_itemTypes.at(i); testSubclassValue(itemType, itemType->id(), "ID value", &idChecker); testSubclassValue(itemType, itemType->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_maps.count()) emit(error("There are no maps")); m_maps.validate(); for (int i = 0; i < m_maps.count(); ++i) { Map* map = m_maps.at(i); testSubclassValue(map, map->id(), "ID value", &idChecker); testSubclassValue(map, map->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_moves.count()) emit(error("There are no moves")); m_moves.validate(); for (int i = 0; i < m_moves.count(); ++i) { Move* move = m_moves.at(i); testSubclassValue(move, move->id(), "ID value", &idChecker); testSubclassValue(move, move->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (m_natures.count() < m_rules->maxNatures()) emit(error("There are too few natures")); m_natures.validate(); for (int i = 0; i < m_natures.count(); ++i) { Nature* nature = m_natures.at(i); testSubclassValue(nature, nature->id(), "ID value", &idChecker); testSubclassValue(nature, nature->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); m_skins.validate(); for (int i = 0; i < m_skins.count(); ++i) { Skin* skin = m_skins.at(i); testSubclassValue(skin, skin->id(), "ID value", &idChecker); testSubclassValue(skin, skin->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_sounds.count()) emit(warning("There are no sounds")); m_sounds.validate(); for (int i = 0; i < m_sounds.count(); ++i) { Sound* sound = m_sounds.at(i); testSubclassValue(sound, sound->id(), "ID value", &idChecker); testSubclassValue(sound, sound->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_species.count()) emit(error("There are no species")); m_species.validate(); for (int i = 0; i < m_species.count(); ++i) { Specie* species = m_species.at(i); testSubclassValue(species, species->id(), "ID value", &idChecker); testSubclassValue(species, species->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_statuses.count()) emit(error("There are no status effects")); m_statuses.validate(); for (int i = 0; i < m_statuses.count(); ++i) { Status* status = m_statuses.at(i); testSubclassValue(status, status->id(), "ID value", &idChecker); testSubclassValue(status, status->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_stores.count()) emit(warning("There are no stores")); m_stores.validate(); for (int i = 0; i < m_stores.count(); ++i) { Store* stores = m_stores.at(i); testSubclassValue(stores, stores->id(), "ID value", &idChecker); testSubclassValue(stores, stores->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_tiles.count()) emit(error("There are no tiles")); m_tiles.validate(); for (int i = 0; i < m_tiles.count(); ++i) { Tile* tile = m_tiles.at(i); testSubclassValue(tile, tile->id(), "ID value", &idChecker); testSubclassValue(tile, tile->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_trainers.count()) emit(warning("There are no trainers")); m_trainers.validate(); for (int i = 0; i < m_trainers.count(); ++i) { Trainer* trainer = m_trainers.at(i); testSubclassValue(trainer, trainer->id(), "ID value", &idChecker); testSubclassValue(trainer, trainer->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_times.count()) emit(error("There are no times")); m_times.validate(); for (int i = 0; i < m_times.count(); ++i) { Time* time = m_times.at(i); testSubclassValue(time, time->id(), "ID value", &idChecker); testSubclassValue(time, time->name(), "name", &nameChecker); testSubclassValue(time, (60 * time->hour()) + time->minute(), "time", &timeChecker); } idChecker.clear(); nameChecker.clear(); if (!m_types.count()) emit(error("There are no types")); m_types.validate(); for (int i = 0; i < m_types.count(); ++i) { Type* type = m_types.at(i); testSubclassValue(type, type->id(), "ID value", &idChecker); testSubclassValue(type, type->name(), "name", &nameChecker); } idChecker.clear(); nameChecker.clear(); if (!m_weathers.count()) emit(warning("There are no weathers")); m_weathers.validate(); for (int i = 0; i < m_weathers.count(); ++i) { Weather* weather = m_weathers.at(i); testSubclassValue(weather, weather->id(), "ID value", &idChecker); testSubclassValue(weather, weather->name(), "name", &nameChecker); } testEnd(); } void Game::load(const QDomElement& xml) { clear(); loadValue(xml.firstChildElement("title"), &m_title); loadValue(xml.firstChildElement("version"), &m_version); loadValue(xml.firstChildElement("description"), &m_description); loadValue(xml.firstChildElement("singlePlayer"), &m_singlePlayer); loadValue(xml.firstChildElement("startScript"), &m_startScript); m_rules->load(xml.firstChildElement("Rules")); m_abilities.importXml(xml, "Ability"); m_authors.importXml(xml, "Author"); m_badges.importXml(xml, "Badge"); m_coinLists.importXml(xml, "CoinList"); m_eggGroups.importXml(xml, "EggGroup"); m_globalScripts.importXml(xml, "GlobalScript"); m_items.importXml(xml, "Item"); m_itemTypes.importXml(xml, "ItemType"); m_maps.importXml(xml, "Map"); m_moves.importXml(xml, "Move"); m_natures.importXml(xml, "Nature"); m_skins.importXml(xml, "Skin"); m_sounds.importXml(xml, "Sound"); m_species.importXml(xml, "Species"); m_sprites.importXml(xml, "Sprite"); m_statuses.importXml(xml, "Status"); m_stores.importXml(xml, "Store"); m_tiles.importXml(xml, "Tile"); m_times.importXml(xml, "Time"); m_trainers.importXml(xml, "Trainer"); m_types.importXml(xml, "Type"); m_weathers.importXml(xml, "Weather"); loadMap(xml.firstChildElement("mapPosition"), &m_mapPosition, "position"); loadMatrix(xml.firstChildElement("typechart"), &m_typechart); m_typechart.resize(m_types.count(), m_types.count(), Fraction(1, 1)); } QDomElement Game::save() const { QDomElement xml = initXmlExport(); xml.removeAttribute("id"); xml.appendChild(saveValue("title", m_title)); xml.appendChild(saveValue("version", m_version)); xml.appendChild(saveValue("description", m_description)); xml.appendChild(saveValue("singlePlayer", m_singlePlayer)); xml.appendChild(saveValue("startScript", m_startScript)); SAVE_Rules(rules); xml.appendChild(saveEnum("mapPosition", m_mapPosition, "position")); xml.appendChild(saveMatrix("typechart", m_typechart)); m_abilities.exportXml(&xml); m_authors.exportXml(&xml); m_badges.exportXml(&xml); m_coinLists.exportXml(&xml); m_eggGroups.exportXml(&xml); m_globalScripts.exportXml(&xml); m_items.exportXml(&xml); m_itemTypes.exportXml(&xml); m_maps.exportXml(&xml); m_moves.exportXml(&xml); m_natures.exportXml(&xml); m_skins.exportXml(&xml); m_sounds.exportXml(&xml); m_species.exportXml(&xml); m_sprites.exportXml(&xml); m_statuses.exportXml(&xml); m_stores.exportXml(&xml); m_tiles.exportXml(&xml); m_times.exportXml(&xml); m_trainers.exportXml(&xml); m_types.exportXml(&xml); m_weathers.exportXml(&xml); return xml; } SETTER(Game, QString&, Title, title) SETTER(Game, QString&, Version, version) SETTER(Game, QString&, Description, description) SETTER(Game, bool, SinglePlayer, singlePlayer) SETTER(Game, Script&, StartScript, startScript) void Game::setMapPosition(const int map, const QPoint& position, const bool remove) { if (remove) { if (m_mapPosition.contains(map)) { m_mapPosition.remove(map); emit(changed()); } } else if (!mapById(map)) EBOUNDS_IDX(map); else if (!m_mapPosition.contains(map) || (position != m_mapPosition[map])) { m_mapPosition[map] = position; emit(changed()); } } SETTER_MATRIX(Game, Fraction&, Typechart, typechart, multiplier) void Game::setRules(const Rules& rules) { *m_rules = rules; } void Game::setRules(const QDomElement& xml) { m_rules->load(xml); } GETTER(Game, QString, title) GETTER(Game, QString, version) GETTER(Game, QString, description) GETTER(Game, bool, singlePlayer) GETTER(Game, Script, startScript) const Matrix& Game::typechart() const { return m_typechart; } Matrix& Game::typechart() { return m_typechart; } Fraction Game::typechart(const int attack, const int defense) const { return m_typechart(attack, defense); } QPoint Game::mapPosition(const int map) const { if (m_mapPosition.contains(map)) return m_mapPosition[map]; return QPoint(); } QMap Game::mapPosition() const { return m_mapPosition; } const Rules* Game::rules() const { return m_rules; } Rules* Game::rules() { return m_rules; } const Game::Abilities& Game::abilities() const { return m_abilities; } Game::Abilities& Game::abilities() { return m_abilities; } const Game::Authors& Game::authors() const { return m_authors; } Game::Authors& Game::authors() { return m_authors; } const Game::Badges& Game::badges() const { return m_badges; } Game::Badges& Game::badges() { return m_badges; } const Game::CoinLists& Game::coinLists() const { return m_coinLists; } Game::CoinLists& Game::coinLists() { return m_coinLists; } const Game::EggGroups& Game::eggGroups() const { return m_eggGroups; } Game::EggGroups& Game::eggGroups() { return m_eggGroups; } const Game::GlobalScripts& Game::globalScripts() const { return m_globalScripts; } Game::GlobalScripts& Game::globalScripts() { return m_globalScripts; } const Game::Items& Game::items() const { return m_items; } Game::Items& Game::items() { return m_items; } const Game::ItemTypes& Game::itemTypes() const { return m_itemTypes; } Game::ItemTypes& Game::itemTypes() { return m_itemTypes; } const Game::Maps& Game::maps() const { return m_maps; } Game::Maps& Game::maps() { return m_maps; } const Game::Moves& Game::moves() const { return m_moves; } Game::Moves& Game::moves() { return m_moves; } const Game::Natures& Game::natures() const { return m_natures; } Game::Natures& Game::natures() { return m_natures; } const Game::Skins& Game::skins() const { return m_skins; } Game::Skins& Game::skins() { return m_skins; } const Game::Sounds& Game::sounds() const { return m_sounds; } Game::Sounds& Game::sounds() { return m_sounds; } const Game::Species& Game::species() const { return m_species; } Game::Species& Game::species() { return m_species; } const Game::Sprites& Game::sprites() const { return m_sprites; } Game::Sprites& Game::sprites() { return m_sprites; } const Game::Statuses& Game::statuses() const { return m_statuses; } Game::Statuses& Game::statuses() { return m_statuses; } const Game::Stores& Game::stores() const { return m_stores; } Game::Stores& Game::stores() { return m_stores; } const Game::Tiles& Game::tiles() const { return m_tiles; } Game::Tiles& Game::tiles() { return m_tiles; } const Game::Trainers& Game::times() const { return m_times; } Game::Trainers& Game::trainers() { return m_trainers; } const Game::Types& Game::types() const { return m_types; } Game::Types& Game::types() { return m_types; } const Game::Weathers& Game::weathers() const { return m_weathers; } Game::Weathers& Game::weathers() { return m_weathers; } CHECK(Game, QString&, title) CHECK(Game, QString&, version) CHECK(Game, QString&, description) CHECK(Game, bool, singlePlayer) CHECK(Game, Script&, startScript) CHECK_BOUNDS(Game, Fraction&, typechart, 0, INT_MAX) CHECK(Game, QPoint&, mapPosition) Game& Game::operator=(const Game& rhs) { if (this == &rhs) return *this; clear(); m_title = rhs.m_title; m_version = rhs.m_version; m_description = rhs.m_description; m_singlePlayer = rhs.m_singlePlayer; m_startScript = rhs.m_startScript; m_mapPosition = rhs.m_mapPosition; *m_rules = *rhs.m_rules; m_abilities = rhs.m_abilities; m_authors = rhs.m_authors; m_badges = rhs.m_badges; m_coinLists = rhs.m_coinLists; m_eggGroups = rhs.m_eggGroups; m_globalScripts = rhs.m_globalScripts; m_items = rhs.m_items; m_itemTypes = rhs.m_itemTypes; m_maps = rhs.m_maps; m_moves = rhs.m_moves; m_natures = rhs.m_natures; m_skins = rhs.m_skins; m_sounds = rhs.m_sounds; m_species = rhs.m_species; m_sprites = rhs.m_sprites; m_statuses = rhs.m_statuses; m_stores = rhs.m_stores; m_tiles = rhs.m_tiles; m_times = rhs.m_times; m_trainers = rhs.m_trainers; m_types = rhs.m_types; m_weathers = rhs.m_weathers; m_typechart = rhs.m_typechart; return *this; } void Game::clear() { m_abilities.clear(); m_authors.clear(); m_badges.clear(); m_coinLists.clear(); m_eggGroups.clear(); m_globalScripts.clear(); m_items.clear(); m_itemTypes.clear(); m_maps.clear(); m_moves.clear(); m_natures.clear(); m_skins.clear(); m_sounds.clear(); m_species.clear(); m_sprites.clear(); m_statuses.clear(); m_stores.clear(); m_tiles.clear(); m_times.clear(); m_trainers.clear(); m_types.clear(); m_weathers.clear(); m_mapPosition.clear(); m_typechart.clear(); Object::clear(); } void Game::typeAdded(const int newSize) { m_typechart.resize(newSize, newSize, Fraction(1, 1)); } void Game::typeRemoved(const int index) { m_typechart.deleteColumn(index); m_typechart.deleteRow(index); }