mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 06:08:35 +00:00
314 lines
10 KiB
C++
314 lines
10 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 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_verbs.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_people.h"
|
|
#include "sherlock/tattoo/tattoo.h"
|
|
|
|
namespace Sherlock {
|
|
|
|
namespace Tattoo {
|
|
|
|
WidgetVerbs::WidgetVerbs(SherlockEngine *vm) : WidgetBase(vm) {
|
|
_selector = _oldSelector = -1;
|
|
_outsideMenu = false;
|
|
}
|
|
|
|
void WidgetVerbs::load(bool objectsOn) {
|
|
Events &events = *_vm->_events;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
Talk &talk = *_vm->_talk;
|
|
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
|
|
Common::Point mousePos = events.mousePos();
|
|
bool isWatson = false;
|
|
|
|
if (talk._talkToAbort)
|
|
return;
|
|
|
|
ui._activeObj = ui._bgFound;
|
|
_outsideMenu = false;
|
|
_verbCommands.clear();
|
|
_selector = _oldSelector = -1;
|
|
|
|
// Check if we need to show options for the highlighted object
|
|
if (objectsOn) {
|
|
// Set the verb list accordingly, depending on the target being a
|
|
// person or an object
|
|
if (ui._personFound) {
|
|
TattooPerson &person = people[ui._activeObj - 1000];
|
|
|
|
if (!scumm_strnicmp(person._npcName.c_str(), "WATS", 4))
|
|
isWatson = true;
|
|
|
|
|
|
if (scumm_strnicmp(person._examine.c_str(), "_EXIT", 5))
|
|
_verbCommands.push_back(FIXED(Look));
|
|
|
|
_verbCommands.push_back(FIXED(Talk));
|
|
|
|
// Add any extra active verbs from the NPC's verb list
|
|
for (int idx = 0; idx < 2; ++idx) {
|
|
if (!person._use[idx]._verb.empty() && !person._use[idx]._verb.hasPrefix(" ") &&
|
|
(person._use[idx]._target.empty() || person._use[idx]._target.hasPrefix(" "))) {
|
|
_verbCommands.push_back(person._use[idx]._verb);
|
|
}
|
|
}
|
|
} else {
|
|
if (!scumm_strnicmp(ui._bgShape->_name.c_str(), "WATS", 4))
|
|
// Looking at Watson
|
|
isWatson = true;
|
|
|
|
if (scumm_strnicmp(ui._bgShape->_examine.c_str(), "_EXIT", 5))
|
|
// It's not an exit, so include Look as an option
|
|
_verbCommands.push_back(FIXED(Look));
|
|
|
|
if (ui._bgShape->_aType == PERSON)
|
|
_verbCommands.push_back(FIXED(Talk));
|
|
|
|
// Add any extra active verbs from the object's verb list
|
|
for (int idx = 0; idx < 6; ++idx) {
|
|
UseType &use = ui._bgShape->_use[idx];
|
|
if (!use._verb.empty() && !use._verb.hasPrefix(" ") && !use._verb.hasPrefix("*") &&
|
|
(use._target.empty() || use._target.hasPrefix("*") || use._target.hasPrefix(" "))) {
|
|
_verbCommands.push_back(use._verb);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If clicked on Watson, have Journal as an option
|
|
if (isWatson)
|
|
_verbCommands.push_back(FIXED(Journal));
|
|
|
|
// Add the system commands
|
|
_verbCommands.push_back(FIXED(Inventory));
|
|
_verbCommands.push_back(FIXED(Options));
|
|
|
|
// Figure out the needed width to show the commands
|
|
int width = 0;
|
|
for (uint idx = 0; idx < _verbCommands.size(); ++idx)
|
|
width = MAX(width, _surface.stringWidth(_verbCommands[idx]));
|
|
width += _surface.widestChar() * 2 + 6;
|
|
int height = (_surface.fontHeight() + 7) * _verbCommands.size() + 3;
|
|
|
|
// Set the bounds
|
|
_bounds = Common::Rect(width, height);
|
|
_bounds.moveTo(mousePos.x - _bounds.width() / 2, mousePos.y - _bounds.height() / 2);
|
|
|
|
// Render the window on the internal surface
|
|
render();
|
|
}
|
|
|
|
void WidgetVerbs::render() {
|
|
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
|
|
ImageFile &images = *ui._interfaceImages;
|
|
|
|
// Create the drawing surface
|
|
_surface.create(_bounds.width(), _bounds.height());
|
|
_surface.clear(TRANSPARENCY);
|
|
|
|
// Draw basic background
|
|
makeInfoArea();
|
|
|
|
// Draw the verb commands and the lines separating them
|
|
for (uint idx = 0; idx < _verbCommands.size(); ++idx) {
|
|
_surface.writeString(_verbCommands[idx], Common::Point((_bounds.width() - _surface.stringWidth(_verbCommands[idx])) / 2,
|
|
(_surface.fontHeight() + 7) * idx + 5), INFO_TOP);
|
|
|
|
if (idx < (_verbCommands.size() - 1)) {
|
|
_surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1), _bounds.width() - 4, INFO_TOP);
|
|
_surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 1, _bounds.width() - 4, INFO_MIDDLE);
|
|
_surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 2, _bounds.width() - 4, INFO_BOTTOM);
|
|
|
|
_surface.SHtransBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1) - 1));
|
|
_surface.SHtransBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width,
|
|
(_surface.fontHeight() + 7) * (idx + 1) - 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
void WidgetVerbs::handleEvents() {
|
|
Events &events = *_vm->_events;
|
|
FixedText &fixedText = *_vm->_fixedText;
|
|
People &people = *_vm->_people;
|
|
TattooScene &scene = *(TattooScene *)_vm->_scene;
|
|
Talk &talk = *_vm->_talk;
|
|
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
|
|
Common::Point mousePos = events.mousePos();
|
|
|
|
Common::String strLook = fixedText.getText(kFixedText_Look);
|
|
Common::String strTalk = fixedText.getText(kFixedText_Talk);
|
|
Common::String strJournal = fixedText.getText(kFixedText_Journal);
|
|
|
|
checkTabbingKeys(_verbCommands.size());
|
|
|
|
// Highlight verb display as necessary
|
|
highlightVerbControls();
|
|
|
|
// Flag if the user has started pressing the button with the cursor outsie the menu
|
|
if (events._firstPress && !_bounds.contains(mousePos))
|
|
_outsideMenu = true;
|
|
|
|
// See if they released the mouse button
|
|
if (events._released || events._rightReleased) {
|
|
// See if they want to close the menu (they clicked outside of the menu)
|
|
if (!_bounds.contains(mousePos)) {
|
|
if (_outsideMenu) {
|
|
if (events._rightReleased) {
|
|
// Change to the item (if any) that was right-clicked on, and re-draw the verb menu
|
|
ui._bgFound = scene.findBgShape(mousePos);
|
|
ui._personFound = ui._bgFound >= 1000;
|
|
ui._bgShape = ui._personFound || ui._bgFound == -1 ? nullptr : &scene._bgShapes[ui._bgFound];
|
|
|
|
bool noDesc = false;
|
|
if (ui._personFound) {
|
|
if (people[ui._bgFound - 1000]._description.empty() || people[ui._bgFound - 1000]._description.hasPrefix(" "))
|
|
noDesc = true;
|
|
} else if (ui._bgFound != -1) {
|
|
if (ui._bgShape->_description.empty() || ui._bgShape->_description.hasPrefix(" "))
|
|
noDesc = true;
|
|
} else {
|
|
noDesc = true;
|
|
}
|
|
|
|
// Call the Routine to turn on the Commands for this Object
|
|
load(!noDesc);
|
|
} else {
|
|
// Close the window and clear the events
|
|
banishWindow();
|
|
events.clearEvents();
|
|
|
|
// Reset the active UI mode
|
|
ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
|
|
}
|
|
}
|
|
} else if (_bounds.contains(mousePos) && _selector != -1) {
|
|
// Mouse is within the menu
|
|
// Erase the menu
|
|
banishWindow();
|
|
events.clearEvents();
|
|
|
|
// See if they are activating the Look Command
|
|
if (!_verbCommands[_selector].compareToIgnoreCase(strLook)) {
|
|
ui._bgFound = ui._activeObj;
|
|
if (ui._activeObj >= 1000) {
|
|
ui._personFound = true;
|
|
} else {
|
|
ui._personFound = false;
|
|
ui._bgShape = &scene._bgShapes[ui._activeObj];
|
|
}
|
|
|
|
ui.lookAtObject();
|
|
|
|
} else if (!_verbCommands[_selector].compareToIgnoreCase(strTalk)) {
|
|
// Talk command is being activated
|
|
talk.initTalk(ui._activeObj);
|
|
ui._activeObj = -1;
|
|
|
|
} else if (!_verbCommands[_selector].compareToIgnoreCase(strJournal)) {
|
|
ui.doJournal();
|
|
|
|
// See if we're in a Lab Table scene
|
|
ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
|
|
} else if (_selector >= ((int)_verbCommands.size() - 2)) {
|
|
switch (_selector - (int)_verbCommands.size() + 2) {
|
|
case 0:
|
|
// Inventory
|
|
ui.doInventory(2);
|
|
break;
|
|
|
|
case 1:
|
|
// Options
|
|
ui.doControls();
|
|
break;
|
|
|
|
default:
|
|
ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
|
|
break;
|
|
}
|
|
} else {
|
|
// If they have selected anything else, process it
|
|
people[HOLMES].gotoStand();
|
|
|
|
if (ui._activeObj < 1000) {
|
|
for (int idx = 0; idx < 6; ++idx) {
|
|
if (!_verbCommands[_selector].compareToIgnoreCase(scene._bgShapes[ui._activeObj]._use[idx]._verb)) {
|
|
// See if they are Picking this object up
|
|
if (!scene._bgShapes[ui._activeObj]._use[idx]._target.compareToIgnoreCase("*PICKUP"))
|
|
ui.pickUpObject(ui._activeObj);
|
|
else
|
|
ui.checkAction(scene._bgShapes[ui._activeObj]._use[idx], ui._activeObj);
|
|
}
|
|
}
|
|
} else {
|
|
for (int idx = 0; idx < 2; ++idx) {
|
|
if (!_verbCommands[_selector].compareToIgnoreCase(people[ui._activeObj - 1000]._use[idx]._verb))
|
|
ui.checkAction(people[ui._activeObj - 1000]._use[idx], ui._activeObj);
|
|
}
|
|
}
|
|
|
|
ui._activeObj = -1;
|
|
if (ui._menuMode != MESSAGE_MODE) {
|
|
// See if we're in a Lab Table Room
|
|
ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
|
|
}
|
|
}
|
|
}
|
|
} else if (ui._keyState.keycode == Common::KEYCODE_ESCAPE) {
|
|
// User closing the menu with the ESC key
|
|
banishWindow();
|
|
ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
|
|
}
|
|
}
|
|
|
|
void WidgetVerbs::highlightVerbControls() {
|
|
Events &events = *_vm->_events;
|
|
Screen &screen = *_vm->_screen;
|
|
Common::Point mousePos = events.mousePos();
|
|
|
|
// Get highlighted verb
|
|
_selector = -1;
|
|
Common::Rect bounds = _bounds;
|
|
bounds.grow(-3);
|
|
if (bounds.contains(mousePos))
|
|
_selector = (mousePos.y - bounds.top) / (screen.fontHeight() + 7);
|
|
|
|
// See if a new verb is being pointed at
|
|
if (_selector != _oldSelector) {
|
|
// Redraw the verb list
|
|
for (int idx = 0; idx < (int)_verbCommands.size(); ++idx) {
|
|
byte color = (idx == _selector) ? (byte)COMMAND_HIGHLIGHTED : (byte)INFO_TOP;
|
|
_surface.writeString(_verbCommands[idx], Common::Point((_bounds.width() - screen.stringWidth(_verbCommands[idx])) / 2,
|
|
(screen.fontHeight() + 7) * idx + 5), color);
|
|
}
|
|
|
|
_oldSelector = _selector;
|
|
}
|
|
}
|
|
|
|
} // End of namespace Tattoo
|
|
|
|
} // End of namespace Sherlock
|