Files
wagic/projects/mtg/src/MTGPack.cpp
techdragon.nguyen@gmail.com ea8e8f36c8 fixed very obscure bug. In VS2010 the string was being trimmed before going into Construct method, but the string length was not updated.
Thus, Construct thought the string length was 1 greater than it should have been causing an out of bounds runtime exception.  In VS2008, the same thing
happened, however no exception was thrown since VS2008 allows access into the undefined memory space and returned a 0 (null) value when it tried to access
outside the string array.  This fix targets specifically the color filters since they seem to be the ones with the error. " color:g;" and not "color:g;" was being
passed.
2011-02-23 18:30:45 +00:00

394 lines
10 KiB
C++

#include "PrecompiledHeader.h"
#include <JGui.h>
#include <dirent.h>
#include "GameApp.h"
#include "Translate.h"
#include "WDataSrc.h"
#include "WFilter.h"
#include "DeckDataWrapper.h"
#include "MTGPack.h"
#include "../../../JGE/src/tinyxml/tinyxml.h"
MTGPack MTGPacks::defaultBooster;
int MTGPackEntryRandom::addCard(WSrcCards *pool, MTGDeck *to)
{
int fails = 0;
if (!pool)
return 1;
WCFilterFactory * ff = WCFilterFactory::GetInstance();
WCardFilter * oldf = pool->unhookFilters();
pool->addFilter(ff->Construct(filter));
fails = pool->addRandomCards(to, copies);
pool->clearFilters();
pool->addFilter(oldf);
return fails;
}
int MTGPackEntrySpecific::addCard(WSrcCards *pool, MTGDeck *to)
{
if (!card)
return copies;
for (int i = 0; i < copies; i++)
to->add(card);
return 0;
}
int MTGPackSlot::add(WSrcCards * ocean, MTGDeck *to, int carryover)
{
if (!entries.size())
return copies;
int fails = 0;
int amt = copies + carryover;
WSrcCards * myPool = NULL;
if (pool.size())
myPool = MTGPack::getPool(pool);
if (!myPool)
myPool = ocean;
for (int i = 0; i < amt; i++)
{
size_t pos = rand() % entries.size();
while (pos < entries.size() && entries[pos]->addCard(myPool, to))
pos++;
if (pos == entries.size())
fails++;
}
if (myPool != ocean)
SAFE_DELETE(myPool);
return fails;
}
WSrcCards * MTGPack::getPool(string poolstr)
{
WSrcCards * mySrc = NULL;
size_t s = poolstr.find("all");
WCFilterFactory * ff = WCFilterFactory::GetInstance();
if (s == string::npos)
{ //Default to just unlocked cards
mySrc = NEW WSrcUnlockedCards();
s = poolstr.find("unlocked");
string sub = poolstr;
if (s != string::npos)
sub = trim(poolstr.substr(s + 8));
if (sub.size())
{
mySrc->addFilter(ff->Construct(sub));
mySrc->bakeFilters();
}
}
else
{ //Use everything.
mySrc = NEW WSrcCards();
string sub = poolstr.substr(s + 3);
if (sub.size())
{
mySrc->addFilter(ff->Construct(sub));
mySrc->loadMatches(MTGCollection());
mySrc->bakeFilters();
}
else
mySrc->loadMatches(MTGCollection());
}
mySrc->Shuffle();
return mySrc;
}
void MTGPackSlot::addEntry(MTGPackEntry*item)
{
if (item)
entries.push_back(item);
}
int MTGPack::assemblePack(MTGDeck *to)
{
int carryover = 0;
WSrcCards * p = getPool(pool);
if (!p)
return -1;
p->Shuffle();
for (size_t i = 0; i < slotss.size(); i++)
{
carryover = slotss[i]->add(p, to, carryover);
if (carryover > 0)
carryover = carryover; //This means we're failing.
}
SAFE_DELETE(p);
return carryover;
}
void MTGPack::countCards()
{
minCards = 0;
maxCards = 0;
for (size_t i = 0; i < slotss.size(); i++)
{
MTGPackSlot * ps = slotss[i];
int top = 0;
int bot = 999999999;
for (size_t y = 0; y < ps->entries.size(); y++)
{
int test = ps->entries[y]->copies * ps->copies;
if (test > top)
top = test;
if (test < bot)
bot = test;
}
maxCards += top;
minCards += bot;
}
}
void MTGPack::load(string filename)
{
//TODO Placeholder until XML format available.
TiXmlDocument packfile(filename.c_str());
if (!packfile.LoadFile())
return;
TiXmlHandle hDoc(&packfile);
TiXmlElement * pPack;
pPack = hDoc.FirstChildElement().Element();
if (!pPack)
{
return;
}
//root should be "pack"
string tag = pPack->Value();
std::transform(tag.begin(), tag.end(), tag.begin(), ::tolower);
if (tag != "pack")
return;
//After validating, handle actual loading.
TiXmlElement * pSlot;
const char * holder = NULL;
holder = pPack->Attribute("price");
if (holder)
price = atoi(holder);
else
price = Constants::PRICE_BOOSTER;
holder = pPack->Attribute("pool");
if (holder)
pool = holder;
else
pool = "";
holder = pPack->Attribute("type");
if (holder)
{
type = holder;
}
else
type = "Booster";
holder = pPack->Attribute("name");
if (holder)
name = holder;
else
name = "Special";
holder = pPack->Attribute("requires");
if (holder)
check = holder;
holder = pPack->Attribute("sort");
if (holder)
sort = holder;
else
sort = "";
std::transform(sort.begin(), sort.end(), sort.begin(), ::tolower);
for (pSlot = pPack->FirstChildElement(); pSlot != NULL; pSlot = pSlot->NextSiblingElement())
{
TiXmlElement * pEntry;
//Load slot.
tag = pSlot->Value();
std::transform(tag.begin(), tag.end(), tag.begin(), ::tolower);
if (tag != "slot")
continue;
MTGPackSlot * s = NEW MTGPackSlot();
slotss.push_back(s);
holder = pSlot->Attribute("copies");
if (holder)
s->copies = atoi(holder);
else
s->copies = 1;
holder = pSlot->Attribute("pool");
if (holder)
s->pool = holder;
for (pEntry = pSlot->FirstChildElement(); pEntry != NULL; pEntry = pEntry->NextSiblingElement())
{
tag = pEntry->Value();
std::transform(tag.begin(), tag.end(), tag.begin(), ::tolower);
if (tag == "card")
{ //Load specific card
MTGPackEntrySpecific * es = NEW MTGPackEntrySpecific();
holder = pEntry->Attribute("copies");
if (holder)
es->copies = atoi(holder);
else
es->copies = 1;
es->card = MTGCollection()->getCardByName(pEntry->Value());
s->addEntry(es);
}
else if (tag == "random_card")
{ //Load random card
MTGPackEntryRandom * er = NEW MTGPackEntryRandom();
holder = pEntry->Attribute("copies");
if (holder)
er->copies = atoi(holder);
else
er->copies = 1;
const char * text = pEntry->GetText();
if (text)
er->filter = text;
s->addEntry(er);
}
else if (tag == "nothing")
{
MTGPackEntryNothing * nt = NEW MTGPackEntryNothing();
s->addEntry(nt);
}
}
}
bValid = true;
countCards();
return;
}
MTGPackSlot::~MTGPackSlot()
{
for (size_t t = 0; t < entries.size(); t++)
{
SAFE_DELETE(entries[t]);
}
entries.clear();
}
MTGPack::~MTGPack()
{
for (size_t t = 0; t < slotss.size(); t++)
{
SAFE_DELETE(slotss[t]);
}
slotss.clear();
}
MTGPacks::~MTGPacks()
{
for (size_t t = 0; t < packs.size(); t++)
{
SAFE_DELETE(packs[t]);
}
packs.clear();
}
MTGPack * MTGPacks::randomPack(int key)
{
if (!key)
key = rand();
size_t s = packs.size();
if (!s)
return NULL;
return packs[key % s];
}
void MTGPacks::loadAll()
{
DIR *mDip = opendir(JGE_GET_RES("packs/").c_str());
struct dirent *mDit;
if (!mDip)
return;
while ((mDit = readdir(mDip)))
{
char myFilename[4096];
sprintf(myFilename, JGE_GET_RES("packs/%s").c_str(), mDit->d_name);
if (mDit->d_name[0] == '.')
continue;
if (!strcmp(mDit->d_name, "default_booster.txt"))
continue;
MTGPack * p = NEW MTGPack(myFilename);
if (!p->isValid())
{
SAFE_DELETE(p);
continue;
}
packs.push_back(p);
}
closedir(mDip);
}
string MTGPack::getName()
{
string n = _(name);
string t = _(type);
char buf[1024];
if (minCards != maxCards)
sprintf(buf, "%s %s (%i-%i cards)", n.c_str(), t.c_str(), minCards, maxCards);
else
sprintf(buf, "%s %s (%i cards)", n.c_str(), t.c_str(), maxCards);
return buf;
}
bool MTGPack::meetsRequirements()
{
bool unlocked = true;
WCFilterFactory * ff = WCFilterFactory::GetInstance();
WSrcCards * myC = getPool(pool);
if (!myC || myC->Size() < maxCards)
unlocked = false; //Top pool lacks cards.
SAFE_DELETE(myC);
if (!check.size() || !unlocked)
return unlocked;
myC = NEW WSrcUnlockedCards(); //Requirements are independent of pool;
WCardFilter * cf = ff->Construct(check);
unlocked = !myC->isEmptySet(cf); //Quick check for empty set status.
SAFE_DELETE(cf); //delete requirement filter
SAFE_DELETE(myC); //delete pool.
return unlocked;
}
bool MTGPack::isUnlocked()
{
if (unlockStatus == 0)
{
if (meetsRequirements())
unlockStatus = 1;
else
unlockStatus = -1;
}
return (unlockStatus > 0);
}
MTGPack * MTGPacks::getDefault()
{
if (!defaultBooster.isValid())
{
defaultBooster.load(JGE_GET_RES("packs/default_booster.txt"));
defaultBooster.unlockStatus = 1;
if (!defaultBooster.isValid())
{
MTGPackSlot * ps = NEW MTGPackSlot();
ps->copies = 1;
ps->addEntry(NEW MTGPackEntryRandom("rarity:mythic;"));
for (int i = 0; i < 7; i++)
ps->addEntry(NEW MTGPackEntryRandom("rarity:rare;"));
defaultBooster.slotss.push_back(ps);
ps = NEW MTGPackSlot();
ps->copies = 3;
ps->addEntry(NEW MTGPackEntryRandom("rarity:uncommon;"));
defaultBooster.slotss.push_back(ps);
ps = NEW MTGPackSlot();
ps->copies = 1;
ps->addEntry(NEW MTGPackEntryRandom("rarity:land;&type:basic;"));
defaultBooster.slotss.push_back(ps);
ps = NEW MTGPackSlot();
ps->copies = 10;
ps->addEntry(NEW MTGPackEntryRandom("rarity:common;"));
defaultBooster.slotss.push_back(ps);
defaultBooster.bValid = true;
defaultBooster.unlockStatus = 1;
}
}
return &defaultBooster;
}
void MTGPacks::refreshUnlocked()
{
for (size_t t = 0; t < packs.size(); t++)
{
if (packs[t]->unlockStatus < 0)
packs[t]->unlockStatus = 0;
}
}