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 }