/* * 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 "Specie.h" // Sigmod includes #include "Game.h" #include "Macros.h" #include "Rules.h" #include "SpecieMove.h" // Qt includes #include using namespace Sigcore; using namespace Sigmod; const QStringList Specie::StyleStr = QStringList() << "Fluctuating" << "Fading" << "Slow" << "Normal" << "Fast" << "Erratic"; Specie::Specie(const Specie& species) : Object(species.parent(), species.id()), m_baseStat(ST_SpecialDefense - ST_HP + 1), m_effortValue(ST_SpecialDefense - ST_HP + 1), m_moves(this) { *this = species; } Specie::Specie(const Game* parent, const int id) : Object(parent, id), m_name(""), m_baseStat(ST_SpecialDefense - ST_HP + 1), m_effortValue(ST_SpecialDefense - ST_HP + 1), m_growth(Normal), m_experienceValue(0), m_catchValue(0), m_maxHoldWeight(0), m_runChance(1, 1), m_fleeChance(1, 1), m_itemChance(1, 1), m_encyclopediaNumber(-1), m_weight(0), m_height(0), m_frontMaleSprite(-1), m_backMaleSprite(-1), m_frontFemaleSprite(-1), m_backFemaleSprite(-1), m_skin(-1), m_encyclopediaEntry(""), m_genderFactor(1, 2), m_eggSpecies(id), m_eggSteps(0), m_evolution("", ""), m_moves(this) { for (int i = 0; i < m_baseStat.size(); ++i) m_baseStat[i] = 1; for (int i = 0; i < m_effortValue.size(); ++i) m_effortValue[i] = 0; } Specie::Specie(const Specie& species, const Game* parent, const int id) : Object(parent, id), m_baseStat(ST_SpecialDefense - ST_HP + 1), m_effortValue(ST_SpecialDefense - ST_HP + 1), m_moves(this) { *this = species; } Specie::Specie(const QDomElement& xml, const Game* parent, const int id) : Object(parent, id), m_baseStat(ST_SpecialDefense - ST_HP + 1), m_effortValue(ST_SpecialDefense - ST_HP + 1), m_moves(this) { initXmlImport(xml, id); load(xml); } void Specie::validate() { testBegin(); if (m_name.isEmpty()) emit(error("Name is empty")); TEST_ARRAY_INDEX(baseStat, ST_HP); TEST_ARRAY_INDEX(baseStat, ST_Attack); TEST_ARRAY_INDEX(baseStat, ST_Defense); TEST_ARRAY_INDEX(baseStat, ST_Speed); if (game()->rules()->specialSplit()) { TEST_ARRAY_INDEX(baseStat, ST_SpecialAttack); TEST_ARRAY_INDEX(baseStat, ST_SpecialDefense); } else TEST_ARRAY_INDEX(baseStat, ST_Special); TEST_ARRAY_INDEX(effortValue, ST_HP); TEST_ARRAY_INDEX(effortValue, ST_Attack); TEST_ARRAY_INDEX(effortValue, ST_Defense); TEST_ARRAY_INDEX(effortValue, ST_Speed); if (game()->rules()->specialSplit()) { TEST_ARRAY_INDEX(effortValue, ST_SpecialAttack); TEST_ARRAY_INDEX(effortValue, ST_SpecialDefense); } else TEST_ARRAY_INDEX(effortValue, ST_Special); TEST(growth); TEST(experienceValue); TEST(maxHoldWeight); TEST(runChance); TEST(fleeChance); TEST(itemChance); TEST(encyclopediaNumber); TEST(weight); if (m_genderFactor < 1) { TEST(frontMaleSprite); TEST(backMaleSprite); } if (game()->rules()->genderAllowed() && (0 < m_genderFactor)) { TEST(frontFemaleSprite); TEST(backFemaleSprite); } TEST(skin); if ((m_encyclopediaNumber != -1) && m_encyclopediaEntry.isEmpty()) emit(error("Encyclopedia entry is empty")); TEST(genderFactor); if (game()->rules()->breedingAllowed() && m_eggGroup.size()) { const Specie* eggSpecies = game()->speciesById(m_eggSpecies); if (!eggSpecies) emit(error(bounds("egg species", m_eggSpecies))); else { if (eggSpecies->growth() != m_growth) emit(error("Growth mismatch with egg species")); TEST(eggSteps); } } TEST_LIST(type); TEST_LIST(eggGroup); if (m_ability.size() < game()->rules()->maxAbilities()) emit(warning("There are too few abilities")); TEST_MAP(ability); if (game()->rules()->maxHeldItems() && !m_item.size()) emit(warning("There are no items")); TEST_MAP(item); if (!m_moves.count()) emit(error("There are no moves")); QSet idChecker; QSet valueChecker; m_moves.validate(); for (int i = 0; i < m_moves.count(); ++i) { SpecieMove* move = m_moves.at(i); testSubclassValue(move, move->id(), "ID value", &idChecker); testSubclassValue(move, move->move(), "name", &valueChecker); } testEnd(); } void Specie::load(const QDomElement& xml) { clear(); loadValue(xml.firstChildElement("name"), &m_name); LOAD_ARRAY(baseStat); LOAD_ARRAY(effortValue); loadEnum(xml.firstChildElement("growth"), &m_growth, StyleStr); loadValue(xml.firstChildElement("experienceValue"), &m_experienceValue); loadValue(xml.firstChildElement("catchValue"), &m_catchValue); loadValue(xml.firstChildElement("maxHoldWeight"), &m_maxHoldWeight); loadValue(xml.firstChildElement("runChance"), &m_runChance); loadValue(xml.firstChildElement("fleeChance"), &m_fleeChance); loadValue(xml.firstChildElement("itemChance"), &m_itemChance); loadValue(xml.firstChildElement("encyclopediaNumber"), &m_encyclopediaNumber); loadValue(xml.firstChildElement("weight"), &m_weight); loadValue(xml.firstChildElement("height"), &m_height); loadValue(xml.firstChildElement("frontMaleSprite"), &m_frontMaleSprite); loadValue(xml.firstChildElement("backMaleSprite"), &m_backMaleSprite); loadValue(xml.firstChildElement("frontFemaleSprite"), &m_frontFemaleSprite); loadValue(xml.firstChildElement("backFemaleSprite"), &m_backFemaleSprite); loadValue(xml.firstChildElement("skin"), &m_skin); loadValue(xml.firstChildElement("encyclopediaEntry"), &m_encyclopediaEntry); loadValue(xml.firstChildElement("genderFactor"), &m_genderFactor); loadValue(xml.firstChildElement("eggSpecies"), &m_eggSpecies); loadValue(xml.firstChildElement("eggSteps"), &m_eggSteps); loadList(xml.firstChildElement("type"), &m_type); loadList(xml.firstChildElement("eggGroup"), &m_eggGroup); loadValue(xml.firstChildElement("evolution"), &m_evolution); loadMap(xml.firstChildElement("ability"), &m_ability, "weight"); loadMap(xml.firstChildElement("item"), &m_item, "weight"); m_moves.importXml(xml, "SpecieMove"); } QDomElement Specie::save() const { QDomElement xml = initXmlExport(); xml.appendChild(saveValue("name", m_name)); SAVE_ARRAY(baseStat); SAVE_ARRAY(effortValue); xml.appendChild(saveEnum("growth", m_growth, StyleStr)); xml.appendChild(saveValue("experienceValue", m_experienceValue)); xml.appendChild(saveValue("catchValue", m_catchValue)); xml.appendChild(saveValue("maxHoldWeight", m_maxHoldWeight)); xml.appendChild(saveValue("runChance", m_runChance)); xml.appendChild(saveValue("fleeChance", m_fleeChance)); xml.appendChild(saveValue("itemChance", m_itemChance)); xml.appendChild(saveValue("encyclopediaNumber", m_encyclopediaNumber)); xml.appendChild(saveValue("weight", m_weight)); xml.appendChild(saveValue("height", m_height)); xml.appendChild(saveValue("frontMaleSprite", m_frontMaleSprite)); xml.appendChild(saveValue("backMaleSprite", m_backMaleSprite)); xml.appendChild(saveValue("frontFemaleSprite", m_frontFemaleSprite)); xml.appendChild(saveValue("backFemaleSprite", m_backFemaleSprite)); xml.appendChild(saveValue("skin", m_skin)); xml.appendChild(saveValue("encyclopediaEntry", m_encyclopediaEntry)); xml.appendChild(saveValue("genderFactor", m_genderFactor)); xml.appendChild(saveValue("eggSpecies", m_eggSpecies)); xml.appendChild(saveValue("eggSteps", m_eggSteps)); xml.appendChild(saveList("type", m_type)); xml.appendChild(saveList("eggGroup", m_eggGroup)); xml.appendChild(saveValue("evolution", m_evolution)); xml.appendChild(saveEnum("ability", m_ability, "weight")); xml.appendChild(saveEnum("item", m_item, "weight")); m_moves.exportXml(&xml); return xml; } SETTER(Specie, QString&, Name, name) SETTER_ARRAY(Specie, int, BaseStat, baseStat, baseStat, Stat, stat, ST_HP) SETTER_ARRAY(Specie, int, EffortValue, effortValue, effortValue, Stat, stat, ST_HP) SETTER(Specie, Style, Growth, growth) SETTER(Specie, int, ExperienceValue, experienceValue) SETTER(Specie, int, CatchValue, catchValue) SETTER(Specie, int, MaxHoldWeight, maxHoldWeight) SETTER(Specie, Fraction&, RunChance, runChance) SETTER(Specie, Fraction&, FleeChance, fleeChance) SETTER(Specie, Fraction&, ItemChance, itemChance) SETTER(Specie, int, EncyclopediaNumber, encyclopediaNumber) SETTER(Specie, int, Weight, weight) SETTER(Specie, int, Height, height) SETTER(Specie, int, FrontMaleSprite, frontMaleSprite) SETTER(Specie, int, BackMaleSprite, backMaleSprite) SETTER(Specie, int, FrontFemaleSprite, frontFemaleSprite) SETTER(Specie, int, BackFemaleSprite, backFemaleSprite) SETTER(Specie, int, Skin, skin) SETTER(Specie, QString&, EncyclopediaEntry, encyclopediaEntry) SETTER(Specie, Fraction&, GenderFactor, genderFactor) SETTER(Specie, int, EggSpecie, eggSpecies) SETTER(Specie, int, EggSteps, eggSteps) SETTER_LIST(Specie, Type, type) SETTER_LIST(Specie, EggGroup, eggGroup) SETTER(Specie, Script&, Evolution, evolution) SETTER_MAP(Specie, Ability, ability, weight) SETTER_MAP(Specie, Item, item, weight) GETTER(Specie, QString, name) GETTER_ARRAY(Specie, int, baseStat, baseStat, Stat, stat, ST_HP) GETTER_ARRAY(Specie, int, effortValue, effortValue, Stat, stat, ST_HP) GETTER(Specie, Specie::Style, growth) GETTER(Specie, int, experienceValue) GETTER(Specie, int, catchValue) GETTER(Specie, int, maxHoldWeight) GETTER(Specie, Fraction, runChance) GETTER(Specie, Fraction, fleeChance) GETTER(Specie, Fraction, itemChance) GETTER(Specie, int, encyclopediaNumber) GETTER(Specie, int, weight) GETTER(Specie, int, height) GETTER(Specie, int, frontMaleSprite) GETTER(Specie, int, backMaleSprite) GETTER(Specie, int, frontFemaleSprite) GETTER(Specie, int, backFemaleSprite) GETTER(Specie, int, skin) GETTER(Specie, QString, encyclopediaEntry) GETTER(Specie, Fraction, genderFactor) GETTER(Specie, int, eggSpecies) GETTER(Specie, int, eggSteps) GETTER_LIST(Specie, type) GETTER_LIST(Specie, eggGroup) GETTER(Specie, Script, evolution) GETTER_MAP(Specie, ability) GETTER_MAP(Specie, item) const Specie::Moves& Specie::moves() const { return m_moves; } Specie::Moves& Specie::moves() { return m_moves; } CHECK(Specie, QString&, name) CHECK_BEGIN_ARRAY(Specie, int, baseStat, baseStat, Stat, stat) switch (stat) { case ST_SpecialDefense: if (game()->rules()->specialSplit()) case ST_HP: case ST_Attack: case ST_Defense: case ST_Speed: case ST_Special: break; default: EBOUNDS(stat, "HP", game()->rules()->specialSplit() ? "SpecialDefense" : "Special"); return false; } TBOUNDS(baseStat, 1, INT_MAX) CHECK_END() CHECK_BEGIN_ARRAY(Specie, int, effortValue, effortValue, Stat, stat) switch (stat) { case ST_SpecialDefense: if (game()->rules()->specialSplit()) case ST_HP: case ST_Attack: case ST_Defense: case ST_Speed: case ST_Special: break; default: EBOUNDS(stat, "HP", game()->rules()->specialSplit() ? "SpecialDefense" : "Special"); return false; } TBOUNDS(effortValue, 0, game()->rules()->maxEVPerStat() ? game()->rules()->maxEVPerStat() : INT_MAX) CHECK_END() CHECK(Specie, Style, growth) CHECK_BOUNDS(Specie, int, experienceValue, 0, INT_MAX) CHECK_BOUNDS(Specie, int, catchValue, 0, 255) CHECK_BOUNDS(Specie, int, maxHoldWeight, -1, INT_MAX) CHECK_BOUNDS(Specie, Fraction&, runChance, 0, 1) CHECK_BOUNDS(Specie, Fraction&, fleeChance, 0, 1) CHECK_BOUNDS(Specie, Fraction&, itemChance, 0, 1) CHECK_BOUNDS(Specie, int, encyclopediaNumber, -1, INT_MAX) CHECK_BOUNDS(Specie, int, weight, 0, INT_MAX) CHECK_BOUNDS(Specie, int, height, 0, INT_MAX) CHECK_BEGIN(Specie, int, frontMaleSprite) if (1 <= m_genderFactor) { ERROR("Specie cannot be male"); return false; } IBOUNDS(frontMaleSprite, game(), sprite); CHECK_END() CHECK_BEGIN(Specie, int, backMaleSprite) if (1 <= m_genderFactor) { ERROR("Specie cannot be male"); return false; } IBOUNDS(backMaleSprite, game(), sprite); CHECK_END() CHECK_BEGIN(Specie, int, frontFemaleSprite) if (!game()->rules()->genderAllowed() || (m_genderFactor <= 0)) { ERROR("Specie cannot be female"); return false; } IBOUNDS(frontFemaleSprite, game(), sprite); CHECK_END() CHECK_BEGIN(Specie, int, backFemaleSprite) if (!game()->rules()->genderAllowed() || (m_genderFactor <= 0)) { ERROR("Specie cannot be female"); return false; } IBOUNDS(backFemaleSprite, game(), sprite); CHECK_END() CHECK_INDEX(Specie, int, skin, game(), skin) CHECK(Specie, QString&, encyclopediaEntry) CHECK_BOUNDS(Specie, Fraction&, genderFactor, -1, 1) CHECK_INDEX(Specie, int, eggSpecies, game(), species) CHECK_BOUNDS(Specie, int, eggSteps, 1, INT_MAX) CHECK_INDEX(Specie, int, type, game(), type) CHECK_INDEX(Specie, int, eggGroup, game(), eggGroup) CHECK(Specie, Script&, evolution) CHECK_BEGIN_ARRAY(Specie, int, ability, weight, int, ability) IBOUNDS(ability, game(), ability); TBOUNDS_MOD(ability_weight, 1, INT_MAX, weight) CHECK_END() CHECK_BEGIN_ARRAY(Specie, int, item, weight, int, item) IBOUNDS(item, game(), item); TBOUNDS_MOD(species_item, 1, INT_MAX, weight) CHECK_END() Specie& Specie::operator=(const Specie& rhs) { if (this == &rhs) return *this; clear(); m_name = rhs.m_name; m_baseStat = rhs.m_baseStat; m_effortValue = rhs.m_effortValue; m_growth = rhs.m_growth; m_experienceValue = rhs.m_experienceValue; m_catchValue = rhs.m_catchValue; m_maxHoldWeight = rhs.m_maxHoldWeight; m_runChance = rhs.m_runChance; m_fleeChance = rhs.m_fleeChance; m_itemChance = rhs.m_itemChance; m_encyclopediaNumber = rhs.m_encyclopediaNumber; m_weight = rhs.m_weight; m_height = rhs.m_height; m_frontMaleSprite = rhs.m_frontMaleSprite; m_backMaleSprite = rhs.m_backMaleSprite; m_frontFemaleSprite = rhs.m_frontFemaleSprite; m_backFemaleSprite = rhs.m_backFemaleSprite; m_skin = rhs.m_skin; m_encyclopediaEntry = rhs.m_encyclopediaEntry; m_genderFactor = rhs.m_genderFactor; m_eggSpecies = rhs.m_eggSpecies; m_eggSteps = rhs.m_eggSteps; m_type = rhs.m_type; m_eggGroup = rhs.m_eggGroup; m_evolution = rhs.m_evolution; m_ability = rhs.m_ability; m_item = rhs.m_item; m_moves = rhs.m_moves; return *this; } void Specie::clear() { m_type.clear(); m_eggGroup.clear(); m_ability.clear(); m_item.clear(); m_moves.clear(); Object::clear(); }