Files
wagic/projects/mtg/src/MTGPack.cpp
wagic.the.homebrew e27cf56fa2 - Support for Zip Filesystem. It is now possible to zip the entire Res folder ("store" method preferred, zip so that the root of the zip has ai, player, etc...) in one single file for read only. Write access is done in another folder (hardcoded to be User/ for now, can be updated depending on platforms, etc...
-- zipFS has several limitations...
--- in a general way, seekg doesn't work... so getting a file's size needs to be done through JFileSystem.
--- getLine on files open with zipFS doesn't work so great. Not sure if it is a normal issue because files are open in binary or not... JFileSystem therefore offers a "readIntoString" function that needs to be used instead of the usual "getline" technique. However getLine can then be used on a stream connected to the string.

-- tested on Windows and PSP, I also made sure android still works, but haven't tested zip support on Android.
-- I tried to maintain backwards compatibility, but this might break on some platforms, if I broke some platforms and you can't find a way to fix them, please contact me and we'll figure something out
-- This removes wagic::ifstream. I didn't reimplement the securities that were involved in this, apologies for that. Might be useful to reimplement such securities in JFileSystem
-- I haven't tested options/profiles in a deep way, it is possible I broke that.
2011-08-21 09:04:59 +00:00

396 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++)
{
std::random_shuffle(entries.begin(), entries.end());
size_t pos = 0;
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()
{
vector<string>packFiles = JFileSystem::GetInstance()->scanfolder("packs/");
for (size_t i = 0; i < packFiles.size(); ++i)
{
string relative = packFiles[i];
char myFilename[4096];
sprintf(myFilename, "packs/%s",relative.c_str());
if (relative[0] == '.')
continue;
if (!strcmp(relative.c_str(), "default_booster.txt"))
continue;
MTGPack * p = NEW MTGPack(myFilename);
if (!p->isValid())
{
SAFE_DELETE(p);
continue;
}
packs.push_back(p);
}
}
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("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;
for (size_t i = 0; i < defaultBooster.slotss.size(); ++ i)
{
defaultBooster.slotss[i]->addEntry(NEW MTGPackEntryRandom("rarity:special;"));
}
}
}
return &defaultBooster;
}
void MTGPacks::refreshUnlocked()
{
for (size_t t = 0; t < packs.size(); t++)
{
if (packs[t]->unlockStatus < 0)
packs[t]->unlockStatus = 0;
}
}