diff options
| author | Ben Boeckel <MathStuf@gmail.com> | 2009-02-05 23:06:24 -0500 |
|---|---|---|
| committer | Ben Boeckel <MathStuf@gmail.com> | 2009-02-05 23:09:37 -0500 |
| commit | 222a422c3339a4e368cc7b53e83a489e181ba0eb (patch) | |
| tree | bb1e124e51cd71b0543583f8151816f392212470 | |
| parent | 7f38027c62f3a6b6d7d7b43e542ecc114407e98b (diff) | |
| download | sigen-222a422c3339a4e368cc7b53e83a489e181ba0eb.tar.gz sigen-222a422c3339a4e368cc7b53e83a489e181ba0eb.tar.xz sigen-222a422c3339a4e368cc7b53e83a489e181ba0eb.zip | |
Cleaned up Arena API and implementation
| -rw-r--r-- | sigencore/Arena.cpp | 226 | ||||
| -rw-r--r-- | sigencore/Arena.h | 46 |
2 files changed, 208 insertions, 64 deletions
diff --git a/sigencore/Arena.cpp b/sigencore/Arena.cpp index 9589e2e0..b2acaf51 100644 --- a/sigencore/Arena.cpp +++ b/sigencore/Arena.cpp @@ -19,16 +19,18 @@ #include "Arena.h" // Sigencore includes +#include "Client.h" #include "Player.h" +#include "RunScript.h" // Sigscript includes #include "../sigscript/ItemWrapper.h" #include "../sigscript/MoveWrapper.h" +#include "../sigscript/RulesWrapper.h" #include "../sigscript/SigmodWrapper.h" #include "../sigscript/SpeciesWrapper.h" // Sigcore includes -// #include "../sigcore/Fraction.h" #include "../sigcore/Script.h" // KDE includes @@ -40,6 +42,10 @@ #include <QtCore/QtConcurrentRun> #include <QtCore/QUuid> +const int Sigencore::Arena::Spectator = -1; +const int Sigencore::Arena::Fighters = -2; +const int Sigencore::Arena::AllTeams = -3; + Sigencore::TeamMember::RequestedAction Sigencore::requestDecision(TeamMember* teamMember) { return TeamMember::RequestedAction(teamMember, QtConcurrent::run(decision, teamMember)); @@ -50,18 +56,15 @@ Sigencore::TeamMember::Action Sigencore::decision(TeamMember* teamMember) return teamMember->requestAction(); } -Sigencore::Arena::Arena(Sigscript::SigmodWrapper* sigmod, QSet<Player*> players, const bool isWild, Sigscript::Config* parent) : +Sigencore::Arena::Arena(Sigscript::SigmodWrapper* sigmod, const bool isWild, Sigscript::Config* parent) : Sigscript::Config(parent), m_sigmod(sigmod), m_isWild(isWild), - m_isOver(false), - m_players(players), + m_state(Setup), m_id(QUuid::createUuid()) { connect(this, SIGNAL(battleEnd()), SLOT(cleanUp())); m_actions = new Kross::ActionCollection(QString("arena-%1").arg(m_id.toString()), Kross::Manager::self().actionCollection()); - foreach (Player* player, m_players) - player->enterArena(this); } Sigencore::Arena::~Arena() @@ -69,25 +72,63 @@ Sigencore::Arena::~Arena() delete m_actions; } -QList<Sigencore::TeamMember*> Sigencore::Arena::active() const +QList<Sigencore::TeamMember*> Sigencore::Arena::active(const int team) const { QList<Sigencore::TeamMember*> active; - foreach (Player* player, m_players) - active += player->active(); + QList<Client*> clients; + if ((team == Fighters) || (team == AllTeams)) + clients = m_teams.keys(); + else + clients = m_teams.keys(team); + foreach (Client* client, clients) + { + Player* player = qobject_cast<Player*>(client); + if (player) + active += player->active(); + } return active; } +QList<Sigencore::Client*> Sigencore::Arena::teamMembers(const int team) const +{ + switch (team) + { + case Fighters: + { + QList<Client*> team = m_teams.keys(); + for (QMutableListIterator<Client*> i(team); i.hasNext(); i.next()) + { + if (m_teams[i.value()] < 0) + i.remove(); + } + return team; + } + case AllTeams: + return m_teams.keys(); + default: + return m_teams.keys(team); + } +} + +int Sigencore::Arena::numTeams() const +{ + QSet<int> teams = m_teams.values().toSet(); + teams.remove(Spectator); + return teams.size(); +} + int Sigencore::Arena::numActiveTeams() const { - int active = 0; - foreach (Player* player, m_players) - active += !player->active().isEmpty(); - return active; + int activeTeams = 0; + QSet<int> teams = m_teams.values().toSet(); + foreach (int team, teams) + activeTeams += !active(team).isEmpty(); + return activeTeams; } -bool Sigencore::Arena::isOver() const +Sigencore::Arena::State Sigencore::Arena::state() const { - return m_isOver; + return m_state; } Sigscript::SigmodWrapper* Sigencore::Arena::sigmod() const @@ -95,6 +136,35 @@ Sigscript::SigmodWrapper* Sigencore::Arena::sigmod() const return m_sigmod; } +bool Sigencore::Arena::addClient(Client* client, const int team) +{ + if ((team < 0) || ((m_state == Setup) && qobject_cast<Player*>(client) && (teamMembers(Fighters).size() < m_sigmod->rules()->maxPlayers()))) + { + m_teams[client] = team; + emit(clientAdded(client, team)); + return true; + } + return false; +} + +void Sigencore::Arena::removeClient(Client* client) +{ + Player* player = qobject_cast<Player*>(client); + if (player && m_spoils.contains(player)) + { + Spoil spoil = m_spoils[player]; + const int net = spoil.first - spoil.second; + if (net < 0) + player->takeMoney(-net); + else if (0 < net) + player->giveMoney(net); + m_spoils.remove(player); + } + const int team = m_teams[client]; + m_teams.remove(client); + emit(clientRemoved(client, team)); +} + void Sigencore::Arena::registerScript(const Sigcore::Script& script) { if (!script.script().isEmpty()) @@ -109,14 +179,16 @@ void Sigencore::Arena::registerScript(const Sigcore::Script& script) void Sigencore::Arena::cleanUp() { + emit(battleAboutToEnd()); emit(aboutToClearActions()); - m_isOver = true; + m_state = Completed; QList<Kross::Action*> actions = m_actions->actions(); foreach (Kross::Action* action, actions) m_actions->removeAction(action); distributeWinnings(); - foreach (Player* player, m_players) - player->exitArena(); + QList<Client*> clients = m_teams.keys(); + foreach (Client* client, clients) + client->exitArena(); } void Sigencore::Arena::handleAction(TeamMember* teamMember, TeamMember::Action action) @@ -132,14 +204,14 @@ void Sigencore::Arena::handleAction(TeamMember* teamMember, TeamMember::Action a const Sigcore::Script script = move->battleScript(); if (!script.script().isEmpty()) { - Kross::Action* kaction = new Kross::Action(m_actions, QUuid::createUuid().toString()); - kaction->setInterpreter(script.interpreter()); - kaction->setCode(script.script().toUtf8()); - kaction->addObject(this, "arena"); - kaction->addObject(teamMember, "user"); + ObjectMap objects; + objects["arena"] = this; + objects["owner"] = teamMember; + objects["client"] = teamMember->client(); + objects["sigmod"] = m_sigmod; for (int i = 0; i < data.second.size(); ++i) - kaction->addObject(findMember(data.second[i]), QString("target%1").arg(i)); - kaction->trigger(); + objects[QString("target%1").arg(i)] = findMember(data.second[i]); + runScript(QUuid::createUuid().toString(), script, objects, m_actions)->trigger(); } } break; @@ -152,19 +224,20 @@ void Sigencore::Arena::handleAction(TeamMember* teamMember, TeamMember::Action a const Sigcore::Script script = item->script(); if (!script.script().isEmpty()) { - Kross::Action* kaction = new Kross::Action(m_actions, QUuid::createUuid().toString()); - kaction->setInterpreter(script.interpreter()); - kaction->setCode(script.script().toUtf8()); - kaction->addObject(this, "arena"); - kaction->addObject(findMember(data.second[0]), "target"); - kaction->trigger(); + ObjectMap objects; + objects["arena"] = this; + objects["client"] = teamMember->client(); + objects["sigmod"] = m_sigmod; + for (int i = 0; i < data.second.size(); ++i) + objects[QString("target%1").arg(i)] = findMember(data.second[i]); + runScript(QUuid::createUuid().toString(), script, objects, m_actions)->trigger(); } } break; } case TeamMember::Switch: { - Player* player = qobject_cast<Player*>(teamMember->containment()); + Player* player = qobject_cast<Player*>(teamMember->client()); if (player) player->switchOut(teamMember, player->findMember(data.second[0])); break; @@ -173,22 +246,23 @@ void Sigencore::Arena::handleAction(TeamMember* teamMember, TeamMember::Action a { if (!m_isWild) break; - Player* self = qobject_cast<Player*>(teamMember->containment()); + Player* self = qobject_cast<Player*>(teamMember->client()); const int numFlee = self->active().size(); bool canRun = true; - foreach (Player* player, m_players) + QList<Client*> clients = m_teams.keys(); + foreach (Client* client, clients) { + Player* player = qobject_cast<Player*>(client); + if (!player) + continue; if (self == player) continue; foreach (TeamMember* active, player->active()) { - for (int i = 0; (i < numFlee) && canRun; ++i) + for (int i = 0; canRun && (i < numFlee); ++i) { if (!active->species()->fleeChance().poll()) - { canRun = false; - break; - } } } if (!canRun) @@ -198,25 +272,32 @@ void Sigencore::Arena::handleAction(TeamMember* teamMember, TeamMember::Action a self->exitArena(); break; } - case TeamMember::Skip: - case TeamMember::Timeout: - case TeamMember::Invalid: + default: break; } - checkForLosers(); } void Sigencore::Arena::setupBattle() { - foreach (Player* player, m_players) - player->enterArena(this); + emit(battleAboutToStart()); + QList<Client*> clients = m_teams.keys(); + foreach (Client* client, clients) + { + Player* player = qobject_cast<Player*>(client); + if (player) + player->enterArena(this); + } + m_state = InProgress; + emit(battleStarted()); } void Sigencore::Arena::distributeWinnings() { - foreach (Player* player, m_players) + QList<Client*> clients = m_teams.keys(); + foreach (Client* client, clients) { - if (!m_spoils.contains(player)) + Player* player = qobject_cast<Player*>(client); + if (!player || !m_spoils.contains(player)) continue; Spoil spoil = m_spoils[player]; const int net = spoil.first - spoil.second; @@ -229,17 +310,62 @@ void Sigencore::Arena::distributeWinnings() void Sigencore::Arena::checkForLosers() { - static QSet<Player*> losers; - foreach (Player* player, m_players) + QList<Client*> clients = m_teams.keys(); + QList<Player*> roundLosers; + QMap<int, int> pot; + QList<int> teams; + QSet<int> activeTeams; + foreach (Client* client, clients) { - + Player* player = qobject_cast<Player*>(client); + if (player && !m_losers.contains(player)) + { + activeTeams.insert(m_teams[player]); + if (player->isKnockedOut()) + roundLosers.append(player); + } + } + foreach (Player* loser, roundLosers) + { + const int money = loser->money(); + Sigcore::Fraction lossFactor(1, 2); + m_sigmod->valueOfType<Sigcore::Fraction>("lossFactor", &lossFactor); + pot[m_teams[loser]] += money * lossFactor; + m_spoils[loser].second = money * lossFactor; } + teams = pot.keys(); + foreach (int teamPot, teams) + { + foreach (int team, activeTeams) + { + if (team == teamPot) + continue; + QList<Client*> members = teamMembers(team); + QList<Player*> survivors; + foreach (Client* member, members) + { + Player* player = qobject_cast<Player*>(member); + m_spoils[player].first += (pot[teamPot] >> 1) / (activeTeams.size() - 1); + if (!player->isKnockedOut()) + survivors.append(player); + } + foreach (Player* survivor, survivors) + m_spoils[survivor].first += (pot[teamPot] >> 1) / survivors.size(); + } + } + m_losers += roundLosers; + if (numActiveTeams() == 1) + cleanUp(); } Sigencore::TeamMember* Sigencore::Arena::findMember(const QUuid& id) { - foreach (Player* player, m_players) + QList<Client*> clients = m_teams.keys(); + foreach (Client* client, clients) { + Player* player = qobject_cast<Player*>(client); + if (!player) + continue; TeamMember* member = player->findMember(id); if (member) return member; diff --git a/sigencore/Arena.h b/sigencore/Arena.h index 4b982fdb..82c3bdeb 100644 --- a/sigencore/Arena.h +++ b/sigencore/Arena.h @@ -47,6 +47,7 @@ class SigmodWrapper; namespace Sigencore { +class Client; class Player; class SIGENCORE_EXPORT Arena : public Sigscript::Config @@ -54,47 +55,64 @@ class SIGENCORE_EXPORT Arena : public Sigscript::Config Q_OBJECT public: + enum State + { + Setup = 0, + InProgress = 1, + Completed = 2 + }; + typedef QPair<int, int> Spoil; + static const int Spectator; + static const int Fighters; + static const int AllTeams; - QList<TeamMember*> active() const; + QList<TeamMember*> active(const int team) const; + QList<Client*> teamMembers(const int team) const; + int numTeams() const; int numActiveTeams() const; - bool isOver() const; + State state() const; Sigscript::SigmodWrapper* sigmod() const; public slots: -// void addClient(Client* client); -// void removeClient(Client* client); - - void registerScript(const Sigcore::Script& script); + bool addClient(Client* client, const int team); + void removeClient(Client* client); signals: - void battleStart(); - void battleEnd(); + void battleAboutToStart(); + void battleStarted(); + void battleAboutToEnd(); + void battleEnded(); void aboutToClearActions(); + + void clientAdded(Client* client, const int team); + void clientRemoved(Client* client, const int team); protected: - Arena(Sigscript::SigmodWrapper* sigmod, QSet<Player*> players, const bool isWild, Sigscript::Config* parent); - ~Arena(); + Arena(Sigscript::SigmodWrapper* sigmod, const bool isWild, Sigscript::Config* parent); + virtual ~Arena(); virtual void handleAction(TeamMember* teamMember, TeamMember::Action action); virtual void setupBattle(); - void distributeWinnings(); + virtual void distributeWinnings(); virtual void checkForLosers(); TeamMember* findMember(const QUuid& id); Sigscript::SigmodWrapper* m_sigmod; const bool m_isWild; - bool m_isOver; -// QSet<Client*> m_clients; - QSet<Player*> m_players; + QMap<Client*, int> m_teams; Kross::ActionCollection* m_actions; QMap<Player*, Spoil> m_spoils; + QList<Player*> m_losers; protected slots: + virtual void registerScript(const Sigcore::Script& script); + virtual void cleanUp(); private: + State m_state; const QUuid m_id; }; |
