From 71296d6461bd8346793ff939b5d2e84d22c58dfa Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Wed, 22 Jul 2015 20:26:28 -0400 Subject: SHERLOCK: RT: Split TattooEngine code into separate widget classes --- engines/sherlock/module.mk | 2 + engines/sherlock/tattoo/tattoo.cpp | 398 +--------------------- engines/sherlock/tattoo/tattoo.h | 35 +- engines/sherlock/tattoo/tattoo_scene.cpp | 4 +- engines/sherlock/tattoo/tattoo_user_interface.cpp | 16 +- engines/sherlock/tattoo/tattoo_user_interface.h | 6 +- engines/sherlock/tattoo/widget_credits.cpp | 210 ++++++++++++ engines/sherlock/tattoo/widget_credits.h | 84 +++++ engines/sherlock/tattoo/widget_hangman.cpp | 264 ++++++++++++++ engines/sherlock/tattoo/widget_hangman.h | 48 +++ 10 files changed, 625 insertions(+), 442 deletions(-) create mode 100644 engines/sherlock/tattoo/widget_credits.cpp create mode 100644 engines/sherlock/tattoo/widget_credits.h create mode 100644 engines/sherlock/tattoo/widget_hangman.cpp create mode 100644 engines/sherlock/tattoo/widget_hangman.h diff --git a/engines/sherlock/module.mk b/engines/sherlock/module.mk index 32c5d3acc3..4c12fc7a00 100644 --- a/engines/sherlock/module.mk +++ b/engines/sherlock/module.mk @@ -33,6 +33,8 @@ MODULE_OBJS = \ tattoo/tattoo_talk.o \ tattoo/tattoo_user_interface.o \ tattoo/widget_base.o \ + tattoo/widget_credits.o \ + tattoo/widget_hangman.o \ tattoo/widget_inventory.o \ tattoo/widget_lab.o \ tattoo/widget_talk.o \ diff --git a/engines/sherlock/tattoo/tattoo.cpp b/engines/sherlock/tattoo/tattoo.cpp index 90d2e5d958..920bef1a4c 100644 --- a/engines/sherlock/tattoo/tattoo.cpp +++ b/engines/sherlock/tattoo/tattoo.cpp @@ -34,13 +34,11 @@ namespace Sherlock { namespace Tattoo { TattooEngine::TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) : - SherlockEngine(syst, gameDesc), _darts(this) { - _creditsActive = false; + SherlockEngine(syst, gameDesc), _darts(this), _hangmanWidget(this) { _runningProlog = false; _fastMode = false; _allowFastMode = true; _transparentMenus = true; - _creditSpeed = 4; } TattooEngine::~TattooEngine() { @@ -175,400 +173,8 @@ void TattooEngine::loadInventory() { inv.push_back(InventoryItem(0, inv8, invDesc8, "_LANT02I")); } -void TattooEngine::initCredits() { - Common::SeekableReadStream *stream = _res->load("credits.txt"); - int spacing = _screen->fontHeight() * 2; - int yp = _screen->h(); - - _creditsActive = true; - _creditLines.clear(); - - while (stream->pos() < stream->size()) { - Common::String line = stream->readLine(); - - if (line.hasPrefix("Scroll Speed")) { - const char *p = line.c_str() + 12; - while ((*p < '0') || (*p > '9')) - p++; - - _creditSpeed = atoi(p); - } else if (line.hasPrefix("Y Spacing")) { - const char *p = line.c_str() + 12; - while ((*p < '0') || (*p > '9')) - p++; - - spacing = atoi(p) + _screen->fontHeight() + 1; - } else { - int width = _screen->stringWidth(line) + 2; - - _creditLines.push_back(CreditLine(line, Common::Point((_screen->w() - width) / 2 + 1, yp), width)); - yp += spacing; - } - } - - // Post-processing for finding split lines - for (int l = 0; l < (int)_creditLines.size(); ++l) { - CreditLine &cl = _creditLines[l]; - const char *p = strchr(cl._line.c_str(), '-'); - - if (p != nullptr && p[1] == '>') { - cl._line2 = Common::String(p + 3); - cl._line = Common::String(cl._line.c_str(), p); - - int width = cl._width; - int width1 = _screen->stringWidth(cl._line); - int width2 = _screen->stringWidth(cl._line2); - - int c = 1; - for (int l1 = l + 1; l1 < (int)_creditLines.size(); ++l1) { - if ((p = strchr(_creditLines[l1]._line.c_str(), '-')) != nullptr) { - if (p[1] == '>') { - Common::String line1 = Common::String(_creditLines[l1]._line.c_str(), p); - Common::String line2 = Common::String(p + 3); - - width1 = MAX(width1, _screen->stringWidth(line1)); - - if (_screen->stringWidth(line2) > width2) - width2 = _screen->stringWidth(line2); - ++c; - } else { - break; - } - } else { - break; - } - } - - width = width1 + width2 + _screen->widestChar(); - width1 += _screen->widestChar(); - - for (int l1 = l; l1 < l + c; ++l1) { - _creditLines[l1]._width = width; - _creditLines[l1]._xOffset = width1; - } - - l += c - 1; - } - } - - delete stream; -} - -void TattooEngine::drawCredits() { - Common::Rect screenRect(0, 0, _screen->w(), _screen->h()); - Surface &bb1 = _screen->_backBuffer1; - - for (uint idx = 0; idx < _creditLines.size() && _creditLines[idx]._position.y < _screen->h(); ++idx) { - if (screenRect.contains(_creditLines[idx]._position)) { - if (!_creditLines[idx]._line2.empty()) { - int x1 = _creditLines[idx]._position.x; - int x2 = x1 + _creditLines[idx]._xOffset; - const Common::String &line1 = _creditLines[idx]._line; - const Common::String &line2 = _creditLines[idx]._line2; - - bb1.writeString(line1, Common::Point(x1 - 1, _creditLines[idx]._position.y - 1), 0); - bb1.writeString(line1, Common::Point(x1, _creditLines[idx]._position.y - 1), 0); - bb1.writeString(line1, Common::Point(x1 + 1, _creditLines[idx]._position.y - 1), 0); - - bb1.writeString(line1, Common::Point(x1 - 1, _creditLines[idx]._position.y), 0); - bb1.writeString(line1, Common::Point(x1 + 1, _creditLines[idx]._position.y), 0); - - bb1.writeString(line1, Common::Point(x1 - 1, _creditLines[idx]._position.y + 1), 0); - bb1.writeString(line1, Common::Point(x1, _creditLines[idx]._position.y + 1), 0); - bb1.writeString(line1, Common::Point(x1 + 1, _creditLines[idx]._position.y + 1), 0); - - bb1.writeString(line1, Common::Point(x1, _creditLines[idx]._position.y), INFO_TOP); - - bb1.writeString(line2, Common::Point(x2 - 1, _creditLines[idx]._position.y - 1), 0); - bb1.writeString(line2, Common::Point(x2, _creditLines[idx]._position.y - 1), 0); - bb1.writeString(line2, Common::Point(x2 + 1, _creditLines[idx]._position.y - 1), 0); - - bb1.writeString(line2, Common::Point(x2 - 1, _creditLines[idx]._position.y), 0); - bb1.writeString(line2, Common::Point(x2 + 1, _creditLines[idx]._position.y), 0); - - bb1.writeString(line2, Common::Point(x2 - 1, _creditLines[idx]._position.y + 1), 0); - bb1.writeString(line2, Common::Point(x2, _creditLines[idx]._position.y + 1), 0); - bb1.writeString(line2, Common::Point(x2 + 1, _creditLines[idx]._position.y + 1), 0); - - bb1.writeString(line2, Common::Point(x2, _creditLines[idx]._position.y), INFO_TOP); - } else { - bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x - 1, _creditLines[idx]._position.y - 1), 0); - bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1), 0); - bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x + 1, _creditLines[idx]._position.y - 1), 0); - - bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x - 1, _creditLines[idx]._position.y), 0); - bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x + 1, _creditLines[idx]._position.y), 0); - - bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x - 1, _creditLines[idx]._position.y + 1), 0); - bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x, _creditLines[idx]._position.y + 1), 0); - bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x + 1, _creditLines[idx]._position.y + 1), 0); - - bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x, _creditLines[idx]._position.y), INFO_TOP); - } - } - } -} - -void TattooEngine::blitCredits() { - Common::Rect screenRect(0, -_creditSpeed, _screen->w(), _screen->h() + _creditSpeed); - - for (uint idx = 0; idx < _creditLines.size(); ++idx) { - if (screenRect.contains(_creditLines[idx]._position)) { - Common::Rect r(_creditLines[idx]._width, _screen->fontHeight() + 2); - r.moveTo(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1); - - _screen->slamRect(r); - } - - _creditLines[idx]._position.y -= _creditSpeed; - } -} - -void TattooEngine::eraseCredits() { - Common::Rect screenRect(0, -_creditSpeed, _screen->w(), _screen->h() + _creditSpeed); - - for (uint idx = 0; idx < _creditLines.size(); ++idx) { - if (screenRect.contains(_creditLines[idx]._position)) { - Common::Rect r(_creditLines[idx]._width, _screen->fontHeight() + 3); - r.moveTo(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1 + _creditSpeed); - - _screen->restoreBackground(r); - } - } - - if (_creditLines[_creditLines.size() - 1]._position.y < -_creditSpeed) { - _creditLines.clear(); - _creditsActive = false; - setFlags(!3000); - } -} - void TattooEngine::doHangManPuzzle() { - char answers[3][10]; - Common::Point lines[3]; - const char *solutions[3]; - int numWide, spacing; - ImageFile *paper; - Common::Point cursorPos; - byte cursorColor = 254; - bool solved = false; - bool done = false; - bool flag = false; - size_t i = 0; - - switch (getLanguage()) { - case Common::FR_FRA: - lines[0] = Common::Point(34, 210); - lines[1] = Common::Point(72, 242); - lines[2] = Common::Point(34, 276); - numWide = 8; - spacing = 19; - paper = new ImageFile("paperf.vgs"); - break; - - case Common::DE_DEU: - lines[0] = Common::Point(44, 73); - lines[1] = Common::Point(56, 169); - lines[2] = Common::Point(47, 256); - numWide = 7; - spacing = 19; - paper = new ImageFile("paperg.vgs"); - break; - - default: - // English - lines[0] = Common::Point(65, 84); - lines[1] = Common::Point(65, 159); - lines[2] = Common::Point(75, 234); - numWide = 5; - spacing = 20; - paper = new ImageFile("paper.vgs"); - break; - } - - ImageFrame &paperFrame = (*paper)[0]; - Common::Rect paperBounds(paperFrame._width, paperFrame._height); - paperBounds.moveTo((_screen->w() - paperFrame._width) / 2, (_screen->h() - paperFrame._height) / 2); - - for (int line = 0; line<3; ++line) { - lines[line].x += paperBounds.left; - lines[line].y += paperBounds.top; - - for (i = 0; i <= (size_t)numWide; ++i) - answers[line][i] = 0; - } - - _screen->_backBuffer1.blitFrom(paperFrame, Common::Point(paperBounds.left + _screen->_currentScroll.x, 0)); - - // If they have already solved the puzzle, put the answer on the graphic - if (readFlags(299)) { - for (int line = 0; line < 3; ++line) { - cursorPos.y = lines[line].y - _screen->fontHeight() - 2; - - for (i = 0; i < strlen(solutions[line]); ++i) { - cursorPos.x = lines[line].x + 8 - _screen->widestChar() / 2 + i * spacing; - _screen->gPrint(Common::Point(cursorPos.x + _screen->widestChar() / 2 - - _screen->charWidth(solutions[line][i]) / 2, cursorPos.y), 0, "%c", solutions[line][i]); - } - } - } - - _screen->slamRect(paperBounds); - cursorPos = Common::Point(lines[0].x + 8 - _screen->widestChar() / 2, lines[0].y - _screen->fontHeight() - 2); - int line = 0; - - // If they have not solved the puzzle, let them solve it here - if (!readFlags(299)) { - do { - while (!_events->kbHit()) { - // See if a key or a mouse button is pressed - _events->pollEventsAndWait(); - _events->setButtonState(); - - flag = !flag; - if (flag) { - _screen->_backBuffer1.fillRect(Common::Rect(cursorPos.x + _screen->_currentScroll.x, cursorPos.y, - cursorPos.x + _screen->widestChar() + _screen->_currentScroll.x - 1, cursorPos.y + _screen->fontHeight() - 1), cursorColor); - if (answers[line][i]) - _screen->gPrint(Common::Point(cursorPos.x + _screen->widestChar() / 2 - _screen->charWidth(answers[line][i]) / 2, - cursorPos.y), 0, "%c", answers[line][i]); - _screen->slamArea(cursorPos.x, cursorPos.y, _screen->widestChar(), _screen->fontHeight()); - } else { - _screen->setDisplayBounds(Common::Rect(cursorPos.x + _screen->_currentScroll.x, cursorPos.y, - cursorPos.x + _screen->widestChar() + _screen->_currentScroll.x, cursorPos.y + _screen->fontHeight())); - _screen->_backBuffer->blitFrom(paperFrame, Common::Point(paperBounds.left + _screen->_currentScroll.x, paperBounds.top)); - _screen->resetDisplayBounds(); - - if (answers[line][i]) - _screen->gPrint(Common::Point(cursorPos.x + _screen->widestChar() / 2 - _screen->charWidth(answers[line][i]) / 2, - cursorPos.y), 0, "%c", answers[line][i]); - _screen->slamArea(cursorPos.x, cursorPos.y, _screen->widestChar(), _screen->fontHeight()); - } - - if (!_events->kbHit()) - _events->wait(2); - } - - if (_events->kbHit()) { - Common::KeyState keyState = _events->getKey(); - - if (((toupper(keyState.ascii) >= 'A') && (toupper(keyState.ascii) <= 'Z')) || - ((keyState.ascii >= 128) && ((keyState.ascii <= 168) || (keyState.ascii == 225)))) { - answers[line][i] = keyState.ascii; - keyState.keycode = Common::KEYCODE_RIGHT; - } - - _screen->setDisplayBounds(Common::Rect(cursorPos.x + _screen->_currentScroll.x, cursorPos.y, - cursorPos.x + _screen->widestChar() + _screen->_currentScroll.x, cursorPos.y + _screen->fontHeight())); - _screen->_backBuffer->blitFrom(paperFrame, Common::Point(paperBounds.left + _screen->_currentScroll.x, paperBounds.top)); - _screen->resetDisplayBounds(); - - if (answers[line][i]) - _screen->gPrint(Common::Point(cursorPos.x + _screen->widestChar() / 2 - _screen->charWidth(answers[line][i]) / 2, - cursorPos.y), 0, "%c", answers[line][i]); - _screen->slamArea(cursorPos.x, cursorPos.y, _screen->widestChar(), _screen->fontHeight()); - - switch (keyState.keycode) { - case Common::KEYCODE_ESCAPE: - done = true; - break; - - case Common::KEYCODE_UP: - case Common::KEYCODE_KP8: - if (line) { - line--; - if (i >= strlen(solutions[line])) - i = strlen(solutions[line]) - 1; - } - break; - - case Common::KEYCODE_DOWN: - case Common::KEYCODE_KP2: - if (line < 2) { - ++line; - if (i >= strlen(solutions[line])) - i = strlen(solutions[line]) - 1; - } - break; - - case Common::KEYCODE_BACKSPACE: - case Common::KEYCODE_LEFT: - case Common::KEYCODE_KP4: - if (i) - --i; - else if (line) { - --line; - - i = strlen(solutions[line]) - 1; - } - - if (keyState.keycode == Common::KEYCODE_BACKSPACE) - answers[line][i] = ' '; - break; - - case Common::KEYCODE_RIGHT: - case Common::KEYCODE_KP6: - if (i < strlen(solutions[line]) - 1) - i++; - else if (line < 2) { - ++line; - i = 0; - } - break; - - case Common::KEYCODE_DELETE: - answers[line][i] = ' '; - break; - - default: - break; - } - } - - cursorPos.x = lines[line].x + 8 - _screen->widestChar() / 2 + i * spacing; - cursorPos.y = lines[line].y - _screen->fontHeight() - 2; - - // See if all of their anwers are correct - if (!scumm_stricmp(answers[0], solutions[0]) && !scumm_stricmp(answers[1], solutions[1]) && - !scumm_stricmp(answers[2], solutions[2])) { - done = true; - solved = true; - } - } while (!done && !shouldQuit()); - } else { - // They have already solved the puzzle, so just display the solution and wait for a mouse or key click - do { - _events->pollEventsAndWait(); - _events->setButtonState(); - - if ((_events->kbHit()) || (_events->_released) || (_events->_rightReleased)) { - done = true; - _events->clearEvents(); - } - } while (!done && !shouldQuit()); - } - - delete paper; - _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(paperBounds.left + _screen->_currentScroll.x, paperBounds.top), - Common::Rect(paperBounds.left + _screen->_currentScroll.x, paperBounds.top, - paperBounds.right + _screen->_currentScroll.x, paperBounds.bottom)); - _scene->doBgAnim(); - - _screen->slamArea(paperBounds.left + _screen->_currentScroll.x, paperBounds.top, - paperBounds.width(), paperBounds.height()); - - // Don't call the talk files if the puzzle has already been solved - if (readFlags(299)) - return; - - // If they solved the puzzle correctly, set the solved flag and run the appropriate talk scripts - if (solved) { - _talk->talkTo("SLVE12S.TLK"); - _talk->talkTo("WATS12X.TLK"); - setFlags(299); - } else { - _talk->talkTo("HOLM12X.TLK"); - } + _hangmanWidget.show(); } } // End of namespace Tattoo diff --git a/engines/sherlock/tattoo/tattoo.h b/engines/sherlock/tattoo/tattoo.h index a9798dce41..774e243733 100644 --- a/engines/sherlock/tattoo/tattoo.h +++ b/engines/sherlock/tattoo/tattoo.h @@ -25,6 +25,7 @@ #include "sherlock/sherlock.h" #include "sherlock/tattoo/tattoo_darts.h" +#include "sherlock/tattoo/widget_hangman.h" namespace Sherlock { @@ -51,21 +52,10 @@ enum { FLAG_ALT_MAP_MUSIC = 525 }; -struct CreditLine { - Common::Point _position; - int _xOffset; - int _width; - Common::String _line, _line2; - - CreditLine(const Common::String &line, const Common::Point &pt, int width) : - _line(line), _position(pt), _width(width), _xOffset(0) {} -}; - class TattooEngine : public SherlockEngine { private: Darts _darts; - Common::Array _creditLines; - int _creditSpeed; + WidgetHangman _hangmanWidget; /** * Loads the initial palette for the game @@ -89,7 +79,6 @@ protected: */ virtual void startScene(); public: - bool _creditsActive; bool _runningProlog; bool _fastMode, _allowFastMode; bool _transparentMenus; @@ -97,26 +86,6 @@ public: TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc); virtual ~TattooEngine(); - /** - * Initialize and load credit data for display - */ - void initCredits(); - - /** - * Draw credits on the screen - */ - void drawCredits(); - - /** - * Blit the drawn credits to the screen - */ - void blitCredits(); - - /** - * Erase any area of the screen covered by credits - */ - void eraseCredits(); - void doHangManPuzzle(); }; diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp index ba462ca255..9b5c5b2156 100644 --- a/engines/sherlock/tattoo/tattoo_scene.cpp +++ b/engines/sherlock/tattoo/tattoo_scene.cpp @@ -350,8 +350,8 @@ void TattooScene::doBgAnim() { ui.drawInterface(); - if (vm._creditsActive) - vm.blitCredits(); + if (ui._creditsWidget.active()) + ui._creditsWidget.blitCredits(); if (!vm._fastMode) events.wait(3); diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp index ae09ba5fc7..731c215a27 100644 --- a/engines/sherlock/tattoo/tattoo_user_interface.cpp +++ b/engines/sherlock/tattoo/tattoo_user_interface.cpp @@ -31,7 +31,7 @@ namespace Tattoo { TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm), _inventoryWidget(vm), _messageWidget(vm), _textWidget(vm), _tooltipWidget(vm), _verbsWidget(vm), - _labWidget(vm) { + _labWidget(vm), _creditsWidget(vm) { Common::fill(&_lookupTable[0], &_lookupTable[PALETTE_COUNT], 0); Common::fill(&_lookupTable1[0], &_lookupTable1[PALETTE_COUNT], 0); _scrollSize = 0; @@ -239,8 +239,8 @@ void TattooUserInterface::handleInput() { _keyState.keycode = Common::KEYCODE_INVALID; // Check for credits starting - if (_vm->readFlags(3000) && !vm._creditsActive) - vm.initCredits(); + if (_vm->readFlags(3000) && !_creditsWidget.active()) + _creditsWidget.initCredits(); // Check the mouse positioning if (events.isCursorVisible()) @@ -294,15 +294,14 @@ void TattooUserInterface::handleInput() { void TattooUserInterface::drawInterface(int bufferNum) { Screen &screen = *_vm->_screen; - TattooEngine &vm = *(TattooEngine *)_vm; // Draw any active on-screen widgets for (Common::List::iterator i = _widgets.begin(); i != _widgets.end(); ++i) (*i)->draw(); // Handle drawing credits - if (vm._creditsActive) - vm.drawCredits(); + if (_creditsWidget.active()) + _creditsWidget.drawCredits(); // Bring the widgets to the screen if (_mask != nullptr) @@ -649,7 +648,6 @@ void TattooUserInterface::setupBGArea(const byte cMap[PALETTE_SIZE]) { } void TattooUserInterface::doBgAnimEraseBackground() { - TattooEngine &vm = *((TattooEngine *)_vm); People &people = *_vm->_people; Scene &scene = *_vm->_scene; Screen &screen = *_vm->_screen; @@ -714,8 +712,8 @@ void TattooUserInterface::doBgAnimEraseBackground() { } // If credits are active, erase the area they cover - if (vm._creditsActive) - vm.eraseCredits(); + if (_creditsWidget.active()) + _creditsWidget.eraseCredits(); } for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { diff --git a/engines/sherlock/tattoo/tattoo_user_interface.h b/engines/sherlock/tattoo/tattoo_user_interface.h index 1cefec688d..b16f91134b 100644 --- a/engines/sherlock/tattoo/tattoo_user_interface.h +++ b/engines/sherlock/tattoo/tattoo_user_interface.h @@ -28,6 +28,7 @@ #include "sherlock/saveload.h" #include "sherlock/screen.h" #include "sherlock/user_interface.h" +#include "sherlock/tattoo/widget_credits.h" #include "sherlock/tattoo/widget_inventory.h" #include "sherlock/tattoo/widget_lab.h" #include "sherlock/tattoo/widget_text.h" @@ -106,10 +107,11 @@ public: Common::Point _maskOffset; int _maskCounter; ImageFile *_interfaceImages; - WidgetText _textWidget; + WidgetCredits _creditsWidget; WidgetLab _labWidget; - WidgetVerbs _verbsWidget; + WidgetText _textWidget; WidgetSceneTooltip _tooltipWidget; + WidgetVerbs _verbsWidget; public: TattooUserInterface(SherlockEngine *vm); virtual ~TattooUserInterface(); diff --git a/engines/sherlock/tattoo/widget_credits.cpp b/engines/sherlock/tattoo/widget_credits.cpp new file mode 100644 index 0000000000..dcb73b5adb --- /dev/null +++ b/engines/sherlock/tattoo/widget_credits.cpp @@ -0,0 +1,210 @@ +/* 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 "sherlock/tattoo/widget_credits.h" +#include "sherlock/tattoo/tattoo.h" + +namespace Sherlock { + +namespace Tattoo { + +WidgetCredits::WidgetCredits(SherlockEngine *vm) : _vm(vm) { + _creditSpeed = 4; + _creditsActive = false; +} + +void WidgetCredits::initCredits() { + Resources &res = *_vm->_res; + Screen &screen = *_vm->_screen; + Common::SeekableReadStream *stream = res.load("credits.txt"); + int spacing = screen.fontHeight() * 2; + int yp = screen.h(); + + _creditsActive = true; + _creditLines.clear(); + + while (stream->pos() < stream->size()) { + Common::String line = stream->readLine(); + + if (line.hasPrefix("Scroll Speed")) { + const char *p = line.c_str() + 12; + while ((*p < '0') || (*p > '9')) + p++; + + _creditSpeed = atoi(p); + } else if (line.hasPrefix("Y Spacing")) { + const char *p = line.c_str() + 12; + while ((*p < '0') || (*p > '9')) + p++; + + spacing = atoi(p) + screen.fontHeight() + 1; + } else { + int width = screen.stringWidth(line) + 2; + + _creditLines.push_back(CreditLine(line, Common::Point((screen.w() - width) / 2 + 1, yp), width)); + yp += spacing; + } + } + + // Post-processing for finding split lines + for (int l = 0; l < (int)_creditLines.size(); ++l) { + CreditLine &cl = _creditLines[l]; + const char *p = strchr(cl._line.c_str(), '-'); + + if (p != nullptr && p[1] == '>') { + cl._line2 = Common::String(p + 3); + cl._line = Common::String(cl._line.c_str(), p); + + int width = cl._width; + int width1 = screen.stringWidth(cl._line); + int width2 = screen.stringWidth(cl._line2); + + int c = 1; + for (int l1 = l + 1; l1 < (int)_creditLines.size(); ++l1) { + if ((p = strchr(_creditLines[l1]._line.c_str(), '-')) != nullptr) { + if (p[1] == '>') { + Common::String line1 = Common::String(_creditLines[l1]._line.c_str(), p); + Common::String line2 = Common::String(p + 3); + + width1 = MAX(width1, screen.stringWidth(line1)); + + if (screen.stringWidth(line2) > width2) + width2 = screen.stringWidth(line2); + ++c; + } else { + break; + } + } else { + break; + } + } + + width = width1 + width2 + screen.widestChar(); + width1 += screen.widestChar(); + + for (int l1 = l; l1 < l + c; ++l1) { + _creditLines[l1]._width = width; + _creditLines[l1]._xOffset = width1; + } + + l += c - 1; + } + } + + delete stream; +} + +void WidgetCredits::drawCredits() { + Screen &screen = *_vm->_screen; + Common::Rect screenRect(0, 0, screen.w(), screen.h()); + Surface &bb1 = screen._backBuffer1; + + for (uint idx = 0; idx < _creditLines.size() && _creditLines[idx]._position.y < screen.h(); ++idx) { + if (screenRect.contains(_creditLines[idx]._position)) { + if (!_creditLines[idx]._line2.empty()) { + int x1 = _creditLines[idx]._position.x; + int x2 = x1 + _creditLines[idx]._xOffset; + const Common::String &line1 = _creditLines[idx]._line; + const Common::String &line2 = _creditLines[idx]._line2; + + bb1.writeString(line1, Common::Point(x1 - 1, _creditLines[idx]._position.y - 1), 0); + bb1.writeString(line1, Common::Point(x1, _creditLines[idx]._position.y - 1), 0); + bb1.writeString(line1, Common::Point(x1 + 1, _creditLines[idx]._position.y - 1), 0); + + bb1.writeString(line1, Common::Point(x1 - 1, _creditLines[idx]._position.y), 0); + bb1.writeString(line1, Common::Point(x1 + 1, _creditLines[idx]._position.y), 0); + + bb1.writeString(line1, Common::Point(x1 - 1, _creditLines[idx]._position.y + 1), 0); + bb1.writeString(line1, Common::Point(x1, _creditLines[idx]._position.y + 1), 0); + bb1.writeString(line1, Common::Point(x1 + 1, _creditLines[idx]._position.y + 1), 0); + + bb1.writeString(line1, Common::Point(x1, _creditLines[idx]._position.y), INFO_TOP); + + bb1.writeString(line2, Common::Point(x2 - 1, _creditLines[idx]._position.y - 1), 0); + bb1.writeString(line2, Common::Point(x2, _creditLines[idx]._position.y - 1), 0); + bb1.writeString(line2, Common::Point(x2 + 1, _creditLines[idx]._position.y - 1), 0); + + bb1.writeString(line2, Common::Point(x2 - 1, _creditLines[idx]._position.y), 0); + bb1.writeString(line2, Common::Point(x2 + 1, _creditLines[idx]._position.y), 0); + + bb1.writeString(line2, Common::Point(x2 - 1, _creditLines[idx]._position.y + 1), 0); + bb1.writeString(line2, Common::Point(x2, _creditLines[idx]._position.y + 1), 0); + bb1.writeString(line2, Common::Point(x2 + 1, _creditLines[idx]._position.y + 1), 0); + + bb1.writeString(line2, Common::Point(x2, _creditLines[idx]._position.y), INFO_TOP); + } else { + bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x - 1, _creditLines[idx]._position.y - 1), 0); + bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1), 0); + bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x + 1, _creditLines[idx]._position.y - 1), 0); + + bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x - 1, _creditLines[idx]._position.y), 0); + bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x + 1, _creditLines[idx]._position.y), 0); + + bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x - 1, _creditLines[idx]._position.y + 1), 0); + bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x, _creditLines[idx]._position.y + 1), 0); + bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x + 1, _creditLines[idx]._position.y + 1), 0); + + bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x, _creditLines[idx]._position.y), INFO_TOP); + } + } + } +} + +void WidgetCredits::blitCredits() { + Screen &screen = *_vm->_screen; + Common::Rect screenRect(0, -_creditSpeed, screen.w(), screen.h() + _creditSpeed); + + for (uint idx = 0; idx < _creditLines.size(); ++idx) { + if (screenRect.contains(_creditLines[idx]._position)) { + Common::Rect r(_creditLines[idx]._width, screen.fontHeight() + 2); + r.moveTo(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1); + + screen.slamRect(r); + } + + _creditLines[idx]._position.y -= _creditSpeed; + } +} + +void WidgetCredits::eraseCredits() { + Screen &screen = *_vm->_screen; + Common::Rect screenRect(0, -_creditSpeed, screen.w(), screen.h() + _creditSpeed); + + for (uint idx = 0; idx < _creditLines.size(); ++idx) { + if (screenRect.contains(_creditLines[idx]._position)) { + Common::Rect r(_creditLines[idx]._width, screen.fontHeight() + 3); + r.moveTo(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1 + _creditSpeed); + + screen.restoreBackground(r); + } + } + + if (_creditLines[_creditLines.size() - 1]._position.y < -_creditSpeed) { + _creditLines.clear(); + _creditsActive = false; + _vm->setFlags(!3000); + } +} + +} // End of namespace Tattoo + +} // End of namespace Sherlock diff --git a/engines/sherlock/tattoo/widget_credits.h b/engines/sherlock/tattoo/widget_credits.h new file mode 100644 index 0000000000..5c0504944e --- /dev/null +++ b/engines/sherlock/tattoo/widget_credits.h @@ -0,0 +1,84 @@ +/* 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. + * + */ + +#ifndef SHERLOCK_TATTOO_CREDITS_H +#define SHERLOCK_TATTOO_CREDITS_H + +#include "common/array.h" +#include "common/rect.h" + +namespace Sherlock { + + class SherlockEngine; + +namespace Tattoo { + +struct CreditLine { + Common::Point _position; + int _xOffset; + int _width; + Common::String _line, _line2; + + CreditLine(const Common::String &line, const Common::Point &pt, int width) : + _line(line), _position(pt), _width(width), _xOffset(0) {} +}; + +class WidgetCredits { +private: + SherlockEngine *_vm; + Common::Array _creditLines; + int _creditSpeed; + bool _creditsActive; +public: + WidgetCredits(SherlockEngine *vm); + + /** + * Returns true if the credits are active + */ + bool active() const { return _creditsActive; } + + /** + * Initialize and load credit data for display + */ + void initCredits(); + + /** + * Draw credits on the screen + */ + void drawCredits(); + + /** + * Blit the drawn credits to the screen + */ + void blitCredits(); + + /** + * Erase any area of the screen covered by credits + */ + void eraseCredits(); +}; + +} // End of namespace Tattoo + +} // End of namespace Sherlock + +#endif diff --git a/engines/sherlock/tattoo/widget_hangman.cpp b/engines/sherlock/tattoo/widget_hangman.cpp new file mode 100644 index 0000000000..84cfb02101 --- /dev/null +++ b/engines/sherlock/tattoo/widget_hangman.cpp @@ -0,0 +1,264 @@ +/* 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 "sherlock/tattoo/widget_hangman.h" +#include "sherlock/tattoo/tattoo.h" + +namespace Sherlock { + +namespace Tattoo { + +void WidgetHangman::show() { + Events &events = *_vm->_events; + Scene &scene = *_vm->_scene; + Screen &screen = *_vm->_screen; + Talk &talk = *_vm->_talk; + char answers[3][10]; + Common::Point lines[3]; + const char *solutions[3]; + int numWide, spacing; + ImageFile *paper; + Common::Point cursorPos; + byte cursorColor = 254; + bool solved = false; + bool done = false; + bool flag = false; + size_t i = 0; + + switch (_vm->getLanguage()) { + case Common::FR_FRA: + lines[0] = Common::Point(34, 210); + lines[1] = Common::Point(72, 242); + lines[2] = Common::Point(34, 276); + numWide = 8; + spacing = 19; + paper = new ImageFile("paperf.vgs"); + break; + + case Common::DE_DEU: + lines[0] = Common::Point(44, 73); + lines[1] = Common::Point(56, 169); + lines[2] = Common::Point(47, 256); + numWide = 7; + spacing = 19; + paper = new ImageFile("paperg.vgs"); + break; + + default: + // English + lines[0] = Common::Point(65, 84); + lines[1] = Common::Point(65, 159); + lines[2] = Common::Point(75, 234); + numWide = 5; + spacing = 20; + paper = new ImageFile("paper.vgs"); + break; + } + + ImageFrame &paperFrame = (*paper)[0]; + Common::Rect paperBounds(paperFrame._width, paperFrame._height); + paperBounds.moveTo((screen.w() - paperFrame._width) / 2, (screen.h() - paperFrame._height) / 2); + + for (int line = 0; line<3; ++line) { + lines[line].x += paperBounds.left; + lines[line].y += paperBounds.top; + + for (i = 0; i <= (size_t)numWide; ++i) + answers[line][i] = 0; + } + + screen._backBuffer1.blitFrom(paperFrame, Common::Point(paperBounds.left + screen._currentScroll.x, 0)); + + // If they have already solved the puzzle, put the answer on the graphic + if (_vm->readFlags(299)) { + for (int line = 0; line < 3; ++line) { + cursorPos.y = lines[line].y - screen.fontHeight() - 2; + + for (i = 0; i < strlen(solutions[line]); ++i) { + cursorPos.x = lines[line].x + 8 - screen.widestChar() / 2 + i * spacing; + screen.gPrint(Common::Point(cursorPos.x + screen.widestChar() / 2 - + screen.charWidth(solutions[line][i]) / 2, cursorPos.y), 0, "%c", solutions[line][i]); + } + } + } + + screen.slamRect(paperBounds); + cursorPos = Common::Point(lines[0].x + 8 - screen.widestChar() / 2, lines[0].y - screen.fontHeight() - 2); + int line = 0; + + // If they have not solved the puzzle, let them solve it here + if (!_vm->readFlags(299)) { + do { + while (!events.kbHit()) { + // See if a key or a mouse button is pressed + events.pollEventsAndWait(); + events.setButtonState(); + + flag = !flag; + if (flag) { + screen._backBuffer1.fillRect(Common::Rect(cursorPos.x + screen._currentScroll.x, cursorPos.y, + cursorPos.x + screen.widestChar() + screen._currentScroll.x - 1, cursorPos.y + screen.fontHeight() - 1), cursorColor); + if (answers[line][i]) + screen.gPrint(Common::Point(cursorPos.x + screen.widestChar() / 2 - screen.charWidth(answers[line][i]) / 2, + cursorPos.y), 0, "%c", answers[line][i]); + screen.slamArea(cursorPos.x, cursorPos.y, screen.widestChar(), screen.fontHeight()); + } else { + screen.setDisplayBounds(Common::Rect(cursorPos.x + screen._currentScroll.x, cursorPos.y, + cursorPos.x + screen.widestChar() + screen._currentScroll.x, cursorPos.y + screen.fontHeight())); + screen._backBuffer->blitFrom(paperFrame, Common::Point(paperBounds.left + screen._currentScroll.x, paperBounds.top)); + screen.resetDisplayBounds(); + + if (answers[line][i]) + screen.gPrint(Common::Point(cursorPos.x + screen.widestChar() / 2 - screen.charWidth(answers[line][i]) / 2, + cursorPos.y), 0, "%c", answers[line][i]); + screen.slamArea(cursorPos.x, cursorPos.y, screen.widestChar(), screen.fontHeight()); + } + + if (!events.kbHit()) + events.wait(2); + } + + if (events.kbHit()) { + Common::KeyState keyState = events.getKey(); + + if (((toupper(keyState.ascii) >= 'A') && (toupper(keyState.ascii) <= 'Z')) || + ((keyState.ascii >= 128) && ((keyState.ascii <= 168) || (keyState.ascii == 225)))) { + answers[line][i] = keyState.ascii; + keyState.keycode = Common::KEYCODE_RIGHT; + } + + screen.setDisplayBounds(Common::Rect(cursorPos.x + screen._currentScroll.x, cursorPos.y, + cursorPos.x + screen.widestChar() + screen._currentScroll.x, cursorPos.y + screen.fontHeight())); + screen._backBuffer->blitFrom(paperFrame, Common::Point(paperBounds.left + screen._currentScroll.x, paperBounds.top)); + screen.resetDisplayBounds(); + + if (answers[line][i]) + screen.gPrint(Common::Point(cursorPos.x + screen.widestChar() / 2 - screen.charWidth(answers[line][i]) / 2, + cursorPos.y), 0, "%c", answers[line][i]); + screen.slamArea(cursorPos.x, cursorPos.y, screen.widestChar(), screen.fontHeight()); + + switch (keyState.keycode) { + case Common::KEYCODE_ESCAPE: + done = true; + break; + + case Common::KEYCODE_UP: + case Common::KEYCODE_KP8: + if (line) { + line--; + if (i >= strlen(solutions[line])) + i = strlen(solutions[line]) - 1; + } + break; + + case Common::KEYCODE_DOWN: + case Common::KEYCODE_KP2: + if (line < 2) { + ++line; + if (i >= strlen(solutions[line])) + i = strlen(solutions[line]) - 1; + } + break; + + case Common::KEYCODE_BACKSPACE: + case Common::KEYCODE_LEFT: + case Common::KEYCODE_KP4: + if (i) + --i; + else if (line) { + --line; + + i = strlen(solutions[line]) - 1; + } + + if (keyState.keycode == Common::KEYCODE_BACKSPACE) + answers[line][i] = ' '; + break; + + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_KP6: + if (i < strlen(solutions[line]) - 1) + i++; + else if (line < 2) { + ++line; + i = 0; + } + break; + + case Common::KEYCODE_DELETE: + answers[line][i] = ' '; + break; + + default: + break; + } + } + + cursorPos.x = lines[line].x + 8 - screen.widestChar() / 2 + i * spacing; + cursorPos.y = lines[line].y - screen.fontHeight() - 2; + + // See if all of their anwers are correct + if (!scumm_stricmp(answers[0], solutions[0]) && !scumm_stricmp(answers[1], solutions[1]) && + !scumm_stricmp(answers[2], solutions[2])) { + done = true; + solved = true; + } + } while (!done && !_vm->shouldQuit()); + } else { + // They have already solved the puzzle, so just display the solution and wait for a mouse or key click + do { + events.pollEventsAndWait(); + events.setButtonState(); + + if ((events.kbHit()) || (events._released) || (events._rightReleased)) { + done = true; + events.clearEvents(); + } + } while (!done && !_vm->shouldQuit()); + } + + delete paper; + screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(paperBounds.left + screen._currentScroll.x, paperBounds.top), + Common::Rect(paperBounds.left + screen._currentScroll.x, paperBounds.top, + paperBounds.right + screen._currentScroll.x, paperBounds.bottom)); + scene.doBgAnim(); + + screen.slamArea(paperBounds.left + screen._currentScroll.x, paperBounds.top, + paperBounds.width(), paperBounds.height()); + + // Don't call the talk files if the puzzle has already been solved + if (_vm->readFlags(299)) + return; + + // If they solved the puzzle correctly, set the solved flag and run the appropriate talk scripts + if (solved) { + talk.talkTo("SLVE12S.TLK"); + talk.talkTo("WATS12X.TLK"); + _vm->setFlags(299); + } else { + talk.talkTo("HOLM12X.TLK"); + } +} + +} // End of namespace Tattoo + +} // End of namespace Sherlock diff --git a/engines/sherlock/tattoo/widget_hangman.h b/engines/sherlock/tattoo/widget_hangman.h new file mode 100644 index 0000000000..daa598720a --- /dev/null +++ b/engines/sherlock/tattoo/widget_hangman.h @@ -0,0 +1,48 @@ +/* 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. + * + */ + +#ifndef SHERLOCK_TATTOO_HANGMAN_H +#define SHERLOCK_TATTOO_HANGMAN_H + +namespace Sherlock { + +namespace Tattoo { + +class TattooEngine; + +class WidgetHangman { +private: + TattooEngine *_vm; +public: + WidgetHangman(TattooEngine *vm) : _vm(vm) {} + + /** + * Show the hangman puzzle + */ + void show(); +}; + +} // End of namespace Tattoo + +} // End of namespace Sherlock + +#endif -- cgit v1.2.3