Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

dialogue.cpp

/* 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.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-11-1/engines/parallaction/dialogue.cpp $
 * $Id: dialogue.cpp 30944 2008-02-23 22:50:18Z sev $
 *
 */

#include "common/events.h"
#include "parallaction/parallaction.h"



namespace Parallaction {

#define SKIPPED_ANSWER           1000

#define MAX_BALLOON_WIDTH                 130

#define MAX_PASSWORD_LENGTH          7

#define QUESTION_BALLOON_X                140
#define QUESTION_BALLOON_Y                10
#define QUESTION_CHARACTER_X          190
#define QUESTION_CHARACTER_Y          80

#define ANSWER_CHARACTER_X                10
#define ANSWER_CHARACTER_Y                80

int16 selectAnswer(Question *q, Graphics::Surface*);
int16 getHoverAnswer(int16 x, int16 y, Question *q);

int16 _answerBalloonX[10] = { 80, 120, 150, 150, 150, 0, 0, 0, 0, 0 };
int16 _answerBalloonY[10] = { 10, 70, 130, 0, 0, 0, 0, 0, 0, 0 };
int16 _answerBalloonW[10] = { 0 };
int16 _answerBalloonH[10] = { 0 };



class DialogueManager {

      Parallaction      *_vm;
      SpeakData         *_data;
      Dialogue          *_dialogue;

      bool              _askPassword;

      bool              isNpc;
      Frames                  *_questioner;
      Frames                  *_answerer;

      Question          *_q;

public:
      DialogueManager(Parallaction *vm, SpeakData *data) : _vm(vm), _data(data) {
            _dialogue = _data->_dialogue;
            isNpc = scumm_stricmp(_data->_name, "yourself") && _data->_name[0] != '\0';
            _questioner = isNpc ? _vm->_disk->loadTalk(_data->_name) : _vm->_char._talk;
            _answerer = _vm->_char._talk;
      }

      ~DialogueManager() {
            if (isNpc) {
                  delete _questioner;
            }
      }

      void run();

protected:
      void clear() {
            _vm->_gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront);
      }

      void displayQuestion();
      bool displayAnswers();
      bool displayAnswer(uint16 i);

      uint16 getAnswer();
      int16 selectAnswer();
      uint16 askPassword();
      int16 getHoverAnswer(int16 x, int16 y);

};

uint16 DialogueManager::askPassword() {
      debugC(3, kDebugExec, "checkDialoguePassword()");

      uint16 passwordLen;

      while (true) {
            clear();

            passwordLen = 0;
            _password[0] = '\0';

            Common::Rect r(_answerBalloonW[0], _answerBalloonH[0]);
            r.moveTo(_answerBalloonX[0], _answerBalloonY[0]);

            _vm->_gfx->drawBalloon(r, 1);
            _vm->_gfx->displayWrappedString(_q->_answers[0]->_text, _answerBalloonX[0], _answerBalloonY[0], 3, MAX_BALLOON_WIDTH);
            _vm->_gfx->flatBlitCnv(_answerer, 0, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y,  Gfx::kBitFront);
            _vm->_gfx->updateScreen();

            Common::Event e;
            while (e.kbd.ascii != Common::KEYCODE_RETURN && passwordLen < MAX_PASSWORD_LENGTH) {

                  // FIXME: see comment for readInput()
                  if (!g_system->getEventManager()->pollEvent(e)) continue;
                  if (e.type == Common::EVENT_QUIT) {
                        // TODO: don't quit() here, just have caller routines to check
                        // on kEngineQuit and exit gracefully to allow the engine to shut down
                        _engineFlags |= kEngineQuit;
                        g_system->quit();
                  }

                  if (e.type != Common::EVENT_KEYDOWN) continue;
                  if (!isdigit(e.kbd.ascii)) continue;

                  _password[passwordLen] = e.kbd.ascii;
                  passwordLen++;
                  _password[passwordLen] = '\0';


                  _vm->_gfx->drawBalloon(r, 1);
                  _vm->_gfx->displayWrappedString(_q->_answers[0]->_text, _answerBalloonX[0], _answerBalloonY[0], 3, MAX_BALLOON_WIDTH);
                  _vm->_gfx->updateScreen();

                  g_system->delayMillis(20);
            }

            if ((!scumm_stricmp(_vm->_char.getBaseName(), _doughName) && !scumm_strnicmp(_password, "1732461", 7)) ||
                  (!scumm_stricmp(_vm->_char.getBaseName(), _donnaName) && !scumm_strnicmp(_password, "1622", 4)) ||
                  (!scumm_stricmp(_vm->_char.getBaseName(), _dinoName) && !scumm_strnicmp(_password, "179", 3))) {

                  break;

            }

      }

      return 0;

}



bool DialogueManager::displayAnswer(uint16 i) {

      uint32 v28 = _vm->_localFlags[_vm->_currentLocationIndex];
      if (_q->_answers[i]->_yesFlags & kFlagsGlobal)
            v28 = _commandFlags | kFlagsGlobal;

      // display suitable answers
      if (((_q->_answers[i]->_yesFlags & v28) == _q->_answers[i]->_yesFlags) && ((_q->_answers[i]->_noFlags & ~v28) == _q->_answers[i]->_noFlags)) {

            _vm->_gfx->getStringExtent(_q->_answers[i]->_text, MAX_BALLOON_WIDTH, &_answerBalloonW[i], &_answerBalloonH[i]);

            Common::Rect r(_answerBalloonW[i], _answerBalloonH[i]);
            r.moveTo(_answerBalloonX[i], _answerBalloonY[i]);

            _vm->_gfx->drawBalloon(r, 1);

            _answerBalloonY[i+1] = 10 + _answerBalloonY[i] + _answerBalloonH[i];
            _askPassword = _vm->_gfx->displayWrappedString(_q->_answers[i]->_text, _answerBalloonX[i], _answerBalloonY[i], 3, MAX_BALLOON_WIDTH);

            return true;
      }

      _answerBalloonY[i+1] = _answerBalloonY[i];
      _answerBalloonY[i] = SKIPPED_ANSWER;

      return false;

}

bool DialogueManager::displayAnswers() {

      bool displayed = false;

      uint16 i = 0;

      while (i < NUM_ANSWERS && _q->_answers[i]) {
            if (displayAnswer(i))
                  displayed = true;

            i++;
      }
      _vm->_gfx->updateScreen();

      return displayed;
}

void DialogueManager::displayQuestion() {

      int16 w = 0, h = 0;

      if (!scumm_stricmp(_q->_text, "NULL")) return;

      _vm->_gfx->flatBlitCnv(_questioner, _q->_mood & 0xF, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y, Gfx::kBitFront);
      _vm->_gfx->getStringExtent(_q->_text, MAX_BALLOON_WIDTH, &w, &h);

      Common::Rect r(w, h);
      r.moveTo(QUESTION_BALLOON_X, QUESTION_BALLOON_Y);

      _vm->_gfx->drawBalloon(r, _q->_mood & 0x10);
      _vm->_gfx->displayWrappedString(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, 0, MAX_BALLOON_WIDTH);
      _vm->_gfx->updateScreen();

      waitUntilLeftClick();

      clear();

      return;
}

uint16 DialogueManager::getAnswer() {

      uint16 answer = 0;

      if (_askPassword == false) {
            answer = selectAnswer();
      } else {
            answer = askPassword();
      }

      clear();

      debugC(3, kDebugExec, "runDialogue: user selected answer #%i", answer);

      return answer;
}

void DialogueManager::run() {

      _askPassword = false;
      CommandList *cmdlist = NULL;

      _q = _dialogue->_questions[0];
      int16 answer;

      _vm->_gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack);

      while (_q) {

            answer = 0;

            displayQuestion();
            if (_q->_answers[0] == NULL) break;

            _answerBalloonY[0] = 10;

            if (scumm_stricmp(_q->_answers[0]->_text, "NULL")) {
                  if (!displayAnswers()) break;
                  answer = getAnswer();
                  cmdlist = &_q->_answers[answer]->_commands;
            }

            _q = _q->_answers[answer]->_following._question;
      }

      clear();

      if (cmdlist)
            _vm->runCommands(*cmdlist);

}

int16 DialogueManager::selectAnswer() {

      int16 numAvailableAnswers = 0;
      int16 _si = 0;
      int16 _di = 0;

      int16 i = 0;
      for (; _q->_answers[i]; i++) {
            if (_answerBalloonY[i] == SKIPPED_ANSWER) continue;

            _di = i;
            numAvailableAnswers++;
      }
      _answerBalloonY[i] = 2000;

      if (numAvailableAnswers == 1) {
            _vm->_gfx->displayWrappedString(_q->_answers[_di]->_text, _answerBalloonX[_di], _answerBalloonY[_di], 0, MAX_BALLOON_WIDTH);
            _vm->_gfx->flatBlitCnv(_answerer, _q->_answers[_di]->_mood & 0xF, ANSWER_CHARACTER_X,     ANSWER_CHARACTER_Y, Gfx::kBitFront);
            _vm->_gfx->updateScreen();
            waitUntilLeftClick();
            return _di;
      }

      int16 v2 = -1;

      _mouseButtons = kMouseNone;
      while (_mouseButtons != kMouseLeftUp) {

            _vm->readInput();
            _si = getHoverAnswer(_vm->_mousePos.x, _vm->_mousePos.y);

            if (_si != v2 && _si != -1) {
                  if (v2 != -1)
                        _vm->_gfx->displayWrappedString(_q->_answers[v2]->_text, _answerBalloonX[v2], _answerBalloonY[v2], 3, MAX_BALLOON_WIDTH);

                  _vm->_gfx->displayWrappedString(_q->_answers[_si]->_text, _answerBalloonX[_si],     _answerBalloonY[_si], 0, MAX_BALLOON_WIDTH);
                  _vm->_gfx->flatBlitCnv(_answerer, _q->_answers[_si]->_mood & 0xF, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y, Gfx::kBitFront);
            }

            _vm->_gfx->updateScreen();
            g_system->delayMillis(30);
            v2 = _si;
      }

      return _si;
}


//
//    finds out which answer is currently selected
//
int16 DialogueManager::getHoverAnswer(int16 x, int16 y) {

      int16 top = 1000;
      int16 bottom = 1000;

      for (int16 _si = 0; _si < NUM_ANSWERS; _si++) {
            if (_q->_answers[_si] == NULL) break;

            if (_answerBalloonY[_si] != SKIPPED_ANSWER) {
                  top = _answerBalloonY[_si];
            }

            int16 _di = _si + 1;
            for (; _answerBalloonY[_di] == SKIPPED_ANSWER; _di++) ;

            bottom = _answerBalloonY[_di];

            // mouse position is compared only with y coordinates
            if (y > top && y < bottom) return _si;

      }

      return -1;

}



void Parallaction::runDialogue(SpeakData *data) {
      debugC(1, kDebugExec, "runDialogue: starting dialogue '%s'", data->_name);

      _gfx->setFont(_dialogueFont);

      if (getPlatform() == Common::kPlatformPC)
            showCursor(false);

      DialogueManager man(this, data);
      man.run();

      showCursor(true);

      return;
}


} // namespace Parallaction

Generated by  Doxygen 1.6.0   Back to index