From 222a422c3339a4e368cc7b53e83a489e181ba0eb Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 5 Feb 2009 23:06:24 -0500 Subject: Cleaned up Arena API and implementation --- sigencore/Arena.cpp | 226 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 176 insertions(+), 50 deletions(-) (limited to 'sigencore/Arena.cpp') 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 #include +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 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::Arena::active() const +QList Sigencore::Arena::active(const int team) const { QList active; - foreach (Player* player, m_players) - active += player->active(); + QList clients; + if ((team == Fighters) || (team == AllTeams)) + clients = m_teams.keys(); + else + clients = m_teams.keys(team); + foreach (Client* client, clients) + { + Player* player = qobject_cast(client); + if (player) + active += player->active(); + } return active; } +QList Sigencore::Arena::teamMembers(const int team) const +{ + switch (team) + { + case Fighters: + { + QList team = m_teams.keys(); + for (QMutableListIterator 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 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 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(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(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 actions = m_actions->actions(); foreach (Kross::Action* action, actions) m_actions->removeAction(action); distributeWinnings(); - foreach (Player* player, m_players) - player->exitArena(); + QList 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(teamMember->containment()); + Player* player = qobject_cast(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(teamMember->containment()); + Player* self = qobject_cast(teamMember->client()); const int numFlee = self->active().size(); bool canRun = true; - foreach (Player* player, m_players) + QList clients = m_teams.keys(); + foreach (Client* client, clients) { + Player* player = qobject_cast(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 clients = m_teams.keys(); + foreach (Client* client, clients) + { + Player* player = qobject_cast(client); + if (player) + player->enterArena(this); + } + m_state = InProgress; + emit(battleStarted()); } void Sigencore::Arena::distributeWinnings() { - foreach (Player* player, m_players) + QList clients = m_teams.keys(); + foreach (Client* client, clients) { - if (!m_spoils.contains(player)) + Player* player = qobject_cast(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 losers; - foreach (Player* player, m_players) + QList clients = m_teams.keys(); + QList roundLosers; + QMap pot; + QList teams; + QSet activeTeams; + foreach (Client* client, clients) { - + Player* player = qobject_cast(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("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 members = teamMembers(team); + QList survivors; + foreach (Client* member, members) + { + Player* player = qobject_cast(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 clients = m_teams.keys(); + foreach (Client* client, clients) { + Player* player = qobject_cast(client); + if (!player) + continue; TeamMember* member = player->findMember(id); if (member) return member; -- cgit