/* 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_control.h" #include "titanic/carry/carry.h" #include "titanic/core/project_item.h" #include "titanic/messages/messages.h" #include "titanic/messages/pet_messages.h" #include "titanic/game_manager.h" #include "titanic/game_state.h" namespace Titanic { BEGIN_MESSAGE_MAP(CPetControl, CGameObject) ON_MESSAGE(MouseButtonDownMsg) ON_MESSAGE(MouseDragStartMsg) ON_MESSAGE(MouseDragMoveMsg) ON_MESSAGE(MouseDragEndMsg) ON_MESSAGE(MouseButtonUpMsg) ON_MESSAGE(MouseDoubleClickMsg) ON_MESSAGE(KeyCharMsg) ON_MESSAGE(VirtualKeyCharMsg) ON_MESSAGE(TimerMsg) END_MESSAGE_MAP() CPetControl::CPetControl() : CGameObject(), _currentArea(PET_CONVERSATION), _fieldC0(0), _locked(0), _fieldC8(0), _activeNPC(nullptr), _remoteTarget(nullptr), _hiddenRoom(nullptr), _drawBounds(20, 350, 620, 480) { _sections[PET_INVENTORY] = &_inventory; _sections[PET_CONVERSATION] = &_conversations; _sections[PET_REMOTE] = &_remote; _sections[PET_ROOMS] = &_rooms; _sections[PET_REAL_LIFE] = &_realLife; _sections[PET_NAV_HELMET] = &_navHelmet; _sections[PET_MESSAGE] = &_message; } void CPetControl::save(SimpleFile *file, int indent) const { file->writeNumberLine(0, indent); file->writeNumberLine(_currentArea, indent); file->writeQuotedLine(_activeNPCName, indent); file->writeQuotedLine(_string2, indent); saveAreas(file, indent); CGameObject::save(file, indent); } void CPetControl::load(SimpleFile *file) { int val = file->readNumber(); isValid(); if (!val) { _currentArea = (PetArea)file->readNumber(); _activeNPCName = file->readString(); _string2 = file->readString(); loadAreas(file, 0); } CGameObject::load(file); } void CPetControl::setup() { warning("TODO: CPetControl::setup"); _rooms.setup(this); _remote.setup(this); _inventory.setup(this); _navHelmet.setup(this); _realLife.setup(this); _message.setup(this); _frame.setup(this); } bool CPetControl::isValid() { return _conversations.isValid(this) && _rooms.isValid(this) && _remote.isValid(this) && _inventory.isValid(this) && _navHelmet.isValid(this) && _realLife.isValid(this) && _message.isValid(this) && _frame.isValid(this); } void CPetControl::loadAreas(SimpleFile *file, int param) { _conversations.load(file, param); _rooms.load(file, param); _remote.load(file, param); _inventory.load(file, param); _navHelmet.load(file, param); _realLife.load(file, param); _message.load(file, param); _frame.load(file, param); } void CPetControl::saveAreas(SimpleFile *file, int indent) const { _conversations.save(file, indent); _rooms.save(file, indent); _remote.save(file, indent); _inventory.save(file, indent); _navHelmet.save(file, indent); _realLife.save(file, indent); _message.save(file, indent); _frame.save(file, indent); } void CPetControl::draw(CScreenManager *screenManager) { CGameManager *gameManager = getGameManager(); Rect bounds = _drawBounds; bounds.constrain(gameManager->_bounds); if (!bounds.isEmpty()) { if (_fieldC8 >= 0) { _inventory.proc5(_fieldC8); _fieldC8 = -1; } _frame.drawFrame(screenManager); // Draw the specific area that's currently active _sections[_currentArea]->draw(screenManager); } } Rect CPetControl::getBounds() { return _sections[_currentArea]->getBounds(); } void CPetControl::postLoad() { CProjectItem *root = getRoot(); if (!_activeNPCName.empty() && root) _activeNPC = root->findByName(_activeNPCName); if (!_string2.empty() && root) _remoteTarget = root->findByName(_string2); setArea(_currentArea); loaded(); } void CPetControl::loaded() { _conversations.postLoad(); _rooms.postLoad(); _remote.postLoad(); _inventory.postLoad(); _navHelmet.postLoad(); _realLife.postLoad(); _message.postLoad(); _frame.postLoad(); } void CPetControl::enterNode(CNodeItem *node) { getGameManager()->_gameState.enterNode(); } void CPetControl::enterRoom(CRoomItem *room) { _rooms.enterRoom(room); _remote.enterRoom(room); } void CPetControl::clear() { _remoteTarget = nullptr; _string2.clear(); } bool CPetControl::fn1(int val) { warning("TODO: CPetControl::fn1"); return false; } void CPetControl::fn4() { warning("TODO: CPetControl::fn4"); } PetArea CPetControl::setArea(PetArea newArea) { if (newArea == _currentArea || !isUnlocked()) return _currentArea; // Signal the currently active area that it's being left _sections[_currentArea]->leave(); // Change the current area PetArea oldArea = _currentArea; _frame.setArea(newArea); _currentArea = newArea; // Signal to the new view that it's been activated _sections[_currentArea]->enter(oldArea); makeDirty(); return newArea; } void CPetControl::fn2(int val) { _sections[_currentArea]->proc38(val); } void CPetControl::fn3(CTreeItem *item) { _remoteTarget = item; if (item) _string2 = item->getName(); else _string2.clear(); } CRoomItem *CPetControl::getHiddenRoom() { if (!_hiddenRoom) _hiddenRoom = CTreeItem::getHiddenRoom(); return _hiddenRoom; } CGameObject *CPetControl::getHiddenObject(const CString &name) { CRoomItem *room = getHiddenRoom(); return room ? findUnder(room, name) : nullptr; } bool CPetControl::containsPt(const Common::Point &pt) const { return _drawBounds.contains(pt); } bool CPetControl::getC0() const { return _fieldC0 > 0; } bool CPetControl::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { if (!containsPt(msg->_mousePos) || getC0()) return false; bool result = false; if (isUnlocked()) result = _frame.MouseButtonDownMsg(msg); if (!result) { result = _sections[_currentArea]->MouseButtonDownMsg(msg); } makeDirty(); return result; } bool CPetControl::MouseDragStartMsg(CMouseDragStartMsg *msg) { if (!containsPt(msg->_mousePos) || getC0()) return false; return _sections[_currentArea]->MouseDragStartMsg(msg); } bool CPetControl::MouseDragMoveMsg(CMouseDragMoveMsg *msg) { return _sections[_currentArea]->MouseDragMoveMsg(msg); } bool CPetControl::MouseDragEndMsg(CMouseDragEndMsg *msg) { return _sections[_currentArea]->MouseDragEndMsg(msg); } bool CPetControl::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { if (!containsPt(msg->_mousePos) || getC0()) return false; bool result = false; if (isUnlocked()) result = _frame.MouseButtonUpMsg(msg); if (!result) result = _sections[_currentArea]->MouseButtonUpMsg(msg); makeDirty(); return result; } bool CPetControl::MouseDoubleClickMsg(CMouseDoubleClickMsg *msg) { if (!containsPt(msg->_mousePos) || getC0()) return false; return _sections[_currentArea]->MouseDoubleClickMsg(msg); } bool CPetControl::KeyCharMsg(CKeyCharMsg *msg) { if (getC0()) return false; return _sections[_currentArea]->KeyCharMsg(msg); } bool CPetControl::VirtualKeyCharMsg(CVirtualKeyCharMsg *msg) { if (getC0()) return false; bool result = _sections[_currentArea]->VirtualKeyCharMsg(msg); if (!result) { switch (msg->_keyState.keycode) { case Common::KEYCODE_F1: result = true; setArea(PET_INVENTORY); break; case Common::KEYCODE_F2: result = true; setArea(PET_CONVERSATION); break; case Common::KEYCODE_F3: result = true; setArea(PET_REMOTE); break; case Common::KEYCODE_F4: result = true; setArea(PET_ROOMS); break; case Common::KEYCODE_F5: result = true; setArea(PET_REAL_LIFE); break; default: break; } } return result; } bool CPetControl::TimerMsg(CTimerMsg *msg) { warning("TODO: CPetControl::CTimerMsg"); return true; } void CPetControl::drawSquares(CScreenManager *screenManager, int count) { _frame.drawSquares(screenManager, count); } CGameObject *CPetControl::dragEnd(const Point &pt) const { return _currentArea == PET_INVENTORY ? _inventory.dragEnd(pt) : nullptr; } bool CPetControl::checkDragEnd(CGameObject *item) const { return _sections[_currentArea]->checkDragEnd(item); } void CPetControl::displayMessage(const CString &msg) const { _sections[_currentArea]->displayMessage(msg); } CGameObject *CPetControl::getFirstObject() const { return static_cast(getFirstChild()); } CGameObject *CPetControl::getNextObject(CGameObject *prior) const { if (!prior || prior->getParent() != this) return nullptr; return static_cast(prior->getNextSibling()); } void CPetControl::addToInventory(CCarry *item) { item->detach(); if (item->getName() == "CarryParcel") { CCarry *child = static_cast(getLastChild()); if (child) child->detach(); item->moveToHiddenRoom(); if (!child) return; item = child; } item->addUnder(this); _inventory.itemsChanged(); setArea(PET_INVENTORY); if (_currentArea == PET_INVENTORY) _inventory.highlightItem(item); makeDirty(); CPETGainedObjectMsg msg; msg.execute(item); } void CPetControl::removeFromInventory(CCarry *item, CTreeItem *newParent, bool refreshUI, bool sendMsg) { if (item && newParent) { item->detach(); item->addUnder(newParent); if (refreshUI) _inventory.itemRemoved(item); if (sendMsg) { CPETLostObjectMsg lostMsg; lostMsg.execute(item); } } } void CPetControl::removeFromInventory(CCarry *item, bool refreshUI, bool sendMsg) { CViewItem *view = getGameManager()->getView(); removeFromInventory(item, view, refreshUI, sendMsg); } void CPetControl::invChange(CCarry *item) { _inventory.change(item); } void CPetControl::moveToHiddenRoom(CTreeItem *item) { CRoomItem *room = getHiddenRoom(); if (room) { item->detach(); room->addUnder(item); } } void CPetControl::playSound(int soundNum) { CTreeItem *player = getHiddenObject("PETSoundPlayer"); if (player) { CPETPlaySoundMsg playMsg(soundNum); playMsg.execute(player); } } CString CPetControl::getRoomName() const { CRoomItem *room = getRoom(); return room ? room->getName() : CString(); } int CPetControl::canSummonNPC(const CString &name) { // If player is the very same view as the NPC, then it's already present if (isNPCInView(name)) return SUMMON_CAN; // Get the room CGameManager *gameManager = getGameManager(); if (!gameManager) return SUMMON_CANT; CRoomItem *room = gameManager->getRoom(); if (!room) return SUMMON_CANT; // Query current room to see whether the bot can be summoned to it CSummonBotQueryMsg queryMsg(name); return queryMsg.execute(room) ? SUMMON_CAN : SUMMON_CANT; } bool CPetControl::isNPCInView(const CString &name) const { CGameManager *gameManager = getGameManager(); if (!gameManager) return false; CViewItem *view = gameManager->getView(); if (!view) return false; // Iterate to find NPC for (CTreeItem *child = view->getFirstChild(); child; child = child->scan(view)) { CGameObject *gameObject = static_cast(child); if (gameObject) { if (!gameObject->getName().compareToIgnoreCase(name)) return true; } } return false; } void CPetControl::summonNPC(const CString &name, int val) { CGameManager *gameManager = getGameManager(); if (gameManager) { CRoomItem *room = gameManager->getRoom(); if (room) { CSummonBotMsg summonMsg(name, val); summonMsg.execute(room); } } } void CPetControl::startPetTimer(uint timerIndex, uint firstDuration, uint duration, void *target) { stopPetTimer(timerIndex); _timers[timerIndex]._id = (timerIndex, firstDuration, duration); _timers[timerIndex]._target = target; setTimer44(_timers[timerIndex]._id, 0); } void CPetControl::stopPetTimer(uint timerIndex) { if (_timers[timerIndex]._target) { stopTimer(_timers[timerIndex]._id); _timers[timerIndex]._target = nullptr; } } void CPetControl::setTimer44(int id, int val) { getGameManager()->setTimer44(id, val); } CString CPetControl::getFullViewName() { CGameManager *gameManager = getGameManager(); return gameManager ? gameManager->getFullViewName() : CString(); } } // End of namespace Titanic