Files
wagic/projects/mtg/src/WDataSrc.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

687 lines
16 KiB
C++

#include "PrecompiledHeader.h"
#include "OptionItem.h"
#include "PlayerData.h"
#include "Translate.h"
#include "PriceList.h"
#include "Subtypes.h"
//WSyncable
bool WSyncable::Hook(WSyncable* s)
{
if (hooked) return false;
hooked = s;
return true;
}
int WSyncable::getPos()
{
if (hooked) return hooked->getPos() + currentPos;
return currentPos;
}
bool WSyncable::next()
{
if (hooked) return hooked->next();
++currentPos;
return true;
}
bool WSyncable::prev()
{
if (hooked) return hooked->prev();
--currentPos;
return true;
}
//WSrcImage
JQuadPtr WSrcImage::getImage(int offset)
{
return WResourceManager::Instance()->RetrieveTempQuad(filename);
}
WSrcImage::WSrcImage(string s)
{
filename = s;
}
//WSrcCards
WSrcCards::WSrcCards(float delay)
{
mDelay = delay;
mLastInput = 0;
currentPos = 0;
filtersRoot = NULL;
}
JQuadPtr WSrcCards::getImage(int offset)
{
if (!WResourceManager::Instance()->IsThreaded())
{
if (mDelay && mLastInput < mDelay)
{
return WResourceManager::Instance()->RetrieveCard(getCard(offset), RETRIEVE_EXISTING);
}
}
return WResourceManager::Instance()->RetrieveCard(getCard(offset));
}
JQuadPtr WSrcCards::getThumb(int offset)
{
return WResourceManager::Instance()->RetrieveCard(getCard(offset), RETRIEVE_THUMB);
}
WSrcCards::~WSrcCards()
{
clearFilters();
cards.clear();
}
void WSrcCards::bakeFilters()
{
vector<MTGCard*> temp;
setOffset(0);
for (int t = 0; t < Size(); t++)
{
temp.push_back(getCard(t));
}
setOffset(0);
cards.clear();
cards.swap(temp);
clearFilters();
return;
}
bool WSrcCards::matchesFilters(MTGCard * c)
{
if (!c) return false;
if (!filtersRoot) return true;
return filtersRoot->isMatch(c);
}
int WSrcCards::Size(bool all)
{
if (!all && filtersRoot) return (int) validated.size();
return (int) cards.size();
}
MTGCard * WSrcCards::getCard(int offset, bool ignore)
{
int oldpos;
int size = (int) cards.size();
MTGCard * c = NULL;
if (!ignore && filtersRoot) size = (int) validated.size();
if (!size) return NULL;
oldpos = currentPos;
if (offset != 0) currentPos += offset;
while (currentPos < 0)
currentPos = size + currentPos;
currentPos = currentPos % size;
if (!ignore && filtersRoot)
c = cards[validated[currentPos]];
else
c = cards[currentPos];
currentPos = oldpos;
return c;
}
int WSrcCards::loadMatches(MTGAllCards* ac)
{
map<int, MTGCard *>::iterator it;
int count = 0;
if (!ac) return count;
for (it = ac->collection.begin(); it != ac->collection.end(); it++)
{
if (it->second && (matchesFilters(it->second)))
{
cards.push_back(it->second);
count++;
}
}
validate();
return count;
}
int WSrcCards::loadMatches(MTGDeck * deck)
{
map<int, int>::iterator it;
int count = 0;
if (!deck) return count;
for (it = deck->cards.begin(); it != deck->cards.end(); it++)
{
MTGCard * c = deck->getCardById(it->first);
if (c && (matchesFilters(c)))
{
cards.push_back(c);
count++;
}
}
validate();
return count;
}
int WSrcCards::loadMatches(WSrcCards* src, bool all)
{
int count = 0;
if (!src) return count;
MTGCard * c = NULL;
int oldp = src->getOffset();
src->setOffset(0);
for (int t = 0; t < src->Size(all); t++)
{
c = src->getCard(t, all);
if (matchesFilters(c))
{
cards.push_back(c);
count++;
}
}
src->setOffset(oldp);
validate();
return count;
}
int WSrcCards::addRandomCards(MTGDeck * i, int howmany)
{
if (!cards.size() || (filtersRoot && !validated.size())) return howmany;
for (int x = 0; x < howmany; x++)
{
if (validated.size())
{
size_t pos = rand() % validated.size();
MTGCard * c = cards[validated[pos]];
i->add(c);
}
else
{
size_t pos = rand() % cards.size();
i->add(cards[pos]);
}
}
return 0;
}
int WSrcCards::addToDeck(MTGDeck * i, int num)
{
int oldpos = getOffset();
int added = 0;
int cycles = 0;
if (!i)
{
if (num < 0) return 0;
return num;
}
setOffset(0);
if (num < 0)
{ //Add it all;
MTGCard * c;
for (;;)
{
c = getCard();
if (!c || !next()) break;
i->add(c);
}
}
else
while (added < num)
{
MTGCard * c = getCard();
if (!next() || !c)
{
if (++cycles == WSrcCards::MAX_CYCLES)
{ //Abort the search, too many cycles.
setOffset(oldpos);
return num - added;
}
setOffset(0);
continue;
}
else
{
i->add(c);
added++;
}
}
setOffset(oldpos);
return 0;
}
bool WSrcCards::next()
{
int size = (int) cards.size();
if (filtersRoot) size = (int) validated.size();
if (currentPos + 1 >= size) return false;
currentPos++;
return true;
}
bool WSrcCards::prev()
{
if (currentPos == 0) return false;
currentPos--;
return true;
}
bool WSrcCards::setOffset(int pos)
{
if (pos < 0 || pos >= (int) cards.size()) return false;
currentPos = pos;
if (!matchesFilters(cards[currentPos])) return next();
return true;
}
void WSrcCards::Shuffle()
{
std::random_shuffle(cards.begin(), cards.end());
validate();
}
void WSrcCards::validate()
{
validated.clear();
updateCounts();
if (!filtersRoot) return;
for (size_t t = 0; t < cards.size(); t++)
{
if (matchesFilters(cards[t])) validated.push_back(t);
}
}
bool WSrcCards::thisCard(int mtgid)
{
for (size_t t = 0; t < cards.size(); t++)
{
if (cards[t] && cards[t]->getId() == mtgid)
{
currentPos = (int) t;
return matchesFilters(cards[currentPos]);
}
}
return false;
}
bool WSrcCards::isEmptySet(WCardFilter * f)
{
size_t max = cards.size();
if (validated.size()) max = validated.size();
if (!f) return (max > 0);
for (size_t t = 0; t < max; t++)
{
if (validated.size())
{
if (f->isMatch(cards[validated[t]])) return false;
}
else if (f->isMatch(cards[t])) return false;
}
return true;
}
void WSrcCards::addFilter(WCardFilter * f)
{
if (filtersRoot == NULL)
filtersRoot = f;
else
filtersRoot = NEW WCFilterAND(f, filtersRoot);
validate();
currentPos = 0;
}
float WSrcCards::filterFee()
{
if (filtersRoot) return filtersRoot->filterFee();
return 0;
}
void WSrcCards::clearFilters()
{
SAFE_DELETE(filtersRoot);
validated.clear();
}
WCardFilter* WSrcCards::unhookFilters()
{
WCardFilter* temp = filtersRoot;
filtersRoot = NULL;
clearFilters();
return temp;
}
void WSrcCards::Sort(int method)
{
switch (method)
{
case WSrcCards::SORT_COLLECTOR:
std::sort(cards.begin(), cards.end(), WCSortCollector());
break;
case WSrcCards::SORT_RARITY:
std::sort(cards.begin(), cards.end(), WCSortRarity());
break;
case WSrcCards::SORT_ALPHA:
default:
std::sort(cards.begin(), cards.end(), WCSortAlpha());
break;
}
validate();
}
//WSrcUnlockedCards
WSrcUnlockedCards::WSrcUnlockedCards(float delay) :
WSrcCards(delay)
{
MTGAllCards * ac = MTGCollection();
map<int, MTGCard*>::iterator it;
char * unlocked = NULL;
unlocked = (char *) calloc(setlist.size(), sizeof(char));
//Figure out which sets are available.
for (int i = 0; i < setlist.size(); i++)
{
unlocked[i] = options[Options::optionSet(i)].number;
}
for (it = ac->collection.begin(); it != ac->collection.end(); it++)
{
if (it->second && unlocked[it->second->setId]) cards.push_back(it->second);
}
if (unlocked)
{
free(unlocked);
unlocked = NULL;
}
if (cards.size())
{
Shuffle();
currentPos = 0;
}
}
//WSrcDeck
int WSrcDeck::loadMatches(MTGDeck * deck)
{
map<int, int>::iterator it;
int count = 0;
if (!deck) return count;
for (it = deck->cards.begin(); it != deck->cards.end(); it++)
{
MTGCard * c = deck->getCardById(it->first);
if (c && matchesFilters(c))
{
Add(c, it->second);
count++;
}
}
validate();
return count;
}
void WSrcDeck::updateCounts()
{
vector<MTGCard*>::iterator it;
map<int, int>::iterator ccount;
clearCounts();
for (it = cards.begin(); it != cards.end(); it++)
{
ccount = copies.find((*it)->getMTGId());
if (ccount == copies.end()) continue;
addCount((*it), ccount->second);
}
}
void WSrcDeck::clearCounts()
{
counts[UNFILTERED_MIN_COPIES] = -1;
counts[UNFILTERED_MAX_COPIES] = 0;
for (int i = 0; i < MAX_COUNTS; i++)
counts[i] = 0;
}
void WSrcDeck::addCount(MTGCard * c, int qty)
{
if (!c || !c->data) return;
map<int, int>::iterator cp = copies.find(c->getMTGId());
if (matchesFilters(c))
{
counts[FILTERED_COPIES] += qty;
if (qty > 0 && cp != copies.end() && (*cp).second == qty)
counts[FILTERED_UNIQUE]++;
else if (qty < 0 && (cp == copies.end() || (*cp).second == 0)) counts[FILTERED_UNIQUE]--;
}
counts[UNFILTERED_COPIES] += qty;
if (qty > 0 && cp != copies.end() && (*cp).second == qty)
counts[UNFILTERED_UNIQUE]++;
else if (qty < 0 && (cp == copies.end() || (*cp).second == 0)) counts[UNFILTERED_UNIQUE]--;
for (int i = Constants::MTG_COLOR_ARTIFACT; i <= Constants::MTG_COLOR_LAND; i++)
if (c->data->hasColor(i)) counts[i] += qty;
if (counts[UNFILTERED_MIN_COPIES] < 0 || qty < counts[UNFILTERED_MIN_COPIES]) counts[UNFILTERED_MIN_COPIES] = qty;
if (qty > counts[UNFILTERED_MAX_COPIES]) counts[UNFILTERED_MAX_COPIES] = qty;
}
int WSrcDeck::Add(MTGCard * c, int quantity)
{
if (!c) return 0;
if (copies.find(c->getMTGId()) == copies.end())
{
cards.push_back(c);
}
copies[c->getMTGId()] += quantity;
addCount(c, quantity);
return 1;
}
int WSrcDeck::Remove(MTGCard * c, int quantity, bool erase)
{
if (!c) return 0;
map<int, int>::iterator it = copies.find(c->getMTGId());
if (it == copies.end()) return 0;
int amt = it->second;
if (amt < quantity) return 0;
amt -= quantity;
it->second = amt;
if (erase && amt == 0)
{
copies.erase(it);
vector<MTGCard*>::iterator i = find(cards.begin(), cards.end(), c);
if (i != cards.end()) cards.erase(i);
}
addCount(c, -quantity);
return 1;
}
void WSrcDeck::Rebuild(MTGDeck * d)
{
d->removeAll();
map<int, int>::iterator it;
for (it = copies.begin(); it != copies.end(); it++)
{
for (int i = 0; i < it->second; i++)
{
d->add(it->first);
}
}
}
int WSrcDeck::count(MTGCard * c)
{
if (!c) return counts[UNFILTERED_COPIES];
if (copies.find(c->getMTGId()) == copies.end()) return 0;
return copies[c->getMTGId()];
}
int WSrcDeck::countByName(MTGCard * card, bool editions)
{
string name = card->data->getLCName();
int total = 0;
vector<MTGCard*>::iterator it;
for (it = cards.begin(); it != cards.end(); it++)
{
if (*it && (*it)->data->getLCName() == name)
{
if (editions)
total++;
else
{
map<int, int>::iterator mi = copies.find((*it)->getMTGId());
if (mi != copies.end()) total += mi->second;
}
}
}
return total;
}
int WSrcDeck::getCount(int count)
{
if (count < 0 || count >= MAX_COUNTS) return counts[UNFILTERED_COPIES];
return counts[count];
}
int WSrcDeck::totalPrice()
{
int total = 0;
PriceList * pricelist = NEW PriceList("settings/prices.dat", MTGCollection());
map<int, int>::iterator it;
for (it = copies.begin(); it != copies.end(); it++)
{
int nb = it->second;
if (nb) total += pricelist->getPrice(it->first);
}
SAFE_DELETE(pricelist);
return total;
}
//WSrcDeckViewer
WSrcDeckViewer::WSrcDeckViewer(WSrcCards * _active, WSrcCards * _inactive) :
WSrcCards(0.2f)
{
active = _active;
inactive = _inactive;
}
void WSrcDeckViewer::swapSrc()
{
WSrcCards * temp = active;
active = inactive;
inactive = temp;
}
WSrcDeckViewer::~WSrcDeckViewer()
{
//Do nothing.
}
//Sorting methods:
int WCSortRarity::rareToInt(char r)
{
switch (r)
{
default:
case Constants::RARITY_T:
return 0;
case Constants::RARITY_L:
return 1;
case Constants::RARITY_C:
return 2;
case Constants::RARITY_U:
return 3;
case Constants::RARITY_R:
return 4;
case Constants::RARITY_M:
return 5;
case Constants::RARITY_S:
return 6;
}
}
bool WCSortRarity::operator()(const MTGCard*l, const MTGCard*r)
{
if (!l || !r || !l->data || !r->data) return false;
return (rareToInt(l->getRarity()) < rareToInt(r->getRarity()));
}
bool WCSortAlpha::operator()(const MTGCard*l, const MTGCard*r)
{
if (!l || !r || !l->data || !r->data) return false;
string ln = l->data->getLCName();
string rn = r->data->getLCName();
if (ln == rn) return l->getMTGId() < r->getMTGId();
return (ln < rn);
}
bool WCSortCollector::operator()(const MTGCard*l, const MTGCard*r)
{
if (!l || !r || !l->data || !r->data) return false;
if (l->setId != r->setId) return (l->setId < r->setId);
int lc, rc;
lc = l->data->countColors();
rc = r->data->countColors();
if (lc == 0) lc = 999;
if (rc == 0) rc = 999;
int isW = (int) l->data->hasColor(Constants::MTG_COLOR_WHITE) - (int) r->data->hasColor(Constants::MTG_COLOR_WHITE);
int isU = (int) l->data->hasColor(Constants::MTG_COLOR_BLUE) - (int) r->data->hasColor(Constants::MTG_COLOR_BLUE);
int isB = (int) l->data->hasColor(Constants::MTG_COLOR_BLACK) - (int) r->data->hasColor(Constants::MTG_COLOR_BLACK);
int isR = (int) l->data->hasColor(Constants::MTG_COLOR_RED) - (int) r->data->hasColor(Constants::MTG_COLOR_RED);
int isG = (int) l->data->hasColor(Constants::MTG_COLOR_GREEN) - (int) r->data->hasColor(Constants::MTG_COLOR_GREEN);
int isArt = (int) l->data->hasType(Subtypes::TYPE_ARTIFACT) - (int) r->data->hasType(Subtypes::TYPE_ARTIFACT);
int isLand = (int) l->data->hasType(Subtypes::TYPE_LAND) - (int) r->data->hasType(Subtypes::TYPE_LAND);
//Nested if hell. TODO: Farm these out to their own objects as a user-defined filter/sort system.
if (!isLand)
{
int isBasic = (int) l->data->hasType("Basic") - (int) r->data->hasType("Basic");
if (!isBasic)
{
if (!isArt)
{
if (lc == rc)
{
if (!isG)
{
if (!isR)
{
if (!isB)
{
if (!isU)
{
if (!isW)
{
string ln = l->data->getLCName();
string rn = r->data->getLCName();
if (ln.substr(0, 4) == "the ") ln = ln.substr(4);
if (rn.substr(0, 4) == "the ") rn = rn.substr(4);
return (ln < rn);
}
return (isW < 0);
}
return (isU < 0);
}
return (isB < 0);
}
return (isR < 0);
}
return (isG < 0);
}
return (lc < rc);
}
return (isArt < 0);
}
else
return (isBasic < 0);
}
return (isLand < 0);
}