From ad7006e2deea930795adb9b7cbf61d1b458aedbe Mon Sep 17 00:00:00 2001 From: "wagic.jeck" Date: Tue, 8 Sep 2009 03:23:19 +0000 Subject: [PATCH] Jeck - Profile and cache improvements, booster duplicate likelihood reduced. * Cache now tracks missing textures for RetrieveQuad, not just RetrieveCard/RetrieveTexture. * Profile options are no longer overwritten when switching profiles. * Main menu notifies of alternate profile- "Database: X" becomes "Profile: Y of X cards." * Boosters iterates through cards, replacing duplicates. Stops after 15 tries to prevent infinite loops on small sets. * Very simplistic theme switcher, only displays when alternate themes are present. --- projects/mtg/include/GameOptions.h | 1 + projects/mtg/include/OptionItem.h | 8 +++++ projects/mtg/include/WResourceManager.h | 6 ++-- projects/mtg/src/GameOptions.cpp | 41 ++++++++++++--------- projects/mtg/src/GameStateMenu.cpp | 23 +++++++++--- projects/mtg/src/GameStateOptions.cpp | 6 ++-- projects/mtg/src/OptionItem.cpp | 46 +++++++++++++++++------- projects/mtg/src/ShopItem.cpp | 16 +++++++++ projects/mtg/src/WResourceManager.cpp | 47 +++++++++++++++++++------ 9 files changed, 145 insertions(+), 49 deletions(-) diff --git a/projects/mtg/include/GameOptions.h b/projects/mtg/include/GameOptions.h index 16eabf2cf..f26105e4a 100644 --- a/projects/mtg/include/GameOptions.h +++ b/projects/mtg/include/GameOptions.h @@ -75,6 +75,7 @@ public: string str; //All calls to asColor should include a fallback color for people without a theme. PIXEL_TYPE asColor(PIXEL_TYPE fallback = ARGB(255,255,255,255)); + bool isDefault(); //Returns true when number is 0 abd string is "" or "default" GameOption(int value = 0); GameOption(string value); }; diff --git a/projects/mtg/include/OptionItem.h b/projects/mtg/include/OptionItem.h index 237cb8040..33f5b937a 100644 --- a/projects/mtg/include/OptionItem.h +++ b/projects/mtg/include/OptionItem.h @@ -24,6 +24,7 @@ public: string displayValue, id; int hasFocus; bool canSelect; + bool bHidden; float x, y; float width, height; virtual ostream& toString(ostream& out)const; @@ -31,6 +32,7 @@ public: OptionItem( string _id, string _displayValue); virtual ~OptionItem() {}; + virtual bool Selectable() {return (canSelect && !bHidden);}; virtual void Entering(); virtual bool Leaving(); virtual void Update(float dt); @@ -69,6 +71,7 @@ class OptionString:public OptionItem{ virtual ostream& toString(ostream& out) const; bool bShowValue; }; + class OptionNewProfile:public OptionString{ public: OptionNewProfile(string _id, string _displayValue) : OptionString(_id, _displayValue) {bShowValue=false;}; @@ -118,6 +121,11 @@ private: string root; }; +class OptionTheme:public OptionDirectory{ + public: + OptionTheme(); +}; + class OptionProfile:public OptionDirectory{ public: OptionProfile(GameApp * _app); diff --git a/projects/mtg/include/WResourceManager.h b/projects/mtg/include/WResourceManager.h index dad70d1bd..24e581453 100644 --- a/projects/mtg/include/WResourceManager.h +++ b/projects/mtg/include/WResourceManager.h @@ -7,7 +7,7 @@ #include "MTGCard.h" #define CACHE_SIZE_PIXELS 2000000 -#define MAX_CACHE_OBJECTS 100 +#define MAX_CACHE_OBJECTS 200 class WCachedResource{ public: @@ -84,6 +84,7 @@ public: void ClearMisses(); void ClearUnlocked(); + void ClearSamples(); void Refresh(); //Refreshes all files in cache, for when mode/profile changes. unsigned int nowTime(); @@ -111,7 +112,6 @@ private: bool RemoveOldestTexture(); bool RemoveOldestSample(); bool cleanup(); - void clearSamples(); WCachedTexture * getCachedTexture(string filename, bool makenew = true, int mode = 0, int format = TEXTURE_FORMAT); WCachedTexture * getCachedCard(MTGCard * card, int type = CACHE_CARD, bool makenew = true); @@ -121,6 +121,8 @@ private: //For cached stuff map textureCache; map sampleCache; + + vector mTextureMissing; //For managed textures. //Current access time. int lastTime; diff --git a/projects/mtg/src/GameOptions.cpp b/projects/mtg/src/GameOptions.cpp index 840cb4499..f96a325ca 100644 --- a/projects/mtg/src/GameOptions.cpp +++ b/projects/mtg/src/GameOptions.cpp @@ -77,6 +77,19 @@ const string Metrics::KEYPAD_TC = "_tKeypadTC"; GameOption::GameOption(int value) : number(value){} GameOption::GameOption(string value) : str(value){} +bool GameOption::isDefault(){ + if(number != 0) + return false; + + string test = str; + std::transform(test.begin(),test.end(),test.begin(),::tolower); + + if(!test.size() || test == "default") + return true; + + return false; +} + PIXEL_TYPE GameOption::asColor(PIXEL_TYPE fallback) { unsigned char color[4]; @@ -177,14 +190,9 @@ GameSettings::GameSettings() //Load global options globalOptions = NEW GameOptions(GLOBAL_SETTINGS); - //Load profile options. - string temp = (*globalOptions)[Options::ACTIVE_PROFILE.substr(2)].str; - if(temp == "") - temp = "Default"; - (*globalOptions)[Options::ACTIVE_PROFILE.substr(2)].str = temp; - - themeOptions = NULL; profileOptions = NULL; + themeOptions = NULL; + checkProfile(); } @@ -227,8 +235,9 @@ string GameSettings::profileFile(string filename, string fallback,bool sanity, b { char buf[512]; string profile =(*this)[Options::ACTIVE_PROFILE].str; + std::transform(profile.begin(),profile.end(),profile.begin(),::tolower); - if(profile != "" && profile != "Default") { + if(profile != "" && profile != "default") { //No file, return root of profile directory if(filename == ""){ sprintf(buf,"%sprofiles/%s",( relative ? "" : RESPATH"/" ),profile.c_str()); @@ -262,13 +271,9 @@ string GameSettings::profileFile(string filename, string fallback,bool sanity, b return buf; } - - void GameSettings::checkProfile(){ - //Load current profile's options. Doesn't save prior set. - + //Load current profile's options. Doesn't save prior set. char buf[512]; - SAFE_DELETE(profileOptions); //Force our directories to exist. MAKEDIR(RESPATH"/profiles"); @@ -277,14 +282,17 @@ void GameSettings::checkProfile(){ temp+="/stats"; MAKEDIR(temp.c_str()); temp = profileFile(PLAYER_SETTINGS,"",false); + + SAFE_DELETE(profileOptions); profileOptions = NEW GameOptions(temp); //Force a theme. - temp = (*profileOptions)[Options::ACTIVE_THEME].str; - if(temp == ""){ + if((*profileOptions)[Options::ACTIVE_THEME].isDefault()){ temp = "Default"; (*profileOptions)[Options::ACTIVE_THEME].str = "Default"; + }else{ + temp = (*profileOptions)[Options::ACTIVE_THEME].str; } //Load theme options @@ -295,7 +303,7 @@ void GameSettings::checkProfile(){ } SAFE_DELETE(themeOptions); - themeOptions = NEW GameOptions(buf); + themeOptions = NEW GameOptions(buf); //Validation of collection, etc, only happens if the game is up. if(theGame == NULL || theGame->collection == NULL) @@ -323,6 +331,7 @@ void GameSettings::checkProfile(){ profileOptions->save(); createUsersFirstDeck(setId); } + } void GameSettings::createUsersFirstDeck(int setId){ diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index a2077eb10..e2b831a97 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -149,6 +149,14 @@ void GameStateMenu::Start(){ mMovingW->SetHotSpot(72,16); JRenderer::GetInstance()->ResetPrivateVRAM(); JRenderer::GetInstance()->EnableVSync(true); + + //How many cards total ? + PlayerData * playerdata = NEW PlayerData(mParent->collection); + if(!options[Options::ACTIVE_PROFILE].isDefault()) + sprintf(nbcardsStr, "%s: %i of %i cards", options[Options::ACTIVE_PROFILE].str.c_str(), playerdata->collection->totalCards(), mParent->collection->totalCards()); + else + sprintf(nbcardsStr, "Database: %i cards", mParent->collection->totalCards()); + SAFE_DELETE(playerdata); } @@ -221,7 +229,7 @@ void GameStateMenu::fillScroller(){ PlayerData * playerdata = NEW PlayerData(mParent->collection); sprintf(buff2, _("You currently have %i credits").c_str(),playerdata->credits); - delete playerdata; + SAFE_DELETE(playerdata); scroller->Add(buff2); scroller->Add(_("More cards and mods at http://wololo.net/wagic")); @@ -282,9 +290,6 @@ void GameStateMenu::Update(float dt) mReadConf = 1; } if (!nextDirectory(RESPATH"/sets/","_cards.dat")){ - //How many cards total ? - sprintf(nbcardsStr, "Database: %i cards", mParent->collection->totalCards()); - //Force default, if necessary. if(options[Options::ACTIVE_PROFILE].str == "") options[Options::ACTIVE_PROFILE].str = "Default"; @@ -304,8 +309,16 @@ void GameStateMenu::Update(float dt) currentState = MENU_STATE_MAJOR_FIRST_TIME | MENU_STATE_MINOR_NONE; } } + + //List active profile and database size. + PlayerData * playerdata = NEW PlayerData(mParent->collection); + if(!options[Options::ACTIVE_PROFILE].isDefault()) + sprintf(nbcardsStr, "%s: %i of %i cards", options[Options::ACTIVE_PROFILE].str.c_str(), playerdata->collection->totalCards(), mParent->collection->totalCards()); + else + sprintf(nbcardsStr, "Database: %i cards", mParent->collection->totalCards()); + SAFE_DELETE(playerdata); resetDirectory(); - } + } break; case MENU_STATE_MAJOR_FIRST_TIME : options.checkProfile(); diff --git a/projects/mtg/src/GameStateOptions.cpp b/projects/mtg/src/GameStateOptions.cpp index acf3b5fb1..aa6a387ea 100644 --- a/projects/mtg/src/GameStateOptions.cpp +++ b/projects/mtg/src/GameStateOptions.cpp @@ -43,11 +43,13 @@ void GameStateOptions::Start() optionsTabs->Add(optionsList); optionsList = NEW OptionsList("Profiles"); - OptionProfile * pickProf = NEW OptionProfile(mParent); - optionsList->Add(pickProf); OptionNewProfile * key = NEW OptionNewProfile("","New Profile"); key->bShowValue = false; optionsList->Add(key); + OptionProfile * pickProf = NEW OptionProfile(mParent); + optionsList->Add(pickProf); + OptionTheme * theme = NEW OptionTheme(); + optionsList->Add(theme); optionsTabs->Add(optionsList); optionsList = NEW OptionsList("Credits"); diff --git a/projects/mtg/src/OptionItem.cpp b/projects/mtg/src/OptionItem.cpp index f2a0f690b..1fb614466 100644 --- a/projects/mtg/src/OptionItem.cpp +++ b/projects/mtg/src/OptionItem.cpp @@ -39,6 +39,7 @@ OptionItem::OptionItem( string _id, string _displayValue) { displayValue = _(_displayValue); canSelect=true; hasFocus=false; + bHidden=false; width = SCREEN_WIDTH; height = 20; } @@ -406,7 +407,7 @@ void OptionsList::Entering(){ //Try to force a selectable option. if(current == -1){ for (int i = 0 ; i < nbitems; i++){ - if(listItems[i]->canSelect) { + if(listItems[i]->Selectable()) { current = i; listItems[current]->Entering(); break; @@ -440,7 +441,7 @@ void OptionsList::Render(){ //Force a selectable option. if(current == -1){ for (int i = 0 ; i < nbitems; i++){ - if(listItems[i]->canSelect) { + if(listItems[i]->Selectable()) { current = i; listItems[current]->Entering(); break; @@ -450,7 +451,7 @@ void OptionsList::Render(){ //Find out how large our list is. for (int pos=0;pos < nbitems; pos++){ listHeight+=listItems[pos]->height+5; - if(listItems[pos]->canSelect){ + if(listItems[pos]->Selectable()){ listSelectable++; if(pos < current) adjustedCurrent++; } @@ -460,14 +461,20 @@ void OptionsList::Render(){ if(listHeight > SCREEN_HEIGHT) { width -= 10; - for (start=current;start > 0; start--) { + for (start=current;start > 0; start--){ + if(listItems[start]->bHidden) + continue; + vHeight += listItems[start]->height+5; if(vHeight >= (SCREEN_HEIGHT-60)/2) break; } vHeight = 0; - for (nowPos=nbitems;nowPos > 1; nowPos--) + for (nowPos=nbitems;nowPos > 1; nowPos--){ + if(listItems[start]->bHidden) + continue; vHeight += listItems[nowPos-1]->height+5; + } if(vHeight <= SCREEN_HEIGHT-40 && nowPos < start) start = nowPos; @@ -481,6 +488,9 @@ void OptionsList::Render(){ if(start >= 0) { for (int pos=0;pos < nbitems; pos++){ + if(listItems[pos]->bHidden) + continue; + if(pos < start){ vHeight += listItems[pos]->height + 5; continue; @@ -523,9 +533,9 @@ void OptionsList::Update(float dt){ { if (potential > 0){ potential--; - while(potential > 0 && listItems[potential]->canSelect == false) + while(potential > 0 && listItems[potential]->Selectable() == false) potential--; - if(potential < 0 || !listItems[potential]->canSelect) + if(potential < 0 || !listItems[potential]->Selectable()) potential = -1; else if(listItems[current]->Leaving()){ current = potential; @@ -537,9 +547,9 @@ void OptionsList::Update(float dt){ { if (potential < nbitems-1){ potential++; - while(potential < nbitems-1 && listItems[potential]->canSelect == false) + while(potential < nbitems-1 && listItems[potential]->Selectable() == false) potential++; - if(potential == nbitems || !listItems[potential]->canSelect) + if(potential == nbitems || !listItems[potential]->Selectable()) potential = -1; else if(potential != current && listItems[current]->Leaving()){ current = potential; @@ -647,7 +657,7 @@ bool OptionsMenu::isTab(string name){ return true; return false; -}; +} int OptionsMenu::Submode() { @@ -664,8 +674,8 @@ void OptionsMenu::acceptSubmode() } void OptionsMenu::reloadValues() { - if(current > -1 && current < nbitems) - tabs[current]->reloadValues(); + for(int i=0;ireloadValues(); } void OptionsMenu::cancelSubmode() @@ -764,12 +774,13 @@ int OptionNewProfile::Submode(){ } return OPTIONS_SUBMODE_NORMAL; } + OptionString::OptionString(string _id, string _displayValue): OptionItem(_id, _displayValue) { bShowValue=true; if(_id != "") value=options[_id].str; -}; +} ostream& OptionString::toString(ostream& out) const{ return out << "OptionString ::: displayValue : " << displayValue @@ -778,3 +789,12 @@ return out << "OptionString ::: displayValue : " << displayValue << " ; hasFocus : " << hasFocus << " ; x,y : " << x << "," << y; } + +OptionTheme::OptionTheme(): OptionDirectory(RESPATH"/themes",Options::ACTIVE_THEME, "Current Theme"){ + addSelection("Default"); + sort(selections.begin(),selections.end()); + initSelections(); + hasFocus=false; + if(selections.size() == 1) + bHidden = true; +} \ No newline at end of file diff --git a/projects/mtg/src/ShopItem.cpp b/projects/mtg/src/ShopItem.cpp index ca139978e..70cebd15d 100644 --- a/projects/mtg/src/ShopItem.cpp +++ b/projects/mtg/src/ShopItem.cpp @@ -364,6 +364,22 @@ void ShopItems::ButtonPressed(int controllerId, int controlId){ tempDeck->addRandomCards(3, sets,1,Constants::RARITY_U); tempDeck->addRandomCards(11, sets,1,Constants::RARITY_C); + //Check for duplicates. Does not guarentee none, just makes them extremely unlikely. + //Code is kind of inefficient, but shouldn't be used often enough to matter. + int loops=0; + for(map::iterator it = tempDeck->cards.begin();it!= tempDeck->cards.end() && loops < 15;it++,loops++){ + int dupes = it->second - 1; + if(dupes <= 0) + continue; + + for(int x=0;xremove(it->first); + + int rarity = (int) tempDeck->database->getCardById(it->first)->getRarity(); + tempDeck->addRandomCards(dupes,&rarity); + it = tempDeck->cards.begin(); + } + playerdata->collection->add(tempDeck); myCollection->Add(tempDeck); diff --git a/projects/mtg/src/WResourceManager.cpp b/projects/mtg/src/WResourceManager.cpp index 8042059f7..6c2f4c1ee 100644 --- a/projects/mtg/src/WResourceManager.cpp +++ b/projects/mtg/src/WResourceManager.cpp @@ -179,7 +179,7 @@ unsigned int WResourceManager::nowTime(){ return ++lastTime; } -void WResourceManager::clearSamples(){ +void WResourceManager::ClearSamples(){ map::iterator next; for(map::iterator it = sampleCache.begin();it!=sampleCache.end();it=next){ next = it; @@ -208,7 +208,7 @@ WCachedSample * WResourceManager::getCachedSample(string filename, bool makenew) csample->sample = JSoundSystem::GetInstance()->LoadSample(sfile.c_str()); //Potential cache overflow- clean the cache if(!csample->sample && fileExists(sfile.c_str())){ - clearSamples(); + ClearSamples(); csample->sample = JSoundSystem::GetInstance()->LoadSample(sfile.c_str()); } } @@ -450,6 +450,11 @@ JQuad * WResourceManager::RetrieveCard(MTGCard * card, int type, int style){ JQuad * WResourceManager::RetrieveQuad(string filename, float offX, float offY, float width, float height, string resname, int style){ + for(vector::iterator it=mTextureMissing.begin();it!=mTextureMissing.end();it++){ + if((*it) == filename) + return NULL; + } + if(resname == "") resname = filename; @@ -504,7 +509,8 @@ JQuad * WResourceManager::RetrieveQuad(string filename, float offX, float offY, return tc->GetQuad(offX,offY,width,height); } - //Texture doesn't exist, so no quad. + //Texture doesn't exist, so no quad. Record miss. + mTextureMissing.push_back(filename); return NULL; } void WResourceManager::Release(JTexture * tex){ @@ -578,6 +584,13 @@ JTexture * WResourceManager::RetrieveTexture(string filename, int style){ else tc = getCachedTexture(filename); } + + if(style == RETRIEVE_MANAGE){ + for(vector::iterator it = mTextureMissing.begin();it!=mTextureMissing.end();it++){ + if((*it) == filename) + return NULL; + } + } //Perform lock or unlock on entry. if(style != RETRIEVE_MANAGE && tc){ @@ -598,8 +611,13 @@ JTexture * WResourceManager::RetrieveTexture(string filename, int style){ textureCache.erase(it); } //Pop texture into resource manager - CreateTexture(filename); - return GetTexture(filename); + int val = CreateTexture(filename); + if(val == INVALID_ID){ + mTextureMissing.push_back(filename); + return NULL;//file not found + } + + return GetTexture(val); } //Texture exists! Get it. @@ -863,7 +881,8 @@ int WResourceManager::fileOK(string filename, bool relative){ } int WResourceManager::CreateTexture(const string &textureName) { - map::iterator itr = mTextureMap.find(textureName); + int id = INVALID_ID; + map::iterator itr = mTextureMap.find(textureName); if (itr == mTextureMap.end()) { @@ -873,14 +892,18 @@ int WResourceManager::CreateTexture(const string &textureName) { JTexture *tex = JRenderer::GetInstance()->LoadTexture(path.c_str()); - if (tex == NULL) - return INVALID_ID; - - int id = mTextureList.size(); + if (tex != NULL) + { + id = mTextureList.size(); mTextureList.push_back(tex); mTextureMap[textureName] = id; + } + else + { - return id; + } + + return id; } else return itr->second; @@ -1000,7 +1023,9 @@ void WResourceManager::Refresh(){ vector::iterator q; JTexture * oldtex; + mTextureMissing.clear(); ClearMisses(); + ClearSamples(); for(it = textureCache.begin();it!=textureCache.end();it++){ if(it->second == NULL)