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