ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

dialogplayer.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/stark/services/dialogplayer.h"
00024 #include "engines/stark/services/diary.h"
00025 #include "engines/stark/services/global.h"
00026 #include "engines/stark/services/services.h"
00027 #include "engines/stark/services/userinterface.h"
00028 
00029 #include "engines/stark/resources/script.h"
00030 #include "engines/stark/resources/speech.h"
00031 
00032 namespace Stark {
00033 
00034 DialogPlayer::DialogPlayer() :
00035         _currentDialog(nullptr),
00036         _currentReply(nullptr),
00037         _interruptedDialog(nullptr),
00038         _interruptedReply(nullptr),
00039         _speechReady(false),
00040         _singleSpeech(nullptr),
00041         _optionsAvailable(false) {
00042 }
00043 
00044 DialogPlayer::~DialogPlayer() {}
00045 
00046 void DialogPlayer::run(Resources::Dialog *dialog) {
00047     reset();
00048 
00049     StarkUserInterface->setInteractive(false);
00050 
00051     if (!_currentDialog) {
00052         Common::String dialogTitle = dialog->getDiaryTitle();
00053         int32 characterId = dialog->getCharacter();
00054         Common::String characterName = StarkGlobal->getCharacterName(characterId);
00055 
00056         StarkDiary->openDialog(dialogTitle, characterName, characterId);
00057     }
00058 
00059     _currentDialog = dialog;
00060     buildOptions();
00061 }
00062 
00063 void DialogPlayer::playSingle(Resources::Speech *speech) {
00064     reset();
00065 
00066     _singleSpeech = speech;
00067     _speechReady = true;
00068 }
00069 
00070 bool DialogPlayer::isRunning() const {
00071     return _currentDialog != nullptr || _interruptedDialog != nullptr;
00072 }
00073 
00074 bool DialogPlayer::isSpeechReady() const {
00075     return _speechReady;
00076 }
00077 
00078 bool DialogPlayer::isSpeechReady(Resources::Speech *speech) const {
00079     return _speechReady && _singleSpeech == speech;
00080 }
00081 
00082 Resources::Speech *DialogPlayer::acquireReadySpeech() {
00083     assert(_speechReady);
00084     _speechReady = false;
00085 
00086     if (_singleSpeech) {
00087         return _singleSpeech;
00088     } else {
00089         return _currentReply->getCurrentSpeech();
00090     }
00091 }
00092 
00093 bool DialogPlayer::areOptionsAvailable() const {
00094     return _optionsAvailable;
00095 }
00096 
00097 Common::Array<DialogPlayer::Option> DialogPlayer::listOptions() const {
00098     return _options;
00099 }
00100 
00101 void DialogPlayer::removeLastOnlyOption() {
00102     int32 lastOnlyOptionIndex = -1;
00103 
00104     for (uint i = 0; i < _options.size(); i++) {
00105         Resources::Dialog::Topic *topic = _options[i]._topic;
00106         Resources::Dialog::Reply *reply = topic->getReply(_options[i]._replyIndex);
00107         if (reply->isLastOnly()) {
00108             lastOnlyOptionIndex = i;
00109             break;
00110         }
00111     }
00112 
00113     if (lastOnlyOptionIndex >= 0) {
00114         _options.remove_at(lastOnlyOptionIndex);
00115     }
00116 }
00117 
00118 void DialogPlayer::buildOptions() {
00119     Resources::Dialog::TopicArray availableTopics = _currentDialog->listAvailableTopics();
00120 
00121     for (uint i = 0; i < availableTopics.size(); i++) {
00122         Option option;
00123 
00124         option._type = kOptionTypeAsk;
00125         option._topic = availableTopics[i];
00126         option._caption = availableTopics[i]->getCaption();
00127         option._replyIndex = availableTopics[i]->getNextReplyIndex();
00128 
00129         Resources::Dialog::Reply *reply = availableTopics[i]->getReply(option._replyIndex);
00130         if (reply->checkCondition()) {
00131             _options.push_back(option);
00132         }
00133     }
00134 
00135     if (_options.size() > 1) {
00136         removeLastOnlyOption();
00137     }
00138 
00139     if (_options.size() == 1) {
00140         // Only one option, just run it
00141         selectOption(0);
00142     } else {
00143         _optionsAvailable = true;
00144     }
00145 }
00146 
00147 void DialogPlayer::selectOption(uint32 index) {
00148     _optionsAvailable = false;
00149 
00150     Option &option = _options[index];
00151 
00152     //TODO: Complete
00153 
00154     switch (option._type) {
00155     case kOptionTypeAsk: {
00156         Resources::Dialog::Topic *topic = option._topic;
00157 
00158         // Set the current reply
00159         _currentReply = topic->startReply(option._replyIndex);
00160 
00161         Resources::Speech *speech = _currentReply->getCurrentSpeech();
00162         if (speech) {
00163             StarkDiary->logSpeech(speech->getPhrase(), speech->getCharacterId());
00164 
00165             _speechReady = true;
00166         } else {
00167             onReplyEnd();
00168         }
00169         break;
00170     }
00171     default:
00172         error("Unhandled option type %d", option._type);
00173     }
00174 }
00175 
00176 void DialogPlayer::onReplyEnd() {
00177     Resources::Script *nextScript = _currentDialog->getNextScript(_currentReply);
00178     Resources::Dialog *nextDialog = _currentDialog->getNextDialog(_currentReply);
00179 
00180     if (nextScript) {
00181         // Save the dialog player's state before running the script,
00182         // so that we can restore it when the script ends.
00183         // The script might run another dialog.
00184         saveToInterruptionSlot();
00185 
00186         nextScript->addReturnObject(_currentDialog);
00187         nextScript->execute(Resources::Script::kCallModeDialogCreateSelections);
00188     } else if (nextDialog) {
00189         run(nextDialog);
00190     } else {
00191         // Quit the dialog
00192         reset();
00193         StarkUserInterface->setInteractive(true);
00194     }
00195 }
00196 
00197 void DialogPlayer::reset() {
00198     if (_currentDialog) {
00199         StarkDiary->closeDialog();
00200     }
00201 
00202     _currentDialog = nullptr;
00203     _currentReply = nullptr;
00204     _singleSpeech = nullptr;
00205     _speechReady = false;
00206     _optionsAvailable = false;
00207     _options.clear();
00208 }
00209 
00210 void DialogPlayer::update() {
00211     if (_singleSpeech || !_currentDialog || !_currentReply) {
00212         return; // Nothing to do
00213     }
00214 
00215     //TODO: Complete
00216 
00217     Resources::Speech *speech = _currentReply->getCurrentSpeech();
00218     if (speech && _speechReady) {
00219         // A new line is already ready, no need to prepare another one
00220         return;
00221     }
00222 
00223     if (!speech || !speech->isPlaying()) {
00224         // A line has ended, play the next one
00225         _currentReply->goToNextLine();
00226         speech = _currentReply->getCurrentSpeech();
00227         if (speech) {
00228             StarkDiary->logSpeech(speech->getPhrase(), speech->getCharacterId());
00229 
00230             _speechReady = true;
00231         } else {
00232             onReplyEnd();
00233         }
00234     }
00235 }
00236 
00237 void DialogPlayer::resume(Resources::Dialog *dialog) {
00238     assert(_interruptedDialog == dialog);
00239 
00240     // Restore our state from before running the script
00241     restoreFromInterruptionSlot();
00242 
00243     Resources::Dialog *nextDialog = _currentDialog->getNextDialog(_currentReply);
00244      if (nextDialog) {
00245         run(nextDialog);
00246     } else {
00247         // Quit the dialog
00248         reset();
00249         StarkUserInterface->setInteractive(true);
00250     }
00251 }
00252 
00253 void DialogPlayer::saveToInterruptionSlot() {
00254     _interruptedDialog = _currentDialog;
00255     _interruptedReply = _currentReply;
00256 }
00257 
00258 void DialogPlayer::restoreFromInterruptionSlot() {
00259     _currentDialog = _interruptedDialog;
00260     _currentReply = _interruptedReply;
00261     _interruptedDialog = nullptr;
00262     _interruptedReply = nullptr;
00263 }
00264 } // End of namespace Stark


Generated on Sat May 18 2019 05:01:00 for ResidualVM by doxygen 1.7.1
curved edge   curved edge