/* 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. * */ /* * This code is based on Labyrinth of Time code with assistance of * * Copyright (c) 1993 Terra Nova Development * Copyright (c) 2004 The Wyrmkeep Entertainment Co. * */ #include "lab/lab.h" #include "gui/message.h" namespace Lab { const uint16 INIT_TILE[4][4] = { { 1, 5, 9, 13 }, { 2, 6, 10, 14 }, { 3, 7, 11, 15 }, { 4, 8, 12, 0 } }; const uint16 SOLUTION[4][4] = { { 7, 1, 8, 3 }, { 2, 11, 15, 4 }, { 9, 5, 14, 6 }, { 10, 13, 12, 0 } }; const int COMBINATION_X[6] = { 45, 83, 129, 166, 211, 248 }; void LabEngine::initTilePuzzle() { for (int i = 0; i < 16; i++) _tiles[i] = nullptr; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) _curTile[i][j] = INIT_TILE[i][j]; } for (int i = 0; i < 6; i++) _combination[i] = 0; } /*****************************************************************************/ /* Processes mouse clicks and changes the combination. */ /*****************************************************************************/ void LabEngine::mouseTile(Common::Point pos) { Common::Point realPos = _utils->vgaUnscale(pos); if ((realPos.x < 101) || (realPos.y < 26)) return; int tileX = (realPos.x - 101) / 30; int tileY = (realPos.y - 26) / 25; if ((tileX < 4) && (tileY < 4)) changeTile(tileX, tileY); } /*****************************************************************************/ /* Changes the combination number of one of the slots */ /*****************************************************************************/ void LabEngine::changeTile(uint16 col, uint16 row) { int16 scrolltype = -1; if (row > 0) { if (_curTile[col][row - 1] == 0) { _curTile[col][row - 1] = _curTile[col][row]; _curTile[col][row] = 0; scrolltype = DOWNSCROLL; } } if (col > 0) { if (_curTile[col - 1][row] == 0) { _curTile[col - 1][row] = _curTile[col][row]; _curTile[col][row] = 0; scrolltype = RIGHTSCROLL; } } if (row < 3) { if (_curTile[col][row + 1] == 0) { _curTile[col][row + 1] = _curTile[col][row]; _curTile[col][row] = 0; scrolltype = UPSCROLL; } } if (col < 3) { if (_curTile[col + 1][row] == 0) { _curTile[col + 1][row] = _curTile[col][row]; _curTile[col][row] = 0; scrolltype = LEFTSCROLL; } } if (scrolltype != -1) { doTileScroll(col, row, scrolltype); if (getFeatures() & GF_WINDOWS_TRIAL) { GUI::MessageDialog trialMessage("This puzzle is not available in the trial version of the game"); trialMessage.runModal(); return; } bool check = true; row = 0; col = 0; while (row < 4) { while (col < 4) { check &= (_curTile[row][col] == SOLUTION[row][col]); col++; } row++; col = 0; } if (check) { _conditions->inclElement(BRICKOPEN); /* unlocked combination */ _anim->_doBlack = true; _graphics->readPict("p:Up/BDOpen", true); } } } /*****************************************************************************/ /* Processes mouse clicks and changes the combination. */ /*****************************************************************************/ void LabEngine::mouseCombination(Common::Point pos) { Common::Point realPos = _utils->vgaUnscale(pos); if (!Common::Rect(44, 63, 285, 99).contains(realPos)) return; uint16 number = 0; if (realPos.x < 83) number = 0; else if (realPos.x < 127) number = 1; else if (realPos.x < 165) number = 2; else if (realPos.x < 210) number = 3; else if (realPos.x < 245) number = 4; else if (realPos.x < 286) number = 5; changeCombination(number); } /*****************************************************************************/ /* Draws the images of the combination lock to the display bitmap. */ /*****************************************************************************/ void LabEngine::doTile(bool showsolution) { uint16 row = 0, col = 0, rowm, colm, num; int16 rows, cols; if (showsolution) { rowm = _utils->vgaScaleY(23); colm = _utils->vgaScaleX(27); rows = _utils->vgaScaleY(31); cols = _utils->vgaScaleX(105); } else { _graphics->setAPen(0); _graphics->rectFillScaled(97, 22, 220, 126); rowm = _utils->vgaScaleY(25); colm = _utils->vgaScaleX(30); rows = _utils->vgaScaleY(25); cols = _utils->vgaScaleX(100); } while (row < 4) { while (col < 4) { if (showsolution) num = SOLUTION[col][row]; else num = _curTile[col][row]; if (showsolution || num) _tiles[num]->drawImage(cols + (col * colm), rows + (row * rowm)); col++; } row++; col = 0; } } /*****************************************************************************/ /* Reads in a backdrop picture. */ /*****************************************************************************/ void LabEngine::showTile(const char *filename, bool showsolution) { uint16 start = showsolution ? 0 : 1; _anim->_doBlack = true; _anim->_noPalChange = true; _graphics->readPict(filename, true); _anim->_noPalChange = false; _graphics->blackScreen(); Common::File *tileFile = tileFile = _resource->openDataFile(showsolution ? "P:TileSolution" : "P:Tile"); for (uint16 curBit = start; curBit < 16; curBit++) _tiles[curBit] = new Image(tileFile); delete tileFile; doTile(showsolution); _graphics->setPalette(_anim->_diffPalette, 256); } /*****************************************************************************/ /* Does the scrolling for the tiles on the tile puzzle. */ /*****************************************************************************/ void LabEngine::doTileScroll(uint16 col, uint16 row, uint16 scrolltype) { int16 dX = 0, dY = 0, dx = 0, dy = 0, sx = 0, sy = 0; uint16 last = 0; if (scrolltype == LEFTSCROLL) { dX = _utils->vgaScaleX(5); sx = _utils->vgaScaleX(5); last = 6; } else if (scrolltype == RIGHTSCROLL) { dX = _utils->vgaScaleX(-5); dx = _utils->vgaScaleX(-5); sx = _utils->vgaScaleX(5); last = 6; } else if (scrolltype == UPSCROLL) { dY = _utils->vgaScaleY(5); sy = _utils->vgaScaleY(5); last = 5; } else if (scrolltype == DOWNSCROLL) { dY = _utils->vgaScaleY(-5); dy = _utils->vgaScaleY(-5); sy = _utils->vgaScaleY(5); last = 5; } sx += _utils->svgaCord(2); uint16 x1 = _utils->vgaScaleX(100) + (col * _utils->vgaScaleX(30)) + dx; uint16 y1 = _utils->vgaScaleY(25) + (row * _utils->vgaScaleY(25)) + dy; for (uint16 i = 0; i < last; i++) { waitTOF(); scrollRaster(dX, dY, x1, y1, x1 + _utils->vgaScaleX(28) + sx, y1 + _utils->vgaScaleY(23) + sy); x1 += dX; y1 += dY; } } /*****************************************************************************/ /* Changes the combination number of one of the slots */ /*****************************************************************************/ void LabEngine::changeCombination(uint16 number) { static const int solution[6] = { 0, 4, 0, 8, 7, 2 }; Image display; uint16 combnum; bool unlocked = true; if (_combination[number] < 9) (_combination[number])++; else _combination[number] = 0; combnum = _combination[number]; display._imageData = _graphics->getCurrentDrawingBuffer(); display._width = _graphics->_screenWidth; display._height = _graphics->_screenHeight; for (uint16 i = 1; i <= (_numberImages[combnum]->_height / 2); i++) { if (_isHiRes) { if (i & 1) waitTOF(); } else waitTOF(); display._imageData = _graphics->getCurrentDrawingBuffer(); _graphics->scrollDisplayY(2, _utils->vgaScaleX(COMBINATION_X[number]), _utils->vgaScaleY(65), _utils->vgaScaleX(COMBINATION_X[number]) + (_numberImages[combnum])->_width - 1, _utils->vgaScaleY(65) + (_numberImages[combnum])->_height); _numberImages[combnum]->blitBitmap(0, (_numberImages[combnum])->_height - (2 * i), &(display), _utils->vgaScaleX(COMBINATION_X[number]), _utils->vgaScaleY(65), (_numberImages[combnum])->_width, 2, false); } for (uint16 i = 0; i < 6; i++) unlocked &= (_combination[i] == solution[i]); if (unlocked) _conditions->inclElement(COMBINATIONUNLOCKED); else _conditions->exclElement(COMBINATIONUNLOCKED); } void LabEngine::scrollRaster(int16 dx, int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2) { if (dx) _graphics->scrollDisplayX(dx, x1, y1, x2, y2); if (dy) _graphics->scrollDisplayY(dy, x1, y1, x2, y2); } /*****************************************************************************/ /* Draws the images of the combination lock to the display bitmap. */ /*****************************************************************************/ void LabEngine::doCombination() { for (uint16 i = 0; i <= 5; i++) _numberImages[_combination[i]]->drawImage(_utils->vgaScaleX(COMBINATION_X[i]), _utils->vgaScaleY(65)); } /*****************************************************************************/ /* Reads in a backdrop picture. */ /*****************************************************************************/ void LabEngine::showCombination(const char *filename) { _anim->_doBlack = true; _anim->_noPalChange = true; _graphics->readPict(filename, true); _anim->_noPalChange = false; _graphics->blackScreen(); Common::File *numFile = _resource->openDataFile("P:Numbers"); for (uint16 CurBit = 0; CurBit < 10; CurBit++) _numberImages[CurBit] = new Image(numFile); delete numFile; doCombination(); _graphics->setPalette(_anim->_diffPalette, 256); } } // End of namespace Lab