diff --git a/nbproject/project.xml b/nbproject/project.xml
index 1fb77ee..9539d75 100644
--- a/nbproject/project.xml
+++ b/nbproject/project.xml
@@ -1,15 +1,22 @@
-
-
- org.netbeans.modules.cnd.makeproject
-
-
- ShoddyBattle2
- 0
- c
- cpp
- h
- UTF-8
-
-
-
-
+
+
+ org.netbeans.modules.cnd.makeproject
+
+
+ ShoddyBattle2
+ 0
+ c
+ cpp
+ h
+ UTF-8
+
+
+ src
+
+
+ Debug
+ Release
+
+
+
+
diff --git a/resources/metagames.xml b/resources/metagames.xml
index 816675a..93ba6df 100644
--- a/resources/metagames.xml
+++ b/resources/metagames.xml
@@ -2,111 +2,131 @@
This file specifies the definitions for the various metagames that can be
played using the matchmaking facility on the server.
-->
+
+
+
+ Generation 4
+
+
+ Standard
+ Standard OU metagame.
+ 1
+ 6
+
+ Arceus
+ Darkrai
+ Deoxys
+ Deoxys-e
+ Deoxys-l
+ Deoxys-f
+ Dialga
+ Garchomp
+ Giratina
+ Giratina-o
+ Groudon
+ Ho-oh
+ Kyogre
+ Latios
+ Lugia
+ Manaphy
+ Mew
+ Mewtwo
+ Palkia
+ Rayquaza
+ Shaymin-s
+ Wobbuffet
+ Wynaut
+
+
+ Classic Sleep Clause
+ OHKO Clause
+ Classic Freeze Clause
+ Strict Damage Clause
+ Evasion Clause
+ Griseous Orb Limitation
+
+
+ 300
+ 3
+ 30
+
+
-
+
+ Uber
+ Uber metagame.
+ 1
+ 6
+
+
+
+ Classic Sleep Clause
+ OHKO Clause
+ Classic Freeze Clause
+ Strict Damage Clause
+ Evasion Clause
+ Griseous Orb Limitation
+
+
+ 300
+ 3
+ 30
+
+
-
- Standard
- standard
- Standard OU metagame with Uber pokemon banned.
- 1
- 6
-
- Arceus
- Darkrai
- Deoxys
- Deoxys-e
- Deoxys-l
- Deoxys-f
- Dialga
- Garchomp
- Giratina
- Giratina-o
- Groudon
- Ho-oh
- Kyogre
- Latios
- Lugia
- Manaphy
- Mew
- Mewtwo
- Palkia
- Rayquaza
- Shaymin-s
- Wobbuffet
- Wynaut
-
-
- Classic Sleep Clause
- OHKO Clause
- Classic Freeze Clause
- Strict Damage Clause
- Evasion Clause
- Griseous Orb Limitation
-
-
- 300
- 3
- 30
-
-
-
-
- Uber
- uber
- Uber metagame.
- 1
- 6
-
-
-
- Classic Sleep Clause
- OHKO Clause
- Classic Freeze Clause
- Strict Damage Clause
- Evasion Clause
- Griseous Orb Limitation
-
-
- 300
- 3
- 30
-
-
-
-
-
- VGC
- vgc
- Basic VGC rules
- 2
- 4
-
- Arceus
- Celebi
- Darkrai
- Deoxys
- Deoxys-e
- Deoxys-l
- Deoxys-f
- Jirachi
- Manaphy
- Phione
- Shaymin
- Mew
-
-
- Species Clause
- Item Clause
- Soul Dew Clause
- Strict Damage Clause
- Griseous Orb Limitation
-
-
- 300
- 3
- 30
-
-
-
-
+
+ VGC
+ Basic VGC rules
+ 2
+ 4
+
+ Arceus
+ Celebi
+ Darkrai
+ Deoxys
+ Deoxys-e
+ Deoxys-l
+ Deoxys-f
+ Jirachi
+ Manaphy
+ Phione
+ Shaymin
+ Mew
+
+
+ Species Clause
+ Item Clause
+ Soul Dew Clause
+ Strict Damage Clause
+ Griseous Orb Limitation
+
+
+ 300
+ 3
+ 30
+
+
+
+
+
+ Super Test
+
+
+ Best Uber
+ BEST Uber metagame.
+ 1
+ 6
+
+
+
+ OHKO Clause
+
+
+ 300
+ 3
+ 30
+
+
+
+
+
\ No newline at end of file
diff --git a/src/database/DatabaseRegistry.cpp b/src/database/DatabaseRegistry.cpp
index 2f74569..65d6671 100644
--- a/src/database/DatabaseRegistry.cpp
+++ b/src/database/DatabaseRegistry.cpp
@@ -377,14 +377,9 @@ double DatabaseRegistry::getRatingEstimate(const int id, const std::string &ladd
}
DatabaseRegistry::ESTIMATE_LIST DatabaseRegistry::getEstimates(const int id,
- const std::vector &metagames) {
+ const std::vector &metagames) {
ESTIMATE_LIST list;
- vector::const_iterator i = metagames.begin();
- for(; i != metagames.end(); ++i) {
- MetagamePtr p = *i;
- double estimate = getRatingEstimate(id, p->getId());
- list.push_back(ESTIMATE_ELEMENT(p->getIdx(), estimate));
- }
+ // TODO: Think on the format of ladder stats. Until then, return blank
return list;
}
diff --git a/src/database/DatabaseRegistry.h b/src/database/DatabaseRegistry.h
index bc30f98..dba7bff 100644
--- a/src/database/DatabaseRegistry.h
+++ b/src/database/DatabaseRegistry.h
@@ -202,7 +202,7 @@ class DatabaseRegistry {
* Get a user's ladder estimates
*/
ESTIMATE_LIST getEstimates(const int id,
- const std::vector &metagames);
+ const std::vector &metagames);
/**
* Initialise the tables required for a ladder.
diff --git a/src/main/main.cpp b/src/main/main.cpp
index 0b8eb57..0765ff5 100644
--- a/src/main/main.cpp
+++ b/src/main/main.cpp
@@ -284,6 +284,7 @@ int initialise(int argc, char **argv, bool &daemon) {
network::Server server(port, userLimit);
server.installSignalHandlers();
+ server.readMetagames("resources/metagames.xml");
ScriptMachine *machine = server.getMachine();
machine->acquireContext()->runFile("resources/main.js");
@@ -306,10 +307,11 @@ int initialise(int argc, char **argv, bool &daemon) {
}
registry->createDefaultDatabase();
-
+
server.initialiseWelcomeMessage(serverName, welcomeMessage);
server.initialiseChannels();
- server.initialiseMatchmaking("resources/metagames.xml");
+ server.initialiseMetagames();
+ server.initialiseMatchmaking();
server.initialiseClauses();
network::NetworkBattle::startTimerThread();
diff --git a/src/matchmaking/MetagameList.cpp b/src/matchmaking/MetagameList.cpp
index 6996072..9924331 100644
--- a/src/matchmaking/MetagameList.cpp
+++ b/src/matchmaking/MetagameList.cpp
@@ -48,36 +48,94 @@ struct Metagame::MetagameImpl {
string m_id;
int m_idx;
string m_description;
- int m_generation;
+ Generation *m_generation;
int m_partySize;
int m_maxTeamLength;
set m_banList;
+ set m_banListProto;
vector m_clauses;
network::TimerOptions m_timerOptions;
- void getMetagame(SpeciesDatabase *, DOMElement *);
+ void getMetagame(DOMElement *);
+
+ void initialise(SpeciesDatabase *species) {
+ set::iterator i = m_banListProto.begin();
+ for (; i != m_banListProto.end(); ++i) {
+ string name = *i;
+ const PokemonSpecies *p = species->getSpecies(name);
+ if (!p) {
+ Log::out() << "Unknown species: " << name << endl;
+ } else {
+ m_banList.insert(p->getSpeciesId());
+ }
+ }
+ }
+};
+
+struct Generation::GenerationImpl {
+ Generation *m_owner;
+ string m_id;
+ string m_name;
+ int m_idx;
+ vector m_metagames;
+
+ void getGeneration(DOMElement *);
+
+ void getMetagameClauses(const int idx, vector &ret) {
+ const int metagamesize = m_metagames.size();
+ if ((idx < 0) || (idx > metagamesize)) {
+ return;
+ }
+
+ MetagamePtr p = m_metagames[idx];
+ const vector &clauses = p->getClauses();
+ const int size = clauses.size();
+ for (int i = 0; i < size; ++i) {
+ ret.push_back(clauses[i]);
+ }
+ }
+
+ void getMetagameBans(const int idx, set &ret) {
+ const int metagameSize = m_metagames.size();
+ if ((idx < 0) || (idx > metagameSize)) {
+ return;
+ }
+
+ MetagamePtr p = m_metagames[idx];
+ const set &bans = p->getBanList();
+ set::const_iterator i = bans.begin();
+ for (; i != bans.end(); ++i) {
+ ret.insert(*i);
+ }
+ }
+
+ void initialiseMetagames(SpeciesDatabase *species) {
+ vector::iterator i = m_metagames.begin();
+ for (; i != m_metagames.end(); ++i) {
+ (*i)->initialise(species);
+ }
+ }
};
int getIntNodeValue(DOMNode *node);
string getStringNodeValue(DOMNode *node, bool text = false);
string getTextFromElement(DOMElement *element, bool text = false);
-void Metagame::MetagameImpl::getMetagame(SpeciesDatabase *species,
- DOMElement *node) {
+void Metagame::MetagameImpl::getMetagame(DOMElement *node) {
XMLCh tempStr[20];
+ XMLString::transcode("id", tempStr, 19);
+ DOMNode *p = node->getAttributes()->getNamedItem(tempStr);
+ if (p) {
+ m_id = getStringNodeValue(p);
+ }
+
XMLString::transcode("name", tempStr, 19);
DOMNodeList *list = node->getElementsByTagName(tempStr);
if (list->getLength() != 0) {
m_name = getTextFromElement((DOMElement *)list->item(0));
}
- XMLString::transcode("id", tempStr, 19);
- list = node->getElementsByTagName(tempStr);
- if (list->getLength() != 0) {
- m_id = getTextFromElement((DOMElement *)list->item(0));
- }
-
XMLString::transcode("description", tempStr, 19);
list = node->getElementsByTagName(tempStr);
if (list->getLength() != 0) {
@@ -108,12 +166,7 @@ void Metagame::MetagameImpl::getMetagame(SpeciesDatabase *species,
for (int i = 0; i < length; ++i) {
DOMElement *pokemon = (DOMElement *)list->item(i);
string txt = getTextFromElement(pokemon);
- const PokemonSpecies *p = species->getSpecies(txt);
- if (!p) {
- Log::out() << "Unknown species: " << txt << endl;
- } else {
- m_banList.insert(p->getSpeciesId());
- }
+ m_banListProto.insert(txt);
}
}
@@ -161,8 +214,39 @@ void Metagame::MetagameImpl::getMetagame(SpeciesDatabase *species,
m_timerOptions.periods = periods;
m_timerOptions.periodLength = periodLength;
}
+}
+
+void Generation::GenerationImpl::getGeneration(DOMElement *node) {
+ XMLCh tempStr[20];
+
+ XMLString::transcode("id", tempStr, 19);
+ DOMNode *p = node->getAttributes()->getNamedItem(tempStr);
+ if (p) {
+ m_id = getStringNodeValue(p);
+ }
- m_generation = GEN_PLATINUM; // TODO
+ XMLString::transcode("name", tempStr, 19);
+ DOMNodeList *list = node->getElementsByTagName(tempStr);
+ if (list->getLength() != 0) {
+ m_name = getTextFromElement((DOMElement *)list->item(0));
+ }
+
+ XMLString::transcode("metagames", tempStr, 19);
+ list = node->getElementsByTagName(tempStr);
+ if (list->getLength() != 0) {
+ DOMElement *metagames = (DOMElement *)list->item(0);
+ XMLString::transcode("metagame", tempStr, 19);
+ list = metagames->getElementsByTagName(tempStr);
+ const int length = list->getLength();
+ for (int i = 0; i < length; ++i) {
+ DOMElement *item = (DOMElement *)list->item(i);
+ MetagamePtr metagame(new Metagame());
+ metagame.get()->m_impl->getMetagame(item);
+ metagame.get()->m_impl->m_idx = i;
+ metagame.get()->m_impl->m_generation = m_owner;
+ m_metagames.push_back(metagame);
+ }
+ }
}
string Metagame::getName() const {
@@ -181,7 +265,7 @@ string Metagame::getDescription() const {
return m_impl->m_description;
}
-int Metagame::getGeneration() const {
+Generation *Metagame::getGeneration() const {
return m_impl->m_generation;
}
@@ -205,7 +289,17 @@ const network::TimerOptions &Metagame::getTimerOptions() const {
return m_impl->m_timerOptions;
}
-class MetagameErrorHandler : public HandlerBase {
+void Metagame::initialise(SpeciesDatabase *species) {
+ m_impl->initialise(species);
+}
+
+Metagame::Metagame():
+ m_impl(boost::shared_ptr(new MetagameImpl())) { }
+
+Generation::Generation():
+ m_impl(boost::shared_ptr(new GenerationImpl())) { }
+
+class GenerationErrorHandler : public HandlerBase {
void error(const SAXParseException& e) {
fatalError(e);
}
@@ -219,15 +313,12 @@ class MetagameErrorHandler : public HandlerBase {
}
};
-Metagame::Metagame():
- m_impl(boost::shared_ptr(new MetagameImpl())) { }
-
-void Metagame::readMetagames(const string &file, SpeciesDatabase *species,
- vector &metagames) {
+void Generation::readGenerations(const string &file,
+ vector &generations) {
XMLPlatformUtils::Initialize();
XercesDOMParser parser;
- MetagameErrorHandler handler;
+ GenerationErrorHandler handler;
parser.setErrorHandler(&handler);
parser.setEntityResolver(&handler);
@@ -237,18 +328,47 @@ void Metagame::readMetagames(const string &file, SpeciesDatabase *species,
DOMElement *root = doc->getDocumentElement();
XMLCh tempStr[12];
- XMLString::transcode("metagame", tempStr, 11);
+ XMLString::transcode("generation", tempStr, 11);
DOMNodeList *list = root->getElementsByTagName(tempStr);
int length = list->getLength();
for (int i = 0; i < length; ++i) {
DOMElement *item = (DOMElement *)list->item(i);
- MetagamePtr metagame(new Metagame());
- metagame.get()->m_impl->getMetagame(species, item);
- metagame.get()->m_impl->m_idx = i;
- metagames.push_back(metagame);
+ GenerationPtr generation(new Generation());
+ generation->m_impl->m_owner = generation.get();
+ generation->m_impl->getGeneration(item);
+ generation->m_impl->m_idx = i;
+ generations.push_back(generation);
}
}
+string Generation::getId() const {
+ return m_impl->m_id;
+}
+
+string Generation::getName() const {
+ return m_impl->m_name;
+}
+
+int Generation::getIdx() const {
+ return m_impl->m_idx;
+}
+
+const vector &Generation::getMetagames() const {
+ return m_impl->m_metagames;
+}
+
+void Generation::getMetagameClauses(const int meta, vector &clauses) {
+ m_impl->getMetagameClauses(meta, clauses);
+}
+
+void Generation::getMetagameBans(const int metagame, set &bans) {
+ m_impl->getMetagameBans(metagame, bans);
+}
+
+void Generation::initialiseMetagames(SpeciesDatabase *species) {
+ m_impl->initialiseMetagames(species);
+}
+
}
diff --git a/src/matchmaking/MetagameList.h b/src/matchmaking/MetagameList.h
index b9dc13a..abb09c8 100644
--- a/src/matchmaking/MetagameList.h
+++ b/src/matchmaking/MetagameList.h
@@ -33,32 +33,55 @@
namespace shoddybattle {
+class Generation;
class Metagame;
typedef boost::shared_ptr MetagamePtr;
+typedef boost::shared_ptr GenerationPtr;
class SpeciesDatabase;
class Metagame {
public:
- static void readMetagames(const std::string &, SpeciesDatabase *,
- std::vector &);
-
Metagame();
std::string getName() const;
std::string getId() const;
int getIdx() const;
std::string getDescription() const;
- int getGeneration() const;
+ Generation *getGeneration() const;
int getActivePartySize() const;
int getMaxTeamLength() const;
const std::set &getBanList() const;
const std::vector &getClauses() const;
const network::TimerOptions &getTimerOptions() const;
+ void initialise(SpeciesDatabase *);
+
private:
class MetagameImpl;
boost::shared_ptr m_impl;
+ friend class Generation;
+};
+
+class Generation {
+public:
+ static void readGenerations(const std::string &,
+ std::vector &);
+
+ Generation();
+
+ std::string getId() const;
+ std::string getName() const;
+ int getIdx() const;
+ const std::vector &getMetagames() const;
+ void getMetagameClauses(const int idx, std::vector &clauses);
+ void getMetagameBans(const int idx, std::set &bans);
+
+ void initialiseMetagames(SpeciesDatabase *);
+
+private:
+ class GenerationImpl;
+ boost::shared_ptr m_impl;
};
} // namespace shoddybattle
diff --git a/src/network/NetworkBattle.cpp b/src/network/NetworkBattle.cpp
index 2564eb4..ed5c3ac 100644
--- a/src/network/NetworkBattle.cpp
+++ b/src/network/NetworkBattle.cpp
@@ -668,6 +668,7 @@ struct NetworkBattleImpl {
* int32 : field id
* string : opponent
* byte : party
+ * byte : generation
* int16 : metagame (-1 for a direct challenge)
* byte : rated
* string : unique battle ID
@@ -678,6 +679,7 @@ struct NetworkBattleImpl {
OutMessage msg(OutMessage::BATTLE_BEGIN);
msg << id << opponent << ((unsigned char)party);
+ msg << (unsigned char)m_field->getGeneration()->getIdx();
msg << (int16_t)m_metagame;
msg << (unsigned char)m_rated;
msg << m_log->getId();
@@ -993,7 +995,7 @@ void NetworkBattle::terminate() {
NetworkBattle::NetworkBattle(Server *server,
ClientPtr *clients,
Pokemon::ARRAY *teams,
- const GENERATION generation,
+ Generation *generation,
const int partySize,
const int maxTeamLength,
vector &clauses,
@@ -1027,7 +1029,7 @@ NetworkBattle::NetworkBattle(Server *server,
// Encode some metadata into the channel topic.
const string topic = m_impl->m_trainer[0] + ","
+ m_impl->m_trainer[1] + ","
- + boost::lexical_cast(generation) + ","
+ + boost::lexical_cast(generation->getIdx()) + ","
+ boost::lexical_cast(partySize) + ","
+ boost::lexical_cast(maxTeamLength) + ","
+ boost::lexical_cast(metagame) + ","
@@ -1181,8 +1183,9 @@ void NetworkBattle::informVictory(const int party) {
m_impl->broadcast(msg.getMsg());
if (m_impl->m_rated) {
- m_impl->m_server->postLadderMatch(m_impl->m_metagame,
- m_impl->m_clients, party);
+ MetagamePtr meta = getGeneration()->getMetagames()[m_impl->m_metagame];
+ string ladder = meta->getId();
+ m_impl->m_server->postLadderMatch(ladder, m_impl->m_clients, party);
}
// terminate this battle
diff --git a/src/network/NetworkBattle.h b/src/network/NetworkBattle.h
index c362039..e049882 100644
--- a/src/network/NetworkBattle.h
+++ b/src/network/NetworkBattle.h
@@ -53,7 +53,7 @@ class NetworkBattle : public BattleField,
NetworkBattle(Server *server,
boost::shared_ptr *clients,
Pokemon::ARRAY *teams,
- const GENERATION generation,
+ Generation *generation,
const int partySize,
const int maxTeamLength,
std::vector &clauses,
diff --git a/src/network/network.cpp b/src/network/network.cpp
index ad683fe..dfd64fb 100644
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -435,7 +435,7 @@ void readTeam(SpeciesDatabase *speciesData,
struct Challenge {
mutex mx;
Pokemon::ARRAY teams[TEAM_COUNT];
- GENERATION generation;
+ int generation;
int partySize;
int teamLength;
int metagame;
@@ -601,18 +601,21 @@ class MetagameQueue {
typedef pair QUEUE_ENTRY;
typedef variate_generator > GENERATOR;
- MetagameQueue(MetagamePtr metagame, bool rated, ServerImpl *server):
+ MetagameQueue(int generation, int metagame, bool rated, ServerImpl *server):
+ m_generation(generation),
m_metagame(metagame),
m_rated(rated),
m_server(server),
m_rand(mt11213b(time(NULL))) { }
-
+
+ MetagamePtr getMetagame();
bool queueClient(ClientImplPtr, Pokemon::ARRAY &);
void removeClient(ClientImplPtr);
void startMatches();
private:
- MetagamePtr m_metagame;
+ int m_generation;
+ int m_metagame;
bool m_rated;
CLIENT_LIST m_clients;
vector m_queue;
@@ -623,7 +626,8 @@ class MetagameQueue {
};
typedef shared_ptr MetagameQueuePtr;
-typedef pair METAGAME_PAIR;
+typedef pair METAGAME;
+typedef pair METAGAME_PAIR;
typedef pair CLAUSE_PAIR;
class ServerImpl {
@@ -635,10 +639,15 @@ class ServerImpl {
void stop();
void removeClient(ClientImplPtr client);
void broadcast(const OutMessage &msg);
+
+ void readMetagames(const string &);
+ void initialiseMetagames();
+
void initialiseWelcomeMessage(const std::string &, const std::string &);
void initialiseChannels();
- void initialiseMatchmaking(const string &);
+ void initialiseMatchmaking();
void initialiseClauses();
+
bool validateTeam(ScriptContextPtr, Pokemon::ARRAY &,
vector &, vector &, const set &);
database::DatabaseRegistry *getRegistry() { return &m_registry; }
@@ -646,24 +655,27 @@ class ServerImpl {
ChannelPtr getMainChannel() const { return m_mainChannel; }
void sendChannelList(ClientImplPtr client);
void sendMetagameList(ClientImplPtr client);
- void getMetagameClauses(const int metagame, vector &clauses);
- const vector &getMetagames() const { return m_metagames; }
+ const vector &getGenerations() const {
+ return m_generations;
+ }
void sendClauseList(ClientImplPtr client);
- void fetchClauses(ScriptContextPtr scx, vector &clauses,
- vector &ret);
- void fetchClauses(ScriptContextPtr scx, const int metagame,
- vector &ret);
- void getMetagameBans(const int metagame, set &bans);
+ void fetchClauses(ScriptContextPtr scx, vector &clauses,
+ vector &ret);
+ void fetchClauses(ScriptContextPtr scx, MetagamePtr metagame,
+ vector &ret);
+ void fetchClauses(ScriptContextPtr scx, const int metagame,
+ const int generation, vector &ret);
ChannelPtr getChannel(const string &);
ClientImplPtr getClient(const string &);
bool authenticateClient(ClientImplPtr client);
void addChannel(ChannelPtr);
void removeChannel(ChannelPtr);
- MetagameQueuePtr getMetagameQueue(const int metagame, const bool rated) {
- return m_queues[METAGAME_PAIR(metagame, rated)];
+ MetagameQueuePtr getMetagameQueue(const int generation, const int metagame,
+ const bool rated) {
+ return m_queues[METAGAME_PAIR(METAGAME(generation, metagame), rated)];
}
- void postLadderMatch(const int, vector &, const int);
+ void postLadderMatch(const string &, vector &, const int);
bool commitBan(const int, const string &, const int, const int,
const bool = false);
void commitPersonalMessage(const string& user, const string& msg);
@@ -685,7 +697,7 @@ class ServerImpl {
class MetagameList : public OutMessage {
public:
- MetagameList(const vector &);
+ MetagameList(const vector &);
};
class ClauseList : public OutMessage {
@@ -704,7 +716,7 @@ class ServerImpl {
tcp::acceptor m_acceptor;
database::DatabaseRegistry m_registry;
ScriptMachine m_machine;
- vector m_metagames;
+ vector m_generations;
map m_queues;
thread m_matchmaking;
thread m_phantomClientWorker;
@@ -739,6 +751,14 @@ ScriptMachine *Server::getMachine() {
return m_impl->getMachine();
}
+void Server::readMetagames(const string &file) {
+ m_impl->readMetagames(file);
+}
+
+void Server::initialiseMetagames() {
+ m_impl->initialiseMetagames();
+}
+
void Server::initialiseWelcomeMessage(const string &name,
const string &welcome) {
m_impl->initialiseWelcomeMessage(name, welcome);
@@ -748,8 +768,8 @@ void Server::initialiseChannels() {
m_impl->initialiseChannels();
}
-void Server::initialiseMatchmaking(const string &file) {
- m_impl->initialiseMatchmaking(file);
+void Server::initialiseMatchmaking() {
+ m_impl->initialiseMatchmaking();
}
void Server::initialiseClauses() {
@@ -1141,17 +1161,25 @@ class ClientImpl : public Client, public enable_shared_from_this {
int teamLength;
msg >> opponent >> generation >> partySize >> teamLength;
int metagame;
- msg >> metagame;
+ msg >> metagame;
// Check for bad challenge info
- const vector &metagames = m_server->getMetagames();
- const int metagameCount = metagames.size();
- if ((partySize < 1) || (teamLength < 1) || (metagame < -1) ||
- (metagame >= metagameCount)) {
+ const vector &generations = m_server->getGenerations();
+ const int generationCount = generations.size();
+ if ((generation >= generationCount) || (partySize < 1) ||
+ (teamLength < 1)) {
sendMessage(ErrorMessage(ErrorMessage::BAD_CHALLENGE, opponent));
return;
}
+ GenerationPtr gen = generations[generation];
+ const vector &metagames = gen->getMetagames();
+ const int metagameCount = metagames.size();
+ if ((metagame < -1) || (metagame >= metagameCount)) {
+ sendMessage(ErrorMessage(ErrorMessage::BAD_CHALLENGE, opponent));
+ return;
+ }
+
if (metagame == -1) {
unsigned char clauseCount;
msg >> clauseCount;
@@ -1180,11 +1208,11 @@ class ClientImpl : public Client, public enable_shared_from_this {
}
}
- challenge->generation = (GENERATION)generation;
+ challenge->generation = generation;
challenge->partySize = partySize;
challenge->teamLength = teamLength;
challenge->metagame = metagame;
-
+
lock_guard lock(m_challengeMutex);
@@ -1239,15 +1267,17 @@ class ClientImpl : public Client, public enable_shared_from_this {
// created - ScriptContextLock is necessary!!
ScriptContextLock cxLock(cx);
vector clauses;
+ int generation = challenge->generation;
int metagame = challenge->metagame;
if (metagame == -1) {
m_server->fetchClauses(cx, challenge->clauses, clauses);
} else {
- m_server->fetchClauses(cx, metagame, clauses);
+ m_server->fetchClauses(cx, generation, metagame, clauses);
}
set bans;
- m_server->getMetagameBans(metagame, bans);
+ GenerationPtr gen = m_server->getGenerations()[generation];
+ gen->getMetagameBans(metagame, bans);
vector violations;
if (!m_server->validateTeam(cx, team, clauses, violations, bans)) {
@@ -1273,13 +1303,16 @@ class ClientImpl : public Client, public enable_shared_from_this {
if (!client) {
return;
}
+
ChallengePtr challenge = m_challenges[opponent];
-
unique_lock lock2(challenge->mx);
if (challenge->teams[1].empty()) {
return;
}
-
+
+ const vector &generations = m_server->getGenerations();
+ GenerationPtr generation = generations[challenge->generation];
+
ScriptMachine *machine = m_server->getMachine();
readTeam(machine->getSpeciesDatabase(),
machine->getMoveDatabase(),
@@ -1296,15 +1329,16 @@ class ClientImpl : public Client, public enable_shared_from_this {
// created - ScriptContextLock is necessary!!
ScriptContextLock cxLock(cx);
vector clauses;
+ int generationId = challenge->generation;
int metagame = challenge->metagame;
if (metagame == -1) {
m_server->fetchClauses(cx, challenge->clauses, clauses);
} else {
- m_server->fetchClauses(cx, metagame, clauses);
+ m_server->fetchClauses(cx, generationId, metagame, clauses);
}
set bans;
- m_server->getMetagameBans(metagame, bans);
+ generation->getMetagameBans(metagame, bans);
vector violations;
if (!m_server->validateTeam(cx, challenge->teams[0], clauses,
@@ -1316,7 +1350,7 @@ class ClientImpl : public Client, public enable_shared_from_this {
TimerOptions timerOpts = TimerOptions();
bool validMetagame = false;
if (metagame >= 0) {
- const vector &metagames = m_server->getMetagames();
+ const vector &metagames = generation->getMetagames();
const int size = metagames.size();
if (metagame >= size) {
validMetagame = false;
@@ -1337,7 +1371,7 @@ class ClientImpl : public Client, public enable_shared_from_this {
NetworkBattle::PTR field(new NetworkBattle(m_server->getServer(),
clients,
challenge->teams,
- challenge->generation,
+ generation.get(),
challenge->partySize,
challenge->teamLength,
clauses,
@@ -1414,15 +1448,18 @@ class ClientImpl : public Client, public enable_shared_from_this {
}
/**
+ * byte : generation id
* byte : metagame id
* byte : rated
* team : the pokemon team to queue
*/
void handleQueueTeam(InMessage &msg) {
+ unsigned char generation;
unsigned char metagame;
unsigned char rated;
- msg >> metagame >> rated;
- MetagameQueuePtr queue = m_server->getMetagameQueue(metagame, rated);
+ msg >> generation >> metagame >> rated;
+ MetagameQueuePtr queue = m_server->getMetagameQueue(generation,
+ metagame, rated);
if (!queue) {
return;
}
@@ -1450,9 +1487,9 @@ class ClientImpl : public Client, public enable_shared_from_this {
ClientImplPtr client = m_server->getClient(user);
if (client) {
const int id = client->getId();
- const vector &metagames = m_server->getMetagames();
+ const vector &gens = m_server->getGenerations();
database::DatabaseRegistry::ESTIMATE_LIST estimates =
- m_server->getRegistry()->getEstimates(id, metagames);
+ m_server->getRegistry()->getEstimates(id, gens);
sendMessage(UserPersonalMessage(user, client->getPersonalMessage(),
estimates));
}
@@ -1463,10 +1500,12 @@ class ClientImpl : public Client, public enable_shared_from_this {
}
void handleCancelQueue(InMessage &msg) {
+ unsigned char generation;
unsigned char metagame;
unsigned char rated;
- msg >> metagame >> rated;
- MetagameQueuePtr queue = m_server->getMetagameQueue(metagame, rated);
+ msg >> generation >> metagame >> rated;
+ MetagameQueuePtr queue = m_server->getMetagameQueue(generation,
+ metagame, rated);
if (!queue) {
return;
}
@@ -1854,24 +1893,31 @@ bool ServerImpl::commitBan(const int channel, const string &user,
return m_registry.setBan(channel, user, bannerId, date, ipBan);
}
-void ServerImpl::postLadderMatch(const int metagame,
+void ServerImpl::postLadderMatch(const string &ladder,
vector &clients, const int victor) {
ClientImpl *impl0 = dynamic_cast(clients[0].get());
ClientImpl *impl1 = dynamic_cast(clients[1].get());
if (!impl0 || !impl1)
return;
- const string ladder = m_metagames[metagame]->getId();
m_registry.postLadderMatch(ladder, impl0->getId(), impl1->getId(), victor);
impl0->updateLadderStats(ladder);
impl1->updateLadderStats(ladder);
}
+MetagamePtr MetagameQueue::getMetagame() {
+ const vector &generations = m_server->getGenerations();
+ GenerationPtr generation = generations[m_generation];
+ return generation->getMetagames()[m_metagame];
+}
+
bool MetagameQueue::queueClient(ClientImplPtr client, Pokemon::ARRAY &team) {
lock_guard lock(m_mutex);
if (m_clients.find(client) != m_clients.end())
return false;
+
+ MetagamePtr metagame = getMetagame();
const int size = team.size();
- if (size > m_metagame->getMaxTeamLength())
+ if (size > metagame->getMaxTeamLength())
return false;
ScriptContextPtr scx = m_server->getMachine()->acquireContext();
@@ -1879,15 +1925,15 @@ bool MetagameQueue::queueClient(ClientImplPtr client, Pokemon::ARRAY &team) {
// created - ScriptContextLock is necessary!!
ScriptContextLock cxLock(scx);
vector clauses;
- m_server->fetchClauses(scx, m_metagame->getIdx(), clauses);
+ m_server->fetchClauses(scx, metagame, clauses);
vector violations;
if (!m_server->validateTeam(scx, team, clauses, violations,
- m_metagame->getBanList())) {
+ metagame->getBanList())) {
client->sendMessage(InvalidTeamMessage(string(), size, violations));
return false;
}
if (m_rated) {
- client->joinLadder(m_metagame->getId());
+ client->joinLadder(metagame->getId());
}
m_clients.insert(client);
m_queue.push_back(QUEUE_ENTRY(client, team));
@@ -1916,7 +1962,9 @@ void MetagameQueue::startMatches() {
GENERATOR generator(m_rand, uniform_int<>());
random_shuffle(m_queue.begin(), m_queue.end(), generator);
}
+
// TODO: Use the generations map to prevent rematches.
+ MetagamePtr metagame = getMetagame();
QUEUE_ENTRY remainder;
int size = m_queue.size();
const bool hasRemainder = size % 2;
@@ -1930,18 +1978,19 @@ void MetagameQueue::startMatches() {
ClientPtr clients[] = { q1.first, q2.first };
Pokemon::ARRAY teams[] = { q1.second, q2.second };
vector clauses;
- m_server->fetchClauses(m_server->getMachine()->acquireContext(),
- m_metagame->getIdx(), clauses);
+ m_server->fetchClauses(m_server->getMachine()->acquireContext(),
+ metagame, clauses);
shared_ptr monitor;
- NetworkBattle::PTR field(new NetworkBattle(m_server->getServer(),
+ NetworkBattle::PTR field(new NetworkBattle(
+ m_server->getServer(),
clients,
teams,
- (GENERATION)m_metagame->getGeneration(),
- m_metagame->getActivePartySize(),
- m_metagame->getMaxTeamLength(),
+ metagame->getGeneration(),
+ metagame->getActivePartySize(),
+ metagame->getMaxTeamLength(),
clauses,
- m_metagame->getTimerOptions(),
- m_metagame->getIdx(),
+ metagame->getTimerOptions(),
+ metagame->getIdx(),
m_rated,
monitor));
field->beginBattle();
@@ -1965,18 +2014,6 @@ void ServerImpl::sendMetagameList(ClientImplPtr client) {
client->sendMessage(*m_metagameList);
}
-void ServerImpl::getMetagameClauses(const int idx, vector &ret) {
- const int metagamesize = m_metagames.size();
- if ((idx < 0) || (idx > metagamesize))
- return;
- MetagamePtr p = m_metagames[idx];
- const vector &clauses = p->getClauses();
- const int size = clauses.size();
- for (int i = 0; i < size; ++i) {
- ret.push_back(clauses[i]);
- }
-}
-
void ServerImpl::sendClauseList(ClientImplPtr client) {
client->sendMessage(ClauseList(m_clauses));
}
@@ -1994,27 +2031,20 @@ void ServerImpl::fetchClauses(ScriptContextPtr scx, vector &clauses,
}
}
-void ServerImpl::fetchClauses(ScriptContextPtr scx, const int metagame,
- vector &ret) {
- vector clauses;
- getMetagameClauses(metagame, clauses);
- vector::iterator i = clauses.begin();
+void ServerImpl::fetchClauses(ScriptContextPtr scx, MetagamePtr metagame,
+ vector &ret) {
+ const vector &clauses = metagame->getClauses();
+ vector::const_iterator i = clauses.begin();
for (; i != clauses.end(); ++i) {
ret.push_back(scx->getClause(*i));
}
}
-void ServerImpl::getMetagameBans(const int metagame, set &ret) {
- const int metagameSize = m_metagames.size();
- if ((metagame < 0) || (metagame > metagameSize)) {
- return;
- }
- MetagamePtr p = m_metagames[metagame];
- const set &bans = p->getBanList();
- set::const_iterator i = bans.begin();
- for (; i != bans.end(); ++i) {
- ret.insert(*i);
- }
+void ServerImpl::fetchClauses(ScriptContextPtr scx, const int generation,
+ const int metagame, vector &ret) {
+ GenerationPtr gen = m_generations[generation];
+ MetagamePtr meta = gen->getMetagames()[metagame];
+ fetchClauses(scx, meta, ret);
}
void ServerImpl::addChannel(ChannelPtr p) {
@@ -2035,9 +2065,9 @@ void Server::removeChannel(ChannelPtr p) {
m_impl->removeChannel(p);
}
-void Server::postLadderMatch(const int metagame,
- vector &clients, const int victor) {
- m_impl->postLadderMatch(metagame, clients, victor);
+void Server::postLadderMatch(const string &ladder, vector &clients,
+ const int victor) {
+ m_impl->postLadderMatch(ladder, clients, victor);
}
ServerImpl::ChannelList::ChannelList(ServerImpl *server):
@@ -2055,38 +2085,47 @@ ServerImpl::ChannelList::ChannelList(ServerImpl *server):
finalise();
}
-ServerImpl::MetagameList::MetagameList(const vector &metagames):
- OutMessage(METAGAME_LIST) {
- const int size = metagames.size();
- *this << (int16_t)size;
- for (int i = 0; i < size; ++i) {
- MetagamePtr p = metagames[i];
- *this << (unsigned char)p->getIdx();
- *this << p->getName();
- *this << p->getId();
- *this << p->getDescription();
- *this << (unsigned char)p->getActivePartySize();
- *this << (unsigned char)p->getMaxTeamLength();
- const set &banList = p->getBanList();
- *this << (int16_t)banList.size();
- set::const_iterator j = banList.begin();
- for (; j != banList.end(); ++j) {
- *this << (int16_t)(*j);
- }
- const vector &clauses = p->getClauses();
- const int size2 = clauses.size();
- *this << (int16_t)size2;
- for (int k = 0; k < size2; ++k) {
- *this << clauses[k];
- }
- const TimerOptions ops = p->getTimerOptions();
- if (ops.enabled) {
- *this << (unsigned char)1;
- *this << (int16_t)ops.pool;
- *this << (unsigned char)ops.periods;
- *this << (int16_t)ops.periodLength;
- } else {
- *this << (unsigned char)0;
+ServerImpl::MetagameList::MetagameList(const vector
+ &generations): OutMessage(METAGAME_LIST) {
+ *this << (unsigned char)generations.size();
+
+ vector::const_iterator i = generations.begin();
+ for (; i != generations.end(); ++i) {
+ GenerationPtr generation = *i;
+ const vector &metagames = generation->getMetagames();
+ *this << generation->getId();
+ *this << generation->getName();
+ *this << (unsigned char)metagames.size();
+
+ vector::const_iterator j = metagames.begin();
+ for (; j != metagames.end(); ++j) {
+ MetagamePtr p = *j;
+ *this << p->getId();
+ *this << p->getName();
+ *this << p->getDescription();
+ *this << (unsigned char)p->getActivePartySize();
+ *this << (unsigned char)p->getMaxTeamLength();
+ const set &banList = p->getBanList();
+ *this << (int16_t)banList.size();
+ set::const_iterator j = banList.begin();
+ for (; j != banList.end(); ++j) {
+ *this << (int16_t)(*j);
+ }
+ const vector &clauses = p->getClauses();
+ const int size2 = clauses.size();
+ *this << (int16_t)size2;
+ for (int k = 0; k < size2; ++k) {
+ *this << clauses[k];
+ }
+ const TimerOptions ops = p->getTimerOptions();
+ if (ops.enabled) {
+ *this << (unsigned char)1;
+ *this << (int16_t)ops.pool;
+ *this << (unsigned char)ops.periods;
+ *this << (int16_t)ops.periodLength;
+ } else {
+ *this << (unsigned char)0;
+ }
}
}
finalise();
@@ -2162,6 +2201,18 @@ ChannelPtr ServerImpl::getChannel(const string &name) {
return ChannelPtr();
}
+void ServerImpl::readMetagames(const string& file) {
+ Generation::readGenerations(file, m_generations);
+}
+
+void ServerImpl::initialiseMetagames() {
+ SpeciesDatabase *species = m_machine.getSpeciesDatabase();
+ vector::iterator i = m_generations.begin();
+ for (; i != m_generations.end(); ++i) {
+ (*i)->initialiseMetagames(species);
+ }
+}
+
void ServerImpl::initialiseWelcomeMessage(const string &name,
const string &welcome) {
shared_ptr auth = m_registry.getAuthenticator();
@@ -2198,21 +2249,28 @@ void ServerImpl::initialiseChannels() {
assert(m_mainChannel);
}
-void ServerImpl::initialiseMatchmaking(const string &file) {
- SpeciesDatabase *species = m_machine.getSpeciesDatabase();
- Metagame::readMetagames(file, species, m_metagames);
- vector::const_iterator i = m_metagames.begin();
- for (; i != m_metagames.end(); ++i) {
- m_registry.initialiseLadder((*i)->getId());
- const int idx = (*i)->getIdx();
- // rated queue
- m_queues[METAGAME_PAIR(idx, true)] =
- MetagameQueuePtr(new MetagameQueue(*i, true, this));
- // unrated queue
- m_queues[METAGAME_PAIR(idx, false)] =
- MetagameQueuePtr(new MetagameQueue(*i, false, this));
- }
- m_metagameList = shared_ptr(new MetagameList(m_metagames));
+void ServerImpl::initialiseMatchmaking() {
+ vector::const_iterator i = m_generations.begin();
+ for (; i != m_generations.end(); ++i) {
+ GenerationPtr generation = *i;
+ const vector &metagames = generation->getMetagames();
+ vector::const_iterator j = metagames.begin();
+ for (; j != metagames.end(); ++j) {
+ m_registry.initialiseLadder((*j)->getId());
+
+ int genIdx = generation->getIdx();
+ int metaIdx = (*j)->getIdx();
+ METAGAME meta(genIdx, metaIdx);
+ // rated queue
+ m_queues[METAGAME_PAIR(meta, true)] = MetagameQueuePtr(
+ new MetagameQueue(genIdx, metaIdx, true, this));
+ // unrated queue
+ m_queues[METAGAME_PAIR(meta, false)] = MetagameQueuePtr(
+ new MetagameQueue(genIdx, metaIdx, false, this));
+ }
+ }
+
+ m_metagameList = shared_ptr(new MetagameList(m_generations));
m_matchmaking = thread(boost::bind(&ServerImpl::handleMatchmaking, this));
}
@@ -2283,7 +2341,7 @@ bool ServerImpl::validateTeam(ScriptContextPtr scx, Pokemon::ARRAY &team,
void ServerImpl::handleMatchmaking() {
while (true) {
this_thread::sleep(posix_time::seconds(15));
- map, MetagameQueuePtr>::iterator i = m_queues.begin();
+ map::iterator i = m_queues.begin();
for (; i != m_queues.end(); ++i) {
i->second->startMatches();
}
@@ -2347,7 +2405,7 @@ void ServerImpl::stop() {
*/
void ServerImpl::removeClient(ClientImplPtr client) {
// Remove the client from any metagame queues that the client may be in.
- map, MetagameQueuePtr>::iterator i = m_queues.begin();
+ map::iterator i = m_queues.begin();
for (; i != m_queues.end(); ++i) {
i->second->removeClient(client);
}
diff --git a/src/network/network.h b/src/network/network.h
index 6e7d656..3781096 100644
--- a/src/network/network.h
+++ b/src/network/network.h
@@ -74,14 +74,17 @@ class Server {
void run();
database::DatabaseRegistry *getRegistry();
ScriptMachine *getMachine();
+ void readMetagames(const std::string &);
+ void initialiseMetagames();
void initialiseWelcomeMessage(const std::string &, const std::string &);
void initialiseChannels();
- void initialiseMatchmaking(const std::string &);
+ void initialiseMatchmaking();
void initialiseClauses();
boost::shared_ptr getMainChannel() const;
void addChannel(boost::shared_ptr);
void removeChannel(boost::shared_ptr);
- void postLadderMatch(const int, std::vector &, const int);
+ void postLadderMatch(const std::string &, std::vector &,
+ const int);
bool commitBan(const int, const std::string &, const int, const int);
private:
diff --git a/src/scripting/FieldObject.cpp b/src/scripting/FieldObject.cpp
index 95ff8fa..f3577e6 100644
--- a/src/scripting/FieldObject.cpp
+++ b/src/scripting/FieldObject.cpp
@@ -54,6 +54,7 @@ JSClass fieldClass = {
enum FIELD_TINYID {
FTI_GENERATION,
+ FTI_GENERATION_ID,
FTI_LAST_MOVE,
FTI_PARTY_SIZE,
FTI_NARRATION,
@@ -580,7 +581,14 @@ JSBool fieldGet(JSContext *cx, JSObject *obj, jsval id, jsval *vp) {
int tid = JSVAL_TO_INT(id);
switch (tid) {
case FTI_GENERATION: {
- *vp = INT_TO_JSVAL(p->getGeneration());
+ *vp = INT_TO_JSVAL(0);
+ // TODO: Return the actual object itself
+ } break;
+ case FTI_GENERATION_ID: {
+ string id = p->getGeneration()->getId();
+ char *pstr = JS_strdup(cx, id.c_str());
+ JSString *str = JS_NewString(cx, pstr, id.length());
+ *vp = STRING_TO_JSVAL(str);
} break;
case FTI_LAST_MOVE: {
MoveObjectPtr move = p->getLastMove();
@@ -622,6 +630,7 @@ JSBool fieldGet(JSContext *cx, JSObject *obj, jsval id, jsval *vp) {
JSPropertySpec fieldProperties[] = {
{ "damage", 0, JSPROP_PERMANENT, NULL, NULL },
{ "generation", FTI_GENERATION, JSPROP_PERMANENT | JSPROP_SHARED, fieldGet, NULL },
+ { "generationId", FTI_GENERATION_ID, JSPROP_PERMANENT | JSPROP_SHARED, fieldGet, NULL },
{ "lastMove", FTI_LAST_MOVE, JSPROP_PERMANENT | JSPROP_SHARED, fieldGet, NULL },
{ "partySize", FTI_PARTY_SIZE, JSPROP_PERMANENT | JSPROP_SHARED, fieldGet, NULL },
{ "narration", FTI_NARRATION, JSPROP_PERMANENT | JSPROP_SHARED, fieldGet, fieldSet },
diff --git a/src/shoddybattle/BattleField.cpp b/src/shoddybattle/BattleField.cpp
index d095db8..a21543a 100644
--- a/src/shoddybattle/BattleField.cpp
+++ b/src/shoddybattle/BattleField.cpp
@@ -41,7 +41,7 @@ namespace shoddybattle {
struct BattleFieldImpl {
FieldObjectPtr object;
const BattleMechanics *mech;
- GENERATION generation;
+ Generation *generation;
ScriptMachine *machine;
ScriptContext *context;
ScriptContextPtr contextRef;
@@ -105,7 +105,7 @@ struct BattleFieldImpl {
void initialise(BattleField *field,
const BattleMechanics *mech,
- GENERATION generation,
+ Generation *generation,
ScriptMachine *machine,
Pokemon::ARRAY teams[TEAM_COUNT],
const std::string trainer[TEAM_COUNT],
@@ -163,7 +163,7 @@ void BattleField::popExecution() {
m_impl->executing.pop();
}
-GENERATION BattleField::getGeneration() const {
+Generation *BattleField::getGeneration() const {
return m_impl->generation;
}
@@ -1358,7 +1358,7 @@ ScriptContext *BattleField::getContext() {
}
void BattleField::initialise(const BattleMechanics *mech,
- GENERATION generation,
+ Generation *generation,
ScriptMachine *machine,
Pokemon::ARRAY teams[TEAM_COUNT],
const std::string trainer[TEAM_COUNT],
@@ -1375,7 +1375,7 @@ void BattleField::initialise(const BattleMechanics *mech,
void BattleFieldImpl::initialise(BattleField *field,
const BattleMechanics *mech,
- GENERATION generation,
+ Generation *generation,
ScriptMachine *machine,
Pokemon::ARRAY teams[TEAM_COUNT],
const std::string trainer[TEAM_COUNT],
diff --git a/src/shoddybattle/BattleField.h b/src/shoddybattle/BattleField.h
index cc879bb..acd1ca3 100644
--- a/src/shoddybattle/BattleField.h
+++ b/src/shoddybattle/BattleField.h
@@ -30,17 +30,13 @@
#include
#include
#include "Pokemon.h"
+#include "../matchmaking/MetagameList.h"
#include "../scripting/ObjectWrapper.h"
namespace shoddybattle {
const int TEAM_COUNT = 2;
-enum GENERATION {
- GEN_DP, // Diamond and Pearl
- GEN_PLATINUM, // Platinum
-};
-
class BattleFieldImpl;
class PokemonSlotImpl;
@@ -147,7 +143,7 @@ class BattleField : public ObjectWrapper {
* no equilvalent mode in the real game.
*/
void initialise(const BattleMechanics *mech,
- const GENERATION,
+ Generation *,
ScriptMachine *machine,
Pokemon::ARRAY teams[TEAM_COUNT],
const std::string trainer[TEAM_COUNT],
@@ -365,7 +361,7 @@ class BattleField : public ObjectWrapper {
ScriptObject *getObject();
- GENERATION getGeneration() const;
+ Generation *getGeneration() const;
/**
* Begin the battle.