diff options
Diffstat (limited to 'engines/tsage/converse.cpp')
-rw-r--r-- | engines/tsage/converse.cpp | 257 |
1 files changed, 196 insertions, 61 deletions
diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp index de5ac62425..d1faca5dac 100644 --- a/engines/tsage/converse.cpp +++ b/engines/tsage/converse.cpp @@ -8,12 +8,12 @@ * 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 + * 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. @@ -416,7 +416,7 @@ SequenceManager *SequenceManager::globalManager() { ConversationChoiceDialog::ConversationChoiceDialog() { _stdColor = 23; _highlightColor = g_globals->_scenePalette._colors.background; - _fontNumber = 1; + _fontNumber = (g_vm->getGameID() == GType_Ringworld2) ? 3 : 1; _savedFgColor = _savedFontNumber = 0; _selectedIndex = 0; } @@ -424,15 +424,15 @@ ConversationChoiceDialog::ConversationChoiceDialog() { int ConversationChoiceDialog::execute(const Common::StringArray &choiceList) { _gfxManager._font.setFontNumber(_fontNumber); - _bounds = Rect(20, 0, 20, 0); + _bounds = Rect(40, 0, 40, 0); _choiceList.clear(); // Set up the list of choices int yp = 0; for (uint idx = 0; idx < choiceList.size(); ++idx) { Rect tempRect; - _gfxManager._font.getStringBounds(choiceList[idx].c_str(), tempRect, 265); - tempRect.moveTo(25, yp + 10); + _gfxManager._font.getStringBounds(choiceList[idx].c_str(), tempRect, textMaxWidth()); + tempRect.moveTo(textLeft(), yp + 10); _choiceList.push_back(ChoiceEntry(choiceList[idx], tempRect)); yp += tempRect.height() + 5; @@ -444,12 +444,25 @@ int ConversationChoiceDialog::execute(const Common::StringArray &choiceList) { _bounds.bottom -= 10; yp = 180 - _bounds.height(); _bounds.translate(0, yp); - _bounds.right = _bounds.left + 280; + _bounds.setWidth(textMaxWidth() + 15); + _bounds.moveTo(160 - (_bounds.width() / 2), _bounds.top); // Draw the dialog draw(); + g_globals->_events.showCursor(); + // Force the display of an arrow cursor during discussions in R2R + if (g_vm->getGameID() == GType_Ringworld2) + R2_GLOBALS._events.setCursor(CURSOR_ARROW); + + // WORKAROUND: On-screen dialogs are really meant to use a GfxManager instance + // for their lifetime, which prevents saving or loading. Since I don't want to spend a lot + // of time refactoring this already working dialog, fake it by putting a dummy gfxmanager at + // the end of the gfx manager list so as to prevent saving or loading + GfxManager gfxManager; + GLOBALS._gfxManagers.push_back(&gfxManager); + // Event handling loop Event event; while (!g_vm->shouldQuit()) { @@ -501,6 +514,7 @@ int ConversationChoiceDialog::execute(const Common::StringArray &choiceList) { // Remove the dialog remove(); + GLOBALS._gfxManagers.remove(&gfxManager); return _selectedIndex; } @@ -513,6 +527,7 @@ void ConversationChoiceDialog::draw() { // Fill in the contents of the entire dialog _gfxManager._bounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + drawFrame(); _gfxManager._bounds = tempRect; @@ -524,7 +539,7 @@ void ConversationChoiceDialog::draw() { Common::String strNum = Common::String::format("%d", idx + 1); // Write the choice number - _gfxManager._font.setPosition(13, _choiceList[idx]._bounds.top); + _gfxManager._font.setPosition(numberLeft(), _choiceList[idx]._bounds.top); _gfxManager._font.writeString(strNum.c_str()); _gfxManager._font.writeLines(_choiceList[idx]._msg.c_str(), _choiceList[idx]._bounds, ALIGN_LEFT); @@ -533,6 +548,18 @@ void ConversationChoiceDialog::draw() { _gfxManager.deactivate(); } +int ConversationChoiceDialog::textLeft() const { + return (g_vm->getGameID() == GType_Ringworld2) ? 20 : 25; +} + +int ConversationChoiceDialog::textMaxWidth() const { + return (g_vm->getGameID() == GType_Ringworld2) ? 250 : 265; +} + +int ConversationChoiceDialog::numberLeft() const { + return (g_vm->getGameID() == GType_Ringworld2) ? 8 : 13; +} + /*--------------------------------------------------------------------------*/ void Obj44::load(const byte *dataP) { @@ -542,8 +569,8 @@ void Obj44::load(const byte *dataP) { _mode = s.readSint16LE(); _lookupValue = s.readSint16LE(); _lookupIndex = s.readSint16LE(); - _field6 = s.readSint16LE(); - _field8 = s.readSint16LE(); + _exitMode = s.readSint16LE(); + _speakerMode = s.readSint16LE(); } _id = s.readSint16LE(); @@ -551,8 +578,8 @@ void Obj44::load(const byte *dataP) { _callbackId[idx] = s.readSint16LE(); if (g_vm->getGameID() == GType_Ringworld2) { - _field16 = s.readSint16LE(); - s.skip(20); + for (int i = 0; i < 11; ++i) + _field16[i] = s.readSint16LE(); } else { s.skip(4); } @@ -578,9 +605,11 @@ void Obj44::synchronize(Serializer &s) { s.syncAsSint16LE(_mode); s.syncAsSint16LE(_lookupValue); s.syncAsSint16LE(_lookupIndex); - s.syncAsSint16LE(_field6); - s.syncAsSint16LE(_field8); - s.syncAsSint16LE(_field16); + s.syncAsSint16LE(_exitMode); + s.syncAsSint16LE(_speakerMode); + + for (int i = 0; i < 11; ++i) + s.syncAsSint16LE(_field16[i]); } } @@ -624,14 +653,15 @@ void StripManager::reset() { _delayFrames = 0; _owner = NULL; _endHandler = NULL; - _field2E6 = false; + _uselessFl = false; _stripNum = -1; - _obj44Index = 0; - _field2E8 = 0; - _field20 = 0; + _obj44ListIndex = 0; + _currObj44Id = 0; + _useless = 0; _activeSpeaker = NULL; _textShown = false; _callbackObject = NULL; + _exitMode = 0; _obj44List.clear(); if (!_script.empty()) { @@ -671,14 +701,16 @@ void StripManager::synchronize(Serializer &s) { Action::synchronize(s); s.syncAsSint32LE(_stripNum); - s.syncAsSint32LE(_obj44Index); - s.syncAsSint32LE(_field20); + s.syncAsSint32LE(_obj44ListIndex); + s.syncAsSint32LE(_useless); s.syncAsSint32LE(_sceneNumber); _sceneBounds.synchronize(s); SYNC_POINTER(_activeSpeaker); s.syncAsByte(_textShown); - s.syncAsByte(_field2E6); - s.syncAsSint32LE(_field2E8); + s.syncAsByte(_uselessFl); + s.syncAsSint32LE(_currObj44Id); + if (g_vm->getGameID() == GType_Ringworld2) + s.syncAsSint16LE(_exitMode); // Synchronize the item list int arrSize = _obj44List.size(); @@ -688,7 +720,7 @@ void StripManager::synchronize(Serializer &s) { for (int i = 0; i < arrSize; ++i) _obj44List[i].synchronize(s); - // Synhcronise script data + // Synchronize script data int scriptSize = _script.size(); s.syncAsUint16LE(scriptSize); if (s.isLoading()) @@ -708,14 +740,24 @@ void StripManager::synchronize(Serializer &s) { } void StripManager::remove() { + if (g_vm->getGameID() == GType_Ringworld2) { + for (uint i = 0; i < _speakerList.size(); ++i) { + if (_activeSpeaker != _speakerList[i]) + _speakerList[i]->stopSpeaking(); + } + } + if (_textShown) { if (_activeSpeaker) _activeSpeaker->removeText(); _textShown = false; } - if (_activeSpeaker) + if (_activeSpeaker) { + if (g_vm->getGameID() == GType_Ringworld2) + static_cast<Ringworld2::VisualSpeaker *>(_activeSpeaker)->_speakerMode = 0xff; _activeSpeaker->remove(); + } if (_sceneNumber != g_globals->_sceneManager._scene->_screenNumber) { g_globals->_sceneManager._scene->_sceneBounds = _sceneBounds; @@ -725,23 +767,37 @@ void StripManager::remove() { if (_onEnd) _onEnd(); + if (g_vm->getGameID() == GType_Ringworld2) + _endHandler = NULL; + Action::remove(); } +void StripManager::dispatch() { + if (g_vm->getGameID() == GType_Ringworld2) { + if (_activeSpeaker) + _activeSpeaker->dispatch(); + } + + Action::dispatch(); +} + void StripManager::signal() { + int strIndex = 0; + if (_textShown) { _activeSpeaker->removeText(); _textShown = false; } - if (_obj44Index < 0) { + if (_obj44ListIndex < 0) { EventHandler *owner = _endHandler; - int stripNum = ABS(_obj44Index); + int stripNum = ABS(_obj44ListIndex); remove(); start(stripNum, owner); return; - } else if (_obj44Index == 10000) { + } else if (_obj44ListIndex == 10000) { // Reached end of strip EventHandler *endHandler = _endHandler; remove(); @@ -758,14 +814,12 @@ void StripManager::signal() { // Load the data for the strip load(); - Obj44 &obj44 = _obj44List[_obj44Index]; + Obj44 &obj44 = _obj44List[_obj44ListIndex]; - if (g_vm->getGameID() != GType_Ringworld2) { - _field2E8 = obj44._id; - } else { + if (g_vm->getGameID() == GType_Ringworld2) { // Return to Ringworld specific handling - if (obj44._field6) - _field2E8 = obj44._field6; + if (obj44._exitMode) + _exitMode = obj44._exitMode; switch (obj44._mode) { case 1: @@ -782,39 +836,101 @@ void StripManager::signal() { } } + _currObj44Id = obj44._id; Common::StringArray choiceList; // Build up a list of script entries int idx; + bool delayFlag = false; - if (g_vm->getGameID() == GType_Ringworld2 && obj44._field16) { + if ((g_vm->getGameID() == GType_Ringworld2) && obj44._field16[0]) { // Special loading mode used in Return to Ringworld for (idx = 0; idx < OBJ44_LIST_SIZE; ++idx) { - int objIndex = _lookupList[obj44._field16 - 1]; - - if (!obj44._list[objIndex]._id) + int f16Index = _lookupList[obj44._field16[0] - 1]; + int entryId = obj44._field16[f16Index]; + + Obj0A &entry = obj44._list[idx]; + if (entry._id == entryId) { + // Get the next one + choiceList.push_back((const char *)&_script[0] + entry._scriptOffset); + strIndex = idx; + delayFlag = true; break; + } + } - // Get the next one - choiceList.push_back((const char *)&_script[0] + obj44._list[objIndex]._scriptOffset); + // If no entry found, get the default response + if (!delayFlag) { + idx = 0; + while (obj44._list[idx + 1]._id) + ++idx; + + choiceList.push_back((const char *)&_script[0] + obj44._list[idx]._scriptOffset); + strIndex = idx; + delayFlag = true; } } else { // Standard choices loading - for (idx = 0; idx < OBJ44_LIST_SIZE; ++idx) { + for (idx = 0; idx < OBJ0A_LIST_SIZE; ++idx) { if (!obj44._list[idx]._id) break; // Get the next one - choiceList.push_back((const char *)&_script[0] + obj44._list[idx]._scriptOffset); + const char *choiceStr = (const char *)&_script[0] + obj44._list[idx]._scriptOffset; + + if (!*choiceStr) { + // Choice is empty + assert(g_vm->getGameID() == GType_Ringworld2); + + if (obj44._list[1]._id) { + // it's a reference to another list slot + int listId = obj44._list[idx]._id; + + int obj44Idx = 0; + while (_obj44List[obj44Idx]._id != listId) + ++obj44Idx; + + if (_obj44List[obj44Idx]._field16[0]) { + // WORKAROUND: The _lookupList isn't always correctly initialized. But it always + // seems to be set to the R2_GLOBALS._stripManager_lookupList, so manually set it + if (!_lookupList) + _lookupList = R2_GLOBALS._stripManager_lookupList; + + int f16Index = _lookupList[_obj44List[obj44Idx]._field16[0] - 1]; + listId = _obj44List[obj44Idx]._field16[f16Index]; + + if (_lookupList[_obj44List[obj44Idx]._field16[0] - 1]) { + int listIdx = 0; + while (_obj44List[obj44Idx]._list[listIdx]._id != listId) + ++listIdx; + + choiceStr = (const char *)&_script[0] + _obj44List[obj44Idx]._list[listIdx]._scriptOffset; + } else { + for (int listIdx = idx; listIdx < (OBJ0A_LIST_SIZE - 1); ++listIdx) { + obj44._list[listIdx]._id = obj44._list[listIdx + 1]._id; + obj44._list[listIdx]._scriptOffset = obj44._list[listIdx + 1]._scriptOffset; + + if (!obj44._list[listIdx + 1]._id) + obj44._list[listIdx]._id = 0; + } + + --idx; + continue; + } + } + } + } + + // Add entry to the list + choiceList.push_back(choiceStr); } } - int strIndex = 0; if (choiceList.size() > 1) // Get the user to select a conversation option strIndex = _choiceDialog.execute(choiceList); - if ((choiceList.size() != 1) && !_field2E6) + if ((delayFlag || choiceList.size() != 1) && !_uselessFl) _delayFrames = 1; else { Speaker *speakerP = getSpeaker((const char *)&_script[0] + obj44._speakerOffset); @@ -831,7 +947,7 @@ void StripManager::signal() { g_globals->_sceneManager._scene->loadScene(_sceneNumber); } - _activeSpeaker->proc12(this); + _activeSpeaker->startSpeaking(this); } if (_callbackObject) { @@ -843,17 +959,34 @@ void StripManager::signal() { } } - if ((g_vm->getGameID() == GType_Ringworld2) && (_obj44List.size() > 0)) - static_cast<Ringworld2::VisualSpeaker *>(_activeSpeaker)->proc15(); + if (g_vm->getGameID() == GType_Ringworld2) { + Ringworld2::VisualSpeaker *speaker = static_cast<Ringworld2::VisualSpeaker *>(_activeSpeaker); - _textShown = true; - _activeSpeaker->setText(choiceList[strIndex]); + if (speaker) { + speaker->_speakerMode = obj44._speakerMode; + if (!choiceList[strIndex].empty()) + speaker->animateSpeaker(); + } + + if (!choiceList[strIndex].empty()) { + _textShown = true; + _activeSpeaker->setText(choiceList[strIndex]); + } else if (!obj44._speakerMode) { + _delayFrames = 1; + } else { + _delayFrames = 0; + speaker->animateSpeaker(); + } + } else { + _textShown = true; + _activeSpeaker->setText(choiceList[strIndex]); + } } - _obj44Index = getNewIndex(obj44._list[strIndex]._id); - if (_obj44Index == 10001) { + _obj44ListIndex = getNewIndex(obj44._list[strIndex]._id); + if (_obj44ListIndex == 10001) { MessageDialog::show("Strip Failure: Node not found", OK_BTN_STRING); - _obj44Index = 0; + _obj44ListIndex = 0; } } @@ -863,16 +996,16 @@ void StripManager::process(Event &event) { return; if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) { - if (_obj44Index != 10000) { - int currIndex = _obj44Index; - while (!_obj44List[_obj44Index]._list[1]._id) { - _obj44Index = getNewIndex(_obj44List[_obj44Index]._list[0]._id); - if ((_obj44Index < 0) || (_obj44Index == 10000)) + if (_obj44ListIndex != 10000) { + int currIndex = _obj44ListIndex; + while (!_obj44List[_obj44ListIndex]._list[1]._id) { + _obj44ListIndex = getNewIndex(_obj44List[_obj44ListIndex]._list[0]._id); + if ((_obj44ListIndex < 0) || (_obj44ListIndex == 10000)) break; - currIndex = _obj44Index; + currIndex = _obj44ListIndex; } - _field2E8 = _obj44List[currIndex]._id; + _currObj44Id = _obj44List[currIndex]._id; } // Signal the end of the strip @@ -915,6 +1048,8 @@ Speaker *StripManager::getSpeaker(const char *speakerName) { int StripManager::getNewIndex(int id) { if (id == 10000) return id; + if ((g_vm->getGameID() == GType_Ringworld2) && (id < 0)) + return id; for (uint idx = 0; idx < _obj44List.size(); ++idx) { if (_obj44List[idx]._id == id) { @@ -966,7 +1101,7 @@ void Speaker::remove() { SceneObjectList::deactivate(); } -void Speaker::proc12(Action *action) { +void Speaker::startSpeaking(Action *action) { _action = action; if (_newSceneNumber != -1) { _oldSceneNumber = g_globals->_sceneManager._sceneNumber; |