Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
32 KB
Referenced Files
None
Subscribers
None
diff --git a/src/EasterEggScreen.cpp b/src/EasterEggScreen.cpp
new file mode 100644
index 0000000..6bdae10
--- /dev/null
+++ b/src/EasterEggScreen.cpp
@@ -0,0 +1,431 @@
+/*
+* Copyright (C) 2018 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 "EasterEggScreen.h"
+#include "SoundManager.h"
+#include "Render.h"
+#include "Globals.h"
+#include "Functions.h"
+#include "InputManager.h"
+#include <SDL_mixer.h>
+#include <SDL_ttf.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <string>
+#include <map>
+
+//Define this to enable fake "ls -la" screen.
+#define SCAM
+
+#ifdef SCAM
+
+const unsigned int randMaxPlusOne = (unsigned int)(RAND_MAX) + 1;
+
+struct FakeSoundEffectState {
+ Sint16 buffer[4096];
+ int state;
+ int randContext;
+
+ int rand() {
+ randContext = (randContext * 1103515245 + 12345) & 0x7FFFFFFF;
+ return ((randContext << 16) | (randContext >> 16)) & RAND_MAX;
+ }
+};
+
+static void SDLCALL fakeSoundEffect(void *udata, Uint8 *stream_, int len) {
+ FakeSoundEffectState *state = (FakeSoundEffectState*)udata;
+ Sint16 *stream = (Sint16*)stream_;
+
+ int len2 = len / 2; // NOTE: len is in bytes, not in samples !!!
+ int len3 = len2;
+ if (len3 > sizeof(state->buffer) / sizeof(state->buffer[0])) {
+ len3 = sizeof(state->buffer) / sizeof(state->buffer[0]);
+ }
+
+ if (state->state & 0xFF) {
+ state->state--;
+ } else {
+ state->state = int(float(state->rand()) / float(randMaxPlusOne) * 9.0f) << 8;
+ if (state->state) state->state |= int(float(state->rand()) / float(randMaxPlusOne) * 10.0f);
+ else state->state |= int(float(state->rand()) / float(randMaxPlusOne) * 80.0f);
+
+ switch (state->state >> 8) {
+ case 1:
+ memcpy(state->buffer, stream, len3 * sizeof(Sint16));
+ break;
+ }
+ }
+
+ int i;
+
+ switch (state->state >> 8) {
+ case 0:
+ break;
+ case 1:
+ memcpy(stream, state->buffer, len3 * sizeof(Sint16));
+ break;
+ case 2:
+ for (i = 0; i < len2; i++) {
+ stream[i] = stream[i] >= 0 ? 0x7FFF : 0x8000;
+ }
+ break;
+ case 3:
+ for (i = 1; i < len2; i++) {
+ stream[i] ^= stream[i - 1];
+ }
+ break;
+ case 4:
+ for (i = 0; i < len2 / 2; i++) {
+ std::swap(stream[i], stream[len2 - 1 - i]);
+ }
+ break;
+ case 5:
+ for (i = 0; i < len2; i++) {
+ bool b = (stream[i] & 0x1000) != 0;
+ if (stream[i] < 0) b = !b;
+ stream[i] <<= 3;
+ if (b) stream[i] = ~stream[i];
+ }
+ break;
+ case 6:
+ memcpy(state->buffer, stream, len3 * sizeof(Sint16));
+ for (i = 0; i < len3; i += 2) {
+ stream[i / 2] = state->buffer[i];
+ }
+ for (i = 1; i < len3; i += 2) {
+ stream[(len3 + i) / 2] = state->buffer[i];
+ }
+ case 7:
+ for (i = 0; i < len2; i++) {
+ float f = float(stream[i]);
+ stream[i] = Sint32(f * f * f / 1073741824.0f);
+ }
+ break;
+ case 8:
+ for (i = 0; i < len2; i++) {
+ stream[i] = 0;
+ }
+ break;
+ }
+}
+
+FakeSoundEffectState fakeSoundEffectState;
+
+static void scamDrawText(ImageManager& imageManager, SDL_Renderer& renderer,
+ const std::map<int, TexturePtr>& cache,
+ int fontWidth, int fontHeight,
+ int x, int y, const char* text)
+{
+ int color = 0, x0 = x;
+
+ for (int i = 0;; i++) {
+ int c = (int)(unsigned char)text[i];
+ if (c == 0) break;
+ if (c == '\n') {
+ x = x0;
+ y += fontHeight;
+ } else if (c == ' ') {
+ x += fontWidth;
+ } else if (c >= 0x10 && c < 0x20) {
+ color = c & 0xF;
+ } else {
+ const int key = c | (color << 8);
+ auto it = cache.find(key);
+ if (it != cache.end()) {
+ applyTexture(x, y, const_cast<TexturePtr&>(it->second), renderer);
+ x += fontWidth;
+ }
+ }
+ }
+}
+
+//Show a fake never-ending "ls -la" screen unless the user press Ctrl+C.
+bool easterEggScreen(ImageManager& imageManager, SDL_Renderer& renderer) {
+ //Some colors.
+ SDL_Color colors[] = {
+ { 0xC0, 0xC0, 0xC0, 0xFF }, //lightgray
+ { 0x00, 0xFF, 0x00, 0xFF }, //green
+ { 0x00, 0x00, 0xFF, 0xFF }, //blue
+ { 0x00, 0xFF, 0xFF, 0xFF }, //cyan
+ { 0xFF, 0x00, 0xFF, 0xFF }, //magenta
+ };
+ const int numberOfColors = sizeof(colors) / sizeof(colors[0]);
+
+ int fontWidth = 0;
+ TTF_GlyphMetrics(fontMono, 'W', NULL, NULL, NULL, NULL, &fontWidth);
+
+ //Initialize some textures.
+ std::map<int, TexturePtr> cache;
+ for (int i = 0; i < numberOfColors; i++) {
+ for (int c = 33; c <= 126; c++) {
+ const char s[2] = { c, 0 };
+ const int key = c | (i << 8);
+ cache[key] = textureFromText(renderer, *fontMono, s, colors[i]);
+ }
+ }
+
+ const char* extensions[] = {
+ "\x11sh", "\x11py",
+ "\x14png", "\x14jpg",
+ "txt", "c", "cpp", "h", "map", "lst", "lua",
+ };
+ const int numberOfExtensions = sizeof(extensions) / sizeof(extensions[0]);
+
+ const char* users[] = {
+ "root", "user", "me", "shadow"
+ };
+ const int numberOfUsers = sizeof(users) / sizeof(users[0]);
+
+ const char* months[12] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ };
+
+ const int numOfDays[12] = {
+ 31, 28, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31,
+ };
+
+ const int fontHeight = TTF_FontHeight(fontMono);
+
+ //Keep the last resize event, this is to only process one.
+ SDL_Event lastResize = {};
+
+ bool ret = false, isRunning = true;
+
+ char s0[72] = {}, s1[72] = {}, s2[256] = {};
+ for (int i = 0; i < 60; i++) {
+ s0[i] = int(float(rand()) / float(randMaxPlusOne) * 15.0f);
+ }
+
+ if (getSettings()->getBoolValue("music")) {
+ fakeSoundEffectState.state = int(float(rand()) / float(randMaxPlusOne) * 80.0f);
+ fakeSoundEffectState.randContext = rand() ^ (rand() << 16);
+ Mix_SetPostMix(fakeSoundEffect, &fakeSoundEffectState);
+ }
+
+ for (int t = 0; isRunning; t++) {
+ while (SDL_PollEvent(&event)) {
+ //Check if we need to quit, if so enter the exit state.
+ if (event.type == SDL_QUIT){
+ setNextState(STATE_EXIT);
+ isRunning = false;
+ }
+
+ //Check for a resize event.
+ if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
+ lastResize = event;
+ continue;
+ }
+
+ //Check Ctrl+C.
+ if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_c
+ && (event.key.keysym.mod & KMOD_CTRL) != 0 && (event.key.keysym.mod & ~KMOD_CTRL) == 0)
+ {
+ ret = true;
+ isRunning = false;
+ }
+
+ //Set the cursor type to the default one, the GUI can change that if needed.
+ currentCursor = CURSOR_POINTER;
+
+ //Let the input manager handle the events.
+ inputMgr.updateState(true);
+ }
+
+ //Process the resize event.
+ if (lastResize.type == SDL_WINDOWEVENT){
+ //TODO - used to be SDL_VIDEORESIZE
+ // so this may trigger on more events than intended
+ event = lastResize;
+ onVideoResize(imageManager, renderer);
+
+ //After resize we erase the event type
+ //TODO - used to be SDL_NOEVENT
+ lastResize.type = SDL_FIRSTEVENT;
+ }
+
+ //update input state (??)
+ inputMgr.updateState(false);
+
+ //Don't update the screen when the sound glitches.
+ if (fakeSoundEffectState.state >> 8) {
+ SDL_Delay(1000 / FPS);
+ continue;
+ }
+
+ //Clear the screen.
+ SDL_SetRenderDrawColor(&renderer, 0, 0, 0, 255);
+ SDL_RenderClear(&renderer);
+
+ const int rows = SCREEN_HEIGHT / fontHeight - 1;
+
+ for (int row = 0; row < rows; row++) {
+ //Generate some random text.
+ int m = int(float(rand()) / float(randMaxPlusOne) * 56.0f);
+ int carry = 0;
+ for (int i = 0; i < 60; i++) {
+ int c = s0[59 - i] + carry;
+ if (i <= m) c += int(float(rand()) / float(randMaxPlusOne) * 15.0f);
+ carry = 0;
+ while (c >= 15) {
+ c -= 15;
+ carry++;
+ }
+ s0[59 - i] = c;
+ }
+
+ int lp;
+ for (lp = 0; s0[lp]; lp++) {
+ char c = s0[lp] - 4;
+ if (c >= 0 && c < 10) {
+ s1[lp] = c + '0';
+ } else if (c == 10) {
+ s1[lp] = '_';
+ } else {
+ break;
+ }
+ }
+ s1[lp] = 0;
+ if (lp < 60) s0[lp] = 4;
+
+ //Choose a random extension.
+ int extension = int(float(rand()) / float(randMaxPlusOne) * 20.0f);
+ const char* ext = NULL;
+ int color = 0;
+ if (extension < numberOfExtensions) {
+ ext = extensions[extension];
+ if (ext[0] >= 0x10 && ext[0] < 0x20) {
+ color = ext[0] & 0xF;
+ ext++;
+ }
+ }
+ if (ext) {
+ s1[lp] = '.';
+ s1[lp + 1] = 0;
+ strcat(s1 + lp, ext);
+ lp = strlen(s1);
+ }
+
+ //Choose a random color.
+ if (extension >= numberOfExtensions) {
+ int r = int(float(rand()) / float(randMaxPlusOne) * 10.0f);
+ if (r <= 2) color = r;
+ }
+
+ bool isLink = int(float(rand()) / float(randMaxPlusOne) * 10.0f) == 0;
+
+ //Choose a random user.
+ const char* user = users[int(float(rand()) / float(randMaxPlusOne) * float(numberOfUsers))];
+
+ //Choose a random permission
+ const char* permission = NULL;
+ switch (int(float(rand()) / float(randMaxPlusOne) * 10.0f)) {
+ case 0:
+ permission = (color == 1 || color == 2) ? "rwxrwxrwx" : "rw-rw-rw-";
+ break;
+ case 1:
+ permission = (color == 1 || color == 2) ? "rwx------" : "rw-------";
+ break;
+ default:
+ permission = (color == 1 || color == 2) ? "rwxr-xr-x" : "rw-r--r--";
+ break;
+ }
+
+ //Choose a random size
+ int size = 0;
+ if (isLink) {
+ size = 3 + lp;
+ } else if (color == 2) {
+ size = 4096;
+ } else {
+ size = int(float(rand()) / float(randMaxPlusOne) * 10000.0f);
+ }
+
+ int num = 1;
+ if (color == 2) {
+ num = int(float(rand()) / float(randMaxPlusOne) * 10.0f);
+ }
+
+ //Choose a random date
+ char date[8];
+ {
+ int d = int(float(rand()) / float(randMaxPlusOne) * 365.0f);
+ int m = 0;
+ while (d >= numOfDays[m]) {
+ d -= numOfDays[m];
+ m++;
+ }
+ sprintf(date, "%s %2d", months[m], d + 1);
+ }
+
+ //Choose a random year or time
+ char year[8];
+ if (int(float(rand()) / float(randMaxPlusOne) * 10.0f) == 0) {
+ sprintf(year, "%d", 1970 + int(float(rand()) / float(randMaxPlusOne) * 100.0f));
+ } else {
+ sprintf(year, "%02d:%02d", int(float(rand()) / float(randMaxPlusOne) * 24.0f), int(float(rand()) / float(randMaxPlusOne) * 60.0f));
+ }
+
+ //Put them together
+ if (isLink) {
+ sprintf(s2, "l%s %d %-6s %-6s %4d %s %5s \x13.%s\x10 -> %c../%s",
+ permission, num, user, user, size, date, year, s1, 0x10 + color, s1
+ );
+ } else {
+ sprintf(s2, "%c%s %d %-6s %-6s %4d %s %5s %c.%s",
+ color == 2 ? 'd' : '-', permission, num, user, user, size, date, year, 0x10 + color, s1
+ );
+ }
+
+ //Show text
+ scamDrawText(imageManager, renderer, cache, fontWidth, fontHeight, 0, row * fontHeight, s2);
+ }
+
+ //Show a caret.
+ if (t & 0x10) {
+ SDL_Rect r = { 0, rows * fontHeight, fontWidth, fontHeight };
+ SDL_SetRenderDrawColor(&renderer, 0x80, 0xFF, 0, 0xFF);
+ SDL_RenderDrawRect(&renderer, &r);
+ }
+
+ //display it
+ flipScreen(renderer);
+ SDL_Delay(1000 / FPS);
+ }
+
+ Mix_SetPostMix(NULL, NULL);
+
+ return ret;
+}
+
+#else
+
+// Only play a sound.
+bool easterEggScreen(ImageManager& imageManager, SDL_Renderer& renderer) {
+ //play a sound effect
+ getSoundManager()->playSound("hit");
+
+ return true;
+}
+
+#endif
diff --git a/src/EasterEggScreen.h b/src/EasterEggScreen.h
new file mode 100644
index 0000000..324a66a
--- /dev/null
+++ b/src/EasterEggScreen.h
@@ -0,0 +1,27 @@
+/*
+* Copyright (C) 2018 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 EASTEREGGSCREEN_H
+#define EASTEREGGSCREEN_H
+
+#include "ImageManager.h"
+
+bool easterEggScreen(ImageManager& imageManager, SDL_Renderer& renderer);
+
+#endif
diff --git a/src/StatisticsScreen.cpp b/src/StatisticsScreen.cpp
index 41ee1ac..f4307de 100644
--- a/src/StatisticsScreen.cpp
+++ b/src/StatisticsScreen.cpp
@@ -1,375 +1,411 @@
/*
* 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"
+#include "EasterEggScreen.h"
#include <SDL_ttf.h>
#include <array>
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(ImageManager& imageManager, SDL_Renderer& renderer, 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);
}
}
}
//Constructor.
StatisticsScreen::StatisticsScreen(ImageManager& imageManager, SDL_Renderer& renderer){
//Update in-game time.
statsMgr.updatePlayTime();
//Render the title.
title = titleTextureFromText(renderer, _("Achievements and Statistics"), objThemes.getTextColor(false), SCREEN_WIDTH);
//Create GUI.
createGUI(imageManager, renderer);
}
//Destructor.
StatisticsScreen::~StatisticsScreen(){
//Delete the GUI.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}
//we are so lazy that we just use height of the first text, ignore the others
#define DRAW_PLAYER_STATISTICS(name,var,fmt) { \
SurfacePtr surface(TTF_RenderUTF8_Blended(fontGUISmall,name,objThemes.getTextColor(true))); \
SurfacePtr stats = createSurface(w,surface->h); \
SDL_FillRect(stats.get(),NULL,-1); \
applySurface(4,0,surface.get(),stats.get(),NULL); \
y=surface->h; \
SDL_snprintf(formatString.data(),formatString.size(),fmt,statsMgr.player##var+statsMgr.shadow##var); \
surface.reset(TTF_RenderUTF8_Blended(fontText,formatString.data(),objThemes.getTextColor(true))); \
applySurface(w-260-surface->w,(y-surface->h)/2,surface.get(),stats.get(),NULL); \
SDL_snprintf(formatString.data(),formatString.size(),fmt,statsMgr.player##var); \
surface.reset(TTF_RenderUTF8_Blended(fontText,formatString.data(),objThemes.getTextColor(true))); \
applySurface(w-140-surface->w,(y-surface->h)/2,surface.get(),stats.get(),NULL); \
SDL_snprintf(formatString.data(),formatString.size(),fmt,statsMgr.shadow##var); \
surface.reset(TTF_RenderUTF8_Blended(fontText,formatString.data(),objThemes.getTextColor(true))); \
applySurface(w-20-surface->w,(y-surface->h)/2,surface.get(),stats.get(),NULL); \
list->addItem(renderer,"",textureFromSurface(renderer, std::move(stats))); /* add it to list box */ \
}
//Add an item to the listbox, that displays "name1", and "var1" formatted with "format"
//we are so lazy that we just use height of the first text, ignore the others
template <class T1>
static void drawMiscStatistics1(SDL_Renderer& renderer, int w,GUIListBox *list,const char* name1,const T1 var1,const char* format1){
//create new surface
SurfacePtr nameSurface(TTF_RenderUTF8_Blended(fontGUISmall,name1,objThemes.getTextColor(true)));
SurfacePtr stats=createSurface(w, nameSurface->h);
SDL_FillRect(stats.get(),NULL,-1);
applySurface(4,0,nameSurface.get(),stats.get(),NULL);
const int x=nameSurface->w+8;
const int y=nameSurface->h;
//draw value
//char s[1024];
std::array<char, 1024> s;
SDL_snprintf(s.data(),s.size(),format1,var1);
SurfacePtr formatSurface(TTF_RenderUTF8_Blended(fontText,s.data(),objThemes.getTextColor(true)));
//NOTE: SDL2 port. Not halving the y value here as this ends up looking better.
applySurface(x,y-formatSurface->h,formatSurface.get(),stats.get(),NULL);
//add it to list box
list->addItem(renderer, "",textureFromSurface(renderer, std::move(stats)));
//over
//return stats;
}
//NOTE: Disabled this for the SDL2 port for now. It looks a bit off anyhow.
//Might want to make a more general method that draws as many "cells" as there is space.
//Draws two stats on one line if there is space.
//we are so lazy that we just use height of the first text, ignore the others
/*template <class T1,class T2>
static void drawMiscStatistics2(int w,GUIListBox *list,const char* name1,const T1 var1,const char* format1,const char* name2,const T2 var2,const char* format2){
SDL_Surface* stats=drawMiscStatistics1(w,list,name1,var1,format1);
//Check if the width is enough
if(w>=800){
//draw name
SDL_Surface* surface=TTF_RenderUTF8_Blended(fontGUISmall,name2,objThemes.getTextColor(true));
applySurface(w/2-8,stats->h-surface->h,surface,stats,NULL);
int x=surface->w+w/2;
SDL_FreeSurface(surface);
//draw value
char s[1024];
sprintf(s,format2,var2);
surface=TTF_RenderUTF8_Blended(fontText,s,objThemes.getTextColor(true));
applySurface(x,(stats->h-surface->h)/2,surface,stats,NULL);
SDL_FreeSurface(surface);
}else{
//Split into two rows
drawMiscStatistics1(w,list,name2,var2,format2);
}
}*/
+void StatisticsScreen::addAchievements(ImageManager& imageManager, SDL_Renderer &renderer, GUIListBox *list, bool revealUnknownAchievements) {
+ for (int idx = 0; achievementList[idx].id != NULL; ++idx) {
+ time_t *lpt = NULL;
+
+ map<string, OwnedAchievement>::iterator it = statsMgr.achievements.find(achievementList[idx].id);
+ if (it != statsMgr.achievements.end()) {
+ lpt = &it->second.achievedTime;
+ }
+
+ AchievementInfo info = achievementList[idx];
+ if (revealUnknownAchievements) {
+ if (info.displayStyle == ACHIEVEMENT_HIDDEN || info.displayStyle == ACHIEVEMENT_TITLE) {
+ info.displayStyle = ACHIEVEMENT_ALL;
+ }
+ }
+
+ SDL_Rect r;
+ r.x = r.y = 0;
+ r.w = list->width - 16;
+ auto surface = statsMgr.createAchievementSurface(renderer, &info, &r, false, lpt);
+
+ if (surface){
+ list->addItem(renderer, "", surface);
+ }
+ }
+}
+
//Method that will create the GUI.
void StatisticsScreen::createGUI(ImageManager& imageManager, SDL_Renderer &renderer){
//Create the root element of the GUI.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
GUIObjectRoot=new GUIObject(imageManager,renderer,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
//Create back button.
GUIObject* obj=new GUIButton(imageManager,renderer,SCREEN_WIDTH*0.5,SCREEN_HEIGHT-60,-1,36,_("Back"),0,true,true,GUIGravityCenter);
obj->name="cmdBack";
obj->eventCallback=this;
GUIObjectRoot->addChild(obj);
//Create list box.
listBox=new GUISingleLineListBox(imageManager,renderer,(SCREEN_WIDTH-500)/2,104,500,32);
listBox->addItem(_("Achievements"));
listBox->addItem(_("Statistics"));
listBox->value=0;
GUIObjectRoot->addChild(listBox);
//Create list box for achievements.
GUIListBox *list=new GUIListBox(imageManager,renderer,64,150,SCREEN_WIDTH-128,SCREEN_HEIGHT-150-72);
list->selectable=false;
GUIObjectRoot->addChild(list);
lists.clear();
lists.push_back(list);
- for(int idx=0;achievementList[idx].id!=NULL;++idx){
- 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_Rect r;
- r.x=r.y=0;
- r.w=list->width-16;
- auto surface= statsMgr.createAchievementSurface(renderer, &achievementList[idx],&r,false,lpt);
-
- if(surface){
- //FIXME - this is broken with SDL2 as the function now operates on a renderer, not sure how best to fix it
-/* hlineRGBA(surface,0,surface->w,0,0,0,0,32);
- hlineRGBA(surface,0,surface->w,surface->h-1,0,0,0,128);
- hlineRGBA(surface,0,surface->w,surface->h-2,0,0,0,32);*/
- list->addItem(renderer, "",surface);
- }
- }
+ addAchievements(imageManager, renderer, list);
//Now create list box for statistics.
list=new GUIListBox(imageManager,renderer,64,150,SCREEN_WIDTH-128,SCREEN_HEIGHT-150-72,true,false);
list->selectable=false;
GUIObjectRoot->addChild(list);
lists.push_back(list);
//Load needed pictures.
//FIXME: hard-coded image path
//TODO: Might want to consider not caching these as most other stuff use textures now.
SDL_Surface* bmPlayer=imageManager.loadImage(getDataPath()+"themes/Cloudscape/characters/player.png");
SDL_Surface* bmShadow=imageManager.loadImage(getDataPath()+"themes/Cloudscape/characters/shadow.png");
SDL_Surface* bmMedal=imageManager.loadImage(getDataPath()+"gfx/medals.png");
//Render stats.
//char s[64],s2[64];
std::array<char, 64> formatString;
SDL_Rect r;
int x,y,w=SCREEN_WIDTH-128;
SharedTexture h_bar = [&](){
//The horizontal bar.
SurfacePtr h_bar(createSurface(w,2));
SDL_Color c = objThemes.getTextColor(true);
Uint32 clr=SDL_MapRGB(h_bar->format,c.r,c.g,c.b);
SDL_FillRect(h_bar.get(),NULL,clr);
return textureFromSurface(renderer, std::move(h_bar));
}();
//Player and shadow specific statistics
//The header.
{
SurfacePtr stats = createSurface(w, 44);
SDL_FillRect(stats.get(),NULL,-1);
SurfacePtr surface(TTF_RenderUTF8_Blended(fontGUISmall,_("Total"),objThemes.getTextColor(true)));
applySurface(w-260-surface->w,stats->h-surface->h,surface.get(),stats.get(),NULL);
//FIXME: hard-coded player and shadow images
r.x=0;r.y=0;r.w=23;r.h=40;
applySurface(w-140-r.w,stats.get()->h-40,bmPlayer,stats.get(),&r);
applySurface(w-20-r.w,stats.get()->h-40,bmShadow,stats.get(),&r);
list->addItem(renderer, "",textureFromSurface(renderer, std::move(stats)));
}
//Each items.
{
DRAW_PLAYER_STATISTICS(_("Traveling distance (m)"),TravelingDistance,"%0.1f");
DRAW_PLAYER_STATISTICS(_("Jump times"),Jumps,"%d");
DRAW_PLAYER_STATISTICS(_("Die times"),Dies,"%d");
DRAW_PLAYER_STATISTICS(_("Squashed times"),Squashed,"%d");
}
//Game specific statistics.
list->addItem(renderer, "",h_bar);
auto drawMiscStats = [&](const char* name1,const int var1,const char* format1) {
drawMiscStatistics1(renderer, w, list, name1, var1, format1);
};
drawMiscStats(_("Recordings:"),statsMgr.recordTimes,"%d");
drawMiscStats(_("Switch pulled times:"),statsMgr.switchTimes,"%d");
drawMiscStats(_("Swap times:"),statsMgr.swapTimes,"%d");
drawMiscStats(_("Save times:"),statsMgr.saveTimes,"%d");
drawMiscStats(_("Load times:"),statsMgr.loadTimes,"%d");
//Level specific statistics
list->addItem(renderer, "",h_bar);
{
SurfacePtr surface(TTF_RenderUTF8_Blended(fontGUISmall,_("Completed levels:"),objThemes.getTextColor(true)));
SurfacePtr stats = createSurface(w, surface->h);
SDL_FillRect(stats.get(),NULL,-1);
applySurface(4,0,surface.get(),stats.get(),NULL);
x=surface->w+8;
y=surface->h;
SDL_snprintf(formatString.data(), formatString.size(),"%d",statsMgr.completedLevels);
surface.reset(TTF_RenderUTF8_Blended(fontText,formatString.data(),objThemes.getTextColor(true)));
applySurface(x,(y-surface->h),surface.get(),stats.get(),NULL);
SDL_snprintf(formatString.data(), formatString.size(),"%d",statsMgr.completedLevels-statsMgr.goldLevels-statsMgr.silverLevels);
surface.reset(TTF_RenderUTF8_Blended(fontText,formatString.data(),objThemes.getTextColor(true)));
applySurface(w-260-surface->w,(y-surface->h)/2,surface.get(),stats.get(),NULL);
r.x=0;r.y=0;r.w=30;r.h=30;
applySurface(w-260-surface->w-30,(y-30)/2,bmMedal,stats.get(),&r);
SDL_snprintf(formatString.data(), formatString.size(),"%d",statsMgr.silverLevels);
surface.reset(TTF_RenderUTF8_Blended(fontText,formatString.data(),objThemes.getTextColor(true)));
applySurface(w-140-surface->w,(y-surface->h)/2,surface.get(),stats.get(),NULL);
r.x+=30;
applySurface(w-140-surface->w-30,(y-30)/2,bmMedal,stats.get(),&r);
SDL_snprintf(formatString.data(), formatString.size(),"%d",statsMgr.goldLevels);
surface.reset(TTF_RenderUTF8_Blended(fontText,formatString.data(),objThemes.getTextColor(true)));
applySurface(w-20-surface->w,(y-surface->h)/2,surface.get(),stats.get(),NULL);
r.x+=30;
applySurface(w-20-surface->w-30,(y-30)/2,bmMedal,stats.get(),&r);
list->addItem(renderer,"",textureFromSurface(renderer, std::move(stats)));
}
//Other statistics.
list->addItem(renderer, "",h_bar);
SDL_snprintf(formatString.data(), formatString.size(),"%02d:%02d:%02d",statsMgr.playTime/3600,(statsMgr.playTime/60)%60,statsMgr.playTime%60);
drawMiscStatistics1(renderer,w,list,_("In-game time:"),formatString.data(),"%s");
SDL_snprintf(formatString.data(), formatString.size(),"%02d:%02d:%02d",statsMgr.levelEditTime/3600,(statsMgr.levelEditTime/60)%60,statsMgr.levelEditTime%60);
drawMiscStatistics1(renderer,w,list,_("Level editing time:"),formatString.data(),"%s");
drawMiscStats(_("Created levels:"),statsMgr.createdLevels,"%d");
}
//In this method all the key and mouse events should be handled.
//NOTE: The GUIEvents won't be handled here.
-void StatisticsScreen::handleEvents(ImageManager&, SDL_Renderer&){
+void StatisticsScreen::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer){
//Check if we need to quit, if so enter the exit state.
if(event.type==SDL_QUIT){
setNextState(STATE_EXIT);
}
//Check horizontal movement
int value = listBox->value;
if (inputMgr.isKeyDownEvent(INPUTMGR_RIGHT)){
isKeyboardOnly = true;
value++;
if (value >= (int)listBox->item.size()) value = 0;
} else if (inputMgr.isKeyDownEvent(INPUTMGR_LEFT)){
isKeyboardOnly = true;
value--;
if (value < 0) value = listBox->item.size() - 1;
}
listBox->value = value;
//Check vertical movement
if (value >= 0 && value < (int)lists.size()) {
if (inputMgr.isKeyDownEvent(INPUTMGR_UP)){
isKeyboardOnly = true;
lists[value]->scrollScrollbar(-1);
} else if (inputMgr.isKeyDownEvent(INPUTMGR_DOWN)){
isKeyboardOnly = true;
lists[value]->scrollScrollbar(1);
}
}
+ //Yet another cheat "ls -la" which reveals all unknown achievements
+ static char input[6];
+ static int inputLen = 0;
+ if (value == 0) {
+ if (event.type == SDL_KEYDOWN) {
+ if (event.key.keysym.sym >= 32 && event.key.keysym.sym <= 126) {
+ if (inputLen < sizeof(input)) input[inputLen] = event.key.keysym.sym;
+ inputLen++;
+ } else {
+ if (event.key.keysym.sym == SDLK_RETURN && inputLen == 6 &&
+ input[0] == 'l' && input[1] == 's' && input[2] == ' ' && input[3] == '-' && input[4] == 'l' && input[5] == 'a')
+ {
+ if (easterEggScreen(imageManager, renderer)) {
+ //new achievement
+ statsMgr.newAchievement("cheat");
+
+ //reload achievement list with hidden achievements revealed
+ lists[0]->clearItems();
+ addAchievements(imageManager, renderer, lists[0], true);
+ }
+ }
+ inputLen = 0;
+ }
+ }
+ } else {
+ inputLen = 0;
+ }
+
//Check if the escape button is pressed, if so go back to the main menu.
if(inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE)){
setNextState(STATE_MENU);
}
}
//All the logic that needs to be done should go in this method.
void StatisticsScreen::logic(ImageManager&, SDL_Renderer&){
}
//This method handles all the rendering.
void StatisticsScreen::render(ImageManager&, SDL_Renderer& renderer){
//Draw background.
objThemes.getBackground(true)->draw(renderer);
objThemes.getBackground(true)->updateAnimation();
//Draw title.
drawTitleTexture(SCREEN_WIDTH, *title, renderer);
//Draw statistics.
int value=listBox->value;
for(unsigned int i=0;i<lists.size();i++){
lists[i]->visible=(i==value);
}
}
//Method that will be called when the screen size has been changed in runtime.
void StatisticsScreen::resize(ImageManager &imageManager, SDL_Renderer &renderer){
//Recreate the gui to fit the new resolution.
createGUI(imageManager, renderer);
}
diff --git a/src/StatisticsScreen.h b/src/StatisticsScreen.h
index d2f448a..2d24390 100644
--- a/src/StatisticsScreen.h
+++ b/src/StatisticsScreen.h
@@ -1,68 +1,74 @@
/*
* 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 STATISTICSSCREEN_H
#define STATISTICSSCREEN_H
#include <SDL.h>
#include "GameState.h"
#include "GUIObject.h"
#include "GUIListBox.h"
#include "Render.h"
class StatisticsScreen:public GameState, private GUIEventCallback{
private:
//Contains title.
TexturePtr title;
//The list box used to switch between statistics and achievements.
GUISingleLineListBox* listBox;
//The list widgets used for achievements and statistics.
std::vector<GUIListBox*> lists;
//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 GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType);
+
+ //Add the list of achievements to the GUIListBox.
+ //list: The list box.
+ //revealUnknownAchievements: Reveal the name and description of unknown achievements. Considered as cheating.
+ void StatisticsScreen::addAchievements(ImageManager& imageManager, SDL_Renderer &renderer, GUIListBox *list, bool revealUnknownAchievements = false);
+
public:
//Constructor.
StatisticsScreen(ImageManager &imageManager, SDL_Renderer& renderer);
//Destructor.
virtual ~StatisticsScreen();
//Method that will create the GUI for the options menu.
void createGUI(ImageManager &imageManager, SDL_Renderer& renderer);
//In this method all the key and mouse events should be handled.
//NOTE: The GUIEvents won't be handled here.
virtual void handleEvents(ImageManager&, SDL_Renderer&) override;
//All the logic that needs to be done should go in this method.
virtual void logic(ImageManager&, SDL_Renderer&) override;
//This method handles all the rendering.
virtual void render(ImageManager&, SDL_Renderer& renderer) override;
//Method that will be called when the screen size has been changed in runtime.
virtual void resize(ImageManager& imageManager, SDL_Renderer& renderer) override;
};
#endif

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 16, 7:24 PM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
63282
Default Alt Text
(32 KB)

Event Timeline