Initial commit
This commit is contained in:
475
engines/mortevielle/dialogs.cpp
Normal file
475
engines/mortevielle/dialogs.cpp
Normal file
@@ -0,0 +1,475 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Mortville Manor DOS source code
|
||||
* Copyright (c) 1987-1989 Lankhor
|
||||
*/
|
||||
|
||||
#include "mortevielle/mortevielle.h"
|
||||
|
||||
#include "mortevielle/dialogs.h"
|
||||
#include "mortevielle/mouse.h"
|
||||
#include "mortevielle/outtext.h"
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Mortevielle {
|
||||
|
||||
DialogManager::DialogManager(MortevielleEngine *vm) {
|
||||
_vm = vm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alert function - Show
|
||||
* @remarks Originally called 'do_alert'
|
||||
*/
|
||||
int DialogManager::show(const Common::String &msg) {
|
||||
// Make a copy of the current screen surface for later restore
|
||||
_vm->_backgroundSurface.copyFrom(*_vm->_screenSurface);
|
||||
|
||||
_vm->_mouse->hideMouse();
|
||||
while (_vm->keyPressed())
|
||||
_vm->getChar();
|
||||
|
||||
_vm->setMouseClick(false);
|
||||
|
||||
int colNumb = 0;
|
||||
int lignNumb = 0;
|
||||
int caseNumb = 0;
|
||||
Common::String alertStr = "";
|
||||
Common::String caseStr;
|
||||
|
||||
decodeAlertDetails(msg, caseNumb, lignNumb, colNumb, alertStr, caseStr);
|
||||
|
||||
Common::Point curPos;
|
||||
if (alertStr == "") {
|
||||
drawAlertBox(10, 5, colNumb);
|
||||
} else {
|
||||
drawAlertBox(8, 7, colNumb);
|
||||
int i = -1;
|
||||
_vm->_screenSurface->_textPos.y = 70;
|
||||
do {
|
||||
curPos.x = 320;
|
||||
Common::String displayStr = "";
|
||||
while ((alertStr[i + 1] != '|') && (alertStr[i + 1] != ']')) {
|
||||
++i;
|
||||
displayStr += alertStr[i];
|
||||
curPos.x -= 3;
|
||||
}
|
||||
_vm->_screenSurface->putxy(curPos.x, _vm->_screenSurface->_textPos.y);
|
||||
_vm->_screenSurface->_textPos.y += 6;
|
||||
_vm->_screenSurface->drawString(displayStr, 4);
|
||||
++i;
|
||||
} while (alertStr[i] != ']');
|
||||
}
|
||||
int esp;
|
||||
if (caseNumb == 1)
|
||||
esp = colNumb - 40;
|
||||
else
|
||||
esp = (uint)(colNumb - caseNumb * 40) / 2;
|
||||
|
||||
int coldep = 320 - ((uint)colNumb / 2) + ((uint)esp / 2);
|
||||
Common::String buttonStr[3];
|
||||
setButtonText(caseStr, coldep, caseNumb, &buttonStr[0], esp);
|
||||
|
||||
int limit[3][3];
|
||||
memset(&limit[0][0], 0, sizeof(int) * 3 * 3);
|
||||
|
||||
limit[1][1] = ((uint)(coldep) / 2) * kResolutionScaler;
|
||||
limit[1][2] = limit[1][1] + 40;
|
||||
if (caseNumb == 1) {
|
||||
limit[2][1] = limit[2][2];
|
||||
} else {
|
||||
limit[2][1] = ((uint)(320 + ((uint)esp >> 1)) / 2) * kResolutionScaler;
|
||||
limit[2][2] = (limit[2][1]) + 40;
|
||||
}
|
||||
_vm->_mouse->showMouse();
|
||||
int id = 0;
|
||||
bool dummyFl = false;
|
||||
bool test3;
|
||||
do {
|
||||
char dummyKey = '\377';
|
||||
_vm->_mouse->moveMouse(dummyFl, dummyKey);
|
||||
if (_vm->shouldQuit())
|
||||
return 0;
|
||||
|
||||
curPos = _vm->_mouse->_pos;
|
||||
bool newaff = false;
|
||||
if ((curPos.y > 95) && (curPos.y < 105)) {
|
||||
bool test1 = (curPos.x > limit[1][1]) && (curPos.x < limit[1][2]);
|
||||
bool test2 = test1;
|
||||
if (caseNumb > 1)
|
||||
test2 |= ((curPos.x > limit[2][1]) && (curPos.x < limit[2][2]));
|
||||
if (test2) {
|
||||
newaff = true;
|
||||
|
||||
int ix;
|
||||
if (test1)
|
||||
ix = 1;
|
||||
else
|
||||
ix = 2;
|
||||
if (ix != id) {
|
||||
_vm->_mouse->hideMouse();
|
||||
if (id != 0) {
|
||||
setPosition(id, coldep, esp);
|
||||
|
||||
Common::String tmpStr(" ");
|
||||
tmpStr += buttonStr[id];
|
||||
tmpStr += " ";
|
||||
_vm->_screenSurface->drawString(tmpStr, 0);
|
||||
}
|
||||
setPosition(ix, coldep, esp);
|
||||
|
||||
Common::String tmp2 = " ";
|
||||
tmp2 += buttonStr[ix];
|
||||
tmp2 += " ";
|
||||
_vm->_screenSurface->drawString(tmp2, 1);
|
||||
|
||||
id = ix;
|
||||
_vm->_mouse->showMouse();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((id != 0) && !newaff) {
|
||||
_vm->_mouse->hideMouse();
|
||||
setPosition(id, coldep, esp);
|
||||
|
||||
Common::String tmp3(" ");
|
||||
tmp3 += buttonStr[id];
|
||||
tmp3 += " ";
|
||||
_vm->_screenSurface->drawString(tmp3, 0);
|
||||
|
||||
id = 0;
|
||||
_vm->_mouse->showMouse();
|
||||
}
|
||||
test3 = (curPos.y > 95) && (curPos.y < 105) && (((curPos.x > limit[1][1]) && (curPos.x < limit[1][2]))
|
||||
|| ((curPos.x > limit[2][1]) && (curPos.x < limit[2][2])));
|
||||
} while (!_vm->getMouseClick());
|
||||
_vm->setMouseClick(false);
|
||||
_vm->_mouse->hideMouse();
|
||||
if (!test3) {
|
||||
id = 1;
|
||||
setPosition(1, coldep, esp);
|
||||
Common::String tmp4(" ");
|
||||
tmp4 += buttonStr[1];
|
||||
tmp4 += " ";
|
||||
_vm->_screenSurface->drawString(tmp4, 1);
|
||||
}
|
||||
_vm->_mouse->showMouse();
|
||||
|
||||
/* Restore the background area */
|
||||
_vm->_screenSurface->copyFrom(_vm->_backgroundSurface, 0, 0);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alert function - Decode Alert Details
|
||||
* @remarks Originally called 'decod'
|
||||
*/
|
||||
void DialogManager::decodeAlertDetails(Common::String inputStr, int &choiceNumb, int &lineNumb, int &col, Common::String &choiceStr, Common::String &choiceListStr) {
|
||||
// The second character of the string contains the number of choices
|
||||
choiceNumb = atoi(inputStr.c_str() + 1);
|
||||
|
||||
choiceStr = "";
|
||||
col = 0;
|
||||
lineNumb = 0;
|
||||
|
||||
// Originally set to 5, decreased to 4 because strings are 0 based, and not 1 based as in Pascal
|
||||
int i = 4;
|
||||
int k = 0;
|
||||
bool empty = true;
|
||||
|
||||
for (; inputStr[i] != ']'; ++i) {
|
||||
choiceStr += inputStr[i];
|
||||
if ((inputStr[i] == '|') || (inputStr[i + 1] == ']')) {
|
||||
if (k > col)
|
||||
col = k;
|
||||
k = 0;
|
||||
++lineNumb;
|
||||
} else if (inputStr[i] != ' ')
|
||||
empty = false;
|
||||
++k;
|
||||
}
|
||||
|
||||
if (empty) {
|
||||
choiceStr = "";
|
||||
col = 20;
|
||||
} else {
|
||||
choiceStr += ']';
|
||||
col += 6;
|
||||
}
|
||||
|
||||
choiceListStr = Common::String(inputStr.c_str() + i);
|
||||
col *= 6;
|
||||
}
|
||||
|
||||
void DialogManager::setPosition(int ji, int coldep, int esp) {
|
||||
_vm->_screenSurface->putxy(coldep + (40 + esp) * (ji - 1), 98);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alert function - Draw Alert Box
|
||||
* @remarks Originally called 'fait_boite'
|
||||
*/
|
||||
void DialogManager::drawAlertBox(int firstLine, int lineNum, int width) {
|
||||
if (width > 640)
|
||||
width = 640;
|
||||
int x = 320 - ((uint)width / 2);
|
||||
int y = (firstLine - 1) * 8;
|
||||
int xx = x + width;
|
||||
int yy = y + (lineNum * 8);
|
||||
_vm->_screenSurface->fillRect(15, Common::Rect(x, y, xx, yy));
|
||||
_vm->_screenSurface->fillRect(0, Common::Rect(x, y + 2, xx, y + 4));
|
||||
_vm->_screenSurface->fillRect(0, Common::Rect(x, yy - 4, xx, yy - 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Alert function - Set Button Text
|
||||
* @remarks Originally called 'fait_choix'
|
||||
*/
|
||||
void DialogManager::setButtonText(Common::String c, int coldep, int nbcase, Common::String *str, int esp) {
|
||||
int i = 1;
|
||||
int x = coldep;
|
||||
for (int l = 1; l <= nbcase; ++l) {
|
||||
str[l] = "";
|
||||
do {
|
||||
++i;
|
||||
char ch = c[i];
|
||||
str[l] += ch;
|
||||
} while (c[i + 1] != ']');
|
||||
i += 2;
|
||||
|
||||
while (str[l].size() < 3)
|
||||
str[l] += ' ';
|
||||
|
||||
_vm->_screenSurface->putxy(x, 98);
|
||||
|
||||
Common::String tmp(" ");
|
||||
tmp += str[l];
|
||||
tmp += " ";
|
||||
|
||||
_vm->_screenSurface->drawString(tmp, 0);
|
||||
x += esp + 40;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Questions asked before entering the hidden passage
|
||||
*/
|
||||
bool DialogManager::showKnowledgeCheck() {
|
||||
const int textIndexArr[10] = {511, 516, 524, 531, 545, 552, 559, 563, 570, 576};
|
||||
const int correctAnswerArr[10] = {4, 7, 1, 6, 4, 4, 2, 5, 3, 1 };
|
||||
|
||||
Hotspot coor[kMaxHotspots+1];
|
||||
|
||||
for (int i = 0; i <= kMaxHotspots; ++i) {
|
||||
coor[i]._rect = Common::Rect();
|
||||
coor[i]._enabled = false;
|
||||
}
|
||||
|
||||
Common::String choiceArray[15];
|
||||
|
||||
int currChoice;
|
||||
int correctCount = 0;
|
||||
|
||||
for (int indx = 0; indx < 10; ++indx) {
|
||||
_vm->_mouse->hideMouse();
|
||||
_vm->clearScreen();
|
||||
_vm->_mouse->showMouse();
|
||||
int dialogHeight = 23;
|
||||
_vm->_screenSurface->fillRect(15, Common::Rect(0, 14, 630, dialogHeight));
|
||||
Common::String tmpStr = _vm->getString(textIndexArr[indx]);
|
||||
_vm->_text->displayStr(tmpStr, 20, 15, 100, 2, 0);
|
||||
|
||||
int firstOption;
|
||||
int lastOption;
|
||||
|
||||
if (indx != 9) {
|
||||
firstOption = textIndexArr[indx] + 1;
|
||||
lastOption = textIndexArr[indx + 1] - 1;
|
||||
} else {
|
||||
firstOption = 503;
|
||||
lastOption = 510;
|
||||
}
|
||||
int optionPosY = 35;
|
||||
int maxLength = 0;
|
||||
|
||||
int prevChoice = 1;
|
||||
for (int j = firstOption; j <= lastOption; ++j, ++prevChoice) {
|
||||
tmpStr = _vm->getString(j);
|
||||
if ((int)tmpStr.size() > maxLength)
|
||||
maxLength = tmpStr.size();
|
||||
_vm->_text->displayStr(tmpStr, 100, optionPosY, 100, 1, 0);
|
||||
choiceArray[prevChoice] = tmpStr;
|
||||
optionPosY += 8;
|
||||
}
|
||||
|
||||
for (int j = 1; j <= lastOption - firstOption + 1; ++j) {
|
||||
coor[j]._rect = Common::Rect(45 * kResolutionScaler, 27 + j * 8, (maxLength * 3 + 55) * kResolutionScaler, 34 + j * 8);
|
||||
coor[j]._enabled = true;
|
||||
|
||||
while ((int)choiceArray[j].size() < maxLength) {
|
||||
choiceArray[j] += ' ';
|
||||
}
|
||||
}
|
||||
coor[lastOption - firstOption + 2]._enabled = false;
|
||||
int rep = 6;
|
||||
_vm->_screenSurface->drawBox(80, 33, 40 + (maxLength * rep), (lastOption - firstOption) * 8 + 16, 15);
|
||||
rep = 0;
|
||||
|
||||
prevChoice = 0;
|
||||
warning("Expected answer: %d", correctAnswerArr[indx]);
|
||||
do {
|
||||
_vm->setMouseClick(false);
|
||||
bool flag;
|
||||
char key;
|
||||
_vm->_mouse->moveMouse(flag, key);
|
||||
if (_vm->shouldQuit())
|
||||
return false;
|
||||
|
||||
currChoice = 1;
|
||||
while (coor[currChoice]._enabled && !_vm->_mouse->isMouseIn(coor[currChoice]._rect))
|
||||
++currChoice;
|
||||
if (coor[currChoice]._enabled) {
|
||||
if ((prevChoice != 0) && (prevChoice != currChoice)) {
|
||||
tmpStr = choiceArray[prevChoice] + '$';
|
||||
_vm->_text->displayStr(tmpStr, 100, 27 + (prevChoice * 8), 100, 1, 0);
|
||||
}
|
||||
if (prevChoice != currChoice) {
|
||||
tmpStr = choiceArray[currChoice] + '$';
|
||||
_vm->_text->displayStr(tmpStr, 100, 27 + (currChoice * 8), 100, 1, 1);
|
||||
prevChoice = currChoice;
|
||||
}
|
||||
} else if (prevChoice != 0) {
|
||||
tmpStr = choiceArray[prevChoice] + '$';
|
||||
_vm->_text->displayStr(tmpStr, 100, 27 + (prevChoice * 8), 100, 1, 0);
|
||||
prevChoice = 0;
|
||||
}
|
||||
} while (!((prevChoice != 0) && _vm->getMouseClick()));
|
||||
|
||||
if (prevChoice == correctAnswerArr[indx])
|
||||
// Answer is correct
|
||||
++correctCount;
|
||||
else {
|
||||
// Skip questions that may give hints on previous wrong answer
|
||||
if (indx == 4)
|
||||
++indx;
|
||||
else if ((indx == 6) || (indx == 7))
|
||||
indx = 9;
|
||||
}
|
||||
}
|
||||
|
||||
return (correctCount == 10);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Draw the F3/F8 dialog
|
||||
*/
|
||||
void DialogManager::drawF3F8() {
|
||||
Common::String f3 = _vm->getEngineString(S_F3);
|
||||
Common::String f8 = _vm->getEngineString(S_F8);
|
||||
|
||||
// Write the F3 and F8 text strings
|
||||
_vm->_screenSurface->putxy(3, 44);
|
||||
_vm->_screenSurface->drawString(f3, 5);
|
||||
_vm->_screenSurface->_textPos.y = 51;
|
||||
_vm->_screenSurface->drawString(f8, 5);
|
||||
|
||||
// Get the width of the written text strings
|
||||
int f3Width = _vm->_screenSurface->getStringWidth(f3);
|
||||
int f8Width = _vm->_screenSurface->getStringWidth(f8);
|
||||
|
||||
// Write out the bounding box
|
||||
_vm->_screenSurface->drawBox(0, 42, MAX(f3Width, f8Width) + 4, 16, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alert function - Loop until F8 is pressed, update
|
||||
* Graphical Device if modified
|
||||
* @remarks Originally called 'diver'
|
||||
*/
|
||||
void DialogManager::checkForF8(int SpeechNum, bool drawFrame2Fl) {
|
||||
_vm->testKeyboard();
|
||||
do {
|
||||
_vm->_soundManager->startSpeech(SpeechNum, 0, 0);
|
||||
_vm->_key = waitForF3F8();
|
||||
if (_vm->shouldQuit())
|
||||
return;
|
||||
} while (_vm->_key != 66); // keycode for F8
|
||||
// just stop the speech when pressing F8
|
||||
if (_vm->_soundManager->_ttsMan != nullptr)
|
||||
_vm->_soundManager->_ttsMan->stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alert function - Loop until F3 or F8 is pressed
|
||||
* @remarks Originally called 'atf3f8'
|
||||
*/
|
||||
int DialogManager::waitForF3F8() {
|
||||
int key;
|
||||
|
||||
do {
|
||||
key = _vm->gettKeyPressed();
|
||||
if (_vm->shouldQuit())
|
||||
return key;
|
||||
} while ((key != 61) && (key != 66));
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intro function - display intro screen
|
||||
* @remarks Originally called 'aff50'
|
||||
*/
|
||||
void DialogManager::displayIntroScreen(bool drawFrame2Fl) {
|
||||
_vm->_caff = 50;
|
||||
_vm->_maff = 0;
|
||||
_vm->_text->taffich();
|
||||
_vm->draw(63, 12);
|
||||
if (drawFrame2Fl)
|
||||
displayIntroFrame2();
|
||||
else
|
||||
_vm->handleDescriptionText(2, kDialogStringIndex + 142);
|
||||
|
||||
// Draw the f3/f8 dialog
|
||||
drawF3F8();
|
||||
}
|
||||
|
||||
/**
|
||||
* Intro function - display 2nd frame of intro
|
||||
* @remarks Originally called 'ani50'
|
||||
*/
|
||||
void DialogManager::displayIntroFrame2() {
|
||||
_vm->_crep = _vm->getAnimOffset(1, 1);
|
||||
_vm->displayPicture(&_vm->_curAnim[_vm->_crep], 63, 12);
|
||||
_vm->_crep = _vm->getAnimOffset(2, 1);
|
||||
_vm->displayPicture(&_vm->_curAnim[_vm->_crep], 63, 12);
|
||||
_vm->_largestClearScreen = false;
|
||||
_vm->handleDescriptionText(2, kDialogStringIndex + 143);
|
||||
}
|
||||
|
||||
} // End of namespace Mortevielle
|
||||
Reference in New Issue
Block a user