diff options
Diffstat (limited to 'engines/hopkins/computer.cpp')
-rw-r--r-- | engines/hopkins/computer.cpp | 1222 |
1 files changed, 1222 insertions, 0 deletions
diff --git a/engines/hopkins/computer.cpp b/engines/hopkins/computer.cpp new file mode 100644 index 0000000000..467153e4dd --- /dev/null +++ b/engines/hopkins/computer.cpp @@ -0,0 +1,1222 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "hopkins/computer.h" + +#include "hopkins/font.h" +#include "hopkins/files.h" +#include "hopkins/globals.h" +#include "hopkins/graphics.h" +#include "hopkins/hopkins.h" +#include "hopkins/objects.h" + +#include "common/system.h" +#include "common/file.h" +#include "common/textconsole.h" + +namespace Hopkins { + +ComputerManager::ComputerManager(HopkinsEngine *vm) { + _vm = vm; + + for (int i = 0; i < 50; i++) { + _menuText[i]._actvFl = false; + _menuText[i]._lineSize = 0; + memset(_menuText[i]._line, 0, 90); + } + Common::fill(&_inputBuf[0], &_inputBuf[200], '\0'); + _breakoutSpr = NULL; + _textColor = 0; + _breakoutLevel = (int16 *)NULL; + _breakoutBrickNbr = 0; + _breakoutScore = 0; + _breakoutLives = 0; + _breakoutSpeed = 0; + _ballRightFl = false; + _ballUpFl = false; + _breakoutLevelNbr = 0; + _padPositionX = 0; + _minBreakoutMoveSpeed = 0; + _maxBreakoutMoveSpeed = 0; + _lastBreakoutMoveSpeed = 0; + _breakoutHiscore = 0; +} + +/** + * Sets up textual entry mode. Used by the code for Hopkins computer. + */ +void ComputerManager::setVideoMode() { + setTextMode(); +} + +/** + * Sets up Textual entry mode + */ +void ComputerManager::setTextMode() { + _vm->_graphicsMan->clearPalette(); + _vm->_graphicsMan->clearScreen(); + + _vm->_graphicsMan->_lineNbr = SCREEN_WIDTH; + _vm->_fontMan->_font = _vm->_globals->freeMemory(_vm->_fontMan->_font); + + Common::String filename = "STFONT.SPR"; + Common::File f; + if (!f.exists(filename)) + filename = "FONTE.SPR"; // Used by the BeOS and OS/2 versions as an alternative + _vm->_fontMan->_font = _vm->_fileIO->loadFile(filename); + _vm->_fontMan->_fontFixedWidth = 8; + _vm->_fontMan->_fontFixedHeight = 8; + + _vm->_graphicsMan->loadImage("WINTEXT"); + _vm->_graphicsMan->fadeInLong(); + loadMenu(); + _vm->_events->_mouseFl = false; +} + +/** + * Clear the screen + */ +void ComputerManager::clearScreen() { + _vm->_graphicsMan->loadImage("WINTEXT"); + _vm->_graphicsMan->fadeInLong(); +} + +/** + * Sets the text mode color + */ +void ComputerManager::setTextColor(int col) { + _textColor = col; +} + +/** + * Sets the text position. + * @param yp Y position + * @param xp X position + * @remarks Yes, the reverse co-ordinate pair is really like that in the original game. + */ +void ComputerManager::setTextPosition(int yp, int xp) { + _textPosition.x = xp << 3; + _textPosition.y = yp << 4; +} + +/** + * Show a computer in the FBI office + * @param mode Which computer to display + */ +void ComputerManager::showComputer(ComputerEnum mode) { + _vm->_events->_escKeyFl = false; + _vm->_graphicsMan->resetDirtyRects(); + setVideoMode(); + setTextColor(4); + setTextPosition(2, 4); + if (mode == COMPUTER_HOPKINS) + outText(Common::String(_menuText[0]._line)); + else if (mode == COMPUTER_SAMANTHA) + outText(Common::String(_menuText[1]._line)); + else // COMPUTER_PUBLIC + outText(Common::String(_menuText[2]._line)); + + setTextColor(1); + if (mode == COMPUTER_PUBLIC) { + setTextPosition(10, 8); + outText(Common::String(_menuText[3]._line)); + } + setTextPosition(12, 28); + outText(Common::String(_menuText[4]._line)); + setTextPosition(14, 35); + + displayMessage(280, 224, 8); + bool passwordMatch = false; + if ((mode == COMPUTER_HOPKINS) && !strcmp(_inputBuf, "HOPKINS")) + passwordMatch = true; + else if ((mode == COMPUTER_SAMANTHA) && !strcmp(_inputBuf, "328MHZA")) + passwordMatch = true; + else if ((mode == COMPUTER_PUBLIC) && !strcmp(_inputBuf, "ALLFREE")) + passwordMatch = true; + + if (passwordMatch) { + while (!_vm->shouldQuit()) { + _vm->_events->_escKeyFl = false; + clearScreen(); + setTextColor(4); + setTextPosition(2, 4); + if (mode == COMPUTER_HOPKINS) + outText(Common::String(_menuText[0]._line)); + else if (mode == COMPUTER_SAMANTHA) + outText(Common::String(_menuText[1]._line)); + else if (mode == COMPUTER_PUBLIC) + outText(Common::String(_menuText[2]._line)); + setTextColor(15); + setTextPosition(8, 25); + setTextColor(15); + outText2(Common::String(_menuText[6]._line)); + setTextPosition(20, 25); + outText2(Common::String(_menuText[7]._line)); + if (mode == COMPUTER_HOPKINS) { + setTextPosition(10, 25); + outText2(Common::String(_menuText[8]._line)); + setTextPosition(12, 25); + outText2(Common::String(_menuText[9]._line)); + setTextPosition(14, 25); + outText2(Common::String(_menuText[10]._line)); + setTextPosition(16, 25); + outText2(Common::String(_menuText[11]._line)); + } else if (mode == COMPUTER_SAMANTHA) { + setTextPosition(10, 25); +// outText2(Common::String(_menuText[0x95A])); <=== CHECKME: Unexpected value! replaced by the following line, for consistancy + outText2(Common::String(_menuText[12]._line)); + setTextPosition(12, 25); + outText2(Common::String(_menuText[13]._line)); + setTextPosition(14, 25); + outText2(Common::String(_menuText[14]._line)); + setTextPosition(16, 25); + outText2(Common::String(_menuText[15]._line)); + setTextPosition(18, 25); + outText2(Common::String(_menuText[16]._line)); + } + + bool numericFlag = false; + char keyPressed; + do { + keyPressed = _vm->_events->waitKeyPress(); + if (_vm->shouldQuit()) + return; + + if ((keyPressed >= '0') && (keyPressed <= '9')) + numericFlag = true; + } while (!numericFlag); + + // 0 - Quit + if (keyPressed == '0') + break; + // 1 - Games + if (keyPressed == '1') { + displayGamesSubMenu(); + } else if (mode == COMPUTER_HOPKINS) { + clearScreen(); + setTextColor(4); + setTextPosition(2, 4); + outText(Common::String(_menuText[0]._line)); + setTextColor(15); + switch (keyPressed) { + case '2': + readText(1); + break; + case '3': + readText(2); + break; + case '4': + readText(3); + break; + case '5': + readText(4); + break; + } + } else if (mode == COMPUTER_SAMANTHA) { + clearScreen(); + setTextColor(4); + setTextPosition(2, 4); + outText(Common::String(_menuText[1]._line)); + setTextColor(15); + switch (keyPressed) { + case '2': + readText(6); + break; + case '3': + readText(7); + break; + case '4': + readText(8); + break; + case '5': + readText(9); + break; + case '6': + readText(10); + _vm->_globals->_saveData->_data[svField270] = 4; + break; + } + } + } + _vm->_graphicsMan->clearScreen(); + _vm->_graphicsMan->updateScreen(); + restoreFBIRoom(); + } else { + // Password doesn't match - Access Denied + setTextColor(4); + setTextPosition(16, 25); + outText(Common::String(_menuText[5]._line)); + _vm->_events->refreshScreenAndEvents(); + _vm->_events->delay(1000); + + memset(_vm->_graphicsMan->_frontBuffer, 0, 307199); + _vm->_graphicsMan->clearScreen(); + _vm->_graphicsMan->updateScreen(); + restoreFBIRoom(); + _vm->_events->mouseOff(); + } + + if (mode == COMPUTER_HOPKINS) + _vm->_globals->_exitId = 13; + else // Free access or Samantha + _vm->_globals->_exitId = 14; + + _vm->_graphicsMan->resetDirtyRects(); +} + +static const char _englishText[] = +"% ****** FBI COMPUTER NUMBER 4985 ****** J.HOPKINS COMPUTER ******\n" +"% ****** FBI COMPUTER NUMBER 4998 ****** S.COLLINS COMPUTER ******\n" +"% ****** FBI COMPUTER NUMBER 4997 ****** ACCES FREE COMPUTER ******\n" +"% PASSWORD IS: ALLFREE\n% ENTER CURRENT PASSWORD\n" +"% ****** ACCES DENIED ******\n" +"% 1) *** GAME ***\n" +"% 0) QUIT COMPUTER\n" +"% 2) STRANGE CADAVER\n" +"% 3) STRANGE CADAVER\n" +"% 4) SENATOR FERGUSSON\n" +"% 5) DOG KILLER\n" +"% 2) SCIENTIST KIDNAPPED.\n" +"% 3) SCIENTIST KIDNAPPED (next).\n" +"% 4) SCIENTIST KIDNAPPED (next).\n" +"% 5) SCIENTIST KIDNAPPED (next).\n" +"% 6) SCIENTIST KIDNAPPED (next).\n" +"%% fin\n"; + +static const char _frenchText[] = +"% ****** FBI COMPUTER NUMBER 4985 ****** J.HOPKINS COMPUTER ******\n" +"% ****** FBI COMPUTER NUMBER 4998 ****** S.COLLINS COMPUTER ******\n" +"% ****** FBI COMPUTER NUMBER 4997 ****** ACCES FREE COMPUTER ******\n" +"% PASSWORD IS: ALLFREE\n" +"% ENTER CURRENT PASSWORD\n" +"% ****** ACCES DENIED ******\n" +"% 1) *** CASSE BRIQUE ***\n" +"% 0) QUITTER L'ORDINATEUR\n" +"% 2) CADAVRE SANS TETE\n" +"% 3) CADAVRE SANS TETE\n" +"% 4) AGRESSION DU SENATEUR\n" +"% 5) LES CHIENS TUEURS\n" +"% 2) DISPARITIONS DE CHERCHEURS.\n" +"% 3) DISPARITIONS (suite).\n" +"% 4) DISPARITIONS (suite).\n" +"% 5) DISPARITIONS (suite).\n" +"% 6) DISPARITIONS (suite).\n" +"%% fin\n"; + +static const char _spanishText[] = +"% **** ORDENADOR DEL FBI NUMERO 4985 **** ORDENADOR J.HOPKINS *****\n" +"% **** ORDENADOR DEL FBI NUMERO 4998 **** ORDENADOR S.COLLINS *****\n" +"% *** ORDENADOR DEL FBI NUMERO 4997 *** ORDENADOR DE ACCESO LIBRE ***\n" +"% LA CONTRASE¥A ES: ALLFREE\n" +"% ESCRIBE CONTRASE¥A ACTUAL\n" +"% **** ACCESO DENEGADO ****\n" +"% 1) *** JUEGO ***\n" +"% 0) SALIR DEL ORDENADOR\n" +"% 2) CADAVER EXTRA¥O\n" +"% 3) CADAVER EXTRA¥O\n" +"% 4) SENADOR FERGUSSON\n" +"% 5) MATAPERROS\n" +"% 2) CIENTIFICO SECUESTRADO.\n" +"% 3) CIENTIFICO SECUESTRADO (siguiente).\n" +"% 4) CIENTIFICO SECUESTRADO (siguiente).\n" +"% 5) CIENTIFICO SECUESTRADO (siguiente).\n" +"% 6) CIENTIFICO SECUESTRADO (siguiente).\n" +"%% fin\n"; + +/** + * Load Menu data + */ +void ComputerManager::loadMenu() { + char *ptr; + if (_vm->_fileIO->fileExists("COMPUTAN.TXT")) { + ptr = (char *)_vm->_fileIO->loadFile("COMPUTAN.TXT"); + } else if (_vm->_globals->_language == LANG_FR) { + ptr = (char *)_vm->_globals->allocMemory(sizeof(_frenchText)); + strcpy(ptr, _frenchText); + } else if (_vm->_globals->_language == LANG_SP) { + ptr = (char *)_vm->_globals->allocMemory(sizeof(_spanishText)); + strcpy(ptr, _spanishText); + } else { + ptr = (char *)_vm->_globals->allocMemory(sizeof(_englishText)); + strcpy(ptr, _englishText); + } + + char *tmpPtr = ptr; + int lineNum = 0; + int strPos; + bool loopCond = false; + + do { + if (tmpPtr[0] == '%') { + if (tmpPtr[1] == '%') { + loopCond = true; + break; + } + _menuText[lineNum]._actvFl = 1; + strPos = 0; + while (strPos <= 89) { + char curChar = tmpPtr[strPos + 2]; + if (curChar == '%' || curChar == 10) + break; + _menuText[lineNum]._line[strPos++] = curChar; + } + if (strPos <= 89) { + _menuText[lineNum]._line[strPos] = 0; + _menuText[lineNum]._lineSize = strPos - 1; + } + ++lineNum; + } + ++tmpPtr; + } while (!loopCond); + _vm->_globals->freeMemory((byte *)ptr); +} + +void ComputerManager::displayMessage(int xp, int yp, int textIdx) { + char curChar; + + int x1 = xp; + int x2 = 0; + + int textIndex = 0; + bool oldMouseFlag = _vm->_events->_mouseFl; + _vm->_events->_mouseFl = false; + + _vm->_fontMan->displayTextVesa(xp, yp, "_", 252); + do { + curChar = _vm->_events->waitKeyPress(); + if (_vm->shouldQuit()) + return; + + char mappedChar = '*'; + + if ((curChar == '-') || ((curChar >= '0') && (curChar <= '9')) || ((curChar >= 'A') && (curChar <= 'Z'))) + mappedChar = curChar; + else if ((curChar >= 'a') && (curChar <= 'z')) + mappedChar = curChar - 32; + + // BackSpace + if (curChar == 8 && textIndex > 0) { + _inputBuf[textIndex--] = 0; + x1 -= _vm->_fontMan->_fontFixedWidth; + x2 = x1 + 2 * _vm->_fontMan->_fontFixedWidth; + _vm->_graphicsMan->copyRect(_vm->_graphicsMan->_backBuffer, x1, yp, 3 * _vm->_fontMan->_fontFixedWidth, 12, _vm->_graphicsMan->_frontBuffer, x1, yp); + _vm->_graphicsMan->addDirtyRect(x1, yp, x2, yp + 12); + _vm->_fontMan->displayTextVesa(x1, yp, "_", 252); + } + if (mappedChar != '*') { + char newChar = mappedChar; + _vm->_graphicsMan->copyRect(_vm->_graphicsMan->_backBuffer, x1, yp, _vm->_fontMan->_fontFixedWidth, 12, _vm->_graphicsMan->_frontBuffer, x1, yp); + _vm->_graphicsMan->addDirtyRect(x1, yp, _vm->_fontMan->_fontFixedWidth + x1, yp + 12); + _inputBuf[textIndex] = newChar; + + Common::String charString = Common::String::format("%c_", newChar); + _vm->_fontMan->displayTextVesa(x1, yp, charString, 252); + ++textIndex; + x1 += _vm->_fontMan->_fontFixedWidth; + } + _vm->_events->refreshScreenAndEvents(); + } while (textIndex != textIdx && curChar != 13); + + _vm->_graphicsMan->copyRect(_vm->_graphicsMan->_backBuffer, x1, yp, _vm->_fontMan->_fontFixedWidth, 12, _vm->_graphicsMan->_frontBuffer, x1, yp); + _vm->_graphicsMan->addDirtyRect(x1, yp, _vm->_fontMan->_fontFixedWidth + x1, yp + 12); + + _vm->_events->refreshScreenAndEvents(); + _inputBuf[textIndex] = 0; + _vm->_events->_mouseFl = oldMouseFlag; +} + +/** + * Outputs a text string + */ +void ComputerManager::outText(const Common::String &msg) { + _vm->_fontMan->renderTextDisplay(_textPosition.x, _textPosition.y, msg, _textColor); +} + +/** + * Outputs a text string + */ +void ComputerManager::outText2(const Common::String &msg) { + _vm->_fontMan->displayTextVesa(_textPosition.x, _textPosition.y, msg, _textColor); +} + +/** + * Restores the scene for the FBI headquarters room + */ +void ComputerManager::restoreFBIRoom() { + _vm->_graphicsMan->fadeOutShort(); + + _vm->_globals->freeMemory(_vm->_fontMan->_font); + _vm->_fontMan->_font = _vm->_fileIO->loadFile("FONTE3.SPR"); + _vm->_fontMan->_fontFixedWidth = 12; + _vm->_fontMan->_fontFixedHeight = 21; + + _vm->_events->_mouseFl = true; +} + +/** + * Display texts for the given menu entry + */ +void ComputerManager::readText(int idx) { + _vm->_events->_escKeyFl = false; + + Common::String filename; + if (_vm->_globals->_language == LANG_EN) + filename = "THOPKAN.TXT"; + else if (_vm->_globals->_language == LANG_FR) + filename = "THOPK.TXT"; + else if (_vm->_globals->_language == LANG_SP) + filename = "THOPKES.TXT"; + + byte *ptr = _vm->_fileIO->loadFile(filename); + uint16 fileSize = _vm->_fileIO->fileSize(filename); + int pos; + for (pos = 0; pos < fileSize; pos++) { + if (ptr[pos] == '%') { + Common::String numStr = Common::String::format("%c%c", ptr[pos + 1], ptr[pos + 2]); + if (idx == atol(numStr.c_str())) + break; + } + } + if (pos > fileSize - 3) + error("Error with Hopkins computer file"); + + pos += 3; + int lineNum = 5; + Common::String curStr = ""; + byte curChar; + do { + curChar = ptr[pos]; + if (curChar == 13) { + setTextPosition(lineNum, 1); + outText(curStr); + + ++lineNum; + _vm->_events->refreshScreenAndEvents(); + curStr = ""; + } else if (curChar != '%') { + curStr += curChar; + } + ++pos; + assert(pos <= fileSize); + } while (curChar != '%'); + + _vm->_events->waitKeyPress(); + ptr = _vm->_globals->freeMemory(ptr); +} + +/** + * Display breakout when Games sub-menu is selected + */ +void ComputerManager::displayGamesSubMenu() { + const byte *oldSpriteData = _vm->_objectsMan->_sprite[0]._spriteData; + uint oldSpeed = _vm->_globals->_speed; + + _vm->_globals->_speed = 1; + _vm->_events->changeMouseCursor(0); + _breakoutSpr = NULL; + _vm->_events->_breakoutFl = true; + _breakoutLevel = (int16 *)NULL; + _breakoutBrickNbr = 0; + _breakoutScore = 0; + _breakoutLives = 5; + _breakoutSpeed = 1; + _ballRightFl = false; + _ballUpFl = false; + _breakoutLevelNbr = 0; + _vm->_graphicsMan->_minY = 0; + _vm->_graphicsMan->_maxX = 320; + _vm->_graphicsMan->_maxY = 200; + _vm->_soundMan->loadSample(1, "SOUND37.WAV"); + _vm->_soundMan->loadSample(2, "SOUND38.WAV"); + _vm->_soundMan->loadSample(3, "SOUND39.WAV"); + _breakoutSpr = _vm->_fileIO->loadFile("CASSE.SPR"); + loadHiscore(); + setModeVGA256(); + + newLevel(); + _vm->_graphicsMan->updateScreen(); + + playBreakout(); + _vm->_graphicsMan->resetDirtyRects(); + _breakoutSpr = _vm->_globals->freeMemory(_breakoutSpr); + _breakoutLevel = (int16 *)_vm->_globals->freeMemory((byte *)_breakoutLevel); + _vm->_objectsMan->_sprite[0]._spriteData = oldSpriteData; + + _vm->_soundMan->removeSample(1); + _vm->_soundMan->removeSample(2); + _vm->_soundMan->removeSample(3); + _vm->_globals->_speed = oldSpeed; + _vm->_events->_breakoutFl = false; + setVideoMode(); + setTextColor(15); + clearScreen(); + _vm->_graphicsMan->_maxX = 680; + _vm->_graphicsMan->_minY = 0; + _vm->_graphicsMan->_maxY = 460; +} + +/** + * Load Highscore from file + */ +void ComputerManager::loadHiscore() { + byte *ptr = _vm->_globals->allocMemory(100); + _vm->_saveLoad->load("HISCORE.DAT", ptr); + + for (int scoreIndex = 0; scoreIndex < 6; ++scoreIndex) { + for (int i = 0; i < 5; ++i) { + char nextChar = ptr[(16 * scoreIndex) + i]; + if (!nextChar) + nextChar = ' '; + _score[scoreIndex]._name += nextChar; + } + + for (int i = 0; i < 9; ++i) { + char nextChar = ptr[(scoreIndex * 16) + 6 + i]; + if (!nextChar) + nextChar = '0'; + _score[scoreIndex]._score += nextChar; + } + } + + _vm->_globals->freeMemory(ptr); + _breakoutHiscore = atol(_score[5]._score.c_str()); +} + +/** + * VGA 256 col + */ +void ComputerManager::setModeVGA256() { + _vm->_graphicsMan->clearScreen(); + _vm->_graphicsMan->clearPalette(); + _vm->_graphicsMan->setScreenWidth(320); +} + +/** + * Load new level + */ +void ComputerManager::newLevel() { + _vm->_objectsMan->removeSprite(0); + _vm->_objectsMan->removeSprite(1); + ++_breakoutLives; + if (_breakoutLives > 11) + _breakoutLives = 11; + _vm->_graphicsMan->loadVgaImage("CASSEF.PCX"); + displayLives(); + _breakoutLevel = (int16 *)_vm->_globals->freeMemory((byte *)_breakoutLevel); + + ++_breakoutLevelNbr; + Common::String file; + Common::File f; + while (!_vm->shouldQuit()) { + file = Common::String::format("TAB%d.TAB", _breakoutLevelNbr); + if (f.open(file)) + break; + + _breakoutLevelNbr = 1; + } + f.close(); + + _breakoutLevel = (int16 *)_vm->_fileIO->loadFile(file); + displayBricks(); + + _vm->_objectsMan->addStaticSprite(_breakoutSpr, Common::Point(150, 192), 0, 13, 0, false, 0, 0); + _vm->_objectsMan->addStaticSprite(_breakoutSpr, Common::Point(164, 187), 1, 14, 0, false, 0, 0); + + _ballPosition = Common::Point(164, 187); + _padPositionX = 150; + _vm->_objectsMan->animateSprite(0); + _vm->_objectsMan->animateSprite(1); + + _vm->_events->mouseOn(); + _vm->_soundMan->playSample(3, 5); +} + +/** + * Display bricks in breakout game + */ +void ComputerManager::displayBricks() { + _breakoutBrickNbr = 0; + _breakoutSpeed = 1; + int16 *level = _breakoutLevel; + + int cellLeft; + int cellTop; + int cellType; + for (int levelIdx = 0; ; levelIdx += 6) { + cellLeft = (int16)FROM_LE_16(level[levelIdx]); + if (cellLeft == -1) + break; + cellTop = FROM_LE_16(level[levelIdx + 1]); + cellType = FROM_LE_16(level[levelIdx + 4]); + + if (cellType <= 6) + ++_breakoutBrickNbr; + + switch (cellType) { + case 1: + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 21); + break; + case 2: + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 22); + break; + case 3: + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 17); + break; + case 4: + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 20); + break; + case 5: + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 19); + break; + case 6: + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 18); + break; + case 31: + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 23); + break; + } + } + + displayScore(); +} + +/** + * Display Lives in breakout game + */ +void ComputerManager::displayLives() { + for (int i = 0, xp = 10; i <= 11; i++, xp += 7) + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, xp, 10, 15); + + for (int i = 0, xp = 10; i < _breakoutLives - 1; i++, xp += 7) + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, xp, 10, 14); + + _vm->_graphicsMan->updateScreen(); +} + +/** + * Main function for breakout game + */ +void ComputerManager::playBreakout() { + int lastBreakoutEvent = 0; + while (!_vm->shouldQuit()) { + while (!_vm->shouldQuit()) { + // Set up the racket and ball + _vm->_events->mouseOff(); + _ballPosition = Common::Point(_padPositionX + 14, 187); + _vm->_objectsMan->setSpriteY(1, 187); + _vm->_objectsMan->setSpriteX(1, _ballPosition.x); + + _vm->_graphicsMan->resetDirtyRects(); + _vm->_events->refreshScreenAndEvents(); + _vm->_graphicsMan->fadeInBreakout(); + + // Wait for mouse press to start playing + do { + _padPositionX = _vm->_events->getMouseX(); + if (_vm->_events->_mousePos.x <= 4) + _padPositionX = 5; + if (_padPositionX > 282) + _padPositionX = 282; + _vm->_objectsMan->setSpriteX(0, _padPositionX); + _vm->_objectsMan->setSpriteX(1, _padPositionX + 14); + _vm->_objectsMan->setSpriteY(1, 187); + _vm->_events->refreshScreenAndEvents(); + } while (!_vm->shouldQuit() && _vm->_events->getMouseButton() != 1); + + _breakoutSpeed = 1; + _ballPosition = Common::Point(_padPositionX + 14, 187); + _ballRightFl = (_padPositionX > 135); + _ballUpFl = false; + + // Play loop + do { + _vm->_soundMan->checkSounds(); + + _padPositionX = _vm->_events->getMouseX(); + if (_vm->_events->_mousePos.x <= 4) + _padPositionX = 5; + if (_padPositionX > 282) + _padPositionX = 282; + _vm->_objectsMan->setSpriteX(0, _padPositionX); + lastBreakoutEvent = moveBall(); + _vm->_events->refreshScreenAndEvents(); + } while (!_vm->shouldQuit() && !lastBreakoutEvent); + if (lastBreakoutEvent != 1) + break; + + --_breakoutLives; + + if (_breakoutLives) { + displayLives(); + if (_breakoutLives) + continue; + } + + _vm->_graphicsMan->fadeOutBreakout(); + _vm->_events->mouseOn(); + _vm->_objectsMan->removeSprite(0); + _vm->_objectsMan->removeSprite(1); + if (_breakoutScore > _breakoutHiscore) + getScoreName(); + if (displayHiscores() != 1) + break; + + _breakoutBrickNbr = 0; + _breakoutScore = 0; + _breakoutLives = 4; + _breakoutSpeed = 1; + _ballRightFl = false; + _ballUpFl = false; + _breakoutLevelNbr = 0; + loadHiscore(); + newLevel(); + } + if (lastBreakoutEvent != 2) + return; + _vm->_graphicsMan->fadeOutBreakout(); + newLevel(); + } +} + +/** + * Show the high scores for the Breakout game + * @return The selected button index: 1 = Game, 2 = Quit + */ +int ComputerManager::displayHiscores() { + _vm->_graphicsMan->resetDirtyRects(); + loadHiscore(); + _vm->_graphicsMan->loadVgaImage("HISCORE.PCX"); + byte *ptr = _vm->_fileIO->loadFile("ALPHA.SPR"); + _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100); + _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100); + _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100); + _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0); + + int yp; + int xp; + // Loop for displaying the scores + for (int scoreIndex = 0; scoreIndex <= 5; scoreIndex++) { + yp = 19 * scoreIndex; + yp += 46; + + // Display the characters of the name + for (int i = 0; i <= 5; i++) + displayHiscoreLine(ptr, 9 * i + 69, yp, _score[scoreIndex]._name[i]); + + // Display the digits of the score + for (int i = 0; i <= 8; i++) + displayHiscoreLine(ptr, 9 * i + 199, yp, _score[scoreIndex]._score[i]); + } + + _vm->_graphicsMan->fadeInBreakout(); + _vm->_graphicsMan->resetDirtyRects(); + int buttonIndex = 0; + do { + _vm->_events->refreshEvents(); + xp = _vm->_events->getMouseX(); + yp = _vm->_events->getMouseY(); + + if (_vm->_events->getMouseButton() == 1 && ABS(xp - 79) <= 33 && ABS(yp - 396) <= 13) + buttonIndex = 1; + else if (_vm->_events->getMouseButton() == 1 && ABS(xp - 583) <= 32 && ABS(yp - 396) <= 13) + buttonIndex = 2; + + _vm->_events->refreshScreenAndEvents(); + } while (!buttonIndex && !_vm->shouldQuit()); + + _vm->_events->mouseOff(); + _vm->_graphicsMan->fadeOutBreakout(); + _vm->_globals->freeMemory(ptr); + return buttonIndex; +} + +/** + * Display a screen to enter player name in the case of a new hiscore + */ +void ComputerManager::getScoreName() { + _vm->_graphicsMan->loadVgaImage("NAME.PCX"); + _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100); + _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100); + _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100); + _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0); + byte *ptr = _vm->_fileIO->loadFile("ALPHA.SPR"); + _vm->_graphicsMan->fadeInBreakout(); + for (int strPos = 0; strPos <= 4; strPos++) { + displayHiscoreLine(ptr, 9 * strPos + 140, 78, 1); + + char curChar = toupper(_vm->_events->waitKeyPress()); + if ((curChar < '0') || (curChar > 'Z')) + curChar = ' '; + if ((curChar > '9') && (curChar < 'A')) + curChar = ' '; + + _score[5]._name.setChar(curChar, strPos); + displayHiscoreLine(ptr, 9 * strPos + 140, 78, curChar); + + for (int idx = 0; idx < 12; ++idx) + _vm->_events->refreshScreenAndEvents(); + } + _score[5]._score = " "; + + char score[16]; + sprintf(score, "%d", _breakoutScore); + int scoreLen = 0; + do + ++scoreLen; + while (score[scoreLen]); + + for (int i = scoreLen, scorePos = 8; i >= 0; i--) { + _score[5]._score.setChar(score[i], scorePos--); + } + _vm->_graphicsMan->fadeOutBreakout(); + _vm->_globals->freeMemory(ptr); + saveScore(); +} + +/** + * Display current score + */ +void ComputerManager::displayScore() { + Common::String scoreStr = Common::String::format("%d", _breakoutScore); + int strSize = scoreStr.size(); + for (int i = strSize - 1, idx = 0; i >= 0; i--) { + displayScoreChar(idx++, scoreStr[i]); + } +} + +/** + * Display a character of the score + */ +void ComputerManager::displayScoreChar(int charPos, int charDisp) { + int xp; + switch (charPos) { + case 1: + xp = 190; + break; + case 2: + xp = 180; + break; + case 3: + xp = 167; + break; + case 4: + xp = 157; + break; + case 5: + xp = 147; + break; + case 9: + xp = 134; + break; + default: + xp = 200; + break; + } + + int idx = 3; + if (charDisp >= '0' && charDisp <= '9') + idx = charDisp - 45; + + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, xp, 11, idx); +} + +/** + * Save Hiscore in file + */ +void ComputerManager::saveScore() { + int scores[6]; + // Load high scores in an array + for (int i = 0; i <= 5; i++) { + scores[i] = atol(_score[i]._score.c_str()); + if (!scores[i]) + scores[i] = 5; + } + + int scorePlace[6]; + // order high scores + for (int scorePlaceIdx = 0; scorePlaceIdx <= 5; scorePlaceIdx++) { + for(int i = 0;;i++) { + int curScore = scores[i]; + if (curScore && scores[0] <= curScore && scores[1] <= curScore && scores[2] <= curScore && scores[3] <= curScore + && scores[4] <= curScore && scores[5] <= curScore) { + scorePlace[scorePlaceIdx] = i; + scores[i] = 0; + break; + } + } + } + + byte *ptr = _vm->_globals->allocMemory(100); + memset(ptr, 0, 99); + for (int scorePlaceIdx = 0; scorePlaceIdx <= 5; scorePlaceIdx++) { + int curBufPtr = 16 * scorePlaceIdx; + for (int namePos = 0; namePos <= 4; namePos++) { + char curChar = _score[scorePlace[scorePlaceIdx]]._name[namePos]; + if (!curChar) + curChar = ' '; + ptr[curBufPtr + namePos] = curChar; + }; + + ptr[curBufPtr + 5] = 0; + + for (int scorePos = 0; scorePos <= 8; scorePos++) { + char curChar = _score[scorePlace[scorePlaceIdx]]._score[scorePos]; + if (!curChar) + curChar = '0'; + ptr[curBufPtr + 6 + scorePos] = curChar; + }; + ptr[curBufPtr + 15] = 0; + } + + _vm->_saveLoad->saveFile("HISCORE.DAT", ptr, 100); + _vm->_globals->freeMemory(ptr); +} + +/** + * Display parts of the hiscore line + */ +void ComputerManager::displayHiscoreLine(const byte *objectData, int x, int y, int curChar) { + int idx = 36; + + if (curChar == 100) + idx = 0; + else if (curChar >= '0' && curChar <= '9') + idx = curChar - '0'; + else if (curChar >= 'A' && curChar <= 'Z') + idx = curChar - 'A' + 10; + else if (curChar == 1) + idx = 37; + _vm->_graphicsMan->fastDisplay2(objectData, x, y, idx); +} + +/** + * Handle ball moves + */ +int ComputerManager::moveBall() { + //(signed int)(6.0 * (long double)_vm->getRandomNumber( rand() / 2147483648.0) + 1; + // TODO: Figure out random number + int randVal = _vm->getRandomNumber(6); + switch (_breakoutSpeed) { + case 1: + _minBreakoutMoveSpeed = 1; + _maxBreakoutMoveSpeed = 1; + break; + case 2: + _minBreakoutMoveSpeed = 1; + _maxBreakoutMoveSpeed = 2; + break; + case 3: + _minBreakoutMoveSpeed = 2; + _maxBreakoutMoveSpeed = 2; + break; + case 4: + _minBreakoutMoveSpeed = 3; + _maxBreakoutMoveSpeed = 2; + break; + } + + int moveSpeed = _minBreakoutMoveSpeed; + if (_lastBreakoutMoveSpeed == _minBreakoutMoveSpeed) + moveSpeed = _maxBreakoutMoveSpeed; + + if (_ballUpFl) + _ballPosition.y += moveSpeed; + else + _ballPosition.y -= moveSpeed; + + if (_ballRightFl) + _ballPosition.x += moveSpeed; + else + _ballPosition.x -= moveSpeed; + + _lastBreakoutMoveSpeed = moveSpeed; + if (_ballPosition.x <= 6) { + _vm->_soundMan->playSample(2, 6); + _ballPosition.x = randVal + 6; + _ballRightFl = !_ballRightFl; + } else if (_ballPosition.x > 307) { + _vm->_soundMan->playSample(2, 6); + _ballPosition.x = 307 - randVal; + _ballRightFl = !_ballRightFl; + } + + if (_ballPosition.y <= 6) { + _vm->_soundMan->playSample(2, 6); + _ballPosition.y = randVal + 7; + _ballUpFl = !_ballUpFl; + } else if (_ballPosition.y >= 186 && _ballPosition.y <= 194) { + _vm->_soundMan->playSample(2, 6); + int ballPosXRight = _ballPosition.x + 6; + if ((_ballPosition.x > _padPositionX - 2) && (ballPosXRight < _padPositionX + 36)) { + _ballUpFl = false; + if (ballPosXRight <= _padPositionX + 15) { + _ballRightFl = false; + if (_ballPosition.x >= _padPositionX && ballPosXRight <= _padPositionX + 5) + _ballPosition.x -= 4; + if (_ballPosition.x >= _padPositionX + 5 && _ballPosition.x + 6 <= _padPositionX + 10) + _ballPosition.x -= 2; + } + if (_ballPosition.x >= _padPositionX + 19 && _ballPosition.x + 6 <= _padPositionX + 36) { + _ballRightFl = true; + if (_ballPosition.x >= _padPositionX + 29) + _ballPosition.x += 4; + if (_ballPosition.x >= _padPositionX + 24 && _ballPosition.x + 6 <= _padPositionX + 29) + _ballPosition.x += 2; + } + } + } + + int retVal = 0; + if (_ballPosition.y > 194) + retVal = 1; + checkBallCollisions(); + _vm->_objectsMan->setSpriteX(1, _ballPosition.x); + _vm->_objectsMan->setSpriteY(1, _ballPosition.y); + if (!_breakoutBrickNbr) + retVal = 2; + return retVal; +} + +/** + * Check ball collision with bricks + */ +void ComputerManager::checkBallCollisions() { + int cellLeft; + + bool brickDestroyedFl = false; + // TODO: Check if correct + int randVal = _vm->getRandomNumber(6) + 1; + int ballLeft = _ballPosition.x; + int ballTop = _ballPosition.y; + int ballRight = _ballPosition.x + 6; + int ballBottom = _ballPosition.y + 6; + int16 *level = _breakoutLevel; + uint16 levelIdx = 0; + do { + cellLeft = level[levelIdx]; + int cellUp = level[levelIdx + 1]; + int cellRight = level[levelIdx + 2]; + int cellBottom = level[levelIdx + 3]; + int cellType = level[levelIdx + 4]; + if (level[levelIdx + 5] == 1 && cellLeft != -1) { + bool collisionFl = false; + if (ballTop <= cellBottom && ballBottom >= cellBottom) { + if (ballLeft >= cellLeft && ballRight <= cellRight) { + collisionFl = true; + _ballUpFl = true; + } + if ((ballRight >= cellLeft) && (ballLeft <= cellLeft)) { + collisionFl = true; + _ballUpFl = true; + _ballRightFl = false; + if (cellType == 31) + _ballPosition.x -= randVal; + } + if ((ballLeft <= cellRight) && (ballRight >= cellRight)) { + collisionFl = true; + _ballUpFl = true; + _ballRightFl = true; + if (cellType == 31) + _ballPosition.x += randVal; + } + } + if (ballBottom >= cellUp && ballTop <= cellUp) { + if (ballLeft >= cellLeft && ballRight <= cellRight) { + collisionFl = true; + _ballUpFl = false; + } + if ((ballRight >= cellLeft) && (ballLeft <= cellLeft)) { + collisionFl = true; + _ballUpFl = false; + _ballRightFl = false; + if (cellType == 31) + _ballPosition.x -= 2; + } + if ((ballLeft <= cellRight) && (ballRight >= cellRight)) { + collisionFl = true; + _ballUpFl = false; + _ballRightFl = true; + if (cellType == 31) + _ballPosition.x += randVal; + } + } + if ((ballTop >= cellUp) && (ballBottom <= cellBottom)) { + if ((ballRight >= cellLeft) && (ballLeft <= cellLeft)) { + collisionFl = true; + _ballRightFl = false; + if (cellType == 31) + _ballPosition.x -= randVal; + } + if ((ballLeft <= cellRight) && (ballRight >= cellRight)) { + collisionFl = true; + _ballRightFl = true; + if (cellType == 31) + _ballPosition.x += randVal; + } + } + if (collisionFl) { + if (cellType == 31) { + _vm->_soundMan->playSample(2, 6); + } else { + _vm->_soundMan->playSample(1, 5); + _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellUp, 16); + switch (cellType) { + case 1: + _breakoutScore += 10; + break; + case 2: + _breakoutScore += 5; + break; + case 3: + _breakoutScore += 50; + if (_breakoutSpeed <= 1) + _breakoutSpeed = 2; + if (_breakoutBrickNbr <= 19) + _breakoutSpeed = 3; + break; + case 4: + _breakoutScore += 20; + break; + case 5: + _breakoutScore += 30; + if (_breakoutSpeed <= 1) + _breakoutSpeed = 2; + break; + case 6: + _breakoutScore += 40; + break; + } + displayScore(); + --_breakoutBrickNbr; + level[levelIdx + 5] = 0; + brickDestroyedFl = true; + } + } + } + + if (brickDestroyedFl) + cellLeft = -1; + levelIdx += 6; + } while (cellLeft != -1); +} + +} // End of namespace Hopkins |