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 "scrambled.h"
19 #include "Minigame.h"
20
BPMiniGame_Scrambled(BPGame * game)21 BPMiniGame_Scrambled::BPMiniGame_Scrambled(BPGame* game) : BPMiniGame(game) {
22 AnswersYOffset = 9;
23
24 CurrentLevel = Score = RandSeed = SelectedItem = TimeStarted = 0;
25
26 LastStateChange = -1;
27
28 sfcBackground = TheGame->LoadBitmap("scrambled", 320, 416);
29
30 sfcAnswer1 = sfcAnswer2 = sfcAnswer3 = sfcAnswer4 = NULL;
31 TheQuestion = NULL;
32
33 GameTitle = "Scrambled!";
34 GameHelp = "I'm going to scramble words and numbers by adding, removing and switching letters. You need to figure out what I've done, then tap the correct answers to my questions.";
35 GameHelp2 = "Have letters been added, swapped or deleted? Has the whole word been reversed? Figure out what I changed to solve the problems!";
36
37 MiniGameType = PUZZLE;
38
39 // note: each of these words have no duplicate letters, eg "DEERS" is not allowed
40 Words.Add(string("ACORN"));
41 Words.Add(string("AFTER"));
42 Words.Add(string("BEACH"));
43 Words.Add(string("BEAST"));
44 Words.Add(string("BLACK"));
45 Words.Add(string("BLADE"));
46 Words.Add(string("BLAST"));
47 Words.Add(string("BLAZE"));
48 Words.Add(string("BLOCK"));
49 Words.Add(string("BRAIN"));
50 Words.Add(string("BRAKE"));
51 Words.Add(string("BRICK"));
52 Words.Add(string("BROWN"));
53 Words.Add(string("CARDS"));
54 Words.Add(string("CHAMP"));
55 Words.Add(string("CHILD"));
56 Words.Add(string("CLAMP"));
57 Words.Add(string("CLEAR"));
58 Words.Add(string("CLEFT"));
59 Words.Add(string("CLOSE"));
60 Words.Add(string("CODER"));
61 Words.Add(string("COULD"));
62 Words.Add(string("CRASH"));
63 Words.Add(string("DAIRY"));
64 Words.Add(string("DIRTY"));
65 Words.Add(string("DOZEN"));
66 Words.Add(string("DRINK"));
67 Words.Add(string("ENJOY"));
68 Words.Add(string("FAITH"));
69 Words.Add(string("FIELD"));
70 Words.Add(string("FINAL"));
71 Words.Add(string("FLASH"));
72 Words.Add(string("FLASK"));
73 Words.Add(string("FLING"));
74 Words.Add(string("FLIRT"));
75 Words.Add(string("FRESH"));
76 Words.Add(string("FUDGE"));
77 Words.Add(string("GIANT"));
78 Words.Add(string("GLINT"));
79 Words.Add(string("GLITZ"));
80 Words.Add(string("GRAPH"));
81 Words.Add(string("GROWL"));
82 Words.Add(string("GUARD"));
83 Words.Add(string("GUIDE"));
84 Words.Add(string("HEART"));
85 Words.Add(string("HEAVY"));
86 Words.Add(string("HORSE"));
87 Words.Add(string("JUICY"));
88 Words.Add(string("LEAST"));
89 Words.Add(string("LEMON"));
90 Words.Add(string("MAGIC"));
91 Words.Add(string("MEANS"));
92 Words.Add(string("MICRO"));
93 Words.Add(string("MISTY"));
94 Words.Add(string("MODEL"));
95 Words.Add(string("MOUTH"));
96 Words.Add(string("MOVIE"));
97 Words.Add(string("OTHER"));
98 Words.Add(string("PAIRS"));
99 Words.Add(string("PARKS"));
100 Words.Add(string("PARTY"));
101 Words.Add(string("PHASE"));
102 Words.Add(string("PHONE"));
103 Words.Add(string("PLACE"));
104 Words.Add(string("PLANK"));
105 Words.Add(string("PLANT"));
106 Words.Add(string("POWER"));
107 Words.Add(string("PRICE"));
108 Words.Add(string("PRINT"));
109 Words.Add(string("QUICK"));
110 Words.Add(string("QUIET"));
111 Words.Add(string("RATED"));
112 Words.Add(string("RIGHT"));
113 Words.Add(string("RIVAL"));
114 Words.Add(string("ROYAL"));
115 Words.Add(string("RUSTY"));
116 Words.Add(string("SCALE"));
117 Words.Add(string("SCORE"));
118 Words.Add(string("SHAKE"));
119 Words.Add(string("SHAVE"));
120 Words.Add(string("SNORE"));
121 Words.Add(string("SPARK"));
122 Words.Add(string("SPEAR"));
123 Words.Add(string("SPEND"));
124 Words.Add(string("STAND"));
125 Words.Add(string("STALK"));
126 Words.Add(string("STORE"));
127 Words.Add(string("SUGAR"));
128 Words.Add(string("SWAMP"));
129 Words.Add(string("SWIFT"));
130 Words.Add(string("SWING"));
131 Words.Add(string("THING"));
132 Words.Add(string("TRAMP"));
133 Words.Add(string("UNDER"));
134 Words.Add(string("WATER"));
135 Words.Add(string("WHARF"));
136 Words.Add(string("WHILE"));
137 Words.Add(string("WHITE"));
138 Words.Add(string("WHOLE"));
139 Words.Add(string("WRITE"));
140
141 Numbers.Add(string("0"));
142 Numbers.Add(string("1"));
143 Numbers.Add(string("2"));
144 Numbers.Add(string("3"));
145 Numbers.Add(string("4"));
146 Numbers.Add(string("5"));
147 Numbers.Add(string("6"));
148 Numbers.Add(string("7"));
149 Numbers.Add(string("8"));
150 Numbers.Add(string("9"));
151
152 Letters.Add(string("A"));
153 Letters.Add(string("B"));
154 Letters.Add(string("C"));
155 Letters.Add(string("D"));
156 Letters.Add(string("E"));
157 Letters.Add(string("F"));
158 Letters.Add(string("G"));
159 Letters.Add(string("H"));
160 Letters.Add(string("J"));
161 Letters.Add(string("K"));
162 Letters.Add(string("L"));
163 Letters.Add(string("M"));
164 Letters.Add(string("N"));
165 Letters.Add(string("P"));
166 Letters.Add(string("Q"));
167 Letters.Add(string("R"));
168 Letters.Add(string("S"));
169 Letters.Add(string("T"));
170 Letters.Add(string("U"));
171 Letters.Add(string("V"));
172 Letters.Add(string("W"));
173 Letters.Add(string("X"));
174 Letters.Add(string("Y"));
175 Letters.Add(string("Z"));
176
177 Positions.Add(0);
178 Positions.Add(1);
179 Positions.Add(2);
180 Positions.Add(3);
181 Positions.Add(4);
182
183 for (int i = 0; i < 4; ++i) {
184 BPMiniGame_Scrambled_Answer* answer = new BPMiniGame_Scrambled_Answer();
185 Answers.Add(answer);
186 }
187
188 BPPoint point = BPPoint(29, 164);
189 AnswerPositions.Add(point);
190
191 point = BPPoint(29, 222);
192 AnswerPositions.Add(point);
193
194 point = BPPoint(29, 280);
195 AnswerPositions.Add(point);
196
197 point = BPPoint(29, 337);
198 AnswerPositions.Add(point);
199
200 LevelUp();
201 }
202
~BPMiniGame_Scrambled()203 BPMiniGame_Scrambled::~BPMiniGame_Scrambled() {
204 SAFE_DELETE(sfcBackground);
205 Answers.Clear();
206 }
207
Start()208 void BPMiniGame_Scrambled::Start() {
209 TimeStarted = TheGame->TickCount;
210 }
211
GetWeight()212 int BPMiniGame_Scrambled::GetWeight() {
213 float TimePassed = (TheGame->TickCount - TimeStarted) / 1000.0f;
214 return MinMax((Score * 75) - round(TimePassed * 4));
215 }
216
Render()217 void BPMiniGame_Scrambled::Render() {
218 TheGame->DrawImage(sfcBackground, 0, 0);
219
220 TheGame->DrawString(TheQuestion, BLACK, 29, 29);
221
222 for (int i = 0; i < Answers.Count; ++i) {
223 BPMiniGame_Scrambled_Answer* answer = Answers[i];
224 TheGame->DrawString(answer->Text, BLACK, answer->Pos.X, answer->Pos.Y + AnswersYOffset);
225 }
226
227 if (GameState == CORRECT) {
228 RenderCorrect();
229 } else if (GameState == WRONG) {
230 RenderWrong();
231 }
232 }
233
FlipLetters(string Word)234 string BPMiniGame_Scrambled::FlipLetters(string Word) {
235 string retval = Word;
236 reverse(retval.begin(), retval.end());
237 return retval;
238 }
239
RemoveLetters(string Word,int Pos)240 string BPMiniGame_Scrambled::RemoveLetters(string Word, int Pos) {
241 string retval = Word;
242
243 retval = retval.erase(Pos, 1);
244 return retval;
245 }
246
SwitchLetters(string Word,int Pos)247 string BPMiniGame_Scrambled::SwitchLetters(string Word, int Pos) {
248 string retval = Word;
249 const char letter = retval[Pos];
250
251 if (Pos == retval.size() - 1) {
252 // this was the last letter; insert it at the front
253 retval[4] = retval[0];
254 retval[0] = letter;
255 } else {
256 retval[Pos] = retval[Pos + 1];
257 retval[Pos + 1] = letter;
258 }
259
260 return retval;
261 }
262
AddLetters(string Word,string Letter,int Pos)263 string BPMiniGame_Scrambled::AddLetters(string Word, string Letter, int Pos) {
264 string retval = Word;
265 retval.insert(Pos, Letter);
266
267 return retval;
268 }
269
GetUniqueNumber(string Word1,string Word2)270 string BPMiniGame_Scrambled::GetUniqueNumber(string Word1, string Word2) {
271 for (int i = 0; i < Numbers.Count; ++i) {
272 string Number = Numbers[i];
273 if (Word1.find(Number) == string::npos && Word2.find(Number) == string::npos) return Number;
274 }
275
276 return "D"; // no unique numbers are around; send back a letter
277 }
278
GetUniqueLetter(string Word1,string Word2)279 string BPMiniGame_Scrambled::GetUniqueLetter(string Word1, string Word2) {
280 while (true) {
281 string Letter = Letters[TheGame->RandomRange(0, Letters.Count - 1)];
282 if (Word1.find(Letter) == string::npos && Word2.find(Letter) == string::npos) return Letter;
283 }
284 }
285
Tick()286 void BPMiniGame_Scrambled::Tick() {
287 if (LastStateChange != -1 && LastStateChange + 500 < TheGame->TickCount) {
288 LevelUp();
289 }
290 }
291
OnMouseDown()292 void BPMiniGame_Scrambled::OnMouseDown() {
293
294 }
295
OnMouseMove()296 void BPMiniGame_Scrambled::OnMouseMove() {
297
298 }
299
OnMouseUp()300 void BPMiniGame_Scrambled::OnMouseUp() {
301 switch (GameState) {
302 case CORRECT:
303 LevelUp();
304 break;
305
306 case WRONG:
307 LevelUp();
308 break;
309
310 case WAITING:
311 for (int i = 0; i < Answers.Count; ++i) {
312 BPMiniGame_Scrambled_Answer* answer = Answers[i];
313 if (TheGame->PointOverRect(TouchEvent.X, TouchEvent.Y, answer->Pos.X, answer->Pos.Y, 264.0f, 47.0f)) {
314 if (answer->Correct) {
315 ++Score;
316 GameState = CORRECT;
317 LastStateChange = TheGame->TickCount;
318 TheGame->PlaySound("correct");
319 } else {
320 --Score;
321 GameState = WRONG;
322 LastStateChange = TheGame->TickCount;
323 TheGame->PlaySound("wrong");
324 }
325
326 return;
327 }
328 }
329
330 break;
331 }
332 }
333
LevelUp()334 void BPMiniGame_Scrambled::LevelUp() {
335 LastStateChange = -1;
336 GameState = WAITING;
337
338 if (!MarathonMode && CurrentLevel >= 10) {
339 Success();
340 return;
341 }
342
343 ++CurrentLevel;
344
345 Numbers.Shuffle();
346 Words.Shuffle();
347 Positions.Shuffle();
348 Answers.Shuffle();
349
350 bool NumbersOnly = false;
351
352 switch (TheGame->RandomRange(0, 3)) {
353 case 0:
354 case 1:
355 // word to number comparison
356 ExampleWord = Words[0];
357 TestWord.clear();
358
359 TestWord.append(Numbers[0]);
360 TestWord.append(Numbers[1]);
361 TestWord.append(Numbers[2]);
362 TestWord.append(Numbers[3]);
363 TestWord.append(Numbers[4]);
364 break;
365
366 case 2:
367 // word to word comparison
368 ExampleWord = Words[0];
369 TestWord = Words[1];
370 break;
371
372 case 3:
373 // number to number comparison
374 NumbersOnly = true; // so we add a number in AddLetters() rather than adding a letter
375
376 ExampleWord.clear();
377
378 ExampleWord.append(Numbers[0]);
379 ExampleWord.append(Numbers[1]);
380 ExampleWord.append(Numbers[2]);
381 ExampleWord.append(Numbers[3]);
382 ExampleWord.append(Numbers[4]);
383
384 Numbers.Shuffle();
385
386 TestWord.clear();
387
388 TestWord.append(Numbers[0]);
389 TestWord.append(Numbers[1]);
390 TestWord.append(Numbers[2]);
391 TestWord.append(Numbers[3]);
392 TestWord.append(Numbers[4]);
393
394 break;
395 }
396
397 switch (TheGame->RandomRange(0, 3)) {
398 case 0:
399 {
400 string LetterToAdd;
401
402 if (NumbersOnly) {
403 LetterToAdd = GetUniqueNumber(ExampleWord, TestWord);
404 } else {
405 LetterToAdd = GetUniqueLetter(ExampleWord, TestWord);
406 }
407
408 ExampleWordAnswer = AddLetters(ExampleWord, LetterToAdd, Positions[0]);
409 Answer1 = AddLetters(TestWord, LetterToAdd, Positions[0]);
410 Answer2 = AddLetters(TestWord, LetterToAdd, Positions[1]);
411 Answer3 = AddLetters(TestWord, LetterToAdd, Positions[2]);
412 Answer4 = AddLetters(TestWord, LetterToAdd, Positions[3]);
413
414 break;
415 }
416
417 case 1:
418 ExampleWordAnswer = FlipLetters(ExampleWord);
419 Answer1 = FlipLetters(TestWord);
420
421 // we're going to be cruel, and flip these words then switch a letter so they look vaguely right at first glance
422 Answer2 = FlipLetters(SwitchLetters(TestWord, Positions[0]));
423 Answer3 = FlipLetters(SwitchLetters(TestWord, Positions[1]));
424 Answer4 = FlipLetters(SwitchLetters(TestWord, Positions[2]));
425 break;
426
427 case 2:
428 ExampleWordAnswer = RemoveLetters(ExampleWord, Positions[0]);
429 Answer1 = RemoveLetters(TestWord, Positions[0]);
430 Answer2 = RemoveLetters(TestWord, Positions[1]);
431 Answer3 = RemoveLetters(TestWord, Positions[2]);
432 Answer4 = RemoveLetters(TestWord, Positions[3]);
433 break;
434
435 case 3:
436 ExampleWordAnswer = SwitchLetters(ExampleWord, Positions[0]);
437 Answer1 = SwitchLetters(TestWord, Positions[0]);
438
439 // to make this a bit harder, we're going to switch two letters in the others
440 Answer2 = SwitchLetters(TestWord, Positions[0]);
441 Answer2 = SwitchLetters(Answer2, Positions[1]);
442
443 Answer3 = SwitchLetters(TestWord, Positions[0]);
444 Answer3 = SwitchLetters(Answer3, Positions[2]);
445
446 Answer4 = SwitchLetters(TestWord, Positions[0]);
447 Answer4 = SwitchLetters(Answer4, Positions[3]);
448 break;
449 }
450
451 Answers[0]->Correct = true;
452 Answers[1]->Correct = false;
453 Answers[2]->Correct = false;
454 Answers[3]->Correct = false;
455
456 TheGame->AllocString(&Answers[0]->Text, Answer1.c_str(), NORMAL, 264.0f, 47.0f, CENTRED);
457 TheGame->AllocString(&Answers[1]->Text, Answer2.c_str(), NORMAL, 264.0f, 47.0f, CENTRED);
458 TheGame->AllocString(&Answers[2]->Text, Answer3.c_str(), NORMAL, 264.0f, 47.0f, CENTRED);
459 TheGame->AllocString(&Answers[3]->Text, Answer4.c_str(), NORMAL, 264.0f, 47.0f, CENTRED);
460
461 Answers.Shuffle();
462
463 Answers[0]->Pos = AnswerPositions[0];
464 Answers[1]->Pos = AnswerPositions[1];
465 Answers[2]->Pos = AnswerPositions[2];
466 Answers[3]->Pos = AnswerPositions[3];
467
468 ostringstream question;
469 question << "If " << ExampleWord.c_str() << " is " << ExampleWordAnswer.c_str() << " then " << TestWord.c_str() << " is...";
470 TheGame->AllocString(&TheQuestion, question.str().c_str(), LARGE, 264.0f, 135.0f, CENTRED);
471 }
472
SetMarathon()473 void BPMiniGame_Scrambled::SetMarathon() {
474 MarathonMode = true;
475 GameHelp = "I'm going to scramble words and numbers by adding, removing and switching letters. Can you figure out what's changed?";
476 }
477