From 32cabc15c2875fea6f81ab31a1e37c2f0b55b144 Mon Sep 17 00:00:00 2001 From: "wrenczes@gmail.com" Date: Fri, 28 Jan 2011 06:00:51 +0000 Subject: [PATCH] Forcing LF as the line ending style through SVN properties. No actual code changes here. --- projects/mtg/include/DeckEditorMenu.h | 42 +- projects/mtg/include/DeckManager.h | 86 +- projects/mtg/include/DeckMenu.h | 168 +- projects/mtg/include/DeckStats.h | 218 +- projects/mtg/include/ExtraCost.h | 306 +- projects/mtg/include/GameStateDeckViewer.h | 304 +- projects/mtg/include/GameStateDuel.h | 152 +- projects/mtg/include/Player.h | 226 +- projects/mtg/include/ReplacementEffects.h | 100 +- projects/mtg/include/SimplePopup.h | 116 +- projects/mtg/include/TextScroller.h | 110 +- projects/mtg/include/Token.h | 26 +- projects/mtg/src/DeckEditorMenu.cpp | 200 +- projects/mtg/src/DeckMenu.cpp | 674 ++-- projects/mtg/src/DeckStats.cpp | 1076 +++---- projects/mtg/src/GameStateDeckViewer.cpp | 3304 ++++++++++---------- projects/mtg/src/GameStateDuel.cpp | 1600 +++++----- projects/mtg/src/MTGDeck.cpp | 2474 +++++++-------- projects/mtg/src/MTGGamePhase.cpp | 128 +- projects/mtg/src/ManaCost.cpp | 1472 ++++----- 20 files changed, 6391 insertions(+), 6391 deletions(-) diff --git a/projects/mtg/include/DeckEditorMenu.h b/projects/mtg/include/DeckEditorMenu.h index 45a2a4f22..1a0a1e410 100644 --- a/projects/mtg/include/DeckEditorMenu.h +++ b/projects/mtg/include/DeckEditorMenu.h @@ -1,21 +1,21 @@ -#pragma once -#include "DeckMenu.h" -#include "DeckDataWrapper.h" -#include "DeckStats.h" - -class DeckEditorMenu: public DeckMenu -{ -protected: - string deckTitle; - -private: - void drawDeckStatistics(); - - DeckDataWrapper *selectedDeck; - StatsWrapper *stw; - -public: - DeckEditorMenu(int id, JGuiListener* listener = NULL, int fontId = 1, const char * _title = "", DeckDataWrapper *selectedDeck = NULL, StatsWrapper *stats = NULL); - void Render(); - ~DeckEditorMenu(); -}; +#pragma once +#include "DeckMenu.h" +#include "DeckDataWrapper.h" +#include "DeckStats.h" + +class DeckEditorMenu: public DeckMenu +{ +protected: + string deckTitle; + +private: + void drawDeckStatistics(); + + DeckDataWrapper *selectedDeck; + StatsWrapper *stw; + +public: + DeckEditorMenu(int id, JGuiListener* listener = NULL, int fontId = 1, const char * _title = "", DeckDataWrapper *selectedDeck = NULL, StatsWrapper *stats = NULL); + void Render(); + ~DeckEditorMenu(); +}; diff --git a/projects/mtg/include/DeckManager.h b/projects/mtg/include/DeckManager.h index 6587bc7dd..7138db76a 100644 --- a/projects/mtg/include/DeckManager.h +++ b/projects/mtg/include/DeckManager.h @@ -1,43 +1,43 @@ -#include -#include - -#include "DeckMetaData.h" - -using namespace std; - -class DeckManager -{ -private: - static bool instanceFlag; - static DeckManager *mInstance; - DeckManager() - { - //private constructor - } - -public: - - vector playerDeckOrderList; - vector aiDeckOrderList; - - map playerDeckStatsMap; - map aiDeckStatsMap; - - void updateMetaDataList(vector* refList, bool isAI); - vector * getPlayerDeckOrderList(); - vector * getAIDeckOrderList(); - - DeckMetaData * getDeckMetaDataById( int deckId, bool isAI ); - StatsWrapper * getExtendedStatsForDeckId( int deckId, MTGAllCards *collection, bool isAI ); - StatsWrapper * getExtendedDeckStats( DeckMetaData *selectedDeck, MTGAllCards *collection, bool isAI ); - static DeckManager * GetInstance(); - static void EndInstance(); - - //convenience method to get the difficulty rating between two decks. This should be refined a little more - //since the eventual move of all deck meta data should be managed by this class - - static int getDifficultyRating(Player *statsPlayer, Player *player); - - ~DeckManager(); - -}; +#include +#include + +#include "DeckMetaData.h" + +using namespace std; + +class DeckManager +{ +private: + static bool instanceFlag; + static DeckManager *mInstance; + DeckManager() + { + //private constructor + } + +public: + + vector playerDeckOrderList; + vector aiDeckOrderList; + + map playerDeckStatsMap; + map aiDeckStatsMap; + + void updateMetaDataList(vector* refList, bool isAI); + vector * getPlayerDeckOrderList(); + vector * getAIDeckOrderList(); + + DeckMetaData * getDeckMetaDataById( int deckId, bool isAI ); + StatsWrapper * getExtendedStatsForDeckId( int deckId, MTGAllCards *collection, bool isAI ); + StatsWrapper * getExtendedDeckStats( DeckMetaData *selectedDeck, MTGAllCards *collection, bool isAI ); + static DeckManager * GetInstance(); + static void EndInstance(); + + //convenience method to get the difficulty rating between two decks. This should be refined a little more + //since the eventual move of all deck meta data should be managed by this class + + static int getDifficultyRating(Player *statsPlayer, Player *player); + + ~DeckManager(); + +}; diff --git a/projects/mtg/include/DeckMenu.h b/projects/mtg/include/DeckMenu.h index 59c68074c..08bcda55b 100644 --- a/projects/mtg/include/DeckMenu.h +++ b/projects/mtg/include/DeckMenu.h @@ -1,84 +1,84 @@ -/* - A class for menus with a fixed layout - */ -#ifndef _DeckMenu_H_ -#define _DeckMenu_H_ - -#include -#include "WFont.h" -#include "hge/hgeparticle.h" -#include "DeckMetaData.h" -#include "TextScroller.h" - -class DeckMenu: public JGuiController -{ -protected: - - float mHeight, mWidth, mX, mY; - float titleX, titleY, titleWidth; - float descX, descY, descHeight, descWidth; - float statsX, statsY, statsHeight, statsWidth; - float avatarX, avatarY; - float detailedInfoBoxX, detailedInfoBoxY; - float starsOffsetX; - - bool menuInitialized; - string backgroundName; - - int fontId; - string title; - string displayTitle; - WFont * mFont; - float titleFontScale; - - int maxItems, startId; - - float selectionT, selectionY; - float timeOpen; - - static hgeParticleSystem* stars; - - void initMenuItems(); - string getDescription(); - string getMetaInformation(); - DeckMetaData *mSelectedDeck; - int mSelectedDeckId; - bool mShowDetailsScreen; - bool mAlwaysShowDetailsButton; - bool mClosed; - -public: - VerticalTextScroller * mScroller; - bool mAutoTranslate; - float mSelectionTargetY; - - //used for detailed info button - JQuad * pspIcons[8]; - JTexture * pspIconsTexture; - - DeckMenu(int id, JGuiListener* listener, int fontId, const string _title = "", const int& startIndex = 0, bool alwaysShowDetailsButton = false); - ~DeckMenu(); - - DeckMetaData * getSelectedDeck(); - void enableDisplayDetailsOverride(); - bool showDetailsScreen(); - bool isClosed() - { - return mClosed; - } - int getSelectedDeckId() - { - return mSelectedDeckId; - } - - void Render(); - void Update(float dt); - void Add(int id, const char * Text, string desc = "", bool forceFocus = false, DeckMetaData *deckMetaData = NULL); - void Close(); - void updateScroller(); - void RenderBackground(); - - static void destroy(); -}; - -#endif +/* + A class for menus with a fixed layout + */ +#ifndef _DeckMenu_H_ +#define _DeckMenu_H_ + +#include +#include "WFont.h" +#include "hge/hgeparticle.h" +#include "DeckMetaData.h" +#include "TextScroller.h" + +class DeckMenu: public JGuiController +{ +protected: + + float mHeight, mWidth, mX, mY; + float titleX, titleY, titleWidth; + float descX, descY, descHeight, descWidth; + float statsX, statsY, statsHeight, statsWidth; + float avatarX, avatarY; + float detailedInfoBoxX, detailedInfoBoxY; + float starsOffsetX; + + bool menuInitialized; + string backgroundName; + + int fontId; + string title; + string displayTitle; + WFont * mFont; + float titleFontScale; + + int maxItems, startId; + + float selectionT, selectionY; + float timeOpen; + + static hgeParticleSystem* stars; + + void initMenuItems(); + string getDescription(); + string getMetaInformation(); + DeckMetaData *mSelectedDeck; + int mSelectedDeckId; + bool mShowDetailsScreen; + bool mAlwaysShowDetailsButton; + bool mClosed; + +public: + VerticalTextScroller * mScroller; + bool mAutoTranslate; + float mSelectionTargetY; + + //used for detailed info button + JQuad * pspIcons[8]; + JTexture * pspIconsTexture; + + DeckMenu(int id, JGuiListener* listener, int fontId, const string _title = "", const int& startIndex = 0, bool alwaysShowDetailsButton = false); + ~DeckMenu(); + + DeckMetaData * getSelectedDeck(); + void enableDisplayDetailsOverride(); + bool showDetailsScreen(); + bool isClosed() + { + return mClosed; + } + int getSelectedDeckId() + { + return mSelectedDeckId; + } + + void Render(); + void Update(float dt); + void Add(int id, const char * Text, string desc = "", bool forceFocus = false, DeckMetaData *deckMetaData = NULL); + void Close(); + void updateScroller(); + void RenderBackground(); + + static void destroy(); +}; + +#endif diff --git a/projects/mtg/include/DeckStats.h b/projects/mtg/include/DeckStats.h index d49b716a4..5b410425d 100644 --- a/projects/mtg/include/DeckStats.h +++ b/projects/mtg/include/DeckStats.h @@ -1,109 +1,109 @@ -#ifndef _DECKSTATS_H_ -#define _DECKSTATS_H_ - -#include -#include -#include -#include "MTGDefinitions.h" -#include - -using namespace std; - -class Player; -class GameObserver; - -class DeckStat -{ -public: - DeckStat(int _nbgames = 0, int _victories = 0); - - int nbgames; - int victories; - int percentVictories(); -}; - -class DeckStats -{ -protected: - static DeckStats * mInstance; -public: - //map stats; // current set of statistics - string currentDeck; - map > masterDeckStats; - - static DeckStats * GetInstance(); - static void EndInstance(); - void saveStats(Player * player, Player * opponent, GameObserver * game); - void save(const char * filename); - void save(Player * player); - void load(const char * filename); - void load(Player * player); - void cleanStats(); - ~DeckStats(); - int percentVictories(string opponentsDeckFile); - int percentVictories(); - DeckStat * getDeckStat(string opponentsFile); - - //returns the total number of games played with this deck - int nbGames(); -}; - -class StatsWrapper -{ -private: - void initValues(); - -public: - StatsWrapper(int deckId); - StatsWrapper(string filename); - ~StatsWrapper(); - - void initStatistics(string deckstats); - - // Stats parameters and status - int mDeckId; - int currentPage; - int pageCount; - bool needUpdate; - - // Actual stats - int percentVictories; - int gamesPlayed; - int cardCount; - int countLands; - int totalPrice; - int totalManaCost; - float avgManaCost; - int totalCreatureCost; - float avgCreatureCost; - int totalSpellCost; - float avgSpellCost; - int countManaProducers; - - int countCreatures, countSpells, countInstants, countEnchantments, countSorceries, countArtifacts; - - float noLandsProbInTurn[Constants::STATS_FOR_TURNS]; - float noCreaturesProbInTurn[Constants::STATS_FOR_TURNS]; - - int countCardsPerCost[Constants::STATS_MAX_MANA_COST + 1]; - int countCardsPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1]; - int countCreaturesPerCost[Constants::STATS_MAX_MANA_COST + 1]; - int countCreaturesPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1]; - int countSpellsPerCost[Constants::STATS_MAX_MANA_COST + 1]; - int countSpellsPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1]; - int countLandsPerColor[Constants::MTG_NB_COLORS + 1]; - int countBasicLandsPerColor[Constants::MTG_NB_COLORS + 1]; - int countNonLandProducersPerColor[Constants::MTG_NB_COLORS + 1]; - int totalCostPerColor[Constants::MTG_NB_COLORS + 1]; - int totalColoredSymbols; - - void updateStats(string filename, MTGAllCards * collection); - void updateStats(DeckDataWrapper *mtgDeck); - int countCardsByType(const char * _type, DeckDataWrapper * myDeck); - float noLuck(int n, int a, int x); - - vector aiDeckNames; - vector aiDeckStats; -}; - -#endif +#ifndef _DECKSTATS_H_ +#define _DECKSTATS_H_ + +#include +#include +#include +#include "MTGDefinitions.h" +#include + +using namespace std; + +class Player; +class GameObserver; + +class DeckStat +{ +public: + DeckStat(int _nbgames = 0, int _victories = 0); + + int nbgames; + int victories; + int percentVictories(); +}; + +class DeckStats +{ +protected: + static DeckStats * mInstance; +public: + //map stats; // current set of statistics + string currentDeck; + map > masterDeckStats; + + static DeckStats * GetInstance(); + static void EndInstance(); + void saveStats(Player * player, Player * opponent, GameObserver * game); + void save(const char * filename); + void save(Player * player); + void load(const char * filename); + void load(Player * player); + void cleanStats(); + ~DeckStats(); + int percentVictories(string opponentsDeckFile); + int percentVictories(); + DeckStat * getDeckStat(string opponentsFile); + + //returns the total number of games played with this deck + int nbGames(); +}; + +class StatsWrapper +{ +private: + void initValues(); + +public: + StatsWrapper(int deckId); + StatsWrapper(string filename); + ~StatsWrapper(); + + void initStatistics(string deckstats); + + // Stats parameters and status + int mDeckId; + int currentPage; + int pageCount; + bool needUpdate; + + // Actual stats + int percentVictories; + int gamesPlayed; + int cardCount; + int countLands; + int totalPrice; + int totalManaCost; + float avgManaCost; + int totalCreatureCost; + float avgCreatureCost; + int totalSpellCost; + float avgSpellCost; + int countManaProducers; + + int countCreatures, countSpells, countInstants, countEnchantments, countSorceries, countArtifacts; + + float noLandsProbInTurn[Constants::STATS_FOR_TURNS]; + float noCreaturesProbInTurn[Constants::STATS_FOR_TURNS]; + + int countCardsPerCost[Constants::STATS_MAX_MANA_COST + 1]; + int countCardsPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1]; + int countCreaturesPerCost[Constants::STATS_MAX_MANA_COST + 1]; + int countCreaturesPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1]; + int countSpellsPerCost[Constants::STATS_MAX_MANA_COST + 1]; + int countSpellsPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1]; + int countLandsPerColor[Constants::MTG_NB_COLORS + 1]; + int countBasicLandsPerColor[Constants::MTG_NB_COLORS + 1]; + int countNonLandProducersPerColor[Constants::MTG_NB_COLORS + 1]; + int totalCostPerColor[Constants::MTG_NB_COLORS + 1]; + int totalColoredSymbols; + + void updateStats(string filename, MTGAllCards * collection); + void updateStats(DeckDataWrapper *mtgDeck); + int countCardsByType(const char * _type, DeckDataWrapper * myDeck); + float noLuck(int n, int a, int x); + + vector aiDeckNames; + vector aiDeckStats; +}; + +#endif diff --git a/projects/mtg/include/ExtraCost.h b/projects/mtg/include/ExtraCost.h index 94419350f..b414fadec 100644 --- a/projects/mtg/include/ExtraCost.h +++ b/projects/mtg/include/ExtraCost.h @@ -1,153 +1,153 @@ -#ifndef _EXTRACOST_H_ -#define _EXTRACOST_H_ - -#include -#include "Counters.h" -using std::vector; - -class TargetChooser; -class MTGCardInstance; -class MTGAbility; - -class ExtraCost{ -public: - TargetChooser * tc; - MTGCardInstance * source; - MTGCardInstance * target; - MTGCardInstance * targets[20]; - std::string mCostRenderString; - - ExtraCost(const std::string& inCostRenderString, TargetChooser *_tc = NULL); - virtual ~ExtraCost(); - virtual int setPayment(MTGCardInstance * card); - virtual int isPaymentSet() { return (target != NULL && targets != NULL); } - virtual int canPay() { return 1; } - virtual int doPay() = 0; - virtual void Render(); - virtual int setSource(MTGCardInstance * _source); - virtual ExtraCost* clone() const = 0; -}; - -class ExtraCosts{ -public: - vectorcosts; - MTGCardInstance * source; - MTGAbility * action; - ExtraCosts(); - ~ExtraCosts(); - void Render(); - int tryToSetPayment(MTGCardInstance * card); - int isPaymentSet(); - int canPay(); - int doPay(); - int reset(); - int setAction(MTGAbility * _action, MTGCardInstance * _source); - void Dump(); - ExtraCosts * clone() const; -}; - -class SacrificeCost: public ExtraCost{ -public: - SacrificeCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual SacrificeCost * clone() const; -}; - -//life cost -class LifeCost: public ExtraCost{ -public: - LifeCost(TargetChooser *_tc = NULL); - - virtual int doPay(); - virtual LifeCost * clone() const; -}; - -//Discard a random card cost -class DiscardRandomCost: public ExtraCost{ -public: - DiscardRandomCost(TargetChooser *_tc = NULL); - virtual int canPay(); - virtual int doPay(); - virtual DiscardRandomCost * clone() const; -}; - -//a choosen discard -class DiscardCost: public ExtraCost{ -public: - DiscardCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual DiscardCost * clone() const; -}; - -//tolibrary cost -class ToLibraryCost: public ExtraCost{ -public: - ToLibraryCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual ToLibraryCost * clone() const; -}; - -//Millyourself cost -class MillCost: public ExtraCost{ -public: - MillCost(TargetChooser *_tc = NULL); - virtual int canPay(); - virtual int doPay(); - virtual MillCost * clone() const; -}; - -//Mill to exile yourself cost -class MillExileCost: public MillCost{ -public: - MillExileCost(TargetChooser *_tc = NULL); - virtual int doPay(); -}; - -//tap other cost -class TapTargetCost: public ExtraCost{ -public: - TapTargetCost(TargetChooser *_tc = NULL); - virtual int isPaymentSet(); - virtual int doPay(); - virtual TapTargetCost * clone() const; -}; - -//exile as cost -class ExileTargetCost: public ExtraCost{ -public: - ExileTargetCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual ExileTargetCost * clone() const; -}; - -//bounce cost -class BounceTargetCost: public ExtraCost{ -public: - BounceTargetCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual BounceTargetCost * clone() const; -}; - -//bounce cost -class Ninja: public ExtraCost{ -public: - Ninja(TargetChooser *_tc = NULL); - virtual int isPaymentSet(); - virtual int doPay(); - virtual Ninja * clone() const; -}; - -class CounterCost: public ExtraCost{ -public: - Counter * counter; - int hasCounters; - CounterCost(Counter * _counter,TargetChooser *_tc = NULL); - ~CounterCost(); - virtual int setPayment(MTGCardInstance * card); - virtual int isPaymentSet(); - virtual int canPay(); - virtual int doPay(); - virtual CounterCost * clone() const; -}; - -#endif +#ifndef _EXTRACOST_H_ +#define _EXTRACOST_H_ + +#include +#include "Counters.h" +using std::vector; + +class TargetChooser; +class MTGCardInstance; +class MTGAbility; + +class ExtraCost{ +public: + TargetChooser * tc; + MTGCardInstance * source; + MTGCardInstance * target; + MTGCardInstance * targets[20]; + std::string mCostRenderString; + + ExtraCost(const std::string& inCostRenderString, TargetChooser *_tc = NULL); + virtual ~ExtraCost(); + virtual int setPayment(MTGCardInstance * card); + virtual int isPaymentSet() { return (target != NULL && targets != NULL); } + virtual int canPay() { return 1; } + virtual int doPay() = 0; + virtual void Render(); + virtual int setSource(MTGCardInstance * _source); + virtual ExtraCost* clone() const = 0; +}; + +class ExtraCosts{ +public: + vectorcosts; + MTGCardInstance * source; + MTGAbility * action; + ExtraCosts(); + ~ExtraCosts(); + void Render(); + int tryToSetPayment(MTGCardInstance * card); + int isPaymentSet(); + int canPay(); + int doPay(); + int reset(); + int setAction(MTGAbility * _action, MTGCardInstance * _source); + void Dump(); + ExtraCosts * clone() const; +}; + +class SacrificeCost: public ExtraCost{ +public: + SacrificeCost(TargetChooser *_tc = NULL); + virtual int doPay(); + virtual SacrificeCost * clone() const; +}; + +//life cost +class LifeCost: public ExtraCost{ +public: + LifeCost(TargetChooser *_tc = NULL); + + virtual int doPay(); + virtual LifeCost * clone() const; +}; + +//Discard a random card cost +class DiscardRandomCost: public ExtraCost{ +public: + DiscardRandomCost(TargetChooser *_tc = NULL); + virtual int canPay(); + virtual int doPay(); + virtual DiscardRandomCost * clone() const; +}; + +//a choosen discard +class DiscardCost: public ExtraCost{ +public: + DiscardCost(TargetChooser *_tc = NULL); + virtual int doPay(); + virtual DiscardCost * clone() const; +}; + +//tolibrary cost +class ToLibraryCost: public ExtraCost{ +public: + ToLibraryCost(TargetChooser *_tc = NULL); + virtual int doPay(); + virtual ToLibraryCost * clone() const; +}; + +//Millyourself cost +class MillCost: public ExtraCost{ +public: + MillCost(TargetChooser *_tc = NULL); + virtual int canPay(); + virtual int doPay(); + virtual MillCost * clone() const; +}; + +//Mill to exile yourself cost +class MillExileCost: public MillCost{ +public: + MillExileCost(TargetChooser *_tc = NULL); + virtual int doPay(); +}; + +//tap other cost +class TapTargetCost: public ExtraCost{ +public: + TapTargetCost(TargetChooser *_tc = NULL); + virtual int isPaymentSet(); + virtual int doPay(); + virtual TapTargetCost * clone() const; +}; + +//exile as cost +class ExileTargetCost: public ExtraCost{ +public: + ExileTargetCost(TargetChooser *_tc = NULL); + virtual int doPay(); + virtual ExileTargetCost * clone() const; +}; + +//bounce cost +class BounceTargetCost: public ExtraCost{ +public: + BounceTargetCost(TargetChooser *_tc = NULL); + virtual int doPay(); + virtual BounceTargetCost * clone() const; +}; + +//bounce cost +class Ninja: public ExtraCost{ +public: + Ninja(TargetChooser *_tc = NULL); + virtual int isPaymentSet(); + virtual int doPay(); + virtual Ninja * clone() const; +}; + +class CounterCost: public ExtraCost{ +public: + Counter * counter; + int hasCounters; + CounterCost(Counter * _counter,TargetChooser *_tc = NULL); + ~CounterCost(); + virtual int setPayment(MTGCardInstance * card); + virtual int isPaymentSet(); + virtual int canPay(); + virtual int doPay(); + virtual CounterCost * clone() const; +}; + +#endif diff --git a/projects/mtg/include/GameStateDeckViewer.h b/projects/mtg/include/GameStateDeckViewer.h index 70ece17a6..81e9897a7 100644 --- a/projects/mtg/include/GameStateDeckViewer.h +++ b/projects/mtg/include/GameStateDeckViewer.h @@ -1,152 +1,152 @@ -#ifndef _GAME_STATE_DECK_VIEWER_H_ -#define _GAME_STATE_DECK_VIEWER_H_ - -#include -#include - -#include - -#include "GameState.h" -#include "DeckEditorMenu.h" -#include "SimpleMenu.h" -#include "WResourceManager.h" -#include "CardGui.h" -#include "GameOptions.h" -#include "PriceList.h" -#include "PlayerData.h" -#include "DeckDataWrapper.h" -#include "DeckStats.h" -#include "WDataSrc.h" -#include "WGui.h" - -#define NO_USER_ACTIVITY_HELP_DELAY 10 -#define NO_USER_ACTIVITY_SHOWCARD_DELAY 0.1 - -enum -{ - STAGE_TRANSITION_RIGHT = 0, - STAGE_TRANSITION_LEFT = 1, - STAGE_WAITING = 2, - STAGE_TRANSITION_UP = 3, - STAGE_TRANSITION_DOWN = 4, - STAGE_ONSCREEN_MENU = 5, - STAGE_WELCOME = 6, - STAGE_MENU = 7, - STAGE_FILTERS = 8 -}; - -// TODO: need a better name for MENU_FIRST_MENU, this is reused for the 1st submenu of -// available options in the duel menu -enum -{ - MENU_CARD_PURCHASE = 2, - MENU_DECK_SELECTION = 10, - MENU_DECK_BUILDER = 11, - MENU_FIRST_DUEL_SUBMENU = 102, - MENU_LANGUAGE_SELECTION = 103, -}; - -// enums for menu options -// TODO: make these enums a little more descriptive. (ie should reflect what menu they are attached to ) -enum DECK_VIEWER_MENU_ITEMS -{ - MENU_ITEM_NEW_DECK = -30, - MENU_ITEM_CHEAT_MODE = -12, - MENU_ITEM_CANCEL = kCancelMenuID, - MENU_ITEM_SAVE_RETURN_MAIN_MENU = 0, - MENU_ITEM_SAVE_RENAME = 1, - MENU_ITEM_SWITCH_DECKS_NO_SAVE = 2, - MENU_ITEM_MAIN_MENU = 3, - MENU_ITEM_EDITOR_CANCEL = kCancelMenuID, - MENU_ITEM_SAVE_AS_AI_DECK = 5, - MENU_ITEM_YES = 20, - MENU_ITEM_NO = 21, - MENU_ITEM_FILTER_BY = 22, - MENUITEM_MORE_INFO = kInfoMenuID - -}; - -#define ALL_COLORS -1 - -#define ROTATE_LEFT 1; -#define ROTATE_RIGHT 0; - -#define HIGH_SPEED 15.0 -#define MED_SPEED 5.0f -#define LOW_SPEED 1.5 - -#define MAX_SAVED_FILTERS 8 -#define CARDS_DISPLAYED 7 - -class GameStateDeckViewer: public GameState, public JGuiListener -{ -private: - JQuad * mIcons[CARDS_DISPLAYED]; - JQuad * pspIcons[8]; - JTexture * pspIconsTexture; - float last_user_activity; - float onScreenTransition; - float mRotation; - float mSlide; - int mAlpha; - int mStage; - int nbDecks; - int deckNum; - int useFilter; - JMusic * bgMusic; - JQuad * backQuad; - int lastPos; - int lastTotal; - - WGuiFilters * filterMenu; - WSrcDeckViewer * source; - - DeckEditorMenu * welcome_menu; - SimpleMenu * subMenu; - DeckEditorMenu * menu; - PriceList* pricelist; - PlayerData * playerdata; - int price; - DeckDataWrapper * displayed_deck; - DeckDataWrapper * myDeck; - DeckDataWrapper * myCollection; - MTGCard * cardIndex[CARDS_DISPLAYED]; - StatsWrapper *stw; - - int hudAlpha; - string newDeckname; - bool isAIDeckSave; - bool mSwitching; - void saveDeck(); //Saves the deck and additional necessary information - void saveAsAIDeck(string deckName); // saves deck as an AI Deck - int getCurrentPos(); - pair cardsCoordinates[CARDS_DISPLAYED]; - -public: - GameStateDeckViewer(GameApp* parent); - virtual ~GameStateDeckViewer(); - void updateDecks(); - void rotateCards(int direction); - void loadIndexes(); - void updateFilters(); - void rebuildFilters(); - void switchDisplay(); - void Start(); - virtual void End(); - void addRemove(MTGCard * card); - virtual void Update(float dt); - void renderOnScreenBasicInfo(); - void renderSlideBar(); - void renderDeckBackground(); - void renderOnScreenMenu(); - virtual void renderCard(int id, float rotation); - virtual void renderCard(int id); - virtual void Render(); - int loadDeck(int deckid); - void LoadDeckStatistics(int deckId); - - void buildEditorMenu(); - virtual void ButtonPressed(int controllerId, int controlId); -}; - -#endif +#ifndef _GAME_STATE_DECK_VIEWER_H_ +#define _GAME_STATE_DECK_VIEWER_H_ + +#include +#include + +#include + +#include "GameState.h" +#include "DeckEditorMenu.h" +#include "SimpleMenu.h" +#include "WResourceManager.h" +#include "CardGui.h" +#include "GameOptions.h" +#include "PriceList.h" +#include "PlayerData.h" +#include "DeckDataWrapper.h" +#include "DeckStats.h" +#include "WDataSrc.h" +#include "WGui.h" + +#define NO_USER_ACTIVITY_HELP_DELAY 10 +#define NO_USER_ACTIVITY_SHOWCARD_DELAY 0.1 + +enum +{ + STAGE_TRANSITION_RIGHT = 0, + STAGE_TRANSITION_LEFT = 1, + STAGE_WAITING = 2, + STAGE_TRANSITION_UP = 3, + STAGE_TRANSITION_DOWN = 4, + STAGE_ONSCREEN_MENU = 5, + STAGE_WELCOME = 6, + STAGE_MENU = 7, + STAGE_FILTERS = 8 +}; + +// TODO: need a better name for MENU_FIRST_MENU, this is reused for the 1st submenu of +// available options in the duel menu +enum +{ + MENU_CARD_PURCHASE = 2, + MENU_DECK_SELECTION = 10, + MENU_DECK_BUILDER = 11, + MENU_FIRST_DUEL_SUBMENU = 102, + MENU_LANGUAGE_SELECTION = 103, +}; + +// enums for menu options +// TODO: make these enums a little more descriptive. (ie should reflect what menu they are attached to ) +enum DECK_VIEWER_MENU_ITEMS +{ + MENU_ITEM_NEW_DECK = -30, + MENU_ITEM_CHEAT_MODE = -12, + MENU_ITEM_CANCEL = kCancelMenuID, + MENU_ITEM_SAVE_RETURN_MAIN_MENU = 0, + MENU_ITEM_SAVE_RENAME = 1, + MENU_ITEM_SWITCH_DECKS_NO_SAVE = 2, + MENU_ITEM_MAIN_MENU = 3, + MENU_ITEM_EDITOR_CANCEL = kCancelMenuID, + MENU_ITEM_SAVE_AS_AI_DECK = 5, + MENU_ITEM_YES = 20, + MENU_ITEM_NO = 21, + MENU_ITEM_FILTER_BY = 22, + MENUITEM_MORE_INFO = kInfoMenuID + +}; + +#define ALL_COLORS -1 + +#define ROTATE_LEFT 1; +#define ROTATE_RIGHT 0; + +#define HIGH_SPEED 15.0 +#define MED_SPEED 5.0f +#define LOW_SPEED 1.5 + +#define MAX_SAVED_FILTERS 8 +#define CARDS_DISPLAYED 7 + +class GameStateDeckViewer: public GameState, public JGuiListener +{ +private: + JQuad * mIcons[CARDS_DISPLAYED]; + JQuad * pspIcons[8]; + JTexture * pspIconsTexture; + float last_user_activity; + float onScreenTransition; + float mRotation; + float mSlide; + int mAlpha; + int mStage; + int nbDecks; + int deckNum; + int useFilter; + JMusic * bgMusic; + JQuad * backQuad; + int lastPos; + int lastTotal; + + WGuiFilters * filterMenu; + WSrcDeckViewer * source; + + DeckEditorMenu * welcome_menu; + SimpleMenu * subMenu; + DeckEditorMenu * menu; + PriceList* pricelist; + PlayerData * playerdata; + int price; + DeckDataWrapper * displayed_deck; + DeckDataWrapper * myDeck; + DeckDataWrapper * myCollection; + MTGCard * cardIndex[CARDS_DISPLAYED]; + StatsWrapper *stw; + + int hudAlpha; + string newDeckname; + bool isAIDeckSave; + bool mSwitching; + void saveDeck(); //Saves the deck and additional necessary information + void saveAsAIDeck(string deckName); // saves deck as an AI Deck + int getCurrentPos(); + pair cardsCoordinates[CARDS_DISPLAYED]; + +public: + GameStateDeckViewer(GameApp* parent); + virtual ~GameStateDeckViewer(); + void updateDecks(); + void rotateCards(int direction); + void loadIndexes(); + void updateFilters(); + void rebuildFilters(); + void switchDisplay(); + void Start(); + virtual void End(); + void addRemove(MTGCard * card); + virtual void Update(float dt); + void renderOnScreenBasicInfo(); + void renderSlideBar(); + void renderDeckBackground(); + void renderOnScreenMenu(); + virtual void renderCard(int id, float rotation); + virtual void renderCard(int id); + virtual void Render(); + int loadDeck(int deckid); + void LoadDeckStatistics(int deckId); + + void buildEditorMenu(); + virtual void ButtonPressed(int controllerId, int controlId); +}; + +#endif diff --git a/projects/mtg/include/GameStateDuel.h b/projects/mtg/include/GameStateDuel.h index f12626a82..838976f10 100644 --- a/projects/mtg/include/GameStateDuel.h +++ b/projects/mtg/include/GameStateDuel.h @@ -1,76 +1,76 @@ -#ifndef _GAME_STATE_DUEL_H_ -#define _GAME_STATE_DUEL_H_ - -#include "GameState.h" -#include "SimpleMenu.h" -#include "SimplePopup.h" -#include "DeckMenu.h" -#include "MTGDeck.h" -#include "GameObserver.h" - -#define CHOOSE_OPPONENT 7 - -#ifdef TESTSUITE -class TestSuite; -#endif -class Credits; -class Rules; - -class GameStateDuel: public GameState, public JGuiListener -{ -private: -#ifdef TESTSUITE - TestSuite * testSuite; -#endif - Credits * credits; - int mGamePhase; - Player * mCurrentPlayer; - Player * mPlayers[2]; - MTGPlayerCards * deck[2]; - GameObserver * game; - DeckMenu * deckmenu; - DeckMenu * opponentMenu; - SimpleMenu * menu; - SimplePopup * popupScreen; // used for informational screens, modal - static int selectedPlayerDeckId; - static int selectedAIDeckId; - - bool premadeDeck; - int OpponentsDeckid; - string musictrack; - Rules * rules; - - bool MusicExist(string FileName); - void loadPlayer(int playerId, int decknb = 0, int isAI = 0); - void ConstructOpponentMenu(); //loads the opponentMenu if it doesn't exist - void initScroller(); - -public: - GameStateDuel(GameApp* parent); - virtual ~GameStateDuel(); -#ifdef TESTSUITE - void loadTestSuitePlayers(); -#endif - virtual void ButtonPressed(int ControllerId, int ControlId); - virtual void Start(); - virtual void End(); - virtual void Update(float dt); - virtual void Render(); - void initRand(unsigned seed = 0); - - enum ENUM_DUEL_STATE_MENU_ITEM - { - MENUITEM_CANCEL = kCancelMenuID, - MENUITEM_NEW_DECK = -10, - MENUITEM_RANDOM_PLAYER = -11, - MENUITEM_RANDOM_AI = -12, - MENUITEM_MAIN_MENU = -13, - MENUITEM_EVIL_TWIN = -14, - MENUITEM_MULLIGAN = -15, - MENUITEM_MORE_INFO = kInfoMenuID - }; - -}; - -#endif - +#ifndef _GAME_STATE_DUEL_H_ +#define _GAME_STATE_DUEL_H_ + +#include "GameState.h" +#include "SimpleMenu.h" +#include "SimplePopup.h" +#include "DeckMenu.h" +#include "MTGDeck.h" +#include "GameObserver.h" + +#define CHOOSE_OPPONENT 7 + +#ifdef TESTSUITE +class TestSuite; +#endif +class Credits; +class Rules; + +class GameStateDuel: public GameState, public JGuiListener +{ +private: +#ifdef TESTSUITE + TestSuite * testSuite; +#endif + Credits * credits; + int mGamePhase; + Player * mCurrentPlayer; + Player * mPlayers[2]; + MTGPlayerCards * deck[2]; + GameObserver * game; + DeckMenu * deckmenu; + DeckMenu * opponentMenu; + SimpleMenu * menu; + SimplePopup * popupScreen; // used for informational screens, modal + static int selectedPlayerDeckId; + static int selectedAIDeckId; + + bool premadeDeck; + int OpponentsDeckid; + string musictrack; + Rules * rules; + + bool MusicExist(string FileName); + void loadPlayer(int playerId, int decknb = 0, int isAI = 0); + void ConstructOpponentMenu(); //loads the opponentMenu if it doesn't exist + void initScroller(); + +public: + GameStateDuel(GameApp* parent); + virtual ~GameStateDuel(); +#ifdef TESTSUITE + void loadTestSuitePlayers(); +#endif + virtual void ButtonPressed(int ControllerId, int ControlId); + virtual void Start(); + virtual void End(); + virtual void Update(float dt); + virtual void Render(); + void initRand(unsigned seed = 0); + + enum ENUM_DUEL_STATE_MENU_ITEM + { + MENUITEM_CANCEL = kCancelMenuID, + MENUITEM_NEW_DECK = -10, + MENUITEM_RANDOM_PLAYER = -11, + MENUITEM_RANDOM_AI = -12, + MENUITEM_MAIN_MENU = -13, + MENUITEM_EVIL_TWIN = -14, + MENUITEM_MULLIGAN = -15, + MENUITEM_MORE_INFO = kInfoMenuID + }; + +}; + +#endif + diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index 68aaa451f..8c4ed9af8 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -1,113 +1,113 @@ -#ifndef _PLAYER_H_ -#define _PLAYER_H_ - -#include "JGE.h" -#include "MTGGameZones.h" -#include "Damage.h" -#include "Targetable.h" - -class MTGDeck; -class MTGPlayerCards; -class MTGInPlay; -class ManaPool; - -class Player: public Damageable -{ -protected: - ManaPool * manaPool; - -public: - enum ENUM_PLAY_MODE - { - MODE_TEST_SUITE, - MODE_HUMAN, - MODE_AI - }; - - JTexture * mAvatarTex; - JQuad * mAvatar; - int playMode; - bool canPutLandsIntoPlay; - int landsPlayerCanStillPlay; - bool nomaxhandsize; - int castedspellsthisturn; - bool onlyonecast; - int castcount; - bool nocreatureinstant; - bool nospellinstant; - bool onlyoneinstant; - bool castrestrictedcreature; - bool castrestrictedspell; - bool onlyoneboth; - bool bothrestrictedspell; - bool bothrestrictedcreature; - bool isPoisoned; - MTGPlayerCards * game; - string deckFile; - string deckFileSmall; - string deckName; - - Player(MTGDeck * deck, string deckFile, string deckFileSmall); - virtual ~Player(); - - virtual void End(); - virtual int displayStack() - { - return 1; - } - const string getDisplayName() const; - int typeAsTarget() - { - return TARGET_PLAYER; - } - - int afterDamage(); - - int gainLife(int value); - int loseLife(int value); - int gainOrLoseLife(int value); - - int poisoned(); - int damaged(); - int prevented(); - void unTapPhase(); - MTGInPlay * inPlay(); - ManaPool * getManaPool(); - void cleanupPhase(); - virtual int Act(float dt) - { - return 0; - } - - virtual int isAI() - { - return 0; - } - - Player * opponent(); - int getId(); - JQuad * getIcon(); - - virtual int receiveEvent(WEvent * event) - { - return 0; - } - - virtual void Render() - { - } - - void loadAvatar(string file); -}; - -class HumanPlayer: public Player -{ -public: - HumanPlayer(MTGDeck * deck, string deckFile, string deckFileSmall); - HumanPlayer(string deckFile); - -}; - -ostream& operator<<(ostream&, const Player&); - -#endif +#ifndef _PLAYER_H_ +#define _PLAYER_H_ + +#include "JGE.h" +#include "MTGGameZones.h" +#include "Damage.h" +#include "Targetable.h" + +class MTGDeck; +class MTGPlayerCards; +class MTGInPlay; +class ManaPool; + +class Player: public Damageable +{ +protected: + ManaPool * manaPool; + +public: + enum ENUM_PLAY_MODE + { + MODE_TEST_SUITE, + MODE_HUMAN, + MODE_AI + }; + + JTexture * mAvatarTex; + JQuad * mAvatar; + int playMode; + bool canPutLandsIntoPlay; + int landsPlayerCanStillPlay; + bool nomaxhandsize; + int castedspellsthisturn; + bool onlyonecast; + int castcount; + bool nocreatureinstant; + bool nospellinstant; + bool onlyoneinstant; + bool castrestrictedcreature; + bool castrestrictedspell; + bool onlyoneboth; + bool bothrestrictedspell; + bool bothrestrictedcreature; + bool isPoisoned; + MTGPlayerCards * game; + string deckFile; + string deckFileSmall; + string deckName; + + Player(MTGDeck * deck, string deckFile, string deckFileSmall); + virtual ~Player(); + + virtual void End(); + virtual int displayStack() + { + return 1; + } + const string getDisplayName() const; + int typeAsTarget() + { + return TARGET_PLAYER; + } + + int afterDamage(); + + int gainLife(int value); + int loseLife(int value); + int gainOrLoseLife(int value); + + int poisoned(); + int damaged(); + int prevented(); + void unTapPhase(); + MTGInPlay * inPlay(); + ManaPool * getManaPool(); + void cleanupPhase(); + virtual int Act(float dt) + { + return 0; + } + + virtual int isAI() + { + return 0; + } + + Player * opponent(); + int getId(); + JQuad * getIcon(); + + virtual int receiveEvent(WEvent * event) + { + return 0; + } + + virtual void Render() + { + } + + void loadAvatar(string file); +}; + +class HumanPlayer: public Player +{ +public: + HumanPlayer(MTGDeck * deck, string deckFile, string deckFileSmall); + HumanPlayer(string deckFile); + +}; + +ostream& operator<<(ostream&, const Player&); + +#endif diff --git a/projects/mtg/include/ReplacementEffects.h b/projects/mtg/include/ReplacementEffects.h index 521194bfb..be06ed1de 100644 --- a/projects/mtg/include/ReplacementEffects.h +++ b/projects/mtg/include/ReplacementEffects.h @@ -1,50 +1,50 @@ -#ifndef _REPLACEMENT_EFFECTS_H_ -#define _REPLACEMENT_EFFECTS_H_ - -#include -using namespace std; -#include "Damage.h" -#include "WEvent.h" - -class TargetChooser; -class MTGAbility; - -class ReplacementEffect -{ -public: - virtual WEvent * replace(WEvent * e) - { - return e; - } - ; - virtual ~ReplacementEffect() {} -}; - -class REDamagePrevention: public ReplacementEffect -{ -protected: - MTGAbility * source; - TargetChooser * tcSource; - TargetChooser * tcTarget; - int damage; - bool oneShot; - int typeOfDamage; -public: - REDamagePrevention(MTGAbility * _source, TargetChooser *_tcSource = NULL, TargetChooser *_tcTarget = NULL, int _damage = -1, bool _oneShot = true, int typeOfDamage = DAMAGE_ALL_TYPES); - WEvent * replace(WEvent *e); - ~REDamagePrevention(); -}; - -class ReplacementEffects -{ -protected: - list modifiers; -public: - ReplacementEffects(); - WEvent * replace(WEvent *e); - int add(ReplacementEffect * re); - int remove(ReplacementEffect * re); - ~ReplacementEffects(); -}; - -#endif +#ifndef _REPLACEMENT_EFFECTS_H_ +#define _REPLACEMENT_EFFECTS_H_ + +#include +using namespace std; +#include "Damage.h" +#include "WEvent.h" + +class TargetChooser; +class MTGAbility; + +class ReplacementEffect +{ +public: + virtual WEvent * replace(WEvent * e) + { + return e; + } + ; + virtual ~ReplacementEffect() {} +}; + +class REDamagePrevention: public ReplacementEffect +{ +protected: + MTGAbility * source; + TargetChooser * tcSource; + TargetChooser * tcTarget; + int damage; + bool oneShot; + int typeOfDamage; +public: + REDamagePrevention(MTGAbility * _source, TargetChooser *_tcSource = NULL, TargetChooser *_tcTarget = NULL, int _damage = -1, bool _oneShot = true, int typeOfDamage = DAMAGE_ALL_TYPES); + WEvent * replace(WEvent *e); + ~REDamagePrevention(); +}; + +class ReplacementEffects +{ +protected: + list modifiers; +public: + ReplacementEffects(); + WEvent * replace(WEvent *e); + int add(ReplacementEffect * re); + int remove(ReplacementEffect * re); + ~ReplacementEffects(); +}; + +#endif diff --git a/projects/mtg/include/SimplePopup.h b/projects/mtg/include/SimplePopup.h index d4f0d8686..aacdd2da9 100644 --- a/projects/mtg/include/SimplePopup.h +++ b/projects/mtg/include/SimplePopup.h @@ -1,58 +1,58 @@ -/* - * SimplePopup.h - * Created on: Nov 18, 2010 - * - * Simple popup dialog box for displaying information only. - */ - -#ifndef SIMPLEPOPUP_H_ -#define SIMPLEPOPUP_H_ - -#pragma once -#include -#include -#include -#include - -class SimplePopup: public JGuiController -{ - -private: - float mWidth, mX, mY; - int mMaxLines; - int mFontId; - DeckMetaData * mDeckInformation; - string mTitle; - WFont *mTextFont; - StatsWrapper *mStatsWrapper; - bool mClosed; - MTGAllCards * mCollection; - - void drawHorzPole(string imageName, bool flipX, bool flipY, float x, float y, float width); - void drawCorner(string imageName, bool flipX, bool flipY, float x, float y); - void drawVertPole(string imageName, bool flipX, bool flipY, float x, float y, float height); - -public: - bool autoTranslate; - - SimplePopup(int id, JGuiListener* listener, const int fontId, const char * _title = "", DeckMetaData* deckInfo = NULL, MTGAllCards * collection = NULL); - ~SimplePopup(void); - void drawBoundingBox(float x, float y, float width, float height); - bool isClosed() - { - return mClosed; - } - MTGAllCards* getCollection() - { - return mCollection; - } - void Render(); - void Update(DeckMetaData* deckMetaData); - - string getDetailedInformation(string deckFilename); - - void Update(float dt); - void Close(); -}; - -#endif /* SIMPLEPOPUP_H_ */ +/* + * SimplePopup.h + * Created on: Nov 18, 2010 + * + * Simple popup dialog box for displaying information only. + */ + +#ifndef SIMPLEPOPUP_H_ +#define SIMPLEPOPUP_H_ + +#pragma once +#include +#include +#include +#include + +class SimplePopup: public JGuiController +{ + +private: + float mWidth, mX, mY; + int mMaxLines; + int mFontId; + DeckMetaData * mDeckInformation; + string mTitle; + WFont *mTextFont; + StatsWrapper *mStatsWrapper; + bool mClosed; + MTGAllCards * mCollection; + + void drawHorzPole(string imageName, bool flipX, bool flipY, float x, float y, float width); + void drawCorner(string imageName, bool flipX, bool flipY, float x, float y); + void drawVertPole(string imageName, bool flipX, bool flipY, float x, float y, float height); + +public: + bool autoTranslate; + + SimplePopup(int id, JGuiListener* listener, const int fontId, const char * _title = "", DeckMetaData* deckInfo = NULL, MTGAllCards * collection = NULL); + ~SimplePopup(void); + void drawBoundingBox(float x, float y, float width, float height); + bool isClosed() + { + return mClosed; + } + MTGAllCards* getCollection() + { + return mCollection; + } + void Render(); + void Update(DeckMetaData* deckMetaData); + + string getDetailedInformation(string deckFilename); + + void Update(float dt); + void Close(); +}; + +#endif /* SIMPLEPOPUP_H_ */ diff --git a/projects/mtg/include/TextScroller.h b/projects/mtg/include/TextScroller.h index e21a42089..e80c18086 100644 --- a/projects/mtg/include/TextScroller.h +++ b/projects/mtg/include/TextScroller.h @@ -1,55 +1,55 @@ -#ifndef _TEXTSCROLLER_H_ -#define _TEXTSCROLLER_H_ - -class JLBFont; -#include -#include -#include -using namespace std; - -class TextScroller: public JGuiObject -{ -protected: - string mText; - string tempText; - int fontId; - float mWidth; // width of the text scroller object - float mScrollSpeed; - float mX; - float mY; - float start; - int timer; - - vector strings; - unsigned int currentId; - int mRandom; - int scrollDirection; - -public: - TextScroller(int fontId, float x, float y, float width, float speed = 30); - void Add(string text); - void Reset(); - void setRandom(int mode = 1); - void Render(); - void Update(float dt); - virtual ostream& toString(ostream& out) const; -}; - -class VerticalTextScroller: public TextScroller -{ -private: - size_t mNbItemsShown; - float mHeight; // maximum height availble for display - float mMarginX; - float mMarginY; // margin used to allow text to scroll off screen without - // affecting look and feel. Should be enough - // for at least one line of text ( mY - line height of current font ) - float mOriginalY; // mY initially, used to restore scroller to original position after update - -public: - VerticalTextScroller(int fontId, float x, float y, float width, float height, float scrollSpeed = 30, size_t _minimumItems = 1); - void Render(); - void Update(float dt); - void Add(string text); -}; -#endif +#ifndef _TEXTSCROLLER_H_ +#define _TEXTSCROLLER_H_ + +class JLBFont; +#include +#include +#include +using namespace std; + +class TextScroller: public JGuiObject +{ +protected: + string mText; + string tempText; + int fontId; + float mWidth; // width of the text scroller object + float mScrollSpeed; + float mX; + float mY; + float start; + int timer; + + vector strings; + unsigned int currentId; + int mRandom; + int scrollDirection; + +public: + TextScroller(int fontId, float x, float y, float width, float speed = 30); + void Add(string text); + void Reset(); + void setRandom(int mode = 1); + void Render(); + void Update(float dt); + virtual ostream& toString(ostream& out) const; +}; + +class VerticalTextScroller: public TextScroller +{ +private: + size_t mNbItemsShown; + float mHeight; // maximum height availble for display + float mMarginX; + float mMarginY; // margin used to allow text to scroll off screen without + // affecting look and feel. Should be enough + // for at least one line of text ( mY - line height of current font ) + float mOriginalY; // mY initially, used to restore scroller to original position after update + +public: + VerticalTextScroller(int fontId, float x, float y, float width, float height, float scrollSpeed = 30, size_t _minimumItems = 1); + void Render(); + void Update(float dt); + void Add(string text); +}; +#endif diff --git a/projects/mtg/include/Token.h b/projects/mtg/include/Token.h index 944c6af6d..5aeb3d8f6 100644 --- a/projects/mtg/include/Token.h +++ b/projects/mtg/include/Token.h @@ -1,13 +1,13 @@ -#ifndef _TOKEN_H_ -#define _TOKEN_H_ - -#include "MTGCardInstance.h" - -class Token: public MTGCardInstance -{ - MTGCardInstance * tokenSource; -public: - Token(string _name, MTGCardInstance * source, int _power = 0, int _toughness = 0); -}; - -#endif +#ifndef _TOKEN_H_ +#define _TOKEN_H_ + +#include "MTGCardInstance.h" + +class Token: public MTGCardInstance +{ + MTGCardInstance * tokenSource; +public: + Token(string _name, MTGCardInstance * source, int _power = 0, int _toughness = 0); +}; + +#endif diff --git a/projects/mtg/src/DeckEditorMenu.cpp b/projects/mtg/src/DeckEditorMenu.cpp index 865bb8834..5620fcd5d 100644 --- a/projects/mtg/src/DeckEditorMenu.cpp +++ b/projects/mtg/src/DeckEditorMenu.cpp @@ -1,100 +1,100 @@ -#include "PrecompiledHeader.h" -#include "DeckEditorMenu.h" -#include "DeckDataWrapper.h" -#include "DeckStats.h" -#include "JTypes.h" -#include "GameApp.h" -#include - -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"; - mShowDetailsScreen = false; - 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(mScroller); // need to delete the scroller init in the base class - mScroller = NEW VerticalTextScroller(Fonts::MAIN_FONT, 40, 230, scrollerWidth, 100); - -} - -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 = WResourceManager::Instance()->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 = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - mainFont->DrawString(deckStatsString.str().c_str(), descX, descY + 25); -} - -DeckEditorMenu::~DeckEditorMenu() -{ - SAFE_DELETE( mScroller ); -} +#include "PrecompiledHeader.h" +#include "DeckEditorMenu.h" +#include "DeckDataWrapper.h" +#include "DeckStats.h" +#include "JTypes.h" +#include "GameApp.h" +#include + +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"; + mShowDetailsScreen = false; + 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(mScroller); // need to delete the scroller init in the base class + mScroller = NEW VerticalTextScroller(Fonts::MAIN_FONT, 40, 230, scrollerWidth, 100); + +} + +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 = WResourceManager::Instance()->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 = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + mainFont->DrawString(deckStatsString.str().c_str(), descX, descY + 25); +} + +DeckEditorMenu::~DeckEditorMenu() +{ + SAFE_DELETE( mScroller ); +} diff --git a/projects/mtg/src/DeckMenu.cpp b/projects/mtg/src/DeckMenu.cpp index 895cad47f..80a321538 100644 --- a/projects/mtg/src/DeckMenu.cpp +++ b/projects/mtg/src/DeckMenu.cpp @@ -1,337 +1,337 @@ -#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 - -namespace -{ - const float kVerticalMargin = 16; - const float kHorizontalMargin = 20; - const float kLineHeight = 20; - const float kDescriptionVerticalBoxPadding = 5; - const float kDescriptionHorizontalBoxPadding = 5; - - const float kDefaultFontScale = 1.0f; - const float kVerticalScrollSpeed = 7.0f; - - const int DETAILED_INFO_THRESHOLD = 20; -} - -hgeParticleSystem* DeckMenu::stars = NULL; - -// -// For the additional info window, maximum characters per line is roughly 30 characters across. -// TODO: -// *** 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, bool showDetailsOverride) : -JGuiController(id, listener), fontId(fontId), mShowDetailsScreen( showDetailsOverride ) -{ - - backgroundName = "DeckMenuBackdrop"; - mAlwaysShowDetailsButton = false; - mSelectedDeck = NULL; - mY = 50; - mWidth = 176; - mX = 115; - - titleX = 110; // center point in title box - titleY = 15; - titleWidth = 180; // width of inner box of title - - descX = 260 + kDescriptionVerticalBoxPadding; - descY = 100 + kDescriptionHorizontalBoxPadding; - descHeight = 145; - descWidth = 200; - - detailedInfoBoxX = 400; - detailedInfoBoxY = 235; - starsOffsetX = 50; - - statsX = 300; - statsY = 15; - statsHeight = 50; - statsWidth = 227; - - mSelectedDeckId = startIndex; - - avatarX = 232; - avatarY = 11; - - menuInitialized = false; - - float scrollerWidth = 200.0f; - float scrollerHeight = 28.0f; - mScroller = NEW VerticalTextScroller(Fonts::MAIN_FONT, 14, 235, scrollerWidth, scrollerHeight, kVerticalScrollSpeed); - - mAutoTranslate = 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 = WResourceManager::Instance()->GetWFont(fontId); - - startId = 0; - selectionT = 0; - timeOpen = 0; - mClosed = false; - - if (mFont->GetStringWidth(title.c_str()) > titleWidth) - titleFontScale = 0.75f; - else - titleFontScale = 1.0f; - - mSelectionTargetY = selectionY = kVerticalMargin; - - if (NULL == stars) - stars = NEW hgeParticleSystem(WResourceManager::Instance()->RetrievePSI("stars.psi", WResourceManager::Instance()->GetQuad("stars"))); - stars->FireAt(mX, mY); - - updateScroller(); -} - -void DeckMenu::RenderBackground() -{ - ostringstream bgFilename; - bgFilename << backgroundName << ".png"; - - static bool loadBackground = true; - if (loadBackground) - { - JQuad *background = WResourceManager::Instance()->RetrieveTempQuad(bgFilename.str(), TEXTURE_SUB_5551); - if (background) - JRenderer::GetInstance()->RenderQuad(background, 0, 0); - else - loadBackground = false; - } -} - -DeckMetaData * DeckMenu::getSelectedDeck() -{ - if (mSelectedDeck) return mSelectedDeck; - - return NULL; -} - -void DeckMenu::enableDisplayDetailsOverride() -{ - mAlwaysShowDetailsButton = true; -} - -bool DeckMenu::showDetailsScreen() -{ - DeckMetaData * currentMenuItem = getSelectedDeck(); - if (currentMenuItem) - { - if (mAlwaysShowDetailsButton) return true; - if (mShowDetailsScreen && currentMenuItem->getVictories() > DETAILED_INFO_THRESHOLD) return true; - } - - return false; -} - -void DeckMenu::initMenuItems() -{ - float sY = mY + kVerticalMargin; - for (int i = startId; i < mCount; ++i) - { - float y = mY + kVerticalMargin + i * kLineHeight; - DeckMenuItem * currentMenuItem = static_cast (mObjects[i]); - currentMenuItem->Relocate(mX, y); - if (currentMenuItem->hasFocus()) sY = y; - } - mSelectionTargetY = selectionY = sY; - - //Grab a texture in VRAM. - pspIconsTexture = WResourceManager::Instance()->RetrieveTexture("iconspsp.png", RETRIEVE_LOCK); - - char buf[512]; - for (int i = 0; i < 8; i++) - { - sprintf(buf, "iconspsp%d", i); - pspIcons[i] = WResourceManager::Instance()->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 (mObjects[i]); - if (currentMenuItem->mY - kLineHeight * startId < mY + height - kLineHeight + 7) - { - if (currentMenuItem->hasFocus()) - { - mSelectedDeckId = i; - mSelectedDeck = currentMenuItem->meta; - - WFont *mainFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - // display the "more info" button if special condition is met - if (showDetailsScreen()) - { - 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( 255, 0, 0, 0) ); - renderer->RenderQuad(pspIcons[5], detailedInfoBoxX, detailedInfoBoxY + 2, 0, pspIconsSize, pspIconsSize); - mainFont->SetColor(currentColor); - mainFont->DrawString(detailedInfoString, boxStartX, detailedInfoBoxY + 10); - } - - // display the avatar image - if (currentMenuItem->imageFilename.size() > 0) - { - JQuad * quad = WResourceManager::Instance()->RetrieveTempQuad(currentMenuItem->imageFilename, TEXTURE_SUB_AVATAR); - if (quad) renderer->RenderQuad(quad, avatarX, avatarY); - } - // fill in the description part of the screen - string text = wordWrap(currentMenuItem->desc, descWidth, mainFont->mFontID ); - 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)); - } - currentMenuItem->RenderWithOffset(-kLineHeight * startId); - } - } - - if (!title.empty()) - { - mFont->SetColor(ARGB(255,255,255,255)); - mFont->DrawString(title.c_str(), titleX, titleY, JGETEXT_CENTER); - } - - mScroller->Render(); - RenderBackground(); - - renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); - stars->Render(); - renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); - -} - -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 += (mSelectionTargetY - 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; - mClosed = true; - stars->FireAt(mX, mY); - } - } - else - { - mClosed = false; - timeOpen += dt * 10; - } - if (mScroller) - mScroller->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), mAutoTranslate, deckMetaData); - Translator * t = Translator::GetInstance(); - map::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; - mScroller->Reset(); - - for (vector::iterator it = taskList.tasks.begin(); it != taskList.tasks.end(); it++) - { - ostringstream taskDescription; - taskDescription << "Credits: " << setw(4) << (*it)->getReward() << " / " - << "Days Left: " << (*it)->getExpiration() << endl - << (*it)->getDesc() << endl << endl; - mScroller->Add(taskDescription.str()); - } - -} - -void DeckMenu::Close() -{ - timeOpen = -1.0; - stars->Stop(true); -} - -void DeckMenu::destroy() -{ - SAFE_DELETE(DeckMenu::stars); -} - -DeckMenu::~DeckMenu() -{ - WResourceManager::Instance()->Release(pspIconsTexture); - SAFE_DELETE(mScroller); -} +#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 + +namespace +{ + const float kVerticalMargin = 16; + const float kHorizontalMargin = 20; + const float kLineHeight = 20; + const float kDescriptionVerticalBoxPadding = 5; + const float kDescriptionHorizontalBoxPadding = 5; + + const float kDefaultFontScale = 1.0f; + const float kVerticalScrollSpeed = 7.0f; + + const int DETAILED_INFO_THRESHOLD = 20; +} + +hgeParticleSystem* DeckMenu::stars = NULL; + +// +// For the additional info window, maximum characters per line is roughly 30 characters across. +// TODO: +// *** 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, bool showDetailsOverride) : +JGuiController(id, listener), fontId(fontId), mShowDetailsScreen( showDetailsOverride ) +{ + + backgroundName = "DeckMenuBackdrop"; + mAlwaysShowDetailsButton = false; + mSelectedDeck = NULL; + mY = 50; + mWidth = 176; + mX = 115; + + titleX = 110; // center point in title box + titleY = 15; + titleWidth = 180; // width of inner box of title + + descX = 260 + kDescriptionVerticalBoxPadding; + descY = 100 + kDescriptionHorizontalBoxPadding; + descHeight = 145; + descWidth = 200; + + detailedInfoBoxX = 400; + detailedInfoBoxY = 235; + starsOffsetX = 50; + + statsX = 300; + statsY = 15; + statsHeight = 50; + statsWidth = 227; + + mSelectedDeckId = startIndex; + + avatarX = 232; + avatarY = 11; + + menuInitialized = false; + + float scrollerWidth = 200.0f; + float scrollerHeight = 28.0f; + mScroller = NEW VerticalTextScroller(Fonts::MAIN_FONT, 14, 235, scrollerWidth, scrollerHeight, kVerticalScrollSpeed); + + mAutoTranslate = 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 = WResourceManager::Instance()->GetWFont(fontId); + + startId = 0; + selectionT = 0; + timeOpen = 0; + mClosed = false; + + if (mFont->GetStringWidth(title.c_str()) > titleWidth) + titleFontScale = 0.75f; + else + titleFontScale = 1.0f; + + mSelectionTargetY = selectionY = kVerticalMargin; + + if (NULL == stars) + stars = NEW hgeParticleSystem(WResourceManager::Instance()->RetrievePSI("stars.psi", WResourceManager::Instance()->GetQuad("stars"))); + stars->FireAt(mX, mY); + + updateScroller(); +} + +void DeckMenu::RenderBackground() +{ + ostringstream bgFilename; + bgFilename << backgroundName << ".png"; + + static bool loadBackground = true; + if (loadBackground) + { + JQuad *background = WResourceManager::Instance()->RetrieveTempQuad(bgFilename.str(), TEXTURE_SUB_5551); + if (background) + JRenderer::GetInstance()->RenderQuad(background, 0, 0); + else + loadBackground = false; + } +} + +DeckMetaData * DeckMenu::getSelectedDeck() +{ + if (mSelectedDeck) return mSelectedDeck; + + return NULL; +} + +void DeckMenu::enableDisplayDetailsOverride() +{ + mAlwaysShowDetailsButton = true; +} + +bool DeckMenu::showDetailsScreen() +{ + DeckMetaData * currentMenuItem = getSelectedDeck(); + if (currentMenuItem) + { + if (mAlwaysShowDetailsButton) return true; + if (mShowDetailsScreen && currentMenuItem->getVictories() > DETAILED_INFO_THRESHOLD) return true; + } + + return false; +} + +void DeckMenu::initMenuItems() +{ + float sY = mY + kVerticalMargin; + for (int i = startId; i < mCount; ++i) + { + float y = mY + kVerticalMargin + i * kLineHeight; + DeckMenuItem * currentMenuItem = static_cast (mObjects[i]); + currentMenuItem->Relocate(mX, y); + if (currentMenuItem->hasFocus()) sY = y; + } + mSelectionTargetY = selectionY = sY; + + //Grab a texture in VRAM. + pspIconsTexture = WResourceManager::Instance()->RetrieveTexture("iconspsp.png", RETRIEVE_LOCK); + + char buf[512]; + for (int i = 0; i < 8; i++) + { + sprintf(buf, "iconspsp%d", i); + pspIcons[i] = WResourceManager::Instance()->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 (mObjects[i]); + if (currentMenuItem->mY - kLineHeight * startId < mY + height - kLineHeight + 7) + { + if (currentMenuItem->hasFocus()) + { + mSelectedDeckId = i; + mSelectedDeck = currentMenuItem->meta; + + WFont *mainFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + // display the "more info" button if special condition is met + if (showDetailsScreen()) + { + 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( 255, 0, 0, 0) ); + renderer->RenderQuad(pspIcons[5], detailedInfoBoxX, detailedInfoBoxY + 2, 0, pspIconsSize, pspIconsSize); + mainFont->SetColor(currentColor); + mainFont->DrawString(detailedInfoString, boxStartX, detailedInfoBoxY + 10); + } + + // display the avatar image + if (currentMenuItem->imageFilename.size() > 0) + { + JQuad * quad = WResourceManager::Instance()->RetrieveTempQuad(currentMenuItem->imageFilename, TEXTURE_SUB_AVATAR); + if (quad) renderer->RenderQuad(quad, avatarX, avatarY); + } + // fill in the description part of the screen + string text = wordWrap(currentMenuItem->desc, descWidth, mainFont->mFontID ); + 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)); + } + currentMenuItem->RenderWithOffset(-kLineHeight * startId); + } + } + + if (!title.empty()) + { + mFont->SetColor(ARGB(255,255,255,255)); + mFont->DrawString(title.c_str(), titleX, titleY, JGETEXT_CENTER); + } + + mScroller->Render(); + RenderBackground(); + + renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); + stars->Render(); + renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); + +} + +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 += (mSelectionTargetY - 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; + mClosed = true; + stars->FireAt(mX, mY); + } + } + else + { + mClosed = false; + timeOpen += dt * 10; + } + if (mScroller) + mScroller->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), mAutoTranslate, deckMetaData); + Translator * t = Translator::GetInstance(); + map::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; + mScroller->Reset(); + + for (vector::iterator it = taskList.tasks.begin(); it != taskList.tasks.end(); it++) + { + ostringstream taskDescription; + taskDescription << "Credits: " << setw(4) << (*it)->getReward() << " / " + << "Days Left: " << (*it)->getExpiration() << endl + << (*it)->getDesc() << endl << endl; + mScroller->Add(taskDescription.str()); + } + +} + +void DeckMenu::Close() +{ + timeOpen = -1.0; + stars->Stop(true); +} + +void DeckMenu::destroy() +{ + SAFE_DELETE(DeckMenu::stars); +} + +DeckMenu::~DeckMenu() +{ + WResourceManager::Instance()->Release(pspIconsTexture); + SAFE_DELETE(mScroller); +} diff --git a/projects/mtg/src/DeckStats.cpp b/projects/mtg/src/DeckStats.cpp index 704f42b1f..cff6eeccc 100644 --- a/projects/mtg/src/DeckStats.cpp +++ b/projects/mtg/src/DeckStats.cpp @@ -1,538 +1,538 @@ -#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::iterator it; - for (it = stats.begin(); it != stats.end(); it++) - { - SAFE_DELETE(it->second); - } - - stats.clear(); - - */ -} - -DeckStats::~DeckStats() -{ - map > ::iterator it; - for (it = masterDeckStats.begin(); it != masterDeckStats.end(); ++it) - { - string key = it->first; - map innerMap = masterDeckStats[key]; - map::iterator it2; - for (it2 = innerMap.begin(); it2 != innerMap.end(); it2++) - { - SAFE_DELETE(it2->second); - } - innerMap.clear(); - } - masterDeckStats.clear(); -} - - -DeckStat* DeckStats::getDeckStat(string opponentsFile) -{ - map stats = masterDeckStats[currentDeck]; - map::iterator it = stats.find(opponentsFile); - if (it == stats.end()) - { - return NULL; - } - else - { - return it->second; - } -} - -int DeckStats::nbGames() -{ - int nbgames = 0; - map stats = masterDeckStats[currentDeck]; - map::iterator it; - for (it = stats.begin(); it != stats.end(); it++) - { - DeckStat * d = it->second; - nbgames += d->nbgames; - } - return nbgames; -} - -int DeckStats::percentVictories(string opponentsFile) -{ - map stats = masterDeckStats[currentDeck]; - map::iterator it = stats.find(opponentsFile); - if (it == stats.end()) - { - return 50; - } - else - { - return (it->second->percentVictories()); - } -} - -int DeckStats::percentVictories() -{ - int victories = 0; - int nbgames = 0; - map stats = masterDeckStats[currentDeck]; - map::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) -{ - - currentDeck = filename; - if ( masterDeckStats.find(filename) != masterDeckStats.end() ) - { - return; - } - wagic::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()); - if ( masterDeckStats[filename].find(deckfile) != masterDeckStats[filename].end()) - { - SAFE_DELETE( masterDeckStats[filename][deckfile] ); - } - DeckStat * newDeckStat = NEW DeckStat(games, victories); - (masterDeckStats[filename])[deckfile] = newDeckStat; - } - 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 stats = masterDeckStats[currentDeck]; - map::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 *stats = &masterDeckStats[currentDeck]; - map::iterator it = stats->find(opponent->deckFileSmall); - if (it == stats->end()) - { - stats->insert( make_pair( opponent->deckFileSmall, NEW DeckStat(1, victory) )); - } - else - { - it->second->victories += victory; - it->second->nbgames += 1; - } - save(player); -} - -void DeckStats::EndInstance() -{ - SAFE_DELETE( mInstance ); -} - - -// StatsWrapper - - float noLandsProbInTurn[Constants::STATS_FOR_TURNS] = {0.0f}; - float noCreaturesProbInTurn[Constants::STATS_FOR_TURNS] = {0.0f}; - - int countCardsPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1] = {{0,0}}; - int countCreaturesPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1] = {{0,0}}; - int countSpellsPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1] = {{0,0}}; - - int countCardsPerCost[Constants::STATS_MAX_MANA_COST + 1] = {0}; - int countCreaturesPerCost[Constants::STATS_MAX_MANA_COST + 1] = {0}; - int countSpellsPerCost[Constants::STATS_MAX_MANA_COST + 1] = {0}; - int countLandsPerColor[Constants::MTG_NB_COLORS + 1] = {0}; - int countBasicLandsPerColor[Constants::MTG_NB_COLORS + 1] = {0}; - int countNonLandProducersPerColor[Constants::MTG_NB_COLORS + 1] = {0}; - int totalCostPerColor[Constants::MTG_NB_COLORS + 1] = {0}; - -void StatsWrapper::initValues() -{ - // initilize all member values to 0 - // Stats parameters and status - mDeckId = currentPage = pageCount = 0; - needUpdate = true; - - // Actual stats - percentVictories = 0; - gamesPlayed = cardCount = countLands = totalPrice = totalManaCost = 0; - totalCreatureCost = totalSpellCost = countManaProducers = 0; - avgManaCost = avgCreatureCost = avgSpellCost = 0.0f; - - countCreatures = countSpells = countInstants = countEnchantments = countSorceries = countArtifacts = 0; - -} - -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) -{ - // initialize member variables to make sure they have valid values - initValues(); - - // 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]; - ostringstream oss; - oss << "deck" << (nbDecks + 1); - string bakaDir = JGE_GET_RES("/ai/baka"); - string deckFilename = oss.str(); - sprintf(buffer, "%s/%s.txt", bakaDir.c_str(), deckFilename.c_str()); - if (fileExists(buffer)) - { - found = 1; - nbDecks++; - - sprintf(smallDeckName, "%s_deck%i", "ai_baka", nbDecks); - DeckStat* deckStat = stats->getDeckStat(string(smallDeckName)); - - if ((deckStat != NULL) && (deckStat->nbgames > 0)) - { - aiDeckNames.push_back(deckFilename); - aiDeckStats.push_back(deckStat); - } - - } - } - 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 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(); -} - +#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::iterator it; + for (it = stats.begin(); it != stats.end(); it++) + { + SAFE_DELETE(it->second); + } + + stats.clear(); + + */ +} + +DeckStats::~DeckStats() +{ + map > ::iterator it; + for (it = masterDeckStats.begin(); it != masterDeckStats.end(); ++it) + { + string key = it->first; + map innerMap = masterDeckStats[key]; + map::iterator it2; + for (it2 = innerMap.begin(); it2 != innerMap.end(); it2++) + { + SAFE_DELETE(it2->second); + } + innerMap.clear(); + } + masterDeckStats.clear(); +} + + +DeckStat* DeckStats::getDeckStat(string opponentsFile) +{ + map stats = masterDeckStats[currentDeck]; + map::iterator it = stats.find(opponentsFile); + if (it == stats.end()) + { + return NULL; + } + else + { + return it->second; + } +} + +int DeckStats::nbGames() +{ + int nbgames = 0; + map stats = masterDeckStats[currentDeck]; + map::iterator it; + for (it = stats.begin(); it != stats.end(); it++) + { + DeckStat * d = it->second; + nbgames += d->nbgames; + } + return nbgames; +} + +int DeckStats::percentVictories(string opponentsFile) +{ + map stats = masterDeckStats[currentDeck]; + map::iterator it = stats.find(opponentsFile); + if (it == stats.end()) + { + return 50; + } + else + { + return (it->second->percentVictories()); + } +} + +int DeckStats::percentVictories() +{ + int victories = 0; + int nbgames = 0; + map stats = masterDeckStats[currentDeck]; + map::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) +{ + + currentDeck = filename; + if ( masterDeckStats.find(filename) != masterDeckStats.end() ) + { + return; + } + wagic::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()); + if ( masterDeckStats[filename].find(deckfile) != masterDeckStats[filename].end()) + { + SAFE_DELETE( masterDeckStats[filename][deckfile] ); + } + DeckStat * newDeckStat = NEW DeckStat(games, victories); + (masterDeckStats[filename])[deckfile] = newDeckStat; + } + 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 stats = masterDeckStats[currentDeck]; + map::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 *stats = &masterDeckStats[currentDeck]; + map::iterator it = stats->find(opponent->deckFileSmall); + if (it == stats->end()) + { + stats->insert( make_pair( opponent->deckFileSmall, NEW DeckStat(1, victory) )); + } + else + { + it->second->victories += victory; + it->second->nbgames += 1; + } + save(player); +} + +void DeckStats::EndInstance() +{ + SAFE_DELETE( mInstance ); +} + + +// StatsWrapper + + float noLandsProbInTurn[Constants::STATS_FOR_TURNS] = {0.0f}; + float noCreaturesProbInTurn[Constants::STATS_FOR_TURNS] = {0.0f}; + + int countCardsPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1] = {{0,0}}; + int countCreaturesPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1] = {{0,0}}; + int countSpellsPerCostAndColor[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1] = {{0,0}}; + + int countCardsPerCost[Constants::STATS_MAX_MANA_COST + 1] = {0}; + int countCreaturesPerCost[Constants::STATS_MAX_MANA_COST + 1] = {0}; + int countSpellsPerCost[Constants::STATS_MAX_MANA_COST + 1] = {0}; + int countLandsPerColor[Constants::MTG_NB_COLORS + 1] = {0}; + int countBasicLandsPerColor[Constants::MTG_NB_COLORS + 1] = {0}; + int countNonLandProducersPerColor[Constants::MTG_NB_COLORS + 1] = {0}; + int totalCostPerColor[Constants::MTG_NB_COLORS + 1] = {0}; + +void StatsWrapper::initValues() +{ + // initilize all member values to 0 + // Stats parameters and status + mDeckId = currentPage = pageCount = 0; + needUpdate = true; + + // Actual stats + percentVictories = 0; + gamesPlayed = cardCount = countLands = totalPrice = totalManaCost = 0; + totalCreatureCost = totalSpellCost = countManaProducers = 0; + avgManaCost = avgCreatureCost = avgSpellCost = 0.0f; + + countCreatures = countSpells = countInstants = countEnchantments = countSorceries = countArtifacts = 0; + +} + +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) +{ + // initialize member variables to make sure they have valid values + initValues(); + + // 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]; + ostringstream oss; + oss << "deck" << (nbDecks + 1); + string bakaDir = JGE_GET_RES("/ai/baka"); + string deckFilename = oss.str(); + sprintf(buffer, "%s/%s.txt", bakaDir.c_str(), deckFilename.c_str()); + if (fileExists(buffer)) + { + found = 1; + nbDecks++; + + sprintf(smallDeckName, "%s_deck%i", "ai_baka", nbDecks); + DeckStat* deckStat = stats->getDeckStat(string(smallDeckName)); + + if ((deckStat != NULL) && (deckStat->nbgames > 0)) + { + aiDeckNames.push_back(deckFilename); + aiDeckStats.push_back(deckStat); + } + + } + } + 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 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(); +} + diff --git a/projects/mtg/src/GameStateDeckViewer.cpp b/projects/mtg/src/GameStateDeckViewer.cpp index ae3081e23..5a8c6c816 100644 --- a/projects/mtg/src/GameStateDeckViewer.cpp +++ b/projects/mtg/src/GameStateDeckViewer.cpp @@ -1,1652 +1,1652 @@ -/* - * GameStateDeckViewer.cpp - * Class handling the Deck Editor - */ - -#include "PrecompiledHeader.h" - -#include -#include - -#include "DeckManager.h" -#include "GameStateDuel.h" -#include "GameStateDeckViewer.h" -#include "Translate.h" -#include "ManaCostHybrid.h" -#include "MTGCardInstance.h" -#include "WFilter.h" -#include "WDataSrc.h" -#include "DeckEditorMenu.h" -#include "SimpleMenu.h" -#include "utils.h" - -//!! helper function; this is probably handled somewhere in the code already. -// If not, should be placed in general library -void StringExplode(string str, string separator, vector* results) -{ - size_t found; - found = str.find_first_of(separator); - while (found != string::npos) - { - if (found > 0) results->push_back(str.substr(0, found)); - str = str.substr(found + 1); - found = str.find_first_of(separator); - } - if (str.length() > 0) results->push_back(str); -} - -GameStateDeckViewer::GameStateDeckViewer(GameApp* parent) : - GameState(parent) -{ - bgMusic = NULL; - nbDecks = 0; - deckNum = 0; - useFilter = 0; - isAIDeckSave = false; - mSwitching = false; - welcome_menu = NULL; - myCollection = NULL; - myDeck = NULL; - filterMenu = NULL; - source = NULL; - hudAlpha = 0; - subMenu = NULL; - mRotation = 0; - mSlide = 0; - mAlpha = 255; - menu = NULL; - stw = NULL; -} - -GameStateDeckViewer::~GameStateDeckViewer() -{ - SAFE_DELETE(bgMusic); - if (myDeck) - { - SAFE_DELETE(myDeck->parent); - SAFE_DELETE(myDeck); - } - if (myCollection) - { - SAFE_DELETE(myCollection->parent); - SAFE_DELETE(myCollection); - } - SAFE_DELETE(stw); - SAFE_DELETE(filterMenu); -} - -void GameStateDeckViewer::rotateCards(int direction) -{ - int left = direction; - if (left) - displayed_deck->next(); - else - displayed_deck->prev(); - loadIndexes(); - - int total = displayed_deck->Size(); - if (total) - { - lastPos = getCurrentPos(); - lastTotal = total; - } - -} - -void GameStateDeckViewer::rebuildFilters() -{ - if (!filterMenu) filterMenu = NEW WGuiFilters("Filter by...", NULL); - if (source) - SAFE_DELETE(source); - source = NEW WSrcDeckViewer(myDeck, myCollection); - filterMenu->setSrc(source); - if (displayed_deck != myDeck) source->swapSrc(); - filterMenu->Finish(true); - - // no stats need updating if there isn't a deck to update - if (stw && myDeck) - stw->updateStats( myDeck );; -} - -void GameStateDeckViewer::updateFilters() -{ - if (!displayed_deck) return; - - filterMenu->recolorFilter(useFilter - 1); - filterMenu->Finish(true); - int totalAfter = displayed_deck->Size(); - if (totalAfter && lastTotal) - { - - //This part is a hack. I don't understand why in some cases "displayed_deck's" currentPos is not 0 at this stage - { - while (int currentPos = displayed_deck->getOffset()) - { - if (currentPos > 0) - displayed_deck->prev(); - else - displayed_deck->next(); - } - } - - int pos = (totalAfter * lastPos) / lastTotal; - for (int i = 0; i < pos - 3; ++i) - { // "-3" because card "0" is displayed at position 3 initially - displayed_deck->next(); - } - } - stw->updateStats( myDeck );; - return; -} - -void GameStateDeckViewer::loadIndexes() -{ - for (int i = 0; i < 7; i++) - { - cardIndex[i] = displayed_deck->getCard(i); - } -} - -void GameStateDeckViewer::switchDisplay() -{ - if (displayed_deck == myCollection) - { - displayed_deck = myDeck; - } - else - { - displayed_deck = myCollection; - } - source->swapSrc(); - updateFilters(); - loadIndexes(); -} - -void GameStateDeckViewer::updateDecks() -{ - SAFE_DELETE(welcome_menu); - welcome_menu = NEW DeckEditorMenu(MENU_DECK_SELECTION, this, Fonts::OPTION_FONT, "Choose Deck To Edit"); - DeckManager * deckManager = DeckManager::GetInstance(); - vector playerDeckList = fillDeckMenu(welcome_menu, options.profileFile()); - - deckNum = 0; - newDeckname = ""; - nbDecks = playerDeckList.size() + 1; - welcome_menu->Add(MENU_ITEM_NEW_DECK, "--NEW--"); - if (options[Options::CHEATMODE].number && (!myCollection || myCollection->getCount(WSrcDeck::UNFILTERED_MIN_COPIES) < 4)) welcome_menu->Add( - MENU_ITEM_CHEAT_MODE, "--UNLOCK CARDS--"); - welcome_menu->Add(MENU_ITEM_CANCEL, "Cancel"); - - // update the deckmanager with the latest information - deckManager->updateMetaDataList(&playerDeckList, false); - // is this necessary to ensure no memory leaks? - playerDeckList.clear(); -} - -void GameStateDeckViewer::buildEditorMenu() -{ - ostringstream deckSummaryInformation; - deckSummaryInformation << "All changes are final." << endl; - - if (menu) - SAFE_DELETE( menu ); - //Build menu. - JRenderer::GetInstance()->FillRoundRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 100, ARGB(0, 0, 0, 0) ); - menu = NEW DeckEditorMenu(MENU_DECK_BUILDER, this, Fonts::OPTION_FONT, "Deck Editor", myDeck, stw); - - menu->Add(MENU_ITEM_FILTER_BY, "Filter By...", "Narrow down the list of cards. "); - menu->Add(MENU_ITEM_SWITCH_DECKS_NO_SAVE, "Switch Decks", "Do not make any changes.\nView another deck."); - menu->Add(MENU_ITEM_SAVE_RENAME, "Rename Deck", "Change the name of the deck"); - menu->Add(MENU_ITEM_SAVE_RETURN_MAIN_MENU, "Save & Quit Editor", "Save changes.\nReturn to the main menu"); - menu->Add(MENU_ITEM_SAVE_AS_AI_DECK, "Save As AI Deck", deckSummaryInformation.str()); - menu->Add(MENU_ITEM_MAIN_MENU, "Quit Editor", "Do not make any changes to deck.\nReturn to the main menu."); - menu->Add(MENU_ITEM_EDITOR_CANCEL, "Cancel", "Close menu."); - -} - -void GameStateDeckViewer::Start() -{ - hudAlpha = 0; - mSwitching = false; - subMenu = NULL; - myDeck = NULL; - mStage = STAGE_WELCOME; - mRotation = 0; - mSlide = 0; - mAlpha = 255; - last_user_activity = NO_USER_ACTIVITY_HELP_DELAY + 1; - onScreenTransition = 0; - useFilter = 0; - lastPos = 0; - lastTotal = 0; - - pricelist = NEW PriceList(JGE_GET_RES("settings/prices.dat").c_str(), mParent->collection); - playerdata = NEW PlayerData(mParent->collection); - myCollection = NEW DeckDataWrapper(playerdata->collection); - myCollection->Sort(WSrcCards::SORT_ALPHA); - displayed_deck = myCollection; - - //Icons - mIcons[Constants::MTG_COLOR_ARTIFACT] = WResourceManager::Instance()->GetQuad("c_artifact"); - mIcons[Constants::MTG_COLOR_LAND] = WResourceManager::Instance()->GetQuad("c_land"); - mIcons[Constants::MTG_COLOR_WHITE] = WResourceManager::Instance()->GetQuad("c_white"); - mIcons[Constants::MTG_COLOR_RED] = WResourceManager::Instance()->GetQuad("c_red"); - mIcons[Constants::MTG_COLOR_BLACK] = WResourceManager::Instance()->GetQuad("c_black"); - mIcons[Constants::MTG_COLOR_BLUE] = WResourceManager::Instance()->GetQuad("c_blue"); - mIcons[Constants::MTG_COLOR_GREEN] = WResourceManager::Instance()->GetQuad("c_green"); - for (int i = 0; i < 7; i++) - { - mIcons[i]->SetHotSpot(16, 16); - } - - //Grab a texture in VRAM. - pspIconsTexture = WResourceManager::Instance()->RetrieveTexture("iconspsp.png", RETRIEVE_LOCK); - - char buf[512]; - for (int i = 0; i < 8; i++) - { - sprintf(buf, "iconspsp%d", i); - pspIcons[i] = WResourceManager::Instance()->RetrieveQuad("iconspsp.png", (float) i * 32, 0, 32, 32, buf); - pspIcons[i]->SetHotSpot(16, 16); - } - - backQuad = WResourceManager::Instance()->GetQuad("back"); - - //init welcome menu - updateDecks(); - - GameApp::playMusic("track1.mp3"); - - loadIndexes(); - mEngine->ResetInput(); - JRenderer::GetInstance()->EnableVSync(true); -} - -void GameStateDeckViewer::End() -{ - JRenderer::GetInstance()->EnableVSync(false); - - SAFE_DELETE(welcome_menu); - SAFE_DELETE(menu); - SAFE_DELETE(subMenu); - - WResourceManager::Instance()->Release(pspIconsTexture); - if (myCollection) - { - SAFE_DELETE(myCollection); - } - if (myDeck) - { - SAFE_DELETE(myDeck->parent); - SAFE_DELETE(myDeck); - } - SAFE_DELETE(pricelist); - SAFE_DELETE(playerdata); - SAFE_DELETE(filterMenu); - SAFE_DELETE(source); -} - -void GameStateDeckViewer::addRemove(MTGCard * card) -{ - if (!card) return; - if (displayed_deck->Remove(card, 1, (displayed_deck == myDeck))) - { - if (displayed_deck == myCollection) - { - myDeck->Add(card); - myDeck->Sort(WSrcCards::SORT_ALPHA); - } - else - { - myCollection->Add(card); - } - } - myCollection->validate(); - myDeck->validate(); - stw->needUpdate = true; - loadIndexes(); -} - -void GameStateDeckViewer::saveDeck() -{ - myDeck->save(); - playerdata->save(); - pricelist->save(); -} - -/** - save the deck in a readable format to allow people to edit the file offline - */ -void GameStateDeckViewer::saveAsAIDeck(string deckName) -{ - - vector aiDecks = GameState::getValidDeckMetaData(JGE_GET_RES("ai/baka"), "ai_baka", NULL); - int nbAiDecks = aiDecks.size() + 1; - aiDecks.clear(); - - string defaultAiDeckName = "deck"; - std::ostringstream oss; - oss << "deck" << nbAiDecks; - defaultAiDeckName = oss.str(); - oss.str(""); - if (myDeck->parent->meta_desc == "") - oss << endl << "Can you beat your own creations?" << endl << "User created AI Deck # " << nbAiDecks; - else - oss << myDeck->parent->meta_desc; - string deckDesc = oss.str(); - string filepath = JGE_GET_RES("ai/baka/"); - filepath.append(defaultAiDeckName).append(".txt"); - DebugTrace("saving AI deck " << filepath); - myDeck->save(filepath, true, deckName, deckDesc); -} - -void GameStateDeckViewer::Update(float dt) -{ - - int x, y; - unsigned int distance2; - unsigned int minDistance2 = -1; - int n = 0; - - if (options.keypadActive()) - { - options.keypadUpdate(dt); - - if (newDeckname != "") - { - newDeckname = options.keypadFinish(); - - if (newDeckname != "") - { - if (isAIDeckSave) - { - saveAsAIDeck(newDeckname); - isAIDeckSave = false; - } - else if (myDeck && myDeck->parent) - { - myDeck->parent->meta_name = newDeckname; - saveDeck(); - } - mStage = STAGE_WAITING; - } - newDeckname = ""; - } - //Prevent screen from updating. - return; - } - hudAlpha = 255 - ((int) last_user_activity * 500); - if (hudAlpha < 0) hudAlpha = 0; - if (subMenu) - { - subMenu->Update(dt); - if (subMenu->isClosed()) - { - SAFE_DELETE(subMenu); - } - return; - } - if (mStage == STAGE_WAITING || mStage == STAGE_ONSCREEN_MENU) - { - switch (mEngine->ReadButton()) - { - case JGE_BTN_LEFT: - last_user_activity = 0; - mStage = STAGE_TRANSITION_LEFT; - break; - case JGE_BTN_RIGHT: - last_user_activity = 0; - mStage = STAGE_TRANSITION_RIGHT; - break; - case JGE_BTN_UP: - last_user_activity = 0; - mStage = STAGE_TRANSITION_UP; - useFilter++; - if (useFilter >= MAX_SAVED_FILTERS) useFilter = 0; - break; - case JGE_BTN_DOWN: - last_user_activity = 0; - mStage = STAGE_TRANSITION_DOWN; - useFilter--; - if (useFilter < 0) useFilter = MAX_SAVED_FILTERS - 1; - break; - case JGE_BTN_CANCEL: - options[Options::DISABLECARDS].number = !options[Options::DISABLECARDS].number; - break; - case JGE_BTN_PRI: - if (last_user_activity > 0.2) - { - last_user_activity = 0; - switchDisplay(); - } - break; - case JGE_BTN_OK: - last_user_activity = 0; - addRemove(cardIndex[2]); - break; - case JGE_BTN_SEC: - last_user_activity = 0; - SAFE_DELETE(subMenu); - char buffer[4096]; - { - MTGCard * card = cardIndex[2]; - if (card && displayed_deck->count(card)) - { - price = pricelist->getSellPrice(card->getMTGId()); - sprintf(buffer, "%s : %i %s", _(card->data->getName()).c_str(), price, _("credits").c_str()); - const float menuXOffset = SCREEN_WIDTH_F - 300; - const float menuYOffset = SCREEN_HEIGHT_F / 2; - subMenu = NEW SimpleMenu(MENU_CARD_PURCHASE, this, Fonts::MAIN_FONT, menuXOffset, menuYOffset, buffer); - subMenu->Add(MENU_ITEM_YES, "Yes"); - subMenu->Add(MENU_ITEM_NO, "No", "", true); - } - } - stw->needUpdate = true; - break; - - case JGE_BTN_MENU: - mStage = STAGE_MENU; - buildEditorMenu(); - break; - case JGE_BTN_CTRL: - mStage = STAGE_FILTERS; - if (!filterMenu) - { - filterMenu = NEW WGuiFilters("Filter by...", NULL); - if (source) - SAFE_DELETE(source); - source = NEW WSrcDeckViewer(myDeck, myCollection); - filterMenu->setSrc(source); - if (displayed_deck != myDeck) source->swapSrc(); - } - filterMenu->Entering(JGE_BTN_NONE); - break; - case JGE_BTN_PREV: - if (last_user_activity < NO_USER_ACTIVITY_HELP_DELAY) - last_user_activity = NO_USER_ACTIVITY_HELP_DELAY + 1; - else if ((mStage == STAGE_ONSCREEN_MENU) && (--stw->currentPage < 0)) stw->currentPage = stw->pageCount; - break; - case JGE_BTN_NEXT: - if (last_user_activity < NO_USER_ACTIVITY_HELP_DELAY) - last_user_activity = NO_USER_ACTIVITY_HELP_DELAY + 1; - else if ((mStage == STAGE_ONSCREEN_MENU) && (++stw->currentPage > stw->pageCount)) stw->currentPage = 0; - break; - default: // no keypress - if (mEngine->GetLeftClickCoordinates(x, y)) - { - for(int i=0; i < CARDS_DISPLAYED; i++) - { - distance2 = (cardsCoordinates[i].second - y) * (cardsCoordinates[i].second - y) + (cardsCoordinates[i].first - x) * (cardsCoordinates[i].first - x); - if (distance2 < minDistance2) - { - minDistance2 = distance2; - n = i; - } - } - - if (n < ((CARDS_DISPLAYED/2) - 1)) - { - last_user_activity = 0; - mStage = STAGE_TRANSITION_RIGHT; - } - if (n > ((CARDS_DISPLAYED/2) + 1)) - { - last_user_activity = 0; - mStage = STAGE_TRANSITION_LEFT; - } - mEngine->LeftClickedProcessed(); - break; - } - - if (last_user_activity > NO_USER_ACTIVITY_HELP_DELAY) - { - if (mStage != STAGE_ONSCREEN_MENU) - { - mStage = STAGE_ONSCREEN_MENU; - onScreenTransition = 1; - } - else - { - if (onScreenTransition > 0) - onScreenTransition -= 0.05f; - else - onScreenTransition = 0; - } - } - else - last_user_activity += dt; - } - - } - if (mStage == STAGE_TRANSITION_RIGHT || mStage == STAGE_TRANSITION_LEFT) - { - if (mStage == STAGE_TRANSITION_RIGHT) - { - mRotation -= dt * MED_SPEED; - if (mRotation < -1.0f) - { - do - { - rotateCards(mStage); - mRotation += 1; - } while (mRotation < -1.0f); - mStage = STAGE_WAITING; - mRotation = 0; - } - } - else if (mStage == STAGE_TRANSITION_LEFT) - { - mRotation += dt * MED_SPEED; - if (mRotation > 1.0f) - { - do - { - rotateCards(mStage); - mRotation -= 1; - } while (mRotation > 1.0f); - mStage = STAGE_WAITING; - mRotation = 0; - } - } - } - if (mStage == STAGE_TRANSITION_DOWN || mStage == STAGE_TRANSITION_UP) - { - if (mStage == STAGE_TRANSITION_DOWN) - { - mSlide -= 0.05f; - if (mSlide < -1.0f) - { - updateFilters(); - loadIndexes(); - mSlide = 1; - } - else if (mSlide > 0 && mSlide < 0.05) - { - mStage = STAGE_WAITING; - mSlide = 0; - } - } - if (mStage == STAGE_TRANSITION_UP) - { - mSlide += 0.05f; - if (mSlide > 1.0f) - { - updateFilters(); - loadIndexes(); - mSlide = -1; - } - else if (mSlide < 0 && mSlide > -0.05) - { - mStage = STAGE_WAITING; - mSlide = 0; - } - } - - } - else if (mStage == STAGE_WELCOME) - welcome_menu->Update(dt); - else if (mStage == STAGE_MENU) - menu->Update(dt); - else if (mStage == STAGE_FILTERS) - { - JButton key = mEngine->ReadButton(); - if (filterMenu) - { - if (key == JGE_BTN_CTRL) - { - //useFilter = 0; - filterMenu->Finish(true); - filterMenu->Update(dt); - loadIndexes(); - return; - } - if (!filterMenu->isFinished()) - { - filterMenu->CheckUserInput(key); - filterMenu->Update(dt); - } - else - { - mStage = STAGE_WAITING; - updateFilters(); - loadIndexes(); - } - } - } -} - -void GameStateDeckViewer::renderOnScreenBasicInfo() -{ - JRenderer *renderer = JRenderer::GetInstance(); - WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - char buffer[256]; - - float y = 0; - int allCopies, nowCopies; - nowCopies = displayed_deck->getCount(WSrcDeck::FILTERED_COPIES); - allCopies = displayed_deck->getCount(WSrcDeck::UNFILTERED_COPIES); - WCardFilter * wc = displayed_deck->getFiltersRoot(); - - if (wc) - sprintf(buffer, "%s %i of %i cards (%i unique)", (displayed_deck == myDeck) ? "DECK: " : " ", nowCopies, allCopies, - displayed_deck->getCount(WSrcDeck::FILTERED_UNIQUE)); - else - sprintf(buffer, "%s%i cards (%i unique)", (displayed_deck == myDeck) ? "DECK: " : " ", allCopies, displayed_deck->getCount( - WSrcDeck::UNFILTERED_UNIQUE)); - - float w = mFont->GetStringWidth(buffer); - renderer->FillRoundRect(SCREEN_WIDTH - (w + 27), y + 5, w + 10, 15, 5, ARGB(128,0,0,0)); - - mFont->DrawString(buffer, SCREEN_WIDTH - 22, y + 15, JGETEXT_RIGHT); - if (useFilter != 0) renderer->RenderQuad(mIcons[useFilter - 1], SCREEN_WIDTH - 10, y + 15, 0.0f, 0.5, 0.5); -} - -//returns position of the current card (cusor) in the currently viewed color/filter -int GameStateDeckViewer::getCurrentPos() -{ - int total = displayed_deck->Size(); - - int currentPos = displayed_deck->getOffset(); - currentPos += 2; //we start by displaying card number 3 - currentPos = currentPos % total + 1; - if (currentPos < 0) currentPos = (total + currentPos); - if (!currentPos) currentPos = total; - return currentPos; -} - -void GameStateDeckViewer::renderSlideBar() -{ - WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - - int total = displayed_deck->Size(); - if (total == 0) return; - - float filler = 15; - float y = SCREEN_HEIGHT_F - 25; - float bar_size = SCREEN_WIDTH_F - 2 * filler; - JRenderer * r = JRenderer::GetInstance(); - int currentPos = getCurrentPos(); - - float cursor_pos = bar_size * currentPos / total; - - r->FillRoundRect(filler + 5, y + 5, bar_size, 0, 3, ARGB(hudAlpha/2,0,0,0)); - r->DrawLine(filler + cursor_pos + 5, y + 5, filler + cursor_pos + 5, y + 10, ARGB(hudAlpha/2,0,0,0)); - - r->FillRoundRect(filler, y, bar_size, 0, 3, ARGB(hudAlpha/2,128,128,128)); - r->DrawLine(filler + cursor_pos, y, filler + cursor_pos, y + 5, ARGB(hudAlpha,255,255,255)); - char buffer[256]; - string deckname = _("Collection"); - if (displayed_deck == myDeck) - { - deckname = _("Deck"); - } - sprintf(buffer, "%s - %i/%i", deckname.c_str(), currentPos, total); - mFont->SetColor(ARGB(hudAlpha,255,255,255)); - mFont->DrawString(buffer, SCREEN_WIDTH / 2, y, JGETEXT_CENTER); - - mFont->SetColor(ARGB(255,255,255,255)); -} - -void GameStateDeckViewer::renderDeckBackground() -{ - int max1 = 0; - int maxC1 = 4; - int max2 = 0; - int maxC2 = 4; - - for (int i = 0; i < Constants::MTG_NB_COLORS - 1; i++) - { - int value = myDeck->getCount(i); - if (value > max1) - { - max2 = max1; - maxC2 = maxC1; - max1 = value; - maxC1 = i; - } - else if (value > max2) - { - max2 = value; - maxC2 = i; - } - } - if (max2 < max1 / 2) - { - maxC2 = maxC1; - } - PIXEL_TYPE colors[] = { ARGB(255, Constants::_r[maxC1], Constants::_g[maxC1], Constants::_b[maxC1]), - ARGB(255, Constants::_r[maxC1], Constants::_g[maxC1], Constants::_b[maxC1]), - ARGB(255, Constants::_r[maxC2], Constants::_g[maxC2], Constants::_b[maxC2]), - ARGB(255, Constants::_r[maxC2], Constants::_g[maxC2], Constants::_b[maxC2]), }; - - JRenderer::GetInstance()->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, colors); - -} - -void GameStateDeckViewer::renderOnScreenMenu() -{ - - WFont * font = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - font->SetColor(ARGB(255,255,255,255)); - JRenderer * r = JRenderer::GetInstance(); - float pspIconsSize = 0.5; - float fH = font->GetHeight() + 1; - - float leftTransition = onScreenTransition * 84; - float rightTransition = onScreenTransition * 204; - float leftPspX = 40 - leftTransition; - float leftPspY = SCREEN_HEIGHT / 2 - 20; - float rightPspX = SCREEN_WIDTH - 100 + rightTransition; - float rightPspY = SCREEN_HEIGHT / 2 - 20; - - if (stw->currentPage == 0) - { - //FillRects - r->FillRect(0 - (onScreenTransition * 84), 0, 84, SCREEN_HEIGHT, ARGB(128,0,0,0)); - r->FillRect(SCREEN_WIDTH - 204 + (onScreenTransition * 204), 0, 200, SCREEN_HEIGHT, ARGB(128,0,0,0)); - - //LEFT PSP CIRCLE render - r->FillCircle(leftPspX, leftPspY, 40, ARGB(128,50,50,50)); - - r->RenderQuad(pspIcons[0], leftPspX, leftPspY - 20, 0, pspIconsSize, pspIconsSize); - r->RenderQuad(pspIcons[1], leftPspX, leftPspY + 20, 0, pspIconsSize, pspIconsSize); - r->RenderQuad(pspIcons[2], leftPspX - 20, leftPspY, 0, pspIconsSize, pspIconsSize); - r->RenderQuad(pspIcons[3], leftPspX + 20, leftPspY, 0, pspIconsSize, pspIconsSize); - - font->DrawString(_("Prev."), leftPspX - 35, leftPspY - 15); - font->DrawString(_("Next"), leftPspX + 15, leftPspY - 15); - font->DrawString(_("card"), leftPspX - 35, leftPspY); - font->DrawString(_("card"), leftPspX + 15, leftPspY); - font->DrawString(_("Next edition"), leftPspX - 33, leftPspY - 35); - font->DrawString(_("Prev. edition"), leftPspX - 33, leftPspY + 25); - - //RIGHT PSP CIRCLE render - r->FillCircle(rightPspX + (onScreenTransition * 204), rightPspY, 40, ARGB(128,50,50,50)); - r->RenderQuad(pspIcons[4], rightPspX + 20, rightPspY, 0, pspIconsSize, pspIconsSize); - r->RenderQuad(pspIcons[5], rightPspX, rightPspY - 20, 0, pspIconsSize, pspIconsSize); - r->RenderQuad(pspIcons[6], rightPspX - 20, rightPspY, 0, pspIconsSize, pspIconsSize); - r->RenderQuad(pspIcons[7], rightPspX, rightPspY + 20, 0, pspIconsSize, pspIconsSize); - - font->DrawString(_("Toggle Images"), rightPspX - 35, rightPspY - 40); - - if (displayed_deck == myCollection) - { - font->DrawString(_("Add card"), rightPspX + 20, rightPspY - 15); - font->DrawString(_("View Deck"), rightPspX - 20, rightPspY - 15, JGETEXT_RIGHT); - } - else - { - font->DrawString(_("Remove card"), rightPspX + 20, rightPspY - 15); - font->DrawString(_("View Collection"), rightPspX - 20, rightPspY - 15, JGETEXT_RIGHT); - } - font->DrawString(_("Sell card"), rightPspX - 30, rightPspY + 20); - //Bottom menus - font->DrawString(_("menu"), SCREEN_WIDTH - 35 + rightTransition, SCREEN_HEIGHT - 15); - font->DrawString(_("filter"), SCREEN_WIDTH - 95 + rightTransition, SCREEN_HEIGHT - 15); - - //Your Deck Information - char buffer[300]; - int nb_letters = 0; - for (int j = 0; j < Constants::MTG_NB_COLORS; j++) - { - int value = myDeck->getCount(j); - if (value > 0) - { - sprintf(buffer, "%i", value); - font->DrawString(buffer, SCREEN_WIDTH - 190 + rightTransition + nb_letters * 13, SCREEN_HEIGHT / 2 + 40); - r->RenderQuad(mIcons[j], SCREEN_WIDTH - 197 + rightTransition + nb_letters * 13, SCREEN_HEIGHT / 2 + 46, 0, 0.5, - 0.5); - if (value > 9) - { - nb_letters += 3; - } - else - { - nb_letters += 2; - } - } - } - int value = myDeck->getCount(WSrcDeck::UNFILTERED_COPIES); - sprintf(buffer, _("Your Deck: %i cards").c_str(), value); - font->DrawString(buffer, SCREEN_WIDTH - 200 + rightTransition, SCREEN_HEIGHT / 2 + 25); - - if (displayed_deck == myCollection) - { - font->DrawString(_("in: collection"), 5 - leftTransition, 5); - font->DrawString(_("Use SQUARE to view your deck,"), SCREEN_WIDTH - 200 + rightTransition, 5); - } - else - { - font->DrawString(_("in: deck"), 5 - leftTransition, 5); - font->DrawString(_("Use SQUARE to view collection,"), SCREEN_WIDTH - 200 + rightTransition, 5); - } - font->DrawString(_("Press L/R to cycle through"), SCREEN_WIDTH - 200 + rightTransition, 5 + fH); - font->DrawString(_("deck statistics."), SCREEN_WIDTH - 200 + rightTransition, 5 + fH * 2); - - } - else - { - stw->updateStats( myDeck );; - - char buffer[300]; - - leftTransition = -(onScreenTransition / 2) * SCREEN_WIDTH; - rightTransition = -leftTransition; - - r->FillRect(0 + leftTransition, 0, SCREEN_WIDTH / 2, SCREEN_HEIGHT, ARGB(128,0,0,0)); - r->FillRect(SCREEN_WIDTH / 2 + rightTransition, 0, SCREEN_WIDTH / 2, SCREEN_HEIGHT, ARGB(128,0,0,0)); - r->FillRect(10 + leftTransition, 10, SCREEN_WIDTH / 2 - 10, SCREEN_HEIGHT - 20, ARGB(128,0,0,0)); - r->FillRect(SCREEN_WIDTH / 2 + rightTransition, 10, SCREEN_WIDTH / 2 - 10, SCREEN_HEIGHT - 20, ARGB(128,0,0,0)); - font->DrawString(_("menu"), SCREEN_WIDTH - 35 + rightTransition, SCREEN_HEIGHT - 15); - font->DrawString(_("filter"), SCREEN_WIDTH - 95 + rightTransition, SCREEN_HEIGHT - 15); - - int nb_letters = 0; - float posX, posY; - DWORD graphColor; - - graphColor = ARGB(200, 155, 155, 155); - string STATS_TITLE_FORMAT = _("%i: %s"); - - switch (stw->currentPage) - { - case 1: // Counts, price - // Title - sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Statistics Summary").c_str()); - font->DrawString(buffer, 10 + leftTransition, 10); - - posY = 30; - posX = 180; - sprintf(buffer, _("Your Deck: %i cards").c_str(), stw->cardCount); - font->DrawString(buffer, 20 + leftTransition, posY); - posY += 10; - - // Counts by color - for (int j = 0; j < Constants::MTG_NB_COLORS; j++) - { - int value = myDeck->getCount(j); - if (value > 0) - { - sprintf(buffer, "%i", value); - font->DrawString(buffer, 38 + nb_letters * 13 + leftTransition, posY + 5); - r->RenderQuad(mIcons[j], 30 + nb_letters * 13 + leftTransition, posY + 11, 0, 0.5, 0.5); - if (value > 9) - { - nb_letters += 3; - } - else - { - nb_letters += 2; - } - } - } - posY += 25; - - r->DrawLine(posX - 4 + leftTransition, posY - 1, posX - 4 + leftTransition, posY + 177, ARGB(128, 255, 255, 255)); - r->DrawLine(19 + leftTransition, posY - 1, 19 + leftTransition, posY + 177, ARGB(128, 255, 255, 255)); - r->DrawLine(posX + 40 + leftTransition, posY - 1, posX + 40 + leftTransition, posY + 177, ARGB(128, 255, 255, 255)); - - r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); - - font->DrawString(_("Lands"), 20 + leftTransition, posY); - sprintf(buffer, _("%i").c_str(), stw->countLands); - font->DrawString(buffer, posX + leftTransition, posY); - - posY += 14; - r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); - font->DrawString(_("Creatures"), 20 + leftTransition, posY); - sprintf(buffer, _("%i").c_str(), stw->countCreatures); - font->DrawString(buffer, posX + leftTransition, posY); - - posY += 14; - r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); - font->DrawString(_("Spells"), 20 + leftTransition, posY); - sprintf(buffer, _("%i").c_str(), stw->countSpells); - font->DrawString(buffer, posX + leftTransition, posY); - - posY += 10; - font->DrawString(_("Instants"), 30 + leftTransition, posY); - sprintf(buffer, _("%i").c_str(), stw->countInstants); - font->DrawString(buffer, posX + leftTransition, posY); - - posY += 10; - font->DrawString(_("Enchantments"), 30 + leftTransition, posY); - sprintf(buffer, _("%i").c_str(), stw->countEnchantments); - font->DrawString(buffer, posX + leftTransition, posY); - - posY += 10; - font->DrawString(_("Sorceries"), 30 + leftTransition, posY); - sprintf(buffer, _("%i").c_str(), stw->countSorceries); - font->DrawString(buffer, posX + leftTransition, posY); - //sprintf(buffer, "Artifacts: %i", stw->countArtifacts); - //mFont->DrawString(buffer, 20, 123); - - posY += 14; - r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); - - font->DrawString(_("Average converted mana cost"), 20 + leftTransition, posY); - sprintf(buffer, _("%2.2f").c_str(), stw->avgManaCost); - font->DrawString(buffer, posX + leftTransition, posY); - - posY += 14; - r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); - font->DrawString(_("Probabilities"), 20 + leftTransition, posY); - - posY += 10; - font->DrawString(_("No land in 1st hand"), 30 + leftTransition, posY); - sprintf(buffer, _("%2.2f%%").c_str(), stw->noLandsProbInTurn[0]); - font->DrawString(buffer, posX + leftTransition, posY); - - posY += 10; - font->DrawString(_("No land in 9 cards"), 30 + leftTransition, posY); - sprintf(buffer, _("%2.2f%%").c_str(), stw->noLandsProbInTurn[2]); - font->DrawString(buffer, posX + leftTransition, posY); - - posY += 10; - font->DrawString(_("No creatures in 1st hand"), 30 + leftTransition, posY); - sprintf(buffer, _("%2.2f%%").c_str(), stw->noCreaturesProbInTurn[0]); - font->DrawString(buffer, posX + leftTransition, posY); - - // Playgame Statistics - posY += 14; - r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); - font->DrawString(_("Playgame statistics"), 20 + leftTransition, posY); - - posY += 10; - font->DrawString(_("Games played"), 30 + leftTransition, posY); - sprintf(buffer, _("%i").c_str(), stw->gamesPlayed); - font->DrawString(buffer, posX + leftTransition, posY); - - posY += 10; - font->DrawString(_("Victory ratio"), 30 + leftTransition, posY); - sprintf(buffer, _("%i%%").c_str(), stw->percentVictories); - font->DrawString(buffer, posX + leftTransition, posY); - - posY += 15; - r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); - font->DrawString(_("Total price (credits)"), 20 + leftTransition, posY); - sprintf(buffer, _("%i ").c_str(), stw->totalPrice); - font->DrawString(buffer, posX + leftTransition, posY); - r->DrawLine(20 + leftTransition, posY + 13, posX + 40 + leftTransition, posY + 13, ARGB(128, 255, 255, 255)); - - break; - - case 5: // Land statistics - sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana production").c_str()); - font->DrawString(buffer, 10 + leftTransition, 10); - - font->DrawString(_("Counts of manasources per type and color:"), 20 + leftTransition, 30); - - posY = 70; - - // Column titles - for (int j = 0; j < Constants::MTG_NB_COLORS - 1; j++) - { - r->RenderQuad(mIcons[j], 52 + j * 15 + leftTransition, posY - 10, 0, 0.5, 0.5); - } - - //font->DrawString(_("C"), 30 + leftTransition, posY-16); - //font->DrawString(_("Ty"), 27 + leftTransition, posY-16); - - // Horizontal table lines - r->DrawLine(27 + leftTransition, posY - 20, 60 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, posY - 20, - ARGB(128, 255, 255, 255)); - r->DrawLine(27 + leftTransition, posY - 1, 60 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, posY - 1, - ARGB(128, 255, 255, 255)); - r->DrawLine(27 + leftTransition, 2 * 10 + posY + 12, 60 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, 2 * 10 - + posY + 12, ARGB(128, 255, 255, 255)); - r->DrawLine(27 + leftTransition, 3 * 10 + posY + 14, 60 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, 3 * 10 - + posY + 14, ARGB(128, 255, 255, 255)); - - // Vertical table lines - r->DrawLine(26 + leftTransition, posY - 20, 26 + leftTransition, 3 * 10 + posY + 14, ARGB(128, 255, 255, 255)); - r->DrawLine(43 + leftTransition, posY - 20, 43 + leftTransition, 3 * 10 + posY + 14, ARGB(128, 255, 255, 255)); - r->DrawLine(60 + leftTransition + (Constants::MTG_NB_COLORS - 2) * 15, posY - 20, 60 + leftTransition - + (Constants::MTG_NB_COLORS - 2) * 15, 3 * 10 + posY + 14, ARGB(128, 255, 255, 255)); - - font->DrawString(_("BL"), 27 + leftTransition, posY); - font->DrawString(_("NB"), 27 + leftTransition, posY + 10); - font->DrawString(_("O"), 30 + leftTransition, posY + 20); - font->DrawString(_("T"), 30 + leftTransition, posY + 33); - - int curCount; - - for (int j = 0; j < Constants::MTG_NB_COLORS - 1; j++) - { - curCount = stw->countBasicLandsPerColor[j]; - sprintf(buffer, (curCount == 0 ? "." : "%i"), curCount); - font->DrawString(buffer, 49 + leftTransition + j * 15, posY); - - curCount = stw->countLandsPerColor[j]; - sprintf(buffer, (curCount == 0 ? "." : "%i"), curCount); - font->DrawString(buffer, 49 + leftTransition + j * 15, posY + 10); - - curCount = stw->countNonLandProducersPerColor[j]; - sprintf(buffer, (curCount == 0 ? "." : "%i"), curCount); - font->DrawString(buffer, 49 + leftTransition + j * 15, posY + 20); - - curCount = stw->countLandsPerColor[j] + stw->countBasicLandsPerColor[j] + stw->countNonLandProducersPerColor[j]; - sprintf(buffer, (curCount == 0 ? "." : "%i"), curCount); - font->DrawString(buffer, 49 + leftTransition + j * 15, posY + 33); - } - - posY += 55; - font->DrawString(_("BL - Basic lands"), 20 + leftTransition, posY); - posY += 10; - font->DrawString(_("NB - Non-basic lands"), 20 + leftTransition, posY); - posY += 10; - font->DrawString(_("O - Other (non-land) manasources"), 26 + leftTransition, posY); - posY += 10; - font->DrawString(_("T - Totals"), 26 + leftTransition, posY); - - break; - - case 6: // Land statistics - in symbols - sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana production - in mana symbols").c_str()); - font->DrawString(buffer, 10 + leftTransition, 10); - font->DrawString(_("Total colored manasymbols in lands' production:"), 20 + leftTransition, 30); - - int totalProducedSymbols; - totalProducedSymbols = 0; - for (int i = 1; i < Constants::MTG_NB_COLORS - 1; i++) - { - totalProducedSymbols += stw->countLandsPerColor[i] + stw->countBasicLandsPerColor[i]; //!! Move to updatestats! - } - - posY = 50; - for (int i = 1; i < Constants::MTG_NB_COLORS - 1; i++) - { - if (stw->countLandsPerColor[i] + stw->countBasicLandsPerColor[i] > 0) - { - sprintf(buffer, _("%i").c_str(), stw->countLandsPerColor[i] + stw->countBasicLandsPerColor[i]); - font->DrawString(buffer, 20 + leftTransition, posY); - sprintf(buffer, _("(%i%%)").c_str(), (int) (100 * (float) (stw->countLandsPerColor[i] - + stw->countBasicLandsPerColor[i]) / totalProducedSymbols)); - font->DrawString(buffer, 33 + leftTransition, posY); - posX = 72; - for (int j = 0; j < stw->countLandsPerColor[i] + stw->countBasicLandsPerColor[i]; j++) - { - r->RenderQuad(mIcons[i], posX + leftTransition, posY + 6, 0, 0.5, 0.5); - posX += ((j + 1) % 10 == 0) ? 17 : 13; - if ((((j + 1) % 30) == 0) && (j < stw->countLandsPerColor[i] + stw->countBasicLandsPerColor[i] - 1)) - { - posX = 72; - posY += 15; - } - } - posY += 17; - } - } - - break; - - case 2: // Mana cost detail - case 3: - case 4: - int (*countPerCost)[Constants::STATS_MAX_MANA_COST + 1]; - int (*countPerCostAndColor)[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1]; - float avgCost; - - switch (stw->currentPage) - { // Nested switch on the same variable. Oh yes. - case 2: // Total counts - // Title - sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana cost detail").c_str()); - font->DrawString(buffer, 10 + leftTransition, 10); - font->DrawString(_("Card counts per mana cost:"), 20 + leftTransition, 30); - avgCost = stw->avgManaCost; - countPerCost = &stw->countCardsPerCost; - countPerCostAndColor = &stw->countCardsPerCostAndColor; - break; - case 3: // Creature counts - // Title - sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana cost detail - Creatures").c_str()); - font->DrawString(buffer, 10 + leftTransition, 10); - font->DrawString(_("Creature counts per mana cost:"), 20 + leftTransition, 30); - avgCost = stw->avgCreatureCost; - countPerCost = &stw->countCreaturesPerCost; - countPerCostAndColor = &stw->countCreaturesPerCostAndColor; - break; - case 4: // Spell counts - // Title - sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana cost detail - Spells").c_str()); - font->DrawString(buffer, 10 + leftTransition, 10); - font->DrawString(_("Non-creature spell counts per mana cost:"), 20 + leftTransition, 30); - avgCost = stw->avgSpellCost; - countPerCost = &stw->countSpellsPerCost; - countPerCostAndColor = &stw->countSpellsPerCostAndColor; - break; - default: - countPerCost = NULL; - countPerCostAndColor = NULL; - avgCost = 0; - break; - } - - posY = 70; - - // Column titles - for (int j = 0; j < Constants::MTG_NB_COLORS - 1; j++) - { - r->RenderQuad(mIcons[j], 67 + j * 15 + leftTransition, posY - 10, 0, 0.5, 0.5); - } - - font->DrawString(_("C"), 30 + leftTransition, posY - 16); - font->DrawString(_("#"), 45 + leftTransition, posY - 16); - - // Horizontal table lines - r->DrawLine(27 + leftTransition, posY - 20, 75 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, posY - 20, - ARGB(128, 255, 255, 255)); - r->DrawLine(27 + leftTransition, posY - 1, 75 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, posY - 1, - ARGB(128, 255, 255, 255)); - r->DrawLine(27 + leftTransition, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, 75 + (Constants::MTG_NB_COLORS - 2) - * 15 + leftTransition, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, ARGB(128, 255, 255, 255)); - - // Vertical table lines - r->DrawLine(26 + leftTransition, posY - 20, 26 + leftTransition, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, - ARGB(128, 255, 255, 255)); - r->DrawLine(41 + leftTransition, posY - 20, 41 + leftTransition, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, - ARGB(128, 255, 255, 255)); - r->DrawLine(58 + leftTransition, posY - 20, 58 + leftTransition, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, - ARGB(128, 255, 255, 255)); - r->DrawLine(75 + leftTransition + (Constants::MTG_NB_COLORS - 2) * 15, posY - 20, 75 + leftTransition - + (Constants::MTG_NB_COLORS - 2) * 15, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, - ARGB(128, 255, 255, 255)); - - for (int i = 0; i <= Constants::STATS_MAX_MANA_COST; i++) - { - sprintf(buffer, _("%i").c_str(), i); - font->DrawString(buffer, 30 + leftTransition, posY); - sprintf(buffer, ((*countPerCost)[i] > 0) ? _("%i").c_str() : ".", (*countPerCost)[i]); - font->DrawString(buffer, 45 + leftTransition, posY); - for (int j = 0; j < Constants::MTG_NB_COLORS - 1; j++) - { - sprintf(buffer, ((*countPerCostAndColor)[i][j] > 0) ? _("%i").c_str() : ".", (*countPerCostAndColor)[i][j]); - font->DrawString(buffer, 64 + leftTransition + j * 15, posY); - } - r->FillRect(77.f + leftTransition + (Constants::MTG_NB_COLORS - 2) * 15.0f, posY + 2.0f, (*countPerCost)[i] * 5.0f, - 8.0f, graphColor); - posY += 10; - } - - posY += 10; - sprintf(buffer, _("Average converted mana cost: %2.2f").c_str(), avgCost); - font->DrawString(buffer, 20 + leftTransition, posY); - posY += 15; - sprintf(buffer, _("C - Converted mana cost. Cards with cost>%i are included in the last row.").c_str(), - Constants::STATS_MAX_MANA_COST); - font->DrawString(buffer, 20 + leftTransition, posY); - posY += 10; - font->DrawString(_("# - Total number of cards with given cost"), 20 + leftTransition, posY); - - break; - - case 8: - // Title - sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Probabilities").c_str()); - font->DrawString(buffer, 10 + leftTransition, 10); - - // No lands detail - float graphScale, graphWidth; - graphWidth = 100; - graphScale = (stw->noLandsProbInTurn[0] == 0) ? 0 : (graphWidth / stw->noLandsProbInTurn[0]); - font->DrawString(_("No lands in first n cards:"), 20 + leftTransition, 30); - - posY = 50; - for (int i = 0; i < Constants::STATS_FOR_TURNS; i++) - { - sprintf(buffer, _("%i:").c_str(), i + 7); - font->DrawString(buffer, 30 + leftTransition, posY); - sprintf(buffer, _("%2.2f%%").c_str(), stw->noLandsProbInTurn[i]); - font->DrawString(buffer, 45 + leftTransition, posY); - r->FillRect(84 + leftTransition, posY + 2, graphScale * stw->noLandsProbInTurn[i], 8, graphColor); - posY += 10; - } - - // No creatures probability detail - posY += 10; - font->DrawString(_("No creatures in first n cards:"), 20 + leftTransition, posY); - posY += 20; - graphScale = (stw->noCreaturesProbInTurn[0] == 0) ? 0 : (graphWidth / stw->noCreaturesProbInTurn[0]); - - for (int i = 0; i < Constants::STATS_FOR_TURNS; i++) - { - sprintf(buffer, _("%i:").c_str(), i + 7); - font->DrawString(buffer, 30 + leftTransition, posY); - sprintf(buffer, _("%2.2f%%").c_str(), stw->noCreaturesProbInTurn[i]); - font->DrawString(buffer, 45 + leftTransition, posY); - r->FillRect(84 + leftTransition, posY + 2, graphScale * stw->noCreaturesProbInTurn[i], 8, graphColor); - posY += 10; - } - - break; - - case 7: // Total mana cost per color - // Title - sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana cost per color").c_str()); - font->DrawString(buffer, 10 + leftTransition, 10); - - font->DrawString(_("Total colored manasymbols in cards' casting costs:"), 20 + leftTransition, 30); - - posY = 50; - for (int i = 1; i < Constants::MTG_NB_COLORS - 1; i++) - { - if (stw->totalCostPerColor[i] > 0) - { - sprintf(buffer, _("%i").c_str(), stw->totalCostPerColor[i]); - font->DrawString(buffer, 20 + leftTransition, posY); - sprintf(buffer, _("(%i%%)").c_str(), (int) (100 * (float) stw->totalCostPerColor[i] / stw->totalColoredSymbols)); - font->DrawString(buffer, 33 + leftTransition, posY); - posX = 72; - for (int j = 0; j < stw->totalCostPerColor[i]; j++) - { - r->RenderQuad(mIcons[i], posX + leftTransition, posY + 6, 0, 0.5, 0.5); - posX += ((j + 1) % 10 == 0) ? 17 : 13; - if ((((j + 1) % 30) == 0) && (j < stw->totalCostPerColor[i] - 1)) - { - posX = 72; - posY += 15; - } - } - posY += 17; - } - } - break; - - case 9: // Victory statistics - // Title - sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Victory statistics").c_str()); - font->DrawString(buffer, 10 + leftTransition, 10); - - font->DrawString(_("Victories against AI:"), 20 + leftTransition, 30); - - sprintf(buffer, _("Games played: %i").c_str(), stw->gamesPlayed); - font->DrawString(buffer, 20 + leftTransition, 45); - sprintf(buffer, _("Victory ratio: %i%%").c_str(), stw->percentVictories); - font->DrawString(buffer, 20 + leftTransition, 55); - - int AIsPerColumn = 19; - posY = 70; - posX = 20; - - // ToDo: Multiple pages when too many AI decks are present - for (int i = 0; i < (int) stw->aiDeckStats.size(); i++) - { - sprintf(buffer, _("%.14s").c_str(), stw->aiDeckNames.at(i).c_str()); - font->DrawString(buffer, posX + (i < 2 * AIsPerColumn ? leftTransition : rightTransition), posY); - sprintf(buffer, _("%i/%i").c_str(), stw->aiDeckStats.at(i)->victories, stw->aiDeckStats.at(i)->nbgames); - font->DrawString(buffer, posX + (i < AIsPerColumn ? leftTransition : rightTransition) + 80, posY); - sprintf(buffer, _("%i%%").c_str(), stw->aiDeckStats.at(i)->percentVictories()); - font->DrawString(buffer, posX + (i < AIsPerColumn ? leftTransition : rightTransition) + 110, posY); - posY += 10; - if (((i + 1) % AIsPerColumn) == 0) - { - posY = 70; - posX += 155; - } - } - break; - } - } -} - - -void GameStateDeckViewer::renderCard(int id, float rotation) -{ - WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - MTGCard * card = cardIndex[id]; - - float max_scale = 0.96f; - float x_center_0 = 180; - float right_border = SCREEN_WIDTH - 20; - - float x_center = x_center_0 + cos((rotation + 8 - id) * M_PI / 12) * (right_border - x_center_0); - float scale = max_scale / 1.12f * cos((x_center - x_center_0) * 1.5f / (right_border - x_center_0)) + 0.2f * max_scale * cos( - cos((x_center - x_center_0) * 0.15f / (right_border - x_center_0))); - float x = x_center; // ; - - float y = (SCREEN_HEIGHT_F) / 2.0f + SCREEN_HEIGHT_F * mSlide * (scale + 0.2f); - - cardsCoordinates[id] = pair(x, y); - - int alpha = (int) (255 * (scale + 1.0 - max_scale)); - - if (!card) return; - JQuad * quad = NULL; - - int cacheError = CACHE_ERROR_NONE; - - if (!options[Options::DISABLECARDS].number) - { - quad = WResourceManager::Instance()->RetrieveCard(card, RETRIEVE_EXISTING); - cacheError = WResourceManager::Instance()->RetrieveError(); - if (!quad && cacheError != CACHE_ERROR_404) - { - if (last_user_activity > (abs(2 - id) + 1) * NO_USER_ACTIVITY_SHOWCARD_DELAY) - quad = WResourceManager::Instance()->RetrieveCard(card); - else - { - quad = backQuad; - } - } - } - - int quadAlpha = alpha; - if (!displayed_deck->count(card)) quadAlpha /= 2; - if (quad) - { - if (quad == backQuad) - { - quad->SetColor(ARGB(255,255,255,255)); - float _scale = scale * (285 / quad->mHeight); - JRenderer::GetInstance()->RenderQuad(quad, x, y, 0.0f, _scale, _scale); - } - else - { - Pos pos = Pos(x, y, scale * 285 / 250, 0.0, 255); - CardGui::DrawCard(card, pos); - } - } - else - { - Pos pos = Pos(x, y, scale * 285 / 250, 0.0, 255); - CardGui::DrawCard(card, pos, DrawMode::kText); - if (!options[Options::DISABLECARDS].number) quad = WResourceManager::Instance()->RetrieveCard(card, CACHE_THUMB); - if (quad) - { - float _scale = 285 * scale / quad->mHeight; - quad->SetColor(ARGB(40,255,255,255)); - JRenderer::GetInstance()->RenderQuad(quad, x, y, 0, _scale, _scale); - } - } - quadAlpha = 255 - quadAlpha; - if (quadAlpha > 0) - { - JRenderer::GetInstance()->FillRect(x - scale * 100.0f, y - scale * 142.5f, scale * 200.0f, scale * 285.0f, - ARGB(quadAlpha,0,0,0)); - } - if (last_user_activity < 3) - { - int fontAlpha = alpha; - float qtY = y - 135 * scale; - float qtX = x + 40 * scale; - char buffer[4096]; - sprintf(buffer, "x%i", displayed_deck->count(card)); - WFont * font = mFont; - font->SetColor(ARGB(fontAlpha/2,0,0,0)); - JRenderer::GetInstance()->FillRect(qtX, qtY, font->GetStringWidth(buffer) + 6, 16, ARGB(fontAlpha/2,0,0,0)); - font->DrawString(buffer, qtX + 4, qtY + 4); - font->SetColor(ARGB(fontAlpha,255,255,255)); - font->DrawString(buffer, qtX + 2, qtY + 2); - font->SetColor(ARGB(255,255,255,255)); - } -} - -void GameStateDeckViewer::renderCard(int id) -{ - renderCard(id, 0); -} - -void GameStateDeckViewer::Render() -{ - - WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - JRenderer * r = JRenderer::GetInstance(); - - r->ClearScreen(ARGB(0,0,0,0)); - if (displayed_deck == myDeck && mStage != STAGE_MENU) - renderDeckBackground(); - int order[3] = { 1, 2, 3 }; - if (mRotation < 0.5 && mRotation > -0.5) - { - order[1] = 3; - order[2] = 2; - } - else if (mRotation < -0.5) - { - order[0] = 3; - order[2] = 1; - } - - renderCard(6, mRotation); - renderCard(5, mRotation); - renderCard(4, mRotation); - renderCard(0, mRotation); - - for (int i = 0; i < 3; i++) - { - renderCard(order[i], mRotation); - } - - if (displayed_deck->Size() > 0) - { - renderSlideBar(); - } - else - { - mFont->DrawString(_("No Card"), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, JGETEXT_CENTER); - } - if (mStage == STAGE_ONSCREEN_MENU) - { - renderOnScreenMenu(); - } - else if (mStage == STAGE_WELCOME) - { - welcome_menu->Render(); - } - else - { - renderOnScreenBasicInfo(); - - } - if (mStage == STAGE_MENU) - { - menu->Render(); - } - if (subMenu) subMenu->Render(); - - if (filterMenu && !filterMenu->isFinished()) filterMenu->Render(); - - if (options.keypadActive()) options.keypadRender(); - -} - -int GameStateDeckViewer::loadDeck(int deckid) -{ - - if (!stw) - { - DeckManager *deckManager = DeckManager::GetInstance(); - stw = deckManager->getExtendedStatsForDeckId( deckid, mParent->collection, false ); - } - - stw->currentPage = 0; - stw->pageCount = 9; - stw->needUpdate = true; - - if (!playerdata) playerdata = NEW PlayerData(mParent->collection); - SAFE_DELETE(myCollection); - myCollection = NEW DeckDataWrapper(playerdata->collection); - myCollection->Sort(WSrcCards::SORT_ALPHA); - displayed_deck = myCollection; - - char deckname[256]; - sprintf(deckname, "deck%i.txt", deckid); - if (myDeck) - { - SAFE_DELETE(myDeck->parent); - SAFE_DELETE(myDeck); - } - myDeck = NEW DeckDataWrapper(NEW MTGDeck(options.profileFile(deckname, "", false, false).c_str(), mParent->collection)); - - // Check whether the cards in the deck are actually available in the player's collection: - int cheatmode = options[Options::CHEATMODE].number; - bool bPure = true; - for (int i = 0; i < myDeck->Size(true); i++) - { - MTGCard * current = myDeck->getCard(i, true); - int howmanyinDeck = myDeck->count(current); - for (int i = myCollection->count(current); i < howmanyinDeck; i++) - { - bPure = false; - if (cheatmode) - { //Are we cheating? - playerdata->collection->add(current); //Yup, add it to collection permanently. - myCollection->Add(current); - } - else - { - myDeck->Remove(current); //Nope. Remove it from deck. - break; - } - } - - myCollection->Remove(current, myDeck->count(current)); - } - if (!bPure) - { - myDeck->validate(); - myCollection->validate(); - } - - myDeck->Sort(WSrcCards::SORT_ALPHA); - SAFE_DELETE(filterMenu); - rebuildFilters(); - loadIndexes(); - return 1; -} - -void GameStateDeckViewer::ButtonPressed(int controllerId, int controlId) -{ - int deckIdNumber = controlId; - int deckListSize = 0; - string defaultAiName; - DeckManager *deckManager = DeckManager::GetInstance(); - vector * deckList; - switch (controllerId) - { - case MENU_DECK_SELECTION: //Deck menu - if (controlId == MENU_ITEM_CANCEL) - { - if (!mSwitching) - mParent->DoTransition(TRANSITION_FADE, GAME_STATE_MENU); - else - mStage = STAGE_WAITING; - - mSwitching = false; - break; - } - else if (controlId == MENUITEM_MORE_INFO) - { - break; - } - else if (controlId == MENU_ITEM_CHEAT_MODE) - { // (PSY) Cheatmode: Complete the collection - playerdata->collection->complete(); // Add the cards - playerdata->collection->save(); // Save the new collection - for (int i = 0; i < setlist.size(); i++) - { // Update unlocked sets - GameOptionAward * goa = dynamic_cast (&options[Options::optionSet(i)]); - if (goa) goa->giveAward(); - } - options.save(); - SAFE_DELETE(myCollection); - myCollection = NEW DeckDataWrapper(playerdata->collection); - myCollection->Sort(WSrcCards::SORT_ALPHA); - displayed_deck = myCollection; - rebuildFilters(); - loadIndexes(); - mStage = STAGE_WELCOME; - break; - } - mStage = STAGE_WAITING; - deckList = deckManager->getPlayerDeckOrderList(); - deckListSize = deckList->size(); - - if (controlId == MENU_ITEM_NEW_DECK) // new deck option selected - deckIdNumber = deckList->size() + 1; - else if (deckListSize > 0 && controlId <= deckListSize) - deckIdNumber = deckList->at(controlId - 1)-> getDeckId(); - else - deckIdNumber = controlId; - - loadDeck(deckIdNumber); - mStage = STAGE_WAITING; - deckNum = controlId; - break; - - case MENU_DECK_BUILDER: //Save / exit menu - switch (controlId) - { - - case MENU_ITEM_SAVE_RETURN_MAIN_MENU: - saveDeck(); - mParent->DoTransition(TRANSITION_FADE, GAME_STATE_MENU); - break; - - case MENU_ITEM_SAVE_RENAME: - if (myDeck && myDeck->parent) - { - options.keypadStart(myDeck->parent->meta_name, &newDeckname); - options.keypadTitle("Rename deck"); - } - break; - - case MENU_ITEM_SAVE_AS_AI_DECK: - // find the next unused ai deck number - // warn user that once saved, no edits can be made - // save entire collection to ai as spelled out card with count - // bring user to main deck editor menu. - isAIDeckSave = true; - defaultAiName = myDeck && myDeck->parent ? myDeck->parent->meta_name : "Custom AI Deck"; - options.keypadStart(defaultAiName, &newDeckname); - options.keypadTitle("Name Custom AI Deck"); - updateDecks(); - mStage = STAGE_WELCOME; - mSwitching = true; - break; - - case MENU_ITEM_SWITCH_DECKS_NO_SAVE: - //updateDecks(); - mStage = STAGE_WELCOME; - mSwitching = true; - break; - case MENU_ITEM_MAIN_MENU: - mParent->DoTransition(TRANSITION_FADE, GAME_STATE_MENU); - break; - case MENU_ITEM_EDITOR_CANCEL: - mStage = STAGE_WAITING; - break; - case MENU_ITEM_FILTER_BY: - mStage = STAGE_FILTERS; - if (!filterMenu) rebuildFilters(); - filterMenu->Entering(JGE_BTN_NONE); - break; - } - break; - - case MENU_CARD_PURCHASE: // Yes/ No sub menu. - switch (controlId) - { - case MENU_ITEM_YES: - { - MTGCard * card = cardIndex[2]; - if (card) - { - int rnd = (rand() % 25); - playerdata->credits += price; - price = price - (rnd * price) / 100; - pricelist->setPrice(card->getMTGId(), price); - playerdata->collection->remove(card->getMTGId()); - displayed_deck->Remove(card, 1); - displayed_deck->validate(); - stw->needUpdate = true; - loadIndexes(); - } - } - case MENU_ITEM_NO: - subMenu->Close(); - break; - } - } -} - +/* + * GameStateDeckViewer.cpp + * Class handling the Deck Editor + */ + +#include "PrecompiledHeader.h" + +#include +#include + +#include "DeckManager.h" +#include "GameStateDuel.h" +#include "GameStateDeckViewer.h" +#include "Translate.h" +#include "ManaCostHybrid.h" +#include "MTGCardInstance.h" +#include "WFilter.h" +#include "WDataSrc.h" +#include "DeckEditorMenu.h" +#include "SimpleMenu.h" +#include "utils.h" + +//!! helper function; this is probably handled somewhere in the code already. +// If not, should be placed in general library +void StringExplode(string str, string separator, vector* results) +{ + size_t found; + found = str.find_first_of(separator); + while (found != string::npos) + { + if (found > 0) results->push_back(str.substr(0, found)); + str = str.substr(found + 1); + found = str.find_first_of(separator); + } + if (str.length() > 0) results->push_back(str); +} + +GameStateDeckViewer::GameStateDeckViewer(GameApp* parent) : + GameState(parent) +{ + bgMusic = NULL; + nbDecks = 0; + deckNum = 0; + useFilter = 0; + isAIDeckSave = false; + mSwitching = false; + welcome_menu = NULL; + myCollection = NULL; + myDeck = NULL; + filterMenu = NULL; + source = NULL; + hudAlpha = 0; + subMenu = NULL; + mRotation = 0; + mSlide = 0; + mAlpha = 255; + menu = NULL; + stw = NULL; +} + +GameStateDeckViewer::~GameStateDeckViewer() +{ + SAFE_DELETE(bgMusic); + if (myDeck) + { + SAFE_DELETE(myDeck->parent); + SAFE_DELETE(myDeck); + } + if (myCollection) + { + SAFE_DELETE(myCollection->parent); + SAFE_DELETE(myCollection); + } + SAFE_DELETE(stw); + SAFE_DELETE(filterMenu); +} + +void GameStateDeckViewer::rotateCards(int direction) +{ + int left = direction; + if (left) + displayed_deck->next(); + else + displayed_deck->prev(); + loadIndexes(); + + int total = displayed_deck->Size(); + if (total) + { + lastPos = getCurrentPos(); + lastTotal = total; + } + +} + +void GameStateDeckViewer::rebuildFilters() +{ + if (!filterMenu) filterMenu = NEW WGuiFilters("Filter by...", NULL); + if (source) + SAFE_DELETE(source); + source = NEW WSrcDeckViewer(myDeck, myCollection); + filterMenu->setSrc(source); + if (displayed_deck != myDeck) source->swapSrc(); + filterMenu->Finish(true); + + // no stats need updating if there isn't a deck to update + if (stw && myDeck) + stw->updateStats( myDeck );; +} + +void GameStateDeckViewer::updateFilters() +{ + if (!displayed_deck) return; + + filterMenu->recolorFilter(useFilter - 1); + filterMenu->Finish(true); + int totalAfter = displayed_deck->Size(); + if (totalAfter && lastTotal) + { + + //This part is a hack. I don't understand why in some cases "displayed_deck's" currentPos is not 0 at this stage + { + while (int currentPos = displayed_deck->getOffset()) + { + if (currentPos > 0) + displayed_deck->prev(); + else + displayed_deck->next(); + } + } + + int pos = (totalAfter * lastPos) / lastTotal; + for (int i = 0; i < pos - 3; ++i) + { // "-3" because card "0" is displayed at position 3 initially + displayed_deck->next(); + } + } + stw->updateStats( myDeck );; + return; +} + +void GameStateDeckViewer::loadIndexes() +{ + for (int i = 0; i < 7; i++) + { + cardIndex[i] = displayed_deck->getCard(i); + } +} + +void GameStateDeckViewer::switchDisplay() +{ + if (displayed_deck == myCollection) + { + displayed_deck = myDeck; + } + else + { + displayed_deck = myCollection; + } + source->swapSrc(); + updateFilters(); + loadIndexes(); +} + +void GameStateDeckViewer::updateDecks() +{ + SAFE_DELETE(welcome_menu); + welcome_menu = NEW DeckEditorMenu(MENU_DECK_SELECTION, this, Fonts::OPTION_FONT, "Choose Deck To Edit"); + DeckManager * deckManager = DeckManager::GetInstance(); + vector playerDeckList = fillDeckMenu(welcome_menu, options.profileFile()); + + deckNum = 0; + newDeckname = ""; + nbDecks = playerDeckList.size() + 1; + welcome_menu->Add(MENU_ITEM_NEW_DECK, "--NEW--"); + if (options[Options::CHEATMODE].number && (!myCollection || myCollection->getCount(WSrcDeck::UNFILTERED_MIN_COPIES) < 4)) welcome_menu->Add( + MENU_ITEM_CHEAT_MODE, "--UNLOCK CARDS--"); + welcome_menu->Add(MENU_ITEM_CANCEL, "Cancel"); + + // update the deckmanager with the latest information + deckManager->updateMetaDataList(&playerDeckList, false); + // is this necessary to ensure no memory leaks? + playerDeckList.clear(); +} + +void GameStateDeckViewer::buildEditorMenu() +{ + ostringstream deckSummaryInformation; + deckSummaryInformation << "All changes are final." << endl; + + if (menu) + SAFE_DELETE( menu ); + //Build menu. + JRenderer::GetInstance()->FillRoundRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 100, ARGB(0, 0, 0, 0) ); + menu = NEW DeckEditorMenu(MENU_DECK_BUILDER, this, Fonts::OPTION_FONT, "Deck Editor", myDeck, stw); + + menu->Add(MENU_ITEM_FILTER_BY, "Filter By...", "Narrow down the list of cards. "); + menu->Add(MENU_ITEM_SWITCH_DECKS_NO_SAVE, "Switch Decks", "Do not make any changes.\nView another deck."); + menu->Add(MENU_ITEM_SAVE_RENAME, "Rename Deck", "Change the name of the deck"); + menu->Add(MENU_ITEM_SAVE_RETURN_MAIN_MENU, "Save & Quit Editor", "Save changes.\nReturn to the main menu"); + menu->Add(MENU_ITEM_SAVE_AS_AI_DECK, "Save As AI Deck", deckSummaryInformation.str()); + menu->Add(MENU_ITEM_MAIN_MENU, "Quit Editor", "Do not make any changes to deck.\nReturn to the main menu."); + menu->Add(MENU_ITEM_EDITOR_CANCEL, "Cancel", "Close menu."); + +} + +void GameStateDeckViewer::Start() +{ + hudAlpha = 0; + mSwitching = false; + subMenu = NULL; + myDeck = NULL; + mStage = STAGE_WELCOME; + mRotation = 0; + mSlide = 0; + mAlpha = 255; + last_user_activity = NO_USER_ACTIVITY_HELP_DELAY + 1; + onScreenTransition = 0; + useFilter = 0; + lastPos = 0; + lastTotal = 0; + + pricelist = NEW PriceList(JGE_GET_RES("settings/prices.dat").c_str(), mParent->collection); + playerdata = NEW PlayerData(mParent->collection); + myCollection = NEW DeckDataWrapper(playerdata->collection); + myCollection->Sort(WSrcCards::SORT_ALPHA); + displayed_deck = myCollection; + + //Icons + mIcons[Constants::MTG_COLOR_ARTIFACT] = WResourceManager::Instance()->GetQuad("c_artifact"); + mIcons[Constants::MTG_COLOR_LAND] = WResourceManager::Instance()->GetQuad("c_land"); + mIcons[Constants::MTG_COLOR_WHITE] = WResourceManager::Instance()->GetQuad("c_white"); + mIcons[Constants::MTG_COLOR_RED] = WResourceManager::Instance()->GetQuad("c_red"); + mIcons[Constants::MTG_COLOR_BLACK] = WResourceManager::Instance()->GetQuad("c_black"); + mIcons[Constants::MTG_COLOR_BLUE] = WResourceManager::Instance()->GetQuad("c_blue"); + mIcons[Constants::MTG_COLOR_GREEN] = WResourceManager::Instance()->GetQuad("c_green"); + for (int i = 0; i < 7; i++) + { + mIcons[i]->SetHotSpot(16, 16); + } + + //Grab a texture in VRAM. + pspIconsTexture = WResourceManager::Instance()->RetrieveTexture("iconspsp.png", RETRIEVE_LOCK); + + char buf[512]; + for (int i = 0; i < 8; i++) + { + sprintf(buf, "iconspsp%d", i); + pspIcons[i] = WResourceManager::Instance()->RetrieveQuad("iconspsp.png", (float) i * 32, 0, 32, 32, buf); + pspIcons[i]->SetHotSpot(16, 16); + } + + backQuad = WResourceManager::Instance()->GetQuad("back"); + + //init welcome menu + updateDecks(); + + GameApp::playMusic("track1.mp3"); + + loadIndexes(); + mEngine->ResetInput(); + JRenderer::GetInstance()->EnableVSync(true); +} + +void GameStateDeckViewer::End() +{ + JRenderer::GetInstance()->EnableVSync(false); + + SAFE_DELETE(welcome_menu); + SAFE_DELETE(menu); + SAFE_DELETE(subMenu); + + WResourceManager::Instance()->Release(pspIconsTexture); + if (myCollection) + { + SAFE_DELETE(myCollection); + } + if (myDeck) + { + SAFE_DELETE(myDeck->parent); + SAFE_DELETE(myDeck); + } + SAFE_DELETE(pricelist); + SAFE_DELETE(playerdata); + SAFE_DELETE(filterMenu); + SAFE_DELETE(source); +} + +void GameStateDeckViewer::addRemove(MTGCard * card) +{ + if (!card) return; + if (displayed_deck->Remove(card, 1, (displayed_deck == myDeck))) + { + if (displayed_deck == myCollection) + { + myDeck->Add(card); + myDeck->Sort(WSrcCards::SORT_ALPHA); + } + else + { + myCollection->Add(card); + } + } + myCollection->validate(); + myDeck->validate(); + stw->needUpdate = true; + loadIndexes(); +} + +void GameStateDeckViewer::saveDeck() +{ + myDeck->save(); + playerdata->save(); + pricelist->save(); +} + +/** + save the deck in a readable format to allow people to edit the file offline + */ +void GameStateDeckViewer::saveAsAIDeck(string deckName) +{ + + vector aiDecks = GameState::getValidDeckMetaData(JGE_GET_RES("ai/baka"), "ai_baka", NULL); + int nbAiDecks = aiDecks.size() + 1; + aiDecks.clear(); + + string defaultAiDeckName = "deck"; + std::ostringstream oss; + oss << "deck" << nbAiDecks; + defaultAiDeckName = oss.str(); + oss.str(""); + if (myDeck->parent->meta_desc == "") + oss << endl << "Can you beat your own creations?" << endl << "User created AI Deck # " << nbAiDecks; + else + oss << myDeck->parent->meta_desc; + string deckDesc = oss.str(); + string filepath = JGE_GET_RES("ai/baka/"); + filepath.append(defaultAiDeckName).append(".txt"); + DebugTrace("saving AI deck " << filepath); + myDeck->save(filepath, true, deckName, deckDesc); +} + +void GameStateDeckViewer::Update(float dt) +{ + + int x, y; + unsigned int distance2; + unsigned int minDistance2 = -1; + int n = 0; + + if (options.keypadActive()) + { + options.keypadUpdate(dt); + + if (newDeckname != "") + { + newDeckname = options.keypadFinish(); + + if (newDeckname != "") + { + if (isAIDeckSave) + { + saveAsAIDeck(newDeckname); + isAIDeckSave = false; + } + else if (myDeck && myDeck->parent) + { + myDeck->parent->meta_name = newDeckname; + saveDeck(); + } + mStage = STAGE_WAITING; + } + newDeckname = ""; + } + //Prevent screen from updating. + return; + } + hudAlpha = 255 - ((int) last_user_activity * 500); + if (hudAlpha < 0) hudAlpha = 0; + if (subMenu) + { + subMenu->Update(dt); + if (subMenu->isClosed()) + { + SAFE_DELETE(subMenu); + } + return; + } + if (mStage == STAGE_WAITING || mStage == STAGE_ONSCREEN_MENU) + { + switch (mEngine->ReadButton()) + { + case JGE_BTN_LEFT: + last_user_activity = 0; + mStage = STAGE_TRANSITION_LEFT; + break; + case JGE_BTN_RIGHT: + last_user_activity = 0; + mStage = STAGE_TRANSITION_RIGHT; + break; + case JGE_BTN_UP: + last_user_activity = 0; + mStage = STAGE_TRANSITION_UP; + useFilter++; + if (useFilter >= MAX_SAVED_FILTERS) useFilter = 0; + break; + case JGE_BTN_DOWN: + last_user_activity = 0; + mStage = STAGE_TRANSITION_DOWN; + useFilter--; + if (useFilter < 0) useFilter = MAX_SAVED_FILTERS - 1; + break; + case JGE_BTN_CANCEL: + options[Options::DISABLECARDS].number = !options[Options::DISABLECARDS].number; + break; + case JGE_BTN_PRI: + if (last_user_activity > 0.2) + { + last_user_activity = 0; + switchDisplay(); + } + break; + case JGE_BTN_OK: + last_user_activity = 0; + addRemove(cardIndex[2]); + break; + case JGE_BTN_SEC: + last_user_activity = 0; + SAFE_DELETE(subMenu); + char buffer[4096]; + { + MTGCard * card = cardIndex[2]; + if (card && displayed_deck->count(card)) + { + price = pricelist->getSellPrice(card->getMTGId()); + sprintf(buffer, "%s : %i %s", _(card->data->getName()).c_str(), price, _("credits").c_str()); + const float menuXOffset = SCREEN_WIDTH_F - 300; + const float menuYOffset = SCREEN_HEIGHT_F / 2; + subMenu = NEW SimpleMenu(MENU_CARD_PURCHASE, this, Fonts::MAIN_FONT, menuXOffset, menuYOffset, buffer); + subMenu->Add(MENU_ITEM_YES, "Yes"); + subMenu->Add(MENU_ITEM_NO, "No", "", true); + } + } + stw->needUpdate = true; + break; + + case JGE_BTN_MENU: + mStage = STAGE_MENU; + buildEditorMenu(); + break; + case JGE_BTN_CTRL: + mStage = STAGE_FILTERS; + if (!filterMenu) + { + filterMenu = NEW WGuiFilters("Filter by...", NULL); + if (source) + SAFE_DELETE(source); + source = NEW WSrcDeckViewer(myDeck, myCollection); + filterMenu->setSrc(source); + if (displayed_deck != myDeck) source->swapSrc(); + } + filterMenu->Entering(JGE_BTN_NONE); + break; + case JGE_BTN_PREV: + if (last_user_activity < NO_USER_ACTIVITY_HELP_DELAY) + last_user_activity = NO_USER_ACTIVITY_HELP_DELAY + 1; + else if ((mStage == STAGE_ONSCREEN_MENU) && (--stw->currentPage < 0)) stw->currentPage = stw->pageCount; + break; + case JGE_BTN_NEXT: + if (last_user_activity < NO_USER_ACTIVITY_HELP_DELAY) + last_user_activity = NO_USER_ACTIVITY_HELP_DELAY + 1; + else if ((mStage == STAGE_ONSCREEN_MENU) && (++stw->currentPage > stw->pageCount)) stw->currentPage = 0; + break; + default: // no keypress + if (mEngine->GetLeftClickCoordinates(x, y)) + { + for(int i=0; i < CARDS_DISPLAYED; i++) + { + distance2 = (cardsCoordinates[i].second - y) * (cardsCoordinates[i].second - y) + (cardsCoordinates[i].first - x) * (cardsCoordinates[i].first - x); + if (distance2 < minDistance2) + { + minDistance2 = distance2; + n = i; + } + } + + if (n < ((CARDS_DISPLAYED/2) - 1)) + { + last_user_activity = 0; + mStage = STAGE_TRANSITION_RIGHT; + } + if (n > ((CARDS_DISPLAYED/2) + 1)) + { + last_user_activity = 0; + mStage = STAGE_TRANSITION_LEFT; + } + mEngine->LeftClickedProcessed(); + break; + } + + if (last_user_activity > NO_USER_ACTIVITY_HELP_DELAY) + { + if (mStage != STAGE_ONSCREEN_MENU) + { + mStage = STAGE_ONSCREEN_MENU; + onScreenTransition = 1; + } + else + { + if (onScreenTransition > 0) + onScreenTransition -= 0.05f; + else + onScreenTransition = 0; + } + } + else + last_user_activity += dt; + } + + } + if (mStage == STAGE_TRANSITION_RIGHT || mStage == STAGE_TRANSITION_LEFT) + { + if (mStage == STAGE_TRANSITION_RIGHT) + { + mRotation -= dt * MED_SPEED; + if (mRotation < -1.0f) + { + do + { + rotateCards(mStage); + mRotation += 1; + } while (mRotation < -1.0f); + mStage = STAGE_WAITING; + mRotation = 0; + } + } + else if (mStage == STAGE_TRANSITION_LEFT) + { + mRotation += dt * MED_SPEED; + if (mRotation > 1.0f) + { + do + { + rotateCards(mStage); + mRotation -= 1; + } while (mRotation > 1.0f); + mStage = STAGE_WAITING; + mRotation = 0; + } + } + } + if (mStage == STAGE_TRANSITION_DOWN || mStage == STAGE_TRANSITION_UP) + { + if (mStage == STAGE_TRANSITION_DOWN) + { + mSlide -= 0.05f; + if (mSlide < -1.0f) + { + updateFilters(); + loadIndexes(); + mSlide = 1; + } + else if (mSlide > 0 && mSlide < 0.05) + { + mStage = STAGE_WAITING; + mSlide = 0; + } + } + if (mStage == STAGE_TRANSITION_UP) + { + mSlide += 0.05f; + if (mSlide > 1.0f) + { + updateFilters(); + loadIndexes(); + mSlide = -1; + } + else if (mSlide < 0 && mSlide > -0.05) + { + mStage = STAGE_WAITING; + mSlide = 0; + } + } + + } + else if (mStage == STAGE_WELCOME) + welcome_menu->Update(dt); + else if (mStage == STAGE_MENU) + menu->Update(dt); + else if (mStage == STAGE_FILTERS) + { + JButton key = mEngine->ReadButton(); + if (filterMenu) + { + if (key == JGE_BTN_CTRL) + { + //useFilter = 0; + filterMenu->Finish(true); + filterMenu->Update(dt); + loadIndexes(); + return; + } + if (!filterMenu->isFinished()) + { + filterMenu->CheckUserInput(key); + filterMenu->Update(dt); + } + else + { + mStage = STAGE_WAITING; + updateFilters(); + loadIndexes(); + } + } + } +} + +void GameStateDeckViewer::renderOnScreenBasicInfo() +{ + JRenderer *renderer = JRenderer::GetInstance(); + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + char buffer[256]; + + float y = 0; + int allCopies, nowCopies; + nowCopies = displayed_deck->getCount(WSrcDeck::FILTERED_COPIES); + allCopies = displayed_deck->getCount(WSrcDeck::UNFILTERED_COPIES); + WCardFilter * wc = displayed_deck->getFiltersRoot(); + + if (wc) + sprintf(buffer, "%s %i of %i cards (%i unique)", (displayed_deck == myDeck) ? "DECK: " : " ", nowCopies, allCopies, + displayed_deck->getCount(WSrcDeck::FILTERED_UNIQUE)); + else + sprintf(buffer, "%s%i cards (%i unique)", (displayed_deck == myDeck) ? "DECK: " : " ", allCopies, displayed_deck->getCount( + WSrcDeck::UNFILTERED_UNIQUE)); + + float w = mFont->GetStringWidth(buffer); + renderer->FillRoundRect(SCREEN_WIDTH - (w + 27), y + 5, w + 10, 15, 5, ARGB(128,0,0,0)); + + mFont->DrawString(buffer, SCREEN_WIDTH - 22, y + 15, JGETEXT_RIGHT); + if (useFilter != 0) renderer->RenderQuad(mIcons[useFilter - 1], SCREEN_WIDTH - 10, y + 15, 0.0f, 0.5, 0.5); +} + +//returns position of the current card (cusor) in the currently viewed color/filter +int GameStateDeckViewer::getCurrentPos() +{ + int total = displayed_deck->Size(); + + int currentPos = displayed_deck->getOffset(); + currentPos += 2; //we start by displaying card number 3 + currentPos = currentPos % total + 1; + if (currentPos < 0) currentPos = (total + currentPos); + if (!currentPos) currentPos = total; + return currentPos; +} + +void GameStateDeckViewer::renderSlideBar() +{ + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + + int total = displayed_deck->Size(); + if (total == 0) return; + + float filler = 15; + float y = SCREEN_HEIGHT_F - 25; + float bar_size = SCREEN_WIDTH_F - 2 * filler; + JRenderer * r = JRenderer::GetInstance(); + int currentPos = getCurrentPos(); + + float cursor_pos = bar_size * currentPos / total; + + r->FillRoundRect(filler + 5, y + 5, bar_size, 0, 3, ARGB(hudAlpha/2,0,0,0)); + r->DrawLine(filler + cursor_pos + 5, y + 5, filler + cursor_pos + 5, y + 10, ARGB(hudAlpha/2,0,0,0)); + + r->FillRoundRect(filler, y, bar_size, 0, 3, ARGB(hudAlpha/2,128,128,128)); + r->DrawLine(filler + cursor_pos, y, filler + cursor_pos, y + 5, ARGB(hudAlpha,255,255,255)); + char buffer[256]; + string deckname = _("Collection"); + if (displayed_deck == myDeck) + { + deckname = _("Deck"); + } + sprintf(buffer, "%s - %i/%i", deckname.c_str(), currentPos, total); + mFont->SetColor(ARGB(hudAlpha,255,255,255)); + mFont->DrawString(buffer, SCREEN_WIDTH / 2, y, JGETEXT_CENTER); + + mFont->SetColor(ARGB(255,255,255,255)); +} + +void GameStateDeckViewer::renderDeckBackground() +{ + int max1 = 0; + int maxC1 = 4; + int max2 = 0; + int maxC2 = 4; + + for (int i = 0; i < Constants::MTG_NB_COLORS - 1; i++) + { + int value = myDeck->getCount(i); + if (value > max1) + { + max2 = max1; + maxC2 = maxC1; + max1 = value; + maxC1 = i; + } + else if (value > max2) + { + max2 = value; + maxC2 = i; + } + } + if (max2 < max1 / 2) + { + maxC2 = maxC1; + } + PIXEL_TYPE colors[] = { ARGB(255, Constants::_r[maxC1], Constants::_g[maxC1], Constants::_b[maxC1]), + ARGB(255, Constants::_r[maxC1], Constants::_g[maxC1], Constants::_b[maxC1]), + ARGB(255, Constants::_r[maxC2], Constants::_g[maxC2], Constants::_b[maxC2]), + ARGB(255, Constants::_r[maxC2], Constants::_g[maxC2], Constants::_b[maxC2]), }; + + JRenderer::GetInstance()->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, colors); + +} + +void GameStateDeckViewer::renderOnScreenMenu() +{ + + WFont * font = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + font->SetColor(ARGB(255,255,255,255)); + JRenderer * r = JRenderer::GetInstance(); + float pspIconsSize = 0.5; + float fH = font->GetHeight() + 1; + + float leftTransition = onScreenTransition * 84; + float rightTransition = onScreenTransition * 204; + float leftPspX = 40 - leftTransition; + float leftPspY = SCREEN_HEIGHT / 2 - 20; + float rightPspX = SCREEN_WIDTH - 100 + rightTransition; + float rightPspY = SCREEN_HEIGHT / 2 - 20; + + if (stw->currentPage == 0) + { + //FillRects + r->FillRect(0 - (onScreenTransition * 84), 0, 84, SCREEN_HEIGHT, ARGB(128,0,0,0)); + r->FillRect(SCREEN_WIDTH - 204 + (onScreenTransition * 204), 0, 200, SCREEN_HEIGHT, ARGB(128,0,0,0)); + + //LEFT PSP CIRCLE render + r->FillCircle(leftPspX, leftPspY, 40, ARGB(128,50,50,50)); + + r->RenderQuad(pspIcons[0], leftPspX, leftPspY - 20, 0, pspIconsSize, pspIconsSize); + r->RenderQuad(pspIcons[1], leftPspX, leftPspY + 20, 0, pspIconsSize, pspIconsSize); + r->RenderQuad(pspIcons[2], leftPspX - 20, leftPspY, 0, pspIconsSize, pspIconsSize); + r->RenderQuad(pspIcons[3], leftPspX + 20, leftPspY, 0, pspIconsSize, pspIconsSize); + + font->DrawString(_("Prev."), leftPspX - 35, leftPspY - 15); + font->DrawString(_("Next"), leftPspX + 15, leftPspY - 15); + font->DrawString(_("card"), leftPspX - 35, leftPspY); + font->DrawString(_("card"), leftPspX + 15, leftPspY); + font->DrawString(_("Next edition"), leftPspX - 33, leftPspY - 35); + font->DrawString(_("Prev. edition"), leftPspX - 33, leftPspY + 25); + + //RIGHT PSP CIRCLE render + r->FillCircle(rightPspX + (onScreenTransition * 204), rightPspY, 40, ARGB(128,50,50,50)); + r->RenderQuad(pspIcons[4], rightPspX + 20, rightPspY, 0, pspIconsSize, pspIconsSize); + r->RenderQuad(pspIcons[5], rightPspX, rightPspY - 20, 0, pspIconsSize, pspIconsSize); + r->RenderQuad(pspIcons[6], rightPspX - 20, rightPspY, 0, pspIconsSize, pspIconsSize); + r->RenderQuad(pspIcons[7], rightPspX, rightPspY + 20, 0, pspIconsSize, pspIconsSize); + + font->DrawString(_("Toggle Images"), rightPspX - 35, rightPspY - 40); + + if (displayed_deck == myCollection) + { + font->DrawString(_("Add card"), rightPspX + 20, rightPspY - 15); + font->DrawString(_("View Deck"), rightPspX - 20, rightPspY - 15, JGETEXT_RIGHT); + } + else + { + font->DrawString(_("Remove card"), rightPspX + 20, rightPspY - 15); + font->DrawString(_("View Collection"), rightPspX - 20, rightPspY - 15, JGETEXT_RIGHT); + } + font->DrawString(_("Sell card"), rightPspX - 30, rightPspY + 20); + //Bottom menus + font->DrawString(_("menu"), SCREEN_WIDTH - 35 + rightTransition, SCREEN_HEIGHT - 15); + font->DrawString(_("filter"), SCREEN_WIDTH - 95 + rightTransition, SCREEN_HEIGHT - 15); + + //Your Deck Information + char buffer[300]; + int nb_letters = 0; + for (int j = 0; j < Constants::MTG_NB_COLORS; j++) + { + int value = myDeck->getCount(j); + if (value > 0) + { + sprintf(buffer, "%i", value); + font->DrawString(buffer, SCREEN_WIDTH - 190 + rightTransition + nb_letters * 13, SCREEN_HEIGHT / 2 + 40); + r->RenderQuad(mIcons[j], SCREEN_WIDTH - 197 + rightTransition + nb_letters * 13, SCREEN_HEIGHT / 2 + 46, 0, 0.5, + 0.5); + if (value > 9) + { + nb_letters += 3; + } + else + { + nb_letters += 2; + } + } + } + int value = myDeck->getCount(WSrcDeck::UNFILTERED_COPIES); + sprintf(buffer, _("Your Deck: %i cards").c_str(), value); + font->DrawString(buffer, SCREEN_WIDTH - 200 + rightTransition, SCREEN_HEIGHT / 2 + 25); + + if (displayed_deck == myCollection) + { + font->DrawString(_("in: collection"), 5 - leftTransition, 5); + font->DrawString(_("Use SQUARE to view your deck,"), SCREEN_WIDTH - 200 + rightTransition, 5); + } + else + { + font->DrawString(_("in: deck"), 5 - leftTransition, 5); + font->DrawString(_("Use SQUARE to view collection,"), SCREEN_WIDTH - 200 + rightTransition, 5); + } + font->DrawString(_("Press L/R to cycle through"), SCREEN_WIDTH - 200 + rightTransition, 5 + fH); + font->DrawString(_("deck statistics."), SCREEN_WIDTH - 200 + rightTransition, 5 + fH * 2); + + } + else + { + stw->updateStats( myDeck );; + + char buffer[300]; + + leftTransition = -(onScreenTransition / 2) * SCREEN_WIDTH; + rightTransition = -leftTransition; + + r->FillRect(0 + leftTransition, 0, SCREEN_WIDTH / 2, SCREEN_HEIGHT, ARGB(128,0,0,0)); + r->FillRect(SCREEN_WIDTH / 2 + rightTransition, 0, SCREEN_WIDTH / 2, SCREEN_HEIGHT, ARGB(128,0,0,0)); + r->FillRect(10 + leftTransition, 10, SCREEN_WIDTH / 2 - 10, SCREEN_HEIGHT - 20, ARGB(128,0,0,0)); + r->FillRect(SCREEN_WIDTH / 2 + rightTransition, 10, SCREEN_WIDTH / 2 - 10, SCREEN_HEIGHT - 20, ARGB(128,0,0,0)); + font->DrawString(_("menu"), SCREEN_WIDTH - 35 + rightTransition, SCREEN_HEIGHT - 15); + font->DrawString(_("filter"), SCREEN_WIDTH - 95 + rightTransition, SCREEN_HEIGHT - 15); + + int nb_letters = 0; + float posX, posY; + DWORD graphColor; + + graphColor = ARGB(200, 155, 155, 155); + string STATS_TITLE_FORMAT = _("%i: %s"); + + switch (stw->currentPage) + { + case 1: // Counts, price + // Title + sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Statistics Summary").c_str()); + font->DrawString(buffer, 10 + leftTransition, 10); + + posY = 30; + posX = 180; + sprintf(buffer, _("Your Deck: %i cards").c_str(), stw->cardCount); + font->DrawString(buffer, 20 + leftTransition, posY); + posY += 10; + + // Counts by color + for (int j = 0; j < Constants::MTG_NB_COLORS; j++) + { + int value = myDeck->getCount(j); + if (value > 0) + { + sprintf(buffer, "%i", value); + font->DrawString(buffer, 38 + nb_letters * 13 + leftTransition, posY + 5); + r->RenderQuad(mIcons[j], 30 + nb_letters * 13 + leftTransition, posY + 11, 0, 0.5, 0.5); + if (value > 9) + { + nb_letters += 3; + } + else + { + nb_letters += 2; + } + } + } + posY += 25; + + r->DrawLine(posX - 4 + leftTransition, posY - 1, posX - 4 + leftTransition, posY + 177, ARGB(128, 255, 255, 255)); + r->DrawLine(19 + leftTransition, posY - 1, 19 + leftTransition, posY + 177, ARGB(128, 255, 255, 255)); + r->DrawLine(posX + 40 + leftTransition, posY - 1, posX + 40 + leftTransition, posY + 177, ARGB(128, 255, 255, 255)); + + r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); + + font->DrawString(_("Lands"), 20 + leftTransition, posY); + sprintf(buffer, _("%i").c_str(), stw->countLands); + font->DrawString(buffer, posX + leftTransition, posY); + + posY += 14; + r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); + font->DrawString(_("Creatures"), 20 + leftTransition, posY); + sprintf(buffer, _("%i").c_str(), stw->countCreatures); + font->DrawString(buffer, posX + leftTransition, posY); + + posY += 14; + r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); + font->DrawString(_("Spells"), 20 + leftTransition, posY); + sprintf(buffer, _("%i").c_str(), stw->countSpells); + font->DrawString(buffer, posX + leftTransition, posY); + + posY += 10; + font->DrawString(_("Instants"), 30 + leftTransition, posY); + sprintf(buffer, _("%i").c_str(), stw->countInstants); + font->DrawString(buffer, posX + leftTransition, posY); + + posY += 10; + font->DrawString(_("Enchantments"), 30 + leftTransition, posY); + sprintf(buffer, _("%i").c_str(), stw->countEnchantments); + font->DrawString(buffer, posX + leftTransition, posY); + + posY += 10; + font->DrawString(_("Sorceries"), 30 + leftTransition, posY); + sprintf(buffer, _("%i").c_str(), stw->countSorceries); + font->DrawString(buffer, posX + leftTransition, posY); + //sprintf(buffer, "Artifacts: %i", stw->countArtifacts); + //mFont->DrawString(buffer, 20, 123); + + posY += 14; + r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); + + font->DrawString(_("Average converted mana cost"), 20 + leftTransition, posY); + sprintf(buffer, _("%2.2f").c_str(), stw->avgManaCost); + font->DrawString(buffer, posX + leftTransition, posY); + + posY += 14; + r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); + font->DrawString(_("Probabilities"), 20 + leftTransition, posY); + + posY += 10; + font->DrawString(_("No land in 1st hand"), 30 + leftTransition, posY); + sprintf(buffer, _("%2.2f%%").c_str(), stw->noLandsProbInTurn[0]); + font->DrawString(buffer, posX + leftTransition, posY); + + posY += 10; + font->DrawString(_("No land in 9 cards"), 30 + leftTransition, posY); + sprintf(buffer, _("%2.2f%%").c_str(), stw->noLandsProbInTurn[2]); + font->DrawString(buffer, posX + leftTransition, posY); + + posY += 10; + font->DrawString(_("No creatures in 1st hand"), 30 + leftTransition, posY); + sprintf(buffer, _("%2.2f%%").c_str(), stw->noCreaturesProbInTurn[0]); + font->DrawString(buffer, posX + leftTransition, posY); + + // Playgame Statistics + posY += 14; + r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); + font->DrawString(_("Playgame statistics"), 20 + leftTransition, posY); + + posY += 10; + font->DrawString(_("Games played"), 30 + leftTransition, posY); + sprintf(buffer, _("%i").c_str(), stw->gamesPlayed); + font->DrawString(buffer, posX + leftTransition, posY); + + posY += 10; + font->DrawString(_("Victory ratio"), 30 + leftTransition, posY); + sprintf(buffer, _("%i%%").c_str(), stw->percentVictories); + font->DrawString(buffer, posX + leftTransition, posY); + + posY += 15; + r->DrawLine(20 + leftTransition, posY - 1, posX + 40 + leftTransition, posY - 1, ARGB(128, 255, 255, 255)); + font->DrawString(_("Total price (credits)"), 20 + leftTransition, posY); + sprintf(buffer, _("%i ").c_str(), stw->totalPrice); + font->DrawString(buffer, posX + leftTransition, posY); + r->DrawLine(20 + leftTransition, posY + 13, posX + 40 + leftTransition, posY + 13, ARGB(128, 255, 255, 255)); + + break; + + case 5: // Land statistics + sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana production").c_str()); + font->DrawString(buffer, 10 + leftTransition, 10); + + font->DrawString(_("Counts of manasources per type and color:"), 20 + leftTransition, 30); + + posY = 70; + + // Column titles + for (int j = 0; j < Constants::MTG_NB_COLORS - 1; j++) + { + r->RenderQuad(mIcons[j], 52 + j * 15 + leftTransition, posY - 10, 0, 0.5, 0.5); + } + + //font->DrawString(_("C"), 30 + leftTransition, posY-16); + //font->DrawString(_("Ty"), 27 + leftTransition, posY-16); + + // Horizontal table lines + r->DrawLine(27 + leftTransition, posY - 20, 60 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, posY - 20, + ARGB(128, 255, 255, 255)); + r->DrawLine(27 + leftTransition, posY - 1, 60 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, posY - 1, + ARGB(128, 255, 255, 255)); + r->DrawLine(27 + leftTransition, 2 * 10 + posY + 12, 60 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, 2 * 10 + + posY + 12, ARGB(128, 255, 255, 255)); + r->DrawLine(27 + leftTransition, 3 * 10 + posY + 14, 60 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, 3 * 10 + + posY + 14, ARGB(128, 255, 255, 255)); + + // Vertical table lines + r->DrawLine(26 + leftTransition, posY - 20, 26 + leftTransition, 3 * 10 + posY + 14, ARGB(128, 255, 255, 255)); + r->DrawLine(43 + leftTransition, posY - 20, 43 + leftTransition, 3 * 10 + posY + 14, ARGB(128, 255, 255, 255)); + r->DrawLine(60 + leftTransition + (Constants::MTG_NB_COLORS - 2) * 15, posY - 20, 60 + leftTransition + + (Constants::MTG_NB_COLORS - 2) * 15, 3 * 10 + posY + 14, ARGB(128, 255, 255, 255)); + + font->DrawString(_("BL"), 27 + leftTransition, posY); + font->DrawString(_("NB"), 27 + leftTransition, posY + 10); + font->DrawString(_("O"), 30 + leftTransition, posY + 20); + font->DrawString(_("T"), 30 + leftTransition, posY + 33); + + int curCount; + + for (int j = 0; j < Constants::MTG_NB_COLORS - 1; j++) + { + curCount = stw->countBasicLandsPerColor[j]; + sprintf(buffer, (curCount == 0 ? "." : "%i"), curCount); + font->DrawString(buffer, 49 + leftTransition + j * 15, posY); + + curCount = stw->countLandsPerColor[j]; + sprintf(buffer, (curCount == 0 ? "." : "%i"), curCount); + font->DrawString(buffer, 49 + leftTransition + j * 15, posY + 10); + + curCount = stw->countNonLandProducersPerColor[j]; + sprintf(buffer, (curCount == 0 ? "." : "%i"), curCount); + font->DrawString(buffer, 49 + leftTransition + j * 15, posY + 20); + + curCount = stw->countLandsPerColor[j] + stw->countBasicLandsPerColor[j] + stw->countNonLandProducersPerColor[j]; + sprintf(buffer, (curCount == 0 ? "." : "%i"), curCount); + font->DrawString(buffer, 49 + leftTransition + j * 15, posY + 33); + } + + posY += 55; + font->DrawString(_("BL - Basic lands"), 20 + leftTransition, posY); + posY += 10; + font->DrawString(_("NB - Non-basic lands"), 20 + leftTransition, posY); + posY += 10; + font->DrawString(_("O - Other (non-land) manasources"), 26 + leftTransition, posY); + posY += 10; + font->DrawString(_("T - Totals"), 26 + leftTransition, posY); + + break; + + case 6: // Land statistics - in symbols + sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana production - in mana symbols").c_str()); + font->DrawString(buffer, 10 + leftTransition, 10); + font->DrawString(_("Total colored manasymbols in lands' production:"), 20 + leftTransition, 30); + + int totalProducedSymbols; + totalProducedSymbols = 0; + for (int i = 1; i < Constants::MTG_NB_COLORS - 1; i++) + { + totalProducedSymbols += stw->countLandsPerColor[i] + stw->countBasicLandsPerColor[i]; //!! Move to updatestats! + } + + posY = 50; + for (int i = 1; i < Constants::MTG_NB_COLORS - 1; i++) + { + if (stw->countLandsPerColor[i] + stw->countBasicLandsPerColor[i] > 0) + { + sprintf(buffer, _("%i").c_str(), stw->countLandsPerColor[i] + stw->countBasicLandsPerColor[i]); + font->DrawString(buffer, 20 + leftTransition, posY); + sprintf(buffer, _("(%i%%)").c_str(), (int) (100 * (float) (stw->countLandsPerColor[i] + + stw->countBasicLandsPerColor[i]) / totalProducedSymbols)); + font->DrawString(buffer, 33 + leftTransition, posY); + posX = 72; + for (int j = 0; j < stw->countLandsPerColor[i] + stw->countBasicLandsPerColor[i]; j++) + { + r->RenderQuad(mIcons[i], posX + leftTransition, posY + 6, 0, 0.5, 0.5); + posX += ((j + 1) % 10 == 0) ? 17 : 13; + if ((((j + 1) % 30) == 0) && (j < stw->countLandsPerColor[i] + stw->countBasicLandsPerColor[i] - 1)) + { + posX = 72; + posY += 15; + } + } + posY += 17; + } + } + + break; + + case 2: // Mana cost detail + case 3: + case 4: + int (*countPerCost)[Constants::STATS_MAX_MANA_COST + 1]; + int (*countPerCostAndColor)[Constants::STATS_MAX_MANA_COST + 1][Constants::MTG_NB_COLORS + 1]; + float avgCost; + + switch (stw->currentPage) + { // Nested switch on the same variable. Oh yes. + case 2: // Total counts + // Title + sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana cost detail").c_str()); + font->DrawString(buffer, 10 + leftTransition, 10); + font->DrawString(_("Card counts per mana cost:"), 20 + leftTransition, 30); + avgCost = stw->avgManaCost; + countPerCost = &stw->countCardsPerCost; + countPerCostAndColor = &stw->countCardsPerCostAndColor; + break; + case 3: // Creature counts + // Title + sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana cost detail - Creatures").c_str()); + font->DrawString(buffer, 10 + leftTransition, 10); + font->DrawString(_("Creature counts per mana cost:"), 20 + leftTransition, 30); + avgCost = stw->avgCreatureCost; + countPerCost = &stw->countCreaturesPerCost; + countPerCostAndColor = &stw->countCreaturesPerCostAndColor; + break; + case 4: // Spell counts + // Title + sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana cost detail - Spells").c_str()); + font->DrawString(buffer, 10 + leftTransition, 10); + font->DrawString(_("Non-creature spell counts per mana cost:"), 20 + leftTransition, 30); + avgCost = stw->avgSpellCost; + countPerCost = &stw->countSpellsPerCost; + countPerCostAndColor = &stw->countSpellsPerCostAndColor; + break; + default: + countPerCost = NULL; + countPerCostAndColor = NULL; + avgCost = 0; + break; + } + + posY = 70; + + // Column titles + for (int j = 0; j < Constants::MTG_NB_COLORS - 1; j++) + { + r->RenderQuad(mIcons[j], 67 + j * 15 + leftTransition, posY - 10, 0, 0.5, 0.5); + } + + font->DrawString(_("C"), 30 + leftTransition, posY - 16); + font->DrawString(_("#"), 45 + leftTransition, posY - 16); + + // Horizontal table lines + r->DrawLine(27 + leftTransition, posY - 20, 75 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, posY - 20, + ARGB(128, 255, 255, 255)); + r->DrawLine(27 + leftTransition, posY - 1, 75 + (Constants::MTG_NB_COLORS - 2) * 15 + leftTransition, posY - 1, + ARGB(128, 255, 255, 255)); + r->DrawLine(27 + leftTransition, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, 75 + (Constants::MTG_NB_COLORS - 2) + * 15 + leftTransition, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, ARGB(128, 255, 255, 255)); + + // Vertical table lines + r->DrawLine(26 + leftTransition, posY - 20, 26 + leftTransition, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, + ARGB(128, 255, 255, 255)); + r->DrawLine(41 + leftTransition, posY - 20, 41 + leftTransition, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, + ARGB(128, 255, 255, 255)); + r->DrawLine(58 + leftTransition, posY - 20, 58 + leftTransition, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, + ARGB(128, 255, 255, 255)); + r->DrawLine(75 + leftTransition + (Constants::MTG_NB_COLORS - 2) * 15, posY - 20, 75 + leftTransition + + (Constants::MTG_NB_COLORS - 2) * 15, Constants::STATS_MAX_MANA_COST * 10 + posY + 12, + ARGB(128, 255, 255, 255)); + + for (int i = 0; i <= Constants::STATS_MAX_MANA_COST; i++) + { + sprintf(buffer, _("%i").c_str(), i); + font->DrawString(buffer, 30 + leftTransition, posY); + sprintf(buffer, ((*countPerCost)[i] > 0) ? _("%i").c_str() : ".", (*countPerCost)[i]); + font->DrawString(buffer, 45 + leftTransition, posY); + for (int j = 0; j < Constants::MTG_NB_COLORS - 1; j++) + { + sprintf(buffer, ((*countPerCostAndColor)[i][j] > 0) ? _("%i").c_str() : ".", (*countPerCostAndColor)[i][j]); + font->DrawString(buffer, 64 + leftTransition + j * 15, posY); + } + r->FillRect(77.f + leftTransition + (Constants::MTG_NB_COLORS - 2) * 15.0f, posY + 2.0f, (*countPerCost)[i] * 5.0f, + 8.0f, graphColor); + posY += 10; + } + + posY += 10; + sprintf(buffer, _("Average converted mana cost: %2.2f").c_str(), avgCost); + font->DrawString(buffer, 20 + leftTransition, posY); + posY += 15; + sprintf(buffer, _("C - Converted mana cost. Cards with cost>%i are included in the last row.").c_str(), + Constants::STATS_MAX_MANA_COST); + font->DrawString(buffer, 20 + leftTransition, posY); + posY += 10; + font->DrawString(_("# - Total number of cards with given cost"), 20 + leftTransition, posY); + + break; + + case 8: + // Title + sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Probabilities").c_str()); + font->DrawString(buffer, 10 + leftTransition, 10); + + // No lands detail + float graphScale, graphWidth; + graphWidth = 100; + graphScale = (stw->noLandsProbInTurn[0] == 0) ? 0 : (graphWidth / stw->noLandsProbInTurn[0]); + font->DrawString(_("No lands in first n cards:"), 20 + leftTransition, 30); + + posY = 50; + for (int i = 0; i < Constants::STATS_FOR_TURNS; i++) + { + sprintf(buffer, _("%i:").c_str(), i + 7); + font->DrawString(buffer, 30 + leftTransition, posY); + sprintf(buffer, _("%2.2f%%").c_str(), stw->noLandsProbInTurn[i]); + font->DrawString(buffer, 45 + leftTransition, posY); + r->FillRect(84 + leftTransition, posY + 2, graphScale * stw->noLandsProbInTurn[i], 8, graphColor); + posY += 10; + } + + // No creatures probability detail + posY += 10; + font->DrawString(_("No creatures in first n cards:"), 20 + leftTransition, posY); + posY += 20; + graphScale = (stw->noCreaturesProbInTurn[0] == 0) ? 0 : (graphWidth / stw->noCreaturesProbInTurn[0]); + + for (int i = 0; i < Constants::STATS_FOR_TURNS; i++) + { + sprintf(buffer, _("%i:").c_str(), i + 7); + font->DrawString(buffer, 30 + leftTransition, posY); + sprintf(buffer, _("%2.2f%%").c_str(), stw->noCreaturesProbInTurn[i]); + font->DrawString(buffer, 45 + leftTransition, posY); + r->FillRect(84 + leftTransition, posY + 2, graphScale * stw->noCreaturesProbInTurn[i], 8, graphColor); + posY += 10; + } + + break; + + case 7: // Total mana cost per color + // Title + sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Mana cost per color").c_str()); + font->DrawString(buffer, 10 + leftTransition, 10); + + font->DrawString(_("Total colored manasymbols in cards' casting costs:"), 20 + leftTransition, 30); + + posY = 50; + for (int i = 1; i < Constants::MTG_NB_COLORS - 1; i++) + { + if (stw->totalCostPerColor[i] > 0) + { + sprintf(buffer, _("%i").c_str(), stw->totalCostPerColor[i]); + font->DrawString(buffer, 20 + leftTransition, posY); + sprintf(buffer, _("(%i%%)").c_str(), (int) (100 * (float) stw->totalCostPerColor[i] / stw->totalColoredSymbols)); + font->DrawString(buffer, 33 + leftTransition, posY); + posX = 72; + for (int j = 0; j < stw->totalCostPerColor[i]; j++) + { + r->RenderQuad(mIcons[i], posX + leftTransition, posY + 6, 0, 0.5, 0.5); + posX += ((j + 1) % 10 == 0) ? 17 : 13; + if ((((j + 1) % 30) == 0) && (j < stw->totalCostPerColor[i] - 1)) + { + posX = 72; + posY += 15; + } + } + posY += 17; + } + } + break; + + case 9: // Victory statistics + // Title + sprintf(buffer, STATS_TITLE_FORMAT.c_str(), stw->currentPage, _("Victory statistics").c_str()); + font->DrawString(buffer, 10 + leftTransition, 10); + + font->DrawString(_("Victories against AI:"), 20 + leftTransition, 30); + + sprintf(buffer, _("Games played: %i").c_str(), stw->gamesPlayed); + font->DrawString(buffer, 20 + leftTransition, 45); + sprintf(buffer, _("Victory ratio: %i%%").c_str(), stw->percentVictories); + font->DrawString(buffer, 20 + leftTransition, 55); + + int AIsPerColumn = 19; + posY = 70; + posX = 20; + + // ToDo: Multiple pages when too many AI decks are present + for (int i = 0; i < (int) stw->aiDeckStats.size(); i++) + { + sprintf(buffer, _("%.14s").c_str(), stw->aiDeckNames.at(i).c_str()); + font->DrawString(buffer, posX + (i < 2 * AIsPerColumn ? leftTransition : rightTransition), posY); + sprintf(buffer, _("%i/%i").c_str(), stw->aiDeckStats.at(i)->victories, stw->aiDeckStats.at(i)->nbgames); + font->DrawString(buffer, posX + (i < AIsPerColumn ? leftTransition : rightTransition) + 80, posY); + sprintf(buffer, _("%i%%").c_str(), stw->aiDeckStats.at(i)->percentVictories()); + font->DrawString(buffer, posX + (i < AIsPerColumn ? leftTransition : rightTransition) + 110, posY); + posY += 10; + if (((i + 1) % AIsPerColumn) == 0) + { + posY = 70; + posX += 155; + } + } + break; + } + } +} + + +void GameStateDeckViewer::renderCard(int id, float rotation) +{ + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + MTGCard * card = cardIndex[id]; + + float max_scale = 0.96f; + float x_center_0 = 180; + float right_border = SCREEN_WIDTH - 20; + + float x_center = x_center_0 + cos((rotation + 8 - id) * M_PI / 12) * (right_border - x_center_0); + float scale = max_scale / 1.12f * cos((x_center - x_center_0) * 1.5f / (right_border - x_center_0)) + 0.2f * max_scale * cos( + cos((x_center - x_center_0) * 0.15f / (right_border - x_center_0))); + float x = x_center; // ; + + float y = (SCREEN_HEIGHT_F) / 2.0f + SCREEN_HEIGHT_F * mSlide * (scale + 0.2f); + + cardsCoordinates[id] = pair(x, y); + + int alpha = (int) (255 * (scale + 1.0 - max_scale)); + + if (!card) return; + JQuad * quad = NULL; + + int cacheError = CACHE_ERROR_NONE; + + if (!options[Options::DISABLECARDS].number) + { + quad = WResourceManager::Instance()->RetrieveCard(card, RETRIEVE_EXISTING); + cacheError = WResourceManager::Instance()->RetrieveError(); + if (!quad && cacheError != CACHE_ERROR_404) + { + if (last_user_activity > (abs(2 - id) + 1) * NO_USER_ACTIVITY_SHOWCARD_DELAY) + quad = WResourceManager::Instance()->RetrieveCard(card); + else + { + quad = backQuad; + } + } + } + + int quadAlpha = alpha; + if (!displayed_deck->count(card)) quadAlpha /= 2; + if (quad) + { + if (quad == backQuad) + { + quad->SetColor(ARGB(255,255,255,255)); + float _scale = scale * (285 / quad->mHeight); + JRenderer::GetInstance()->RenderQuad(quad, x, y, 0.0f, _scale, _scale); + } + else + { + Pos pos = Pos(x, y, scale * 285 / 250, 0.0, 255); + CardGui::DrawCard(card, pos); + } + } + else + { + Pos pos = Pos(x, y, scale * 285 / 250, 0.0, 255); + CardGui::DrawCard(card, pos, DrawMode::kText); + if (!options[Options::DISABLECARDS].number) quad = WResourceManager::Instance()->RetrieveCard(card, CACHE_THUMB); + if (quad) + { + float _scale = 285 * scale / quad->mHeight; + quad->SetColor(ARGB(40,255,255,255)); + JRenderer::GetInstance()->RenderQuad(quad, x, y, 0, _scale, _scale); + } + } + quadAlpha = 255 - quadAlpha; + if (quadAlpha > 0) + { + JRenderer::GetInstance()->FillRect(x - scale * 100.0f, y - scale * 142.5f, scale * 200.0f, scale * 285.0f, + ARGB(quadAlpha,0,0,0)); + } + if (last_user_activity < 3) + { + int fontAlpha = alpha; + float qtY = y - 135 * scale; + float qtX = x + 40 * scale; + char buffer[4096]; + sprintf(buffer, "x%i", displayed_deck->count(card)); + WFont * font = mFont; + font->SetColor(ARGB(fontAlpha/2,0,0,0)); + JRenderer::GetInstance()->FillRect(qtX, qtY, font->GetStringWidth(buffer) + 6, 16, ARGB(fontAlpha/2,0,0,0)); + font->DrawString(buffer, qtX + 4, qtY + 4); + font->SetColor(ARGB(fontAlpha,255,255,255)); + font->DrawString(buffer, qtX + 2, qtY + 2); + font->SetColor(ARGB(255,255,255,255)); + } +} + +void GameStateDeckViewer::renderCard(int id) +{ + renderCard(id, 0); +} + +void GameStateDeckViewer::Render() +{ + + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + JRenderer * r = JRenderer::GetInstance(); + + r->ClearScreen(ARGB(0,0,0,0)); + if (displayed_deck == myDeck && mStage != STAGE_MENU) + renderDeckBackground(); + int order[3] = { 1, 2, 3 }; + if (mRotation < 0.5 && mRotation > -0.5) + { + order[1] = 3; + order[2] = 2; + } + else if (mRotation < -0.5) + { + order[0] = 3; + order[2] = 1; + } + + renderCard(6, mRotation); + renderCard(5, mRotation); + renderCard(4, mRotation); + renderCard(0, mRotation); + + for (int i = 0; i < 3; i++) + { + renderCard(order[i], mRotation); + } + + if (displayed_deck->Size() > 0) + { + renderSlideBar(); + } + else + { + mFont->DrawString(_("No Card"), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, JGETEXT_CENTER); + } + if (mStage == STAGE_ONSCREEN_MENU) + { + renderOnScreenMenu(); + } + else if (mStage == STAGE_WELCOME) + { + welcome_menu->Render(); + } + else + { + renderOnScreenBasicInfo(); + + } + if (mStage == STAGE_MENU) + { + menu->Render(); + } + if (subMenu) subMenu->Render(); + + if (filterMenu && !filterMenu->isFinished()) filterMenu->Render(); + + if (options.keypadActive()) options.keypadRender(); + +} + +int GameStateDeckViewer::loadDeck(int deckid) +{ + + if (!stw) + { + DeckManager *deckManager = DeckManager::GetInstance(); + stw = deckManager->getExtendedStatsForDeckId( deckid, mParent->collection, false ); + } + + stw->currentPage = 0; + stw->pageCount = 9; + stw->needUpdate = true; + + if (!playerdata) playerdata = NEW PlayerData(mParent->collection); + SAFE_DELETE(myCollection); + myCollection = NEW DeckDataWrapper(playerdata->collection); + myCollection->Sort(WSrcCards::SORT_ALPHA); + displayed_deck = myCollection; + + char deckname[256]; + sprintf(deckname, "deck%i.txt", deckid); + if (myDeck) + { + SAFE_DELETE(myDeck->parent); + SAFE_DELETE(myDeck); + } + myDeck = NEW DeckDataWrapper(NEW MTGDeck(options.profileFile(deckname, "", false, false).c_str(), mParent->collection)); + + // Check whether the cards in the deck are actually available in the player's collection: + int cheatmode = options[Options::CHEATMODE].number; + bool bPure = true; + for (int i = 0; i < myDeck->Size(true); i++) + { + MTGCard * current = myDeck->getCard(i, true); + int howmanyinDeck = myDeck->count(current); + for (int i = myCollection->count(current); i < howmanyinDeck; i++) + { + bPure = false; + if (cheatmode) + { //Are we cheating? + playerdata->collection->add(current); //Yup, add it to collection permanently. + myCollection->Add(current); + } + else + { + myDeck->Remove(current); //Nope. Remove it from deck. + break; + } + } + + myCollection->Remove(current, myDeck->count(current)); + } + if (!bPure) + { + myDeck->validate(); + myCollection->validate(); + } + + myDeck->Sort(WSrcCards::SORT_ALPHA); + SAFE_DELETE(filterMenu); + rebuildFilters(); + loadIndexes(); + return 1; +} + +void GameStateDeckViewer::ButtonPressed(int controllerId, int controlId) +{ + int deckIdNumber = controlId; + int deckListSize = 0; + string defaultAiName; + DeckManager *deckManager = DeckManager::GetInstance(); + vector * deckList; + switch (controllerId) + { + case MENU_DECK_SELECTION: //Deck menu + if (controlId == MENU_ITEM_CANCEL) + { + if (!mSwitching) + mParent->DoTransition(TRANSITION_FADE, GAME_STATE_MENU); + else + mStage = STAGE_WAITING; + + mSwitching = false; + break; + } + else if (controlId == MENUITEM_MORE_INFO) + { + break; + } + else if (controlId == MENU_ITEM_CHEAT_MODE) + { // (PSY) Cheatmode: Complete the collection + playerdata->collection->complete(); // Add the cards + playerdata->collection->save(); // Save the new collection + for (int i = 0; i < setlist.size(); i++) + { // Update unlocked sets + GameOptionAward * goa = dynamic_cast (&options[Options::optionSet(i)]); + if (goa) goa->giveAward(); + } + options.save(); + SAFE_DELETE(myCollection); + myCollection = NEW DeckDataWrapper(playerdata->collection); + myCollection->Sort(WSrcCards::SORT_ALPHA); + displayed_deck = myCollection; + rebuildFilters(); + loadIndexes(); + mStage = STAGE_WELCOME; + break; + } + mStage = STAGE_WAITING; + deckList = deckManager->getPlayerDeckOrderList(); + deckListSize = deckList->size(); + + if (controlId == MENU_ITEM_NEW_DECK) // new deck option selected + deckIdNumber = deckList->size() + 1; + else if (deckListSize > 0 && controlId <= deckListSize) + deckIdNumber = deckList->at(controlId - 1)-> getDeckId(); + else + deckIdNumber = controlId; + + loadDeck(deckIdNumber); + mStage = STAGE_WAITING; + deckNum = controlId; + break; + + case MENU_DECK_BUILDER: //Save / exit menu + switch (controlId) + { + + case MENU_ITEM_SAVE_RETURN_MAIN_MENU: + saveDeck(); + mParent->DoTransition(TRANSITION_FADE, GAME_STATE_MENU); + break; + + case MENU_ITEM_SAVE_RENAME: + if (myDeck && myDeck->parent) + { + options.keypadStart(myDeck->parent->meta_name, &newDeckname); + options.keypadTitle("Rename deck"); + } + break; + + case MENU_ITEM_SAVE_AS_AI_DECK: + // find the next unused ai deck number + // warn user that once saved, no edits can be made + // save entire collection to ai as spelled out card with count + // bring user to main deck editor menu. + isAIDeckSave = true; + defaultAiName = myDeck && myDeck->parent ? myDeck->parent->meta_name : "Custom AI Deck"; + options.keypadStart(defaultAiName, &newDeckname); + options.keypadTitle("Name Custom AI Deck"); + updateDecks(); + mStage = STAGE_WELCOME; + mSwitching = true; + break; + + case MENU_ITEM_SWITCH_DECKS_NO_SAVE: + //updateDecks(); + mStage = STAGE_WELCOME; + mSwitching = true; + break; + case MENU_ITEM_MAIN_MENU: + mParent->DoTransition(TRANSITION_FADE, GAME_STATE_MENU); + break; + case MENU_ITEM_EDITOR_CANCEL: + mStage = STAGE_WAITING; + break; + case MENU_ITEM_FILTER_BY: + mStage = STAGE_FILTERS; + if (!filterMenu) rebuildFilters(); + filterMenu->Entering(JGE_BTN_NONE); + break; + } + break; + + case MENU_CARD_PURCHASE: // Yes/ No sub menu. + switch (controlId) + { + case MENU_ITEM_YES: + { + MTGCard * card = cardIndex[2]; + if (card) + { + int rnd = (rand() % 25); + playerdata->credits += price; + price = price - (rnd * price) / 100; + pricelist->setPrice(card->getMTGId(), price); + playerdata->collection->remove(card->getMTGId()); + displayed_deck->Remove(card, 1); + displayed_deck->validate(); + stw->needUpdate = true; + loadIndexes(); + } + } + case MENU_ITEM_NO: + subMenu->Close(); + break; + } + } +} + diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index 0ddfb82d9..b49d8f821 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -1,800 +1,800 @@ -#include "PrecompiledHeader.h" - -#include "DeckMenu.h" -#include "GameStateDuel.h" -#include "GameOptions.h" -#include "utils.h" -#include "AIPlayer.h" -#include "AIMomirPlayer.h" -#include "PlayerData.h" -#include "DeckStats.h" -#include "DeckManager.h" - -#include "DeckMetaData.h" -#include "MTGRules.h" -#include "Credits.h" -#include "Translate.h" -#include "Rules.h" - -#ifdef TESTSUITE -#include "TestSuiteAI.h" -#endif - -#if defined (WIN32) || defined (LINUX) -#include -#endif - -const float MENU_FONT_SCALE = 1.0f; - -enum ENUM_DUEL_STATE -{ - DUEL_STATE_START, - DUEL_STATE_END, - DUEL_STATE_CHOOSE_DECK1, - DUEL_STATE_DECK1_DETAILED_INFO, - DUEL_STATE_DECK2_DETAILED_INFO, - DUEL_STATE_CHOOSE_DECK1_TO_2, - DUEL_STATE_CHOOSE_DECK2, - DUEL_STATE_CHOOSE_DECK2_TO_PLAY, - DUEL_STATE_ERROR_NO_DECK, - DUEL_STATE_CANCEL, - DUEL_STATE_PLAY, - DUEL_STATE_BACK_TO_MAIN_MENU, - DUEL_STATE_MENU, - DUEL_STATE_ERROR -}; - -enum ENUM_DUEL_MENUS -{ - DUEL_MENU_GAME_MENU, - DUEL_MENU_CHOOSE_DECK, - DUEL_MENU_CHOOSE_OPPONENT, - DUEL_MENU_DETAILED_DECK1_INFO, - DUEL_MENU_DETAILED_DECK2_INFO -}; - -int GameStateDuel::selectedPlayerDeckId = 0; -int GameStateDuel::selectedAIDeckId = 0; - -GameStateDuel::GameStateDuel(GameApp* parent) : - GameState(parent) -{ - for (int i = 0; i < 2; i++) - { - deck[i] = NULL; - mPlayers[i] = NULL; - } - premadeDeck = false; - game = NULL; - deckmenu = NULL; - opponentMenu = NULL; - menu = NULL; - popupScreen = NULL; - -#ifdef TESTSUITE - testSuite = NULL; -#endif - - credits = NULL; - rules = NULL; - -} - -GameStateDuel::~GameStateDuel() -{ - End(); -} - -void GameStateDuel::Start() -{ - JRenderer * renderer = JRenderer::GetInstance(); - renderer->EnableVSync(true); - OpponentsDeckid = 0; - -#ifdef TESTSUITE - SAFE_DELETE(testSuite); - testSuite = NEW TestSuite(JGE_GET_RES("test/_tests.txt").c_str(),mParent->collection); -#endif - - mGamePhase = DUEL_STATE_CHOOSE_DECK1; - credits = NEW Credits(); - - menu = NULL; - - int decksneeded = 0; - for (int i = 0; i < 2; i++) - { - if (mParent->players[i] == PLAYER_TYPE_HUMAN) - { - decksneeded = 1; - - deckmenu = NEW DeckMenu(DUEL_MENU_CHOOSE_DECK, this, Fonts::OPTION_FONT, "Choose a Deck", - GameStateDuel::selectedPlayerDeckId, true); - deckmenu->enableDisplayDetailsOverride(); - DeckManager *deckManager = DeckManager::GetInstance(); - vector playerDeckList = getValidDeckMetaData(options.profileFile()); - int nbDecks = playerDeckList.size(); - - if (nbDecks) - { - decksneeded = 0; - if (nbDecks > 1) deckmenu->Add(MENUITEM_RANDOM_PLAYER, "Random", "Play with a random deck."); - } - - renderDeckMenu(deckmenu, playerDeckList); - // save the changes to the player deck list maintained in DeckManager - deckManager->updateMetaDataList(&playerDeckList, false); - playerDeckList.clear(); - - break; - } - } - - if (deckmenu) - { - if (decksneeded) - { - //translate deck creating desc - Translator * t = Translator::GetInstance(); - map::iterator it = t->deckValues.find("Create your Deck!"); - if (it != t->deckValues.end()) - deckmenu->Add(MENUITEM_NEW_DECK, "Create your Deck!", it->second); - else - deckmenu->Add(MENUITEM_NEW_DECK, "Create your Deck!", "Highly recommended to get\nthe full Wagic experience!"); - premadeDeck = true; - fillDeckMenu(deckmenu, JGE_GET_RES("player/premade")); - } - if (!decksneeded) - { - deckmenu->Add(MENUITEM_NEW_DECK, "New Deck...", "Create a new deck to play with."); - } - deckmenu->Add(MENUITEM_CANCEL, "Main Menu", "Return to Main Menu"); - } - - for (int i = 0; i < 2; ++i) - { - mPlayers[i] = NULL; - } -} - -void GameStateDuel::loadPlayer(int playerId, int decknb, int isAI) -{ - if (decknb) - { - if (!isAI) - { //Human Player - char deckFile[255]; - if (premadeDeck) - sprintf(deckFile, JGE_GET_RES("player/premade/deck%i.txt").c_str(), decknb); - else - sprintf(deckFile, "%s/deck%i.txt", options.profileFile().c_str(), decknb); - char deckFileSmall[255]; - sprintf(deckFileSmall, "player_deck%i", decknb); - MTGDeck * tempDeck = NEW MTGDeck(deckFile, mParent->collection); - mPlayers[playerId] = NEW HumanPlayer(tempDeck, deckFile, deckFileSmall); - - deck[playerId] = mPlayers[playerId]->game; - delete tempDeck; - } - else - { //AI Player, chooses deck - AIPlayerFactory playerCreator; - Player * opponent = NULL; - if (playerId == 1) opponent = mPlayers[0]; - mPlayers[playerId] = playerCreator.createAIPlayer(mParent->collection, opponent, decknb); - deck[playerId] = mPlayers[playerId]->game; - } - } - else - { //Random deck - AIPlayerFactory playerCreator; - Player * opponent = NULL; - if (playerId == 1) opponent = mPlayers[0]; - mPlayers[playerId] = playerCreator.createAIPlayer(mParent->collection, opponent); - deck[playerId] = mPlayers[playerId]->game; - } -} - -void GameStateDuel::initRand(unsigned int seed) -{ - if (!seed) seed = time(0); - srand(seed); -} - -#ifdef TESTSUITE -void GameStateDuel::loadTestSuitePlayers() -{ - if (!testSuite) return; - initRand(testSuite->seed); - SAFE_DELETE(game); - for (int i = 0; i < 2; i++) - { - mPlayers[i] = NEW TestSuiteAI(testSuite, i); - deck[i] = mPlayers[i]->game; - } - mParent->gameType = testSuite->gameType; - - GameObserver::Init(mPlayers, 2); - game = GameObserver::GetInstance(); - game->startGame(rules); - if (mParent->gameType == GAME_TYPE_MOMIR) - { - game->addObserver(NEW MTGMomirRule(-1, mParent->collection)); - } -} -#endif - -void GameStateDuel::End() -{ - DebugTrace("Ending GameStateDuel"); - - JRenderer::GetInstance()->EnableVSync(false); - - if (!premadeDeck && mPlayers[0] && mPlayers[1]) // save the stats for the game - mPlayers[0]->End(); - else if ( !mPlayers[1] && mPlayers[0] ) - // clean up player object - SAFE_DELETE( mPlayers[0] ); - GameObserver::EndInstance(); // this will delete both player objects if a game has been played - - game = NULL; - premadeDeck = false; - - for (int i = 0; i < 2; i++) - { - mPlayers[i] = NULL; - deck[i] = NULL; - } - SAFE_DELETE(credits); - SAFE_DELETE(rules); - - SAFE_DELETE(menu); - SAFE_DELETE(opponentMenu); - SAFE_DELETE(deckmenu); - SAFE_DELETE(popupScreen); - -#ifdef TESTSUITE - SAFE_DELETE(testSuite); -#endif -} - -//TODO Move This to utils or ResourceManager. Don't we have more generic functions that can do that? -bool GameStateDuel::MusicExist(string FileName) -{ - string filepath = JGE_GET_RES(WResourceManager::Instance()->musicFile(FileName)); - wagic::ifstream file(filepath.c_str()); - if (file) - { - file.close(); - return true; - } - else - return false; -} - -void GameStateDuel::ConstructOpponentMenu() -{ - if (opponentMenu == NULL) - { - opponentMenu = NEW DeckMenu(DUEL_MENU_CHOOSE_OPPONENT, this, Fonts::OPTION_FONT, "Choose Opponent", - GameStateDuel::selectedAIDeckId, true); - opponentMenu->Add(MENUITEM_RANDOM_AI, "Random"); - if (options[Options::EVILTWIN_MODE_UNLOCKED].number) opponentMenu->Add(MENUITEM_EVIL_TWIN, "Evil Twin", - _("Can you defeat yourself?").c_str()); - DeckManager * deckManager = DeckManager::GetInstance(); - vector opponentDeckList; - int nbUnlockedDecks = options[Options::CHEATMODEAIDECK].number ? 1000 : options[Options::AIDECKS_UNLOCKED].number; - opponentDeckList = fillDeckMenu(opponentMenu, JGE_GET_RES("ai/baka"), "ai_baka", mPlayers[0], nbUnlockedDecks); - deckManager->updateMetaDataList(&opponentDeckList, true); - opponentMenu->Add(MENUITEM_CANCEL, "Cancel", _("Choose a different player deck").c_str()); - opponentDeckList.clear(); - } -} - -void GameStateDuel::Update(float dt) -{ - switch (mGamePhase) - { - case DUEL_STATE_ERROR_NO_DECK: - if (JGE_BTN_OK == mEngine->ReadButton()) mParent->SetNextState(GAME_STATE_DECK_VIEWER); - break; - - case DUEL_STATE_DECK1_DETAILED_INFO: - case DUEL_STATE_DECK2_DETAILED_INFO: - popupScreen->Update(dt); - break; - - case DUEL_STATE_CHOOSE_DECK1: - if (mParent->gameType == GAME_TYPE_MOMIR) - { - rules = NEW Rules("momir.txt"); - mGamePhase = DUEL_STATE_PLAY; - } - else if (mParent->gameType == GAME_TYPE_RANDOM1) - { - rules = NEW Rules("random1.txt"); - mGamePhase = DUEL_STATE_PLAY; - } - else if (mParent->gameType == GAME_TYPE_RANDOM2) - { - rules = NEW Rules("random2.txt"); - mGamePhase = DUEL_STATE_PLAY; - } -#ifdef TESTSUITE - else if (mParent->players[1] == PLAYER_TYPE_TESTSUITE) - { - if (testSuite && testSuite->loadNext()) - { - rules = NEW Rules("testsuite.txt"); - loadTestSuitePlayers(); - mGamePhase = DUEL_STATE_PLAY; - testSuite->pregameTests(); - testSuite->initGame(); - } - else - { - if (!game) - { - mGamePhase = DUEL_STATE_ERROR; - } - else - { - mGamePhase = DUEL_STATE_END; - } - } - } -#endif - else - { - if (!rules) rules = NEW Rules("mtg.txt"); - if (mParent->players[0] == PLAYER_TYPE_HUMAN) - { - if (!popupScreen || popupScreen->isClosed()) deckmenu->Update(dt); - } - else - { - loadPlayer(0); - mGamePhase = DUEL_STATE_CHOOSE_DECK2; - } - } - break; - case DUEL_STATE_CHOOSE_DECK1_TO_2: - if (deckmenu->isClosed()) - mGamePhase = DUEL_STATE_CHOOSE_DECK2; - else - deckmenu->Update(dt); - break; - case DUEL_STATE_CHOOSE_DECK2: - if (mParent->players[1] == PLAYER_TYPE_HUMAN) - deckmenu->Update(dt); - else - { - if (mParent->players[0] == PLAYER_TYPE_HUMAN) - { - ConstructOpponentMenu(); - opponentMenu->Update(dt); - } - else - { - loadPlayer(1); - mGamePhase = DUEL_STATE_PLAY; - } - } - break; - case DUEL_STATE_CHOOSE_DECK2_TO_PLAY: - if (mParent->players[1] == PLAYER_TYPE_HUMAN) - { - if (deckmenu->isClosed()) - mGamePhase = DUEL_STATE_PLAY; - else - deckmenu->Update(dt); - } - else - { - ConstructOpponentMenu(); - if (opponentMenu->isClosed()) - mGamePhase = DUEL_STATE_PLAY; - else - opponentMenu->Update(dt); - } - break; - case DUEL_STATE_PLAY: - if (!game) - { - GameObserver::Init(mPlayers, 2); - game = GameObserver::GetInstance(); - game->startGame(rules); - if (mParent->gameType == GAME_TYPE_MOMIR) - { - game->addObserver(NEW MTGMomirRule(-1, mParent->collection)); - } - - //start of in game music code - musictrack = ""; - //check opponent id and choose the music track based on it - if (OpponentsDeckid) - { - char temp[4096]; - sprintf(temp, "ai_baka_music%i.mp3", OpponentsDeckid); - musictrack.assign(temp); - } - else if (mParent->gameType == GAME_TYPE_CLASSIC) - musictrack = "ai_baka_music.mp3"; - else if (mParent->gameType == GAME_TYPE_MOMIR) - musictrack = "ai_baka_music_momir.mp3"; - else if (mParent->gameType == GAME_TYPE_RANDOM1 || mParent->gameType == GAME_TYPE_RANDOM2) musictrack - = "ai_baka_music_random.mp3"; - - if (!MusicExist(musictrack)) musictrack = "ai_baka_music.mp3"; - - GameApp::playMusic(musictrack); - } - game->Update(dt); - if (game->gameOver) - { - if (game->players[1]->playMode != Player::MODE_TEST_SUITE) credits->compute(game->players[0], game->players[1], mParent); - mGamePhase = DUEL_STATE_END; -#ifdef TESTSUITE - if (mParent->players[1] == PLAYER_TYPE_TESTSUITE) - { - if (testSuite->loadNext()) - { - loadTestSuitePlayers(); - mGamePhase = DUEL_STATE_PLAY; - testSuite->initGame(); - } - else - mGamePhase = DUEL_STATE_END; - } - else -#endif - if (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU) - { - End(); - Start(); - } - } - if (mEngine->GetButtonClick(JGE_BTN_MENU)) - { - if (!menu) - { - menu = NEW SimpleMenu(DUEL_MENU_GAME_MENU, this, Fonts::MENU_FONT, SCREEN_WIDTH / 2 - 100, 25, - game->players[1]->deckName.c_str()); - int cardsinhand = game->players[0]->game->hand->nb_cards; - - //almosthumane - mulligan - if ((game->turn < 1) && (cardsinhand != 0) && game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN - && game->players[0]->game->inPlay->nb_cards == 0 && game->players[0]->game->graveyard->nb_cards == 0 - && game->players[0]->game->exile->nb_cards == 0) //1st Play Check - //IF there was no play at the moment automatically mulligan - { - menu->Add(MENUITEM_MULLIGAN, "Mulligan"); - } - //END almosthumane - mulligan - menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); - menu->Add(MENUITEM_CANCEL, "Cancel"); - } - mGamePhase = DUEL_STATE_MENU; - } - break; - case DUEL_STATE_MENU: - menu->Update(dt); - break; - case DUEL_STATE_CANCEL: - menu->Update(dt); - if (menu->isClosed()) - { - mGamePhase = DUEL_STATE_PLAY; - SAFE_DELETE(menu); - } - break; - case DUEL_STATE_BACK_TO_MAIN_MENU: - if (menu) - { - menu->Update(dt); - if (menu->isClosed()) - { - PlayerData * playerdata = NEW PlayerData(mParent->collection); - playerdata->taskList->passOneDay(); - playerdata->taskList->save(); - SAFE_DELETE(playerdata); - SAFE_DELETE(menu); - } - } - mParent->DoTransition(TRANSITION_FADE, GAME_STATE_MENU); - - break; - default: - if (JGE_BTN_OK == mEngine->ReadButton()) mParent->SetNextState(GAME_STATE_MENU); - } -} - -void GameStateDuel::Render() -{ - WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - JRenderer * r = JRenderer::GetInstance(); - r->ClearScreen(ARGB(0,0,0,0)); - - if (game) game->Render(); - - switch (mGamePhase) - { - case DUEL_STATE_END: - { - JRenderer * r = JRenderer::GetInstance(); - r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(200,0,0,0)); - credits->Render(); -#ifdef TESTSUITE - if (mParent->players[1] == PLAYER_TYPE_TESTSUITE) - { - r->ClearScreen(ARGB(255,0,0,0)); - char buf[4096]; - int nbFailed = testSuite->nbFailed; - int nbTests = testSuite->nbTests; - if (!nbFailed) - { - sprintf(buf, "All %i tests successful!", nbTests); - } - else - { - sprintf(buf, "%i tests out of %i FAILED!", nbFailed, nbTests); - } - mFont->SetColor(ARGB(255,255,255,255)); - mFont->DrawString(buf,0,SCREEN_HEIGHT/2); - nbFailed = testSuite->nbAIFailed; - nbTests = testSuite->nbAITests; - if (nbTests) - { - if (!nbFailed) - { - sprintf(buf, "AI Tests: All %i tests successful!", nbTests); - } - else - { - sprintf(buf, "AI Tests: %i tests out of %i FAILED!", nbFailed, nbTests); - } - mFont->DrawString(buf,0,SCREEN_HEIGHT/2+20); - } - } -#endif - break; - } - case DUEL_STATE_ERROR: - { - r->ClearScreen(ARGB(200,0,0,0)); - mFont->DrawString(_("AN ERROR OCCURRED, CHECK FILE NAMES").c_str(), 0, SCREEN_HEIGHT / 2); - break; - } - case DUEL_STATE_CHOOSE_DECK1: - case DUEL_STATE_CHOOSE_DECK1_TO_2: - case DUEL_STATE_CHOOSE_DECK2: - case DUEL_STATE_CHOOSE_DECK2_TO_PLAY: - case DUEL_STATE_DECK1_DETAILED_INFO: - case DUEL_STATE_DECK2_DETAILED_INFO: - if (mParent->gameType != GAME_TYPE_CLASSIC) - mFont->DrawString(_("LOADING DECKS").c_str(), 0, SCREEN_HEIGHT / 2); - else - { - if (opponentMenu) - opponentMenu->Render(); - else if (deckmenu && !deckmenu->isClosed()) deckmenu->Render(); - - if (menu) menu->Render(); - - if (popupScreen && !popupScreen->isClosed()) popupScreen->Render(); - } - break; - case DUEL_STATE_ERROR_NO_DECK: - mFont->DrawString(_("NO DECK AVAILABLE,").c_str(), 0, SCREEN_HEIGHT / 2); - mFont->DrawString(_("PRESS CIRCLE TO GO TO THE DECK EDITOR!").c_str(), 0, SCREEN_HEIGHT / 2 + 20); - break; - case DUEL_STATE_MENU: - case DUEL_STATE_CANCEL: - case DUEL_STATE_BACK_TO_MAIN_MENU: - if (game) - { - r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(100,0,0,0)); - char buffer[4096]; - sprintf(buffer, _("Turn:%i").c_str(), game->turn); - mFont->SetColor(ARGB(255,255,255,255)); - mFont->DrawString(buffer, SCREEN_WIDTH / 2, 0, JGETEXT_CENTER); - } - if (menu) menu->Render(); - } -} - -void GameStateDuel::ButtonPressed(int controllerId, int controlId) -{ - int deckNumber = controlId; - DeckManager * deckManager = DeckManager::GetInstance(); - int aiDeckSize = deckManager->getAIDeckOrderList()->size(); - switch (controllerId) - { - - case DUEL_MENU_DETAILED_DECK1_INFO: - if ((popupScreen || deckmenu->showDetailsScreen())) - { - DeckMetaData* selectedDeck = deckmenu->getSelectedDeck(); - if (!popupScreen->isClosed()) - { - popupScreen->Close(); - mGamePhase = DUEL_STATE_CHOOSE_DECK1; - SAFE_DELETE( popupScreen ); - } - else - { - popupScreen->Update(selectedDeck); - popupScreen->Render(); - } - } - break; - case DUEL_MENU_DETAILED_DECK2_INFO: - if ((popupScreen || opponentMenu->showDetailsScreen())) - { - DeckMetaData* selectedDeck = opponentMenu->getSelectedDeck(); - if (!popupScreen->isClosed()) - { - popupScreen->Close(); - mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY; - SAFE_DELETE( popupScreen ); - } - else - { - popupScreen->Update(selectedDeck); - popupScreen->Render(); - } - } - break; - - case DUEL_MENU_CHOOSE_OPPONENT: - - switch (controlId) - { - case MENUITEM_RANDOM_AI: - loadPlayer(1); - opponentMenu->Close(); - mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY; - break; - default: - // cancel option. return to player deck selection - - if (controlId == MENUITEM_CANCEL) - { - opponentMenu->Close(); - deckmenu->Close(); - mParent->SetNextState(DUEL_STATE_CHOOSE_DECK1); - mGamePhase = DUEL_STATE_CHOOSE_DECK1; - break; - } - - else if (controlId == MENUITEM_MORE_INFO && opponentMenu->showDetailsScreen()) - { - DeckMetaData* selectedDeck = opponentMenu->getSelectedDeck(); - if (!popupScreen) - { - popupScreen = NEW SimplePopup(DUEL_MENU_DETAILED_DECK2_INFO, this, Fonts::MAIN_FONT, "Detailed Information", - selectedDeck, mParent->collection); - popupScreen->Render(); - selectedAIDeckId = selectedDeck->getDeckId(); - } - else - { - popupScreen->Update(selectedDeck); - } - mGamePhase = DUEL_STATE_DECK2_DETAILED_INFO; - break; - } - else if (controlId == MENUITEM_MORE_INFO && !opponentMenu->showDetailsScreen()) - { - // do nothing, ignore all key requests until popup is dismissed. - break; - } - else if (controlId != MENUITEM_EVIL_TWIN && aiDeckSize > 0) // evil twin - deckNumber = deckManager->getAIDeckOrderList()->at(controlId - 1)->getDeckId(); - loadPlayer(1, deckNumber, 1); - OpponentsDeckid = deckNumber; - opponentMenu->Close(); - mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY; - break; - } - break; - - case DUEL_MENU_CHOOSE_DECK: - - if (controlId == MENUITEM_RANDOM_PLAYER) // Random Player Deck Selection - { - vector * playerDeckList = deckManager->getPlayerDeckOrderList(); - deckNumber = playerDeckList->at(WRand() * 1001 % (playerDeckList->size()))->getDeckId(); - loadPlayer(0, deckNumber); - deckmenu->Close(); - mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY; - break; - } - else if (controlId == MENUITEM_MAIN_MENU || controlId == MENUITEM_CANCEL) // user clicked on "Cancel" - { - if (deckmenu) deckmenu->Close(); - mGamePhase = DUEL_STATE_BACK_TO_MAIN_MENU; - break; - } - else if (controlId == MENUITEM_MORE_INFO && deckmenu->showDetailsScreen()) - { - DeckMetaData* selectedDeck = deckmenu->getSelectedDeck(); - if (!popupScreen) - { - popupScreen = NEW SimplePopup(DUEL_MENU_DETAILED_DECK1_INFO, this, Fonts::MAIN_FONT, "Detailed Information", - selectedDeck, mParent->collection); - popupScreen->Render(); - selectedPlayerDeckId = deckmenu->getSelectedDeckId(); - } - else - { - popupScreen->Update(selectedDeck); - } - mGamePhase = DUEL_STATE_DECK1_DETAILED_INFO; - break; - } - else if (controlId == MENUITEM_MORE_INFO) - { - // do nothing - break; - } - if (controlId < 0) - { - mParent->SetNextState(GAME_STATE_DECK_VIEWER); - return; - } - if (mGamePhase == DUEL_STATE_CHOOSE_DECK1) - { - vector * playerDeck = deckManager->getPlayerDeckOrderList(); - if (!premadeDeck && controlId > 0) - deckNumber = playerDeck->at(controlId - 1)->getDeckId(); - loadPlayer(0, deckNumber); - deckmenu->Close(); - mGamePhase = DUEL_STATE_CHOOSE_DECK1_TO_2; - playerDeck = NULL; - } - else - { - loadPlayer(1, controlId); - deckmenu->Close(); - mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY; - } - break; - - default: - - switch (controlId) - { - - case MENUITEM_MAIN_MENU: - menu->Close(); - mGamePhase = DUEL_STATE_BACK_TO_MAIN_MENU; - break; - case MENUITEM_CANCEL: - menu->Close(); - mGamePhase = DUEL_STATE_CANCEL; - break; - case MENUITEM_MULLIGAN: - //almosthumane - mulligan - - - int cardsinhand = game->players[0]->game->hand->nb_cards; - - for (int i = 0; i < cardsinhand; i++) //Discard hand - game->currentPlayer->game->putInZone(game->currentPlayer->game->hand->cards[0], - game->currentPlayer->game->hand, - game->currentPlayer->game->library); - - game->currentPlayer->game->library->shuffle(); //Shuffle - - for (int i = 0; i < (cardsinhand - 1); i++) - game->draw(); //Draw hand with 1 less card penalty //almhum - menu->Close(); - mGamePhase = DUEL_STATE_CANCEL; - break; - - //END almosthumane - mulligan - } - - } -} +#include "PrecompiledHeader.h" + +#include "DeckMenu.h" +#include "GameStateDuel.h" +#include "GameOptions.h" +#include "utils.h" +#include "AIPlayer.h" +#include "AIMomirPlayer.h" +#include "PlayerData.h" +#include "DeckStats.h" +#include "DeckManager.h" + +#include "DeckMetaData.h" +#include "MTGRules.h" +#include "Credits.h" +#include "Translate.h" +#include "Rules.h" + +#ifdef TESTSUITE +#include "TestSuiteAI.h" +#endif + +#if defined (WIN32) || defined (LINUX) +#include +#endif + +const float MENU_FONT_SCALE = 1.0f; + +enum ENUM_DUEL_STATE +{ + DUEL_STATE_START, + DUEL_STATE_END, + DUEL_STATE_CHOOSE_DECK1, + DUEL_STATE_DECK1_DETAILED_INFO, + DUEL_STATE_DECK2_DETAILED_INFO, + DUEL_STATE_CHOOSE_DECK1_TO_2, + DUEL_STATE_CHOOSE_DECK2, + DUEL_STATE_CHOOSE_DECK2_TO_PLAY, + DUEL_STATE_ERROR_NO_DECK, + DUEL_STATE_CANCEL, + DUEL_STATE_PLAY, + DUEL_STATE_BACK_TO_MAIN_MENU, + DUEL_STATE_MENU, + DUEL_STATE_ERROR +}; + +enum ENUM_DUEL_MENUS +{ + DUEL_MENU_GAME_MENU, + DUEL_MENU_CHOOSE_DECK, + DUEL_MENU_CHOOSE_OPPONENT, + DUEL_MENU_DETAILED_DECK1_INFO, + DUEL_MENU_DETAILED_DECK2_INFO +}; + +int GameStateDuel::selectedPlayerDeckId = 0; +int GameStateDuel::selectedAIDeckId = 0; + +GameStateDuel::GameStateDuel(GameApp* parent) : + GameState(parent) +{ + for (int i = 0; i < 2; i++) + { + deck[i] = NULL; + mPlayers[i] = NULL; + } + premadeDeck = false; + game = NULL; + deckmenu = NULL; + opponentMenu = NULL; + menu = NULL; + popupScreen = NULL; + +#ifdef TESTSUITE + testSuite = NULL; +#endif + + credits = NULL; + rules = NULL; + +} + +GameStateDuel::~GameStateDuel() +{ + End(); +} + +void GameStateDuel::Start() +{ + JRenderer * renderer = JRenderer::GetInstance(); + renderer->EnableVSync(true); + OpponentsDeckid = 0; + +#ifdef TESTSUITE + SAFE_DELETE(testSuite); + testSuite = NEW TestSuite(JGE_GET_RES("test/_tests.txt").c_str(),mParent->collection); +#endif + + mGamePhase = DUEL_STATE_CHOOSE_DECK1; + credits = NEW Credits(); + + menu = NULL; + + int decksneeded = 0; + for (int i = 0; i < 2; i++) + { + if (mParent->players[i] == PLAYER_TYPE_HUMAN) + { + decksneeded = 1; + + deckmenu = NEW DeckMenu(DUEL_MENU_CHOOSE_DECK, this, Fonts::OPTION_FONT, "Choose a Deck", + GameStateDuel::selectedPlayerDeckId, true); + deckmenu->enableDisplayDetailsOverride(); + DeckManager *deckManager = DeckManager::GetInstance(); + vector playerDeckList = getValidDeckMetaData(options.profileFile()); + int nbDecks = playerDeckList.size(); + + if (nbDecks) + { + decksneeded = 0; + if (nbDecks > 1) deckmenu->Add(MENUITEM_RANDOM_PLAYER, "Random", "Play with a random deck."); + } + + renderDeckMenu(deckmenu, playerDeckList); + // save the changes to the player deck list maintained in DeckManager + deckManager->updateMetaDataList(&playerDeckList, false); + playerDeckList.clear(); + + break; + } + } + + if (deckmenu) + { + if (decksneeded) + { + //translate deck creating desc + Translator * t = Translator::GetInstance(); + map::iterator it = t->deckValues.find("Create your Deck!"); + if (it != t->deckValues.end()) + deckmenu->Add(MENUITEM_NEW_DECK, "Create your Deck!", it->second); + else + deckmenu->Add(MENUITEM_NEW_DECK, "Create your Deck!", "Highly recommended to get\nthe full Wagic experience!"); + premadeDeck = true; + fillDeckMenu(deckmenu, JGE_GET_RES("player/premade")); + } + if (!decksneeded) + { + deckmenu->Add(MENUITEM_NEW_DECK, "New Deck...", "Create a new deck to play with."); + } + deckmenu->Add(MENUITEM_CANCEL, "Main Menu", "Return to Main Menu"); + } + + for (int i = 0; i < 2; ++i) + { + mPlayers[i] = NULL; + } +} + +void GameStateDuel::loadPlayer(int playerId, int decknb, int isAI) +{ + if (decknb) + { + if (!isAI) + { //Human Player + char deckFile[255]; + if (premadeDeck) + sprintf(deckFile, JGE_GET_RES("player/premade/deck%i.txt").c_str(), decknb); + else + sprintf(deckFile, "%s/deck%i.txt", options.profileFile().c_str(), decknb); + char deckFileSmall[255]; + sprintf(deckFileSmall, "player_deck%i", decknb); + MTGDeck * tempDeck = NEW MTGDeck(deckFile, mParent->collection); + mPlayers[playerId] = NEW HumanPlayer(tempDeck, deckFile, deckFileSmall); + + deck[playerId] = mPlayers[playerId]->game; + delete tempDeck; + } + else + { //AI Player, chooses deck + AIPlayerFactory playerCreator; + Player * opponent = NULL; + if (playerId == 1) opponent = mPlayers[0]; + mPlayers[playerId] = playerCreator.createAIPlayer(mParent->collection, opponent, decknb); + deck[playerId] = mPlayers[playerId]->game; + } + } + else + { //Random deck + AIPlayerFactory playerCreator; + Player * opponent = NULL; + if (playerId == 1) opponent = mPlayers[0]; + mPlayers[playerId] = playerCreator.createAIPlayer(mParent->collection, opponent); + deck[playerId] = mPlayers[playerId]->game; + } +} + +void GameStateDuel::initRand(unsigned int seed) +{ + if (!seed) seed = time(0); + srand(seed); +} + +#ifdef TESTSUITE +void GameStateDuel::loadTestSuitePlayers() +{ + if (!testSuite) return; + initRand(testSuite->seed); + SAFE_DELETE(game); + for (int i = 0; i < 2; i++) + { + mPlayers[i] = NEW TestSuiteAI(testSuite, i); + deck[i] = mPlayers[i]->game; + } + mParent->gameType = testSuite->gameType; + + GameObserver::Init(mPlayers, 2); + game = GameObserver::GetInstance(); + game->startGame(rules); + if (mParent->gameType == GAME_TYPE_MOMIR) + { + game->addObserver(NEW MTGMomirRule(-1, mParent->collection)); + } +} +#endif + +void GameStateDuel::End() +{ + DebugTrace("Ending GameStateDuel"); + + JRenderer::GetInstance()->EnableVSync(false); + + if (!premadeDeck && mPlayers[0] && mPlayers[1]) // save the stats for the game + mPlayers[0]->End(); + else if ( !mPlayers[1] && mPlayers[0] ) + // clean up player object + SAFE_DELETE( mPlayers[0] ); + GameObserver::EndInstance(); // this will delete both player objects if a game has been played + + game = NULL; + premadeDeck = false; + + for (int i = 0; i < 2; i++) + { + mPlayers[i] = NULL; + deck[i] = NULL; + } + SAFE_DELETE(credits); + SAFE_DELETE(rules); + + SAFE_DELETE(menu); + SAFE_DELETE(opponentMenu); + SAFE_DELETE(deckmenu); + SAFE_DELETE(popupScreen); + +#ifdef TESTSUITE + SAFE_DELETE(testSuite); +#endif +} + +//TODO Move This to utils or ResourceManager. Don't we have more generic functions that can do that? +bool GameStateDuel::MusicExist(string FileName) +{ + string filepath = JGE_GET_RES(WResourceManager::Instance()->musicFile(FileName)); + wagic::ifstream file(filepath.c_str()); + if (file) + { + file.close(); + return true; + } + else + return false; +} + +void GameStateDuel::ConstructOpponentMenu() +{ + if (opponentMenu == NULL) + { + opponentMenu = NEW DeckMenu(DUEL_MENU_CHOOSE_OPPONENT, this, Fonts::OPTION_FONT, "Choose Opponent", + GameStateDuel::selectedAIDeckId, true); + opponentMenu->Add(MENUITEM_RANDOM_AI, "Random"); + if (options[Options::EVILTWIN_MODE_UNLOCKED].number) opponentMenu->Add(MENUITEM_EVIL_TWIN, "Evil Twin", + _("Can you defeat yourself?").c_str()); + DeckManager * deckManager = DeckManager::GetInstance(); + vector opponentDeckList; + int nbUnlockedDecks = options[Options::CHEATMODEAIDECK].number ? 1000 : options[Options::AIDECKS_UNLOCKED].number; + opponentDeckList = fillDeckMenu(opponentMenu, JGE_GET_RES("ai/baka"), "ai_baka", mPlayers[0], nbUnlockedDecks); + deckManager->updateMetaDataList(&opponentDeckList, true); + opponentMenu->Add(MENUITEM_CANCEL, "Cancel", _("Choose a different player deck").c_str()); + opponentDeckList.clear(); + } +} + +void GameStateDuel::Update(float dt) +{ + switch (mGamePhase) + { + case DUEL_STATE_ERROR_NO_DECK: + if (JGE_BTN_OK == mEngine->ReadButton()) mParent->SetNextState(GAME_STATE_DECK_VIEWER); + break; + + case DUEL_STATE_DECK1_DETAILED_INFO: + case DUEL_STATE_DECK2_DETAILED_INFO: + popupScreen->Update(dt); + break; + + case DUEL_STATE_CHOOSE_DECK1: + if (mParent->gameType == GAME_TYPE_MOMIR) + { + rules = NEW Rules("momir.txt"); + mGamePhase = DUEL_STATE_PLAY; + } + else if (mParent->gameType == GAME_TYPE_RANDOM1) + { + rules = NEW Rules("random1.txt"); + mGamePhase = DUEL_STATE_PLAY; + } + else if (mParent->gameType == GAME_TYPE_RANDOM2) + { + rules = NEW Rules("random2.txt"); + mGamePhase = DUEL_STATE_PLAY; + } +#ifdef TESTSUITE + else if (mParent->players[1] == PLAYER_TYPE_TESTSUITE) + { + if (testSuite && testSuite->loadNext()) + { + rules = NEW Rules("testsuite.txt"); + loadTestSuitePlayers(); + mGamePhase = DUEL_STATE_PLAY; + testSuite->pregameTests(); + testSuite->initGame(); + } + else + { + if (!game) + { + mGamePhase = DUEL_STATE_ERROR; + } + else + { + mGamePhase = DUEL_STATE_END; + } + } + } +#endif + else + { + if (!rules) rules = NEW Rules("mtg.txt"); + if (mParent->players[0] == PLAYER_TYPE_HUMAN) + { + if (!popupScreen || popupScreen->isClosed()) deckmenu->Update(dt); + } + else + { + loadPlayer(0); + mGamePhase = DUEL_STATE_CHOOSE_DECK2; + } + } + break; + case DUEL_STATE_CHOOSE_DECK1_TO_2: + if (deckmenu->isClosed()) + mGamePhase = DUEL_STATE_CHOOSE_DECK2; + else + deckmenu->Update(dt); + break; + case DUEL_STATE_CHOOSE_DECK2: + if (mParent->players[1] == PLAYER_TYPE_HUMAN) + deckmenu->Update(dt); + else + { + if (mParent->players[0] == PLAYER_TYPE_HUMAN) + { + ConstructOpponentMenu(); + opponentMenu->Update(dt); + } + else + { + loadPlayer(1); + mGamePhase = DUEL_STATE_PLAY; + } + } + break; + case DUEL_STATE_CHOOSE_DECK2_TO_PLAY: + if (mParent->players[1] == PLAYER_TYPE_HUMAN) + { + if (deckmenu->isClosed()) + mGamePhase = DUEL_STATE_PLAY; + else + deckmenu->Update(dt); + } + else + { + ConstructOpponentMenu(); + if (opponentMenu->isClosed()) + mGamePhase = DUEL_STATE_PLAY; + else + opponentMenu->Update(dt); + } + break; + case DUEL_STATE_PLAY: + if (!game) + { + GameObserver::Init(mPlayers, 2); + game = GameObserver::GetInstance(); + game->startGame(rules); + if (mParent->gameType == GAME_TYPE_MOMIR) + { + game->addObserver(NEW MTGMomirRule(-1, mParent->collection)); + } + + //start of in game music code + musictrack = ""; + //check opponent id and choose the music track based on it + if (OpponentsDeckid) + { + char temp[4096]; + sprintf(temp, "ai_baka_music%i.mp3", OpponentsDeckid); + musictrack.assign(temp); + } + else if (mParent->gameType == GAME_TYPE_CLASSIC) + musictrack = "ai_baka_music.mp3"; + else if (mParent->gameType == GAME_TYPE_MOMIR) + musictrack = "ai_baka_music_momir.mp3"; + else if (mParent->gameType == GAME_TYPE_RANDOM1 || mParent->gameType == GAME_TYPE_RANDOM2) musictrack + = "ai_baka_music_random.mp3"; + + if (!MusicExist(musictrack)) musictrack = "ai_baka_music.mp3"; + + GameApp::playMusic(musictrack); + } + game->Update(dt); + if (game->gameOver) + { + if (game->players[1]->playMode != Player::MODE_TEST_SUITE) credits->compute(game->players[0], game->players[1], mParent); + mGamePhase = DUEL_STATE_END; +#ifdef TESTSUITE + if (mParent->players[1] == PLAYER_TYPE_TESTSUITE) + { + if (testSuite->loadNext()) + { + loadTestSuitePlayers(); + mGamePhase = DUEL_STATE_PLAY; + testSuite->initGame(); + } + else + mGamePhase = DUEL_STATE_END; + } + else +#endif + if (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU) + { + End(); + Start(); + } + } + if (mEngine->GetButtonClick(JGE_BTN_MENU)) + { + if (!menu) + { + menu = NEW SimpleMenu(DUEL_MENU_GAME_MENU, this, Fonts::MENU_FONT, SCREEN_WIDTH / 2 - 100, 25, + game->players[1]->deckName.c_str()); + int cardsinhand = game->players[0]->game->hand->nb_cards; + + //almosthumane - mulligan + if ((game->turn < 1) && (cardsinhand != 0) && game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN + && game->players[0]->game->inPlay->nb_cards == 0 && game->players[0]->game->graveyard->nb_cards == 0 + && game->players[0]->game->exile->nb_cards == 0) //1st Play Check + //IF there was no play at the moment automatically mulligan + { + menu->Add(MENUITEM_MULLIGAN, "Mulligan"); + } + //END almosthumane - mulligan + menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); + menu->Add(MENUITEM_CANCEL, "Cancel"); + } + mGamePhase = DUEL_STATE_MENU; + } + break; + case DUEL_STATE_MENU: + menu->Update(dt); + break; + case DUEL_STATE_CANCEL: + menu->Update(dt); + if (menu->isClosed()) + { + mGamePhase = DUEL_STATE_PLAY; + SAFE_DELETE(menu); + } + break; + case DUEL_STATE_BACK_TO_MAIN_MENU: + if (menu) + { + menu->Update(dt); + if (menu->isClosed()) + { + PlayerData * playerdata = NEW PlayerData(mParent->collection); + playerdata->taskList->passOneDay(); + playerdata->taskList->save(); + SAFE_DELETE(playerdata); + SAFE_DELETE(menu); + } + } + mParent->DoTransition(TRANSITION_FADE, GAME_STATE_MENU); + + break; + default: + if (JGE_BTN_OK == mEngine->ReadButton()) mParent->SetNextState(GAME_STATE_MENU); + } +} + +void GameStateDuel::Render() +{ + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + JRenderer * r = JRenderer::GetInstance(); + r->ClearScreen(ARGB(0,0,0,0)); + + if (game) game->Render(); + + switch (mGamePhase) + { + case DUEL_STATE_END: + { + JRenderer * r = JRenderer::GetInstance(); + r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(200,0,0,0)); + credits->Render(); +#ifdef TESTSUITE + if (mParent->players[1] == PLAYER_TYPE_TESTSUITE) + { + r->ClearScreen(ARGB(255,0,0,0)); + char buf[4096]; + int nbFailed = testSuite->nbFailed; + int nbTests = testSuite->nbTests; + if (!nbFailed) + { + sprintf(buf, "All %i tests successful!", nbTests); + } + else + { + sprintf(buf, "%i tests out of %i FAILED!", nbFailed, nbTests); + } + mFont->SetColor(ARGB(255,255,255,255)); + mFont->DrawString(buf,0,SCREEN_HEIGHT/2); + nbFailed = testSuite->nbAIFailed; + nbTests = testSuite->nbAITests; + if (nbTests) + { + if (!nbFailed) + { + sprintf(buf, "AI Tests: All %i tests successful!", nbTests); + } + else + { + sprintf(buf, "AI Tests: %i tests out of %i FAILED!", nbFailed, nbTests); + } + mFont->DrawString(buf,0,SCREEN_HEIGHT/2+20); + } + } +#endif + break; + } + case DUEL_STATE_ERROR: + { + r->ClearScreen(ARGB(200,0,0,0)); + mFont->DrawString(_("AN ERROR OCCURRED, CHECK FILE NAMES").c_str(), 0, SCREEN_HEIGHT / 2); + break; + } + case DUEL_STATE_CHOOSE_DECK1: + case DUEL_STATE_CHOOSE_DECK1_TO_2: + case DUEL_STATE_CHOOSE_DECK2: + case DUEL_STATE_CHOOSE_DECK2_TO_PLAY: + case DUEL_STATE_DECK1_DETAILED_INFO: + case DUEL_STATE_DECK2_DETAILED_INFO: + if (mParent->gameType != GAME_TYPE_CLASSIC) + mFont->DrawString(_("LOADING DECKS").c_str(), 0, SCREEN_HEIGHT / 2); + else + { + if (opponentMenu) + opponentMenu->Render(); + else if (deckmenu && !deckmenu->isClosed()) deckmenu->Render(); + + if (menu) menu->Render(); + + if (popupScreen && !popupScreen->isClosed()) popupScreen->Render(); + } + break; + case DUEL_STATE_ERROR_NO_DECK: + mFont->DrawString(_("NO DECK AVAILABLE,").c_str(), 0, SCREEN_HEIGHT / 2); + mFont->DrawString(_("PRESS CIRCLE TO GO TO THE DECK EDITOR!").c_str(), 0, SCREEN_HEIGHT / 2 + 20); + break; + case DUEL_STATE_MENU: + case DUEL_STATE_CANCEL: + case DUEL_STATE_BACK_TO_MAIN_MENU: + if (game) + { + r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(100,0,0,0)); + char buffer[4096]; + sprintf(buffer, _("Turn:%i").c_str(), game->turn); + mFont->SetColor(ARGB(255,255,255,255)); + mFont->DrawString(buffer, SCREEN_WIDTH / 2, 0, JGETEXT_CENTER); + } + if (menu) menu->Render(); + } +} + +void GameStateDuel::ButtonPressed(int controllerId, int controlId) +{ + int deckNumber = controlId; + DeckManager * deckManager = DeckManager::GetInstance(); + int aiDeckSize = deckManager->getAIDeckOrderList()->size(); + switch (controllerId) + { + + case DUEL_MENU_DETAILED_DECK1_INFO: + if ((popupScreen || deckmenu->showDetailsScreen())) + { + DeckMetaData* selectedDeck = deckmenu->getSelectedDeck(); + if (!popupScreen->isClosed()) + { + popupScreen->Close(); + mGamePhase = DUEL_STATE_CHOOSE_DECK1; + SAFE_DELETE( popupScreen ); + } + else + { + popupScreen->Update(selectedDeck); + popupScreen->Render(); + } + } + break; + case DUEL_MENU_DETAILED_DECK2_INFO: + if ((popupScreen || opponentMenu->showDetailsScreen())) + { + DeckMetaData* selectedDeck = opponentMenu->getSelectedDeck(); + if (!popupScreen->isClosed()) + { + popupScreen->Close(); + mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY; + SAFE_DELETE( popupScreen ); + } + else + { + popupScreen->Update(selectedDeck); + popupScreen->Render(); + } + } + break; + + case DUEL_MENU_CHOOSE_OPPONENT: + + switch (controlId) + { + case MENUITEM_RANDOM_AI: + loadPlayer(1); + opponentMenu->Close(); + mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY; + break; + default: + // cancel option. return to player deck selection + + if (controlId == MENUITEM_CANCEL) + { + opponentMenu->Close(); + deckmenu->Close(); + mParent->SetNextState(DUEL_STATE_CHOOSE_DECK1); + mGamePhase = DUEL_STATE_CHOOSE_DECK1; + break; + } + + else if (controlId == MENUITEM_MORE_INFO && opponentMenu->showDetailsScreen()) + { + DeckMetaData* selectedDeck = opponentMenu->getSelectedDeck(); + if (!popupScreen) + { + popupScreen = NEW SimplePopup(DUEL_MENU_DETAILED_DECK2_INFO, this, Fonts::MAIN_FONT, "Detailed Information", + selectedDeck, mParent->collection); + popupScreen->Render(); + selectedAIDeckId = selectedDeck->getDeckId(); + } + else + { + popupScreen->Update(selectedDeck); + } + mGamePhase = DUEL_STATE_DECK2_DETAILED_INFO; + break; + } + else if (controlId == MENUITEM_MORE_INFO && !opponentMenu->showDetailsScreen()) + { + // do nothing, ignore all key requests until popup is dismissed. + break; + } + else if (controlId != MENUITEM_EVIL_TWIN && aiDeckSize > 0) // evil twin + deckNumber = deckManager->getAIDeckOrderList()->at(controlId - 1)->getDeckId(); + loadPlayer(1, deckNumber, 1); + OpponentsDeckid = deckNumber; + opponentMenu->Close(); + mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY; + break; + } + break; + + case DUEL_MENU_CHOOSE_DECK: + + if (controlId == MENUITEM_RANDOM_PLAYER) // Random Player Deck Selection + { + vector * playerDeckList = deckManager->getPlayerDeckOrderList(); + deckNumber = playerDeckList->at(WRand() * 1001 % (playerDeckList->size()))->getDeckId(); + loadPlayer(0, deckNumber); + deckmenu->Close(); + mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY; + break; + } + else if (controlId == MENUITEM_MAIN_MENU || controlId == MENUITEM_CANCEL) // user clicked on "Cancel" + { + if (deckmenu) deckmenu->Close(); + mGamePhase = DUEL_STATE_BACK_TO_MAIN_MENU; + break; + } + else if (controlId == MENUITEM_MORE_INFO && deckmenu->showDetailsScreen()) + { + DeckMetaData* selectedDeck = deckmenu->getSelectedDeck(); + if (!popupScreen) + { + popupScreen = NEW SimplePopup(DUEL_MENU_DETAILED_DECK1_INFO, this, Fonts::MAIN_FONT, "Detailed Information", + selectedDeck, mParent->collection); + popupScreen->Render(); + selectedPlayerDeckId = deckmenu->getSelectedDeckId(); + } + else + { + popupScreen->Update(selectedDeck); + } + mGamePhase = DUEL_STATE_DECK1_DETAILED_INFO; + break; + } + else if (controlId == MENUITEM_MORE_INFO) + { + // do nothing + break; + } + if (controlId < 0) + { + mParent->SetNextState(GAME_STATE_DECK_VIEWER); + return; + } + if (mGamePhase == DUEL_STATE_CHOOSE_DECK1) + { + vector * playerDeck = deckManager->getPlayerDeckOrderList(); + if (!premadeDeck && controlId > 0) + deckNumber = playerDeck->at(controlId - 1)->getDeckId(); + loadPlayer(0, deckNumber); + deckmenu->Close(); + mGamePhase = DUEL_STATE_CHOOSE_DECK1_TO_2; + playerDeck = NULL; + } + else + { + loadPlayer(1, controlId); + deckmenu->Close(); + mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY; + } + break; + + default: + + switch (controlId) + { + + case MENUITEM_MAIN_MENU: + menu->Close(); + mGamePhase = DUEL_STATE_BACK_TO_MAIN_MENU; + break; + case MENUITEM_CANCEL: + menu->Close(); + mGamePhase = DUEL_STATE_CANCEL; + break; + case MENUITEM_MULLIGAN: + //almosthumane - mulligan + + + int cardsinhand = game->players[0]->game->hand->nb_cards; + + for (int i = 0; i < cardsinhand; i++) //Discard hand + game->currentPlayer->game->putInZone(game->currentPlayer->game->hand->cards[0], + game->currentPlayer->game->hand, + game->currentPlayer->game->library); + + game->currentPlayer->game->library->shuffle(); //Shuffle + + for (int i = 0; i < (cardsinhand - 1); i++) + game->draw(); //Draw hand with 1 less card penalty //almhum + menu->Close(); + mGamePhase = DUEL_STATE_CANCEL; + break; + + //END almosthumane - mulligan + } + + } +} diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 53558e155..5bf3457e0 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -1,1237 +1,1237 @@ -#include "PrecompiledHeader.h" - -#include "MTGDeck.h" -#include "utils.h" -#include "Subtypes.h" -#include "Translate.h" -#include "DeckMetaData.h" -#include "PriceList.h" -#include "WDataSrc.h" -#include "MTGPack.h" -#include "utils.h" - -#if defined (WIN32) || defined (LINUX) -#include -#endif - -static inline int getGrade(int v) -{ - switch (v) - { - case 'P': - case 'p': - return Constants::GRADE_SUPPORTED; - case 'R': - case 'r': - return Constants::GRADE_BORDERLINE; - case 'O': - case 'o': - return Constants::GRADE_UNOFFICIAL; - case 'A': - case 'a': - return Constants::GRADE_CRAPPY; - case 'S': - case 's': - return Constants::GRADE_UNSUPPORTED; - case 'N': - case 'n': - return Constants::GRADE_DANGEROUS; - } - return 0; -} - -//MTGAllCards -int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primitive) -{ - if ('#' == s[0]) return 0; - size_t i = s.find_first_of('='); - if (i == string::npos || 0 == i) - { - DebugTrace("MTGDECK: Bad Line:\n\t" << s); - return 0; - } - - char* key = const_cast (s.c_str()); // I know what I'm doing, let me do it - key[i] = 0; - char* val = key + i + 1; - - switch (key[0]) - { - case 'a': - if (0 == strcmp("auto", key)) - { - if (!primitive) primitive = NEW CardPrimitive(); - primitive->addMagicText(val); - } - else if (0 == strncmp("auto", key, 4)) - { - if (!primitive) primitive = NEW CardPrimitive(); - primitive->addMagicText(val, key + 4); - } - else if (0 == strcmp("alias", key)) - { - if (!primitive) primitive = NEW CardPrimitive(); - primitive->alias = atoi(val); - } - else if (0 == strcmp("abilities", key)) - { - if (!primitive) primitive = NEW CardPrimitive(); - string value = val; - //Specific Abilities - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - while (value.size()) - { - string attribute; - size_t found2 = value.find(','); - if (found2 != string::npos) - { - attribute = value.substr(0, found2); - value = value.substr(found2 + 1); - } - else - { - attribute = value; - value = ""; - } - - for (int j = Constants::NB_BASIC_ABILITIES - 1; j >= 0; --j) - { - size_t found = attribute.find(Constants::MTGBasicAbilities[j]); - if (found != string::npos) - { - primitive->basicAbilities[j] = 1; - break; - } - } - } - } - break; - - case 'c': //color - if (!primitive) primitive = NEW CardPrimitive(); - { - string value = val; - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - vector values = split(value, ','); - int removeAllOthers = 1; - for (size_t values_i = 0; values_i < values.size(); ++values_i) - { - primitive->setColor(values[values_i], removeAllOthers); - removeAllOthers = 0; - } - } - break; - - case 'g': //grade - if (s.size() - i - 1 > 2) currentGrade = getGrade(val[2]); - break; - - case 'k': //kicker - if (!primitive) primitive = NEW CardPrimitive(); - if (ManaCost * cost = primitive->getManaCost()) - { - string value = val; - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - cost->kicker = ManaCost::parseManaCost(value); - } - break; - - case 'o': //othercost - if (!primitive) primitive = NEW CardPrimitive(); - if(key[5] == 'r')//otherrestrictions - { - string value = val; - primitive->setOtherRestrictions(value); - - } - else - { - if (ManaCost * cost = primitive->getManaCost()) - { - string value = val; - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - cost->alternative = ManaCost::parseManaCost(value); - } - } - break; - - case 'b': //buyback - if (!primitive) primitive = NEW CardPrimitive(); - if (ManaCost * cost = primitive->getManaCost()) - { - string value = val; - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - cost->BuyBack = ManaCost::parseManaCost(value); - } - break; - case 'f': //flashback//morph - { - if (!primitive) primitive = NEW CardPrimitive(); - if(ManaCost * cost = primitive->getManaCost()) - { - if( s.find("facedown") != string::npos)//morph - { - string value = val; - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - cost->morph = ManaCost::parseManaCost(value); - } - else - { - string value = val; - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - cost->FlashBack = ManaCost::parseManaCost(value); - } - } - break; - } - case 'i': //id - if (!card) card = NEW MTGCard(); - card->setMTGId(atoi(val)); - break; - - case 'm': //mana - if (!primitive) primitive = NEW CardPrimitive(); - { - string value = val; - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - primitive->setManaCost(value); - } - break; - - case 'n': //name - if (!primitive) primitive = NEW CardPrimitive(); - if (0 == strcmp("Bloodrock Cyclops", val)) cout << "val" << endl; - primitive->setName(val); - break; - - case 'p': - if ('r' == key[1]) - { // primitive - if (!card) card = NEW MTGCard(); - map::iterator it = primitives.find(val); - if (it != primitives.end()) card->setPrimitive(it->second); - } - else - { //power - if (!primitive) primitive = NEW CardPrimitive(); - primitive->setPower(atoi(val)); - } - break; - - case 'r': //retrace/rarity - if('s' == key[2] && 't' == key[3])//restrictions - { - if (!primitive) primitive = NEW CardPrimitive(); - string value = val; - primitive->setRestrictions(CardPrimitive::NO_RESTRICTION); - primitive->hasRestriction = false; - if (value.find("control two or more vampires") != string::npos) - primitive->setRestrictions(CardPrimitive::VAMPIRES); - if (value.find("control less creatures") != string::npos) - primitive->setRestrictions(CardPrimitive::LESS_CREATURES); - if (value.find("control snow land") != string::npos) - primitive->setRestrictions(CardPrimitive::SNOW_LAND_INPLAY); - if (value.find("casted a spell") != string::npos) - primitive->setRestrictions(CardPrimitive::CASTED_A_SPELL); - if (value.find("one of a kind") != string::npos) - primitive->setRestrictions(CardPrimitive::ONE_OF_AKIND); - if (value.find("fourth turn") != string::npos) - primitive->setRestrictions(CardPrimitive::FOURTHTURN); - if (value.find("before battle damage") != string::npos) - primitive->setRestrictions(CardPrimitive::BEFORECOMBATDAMAGE); - if (value.find("after battle") != string::npos) - primitive->setRestrictions(CardPrimitive::AFTERCOMBAT); - if (value.find("during battle") != string::npos) - primitive->setRestrictions(CardPrimitive::DURINGCOMBAT); - if (value.find("myturnonly") != string::npos) - primitive->setRestrictions(CardPrimitive::PLAYER_TURN_ONLY); - if (value.find("opponentturnonly") != string::npos) - primitive->setRestrictions(CardPrimitive::OPPONENT_TURN_ONLY); - if (value.find("assorcery") != string::npos) - primitive->setRestrictions(CardPrimitive::AS_SORCERY); - string types[] = { "my", "opponent", "" }; - int starts[] = { CardPrimitive::MY_BEFORE_BEGIN, CardPrimitive::OPPONENT_BEFORE_BEGIN, CardPrimitive::BEFORE_BEGIN }; - for (int j = 0; j < 3; ++j) - { - size_t found = value.find(types[j]); - if (found != string::npos) - { - for (int i = 0; i < Constants::NB_MTG_PHASES; i++) - { - string toFind = types[j]; - toFind.append(Constants::MTGPhaseCodeNames[i]).append("only"); - found = value.find(toFind); - if (found != string::npos) - { - if(primitive->hasRestriction == false) - { - primitive->setRestrictions(starts[j] + i); - primitive->hasRestriction = true; - } - } - } - } - } - } - else if ('e' == key[1] && 't' == key[2]) - { //retrace - if (!primitive) primitive = NEW CardPrimitive(); - if (ManaCost * cost = primitive->getManaCost()) - { - string value = val; - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - cost->Retrace = ManaCost::parseManaCost(value); - } - } - else if (s.find("rar") != string::npos) - {//rarity - if (!card) card = NEW MTGCard(); - card->setRarity(val[0]); - } - break; - case 's': //subtype - if (!primitive) primitive = NEW CardPrimitive(); - while (true) - { - char* found = strchr(val, ' '); - if (found) - { - string value(val, found - val); - primitive->setSubtype(value); - val = found + 1; - } - else - { - primitive->setSubtype(val); - break; - } - } - break; - - case 't': - if (!primitive) primitive = NEW CardPrimitive(); - if (0 == strcmp("target", key)) - { - string value = val; - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - primitive->spellTargetType = value; - } - else if (0 == strcmp("text", key)) - primitive->setText(val); - else if (0 == strcmp("type", key)) - { - while (true) - { - char* found = strchr(val, ' '); - if (found) - { - string value(val, found - val); - primitive->setType(value); - val = found + 1; - } - else - { - primitive->setType(val); - break; - } - } - } - else if (0 == strcmp("toughness", key)) primitive->setToughness(atoi(val)); - break; - - default: - DebugTrace( endl << "MTGDECK Parsing Error: " << " [" << primitive->getName() << "]" << s << std::endl); - break; - } - - tempPrimitive = primitive; - tempCard = card; - - return i; - -} - -void MTGAllCards::initCounters() -{ - for (int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - colorsCount[i] = NULL; - } -} - -void MTGAllCards::init() -{ - tempCard = NULL; - tempPrimitive = NULL; - total_cards = 0; - initCounters(); -} - -int MTGAllCards::load(const char * config_file, const char * set_name, int autoload) -{ - conf_read_mode = 0; - const int set_id = set_name ? setlist.Add(set_name) : MTGSets::INTERNAL_SET; - MTGSetInfo *si = setlist.getInfo(set_id); - - wagic::ifstream setFile(config_file, ios::in | ios::ate); - if (!setFile) return total_cards; - - streampos fileSize = setFile.tellg(); - setFile.seekg(0, ios::beg); - - std::string contents; - contents.resize((std::string::size_type) fileSize); - setFile.read(&contents[0], fileSize); - std::stringstream stream(contents); - - string s; - - while (true) - { - if (!std::getline(stream, s)) return total_cards; - if (!s.size()) continue; - - if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); // Handle DOS files - switch (conf_read_mode) - { - case MTGAllCards::READ_ANYTHING: - if (s[0] == '[') - { - currentGrade = Constants::GRADE_SUPPORTED; // Default value - conf_read_mode = ('m' == s[1]) ? MTGAllCards::READ_METADATA : MTGAllCards::READ_CARD; // M for metadata. - } - else - { - //Global grade for file, to avoid reading the entire file if unnnecessary - if (s[0] == 'g' && s.size() > 8) - { - int fileGrade = getGrade(s[8]); - int maxGrade = options[Options::MAX_GRADE].number; - if (!maxGrade) maxGrade = Constants::GRADE_BORDERLINE; //Default setting for grade is borderline? - if (fileGrade > maxGrade) - { - return total_cards; - } - } - } - continue; - case MTGAllCards::READ_METADATA: - if (s[0] == '[' && s[1] == '/') - conf_read_mode = MTGAllCards::READ_ANYTHING; - else if (si) si->processConfLine(s); - continue; - case MTGAllCards::READ_CARD: - if (s[0] == '[' && s[1] == '/') - { - conf_read_mode = MTGAllCards::READ_ANYTHING; - if (tempPrimitive) tempPrimitive = addPrimitive(tempPrimitive, tempCard); - if (tempCard) - { - if (tempPrimitive) tempCard->setPrimitive(tempPrimitive); - addCardToCollection(tempCard, set_id); - } - tempCard = NULL; - tempPrimitive = NULL; - } - else - { - processConfLine(s, tempCard, tempPrimitive); - } - continue; - } - } - return total_cards; -} - -MTGAllCards::MTGAllCards() -{ - init(); -} - -MTGAllCards::~MTGAllCards() -{ - //Why don't we call destroyAllCards from here ??? -} - -void MTGAllCards::destroyAllCards() -{ - - for (map::iterator it = collection.begin(); it != collection.end(); it++) - delete (it->second); - collection.clear(); - ids.clear(); - - for (map::iterator it = primitives.begin(); it != primitives.end(); it++) - delete (it->second); - primitives.clear(); - -} - -MTGAllCards::MTGAllCards(const char * config_file, const char * set_name) -{ - init(); - load(config_file, set_name, 0); -} - -int MTGAllCards::randomCardId() -{ - int id = (rand() % ids.size()); - return ids[id]; -} - -int MTGAllCards::countBySet(int setId) -{ - int result = 0; - map::iterator it; - - for (it = collection.begin(); it != collection.end(); it++) - { - MTGCard * c = it->second; - if (c->setId == setId) - { - result++; - } - } - return result; -} - -//TODO more efficient way ? -int MTGAllCards::countByType(const char * _type) -{ - int result = 0; - map::iterator it; - for (it = collection.begin(); it != collection.end(); it++) - { - MTGCard * c = it->second; - if (c->data->hasType(_type)) - { - result++; - } - } - return result; -} - -int MTGAllCards::countByColor(int color) -{ - if (colorsCount[color] == 0) - { - for (int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - colorsCount[i] = 0; - } - map::iterator it; - for (it = collection.begin(); it != collection.end(); it++) - { - MTGCard * c = it->second; - int j = c->data->getColor(); - - colorsCount[j]++; - } - } - return colorsCount[color]; -} - -int MTGAllCards::totalCards() -{ - return (total_cards); -} - -bool MTGAllCards::addCardToCollection(MTGCard * card, int setId) -{ - card->setId = setId; - int newId = card->getId(); - if (collection.find(newId) != collection.end()) - { -#if defined (_DEBUG) - string cardName = card->data ? card->data->name : card->getImageName(); - string setName = setId != -1 ? setlist.getInfo(setId)->getName() : ""; - DebugTrace("warning, card id collision! : " << newId << " -> " << cardName << "(" << setName << ")"); -#endif - SAFE_DELETE(card); - return false; - } - - //Don't add cards that don't have a primitive - if (!card->data) - { - SAFE_DELETE(card); - return false; - } - ids.push_back(newId); - - collection[newId] = card; //Push card into collection. - MTGSetInfo * si = setlist.getInfo(setId); - if (si) si->count(card); //Count card in set info - ++total_cards; - return true; -} - -CardPrimitive * MTGAllCards::addPrimitive(CardPrimitive * primitive, MTGCard * card) -{ - int maxGrade = options[Options::MAX_GRADE].number; - if (!maxGrade) maxGrade = Constants::GRADE_BORDERLINE; //Default setting for grade is borderline? - if (currentGrade > maxGrade) - { - SAFE_DELETE(primitive); - return NULL; - } - string key; - if (card) - { - std::stringstream ss; - ss << card->getId(); - ss >> key; - } - else - key = primitive->name; - if (primitives.find(key) != primitives.end()) - { - //ERROR - //Todo move the deletion somewhere else ? - DebugTrace("MTGDECK: primitives conflict: "<< key); - SAFE_DELETE(primitive); - return NULL; - } - //translate cards text - Translator * t = Translator::GetInstance(); - map::iterator it = t->tempValues.find(primitive->name); - if (it != t->tempValues.end()) - { - primitive->setText(it->second); - } - - //Legacy: - //For the Deck editor, we need Lands and Artifact to be colors... - if (primitive->hasType(Subtypes::TYPE_LAND)) primitive->setColor(Constants::MTG_COLOR_LAND); - if (primitive->hasType(Subtypes::TYPE_ARTIFACT)) primitive->setColor(Constants::MTG_COLOR_ARTIFACT); - - primitives[key] = primitive; - return primitive; -} - -MTGCard * MTGAllCards::getCardById(int id) -{ - map::iterator it = collection.find(id); - if (it != collection.end()) - { - return (it->second); - } - return 0; -} - -MTGCard * MTGAllCards::_(int index) -{ - if (index >= total_cards) return NULL; - return getCardById(ids[index]); -} - -MTGCard * MTGAllCards::getCardByName(string name) -{ - if (!name.size()) return NULL; - if (name[0] == '#') return NULL; - - int cardnb = atoi(name.c_str()); - if (cardnb) - { - return getCardById(cardnb); - } - - std::transform(name.begin(), name.end(), name.begin(), ::tolower); - int setId = -1; - size_t found = name.find(" ("); - if (found != string::npos) - { - size_t end = name.find(")"); - string setName = name.substr(found + 2, end - found - 2); - trim(setName); - name = name.substr(0, found); - trim(name); - setId = setlist[setName]; - } - map::iterator it; - for (it = collection.begin(); it != collection.end(); it++) - { - MTGCard * c = it->second; - if (setId != -1 && setId != c->setId) continue; - string cardName = c->data->name; - std::transform(cardName.begin(), cardName.end(), cardName.begin(), ::tolower); - if (cardName.compare(name) == 0) return c; - - } - return NULL; -} - -//MTGDeck -MTGDeck::MTGDeck(MTGAllCards * _allcards) -{ - total_cards = 0; - database = _allcards; - filename = ""; - meta_name = ""; -} - -int MTGDeck::totalPrice() -{ - int total = 0; - PriceList * pricelist = NEW PriceList(JGE_GET_RES("settings/prices.dat").c_str(), GameApp::collection); - map::iterator it; - for (it = cards.begin(); it != cards.end(); it++) - { - int nb = it->second; - if (nb) total += pricelist->getPrice(it->first); - } - SAFE_DELETE(pricelist); - return total; -} - -MTGDeck::MTGDeck(const char * config_file, MTGAllCards * _allcards, int meta_only) -{ - total_cards = 0; - database = _allcards; - filename = config_file; - size_t slash = filename.find_last_of("/"); - size_t dot = filename.find("."); - meta_name = filename.substr(slash + 1, dot - slash - 1); - wagic::ifstream file(config_file); - std::string s; - - if (file) - { - while (std::getline(file, s)) - { - if (!s.size()) continue; - if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files - if (s[0] == '#') - { - size_t found = s.find("NAME:"); - if (found != string::npos) - { - meta_name = s.substr(found + 5); - continue; - } - found = s.find("DESC:"); - if (found != string::npos) - { - if (meta_desc.size()) meta_desc.append("\n"); - meta_desc.append(s.substr(found + 5)); - continue; - } - continue; - } - if (meta_only) break; - int cardnb = atoi(s.c_str()); - if (cardnb) - { - add(cardnb); - } - else - { - int nb = 1; - size_t found = s.find(" *"); - if (found != string::npos) - { - nb = atoi(s.substr(found + 2).c_str()); - s = s.substr(0, found); - } - MTGCard * card = database->getCardByName(s); - if (card) - { - for (int i = 0; i < nb; i++) - { - add(card); - } - } - else - { - DebugTrace("could not find Card matching name: " << s); - } - } - } - file.close(); - } - else - { - //TODO Error management - } -} - -int MTGDeck::totalCards() -{ - return total_cards; -} - -MTGCard * MTGDeck::getCardById(int mtgId) -{ - return database->getCardById(mtgId); -} - -int MTGDeck::addRandomCards(int howmany, int * setIds, int nbSets, int rarity, const char * _subtype, int * colors, int nbcolors) -{ - if (howmany <= 0) return 1; - - int unallowedColors[Constants::MTG_NB_COLORS + 1]; - for (int i = 0; i < Constants::MTG_NB_COLORS; ++i) - { - if (nbcolors) - unallowedColors[i] = 1; - else - unallowedColors[i] = 0; - } - for (int i = 0; i < nbcolors; ++i) - { - unallowedColors[colors[i]] = 0; - } - - int collectionTotal = database->totalCards(); - if (!collectionTotal) return 0; - - char subtype[4096]; - if (_subtype) sprintf(subtype, "%s", _subtype); - - vector subcollection; - int subtotal = 0; - for (int i = 0; i < collectionTotal; i++) - { - MTGCard * card = database->_(i); - int r = card->getRarity(); - if (r != Constants::RARITY_T && (rarity == -1 || r == rarity) && // remove tokens - card->setId != MTGSets::INTERNAL_SET && //remove cards that are defined in primitives. Those are workarounds (usually tokens) and should only be used internally - (!_subtype || card->data->hasSubtype(subtype))) - { - int ok = 0; - - if (!nbSets) ok = 1; - for (int j = 0; j < nbSets; ++j) - { - if (card->setId == setIds[j]) - { - ok = 1; - break; - } - } - - if (ok) - { - for (int j = 0; j < Constants::MTG_NB_COLORS; ++j) - { - if (unallowedColors[j] && card->data->hasColor(j)) - { - ok = 0; - break; - } - } - } - - if (ok) - { - subcollection.push_back(card->getId()); - subtotal++; - } - } - } - if (subtotal == 0) - { - if (rarity == Constants::RARITY_M) return addRandomCards(howmany, setIds, nbSets, Constants::RARITY_R, _subtype, colors, - nbcolors); - return 0; - } - for (int i = 0; i < howmany; i++) - { - int id = (rand() % subtotal); - add(subcollection[id]); - } - return 1; -} - -int MTGDeck::add(MTGDeck * deck) -{ - map::iterator it; - for (it = deck->cards.begin(); it != deck->cards.end(); it++) - { - for (int i = 0; i < it->second; i++) - { - add(it->first); - } - } - return deck->totalCards(); -} - -int MTGDeck::add(int cardid) -{ - if (!database->getCardById(cardid)) return 0; - if (cards.find(cardid) == cards.end()) - { - cards[cardid] = 1; - } - else - { - cards[cardid]++; - } - ++total_cards; - //initCounters(); - return total_cards; -} - -int MTGDeck::add(MTGCard * card) -{ - if (!card) return 0; - return (add(card->getId())); -} - -int MTGDeck::complete() -{ - /* (PSY) adds cards to the deck/collection. Makes sure that the deck - or collection has at least 4 of every implemented card. Does not - change the number of cards of which already 4 or more are present. */ - int id, n; - bool StypeIsNothing; - size_t databaseSize = database->ids.size(); - for (size_t it = 0; it < databaseSize; it++) - { - id = database->ids[it]; - StypeIsNothing = false; - if (database->getCardById(id)->data->hasType("nothing")) - { - StypeIsNothing = true; - } - if (!StypeIsNothing ) - { - if (cards.find(id) == cards.end()) - { - cards[id] = 4; - total_cards += 4; - } - else - { - n = cards[id]; - if (n < 4) - { - total_cards += 4 - n; - cards[id] = 4; - } - } - } - } - return 1; -} - -int MTGDeck::removeAll() -{ - total_cards = 0; - cards.clear(); - //initCounters(); - return 1; -} - -int MTGDeck::remove(int cardid) -{ - if (cards.find(cardid) == cards.end() || cards[cardid] == 0) return 0; - cards[cardid]--; - total_cards--; - //initCounters(); - return 1; -} - -int MTGDeck::remove(MTGCard * card) -{ - if (!card) return 0; - return (remove(card->getId())); -} - -int MTGDeck::save() -{ - return save(filename, false, meta_name, meta_desc); -} - -int MTGDeck::save(string destFileName, bool useExpandedDescriptions, string &deckTitle, string &deckDesc) -{ - string tmp = destFileName; - tmp.append(".tmp"); //not thread safe - std::ofstream file(tmp.c_str()); - char writer[512]; - if (file) - { - DebugTrace("Saving Deck: " << deckTitle << " to " << destFileName ); - if (meta_name.size()) - { - file << "#NAME:" << deckTitle << '\n'; - } - - if (meta_desc.size()) - { - size_t found = 0; - string desc = deckDesc; - found = desc.find_first_of("\n"); - while (found != string::npos) - { - file << "#DESC:" << desc.substr(0, found + 1); - desc = desc.substr(found + 1); - found = desc.find_first_of("\n"); - } - file << "#DESC:" << desc << "\n"; - } - - if (useExpandedDescriptions) - { - map::iterator it; - for (it = cards.begin(); it != cards.end(); it++) - { - int nbCards = it->second; - MTGCard *card = this->getCardById(it->first); - if (card == NULL) - { - continue; - } - MTGSetInfo *setInfo = setlist.getInfo(card->setId); - string setName = setInfo->id; - string cardName = card->data->getName(); - file << cardName << "\t " << "(" << setName << ") *" << nbCards << endl; - setInfo = NULL; - } - } - else - { - map::iterator it; - for (it = cards.begin(); it != cards.end(); it++) - { - sprintf(writer, "%i\n", it->first); - for (int j = 0; j < it->second; j++) - { - file << writer; - } - } - } - file.close(); - std::remove(destFileName.c_str()); - rename(tmp.c_str(), destFileName.c_str()); - } - DeckMetaDataList::decksMetaData->invalidate(destFileName); - return 1; -} - -//MTGSets -MTGSets setlist; //Our global. - -MTGSets::MTGSets() -{ -} - -MTGSets::~MTGSets() -{ - for (size_t i = 0; i < setinfo.size(); ++i) - { - delete (setinfo[i]); - } -} - -MTGSetInfo* MTGSets::getInfo(int setID) -{ - if (setID < 0 || setID >= (int) setinfo.size()) return NULL; - - return setinfo[setID]; -} - -MTGSetInfo* MTGSets::randomSet(int blockId, int atleast) -{ - char * unlocked = (char *) calloc(size(), sizeof(char)); - - //Figure out which sets are available. - for (int i = 0; i < size(); i++) - { - unlocked[i] = options[Options::optionSet(i)].number; - } - //No luck randomly. Now iterate from a random location. - int a = 0, iter = 0; - while (iter < 3) - { - a = rand() % size(); - for (int i = a; i < size(); i++) - { - if (unlocked[i] && (blockId == -1 || setinfo[i]->block == blockId) && - (atleast == -1 || setinfo[i]->totalCards() >= atleast)) - { - free(unlocked); - return setinfo[i]; - } - } - for (int i = 0; i < a; i++) - { - if (unlocked[i] && (blockId == -1 || setinfo[i]->block == blockId) && - (atleast == -1 || setinfo[i]->totalCards() >= atleast)) - { - free(unlocked); - return setinfo[i]; - } - } - blockId = -1; - iter++; - if (iter == 2) atleast = -1; - } - free(unlocked); - return NULL; -} - -int blockSize(int blockId); - -int MTGSets::Add(const char * name) -{ - int setid = findSet(name); - if (setid != -1) return setid; - - MTGSetInfo* s = NEW MTGSetInfo(name); - setinfo.push_back(s); - setid = (int) setinfo.size(); - - return setid - 1; -} - -int MTGSets::findSet(string name) -{ - std::transform(name.begin(), name.end(), name.begin(), ::tolower); - - for (int i = 0; i < (int) setinfo.size(); i++) - { - MTGSetInfo* s = setinfo[i]; - if (!s) continue; - string set = s->id; - std::transform(set.begin(), set.end(), set.begin(), ::tolower); - if (set.compare(name) == 0) return i; - } - return -1; -} - -int MTGSets::findBlock(string s) -{ - if (!s.size()) return -1; - - string comp = s; - std::transform(comp.begin(), comp.end(), comp.begin(), ::tolower); - for (int i = 0; i < (int) blocks.size(); i++) - { - string b = blocks[i]; - std::transform(b.begin(), b.end(), b.begin(), ::tolower); - if (b.compare(comp) == 0) return i; - } - - blocks.push_back(s); - return ((int) blocks.size()) - 1; -} - -int MTGSets::operator[](string id) -{ - return findSet(id); -} - -string MTGSets::operator[](int id) -{ - if (id < 0 || id >= (int) setinfo.size()) return ""; - - MTGSetInfo * si = setinfo[id]; - if (!si) return ""; - - return si->id; -} - -int MTGSets::getSetNum(MTGSetInfo*i) -{ - int it; - for (it = 0; it < size(); it++) - { - if (setinfo[it] == i) return it; - } - return -1; -} -int MTGSets::size() -{ - return (int) setinfo.size(); -} - -//MTGSetInfo -MTGSetInfo::~MTGSetInfo() -{ - SAFE_DELETE(mPack); -} - -MTGSetInfo::MTGSetInfo(string _id) -{ - string whitespaces(" \t\f\v\n\r"); - id = _id; - block = -1; - year = -1; - - for (int i = 0; i < MTGSetInfo::MAX_COUNT; i++) - counts[i] = 0; - - char myFilename[4096]; - sprintf(myFilename, JGE_GET_RES("sets/%s/booster.txt").c_str(), id.c_str()); - mPack = NEW MTGPack(myFilename); - if (!mPack->isValid()) - { - SAFE_DELETE(mPack); - } - bZipped = false; - bThemeZipped = false; -} - -void MTGSetInfo::count(MTGCard*c) -{ - if (!c) return; - - switch (c->getRarity()) - { - case Constants::RARITY_M: - counts[MTGSetInfo::MYTHIC]++; - break; - case Constants::RARITY_R: - counts[MTGSetInfo::RARE]++; - break; - case Constants::RARITY_U: - counts[MTGSetInfo::UNCOMMON]++; - break; - case Constants::RARITY_C: - counts[MTGSetInfo::COMMON]++; - break; - default: - case Constants::RARITY_L: - counts[MTGSetInfo::LAND]++; - break; - } - - counts[MTGSetInfo::TOTAL_CARDS]++; -} - -int MTGSetInfo::totalCards() -{ - return counts[MTGSetInfo::TOTAL_CARDS]; -} - -string MTGSetInfo::getName() -{ - if (name.size()) return name; //Pretty name is translated when rendering. - return id; //Ugly name as well. -} - -string MTGSetInfo::getBlock() -{ - if (block < 0 || block >= (int) setlist.blocks.size()) return "None"; - - return setlist.blocks[block]; -} - -void MTGSetInfo::processConfLine(string line) -{ - size_t i = line.find_first_of("="); - if (i == string::npos) return; - - string key = line.substr(0, i); - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - string value = line.substr(i + 1); - - if (key.compare("name") == 0) - name = value; - else if (key.compare("author") == 0) - author = value; - else if (key.compare("block") == 0) - block = setlist.findBlock(value.c_str()); - else if (key.compare("year") == 0) year = atoi(value.c_str()); -} +#include "PrecompiledHeader.h" + +#include "MTGDeck.h" +#include "utils.h" +#include "Subtypes.h" +#include "Translate.h" +#include "DeckMetaData.h" +#include "PriceList.h" +#include "WDataSrc.h" +#include "MTGPack.h" +#include "utils.h" + +#if defined (WIN32) || defined (LINUX) +#include +#endif + +static inline int getGrade(int v) +{ + switch (v) + { + case 'P': + case 'p': + return Constants::GRADE_SUPPORTED; + case 'R': + case 'r': + return Constants::GRADE_BORDERLINE; + case 'O': + case 'o': + return Constants::GRADE_UNOFFICIAL; + case 'A': + case 'a': + return Constants::GRADE_CRAPPY; + case 'S': + case 's': + return Constants::GRADE_UNSUPPORTED; + case 'N': + case 'n': + return Constants::GRADE_DANGEROUS; + } + return 0; +} + +//MTGAllCards +int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primitive) +{ + if ('#' == s[0]) return 0; + size_t i = s.find_first_of('='); + if (i == string::npos || 0 == i) + { + DebugTrace("MTGDECK: Bad Line:\n\t" << s); + return 0; + } + + char* key = const_cast (s.c_str()); // I know what I'm doing, let me do it + key[i] = 0; + char* val = key + i + 1; + + switch (key[0]) + { + case 'a': + if (0 == strcmp("auto", key)) + { + if (!primitive) primitive = NEW CardPrimitive(); + primitive->addMagicText(val); + } + else if (0 == strncmp("auto", key, 4)) + { + if (!primitive) primitive = NEW CardPrimitive(); + primitive->addMagicText(val, key + 4); + } + else if (0 == strcmp("alias", key)) + { + if (!primitive) primitive = NEW CardPrimitive(); + primitive->alias = atoi(val); + } + else if (0 == strcmp("abilities", key)) + { + if (!primitive) primitive = NEW CardPrimitive(); + string value = val; + //Specific Abilities + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + while (value.size()) + { + string attribute; + size_t found2 = value.find(','); + if (found2 != string::npos) + { + attribute = value.substr(0, found2); + value = value.substr(found2 + 1); + } + else + { + attribute = value; + value = ""; + } + + for (int j = Constants::NB_BASIC_ABILITIES - 1; j >= 0; --j) + { + size_t found = attribute.find(Constants::MTGBasicAbilities[j]); + if (found != string::npos) + { + primitive->basicAbilities[j] = 1; + break; + } + } + } + } + break; + + case 'c': //color + if (!primitive) primitive = NEW CardPrimitive(); + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + vector values = split(value, ','); + int removeAllOthers = 1; + for (size_t values_i = 0; values_i < values.size(); ++values_i) + { + primitive->setColor(values[values_i], removeAllOthers); + removeAllOthers = 0; + } + } + break; + + case 'g': //grade + if (s.size() - i - 1 > 2) currentGrade = getGrade(val[2]); + break; + + case 'k': //kicker + if (!primitive) primitive = NEW CardPrimitive(); + if (ManaCost * cost = primitive->getManaCost()) + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + cost->kicker = ManaCost::parseManaCost(value); + } + break; + + case 'o': //othercost + if (!primitive) primitive = NEW CardPrimitive(); + if(key[5] == 'r')//otherrestrictions + { + string value = val; + primitive->setOtherRestrictions(value); + + } + else + { + if (ManaCost * cost = primitive->getManaCost()) + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + cost->alternative = ManaCost::parseManaCost(value); + } + } + break; + + case 'b': //buyback + if (!primitive) primitive = NEW CardPrimitive(); + if (ManaCost * cost = primitive->getManaCost()) + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + cost->BuyBack = ManaCost::parseManaCost(value); + } + break; + case 'f': //flashback//morph + { + if (!primitive) primitive = NEW CardPrimitive(); + if(ManaCost * cost = primitive->getManaCost()) + { + if( s.find("facedown") != string::npos)//morph + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + cost->morph = ManaCost::parseManaCost(value); + } + else + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + cost->FlashBack = ManaCost::parseManaCost(value); + } + } + break; + } + case 'i': //id + if (!card) card = NEW MTGCard(); + card->setMTGId(atoi(val)); + break; + + case 'm': //mana + if (!primitive) primitive = NEW CardPrimitive(); + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + primitive->setManaCost(value); + } + break; + + case 'n': //name + if (!primitive) primitive = NEW CardPrimitive(); + if (0 == strcmp("Bloodrock Cyclops", val)) cout << "val" << endl; + primitive->setName(val); + break; + + case 'p': + if ('r' == key[1]) + { // primitive + if (!card) card = NEW MTGCard(); + map::iterator it = primitives.find(val); + if (it != primitives.end()) card->setPrimitive(it->second); + } + else + { //power + if (!primitive) primitive = NEW CardPrimitive(); + primitive->setPower(atoi(val)); + } + break; + + case 'r': //retrace/rarity + if('s' == key[2] && 't' == key[3])//restrictions + { + if (!primitive) primitive = NEW CardPrimitive(); + string value = val; + primitive->setRestrictions(CardPrimitive::NO_RESTRICTION); + primitive->hasRestriction = false; + if (value.find("control two or more vampires") != string::npos) + primitive->setRestrictions(CardPrimitive::VAMPIRES); + if (value.find("control less creatures") != string::npos) + primitive->setRestrictions(CardPrimitive::LESS_CREATURES); + if (value.find("control snow land") != string::npos) + primitive->setRestrictions(CardPrimitive::SNOW_LAND_INPLAY); + if (value.find("casted a spell") != string::npos) + primitive->setRestrictions(CardPrimitive::CASTED_A_SPELL); + if (value.find("one of a kind") != string::npos) + primitive->setRestrictions(CardPrimitive::ONE_OF_AKIND); + if (value.find("fourth turn") != string::npos) + primitive->setRestrictions(CardPrimitive::FOURTHTURN); + if (value.find("before battle damage") != string::npos) + primitive->setRestrictions(CardPrimitive::BEFORECOMBATDAMAGE); + if (value.find("after battle") != string::npos) + primitive->setRestrictions(CardPrimitive::AFTERCOMBAT); + if (value.find("during battle") != string::npos) + primitive->setRestrictions(CardPrimitive::DURINGCOMBAT); + if (value.find("myturnonly") != string::npos) + primitive->setRestrictions(CardPrimitive::PLAYER_TURN_ONLY); + if (value.find("opponentturnonly") != string::npos) + primitive->setRestrictions(CardPrimitive::OPPONENT_TURN_ONLY); + if (value.find("assorcery") != string::npos) + primitive->setRestrictions(CardPrimitive::AS_SORCERY); + string types[] = { "my", "opponent", "" }; + int starts[] = { CardPrimitive::MY_BEFORE_BEGIN, CardPrimitive::OPPONENT_BEFORE_BEGIN, CardPrimitive::BEFORE_BEGIN }; + for (int j = 0; j < 3; ++j) + { + size_t found = value.find(types[j]); + if (found != string::npos) + { + for (int i = 0; i < Constants::NB_MTG_PHASES; i++) + { + string toFind = types[j]; + toFind.append(Constants::MTGPhaseCodeNames[i]).append("only"); + found = value.find(toFind); + if (found != string::npos) + { + if(primitive->hasRestriction == false) + { + primitive->setRestrictions(starts[j] + i); + primitive->hasRestriction = true; + } + } + } + } + } + } + else if ('e' == key[1] && 't' == key[2]) + { //retrace + if (!primitive) primitive = NEW CardPrimitive(); + if (ManaCost * cost = primitive->getManaCost()) + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + cost->Retrace = ManaCost::parseManaCost(value); + } + } + else if (s.find("rar") != string::npos) + {//rarity + if (!card) card = NEW MTGCard(); + card->setRarity(val[0]); + } + break; + case 's': //subtype + if (!primitive) primitive = NEW CardPrimitive(); + while (true) + { + char* found = strchr(val, ' '); + if (found) + { + string value(val, found - val); + primitive->setSubtype(value); + val = found + 1; + } + else + { + primitive->setSubtype(val); + break; + } + } + break; + + case 't': + if (!primitive) primitive = NEW CardPrimitive(); + if (0 == strcmp("target", key)) + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + primitive->spellTargetType = value; + } + else if (0 == strcmp("text", key)) + primitive->setText(val); + else if (0 == strcmp("type", key)) + { + while (true) + { + char* found = strchr(val, ' '); + if (found) + { + string value(val, found - val); + primitive->setType(value); + val = found + 1; + } + else + { + primitive->setType(val); + break; + } + } + } + else if (0 == strcmp("toughness", key)) primitive->setToughness(atoi(val)); + break; + + default: + DebugTrace( endl << "MTGDECK Parsing Error: " << " [" << primitive->getName() << "]" << s << std::endl); + break; + } + + tempPrimitive = primitive; + tempCard = card; + + return i; + +} + +void MTGAllCards::initCounters() +{ + for (int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + colorsCount[i] = NULL; + } +} + +void MTGAllCards::init() +{ + tempCard = NULL; + tempPrimitive = NULL; + total_cards = 0; + initCounters(); +} + +int MTGAllCards::load(const char * config_file, const char * set_name, int autoload) +{ + conf_read_mode = 0; + const int set_id = set_name ? setlist.Add(set_name) : MTGSets::INTERNAL_SET; + MTGSetInfo *si = setlist.getInfo(set_id); + + wagic::ifstream setFile(config_file, ios::in | ios::ate); + if (!setFile) return total_cards; + + streampos fileSize = setFile.tellg(); + setFile.seekg(0, ios::beg); + + std::string contents; + contents.resize((std::string::size_type) fileSize); + setFile.read(&contents[0], fileSize); + std::stringstream stream(contents); + + string s; + + while (true) + { + if (!std::getline(stream, s)) return total_cards; + if (!s.size()) continue; + + if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); // Handle DOS files + switch (conf_read_mode) + { + case MTGAllCards::READ_ANYTHING: + if (s[0] == '[') + { + currentGrade = Constants::GRADE_SUPPORTED; // Default value + conf_read_mode = ('m' == s[1]) ? MTGAllCards::READ_METADATA : MTGAllCards::READ_CARD; // M for metadata. + } + else + { + //Global grade for file, to avoid reading the entire file if unnnecessary + if (s[0] == 'g' && s.size() > 8) + { + int fileGrade = getGrade(s[8]); + int maxGrade = options[Options::MAX_GRADE].number; + if (!maxGrade) maxGrade = Constants::GRADE_BORDERLINE; //Default setting for grade is borderline? + if (fileGrade > maxGrade) + { + return total_cards; + } + } + } + continue; + case MTGAllCards::READ_METADATA: + if (s[0] == '[' && s[1] == '/') + conf_read_mode = MTGAllCards::READ_ANYTHING; + else if (si) si->processConfLine(s); + continue; + case MTGAllCards::READ_CARD: + if (s[0] == '[' && s[1] == '/') + { + conf_read_mode = MTGAllCards::READ_ANYTHING; + if (tempPrimitive) tempPrimitive = addPrimitive(tempPrimitive, tempCard); + if (tempCard) + { + if (tempPrimitive) tempCard->setPrimitive(tempPrimitive); + addCardToCollection(tempCard, set_id); + } + tempCard = NULL; + tempPrimitive = NULL; + } + else + { + processConfLine(s, tempCard, tempPrimitive); + } + continue; + } + } + return total_cards; +} + +MTGAllCards::MTGAllCards() +{ + init(); +} + +MTGAllCards::~MTGAllCards() +{ + //Why don't we call destroyAllCards from here ??? +} + +void MTGAllCards::destroyAllCards() +{ + + for (map::iterator it = collection.begin(); it != collection.end(); it++) + delete (it->second); + collection.clear(); + ids.clear(); + + for (map::iterator it = primitives.begin(); it != primitives.end(); it++) + delete (it->second); + primitives.clear(); + +} + +MTGAllCards::MTGAllCards(const char * config_file, const char * set_name) +{ + init(); + load(config_file, set_name, 0); +} + +int MTGAllCards::randomCardId() +{ + int id = (rand() % ids.size()); + return ids[id]; +} + +int MTGAllCards::countBySet(int setId) +{ + int result = 0; + map::iterator it; + + for (it = collection.begin(); it != collection.end(); it++) + { + MTGCard * c = it->second; + if (c->setId == setId) + { + result++; + } + } + return result; +} + +//TODO more efficient way ? +int MTGAllCards::countByType(const char * _type) +{ + int result = 0; + map::iterator it; + for (it = collection.begin(); it != collection.end(); it++) + { + MTGCard * c = it->second; + if (c->data->hasType(_type)) + { + result++; + } + } + return result; +} + +int MTGAllCards::countByColor(int color) +{ + if (colorsCount[color] == 0) + { + for (int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + colorsCount[i] = 0; + } + map::iterator it; + for (it = collection.begin(); it != collection.end(); it++) + { + MTGCard * c = it->second; + int j = c->data->getColor(); + + colorsCount[j]++; + } + } + return colorsCount[color]; +} + +int MTGAllCards::totalCards() +{ + return (total_cards); +} + +bool MTGAllCards::addCardToCollection(MTGCard * card, int setId) +{ + card->setId = setId; + int newId = card->getId(); + if (collection.find(newId) != collection.end()) + { +#if defined (_DEBUG) + string cardName = card->data ? card->data->name : card->getImageName(); + string setName = setId != -1 ? setlist.getInfo(setId)->getName() : ""; + DebugTrace("warning, card id collision! : " << newId << " -> " << cardName << "(" << setName << ")"); +#endif + SAFE_DELETE(card); + return false; + } + + //Don't add cards that don't have a primitive + if (!card->data) + { + SAFE_DELETE(card); + return false; + } + ids.push_back(newId); + + collection[newId] = card; //Push card into collection. + MTGSetInfo * si = setlist.getInfo(setId); + if (si) si->count(card); //Count card in set info + ++total_cards; + return true; +} + +CardPrimitive * MTGAllCards::addPrimitive(CardPrimitive * primitive, MTGCard * card) +{ + int maxGrade = options[Options::MAX_GRADE].number; + if (!maxGrade) maxGrade = Constants::GRADE_BORDERLINE; //Default setting for grade is borderline? + if (currentGrade > maxGrade) + { + SAFE_DELETE(primitive); + return NULL; + } + string key; + if (card) + { + std::stringstream ss; + ss << card->getId(); + ss >> key; + } + else + key = primitive->name; + if (primitives.find(key) != primitives.end()) + { + //ERROR + //Todo move the deletion somewhere else ? + DebugTrace("MTGDECK: primitives conflict: "<< key); + SAFE_DELETE(primitive); + return NULL; + } + //translate cards text + Translator * t = Translator::GetInstance(); + map::iterator it = t->tempValues.find(primitive->name); + if (it != t->tempValues.end()) + { + primitive->setText(it->second); + } + + //Legacy: + //For the Deck editor, we need Lands and Artifact to be colors... + if (primitive->hasType(Subtypes::TYPE_LAND)) primitive->setColor(Constants::MTG_COLOR_LAND); + if (primitive->hasType(Subtypes::TYPE_ARTIFACT)) primitive->setColor(Constants::MTG_COLOR_ARTIFACT); + + primitives[key] = primitive; + return primitive; +} + +MTGCard * MTGAllCards::getCardById(int id) +{ + map::iterator it = collection.find(id); + if (it != collection.end()) + { + return (it->second); + } + return 0; +} + +MTGCard * MTGAllCards::_(int index) +{ + if (index >= total_cards) return NULL; + return getCardById(ids[index]); +} + +MTGCard * MTGAllCards::getCardByName(string name) +{ + if (!name.size()) return NULL; + if (name[0] == '#') return NULL; + + int cardnb = atoi(name.c_str()); + if (cardnb) + { + return getCardById(cardnb); + } + + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + int setId = -1; + size_t found = name.find(" ("); + if (found != string::npos) + { + size_t end = name.find(")"); + string setName = name.substr(found + 2, end - found - 2); + trim(setName); + name = name.substr(0, found); + trim(name); + setId = setlist[setName]; + } + map::iterator it; + for (it = collection.begin(); it != collection.end(); it++) + { + MTGCard * c = it->second; + if (setId != -1 && setId != c->setId) continue; + string cardName = c->data->name; + std::transform(cardName.begin(), cardName.end(), cardName.begin(), ::tolower); + if (cardName.compare(name) == 0) return c; + + } + return NULL; +} + +//MTGDeck +MTGDeck::MTGDeck(MTGAllCards * _allcards) +{ + total_cards = 0; + database = _allcards; + filename = ""; + meta_name = ""; +} + +int MTGDeck::totalPrice() +{ + int total = 0; + PriceList * pricelist = NEW PriceList(JGE_GET_RES("settings/prices.dat").c_str(), GameApp::collection); + map::iterator it; + for (it = cards.begin(); it != cards.end(); it++) + { + int nb = it->second; + if (nb) total += pricelist->getPrice(it->first); + } + SAFE_DELETE(pricelist); + return total; +} + +MTGDeck::MTGDeck(const char * config_file, MTGAllCards * _allcards, int meta_only) +{ + total_cards = 0; + database = _allcards; + filename = config_file; + size_t slash = filename.find_last_of("/"); + size_t dot = filename.find("."); + meta_name = filename.substr(slash + 1, dot - slash - 1); + wagic::ifstream file(config_file); + std::string s; + + if (file) + { + while (std::getline(file, s)) + { + if (!s.size()) continue; + if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files + if (s[0] == '#') + { + size_t found = s.find("NAME:"); + if (found != string::npos) + { + meta_name = s.substr(found + 5); + continue; + } + found = s.find("DESC:"); + if (found != string::npos) + { + if (meta_desc.size()) meta_desc.append("\n"); + meta_desc.append(s.substr(found + 5)); + continue; + } + continue; + } + if (meta_only) break; + int cardnb = atoi(s.c_str()); + if (cardnb) + { + add(cardnb); + } + else + { + int nb = 1; + size_t found = s.find(" *"); + if (found != string::npos) + { + nb = atoi(s.substr(found + 2).c_str()); + s = s.substr(0, found); + } + MTGCard * card = database->getCardByName(s); + if (card) + { + for (int i = 0; i < nb; i++) + { + add(card); + } + } + else + { + DebugTrace("could not find Card matching name: " << s); + } + } + } + file.close(); + } + else + { + //TODO Error management + } +} + +int MTGDeck::totalCards() +{ + return total_cards; +} + +MTGCard * MTGDeck::getCardById(int mtgId) +{ + return database->getCardById(mtgId); +} + +int MTGDeck::addRandomCards(int howmany, int * setIds, int nbSets, int rarity, const char * _subtype, int * colors, int nbcolors) +{ + if (howmany <= 0) return 1; + + int unallowedColors[Constants::MTG_NB_COLORS + 1]; + for (int i = 0; i < Constants::MTG_NB_COLORS; ++i) + { + if (nbcolors) + unallowedColors[i] = 1; + else + unallowedColors[i] = 0; + } + for (int i = 0; i < nbcolors; ++i) + { + unallowedColors[colors[i]] = 0; + } + + int collectionTotal = database->totalCards(); + if (!collectionTotal) return 0; + + char subtype[4096]; + if (_subtype) sprintf(subtype, "%s", _subtype); + + vector subcollection; + int subtotal = 0; + for (int i = 0; i < collectionTotal; i++) + { + MTGCard * card = database->_(i); + int r = card->getRarity(); + if (r != Constants::RARITY_T && (rarity == -1 || r == rarity) && // remove tokens + card->setId != MTGSets::INTERNAL_SET && //remove cards that are defined in primitives. Those are workarounds (usually tokens) and should only be used internally + (!_subtype || card->data->hasSubtype(subtype))) + { + int ok = 0; + + if (!nbSets) ok = 1; + for (int j = 0; j < nbSets; ++j) + { + if (card->setId == setIds[j]) + { + ok = 1; + break; + } + } + + if (ok) + { + for (int j = 0; j < Constants::MTG_NB_COLORS; ++j) + { + if (unallowedColors[j] && card->data->hasColor(j)) + { + ok = 0; + break; + } + } + } + + if (ok) + { + subcollection.push_back(card->getId()); + subtotal++; + } + } + } + if (subtotal == 0) + { + if (rarity == Constants::RARITY_M) return addRandomCards(howmany, setIds, nbSets, Constants::RARITY_R, _subtype, colors, + nbcolors); + return 0; + } + for (int i = 0; i < howmany; i++) + { + int id = (rand() % subtotal); + add(subcollection[id]); + } + return 1; +} + +int MTGDeck::add(MTGDeck * deck) +{ + map::iterator it; + for (it = deck->cards.begin(); it != deck->cards.end(); it++) + { + for (int i = 0; i < it->second; i++) + { + add(it->first); + } + } + return deck->totalCards(); +} + +int MTGDeck::add(int cardid) +{ + if (!database->getCardById(cardid)) return 0; + if (cards.find(cardid) == cards.end()) + { + cards[cardid] = 1; + } + else + { + cards[cardid]++; + } + ++total_cards; + //initCounters(); + return total_cards; +} + +int MTGDeck::add(MTGCard * card) +{ + if (!card) return 0; + return (add(card->getId())); +} + +int MTGDeck::complete() +{ + /* (PSY) adds cards to the deck/collection. Makes sure that the deck + or collection has at least 4 of every implemented card. Does not + change the number of cards of which already 4 or more are present. */ + int id, n; + bool StypeIsNothing; + size_t databaseSize = database->ids.size(); + for (size_t it = 0; it < databaseSize; it++) + { + id = database->ids[it]; + StypeIsNothing = false; + if (database->getCardById(id)->data->hasType("nothing")) + { + StypeIsNothing = true; + } + if (!StypeIsNothing ) + { + if (cards.find(id) == cards.end()) + { + cards[id] = 4; + total_cards += 4; + } + else + { + n = cards[id]; + if (n < 4) + { + total_cards += 4 - n; + cards[id] = 4; + } + } + } + } + return 1; +} + +int MTGDeck::removeAll() +{ + total_cards = 0; + cards.clear(); + //initCounters(); + return 1; +} + +int MTGDeck::remove(int cardid) +{ + if (cards.find(cardid) == cards.end() || cards[cardid] == 0) return 0; + cards[cardid]--; + total_cards--; + //initCounters(); + return 1; +} + +int MTGDeck::remove(MTGCard * card) +{ + if (!card) return 0; + return (remove(card->getId())); +} + +int MTGDeck::save() +{ + return save(filename, false, meta_name, meta_desc); +} + +int MTGDeck::save(string destFileName, bool useExpandedDescriptions, string &deckTitle, string &deckDesc) +{ + string tmp = destFileName; + tmp.append(".tmp"); //not thread safe + std::ofstream file(tmp.c_str()); + char writer[512]; + if (file) + { + DebugTrace("Saving Deck: " << deckTitle << " to " << destFileName ); + if (meta_name.size()) + { + file << "#NAME:" << deckTitle << '\n'; + } + + if (meta_desc.size()) + { + size_t found = 0; + string desc = deckDesc; + found = desc.find_first_of("\n"); + while (found != string::npos) + { + file << "#DESC:" << desc.substr(0, found + 1); + desc = desc.substr(found + 1); + found = desc.find_first_of("\n"); + } + file << "#DESC:" << desc << "\n"; + } + + if (useExpandedDescriptions) + { + map::iterator it; + for (it = cards.begin(); it != cards.end(); it++) + { + int nbCards = it->second; + MTGCard *card = this->getCardById(it->first); + if (card == NULL) + { + continue; + } + MTGSetInfo *setInfo = setlist.getInfo(card->setId); + string setName = setInfo->id; + string cardName = card->data->getName(); + file << cardName << "\t " << "(" << setName << ") *" << nbCards << endl; + setInfo = NULL; + } + } + else + { + map::iterator it; + for (it = cards.begin(); it != cards.end(); it++) + { + sprintf(writer, "%i\n", it->first); + for (int j = 0; j < it->second; j++) + { + file << writer; + } + } + } + file.close(); + std::remove(destFileName.c_str()); + rename(tmp.c_str(), destFileName.c_str()); + } + DeckMetaDataList::decksMetaData->invalidate(destFileName); + return 1; +} + +//MTGSets +MTGSets setlist; //Our global. + +MTGSets::MTGSets() +{ +} + +MTGSets::~MTGSets() +{ + for (size_t i = 0; i < setinfo.size(); ++i) + { + delete (setinfo[i]); + } +} + +MTGSetInfo* MTGSets::getInfo(int setID) +{ + if (setID < 0 || setID >= (int) setinfo.size()) return NULL; + + return setinfo[setID]; +} + +MTGSetInfo* MTGSets::randomSet(int blockId, int atleast) +{ + char * unlocked = (char *) calloc(size(), sizeof(char)); + + //Figure out which sets are available. + for (int i = 0; i < size(); i++) + { + unlocked[i] = options[Options::optionSet(i)].number; + } + //No luck randomly. Now iterate from a random location. + int a = 0, iter = 0; + while (iter < 3) + { + a = rand() % size(); + for (int i = a; i < size(); i++) + { + if (unlocked[i] && (blockId == -1 || setinfo[i]->block == blockId) && + (atleast == -1 || setinfo[i]->totalCards() >= atleast)) + { + free(unlocked); + return setinfo[i]; + } + } + for (int i = 0; i < a; i++) + { + if (unlocked[i] && (blockId == -1 || setinfo[i]->block == blockId) && + (atleast == -1 || setinfo[i]->totalCards() >= atleast)) + { + free(unlocked); + return setinfo[i]; + } + } + blockId = -1; + iter++; + if (iter == 2) atleast = -1; + } + free(unlocked); + return NULL; +} + +int blockSize(int blockId); + +int MTGSets::Add(const char * name) +{ + int setid = findSet(name); + if (setid != -1) return setid; + + MTGSetInfo* s = NEW MTGSetInfo(name); + setinfo.push_back(s); + setid = (int) setinfo.size(); + + return setid - 1; +} + +int MTGSets::findSet(string name) +{ + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + + for (int i = 0; i < (int) setinfo.size(); i++) + { + MTGSetInfo* s = setinfo[i]; + if (!s) continue; + string set = s->id; + std::transform(set.begin(), set.end(), set.begin(), ::tolower); + if (set.compare(name) == 0) return i; + } + return -1; +} + +int MTGSets::findBlock(string s) +{ + if (!s.size()) return -1; + + string comp = s; + std::transform(comp.begin(), comp.end(), comp.begin(), ::tolower); + for (int i = 0; i < (int) blocks.size(); i++) + { + string b = blocks[i]; + std::transform(b.begin(), b.end(), b.begin(), ::tolower); + if (b.compare(comp) == 0) return i; + } + + blocks.push_back(s); + return ((int) blocks.size()) - 1; +} + +int MTGSets::operator[](string id) +{ + return findSet(id); +} + +string MTGSets::operator[](int id) +{ + if (id < 0 || id >= (int) setinfo.size()) return ""; + + MTGSetInfo * si = setinfo[id]; + if (!si) return ""; + + return si->id; +} + +int MTGSets::getSetNum(MTGSetInfo*i) +{ + int it; + for (it = 0; it < size(); it++) + { + if (setinfo[it] == i) return it; + } + return -1; +} +int MTGSets::size() +{ + return (int) setinfo.size(); +} + +//MTGSetInfo +MTGSetInfo::~MTGSetInfo() +{ + SAFE_DELETE(mPack); +} + +MTGSetInfo::MTGSetInfo(string _id) +{ + string whitespaces(" \t\f\v\n\r"); + id = _id; + block = -1; + year = -1; + + for (int i = 0; i < MTGSetInfo::MAX_COUNT; i++) + counts[i] = 0; + + char myFilename[4096]; + sprintf(myFilename, JGE_GET_RES("sets/%s/booster.txt").c_str(), id.c_str()); + mPack = NEW MTGPack(myFilename); + if (!mPack->isValid()) + { + SAFE_DELETE(mPack); + } + bZipped = false; + bThemeZipped = false; +} + +void MTGSetInfo::count(MTGCard*c) +{ + if (!c) return; + + switch (c->getRarity()) + { + case Constants::RARITY_M: + counts[MTGSetInfo::MYTHIC]++; + break; + case Constants::RARITY_R: + counts[MTGSetInfo::RARE]++; + break; + case Constants::RARITY_U: + counts[MTGSetInfo::UNCOMMON]++; + break; + case Constants::RARITY_C: + counts[MTGSetInfo::COMMON]++; + break; + default: + case Constants::RARITY_L: + counts[MTGSetInfo::LAND]++; + break; + } + + counts[MTGSetInfo::TOTAL_CARDS]++; +} + +int MTGSetInfo::totalCards() +{ + return counts[MTGSetInfo::TOTAL_CARDS]; +} + +string MTGSetInfo::getName() +{ + if (name.size()) return name; //Pretty name is translated when rendering. + return id; //Ugly name as well. +} + +string MTGSetInfo::getBlock() +{ + if (block < 0 || block >= (int) setlist.blocks.size()) return "None"; + + return setlist.blocks[block]; +} + +void MTGSetInfo::processConfLine(string line) +{ + size_t i = line.find_first_of("="); + if (i == string::npos) return; + + string key = line.substr(0, i); + std::transform(key.begin(), key.end(), key.begin(), ::tolower); + string value = line.substr(i + 1); + + if (key.compare("name") == 0) + name = value; + else if (key.compare("author") == 0) + author = value; + else if (key.compare("block") == 0) + block = setlist.findBlock(value.c_str()); + else if (key.compare("year") == 0) year = atoi(value.c_str()); +} diff --git a/projects/mtg/src/MTGGamePhase.cpp b/projects/mtg/src/MTGGamePhase.cpp index 5002afece..955329b41 100644 --- a/projects/mtg/src/MTGGamePhase.cpp +++ b/projects/mtg/src/MTGGamePhase.cpp @@ -1,64 +1,64 @@ -#include "PrecompiledHeader.h" - -#include "MTGGamePhase.h" - -MTGGamePhase::MTGGamePhase(int id) : - ActionElement(id) -{ - animation = 0; - currentState = -1; - mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - mFont->SetBase(0); // using 2nd font -} - -void MTGGamePhase::Update(float dt) -{ - - int newState = GameObserver::GetInstance()->getCurrentGamePhase(); - if (newState != currentState) - { - activeState = ACTIVE; - animation = 4; - currentState = newState; - } - - if (animation > 0) - { - animation--; - } - else - { - activeState = INACTIVE; - animation = 0; - - } - -} - -bool MTGGamePhase::CheckUserInput(JButton key) -{ - GameObserver * game = GameObserver::GetInstance(); - if (activeState == INACTIVE) - { - JButton trigger = (options[Options::REVERSETRIGGERS].number ? JGE_BTN_NEXT : JGE_BTN_PREV); - if ((trigger == key) && game->currentActionPlayer == game->currentlyActing()) - { - activeState = ACTIVE; - game->userRequestNextGamePhase(); - return true; - } - } - return false; -} - -MTGGamePhase * MTGGamePhase::clone() const -{ - MTGGamePhase * a = NEW MTGGamePhase(*this); - a->isClone = 1; - return a; -} - -ostream& MTGGamePhase::toString(ostream& out) const -{ - return out << "MTGGamePhase ::: animation " << animation << " ; currentState : " << currentState; -} +#include "PrecompiledHeader.h" + +#include "MTGGamePhase.h" + +MTGGamePhase::MTGGamePhase(int id) : + ActionElement(id) +{ + animation = 0; + currentState = -1; + mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + mFont->SetBase(0); // using 2nd font +} + +void MTGGamePhase::Update(float dt) +{ + + int newState = GameObserver::GetInstance()->getCurrentGamePhase(); + if (newState != currentState) + { + activeState = ACTIVE; + animation = 4; + currentState = newState; + } + + if (animation > 0) + { + animation--; + } + else + { + activeState = INACTIVE; + animation = 0; + + } + +} + +bool MTGGamePhase::CheckUserInput(JButton key) +{ + GameObserver * game = GameObserver::GetInstance(); + if (activeState == INACTIVE) + { + JButton trigger = (options[Options::REVERSETRIGGERS].number ? JGE_BTN_NEXT : JGE_BTN_PREV); + if ((trigger == key) && game->currentActionPlayer == game->currentlyActing()) + { + activeState = ACTIVE; + game->userRequestNextGamePhase(); + return true; + } + } + return false; +} + +MTGGamePhase * MTGGamePhase::clone() const +{ + MTGGamePhase * a = NEW MTGGamePhase(*this); + a->isClone = 1; + return a; +} + +ostream& MTGGamePhase::toString(ostream& out) const +{ + return out << "MTGGamePhase ::: animation " << animation << " ; currentState : " << currentState; +} diff --git a/projects/mtg/src/ManaCost.cpp b/projects/mtg/src/ManaCost.cpp index 584e090a7..e8cc98c79 100644 --- a/projects/mtg/src/ManaCost.cpp +++ b/projects/mtg/src/ManaCost.cpp @@ -1,736 +1,736 @@ -#include "PrecompiledHeader.h" - -#include "ManaCost.h" -#include "ManaCostHybrid.h" -#include "ExtraCost.h" -#include "TargetChooser.h" -#include "Targetable.h" -#include "Player.h" -#include "WEvent.h" -#include "MTGAbility.h" - -ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstance * c) -{ - ManaCost * manaCost; - if (_manaCost) - { - manaCost = _manaCost; - } - else - { - manaCost = NEW ManaCost(); - } - int state = 0; - size_t start = 0; - size_t end = 0; - while (!s.empty() && state != -1) - { - switch (state) - { - case 0: - start = s.find_first_of("{"); - if (start == string::npos) - { - return manaCost; - } - else - { - state = 1; - } - break; - case 1: - end = s.find_first_of("}"); - if (end == string::npos) - { - state = -1; - } - else - { - string value = s.substr(start + 1, end - 1 - start); - - if (value == "u") - { - manaCost->add(Constants::MTG_COLOR_BLUE, 1); - } - else if (value == "b") - { - manaCost->add(Constants::MTG_COLOR_BLACK, 1); - } - else if (value == "w") - { - manaCost->add(Constants::MTG_COLOR_WHITE, 1); - } - else if (value == "g") - { - manaCost->add(Constants::MTG_COLOR_GREEN, 1); - } - else if (value == "r") - { - manaCost->add(Constants::MTG_COLOR_RED, 1); - - } - else - { - - //Parse target for extraCosts - TargetChooserFactory tcf; - TargetChooser * tc = NULL; - size_t target_start = value.find("("); - size_t target_end = value.find(")"); - if (target_start != string::npos && target_end != string::npos) - { - string target = value.substr(target_start + 1, target_end - 1 - target_start); - tc = tcf.createTargetChooser(target, c); - } - - //switch on the first letter. If two costs share their first letter, add an "if" within the switch - switch (value[0]) - { - case 'x': - manaCost->x(); - break; - case 't': //Tap - if (value == "t") - { - //default Tap is handled outside of Manacost - } - else - { - manaCost->addExtraCost(NEW TapTargetCost(tc)); - } - break; - case 's': - if (value == "s2l") - { //Send To Library Cost (move from anywhere to Library) - manaCost->addExtraCost(NEW ToLibraryCost(tc)); - } - else - { //Sacrifice - manaCost->addExtraCost(NEW SacrificeCost(tc)); - } - break; - case 'e': //Exile - manaCost->addExtraCost(NEW ExileTargetCost(tc)); - break; - case 'h': //bounce (move to Hand) - manaCost->addExtraCost(NEW BounceTargetCost(tc)); - break; - case 'l': - if (value == "l2e") - { //Mill to exile yourself as a cost (Library 2 Exile) - manaCost->addExtraCost(NEW MillExileCost(tc)); - } - else - { //Life cost - manaCost->addExtraCost(NEW LifeCost(tc)); - } - break; - case 'd': //DiscardRandom cost - if (value == "d") - { - manaCost->addExtraCost(NEW DiscardRandomCost(tc)); - } - else - { - manaCost->addExtraCost(NEW DiscardCost(tc)); - } - break; - case 'm': //Mill yourself as a cost - manaCost->addExtraCost(NEW MillCost(tc)); - break; - case 'n': //return unblocked attacker cost - TargetChooserFactory tcf; - tc = tcf.createTargetChooser("creature|myBattlefield", c); - manaCost->addExtraCost(NEW Ninja(tc)); - break; - case 'c': //Counters - { - size_t counter_start = value.find("("); - size_t counter_end = value.find(")", counter_start); - AbilityFactory abf; - string counterString = value.substr(counter_start + 1, counter_end - counter_start - 1); - Counter * counter = abf.parseCounter(counterString, c); - size_t separator = value.find(",", counter_start); - size_t separator2 = string::npos; - if (separator != string::npos) - { - separator2 = value.find(",", separator + 1); - } - SAFE_DELETE(tc); - size_t target_start = string::npos; - if (separator2 != string::npos) - { - target_start = value.find(",", separator2 + 1); - } - size_t target_end = counter_end; - if (target_start != string::npos && target_end != string::npos) - { - string target = value.substr(target_start + 1, target_end - 1 - target_start); - tc = tcf.createTargetChooser(target, c); - } - manaCost->addExtraCost(NEW CounterCost(counter, tc)); - break; - } - default: //uncolored cost and hybrid costs - { - int intvalue = atoi(value.c_str()); - int colors[2]; - int values[2]; - if (intvalue < 10 && value.size() > 1) - { - for (int i = 0; i < 2; i++) - { - char c = value[i]; - if (c >= '0' && c <= '9') - { - colors[i] = Constants::MTG_COLOR_ARTIFACT; - values[i] = c - '0'; - } - else - { - for (int j = 0; j < Constants::MTG_NB_COLORS; j++) - { - if (c == Constants::MTGColorChars[j]) - { - colors[i] = j; - values[i] = 1; - } - } - } - } - manaCost->addHybrid(colors[0], values[0], colors[1], values[1]); - } - else - { - manaCost->add(Constants::MTG_COLOR_ARTIFACT, intvalue); - } - break; - } - } - } - s = s.substr(end + 1); - state = 0; - } - break; - default: - break; - } - } - return manaCost; -} - -ManaCost::ManaCost() -{ - init(); -} -ManaCost::ManaCost(int _cost[], int nb_elems) -{ - init(); - int i; - int total = nb_elems; - for (i = 0; i < total; i++) - { - cost[_cost[i * 2]] = _cost[i * 2 + 1]; - } - -} - -ManaCost::ManaCost(ManaCost * _manaCost) -{ - init(); - int i; - for (i = 0; i <= Constants::MTG_NB_COLORS; i++) - { - cost[i] = _manaCost->getCost(i); - } -} - -ManaCost::~ManaCost() -{ - for (unsigned int i = 0; i < nbhybrids; i++) - { - SAFE_DELETE(hybrids[i]); - } - SAFE_DELETE(extraCosts); - SAFE_DELETE(kicker); - SAFE_DELETE(alternative); - SAFE_DELETE(BuyBack); - SAFE_DELETE(FlashBack); - SAFE_DELETE(Retrace); - SAFE_DELETE(morph); -} - -void ManaCost::x() -{ - cost[Constants::MTG_NB_COLORS] = 1; -} - -int ManaCost::hasX() -{ - return cost[Constants::MTG_NB_COLORS]; -} - -void ManaCost::init() -{ - int i; - for (i = 0; i <= Constants::MTG_NB_COLORS; i++) - { - cost[i] = 0; - } - nbhybrids = 0; - extraCosts = NULL; - extraCostsIsCopy = 0; - kicker = NULL; - alternative = NULL; - BuyBack = NULL; - FlashBack = NULL; - Retrace = NULL; - morph = NULL; -} - -void ManaCost::copy(ManaCost * _manaCost) -{ - if (!_manaCost) - return; - for (unsigned int i = 0; i <= Constants::MTG_NB_COLORS; i++) - { - cost[i] = _manaCost->getCost(i); - } - for (unsigned int i = 0; i < nbhybrids; i++) - { - SAFE_DELETE(hybrids[i]); - } - for (unsigned int i = 0; i < _manaCost->nbhybrids; i++) - { - hybrids[i] = NEW ManaCostHybrid((*_manaCost->hybrids[i])); - } - nbhybrids = _manaCost->nbhybrids; - - SAFE_DELETE(extraCosts); - if (_manaCost->extraCosts) - { - extraCosts = _manaCost->extraCosts->clone(); - } - - SAFE_DELETE(kicker); - if (_manaCost->kicker) - { - kicker = NEW ManaCost(); - kicker->copy(_manaCost->kicker); - } - SAFE_DELETE(alternative); - if (_manaCost->alternative) - { - alternative = NEW ManaCost(); - alternative->copy(_manaCost->alternative); - } - SAFE_DELETE(BuyBack); - if (_manaCost->BuyBack) - { - BuyBack = NEW ManaCost(); - BuyBack->copy(_manaCost->BuyBack); - } - SAFE_DELETE(FlashBack); - if (_manaCost->FlashBack) - { - FlashBack = NEW ManaCost(); - FlashBack->copy(_manaCost->FlashBack); - } - SAFE_DELETE(Retrace); - if (_manaCost->Retrace) - { - Retrace = NEW ManaCost(); - Retrace->copy(_manaCost->Retrace); - } - SAFE_DELETE(morph); - if (_manaCost->morph) - { - morph = NEW ManaCost(); - morph->copy(_manaCost->morph); - } -} - -int ManaCost::getCost(int color) -{ - return cost[color]; -} - -ManaCostHybrid * ManaCost::getHybridCost(unsigned int i) -{ - if (nbhybrids <= i) - return NULL; - return hybrids[i]; -} - -int ManaCost::hasColor(int color) -{ - if (cost[color]) - return 1; - for (unsigned int i = 0; i < nbhybrids; i++) - { - if (hybrids[i]->hasColor(color)) - return 1; - } - return 0; -} - -int ManaCost::isNull() -{ - if (getConvertedCost()) - return 0; - if (extraCosts) - return 0; - return 1; -} - -int ManaCost::getConvertedCost() -{ - int result = 0; - for (unsigned int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - result += cost[i]; - } - for (unsigned int i = 0; i < nbhybrids; i++) - { - result += hybrids[i]->getConvertedCost(); - } - return result; -} - -int ManaCost::remove(int color, int value) -{ - cost[color] -= value; - if (cost[color] < 0) - { - cost[color] = 0; - } - return 1; -} - -int ManaCost::add(int color, int value) -{ - if (value < 0) - value = 0; - cost[color] += value; - return 1; -} - -int ManaCost::add(ManaCost * _cost) -{ - if (!_cost) - return 0; - for (unsigned int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - cost[i] += _cost->getCost(i); - } - for (unsigned int i = 0; i < _cost->nbhybrids; i++) - { - hybrids[nbhybrids] = NEW ManaCostHybrid((*_cost->hybrids[i])); - nbhybrids++; - } - return 1; -} - -int ManaCost::addHybrid(int c1, int v1, int c2, int v2) -{ - ManaCostHybrid * h = NEW ManaCostHybrid(c1, v1, c2, v2); - hybrids[nbhybrids] = h; - nbhybrids++; - return nbhybrids; -} - -int ManaCost::addExtraCost(ExtraCost * _cost) -{ - if (!extraCosts) - extraCosts = NEW ExtraCosts(); - extraCosts->costs.push_back(_cost); - return 1; -} - -int ManaCost::isExtraPaymentSet() -{ - if (!extraCosts) - return 1; - return extraCosts->isPaymentSet(); -} - -int ManaCost::canPayExtra() -{ - if (!extraCosts) - return 1; - return extraCosts->canPay(); -} - -int ManaCost::doPayExtra() -{ - if (!extraCosts) - return 0; - return extraCosts->doPay(); //TODO reset ? -} - -int ManaCost::setExtraCostsAction(MTGAbility * action, MTGCardInstance * card) -{ - if (extraCosts) - extraCosts->setAction(action, card); - return 1; -} - -int ManaCost::pay(ManaCost * _cost) -{ - int result = MANA_PAID; - ManaCost * toPay = NEW ManaCost(); - toPay->copy(_cost); - - if (toPay->kicker) - { - toPay->add(toPay->kicker); - if (!canAfford(toPay)) - { - toPay->copy(_cost); - } - else - { - result = MANA_PAID_WITH_KICKER; - } - } - - ManaCost * diff = Diff(toPay); - for (int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - cost[i] = diff->getCost(i); - } - delete diff; - delete toPay; - return result; - //TODO return 0 if can't afford the cost! -} - -//return 1 if _cost can be paid with current data, 0 otherwise -int ManaCost::canAfford(ManaCost * _cost) -{ - ManaCost * diff = Diff(_cost); - int positive = diff->isPositive(); - delete diff; - if (positive) - { - return 1; - } - return 0; -} - -int ManaCost::isPositive() -{ - for (int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - - if (cost[i] < 0) - { - return 0; - } - } - return 1; - -} - -void ManaCost::randomDiffHybrids(ManaCost * _cost, int diff[]) -{ - int _nbhybrids = _cost->nbhybrids; - for (int i = 0; i < _nbhybrids; i++) - { - ManaCostHybrid * h = _cost->hybrids[i]; - diff[h->color1 * 2 + 1] -= h->value1; - } -} - -int ManaCost::tryToPayHybrids(ManaCostHybrid * _hybrids[], int _nbhybrids, int diff[]) -{ - if (!_nbhybrids) - return 1; - int result = 0; - ManaCostHybrid * h = _hybrids[_nbhybrids - 1]; - if (diff[h->color1 * 2 + 1] >= h->value1) - { - diff[h->color1 * 2 + 1] -= h->value1; - result = tryToPayHybrids(_hybrids, _nbhybrids - 1, diff); - if (result) - return 1; - diff[h->color1 * 2 + 1] += h->value1; - } - if (diff[h->color2 * 2 + 1] >= h->value2) - { - diff[h->color2 * 2 + 1] -= h->value2; - result = tryToPayHybrids(_hybrids, _nbhybrids - 1, diff); - if (result) - return 1; - diff[h->color2 * 2 + 1] += h->value2; - } - return 0; -} - -//compute the difference between two mana costs -ManaCost * ManaCost::Diff(ManaCost * _cost) -{ - int diff[(Constants::MTG_NB_COLORS + 1) * 2]; - diff[Constants::MTG_NB_COLORS * 2] = Constants::MTG_NB_COLORS; - for (int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - diff[i * 2] = i; - diff[i * 2 + 1] = cost[i] - _cost->getCost(i); - } - int hybridResult = tryToPayHybrids(_cost->hybrids, _cost->nbhybrids, diff); - if (!hybridResult) - randomDiffHybrids(_cost, diff); - - //Colorless mana, special case - int colorless_idx = Constants::MTG_COLOR_ARTIFACT * 2 + 1; - if (diff[colorless_idx] < 0) - { - for (int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - if (diff[i * 2 + 1] > 0) - { - if (diff[i * 2 + 1] + diff[colorless_idx] > 0) - { - diff[i * 2 + 1] += diff[colorless_idx]; - diff[colorless_idx] = 0; - break; - } - else - { - diff[colorless_idx] += diff[i * 2 + 1]; - diff[i * 2 + 1] = 0; - } - } - } - } - - //Cost X - if (_cost->hasX()) - { - diff[Constants::MTG_NB_COLORS * 2 + 1] = 0; - for (int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - if (diff[i * 2 + 1] > 0) - { - diff[Constants::MTG_NB_COLORS * 2 + 1] += diff[i * 2 + 1]; - diff[i * 2 + 1] = 0; - } - } - } - - ManaCost * result = NEW ManaCost(diff, Constants::MTG_NB_COLORS + 1); - return result; - -} - -string ManaCost::toString() -{ - ostringstream oss; - oss << "\n===ManaCost===\n"; - for (int i = 0; i <= Constants::MTG_NB_COLORS; i++) - { - if (cost[i]) - { - oss << Constants::MTGColorChars[i] << ":" << cost[i] << " - "; - } - } - - for (unsigned int i = 0; i < nbhybrids; i++) - { - ManaCostHybrid * h = hybrids[i]; - oss << "H:{" << Constants::MTGColorChars[h->color1] << ":" << h->value1 << "}/{" << Constants::MTGColorChars[h->color2] - << ":" << h->value2 << "}"; - } - oss << "\n=============\n"; - return oss.str(); -} - -#ifdef WIN32 -void ManaCost::Dump() -{ - DebugTrace( this->toString() ); -} - -#endif - -ostream& operator<<(ostream& out, const ManaCost& m) -{ - return out << "(manacost)"; -} - -void ManaPool::init() -{ - ManaCost::init(); - WEvent * e = NEW WEventEmptyManaPool(this); - GameObserver::GetInstance()->receiveEvent(e); -} - -ManaPool::ManaPool(Player * player) : - ManaCost(), player(player) -{ -} - -ManaPool::ManaPool(ManaCost * _manaCost, Player * player) : - ManaCost(_manaCost), player(player) -{ -} - -int ManaPool::remove(int color, int value) -{ - int result = ManaCost::remove(color, value); - for (int i = 0; i < value; ++i) - { - WEvent * e = NEW WEventConsumeMana(color, this); - GameObserver::GetInstance()->receiveEvent(e); - } - return result; -} - -int ManaPool::add(int color, int value, MTGCardInstance * source) -{ - int result = ManaCost::add(color, value); - for (int i = 0; i < value; ++i) - { - WEvent * e = NEW WEventEngageMana(color, source, this); - GameObserver::GetInstance()->receiveEvent(e); - } - return result; -} - -int ManaPool::add(ManaCost * _cost, MTGCardInstance * source) -{ - if (!_cost) - return 0; - int result = ManaCost::add(_cost); - for (unsigned int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - for (int j = 0; j < _cost->getCost(i); j++) - { - WEvent * e = NEW WEventEngageMana(i, source, this); - GameObserver::GetInstance()->receiveEvent(e); - } - } - return result; -} - -int ManaPool::pay(ManaCost * _cost) -{ - int current[Constants::MTG_NB_COLORS]; - for (unsigned int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - current[i] = cost[i]; - } - - int result = ManaCost::pay(_cost); - for (unsigned int i = 0; i < Constants::MTG_NB_COLORS; i++) - { - int value = current[i] - cost[i]; - for (int j = 0; j < value; j++) - { - WEvent * e = NEW WEventConsumeMana(i, this); - GameObserver::GetInstance()->receiveEvent(e); - - } - } - return result; -} +#include "PrecompiledHeader.h" + +#include "ManaCost.h" +#include "ManaCostHybrid.h" +#include "ExtraCost.h" +#include "TargetChooser.h" +#include "Targetable.h" +#include "Player.h" +#include "WEvent.h" +#include "MTGAbility.h" + +ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstance * c) +{ + ManaCost * manaCost; + if (_manaCost) + { + manaCost = _manaCost; + } + else + { + manaCost = NEW ManaCost(); + } + int state = 0; + size_t start = 0; + size_t end = 0; + while (!s.empty() && state != -1) + { + switch (state) + { + case 0: + start = s.find_first_of("{"); + if (start == string::npos) + { + return manaCost; + } + else + { + state = 1; + } + break; + case 1: + end = s.find_first_of("}"); + if (end == string::npos) + { + state = -1; + } + else + { + string value = s.substr(start + 1, end - 1 - start); + + if (value == "u") + { + manaCost->add(Constants::MTG_COLOR_BLUE, 1); + } + else if (value == "b") + { + manaCost->add(Constants::MTG_COLOR_BLACK, 1); + } + else if (value == "w") + { + manaCost->add(Constants::MTG_COLOR_WHITE, 1); + } + else if (value == "g") + { + manaCost->add(Constants::MTG_COLOR_GREEN, 1); + } + else if (value == "r") + { + manaCost->add(Constants::MTG_COLOR_RED, 1); + + } + else + { + + //Parse target for extraCosts + TargetChooserFactory tcf; + TargetChooser * tc = NULL; + size_t target_start = value.find("("); + size_t target_end = value.find(")"); + if (target_start != string::npos && target_end != string::npos) + { + string target = value.substr(target_start + 1, target_end - 1 - target_start); + tc = tcf.createTargetChooser(target, c); + } + + //switch on the first letter. If two costs share their first letter, add an "if" within the switch + switch (value[0]) + { + case 'x': + manaCost->x(); + break; + case 't': //Tap + if (value == "t") + { + //default Tap is handled outside of Manacost + } + else + { + manaCost->addExtraCost(NEW TapTargetCost(tc)); + } + break; + case 's': + if (value == "s2l") + { //Send To Library Cost (move from anywhere to Library) + manaCost->addExtraCost(NEW ToLibraryCost(tc)); + } + else + { //Sacrifice + manaCost->addExtraCost(NEW SacrificeCost(tc)); + } + break; + case 'e': //Exile + manaCost->addExtraCost(NEW ExileTargetCost(tc)); + break; + case 'h': //bounce (move to Hand) + manaCost->addExtraCost(NEW BounceTargetCost(tc)); + break; + case 'l': + if (value == "l2e") + { //Mill to exile yourself as a cost (Library 2 Exile) + manaCost->addExtraCost(NEW MillExileCost(tc)); + } + else + { //Life cost + manaCost->addExtraCost(NEW LifeCost(tc)); + } + break; + case 'd': //DiscardRandom cost + if (value == "d") + { + manaCost->addExtraCost(NEW DiscardRandomCost(tc)); + } + else + { + manaCost->addExtraCost(NEW DiscardCost(tc)); + } + break; + case 'm': //Mill yourself as a cost + manaCost->addExtraCost(NEW MillCost(tc)); + break; + case 'n': //return unblocked attacker cost + TargetChooserFactory tcf; + tc = tcf.createTargetChooser("creature|myBattlefield", c); + manaCost->addExtraCost(NEW Ninja(tc)); + break; + case 'c': //Counters + { + size_t counter_start = value.find("("); + size_t counter_end = value.find(")", counter_start); + AbilityFactory abf; + string counterString = value.substr(counter_start + 1, counter_end - counter_start - 1); + Counter * counter = abf.parseCounter(counterString, c); + size_t separator = value.find(",", counter_start); + size_t separator2 = string::npos; + if (separator != string::npos) + { + separator2 = value.find(",", separator + 1); + } + SAFE_DELETE(tc); + size_t target_start = string::npos; + if (separator2 != string::npos) + { + target_start = value.find(",", separator2 + 1); + } + size_t target_end = counter_end; + if (target_start != string::npos && target_end != string::npos) + { + string target = value.substr(target_start + 1, target_end - 1 - target_start); + tc = tcf.createTargetChooser(target, c); + } + manaCost->addExtraCost(NEW CounterCost(counter, tc)); + break; + } + default: //uncolored cost and hybrid costs + { + int intvalue = atoi(value.c_str()); + int colors[2]; + int values[2]; + if (intvalue < 10 && value.size() > 1) + { + for (int i = 0; i < 2; i++) + { + char c = value[i]; + if (c >= '0' && c <= '9') + { + colors[i] = Constants::MTG_COLOR_ARTIFACT; + values[i] = c - '0'; + } + else + { + for (int j = 0; j < Constants::MTG_NB_COLORS; j++) + { + if (c == Constants::MTGColorChars[j]) + { + colors[i] = j; + values[i] = 1; + } + } + } + } + manaCost->addHybrid(colors[0], values[0], colors[1], values[1]); + } + else + { + manaCost->add(Constants::MTG_COLOR_ARTIFACT, intvalue); + } + break; + } + } + } + s = s.substr(end + 1); + state = 0; + } + break; + default: + break; + } + } + return manaCost; +} + +ManaCost::ManaCost() +{ + init(); +} +ManaCost::ManaCost(int _cost[], int nb_elems) +{ + init(); + int i; + int total = nb_elems; + for (i = 0; i < total; i++) + { + cost[_cost[i * 2]] = _cost[i * 2 + 1]; + } + +} + +ManaCost::ManaCost(ManaCost * _manaCost) +{ + init(); + int i; + for (i = 0; i <= Constants::MTG_NB_COLORS; i++) + { + cost[i] = _manaCost->getCost(i); + } +} + +ManaCost::~ManaCost() +{ + for (unsigned int i = 0; i < nbhybrids; i++) + { + SAFE_DELETE(hybrids[i]); + } + SAFE_DELETE(extraCosts); + SAFE_DELETE(kicker); + SAFE_DELETE(alternative); + SAFE_DELETE(BuyBack); + SAFE_DELETE(FlashBack); + SAFE_DELETE(Retrace); + SAFE_DELETE(morph); +} + +void ManaCost::x() +{ + cost[Constants::MTG_NB_COLORS] = 1; +} + +int ManaCost::hasX() +{ + return cost[Constants::MTG_NB_COLORS]; +} + +void ManaCost::init() +{ + int i; + for (i = 0; i <= Constants::MTG_NB_COLORS; i++) + { + cost[i] = 0; + } + nbhybrids = 0; + extraCosts = NULL; + extraCostsIsCopy = 0; + kicker = NULL; + alternative = NULL; + BuyBack = NULL; + FlashBack = NULL; + Retrace = NULL; + morph = NULL; +} + +void ManaCost::copy(ManaCost * _manaCost) +{ + if (!_manaCost) + return; + for (unsigned int i = 0; i <= Constants::MTG_NB_COLORS; i++) + { + cost[i] = _manaCost->getCost(i); + } + for (unsigned int i = 0; i < nbhybrids; i++) + { + SAFE_DELETE(hybrids[i]); + } + for (unsigned int i = 0; i < _manaCost->nbhybrids; i++) + { + hybrids[i] = NEW ManaCostHybrid((*_manaCost->hybrids[i])); + } + nbhybrids = _manaCost->nbhybrids; + + SAFE_DELETE(extraCosts); + if (_manaCost->extraCosts) + { + extraCosts = _manaCost->extraCosts->clone(); + } + + SAFE_DELETE(kicker); + if (_manaCost->kicker) + { + kicker = NEW ManaCost(); + kicker->copy(_manaCost->kicker); + } + SAFE_DELETE(alternative); + if (_manaCost->alternative) + { + alternative = NEW ManaCost(); + alternative->copy(_manaCost->alternative); + } + SAFE_DELETE(BuyBack); + if (_manaCost->BuyBack) + { + BuyBack = NEW ManaCost(); + BuyBack->copy(_manaCost->BuyBack); + } + SAFE_DELETE(FlashBack); + if (_manaCost->FlashBack) + { + FlashBack = NEW ManaCost(); + FlashBack->copy(_manaCost->FlashBack); + } + SAFE_DELETE(Retrace); + if (_manaCost->Retrace) + { + Retrace = NEW ManaCost(); + Retrace->copy(_manaCost->Retrace); + } + SAFE_DELETE(morph); + if (_manaCost->morph) + { + morph = NEW ManaCost(); + morph->copy(_manaCost->morph); + } +} + +int ManaCost::getCost(int color) +{ + return cost[color]; +} + +ManaCostHybrid * ManaCost::getHybridCost(unsigned int i) +{ + if (nbhybrids <= i) + return NULL; + return hybrids[i]; +} + +int ManaCost::hasColor(int color) +{ + if (cost[color]) + return 1; + for (unsigned int i = 0; i < nbhybrids; i++) + { + if (hybrids[i]->hasColor(color)) + return 1; + } + return 0; +} + +int ManaCost::isNull() +{ + if (getConvertedCost()) + return 0; + if (extraCosts) + return 0; + return 1; +} + +int ManaCost::getConvertedCost() +{ + int result = 0; + for (unsigned int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + result += cost[i]; + } + for (unsigned int i = 0; i < nbhybrids; i++) + { + result += hybrids[i]->getConvertedCost(); + } + return result; +} + +int ManaCost::remove(int color, int value) +{ + cost[color] -= value; + if (cost[color] < 0) + { + cost[color] = 0; + } + return 1; +} + +int ManaCost::add(int color, int value) +{ + if (value < 0) + value = 0; + cost[color] += value; + return 1; +} + +int ManaCost::add(ManaCost * _cost) +{ + if (!_cost) + return 0; + for (unsigned int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + cost[i] += _cost->getCost(i); + } + for (unsigned int i = 0; i < _cost->nbhybrids; i++) + { + hybrids[nbhybrids] = NEW ManaCostHybrid((*_cost->hybrids[i])); + nbhybrids++; + } + return 1; +} + +int ManaCost::addHybrid(int c1, int v1, int c2, int v2) +{ + ManaCostHybrid * h = NEW ManaCostHybrid(c1, v1, c2, v2); + hybrids[nbhybrids] = h; + nbhybrids++; + return nbhybrids; +} + +int ManaCost::addExtraCost(ExtraCost * _cost) +{ + if (!extraCosts) + extraCosts = NEW ExtraCosts(); + extraCosts->costs.push_back(_cost); + return 1; +} + +int ManaCost::isExtraPaymentSet() +{ + if (!extraCosts) + return 1; + return extraCosts->isPaymentSet(); +} + +int ManaCost::canPayExtra() +{ + if (!extraCosts) + return 1; + return extraCosts->canPay(); +} + +int ManaCost::doPayExtra() +{ + if (!extraCosts) + return 0; + return extraCosts->doPay(); //TODO reset ? +} + +int ManaCost::setExtraCostsAction(MTGAbility * action, MTGCardInstance * card) +{ + if (extraCosts) + extraCosts->setAction(action, card); + return 1; +} + +int ManaCost::pay(ManaCost * _cost) +{ + int result = MANA_PAID; + ManaCost * toPay = NEW ManaCost(); + toPay->copy(_cost); + + if (toPay->kicker) + { + toPay->add(toPay->kicker); + if (!canAfford(toPay)) + { + toPay->copy(_cost); + } + else + { + result = MANA_PAID_WITH_KICKER; + } + } + + ManaCost * diff = Diff(toPay); + for (int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + cost[i] = diff->getCost(i); + } + delete diff; + delete toPay; + return result; + //TODO return 0 if can't afford the cost! +} + +//return 1 if _cost can be paid with current data, 0 otherwise +int ManaCost::canAfford(ManaCost * _cost) +{ + ManaCost * diff = Diff(_cost); + int positive = diff->isPositive(); + delete diff; + if (positive) + { + return 1; + } + return 0; +} + +int ManaCost::isPositive() +{ + for (int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + + if (cost[i] < 0) + { + return 0; + } + } + return 1; + +} + +void ManaCost::randomDiffHybrids(ManaCost * _cost, int diff[]) +{ + int _nbhybrids = _cost->nbhybrids; + for (int i = 0; i < _nbhybrids; i++) + { + ManaCostHybrid * h = _cost->hybrids[i]; + diff[h->color1 * 2 + 1] -= h->value1; + } +} + +int ManaCost::tryToPayHybrids(ManaCostHybrid * _hybrids[], int _nbhybrids, int diff[]) +{ + if (!_nbhybrids) + return 1; + int result = 0; + ManaCostHybrid * h = _hybrids[_nbhybrids - 1]; + if (diff[h->color1 * 2 + 1] >= h->value1) + { + diff[h->color1 * 2 + 1] -= h->value1; + result = tryToPayHybrids(_hybrids, _nbhybrids - 1, diff); + if (result) + return 1; + diff[h->color1 * 2 + 1] += h->value1; + } + if (diff[h->color2 * 2 + 1] >= h->value2) + { + diff[h->color2 * 2 + 1] -= h->value2; + result = tryToPayHybrids(_hybrids, _nbhybrids - 1, diff); + if (result) + return 1; + diff[h->color2 * 2 + 1] += h->value2; + } + return 0; +} + +//compute the difference between two mana costs +ManaCost * ManaCost::Diff(ManaCost * _cost) +{ + int diff[(Constants::MTG_NB_COLORS + 1) * 2]; + diff[Constants::MTG_NB_COLORS * 2] = Constants::MTG_NB_COLORS; + for (int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + diff[i * 2] = i; + diff[i * 2 + 1] = cost[i] - _cost->getCost(i); + } + int hybridResult = tryToPayHybrids(_cost->hybrids, _cost->nbhybrids, diff); + if (!hybridResult) + randomDiffHybrids(_cost, diff); + + //Colorless mana, special case + int colorless_idx = Constants::MTG_COLOR_ARTIFACT * 2 + 1; + if (diff[colorless_idx] < 0) + { + for (int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + if (diff[i * 2 + 1] > 0) + { + if (diff[i * 2 + 1] + diff[colorless_idx] > 0) + { + diff[i * 2 + 1] += diff[colorless_idx]; + diff[colorless_idx] = 0; + break; + } + else + { + diff[colorless_idx] += diff[i * 2 + 1]; + diff[i * 2 + 1] = 0; + } + } + } + } + + //Cost X + if (_cost->hasX()) + { + diff[Constants::MTG_NB_COLORS * 2 + 1] = 0; + for (int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + if (diff[i * 2 + 1] > 0) + { + diff[Constants::MTG_NB_COLORS * 2 + 1] += diff[i * 2 + 1]; + diff[i * 2 + 1] = 0; + } + } + } + + ManaCost * result = NEW ManaCost(diff, Constants::MTG_NB_COLORS + 1); + return result; + +} + +string ManaCost::toString() +{ + ostringstream oss; + oss << "\n===ManaCost===\n"; + for (int i = 0; i <= Constants::MTG_NB_COLORS; i++) + { + if (cost[i]) + { + oss << Constants::MTGColorChars[i] << ":" << cost[i] << " - "; + } + } + + for (unsigned int i = 0; i < nbhybrids; i++) + { + ManaCostHybrid * h = hybrids[i]; + oss << "H:{" << Constants::MTGColorChars[h->color1] << ":" << h->value1 << "}/{" << Constants::MTGColorChars[h->color2] + << ":" << h->value2 << "}"; + } + oss << "\n=============\n"; + return oss.str(); +} + +#ifdef WIN32 +void ManaCost::Dump() +{ + DebugTrace( this->toString() ); +} + +#endif + +ostream& operator<<(ostream& out, const ManaCost& m) +{ + return out << "(manacost)"; +} + +void ManaPool::init() +{ + ManaCost::init(); + WEvent * e = NEW WEventEmptyManaPool(this); + GameObserver::GetInstance()->receiveEvent(e); +} + +ManaPool::ManaPool(Player * player) : + ManaCost(), player(player) +{ +} + +ManaPool::ManaPool(ManaCost * _manaCost, Player * player) : + ManaCost(_manaCost), player(player) +{ +} + +int ManaPool::remove(int color, int value) +{ + int result = ManaCost::remove(color, value); + for (int i = 0; i < value; ++i) + { + WEvent * e = NEW WEventConsumeMana(color, this); + GameObserver::GetInstance()->receiveEvent(e); + } + return result; +} + +int ManaPool::add(int color, int value, MTGCardInstance * source) +{ + int result = ManaCost::add(color, value); + for (int i = 0; i < value; ++i) + { + WEvent * e = NEW WEventEngageMana(color, source, this); + GameObserver::GetInstance()->receiveEvent(e); + } + return result; +} + +int ManaPool::add(ManaCost * _cost, MTGCardInstance * source) +{ + if (!_cost) + return 0; + int result = ManaCost::add(_cost); + for (unsigned int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + for (int j = 0; j < _cost->getCost(i); j++) + { + WEvent * e = NEW WEventEngageMana(i, source, this); + GameObserver::GetInstance()->receiveEvent(e); + } + } + return result; +} + +int ManaPool::pay(ManaCost * _cost) +{ + int current[Constants::MTG_NB_COLORS]; + for (unsigned int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + current[i] = cost[i]; + } + + int result = ManaCost::pay(_cost); + for (unsigned int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + int value = current[i] - cost[i]; + for (int j = 0; j < value; j++) + { + WEvent * e = NEW WEventConsumeMana(i, this); + GameObserver::GetInstance()->receiveEvent(e); + + } + } + return result; +}