/* 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 "illusions/bbdou/illusions_bbdou.h" #include "illusions/bbdou/bbdou_cursor.h" #include "illusions/bbdou/bbdou_specialcode.h" #include "illusions/actor.h" #include "illusions/camera.h" #include "illusions/dictionary.h" #include "illusions/input.h" namespace Illusions { // NOTE It's assumed there's only one game cursor object // The original stores the _data inside the actor, here it's inside the Cursor class. // BbdouCursor BbdouCursor::BbdouCursor(IllusionsEngine_BBDOU *vm, BbdouSpecialCode *bbdou) : _vm(vm), _bbdou(bbdou) { } BbdouCursor::~BbdouCursor() { } void BbdouCursor::init(uint32 objectId, uint32 progResKeywordId) { Common::Point pos = _vm->_camera->getCurrentPan(); _vm->_controls->placeActor(0x50001, pos, 0x6000C, objectId, 0); Control *control = _vm->_dict->getObjectControl(objectId); // TODO? control->_actor->setControlRoutine(new Common::Functor2Mem(this, &BbdouCursor::actorControlRoutine1)); control->_flags |= 8; _data._mode = 1; _data._mode2 = 0; _data._verbId1 = 0x1B0000; _data._progResKeywordId = progResKeywordId; _data._currOverlappedObjectId = 0; _data._overlappedObjectId = 0; _data._sequenceId = 0x6000F; _data._holdingObjectId = 0; _data._holdingObjectId2 = 0; _data._visibleCtr = 0; _data._causeThreadId1 = 0; _data._causeThreadId2 = 0; _data._field90 = 0; _data._flags = 0; _data._verbState._minPriority = 1; _data._currCursorTrackingSequenceId = 0; _data._idleCtr = 0; _data._verbState._verbId = 0x1B0000; _data._verbState._cursorState = 1; _data._verbState._isBubbleVisible = 0; _data._verbState._objectIds[0] = 0; _data._verbState._objectIds[1] = 0; _data._verbState._index = 0; _data._verbState._flag56 = false; resetActiveVerbs(); control->setActorIndexTo1(); } void BbdouCursor::enable(uint32 objectId) { ++_data._visibleCtr; if (_data._visibleCtr == 1) { Control *control = _vm->_dict->getObjectControl(objectId); show(control); _vm->_camera->pushCameraMode(); _vm->_camera->panEdgeFollow(objectId, 360); _data._idleCtr = 0; } _vm->_input->discardAllEvents(); } void BbdouCursor::disable(uint32 objectId) { hide(objectId); } void BbdouCursor::reset(uint32 objectId) { Control *control = _vm->_dict->getObjectControl(objectId); _data._verbState._cursorState = 1; _data._mode = 1; _data._mode2 = 0; _data._verbId1 = 0x1B0000; _data._currOverlappedObjectId = 0; _data._overlappedObjectId = 0; _data._sequenceId = 0x6000F; _data._holdingObjectId = 0; _data._holdingObjectId2 = 0; _data._visibleCtr = 0; _data._causeThreadId1 = 0; _data._flags = 0; _data._verbState._minPriority = 1; _data._currCursorTrackingSequenceId = 0; _data._idleCtr = 0; _data._verbState._verbId = 0x1B0000; _data._verbState._isBubbleVisible = 0; _data._verbState._objectIds[0] = 0; _data._verbState._objectIds[1] = 0; _data._verbState._index = 0; _data._verbState._flag56 = false; resetActiveVerbs(); control->setActorIndexTo1(); control->startSequenceActor(0x60029, 2, 0); _bbdou->hideVerbBubble(control->_objectId, &_data._verbState); // TODO? control->_actor->setControlRoutine(new Common::Functor2Mem(this, &BbdouCursor::cursorInteractControlRoutine)); } void BbdouCursor::addCursorSequenceId(uint32 objectId, uint32 sequenceId) { for (uint i = 0; i < kMaxCursorSequences; ++i) if (_cursorSequences[i]._objectId == 0) { _cursorSequences[i]._objectId = objectId; _cursorSequences[i]._sequenceId = sequenceId; break; } } uint32 BbdouCursor::findCursorSequenceId(uint32 objectId) { for (uint i = 0; i < kMaxCursorSequences; ++i) if (_cursorSequences[i]._objectId == objectId) return _cursorSequences[i]._sequenceId; return 0; } bool BbdouCursor::updateTrackingCursor(Control *control) { uint32 sequenceId; if (getTrackingCursorSequenceId(control, sequenceId)) { if (_data._currCursorTrackingSequenceId != sequenceId) { saveBeforeTrackingCursor(control, sequenceId); show(control); _data._currCursorTrackingSequenceId = sequenceId; } return true; } else { if (_data._currCursorTrackingSequenceId) { _data._currCursorTrackingSequenceId = 0; restoreAfterTrackingCursor(); show(control); } return false; } } void BbdouCursor::saveInfo() { _data._mode2 = _data._mode; _data._sequenceId2 = _data._sequenceId; _data._holdingObjectId2 = _data._holdingObjectId; } void BbdouCursor::restoreInfo() { _data._mode = _data._mode2; _data._holdingObjectId = _data._holdingObjectId2; _data._sequenceId = _data._sequenceId2; _data._mode2 = 0; _data._holdingObjectId2 = 0; _data._sequenceId2 = 0; } void BbdouCursor::saveBeforeTrackingCursor(Control *control, uint32 sequenceId) { if (_data._currOverlappedObjectId || _data._mode == 3) { if (_data._mode == 3) restoreInfo(); control->setActorIndexTo1(); if (_data._verbState._isBubbleVisible) _bbdou->playSoundEffect(4); _bbdou->hideVerbBubble(control->_objectId, &_data._verbState); } _data._currOverlappedObjectId = 0; if (_data._mode != 4) { saveInfo(); _data._mode = 4; _data._holdingObjectId = 0; } _data._sequenceId = sequenceId; } void BbdouCursor::restoreAfterTrackingCursor() { _data._holdingObjectId = _data._holdingObjectId2; if (_data._holdingObjectId2) { _data._mode = 2; _data._sequenceId = findCursorSequenceId(_data._holdingObjectId2); } else { _data._mode = 1; _data._sequenceId = 0x6000F; } _data._mode2 = 0; _data._sequenceId2 = 0; _data._holdingObjectId2 = 0; _data._currCursorTrackingSequenceId = 0; } uint32 BbdouCursor::getSequenceId1(int sequenceIndex) { switch (sequenceIndex) { case 2: return 0x60010; case 3: return 0x60011; case 4: return 0x60012; case 5: return 0x60013; case 6: return 0x60015; case 7: return 0x60014; default: return 0; } } uint BbdouCursor::calcTrackingFlags(Common::Point actorPos, Common::Point trackingLimits) { uint trackingFlags = 0; int16 x = actorPos.x - 320; int16 y = actorPos.y - 240; if (x < -trackingLimits.x) trackingFlags = 1; else if (x > trackingLimits.x) trackingFlags = 3; else trackingFlags = 2; if (y < -trackingLimits.y) trackingFlags += 0; else if (y > trackingLimits.y) trackingFlags += 6; else trackingFlags += 3; return trackingFlags; } uint BbdouCursor::calcTrackingCursorIndex(uint trackingFlags) { uint cursorIndex = 0; switch (trackingFlags) { case 1: if (_vm->_camera->isAtPanLimit(1)) { if (!_vm->_camera->isAtPanLimit(3)) cursorIndex = 4; } else { if (!_vm->_camera->isAtPanLimit(3)) cursorIndex = 1; else cursorIndex = 2; } break; case 2: if (!_vm->_camera->isAtPanLimit(1)) cursorIndex = 2; break; case 3: if (_vm->_camera->isAtPanLimit(1)) { if (!_vm->_camera->isAtPanLimit(4)) cursorIndex = 6; } else { if (!_vm->_camera->isAtPanLimit(4)) cursorIndex = 3; else cursorIndex = 2; } break; case 4: if (!_vm->_camera->isAtPanLimit(3)) cursorIndex = 4; break; case 6: if (!_vm->_camera->isAtPanLimit(4)) cursorIndex = 6; break; case 7: if (_vm->_camera->isAtPanLimit(2)) { if (!_vm->_camera->isAtPanLimit(3)) cursorIndex = 4; } else { if (!_vm->_camera->isAtPanLimit(3)) cursorIndex = 8; else cursorIndex = 7; } break; case 8: if (!_vm->_camera->isAtPanLimit(2)) cursorIndex = 8; break; case 9: if (_vm->_camera->isAtPanLimit(2)) { if (!_vm->_camera->isAtPanLimit(4)) cursorIndex = 6; } else { if (!_vm->_camera->isAtPanLimit(4)) cursorIndex = 9; else cursorIndex = 8; } break; } return cursorIndex; } bool BbdouCursor::getTrackingCursorSequenceId(Control *control, uint32 &outSequenceId) { static const uint32 kTrackingCursorSequenceIds[] = { 0, 0x000609BF, 0x00060018, 0x000609C0, 0x00060016, 0, 0x00060017, 0x000609C1, 0x00060019, 0x000609C2 }; Common::Point trackingLimits = _vm->_camera->getTrackingLimits(); uint trackingFlags = calcTrackingFlags(control->_actor->_position, trackingLimits); uint cursorIndex = calcTrackingCursorIndex(trackingFlags); outSequenceId = kTrackingCursorSequenceIds[cursorIndex]; return outSequenceId != 0; } void BbdouCursor::resetActiveVerbs() { for (uint i = 0; i < 32; ++i) _data._verbState._verbActive[i] = false; if (_data._verbState._cursorState == 1) { _data._verbState._verbActive[1] = true; _data._verbState._verbActive[2] = true; _data._verbState._verbActive[3] = true; _data._verbState._verbActive[5] = true; } else if (_data._verbState._cursorState == 3) { _data._verbState._verbActive[1] = true; _data._verbState._verbActive[2] = true; } } void BbdouCursor::show(Control *control) { control->startSequenceActor(_data._sequenceId, 2, 0); control->appearActor(); } void BbdouCursor::hide(uint32 objectId) { --_data._visibleCtr; if (_data._visibleCtr == 0) { Control *control = _vm->_dict->getObjectControl(objectId); control->startSequenceActor(0x60029, 2, 0); _bbdou->hideVerbBubble(objectId, &_data._verbState); _vm->_camera->popCameraMode(); } _vm->_input->discardAllEvents(); } } // End of namespace Illusions