322 lines
9.2 KiB
C++
322 lines
9.2 KiB
C++
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "sherlock/tattoo/widget_foolscap.h"
|
|
#include "sherlock/tattoo/tattoo_fixed_text.h"
|
|
#include "sherlock/tattoo/tattoo_scene.h"
|
|
#include "sherlock/tattoo/tattoo_user_interface.h"
|
|
#include "sherlock/tattoo/tattoo.h"
|
|
|
|
#include "backends/keymapper/keymapper.h"
|
|
|
|
namespace Sherlock {
|
|
|
|
namespace Tattoo {
|
|
|
|
WidgetFoolscap::WidgetFoolscap(TattooEngine *vm) : WidgetBase(vm) {
|
|
for (int idx = 0; idx < 3; ++idx) {
|
|
Common::fill(&_answers[idx][0], &_answers[idx][10], 0);
|
|
_solutions[idx] = nullptr;
|
|
}
|
|
_images = nullptr;
|
|
_numWide = 0;
|
|
_spacing = 0;
|
|
_blinkFlag = false;
|
|
_blinkCounter = 0;
|
|
_lineNum = _charNum = 0;
|
|
_solved = false;
|
|
}
|
|
|
|
WidgetFoolscap::~WidgetFoolscap() {
|
|
delete _images;
|
|
}
|
|
|
|
void WidgetFoolscap::show() {
|
|
Screen &screen = *_vm->_screen;
|
|
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
|
|
|
|
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;
|
|
_images = 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;
|
|
_images = 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;
|
|
_images = new ImageFile("paper.vgs");
|
|
break;
|
|
}
|
|
|
|
_solved = false;
|
|
_blinkFlag = false;
|
|
_blinkCounter = 0;
|
|
_lineNum = _charNum = 0;
|
|
_cursorPos = Common::Point(_lines[0].x + 8 - screen.widestChar() / 2, _lines[0].y - screen.fontHeight() - 2);
|
|
|
|
// Set up window bounds
|
|
ImageFrame &paperFrame = (*_images)[0];
|
|
_bounds = Common::Rect(paperFrame._width, paperFrame._height);
|
|
_bounds.moveTo(screen._currentScroll.x + (SHERLOCK_SCREEN_WIDTH - paperFrame._width) / 2,
|
|
(SHERLOCK_SCREEN_HEIGHT - paperFrame._height) / 2);
|
|
|
|
// Clear answer data and set correct solution strings
|
|
for (int idx = 0; idx < 3; ++idx)
|
|
Common::fill(&_answers[idx][0], &_answers[idx][10], 0);
|
|
_solutions[0] = FIXED(Apply);
|
|
_solutions[1] = FIXED(Water);
|
|
_solutions[2] = FIXED(Heat);
|
|
|
|
// Set up the window background
|
|
_surface.create(_bounds.width(), _bounds.height());
|
|
_surface.SHblitFrom(paperFrame, Common::Point(0, 0));
|
|
|
|
// If they have already solved the puzzle, put the answer on the graphic
|
|
if (_vm->readFlags(299)) {
|
|
Common::Point cursorPos;
|
|
for (int line = 0; line < 3; ++line) {
|
|
cursorPos.y = _lines[line].y - screen.fontHeight() - 2;
|
|
|
|
for (uint idx = 0; idx < strlen(_solutions[line]); ++idx) {
|
|
cursorPos.x = _lines[line].x + 8 - screen.widestChar() / 2 + idx * _spacing;
|
|
char c = _solutions[line][idx];
|
|
|
|
Common::String str = Common::String::format("%c", c);
|
|
_surface.writeString(str, Common::Point(cursorPos.x + screen.widestChar() / 2
|
|
- screen.charWidth(c) / 2, cursorPos.y), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Show the window
|
|
summonWindow();
|
|
ui._menuMode = FOOLSCAP_MODE;
|
|
|
|
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
|
keymapper->getKeymap("tattoo")->setEnabled(false);
|
|
keymapper->getKeymap("tattoo-foolscap")->setEnabled(true);
|
|
}
|
|
|
|
void WidgetFoolscap::handleEvents() {
|
|
Events &events = *_vm->_events;
|
|
Screen &screen = *_vm->_screen;
|
|
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
|
|
Common::Point mousePos = events.mousePos();
|
|
byte cursorColor = 254;
|
|
|
|
if (events._firstPress && !_bounds.contains(mousePos))
|
|
_outsideMenu = true;
|
|
|
|
// If they have not solved the puzzle, let them solve it here
|
|
if (!_vm->readFlags(299)) {
|
|
if (!ui._keyState.keycode && !ui._action) {
|
|
if (--_blinkCounter < 0) {
|
|
_blinkCounter = 3;
|
|
_blinkFlag = !_blinkFlag;
|
|
|
|
if (_blinkFlag) {
|
|
// Draw the caret
|
|
_surface.fillRect(Common::Rect(_cursorPos.x, _cursorPos.y, _cursorPos.x + screen.widestChar() - 1,
|
|
_cursorPos.y + screen.fontHeight() - 1), cursorColor);
|
|
|
|
if (_answers[_lineNum][_charNum]) {
|
|
Common::String str = Common::String::format("%c", _answers[_lineNum][_charNum]);
|
|
_surface.writeString(str, Common::Point(_cursorPos.x + screen.widestChar() / 2
|
|
- screen.charWidth(_answers[_lineNum][_charNum]) / 2, _cursorPos.y), 0);
|
|
}
|
|
} else {
|
|
// Restore background
|
|
restoreChar();
|
|
|
|
// Draw the character at that position if there is one
|
|
if (_answers[_lineNum][_charNum]) {
|
|
Common::String str = Common::String::format("%c", _answers[_lineNum][_charNum]);
|
|
_surface.writeString(str, Common::Point(_cursorPos.x + screen.widestChar() / 2
|
|
- screen.charWidth(_answers[_lineNum][_charNum]) / 2, _cursorPos.y), 0);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// Handle keyboard and action events
|
|
handleKeyboardEvents();
|
|
}
|
|
}
|
|
|
|
if ((events._released || events._rightReleased) && _outsideMenu && !_bounds.contains(mousePos)) {
|
|
// Clicked outside window to close it
|
|
events.clearEvents();
|
|
close();
|
|
}
|
|
}
|
|
|
|
void WidgetFoolscap::handleKeyboardEvents() {
|
|
Screen &screen = *_vm->_screen;
|
|
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
|
|
Common::KeyState keyState = ui._keyState;
|
|
Common::CustomEventType action = ui._action;
|
|
|
|
if ((toupper(keyState.ascii) >= 'A') && (toupper(keyState.ascii) <= 'Z')) {
|
|
// Visible key pressed, set it and set the keycode to move the caret to the right
|
|
_answers[_lineNum][_charNum] = keyState.ascii;
|
|
action = kActionTattooFoolscapRight;
|
|
}
|
|
|
|
// Restore background
|
|
restoreChar();
|
|
|
|
if (_answers[_lineNum][_charNum]) {
|
|
Common::String str = Common::String::format("%c", _answers[_lineNum][_charNum]);
|
|
_surface.writeString(str, Common::Point(_cursorPos.x + screen.widestChar() / 2
|
|
- screen.charWidth(_answers[_lineNum][_charNum]) / 2, _cursorPos.y), 0);
|
|
}
|
|
|
|
switch (keyState.keycode) {
|
|
case Common::KEYCODE_BACKSPACE:
|
|
if (_charNum)
|
|
--_charNum;
|
|
else if (_lineNum) {
|
|
--_lineNum;
|
|
|
|
_charNum = strlen(_solutions[_lineNum]) - 1;
|
|
}
|
|
|
|
_answers[_lineNum][_charNum] = ' ';
|
|
break;
|
|
|
|
case Common::KEYCODE_DELETE:
|
|
_answers[_lineNum][_charNum] = ' ';
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (action) {
|
|
case kActionTattooFoolscapExit:
|
|
close();
|
|
break;
|
|
|
|
case kActionTattooFoolscapUp:
|
|
if (_lineNum) {
|
|
--_lineNum;
|
|
if (_charNum >= (int)strlen(_solutions[_lineNum]))
|
|
_charNum = (int)strlen(_solutions[_lineNum]) - 1;
|
|
}
|
|
break;
|
|
|
|
case kActionTattooFoolscapDown:
|
|
if (_lineNum < 2) {
|
|
++_lineNum;
|
|
if (_charNum >= (int)strlen(_solutions[_lineNum]))
|
|
_charNum = (int)strlen(_solutions[_lineNum]) - 1;
|
|
}
|
|
break;
|
|
|
|
case kActionTattooFoolscapLeft:
|
|
if (_charNum)
|
|
--_charNum;
|
|
else if (_lineNum) {
|
|
--_lineNum;
|
|
|
|
_charNum = strlen(_solutions[_lineNum]) - 1;
|
|
}
|
|
break;
|
|
|
|
case kActionTattooFoolscapRight:
|
|
if (_charNum < (int)strlen(_solutions[_lineNum]) - 1)
|
|
++_charNum;
|
|
else if (_lineNum < 2) {
|
|
++_lineNum;
|
|
_charNum = 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
_cursorPos.x = _lines[_lineNum].x + 8 - screen.widestChar() / 2 + _charNum * _spacing;
|
|
_cursorPos.y = _lines[_lineNum].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])) {
|
|
_solved = true;
|
|
close();
|
|
}
|
|
}
|
|
|
|
void WidgetFoolscap::restoreChar() {
|
|
Screen &screen = *_vm->_screen;
|
|
ImageFrame &bgFrame = (*_images)[0];
|
|
_surface.SHblitFrom(bgFrame, _cursorPos, Common::Rect(_cursorPos.x, _cursorPos.y,
|
|
_cursorPos.x + screen.widestChar(), _cursorPos.y + screen.fontHeight()));
|
|
}
|
|
|
|
void WidgetFoolscap::close() {
|
|
TattooScene &scene = *(TattooScene *)_vm->_scene;
|
|
Talk &talk = *_vm->_talk;
|
|
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
|
|
delete _images;
|
|
_images = nullptr;
|
|
|
|
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
|
keymapper->getKeymap("tattoo-foolscap")->setEnabled(false);
|
|
keymapper->getKeymap("tattoo")->setEnabled(true);
|
|
|
|
// Close the window
|
|
banishWindow();
|
|
ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
|
|
|
|
// Don't call the talk files if the puzzle has already been solved
|
|
if (!_vm->readFlags(299)) {
|
|
// Run the appropriate script depending on whether or not they solved the puzzle correctly
|
|
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
|