summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Boeckel <MathStuf@gmail.com>2009-02-05 23:06:24 -0500
committerBen Boeckel <MathStuf@gmail.com>2009-02-05 23:09:37 -0500
commit222a422c3339a4e368cc7b53e83a489e181ba0eb (patch)
treebb1e124e51cd71b0543583f8151816f392212470
parent7f38027c62f3a6b6d7d7b43e542ecc114407e98b (diff)
downloadsigen-222a422c3339a4e368cc7b53e83a489e181ba0eb.tar.gz
sigen-222a422c3339a4e368cc7b53e83a489e181ba0eb.tar.xz
sigen-222a422c3339a4e368cc7b53e83a489e181ba0eb.zip
Cleaned up Arena API and implementation
-rw-r--r--sigencore/Arena.cpp226
-rw-r--r--sigencore/Arena.h46
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;
};