Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
44 KB
Referenced Files
None
Subscribers
None
diff --git a/src/AchievementList.h b/src/AchievementList.h
new file mode 100644
index 0000000..00edd66
--- /dev/null
+++ b/src/AchievementList.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 Me and My Shadow
+ *
+ * This file is part of Me and My Shadow.
+ *
+ * Me and My Shadow is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Me and My Shadow is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Note: This is an internal file for all avaliable achievements.
+// Don't include it in other files!
+
+AchievementInfo achievementList[]={
+ {"newbie",__("Newbie"),"themes/Cloudscape/player.png",{0,0,23,40},__("Congratulations, you completed one level!"),ACHIEVEMT_TITLE},
+ {"experienced",__("Experienced player"),"themes/Cloudscape/player.png",{0,0,23,40},__("Completed 50 levels."),ACHIEVEMT_PROGRESS},
+ {"goodjob",__("Good job!"),"gfx/medals.png",{60,0,30,30},__("Get your first gold medal."),ACHIEVEMT_ALL},
+ {"expert",__("Expert"),"gfx/medals.png",{60,0,30,30},__("Earned 50 gold medal."),ACHIEVEMT_PROGRESS},
+
+ {"tutorial",__("Graduate"),"gfx/medals.png",{60,0,30,30},__("Complete the tutorial level pack."),ACHIEVEMT_PROGRESS},
+ {"tutorialGold",__("Outstanding graduate"),"gfx/medals.png",{60,0,30,30},__("Complete the tutorial level pack with all levels gold medal."),ACHIEVEMT_PROGRESS},
+
+ {"addicted",__("Addicted"),"themes/Cloudscape/player.png",{0,0,23,40},__("Played Me and My Shadow for more than 2 hours.")},
+ {"loyalFan",__("Me and My Shadow loyal fan"),"themes/Cloudscape/player.png",{0,0,23,40},__("Played Me and My Shadow for more than 24 hours.")},
+
+ {"constructor",__("Constructor"),"gfx/gui.png",{112,16,16,16},__("Use the level editor for more than 2 hours.")},
+ {"constructor2",__("The creator"),"gfx/gui.png",{112,16,16,16},__("Use the level editor for more than 24 hours.")},
+
+ {"create1",__("Look, cute level!"),"gfx/gui.png",{112,16,16,16},__("Created your first level."),ACHIEVEMT_ALL},
+ {"create50",__("The level museum"),"gfx/gui.png",{112,16,16,16},__("Created 50 levels."),ACHIEVEMT_PROGRESS},
+
+ {"frog",__("Frog"),"themes/Cloudscape/player.png",{0,0,23,40},__("Jump for 1000 times."),ACHIEVEMT_PROGRESS},
+
+ {"die1",__("Be careful!"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("The first death.")},
+ {"die50",__("It doesn't matter..."),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Died for 50 times.")},
+ {"die1000",__("Expert of trial and error"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Died for 1000 times."),ACHIEVEMT_TITLE},
+
+ {"squash1",__("Keep an eye for moving walls!"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("First time being squashed.")},
+ {"suqash50",__("Potato masher"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Squashed for 50 times.")},
+
+ {"doubleKill",__("Double kill"),"themes/Cloudscape/deathright.png",{0,14,23,40},__("Make both player and shadow die.")},
+
+ {"programmer",__("Programmer"),"gfx/gui.png",{112,16,16,16},__("Played the development version of Me and My Shadow.")},
+
+ //end of achievements
+ {}
+};
diff --git a/src/StatisticsManager.cpp b/src/StatisticsManager.cpp
index e6ad626..9843719 100644
--- a/src/StatisticsManager.cpp
+++ b/src/StatisticsManager.cpp
@@ -1,608 +1,636 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "StatisticsManager.h"
#include "FileManager.h"
#include "TreeStorageNode.h"
#include "POASerializer.h"
#include "Functions.h"
#include "LevelPackManager.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <iostream>
#include <fstream>
+#include <sstream>
#include <vector>
#include <map>
+#include "libs/tinyformat/tinyformat.h"
using namespace std;
StatisticsManager statsMgr;
static const int achievementDisplayTime=100;
static const int achievementIntervalTime=120;
-//internal struct for achievement info
-struct AchievementInfo{
- //achievement id for save to statistics file
- const char* id;
- //achievement name for display
- const char* name;
- //achievement image. NULL for no image. will be loaded at getDataPath()+imageFile
- const char* imageFile;
- //SDL_Surface of achievement image.
- SDL_Surface* imageSurface;
- //image offset and size.
- SDL_Rect r;
- //achievement description. supports multi-line text
- const char* description;
-};
-
-static AchievementInfo achievementList[]={
- {"newbie",__("Newbie"),"themes/Cloudscape/player.png",NULL,{0,0,23,40},__("Congratulations, you completed one level!")},
- {"experienced",__("Experienced player"),"themes/Cloudscape/player.png",NULL,{0,0,23,40},__("Completed 50 levels.")},
- {"goodjob",__("Good job!"),"gfx/medals.png",NULL,{60,0,30,30},__("Get your first gold medal.")},
- {"expert",__("Expert"),"gfx/medals.png",NULL,{60,0,30,30},__("Earned 50 gold medal.")},
-
- {"tutorial",__("Graduate"),"gfx/medals.png",NULL,{60,0,30,30},__("Complete the tutorial level pack.")},
- {"tutorialGold",__("Outstanding graduate"),"gfx/medals.png",NULL,{60,0,30,30},__("Complete the tutorial level pack with all levels gold medal.")},
-
- {"addicted",__("Addicted"),"themes/Cloudscape/player.png",NULL,{0,0,23,40},__("Played Me and My Shadow for more than 2 hours.")},
- {"loyalFan",__("Me and My Shadow loyal fan"),"themes/Cloudscape/player.png",NULL,{0,0,23,40},__("Played Me and My Shadow for more than 24 hours.")},
-
- {"constructor",__("Constructor"),"gfx/gui.png",NULL,{112,16,16,16},__("Use the level editor for more than 2 hours.")},
- {"constructor2",__("The creator"),"gfx/gui.png",NULL,{112,16,16,16},__("Use the level editor for more than 24 hours.")},
-
- {"create1",__("Look, cute level!"),"gfx/gui.png",NULL,{112,16,16,16},__("Created your first level.")},
- {"create50",__("The level museum"),"gfx/gui.png",NULL,{112,16,16,16},__("Created 50 levels.")},
-
- {"frog",__("Frog"),"themes/Cloudscape/player.png",NULL,{0,0,23,40},__("Jump for 1000 times.")},
-
- {"die1",__("Be careful!"),"themes/Cloudscape/deathright.png",NULL,{0,14,23,40},__("The first death.")},
- {"die50",__("It doesn't matter..."),"themes/Cloudscape/deathright.png",NULL,{0,14,23,40},__("Died for 50 times.")},
- {"die1000",__("Expert of trial and error"),"themes/Cloudscape/deathright.png",NULL,{0,14,23,40},__("Died for 1000 times.")},
-
- {"squash1",__("Keep an eye for moving walls!"),"themes/Cloudscape/deathright.png",NULL,{0,14,23,40},__("First time being squashed.")},
- {"suqash50",__("Potato masher"),"themes/Cloudscape/deathright.png",NULL,{0,14,23,40},__("Squashed for 50 times.")},
-
- {"doubleKill",__("Double kill"),"themes/Cloudscape/deathright.png",NULL,{0,14,23,40},__("Make both player and shadow die.")},
-
- //test only
- {"programmer",__("Programmer"),"gfx/gui.png",NULL,{112,16,16,16},__("Played the development version of Me and My Shadow.")},
-
- //end of achievements
- {NULL,NULL,NULL,NULL,{0,0,0,0},NULL}
-};
+#include "AchievementList.h"
static map<string,AchievementInfo*> avaliableAchievements;
//================================================================
StatisticsManager::StatisticsManager(){
bmDropShadow=NULL;
bmAchievement=NULL;
startTime=time(NULL);
clear();
}
StatisticsManager::~StatisticsManager(){
if(bmAchievement){
SDL_FreeSurface(bmAchievement);
bmAchievement=NULL;
}
}
void StatisticsManager::clear(){
playerTravelingDistance=shadowTravelingDistance=0.0f;
playerJumps=shadowJumps
=playerDies=shadowDies
=playerSquashed=shadowSquashed
=completedLevels=silverLevels=goldLevels
=recordTimes=switchTimes=swapTimes
=playTime=levelEditTime
=createdLevels=0;
achievements.clear();
queuedAchievements.clear();
achievementTime=0;
currentAchievement=0;
if(bmAchievement){
SDL_FreeSurface(bmAchievement);
bmAchievement=NULL;
}
}
#define LOAD_STATS(var,func) { \
vector<string> &v=node.attributes[ #var ]; \
if(!v.empty() && !v[0].empty()) \
var=func(v[0].c_str()); \
}
void StatisticsManager::loadFile(const std::string& fileName){
clear();
ifstream file(fileName.c_str());
if(!file) return;
TreeStorageNode node;
POASerializer serializer;
if(!serializer.readNode(file,&node,true)) return;
//load statistics
LOAD_STATS(playerTravelingDistance,atof);
LOAD_STATS(shadowTravelingDistance,atof);
LOAD_STATS(playerJumps,atoi);
LOAD_STATS(shadowJumps,atoi);
LOAD_STATS(playerDies,atoi);
LOAD_STATS(shadowDies,atoi);
LOAD_STATS(playerSquashed,atoi);
LOAD_STATS(shadowSquashed,atoi);
LOAD_STATS(recordTimes,atoi);
LOAD_STATS(switchTimes,atoi);
LOAD_STATS(swapTimes,atoi);
LOAD_STATS(playTime,atoi);
LOAD_STATS(levelEditTime,atoi);
LOAD_STATS(createdLevels,atoi);
//load achievements.
+ //format is: name;time,name;time,...
{
vector<string> &v=node.attributes["achievements"];
for(unsigned int i=0;i<v.size();i++){
- map<string,AchievementInfo*>::iterator it=avaliableAchievements.find(v[i]);
+ string s=v[i];
+ time_t t=0;
+
+ string::size_type lps=s.find(';');
+ if(lps!=string::npos){
+ string s1=s.substr(lps+1);
+ s=s.substr(0,lps);
+
+ long long n;
+ sscanf(s1.c_str(),
+#ifdef WIN32
+ "%I64d",
+#else
+ "%Ld",
+#endif
+ &n);
+
+ t=(time_t)n;
+ }
+
+ map<string,AchievementInfo*>::iterator it=avaliableAchievements.find(s);
if(it!=avaliableAchievements.end()){
- achievements[it->first]=it->second;
+ OwnedAchievement ach={t,it->second};
+ achievements[it->first]=ach;
}
}
}
}
//Call when level edit is start
void StatisticsManager::startLevelEdit(){
levelEditStartTime=time(NULL);
}
//Call when level edit is end
void StatisticsManager::endLevelEdit(){
levelEditTime+=time(NULL)-levelEditStartTime;
}
//update in-game time
void StatisticsManager::updatePlayTime(){
time_t endTime=time(NULL);
playTime+=endTime-startTime;
startTime=endTime;
}
#define SAVE_STATS(var,pattern) { \
sprintf(s,pattern,var); \
node.attributes[ #var ].push_back(s); \
}
void StatisticsManager::saveFile(const std::string& fileName){
char s[64];
//update in-game time
updatePlayTime();
ofstream file(fileName.c_str());
if(!file) return;
TreeStorageNode node;
//save statistics
SAVE_STATS(playerTravelingDistance,"%.2f");
SAVE_STATS(shadowTravelingDistance,"%.2f");
SAVE_STATS(playerJumps,"%d");
SAVE_STATS(shadowJumps,"%d");
SAVE_STATS(playerDies,"%d");
SAVE_STATS(shadowDies,"%d");
SAVE_STATS(playerSquashed,"%d");
SAVE_STATS(shadowSquashed,"%d");
SAVE_STATS(recordTimes,"%d");
SAVE_STATS(switchTimes,"%d");
SAVE_STATS(swapTimes,"%d");
SAVE_STATS(playTime,"%d");
SAVE_STATS(levelEditTime,"%d");
SAVE_STATS(createdLevels,"%d");
//save achievements.
+ //format is: name;time,name;time,...
{
vector<string>& v=node.attributes["achievements"];
- for(map<string,AchievementInfo*>::iterator it=achievements.begin();it!=achievements.end();++it){
- v.push_back(it->first);
+ for(map<string,OwnedAchievement>::iterator it=achievements.begin();it!=achievements.end();++it){
+ stringstream strm;
+ char s[32];
+
+ long long n=it->second.achievedTime;
+ sprintf(s,
+#ifdef WIN32
+ "%I64d",
+#else
+ "%Ld",
+#endif
+ n);
+ strm<<it->first<<";"<<s;
+
+ v.push_back(strm.str());
}
}
POASerializer serializer;
serializer.writeNode(&node,file,true,true);
}
void StatisticsManager::loadPicture(){
//Load drop shadow picture
bmDropShadow=loadImage(getDataPath()+"gfx/dropshadow.png");
}
void StatisticsManager::registerAchievements(){
if(!avaliableAchievements.empty()) return;
for(int i=0;achievementList[i].id!=NULL;i++){
avaliableAchievements[achievementList[i].id]=&achievementList[i];
if(achievementList[i].imageFile!=NULL){
achievementList[i].imageSurface=loadImage(getDataPath()+achievementList[i].imageFile);
}
}
}
void StatisticsManager::render(){
- //debug
- if(achievementTime==0){
- if(SDL_GetKeyState(NULL)[SDLK_1]) newAchievement("hello",false);
- if(SDL_GetKeyState(NULL)[SDLK_2]) newAchievement("123",false);
- }
-
if(achievementTime==0 && bmAchievement==NULL && currentAchievement<(int)queuedAchievements.size()){
//create surface
bmAchievement=createAchievementSurface(queuedAchievements[currentAchievement++]);
drawGUIBox(0,0,bmAchievement->w,bmAchievement->h,bmAchievement,0xFFFFFF00);
//check if queue is empty
if(currentAchievement>=(int)queuedAchievements.size()){
queuedAchievements.clear();
currentAchievement=0;
}
//play a sound
if(getSettings()->getBoolValue("sound")){
Mix_PlayChannel(-1,achievementSound,0);
}
}
//check if we need to display achievements
if(bmAchievement){
achievementTime++;
if(achievementTime<=0){
return;
}else if(achievementTime<=5){
drawAchievement(achievementTime);
}else if(achievementTime<=achievementDisplayTime-5){
drawAchievement(5);
}else if(achievementTime<achievementDisplayTime){
drawAchievement(achievementDisplayTime-achievementTime);
}else if(achievementTime>=achievementIntervalTime){
if(bmAchievement){
SDL_FreeSurface(bmAchievement);
bmAchievement=NULL;
}
achievementTime=0;
}
}
}
void StatisticsManager::newAchievement(const std::string& id,bool save){
//check avaliable achievements
map<string,AchievementInfo*>::iterator it=avaliableAchievements.find(id);
if(it==avaliableAchievements.end()) return;
//check if already have this achievement
if(save){
- map<string,AchievementInfo*>::iterator it2=achievements.find(id);
+ map<string,OwnedAchievement>::iterator it2=achievements.find(id);
if(it2!=achievements.end()) return;
- achievements[id]=it->second;
+
+ OwnedAchievement ach={time(NULL),it->second};
+ achievements[id]=ach;
}
//add it to queue
queuedAchievements.push_back(it->second);
}
-SDL_Surface* StatisticsManager::createAchievementSurface(AchievementInfo* info,SDL_Surface* surface,SDL_Rect* rect,bool showTip){
+float StatisticsManager::getAchievementProgress(AchievementInfo* info){
+ //TODO:
+ return -3.0f;
+}
+
+SDL_Surface* StatisticsManager::createAchievementSurface(AchievementInfo* info,SDL_Surface* surface,SDL_Rect* rect,bool showTip,const time_t *achievedTime){
if(info==NULL || info->id==NULL) return NULL;
//prepare text
SDL_Surface *title0=NULL,*title1=NULL;
vector<SDL_Surface*> descSurfaces;
SDL_Color fg={0,0,0};
int fontHeight=TTF_FontLineSkip(fontText);
- if(showTip) title0=TTF_RenderUTF8_Blended(fontText,_("New achievement:"),fg);
- title1=TTF_RenderUTF8_Blended(fontGUISmall,_(info->name),fg);
+ bool showDescription=false;
+ bool showImage=false;
+ float achievementProgress=0.0f;
+
+ if(showTip){
+ title0=TTF_RenderUTF8_Blended(fontText,_("New achievement:"),fg);
+ title1=TTF_RenderUTF8_Blended(fontGUISmall,_(info->name),fg);
+ showDescription=showImage=true;
+ }else if(achievedTime){
+ char s[128];
+ strftime(s,sizeof(s),"%c",localtime(achievedTime));
+
+ stringstream strm;
+ tinyformat::format(strm,_("Achieved at %s"),s);
+
+ title1=TTF_RenderUTF8_Blended(fontText,strm.str().c_str(),fg);
+ title0=TTF_RenderUTF8_Blended(fontGUISmall,_(info->name),fg);
+ showDescription=showImage=true;
+ }else if(info->displayStyle==ACHIEVEMT_HIDDEN){
+ title0=TTF_RenderUTF8_Blended(fontGUISmall,_("Unknown achievement"),fg);
+ }else{
+ if(info->displayStyle==ACHIEVEMT_PROGRESS){
+ achievementProgress=getAchievementProgress(info);
+
+ stringstream strm;
+ tinyformat::format(strm,_("Achieved %0.1f%%"),achievementProgress);
+
+ title1=TTF_RenderUTF8_Blended(fontText,strm.str().c_str(),fg);
+ }else{
+ title1=TTF_RenderUTF8_Blended(fontText,_("Not achieved"),fg);
+ }
+
+ title0=TTF_RenderUTF8_Blended(fontGUISmall,_(info->name),fg);
- if(info->description!=NULL){
+ showDescription= info->displayStyle==ACHIEVEMT_ALL || info->displayStyle==ACHIEVEMT_PROGRESS;
+ showImage=true;
+ }
+
+ if(info->description!=NULL && showDescription){
string description=_(info->description);
string::size_type lps=0,lpe;
for(;;){
lpe=description.find('\n',lps);
if(lpe==string::npos){
descSurfaces.push_back(TTF_RenderUTF8_Blended(fontText,(description.substr(lps)+' ').c_str(),fg));
break;
}else{
descSurfaces.push_back(TTF_RenderUTF8_Blended(fontText,(description.substr(lps,lpe-lps)+' ').c_str(),fg));
lps=lpe+1;
}
}
}
//calculate the size
int w=0,h=0,w1=8,h1=0;
if(title0!=NULL){
if(title0->w>w) w=title0->w;
h1+=title0->h;
}
if(title1!=NULL){
if(title1->w>w) w=title1->w;
h1+=title1->h;
}
- if(info->imageSurface!=NULL){
+ if(info->imageSurface!=NULL && showImage){
w1+=info->r.w+8;
w+=info->r.w+8;
if(info->r.h>h1) h1=info->r.h;
}
h=h1+8;
for(unsigned int i=0;i<descSurfaces.size();i++){
if(descSurfaces[i]!=NULL){
if(descSurfaces[i]->w>w) w=descSurfaces[i]->w;
}
}
h+=descSurfaces.size()*fontHeight;
w+=16;
h+=16;
//check if size is specified
int left=0,top=0;
if(rect!=NULL){
if(surface!=NULL){
left=rect->x;
top=rect->y;
}
if(rect->w>0) w=rect->w;
else rect->w=w;
rect->h=h;
}
//create surface if necessary
if(surface==NULL){
surface=SDL_CreateRGBSurface(SDL_HWSURFACE,w,h,
screen->format->BitsPerPixel,screen->format->Rmask,screen->format->Gmask,screen->format->Bmask,0);
}
//draw background
SDL_Rect r={left,top,w,h};
- SDL_FillRect(surface,&r,SDL_MapRGB(surface->format,255,255,255));
+ if(showTip || achievedTime){
+ SDL_FillRect(surface,&r,SDL_MapRGB(surface->format,255,255,255));
+ }else{
+ SDL_FillRect(surface,&r,SDL_MapRGB(surface->format,192,192,192));
+ }
//draw picture
- if(info->imageSurface!=NULL){
+ if(info->imageSurface!=NULL && showImage){
SDL_Rect r={left+8,top+8+(h1-info->r.h)/2,0,0};
SDL_BlitSurface(info->imageSurface,&info->r,surface,&r);
}
//draw text
h=8;
if(title0!=NULL){
SDL_Rect r={left+w1,top+h,0,0};
SDL_BlitSurface(title0,NULL,surface,&r);
h+=title0->h;
}
if(title1!=NULL){
SDL_Rect r={left+w1,top+h,0,0};
SDL_BlitSurface(title1,NULL,surface,&r);
}
h=h1+16;
for(unsigned int i=0;i<descSurfaces.size();i++){
if(descSurfaces[i]!=NULL){
SDL_Rect r={left+8,top+h+i*fontHeight,0,0};
SDL_BlitSurface(descSurfaces[i],NULL,surface,&r);
}
}
//clean up
if(title0) SDL_FreeSurface(title0);
if(title1) SDL_FreeSurface(title1);
for(unsigned int i=0;i<descSurfaces.size();i++){
if(descSurfaces[i]!=NULL){
SDL_FreeSurface(descSurfaces[i]);
}
}
//over
return surface;
}
void StatisticsManager::drawAchievement(int alpha){
if(bmAchievement==NULL) return;
if(alpha<=0) return;
if(alpha>5) alpha=5;
SDL_Rect r={screen->w-32-bmAchievement->w,32,
bmAchievement->w,bmAchievement->h};
//draw the surface
SDL_SetAlpha(bmAchievement,SDL_SRCALPHA,alpha*40);
SDL_BlitSurface(bmAchievement,NULL,screen,&r);
//draw drop shadow - corner
{
int w1=r.w/2,w2=r.w-w1,h1=r.h/2,h2=r.h-h1;
if(w1>16) w1=16;
if(w2>16) w2=16;
if(h1>16) h1=16;
if(h2>16) h2=16;
int x=(5-alpha)*64;
//top-left
SDL_Rect r1={x,0,w1+16,h1+16},r2={r.x-16,r.y-16,0,0};
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
//top-right
r1.x=x+48-w2;r1.w=w2+16;r2.x=r.x+r.w-w2;
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
//bottom-right
r1.y=48-h2;r1.h=h2+16;r2.y=r.y+r.h-h2;
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
//bottom-left
r1.x=x;r1.w=w1+16;r2.x=r.x-16;
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
}
//draw drop shadow - border
int i=r.w-32;
while(i>0){
int ii=i>128?128:i;
//top
SDL_Rect r1={0,256-alpha*16,ii,16},r2={r.x+r.w-16-i,r.y-16,0,0};
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
//bottom
r1.x=128;r2.y=r.y+r.h;
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
i-=ii;
}
i=r.h-32;
while(i>0){
int ii=i>128?128:i;
//top
SDL_Rect r1={512-alpha*16,0,16,ii},r2={r.x-16,r.y+r.h-16-i,0,0};
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
//bottom
r1.y=128;r2.x=r.x+r.w;
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
i-=ii;
}
}
void StatisticsManager::reloadCompletedLevelsAndAchievements(){
completedLevels=silverLevels=goldLevels=0;
LevelPackManager *lpm=getLevelPackManager();
vector<string> v=lpm->enumLevelPacks();
bool tutorial=false,tutorialGold=false;
for(unsigned int i=0;i<v.size();i++){
string& s=v[i];
LevelPack *levels=lpm->getLevelPack(s);
levels->loadProgress(getUserPath(USER_DATA)+"progress/"+s+".progress");
bool b=false;
if(s=="tutorial"){
b=tutorial=tutorialGold=true;
}
for(int n=0,m=levels->getLevelCount();n<m;n++){
LevelPack::Level *lv=levels->getLevel(n);
int medal=lv->won;
if(medal){
if(lv->targetTime<0 || lv->time<=lv->targetTime)
medal++;
if(lv->targetRecordings<0 || lv->recordings<=lv->targetRecordings)
medal++;
completedLevels++;
if(medal==2) silverLevels++;
if(medal==3) goldLevels++;
if(medal!=3 && b) tutorialGold=false;
}else if(b){
tutorial=tutorialGold=false;
}
}
}
//upadte achievements
updateLevelAchievements();
updateTutorialAchievementsInternal((tutorial?1:0)|(tutorialGold?2:0));
}
void StatisticsManager::reloadOtherAchievements(){
int i;
if(playTime>=7200) newAchievement("addicted");
if(playTime>=86400) newAchievement("loyalFan");
if(levelEditTime>=7200) newAchievement("constructor");
if(levelEditTime>=86400) newAchievement("constructor2");
if(createdLevels>=1) newAchievement("create1");
if(createdLevels>=50) newAchievement("create50");
i=playerJumps+shadowJumps;
if(i>=1000) newAchievement("frog");
i=playerDies+shadowDies;
if(i>=1) newAchievement("die1");
if(i>=50) newAchievement("die50");
if(i>=1000) newAchievement("die1000");
i=playerSquashed+shadowSquashed;
if(i>=1) newAchievement("squash1");
if(i>=50) newAchievement("squash50");
if(version.find("Development")!=string::npos) newAchievement("programmer");
}
//Update level specified achievements.
//Make sure the completed level count is correct.
void StatisticsManager::updateLevelAchievements(){
if(completedLevels>=1) newAchievement("newbie");
if(goldLevels>=1) newAchievement("goodjob");
if(completedLevels>=50) newAchievement("experienced");
if(goldLevels>=50) newAchievement("expert");
}
//Update tutorial specified achievements.
//Make sure the level progress of tutorial is correct.
void StatisticsManager::updateTutorialAchievements(){
//find tutorial level pack
LevelPackManager *lpm=getLevelPackManager();
LevelPack *levels=lpm->getLevelPack("tutorial");
if(levels==NULL) return;
bool tutorial=true,tutorialGold=true;
for(int n=0,m=levels->getLevelCount();n<m;n++){
LevelPack::Level *lv=levels->getLevel(n);
int medal=lv->won;
if(medal){
if(lv->targetTime<0 || lv->time<=lv->targetTime)
medal++;
if(lv->targetRecordings<0 || lv->recordings<=lv->targetRecordings)
medal++;
if(medal!=3) tutorialGold=false;
}else{
tutorial=tutorialGold=false;
break;
}
}
//upadte achievements
updateTutorialAchievementsInternal((tutorial?1:0)|(tutorialGold?2:0));
}
//internal function
//flags: a bit-field value indicates which achievements we have.
void StatisticsManager::updateTutorialAchievementsInternal(int flags){
if(flags&1) newAchievement("tutorial");
if(flags&2) newAchievement("tutorialGold");
}
diff --git a/src/StatisticsManager.h b/src/StatisticsManager.h
index f0d205c..cc4a7d7 100644
--- a/src/StatisticsManager.h
+++ b/src/StatisticsManager.h
@@ -1,141 +1,175 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef STATISTICSMANAGER_H
#define STATISTICSMANAGER_H
#include <SDL/SDL.h>
#include <string>
#include <vector>
#include <map>
+#include <time.h>
+
+enum AchievementDisplayStyle{
+ ACHIEVEMT_HIDDEN,
+ ACHIEVEMT_TITLE,
+ ACHIEVEMT_ALL,
+ ACHIEVEMT_PROGRESS,
+};
//internal struct for achievement info
-struct AchievementInfo;
+struct AchievementInfo{
+ //achievement id for save to statistics file
+ const char* id;
+ //achievement name for display
+ const char* name;
+ //achievement image. NULL for no image. will be loaded at getDataPath()+imageFile
+ const char* imageFile;
+ //image offset and size.
+ SDL_Rect r;
+ //achievement description. supports multi-line text
+ const char* description;
+ //display style
+ AchievementDisplayStyle displayStyle;
+
+ //SDL_Surface of achievement image.
+ SDL_Surface* imageSurface;
+};
+
+struct OwnedAchievement{
+ time_t achievedTime;
+ AchievementInfo* info;
+};
class StatisticsScreen;
class StatisticsManager{
friend class StatisticsScreen;
public:
//Player and shadow traveling distance (m), 1 block = 1 meter
float playerTravelingDistance,shadowTravelingDistance;
//Player and shadow jumps
int playerJumps,shadowJumps;
//Player and shadow dies
int playerDies,shadowDies;
//Player and shadow squashed
int playerSquashed,shadowSquashed;
//Completed levels. Note: this is dynamically calculated, and doesn't save to file.
int completedLevels,silverLevels,goldLevels;
//Record times
int recordTimes;
//number of switched pulled
int switchTimes;
//swap times
int swapTimes;
//play time (s)
int playTime;
//level edit time (s)
int levelEditTime;
//created levels
int createdLevels;
private:
//current achievement displayed time
int achievementTime;
//some picture
SDL_Surface *bmDropShadow;
//SDL_Surface for current achievement (excluding drop shadow)
SDL_Surface *bmAchievement;
//currently owned achievements
- std::map<std::string,AchievementInfo*> achievements;
+ std::map<std::string,OwnedAchievement> achievements;
//queued achievements for display
std::vector<AchievementInfo*> queuedAchievements;
//currently displayed achievement
int currentAchievement;
//starting time
time_t startTime;
//level edit starting time
time_t levelEditStartTime;
public:
StatisticsManager();
~StatisticsManager();
//clear the statistics and achievements.
void clear();
//load needed picture
void loadPicture();
//register avaliable achievements
static void registerAchievements();
//load statistics file.
void loadFile(const std::string& fileName);
//save statistics file.
void saveFile(const std::string& fileName);
//add or display a new achievement.
//name: the achievement id. if can't find it in avaliable achievement, nothing happens.
//save: if true then save to currently owned achievements. if it already exists in
//currently owned achievements, nothing happens.
//if false then just added it to queue, including duplicated achievements.
void newAchievement(const std::string& id,bool save=true);
//if there are new achievements, draw it on the screen,
//otherwise do nothing.
void render();
//Call this function to update completed levels.
//Note: Level progress files are reloaded, so it's slow.
void reloadCompletedLevelsAndAchievements();
//Call this function to update other achievements at game startup.
void reloadOtherAchievements();
//Update level specified achievements.
//Make sure the completed level count is correct.
void updateLevelAchievements();
//Update tutorial specified achievements.
//Make sure the level progress of tutorial is correct.
void updateTutorialAchievements();
//Call when level edit is start
void startLevelEdit();
//Call when level edit is end
void endLevelEdit();
//update in-game time
void updatePlayTime();
//create a SDL_Surface contains specified achievements or draw to existing surface.
//info: achievement info.
//surface: specifies SDL_Surface to draw on. if NULL then new surface will be created.
//rect [in, out, optional]: specifies position and optionally width to draw on. height will be returned.
- //if NULL then will be drawn on top-left corner. if surface is NULL then rect->x and rect->y are ignored.
+ // if NULL then will be drawn on top-left corner. if surface is NULL then rect->x and rect->y are ignored.
//showTip: shows "New achievement" tip
+ //achievedTime: if we should show achieved time (and progress bar if AchievementInfo specifies) and when is it.
+ // Note: if showTip=true then this argument does nothing.
//return value: SDL_Surface contains specified achievements or NULL if any error occured.
- SDL_Surface* createAchievementSurface(AchievementInfo* info,SDL_Surface* surface=NULL,SDL_Rect* rect=NULL,bool showTip=true);
+ SDL_Surface* createAchievementSurface(AchievementInfo* info,SDL_Surface* surface=NULL,SDL_Rect* rect=NULL,bool showTip=true,const time_t *achievedTime=NULL);
private:
//internal function
//flags: a bit-field value indicates which achievements we have.
void updateTutorialAchievementsInternal(int flags);
//internal function. alpha should be 1-5, 5 means fully opaque (not really)
void drawAchievement(int alpha);
+ //internal function for get progress (in percent, 0-100)
+ float getAchievementProgress(AchievementInfo* info);
};
extern StatisticsManager statsMgr;
+extern AchievementInfo achievementList[];
#endif
\ No newline at end of file
diff --git a/src/StatisticsScreen.cpp b/src/StatisticsScreen.cpp
index fde22c8..20f12c9 100644
--- a/src/StatisticsScreen.cpp
+++ b/src/StatisticsScreen.cpp
@@ -1,415 +1,423 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include "StatisticsManager.h"
#include "StatisticsScreen.h"
#include "Globals.h"
#include "Functions.h"
#include "ThemeManager.h"
#include "InputManager.h"
#include "GUIListBox.h"
#include "GUIScrollBar.h"
#ifdef __APPLE__
#include <SDL_image/SDL_image.h>
#include <SDL_gfx/SDL_gfxPrimitives.h>
#else
#include <SDL/SDL_image.h>
#include <SDL/SDL_gfxPrimitives.h>
#endif
using namespace std;
//GUI events are handled here.
//name: The name of the element that invoked the event.
//obj: Pointer to the object that invoked the event.
//eventType: Integer containing the type of event.
void StatisticsScreen::GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType){
//Check what type of event it was.
if(eventType==GUIEventClick){
if(name=="cmdBack"){
//Goto the main menu.
setNextState(STATE_MENU);
}
}
}
#define DRAW_PLAYER_STATISTICS(name,var,format) { \
surface=TTF_RenderUTF8_Blended(fontGUISmall,name,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(0,y,surface,stats,NULL); \
y+=(h1=surface->h); \
SDL_FreeSurface(surface); \
sprintf(s,format,statsMgr.player##var+statsMgr.shadow##var); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(400-surface->w,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
sprintf(s,format,statsMgr.player##var); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(520-surface->w,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
sprintf(s,format,statsMgr.shadow##var); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(640-surface->w,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
}
#define DRAW_MISC_STATISTICS_1(name1,var1,format1) { \
surface=TTF_RenderUTF8_Blended(fontGUISmall,name1,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(0,y,surface,stats,NULL); \
x=surface->w+8; \
y+=(h1=surface->h); \
SDL_FreeSurface(surface); \
sprintf(s,format1,statsMgr.var1); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
}
//we are so lazy that we just use height of the first one, ignore second one
#define DRAW_MISC_STATISTICS_2(name1,var1,format1,name2,var2,format2) { \
surface=TTF_RenderUTF8_Blended(fontGUISmall,name1,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(0,y,surface,stats,NULL); \
x=surface->w+8; \
y+=(h1=surface->h); \
SDL_FreeSurface(surface); \
sprintf(s,format1,statsMgr.var1); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
surface=TTF_RenderUTF8_Blended(fontGUISmall,name2,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(320,y-surface->h,surface,stats,NULL); \
x=surface->w+328; \
SDL_FreeSurface(surface); \
sprintf(s,format2,statsMgr.var2); \
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor); \
SDL_SetAlpha(surface,0,0xFF); \
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL); \
SDL_FreeSurface(surface); \
}
//Constructor.
StatisticsScreen::StatisticsScreen(){
//update in-game time
statsMgr.updatePlayTime();
//Load needed pictures.
//Note: we don't use ImageManager because we need to process these pictures.
SDL_Surface *bmPlayer=IMG_Load((getDataPath()+"themes/Cloudscape/player.png").c_str());
SDL_Surface *bmShadow=IMG_Load((getDataPath()+"themes/Cloudscape/shadow.png").c_str());
SDL_Surface *bmMedal=IMG_Load((getDataPath()+"gfx/medals.png").c_str());
//disable the alpha channel
SDL_SetAlpha(bmPlayer,0,0xFF);
SDL_SetAlpha(bmShadow,0,0xFF);
SDL_SetAlpha(bmMedal,0,0xFF);
//Render the title.
title=TTF_RenderUTF8_Blended(fontTitle,_("Achievements and Statistics"),themeTextColor);
//Render stats.
Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
stats=SDL_CreateRGBSurface(SDL_SWSURFACE,640,400,32,rmask,gmask,bmask,amask);
char s[64];
SDL_Surface *surface;
SDL_Rect r;
int x,y=0,h1;
Uint32 clr=SDL_MapRGB(stats->format,themeTextColor.r,themeTextColor.g,themeTextColor.b);
//Player and shadow specific statistics
surface=TTF_RenderUTF8_Blended(fontGUISmall,_("Total"),themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(400-surface->w,40-surface->h,surface,stats,NULL);
SDL_FreeSurface(surface);
r.x=0;r.y=0;r.w=23;r.h=40;
applySurface(520-r.w,0,bmPlayer,stats,&r);
applySurface(640-r.w,0,bmShadow,stats,&r);
y+=40;
DRAW_PLAYER_STATISTICS(_("Traveling distance (m)"),TravelingDistance,"%0.2f");
DRAW_PLAYER_STATISTICS(_("Jump times"),Jumps,"%d");
DRAW_PLAYER_STATISTICS(_("Die times"),Dies,"%d");
DRAW_PLAYER_STATISTICS(_("Squashed times"),Squashed,"%d");
//Game specific statistics
r.x=0;r.y=y;r.w=stats->w;r.h=2;
SDL_FillRect(stats,&r,clr);
y+=2;
DRAW_MISC_STATISTICS_2(_("Recordings:"),recordTimes,"%d",_("Switch pulled times:"),switchTimes,"%d");
DRAW_MISC_STATISTICS_1(_("Swap times:"),swapTimes,"%d");
//Level specific statistics
r.x=0;r.y=y;r.w=stats->w;r.h=2;
SDL_FillRect(stats,&r,clr);
y+=2;
surface=TTF_RenderUTF8_Blended(fontGUISmall,_("Completed levels:"),themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(0,y,surface,stats,NULL);
x=surface->w+8;
y+=(h1=surface->h);
SDL_FreeSurface(surface);
sprintf(s,"%d",statsMgr.completedLevels);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL);
SDL_FreeSurface(surface);
sprintf(s,"%d",statsMgr.completedLevels-statsMgr.goldLevels-statsMgr.silverLevels);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(400-surface->w,y-(surface->h+h1)/2,surface,stats,NULL);
r.x=0;r.y=0;r.w=30;r.h=30;
applySurface(400-surface->w-30,y-(30+h1)/2,bmMedal,stats,&r);
SDL_FreeSurface(surface);
sprintf(s,"%d",statsMgr.silverLevels);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(520-surface->w,y-(surface->h+h1)/2,surface,stats,NULL);
r.x+=30;
applySurface(520-surface->w-30,y-(30+h1)/2,bmMedal,stats,&r);
SDL_FreeSurface(surface);
sprintf(s,"%d",statsMgr.goldLevels);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(640-surface->w,y-(surface->h+h1)/2,surface,stats,NULL);
r.x+=30;
applySurface(640-surface->w-30,y-(30+h1)/2,bmMedal,stats,&r);
SDL_FreeSurface(surface);
//Other statistics
r.x=0;r.y=y;r.w=stats->w;r.h=2;
SDL_FillRect(stats,&r,clr);
y+=2;
surface=TTF_RenderUTF8_Blended(fontGUISmall,_("In-game time:"),themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(0,y,surface,stats,NULL);
x=surface->w+8;
y+=(h1=surface->h);
SDL_FreeSurface(surface);
sprintf(s,"%02d:%02d:%02d",statsMgr.playTime/3600,(statsMgr.playTime/60)%60,statsMgr.playTime%60);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL);
SDL_FreeSurface(surface);
surface=TTF_RenderUTF8_Blended(fontGUISmall,_("Level editing time:"),themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(320,y-surface->h,surface,stats,NULL);
x=surface->w+328;
SDL_FreeSurface(surface);
sprintf(s,"%02d:%02d:%02d",statsMgr.levelEditTime/3600,(statsMgr.levelEditTime/60)%60,statsMgr.levelEditTime%60);
surface=TTF_RenderUTF8_Blended(fontText,s,themeTextColor);
SDL_SetAlpha(surface,0,0xFF);
applySurface(x,y-(surface->h+h1)/2,surface,stats,NULL);
SDL_FreeSurface(surface);
DRAW_MISC_STATISTICS_1(_("Created levels:"),createdLevels,"%d");
//Free loaded surface
SDL_FreeSurface(bmPlayer);
SDL_FreeSurface(bmShadow);
SDL_FreeSurface(bmMedal);
//Create GUI
achievements=NULL;
createGUI();
}
//Destructor.
StatisticsScreen::~StatisticsScreen(){
//Delete the GUI.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//Free images
SDL_FreeSurface(title);
SDL_FreeSurface(stats);
SDL_FreeSurface(achievements);
}
//Method that will create the GUI for the options menu.
void StatisticsScreen::createGUI(){
//Draw achievements
if(achievements) SDL_FreeSurface(achievements);
vector<SDL_Surface*> surfaces;
int w=SCREEN_WIDTH-128-16,h=0;
- for(map<string,AchievementInfo*>::iterator it=statsMgr.achievements.begin();
- it!=statsMgr.achievements.end();++it)
- {
+ for(int idx=0;achievementList[idx].id!=NULL;++idx){
SDL_Rect r={0,0,w,0};
- SDL_Surface *surface=statsMgr.createAchievementSurface(it->second,NULL,&r,false);
+
+ time_t *lpt=NULL;
+
+ map<string,OwnedAchievement>::iterator it=statsMgr.achievements.find(achievementList[idx].id);
+ if(it!=statsMgr.achievements.end()){
+ lpt=&it->second.achievedTime;
+ }
+
+ SDL_Surface *surface=statsMgr.createAchievementSurface(&achievementList[idx],NULL,&r,false,lpt);
+
if(surface!=NULL){
//Draw single smooth line for separating items in a list.
lineRGBA(surface,0,surface->h-1,surface->w,surface->h-1,0,0,0,128);
lineRGBA(surface,0,surface->h-2,surface->w,surface->h-2,0,0,0,32);
lineRGBA(surface,0,0,surface->w,0,0,0,0,32);
surfaces.push_back(surface);
h+=r.h;
}
}
if(surfaces.empty()){
+ //impossible now
achievements=TTF_RenderUTF8_Blended(fontText,_("You don't have any achievements now. Play the game and try to earn some!"),themeTextColor);
}else{
achievements=SDL_CreateRGBSurface(SDL_HWSURFACE,w,h,
screen->format->BitsPerPixel,screen->format->Rmask,screen->format->Gmask,screen->format->Bmask,0);
h=0;
for(unsigned int i=0;i<surfaces.size();i++){
SDL_Rect r={0,h,0,0};
SDL_BlitSurface(surfaces[i],NULL,achievements,&r);
h+=surfaces[i]->h;
SDL_FreeSurface(surfaces[i]);
}
}
//Create the root element of the GUI.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
GUIObjectRoot=new GUIObject(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,GUIObjectNone);
//Create back button.
GUIObject* obj=new GUIObject(SCREEN_WIDTH*0.5,SCREEN_HEIGHT-60,-1,36,GUIObjectButton,_("Back"),0,true,true,GUIGravityCenter);
obj->name="cmdBack";
obj->eventCallback=this;
GUIObjectRoot->addChild(obj);
//Create list box
listBox=new GUISingleLineListBox((SCREEN_WIDTH-500)/2,104,500,32);
listBox->item.push_back(_("Achievements"));
listBox->item.push_back(_("Statistics"));
listBox->value=0;
GUIObjectRoot->addChild(listBox);
//Create vertical scrollbar.
h-=SCREEN_HEIGHT-144-80;
if(h<0) h=0;
scrollbarV=new GUIScrollBar(SCREEN_WIDTH-64-16,144,16,SCREEN_HEIGHT-144-80,1,0,0,h,16,SCREEN_HEIGHT-144-80,true,false);
GUIObjectRoot->addChild(scrollbarV);
}
//In this method all the key and mouse events should be handled.
//Note: The GUIEvents won't be handled here.
void StatisticsScreen::handleEvents(){
//Check if we need to quit, if so enter the exit state.
if(event.type==SDL_QUIT){
setNextState(STATE_EXIT);
}
//Check if the escape button is pressed, if so go back to the main menu.
if(inputMgr.isKeyUpEvent(INPUTMGR_ESCAPE)){
setNextState(STATE_MENU);
}
//Check for scrolling down and up with mouse scroll wheel.
if(event.type==SDL_MOUSEBUTTONDOWN && event.button.button==SDL_BUTTON_WHEELDOWN && scrollbarV->visible){
if(scrollbarV->value<scrollbarV->maxValue)
scrollbarV->value+=scrollbarV->smallChange*4;
if(scrollbarV->value>scrollbarV->maxValue)
scrollbarV->value=scrollbarV->maxValue;
return;
}else if(event.type==SDL_MOUSEBUTTONDOWN && event.button.button==SDL_BUTTON_WHEELUP && scrollbarV->visible){
if(scrollbarV->value>0)
scrollbarV->value-=scrollbarV->smallChange*4;
if(scrollbarV->value<0)
scrollbarV->value=0;
return;
}
}
//All the logic that needs to be done should go in this method.
void StatisticsScreen::logic(){
}
//This method handles all the rendering.
void StatisticsScreen::render(){
//Draw background.
objThemes.getBackground(true)->draw(screen);
objThemes.getBackground(true)->updateAnimation();
//Draw title.
applySurface((SCREEN_WIDTH-title->w)/2,40-TITLE_FONT_RAISE,title,screen,NULL);
switch(listBox->value){
case 0:
//achievements
{
scrollbarV->visible=(scrollbarV->maxValue>0);
SDL_Rect r1={0,scrollbarV->value,achievements->w,SCREEN_HEIGHT-144-80};
SDL_Rect r2={64,144,0,0};
SDL_BlitSurface(achievements,&r1,screen,&r2);
if(scrollbarV->visible)
drawGUIBox(63,144,achievements->w+3,SCREEN_HEIGHT-144-80,screen,SDL_MapRGB(screen->format,0,0,0));
else
drawGUIBox(63,144,achievements->w+1,achievements->h,screen,SDL_MapRGB(screen->format,0,0,0));
}
break;
case 1:
//statistics
scrollbarV->visible=false;
applySurface((SCREEN_WIDTH-stats->w)/2,144,stats,screen,NULL);
break;
}
}
//Method that will be called when the screen size has been changed in runtime.
void StatisticsScreen::resize(){
//Recreate the gui to fit the new resolution.
createGUI();
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 16, 1:44 PM (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
64168
Default Alt Text
(44 KB)

Event Timeline