diff --git a/projects/mtg/include/DeckManager.h b/projects/mtg/include/DeckManager.h index 2c6d67ec4..b3cf8d9dd 100644 --- a/projects/mtg/include/DeckManager.h +++ b/projects/mtg/include/DeckManager.h @@ -27,10 +27,13 @@ public: vector * getPlayerDeckOrderList(); vector * getAIDeckOrderList(); + void saveDeck ( MTGDeck *deck, int deckId, MTGAllCards *collection ); + void AddMetaData( const std::string& filename, bool isAI); DeckMetaData* getDeckMetaDataById(int deckId, bool isAI); DeckMetaData* getDeckMetaDataByFilename(const std::string& filename, bool isAI); StatsWrapper* getExtendedStatsForDeckId(int deckId, MTGAllCards* collection, bool isAI); StatsWrapper* getExtendedDeckStats(DeckMetaData* selectedDeck, MTGAllCards* collection, bool isAI); + static DeckManager* GetInstance(); static void EndInstance(); diff --git a/projects/mtg/include/DeckMetaData.h b/projects/mtg/include/DeckMetaData.h index d04abbefd..eeb074050 100644 --- a/projects/mtg/include/DeckMetaData.h +++ b/projects/mtg/include/DeckMetaData.h @@ -22,13 +22,16 @@ private: string mName; int mDeckId; string mAvatarFilename; - + string mColorIndex; + // statistical information int mGamesPlayed, mVictories, mPercentVictories, mDifficulty; DeckMetaData(); public: + + DeckMetaData(const string& filename); void LoadDeck(); void LoadStats(); @@ -38,6 +41,7 @@ public: string getDescription(); string getName(); string getAvatarFilename(); + string getColorIndex(); int getAvatarId(int deckId); string getStatsSummary(); @@ -48,6 +52,7 @@ public: int getDifficulty(); string getDifficultyString(); + void setColorIndex(const string& colorIndex); void Invalidate(); string mStatsFilename; @@ -57,16 +62,5 @@ public: bool mIsAI; }; -class DeckMetaDataList -{ -private: - map values; - -public: - void invalidate(string filename); - DeckMetaData * get(string filename); - ~DeckMetaDataList(); - static DeckMetaDataList * decksMetaData; -}; #endif diff --git a/projects/mtg/include/GameOptions.h b/projects/mtg/include/GameOptions.h index 781185d4b..69fc35969 100644 --- a/projects/mtg/include/GameOptions.h +++ b/projects/mtg/include/GameOptions.h @@ -59,6 +59,7 @@ public: //My interrupts INTERRUPTMYSPELLS, INTERRUPTMYABILITIES, + SAVEDETAILEDDECKINFO, //Other interrupts INTERRUPT_BEFOREBEGIN, INTERRUPT_UNTAP, diff --git a/projects/mtg/include/MTGDeck.h b/projects/mtg/include/MTGDeck.h index e3acf9e13..c0a87726e 100644 --- a/projects/mtg/include/MTGDeck.h +++ b/projects/mtg/include/MTGDeck.h @@ -141,6 +141,7 @@ public: map cards; string meta_desc; string meta_name; + string meta_deck_colors; int totalCards(); int totalPrice(); MTGDeck(MTGAllCards * _allcards); @@ -154,6 +155,7 @@ public: int removeAll(); int add(MTGCard * card); int remove(MTGCard * card); + string getFilename(); int save(); int save(string destFileName, bool useExpandedDescriptions, string &deckTitle, string &deckDesc); MTGCard * getCardById(int id); diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 7700fb357..061f4540c 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -7,6 +7,7 @@ #include "ExtraCost.h" #include "GuiCombat.h" #include "GameStateDuel.h" +#include "DeckManager.h" const char * const MTG_LAND_TEXTS[] = { "artifact", "forest", "island", "mountain", "swamp", "plains", "other lands" }; @@ -1139,7 +1140,7 @@ AIPlayer * AIPlayerFactory::createAIPlayer(MTGAllCards * collection, Player * op char deckFile[512]; char avatarFile[512]; char deckFileSmall[512]; - + if (deckid == GameStateDuel::MENUITEM_EVIL_TWIN) { //Evil twin sprintf(deckFile, "%s", opponent->deckFile.c_str()); @@ -1177,11 +1178,10 @@ AIPlayer * AIPlayerFactory::createAIPlayer(MTGAllCards * collection, Player * op } MTGDeck * tempDeck = NEW MTGDeck(deckFile, collection); - //MTGPlayerCards * deck = NEW MTGPlayerCards(tempDeck); AIPlayerBaka * baka = NEW AIPlayerBaka(tempDeck, deckFile, deckFileSmall, avatarFile); baka->deckId = deckid; - - delete tempDeck; + DeckManager::GetInstance()->saveDeck( tempDeck, deckid, collection); + SAFE_DELETE(tempDeck); return baka; } diff --git a/projects/mtg/src/DeckManager.cpp b/projects/mtg/src/DeckManager.cpp index 663e8ba6b..018083f43 100644 --- a/projects/mtg/src/DeckManager.cpp +++ b/projects/mtg/src/DeckManager.cpp @@ -51,7 +51,19 @@ DeckMetaData* DeckManager::getDeckMetaDataById( int deckId, bool isAI ) { deck = *pos; } - + else + { + ostringstream deckFilename; + string filepath; + if ( isAI ) + filepath = options.profileFile( "ai/baka/"); + else + filepath = options.profileFile( "" ); + + deckFilename << filepath << "/deck" << deckId << ".txt"; + AddMetaData( deckFilename.str(), isAI ); + deck = deckList.back(); + } return deck; } @@ -82,10 +94,54 @@ DeckMetaData* DeckManager::getDeckMetaDataByFilename(const string& filename, boo { deck = *pos; } - + else + { + if ( FileExists( filename) ) + { + AddMetaData( filename, isAI ); + deck = deckList.back(); + } + } return deck; } +void DeckManager::saveDeck( MTGDeck *deck, int deckId, MTGAllCards *collection ) +{ + if ( deck->meta_deck_colors == "" ) + { + bool isAI = deck->getFilename().find("baka") != string::npos; + StatsWrapper *stats = getExtendedStatsForDeckId( deckId, collection, isAI ); + ostringstream manaColorIndex; + for (int i = Constants::MTG_COLOR_ARTIFACT; i < Constants::MTG_COLOR_LAND; ++i) + { + if (stats->totalCostPerColor[i] != 0) + manaColorIndex << "1"; + else + manaColorIndex <<"0"; + } + deck->meta_deck_colors = manaColorIndex.str(); + // save the deck to disk + deck->save( deck->getFilename(), true, deck->meta_name, deck->meta_desc ); + // update DeckMetaData object + DeckMetaData *meta = getDeckMetaDataByFilename(deck->getFilename(), isAI); + meta->setColorIndex( deck->meta_deck_colors ); + } +} + + +void DeckManager::AddMetaData( const string& filename, bool isAI ) +{ + if (isAI) + { + aiDeckOrderList.push_back ( NEW DeckMetaData( filename ) ); + aiDeckStatsMap.insert( make_pair( filename.c_str(), new StatsWrapper( aiDeckOrderList.back()->getDeckId()) )); + } + else + { + playerDeckOrderList.push_back ( NEW DeckMetaData( filename ) ); + playerDeckStatsMap.insert( make_pair( filename.c_str(), new StatsWrapper( playerDeckOrderList.back()->getDeckId()) )); + } +} StatsWrapper * DeckManager::getExtendedStatsForDeckId( int deckId, MTGAllCards *collection, bool isAI ) { @@ -111,7 +167,7 @@ StatsWrapper * DeckManager::getExtendedDeckStats( DeckMetaData *selectedDeck, MT int deckId = selectedDeck->getDeckId(); map* statsMap = isAI ? &aiDeckStatsMap : &playerDeckStatsMap; - if (statsMap->find(deckName) == statsMap->end()) + if ( statsMap->find(deckName) == statsMap->end()) { stats = NEW StatsWrapper(deckId); stats->updateStats( deckName, collection); @@ -120,8 +176,9 @@ StatsWrapper * DeckManager::getExtendedDeckStats( DeckMetaData *selectedDeck, MT else { stats = statsMap->find(deckName)->second; + if ( stats->needUpdate ) + stats->updateStats( deckName, collection ); } - return stats; } @@ -133,15 +190,27 @@ void DeckManager::EndInstance() { if (mInstance) { - mInstance->aiDeckOrderList.clear(); - mInstance->playerDeckOrderList.clear(); + map::iterator it; + vector::iterator metaDataIter; + for (it = mInstance->aiDeckStatsMap.begin(); it != mInstance->aiDeckStatsMap.end(); it++){ SAFE_DELETE(it->second); } for (it = mInstance->playerDeckStatsMap.begin(); it != mInstance->playerDeckStatsMap.end(); it++){ SAFE_DELETE(it->second); } + + for( metaDataIter = mInstance->aiDeckOrderList.begin(); metaDataIter != mInstance->aiDeckOrderList.end(); ++metaDataIter) + { + SAFE_DELETE( *metaDataIter ); + } + for( metaDataIter = mInstance->playerDeckOrderList.begin(); metaDataIter != mInstance->playerDeckOrderList.end(); ++metaDataIter) + { + SAFE_DELETE( *metaDataIter ); + } + mInstance->aiDeckOrderList.clear(); + mInstance->playerDeckOrderList.clear(); mInstance->aiDeckStatsMap.clear(); mInstance->playerDeckStatsMap.clear(); SAFE_DELETE( mInstance ); @@ -163,10 +232,7 @@ DeckManager* DeckManager::GetInstance() // p2 is the opponent int DeckManager::getDifficultyRating(Player *statsPlayer, Player *player) { - DeckMetaDataList * metas = DeckMetaDataList::decksMetaData; - - DeckMetaData *meta = metas->get(player->deckFile); - + DeckMetaData *meta = DeckManager::GetInstance()->getDeckMetaDataByFilename(player->deckFile, (player->isAI() == 1) ); return meta->getDifficulty(); } diff --git a/projects/mtg/src/DeckMenu.cpp b/projects/mtg/src/DeckMenu.cpp index d7d8e2da6..62d9f1041 100644 --- a/projects/mtg/src/DeckMenu.cpp +++ b/projects/mtg/src/DeckMenu.cpp @@ -220,7 +220,8 @@ void DeckMenu::Render() 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) { @@ -247,8 +248,28 @@ void DeckMenu::Render() mScroller->Render(); RenderBackground(); - - renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); + + // display the deck mana colors if known + // We only want to display the mana symbols on the game screens and not the Deck Editor screens. + // Need a better way to determine when to display the mana symbols. Perhaps make it a property setting. + bool displayDeckMana = backgroundName.find("DeckMenuBackdrop") != string::npos; + float manaIconX = 300; + float manaIconY = 75; + if (mSelectedDeck &&displayDeckMana) + { + string deckManaColors = mSelectedDeck->getColorIndex(); + if ( deckManaColors.compare("") != 0 ) + for( int colorIdx = Constants::MTG_COLOR_ARTIFACT; colorIdx < 5; ++colorIdx ) + { + if ( (deckManaColors.at(colorIdx) == '1') != 0) + { + renderer->RenderQuad(manaIcons[colorIdx], manaIconX, manaIconY); + manaIconX += 30; + } + } + } + + renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); stars->Render(); renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); diff --git a/projects/mtg/src/DeckMetaData.cpp b/projects/mtg/src/DeckMetaData.cpp index bbe7f016a..8502f04ed 100644 --- a/projects/mtg/src/DeckMetaData.cpp +++ b/projects/mtg/src/DeckMetaData.cpp @@ -9,8 +9,6 @@ //Merge this with DeckStats //Have this class handle all the Meta Data rather than relying on MTGDeck. Then MTGDeck would have a MetaData object... -DeckMetaDataList * DeckMetaDataList::decksMetaData = NEW DeckMetaDataList(); - DeckMetaData::DeckMetaData(const string& filename) : mFilename(filename), mGamesPlayed(0), mVictories(0), mPercentVictories(0), mDifficulty(0), mDeckLoaded(false), mStatsLoaded(false) @@ -96,46 +94,13 @@ void DeckMetaData::LoadDeck() mName = trim(deck.meta_name); mDescription = trim(deck.meta_desc); mDeckId = atoi((mFilename.substr(mFilename.find("deck") + 4, mFilename.find(".txt"))).c_str()); - + mColorIndex = deck.meta_deck_colors; mDeckLoaded = true; } } -DeckMetaDataList::~DeckMetaDataList() -{ - for (map::iterator it = values.begin(); it != values.end(); ++it) - { - SAFE_DELETE(it->second); - } - values.clear(); -} - -void DeckMetaDataList::invalidate(string filename) -{ - map::iterator it = values.find(filename); - if (it != values.end()) - { - SAFE_DELETE(it->second); - values.erase(it); - } -} - -DeckMetaData * DeckMetaDataList::get(string filename) -{ - map::iterator it = values.find(filename); - if (it == values.end()) - { - if (fileExists(filename.c_str())) - { - values[filename] = NEW DeckMetaData(filename); - } - } - - return values[filename]; //this creates a NULL entry if the file does not exist -} - //Accessors string DeckMetaData::getFilename() @@ -158,6 +123,11 @@ string DeckMetaData::getAvatarFilename() return mAvatarFilename; } +string DeckMetaData::getColorIndex() +{ + return mColorIndex; +} + int DeckMetaData::getGamesPlayed() { return mGamesPlayed; @@ -211,6 +181,11 @@ string DeckMetaData::getStatsSummary() return statsSummary.str(); } +void DeckMetaData::setColorIndex(const string& colorIndex) +{ + mColorIndex = colorIndex; +} + void DeckMetaData::Invalidate() { mStatsLoaded = false; diff --git a/projects/mtg/src/GameApp.cpp b/projects/mtg/src/GameApp.cpp index 2c51a03b1..355f12d0d 100644 --- a/projects/mtg/src/GameApp.cpp +++ b/projects/mtg/src/GameApp.cpp @@ -279,7 +279,6 @@ void GameApp::Destroy() DeckStats::EndInstance(); SAFE_DELETE(Subtypes::subtypesList); - SAFE_DELETE(DeckMetaDataList::decksMetaData); playMusic("none"); diff --git a/projects/mtg/src/GameOptions.cpp b/projects/mtg/src/GameOptions.cpp index 35cca2af6..7a84d4034 100644 --- a/projects/mtg/src/GameOptions.cpp +++ b/projects/mtg/src/GameOptions.cpp @@ -49,6 +49,7 @@ const string Options::optionNames[] = { "aidecks", "interruptMySpells", "interruptMyAbilities", + "saveDetailedDeckInfo", //General interrupts "interruptBeforeBegin", "interruptUntap", diff --git a/projects/mtg/src/GameState.cpp b/projects/mtg/src/GameState.cpp index 421f939ec..bd49e1856 100644 --- a/projects/mtg/src/GameState.cpp +++ b/projects/mtg/src/GameState.cpp @@ -6,6 +6,7 @@ #include "SimpleMenu.h" #include "DeckStats.h" #include "DeckMetaData.h" +#include "DeckManager.h" #include "Player.h" // The purpose of this method is to create a listing of decks to be used for the input menu @@ -37,15 +38,16 @@ vector GameState::BuildDeckList(const string& path, const string { vector retList; - DeckMetaDataList * metas = DeckMetaDataList::decksMetaData; int found = 1; int nbDecks = 1; + DeckManager *deckManager = DeckManager::GetInstance(); + bool isAI = path.find("baka") != string::npos; while (found && (!maxDecks || nbDecks <= maxDecks)) { found = 0; std::ostringstream filename; filename << path << "/deck" << nbDecks << ".txt"; - DeckMetaData * meta = metas->get(filename.str()); + DeckMetaData * meta = deckManager->getDeckMetaDataByFilename(filename.str(), isAI); if (meta) { diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index 00ec86c06..0e0557b7f 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -171,7 +171,7 @@ void GameStateDuel::loadPlayer(int playerId, int decknb, int isAI) sprintf(deckFileSmall, "player_deck%i", decknb); MTGDeck * tempDeck = NEW MTGDeck(deckFile, mParent->collection); mPlayers[playerId] = NEW HumanPlayer(tempDeck, deckFile, deckFileSmall); - + DeckManager::GetInstance()->saveDeck( tempDeck, decknb, mParent->collection); delete tempDeck; } else diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 5bf3457e0..26ba871cb 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -9,6 +9,7 @@ #include "WDataSrc.h" #include "MTGPack.h" #include "utils.h" +#include "DeckManager.h" #if defined (WIN32) || defined (LINUX) #include @@ -43,13 +44,10 @@ static inline int getGrade(int v) //MTGAllCards int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primitive) { - if ('#' == s[0]) return 0; + if ('#' == s[0]) return 1; // a comment shouldn't be treated as an error condition 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; @@ -373,6 +371,7 @@ int MTGAllCards::load(const char * config_file, const char * set_name, int autol const int set_id = set_name ? setlist.Add(set_name) : MTGSets::INTERNAL_SET; MTGSetInfo *si = setlist.getInfo(set_id); + int lineNumber = 0; wagic::ifstream setFile(config_file, ios::in | ios::ate); if (!setFile) return total_cards; @@ -389,6 +388,7 @@ int MTGAllCards::load(const char * config_file, const char * set_name, int autol while (true) { if (!std::getline(stream, s)) return total_cards; + lineNumber++; if (!s.size()) continue; if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); // Handle DOS files @@ -435,7 +435,8 @@ int MTGAllCards::load(const char * config_file, const char * set_name, int autol } else { - processConfLine(s, tempCard, tempPrimitive); + if (!processConfLine(s, tempCard, tempPrimitive)) + DebugTrace("MTGDECK: BAD Line: \n[" << lineNumber << "]: " << s ); } continue; } @@ -716,6 +717,12 @@ MTGDeck::MTGDeck(const char * config_file, MTGAllCards * _allcards, int meta_onl meta_desc.append(s.substr(found + 5)); continue; } + found = s.find("MANA:"); + if ( found != string::npos ) + { + string colorIndex = s.substr(found + 5); + meta_deck_colors = trim(colorIndex); + } continue; } if (meta_only) break; @@ -760,6 +767,11 @@ int MTGDeck::totalCards() return total_cards; } +string MTGDeck::getFilename() +{ + return filename; +} + MTGCard * MTGDeck::getCardById(int mtgId) { return database->getCardById(mtgId); @@ -970,8 +982,31 @@ int MTGDeck::save(string destFileName, bool useExpandedDescriptions, string &dec } file << "#DESC:" << desc << "\n"; } + + // add in color information + bool saveDetailedDeckInfo = options.get( Options::SAVEDETAILEDDECKINFO )->number == 1; - if (useExpandedDescriptions) + if ( filename.find("collection.dat") == string::npos ) + { + DeckManager *deckManager = DeckManager::GetInstance(); + file <<"#MANA:"; + string deckId = filename.substr( filename.find("/deck")+5, filename.find(".txt") - (filename.find("/deck")+5) ); + bool isAI = filename.find("ai/baka") != string::npos; + StatsWrapper *stats = deckManager->getExtendedStatsForDeckId( atoi(deckId.c_str()), this->database, isAI ); + + for (int i = Constants::MTG_COLOR_ARTIFACT; i < Constants::MTG_COLOR_LAND; ++i) + { + if (stats->totalCostPerColor[i] != 0) + file << "1"; + else + file <<"0"; + } + file << endl; + } + else + saveDetailedDeckInfo = false; + + if (useExpandedDescriptions || saveDetailedDeckInfo) { map::iterator it; for (it = cards.begin(); it != cards.end(); it++) @@ -1005,7 +1040,6 @@ int MTGDeck::save(string destFileName, bool useExpandedDescriptions, string &dec std::remove(destFileName.c_str()); rename(tmp.c_str(), destFileName.c_str()); } - DeckMetaDataList::decksMetaData->invalidate(destFileName); return 1; }