1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "hopkins/computer.h"
24 
25 #include "hopkins/font.h"
26 #include "hopkins/files.h"
27 #include "hopkins/globals.h"
28 #include "hopkins/graphics.h"
29 #include "hopkins/hopkins.h"
30 #include "hopkins/objects.h"
31 
32 #include "common/system.h"
33 #include "common/file.h"
34 #include "common/textconsole.h"
35 
36 namespace Hopkins {
37 
ComputerManager(HopkinsEngine * vm)38 ComputerManager::ComputerManager(HopkinsEngine *vm) {
39 	_vm = vm;
40 
41 	for (int i = 0; i < ARRAYSIZE(_menuText); i++) {
42 		_menuText[i]._lineSize = 0;
43 		memset(_menuText[i]._line, 0, ARRAYSIZE(_menuText[0]._line));
44 	}
45 	Common::fill(&_inputBuf[0], &_inputBuf[200], '\0');
46 	_breakoutSpr = NULL;
47 	_textColor = 0;
48 	_breakoutLevel = (int16 *)NULL;
49 	_breakoutBrickNbr = 0;
50 	_breakoutScore = 0;
51 	_breakoutLives = 0;
52 	_breakoutSpeed = 0;
53 	_ballRightFl = false;
54 	_ballUpFl = false;
55 	_breakoutLevelNbr = 0;
56 	_padPositionX = 0;
57 	_minBreakoutMoveSpeed = 0;
58 	_maxBreakoutMoveSpeed = 0;
59 	_lastBreakoutMoveSpeed = 0;
60 	_lowestHiScore = 0;
61 }
62 
63 /**
64  * Sets up textual entry mode. Used by the code for Hopkins computer.
65  */
setVideoMode()66 void ComputerManager::setVideoMode() {
67 	setTextMode();
68 }
69 
70 /**
71  * Sets up Textual entry mode
72  */
setTextMode()73 void ComputerManager::setTextMode() {
74 	_vm->_graphicsMan->clearPalette();
75 	_vm->_graphicsMan->clearScreen();
76 
77 	_vm->_graphicsMan->_lineNbr = SCREEN_WIDTH;
78 	_vm->_fontMan->_font = _vm->_globals->freeMemory(_vm->_fontMan->_font);
79 
80 	Common::String filename = "STFONT.SPR";
81 	Common::File f;
82 	if (!f.exists(filename))
83 		filename = "FONTE.SPR"; // Used by the BeOS and OS/2 versions as an alternative
84 	_vm->_fontMan->_font = _vm->_fileIO->loadFile(filename);
85 	_vm->_fontMan->_fontFixedWidth = 8;
86 	_vm->_fontMan->_fontFixedHeight = 8;
87 
88 	_vm->_graphicsMan->loadImage("WINTEXT");
89 	_vm->_graphicsMan->fadeInLong();
90 	loadMenu();
91 	_vm->_events->_mouseFl = false;
92 }
93 
94 /**
95  * Clear the screen
96  */
clearScreen()97 void ComputerManager::clearScreen() {
98 	_vm->_graphicsMan->loadImage("WINTEXT");
99 	_vm->_graphicsMan->fadeInLong();
100 }
101 
102 /**
103  * Sets the text mode color
104  */
setTextColor(int col)105 void ComputerManager::setTextColor(int col) {
106 	_textColor = col;
107 }
108 
109 /**
110  * Sets the text position.
111  * @param yp		Y position
112  * @param xp		X position
113  * @remarks		Yes, the reverse co-ordinate pair is really like that in the original game.
114  */
setTextPosition(int yp,int xp)115 void ComputerManager::setTextPosition(int yp, int xp) {
116 	_textPosition.x = xp << 3;
117 	_textPosition.y = yp << 4;
118 }
119 
120 /**
121  * Show a computer in the FBI office
122  * @param mode		Which computer to display
123  */
showComputer(ComputerEnum mode)124 void ComputerManager::showComputer(ComputerEnum mode) {
125 	_vm->_events->_escKeyFl = false;
126 	_vm->_graphicsMan->resetDirtyRects();
127 	setVideoMode();
128 	setTextColor(4);
129 	setTextPosition(2, 4);
130 	if (mode == COMPUTER_HOPKINS)
131 		outText(Common::String(_menuText[0]._line));
132 	else if (mode == COMPUTER_SAMANTHA)
133 		outText(Common::String(_menuText[1]._line));
134 	else // COMPUTER_PUBLIC
135 		outText(Common::String(_menuText[2]._line));
136 
137 	setTextColor(1);
138 	if (mode == COMPUTER_PUBLIC) {
139 		setTextPosition(10, 8);
140 		outText(Common::String(_menuText[3]._line));
141 	}
142 	setTextPosition(12, 28);
143 	outText(Common::String(_menuText[4]._line));
144 	setTextPosition(14, 35);
145 
146 	displayMessage(280, 224, 8);
147 	bool passwordMatch = false;
148 	if ((mode == COMPUTER_HOPKINS) && !strcmp(_inputBuf, "HOPKINS"))
149 		passwordMatch = true;
150 	else if ((mode == COMPUTER_SAMANTHA) && !strcmp(_inputBuf, "328MHZA"))
151 		passwordMatch = true;
152 	else if ((mode == COMPUTER_PUBLIC) && !strcmp(_inputBuf, "ALLFREE"))
153 		passwordMatch = true;
154 
155 	if (passwordMatch) {
156 		while (!_vm->shouldQuit()) {
157 			_vm->_events->_escKeyFl = false;
158 			clearScreen();
159 			setTextColor(4);
160 			setTextPosition(2, 4);
161 			if (mode == COMPUTER_HOPKINS)
162 				outText(Common::String(_menuText[0]._line));
163 			else if (mode == COMPUTER_SAMANTHA)
164 				outText(Common::String(_menuText[1]._line));
165 			else if (mode == COMPUTER_PUBLIC)
166 				outText(Common::String(_menuText[2]._line));
167 			setTextColor(15);
168 			setTextPosition(8, 25);
169 			setTextColor(15);
170 			outText2(Common::String(_menuText[6]._line));
171 			setTextPosition(20, 25);
172 			outText2(Common::String(_menuText[7]._line));
173 			if (mode == COMPUTER_HOPKINS) {
174 				setTextPosition(10, 25);
175 				outText2(Common::String(_menuText[8]._line));
176 				setTextPosition(12, 25);
177 				outText2(Common::String(_menuText[9]._line));
178 				setTextPosition(14, 25);
179 				outText2(Common::String(_menuText[10]._line));
180 				setTextPosition(16, 25);
181 				outText2(Common::String(_menuText[11]._line));
182 			} else if (mode == COMPUTER_SAMANTHA) {
183 				setTextPosition(10, 25);
184 //				outText2(Common::String(_menuText[0x95A])); <=== CHECKME: Unexpected value! replaced by the following line, for consistancy
185 				outText2(Common::String(_menuText[12]._line));
186 				setTextPosition(12, 25);
187 				outText2(Common::String(_menuText[13]._line));
188 				setTextPosition(14, 25);
189 				outText2(Common::String(_menuText[14]._line));
190 				setTextPosition(16, 25);
191 				outText2(Common::String(_menuText[15]._line));
192 				setTextPosition(18, 25);
193 				outText2(Common::String(_menuText[16]._line));
194 			}
195 
196 			bool numericFlag = false;
197 			char keyPressed;
198 			do {
199 				keyPressed = _vm->_events->waitKeyPress();
200 				if (_vm->shouldQuit())
201 					return;
202 
203 				if ((keyPressed >= '0') && (keyPressed <= '9'))
204 					numericFlag = true;
205 			} while (!numericFlag);
206 
207 			// 0 - Quit
208 			if (keyPressed == '0')
209 				break;
210 			// 1 - Games
211 			if (keyPressed == '1') {
212 				displayGamesSubMenu();
213 			} else if (mode == COMPUTER_HOPKINS) {
214 				clearScreen();
215 				setTextColor(4);
216 				setTextPosition(2, 4);
217 				outText(Common::String(_menuText[0]._line));
218 				setTextColor(15);
219 				switch (keyPressed) {
220 				case '2':
221 					readText(1);
222 					break;
223 				case '3':
224 					readText(2);
225 					break;
226 				case '4':
227 					readText(3);
228 					break;
229 				case '5':
230 					readText(4);
231 					break;
232 				default:
233 					break;
234 				}
235 			} else if (mode == COMPUTER_SAMANTHA) {
236 				clearScreen();
237 				setTextColor(4);
238 				setTextPosition(2, 4);
239 				outText(Common::String(_menuText[1]._line));
240 				setTextColor(15);
241 				switch (keyPressed) {
242 				case '2':
243 					readText(6);
244 					break;
245 				case '3':
246 					readText(7);
247 					break;
248 				case '4':
249 					readText(8);
250 					break;
251 				case '5':
252 					readText(9);
253 					break;
254 				case '6':
255 					readText(10);
256 					_vm->_globals->_saveData->_data[svField270] = 4;
257 					break;
258 				default:
259 					break;
260 				}
261 			}
262 		}
263 		_vm->_graphicsMan->clearScreen();
264 		_vm->_graphicsMan->updateScreen();
265 		restoreFBIRoom();
266 	} else {
267 		// Password doesn't match - Access Denied
268 		setTextColor(4);
269 		setTextPosition(16, 25);
270 		outText(Common::String(_menuText[5]._line));
271 		_vm->_events->refreshScreenAndEvents();
272 		_vm->_events->delay(1000);
273 
274 		memset(_vm->_graphicsMan->_frontBuffer, 0, 307199);
275 		_vm->_graphicsMan->clearScreen();
276 		_vm->_graphicsMan->updateScreen();
277 		restoreFBIRoom();
278 		_vm->_events->mouseOff();
279 	}
280 
281 	if (mode == COMPUTER_HOPKINS)
282 		_vm->_globals->_exitId = 13;
283 	else // Free access or Samantha
284 		_vm->_globals->_exitId = 14;
285 
286 	_vm->_graphicsMan->resetDirtyRects();
287 }
288 
289 static const char _englishText[] =
290 "% ****** FBI COMPUTER NUMBER 4985 ****** J.HOPKINS COMPUTER ******\n"
291 "% ****** FBI COMPUTER NUMBER 4998 ****** S.COLLINS COMPUTER ******\n"
292 "% ****** FBI COMPUTER NUMBER 4997 ****** ACCES FREE COMPUTER ******\n"
293 "% PASSWORD IS: ALLFREE\n% ENTER CURRENT PASSWORD\n"
294 "% ****** ACCES DENIED ******\n"
295 "% 1) *** GAME ***\n"
296 "% 0) QUIT COMPUTER\n"
297 "% 2) STRANGE CADAVER\n"
298 "% 3) STRANGE CADAVER\n"
299 "% 4) SENATOR FERGUSSON\n"
300 "% 5) DOG KILLER\n"
301 "% 2) SCIENTIST KIDNAPPED.\n"
302 "% 3) SCIENTIST KIDNAPPED (next).\n"
303 "% 4) SCIENTIST KIDNAPPED (next).\n"
304 "% 5) SCIENTIST KIDNAPPED (next).\n"
305 "% 6) SCIENTIST KIDNAPPED (next).\n"
306 "%% fin\n";
307 
308 static const char _frenchText[] =
309 "% ****** FBI COMPUTER NUMBER 4985 ****** J.HOPKINS COMPUTER ******\n"
310 "% ****** FBI COMPUTER NUMBER 4998 ****** S.COLLINS COMPUTER ******\n"
311 "% ****** FBI COMPUTER NUMBER 4997 ****** ACCES FREE COMPUTER ******\n"
312 "% PASSWORD IS: ALLFREE\n"
313 "% ENTER CURRENT PASSWORD\n"
314 "% ****** ACCES DENIED ******\n"
315 "% 1) *** CASSE BRIQUE ***\n"
316 "% 0) QUITTER L'ORDINATEUR\n"
317 "% 2) CADAVRE SANS TETE\n"
318 "% 3) CADAVRE SANS TETE\n"
319 "% 4) AGRESSION DU SENATEUR\n"
320 "% 5) LES CHIENS TUEURS\n"
321 "% 2) DISPARITIONS DE CHERCHEURS.\n"
322 "% 3) DISPARITIONS (suite).\n"
323 "% 4) DISPARITIONS (suite).\n"
324 "% 5) DISPARITIONS (suite).\n"
325 "% 6) DISPARITIONS (suite).\n"
326 "%% fin\n";
327 
328 static const char _spanishText[] =
329 "% **** ORDENADOR DEL FBI NUMERO 4985 **** ORDENADOR J.HOPKINS *****\n"
330 "% **** ORDENADOR DEL FBI NUMERO 4998 **** ORDENADOR S.COLLINS *****\n"
331 "% *** ORDENADOR DEL FBI NUMERO 4997 *** ORDENADOR DE ACCESO LIBRE ***\n"
332 "% LA CONTRASE\xA5" "A ES: ALLFREE\n"
333 "% ESCRIBE CONTRASE\xA5" "A ACTUAL\n"
334 "% **** ACCESO DENEGADO ****\n"
335 "% 1) *** JUEGO ***\n"
336 "% 0) SALIR DEL ORDENADOR\n"
337 "% 2) CADAVER EXTRA\xA5" "O\n"
338 "% 3) CADAVER EXTRA\xA5" "O\n"
339 "% 4) SENADOR FERGUSSON\n"
340 "% 5) MATAPERROS\n"
341 "% 2) CIENTIFICO SECUESTRADO.\n"
342 "% 3) CIENTIFICO SECUESTRADO (siguiente).\n"
343 "% 4) CIENTIFICO SECUESTRADO (siguiente).\n"
344 "% 5) CIENTIFICO SECUESTRADO (siguiente).\n"
345 "% 6) CIENTIFICO SECUESTRADO (siguiente).\n"
346 "%% fin\n";
347 
348 /**
349  * Load Menu data
350  */
loadMenu()351 void ComputerManager::loadMenu() {
352 	debug(9, "ComputerManager::loadMenu()");
353 	char *ptr;
354 	if (_vm->_fileIO->fileExists("COMPUTAN.TXT")) {
355 		ptr = (char *)_vm->_fileIO->loadFile("COMPUTAN.TXT");
356 	} else {
357 		switch (_vm->_globals->_language) {
358 		case LANG_FR:
359 			ptr = (char *)_vm->_globals->allocMemory(sizeof(_frenchText));
360 			Common::strlcpy(ptr, _frenchText, sizeof(_frenchText));
361 			break;
362 		case LANG_SP:
363 			ptr = (char *)_vm->_globals->allocMemory(sizeof(_spanishText));
364 			Common::strlcpy(ptr, _spanishText, sizeof(_spanishText));
365 			break;
366 		default:
367 			ptr = (char *)_vm->_globals->allocMemory(sizeof(_englishText));
368 			Common::strlcpy(ptr, _englishText, sizeof(_englishText));
369 			break;
370 		}
371 	}
372 
373 	char *tmpPtr = ptr;
374 	int lineNum = 0;
375 
376 	const char lineSep = tmpPtr[0];
377 
378 	while (tmpPtr[0] != '\0' && lineNum < ARRAYSIZE(_menuText)) {
379 		if (tmpPtr[0] == '%' && tmpPtr[1] == '%') {
380 			// End of file marker found - Break out of parse loop
381 			break;
382 		}
383 
384 		if (tmpPtr[0] == lineSep) {
385 			int strPos = 0;
386 			while (strPos < ARRAYSIZE(_menuText[0]._line)) {
387 				char curChar = tmpPtr[strPos + 2];
388 				if (curChar == '\0' || curChar == lineSep || curChar == 0x0a) // Line Feed
389 					break;
390 				_menuText[lineNum]._line[strPos++] = curChar;
391 			}
392 
393 			if (strPos < ARRAYSIZE(_menuText[0]._line)) {
394 				_menuText[lineNum]._line[strPos] = 0;
395 				_menuText[lineNum]._lineSize = strPos - 1;
396 			}
397 
398 			if (strPos != 0) {
399 				debug(9, "_menuText[%d]._line (size: %d): \"%s\"", lineNum, _menuText[lineNum]._lineSize, _menuText[lineNum]._line);
400 				++lineNum;
401 			}
402 		}
403 		++tmpPtr;
404 	}
405 
406 	_vm->_globals->freeMemory((byte *)ptr);
407 }
408 
displayMessage(int xp,int yp,int textIdx)409 void ComputerManager::displayMessage(int xp, int yp, int textIdx) {
410 	char curChar;
411 
412 	int x1 = xp;
413 	int x2 = 0;
414 
415 	int textIndex = 0;
416 	bool oldMouseFlag = _vm->_events->_mouseFl;
417 	_vm->_events->_mouseFl = false;
418 
419 	_vm->_fontMan->displayTextVesa(xp, yp, "_", 252);
420 	do {
421 		curChar = _vm->_events->waitKeyPress();
422 		if (_vm->shouldQuit())
423 			return;
424 
425 		char mappedChar = '*';
426 
427 		if ((curChar == '-') || ((curChar >= '0') && (curChar <= '9')) || ((curChar >= 'A') && (curChar <= 'Z')))
428 			mappedChar = curChar;
429 		else if ((curChar >= 'a') && (curChar <= 'z'))
430 			mappedChar = curChar - 32;
431 
432 		// BackSpace
433 		if (curChar == 8 && textIndex > 0) {
434 			_inputBuf[textIndex--] = 0;
435 			x1 -= _vm->_fontMan->_fontFixedWidth;
436 			x2 = x1 + 2 * _vm->_fontMan->_fontFixedWidth;
437 			_vm->_graphicsMan->copyRect(_vm->_graphicsMan->_backBuffer, x1, yp, 3 * _vm->_fontMan->_fontFixedWidth, 12, _vm->_graphicsMan->_frontBuffer, x1, yp);
438 			_vm->_graphicsMan->addDirtyRect(x1, yp, x2, yp + 12);
439 			_vm->_fontMan->displayTextVesa(x1, yp, "_", 252);
440 		}
441 		if (mappedChar != '*') {
442 			char newChar = mappedChar;
443 			_vm->_graphicsMan->copyRect(_vm->_graphicsMan->_backBuffer, x1, yp, _vm->_fontMan->_fontFixedWidth, 12, _vm->_graphicsMan->_frontBuffer, x1, yp);
444 			_vm->_graphicsMan->addDirtyRect(x1, yp, _vm->_fontMan->_fontFixedWidth + x1, yp + 12);
445 			_inputBuf[textIndex] = newChar;
446 
447 			Common::String charString = Common::String::format("%c_", newChar);
448 			_vm->_fontMan->displayTextVesa(x1, yp, charString, 252);
449 			++textIndex;
450 			x1 += _vm->_fontMan->_fontFixedWidth;
451 		}
452 		_vm->_events->refreshScreenAndEvents();
453 	} while (textIndex != textIdx && curChar != 13);
454 
455 	_vm->_graphicsMan->copyRect(_vm->_graphicsMan->_backBuffer, x1, yp, _vm->_fontMan->_fontFixedWidth, 12, _vm->_graphicsMan->_frontBuffer, x1, yp);
456 	_vm->_graphicsMan->addDirtyRect(x1, yp, _vm->_fontMan->_fontFixedWidth + x1, yp + 12);
457 
458 	_vm->_events->refreshScreenAndEvents();
459 	_inputBuf[textIndex] = 0;
460 	_vm->_events->_mouseFl = oldMouseFlag;
461 }
462 
463 /**
464  * Outputs a text string
465  */
outText(const Common::String & msg)466 void ComputerManager::outText(const Common::String &msg) {
467 	_vm->_fontMan->renderTextDisplay(_textPosition.x, _textPosition.y, msg, _textColor);
468 }
469 
470 /**
471  * Outputs a text string
472  */
outText2(const Common::String & msg)473 void ComputerManager::outText2(const Common::String &msg) {
474 	_vm->_fontMan->displayTextVesa(_textPosition.x, _textPosition.y, msg, _textColor);
475 }
476 
477 /**
478  * Restores the scene for the FBI headquarters room
479  */
restoreFBIRoom()480 void ComputerManager::restoreFBIRoom() {
481 	_vm->_graphicsMan->fadeOutShort();
482 
483 	_vm->_globals->freeMemory(_vm->_fontMan->_font);
484 	_vm->_fontMan->_font = _vm->_fileIO->loadFile("FONTE3.SPR");
485 	_vm->_fontMan->_fontFixedWidth = 12;
486 	_vm->_fontMan->_fontFixedHeight = 21;
487 
488 	_vm->_events->_mouseFl = true;
489 }
490 
491 /**
492  * Display texts for the given menu entry
493  */
readText(int idx)494 void ComputerManager::readText(int idx) {
495 	_vm->_events->_escKeyFl = false;
496 
497 	Common::String filename;
498 	switch (_vm->_globals->_language) {
499 	case LANG_EN:
500 		filename = "THOPKAN.TXT";
501 		break;
502 	case LANG_FR:
503 		filename = "THOPK.TXT";
504 		break;
505 	case LANG_SP:
506 		filename = "THOPKES.TXT";
507 		break;
508 	default:
509 		break;
510 	}
511 
512 	byte *ptr = _vm->_fileIO->loadFile(filename);
513 	uint16 fileSize = _vm->_fileIO->fileSize(filename);
514 	int pos;
515 	for (pos = 0; pos < fileSize; pos++) {
516 		if (ptr[pos] == '%') {
517 			Common::String numStr = Common::String::format("%c%c", ptr[pos + 1], ptr[pos + 2]);
518 			if (idx == atol(numStr.c_str()))
519 				break;
520 		}
521 	}
522 	if (pos > fileSize - 3)
523 		error("Error with Hopkins computer file");
524 
525 	pos += 3;
526 	int lineNum = 5;
527 	Common::String curStr = "";
528 	byte curChar;
529 	do {
530 		curChar = ptr[pos];
531 		if (curChar == 13) {
532 			setTextPosition(lineNum, 1);
533 			outText(curStr);
534 
535 			++lineNum;
536 			_vm->_events->refreshScreenAndEvents();
537 			curStr = "";
538 		} else if (curChar != '%') {
539 			curStr += curChar;
540 		}
541 		++pos;
542 		assert(pos <= fileSize);
543 	} while (curChar != '%');
544 
545 	_vm->_events->waitKeyPress();
546 	ptr = _vm->_globals->freeMemory(ptr);
547 }
548 
549 /**
550  * Display breakout when Games sub-menu is selected
551  */
displayGamesSubMenu()552 void ComputerManager::displayGamesSubMenu() {
553 	const byte *oldSpriteData = _vm->_objectsMan->_sprite[0]._spriteData;
554 	uint oldSpeed = _vm->_globals->_speed;
555 
556 	_vm->_globals->_speed = 1;
557 	_vm->_events->changeMouseCursor(0);
558 	_breakoutSpr = NULL;
559 	_vm->_events->_breakoutFl = true;
560 	_breakoutLevel = (int16 *)NULL;
561 	_breakoutBrickNbr = 0;
562 	_breakoutScore = 0;
563 	_breakoutLives = 5;
564 	_breakoutSpeed = 1;
565 	_ballRightFl = false;
566 	_ballUpFl = false;
567 	_breakoutLevelNbr = 0;
568 	_vm->_graphicsMan->_minY = 0;
569 	_vm->_graphicsMan->_maxX = 320;
570 	_vm->_graphicsMan->_maxY = 200;
571 	_vm->_soundMan->loadSample(1, "SOUND37.WAV");
572 	_vm->_soundMan->loadSample(2, "SOUND38.WAV");
573 	_vm->_soundMan->loadSample(3, "SOUND39.WAV");
574 	_breakoutSpr = _vm->_fileIO->loadFile("CASSE.SPR");
575 	loadHiscore();
576 	setModeVGA256();
577 
578 	newLevel();
579 	_vm->_graphicsMan->updateScreen();
580 
581 	playBreakout();
582 	_vm->_graphicsMan->resetDirtyRects();
583 	_breakoutSpr = _vm->_globals->freeMemory(_breakoutSpr);
584 	_breakoutLevel = (int16 *)_vm->_globals->freeMemory((byte *)_breakoutLevel);
585 	_vm->_objectsMan->_sprite[0]._spriteData = oldSpriteData;
586 
587 	_vm->_soundMan->removeSample(1);
588 	_vm->_soundMan->removeSample(2);
589 	_vm->_soundMan->removeSample(3);
590 	_vm->_globals->_speed = oldSpeed;
591 	_vm->_events->_breakoutFl = false;
592 	setVideoMode();
593 	setTextColor(15);
594 	clearScreen();
595 	_vm->_graphicsMan->_maxX = 680;
596 	_vm->_graphicsMan->_minY = 0;
597 	_vm->_graphicsMan->_maxY = 460;
598 }
599 
600 /**
601  * Load Highscore from file
602  */
loadHiscore()603 void ComputerManager::loadHiscore() {
604 	byte *ptr = _vm->_globals->allocMemory(100);
605 	memset(ptr, 0, 100);
606 
607 	if (_vm->_saveLoad->saveExists(_vm->getTargetName() + "-highscore.dat"))
608 		_vm->_saveLoad->load(_vm->getTargetName() + "-highscore.dat", ptr);
609 
610 	for (int scoreIndex = 0; scoreIndex < 6; ++scoreIndex) {
611 		_score[scoreIndex]._name = "      ";
612 		_score[scoreIndex]._score = "         ";
613 
614 		for (int i = 0; i < 6; ++i) {
615 			char nextChar = ptr[(16 * scoreIndex) + i];
616 			if (!nextChar)
617 				nextChar = ' ';
618 			_score[scoreIndex]._name.setChar(nextChar, i);
619 		}
620 
621 		for (int i = 0; i < 9; ++i) {
622 			char nextChar = ptr[(scoreIndex * 16) + 6 + i];
623 			if (!nextChar)
624 				nextChar = '0';
625 			_score[scoreIndex]._score.setChar(nextChar, i);
626 		}
627 	}
628 
629 	_lowestHiScore = atol(_score[5]._score.c_str());
630 	_vm->_globals->freeMemory(ptr);
631 }
632 
633 /**
634  * VGA 256 col
635  */
setModeVGA256()636 void ComputerManager::setModeVGA256() {
637 	_vm->_graphicsMan->clearScreen();
638 	_vm->_graphicsMan->clearPalette();
639 	_vm->_graphicsMan->setScreenWidth(320);
640 }
641 
642 /**
643  * Load new level
644  */
newLevel()645 void ComputerManager::newLevel() {
646 	_vm->_objectsMan->removeSprite(0);
647 	_vm->_objectsMan->removeSprite(1);
648 	++_breakoutLives;
649 	if (_breakoutLives > 11)
650 		_breakoutLives = 11;
651 	_vm->_graphicsMan->loadVgaImage("CASSEF.PCX");
652 	displayLives();
653 	_breakoutLevel = (int16 *)_vm->_globals->freeMemory((byte *)_breakoutLevel);
654 
655 	++_breakoutLevelNbr;
656 	Common::String file;
657 	Common::File f;
658 	while (!_vm->shouldQuit()) {
659 		file = Common::String::format("TAB%d.TAB", _breakoutLevelNbr);
660 		if (f.open(file))
661 			break;
662 
663 		_breakoutLevelNbr = 1;
664 	}
665 	f.close();
666 
667 	_breakoutLevel = (int16 *)_vm->_fileIO->loadFile(file);
668 	displayBricks();
669 
670 	_vm->_objectsMan->addStaticSprite(_breakoutSpr, Common::Point(150, 192), 0, 13, 0, false, 0, 0);
671 	_vm->_objectsMan->addStaticSprite(_breakoutSpr, Common::Point(164, 187), 1, 14, 0, false, 0, 0);
672 
673 	_ballPosition = Common::Point(164, 187);
674 	_padPositionX = 150;
675 	_vm->_objectsMan->animateSprite(0);
676 	_vm->_objectsMan->animateSprite(1);
677 
678 	_vm->_events->mouseOn();
679 	_vm->_soundMan->playSample(3, 5);
680 }
681 
682 /**
683  * Display bricks in breakout game
684  */
displayBricks()685 void ComputerManager::displayBricks() {
686 	_breakoutBrickNbr = 0;
687 	_breakoutSpeed = 1;
688 	int16 *level = _breakoutLevel;
689 
690 	for (int levelIdx = 0; ; levelIdx += 6) {
691 		int cellLeft = (int16)FROM_LE_16(level[levelIdx]);
692 		if (cellLeft == -1)
693 			break;
694 		int cellTop = FROM_LE_16(level[levelIdx + 1]);
695 		int cellType = FROM_LE_16(level[levelIdx + 4]);
696 
697 		if (cellType <= 6)
698 			++_breakoutBrickNbr;
699 
700 		switch (cellType) {
701 		case 1:
702 			_vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 21);
703 			break;
704 		case 2:
705 			_vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 22);
706 			break;
707 		case 3:
708 			_vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 17);
709 			break;
710 		case 4:
711 			_vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 20);
712 			break;
713 		case 5:
714 			_vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 19);
715 			break;
716 		case 6:
717 			_vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 18);
718 			break;
719 		case 31:
720 			_vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 23);
721 			break;
722 		default:
723 			break;
724 		}
725 	}
726 
727 	displayScore();
728 
729 	// Refresh the entire screen
730 	_vm->_graphicsMan->addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
731 	_vm->_graphicsMan->updateScreen();
732 }
733 
734 /**
735  * Display Lives in breakout game
736  */
displayLives()737 void ComputerManager::displayLives() {
738 	for (int i = 0, xp = 10; i <= 11; i++, xp += 7)
739 		_vm->_graphicsMan->fastDisplay2(_breakoutSpr, xp, 10, 15);
740 
741 	for (int i = 0, xp = 10; i < _breakoutLives - 1; i++, xp += 7)
742 		_vm->_graphicsMan->fastDisplay2(_breakoutSpr, xp, 10, 14);
743 
744 	_vm->_graphicsMan->updateScreen();
745 }
746 
747 /**
748  * Main function for breakout game
749  */
playBreakout()750 void ComputerManager::playBreakout() {
751 	int lastBreakoutEvent = 0;
752 	while (!_vm->shouldQuit()) {
753 		while (!_vm->shouldQuit()) {
754 			// Set up the racket and ball
755 			_vm->_events->mouseOff();
756 			_ballPosition = Common::Point(_padPositionX + 14, 187);
757 			_vm->_objectsMan->setSpriteY(1, 187);
758 			_vm->_objectsMan->setSpriteX(1, _ballPosition.x);
759 
760 			_vm->_graphicsMan->resetDirtyRects();
761 			_vm->_events->refreshScreenAndEvents();
762 			_vm->_graphicsMan->fadeInBreakout();
763 
764 			// Wait for mouse press to start playing
765 			do {
766 				_padPositionX = _vm->_events->getMouseX();
767 				if (_vm->_events->_mousePos.x <= 4)
768 					_padPositionX = 5;
769 				if (_padPositionX > 282)
770 					_padPositionX = 282;
771 				_vm->_objectsMan->setSpriteX(0, _padPositionX);
772 				_vm->_objectsMan->setSpriteX(1, _padPositionX + 14);
773 				_vm->_objectsMan->setSpriteY(1, 187);
774 				_vm->_events->refreshScreenAndEvents();
775 			} while (!_vm->shouldQuit() && _vm->_events->getMouseButton() != 1);
776 
777 			_breakoutSpeed = 1;
778 			_ballPosition = Common::Point(_padPositionX + 14, 187);
779 			_ballRightFl = (_padPositionX > 135);
780 			_ballUpFl = false;
781 
782 			// Play loop
783 			do {
784 				_vm->_soundMan->checkSounds();
785 
786 				_padPositionX = _vm->_events->getMouseX();
787 				if (_vm->_events->_mousePos.x <= 4)
788 					_padPositionX = 5;
789 				if (_padPositionX > 282)
790 					_padPositionX = 282;
791 				_vm->_objectsMan->setSpriteX(0, _padPositionX);
792 				lastBreakoutEvent = moveBall();
793 				_vm->_events->refreshScreenAndEvents();
794 			} while (!_vm->shouldQuit() && !lastBreakoutEvent);
795 			if (lastBreakoutEvent != 1)
796 				break;
797 
798 			--_breakoutLives;
799 
800 			if (_breakoutLives) {
801 				displayLives();
802 				if (_breakoutLives)
803 					continue;
804 			}
805 
806 			_vm->_graphicsMan->fadeOutBreakout();
807 			_vm->_events->mouseOn();
808 			_vm->_objectsMan->removeSprite(0);
809 			_vm->_objectsMan->removeSprite(1);
810 			if (_breakoutScore > _lowestHiScore)
811 				getScoreName();
812 			if (displayHiscores() != 1)
813 				break;
814 
815 			_breakoutBrickNbr = 0;
816 			_breakoutScore = 0;
817 			_breakoutLives = 4;
818 			_breakoutSpeed = 1;
819 			_ballRightFl = false;
820 			_ballUpFl = false;
821 			_breakoutLevelNbr = 0;
822 			loadHiscore();
823 			newLevel();
824 		}
825 		if (lastBreakoutEvent != 2)
826 			return;
827 		_vm->_graphicsMan->fadeOutBreakout();
828 		newLevel();
829 	}
830 }
831 
832 /**
833  * Show the high scores for the Breakout game
834  * @return		The selected button index: 1 = Game, 2 = Quit
835  */
displayHiscores()836 int ComputerManager::displayHiscores() {
837 	_vm->_graphicsMan->resetDirtyRects();
838 	loadHiscore();
839 	_vm->_graphicsMan->loadVgaImage("HISCORE.PCX");
840 	byte *ptr = _vm->_fileIO->loadFile("ALPHA.SPR");
841 	_vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
842 	_vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
843 	_vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
844 	_vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
845 
846 	int yp;
847 	// Loop for displaying the scores
848 	for (int scoreIndex = 0; scoreIndex <= 5; scoreIndex++) {
849 		yp = 19 * scoreIndex;
850 		yp += 46;
851 
852 		// Display the characters of the name
853 		for (int i = 0; i < 6; i++)
854 			displayHiscoreLine(ptr, 9 * i + 69, yp, _score[scoreIndex]._name[i]);
855 
856 		// Display the digits of the score
857 		for (int i = 0; i < 9; i++)
858 			displayHiscoreLine(ptr, 9 * i + 199, yp, _score[scoreIndex]._score[i]);
859 	}
860 
861 	_vm->_graphicsMan->fadeInBreakout();
862 	_vm->_graphicsMan->resetDirtyRects();
863 	int buttonIndex = 0;
864 	do {
865 		_vm->_events->refreshEvents();
866 		int xp = _vm->_events->getMouseX();
867 		yp = _vm->_events->getMouseY();
868 
869 		if (_vm->_events->getMouseButton() == 1 && ABS(xp - 79) <= 33 && ABS(yp - 396) <= 13)
870 			buttonIndex = 1;
871 		else if (_vm->_events->getMouseButton() == 1 && ABS(xp - 583) <= 32 && ABS(yp - 396) <= 13)
872 			buttonIndex = 2;
873 
874 		_vm->_events->refreshScreenAndEvents();
875 	} while (!buttonIndex && !_vm->shouldQuit());
876 
877 	_vm->_events->mouseOff();
878 	_vm->_graphicsMan->fadeOutBreakout();
879 	_vm->_globals->freeMemory(ptr);
880 	return buttonIndex;
881 }
882 
883 /**
884  * Display a screen to enter player name in the case of a new hiscore
885  */
getScoreName()886 void ComputerManager::getScoreName() {
887 	_vm->_graphicsMan->loadVgaImage("NAME.PCX");
888 	_vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
889 	_vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
890 	_vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
891 	_vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
892 	byte *ptr = _vm->_fileIO->loadFile("ALPHA.SPR");
893 	_vm->_graphicsMan->fadeInBreakout();
894 
895 	// Figure out the line to put the new high score on
896 	int scoreLine = 0;
897 	while (scoreLine < 5 && _breakoutScore < atol(_score[scoreLine]._score.c_str()))
898 		++scoreLine;
899 
900 	// If it's not the lasat line, move the lines down
901 	for (int line = 5; line > scoreLine; --line) {
902 		_score[line]._name = _score[line - 1]._name;
903 		_score[line]._score = _score[line - 1]._score;
904 	}
905 
906 	// Get the name for the new high score
907 	for (int strPos = 0; strPos <= 4; strPos++) {
908 		displayHiscoreLine(ptr, 9 * strPos + 140, 78, 1);
909 
910 		char curChar = toupper(_vm->_events->waitKeyPress());
911 		if ((curChar < '0') || (curChar > 'Z'))
912 			curChar = ' ';
913 		if ((curChar > '9') && (curChar < 'A'))
914 			curChar = ' ';
915 
916 		_score[scoreLine]._name.setChar(curChar, strPos);
917 		displayHiscoreLine(ptr, 9 * strPos + 140, 78, curChar);
918 
919 		for (int idx = 0; idx < 12; ++idx)
920 			_vm->_events->refreshScreenAndEvents();
921 	}
922 
923 	// Set up the new score
924 	_score[scoreLine]._score = "         ";
925 
926 	char score[16];
927 	sprintf(score, "%d", _breakoutScore);
928 	int scoreLen = 0;
929 	do {
930 		++scoreLen;
931 	} while (score[scoreLen]);
932 
933 	for (int i = scoreLen - 1, scorePos = 8; i >= 0; i--) {
934 		_score[scoreLine]._score.setChar(score[i], scorePos--);
935 	}
936 	_vm->_graphicsMan->fadeOutBreakout();
937 	_vm->_globals->freeMemory(ptr);
938 	saveScore();
939 }
940 
941 /**
942  * Display current score
943  */
displayScore()944 void ComputerManager::displayScore() {
945 	Common::String scoreStr = Common::String::format("%d", _breakoutScore);
946 	int strSize = scoreStr.size();
947 	for (int i = strSize - 1, idx = 0; i >= 0; i--) {
948 		displayScoreChar(idx++, scoreStr[i]);
949 	}
950 }
951 
952 /**
953  * Display a character of the score
954  */
displayScoreChar(int charPos,int charDisp)955 void ComputerManager::displayScoreChar(int charPos, int charDisp) {
956 	int xp;
957 	switch (charPos) {
958 	case 1:
959 		xp = 190;
960 		break;
961 	case 2:
962 		xp = 180;
963 		break;
964 	case 3:
965 		xp = 167;
966 		break;
967 	case 4:
968 		xp = 157;
969 		break;
970 	case 5:
971 		xp = 147;
972 		break;
973 	case 9:
974 		xp = 134;
975 		break;
976 	default:
977 		xp = 200;
978 		break;
979 	}
980 
981 	int idx = 3;
982 	if (charDisp >= '0' && charDisp <= '9')
983 		idx = charDisp - 45;
984 
985 	_vm->_graphicsMan->fastDisplay2(_breakoutSpr, xp, 11, idx);
986 }
987 
988 /**
989  * Save Hiscore in file
990  */
saveScore()991 void ComputerManager::saveScore() {
992 	int scores[6];
993 	// Load high scores in an array
994 	for (int i = 0; i <= 5; i++) {
995 		scores[i] = atol(_score[i]._score.c_str());
996 		if (!scores[i])
997 			scores[i] = 5;
998 	}
999 
1000 	int scorePlace[6];
1001 	// order high scores
1002 	for (int scorePlaceIdx = 0; scorePlaceIdx <= 5; scorePlaceIdx++) {
1003 		for(int i = 0;;i++) {
1004 			int curScore = scores[i];
1005 			if (curScore && scores[0] <= curScore && scores[1] <= curScore && scores[2] <= curScore && scores[3] <= curScore
1006 				&& scores[4] <= curScore && scores[5] <= curScore) {
1007 				scorePlace[scorePlaceIdx] = i;
1008 				scores[i] = 0;
1009 				break;
1010 			}
1011 		}
1012 	}
1013 
1014 	byte *ptr = _vm->_globals->allocMemory(100);
1015 	memset(ptr, 0, 100);
1016 	for (int scorePlaceIdx = 0; scorePlaceIdx <= 5; scorePlaceIdx++) {
1017 		int curBufPtr = 16 * scorePlaceIdx;
1018 		for (int namePos = 0; namePos < 6; namePos++) {
1019 			char curChar = _score[scorePlace[scorePlaceIdx]]._name[namePos];
1020 			if (!curChar)
1021 				curChar = ' ';
1022 			ptr[curBufPtr + namePos] = curChar;
1023 		};
1024 
1025 		ptr[curBufPtr + 5] = 0;
1026 
1027 		for (int scorePos = 0; scorePos <= 8; scorePos++) {
1028 			char curChar = _score[scorePlace[scorePlaceIdx]]._score[scorePos];
1029 			if (!curChar)
1030 				curChar = '0';
1031 			ptr[curBufPtr + 6 + scorePos] = curChar;
1032 		};
1033 		ptr[curBufPtr + 15] = 0;
1034 	}
1035 
1036 	_vm->_saveLoad->saveFile(_vm->getTargetName() + "-highscore.dat", ptr, 100);
1037 	_vm->_globals->freeMemory(ptr);
1038 }
1039 
1040 /**
1041  * Display parts of the hiscore line
1042  */
displayHiscoreLine(const byte * objectData,int x,int y,int curChar)1043 void ComputerManager::displayHiscoreLine(const byte *objectData, int x, int y, int curChar) {
1044 	int idx = 36;
1045 
1046 	if (curChar == 100)
1047 		idx = 0;
1048 	else if (curChar >= '0' && curChar <= '9')
1049 		idx = curChar - '0';
1050 	else if (curChar >= 'A' && curChar <= 'Z')
1051 		idx = curChar - 'A' + 10;
1052 	else if (curChar == 1)
1053 		idx = 37;
1054 	_vm->_graphicsMan->fastDisplay2(objectData, x, y, idx);
1055 }
1056 
1057 /**
1058  * Handle ball moves
1059  */
moveBall()1060 int ComputerManager::moveBall() {
1061 	//(signed int)(6.0 * (long double)_vm->getRandomNumber( rand() / 2147483648.0) + 1;
1062 	// TODO: Figure out random number
1063 	int randVal = _vm->getRandomNumber(6);
1064 	switch (_breakoutSpeed) {
1065 	case 1:
1066 		_minBreakoutMoveSpeed = 1;
1067 		_maxBreakoutMoveSpeed = 1;
1068 		break;
1069 	case 2:
1070 		_minBreakoutMoveSpeed = 1;
1071 		_maxBreakoutMoveSpeed = 2;
1072 		break;
1073 	case 3:
1074 		_minBreakoutMoveSpeed = 2;
1075 		_maxBreakoutMoveSpeed = 2;
1076 		break;
1077 	case 4:
1078 		_minBreakoutMoveSpeed = 3;
1079 		_maxBreakoutMoveSpeed = 2;
1080 		break;
1081 	default:
1082 		break;
1083 	}
1084 
1085 	int moveSpeed = _minBreakoutMoveSpeed;
1086 	if (_lastBreakoutMoveSpeed == _minBreakoutMoveSpeed)
1087 		moveSpeed = _maxBreakoutMoveSpeed;
1088 
1089 	if (_ballUpFl)
1090 		_ballPosition.y += moveSpeed;
1091 	else
1092 		_ballPosition.y -= moveSpeed;
1093 
1094 	if (_ballRightFl)
1095 		_ballPosition.x += moveSpeed;
1096 	else
1097 		_ballPosition.x -= moveSpeed;
1098 
1099 	_lastBreakoutMoveSpeed = moveSpeed;
1100 	if (_ballPosition.x <= 6) {
1101 		_vm->_soundMan->playSample(2, 6);
1102 		_ballPosition.x = randVal + 6;
1103 		_ballRightFl = !_ballRightFl;
1104 	} else if (_ballPosition.x > 307) {
1105 		_vm->_soundMan->playSample(2, 6);
1106 		_ballPosition.x = 307 - randVal;
1107 		_ballRightFl = !_ballRightFl;
1108 	}
1109 
1110 	if (_ballPosition.y <= 6) {
1111 		_vm->_soundMan->playSample(2, 6);
1112 		_ballPosition.y = randVal + 7;
1113 		_ballUpFl = !_ballUpFl;
1114 	} else if (_ballPosition.y >= 186 && _ballPosition.y <= 194) {
1115 		_vm->_soundMan->playSample(2, 6);
1116 		int ballPosXRight = _ballPosition.x + 6;
1117 		if ((_ballPosition.x > _padPositionX - 2) && (ballPosXRight < _padPositionX + 36)) {
1118 			_ballUpFl = false;
1119 			if (ballPosXRight <= _padPositionX + 15) {
1120 				_ballRightFl = false;
1121 				if (_ballPosition.x >= _padPositionX && ballPosXRight <= _padPositionX + 5)
1122 					_ballPosition.x -= 4;
1123 				if (_ballPosition.x >= _padPositionX + 5 && _ballPosition.x + 6 <= _padPositionX + 10)
1124 					_ballPosition.x -= 2;
1125 			}
1126 			if (_ballPosition.x >= _padPositionX + 19 && _ballPosition.x + 6 <= _padPositionX + 36) {
1127 				_ballRightFl = true;
1128 				if (_ballPosition.x >= _padPositionX + 29)
1129 					_ballPosition.x += 4;
1130 				if (_ballPosition.x >= _padPositionX + 24 && _ballPosition.x + 6 <= _padPositionX + 29)
1131 					_ballPosition.x += 2;
1132 			}
1133 		}
1134 	}
1135 
1136 	int retVal = 0;
1137 	if (_ballPosition.y > 194)
1138 		retVal = 1;
1139 	checkBallCollisions();
1140 	_vm->_objectsMan->setSpriteX(1, _ballPosition.x);
1141 	_vm->_objectsMan->setSpriteY(1, _ballPosition.y);
1142 	if (!_breakoutBrickNbr)
1143 		retVal = 2;
1144 	return retVal;
1145 }
1146 
1147 /**
1148  * Check ball collision with bricks
1149  */
checkBallCollisions()1150 void ComputerManager::checkBallCollisions() {
1151 	int cellLeft;
1152 
1153 	bool brickDestroyedFl = false;
1154 	// TODO: Check if correct
1155 	int randVal = _vm->getRandomNumber(6) + 1;
1156 	int ballLeft = _ballPosition.x;
1157 	int ballTop = _ballPosition.y;
1158 	int ballRight = _ballPosition.x + 6;
1159 	int ballBottom = _ballPosition.y + 6;
1160 	int16 *level = _breakoutLevel;
1161 	uint16 levelIdx = 0;
1162 	do {
1163 		cellLeft = level[levelIdx];
1164 		int cellUp = level[levelIdx + 1];
1165 		int cellRight = level[levelIdx + 2];
1166 		int cellBottom = level[levelIdx + 3];
1167 		int cellType = level[levelIdx + 4];
1168 		if (level[levelIdx + 5] == 1 && cellLeft != -1) {
1169 			bool collisionFl = false;
1170 			if (ballTop <= cellBottom && ballBottom >= cellBottom) {
1171 				if (ballLeft >= cellLeft && ballRight <= cellRight) {
1172 					collisionFl = true;
1173 					_ballUpFl = true;
1174 				}
1175 				if ((ballRight >= cellLeft) && (ballLeft <= cellLeft)) {
1176 					collisionFl = true;
1177 					_ballUpFl = true;
1178 					_ballRightFl = false;
1179 					if (cellType == 31)
1180 						_ballPosition.x -= randVal;
1181 				}
1182 				if ((ballLeft <= cellRight) && (ballRight >= cellRight)) {
1183 					collisionFl = true;
1184 					_ballUpFl = true;
1185 					_ballRightFl = true;
1186 					if (cellType == 31)
1187 						_ballPosition.x += randVal;
1188 				}
1189 			}
1190 			if (ballBottom >= cellUp && ballTop <= cellUp) {
1191 				if (ballLeft >= cellLeft && ballRight <= cellRight) {
1192 					collisionFl = true;
1193 					_ballUpFl = false;
1194 				}
1195 				if ((ballRight >= cellLeft) && (ballLeft <= cellLeft)) {
1196 					collisionFl = true;
1197 					_ballUpFl = false;
1198 					_ballRightFl = false;
1199 					if (cellType == 31)
1200 						_ballPosition.x -= 2;
1201 				}
1202 				if ((ballLeft <= cellRight) && (ballRight >= cellRight)) {
1203 					collisionFl = true;
1204 					_ballUpFl = false;
1205 					_ballRightFl = true;
1206 					if (cellType == 31)
1207 						_ballPosition.x += randVal;
1208 				}
1209 			}
1210 			if ((ballTop >= cellUp) && (ballBottom <= cellBottom)) {
1211 				if ((ballRight >= cellLeft) && (ballLeft <= cellLeft)) {
1212 					collisionFl = true;
1213 					_ballRightFl = false;
1214 					if (cellType == 31)
1215 						_ballPosition.x -= randVal;
1216 				}
1217 				if ((ballLeft <= cellRight) && (ballRight >= cellRight)) {
1218 					collisionFl = true;
1219 					_ballRightFl = true;
1220 					if (cellType == 31)
1221 						_ballPosition.x += randVal;
1222 				}
1223 			}
1224 			if (collisionFl) {
1225 				if (cellType == 31) {
1226 					_vm->_soundMan->playSample(2, 6);
1227 				} else {
1228 					_vm->_soundMan->playSample(1, 5);
1229 					_vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellUp, 16);
1230 					switch (cellType) {
1231 					case 1:
1232 						_breakoutScore += 10;
1233 						break;
1234 					case 2:
1235 						_breakoutScore += 5;
1236 						break;
1237 					case 3:
1238 						_breakoutScore += 50;
1239 						if (_breakoutSpeed <= 1)
1240 							_breakoutSpeed = 2;
1241 						if (_breakoutBrickNbr <= 19)
1242 							_breakoutSpeed = 3;
1243 						break;
1244 					case 4:
1245 						_breakoutScore += 20;
1246 						break;
1247 					case 5:
1248 						_breakoutScore += 30;
1249 						if (_breakoutSpeed <= 1)
1250 							_breakoutSpeed = 2;
1251 						break;
1252 					case 6:
1253 						_breakoutScore += 40;
1254 						break;
1255 					default:
1256 						break;
1257 					}
1258 					displayScore();
1259 					--_breakoutBrickNbr;
1260 					level[levelIdx + 5] = 0;
1261 					brickDestroyedFl = true;
1262 				}
1263 			}
1264 		}
1265 
1266 		if (brickDestroyedFl)
1267 			cellLeft = -1;
1268 		levelIdx += 6;
1269 	} while (cellLeft != -1);
1270 }
1271 
1272 } // End of namespace Hopkins
1273