/* * 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 "Species.h" // Sigmod includes #include "Game.h" #include "Macros.h" #include "Rules.h" #include "SpeciesMove.h" // Qt includes #include using namespace Sigcore; using namespace Sigmod; const QStringList Species::StyleStr = QStringList() << "Fluctuating" << "Fading" << "Slow" << "Normal" << "Fast" << "Erratic"; Species::Species(const Species& species) : Object(species.parent(), species.id()), m_baseStat(ST_SpecialDefense - ST_HP + 1), m_effortValue(ST_SpecialDefense - ST_HP + 1) { *this = species; } Species::Species(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("", "") { 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; } Species::Species(const Species& species, const Game* parent, const int id) : Object(parent, id), m_baseStat(ST_SpecialDefense - ST_HP + 1), m_effortValue(ST_SpecialDefense - ST_HP + 1) { *this = species; } Species::Species(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) { LOAD_ID(); load(xml); } Species::~Species() { clear(); } void Species::validate() { TEST_BEGIN(); 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 Species* 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); TEST_MAP(ability); if (game()->rules()->maxHeldItems() && !m_item.size()) emit(warning("There are no items")); TEST_MAP(item); QSet idChecker; QSet valueChecker; if (!moveCount()) emit(error("There are no moves")); TEST_SUB_BEGIN(SpeciesMove, moves); TEST_SUB("move", id); TEST_SUB_RAW(value, "move", move); TEST_SUB_END(); TEST_END(); } void Species::load(const QDomElement& xml) { LOAD_BEGIN(); LOAD(name); LOAD_ARRAY(baseStat); LOAD_ARRAY(effortValue); LOAD_ENUM(growth, Style); LOAD(experienceValue); LOAD(catchValue); LOAD(maxHoldWeight); LOAD(runChance); LOAD(fleeChance); LOAD(itemChance); LOAD(encyclopediaNumber); LOAD(weight); LOAD(height); LOAD(frontMaleSprite); LOAD(backMaleSprite); LOAD(frontFemaleSprite); LOAD(backFemaleSprite); LOAD(skin); LOAD(encyclopediaEntry); LOAD(genderFactor); LOAD(eggSpecies); LOAD(eggSteps); LOAD_LIST(type); LOAD_LIST(eggGroup); LOAD(evolution); LOAD_MAP(ability, weight); LOAD_MAP(item, weight); LOAD_SUB(newMove, SpeciesMove); } QDomElement Species::save() const { SAVE_CREATE(); SAVE(name); SAVE_ARRAY(baseStat); SAVE_ARRAY(effortValue); SAVE_ENUM(growth, Style); SAVE(experienceValue); SAVE(catchValue); SAVE(maxHoldWeight); SAVE(runChance); SAVE(fleeChance); SAVE(itemChance); SAVE(encyclopediaNumber); SAVE(weight); SAVE(height); SAVE(frontMaleSprite); SAVE(backMaleSprite); SAVE(frontFemaleSprite); SAVE(backFemaleSprite); SAVE(skin); SAVE(encyclopediaEntry); SAVE(genderFactor); SAVE(eggSpecies); SAVE(eggSteps); SAVE_LIST(type); SAVE_LIST(eggGroup); SAVE(evolution); SAVE_MAP(ability, weight); SAVE_MAP(item, weight); SAVE_SUB(SpeciesMove, moves); return xml; } SETTER(Species, QString&, Name, name) SETTER_ARRAY(Species, int, BaseStat, baseStat, baseStat, Stat, stat, ST_HP) SETTER_ARRAY(Species, int, EffortValue, effortValue, effortValue, Stat, stat, ST_HP) SETTER(Species, Style, Growth, growth) SETTER(Species, int, ExperienceValue, experienceValue) SETTER(Species, int, CatchValue, catchValue) SETTER(Species, int, MaxHoldWeight, maxHoldWeight) SETTER(Species, Fraction&, RunChance, runChance) SETTER(Species, Fraction&, FleeChance, fleeChance) SETTER(Species, Fraction&, ItemChance, itemChance) SETTER(Species, int, EncyclopediaNumber, encyclopediaNumber) SETTER(Species, int, Weight, weight) SETTER(Species, int, Height, height) SETTER(Species, int, FrontMaleSprite, frontMaleSprite) SETTER(Species, int, BackMaleSprite, backMaleSprite) SETTER(Species, int, FrontFemaleSprite, frontFemaleSprite) SETTER(Species, int, BackFemaleSprite, backFemaleSprite) SETTER(Species, int, Skin, skin) SETTER(Species, QString&, EncyclopediaEntry, encyclopediaEntry) SETTER(Species, Fraction&, GenderFactor, genderFactor) SETTER(Species, int, EggSpecies, eggSpecies) SETTER(Species, int, EggSteps, eggSteps) SETTER_LIST(Species, Type, type) SETTER_LIST(Species, EggGroup, eggGroup) SETTER(Species, Script&, Evolution, evolution) SETTER_MAP(Species, Ability, ability, weight) SETTER_MAP(Species, Item, item, weight) GETTER(Species, QString, name) GETTER_ARRAY(Species, int, baseStat, baseStat, Stat, stat, ST_HP) GETTER_ARRAY(Species, int, effortValue, effortValue, Stat, stat, ST_HP) GETTER(Species, Species::Style, growth) GETTER(Species, int, experienceValue) GETTER(Species, int, catchValue) GETTER(Species, int, maxHoldWeight) GETTER(Species, Fraction, runChance) GETTER(Species, Fraction, fleeChance) GETTER(Species, Fraction, itemChance) GETTER(Species, int, encyclopediaNumber) GETTER(Species, int, weight) GETTER(Species, int, height) GETTER(Species, int, frontMaleSprite) GETTER(Species, int, backMaleSprite) GETTER(Species, int, frontFemaleSprite) GETTER(Species, int, backFemaleSprite) GETTER(Species, int, skin) GETTER(Species, QString, encyclopediaEntry) GETTER(Species, Fraction, genderFactor) GETTER(Species, int, eggSpecies) GETTER(Species, int, eggSteps) GETTER_LIST(Species, type) GETTER_LIST(Species, eggGroup) GETTER(Species, Script, evolution) GETTER_MAP(Species, ability) GETTER_MAP(Species, item) CHECK(Species, QString&, name) CHECK_BEGIN_ARRAY(Species, 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(Species, 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(Species, Style, growth) CHECK_BOUNDS(Species, int, experienceValue, 0, INT_MAX) CHECK_BOUNDS(Species, int, catchValue, 0, 255) CHECK_BOUNDS(Species, int, maxHoldWeight, -1, INT_MAX) CHECK_BOUNDS(Species, Fraction&, runChance, 0, 1) CHECK_BOUNDS(Species, Fraction&, fleeChance, 0, 1) CHECK_BOUNDS(Species, Fraction&, itemChance, 0, 1) CHECK_BOUNDS(Species, int, encyclopediaNumber, -1, INT_MAX) CHECK_BOUNDS(Species, int, weight, 0, INT_MAX) CHECK_BOUNDS(Species, int, height, 0, INT_MAX) CHECK_BEGIN(Species, int, frontMaleSprite) if (1 <= m_genderFactor) { ERROR("Species cannot be male"); return false; } IBOUNDS(frontMaleSprite, game(), sprite); CHECK_END() CHECK_BEGIN(Species, int, backMaleSprite) if (1 <= m_genderFactor) { ERROR("Species cannot be male"); return false; } IBOUNDS(backMaleSprite, game(), sprite); CHECK_END() CHECK_BEGIN(Species, int, frontFemaleSprite) if (!game()->rules()->genderAllowed() || (m_genderFactor <= 0)) { ERROR("Species cannot be female"); return false; } IBOUNDS(frontFemaleSprite, game(), sprite); CHECK_END() CHECK_BEGIN(Species, int, backFemaleSprite) if (!game()->rules()->genderAllowed() || (m_genderFactor <= 0)) { ERROR("Species cannot be female"); return false; } IBOUNDS(backFemaleSprite, game(), sprite); CHECK_END() CHECK_INDEX(Species, int, skin, game(), skin) CHECK(Species, QString&, encyclopediaEntry) CHECK_BOUNDS(Species, Fraction&, genderFactor, -1, 1) CHECK_INDEX(Species, int, eggSpecies, game(), species) CHECK_BOUNDS(Species, int, eggSteps, 1, INT_MAX) CHECK_INDEX(Species, int, type, game(), type) CHECK_INDEX(Species, int, eggGroup, game(), eggGroup) CHECK(Species, Script&, evolution) CHECK_BEGIN_ARRAY(Species, int, ability, weight, int, ability) IBOUNDS(ability, game(), ability); TBOUNDS_MOD(ability_weight, 1, INT_MAX, weight) CHECK_END() CHECK_BEGIN_ARRAY(Species, int, item, weight, int, item) IBOUNDS(item, game(), item); TBOUNDS_MOD(species_item, 1, INT_MAX, weight) CHECK_END() SUBCLASS(Species, Move, move, moves) Species& Species::operator=(const Species& rhs) { if (this == &rhs) return *this; clear(); COPY(name); COPY(baseStat); COPY(effortValue); COPY(growth); COPY(experienceValue); COPY(catchValue); COPY(maxHoldWeight); COPY(runChance); COPY(fleeChance); COPY(itemChance); COPY(encyclopediaNumber); COPY(weight); COPY(height); COPY(frontMaleSprite); COPY(backMaleSprite); COPY(frontFemaleSprite); COPY(backFemaleSprite); COPY(skin); COPY(encyclopediaEntry); COPY(genderFactor); COPY(eggSpecies); COPY(eggSteps); COPY(type); COPY(eggGroup); COPY(evolution); COPY(ability); COPY(item); COPY_SUB(SpeciesMove, moves); return *this; } void Species::clear() { m_type.clear(); m_eggGroup.clear(); m_ability.clear(); m_item.clear(); SUBCLASS_CLEAR(moves); }