aboutsummaryrefslogtreecommitdiff
path: root/engines/titanic/pet_control/pet_conversations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/titanic/pet_control/pet_conversations.cpp')
-rw-r--r--engines/titanic/pet_control/pet_conversations.cpp583
1 files changed, 583 insertions, 0 deletions
diff --git a/engines/titanic/pet_control/pet_conversations.cpp b/engines/titanic/pet_control/pet_conversations.cpp
new file mode 100644
index 0000000000..9bae8e7070
--- /dev/null
+++ b/engines/titanic/pet_control/pet_conversations.cpp
@@ -0,0 +1,583 @@
+/* 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 "titanic/pet_control/pet_conversations.h"
+#include "titanic/pet_control/pet_control.h"
+#include "titanic/game_manager.h"
+
+namespace Titanic {
+
+CPetConversations::CPetConversations() : CPetSection(),
+ _logChanged(false), _field418(0), _npcNum(-1),
+ _rect1(22, 352, 598, 478) {
+ Rect logRect(85, 18, 513, 87);
+ logRect.translate(20, 350);
+ _log.setBounds(logRect);
+ _log.resize(50);
+ _log.setHasBorder(false);
+ _log.setColor(getColor(2));
+ _log.setup();
+ _log.addLine("Welcome to your PET v1.0a");
+
+ Rect inputRect(85, 95, 513, 135);
+ inputRect.translate(20, 350);
+ _textInput.setBounds(inputRect);
+ _textInput.setHasBorder(false);
+ _textInput.resize(2);
+ _textInput.setMaxCharsPerLine(74);
+ _textInput.setColor(getColor(0));
+ _textInput.setup();
+
+ _npcLevels[0] = _npcLevels[1] = _npcLevels[2] = 0;
+}
+
+bool CPetConversations::setup(CPetControl *petControl) {
+ if (petControl && setupControl(petControl))
+ return reset();
+ return false;
+}
+
+bool CPetConversations::reset() {
+ _dials[0].setup(MODE_UNSELECTED, "3PetDial1", _petControl);
+ _dials[1].setup(MODE_UNSELECTED, "3PetDial2", _petControl);
+ _dials[2].setup(MODE_UNSELECTED, "3PetDial3", _petControl);
+
+ _dialBackground.reset("PetDialBack", _petControl);
+ _scrollUp.reset("PetScrollUp", _petControl);
+ _scrollDown.reset("PetScrollDown", _petControl);
+
+ _doorBot.reset("PetCallDoorOut", _petControl, MODE_UNSELECTED);
+ _doorBot.reset("PetCallDoorIn", _petControl, MODE_SELECTED);
+ _bellBot.reset("PetCallBellOut", _petControl, MODE_UNSELECTED);
+ _bellBot.reset("PetCallBellIn", _petControl, MODE_SELECTED);
+
+ _indent.reset("PetSmallCharacterIndent", _petControl);
+ _splitter.reset("PetSplitter", _petControl);
+
+ _npcIcons[0].setup(MODE_UNSELECTED, "3PetSmlDoorbot", _petControl);
+ _npcIcons[1].setup(MODE_UNSELECTED, "3PetSmlDeskbot", _petControl);
+ _npcIcons[2].setup(MODE_UNSELECTED, "3PetSmlLiftbot", _petControl);
+ _npcIcons[3].setup(MODE_UNSELECTED, "3PetSmlParrot", _petControl);
+ _npcIcons[4].setup(MODE_UNSELECTED, "3PetSmlBarbot", _petControl);
+ _npcIcons[5].setup(MODE_UNSELECTED, "3PetSmlChatterbot", _petControl);
+ _npcIcons[6].setup(MODE_UNSELECTED, "3PetSmlBellbot", _petControl);
+ _npcIcons[7].setup(MODE_UNSELECTED, "3PetSmlMaitreD", _petControl);
+ _npcIcons[8].setup(MODE_UNSELECTED, "3PetSmlSuccubus", _petControl);
+
+ if (_petControl->getPassengerClass() == 1) {
+ uint col = getColor(0);
+ _textInput.setColor(col);
+ _textInput.setLineColor(0, col);
+
+ // Replace the log colors with new 1st class ones
+ uint colors1[5], colors2[5];
+ copyColors(2, colors1);
+ copyColors(1, colors2);
+ _log.remapColors(5, colors1, colors2);
+
+ _log.setColor(getColor(2));
+ }
+
+ return true;
+}
+
+void CPetConversations::draw(CScreenManager *screenManager) {
+ _dialBackground.draw(screenManager);
+ _splitter.draw(screenManager);
+ _dials[0].draw(screenManager);
+ _dials[1].draw(screenManager);
+ _dials[2].draw(screenManager);
+
+ _indent.draw(screenManager);
+ _doorBot.draw(screenManager);
+ _bellBot.draw(screenManager);
+ _scrollUp.draw(screenManager);
+ _scrollDown.draw(screenManager);
+ _log.draw(screenManager);
+ _textInput.draw(screenManager);
+
+ if (_logChanged) {
+ int startIndex = _log.getLinesStart();
+ if (startIndex >= 0) {
+ int npcNum = _log.getNPCNum(1, startIndex);
+ if (npcNum > 0 && npcNum < 10)
+ _npcNum = npcNum;
+ }
+
+ _logChanged = false;
+ }
+
+ if (_npcNum >= 0)
+ _npcIcons[_npcNum].draw(screenManager);
+}
+
+Rect CPetConversations::getBounds() const {
+ Rect rect = _dials[0].getBounds();
+ rect.combine(_dials[1].getBounds());
+ rect.combine(_dials[2].getBounds());
+
+ return rect;
+}
+
+bool CPetConversations::isValid(CPetControl *petControl) {
+ return setupControl(petControl);
+}
+
+bool CPetConversations::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
+ if (_scrollDown.MouseButtonDownMsg(msg->_mousePos)) {
+ scrollDown();
+ return true;
+ } else if (_scrollUp.MouseButtonDownMsg(msg->_mousePos)) {
+ scrollUp();
+ return true;
+ }
+
+ return
+ _doorBot.MouseButtonDownMsg(msg->_mousePos) ||
+ _bellBot.MouseButtonDownMsg(msg->_mousePos);
+}
+
+bool CPetConversations::MouseButtonUpMsg(CMouseButtonUpMsg *msg) {
+ if (_scrollUp.MouseButtonUpMsg(msg->_mousePos) ||
+ _scrollDown.MouseButtonUpMsg(msg->_mousePos))
+ return true;
+
+ if (_doorBot.MouseButtonUpMsg(msg->_mousePos)) {
+ switch (canSummonBot("DoorBot")) {
+ case SUMMON_CANT:
+ _log.addLine("Sadly, it is not possible to summon the DoorBot from this location.", getColor(1));
+ break;
+ case SUMMON_CAN:
+ summonBot("DoorBot");
+ return true;
+ default:
+ break;
+ }
+
+ // Scroll to the bottom of the log
+ scrollToBottom();
+ return true;
+ }
+
+ if (_bellBot.MouseButtonUpMsg(msg->_mousePos)) {
+ switch (canSummonBot("BellBot")) {
+ case SUMMON_CANT:
+ _log.addLine("Sadly, it is not possible to summon the BellBot from this location.", getColor(1));
+ break;
+ case SUMMON_CAN:
+ summonBot("BellBot");
+ return true;
+ default:
+ break;
+ }
+
+ // Scroll to the bottom of the log
+ scrollToBottom();
+ return true;
+ }
+
+ return false;
+}
+
+bool CPetConversations::MouseDoubleClickMsg(CMouseDoubleClickMsg *msg) {
+ return _scrollDown.MouseDoubleClickMsg(msg->_mousePos)
+ || _scrollUp.MouseDoubleClickMsg(msg->_mousePos);
+}
+
+bool CPetConversations::KeyCharMsg(CKeyCharMsg *msg) {
+ Common::KeyState keyState;
+ keyState.ascii = msg->_key;
+ return handleKey(keyState);
+}
+
+bool CPetConversations::VirtualKeyCharMsg(CVirtualKeyCharMsg *msg) {
+ return handleKey(msg->_keyState);
+}
+
+void CPetConversations::displayMessage(const CString &msg) {
+ _log.addLine(msg, getColor(1));
+ scrollToBottom();
+}
+
+void CPetConversations::load(SimpleFile *file, int param) {
+ _textInput.load(file, param);
+ _log.load(file, param);
+
+ for (int idx = 0; idx < TOTAL_DIALS; ++idx)
+ _npcLevels[idx] = file->readNumber();
+}
+
+void CPetConversations::postLoad() {
+ reset();
+}
+
+void CPetConversations::save(SimpleFile *file, int indent) {
+ _textInput.save(file, indent);
+ _log.save(file, indent);
+
+ for (int idx = 0; idx < TOTAL_DIALS; ++idx)
+ file->writeNumberLine(_npcLevels[idx], indent);
+}
+
+void CPetConversations::enter(PetArea oldArea) {
+ resetDials();
+
+ if (_petControl && _petControl->_activeNPC)
+ // Start a timer for the NPC
+ startNPCTimer();
+
+ // Show the text cursor
+ _textInput.showCursor(-2);
+}
+
+void CPetConversations::leave() {
+ _textInput.hideCursor();
+ stopNPCTimer();
+}
+
+void CPetConversations::timerExpired(int val) {
+ if (val == 1) {
+ CPetSection::timerExpired(val);
+ } else {
+ CString name = _field418 ? _npcName : getActiveNPCName();
+
+ for (int idx = 0; idx < TOTAL_DIALS; ++idx) {
+ if (!_dials[idx].hasActiveMovie())
+ updateDial(idx, name);
+ }
+ }
+}
+
+void CPetConversations::displayNPCName(CGameObject *npc) {
+ if (npc) {
+ displayMessage(CString());
+ CString msg = "Talking to ";
+ CString name = npc->getName();
+ int id = 1;
+
+ if (name.contains("Doorbot")) {
+ msg += "the DoorBot";
+ } else if (name.contains("DeskBot")) {
+ id = 2;
+ msg += "the DeskBot";
+ } else if (name.contains("LiftBot")) {
+ id = 3;
+ msg += "a LiftBot";
+ } else if (name.contains("Parrot")) {
+ id = 4;
+ msg += "the Parrot";
+ } else if (name.contains("BarBot")) {
+ id = 5;
+ msg += "the BarBot";
+ } else if (name.contains("ChatterBot")) {
+ id = 6;
+ msg += "a ChatterBot";
+ } else if (name.contains("BellBot")) {
+ id = 7;
+ msg += "the BellBot";
+ } else if (name.contains("Maitre")) {
+ id = 8;
+ msg += "the Maitre d'Bot";
+ } else if (name.contains("Succubus") || name.contains("Sub")) {
+ id = 9;
+ msg += "a Succ-U-Bus";
+ } else {
+ msg += "Unknown";
+ }
+
+ _log.setNPC(1, id);
+ displayMessage(msg);
+ }
+}
+
+void CPetConversations::setNPC(const CString &name) {
+ _field418 = 0;
+ resetDials(name);
+ startNPCTimer();
+}
+
+void CPetConversations::resetNPC() {
+ stopNPCTimer();
+ resetDials("0");
+}
+
+void CPetConversations::showCursor() {
+ _textInput.showCursor(-2);
+}
+
+void CPetConversations::hideCursor() {
+ _textInput.hideCursor();
+}
+
+bool CPetConversations::setupControl(CPetControl *petControl) {
+ if (petControl) {
+ _petControl = petControl;
+
+ _dialBackground.setBounds(Rect(0, 0, 21, 130));
+ _dialBackground.translate(20, 350);
+
+ const Rect rect1(0, 0, 22, 36);
+ _dials[0].setBounds(rect1);
+ _dials[0].translate(20, 359);
+ _dials[1].setBounds(rect1);
+ _dials[1].translate(20, 397);
+ _dials[2].setBounds(rect1);
+ _dials[2].translate(20, 434);
+
+ const Rect rect2(0, 0, 11, 24);
+ _scrollUp.setBounds(rect2);
+ _scrollUp.translate(87, 374);
+ _scrollDown.setBounds(rect2);
+ _scrollDown.translate(87, 421);
+
+ const Rect rect3(0, 0, 39, 39);
+ _doorBot.setBounds(rect3);
+ _doorBot.translate(546, 372);
+ _bellBot.setBounds(rect3);
+ _bellBot.translate(546, 418);
+
+ _indent.setBounds(Rect(0, 0, 37, 70));
+ _indent.translate(46, 374);
+ _splitter.setBounds(Rect(0, 0, 435, 3));
+ _splitter.translate(102, 441);
+
+ const Rect rect4(0, 0, 33, 66);
+ for (int idx = 0; idx < 9; ++idx) {
+ _npcIcons[idx].setBounds(rect4);
+ _npcIcons[idx].translate(48, 376);
+ }
+ }
+
+ return true;
+}
+
+void CPetConversations::scrollUp() {
+ _log.scrollUp(CScreenManager::_screenManagerPtr);
+ if (_petControl)
+ _petControl->makeDirty();
+ _logChanged = true;
+}
+
+void CPetConversations::scrollDown() {
+ _log.scrollDown(CScreenManager::_screenManagerPtr);
+ if (_petControl)
+ _petControl->makeDirty();
+ _logChanged = true;
+}
+
+void CPetConversations::scrollUpPage() {
+ _log.scrollUpPage(CScreenManager::_screenManagerPtr);
+ if (_petControl)
+ _petControl->makeDirty();
+ _logChanged = true;
+}
+
+void CPetConversations::scrollDownPage() {
+ _log.scrollDownPage(CScreenManager::_screenManagerPtr);
+ if (_petControl)
+ _petControl->makeDirty();
+ _logChanged = true;
+}
+
+void CPetConversations::scrollToTop() {
+ _log.scrollToTop(CScreenManager::_screenManagerPtr);
+ if (_petControl)
+ _petControl->makeDirty();
+ _logChanged = true;
+}
+
+void CPetConversations::scrollToBottom() {
+ _log.scrollToBottom(CScreenManager::_screenManagerPtr);
+ if (_petControl)
+ _petControl->makeDirty();
+ _logChanged = true;
+}
+
+int CPetConversations::canSummonBot(const CString &name) {
+ return _petControl ? _petControl->canSummonBot(name) : SUMMON_CANT;
+}
+
+void CPetConversations::summonBot(const CString &name) {
+ if (_petControl) {
+ if (_petControl->getPassengerClass() >= 4) {
+ _petControl->displayMessage("Sorry, you must be at least 3rd class before you can summon for help.");
+ } else {
+ _petControl->summonBot(name, 0);
+ }
+ }
+}
+
+void CPetConversations::startNPCTimer() {
+ _petControl->startPetTimer(1, 1000, 1000, this);
+}
+
+void CPetConversations::stopNPCTimer() {
+ _petControl->stopPetTimer(1);
+}
+
+TTnpcScript *CPetConversations::getNPCScript(const CString &name) const {
+ if (name.empty() || !_petControl)
+ return nullptr;
+ CGameManager *gameManager = _petControl->getGameManager();
+ if (!gameManager)
+ return nullptr;
+ CTrueTalkManager *trueTalk = gameManager->getTalkManager();
+ if (!trueTalk)
+ return nullptr;
+
+ return trueTalk->getTalker(name);
+}
+
+bool CPetConversations::handleKey(const Common::KeyState &keyState) {
+ switch (keyState.keycode) {
+ case Common::KEYCODE_UP:
+ case Common::KEYCODE_KP8:
+ scrollUp();
+ break;
+ case Common::KEYCODE_DOWN:
+ case Common::KEYCODE_KP2:
+ scrollDown();
+ break;
+ case Common::KEYCODE_PAGEUP:
+ case Common::KEYCODE_KP9:
+ scrollUpPage();
+ break;
+ case Common::KEYCODE_PAGEDOWN:
+ case Common::KEYCODE_KP3:
+ scrollDownPage();
+ break;
+ case Common::KEYCODE_HOME:
+ case Common::KEYCODE_KP7:
+ scrollToTop();
+ break;
+ case Common::KEYCODE_END:
+ case Common::KEYCODE_KP1:
+ scrollToBottom();
+ break;
+ default:
+ if (keyState.ascii > 0 && keyState.ascii) {
+ if (_textInput.handleKey(keyState.ascii))
+ // Text line finished, so process line
+ textLineEntered(_textInput.getText());
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void CPetConversations::textLineEntered(const CString &textLine) {
+ if (textLine.empty() || !_petControl)
+ return;
+
+ if (_petControl->_activeNPC) {
+ _log.addLine("- " + textLine, getColor(0));
+
+ CTextInputMsg inputMsg(textLine, "");
+ inputMsg.execute(_petControl->_activeNPC);
+
+ if (!inputMsg._response.empty())
+ _log.addLine(inputMsg._response);
+ } else {
+ _log.addLine("There is no one here to talk to", getColor(1));
+ }
+
+ // Clear input line and scroll log down to end to show response
+ _textInput.setup();
+ scrollToBottom();
+}
+
+void CPetConversations::setActiveNPC(const CString &name) {
+ _npcName = name;
+ _field418 = 1;
+ resetDials();
+ startNPCTimer();
+}
+
+void CPetConversations::updateDial(uint dialNum, const CString &npcName) {
+ TTnpcScript *script = getNPCScript(npcName);
+ uint newLevel = getDialLevel(dialNum, script);
+ npcDialChange(dialNum, _npcLevels[dialNum], newLevel);
+ _npcLevels[dialNum] = newLevel;
+}
+
+uint CPetConversations::getDialLevel(uint dialNum, TTnpcScript *script, int v) {
+ bool flag = v != 0;
+
+ if (!script)
+ return 0;
+ else
+ return MAX(script->getDialLevel(dialNum, flag), 15);
+}
+
+void CPetConversations::npcDialChange(uint dialNum, int oldLevel, int newLevel) {
+ const uint range1[2] = { 0, 21 };
+ const uint range2[2] = { 22, 43 };
+
+ if (newLevel != oldLevel) {
+ uint src = range1[0], dest = range1[1];
+ if (oldLevel < newLevel) {
+ src = range2[0];
+ dest = range2[1];
+ }
+
+ int64 val1 = (oldLevel * dest) + (100 - oldLevel) * src;
+ val1 *= 0x51EB851F;
+ val1 >>= 37;
+ uint startFrame = val1 + (val1 >> 31);
+
+ int64 val2 = (newLevel * dest) + (100 - newLevel) * src;
+ val2 *= 0x51EB851F;
+ val2 >>= 37;
+ uint endFrame = val2 + (val2 >> 31);
+
+ if (startFrame != endFrame)
+ _dials[dialNum].playMovie(startFrame, endFrame);
+ }
+}
+
+void CPetConversations::resetDials() {
+ resetDials(getActiveNPCName());
+}
+
+void CPetConversations::resetDials(const CString &name) {
+ TTnpcScript *script = getNPCScript(name);
+
+ for (int idx = 0; idx < TOTAL_DIALS; ++idx) {
+ uint oldLevel = _npcLevels[idx];
+ uint newLevel = getDialLevel(idx, script);
+ npcDialChange(idx, oldLevel, newLevel);
+ _npcLevels[idx] = newLevel;
+ }
+}
+
+void CPetConversations::resetDials0() {
+ stopNPCTimer();
+ resetDials("0");
+}
+
+void CPetConversations::addLine(const CString &line) {
+ _log.addLine(line);
+ scrollToBottom();
+}
+
+} // End of namespace Titanic