From 8af5870d4853250c80dda3b70e30d0a103c69b88 Mon Sep 17 00:00:00 2001 From: "techdragon.nguyen@gmail.com" Date: Mon, 31 Jan 2011 10:04:18 +0000 Subject: [PATCH] * Added new options parameter. "SaveDetailedDeckInfo". This will force the system to save all deck files in long format. This is not configurable from the game. It must be set manually inside options.txt. ie. saveDetailedDeckInfo=1 * added extra debug information (line number inside text file) when card parser fails to recognize a line. - modified return value from "processConfLine()" to return 0 only when a true error occurs and print out "MTGDeck: Bad Line: []: " - processConfLine will now return 1 for lines starting with "#". Previously it returned 0 which is incorrect as comments should not be considered as errors. * removed DeckMetaDataList class from code. This was duplicating the DeckMetaData storage in DeckManager * new feature for deck selection screens. - player decks will now have an indication of what mana color it consists of. - Ai decks will show symbols once the player has played against the AI deck at least once. -- This is made possible with a new meta data inside each deck file. MANA: --- projects/mtg/include/DeckManager.h | 3 + projects/mtg/include/DeckMetaData.h | 18 ++---- projects/mtg/include/GameOptions.h | 1 + projects/mtg/include/MTGDeck.h | 2 + projects/mtg/src/AIPlayer.cpp | 8 +-- projects/mtg/src/DeckManager.cpp | 86 +++++++++++++++++++++++++---- projects/mtg/src/DeckMenu.cpp | 27 ++++++++- projects/mtg/src/DeckMetaData.cpp | 47 ++++------------ projects/mtg/src/GameApp.cpp | 1 - projects/mtg/src/GameOptions.cpp | 1 + projects/mtg/src/GameState.cpp | 6 +- projects/mtg/src/GameStateDuel.cpp | 2 +- projects/mtg/src/MTGDeck.cpp | 48 +++++++++++++--- 13 files changed, 174 insertions(+), 76 deletions(-) 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; }