1 // Brain Party
2 // Copyright (C) 2010 Paul Hudson (http://www.tuxradar.com/brainparty)
3 
4 // Brain Party is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 
18 #include "Minigame.h"
19 
BPMiniGame(BPGame * game)20 BPMiniGame::BPMiniGame(BPGame* game) {
21 	TheGame = game;
22 
23 	ReturnType = RT_NORMAL;
24 
25 	FinishedTime = FinalWeight = 0;
26 
27 	FinalGrade = NULL;
28 
29 	sfcGameTitle = NULL;
30 	sfcGameHelp = NULL;
31 	sfcFinalWeight = NULL;
32 	sfcFinalGrade = NULL;
33 
34 	MarathonMode = false;
35 
36 	WantToQuit = -1;
37 }
38 
Init()39 void BPMiniGame::Init() {
40 	TheGame->AllocString(&sfcGameTitle, GameTitle, LARGE, 276, 46, LEFT, true);
41 	TheGame->AllocString(&sfcGameHelp, GameHelp, XSMALL, 276, 170, LEFT);
42 }
43 
~BPMiniGame()44 BPMiniGame::~BPMiniGame() {
45 //	SAFE_DELETE(GameTitle);
46 //	SAFE_DELETE(sfcGameTitle);
47 //	SAFE_DELETE(GameHelp);
48 //	SAFE_DELETE(sfcGameHelp);
49 //	SAFE_DELETE(GameHelp2);
50 //	SAFE_DELETE(FinalGrade);
51 
52 //	SAFE_DELETE(sfcFinalWeight);
53 //	SAFE_DELETE(sfcFinalGrade);
54 }
55 
GetRank(int Weight)56 RankTypes BPMiniGame::GetRank(int Weight) {
57 	if (Weight < 50) {
58 		return FAIL;
59 	} else if (Weight < 150) {
60 		return BRONZE;
61 	} else if (Weight < 350) {
62 		return SILVER;
63 	} else if (Weight < 450) {
64 		return GOLD;
65 	} else {
66 		return PLATINUM;
67 	}
68 }
69 
GetGrade(int Weight)70 const char* BPMiniGame::GetGrade(int Weight) {
71 	if (Weight < 50) {
72 		return "F";
73 	} else if (Weight < 50) {
74 		return "D-";
75 	} else if (Weight < 100) {
76 		return "D";
77 	} else if (Weight < 125) {
78 		return "D+";
79 	} else if (Weight < 150) {
80 		return "D++";
81 	} else if (Weight < 175) {
82 		return "C-";
83 	} else if (Weight < 200) {
84 		return "C";
85 	} else if (Weight < 225) {
86 		return "C+";
87 	} else if (Weight < 250) {
88 		return "C++";
89 	} else if (Weight < 275) {
90 		return "B-";
91 	} else if (Weight < 300) {
92 		return "B";
93 	} else if (Weight < 325) {
94 		return "B+";
95 	} else if (Weight < 350) {
96 		return "B++";
97 	} else if (Weight < 375) {
98 		return "A-";
99 	} else if (Weight < 400) {
100 		return "A";
101 	} else if (Weight < 425) {
102 		return "A+";
103 	} else if (Weight < 450) {
104 		return "A++";
105 	} else {
106 		return "A*";
107 	}
108 }
109 
TickMiniGame()110 void BPMiniGame::TickMiniGame() {
111 	Tick();
112 }
113 
RenderMiniGame()114 void BPMiniGame::RenderMiniGame() {
115 	if (FinishedTime != 0 && FinishedTime + 250 < this->TheGame->TickCount) {
116 		RenderScore();
117 	} else {
118 		Render();
119 
120 		TheGame->DrawImage(TheGame->sfcBottomBar, 0, 416);
121 
122 		if (WantToQuit != -1) {
123 			float diff = TheGame->TickCount - WantToQuit;
124 			diff /= 200.0f;
125 			diff = TheGame->Clamp(diff, 0.0f, 1.0f);
126 
127 			Colour col = Colour(1.0f, 1.0f, 1.0f, TheGame->SmoothStep(0.0f, 1.0f, diff));
128 
129 			TheGame->DrawImage(TheGame->sfcQuitTest, 0, 0, col);
130 		}
131 	}
132 }
133 
RenderScore()134 void BPMiniGame::RenderScore() {
135 	switch (FinalRank) {
136 		case FAIL:
137 			TheGame->DrawImage(TheGame->sfcResultsFail, 0, 0);
138 			break;
139 
140 		case BRONZE:
141 			TheGame->DrawImage(TheGame->sfcResultsBronze, 0, 0);
142 			break;
143 
144 		case SILVER:
145 			TheGame->DrawImage(TheGame->sfcResultsSilver, 0, 0);
146 			break;
147 
148 		case GOLD:
149 			TheGame->DrawImage(TheGame->sfcResultsGold, 0, 0);
150 			break;
151 
152 		case PLATINUM:
153 			TheGame->DrawImage(TheGame->sfcResultsPlatinum, 0, 0);
154 			break;
155 
156 		default: // no score has been assigned yet; just fill it in black
157 			TheGame->Clear(TheGame->Black);
158 			return;
159 	}
160 
161 	TheGame->DrawString(sfcFinalWeight, WHITE, 0, 10);
162 	TheGame->DrawString(sfcFinalGrade, WHITE, 0, 50);
163 }
164 
Success()165 void BPMiniGame::Success() {
166 	TheGame->StopMusic();
167 
168 	// minigame was completed successfully!
169 	if (FinishedTime == 0) {
170 		FinishedTime = TheGame->TickCount;
171 		CalculateResult();
172 
173 		if (FinalRank == FAIL) {
174 			TheGame->PlaySound("glass_break");
175 		} else if (FinalRank == PLATINUM) {
176 			TheGame->PlaySound("result");
177 
178 			if (TheGame->Secret1 == false && strcmp(GameTitle, "Balloon Blaster") == 0) {
179 				// they just unlocked a secret
180 				MessageBox::Show("Congratulations on getting a platinum rating in Balloon Blaster - as a special bonus you've also unlocked a secret! Visit the Results screen to see what you've unlocked.", "Congratulations!");
181 				TheGame->Secret1 = true;
182 				TheGame->SaveSettings();
183 			} else if (TheGame->Secret2 == false && strcmp(GameTitle, "Jewel Jam") == 0) {
184 				// they just unlocked a secret
185 				MessageBox::Show("Congratulations on getting a platinum rating in Jewel Jam - as a special bonus you've also unlocked a secret! Visit the Results screen to see what you've unlocked.", "Congratulations!");
186 				TheGame->Secret2 = true;
187 				TheGame->SaveSettings();
188 			} else if (TheGame->Secret3 == false && strcmp(GameTitle, "Odd One Out") == 0) {
189 				// they just unlocked a secret
190 				MessageBox::Show("Congratulations on getting a platinum rating in Odd One Out - as a special bonus you've also unlocked a secret! Visit the Results screen to see what you've unlocked.", "Congratulations!");
191 				TheGame->Secret3 = true;
192 				TheGame->SaveSettings();
193 			} else if (TheGame->Secret4 == false && strcmp(GameTitle, "Untangler") == 0) {
194 				// they just unlocked a secret
195 				MessageBox::Show("Congratulations on getting a platinum rating in Untangler - as a special bonus you've also unlocked a secret! Visit the Results screen to see what you've unlocked.", "Congratulations!");
196 				TheGame->Secret4 = true;
197 				TheGame->SaveSettings();
198 			}
199 		} else {
200 			TheGame->PlaySound("result");
201 		}
202 	}
203 }
204 
Failure()205 void BPMiniGame::Failure() {
206 	TheGame->StopMusic();
207 
208 	// minigame was not completed successfully!
209 	if (FinishedTime == 0) {
210 		FinishedTime = TheGame->TickCount;
211 		FinalWeight = 0;
212 		FinalRank = GetRank(0);
213 		FinalGrade = GetGrade(0);
214 
215 		TheGame->PlaySound("glass_break");
216 	}
217 }
218 
CalculateResult()219 void BPMiniGame::CalculateResult() {
220 	FinalWeight = GetWeight();
221 	FinalRank = GetRank(FinalWeight);
222 	FinalGrade = GetGrade(FinalWeight);
223 
224 	ostringstream brainweight;
225 	brainweight << "Brain weight: " << FinalWeight << "g";
226 	TheGame->AllocString(&sfcFinalWeight, brainweight.str().c_str(), LARGE, 320, 120, CENTRED);
227 
228 	ostringstream finalgrade;
229 	finalgrade << "Grade: " << FinalGrade;
230 	TheGame->AllocString(&sfcFinalGrade, finalgrade.str().c_str(), LARGE, 320, 80, CENTRED);
231 }
232 
HandleMouseUp(BPPoint e)233 void BPMiniGame::HandleMouseUp(BPPoint e) {
234 	TouchEvent = e;
235 
236 	if (FinishedTime != 0) {
237 		if (FinishedTime + 900 < TheGame->TickCount) {
238 			// showing results screen; this delay is important because it stops people skipping the results screen by accident
239 			ContinueGame();
240 		} else {
241 			// do nothing; waiting for results screen to appear
242 		}
243 	} else {
244 		if (WantToQuit != -1) {
245 			// player has asked to quit the test - check their confirmation result
246 			if (TheGame->PointOverRect(e.X, e.Y, 0, 274, 320, 65)) {
247 				// don't quit!
248 				WantToQuit = -1;
249 				TheGame->PlaySound("mouse_click");
250 			} else if (TheGame->PointOverRect(e.X, e.Y, 0, 370, 320, 65)) {
251 				TheGame->CancelTest();
252 				TheGame->PlaySound("mouse_click");
253 			}
254 		} else {
255 			if (e.Y > 416 && (BackDown || HelpDown)) {
256 				// user clicked on either Back or Help; if they didn't mouse down + mouse up on back or help, pass the click to the mini game for handling
257 				if (e.X < 89) {
258 					if (BackDown) {
259 						// only go back if we have mouse down + mouse up
260 						if (TheGame->InTestMode) {
261 							WantToQuit = TheGame->TickCount;
262 						} else {
263 							GoBack();
264 						}
265 
266 						TheGame->PlaySound("mouse_click");
267 					}
268 				} else if (e.X > 228) {
269 					if (HelpDown) {
270 						ShowHelp(); // only go back if we have mouse down + mouse up
271 						TheGame->PlaySound("mouse_click");
272 					}
273 				}
274 			} else {
275 				OnMouseUp();
276 			}
277 
278 			BackDown = false;
279 			HelpDown = false;
280 		}
281 	}
282 }
283 
HandleMouseDown(BPPoint e)284 void BPMiniGame::HandleMouseDown(BPPoint e) {
285 	if (WantToQuit != -1) return; // user is trying to quit; ignore these taps
286 
287 	TouchEvent = e;
288 
289 	if (FinishedTime != 0) return; // ignore these clicks
290 
291 	if (e.Y > 416) {
292 		// user clicked on either Back or Help
293 		if (e.X < 89) {
294 			BackDown = true;
295 		} else if (e.X > 228) {
296 			HelpDown = true;
297 		}
298 	} else {
299 		// Uncomment to quickly test whizzing through games
300 		//Success();
301 		//return;
302 		OnMouseDown();
303 	}
304 }
305 
HandleMouseMove(BPPoint e)306 void BPMiniGame::HandleMouseMove(BPPoint e) {
307 	if (WantToQuit != -1) return; // user is trying to quit; ignore these taps
308 
309 	TouchEvent = e;
310 
311 	if (e.Y < 416) {
312 		OnMouseMove();
313 	}
314 }
315 
DivRem(int Num,int Div,int & Rem)316 int BPMiniGame::DivRem(int Num, int Div, int &Rem) {
317 	Rem = Num % Div;
318 	return (int)floor(Num / Div);
319 }
320 
ShowHelp()321 void BPMiniGame::ShowHelp() {
322 	MessageBox::Show(GameHelp2, GameTitle);
323 }
324 
GoBack()325 void BPMiniGame::GoBack() {
326 	switch (ReturnType) {
327 		case RT_NORMAL:
328 			if (MarathonMode) {
329 				TheGame->GameState = MARATHON;
330 				TheGame->PlayMusic("theme");
331 			} else {
332 				if (TheGame->InTestMode) {
333 					TheGame->GameState = TEST_STATUS;
334 				} else {
335 					TheGame->GameState = PRACTISE_MENU;
336 					TheGame->PlayMusic("theme");
337 				}
338 			}
339 
340 			break;
341 
342 		case RT_SECRET:
343 			TheGame->GameState = HISTORY;
344 			TheGame->PlayMusic("theme");
345 
346 			break;
347 
348 		case RT_BRAINBOOST:
349 			TheGame->GameState = BRAINBOOST;
350 			TheGame->PlayMusic("theme");
351 			break;
352 	}
353 }
354 
ContinueGame()355 void BPMiniGame::ContinueGame() {
356 	if (TheGame->InTestMode) {
357 		TheGame->AddTestScore(FinalWeight);
358 	} else {
359 		GoBack();
360 	}
361 }
362 
Round(double num)363 int BPMiniGame::Round(double num) {
364 	return (int)round(num);
365 }
366 
MinMax(int num)367 int BPMiniGame::MinMax(int num) {
368 	if (num <= 0) return 0;
369 
370 	float fnum = num;
371 
372 	if (fnum > 500) return 500;
373 
374 	return round(fnum);
375 }
376 
SetMarathon()377 void BPMiniGame::SetMarathon() {
378 	// do nothing by default
379 }
380 
DrawProfessorText()381 void BPMiniGame::DrawProfessorText() {
382 	TheGame->DrawString(sfcGameTitle, BLACK, 23, 20);
383 	TheGame->DrawString(sfcGameHelp, BLACK, 23, 53);
384 }
385 
RedrawClock()386 bool BPMiniGame::RedrawClock() {
387 	// used to redraw clocks in minigames that use them at a regular pace
388 	static int ClockTime = 0;
389 
390 	ClockTime += TheGame->ElapsedTickCount;
391 
392 	if (ClockTime > TIMERREDRAW) {
393 		ClockTime -= TIMERREDRAW;
394 		return true;
395 	} else {
396 		return false;
397 	}
398 }
399 
400 
RenderCorrect()401 void BPMiniGame::RenderCorrect() {
402 	TheGame->DrawImage(TheGame->sfcCorrect, 0, 172);
403 }
404 
RenderWrong()405 void BPMiniGame::RenderWrong() {
406 	TheGame->DrawImage(TheGame->sfcWrong, 0, 172);
407 }
408 
PlayMusic()409 void BPMiniGame::PlayMusic() {
410 	switch (MiniGameType) {
411 		case ACTION:
412 			switch (TheGame->RandomRange(0, 3)) {
413 				case 0:
414 					TheGame->PlayMusic("starmarch");
415 					break;
416 
417 				case 1:
418 					TheGame->PlayMusic("nevertoolate");
419 					break;
420 
421 				case 2:
422 					TheGame->PlayMusic("chekolake");
423 					break;
424 
425 				case 3:
426 					TheGame->PlayMusic("highway");
427 					break;
428 			}
429 
430 			break;
431 
432 		case LIVELY:
433 			switch (TheGame->RandomRange(0, 2)) {
434 				case 0:
435 					TheGame->PlayMusic("lively");
436 					break;
437 
438 				case 1:
439 					TheGame->PlayMusic("electricity");
440 					break;
441 
442 				case 2:
443 					TheGame->PlayMusic("nevertoolate");
444 					break;
445 			}
446 
447 			break;
448 
449 		case PUZZLE:
450 			switch (TheGame->RandomRange(0, 2)) {
451 				case 0:
452 					TheGame->PlayMusic("ambient");
453 					break;
454 
455 				case 1:
456 					TheGame->PlayMusic("brainrace");
457 					break;
458 
459 				case 2:
460 					TheGame->PlayMusic("morningwave");
461 					break;
462 			}
463 
464 			break;
465 	}
466 }
467 
GenerateStarfield(BPPList<BPMiniGame_BGStar * > & list)468 void BPMiniGame::GenerateStarfield(BPPList<BPMiniGame_BGStar*> &list) {
469 	for (int i = 0; i < 100; ++i) {
470 		BPMiniGame_BGStar* star = new BPMiniGame_BGStar();
471 		star->Type = TheGame->RandomRange(0, 2);
472 		star->Pos = BPPoint(TheGame->RandomRange(0, 320), TheGame->RandomRange(0, 416));
473 		star->Speed = (star->Type + TheGame->RandomRange(0, 2)) / 3.0f;
474 		if (star->Speed < 0.2f) star->Speed = 0.2f;
475 		list.Add(star);
476 	}
477 }
478 
UpdateStarfield(BPPList<BPMiniGame_BGStar * > & list)479 void BPMiniGame::UpdateStarfield(BPPList<BPMiniGame_BGStar*> &list) {
480 	for (int i = 0; i < list.Count; ++i) {
481 		BPMiniGame_BGStar* star = list[i];
482 
483 		star->Pos.X -= star->Speed;
484 		if (star->Pos.X < -2) {
485 			star->Pos = BPPoint(322, TheGame->RandomRange(0, 416));
486 		}
487 	}
488 }
489 
DrawStarfield(BPPList<BPMiniGame_BGStar * > & list)490 void BPMiniGame::DrawStarfield(BPPList<BPMiniGame_BGStar*> &list) {
491 	for (int i = 0; i < 100; ++i) {
492 		BPMiniGame_BGStar* star = list[i];
493 
494 		TheGame->DrawImage(TheGame->sfcStarTypes[star->Type], star->Pos.X, star->Pos.Y);
495 	}
496 }
497