Files
scummvm-cursorfix/engines/sherlock/tattoo/widget_foolscap.cpp
2026-02-02 04:50:13 +01:00

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