New descriptive text popup feature for deck selection
http://wololo.net/forum/viewtopic.php?f=13&t=2423
This commit is contained in:
+102
-103
@@ -1,103 +1,102 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "DeckEditorMenu.h"
|
||||
#include "DeckDataWrapper.h"
|
||||
#include "DeckStats.h"
|
||||
#include "JTypes.h"
|
||||
#include "GameApp.h"
|
||||
#include <iomanip>
|
||||
|
||||
DeckEditorMenu::DeckEditorMenu(int id, JGuiListener* listener, int fontId, const char * _title, DeckDataWrapper *_selectedDeck,
|
||||
StatsWrapper *stats) :
|
||||
DeckMenu(id, listener, fontId, _title), selectedDeck(_selectedDeck), stw(stats)
|
||||
{
|
||||
backgroundName = "DeckEditorMenuBackdrop";
|
||||
|
||||
deckTitle = selectedDeck ? selectedDeck->parent->meta_name : "";
|
||||
|
||||
mX = 123;
|
||||
mY = 70;
|
||||
starsOffsetX = 50;
|
||||
|
||||
titleX = 110; // center point in title box
|
||||
titleY = 25;
|
||||
titleWidth = 180; // width of inner box of title
|
||||
|
||||
descX = 275;
|
||||
descY = 80;
|
||||
descHeight = 154;
|
||||
descWidth = 175;
|
||||
|
||||
statsHeight = 50;
|
||||
statsWidth = 185;
|
||||
statsX = 280;
|
||||
statsY = 12;
|
||||
|
||||
avatarX = 222;
|
||||
avatarY = 8;
|
||||
|
||||
float scrollerWidth = 80;
|
||||
SAFE_DELETE(scroller); // need to delete the scroller init in the base class
|
||||
scroller = NEW TextScroller(Fonts::MAIN_FONT, 40, 230, scrollerWidth, 100, 1, 1);
|
||||
|
||||
}
|
||||
|
||||
void DeckEditorMenu::Render()
|
||||
{
|
||||
JRenderer *r = JRenderer::GetInstance();
|
||||
r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(200,0,0,0));
|
||||
|
||||
DeckMenu::Render();
|
||||
if (deckTitle.size() > 0)
|
||||
{
|
||||
WFont *mainFont = resources.GetWFont(Fonts::OPTION_FONT);
|
||||
DWORD currentColor = mainFont->GetColor();
|
||||
mainFont->SetColor(ARGB(255,255,255,255));
|
||||
mainFont->DrawString(deckTitle.c_str(), statsX + (statsWidth / 2), statsHeight / 2, JGETEXT_CENTER);
|
||||
mainFont->SetColor(currentColor);
|
||||
}
|
||||
|
||||
if (stw && selectedDeck)
|
||||
drawDeckStatistics();
|
||||
|
||||
}
|
||||
|
||||
void DeckEditorMenu::drawDeckStatistics()
|
||||
{
|
||||
ostringstream deckStatsString;
|
||||
|
||||
deckStatsString
|
||||
<< "------- Deck Summary -----" << endl
|
||||
<< "Cards: "<< selectedDeck->getCount() << endl
|
||||
<< "Creatures: "<< setw(2) << stw->countCreatures
|
||||
<< " Enchantments: " << stw->countEnchantments << endl
|
||||
<< "Instants: " << setw(4) << stw->countInstants
|
||||
<< " Sorceries: " << setw(2) << stw->countSorceries << endl
|
||||
<< "Lands: "
|
||||
<< "A: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_ARTIFACT ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_ARTIFACT ] << " "
|
||||
<< "G: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_GREEN ] + stw->countLandsPerColor[ Constants::MTG_COLOR_GREEN ] << " "
|
||||
<< "R: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_RED ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_RED ] << " "
|
||||
<< "U: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_BLUE ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_BLUE ] << " "
|
||||
<< "B: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_BLACK ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_BLACK ] << " "
|
||||
<< "W: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_WHITE ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_WHITE ] << endl
|
||||
|
||||
<< " --- Card color count --- " << endl
|
||||
<< "A: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_ARTIFACT) << " "
|
||||
<< "G: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_GREEN) << " "
|
||||
<< "U: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_BLUE) << " "
|
||||
<< "R: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_RED) << " "
|
||||
<< "B: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_BLACK) << " "
|
||||
<< "W: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_WHITE) << endl
|
||||
|
||||
<< " --- Average Cost --- " << endl
|
||||
<< "Creature: "<< setprecision(2) << stw->avgCreatureCost << endl
|
||||
<< "Mana: " << setprecision(2) << stw->avgManaCost << " "
|
||||
<< "Spell: " << setprecision(2) << stw->avgSpellCost << endl;
|
||||
|
||||
WFont *mainFont = resources.GetWFont( Fonts::MAIN_FONT );
|
||||
mainFont->DrawString( deckStatsString.str().c_str(), descX, descY + 25 );
|
||||
}
|
||||
|
||||
DeckEditorMenu::~DeckEditorMenu()
|
||||
{
|
||||
SAFE_DELETE( scroller );
|
||||
}
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "DeckEditorMenu.h"
|
||||
#include "DeckDataWrapper.h"
|
||||
#include "DeckStats.h"
|
||||
#include "JTypes.h"
|
||||
#include "GameApp.h"
|
||||
#include <iomanip>
|
||||
|
||||
DeckEditorMenu::DeckEditorMenu(int id, JGuiListener* listener, int fontId, const char * _title, DeckDataWrapper *_selectedDeck, StatsWrapper *stats) :
|
||||
DeckMenu(id, listener, fontId, _title), selectedDeck(_selectedDeck), stw(stats)
|
||||
{
|
||||
backgroundName = "DeckEditorMenuBackdrop";
|
||||
|
||||
deckTitle = selectedDeck ? selectedDeck->parent->meta_name : "";
|
||||
enableDetails = false;
|
||||
|
||||
mX = 123;
|
||||
mY = 70;
|
||||
starsOffsetX = 50;
|
||||
|
||||
titleX = 110; // center point in title box
|
||||
titleY = 25;
|
||||
titleWidth = 180; // width of inner box of title
|
||||
|
||||
descX = 275;
|
||||
descY = 80;
|
||||
descHeight = 154;
|
||||
descWidth = 175;
|
||||
|
||||
statsHeight = 50;
|
||||
statsWidth = 185;
|
||||
statsX = 280;
|
||||
statsY = 12;
|
||||
|
||||
avatarX = 222;
|
||||
avatarY = 8;
|
||||
|
||||
float scrollerWidth = 80;
|
||||
SAFE_DELETE(scroller); // need to delete the scroller init in the base class
|
||||
this->showDetailsScreen = false;
|
||||
scroller = NEW TextScroller(Fonts::MAIN_FONT, 40, 230, scrollerWidth, 100, 1, 1);
|
||||
|
||||
}
|
||||
|
||||
void DeckEditorMenu::Render()
|
||||
{
|
||||
JRenderer *r = JRenderer::GetInstance();
|
||||
r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(200,0,0,0));
|
||||
|
||||
DeckMenu::Render();
|
||||
if (deckTitle.size() > 0)
|
||||
{
|
||||
WFont *mainFont = resources.GetWFont(Fonts::OPTION_FONT);
|
||||
DWORD currentColor = mainFont->GetColor();
|
||||
mainFont->SetColor(ARGB(255,255,255,255));
|
||||
mainFont->DrawString(deckTitle.c_str(), statsX + (statsWidth / 2), statsHeight / 2, JGETEXT_CENTER);
|
||||
mainFont->SetColor(currentColor);
|
||||
}
|
||||
|
||||
if (stw && selectedDeck) drawDeckStatistics();
|
||||
|
||||
}
|
||||
|
||||
void DeckEditorMenu::drawDeckStatistics()
|
||||
{
|
||||
ostringstream deckStatsString;
|
||||
|
||||
deckStatsString
|
||||
<< "------- Deck Summary -----" << endl
|
||||
<< "Cards: "<< stw->cardCount << endl
|
||||
<< "Creatures: "<< setw(2) << stw->countCreatures
|
||||
<< " Enchantments: " << stw->countEnchantments << endl
|
||||
<< "Instants: " << setw(4) << stw->countInstants
|
||||
<< " Sorceries: " << setw(2) << stw->countSorceries << endl
|
||||
<< "Lands: "
|
||||
<< "A: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_ARTIFACT ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_ARTIFACT ] << " "
|
||||
<< "G: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_GREEN ] + stw->countLandsPerColor[ Constants::MTG_COLOR_GREEN ] << " "
|
||||
<< "R: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_RED ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_RED ] << " "
|
||||
<< "U: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_BLUE ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_BLUE ] << " "
|
||||
<< "B: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_BLACK ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_BLACK ] << " "
|
||||
<< "W: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_WHITE ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_WHITE ] << endl
|
||||
<< " --- Card color count --- " << endl
|
||||
<< "A: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_ARTIFACT) << " "
|
||||
<< "G: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_GREEN) << " "
|
||||
<< "U: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_BLUE) << " "
|
||||
<< "R: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_RED) << " "
|
||||
<< "B: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_BLACK) << " "
|
||||
<< "W: " << setw(2) << left << selectedDeck->getCount(Constants::MTG_COLOR_WHITE) << endl
|
||||
|
||||
<< " --- Average Cost --- " << endl
|
||||
<< "Creature: "<< setprecision(2) << stw->avgCreatureCost << endl
|
||||
<< "Mana: " << setprecision(2) << stw->avgManaCost << " "
|
||||
<< "Spell: " << setprecision(2) << stw->avgSpellCost << endl;
|
||||
|
||||
WFont *mainFont = resources.GetWFont(Fonts::MAIN_FONT);
|
||||
mainFont->DrawString(deckStatsString.str().c_str(), descX, descY + 25);
|
||||
}
|
||||
|
||||
DeckEditorMenu::~DeckEditorMenu()
|
||||
{
|
||||
SAFE_DELETE( scroller );
|
||||
}
|
||||
|
||||
+328
-281
@@ -1,281 +1,328 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "DeckMenu.h"
|
||||
#include "DeckMenuItem.h"
|
||||
#include "DeckMetaData.h"
|
||||
#include "JTypes.h"
|
||||
#include "GameApp.h"
|
||||
#include "Translate.h"
|
||||
#include "TextScroller.h"
|
||||
#include "Tasks.h"
|
||||
#include <iomanip>
|
||||
|
||||
namespace
|
||||
{
|
||||
const float kVerticalMargin = 16;
|
||||
const float kHorizontalMargin = 20;
|
||||
const float kLineHeight = 20;
|
||||
const float kDescriptionVerticalBoxPadding = 5;
|
||||
const float kDescriptionHorizontalBoxPadding = 5;
|
||||
}
|
||||
|
||||
hgeParticleSystem* DeckMenu::stars = NULL;
|
||||
|
||||
//
|
||||
// For the additional info window, maximum characters per line is roughly 30 characters across.
|
||||
// TODO: figure a way to get incoming text to wrap.
|
||||
//
|
||||
// used fixed locations where the menu, title and descriptive text are located.
|
||||
// * menu at (125, 60 )
|
||||
// * descriptive information 125
|
||||
// *** Need to make this configurable in a file somewhere to allow for class reuse
|
||||
|
||||
DeckMenu::DeckMenu(int id, JGuiListener* listener, int fontId, const string _title, const float& mFontScale) :
|
||||
JGuiController(id, listener), fontId(fontId), menuFontScale(mFontScale)
|
||||
{
|
||||
|
||||
backgroundName = "DeckMenuBackdrop";
|
||||
|
||||
mY = 55;
|
||||
mWidth = 176;
|
||||
mX = 125;
|
||||
|
||||
titleX = 130; // center point in title box
|
||||
titleY = 28;
|
||||
titleWidth = 180; // width of inner box of title
|
||||
|
||||
descX = 230 + kDescriptionVerticalBoxPadding;
|
||||
descY = 65 + kDescriptionHorizontalBoxPadding;
|
||||
descHeight = 145;
|
||||
descWidth = 220;
|
||||
|
||||
starsOffsetX = 50;
|
||||
|
||||
statsX = 280;
|
||||
statsY = 8;
|
||||
statsHeight = 50;
|
||||
statsWidth = 227;
|
||||
|
||||
avatarX = 230;
|
||||
avatarY = 8;
|
||||
|
||||
menuInitialized = false;
|
||||
|
||||
float scrollerWidth = 80;
|
||||
scroller = NEW TextScroller(Fonts::MAIN_FONT, 40, 230, scrollerWidth, 100, 1, 1);
|
||||
|
||||
autoTranslate = true;
|
||||
maxItems = 7;
|
||||
mHeight = 2 * kVerticalMargin + (maxItems * kLineHeight);
|
||||
|
||||
// we want to cap the deck titles to 15 characters to avoid overflowing deck names
|
||||
title = _(_title);
|
||||
displayTitle = title;
|
||||
mFont = resources.GetWFont(fontId);
|
||||
|
||||
startId = 0;
|
||||
selectionT = 0;
|
||||
timeOpen = 0;
|
||||
closed = false;
|
||||
|
||||
if (mFont->GetStringWidth(title.c_str()) > titleWidth)
|
||||
titleFontScale = 0.75f;
|
||||
else
|
||||
titleFontScale = 1.0f;
|
||||
|
||||
selectionTargetY = selectionY = kVerticalMargin;
|
||||
|
||||
if (NULL == stars)
|
||||
stars = NEW hgeParticleSystem(resources.RetrievePSI("stars.psi", resources.GetQuad("stars")));
|
||||
stars->FireAt(mX, mY);
|
||||
|
||||
updateScroller();
|
||||
}
|
||||
|
||||
void DeckMenu::RenderBackground()
|
||||
{
|
||||
ostringstream bgFilename;
|
||||
bgFilename << backgroundName << ".png";
|
||||
|
||||
static bool loadBackground = true;
|
||||
if (loadBackground)
|
||||
{
|
||||
JQuad *background = resources.RetrieveTempQuad(bgFilename.str(), TEXTURE_SUB_5551);
|
||||
if (background)
|
||||
JRenderer::GetInstance()->RenderQuad(background, 0, 0);
|
||||
else
|
||||
loadBackground = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DeckMenu::initMenuItems()
|
||||
{
|
||||
float sY = mY + kVerticalMargin;
|
||||
for (int i = startId; i < startId + mCount; ++i)
|
||||
{
|
||||
float y = mY + kVerticalMargin + i * kLineHeight;
|
||||
DeckMenuItem * currentMenuItem = static_cast<DeckMenuItem*> (mObjects[i]);
|
||||
currentMenuItem->Relocate(mX, y);
|
||||
if (currentMenuItem->hasFocus())
|
||||
sY = y;
|
||||
}
|
||||
selectionTargetY = selectionY = sY;
|
||||
}
|
||||
|
||||
void DeckMenu::Render()
|
||||
{
|
||||
JRenderer * renderer = JRenderer::GetInstance();
|
||||
float height = mHeight;
|
||||
|
||||
if (!menuInitialized)
|
||||
{
|
||||
initMenuItems();
|
||||
stars->Fire();
|
||||
timeOpen = 0;
|
||||
menuInitialized = true;
|
||||
}
|
||||
if (timeOpen < 1)
|
||||
height *= timeOpen > 0 ? timeOpen : -timeOpen;
|
||||
|
||||
renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE);
|
||||
stars->Render();
|
||||
renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
for (int i = startId; i < startId + maxItems; i++)
|
||||
{
|
||||
if (i > mCount - 1)
|
||||
break;
|
||||
DeckMenuItem *currentMenuItem = static_cast<DeckMenuItem*> (mObjects[i]);
|
||||
if (currentMenuItem->mY - kLineHeight * startId < mY + height - kLineHeight + 7)
|
||||
{
|
||||
if (currentMenuItem->hasFocus())
|
||||
{
|
||||
// display the avatar image
|
||||
if (currentMenuItem->imageFilename.size() > 0)
|
||||
{
|
||||
JQuad * quad = resources.RetrieveTempQuad(currentMenuItem->imageFilename, TEXTURE_SUB_AVATAR);
|
||||
if (quad)
|
||||
renderer->RenderQuad(quad, avatarX, avatarY);
|
||||
}
|
||||
// fill in the description part of the screen
|
||||
string text = currentMenuItem->desc;
|
||||
WFont *mainFont = resources.GetWFont(Fonts::MAIN_FONT);
|
||||
mainFont->DrawString(text.c_str(), descX, descY);
|
||||
mFont->SetColor(ARGB(255,255,255,255));
|
||||
|
||||
// fill in the statistical portion
|
||||
if (currentMenuItem->meta)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "Deck: " << currentMenuItem->meta->getName() << endl;
|
||||
oss << currentMenuItem->meta->getStatsSummary();
|
||||
|
||||
mainFont->DrawString(oss.str(), statsX, statsY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mFont->SetColor(ARGB(150,255,255,255));
|
||||
}
|
||||
mFont->SetScale(menuFontScale);
|
||||
currentMenuItem->RenderWithOffset(-kLineHeight * startId);
|
||||
}
|
||||
}
|
||||
|
||||
RenderBackground();
|
||||
|
||||
if (!title.empty())
|
||||
{
|
||||
mFont->SetColor(ARGB(255,255,255,255));
|
||||
mFont->SetScale(titleFontScale);
|
||||
mFont->DrawString(title.c_str(), titleX, titleY, JGETEXT_CENTER);
|
||||
}
|
||||
mFont->SetScale(1.0f);
|
||||
scroller->Render();
|
||||
|
||||
}
|
||||
|
||||
void DeckMenu::Update(float dt)
|
||||
{
|
||||
JGuiController::Update(dt);
|
||||
if (mCurr > startId + maxItems - 1)
|
||||
startId = mCurr - maxItems + 1;
|
||||
else if (mCurr < startId)
|
||||
startId = mCurr;
|
||||
stars->Update(dt);
|
||||
selectionT += 3 * dt;
|
||||
selectionY += (selectionTargetY - selectionY) * 8 * dt;
|
||||
|
||||
float starsX = starsOffsetX + ((mWidth - 2 * kHorizontalMargin) * (1 + cos(selectionT)) / 2);
|
||||
float starsY = selectionY + 5 * cos(selectionT * 2.35f) + kLineHeight / 2 - kLineHeight * startId;
|
||||
stars->MoveTo(starsX, starsY);
|
||||
if (timeOpen < 0)
|
||||
{
|
||||
timeOpen += dt * 10;
|
||||
if (timeOpen >= 0)
|
||||
{
|
||||
timeOpen = 0;
|
||||
closed = true;
|
||||
stars->FireAt(mX, mY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
closed = false;
|
||||
timeOpen += dt * 10;
|
||||
}
|
||||
|
||||
scroller->Update(dt);
|
||||
}
|
||||
|
||||
void DeckMenu::Add(int id, const char * text, string desc, bool forceFocus, DeckMetaData * deckMetaData)
|
||||
{
|
||||
DeckMenuItem * menuItem = NEW DeckMenuItem(this, id, fontId, text, 0, mY + kVerticalMargin + mCount * kLineHeight,
|
||||
(mCount == 0), autoTranslate, deckMetaData);
|
||||
Translator * t = Translator::GetInstance();
|
||||
map<string, string>::iterator it = t->deckValues.find(text);
|
||||
if (it != t->deckValues.end()) //translate decks desc
|
||||
menuItem->desc = it->second;
|
||||
else
|
||||
menuItem->desc = deckMetaData ? deckMetaData->getDescription() : desc;
|
||||
|
||||
JGuiController::Add(menuItem);
|
||||
if (mCount <= maxItems)
|
||||
mHeight += kLineHeight;
|
||||
if (forceFocus)
|
||||
{
|
||||
mObjects[mCurr]->Leaving(JGE_BTN_DOWN);
|
||||
mCurr = mCount - 1;
|
||||
menuItem->Entering();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckMenu::updateScroller()
|
||||
{
|
||||
// add all the items from the Tasks db.
|
||||
TaskList taskList;
|
||||
scroller->Reset();
|
||||
for (vector<Task*>::iterator it = taskList.tasks.begin(); it != taskList.tasks.end(); it++)
|
||||
{
|
||||
ostringstream taskDescription;
|
||||
taskDescription << "[ " << setw(4) << (*it)->getReward() << " / " << (*it)->getExpiration() << " ] "
|
||||
<< (*it)->getDesc() << endl;
|
||||
scroller->Add(taskDescription.str());
|
||||
}
|
||||
}
|
||||
|
||||
void DeckMenu::Close()
|
||||
{
|
||||
timeOpen = -1.0;
|
||||
stars->Stop(true);
|
||||
}
|
||||
|
||||
void DeckMenu::destroy()
|
||||
{
|
||||
SAFE_DELETE(DeckMenu::stars);
|
||||
}
|
||||
|
||||
DeckMenu::~DeckMenu()
|
||||
{
|
||||
SAFE_DELETE(scroller);
|
||||
}
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "DeckMenu.h"
|
||||
#include "DeckMenuItem.h"
|
||||
#include "DeckMetaData.h"
|
||||
#include "JTypes.h"
|
||||
#include "GameApp.h"
|
||||
#include "Translate.h"
|
||||
#include "TextScroller.h"
|
||||
#include "Tasks.h"
|
||||
#include <iomanip>
|
||||
|
||||
namespace
|
||||
{
|
||||
const float kVerticalMargin = 16;
|
||||
const float kHorizontalMargin = 20;
|
||||
const float kLineHeight = 20;
|
||||
const float kDescriptionVerticalBoxPadding = 5;
|
||||
const float kDescriptionHorizontalBoxPadding = 5;
|
||||
const int DETAILED_INFO_THRESHOLD = 4;
|
||||
}
|
||||
|
||||
hgeParticleSystem* DeckMenu::stars = NULL;
|
||||
|
||||
//
|
||||
// For the additional info window, maximum characters per line is roughly 30 characters across.
|
||||
// TODO: figure a way to get incoming text to wrap.
|
||||
//
|
||||
// used fixed locations where the menu, title and descriptive text are located.
|
||||
// * menu at (125, 60 )
|
||||
// * descriptive information 125
|
||||
// *** Need to make this configurable in a file somewhere to allow for class reuse
|
||||
|
||||
DeckMenu::DeckMenu(int id, JGuiListener* listener, int fontId, const string _title, const int& startIndex, const float& mFontScale) :
|
||||
JGuiController(id, listener), fontId(fontId), menuFontScale(mFontScale)
|
||||
{
|
||||
|
||||
backgroundName = "DeckMenuBackdrop";
|
||||
|
||||
selectedDeck = NULL;
|
||||
enableDetails = true;
|
||||
mY = 55;
|
||||
mWidth = 176;
|
||||
mX = 125;
|
||||
|
||||
titleX = 130; // center point in title box
|
||||
titleY = 28;
|
||||
titleWidth = 180; // width of inner box of title
|
||||
|
||||
descX = 230 + kDescriptionVerticalBoxPadding;
|
||||
descY = 65 + kDescriptionHorizontalBoxPadding;
|
||||
descHeight = 145;
|
||||
descWidth = 220;
|
||||
|
||||
detailedInfoBoxX = 400;
|
||||
detailedInfoBoxY = 235;
|
||||
starsOffsetX = 50;
|
||||
|
||||
statsX = 280;
|
||||
statsY = 8;
|
||||
statsHeight = 50;
|
||||
statsWidth = 227;
|
||||
|
||||
selectedDeckId = startIndex;
|
||||
|
||||
avatarX = 230;
|
||||
avatarY = 8;
|
||||
|
||||
menuInitialized = false;
|
||||
|
||||
float scrollerWidth = 80;
|
||||
scroller = NEW TextScroller(Fonts::MAIN_FONT, 40, 230, scrollerWidth, 100, 1, 1);
|
||||
|
||||
autoTranslate = true;
|
||||
maxItems = 7;
|
||||
mHeight = 2 * kVerticalMargin + (maxItems * kLineHeight);
|
||||
|
||||
// we want to cap the deck titles to 15 characters to avoid overflowing deck names
|
||||
title = _(_title);
|
||||
displayTitle = title;
|
||||
mFont = resources.GetWFont(fontId);
|
||||
|
||||
startId = 0;
|
||||
selectionT = 0;
|
||||
timeOpen = 0;
|
||||
closed = false;
|
||||
|
||||
if (mFont->GetStringWidth(title.c_str()) > titleWidth)
|
||||
titleFontScale = 0.75f;
|
||||
else
|
||||
titleFontScale = 1.0f;
|
||||
|
||||
selectionTargetY = selectionY = kVerticalMargin;
|
||||
|
||||
if (NULL == stars) stars = NEW hgeParticleSystem(resources.RetrievePSI("stars.psi", resources.GetQuad("stars")));
|
||||
stars->FireAt(mX, mY);
|
||||
|
||||
updateScroller();
|
||||
}
|
||||
|
||||
void DeckMenu::RenderBackground()
|
||||
{
|
||||
ostringstream bgFilename;
|
||||
bgFilename << backgroundName << ".png";
|
||||
|
||||
static bool loadBackground = true;
|
||||
if (loadBackground)
|
||||
{
|
||||
JQuad *background = resources.RetrieveTempQuad(bgFilename.str(), TEXTURE_SUB_5551);
|
||||
if (background)
|
||||
JRenderer::GetInstance()->RenderQuad(background, 0, 0);
|
||||
else
|
||||
loadBackground = false;
|
||||
}
|
||||
}
|
||||
|
||||
DeckMetaData * DeckMenu::getSelectedDeck()
|
||||
{
|
||||
if (selectedDeck) return selectedDeck;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool DeckMenu::selectedDeckHasDetails()
|
||||
{
|
||||
DeckMetaData * currentMenuItem = getSelectedDeck();
|
||||
if (currentMenuItem) return (enableDetails && currentMenuItem->getGamesPlayed() > DETAILED_INFO_THRESHOLD);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeckMenu::initMenuItems()
|
||||
{
|
||||
float sY = mY + kVerticalMargin;
|
||||
for (int i = startId; i < startId + mCount; ++i)
|
||||
{
|
||||
float y = mY + kVerticalMargin + i * kLineHeight;
|
||||
DeckMenuItem * currentMenuItem = static_cast<DeckMenuItem*> (mObjects[i]);
|
||||
currentMenuItem->Relocate(mX, y);
|
||||
if (currentMenuItem->hasFocus()) sY = y;
|
||||
}
|
||||
selectionTargetY = selectionY = sY;
|
||||
|
||||
//Grab a texture in VRAM.
|
||||
pspIconsTexture = resources.RetrieveTexture("iconspsp.png", RETRIEVE_LOCK);
|
||||
|
||||
char buf[512];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
sprintf(buf, "iconspsp%d", i);
|
||||
pspIcons[i] = resources.RetrieveQuad("iconspsp.png", (float) i * 32, 0, 32, 32, buf);
|
||||
pspIcons[i]->SetHotSpot(16, 16);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DeckMenu::Render()
|
||||
{
|
||||
JRenderer * renderer = JRenderer::GetInstance();
|
||||
float height = mHeight;
|
||||
|
||||
if (!menuInitialized)
|
||||
{
|
||||
initMenuItems();
|
||||
stars->Fire();
|
||||
timeOpen = 0;
|
||||
menuInitialized = true;
|
||||
}
|
||||
if (timeOpen < 1) height *= timeOpen > 0 ? timeOpen : -timeOpen;
|
||||
|
||||
for (int i = startId; i < startId + maxItems; i++)
|
||||
{
|
||||
if (i > mCount - 1) break;
|
||||
DeckMenuItem *currentMenuItem = static_cast<DeckMenuItem*> (mObjects[i]);
|
||||
if (currentMenuItem->mY - kLineHeight * startId < mY + height - kLineHeight + 7)
|
||||
{
|
||||
if (currentMenuItem->hasFocus())
|
||||
{
|
||||
selectedDeckId = i;
|
||||
selectedDeck = currentMenuItem->meta;
|
||||
|
||||
WFont *mainFont = resources.GetWFont(Fonts::MAIN_FONT);
|
||||
|
||||
// display the "more info" button if special condition is met
|
||||
if (selectedDeckHasDetails())
|
||||
{
|
||||
showDetailsScreen = true;
|
||||
float pspIconsSize = 0.5;
|
||||
const string detailedInfoString = "Detailed Info";
|
||||
float stringWidth = mainFont->GetStringWidth(detailedInfoString.c_str());
|
||||
float boxStartX = detailedInfoBoxX - stringWidth / 2;
|
||||
DWORD currentColor = mainFont->GetColor();
|
||||
renderer->FillRoundRect( boxStartX, detailedInfoBoxY - 5, stringWidth,
|
||||
mainFont->GetHeight() + 15, .5, ARGB( 125, 0, 255, 255) );
|
||||
renderer->RenderQuad(pspIcons[5], detailedInfoBoxX, detailedInfoBoxY + 2, 0, pspIconsSize, pspIconsSize);
|
||||
mainFont->SetColor(currentColor);
|
||||
mainFont->DrawString(detailedInfoString, boxStartX, detailedInfoBoxY + 10);
|
||||
}
|
||||
else
|
||||
showDetailsScreen = false;
|
||||
|
||||
// display the avatar image
|
||||
if (currentMenuItem->imageFilename.size() > 0)
|
||||
{
|
||||
JQuad * quad = resources.RetrieveTempQuad(currentMenuItem->imageFilename, TEXTURE_SUB_AVATAR);
|
||||
if (quad) renderer->RenderQuad(quad, avatarX, avatarY);
|
||||
}
|
||||
// fill in the description part of the screen
|
||||
string text = currentMenuItem->desc;
|
||||
mainFont->DrawString(text.c_str(), descX, descY);
|
||||
mFont->SetColor(ARGB(255,255,255,255));
|
||||
|
||||
// fill in the statistical portion
|
||||
if (currentMenuItem->meta)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "Deck: " << currentMenuItem->meta->getName() << endl;
|
||||
oss << currentMenuItem->meta->getStatsSummary();
|
||||
|
||||
mainFont->DrawString(oss.str(), statsX, statsY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mFont->SetColor(ARGB(150,255,255,255));
|
||||
}
|
||||
mFont->SetScale(menuFontScale);
|
||||
currentMenuItem->RenderWithOffset(-kLineHeight * startId);
|
||||
}
|
||||
}
|
||||
|
||||
RenderBackground();
|
||||
|
||||
if (!title.empty())
|
||||
{
|
||||
mFont->SetColor(ARGB(255,255,255,255));
|
||||
mFont->SetScale(titleFontScale);
|
||||
mFont->DrawString(title.c_str(), titleX, titleY, JGETEXT_CENTER);
|
||||
}
|
||||
mFont->SetScale(1.0f);
|
||||
scroller->Render();
|
||||
|
||||
}
|
||||
|
||||
void DeckMenu::Update(float dt)
|
||||
{
|
||||
JGuiController::Update(dt);
|
||||
if (mCurr > startId + maxItems - 1)
|
||||
startId = mCurr - maxItems + 1;
|
||||
else if (mCurr < startId) startId = mCurr;
|
||||
stars->Update(dt);
|
||||
selectionT += 3 * dt;
|
||||
selectionY += (selectionTargetY - selectionY) * 8 * dt;
|
||||
|
||||
float starsX = starsOffsetX + ((mWidth - 2 * kHorizontalMargin) * (1 + cos(selectionT)) / 2);
|
||||
float starsY = selectionY + 5 * cos(selectionT * 2.35f) + kLineHeight / 2 - kLineHeight * startId;
|
||||
stars->MoveTo(starsX, starsY);
|
||||
if (timeOpen < 0)
|
||||
{
|
||||
timeOpen += dt * 10;
|
||||
if (timeOpen >= 0)
|
||||
{
|
||||
timeOpen = 0;
|
||||
closed = true;
|
||||
stars->FireAt(mX, mY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
closed = false;
|
||||
timeOpen += dt * 10;
|
||||
}
|
||||
if (scroller) scroller->Update(dt);
|
||||
}
|
||||
|
||||
void DeckMenu::Add(int id, const char * text, string desc, bool forceFocus, DeckMetaData * deckMetaData)
|
||||
{
|
||||
DeckMenuItem * menuItem = NEW DeckMenuItem(this, id, fontId, text, 0, mY + kVerticalMargin + mCount * kLineHeight,
|
||||
(mCount == 0), autoTranslate, deckMetaData);
|
||||
Translator * t = Translator::GetInstance();
|
||||
map<string, string>::iterator it = t->deckValues.find(text);
|
||||
if (it != t->deckValues.end()) //translate decks desc
|
||||
menuItem->desc = it->second;
|
||||
else
|
||||
menuItem->desc = deckMetaData ? deckMetaData->getDescription() : desc;
|
||||
|
||||
JGuiController::Add(menuItem);
|
||||
if (mCount <= maxItems) mHeight += kLineHeight;
|
||||
|
||||
if (forceFocus)
|
||||
{
|
||||
mObjects[mCurr]->Leaving(JGE_BTN_DOWN);
|
||||
mCurr = mCount - 1;
|
||||
menuItem->Entering();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckMenu::updateScroller()
|
||||
{
|
||||
// add all the items from the Tasks db.
|
||||
TaskList taskList;
|
||||
scroller->Reset();
|
||||
for (vector<Task*>::iterator it = taskList.tasks.begin(); it != taskList.tasks.end(); it++)
|
||||
{
|
||||
ostringstream taskDescription;
|
||||
taskDescription << "[ " << setw(4) << (*it)->getReward() << " / " << (*it)->getExpiration() << " ] "
|
||||
<< (*it)->getDesc() << endl;
|
||||
scroller->Add(taskDescription.str());
|
||||
}
|
||||
}
|
||||
|
||||
void DeckMenu::Close()
|
||||
{
|
||||
timeOpen = -1.0;
|
||||
stars->Stop(true);
|
||||
}
|
||||
|
||||
void DeckMenu::destroy()
|
||||
{
|
||||
SAFE_DELETE(DeckMenu::stars);
|
||||
}
|
||||
|
||||
DeckMenu::~DeckMenu()
|
||||
{
|
||||
resources.Release(pspIconsTexture);
|
||||
SAFE_DELETE(scroller);
|
||||
scroller = NULL;
|
||||
}
|
||||
|
||||
+466
-242
@@ -1,242 +1,466 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "DeckStats.h"
|
||||
#include "Player.h"
|
||||
#include "GameObserver.h"
|
||||
|
||||
DeckStats * DeckStats::mInstance = NULL;
|
||||
|
||||
int DeckStat::percentVictories()
|
||||
{
|
||||
if (nbgames == 0)
|
||||
return 50;
|
||||
return (100 * victories / nbgames);
|
||||
}
|
||||
|
||||
DeckStats * DeckStats::GetInstance()
|
||||
{
|
||||
if (!mInstance)
|
||||
{
|
||||
mInstance = NEW DeckStats();
|
||||
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
void DeckStats::cleanStats()
|
||||
{
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
SAFE_DELETE(it->second);
|
||||
}
|
||||
|
||||
stats.clear();
|
||||
}
|
||||
|
||||
DeckStats::~DeckStats()
|
||||
{
|
||||
cleanStats();
|
||||
}
|
||||
|
||||
int DeckStats::percentVictories(string opponentsFile)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponentsFile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (it->second->percentVictories());
|
||||
}
|
||||
}
|
||||
|
||||
DeckStat* DeckStats::getDeckStat(string opponentsFile)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponentsFile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
int DeckStats::nbGames()
|
||||
{
|
||||
int nbgames = 0;
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
DeckStat * d = it->second;
|
||||
nbgames += d->nbgames;
|
||||
}
|
||||
return nbgames;
|
||||
}
|
||||
|
||||
int DeckStats::percentVictories()
|
||||
{
|
||||
int victories = 0;
|
||||
int nbgames = 0;
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
DeckStat * d = it->second;
|
||||
nbgames += d->nbgames;
|
||||
victories += d->victories;
|
||||
}
|
||||
if (nbgames)
|
||||
{
|
||||
return (victories * 100) / nbgames;
|
||||
}
|
||||
return 50;
|
||||
}
|
||||
|
||||
void DeckStats::load(Player * player)
|
||||
{
|
||||
char filename[512];
|
||||
sprintf(filename, "stats/%s.txt", player->deckFileSmall.c_str());
|
||||
load(options.profileFile(filename).c_str());
|
||||
}
|
||||
|
||||
void DeckStats::load(const char * filename)
|
||||
{
|
||||
cleanStats();
|
||||
std::ifstream file(filename);
|
||||
std::string s;
|
||||
|
||||
if (file)
|
||||
{
|
||||
while (std::getline(file, s))
|
||||
{
|
||||
string deckfile = s;
|
||||
std::getline(file, s);
|
||||
int games = atoi(s.c_str());
|
||||
std::getline(file, s);
|
||||
int victories = atoi(s.c_str());
|
||||
map<string, DeckStat *>::iterator it = stats.find(deckfile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
stats[deckfile] = NEW DeckStat(games, victories);
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckStats::save(Player * player)
|
||||
{
|
||||
char filename[512];
|
||||
sprintf(filename, "stats/%s.txt", player->deckFileSmall.c_str());
|
||||
save(options.profileFile(filename).c_str());
|
||||
}
|
||||
|
||||
void DeckStats::save(const char * filename)
|
||||
{
|
||||
std::ofstream file(filename);
|
||||
char writer[512];
|
||||
if (file)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
sprintf(writer, "%s\n", it->first.c_str());
|
||||
file << writer;
|
||||
sprintf(writer, "%i\n", it->second->nbgames);
|
||||
file << writer;
|
||||
sprintf(writer, "%i\n", it->second->victories);
|
||||
file << writer;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckStats::saveStats(Player *player, Player *opponent, GameObserver * game)
|
||||
{
|
||||
int victory = 1;
|
||||
if (!game->gameOver)
|
||||
{
|
||||
if (player->life == opponent->life)
|
||||
return;
|
||||
if (player->life < opponent->life)
|
||||
victory = 0;
|
||||
}
|
||||
else if (game->gameOver == player)
|
||||
{
|
||||
victory = 0;
|
||||
}
|
||||
load(player);
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponent->deckFileSmall);
|
||||
if (it == stats.end())
|
||||
{
|
||||
stats[opponent->deckFileSmall] = NEW DeckStat(1, victory);
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second->victories += victory;
|
||||
it->second->nbgames += 1;
|
||||
}
|
||||
save(player);
|
||||
}
|
||||
|
||||
StatsWrapper::StatsWrapper(int deckId)
|
||||
{
|
||||
// Load deck statistics
|
||||
char buffer[512];
|
||||
DeckStats * stats = DeckStats::GetInstance();
|
||||
aiDeckNames.clear();
|
||||
aiDeckStats.clear();
|
||||
|
||||
sprintf(buffer, "stats/player_deck%i.txt", deckId);
|
||||
string deckstats = options.profileFile(buffer);
|
||||
|
||||
if (fileExists(deckstats.c_str()))
|
||||
{
|
||||
stats->load(deckstats.c_str());
|
||||
percentVictories = stats->percentVictories();
|
||||
gamesPlayed = stats->nbGames();
|
||||
|
||||
// Detailed deck statistics against AI
|
||||
int found = 1;
|
||||
int nbDecks = 0;
|
||||
while (found)
|
||||
{
|
||||
found = 0;
|
||||
char buffer[512];
|
||||
char smallDeckName[512];
|
||||
sprintf(buffer, "%s/deck%i.txt", RESPATH"/ai/baka", nbDecks + 1);
|
||||
if (fileExists(buffer))
|
||||
{
|
||||
MTGDeck * mtgd = NEW MTGDeck(buffer, NULL, 1);
|
||||
found = 1;
|
||||
nbDecks++;
|
||||
|
||||
sprintf(smallDeckName, "%s_deck%i", "ai_baka", nbDecks);
|
||||
DeckStat* deckStat = stats->getDeckStat(string(smallDeckName));
|
||||
|
||||
if ((deckStat != NULL) && (deckStat->nbgames > 0))
|
||||
{
|
||||
int percentVictories = stats->percentVictories(string(smallDeckName));
|
||||
aiDeckNames.push_back(string(mtgd->meta_name));
|
||||
aiDeckStats.push_back(deckStat);
|
||||
}
|
||||
|
||||
delete mtgd;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gamesPlayed = 0;
|
||||
percentVictories = 0;
|
||||
}
|
||||
}
|
||||
|
||||
StatsWrapper::~StatsWrapper()
|
||||
{
|
||||
aiDeckNames.clear();
|
||||
aiDeckStats.clear();
|
||||
}
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "DeckStats.h"
|
||||
#include "Player.h"
|
||||
#include "GameObserver.h"
|
||||
#include "MTGDeck.h"
|
||||
#include "ManaCostHybrid.h"
|
||||
|
||||
DeckStats * DeckStats::mInstance = NULL;
|
||||
|
||||
DeckStat::DeckStat(int _nbgames, int _victories) : nbgames(_nbgames), victories(_victories)
|
||||
{
|
||||
}
|
||||
|
||||
int DeckStat::percentVictories()
|
||||
{
|
||||
if (nbgames == 0) return 50;
|
||||
return (100 * victories / nbgames);
|
||||
}
|
||||
|
||||
DeckStats * DeckStats::GetInstance()
|
||||
{
|
||||
if (!mInstance)
|
||||
{
|
||||
mInstance = NEW DeckStats();
|
||||
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
void DeckStats::cleanStats()
|
||||
{
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
SAFE_DELETE(it->second);
|
||||
}
|
||||
|
||||
stats.clear();
|
||||
}
|
||||
|
||||
DeckStats::~DeckStats()
|
||||
{
|
||||
cleanStats();
|
||||
}
|
||||
|
||||
int DeckStats::percentVictories(string opponentsFile)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponentsFile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (it->second->percentVictories());
|
||||
}
|
||||
}
|
||||
|
||||
DeckStat* DeckStats::getDeckStat(string opponentsFile)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponentsFile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
int DeckStats::nbGames()
|
||||
{
|
||||
int nbgames = 0;
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
DeckStat * d = it->second;
|
||||
nbgames += d->nbgames;
|
||||
}
|
||||
return nbgames;
|
||||
}
|
||||
|
||||
int DeckStats::percentVictories()
|
||||
{
|
||||
int victories = 0;
|
||||
int nbgames = 0;
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
DeckStat * d = it->second;
|
||||
nbgames += d->nbgames;
|
||||
victories += d->victories;
|
||||
}
|
||||
if (nbgames)
|
||||
{
|
||||
return (victories * 100) / nbgames;
|
||||
}
|
||||
return 50;
|
||||
}
|
||||
|
||||
void DeckStats::load(Player * player)
|
||||
{
|
||||
char filename[512];
|
||||
sprintf(filename, "stats/%s.txt", player->deckFileSmall.c_str());
|
||||
load(options.profileFile(filename).c_str());
|
||||
}
|
||||
|
||||
void DeckStats::load(const char * filename)
|
||||
{
|
||||
cleanStats();
|
||||
std::ifstream file(filename);
|
||||
std::string s;
|
||||
|
||||
if (file)
|
||||
{
|
||||
while (std::getline(file, s))
|
||||
{
|
||||
string deckfile = s;
|
||||
std::getline(file, s);
|
||||
int games = atoi(s.c_str());
|
||||
std::getline(file, s);
|
||||
int victories = atoi(s.c_str());
|
||||
map<string, DeckStat *>::iterator it = stats.find(deckfile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
stats[deckfile] = NEW DeckStat(games, victories);
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckStats::save(Player * player)
|
||||
{
|
||||
char filename[512];
|
||||
sprintf(filename, "stats/%s.txt", player->deckFileSmall.c_str());
|
||||
save(options.profileFile(filename).c_str());
|
||||
}
|
||||
|
||||
void DeckStats::save(const char * filename)
|
||||
{
|
||||
std::ofstream file(filename);
|
||||
char writer[512];
|
||||
if (file)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
sprintf(writer, "%s\n", it->first.c_str());
|
||||
file << writer;
|
||||
sprintf(writer, "%i\n", it->second->nbgames);
|
||||
file << writer;
|
||||
sprintf(writer, "%i\n", it->second->victories);
|
||||
file << writer;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckStats::saveStats(Player *player, Player *opponent, GameObserver * game)
|
||||
{
|
||||
int victory = 1;
|
||||
if (!game->gameOver)
|
||||
{
|
||||
if (player->life == opponent->life) return;
|
||||
if (player->life < opponent->life) victory = 0;
|
||||
}
|
||||
else if (game->gameOver == player)
|
||||
{
|
||||
victory = 0;
|
||||
}
|
||||
load(player);
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponent->deckFileSmall);
|
||||
if (it == stats.end())
|
||||
{
|
||||
stats[opponent->deckFileSmall] = NEW DeckStat(1, victory);
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second->victories += victory;
|
||||
it->second->nbgames += 1;
|
||||
}
|
||||
save(player);
|
||||
}
|
||||
StatsWrapper::StatsWrapper(int deckId)
|
||||
{
|
||||
mDeckId = deckId;
|
||||
char buffer[512];
|
||||
sprintf(buffer, "stats/player_deck%i.txt", deckId);
|
||||
string deckstats = options.profileFile(buffer);
|
||||
initStatistics(deckstats);
|
||||
}
|
||||
|
||||
StatsWrapper::StatsWrapper(string deckstats)
|
||||
{
|
||||
initStatistics(deckstats);
|
||||
}
|
||||
|
||||
void StatsWrapper::initStatistics(string deckstats)
|
||||
{
|
||||
// Load deck statistics
|
||||
DeckStats * stats = DeckStats::GetInstance();
|
||||
aiDeckNames.clear();
|
||||
aiDeckStats.clear();
|
||||
|
||||
if (fileExists(deckstats.c_str()))
|
||||
{
|
||||
stats->load(deckstats.c_str());
|
||||
percentVictories = stats->percentVictories();
|
||||
gamesPlayed = stats->nbGames();
|
||||
|
||||
// Detailed deck statistics against AI
|
||||
int found = 1;
|
||||
int nbDecks = 0;
|
||||
found = 0;
|
||||
char buffer[512];
|
||||
char smallDeckName[512];
|
||||
sprintf(buffer, "%s/deck%i.txt", RESPATH"/ai/baka", nbDecks + 1);
|
||||
if (fileExists(buffer))
|
||||
{
|
||||
MTGDeck * mtgd = NEW MTGDeck(buffer, NULL, 1);
|
||||
found = 1;
|
||||
nbDecks++;
|
||||
|
||||
sprintf(smallDeckName, "%s_deck%i", "ai_baka", nbDecks);
|
||||
DeckStat* deckStat = stats->getDeckStat(string(smallDeckName));
|
||||
|
||||
if ((deckStat != NULL) && (deckStat->nbgames > 0))
|
||||
{
|
||||
int percentVictories = stats->percentVictories(string(smallDeckName));
|
||||
aiDeckNames.push_back(string(mtgd->meta_name));
|
||||
aiDeckStats.push_back(deckStat);
|
||||
}
|
||||
|
||||
delete mtgd;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gamesPlayed = 0;
|
||||
percentVictories = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void StatsWrapper::updateStats(string filename, MTGAllCards *collection)
|
||||
{
|
||||
if (fileExists(filename.c_str()))
|
||||
{
|
||||
MTGDeck * mtgd = NEW MTGDeck(filename.c_str(), collection);
|
||||
DeckDataWrapper *deckDataWrapper = NEW DeckDataWrapper(mtgd);
|
||||
updateStats(deckDataWrapper);
|
||||
SAFE_DELETE( mtgd );
|
||||
SAFE_DELETE( deckDataWrapper );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void StatsWrapper::updateStats(DeckDataWrapper *myDeck)
|
||||
{
|
||||
if (!this->needUpdate || !myDeck) return;
|
||||
this->needUpdate = false;
|
||||
this->cardCount = myDeck->getCount(WSrcDeck::UNFILTERED_COPIES);
|
||||
this->countLands = myDeck->getCount(Constants::MTG_COLOR_LAND);
|
||||
this->totalPrice = myDeck->totalPrice();
|
||||
|
||||
this->countManaProducers = 0;
|
||||
// Mana cost
|
||||
int currentCount, convertedCost;
|
||||
ManaCost * currentCost;
|
||||
this->totalManaCost = 0;
|
||||
this->totalCreatureCost = 0;
|
||||
this->totalSpellCost = 0;
|
||||
MTGCard * current = myDeck->getCard();
|
||||
|
||||
// Clearing arrays
|
||||
for (int i = 0; i <= Constants::STATS_MAX_MANA_COST; i++)
|
||||
{
|
||||
this->countCardsPerCost[i] = 0;
|
||||
this->countCreaturesPerCost[i] = 0;
|
||||
this->countSpellsPerCost[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= Constants::MTG_NB_COLORS; i++)
|
||||
{
|
||||
this->totalCostPerColor[i] = 0;
|
||||
this->countLandsPerColor[i] = 0;
|
||||
this->countBasicLandsPerColor[i] = 0;
|
||||
this->countNonLandProducersPerColor[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= Constants::STATS_MAX_MANA_COST; i++)
|
||||
{
|
||||
for (int k = 0; k <= Constants::MTG_NB_COLORS; k++)
|
||||
{
|
||||
this->countCardsPerCostAndColor[i][k] = 0;
|
||||
this->countCreaturesPerCostAndColor[i][k] = 0;
|
||||
this->countSpellsPerCostAndColor[i][k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int ic = 0; ic < myDeck->Size(true); ic++)
|
||||
{
|
||||
current = myDeck->getCard(ic, true);
|
||||
currentCost = current->data->getManaCost();
|
||||
convertedCost = currentCost->getConvertedCost();
|
||||
currentCount = myDeck->count(current);
|
||||
|
||||
// Add to the cards per cost counters
|
||||
this->totalManaCost += convertedCost * currentCount;
|
||||
if (convertedCost > Constants::STATS_MAX_MANA_COST)
|
||||
{
|
||||
convertedCost = Constants::STATS_MAX_MANA_COST;
|
||||
}
|
||||
this->countCardsPerCost[convertedCost] += currentCount;
|
||||
if (current->data->isCreature())
|
||||
{
|
||||
this->countCreaturesPerCost[convertedCost] += currentCount;
|
||||
this->totalCreatureCost += convertedCost * currentCount;
|
||||
}
|
||||
else if (current->data->isSpell())
|
||||
{
|
||||
this->countSpellsPerCost[convertedCost] += currentCount;
|
||||
this->totalSpellCost += convertedCost * currentCount;
|
||||
}
|
||||
|
||||
// Lets look for mana producing abilities
|
||||
|
||||
vector<string> abilitiesVector;
|
||||
string thisstring = current->data->magicText;
|
||||
abilitiesVector = split(thisstring, '\n');
|
||||
|
||||
for (int v = 0; v < (int) abilitiesVector.size(); v++)
|
||||
{
|
||||
string s = abilitiesVector[v];
|
||||
size_t t = s.find("add");
|
||||
if (t != string::npos)
|
||||
{
|
||||
s = s.substr(t + 3);
|
||||
ManaCost * mc = ManaCost::parseManaCost(s);
|
||||
for (int j = 0; j < Constants::MTG_NB_COLORS; j++)
|
||||
{
|
||||
if (mc->hasColor(j))
|
||||
{
|
||||
if (current->data->isLand())
|
||||
{
|
||||
if (current->data->hasType("Basic"))
|
||||
{
|
||||
this->countBasicLandsPerColor[j] += currentCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->countLandsPerColor[j] += currentCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->countNonLandProducersPerColor[j] += currentCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
SAFE_DELETE(mc);
|
||||
}
|
||||
}
|
||||
|
||||
// Add to the per color counters
|
||||
// a. regular costs
|
||||
for (int j = 0; j < Constants::MTG_NB_COLORS; j++)
|
||||
{
|
||||
this->totalCostPerColor[j] += currentCost->getCost(j) * currentCount;
|
||||
if (current->data->hasColor(j))
|
||||
{
|
||||
// Add to the per cost and color counter
|
||||
this->countCardsPerCostAndColor[convertedCost][j] += currentCount;
|
||||
if (current->data->isCreature())
|
||||
{
|
||||
this->countCreaturesPerCostAndColor[convertedCost][j] += currentCount;
|
||||
}
|
||||
else if (current->data->isSpell())
|
||||
{
|
||||
this->countSpellsPerCostAndColor[convertedCost][j] += currentCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// b. Hybrid costs
|
||||
ManaCostHybrid * hybridCost;
|
||||
int i;
|
||||
i = 0;
|
||||
|
||||
while ((hybridCost = currentCost->getHybridCost(i++)) != NULL)
|
||||
{
|
||||
this->totalCostPerColor[hybridCost->color1] += hybridCost->value1 * currentCount;
|
||||
this->totalCostPerColor[hybridCost->color2] += hybridCost->value2 * currentCount;
|
||||
}
|
||||
}
|
||||
|
||||
this->totalColoredSymbols = 0;
|
||||
for (int j = 1; j < Constants::MTG_NB_COLORS; j++)
|
||||
{
|
||||
this->totalColoredSymbols += this->totalCostPerColor[j];
|
||||
}
|
||||
|
||||
this->countCardsPerCost[0] -= this->countLands;
|
||||
|
||||
// Counts by type
|
||||
this->countCreatures = countCardsByType("Creature", myDeck);
|
||||
this->countInstants = countCardsByType("Instant", myDeck);
|
||||
this->countEnchantments = countCardsByType("Enchantment", myDeck);
|
||||
this->countSorceries = countCardsByType("Sorcery", myDeck);
|
||||
this->countSpells = this->countInstants + this->countEnchantments + this->countSorceries;
|
||||
//this->countArtifacts = countCardsByType("Artifact", myDeck);
|
||||
|
||||
// Average mana costs
|
||||
this->avgManaCost = ((this->cardCount - this->countLands) <= 0) ? 0 : (float) this->totalManaCost / (this->cardCount
|
||||
- this->countLands);
|
||||
this->avgCreatureCost = (this->countCreatures <= 0) ? 0 : (float) this->totalCreatureCost / this->countCreatures;
|
||||
this->avgSpellCost = (this->countSpells <= 0) ? 0 : (float) this->totalSpellCost / this->countSpells;
|
||||
|
||||
// Probabilities
|
||||
// TODO: this could be optimized by reusing results
|
||||
for (int i = 0; i < Constants::STATS_FOR_TURNS; i++)
|
||||
{
|
||||
this->noLandsProbInTurn[i] = noLuck(this->cardCount, this->countLands, 7 + i) * 100;
|
||||
this->noCreaturesProbInTurn[i] = noLuck(this->cardCount, this->countCreatures, 7 + i) * 100;
|
||||
}
|
||||
}
|
||||
|
||||
// This should probably be cached in DeckDataWrapper
|
||||
// or at least be calculated for all common types in one go
|
||||
int StatsWrapper::countCardsByType(const char * _type, DeckDataWrapper * myDeck)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < myDeck->Size(true); i++)
|
||||
{
|
||||
MTGCard * current = myDeck->getCard(i, true);
|
||||
if (current->data->hasType(_type))
|
||||
{
|
||||
result += myDeck->count(current);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// n cards total, a of them are of desired type (A), x drawn
|
||||
// returns probability of no A's
|
||||
float StatsWrapper::noLuck(int n, int a, int x)
|
||||
{
|
||||
if ((a >= n) || (a == 0)) return 1;
|
||||
if ((n == 0) || (x == 0) || (x > n) || (n - a < x)) return 0;
|
||||
|
||||
a = n - a;
|
||||
float result = 1;
|
||||
|
||||
for (int i = 0; i < x; i++)
|
||||
result *= (float) (a - i) / (n - i);
|
||||
return result;
|
||||
}
|
||||
|
||||
StatsWrapper::~StatsWrapper()
|
||||
{
|
||||
aiDeckNames.clear();
|
||||
aiDeckStats.clear();
|
||||
}
|
||||
|
||||
|
||||
+1812
-1838
File diff suppressed because it is too large
Load Diff
+799
-705
File diff suppressed because it is too large
Load Diff
+1164
-1220
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* SimplePopup.cpp
|
||||
*
|
||||
* Created on: Nov 18, 2010
|
||||
* Author: Michael
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "SimplePopup.h"
|
||||
#include "JTypes.h"
|
||||
#include "GameApp.h"
|
||||
#include "DeckStats.h"
|
||||
#include "DeckManager.h"
|
||||
#include <iomanip>
|
||||
|
||||
SimplePopup::SimplePopup(int id, JGuiListener* listener, const int fontId, const char * _title, DeckMetaData* deckMetaData, MTGAllCards * collection) :
|
||||
JGuiController(id, listener), mFontId(fontId), mCollection(collection)
|
||||
{
|
||||
mX = 35;
|
||||
mY = 50;
|
||||
mTitle = _title;
|
||||
mMaxLines = 10;
|
||||
mTextFont = resources.GetWFont(fontId);
|
||||
this->mCount = 1;
|
||||
stw = NULL;
|
||||
Update(deckMetaData);
|
||||
}
|
||||
|
||||
void SimplePopup::Render()
|
||||
{
|
||||
closed = false;
|
||||
|
||||
JRenderer *r = JRenderer::GetInstance();
|
||||
string detailedInformation = getDetailedInformation(mDeckInformation->getFilename());
|
||||
|
||||
mTextFont->SetScale(0.85f);
|
||||
const float textWidth = 183.0f;
|
||||
const float textHeight = mTextFont->GetHeight() * 10;
|
||||
r->DrawRoundRect(mX, mY, textWidth, textHeight, 2.0f, ARGB( 255, 125, 255, 0) );
|
||||
r->FillRoundRect(mX, mY, textWidth, textHeight, 2.0f, ARGB( 255, 0, 0, 0 ) );
|
||||
|
||||
mTextFont->DrawString(detailedInformation.c_str(), mX + 20 , mY + 10);
|
||||
|
||||
}
|
||||
void SimplePopup::Update(DeckMetaData* selectedDeck)
|
||||
{
|
||||
mDeckInformation = selectedDeck;
|
||||
SAFE_DELETE(stw);
|
||||
stw = NEW StatsWrapper(mDeckInformation->getDeckId());
|
||||
stw->updateStats(mDeckInformation->getFilename(), mCollection);
|
||||
}
|
||||
|
||||
|
||||
string SimplePopup::getDetailedInformation(string filename)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss
|
||||
<< "------- Deck Summary -----" << endl
|
||||
<< "Cards: "<< stw->cardCount << endl
|
||||
<< "Creatures: "<< setw(2) << stw->countCreatures
|
||||
<< " Enchantments: " << stw->countEnchantments << endl
|
||||
<< "Instants: " << setw(4) << stw->countInstants
|
||||
<< " Sorceries: " << setw(2) << stw->countSorceries << endl
|
||||
<< "Lands: "
|
||||
<< "A: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_ARTIFACT ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_ARTIFACT ] << " "
|
||||
<< "G: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_GREEN ] + stw->countLandsPerColor[ Constants::MTG_COLOR_GREEN ] << " "
|
||||
<< "R: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_RED ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_RED ] << " "
|
||||
<< "U: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_BLUE ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_BLUE ] << " "
|
||||
<< "B: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_BLACK ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_BLACK ] << " "
|
||||
<< "W: " << setw(2) << left << stw->countLandsPerColor[ Constants::MTG_COLOR_WHITE ] + stw->countBasicLandsPerColor[ Constants::MTG_COLOR_WHITE ] << endl
|
||||
<< " --- Mana Curve --- " << endl;
|
||||
|
||||
for ( int costIdx = 0; costIdx < 15; ++costIdx )
|
||||
if ( stw->countCardsPerCost[ costIdx ] > 0 )
|
||||
oss << costIdx << ": " << setw(2) << left << stw->countCardsPerCost[ costIdx ] << " ";
|
||||
|
||||
oss << endl;
|
||||
|
||||
oss
|
||||
<< " --- Average Cost --- " << endl
|
||||
<< "Creature: "<< setprecision(2) << stw->avgCreatureCost << endl
|
||||
<< "Mana: " << setprecision(2) << stw->avgManaCost << " "
|
||||
<< "Spell: " << setprecision(2) << stw->avgSpellCost << endl;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void SimplePopup::Update(float dt)
|
||||
{
|
||||
JButton key = mEngine->ReadButton();
|
||||
CheckUserInput(key);
|
||||
}
|
||||
|
||||
void SimplePopup::Close()
|
||||
{
|
||||
closed = true;
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
SimplePopup::~SimplePopup(void)
|
||||
{
|
||||
mTextFont = NULL;
|
||||
mDeckInformation = NULL;
|
||||
SAFE_DELETE(stw);
|
||||
}
|
||||
|
||||
void SimplePopup::drawHorzPole(float x, float y, float width)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SimplePopup::drawVertPole(float x, float y, float height)
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user