Files
wagic/projects/mtg/src/MTGDeck.cpp

1165 lines
31 KiB
C++

#include "PrecompiledHeader.h"
#include "MTGDeck.h"
#include "utils.h"
#include "Subtypes.h"
#include "Translate.h"
#include "DeckMetaData.h"
#include "PriceList.h"
#include "WDataSrc.h"
#include "MTGPack.h"
#include "utils.h"
#if defined (WIN32) || defined (LINUX)
#include <time.h>
#endif
static inline int getGrade(int v)
{
switch (v)
{
case 'P':
case 'p':
return Constants::GRADE_SUPPORTED;
case 'R':
case 'r':
return Constants::GRADE_BORDERLINE;
case 'O':
case 'o':
return Constants::GRADE_UNOFFICIAL;
case 'A':
case 'a':
return Constants::GRADE_CRAPPY;
case 'S':
case 's':
return Constants::GRADE_UNSUPPORTED;
case 'N':
case 'n':
return Constants::GRADE_DANGEROUS;
}
return 0;
}
//MTGAllCards
int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primitive)
{
if ('#' == s[0]) return 0;
size_t i = s.find_first_of('=');
if (i == string::npos || 0 == i)
{
DebugTrace("MTGDECK: Bad Line:\n\t" << s);
return 0;
}
char* key = const_cast<char*> (s.c_str()); // I know what I'm doing, let me do it
key[i] = 0;
char* val = key + i + 1;
switch (key[0])
{
case 'a':
if (0 == strcmp("auto", key))
{
if (!primitive) primitive = NEW CardPrimitive();
primitive->addMagicText(val);
}
else if (0 == strncmp("auto", key, 4))
{
if (!primitive) primitive = NEW CardPrimitive();
primitive->addMagicText(val, key + 4);
}
else if (0 == strcmp("alias", key))
{
if (!primitive) primitive = NEW CardPrimitive();
primitive->alias = atoi(val);
}
else if (0 == strcmp("abilities", key))
{
if (!primitive) primitive = NEW CardPrimitive();
string value = val;
//Specific Abilities
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
while (value.size())
{
string attribute;
size_t found2 = value.find(',');
if (found2 != string::npos)
{
attribute = value.substr(0, found2);
value = value.substr(found2 + 1);
}
else
{
attribute = value;
value = "";
}
for (int j = Constants::NB_BASIC_ABILITIES - 1; j >= 0; --j)
{
size_t found = attribute.find(Constants::MTGBasicAbilities[j]);
if (found != string::npos)
{
primitive->basicAbilities[j] = 1;
break;
}
}
}
}
break;
case 'c': //color
if (!primitive) primitive = NEW CardPrimitive();
{
string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
vector<string> values = split(value, ',');
int removeAllOthers = 1;
for (size_t values_i = 0; values_i < values.size(); ++values_i)
{
primitive->setColor(values[values_i], removeAllOthers);
removeAllOthers = 0;
}
}
break;
case 'g': //grade
if (s.size() - i - 1 > 2) currentGrade = getGrade(val[2]);
break;
case 'k': //kicker
if (!primitive) primitive = NEW CardPrimitive();
if (ManaCost * cost = primitive->getManaCost())
{
string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
cost->kicker = ManaCost::parseManaCost(value);
}
break;
case 'o': //othercost
if (!primitive) primitive = NEW CardPrimitive();
if (ManaCost * cost = primitive->getManaCost())
{
string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
cost->alternative = ManaCost::parseManaCost(value);
}
break;
case 'b': //buyback
if (!primitive) primitive = NEW CardPrimitive();
if (ManaCost * cost = primitive->getManaCost())
{
string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
cost->BuyBack = ManaCost::parseManaCost(value);
}
break;
case 'f': //flashback
if (!primitive) primitive = NEW CardPrimitive();
if (ManaCost * cost = primitive->getManaCost())
{
string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
cost->FlashBack = ManaCost::parseManaCost(value);
}
break;
case 'i': //id
if (!card) card = NEW MTGCard();
card->setMTGId(atoi(val));
break;
case 'm': //mana
if (!primitive) primitive = NEW CardPrimitive();
{
string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
primitive->setManaCost(value);
}
break;
case 'n': //name
if (!primitive) primitive = NEW CardPrimitive();
if (0 == strcmp("Bloodrock Cyclops", val)) cout << "val" << endl;
primitive->setName(val);
break;
case 'p':
if ('r' == key[1])
{ // primitive
if (!card) card = NEW MTGCard();
map<string, CardPrimitive*>::iterator it = primitives.find(val);
if (it != primitives.end()) card->setPrimitive(it->second);
}
else
{ //power
if (!primitive) primitive = NEW CardPrimitive();
primitive->setPower(atoi(val));
}
break;
case 'r': //retrace/rarity
if ('e' == key[1])
{ //retrace
if (!primitive) primitive = NEW CardPrimitive();
if (ManaCost * cost = primitive->getManaCost())
{
string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
cost->Retrace = ManaCost::parseManaCost(value);
}
}
else
{//rarity
if (!card) card = NEW MTGCard();
card->setRarity(val[0]);
}
break;
case 's': //subtype
if (!primitive) primitive = NEW CardPrimitive();
while (true)
{
char* found = strchr(val, ' ');
if (found)
{
string value(val, found - val);
primitive->setSubtype(value);
val = found + 1;
}
else
{
primitive->setSubtype(val);
break;
}
}
break;
case 't':
if (!primitive) primitive = NEW CardPrimitive();
if (0 == strcmp("target", key))
{
string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
primitive->spellTargetType = value;
}
else if (0 == strcmp("text", key))
primitive->setText(val);
else if (0 == strcmp("type", key))
{
while (true)
{
char* found = strchr(val, ' ');
if (found)
{
string value(val, found - val);
primitive->setType(value);
val = found + 1;
}
else
{
primitive->setType(val);
break;
}
}
}
else if (0 == strcmp("toughness", key)) primitive->setToughness(atoi(val));
break;
default:
DebugTrace( endl << "MTGDECK Parsing Error: " << " [" << primitive->getName() << "]" << s << std::endl);
break;
}
tempPrimitive = primitive;
tempCard = card;
return i;
}
void MTGAllCards::initCounters()
{
for (int i = 0; i < Constants::MTG_NB_COLORS; i++)
{
colorsCount[i] = NULL;
}
}
void MTGAllCards::init()
{
tempCard = NULL;
tempPrimitive = NULL;
total_cards = 0;
initCounters();
}
int MTGAllCards::load(const char * config_file, const char * set_name, int autoload)
{
conf_read_mode = 0;
const int set_id = set_name ? setlist.Add(set_name) : MTGSets::INTERNAL_SET;
MTGSetInfo *si = setlist.getInfo(set_id);
std::ifstream setFile(config_file, ios::in | ios::ate);
if (!setFile) return total_cards;
streampos fileSize = setFile.tellg();
setFile.seekg(0, ios::beg);
std::string contents;
contents.resize((std::string::size_type) fileSize);
setFile.read(&contents[0], fileSize);
std::stringstream stream(contents);
string s;
while (true)
{
if (!std::getline(stream, s)) return total_cards;
if (!s.size()) continue;
if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); // Handle DOS files
switch (conf_read_mode)
{
case MTGAllCards::READ_ANYTHING:
if (s[0] == '[')
{
currentGrade = Constants::GRADE_SUPPORTED; // Default value
conf_read_mode = ('m' == s[1]) ? MTGAllCards::READ_METADATA : MTGAllCards::READ_CARD; // M for metadata.
}
else
{
//Global grade for file, to avoid reading the entire file if unnnecessary
if (s[0] == 'g' && s.size() > 8)
{
int fileGrade = getGrade(s[8]);
int maxGrade = options[Options::MAX_GRADE].number;
if (!maxGrade) maxGrade = Constants::GRADE_BORDERLINE; //Default setting for grade is borderline?
if (fileGrade > maxGrade)
{
return total_cards;
}
}
}
continue;
case MTGAllCards::READ_METADATA:
if (s[0] == '[' && s[1] == '/')
conf_read_mode = MTGAllCards::READ_ANYTHING;
else if (si) si->processConfLine(s);
continue;
case MTGAllCards::READ_CARD:
if (s[0] == '[' && s[1] == '/')
{
conf_read_mode = MTGAllCards::READ_ANYTHING;
if (tempPrimitive) tempPrimitive = addPrimitive(tempPrimitive, tempCard);
if (tempCard)
{
if (tempPrimitive) tempCard->setPrimitive(tempPrimitive);
addCardToCollection(tempCard, set_id);
}
tempCard = NULL;
tempPrimitive = NULL;
}
else
{
processConfLine(s, tempCard, tempPrimitive);
}
continue;
}
}
return total_cards;
}
MTGAllCards::MTGAllCards()
{
init();
}
MTGAllCards::~MTGAllCards()
{
//Why don't we call destroyAllCards from here ???
}
void MTGAllCards::destroyAllCards()
{
for (map<int, MTGCard *>::iterator it = collection.begin(); it != collection.end(); it++)
delete (it->second);
collection.clear();
ids.clear();
for (map<string, CardPrimitive *>::iterator it = primitives.begin(); it != primitives.end(); it++)
delete (it->second);
primitives.clear();
}
MTGAllCards::MTGAllCards(const char * config_file, const char * set_name)
{
init();
load(config_file, set_name, 0);
}
int MTGAllCards::randomCardId()
{
int id = (rand() % ids.size());
return ids[id];
}
int MTGAllCards::countBySet(int setId)
{
int result = 0;
map<int, MTGCard *>::iterator it;
for (it = collection.begin(); it != collection.end(); it++)
{
MTGCard * c = it->second;
if (c->setId == setId)
{
result++;
}
}
return result;
}
//TODO more efficient way ?
int MTGAllCards::countByType(const char * _type)
{
int result = 0;
map<int, MTGCard *>::iterator it;
for (it = collection.begin(); it != collection.end(); it++)
{
MTGCard * c = it->second;
if (c->data->hasType(_type))
{
result++;
}
}
return result;
}
int MTGAllCards::countByColor(int color)
{
if (colorsCount[color] == 0)
{
for (int i = 0; i < Constants::MTG_NB_COLORS; i++)
{
colorsCount[i] = 0;
}
map<int, MTGCard *>::iterator it;
for (it = collection.begin(); it != collection.end(); it++)
{
MTGCard * c = it->second;
int j = c->data->getColor();
colorsCount[j]++;
}
}
return colorsCount[color];
}
int MTGAllCards::totalCards()
{
return (total_cards);
}
bool MTGAllCards::addCardToCollection(MTGCard * card, int setId)
{
card->setId = setId;
int newId = card->getId();
if (collection.find(newId) != collection.end())
{
#if defined (_DEBUG)
string cardName = card->data ? card->data->name : card->getImageName();
string setName = setId != -1 ? setlist.getInfo(setId)->getName() : "";
DebugTrace("warning, card id collision! : " << newId << " -> " << cardName << "(" << setName << ")");
#endif
SAFE_DELETE(card);
return false;
}
//Don't add cards that don't have a primitive
if (!card->data)
{
SAFE_DELETE(card);
return false;
}
ids.push_back(newId);
collection[newId] = card; //Push card into collection.
MTGSetInfo * si = setlist.getInfo(setId);
if (si) si->count(card); //Count card in set info
++total_cards;
return true;
}
CardPrimitive * MTGAllCards::addPrimitive(CardPrimitive * primitive, MTGCard * card)
{
int maxGrade = options[Options::MAX_GRADE].number;
if (!maxGrade) maxGrade = Constants::GRADE_BORDERLINE; //Default setting for grade is borderline?
if (currentGrade > maxGrade)
{
SAFE_DELETE(primitive);
return NULL;
}
string key;
if (card)
{
std::stringstream ss;
ss << card->getId();
ss >> key;
}
else
key = primitive->name;
if (primitives.find(key) != primitives.end())
{
//ERROR
//Todo move the deletion somewhere else ?
DebugTrace("MTGDECK: primitives conflict: "<< key);
SAFE_DELETE(primitive);
return NULL;
}
//translate cards text
Translator * t = Translator::GetInstance();
map<string,string>::iterator it = t->tempValues.find(primitive->name);
if (it != t->tempValues.end())
{
primitive->setText(it->second);
}
//Legacy:
//For the Deck editor, we need Lands and Artifact to be colors...
if (primitive->hasType(Subtypes::TYPE_LAND)) primitive->setColor(Constants::MTG_COLOR_LAND);
if (primitive->hasType(Subtypes::TYPE_ARTIFACT)) primitive->setColor(Constants::MTG_COLOR_ARTIFACT);
primitives[key] = primitive;
return primitive;
}
MTGCard * MTGAllCards::getCardById(int id)
{
map<int, MTGCard *>::iterator it = collection.find(id);
if (it != collection.end())
{
return (it->second);
}
return 0;
}
MTGCard * MTGAllCards::_(int index)
{
if (index >= total_cards) return NULL;
return getCardById(ids[index]);
}
MTGCard * MTGAllCards::getCardByName(string name)
{
if (!name.size()) return NULL;
if (name[0] == '#') return NULL;
int cardnb = atoi(name.c_str());
if (cardnb)
{
return getCardById(cardnb);
}
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
int setId = -1;
size_t found = name.find(" (");
if (found != string::npos)
{
size_t end = name.find(")");
string setName = name.substr(found + 2, end - found - 2);
trim(setName);
name = name.substr(0, found);
trim(name);
setId = setlist[setName];
}
map<int, MTGCard *>::iterator it;
for (it = collection.begin(); it != collection.end(); it++)
{
MTGCard * c = it->second;
if (setId != -1 && setId != c->setId) continue;
string cardName = c->data->name;
std::transform(cardName.begin(), cardName.end(), cardName.begin(), ::tolower);
if (cardName.compare(name) == 0) return c;
}
return NULL;
}
//MTGDeck
MTGDeck::MTGDeck(MTGAllCards * _allcards)
{
total_cards = 0;
database = _allcards;
filename = "";
meta_name = "";
}
int MTGDeck::totalPrice()
{
int total = 0;
PriceList * pricelist = NEW PriceList(JGE_GET_RES("settings/prices.dat").c_str(), GameApp::collection);
map<int, int>::iterator it;
for (it = cards.begin(); it != cards.end(); it++)
{
int nb = it->second;
if (nb) total += pricelist->getPrice(it->first);
}
SAFE_DELETE(pricelist);
return total;
}
MTGDeck::MTGDeck(const char * config_file, MTGAllCards * _allcards, int meta_only)
{
total_cards = 0;
database = _allcards;
filename = config_file;
size_t slash = filename.find_last_of("/");
size_t dot = filename.find(".");
meta_name = filename.substr(slash + 1, dot - slash - 1);
std::ifstream file(config_file);
std::string s;
if (file)
{
while (std::getline(file, s))
{
if (!s.size()) continue;
if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files
if (s[0] == '#')
{
size_t found = s.find("NAME:");
if (found != string::npos)
{
meta_name = s.substr(found + 5);
continue;
}
found = s.find("DESC:");
if (found != string::npos)
{
if (meta_desc.size()) meta_desc.append("\n");
meta_desc.append(s.substr(found + 5));
continue;
}
continue;
}
if (meta_only) break;
int cardnb = atoi(s.c_str());
if (cardnb)
{
add(cardnb);
}
else
{
int nb = 1;
size_t found = s.find(" *");
if (found != string::npos)
{
nb = atoi(s.substr(found + 2).c_str());
s = s.substr(0, found);
}
MTGCard * card = database->getCardByName(s);
if (card)
{
for (int i = 0; i < nb; i++)
{
add(card);
}
}
else
{
DebugTrace("could not find Card matching name: " << s);
}
}
}
file.close();
}
else
{
//TODO Error management
}
}
int MTGDeck::totalCards()
{
return total_cards;
}
MTGCard * MTGDeck::getCardById(int mtgId)
{
return database->getCardById(mtgId);
}
int MTGDeck::addRandomCards(int howmany, int * setIds, int nbSets, int rarity, const char * _subtype, int * colors, int nbcolors)
{
if (howmany <= 0) return 1;
int unallowedColors[Constants::MTG_NB_COLORS + 1];
for (int i = 0; i < Constants::MTG_NB_COLORS; ++i)
{
if (nbcolors)
unallowedColors[i] = 1;
else
unallowedColors[i] = 0;
}
for (int i = 0; i < nbcolors; ++i)
{
unallowedColors[colors[i]] = 0;
}
int collectionTotal = database->totalCards();
if (!collectionTotal) return 0;
char subtype[4096];
if (_subtype) sprintf(subtype, "%s", _subtype);
vector<int> subcollection;
int subtotal = 0;
for (int i = 0; i < collectionTotal; i++)
{
MTGCard * card = database->_(i);
int r = card->getRarity();
if (r != Constants::RARITY_T && (rarity == -1 || r == rarity) && // remove tokens
card->setId != MTGSets::INTERNAL_SET && //remove cards that are defined in primitives. Those are workarounds (usually tokens) and should only be used internally
(!_subtype || card->data->hasSubtype(subtype)))
{
int ok = 0;
if (!nbSets) ok = 1;
for (int j = 0; j < nbSets; ++j)
{
if (card->setId == setIds[j])
{
ok = 1;
break;
}
}
if (ok)
{
for (int j = 0; j < Constants::MTG_NB_COLORS; ++j)
{
if (unallowedColors[j] && card->data->hasColor(j))
{
ok = 0;
break;
}
}
}
if (ok)
{
subcollection.push_back(card->getId());
subtotal++;
}
}
}
if (subtotal == 0)
{
if (rarity == Constants::RARITY_M) return addRandomCards(howmany, setIds, nbSets, Constants::RARITY_R, _subtype, colors,
nbcolors);
return 0;
}
for (int i = 0; i < howmany; i++)
{
int id = (rand() % subtotal);
add(subcollection[id]);
}
return 1;
}
int MTGDeck::add(MTGDeck * deck)
{
map<int, int>::iterator it;
for (it = deck->cards.begin(); it != deck->cards.end(); it++)
{
for (int i = 0; i < it->second; i++)
{
add(it->first);
}
}
return deck->totalCards();
}
int MTGDeck::add(int cardid)
{
if (!database->getCardById(cardid)) return 0;
if (cards.find(cardid) == cards.end())
{
cards[cardid] = 1;
}
else
{
cards[cardid]++;
}
++total_cards;
//initCounters();
return total_cards;
}
int MTGDeck::add(MTGCard * card)
{
if (!card) return 0;
return (add(card->getId()));
}
int MTGDeck::complete()
{
/* (PSY) adds cards to the deck/collection. Makes sure that the deck
or collection has at least 4 of every implemented card. Does not
change the number of cards of which already 4 or more are present. */
int id, n;
bool StypeIsNothing;
size_t databaseSize = database->ids.size();
for (size_t it = 0; it < databaseSize; it++)
{
id = database->ids[it];
StypeIsNothing = false;
if (database->getCardById(id)->data->hasType("nothing"))
{
StypeIsNothing = true;
}
if (!StypeIsNothing == true)
{
if (cards.find(id) == cards.end())
{
cards[id] = 4;
total_cards += 4;
}
else
{
n = cards[id];
if (n < 4)
{
total_cards += 4 - n;
cards[id] = 4;
}
}
}
}
return 1;
}
int MTGDeck::removeAll()
{
total_cards = 0;
cards.clear();
//initCounters();
return 1;
}
int MTGDeck::remove(int cardid)
{
if (cards.find(cardid) == cards.end() || cards[cardid] == 0) return 0;
cards[cardid]--;
total_cards--;
//initCounters();
return 1;
}
int MTGDeck::remove(MTGCard * card)
{
if (!card) return 0;
return (remove(card->getId()));
}
int MTGDeck::save()
{
return save(filename, false, meta_name, meta_desc);
}
int MTGDeck::save(string destFileName, bool useExpandedDescriptions, string &deckTitle, string &deckDesc)
{
string tmp = destFileName;
tmp.append(".tmp"); //not thread safe
std::ofstream file(tmp.c_str());
char writer[512];
if (file)
{
DebugTrace("Saving Deck: " << deckTitle << " to " << destFileName );
if (meta_name.size())
{
file << "#NAME:" << deckTitle << '\n';
}
if (meta_desc.size())
{
size_t found = 0;
string desc = deckDesc;
found = desc.find_first_of("\n");
while (found != string::npos)
{
file << "#DESC:" << desc.substr(0, found + 1);
desc = desc.substr(found + 1);
found = desc.find_first_of("\n");
}
file << "#DESC:" << desc << "\n";
}
if (useExpandedDescriptions)
{
map<int, int>::iterator it;
for (it = cards.begin(); it != cards.end(); it++)
{
int nbCards = it->second;
MTGCard *card = this->getCardById(it->first);
if (card == NULL)
{
continue;
}
MTGSetInfo *setInfo = setlist.getInfo(card->setId);
string setName = setInfo->id;
string cardName = card->data->getName();
file << cardName << "\t " << "(" << setName << ") *" << nbCards << endl;
setInfo = NULL;
}
}
else
{
map<int, int>::iterator it;
for (it = cards.begin(); it != cards.end(); it++)
{
sprintf(writer, "%i\n", it->first);
for (int j = 0; j < it->second; j++)
{
file << writer;
}
}
}
file.close();
std::remove(destFileName.c_str());
rename(tmp.c_str(), destFileName.c_str());
}
DeckMetaDataList::decksMetaData->invalidate(destFileName);
return 1;
}
//MTGSets
MTGSets setlist; //Our global.
MTGSets::MTGSets()
{
}
MTGSets::~MTGSets()
{
for (size_t i = 0; i < setinfo.size(); ++i)
{
delete (setinfo[i]);
}
}
MTGSetInfo* MTGSets::getInfo(int setID)
{
if (setID < 0 || setID >= (int) setinfo.size()) return NULL;
return setinfo[setID];
}
MTGSetInfo* MTGSets::randomSet(int blockId, int atleast)
{
char * unlocked = (char *) calloc(size(), sizeof(char));
int attempts = 50;
//Figure out which sets are available.
for (int i = 0; i < size(); i++)
{
unlocked[i] = options[Options::optionSet(i)].number;
}
//No luck randomly. Now iterate from a random location.
int a = 0, iter = 0;
while (iter < 3)
{
a = rand() % size();
for (int i = a; i < size(); i++)
{
if (unlocked[i] && (blockId == -1 || setinfo[i]->block == blockId) &&
(atleast == -1 || setinfo[i]->totalCards() >= atleast))
{
free(unlocked);
return setinfo[i];
}
}
for (int i = 0; i < a; i++)
{
if (unlocked[i] && (blockId == -1 || setinfo[i]->block == blockId) &&
(atleast == -1 || setinfo[i]->totalCards() >= atleast))
{
free(unlocked);
return setinfo[i];
}
}
blockId = -1;
iter++;
if (iter == 2) atleast = -1;
}
free(unlocked);
return NULL;
}
int blockSize(int blockId);
int MTGSets::Add(const char * name)
{
int setid = findSet(name);
if (setid != -1) return setid;
MTGSetInfo* s = NEW MTGSetInfo(name);
setinfo.push_back(s);
setid = (int) setinfo.size();
return setid - 1;
}
int MTGSets::findSet(string name)
{
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
for (int i = 0; i < (int) setinfo.size(); i++)
{
MTGSetInfo* s = setinfo[i];
if (!s) continue;
string set = s->id;
std::transform(set.begin(), set.end(), set.begin(), ::tolower);
if (set.compare(name) == 0) return i;
}
return -1;
}
int MTGSets::findBlock(string s)
{
if (!s.size()) return -1;
string comp = s;
std::transform(comp.begin(), comp.end(), comp.begin(), ::tolower);
for (int i = 0; i < (int) blocks.size(); i++)
{
string b = blocks[i];
std::transform(b.begin(), b.end(), b.begin(), ::tolower);
if (b.compare(comp) == 0) return i;
}
blocks.push_back(s);
return ((int) blocks.size()) - 1;
}
int MTGSets::operator[](string id)
{
return findSet(id);
}
string MTGSets::operator[](int id)
{
if (id < 0 || id >= (int) setinfo.size()) return "";
MTGSetInfo * si = setinfo[id];
if (!si) return "";
return si->id;
}
int MTGSets::getSetNum(MTGSetInfo*i)
{
int it;
for (it = 0; it < size(); it++)
{
if (setinfo[it] == i) return it;
}
return -1;
}
int MTGSets::size()
{
return (int) setinfo.size();
}
//MTGSetInfo
MTGSetInfo::~MTGSetInfo()
{
SAFE_DELETE(mPack);
}
MTGSetInfo::MTGSetInfo(string _id)
{
string whitespaces(" \t\f\v\n\r");
id = _id;
block = -1;
year = -1;
for (int i = 0; i < MTGSetInfo::MAX_COUNT; i++)
counts[i] = 0;
char myFilename[4096];
sprintf(myFilename, JGE_GET_RES("sets/%s/booster.txt").c_str(), id.c_str());
mPack = NEW MTGPack(myFilename);
if (!mPack->isValid())
{
SAFE_DELETE(mPack);
}
bZipped = false;
bThemeZipped = false;
}
void MTGSetInfo::count(MTGCard*c)
{
if (!c) return;
switch (c->getRarity())
{
case Constants::RARITY_M:
counts[MTGSetInfo::MYTHIC]++;
break;
case Constants::RARITY_R:
counts[MTGSetInfo::RARE]++;
break;
case Constants::RARITY_U:
counts[MTGSetInfo::UNCOMMON]++;
break;
case Constants::RARITY_C:
counts[MTGSetInfo::COMMON]++;
break;
default:
case Constants::RARITY_L:
counts[MTGSetInfo::LAND]++;
break;
}
counts[MTGSetInfo::TOTAL_CARDS]++;
}
int MTGSetInfo::totalCards()
{
return counts[MTGSetInfo::TOTAL_CARDS];
}
string MTGSetInfo::getName()
{
if (name.size()) return name; //Pretty name is translated when rendering.
return id; //Ugly name as well.
}
string MTGSetInfo::getBlock()
{
if (block < 0 || block >= (int) setlist.blocks.size()) return "None";
return setlist.blocks[block];
}
void MTGSetInfo::processConfLine(string line)
{
size_t i = line.find_first_of("=");
if (i == string::npos) return;
string key = line.substr(0, i);
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
string value = line.substr(i + 1);
if (key.compare("name") == 0)
name = value;
else if (key.compare("author") == 0)
author = value;
else if (key.compare("block") == 0)
block = setlist.findBlock(value.c_str());
else if (key.compare("year") == 0) year = atoi(value.c_str());
}