diff options
| author | Ben Boeckel <MathStuf@gmail.com> | 2009-01-27 22:07:08 -0500 |
|---|---|---|
| committer | Ben Boeckel <MathStuf@gmail.com> | 2009-01-27 22:07:08 -0500 |
| commit | e04c4922a13ed10e9d6b086eacc299f0c5a05984 (patch) | |
| tree | 907e109278adbea9ae100feb61e020174033a3e5 /sigencore/TeamMember.cpp | |
| parent | d111ea6a931a7120631f6e88e9414cbdb851e0e8 (diff) | |
| download | sigen-e04c4922a13ed10e9d6b086eacc299f0c5a05984.tar.gz sigen-e04c4922a13ed10e9d6b086eacc299f0c5a05984.tar.xz sigen-e04c4922a13ed10e9d6b086eacc299f0c5a05984.zip | |
Begin migration of core classes to libsigencore
Diffstat (limited to 'sigencore/TeamMember.cpp')
| -rw-r--r-- | sigencore/TeamMember.cpp | 705 |
1 files changed, 705 insertions, 0 deletions
diff --git a/sigencore/TeamMember.cpp b/sigencore/TeamMember.cpp new file mode 100644 index 00000000..55ba656a --- /dev/null +++ b/sigencore/TeamMember.cpp @@ -0,0 +1,705 @@ +/* + * Copyright 2007-2008 Ben Boeckel <MathStuf@gmail.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +// Header include +#include "TeamMember.h" + +// Sigbattle includes +#include "Arena.h" +#include "Containment.h" +#include "Player.h" + +// Sigscript includes +#include "../sigscript/AbilityWrapper.h" +#include "../sigscript/ItemWrapper.h" +#include "../sigscript/MapTrainerTeamMemberWrapper.h" +#include "../sigscript/MoveWrapper.h" +#include "../sigscript/NatureWrapper.h" +#include "../sigscript/RulesWrapper.h" +#include "../sigscript/SigmodWrapper.h" +#include "../sigscript/StatusWrapper.h" +#include "../sigscript/SpeciesWrapper.h" +#include "../sigscript/SpeciesMoveWrapper.h" + +// Sigcore includes +#include "../sigcore/Hat.h" + +// KDE includes +#include <kross/core/action.h> +#include <kross/core/actioncollection.h> +#include <kross/core/manager.h> + +// Qt includes +#include <QtCore/QUuid> + +// C includes +#include <cmath> + +int Sigbattle::actionPriority(TeamMember* teamMember, const TeamMember::Action& action) +{ + int priority = INT_MAX; + switch (action.first) + { + case TeamMember::Attack: + { + QString move = action.second.first.toString(); + if (teamMember->hasValueOfType<int>(QString("move-priority-%1").arg(move))) + { + priority = teamMember->valueOfType<int>(QString("move-priority-%1").arg(move)); + teamMember->removeValue(QString("move-priority-%1").arg(move)); + } + else + priority = teamMember->sigmod()->move(move)->priority(); + break; + } + case TeamMember::Item: + priority = INT_MIN / 3; + break; + case TeamMember::Switch: + priority = INT_MIN / 2; + break; + case TeamMember::Run: + priority = INT_MIN; + break; + case TeamMember::Skip: + priority = INT_MAX - 2; + break; + case TeamMember::Timeout: + priority = INT_MAX; + break; + case TeamMember::Invalid: + priority = INT_MAX - 1; + break; + } + return priority; +} + +Sigbattle::TeamMember::TeamMember(const int speciesId, const QString& name, const int level, Containment* containment, const bool suppressItems) : + Sigscript::Config(containment), + m_containment(containment), + m_id(QUuid::createUuid()) +{ + makeConnections(); + setSpecies(sigmod()->species(speciesId)); + if (name.isEmpty()) + setName(m_species->name()); + else + setName(name); + setLevel(level); + if (!suppressItems) + initItems(); + initAbilities(); + initMoves(); + initNatures(); + initStats(); + if (m_species->genderFactor() <= 1) + m_gender = (m_species->genderFactor().poll() ? Male : Female); + else + m_gender = Genderless; + for (int i = 0; i <= Sigmod::ST_SpecialDefense; ++i) + m_statExp[i] = 0; + if (m_containment->isMutable()) + { + const Sigcore::Script script = m_species->evolution(); + if (!script.script().isEmpty()) + { + Kross::Action* evolution = new Kross::Action(Kross::Manager::self().actionCollection()->collection("evolutions"), QUuid::createUuid().toString()); + evolution->setInterpreter(script.interpreter()); + evolution->setCode(script.script().toUtf8()); + evolution->addObject(this, "owner"); + evolution->trigger(); + } + } + m_currentHp = statValue(Sigmod::ST_HP); +} + +Sigbattle::TeamMember::TeamMember(Sigscript::MapTrainerTeamMemberWrapper* teamMember, Containment* containment) : + Sigscript::Config(containment), + m_containment(containment), + m_id(QUuid::createUuid()) +{ + makeConnections(); + setSpecies(teamMember->species()); + setName(m_species->name()); + setLevel(teamMember->level()); + const QMap<Sigscript::ItemWrapper*, int>& itemMap = teamMember->items(); + QList<Sigscript::ItemWrapper*> items = itemMap.keys(); + foreach (Sigscript::ItemWrapper* item, items) + { + for (int i = 0; i < itemMap[item]; ++i) + m_items.append(item); + } + initAbilities(teamMember->abilities()); + initMoves(teamMember->moves()); + initNatures(teamMember->natures()); + initStats(); + if (m_species->genderFactor() <= 1) + m_gender = (m_species->genderFactor().poll() ? Male : Female); + else + m_gender = Genderless; + for (int i = 0; i <= Sigmod::ST_SpecialDefense; ++i) + m_statExp[i] = 0; + m_currentHp = statValue(Sigmod::ST_HP); +} + +Sigbattle::Containment* Sigbattle::TeamMember::containment() const +{ + return m_containment; +} + +QUuid Sigbattle::TeamMember::id() const +{ + return m_id; +} + +QString Sigbattle::TeamMember::name() const +{ + if (hasValueOfType<QString>("name")) + return valueOfType<QString>("name"); + return m_name; +} + +long long Sigbattle::TeamMember::currentHp() const +{ + return m_currentHp; +} + +Sigscript::SpeciesWrapper* Sigbattle::TeamMember::species() const +{ + if (hasValueOfType<Sigscript::SpeciesWrapper*>("species")) + return valueOfType<Sigscript::SpeciesWrapper*>("species"); + return m_species; +} + +int Sigbattle::TeamMember::level() const +{ + return m_level; +} + +Sigbattle::TeamMember::Gender Sigbattle::TeamMember::gender() const +{ + if (hasValueOfType<Gender>("gender")) + return valueOfType<Gender>("gender"); + return m_gender; +} + +long long Sigbattle::TeamMember::levelExperience() const +{ + if (hasValueOfType<long long>("levelExperience")) + return valueOfType<long long>("levelExperience"); + return m_levelExp; +} + +int Sigbattle::TeamMember::baseStat(const Sigmod::Stat stat) const +{ + if (hasValueOfType<bool>("overrideBaseStats") && valueOfType<bool>("overrideBaseStats")) + return species()->baseStat(stat); + return m_species->baseStat(stat); +} + +long long Sigbattle::TeamMember::statExperience(const Sigmod::Stat stat) const +{ + const QString valueName = QString("statExperience-%1").arg((sigmod()->rules()->specialSplit() ? Sigmod::StatGSCStr : Sigmod::StatRBYStr)[stat]); + if (hasValueOfType<long long>(valueName)) + return valueOfType<long long>(valueName); + return m_statExp[stat]; +} + +int Sigbattle::TeamMember::dv(const Sigmod::Stat stat) const +{ + const QString valueName = QString("dv-%1").arg((sigmod()->rules()->specialSplit() ? Sigmod::StatGSCStr : Sigmod::StatRBYStr)[stat]); + if (hasValueOfType<int>(valueName)) + { + const int dv = valueOfType<int>(valueName); + if (dv < (sigmod()->rules()->specialDVSplit() ? 32 : 16)) + return dv; + } + return m_dv[stat]; +} + +long long Sigbattle::TeamMember::statValue(const Sigmod::Stat stat, const long long exp) const +{ + long long statValue; + if (exp < 0) + statValue = statExperience(stat); + else + statValue = exp; + if (!sigmod()->rules()->effortValuesAllowed() && statValue) + statValue = sqrt(statValue - 1) + 1; + statValue >>= 2; + statValue += baseStat(stat) << 1; + if (sigmod()->rules()->specialDVSplit()) + { + if (stat == Sigmod::ST_SpecialDefense) + statValue += dv(Sigmod::ST_Special) << 1; + else + statValue += dv(stat) << 1; + } + else + statValue += dv(stat); + statValue *= double(m_level) / sigmod()->rules()->maxLevel(); + if (stat == Sigmod::ST_HP) + statValue += 10 + m_level; + else + { + statValue += 5; + Sigcore::Fraction multiplier; + foreach (Sigscript::NatureWrapper* nature, m_natures) + multiplier *= nature->stat(stat); + statValue *= multiplier; + } + return statValue; +} + +long long Sigbattle::TeamMember::calcExp(int level) const +{ + if (level < 0) + level = m_level; + const long long square = level * level; + const long long cube = square * level; + switch (m_species->growth()) + { + case Sigmod::Species::Fluctuating: + if (level <= 15) + return cube * ((24 + (level + 1) / 3) / 50.0); + else if (level <= 35) + return cube * ((14 + level) / 50.0); + else if (level <= 100) + return cube * ((32 + (level / 2)) / 50.0); + // TODO: better way for further growth? + else if (level <= 102) + return cube * (23 + level) / 75; + else + return 5 * cube / 3; + case Sigmod::Species::Fading: + return 6 * cube / 5 - 15 * square + 100 * level - 140; + case Sigmod::Species::Slow: + return 5 * cube / 4; + case Sigmod::Species::Normal: + return cube; + case Sigmod::Species::Fast: + return 4 * cube / 5; + case Sigmod::Species::Erratic: + { + const double p[] = {0.000, 0.008, 0.014}; + if (level <= 50) + return cube * ((100 - level) / 50.0); + else if (level <= 68) + return cube * ((150 - level) / 100.0); + else if (level <= 98) + return cube * (1.274 - (level / 3) / 50.0 - p[level % 3]); + else if (level <= 100) + return cube * ((160 - level) / 100.0); + // TODO: better way for further growth? + else + return 3 * cube / 5; + } + default: + break; + } + return -1; +} + +bool Sigbattle::TeamMember::canLearnMove(Sigscript::MoveWrapper* move) const +{ + for (int i = 0; i < m_species->moveCount(); ++i) + { + if (move->id() == m_species->move(i)->move()->id()) + return true; + } + return false; +} + +long long Sigbattle::TeamMember::timer() const +{ + return m_timer; +} + +void Sigbattle::TeamMember::boostLevels(const int levels) +{ + if ((m_level + levels) < sigmod()->rules()->maxLevel()) + { + for (int i = 0; i < levels; ++i) + setLevel(m_level + 1); + } +} + +void Sigbattle::TeamMember::evolveInto(Sigscript::SpeciesWrapper* newSpecies) +{ + emit(evolveStart()); + int oldStats[Sigmod::ST_SpecialDefense - Sigmod::ST_HP + 1] = {}; + int newStats[Sigmod::ST_SpecialDefense - Sigmod::ST_HP + 1] = {}; + oldStats[Sigmod::ST_Attack] = statValue(Sigmod::ST_Attack); + oldStats[Sigmod::ST_Defense] = statValue(Sigmod::ST_Defense); + oldStats[Sigmod::ST_Speed] = statValue(Sigmod::ST_Speed); + if (sigmod()->rules()->specialSplit()) + { + oldStats[Sigmod::ST_SpecialAttack] = statValue(Sigmod::ST_SpecialAttack); + oldStats[Sigmod::ST_SpecialDefense] = statValue(Sigmod::ST_SpecialDefense); + } + else + oldStats[Sigmod::ST_Special] = statValue(Sigmod::ST_Special); + setSpecies(newSpecies); + newStats[Sigmod::ST_Attack] = statValue(Sigmod::ST_Attack); + newStats[Sigmod::ST_Defense] = statValue(Sigmod::ST_Defense); + newStats[Sigmod::ST_Speed] = statValue(Sigmod::ST_Speed); + if (sigmod()->rules()->specialSplit()) + { + newStats[Sigmod::ST_SpecialAttack] = statValue(Sigmod::ST_SpecialAttack); + newStats[Sigmod::ST_SpecialDefense] = statValue(Sigmod::ST_SpecialDefense); + } + else + newStats[Sigmod::ST_Special] = statValue(Sigmod::ST_Special); + if (oldStats[Sigmod::ST_Attack] != newStats[Sigmod::ST_Attack]) + emit(statChanged(Sigmod::ST_Attack, newStats[Sigmod::ST_Attack])); + if (oldStats[Sigmod::ST_Defense] != newStats[Sigmod::ST_Defense]) + emit(statChanged(Sigmod::ST_Defense, newStats[Sigmod::ST_Defense])); + if (oldStats[Sigmod::ST_Speed] != newStats[Sigmod::ST_Speed]) + emit(statChanged(Sigmod::ST_Speed, newStats[Sigmod::ST_Speed])); + if (sigmod()->rules()->specialSplit()) + { + if (oldStats[Sigmod::ST_SpecialAttack] != newStats[Sigmod::ST_SpecialAttack]) + emit(statChanged(Sigmod::ST_SpecialAttack, newStats[Sigmod::ST_SpecialAttack])); + if (oldStats[Sigmod::ST_SpecialDefense] != newStats[Sigmod::ST_SpecialDefense]) + emit(statChanged(Sigmod::ST_SpecialDefense, newStats[Sigmod::ST_SpecialDefense])); + } + else + { + if (oldStats[Sigmod::ST_Special] != newStats[Sigmod::ST_Special]) + emit(statChanged(Sigmod::ST_Special, newStats[Sigmod::ST_Special])); + } + emit(evolveEnd()); +} + +void Sigbattle::TeamMember::setName(const QString& name) +{ + if (m_name != name) + { + const QString oldName = m_name; + m_name = name; + emit(nameChanged(oldName, m_name)); + } +} + +void Sigbattle::TeamMember::cureStatus(Sigscript::StatusWrapper* status) +{ + if (m_status.contains(status)) + { + QList<Kross::Action*> actions = m_status.values(status); + qDeleteAll(actions); + m_status.remove(status); + emit(statusCured(status)); + } +} + +void Sigbattle::TeamMember::giveStatus(Sigscript::StatusWrapper* status) +{ + if (!m_status.contains(status)) + { + const Sigcore::Script script = status->worldScript(); + if (!script.script().isEmpty()) + { + Kross::Action* statusAction = new Kross::Action(Kross::Manager::self().actionCollection()->collection("status"), QUuid::createUuid().toString()); + statusAction->setInterpreter(script.interpreter()); + statusAction->setCode(script.script().toUtf8()); + statusAction->addObject(this, "owner"); + statusAction->trigger(); + m_status.insert(status, statusAction); + emit(statusInflicted(status)); + } + } +} + +void Sigbattle::TeamMember::giveLevelExp(const int exp) +{ + if (m_level == sigmod()->rules()->maxLevel()) + return; + const int expNeeded = calcExp(m_level + 1) - calcExp(); + if (exp < expNeeded) + { + m_levelExp += exp; + emit(expGained(exp)); + } + else + { + setLevel(m_level + 1); + emit(expGained(expNeeded)); + giveLevelExp(exp - expNeeded); + } +} + +void Sigbattle::TeamMember::giveStatExp(const Sigmod::Stat stat, const int exp) +{ + const int oldStat = statValue(stat); + int expToGive = exp; + if (sigmod()->rules()->effortValuesAllowed()) + { + int totalEV = 0; + for (int i = 0; i <= Sigmod::ST_SpecialDefense; ++i) + totalEV += m_statExp[i]; + while (expToGive && (totalEV < sigmod()->rules()->maxTotalEV()) && (m_statExp[stat] < sigmod()->rules()->maxEVPerStat())) + { + --expToGive; + ++totalEV; + ++m_statExp[stat]; + } + } + else + { + while (expToGive && (m_statExp[stat] < INT_MAX)) + { + --expToGive; + ++m_statExp[stat]; + } + } + const int newStat = statValue(stat); + if (oldStat != newStat) + emit(statChanged(stat, newStat)); +} + +void Sigbattle::TeamMember::takeItem(Sigscript::ItemWrapper* item) +{ + if (m_items.contains(item)) + { + m_items.removeAt(m_items.indexOf(item)); + emit(itemTaken(item)); + } +} + +void Sigbattle::TeamMember::giveItem(Sigscript::ItemWrapper* item) +{ + if ((m_items.size() < sigmod()->rules()->maxHeldItems()) && checkWeight(item)) + { + m_items.append(item); + emit(itemGiven(item)); + } +} + +void Sigbattle::TeamMember::forgetMove(Sigscript::MoveWrapper* move) +{ + if (m_moves.contains(move)) + { + m_moves.removeAll(move); + emit(moveForgotten(move)); + } +} + +void Sigbattle::TeamMember::teachMove(Sigscript::MoveWrapper* move) +{ + if (canLearnMove(move)) + { + if (m_moves.size() < sigmod()->rules()->maxMoves()) + { + m_moves.append(move); + emit(moveLearned(move)); + } + emit(movesFull(move)); + } + emit(unlearnableMove(move)); +} + +Sigbattle::TeamMember::Action Sigbattle::TeamMember::requestAction() +{ + Player* player = qobject_cast<Player*>(m_containment); + m_lastAction = player ? player->requestAction(this) : Action(Invalid, ActionData()); + return m_lastAction; +} + +Sigbattle::TeamMember::Action Sigbattle::TeamMember::latestAction() const +{ + return m_lastAction; + Player* player = qobject_cast<Player*>(m_containment); + if (player) + return player->requestAction(this); + return Action(Invalid, ActionData()); +} + +void Sigbattle::TeamMember::makeActive(Arena* arena) +{ + m_timer = 0; + QList<Sigscript::StatusWrapper*> statuses = m_status.uniqueKeys(); + foreach (Sigscript::StatusWrapper* status, statuses) + { + const Sigcore::Script script = status->battleScript(); + if (!script.script().isEmpty()) + { + Kross::Action* action = new Kross::Action(Kross::Manager::self().actionCollection()->collection("status"), QUuid::createUuid().toString()); + action->setInterpreter(script.interpreter()); + action->setCode(script.script().toUtf8()); + action->addObject(arena, "arena"); + action->addObject(this, "owner"); + action->trigger(); + m_statusBattleScripts.append(action); + } + } + QList<Sigscript::AbilityWrapper*> abilities = m_abilities.keys(); + foreach (Sigscript::AbilityWrapper* ability, abilities) + { + const Sigcore::Script script = ability->battleScript(); + if (!script.script().isEmpty()) + { + Kross::Action* action = new Kross::Action(Kross::Manager::self().actionCollection()->collection("ability"), QUuid::createUuid().toString()); + action->setInterpreter(script.interpreter()); + action->setCode(script.script().toUtf8()); + action->addObject(arena, "arena"); + action->addObject(this, "owner"); + action->trigger(); + m_abilityBattleScripts.append(action); + } + } +} + +void Sigbattle::TeamMember::leaveArena() +{ + Kross::ActionCollection* collection = Kross::Manager::self().actionCollection()->collection("status"); + foreach (Kross::Action* action, m_statusBattleScripts) + collection->removeAction(action); + collection = Kross::Manager::self().actionCollection()->collection("ability"); + foreach (Kross::Action* action, m_abilityBattleScripts) + collection->removeAction(action); +} + +void Sigbattle::TeamMember::advanceTimer(const long long jump) +{ + m_timer += jump; +} + +void Sigbattle::TeamMember::writeBack() +{ + // TODO: write back all (applicable) differences between config and local storage +} + +Sigscript::SigmodWrapper* Sigbattle::TeamMember::sigmod() const +{ + return m_containment->sigmod(); +} + +void Sigbattle::TeamMember::setSpecies(Sigscript::SpeciesWrapper* species) +{ + m_species = species; + emit(speciesChanged(m_species)); +} + +void Sigbattle::TeamMember::setLevel(const int level) +{ + emit(levelAboutToGrow()); + m_level = level; + emit(levelGrown(level)); + m_levelExp = calcExp(); +} + +void Sigbattle::TeamMember::levelGrown() +{ + for (int i = 0; i < m_species->moveCount(); ++i) + { + Sigscript::SpeciesMoveWrapper* move = m_species->move(i); + if (move->level() == m_level) + teachMove(move->move()); + } +} + +bool Sigbattle::TeamMember::checkWeight(const Sigscript::ItemWrapper* item) +{ + int totalWeight = item->weight(); + foreach (Sigscript::ItemWrapper* item, m_items) + totalWeight += item->weight(); + return (totalWeight <= species()->maxHoldWeight()); +} + +void Sigbattle::TeamMember::makeConnections() +{ + // TODO: make connections that are necessary (watching Config changes mainly) +} + +void Sigbattle::TeamMember::initAbility(Sigscript::AbilityWrapper* ability) +{ + const Sigcore::Script script = ability->battleScript(); + if (!script.script().isEmpty()) + { + Kross::Action* action = new Kross::Action(Kross::Manager::self().actionCollection()->collection("ability"), QUuid::createUuid().toString()); + action->setInterpreter(script.interpreter()); + action->setCode(script.script().toUtf8()); + action->addObject(this, "owner", Kross::ChildrenInterface::AutoConnectSignals); + action->trigger(); + m_abilities[ability] = action; + } +} + +void Sigbattle::TeamMember::initItems() +{ + Sigcore::Hat<Sigscript::ItemWrapper*> hat = m_species->itemHat(); + for (int i = 0; i < sigmod()->rules()->maxHeldItems(); ++i) + { + if (m_species->itemChance().poll()) + { + Sigscript::ItemWrapper* item = hat.pick(); + if (checkWeight(item)) + m_items.append(item); + } + } +} + +void Sigbattle::TeamMember::initAbilities(const QList<Sigscript::AbilityWrapper*>& initial) +{ + foreach (Sigscript::AbilityWrapper* ability, initial) + initAbility(ability); + Sigcore::Hat<Sigscript::AbilityWrapper*> hat = m_species->abilityHat(); + while (m_abilities.size() < sigmod()->rules()->maxAbilities()) + { + Sigscript::AbilityWrapper* ability = hat.takeAndClear(); + if (!m_abilities.contains(ability)) + initAbility(ability); + } +} + +void Sigbattle::TeamMember::initMoves(const QList<Sigscript::MoveWrapper*>& initial) +{ + m_moves = initial; + for (int i = 0; (i < m_species->moveCount()) && (m_moves.size() < sigmod()->rules()->maxMoves()); ++i) + { + Sigscript::SpeciesMoveWrapper* move = m_species->move(i); + if (!m_moves.contains(move->move()) && (((move->level() < m_level) && move->level()) || (!m_containment->isMutable() && (move->wild() < m_level)))) + m_moves.append(move->move()); + } +} + +void Sigbattle::TeamMember::initNatures(const QList<Sigscript::NatureWrapper*>& initial) +{ + m_natures = initial; + Sigcore::Hat<Sigscript::NatureWrapper*> hat = sigmod()->natureHat(); + while (m_natures.size() < sigmod()->rules()->maxNatures()) + { + Sigscript::NatureWrapper* nature = hat.takeAndClear(); + if (!m_natures.contains(nature)) + m_natures.append(nature); + } +} + +void Sigbattle::TeamMember::initStats() +{ + if (sigmod()->rules()->specialDVSplit()) + { + for (int i = Sigmod::ST_HP; i <= Sigmod::ST_SpecialDefense; ++i) + m_dv[i] = qrand() & 31; + } + else + { + for (int i = Sigmod::ST_Attack; i <= Sigmod::ST_Special; ++i) + m_dv[i] = qrand() & 15; + m_dv[Sigmod::ST_HP] = ((m_dv[Sigmod::ST_Attack] & 1) << 3) + ((m_dv[Sigmod::ST_Defense] & 1) << 2) + ((m_dv[Sigmod::ST_Speed] & 1) << 1) + (m_dv[Sigmod::ST_Special] & 1); + } +} |
