diff options
Diffstat (limited to 'engines/sherlock/tattoo/widget_verbs.cpp')
-rw-r--r-- | engines/sherlock/tattoo/widget_verbs.cpp | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/engines/sherlock/tattoo/widget_verbs.cpp b/engines/sherlock/tattoo/widget_verbs.cpp new file mode 100644 index 0000000000..3cdd1247c1 --- /dev/null +++ b/engines/sherlock/tattoo/widget_verbs.cpp @@ -0,0 +1,311 @@ +/* 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]; + TattooPerson &npc = people[ui._activeObj - 1001]; + + if (!scumm_strnicmp(npc._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) { + if (!ui._bgShape->_use[idx]._verb.empty() && !ui._bgShape->_use[idx]._verb.hasPrefix(" ") && + (ui._bgShape->_use[idx]._target.empty() || ui._bgShape->_use[idx]._target.hasPrefix(" "))) { + _verbCommands.push_back(ui._bgShape->_use[idx]._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.fill(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.transBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1) - 1)); + _surface.transBlitFrom(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(); + bool noDesc = false; + + 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]; + + 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 { + // Free the current menu graphics & erase the menu + banishWindow(); + + // See if we're in a Lab Table Room + ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE; + } + } + } else if (_bounds.contains(mousePos) && _selector != -1) { + // Mouse is within the menu + // Erase the menu + banishWindow(); + + // 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.talk(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 |