1 /*
2 ===========================================================================
3 blockattack - Block Attack - Rise of the Blocks
4 Copyright (C) 2005-2016 Poul Sander
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see http://www.gnu.org/licenses/
18
19 Source information and contacts persons can be found at
20 http://www.blockattack.net
21 ===========================================================================
22 */
23
24 #include "ScoresDisplay.hpp"
25 #include "global.hpp"
26 #include "common.h"
27 #include "stats.h"
28 #include "MenuSystem.h"
29
30 const int buttonOffsetX = 140;
31 const int buttonOffsetY = 180;
32 extern sago::SagoSprite bExit;
33
setButtonFont(const sago::SagoDataHolder * holder,sago::SagoTextField & field,const char * text)34 static void setButtonFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) {
35 field.SetHolder(holder);
36 field.SetFont("freeserif");
37 field.SetColor({255,255,255,255});
38 field.SetFontSize(24);
39 field.SetOutline(1, {128,128,128,255});
40 field.SetText(text);
41 }
42
getCachedText(const std::string & text)43 sago::SagoTextField* ScoresDisplay::getCachedText(const std::string& text) {
44 std::shared_ptr<sago::SagoTextField> ptr = fieldCache[text];
45 if (!ptr) {
46 std::shared_ptr<sago::SagoTextField> newText = std::make_shared<sago::SagoTextField>();
47 sagoTextSetBlueFont(*newText.get());
48 newText->SetText(text);
49 fieldCache[text] = newText;
50 }
51 return fieldCache[text].get();
52 }
53
Write(SDL_Renderer * target,int x,int y,const char * text)54 void ScoresDisplay::Write(SDL_Renderer* target, int x, int y, const char* text) {
55 getCachedText(text)->Draw(target, x, y);
56 }
57
58 const int numberOfPages = 7;
59
DrawBackgroundAndCalcPlacements()60 void ScoresDisplay::DrawBackgroundAndCalcPlacements() {
61 DrawBackground(globalData.screen);
62 nextX = globalData.xsize-buttonXsize-20;
63 backY = globalData.ysize-buttonYsize-20;
64 nextY = backY;
65 }
66
67 //Draws the highscores
DrawHighscores(int x,int y,bool endless,int level=0)68 void ScoresDisplay::DrawHighscores(int x, int y, bool endless, int level = 0) {
69 DrawBackgroundAndCalcPlacements();
70 if (endless) {
71 std::string header;
72 switch (level) {
73 case 1:
74 header = _("Endless (Fast):");
75 break;
76 case 2:
77 header = _("Endless (Faster):");
78 break;
79 case 3:
80 header = _("Endless (Even faster):");
81 break;
82 case 4:
83 header = _("Endless (Fastest):");
84 break;
85 default:
86 header = _("Endless:");
87 };
88 Write(globalData.screen, x+100,y+100, header.c_str() );
89 }
90 else {
91 Write(globalData.screen, x+100,y+100, _("Time Trial:") );
92 }
93 for (int i =0; i<10; i++) {
94 record r;
95 if (endless) {
96 switch (level) {
97 case 1:
98 r = theTopScoresEndless1.getScoreNumber(i);
99 break;
100 case 2:
101 r = theTopScoresEndless2.getScoreNumber(i);
102 break;
103 case 3:
104 r = theTopScoresEndless3.getScoreNumber(i);
105 break;
106 case 4:
107 r = theTopScoresEndless4.getScoreNumber(i);
108 break;
109 default:
110 r = theTopScoresEndless0.getScoreNumber(i);
111 }
112 }
113 else {
114 r = theTopScoresTimeTrial.getScoreNumber(i);
115 }
116 char playerScore[32];
117 char playerName[32];
118 snprintf(playerScore, sizeof(playerScore), "%i", r.score);
119 snprintf(playerName, sizeof(playerName), "%s", r.name.c_str());
120 Write(globalData.screen, x+420,y+150+i*35, playerScore);
121 Write(globalData.screen, x+60,y+150+i*35, playerName);
122 }
123 }
124
DrawStats()125 void ScoresDisplay::DrawStats() {
126 DrawBackgroundAndCalcPlacements();
127 int y = 5;
128 const int y_spacing = 30;
129 Write(globalData.screen, 10,y,_("Stats") );
130 y+=y_spacing*2;
131 Write(globalData.screen, 10,y,_("Chains") );
132 for (int i=2; i<13; i++) {
133 y+=y_spacing;
134 Write(globalData.screen, 10,y,(std::to_string(i)+"X").c_str());
135 std::string numberAsString = std::to_string(Stats::getInstance()->getNumberOf("chainX"+std::to_string(i)));
136 Write(globalData.screen, 300,y,numberAsString.c_str());
137 }
138 y+=y_spacing*2;
139 Write(globalData.screen, 10,y,_("Lines Pushed: ") );
140 std::string numberAsString = std::to_string(Stats::getInstance()->getNumberOf("linesPushed"));
141 Write(globalData.screen, 300,y,numberAsString.c_str());
142
143 y+=y_spacing;
144 Write(globalData.screen, 10,y, _("Puzzles solved: ") );
145 numberAsString = std::to_string(Stats::getInstance()->getNumberOf("puzzlesSolved"));
146 Write(globalData.screen, 300,y,numberAsString.c_str());
147
148 y+=y_spacing*2;
149 Write(globalData.screen, 10,y, _("Run time: ") );
150 commonTime ct = TimeHandler::peekTime("totalTime",TimeHandler::ms2ct(SDL_GetTicks()));
151 y+=y_spacing;
152 Write(globalData.screen, 10, y, SPrintCF( _("Days: %i"), ct.days) );
153 y+=y_spacing;
154 Write(globalData.screen, 10, y, SPrintCF( _("Hours: %i"), ct.hours) );
155 y+=y_spacing;
156 Write(globalData.screen, 10, y, SPrintCF( _("Minutes: %i"), ct.minutes) );
157 y+=y_spacing;
158 Write(globalData.screen, 10, y, SPrintCF( _("Seconds: %i"), ct.seconds) );
159
160 y-=y_spacing*4; //Four rows back
161 const int x_offset3 = globalData.xsize/3+10; //Ofset for three rows
162 Write(globalData.screen, x_offset3,y, _("Play time: ") );
163 ct = TimeHandler::getTime("playTime");
164 y+=y_spacing;
165 Write(globalData.screen, x_offset3, y, SPrintCF( _("Days: %i"), ct.days) );
166 y+=y_spacing;
167 Write(globalData.screen, x_offset3, y, SPrintCF( _("Hours: %i"), ct.hours) );
168 y+=y_spacing;
169 Write(globalData.screen, x_offset3, y, SPrintCF( _("Minutes: %i"), ct.minutes) );
170 y+=y_spacing;
171 Write(globalData.screen, x_offset3, y, SPrintCF( _("Seconds: %i"), ct.seconds) );
172
173 const int x_offset = globalData.xsize/2+10;
174 y = 5+y_spacing*2;
175 Write(globalData.screen, x_offset,y, _("VS CPU (win/loss)") );
176 for (int i=0; i<7; i++) {
177 y += y_spacing;
178 Write(globalData.screen, x_offset,y,std::string("AI "+std::to_string(i+1)).c_str());
179 numberAsString = std::to_string(Stats::getInstance()->getNumberOf("defeatedAI"+std::to_string(i)));
180 std::string numberAsString2 = std::to_string(Stats::getInstance()->getNumberOf("defeatedByAI"+std::to_string(i)));
181 std::string toPrint = numberAsString + "/" + numberAsString2;
182 Write(globalData.screen, x_offset+230,y,toPrint.c_str());
183 }
184 }
185
ScoresDisplay()186 ScoresDisplay::ScoresDisplay() {
187 }
188
~ScoresDisplay()189 ScoresDisplay::~ScoresDisplay() {
190 }
191
IsActive()192 bool ScoresDisplay::IsActive() {
193 return isActive;
194 }
195
Draw(SDL_Renderer *)196 void ScoresDisplay::Draw(SDL_Renderer*) {
197 switch (page) {
198 case 0:
199 case 1:
200 case 2:
201 case 3:
202 case 4:
203 //Highscores, endless
204 DrawHighscores(100,100,true, page);
205 break;
206 case 5:
207 //Highscores, Time Trial
208 DrawHighscores(100,100,false);
209 break;
210 case 6:
211 default:
212 DrawStats();
213 };
214
215 const sago::SagoDataHolder* holder = &globalData.spriteHolder->GetDataHolder();
216 //Draw buttons:
217 bExit.Draw(globalData.screen, SDL_GetTicks(), globalData.xsize-buttonOffsetX, globalData.ysize-buttonOffsetY);
218 globalData.bBack.Draw(globalData.screen, 0, backX, backY);
219 static sago::SagoTextField backLabel;
220 setButtonFont(holder, backLabel, _("Back"));
221 backLabel.Draw(globalData.screen, backX+60,backY+10, sago::SagoTextField::Alignment::center);
222 globalData.bNext.Draw(globalData.screen, 0, nextX, nextY);
223 static sago::SagoTextField nextLabel;
224 setButtonFont(holder, nextLabel, _("Next"));
225 nextLabel.Draw(globalData.screen, nextX+60, nextY+10, sago::SagoTextField::Alignment::center);
226
227 //Draw page number
228 std::string pageXofY = SPrintStringF(_("Page %i of %i"), page+1, numberOfPages);
229 getCachedText(pageXofY)->Draw(globalData.screen, globalData.xsize/2, globalData.ysize-60, sago::SagoTextField::Alignment::center);
230 }
231
ProcessInput(const SDL_Event & event,bool & processed)232 void ScoresDisplay::ProcessInput(const SDL_Event& event, bool& processed) {
233
234 UpdateMouseCoordinates(event, globalData.mousex, globalData.mousey);
235
236 if (isRightEvent(event)) {
237 page++;
238 if (page>=numberOfPages) {
239 page = 0;
240 }
241 processed = true;
242 }
243
244 if (isLeftEvent(event)) {
245 page--;
246 if (page<0) {
247 page = numberOfPages-1;
248 }
249 processed = true;
250 }
251
252 if (isConfirmEvent(event) || isEscapeEvent(event)) {
253 isActive = false;
254 processed = true;
255 }
256 }
257
Update()258 void ScoresDisplay::Update() {
259 // If the mouse button is released, make bMouseUp equal true
260 if ( !(SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) ) {
261 bMouseUp=true;
262 }
263
264 if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
265 bMouseUp = false;
266
267 //The Exit button:
268 if ((globalData.mousex>globalData.xsize-buttonOffsetX) && (globalData.mousex<globalData.xsize-buttonOffsetX+bExit.GetWidth())
269 && (globalData.mousey>globalData.ysize-buttonOffsetY) && (globalData.mousey<globalData.ysize-buttonOffsetY+bExit.GetHeight())) {
270 isActive = false;
271 }
272
273 //The back button:
274 if ((globalData.mousex>backX) && (globalData.mousex<backX+buttonXsize) && (globalData.mousey>backY) && (globalData.mousey<backY+buttonYsize)) {
275 page--;
276 if (page<0) {
277 page = numberOfPages-1;
278 }
279 }
280
281 //The next button:
282 if ((globalData.mousex>nextX) && (globalData.mousex<nextX+buttonXsize) && (globalData.mousey>nextY) && (globalData.mousey<nextY+buttonYsize)) {
283 page++;
284 if (page>=numberOfPages) {
285 page = 0;
286 }
287 }
288 }
289 }