Files
wagic/projects/mtg/src/GameStateShop.cpp
wrenczes@gmail.com 76cba56a1c Resuming on my threading support work with the card caching mechanism. This change unfortunately touches quite a few files, but I needed to get it out of the way before things got out of hand: one significant hurdle is the assumed lifetime of a JQuad pointer. In a single threaded model, the life time of the pointer is clear: you fetch it into the cache, the cache makes room, you use the pointer immediately. In a multithreaded context however, it's unsafe, as the drawing thread can request a few JQuads, and the cache operating on a separate thread can potentially bounce a JQuad out of the cache before the draw routine is done using it, which ends up in an access violation when you attempt to draw using an invalidated quad pointer. To prevent this, the bulk of this change swaps out the use of naked JQuad* pointers in the code with a JQuadPtr, which is basically a typedef to a boost shared_ptr<JQuad>.
This btw points out another circular dependancy between the texture and the JQuad - a texture owns a bunch of JQuads, yet the renderer uses JQuads and always assumes that the texture is valid.  We're going to need to add more defensiveness to JGE to protect against this.

Other changes in this check-in:  WResourceManager doesn't derive from JResourceManager anymore.  It actually didn't require anything from the base, so I killed the dependency.  Also cleaned up the notion of a WTrackedQuad in the WCachedResource - it didn't need a separate class, just a better container.

I've build this & tested against PSP, win, linux, QT (linux).  I haven't tried against iOS and QT Win, or Maemo.  If these other platforms are broken, I apologize in advance! - I'm hoping it should be fairly simple to put them back into play.
2011-02-01 10:37:21 +00:00

1001 lines
29 KiB
C++

/*
The shop is where the player can buy cards, decks...
*/
#include "PrecompiledHeader.h"
#include <JRenderer.h>
#include "GameStateShop.h"
#include "GameApp.h"
#include "MTGDeck.h"
#include "MTGPack.h"
#include "Translate.h"
#include "GameOptions.h"
#include "TestSuiteAI.h"
#include <hge/hgedistort.h>
float GameStateShop::_x1[] = { 79, 19, 27, 103, 154, 187, 102, 144, 198, 133, 183 };
float GameStateShop::_y1[] = { 150, 194, 222, 167, 164, 156, 195, 190, 175, 220, 220 };
float GameStateShop::_x2[] = { 103, 48, 74, 135, 183, 215, 138, 181, 231, 171, 225 };
float GameStateShop::_y2[] = { 155, 179, 218, 165, 166, 155, 195, 186, 177, 225, 216 };
float GameStateShop::_x3[] = { 48, 61, 9, 96, 139, 190, 81, 146, 187, 97, 191 };
float GameStateShop::_y3[] = { 164, 205, 257, 184, 180, 170, 219, 212, 195, 251, 252 };
float GameStateShop::_x4[] = { 76, 90, 65, 131, 171, 221, 123, 187, 225, 141, 237 };
float GameStateShop::_y4[] = { 169, 188, 250, 182, 182, 168, 220, 208, 198, 259, 245 };
namespace
{
float kGamepadIconSize = 0.5f;
std::string kOtherCardsString(": Other cards");
std::string kCreditsString("Credits: ");
}
BoosterDisplay::BoosterDisplay(int id, GameObserver* game, int x, int y, JGuiListener * listener, TargetChooser * tc,
int nb_displayed_items) :
CardDisplay(id, game, x, y, listener, tc, nb_displayed_items)
{
}
bool BoosterDisplay::CheckUserInput(JButton key)
{
if (JGE_BTN_UP == key || JGE_BTN_DOWN == key)
return false;
return CardDisplay::CheckUserInput(key);
}
GameStateShop::GameStateShop(GameApp* parent) :
GameState(parent)
{
menu = NULL;
for (int i = 0; i < 8; i++)
altThumb[i] = NULL;
boosterDisplay = NULL;
taskList = NULL;
srcCards = NULL;
shopMenu = NULL;
bigDisplay = NULL;
myCollection = NULL;
packlist = NULL;
pricelist = NULL;
playerdata = NULL;
booster = NULL;
lightAlpha = 0;
filterMenu = NULL;
alphaChange = 0;
for (int i = 0; i < SHOP_ITEMS; i++)
{
mPrices[i] = 0;
mCounts[i] = 0;
}
mTouched = false;
kOtherCardsString = _(kOtherCardsString);
kCreditsString = _(kCreditsString);
}
GameStateShop::~GameStateShop()
{
End();
}
void GameStateShop::Create()
{
}
void GameStateShop::Start()
{
menu = NULL;
bListCards = false;
mTouched = false;
mStage = STAGE_FADE_IN;
mElapsed = 0;
needLoad = true;
booster = NULL;
srcCards = NEW WSrcUnlockedCards(0);
srcCards->setElapsed(15);
srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterRarity("T")));
srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterSet(MTGSets::INTERNAL_SET)));
bigSync = 0;
shopMenu = NEW WGuiMenu(JGE_BTN_DOWN, JGE_BTN_UP, true, &bigSync);
MTGAllCards * ac = GameApp::collection;
playerdata = NEW PlayerData(ac);
myCollection = NEW DeckDataWrapper(playerdata->collection);
pricelist = NEW PriceList(JGE_GET_RES("settings/prices.dat").c_str(), ac);
for (int i = 0; i < SHOP_SLOTS; i++)
{
WGuiCardDistort * dist;
if (i < BOOSTER_SLOTS)
dist = NEW WGuiCardDistort(NULL, true);
else
{
dist = NEW WGuiCardDistort(srcCards, true);
dist->mOffset.setOffset(i - BOOSTER_SLOTS);
}
dist->xy = WDistort(_x1[i], _y1[i], _x2[i], _y2[i], _x3[i], _y3[i], _x4[i], _y4[i]);
shopMenu->Add(NEW WGuiButton(dist, -102, i, this));
}
shopMenu->Entering(JGE_BTN_NONE);
if (!bigDisplay)
{
bigDisplay = NEW WGuiCardImage(srcCards);
bigDisplay->mOffset.Hook(&bigSync);
bigDisplay->mOffset.setOffset(-BOOSTER_SLOTS);
bigDisplay->setX(385);
bigDisplay->setY(135);
}
//alternateRender doesn't lock, so lock our thumbnails for hgeDistort.
altThumb[0] = WResourceManager::Instance()->RetrieveTexture("artifact_thumb.jpg", RETRIEVE_LOCK);
altThumb[1] = WResourceManager::Instance()->RetrieveTexture("green_thumb.jpg", RETRIEVE_LOCK);
altThumb[2] = WResourceManager::Instance()->RetrieveTexture("blue_thumb.jpg", RETRIEVE_LOCK);
altThumb[3] = WResourceManager::Instance()->RetrieveTexture("red_thumb.jpg", RETRIEVE_LOCK);
altThumb[4] = WResourceManager::Instance()->RetrieveTexture("black_thumb.jpg", RETRIEVE_LOCK);
altThumb[5] = WResourceManager::Instance()->RetrieveTexture("white_thumb.jpg", RETRIEVE_LOCK);
altThumb[6] = WResourceManager::Instance()->RetrieveTexture("land_thumb.jpg", RETRIEVE_LOCK);
altThumb[7] = WResourceManager::Instance()->RetrieveTexture("gold_thumb.jpg", RETRIEVE_LOCK);
for (int i = 0; i < 8; ++i)
{
std::ostringstream stream;
stream << "iconspsp" << i;
pspIcons[i] = WResourceManager::Instance()->RetrieveQuad("iconspsp.png", (float) i * 32, 0, 32, 32, stream.str(), RETRIEVE_MANAGE);
pspIcons[i]->SetHotSpot(16, 16);
}
JRenderer::GetInstance()->EnableVSync(true);
taskList = NULL;
packlist = NEW MTGPacks();
packlist->loadAll();
load();
}
string GameStateShop::descPurchase(int controlId, bool tiny)
{
char buffer[4096];
string name;
if (controlId < BOOSTER_SLOTS)
{
name = mBooster[controlId].getName();
}
else
{
MTGCard * c = srcCards->getCard(controlId - BOOSTER_SLOTS);
if (!c)
return "";
name = _(c->data->getName());
}
if (mInventory[controlId] <= 0)
{
if (tiny)
sprintf(buffer, _("SOLD OUT").c_str(), name.c_str());
else
sprintf(buffer, _("%s : SOLD OUT").c_str(), name.c_str());
return buffer;
}
if (tiny)
{
if (controlId < BOOSTER_SLOTS || mCounts[controlId] == 0)
return name;
sprintf(buffer, _("%s (%i)").c_str(), name.c_str(), mCounts[controlId]);
return buffer;
}
switch (options[Options::ECON_DIFFICULTY].number)
{
case Constants::ECON_HARD:
case Constants::ECON_NORMAL:
if (mCounts[controlId] < 1)
sprintf(buffer, _("%s").c_str(), name.c_str());
else
sprintf(buffer, _("%s (%i)").c_str(), name.c_str(), mCounts[controlId]);
break;
default:
if (mCounts[controlId] < 1)
sprintf(buffer, _("%s : %i credits").c_str(), name.c_str(), mPrices[controlId]);
else
sprintf(buffer, _("%s (%i) : %i credits").c_str(), name.c_str(), mCounts[controlId], mPrices[controlId]);
break;
}
return buffer;
}
void GameStateShop::beginPurchase(int controlId)
{
WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MENU_FONT);
mFont->SetScale(DEFAULT_MENU_FONT_SCALE);
SAFE_DELETE(menu);
if (mInventory[controlId] <= 0)
{
menu = NEW SimpleMenu(-145, this, Fonts::MENU_FONT, SCREEN_WIDTH - 300, SCREEN_HEIGHT / 2, _("Sold Out").c_str());
menu->Add(-1, "Ok");
}
else if (playerdata->credits - mPrices[controlId] < 0)
{
menu = NEW SimpleMenu(-145, this, Fonts::MENU_FONT, SCREEN_WIDTH - 300, SCREEN_HEIGHT / 2, _("Not enough credits").c_str());
menu->Add(-1, "Ok");
if (options[Options::CHEATMODE].number)
{
menu->Add(-2, "Steal it");
}
}
else
{
char buf[512];
if (controlId < BOOSTER_SLOTS)
sprintf(buf, _("Purchase Booster: %i credits").c_str(), mPrices[controlId]);
else
sprintf(buf, _("Purchase Card: %i credits").c_str(), mPrices[controlId]);
menu = NEW SimpleMenu(-145, this, Fonts::MENU_FONT, SCREEN_WIDTH - 300, SCREEN_HEIGHT / 2, buf);
menu->Add(controlId, "Yes");
menu->Add(-1, "No");
}
}
void GameStateShop::cancelCard(int controlId)
{
//Update prices
MTGCard * c = srcCards->getCard(controlId - BOOSTER_SLOTS);
if (!c || !c->data || playerdata->credits - mPrices[controlId] < 0)
return; //We only care about their opinion if they /can/ buy it.
int price = mPrices[controlId];
int rnd;
switch (options[Options::ECON_DIFFICULTY].number)
{
case Constants::ECON_HARD:
rnd = rand() % 10;
break;
case Constants::ECON_EASY:
rnd = rand() % 50;
break;
default:
rnd = rand() % 25;
break;
}
price = price - (rnd * price) / 100;
if (price < pricelist->getPrice(c->getMTGId())) //filters have a tendancy to increase the price instead of lowering it!
pricelist->setPrice(c->getMTGId(), price);
//Prices do not immediately go down when you ignore something.
return;
}
void GameStateShop::cancelBooster(int controlId)
{
return; //TODO FIXME Tie boosters into pricelist.
}
void GameStateShop::purchaseCard(int controlId)
{
MTGCard * c = srcCards->getCard(controlId - BOOSTER_SLOTS);
if (!c || !c->data || playerdata->credits - mPrices[controlId] < 0)
return;
myCollection->Add(c);
int price = mPrices[controlId];
pricelist->setPrice(c->getMTGId(), price); // In case they changed their minds after cancelling.
playerdata->credits -= price;
//Update prices
int rnd;
switch (options[Options::ECON_DIFFICULTY].number)
{
case Constants::ECON_HARD:
rnd = rand() % 50;
break;
case Constants::ECON_EASY:
rnd = rand() % 10;
break;
default:
rnd = rand() % 25;
break;
}
price = price + (rnd * price) / 100;
pricelist->setPrice(c->getMTGId(), price);
mPrices[controlId] = pricelist->getPurchasePrice(c->getMTGId()); //Prices go up immediately.
mInventory[controlId]--;
updateCounts();
mTouched = true;
menu->Close();
}
void GameStateShop::purchaseBooster(int controlId)
{
if (playerdata->credits - mPrices[controlId] < 0)
return;
playerdata->credits -= mPrices[controlId];
mInventory[controlId]--;
SAFE_DELETE(booster);
deleteDisplay();
booster = NEW MTGDeck(mParent->collection);
boosterDisplay = NEW BoosterDisplay(12, NULL, SCREEN_WIDTH - 200, SCREEN_HEIGHT / 2, this, NULL, 5);
mBooster[controlId].addToDeck(booster, srcCards);
string sort = mBooster[controlId].getSort();
DeckDataWrapper * ddw = NEW DeckDataWrapper(booster);
if (sort == "alpha")
ddw->Sort(WSrcCards::SORT_ALPHA);
else if (sort == "collector")
ddw->Sort(WSrcCards::SORT_COLLECTOR);
else
ddw->Sort(WSrcCards::SORT_RARITY);
for (int x = 0; x < ddw->Size(); x++)
{
MTGCard * c = ddw->getCard(x);
MTGCardInstance * ci = NEW MTGCardInstance(c, NULL);
boosterDisplay->AddCard(ci);
subBooster.push_back(ci);
}
SAFE_DELETE(ddw);
myCollection->loadMatches(booster);
mTouched = true;
save(true);
menu->Close();
}
int GameStateShop::purchasePrice(int offset)
{
MTGCard * c = NULL;
if (!pricelist || !srcCards || (c = srcCards->getCard(offset)) == NULL)
return 0;
float price = (float) pricelist->getPurchasePrice(c->getMTGId());
int filteradd = srcCards->Size(true);
filteradd = ((filteradd - srcCards->Size()) / filteradd);
switch (options[Options::ECON_DIFFICULTY].number)
{
case Constants::ECON_EASY:
filteradd /= 2;
break;
case Constants::ECON_HARD:
filteradd *= 2;
break;
default:
break;
}
return (int) (price + price * (filteradd * srcCards->filterFee()));
}
void GameStateShop::updateCounts()
{
for (int i = BOOSTER_SLOTS; i < SHOP_ITEMS; i++)
{
MTGCard * c = srcCards->getCard(i - BOOSTER_SLOTS);
if (!c)
mCounts[i] = 0;
else
mCounts[i] = myCollection->countByName(c);
}
}
void GameStateShop::load()
{
for (int i = 0; i < BOOSTER_SLOTS; i++)
{
mBooster[i].randomize(packlist);
mInventory[i] = 1 + rand() % mBooster[i].maxInventory();
mPrices[i] = pricelist->getOtherPrice(mBooster[i].basePrice());
}
for (int i = BOOSTER_SLOTS; i < SHOP_ITEMS; i++)
{
MTGCard * c = NULL;
if ((c = srcCards->getCard(i - BOOSTER_SLOTS)) == NULL)
{
mPrices[i] = 0;
mCounts[i] = 0;
mInventory[i] = 0;
continue;
}
mPrices[i] = purchasePrice(i - BOOSTER_SLOTS);
mCounts[i] = myCollection->countByName(c);
switch (c->getRarity())
{
case Constants::RARITY_C:
mInventory[i] = 2 + rand() % 8;
break;
case Constants::RARITY_L:
mInventory[i] = 100;
break;
default: //We're using some non-coded rarities (S) in cards.dat.
case Constants::RARITY_U:
mInventory[i] = 1 + rand() % 5;
break;
case Constants::RARITY_R:
mInventory[i] = 1 + rand() % 2;
break;
}
}
}
void GameStateShop::save(bool force)
{
if (mTouched || force)
{
if (myCollection)
myCollection->Rebuild(playerdata->collection);
if (playerdata)
playerdata->save();
if (pricelist)
pricelist->save();
}
mTouched = false;
}
void GameStateShop::End()
{
save();
JRenderer::GetInstance()->EnableVSync(false);
mElapsed = 0;
SAFE_DELETE(shopMenu);
SAFE_DELETE(bigDisplay);
SAFE_DELETE(srcCards);
SAFE_DELETE(playerdata);
SAFE_DELETE(pricelist);
SAFE_DELETE(myCollection);
SAFE_DELETE(booster);
SAFE_DELETE(filterMenu);
SAFE_DELETE(packlist);
deleteDisplay();
//Release alternate thumbnails.
for (int i = 0; i < 8; i++)
{
WResourceManager::Instance()->Release(altThumb[i]);
altThumb[i] = NULL;
}
SAFE_DELETE(menu);
SAFE_DELETE(taskList);
}
void GameStateShop::Destroy()
{
}
void GameStateShop::beginFilters()
{
if (!filterMenu)
{
filterMenu = NEW WGuiFilters("Ask about...", srcCards);
filterMenu->setY(2);
filterMenu->setHeight(SCREEN_HEIGHT - 2);
}
mStage = STAGE_ASK_ABOUT;
filterMenu->Entering(JGE_BTN_NONE);
}
void GameStateShop::Update(float dt)
{
if (menu && menu->isClosed())
SAFE_DELETE(menu);
srcCards->Update(dt);
alphaChange = 25 - static_cast<int>((float) (rand() - 1) / (RAND_MAX) * 50.0f);
lightAlpha += alphaChange;
if (lightAlpha < 0)
lightAlpha = 0;
if (lightAlpha > 50)
lightAlpha = 50;
// mParent->effect->UpdateSmall(dt);
// mParent->effect->UpdateBig(dt);
if (mStage != STAGE_FADE_IN)
mElapsed += dt;
JButton btn;
switch (mStage)
{
case STAGE_SHOP_PURCHASE:
if (menu)
menu->Update(dt);
beginPurchase(mBuying);
mStage = STAGE_SHOP_SHOP;
break;
case STAGE_SHOP_MENU:
if (menu)
menu->Update(dt);
else
{
menu = NEW SimpleMenu(11, this, Fonts::MENU_FONT, SCREEN_WIDTH / 2 - 100, 20);
menu->Add(22, "Ask about...");
menu->Add(14, "Check task board");
if (options[Options::CHEATMODE].number)
menu->Add(-2, "Steal 1,000 credits");
menu->Add(12, "Save & Back to Main Menu");
menu->Add(kCancelMenuID, "Cancel");
}
break;
case STAGE_SHOP_TASKS:
if (menu)
{
menu->Update(dt);
return;
}
if (taskList)
{
btn = mEngine->ReadButton();
taskList->Update(dt);
if (taskList->getState() != TaskList::TASKS_INACTIVE)
{
if (btn == JGE_BTN_SEC || btn == JGE_BTN_CANCEL || btn == JGE_BTN_PREV)
{
taskList->End();
return;
}
else if (taskList->getState() == TaskList::TASKS_ACTIVE && btn == JGE_BTN_MENU)
{
if (!menu)
{
menu = NEW SimpleMenu(11, this, Fonts::MENU_FONT, SCREEN_WIDTH / 2 - 100, 20);
menu->Add(15, "Return to shop");
menu->Add(12, "Save & Back to Main Menu");
menu->Add(kCancelMenuID, "Cancel");
}
}
}
else
mStage = STAGE_SHOP_SHOP;
}
#ifdef TESTSUITE
if ((mEngine->GetButtonClick(JGE_BTN_PRI)) && (taskList))
{
taskList->passOneDay();
if (taskList->getTaskCount() < 6)
{
taskList->addRandomTask();
taskList->addRandomTask();
}
taskList->save();
}
#endif
break;
case STAGE_ASK_ABOUT:
btn = mEngine->ReadButton();
if (menu && !menu->isClosed())
{
menu->CheckUserInput(btn);
menu->Update(dt);
return;
}
if (filterMenu)
{
if (btn == JGE_BTN_CTRL)
{
needLoad = filterMenu->Finish();
filterMenu->Update(dt);
return;
}
if (filterMenu->isFinished())
{
if (needLoad)
{
srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterRarity("T")));
srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterSet(MTGSets::INTERNAL_SET)));
if (!srcCards->Size())
{
srcCards->clearFilters(); //Repetition of check at end of filterMenu->Finish(), for the token removal
srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterRarity("T")));
srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterSet(MTGSets::INTERNAL_SET)));
}
load();
}
mStage = STAGE_SHOP_SHOP;
}
else
{
filterMenu->CheckUserInput(btn);
filterMenu->Update(dt);
}
return;
}
break;
case STAGE_SHOP_SHOP:
btn = mEngine->ReadButton();
if (menu && !menu->isClosed())
{
menu->CheckUserInput(btn);
menu->Update(dt);
return;
}
if (btn == JGE_BTN_MENU)
{
if (boosterDisplay)
{
deleteDisplay();
return;
}
mStage = STAGE_SHOP_MENU;
return;
}
else if (btn == JGE_BTN_CTRL)
beginFilters();
else if (btn == JGE_BTN_NEXT)
{
mStage = STAGE_SHOP_TASKS;
if (!taskList)
taskList = NEW TaskList();
taskList->Start();
}
else if (btn == JGE_BTN_PRI)
{
srcCards->Shuffle();
load();
}
else if (btn == JGE_BTN_CANCEL)
options[Options::DISABLECARDS].number = !options[Options::DISABLECARDS].number;
else if (boosterDisplay)
{
if (btn == JGE_BTN_SEC)
deleteDisplay();
else
{
boosterDisplay->CheckUserInput(btn);
boosterDisplay->Update(dt);
}
return;
}
else if (btn == JGE_BTN_SEC)
bListCards = !bListCards;
else if (shopMenu)
{
if (shopMenu->CheckUserInput(btn))
srcCards->Touch();
}
if (shopMenu)
shopMenu->Update(dt);
break;
case STAGE_FADE_IN:
mParent->DoAnimation(TRANSITION_FADE_IN);
mStage = STAGE_SHOP_SHOP;
break;
}
}
void GameStateShop::deleteDisplay()
{
vector<MTGCardInstance*>::iterator i;
for (i = subBooster.begin(); i != subBooster.end(); i++)
{
if (!*i)
continue;
delete *i;
}
subBooster.clear();
SAFE_DELETE(boosterDisplay);
}
void GameStateShop::Render()
{
//Erase
WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT);
JRenderer * r = JRenderer::GetInstance();
r->ClearScreen(ARGB(0,0,0,0));
if (mStage == STAGE_FADE_IN)
return;
JQuadPtr mBg = WResourceManager::Instance()->RetrieveTempQuad("shop.jpg", TEXTURE_SUB_5551);
if (mBg.get())
r->RenderQuad(mBg.get(), 0, 0);
JQuadPtr quad = WResourceManager::Instance()->RetrieveTempQuad("shop_light.jpg", TEXTURE_SUB_5551);
if (quad.get())
{
r->EnableTextureFilter(false);
r->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE);
quad->SetColor(ARGB(lightAlpha,255,255,255));
r->RenderQuad(quad.get(), 0, 0);
r->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
r->EnableTextureFilter(true);
}
if (shopMenu)
shopMenu->Render();
if (filterMenu && !filterMenu->isFinished())
filterMenu->Render();
else
{
if (boosterDisplay)
boosterDisplay->Render();
else if (bigDisplay)
{
if (bigDisplay->mOffset.getPos() >= 0)
bigDisplay->setSource(srcCards);
else
bigDisplay->setSource(NULL);
bigDisplay->Render();
float elp = srcCards->getElapsed();
//Render the card list overlay.
if (bListCards || elp > LIST_FADEIN)
{
int alpha = 200;
if (!bListCards && elp < LIST_FADEIN + .25)
{
alpha = static_cast<int> (800 * (elp - LIST_FADEIN));
}
r->FillRoundRect(300, 10, 160, SHOP_SLOTS * 20 + 15, 5, ARGB(alpha,0,0,0));
alpha += 55;
for (int i = 0; i < SHOP_SLOTS; i++)
{
if (i == shopMenu->getSelected())
mFont->SetColor(ARGB(alpha,255,255,0));
else
mFont->SetColor(ARGB(alpha,255,255,255));
char buffer[512];
string s = descPurchase(i, true);
sprintf(buffer, "%s", s.c_str());
float x = 310;
float y = static_cast<float> (25 + 20 * i);
mFont->DrawString(buffer, x, y);
}
}
}
}
//Render the info bar
r->FillRect(0, SCREEN_HEIGHT - 17, SCREEN_WIDTH, 17, ARGB(128,0,0,0));
std::ostringstream stream;
stream << kCreditsString << playerdata->credits;
mFont->SetColor(ARGB(255,255,255,255));
mFont->DrawString(stream.str(), 5, SCREEN_HEIGHT - 14);
float len = 4 + mFont->GetStringWidth(kOtherCardsString.c_str());
r->RenderQuad(pspIcons[6].get(), SCREEN_WIDTH - len - kGamepadIconSize - 10, SCREEN_HEIGHT - 8, 0, kGamepadIconSize, kGamepadIconSize);
mFont->DrawString(kOtherCardsString, SCREEN_WIDTH - len, SCREEN_HEIGHT - 14);
mFont->SetColor(ARGB(255,255,255,0));
mFont->DrawString(descPurchase(bigSync.getPos()).c_str(), SCREEN_WIDTH / 2, SCREEN_HEIGHT - 14, JGETEXT_CENTER);
mFont->SetColor(ARGB(255,255,255,255));
if (mStage == STAGE_SHOP_TASKS && taskList)
{
taskList->Render();
}
if (menu)
menu->Render();
}
void GameStateShop::ButtonPressed(int controllerId, int controlId)
{
int sel = bigSync.getOffset();
switch (controllerId)
{
case -102: //Buying something...
mStage = STAGE_SHOP_PURCHASE;
if (menu)
menu->Close();
mBuying = controlId;
return;
case -145:
if (controlId == -1)
{ //Nope, don't buy.
if (sel < BOOSTER_SLOTS)
cancelBooster(sel);
else
cancelCard(sel);
menu->Close();
mStage = STAGE_SHOP_SHOP;
return;
}
if (sel > -1 && sel < SHOP_ITEMS)
{
if (controlId == -2)
playerdata->credits += mPrices[sel]; //We stole it.
if (sel < BOOSTER_SLOTS) //Clicked a booster.
purchaseBooster(sel);
else
purchaseCard(sel);
//Check if we just scored an award...
if (myCollection && myCollection->totalPrice() > 10000)
{
GameOptionAward * goa = dynamic_cast<GameOptionAward *> (&options[Options::AWARD_COLLECTOR]);
if (goa) goa->giveAward();
}
}
mStage = STAGE_SHOP_SHOP;
return;
}
//Basic Menu.
switch (controlId)
{
case 12:
if (taskList)
taskList->save();
mStage = STAGE_SHOP_SHOP;
mParent->DoTransition(TRANSITION_FADE, GAME_STATE_MENU);
save();
break;
case 14:
mStage = STAGE_SHOP_TASKS;
if (!taskList)
taskList = NEW TaskList();
taskList->Start();
break;
case 15:
if (taskList)
taskList->End();
break;
case 22:
beginFilters();
break;
case -2:
playerdata->credits += 1000;
default:
mStage = STAGE_SHOP_SHOP;
}
menu->Close();
}
//ShopBooster
ShopBooster::ShopBooster()
{
pack = NULL;
mainSet = NULL;
altSet = NULL;
}
string ShopBooster::getSort()
{
if (pack)
return pack->getSort();
return "";
}
;
string ShopBooster::getName()
{
char buffer[512];
if (!mainSet && pack)
return pack->getName();
if (altSet == mainSet)
altSet = NULL;
if (altSet)
sprintf(buffer, _("%s & %s (15 Cards)").c_str(), mainSet->id.c_str(), altSet->id.c_str());
else if (mainSet)
sprintf(buffer, _("%s Booster (15 Cards)").c_str(), mainSet->id.c_str());
return buffer;
}
void ShopBooster::randomize(MTGPacks * packlist)
{
mainSet = NULL;
altSet = NULL;
pack = NULL;
if (!setlist.size())
return;
if (packlist && setlist.size() > 10)
{ //FIXME make these an unlockable item.
int rnd = rand() % 100;
if (rnd <= Constants::CHANCE_CUSTOM_PACK)
{
randomCustom(packlist);
return;
}
}
randomStandard();
}
int ShopBooster::basePrice()
{
if (pack)
return pack->getPrice();
else if (altSet)
return Constants::PRICE_MIXED_BOOSTER;
return Constants::PRICE_BOOSTER;
}
void ShopBooster::randomCustom(MTGPacks * packlist)
{
pack = packlist->randomPack();
if (pack && !pack->isUnlocked())
pack = NULL;
if (!pack)
randomStandard();
}
void ShopBooster::randomStandard()
{
MTGSetInfo * si = setlist.randomSet(-1);
mainSet = si;
altSet = NULL;
int mSetCount = si->counts[MTGSetInfo::TOTAL_CARDS];
if (mSetCount < 80)
{
if (rand() % 100 < Constants::CHANCE_PURE_OVERRIDE)
{ //Chance of picking a pure pack instead.
si = setlist.randomSet(-1, 80);
mSetCount = si->counts[MTGSetInfo::TOTAL_CARDS];
mainSet = si;
}
else
altSet = setlist.randomSet(si->block, 80 - mSetCount);
}
else if (rand() % 100 < Constants::CHANCE_MIXED_OVERRIDE) //Chance of having a mixed booster anyways.
altSet = setlist.randomSet(si->block);
for (int attempts = 0; attempts < 10; attempts++)
{ //Try to prevent altSet == mainSet.
if (altSet != mainSet)
break;
altSet = setlist.randomSet(-1, 80 - mSetCount);
}
if (altSet == mainSet)
altSet = NULL; //Prevent "10E & 10E Booster"
if (!altSet)
pack = mainSet->mPack;
}
int ShopBooster::maxInventory()
{
if (altSet || pack)
return 2;
return 5;
}
void ShopBooster::addToDeck(MTGDeck * d, WSrcCards * srcCards)
{
if (!pack)
{ //A combination booster.
MTGPack * mP = MTGPacks::getDefault();
if (!altSet && mainSet->mPack)
mP = mainSet->mPack;
char buf[512];
if (!altSet)
sprintf(buf, "set:%s;", mainSet->id.c_str());
else
sprintf(buf, "set:%s;|set:%s;", mainSet->id.c_str(), altSet->id.c_str());
mP->pool = buf;
mP->assemblePack(d); //Use the primary packfile. assemblePack deletes pool.
}
else
pack->assemblePack(d);
}
#ifdef TESTSUITE
bool ShopBooster::unitTest()
{
//this tests the default random pack creation.
MTGDeck * d = NEW MTGDeck(GameApp::collection);
char result[1024];
randomStandard();
MTGPack * mP = MTGPacks::getDefault();
if(!altSet && mainSet->mPack) mP = mainSet->mPack;
char buf[512];
if(!altSet) sprintf(buf,"set:%s;",mainSet->id.c_str());
else sprintf(buf,"set:%s;|set:%s;",mainSet->id.c_str(),altSet->id.c_str());
mP->pool = buf;
mP->assemblePack(d); //Use the primary packfile. assemblePack deletes pool.
DeckDataWrapper* ddw = NEW DeckDataWrapper(d);
bool res = true;
int u = 0, r = 0;
int card = 0;
for(int i=0;i<ddw->Size(true);i++)
{
MTGCard * c = ddw->getCard(i);
if(!c) break;
if(c->getRarity() == Constants::RARITY_R || c->getRarity() == Constants::RARITY_M)
r+=ddw->count(c);
else if(c->getRarity() == Constants::RARITY_U)
u+=ddw->count(c);
card++;
}
int count = ddw->getCount();
SAFE_DELETE(ddw);
SAFE_DELETE(d);
if(r != 1 || u != 3 )
{
sprintf(result, "<span class=\"error\">==Unexpected rarity count==</span><br />");
TestSuite::Log(result);
res = false;
}
if(count < 14)
{
sprintf(result, "<span class=\"error\">==Unexpected card count==</span><br />");
TestSuite::Log(result);
res = false;
}
sprintf(result, "<span class=\"success\">==Test Succesful !==</span><br />");
TestSuite::Log(result);
SAFE_DELETE(ddw);
SAFE_DELETE(d);
return res;
}
#endif