scummvm/engines/mads/action.cpp

624 lines
17 KiB
C++
Raw Normal View History

2014-03-03 00:29:54 +00:00
/* 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 "common/scummsys.h"
#include "mads/mads.h"
2014-03-03 00:29:54 +00:00
#include "mads/action.h"
#include "mads/inventory.h"
2014-03-03 00:29:54 +00:00
#include "mads/scene.h"
#include "mads/staticres.h"
2014-03-03 00:29:54 +00:00
namespace MADS {
MADSAction::MADSAction(MADSEngine *vm) : _vm(vm) {
2014-03-03 00:29:54 +00:00
clear();
_currentAction = VERB_NONE;
_startWalkFlag = false;
_statusTextIndex = -1;
_selectedAction = 0;
_inProgress = false;
_savedFields._actionMode = ABORTMODE_0;
_savedFields._actionMode2 = ABORTMODE_0;
_savedFields._selectedRow = -1;
_savedFields._hotspotId = 0;
_savedFields._v86F3A = 0;
_savedFields._v86F42 = 0;
_savedFields._articleNumber = 0;
_savedFields._lookFlag = false;
2014-03-03 00:29:54 +00:00
}
void MADSAction::clear() {
2014-03-03 00:29:54 +00:00
_v83338 = 1;
_actionMode = ACTIONMODE_NONE;
_actionMode2 = ACTIONMODE2_0;
2014-03-03 00:29:54 +00:00
_v86F42 = 0;
_v86F4E = 0;
_articleNumber = 0;
_lookFlag = false;
_v86F4A = 0;
_selectedRow = -1;
_hotspotId = -1;
_v86F3A = -1;
_v86F4C = -1;
2014-03-03 05:42:41 +00:00
_action._verbId = -1;
_action._objectNameId = -1;
_action._indirectObjectId = -1;
2014-03-03 00:29:54 +00:00
_textChanged = true;
_walkFlag = false;
}
void MADSAction::appendVocab(int vocabId, bool capitalise) {
Common::String vocabStr = _vm->_game->_scene.getVocab(vocabId);
2014-03-03 00:29:54 +00:00
if (capitalise)
vocabStr.setChar(toupper(vocabStr[0]), 0);
2014-03-03 00:29:54 +00:00
_statusText += vocabStr;
_statusText += " ";
2014-03-03 00:29:54 +00:00
}
void MADSAction::checkCustomDest(int v) {
Scene &scene = _vm->_game->_scene;
if (_v86F4A && (v == -3 || _savedFields._selectedRow < 0)) {
_startWalkFlag = true;
scene._destPos = scene._customDest;
}
}
void MADSAction::set() {
Scene &scene = _vm->_game->_scene;
UserInterface &userInterface = scene._userInterface;
bool flag = false;
_statusText = "";
2014-03-03 00:29:54 +00:00
_action._verbId = -1;
_action._objectNameId = -1;
_action._indirectObjectId = -1;
2014-03-03 00:29:54 +00:00
if (_actionMode == ACTIONMODE_TALK) {
2014-03-03 00:29:54 +00:00
// Handle showing the conversation selection. Rex at least doesn't actually seem to use this
if (_selectedRow >= 0) {
Common::String desc = userInterface._talkStrings[userInterface._talkIds[_selectedRow]];
if (!desc.empty())
_statusText = desc;
2014-03-03 00:29:54 +00:00
}
} else if (_lookFlag && (_selectedRow == 0)) {
// Two 'look' actions in succession, so the action becomes 'Look around'
_statusText = kLookAroundStr;
2014-03-03 00:29:54 +00:00
} else {
if ((_actionMode == ACTIONMODE_OBJECT) && (_selectedRow >= 0) && (_flags1 == 2) && (_flags2 == 0)) {
2014-03-03 00:29:54 +00:00
// Use/to action
int invIndex = userInterface._selectedInvIndex;
InventoryObject &objEntry = _vm->_game->_objects.getItem(invIndex);
2014-03-03 00:29:54 +00:00
_action._objectNameId = objEntry._descId;
_action._verbId = objEntry._vocabList[_selectedRow]._vocabId;
2014-03-03 00:29:54 +00:00
// Set up the status text stirng
_statusText = kUseStr;
appendVocab(_action._objectNameId);
_statusText += kToStr;
appendVocab(_action._verbId);
2014-03-03 00:29:54 +00:00
} else {
// Handling for if an action has been selected
if (_selectedRow >= 0) {
if (_actionMode == ACTIONMODE_VERB) {
2014-03-03 00:29:54 +00:00
// Standard verb action
_currentAction = scene._verbList[_selectedRow]._id;
2014-03-03 00:29:54 +00:00
} else {
// Selected action on an inventory object
int invIndex = userInterface._selectedInvIndex;
InventoryObject &objEntry = _vm->_game->_objects.getItem(invIndex);
2014-03-03 00:29:54 +00:00
_currentAction = objEntry._vocabList[_selectedRow]._vocabId;
2014-03-03 00:29:54 +00:00
}
appendVocab(_action._verbId, true);
2014-03-03 00:29:54 +00:00
if (_currentAction == VERB_LOOK) {
2014-03-03 00:29:54 +00:00
// Add in the word 'add'
_statusText += kAtStr;
_statusText += " ";
2014-03-03 00:29:54 +00:00
}
}
// Handling for if a hotspot has been selected/highlighted
if ((_hotspotId >= 0) && (_selectedRow >= 0) && (_articleNumber > 0) && (_flags1 == 2)) {
flag = true;
_statusText += kArticleList[_articleNumber];
_statusText += " ";
2014-03-03 00:29:54 +00:00
}
if (_hotspotId >= 0) {
if (_selectedRow < 0) {
int verbId;
if (_hotspotId < (int)scene._hotspots.size()) {
2014-03-03 00:29:54 +00:00
// Get the verb Id from the hotspot
verbId = scene._hotspots[_hotspotId]._verbId;
2014-03-03 00:29:54 +00:00
} else {
// Get the verb Id from the scene object
verbId = scene._dynamicHotspots[_hotspotId - scene._hotspots.size()]._vocabId;
2014-03-03 00:29:54 +00:00
}
if (verbId > 0) {
// Set the specified action
_currentAction = verbId;
appendVocab(_currentAction, true);
} else {
// Default to a standard 'walk to'
_currentAction = VERB_WALKTO;
_statusText += kWalkToStr;
2014-03-03 00:29:54 +00:00
}
}
if ((_actionMode2 == ACTIONMODE2_2) || (_actionMode2 == ACTIONMODE2_5)) {
2014-03-03 00:29:54 +00:00
// Get name from given inventory object
InventoryObject &invObject = _vm->_game->_objects.getItem(_hotspotId);
_action._objectNameId = invObject._descId;
} else if (_hotspotId < (int)scene._hotspots.size()) {
2014-03-03 00:29:54 +00:00
// Get name from scene hotspot
_action._objectNameId = scene._hotspots[_hotspotId]._vocabId;
2014-03-03 00:29:54 +00:00
} else {
// Get name from temporary scene hotspot
_action._objectNameId = scene._dynamicHotspots[_hotspotId - scene._hotspots.size()]._vocabId;
2014-03-03 00:29:54 +00:00
}
appendVocab(_action._objectNameId);
2014-03-03 00:29:54 +00:00
}
}
if ((_hotspotId >= 0) && (_articleNumber > 0) && !flag) {
if (_articleNumber == -1) {
if (_v86F3A >= 0) {
int articleNum = 0;
if ((_v86F42 == 2) || (_v86F42 == 5)) {
InventoryObject &invObject = _vm->_game->_objects.getItem(_hotspotId);
articleNum = invObject._article;
} else if (_v86F3A < (int)scene._hotspots.size()) {
articleNum = scene._hotspots[_hotspotId]._articleNumber;
2014-03-03 00:29:54 +00:00
} else {
articleNum = scene._hotspots[_hotspotId - scene._hotspots.size()]._articleNumber;
2014-03-03 00:29:54 +00:00
}
_statusText += kArticleList[articleNum];
_statusText += " ";
}
} else if ((_articleNumber == VERB_LOOK) || (_vm->getGameID() != GType_RexNebular) ||
(scene._vocabStrings[_action._indirectObjectId] != kFenceStr)) {
2014-03-03 00:29:54 +00:00
// Write out the article
_statusText += kArticleList[_articleNumber];
2014-03-03 00:29:54 +00:00
} else {
// Special case for a 'fence' entry in Rex Nebular
_statusText += kOverStr;
2014-03-03 00:29:54 +00:00
}
_statusText += " ";
2014-03-03 00:29:54 +00:00
}
// Append object description if necessary
if (_v86F3A >= 0)
appendVocab(_action._indirectObjectId);
2014-03-03 00:29:54 +00:00
// Remove any trailing space character
if (_statusText.hasSuffix(" "))
_statusText.deleteLastChar();
2014-03-03 00:29:54 +00:00
}
_textChanged = true;
}
void MADSAction::refresh() {
Scene &scene = _vm->_game->_scene;
2014-03-03 00:29:54 +00:00
// Exit immediately if nothing has changed
if (!_textChanged)
return;
// Remove any old copy of the status text
if (_statusTextIndex >= 0) {
scene._textDisplay.expire(_statusTextIndex);
2014-03-03 00:29:54 +00:00
_statusTextIndex = -1;
}
if (!_statusText.empty()) {
if ((_vm->_game->_screenObjects._v832EC == 0) || (_vm->_game->_screenObjects._v832EC == 2)) {
Font *font = _vm->_font->getFont(FONT_MAIN);
2014-03-03 00:29:54 +00:00
int textSpacing = -1;
int strWidth = font->getWidth(_statusText);
if (strWidth > MADS_SCREEN_WIDTH) {
2014-03-03 00:29:54 +00:00
// Too large to fit, so fall back on interface font
font = _vm->_font->getFont(FONT_INTERFACE);
2014-03-03 00:29:54 +00:00
strWidth = font->getWidth(_statusText, 0);
textSpacing = 0;
}
// Add a new text display entry to display the status text at the bottom of the screen area
_statusTextIndex = scene._textDisplay.add(160 - (strWidth / 2),
MADS_SCENE_HEIGHT + scene._posAdjust.y - 13, 3, textSpacing, _statusText, font);
2014-03-03 00:29:54 +00:00
}
}
_textChanged = false;
}
void MADSAction::startAction() {
Game &game = *_vm->_game;
Scene &scene = _vm->_game->_scene;
DynamicHotspots &dynHotspots = scene._dynamicHotspots;
Hotspots &hotspots = scene._hotspots;
game._player.moveComplete();
2014-03-03 00:29:54 +00:00
_inProgress = true;
_v8453A = ABORTMODE_0;
_savedFields._selectedRow = _selectedRow;
_savedFields._hotspotId = _hotspotId;
_savedFields._v86F3A = _v86F3A;
_savedFields._articleNumber = _articleNumber;
_savedFields._actionMode = _actionMode;
_savedFields._actionMode2 = _actionMode2;
_savedFields._v86F42 = _v86F42;
_savedFields._lookFlag = _lookFlag;
_activeAction = _action;
2014-03-03 00:29:54 +00:00
// Copy the action to be active
_activeAction = _action;
_dialogTitle = _statusText;
2014-03-03 00:29:54 +00:00
if ((_actionMode2 == ACTIONMODE2_4) && (_v86F42 == 0))
_v8453A = -1;
2014-03-03 00:29:54 +00:00
_startWalkFlag = false;
int hotspotId = -1;
if (!_savedFields._lookFlag && (_vm->_game->_screenObjects._v832EC != 1)) {
if (_savedFields._actionMode2 == ACTIONMODE2_4)
hotspotId = _savedFields._hotspotId;
else if (_v86F42 == 4)
hotspotId = _savedFields._v86F3A;
2014-03-03 00:29:54 +00:00
if (hotspotId >= (int)hotspots.size()) {
DynamicHotspot &hs = dynHotspots[hotspotId - hotspots.size()];
if ((hs._feetPos.x == -1) || (hs._feetPos.x == -3)) {
checkCustomDest(hs._feetPos.x);
} else if (hs._feetPos.x == 0) {
scene._targetFacing = hs._facing;
} else if (_savedFields._actionMode == ACTIONMODE_NONE || hs._cursor >= CURSOR_WAIT) {
2014-03-03 00:29:54 +00:00
_startWalkFlag = true;
scene._destPos = hs._feetPos;
2014-03-03 00:29:54 +00:00
}
scene._targetFacing = hs._facing;
2014-03-03 00:29:54 +00:00
hotspotId = -1;
}
}
if (hotspotId >= 0 && hotspotId < (int)hotspots.size()) {
Hotspot &hs = hotspots[hotspotId];
if (hs._feetPos.x == -1 || hs._feetPos.x != -3) {
checkCustomDest(hs._feetPos.x);
} else if (hs._feetPos.x >= 0) {
if (_savedFields._actionMode == ACTIONMODE_NONE || hs._cursor < CURSOR_WAIT) {
2014-03-03 00:29:54 +00:00
_startWalkFlag = true;
scene._destPos = hs._feetPos;
2014-03-03 00:29:54 +00:00
}
}
scene._targetFacing = hs._facing;
2014-03-03 00:29:54 +00:00
}
_walkFlag = _startWalkFlag;
}
void MADSAction::checkAction() {
if (isAction(VERB_LOOK) || isAction(VERB_THROW))
2014-03-03 00:29:54 +00:00
_startWalkFlag = 0;
}
bool MADSAction::isAction(int verbId, int objectNameId, int indirectObjectId) {
if (_activeAction._verbId != verbId)
2014-03-03 00:29:54 +00:00
return false;
if ((objectNameId != 0) && (_activeAction._objectNameId != objectNameId))
2014-03-03 00:29:54 +00:00
return false;
if ((indirectObjectId != 0) && (_activeAction._indirectObjectId != indirectObjectId))
2014-03-03 00:29:54 +00:00
return false;
2014-03-03 00:29:54 +00:00
return true;
}
void MADSAction::checkActionAtMousePos() {
Scene &scene = _vm->_game->_scene;
UserInterface &userInterface = scene._userInterface;
ScreenObjects &screenObjects = _vm->_game->_screenObjects;
if ((userInterface._category == CAT_ACTION || userInterface._category == CAT_INV_VOCAB) &&
_v83338 != 1 && scene._highlightedHotspot >= 0) {
if (_v86F4E == userInterface._category || _v86F4C != scene._highlightedHotspot ||
(_v83338 != 2 && _v83338 != 3))
clear();
else if (_selectedRow != 0 || userInterface._category != CAT_ACTION)
scene._lookFlag = false;
else
scene._lookFlag = true;
}
if (screenObjects._v7FECA && _vm->_events->_mouseButtons) {
switch (userInterface._category) {
case CAT_ACTION:
case CAT_INV_VOCAB:
return;
case CAT_INV_LIST:
case CAT_TALK_ENTRY:
if (_v83338 != 3) {
if (userInterface._selectedActionIndex >= 0) {
_actionMode = ACTIONMODE_VERB;
_selectedRow = userInterface._selectedActionIndex;
_flags1 = scene._verbList[_selectedRow]._action1;
_flags2 = scene._verbList[_selectedRow]._action2;
_v83338 = 2;
} else if (userInterface._selectedItemVocabIdx >= 0) {
_actionMode = ACTIONMODE_OBJECT;
_selectedRow = userInterface._selectedItemVocabIdx;
int objectId = _vm->_game->_objects._inventoryList[_selectedRow];
InventoryObject &invObject = _vm->_game->_objects[objectId];
_flags1 = invObject._vocabList[_selectedRow - 1]._actionFlags1;
_flags2 = invObject._vocabList[_selectedRow - 1]._actionFlags2;
_actionMode2 = ACTIONMODE2_2;
_hotspotId = userInterface._selectedInvIndex;
_articleNumber = _flags2;
if ((_flags1 == 1 && _flags2 == 0) || (_flags1 == 2 && _flags2 != 0))
_v83338 = 4;
else
_v83338 = 3;
}
}
break;
}
}
switch (_v83338) {
case 1:
_articleNumber = 0;
switch (userInterface._category) {
case CAT_ACTION:
_actionMode = ACTIONMODE_VERB;
_selectedRow = scene._highlightedHotspot;
if (_selectedRow >= 0) {
_flags1 = scene._verbList[_selectedRow]._action1;
_flags2 = scene._verbList[_selectedRow]._action2;
}
break;
case CAT_INV_VOCAB:
_actionMode = ACTIONMODE_OBJECT;
_selectedRow = scene._highlightedHotspot;
if (_selectedRow < 0) {
_hotspotId = -1;
_actionMode2 = ACTIONMODE2_0;
} else {
int objectId = _vm->_game->_objects._inventoryList[_selectedRow];
InventoryObject &invObject = _vm->_game->_objects[objectId];
_flags1 = invObject._vocabList[_selectedRow - 2]._actionFlags1;
_flags2 = invObject._vocabList[_selectedRow - 2]._actionFlags2;
_hotspotId = userInterface._selectedInvIndex;
_actionMode2 = ACTIONMODE2_2;
if (_flags1 == 2)
_articleNumber = _flags2;
}
break;
case CAT_HOTSPOT:
_selectedRow = -1;
_actionMode = ACTIONMODE_NONE;
_actionMode2 = ACTIONMODE2_4;
_hotspotId = scene._highlightedHotspot;
break;
case CAT_TALK_ENTRY:
_actionMode = ACTIONMODE_TALK;
_selectedRow = scene._highlightedHotspot;
break;
default:
break;
}
break;
case 2:
_articleNumber = 0;
switch (userInterface._category) {
case CAT_INV_LIST:
case CAT_HOTSPOT:
case CAT_INV_ANIM:
// TODO: We may not need a separate ActionMode2 enum
_actionMode2 = (ActionMode2)userInterface._category;
_hotspotId = scene._highlightedHotspot;
break;
default:
break;
}
break;
case 3:
switch (userInterface._category) {
case CAT_INV_LIST:
case CAT_HOTSPOT:
case CAT_INV_ANIM:
_v86F42 = userInterface._category;
_v86F3A = scene._highlightedHotspot;
break;
default:
break;
}
break;
default:
break;
}
}
void MADSAction::leftClick() {
Scene &scene = _vm->_game->_scene;
UserInterface &userInterface = scene._userInterface;
ScreenObjects &screenObjects = _vm->_game->_screenObjects;
bool abortFlag = false;
if ((userInterface._category == CAT_ACTION || userInterface._category == CAT_INV_VOCAB) &&
_v83338 != 1 && scene._highlightedHotspot >= 0 &&
_v86F4E == userInterface._category && _v86F4C == scene._highlightedHotspot &&
(_v83338 == 2 || userInterface._category == CAT_INV_VOCAB)) {
abortFlag = true;
if (_selectedRow == 0 && userInterface._category == CAT_ACTION) {
_selectedAction = CAT_ACTION;
scene._lookFlag = true;
} else {
_selectedAction = CAT_NONE;
scene._lookFlag = false;
clear();
}
}
if (abortFlag || (screenObjects._v7FECA && (userInterface._category == CAT_ACTION ||
userInterface._category == CAT_INV_VOCAB)))
return;
switch (_v83338) {
case 1:
switch (userInterface._category) {
case CAT_ACTION:
if (_selectedRow >= 0) {
if (!_flags1) {
_selectedAction = -1;
}
else {
_v86F4C = _selectedRow;
_v86F4E = _actionMode;
_v83338 = 2;
}
}
break;
case CAT_INV_LIST:
if (scene._highlightedHotspot >= 0) {
userInterface.selectObject(scene._highlightedHotspot);
}
break;
case CAT_INV_VOCAB:
if (_selectedRow >= 0) {
if (_flags1 != 1 || _flags2 != 0) {
if (_flags1 != 2 || _flags2 == 0) {
_v83338 = 3;
_articleNumber = _flags2;
}
else {
_articleNumber = _flags2;
_selectedAction = -1;
}
}
else {
_selectedAction = -1;
}
_v86F4C = _selectedRow;
_v86F4E = _actionMode;
}
break;
case CAT_HOTSPOT:
_v86F4C = -1;
_v86F4E = 0;
if (_vm->_events->currentPos().y < MADS_SCENE_HEIGHT)
scene._customDest = _vm->_events->currentPos() + scene._posAdjust;
break;
case CAT_TALK_ENTRY:
if (_selectedRow >= 0)
_selectedAction = -1;
break;
default:
break;
}
break;
case 2:
switch (userInterface._category) {
case CAT_INV_LIST:
case CAT_HOTSPOT:
case CAT_INV_ANIM:
if (_hotspotId >= 0) {
if (_flags2) {
_articleNumber = _flags2;
_v83338 = 3;
}
else {
_selectedAction = -1;
}
if (userInterface._category == CAT_HOTSPOT) {
scene._customDest = _vm->_events->mousePos() + scene._posAdjust;
_v86F4A = true;
}
}
break;
default:
break;
}
break;
case 3:
switch (userInterface._category) {
case CAT_INV_LIST:
case CAT_HOTSPOT:
case CAT_INV_ANIM:
if (_v86F3A >= 0) {
_selectedAction = -1;
if (userInterface._category == CAT_HOTSPOT) {
if (!_v86F4A) {
scene._customDest = _vm->_events->mousePos() + scene._posAdjust;
_v86F4A = true;
}
}
}
break;
default:
break;
}
break;
}
}
2014-03-03 00:29:54 +00:00
} // End of namespace MADS