/* 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 "hopkins/objects.h" #include "hopkins/dialogs.h" #include "hopkins/files.h" #include "hopkins/globals.h" #include "hopkins/hopkins.h" #include "common/system.h" #include "graphics/palette.h" #include "common/file.h" #include "common/rect.h" #include "engines/util.h" namespace Hopkins { ObjectsManager::ObjectsManager(HopkinsEngine *vm) { _vm = vm; for (int i = 0; i < 6; ++i) Common::fill((byte *)&_sprite[i], (byte *)&_sprite[i] + sizeof(SpriteItem), 0); for (int i = 0; i < 36; ++i) { Common::fill((byte *)&_bob[i], (byte *)&_bob[i] + sizeof(BobItem), 0); Common::fill((byte *)&_lockedAnims[i], (byte *)&_lockedAnims[i] + sizeof(LockAnimItem), 0); } for (int i = 0; i < 30; ++i) { Common::fill((byte *)&_vBob[i], (byte *)&_vBob[i] + sizeof(VBobItem), 0); } for (int i = 0; i < 300; ++i) Common::fill((byte *)&_objectAuthIcons[i], (byte *)&_objectAuthIcons[i] + sizeof(ObjectAuthIcon), 0); _sortedDisplayCount = 0; for (int i = 0; i < 51; ++i) Common::fill((byte *)&_sortedDisplay[i], (byte *)&_sortedDisplay[i] + sizeof(SortItem), 0); for (int i = 0; i < 25; ++i) Common::fill((byte *)&_hidingItem[i], (byte *)&_hidingItem[i] + sizeof(HidingItem), 0); for (int i = 0; i < 6; ++i) _hidingItemData[i] = NULL; for (int i = 0; i < 6; ++i) Common::fill((byte *)&_liste[i], (byte *)&_liste[i] + sizeof(ListeItem), 0); for (int i = 0; i < 35; ++i) Common::fill((byte *)&_liste2[i], (byte *)&_liste2[i] + sizeof(ListeItem), 0); _helicopterFl = false; _priorityFl = false; _oldBorderPos = Common::Point(0, 0); _oldBorderSpriteIndex = 0; _borderPos = Common::Point(0, 0); _borderSpriteIndex = 0; _saveLoadX = _saveLoadY = 0; _oldCharacterPosX = _oldCharacterPosY = 0; _eraseVisibleCounter = 0; _saveLoadSprite = NULL; _saveLoadSprite2 = NULL; _spritePtr = NULL; _oldSpriteData = NULL; _saveLoadFl = false; _visibleFl = false; _zoneNum = 0; _forceZoneFl = false; _changeVerbFl = false; _verb = 0; _changeHeadFl = false; _disableFl = false; _twoCharactersFl = false; _characterPos = Common::Point(0, 0); _startSpriteIndex = 0; _jumpVerb = 0; _jumpZone = 0; _oldSpriteIndex = 0; _oldFrameIndex = 0; _oldFlipFl = false; _curObjectIndex = 0; _forestFl = false; _mapCarPosX = _mapCarPosY = 0; _forestSprite = NULL; _gestureBuf = NULL; _curGestureFile = 0; _headSprites = NULL; _homeRateCounter = 0; _lastDirection = DIR_NONE; _oldDirection = DIR_NONE; _oldDirectionSpriteIdx = 59; _objectWidth = _objectHeight = 0; _hidingActiveFl = false; _curObjectFileNum = 0; _objectDataBuf = NULL; _charactersEnabledFl = false; _refreshBobMode10Fl = false; } ObjectsManager::~ObjectsManager() { _vm->_globals->freeMemory(_forestSprite); _vm->_globals->freeMemory(_gestureBuf); _vm->_globals->freeMemory(_headSprites); _vm->_globals->freeMemory(_objectDataBuf); clearVBob(); for (int idx = 0; idx < 6; ++idx) _hidingItemData[idx] = _vm->_globals->freeMemory(_hidingItemData[idx]); } void ObjectsManager::clearAll() { _forestFl = false; _forestSprite = _vm->_globals->freeMemory(_forestSprite); _curGestureFile = 0; _gestureBuf = _vm->_globals->freeMemory(_gestureBuf); _curObjectFileNum = 0; for (int idx = 0; idx < 6; ++idx) _hidingItemData[idx] = _vm->_globals->freeMemory(_hidingItemData[idx]); _objectDataBuf = _vm->_globals->freeMemory(_objectDataBuf); initVBob(); } // Load Object void ObjectsManager::loadObjects() { byte *data = _vm->_fileIO->loadFile("OBJET.DAT"); byte *srcP = data; for (int idx = 0; idx < 300; ++idx) { ObjectAuthIcon *objectAuthIcon = &_objectAuthIcons[idx]; objectAuthIcon->_objectFileNum = *srcP++; objectAuthIcon->_idx = *srcP++; objectAuthIcon->_flag1 = *srcP++; objectAuthIcon->_flag2 = *srcP++; objectAuthIcon->_flag3 = *srcP++; objectAuthIcon->_flag4 = *srcP++; objectAuthIcon->_flag5 = *srcP++; objectAuthIcon->_flag6 = *srcP++; } _vm->_globals->freeMemory(data); } // Reset Hiding Items void ObjectsManager::resetHidingItems() { for (int idx = 1; idx <= 5; ++idx) { _hidingItemData[idx] = _vm->_globals->freeMemory(_hidingItemData[idx]); } for (int idx = 0; idx <= 20; ++idx) { HidingItem *hid = &_hidingItem[idx]; hid->_spriteData = NULL; hid->_x = 0; hid->_y = 0; hid->_spriteIndex = 0; hid->_useCount = 0; hid->_width = 0; hid->_height = 0; hid->_resetUseCount = false; hid->_yOffset = 0; } _hidingActiveFl = false; } /** * Change Object */ void ObjectsManager::changeObject(int objIndex) { _vm->_events->_objectBuf = loadObjectFromFile(objIndex, true); _curObjectIndex = objIndex; } byte *ObjectsManager::loadObjectFromFile(int objIndex, bool mode) { byte *dataP = NULL; int objectFileNum = _objectAuthIcons[objIndex]._objectFileNum; int idx = _objectAuthIcons[objIndex]._idx; if (mode) ++idx; if (objectFileNum != _curObjectFileNum) { if (_objectDataBuf) removeObjectDataBuf(); if (objectFileNum == 1) { _objectDataBuf = loadSprite("OBJET1.SPR"); } _curObjectFileNum = objectFileNum; } int width = getWidth(_objectDataBuf, idx); int height = getHeight(_objectDataBuf, idx); _objectWidth = width; _objectHeight = height; if (mode) { sprite_alone(_objectDataBuf, _vm->_events->_objectBuf, idx); dataP = _vm->_events->_objectBuf; } else { dataP = _vm->_globals->allocMemory(height * width); if (dataP == NULL) error("CAPTURE_OBJET"); capture_mem_sprite(_objectDataBuf, dataP, idx); } return dataP; } /** * Remove an Object from the inventory */ void ObjectsManager::removeObject(int objIndex) { int idx; for (idx = 1; idx <= 32; ++idx) { if (_vm->_globals->_inventory[idx] == objIndex) break; } if (idx <= 32) { if (idx == 32) { _vm->_globals->_inventory[32] = 0; } else { for (int i = idx; i < 32; ++i) _vm->_globals->_inventory[i] = _vm->_globals->_inventory[i + 1]; } } changeObject(14); } /** * Set Offset XY */ void ObjectsManager::setOffsetXY(byte *data, int idx, int xp, int yp, bool isSize) { byte *startP = data + 3; for (int i = idx; i; --i) startP += READ_LE_UINT32(startP) + 16; byte *rectP = startP + 8; if (isSize) { // Set size byte *pointP = rectP + 4; WRITE_LE_UINT16(pointP, xp); WRITE_LE_UINT16(pointP + 2, yp); } else { // Set position WRITE_LE_UINT16(rectP, xp); WRITE_LE_UINT16(rectP + 2, yp); } } int ObjectsManager::getOffsetX(const byte *spriteData, int spriteIndex, bool isSize) { const byte *data = spriteData + 3; for (int i = spriteIndex; i; --i) data += READ_LE_UINT32(data) + 16; int result; if (isSize) result = READ_LE_INT16(data + 12); else result = READ_LE_INT16(data + 8); return result; } int ObjectsManager::getOffsetY(const byte *spriteData, int spriteIndex, bool isSize) { const byte *data = spriteData + 3; for (int i = spriteIndex; i; --i) data += READ_LE_UINT32(data) + 16; int result; if (isSize) result = READ_LE_INT16(data + 14); else result = READ_LE_INT16(data + 10); return result; } /** * Get Width */ int ObjectsManager::getWidth(const byte *objectData, int idx) { const byte *rectP = objectData + 3; for (int i = idx; i; --i) rectP += READ_LE_UINT32(rectP) + 16; return READ_LE_INT16(rectP + 4); } /** * Get height */ int ObjectsManager::getHeight(const byte *objectData, int idx) { const byte *rectP = objectData + 3; for (int i = idx; i; --i) rectP += READ_LE_UINT32(rectP) + 16; return READ_LE_INT16(rectP + 6); } void ObjectsManager::sprite_alone(const byte *objectData, byte *sprite, int objIndex) { const byte *objP = objectData + 3; for (int i = objIndex; i; --i) { objP += READ_LE_UINT32(objP) + 16; } objP += 4; int result = READ_LE_INT16(objP) * READ_LE_INT16(objP + 2); memcpy(sprite + 3, objP - 4, result + 16); } void ObjectsManager::capture_mem_sprite(const byte *objectData, byte *sprite, int objIndex) { const byte *objP = objectData + 3; for (int i = objIndex; i; --i) { objP += READ_LE_UINT32(objP) + 16; } objP += 4; int result = READ_LE_INT16(objP) * READ_LE_INT16(objP + 2); memcpy(sprite, objP + 12, result); } void ObjectsManager::removeObjectDataBuf() { _curObjectFileNum = 0; _objectDataBuf = _vm->_globals->freeMemory(_objectDataBuf); } /** * Load Sprite from file */ byte *ObjectsManager::loadSprite(const Common::String &file) { return _vm->_fileIO->loadFile(file); } /** * Add Object */ void ObjectsManager::addObject(int objIndex) { int arrIndex = 0; for (;;) { ++arrIndex; if ((!_vm->_globals->_inventory[arrIndex]) || (arrIndex == 32)) break; } _vm->_globals->_inventory[arrIndex] = objIndex; } /** * Display Sprite */ void ObjectsManager::displaySprite() { int clipX; int clipY; uint16 arr[50]; // Handle copying any background areas that text are going to be drawn on _sortedDisplayCount = 0; for (int idx = 0; idx <= 10; ++idx) { TxtItemList *curTxtList = &_vm->_fontMan->_textList[idx]; if (curTxtList->_enabledFl && _vm->_fontMan->_text[idx]._textType != 2) { clipX = curTxtList->_pos.x - 2; if (clipX < _vm->_graphicsMan->_minX) clipX = _vm->_graphicsMan->_minX; clipY = curTxtList->_pos.y - 2; if (clipY < _vm->_graphicsMan->_minY) clipY = _vm->_graphicsMan->_minY; _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, clipX, clipY, curTxtList->_width + 4, curTxtList->_height + 4, _vm->_graphicsMan->_frontBuffer, clipX, clipY); curTxtList->_enabledFl = false; } } if (!_charactersEnabledFl) { for (int idx = 0; idx < MAX_SPRITE; ++idx) { ListeItem *curList = &_liste[idx]; if (curList->_visibleFl) { clipX = curList->_posX - 2; if (clipX < _vm->_graphicsMan->_minX) clipX = _vm->_graphicsMan->_minX; clipY = curList->_posY - 2; if (clipY < _vm->_graphicsMan->_minY) clipY = _vm->_graphicsMan->_minY; _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, clipX, clipY, curList->_width + 4, curList->_height + 4, _vm->_graphicsMan->_frontBuffer, clipX, clipY); curList->_visibleFl = false; } } } displayBobAnim(); displayVBob(); if (!_charactersEnabledFl) { // Handle drawing characters on the screen for (int idx = 0; idx < MAX_SPRITE; ++idx) { _liste[idx]._visibleFl = false; SpriteItem *curSpr = &_sprite[idx]; if (curSpr->_animationType == 1) { computeSprite(idx); if (curSpr->_activeFl) beforeSort(SORT_SPRITE, idx, curSpr->_height + curSpr->_destY); } } if (_hidingActiveFl) checkHidingItem(); } if (_priorityFl && _sortedDisplayCount) { for (int i = 1; i <= 48; i++) arr[i] = i; bool loopCondFl; do { loopCondFl = false; for (int sortIdx = 1; sortIdx < _sortedDisplayCount; sortIdx++) { if (_sortedDisplay[arr[sortIdx]]._priority > _sortedDisplay[arr[sortIdx + 1]]._priority) { SWAP(arr[sortIdx], arr[sortIdx + 1]); loopCondFl = true; } } } while (loopCondFl); for (int sortIdx = 1; sortIdx < _sortedDisplayCount + 1; sortIdx++) { int idx = arr[sortIdx]; switch (_sortedDisplay[idx]._sortMode) { case SORT_BOB: setBobInfo(_sortedDisplay[idx]._index); break; case SORT_SPRITE: showSprite(_sortedDisplay[idx]._index); break; case SORT_HIDING: displayHiding(_sortedDisplay[idx]._index); break; default: break; } _sortedDisplay[idx]._sortMode = SORT_NONE; } } else { for (int idx = 1; idx < _sortedDisplayCount + 1; ++idx) { switch (_sortedDisplay[idx]._sortMode) { case SORT_BOB: setBobInfo(_sortedDisplay[idx]._index); break; case SORT_SPRITE: showSprite(_sortedDisplay[idx]._index); break; case SORT_HIDING: displayHiding(_sortedDisplay[idx]._index); break; default: break; } _sortedDisplay[idx]._sortMode = SORT_NONE; } } // Reset the Sort array for (int idx = 0; idx < 50; ++idx) { SortItem *disp = &_sortedDisplay[idx]; disp->_sortMode = SORT_NONE; disp->_index = 0; disp->_priority = 0; } _sortedDisplayCount = 0; _vm->_dialog->drawInvent(_oldBorderPos, _oldBorderSpriteIndex, _borderPos, _borderSpriteIndex); if (_saveLoadFl) { int16 posX = _vm->_events->_startPos.x; _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, _saveLoadSprite, posX + 183, 60, 274, 353); if (_saveLoadX && _saveLoadY) _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _saveLoadSprite2, _saveLoadX + posX + 300, _saveLoadY + 300, 0); _vm->_graphicsMan->addDirtyRect(posX + 183, 60, posX + 457, 413); } // If the Options dialog is activated, draw the elements if (_vm->_globals->_optionDialogFl) { int16 posX = _vm->_events->_startPos.x; _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr, posX + 464, 407, 0); _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr, posX + 657, 556, _vm->_globals->_menuSpeed); _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr, posX + 731, 495, _vm->_globals->_menuTextOff); _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr, posX + 731, 468, _vm->_globals->_menuVoiceOff); _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr, posX + 731, 441, _vm->_globals->_menuSoundOff); _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr, posX + 731, 414, _vm->_globals->_menuMusicOff); _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr, posX + 600, 522, _vm->_globals->_menuDisplayType); _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr, posX + 611, 502, _vm->_globals->_menuScrollSpeed); _vm->_graphicsMan->addDirtyRect(posX + 164, 107, posX + 498, 320); } // Loop to draw any on-screen text for (int idx = 0; idx <= 10; ++idx) { TxtItem *curTxt = &_vm->_fontMan->_text[idx]; if (curTxt->_textOnFl) { TxtItemList *curTxtList = &_vm->_fontMan->_textList[idx]; if ((curTxt->_textType < 2) || (curTxt->_textType > 3)) _vm->_fontMan->box(idx, curTxt->_messageId, curTxt->_filename, _vm->_events->_startPos.x + curTxt->_pos.x, curTxt->_pos.y); else _vm->_fontMan->box(idx, curTxt->_messageId, curTxt->_filename, curTxt->_pos.x, curTxt->_pos.y); curTxtList->_enabledFl = true; if ((curTxt->_textType < 2) || (curTxt->_textType > 3)) curTxtList->_pos.x = _vm->_events->_startPos.x + curTxt->_pos.x; else curTxtList->_pos.x = curTxt->_pos.x; curTxtList->_pos.y = curTxt->_pos.y; curTxtList->_width = curTxt->_width; curTxtList->_height = curTxt->_height; if (curTxtList->_pos.x < _vm->_graphicsMan->_minX) curTxtList->_pos.x = _vm->_graphicsMan->_minX - 1; if (curTxtList->_pos.y < _vm->_graphicsMan->_minY) curTxtList->_pos.y = _vm->_graphicsMan->_minY - 1; int posX = curTxtList->_pos.x; if (curTxtList->_width + posX > _vm->_graphicsMan->_maxX) curTxtList->_width = _vm->_graphicsMan->_maxX - posX; int posY = curTxtList->_pos.y; if (curTxtList->_height + posY > _vm->_graphicsMan->_maxY) curTxtList->_height = _vm->_graphicsMan->_maxY - posY; if (curTxtList->_width <= 0 || curTxtList->_height <= 0) curTxtList->_enabledFl = false; } } _vm->_dialog->inventAnim(); } void ObjectsManager::resetBob(int idx) { BobItem &bob = _bob[idx]; ListeItem &item = _liste2[idx]; bob._bobMode = 0; bob._spriteData = NULL; bob._xp = 0; bob._yp = 0; bob._frameIndex = 0; bob._animDataIdx = 0; bob._moveChange1 = 0; bob._moveChange2 = 0; bob._disabledAnimationFl = false; bob._animData = NULL; bob._bobMode10 = false; bob._bobModeChange = 0; bob._modeChangeCtr = 0; bob._modeChangeUnused = 0; bob._disableFl = false; bob._zoomFactor = 0; bob._flipFl = false; bob._oldX2 = 0; item._visibleFl = false; item._posX = 0; item._posY = 0; item._width = 0; item._height = 0; } void ObjectsManager::setBobInfo(int idx) { BobItem *curBob = &_bob[idx]; if (!curBob->_activeFl) return; int xp = curBob->_oldX; int yp = curBob->_oldY; if (curBob->_isSpriteFl) _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, curBob->_spriteData, xp + 300, yp + 300, curBob->_frameIndex); else _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, curBob->_spriteData, xp + 300, yp + 300, curBob->_frameIndex, curBob->_zoomOutFactor, curBob->_zooInmFactor, curBob->_flipFl); ListeItem *curLst = &_liste2[idx]; curLst->_visibleFl = true; curLst->_posX = xp; curLst->_posY = yp; curLst->_width = curBob->_oldWidth; curLst->_height = curBob->_oldHeight; if (curLst->_posX < _vm->_graphicsMan->_minX) { curLst->_width -= _vm->_graphicsMan->_minX - curLst->_posX; curLst->_posX = _vm->_graphicsMan->_minX; } if (curLst->_posY < _vm->_graphicsMan->_minY) { curLst->_height -= _vm->_graphicsMan->_minY - curLst->_posY; curLst->_posY = _vm->_graphicsMan->_minY; } if (curLst->_width + curLst->_posX > _vm->_graphicsMan->_maxX) curLst->_width = _vm->_graphicsMan->_maxX - curLst->_posX; if (curLst->_height + curLst->_posY > _vm->_graphicsMan->_maxY) curLst->_height = _vm->_graphicsMan->_maxY - curLst->_posY; if (curLst->_width <= 0 || curLst->_height <= 0) curLst->_visibleFl = false; if (curLst->_visibleFl) _vm->_graphicsMan->addDirtyRect(curLst->_posX, curLst->_posY, curLst->_posX + curLst->_width, curLst->_posY + curLst->_height); } void ObjectsManager::displayBob(int idx) { BobItem *curBob = &_bob[idx]; _priorityFl = true; if (curBob->_bobMode) return; resetBob(idx); const byte *data = _vm->_animMan->_animBqe[idx]._data; int bankIdx = READ_LE_INT16(data); if (!bankIdx) return; if ((!_vm->_animMan->Bank[bankIdx]._loadedFl) || (!READ_LE_UINT16(data + 24))) return; int16 bobModeChange = READ_LE_INT16(data + 2); int16 modeChangeUnused = READ_LE_INT16(data + 4); // data[6] isn't used, read skipped int16 newModeChangeCtr = READ_LE_INT16(data + 8); if (!bobModeChange) bobModeChange = 1; if (!newModeChangeCtr) newModeChangeCtr = -1; curBob->_isSpriteFl = false; if (_vm->_animMan->Bank[bankIdx]._fileHeader == 1) { curBob->_isSpriteFl = true; curBob->_zoomFactor = 0; curBob->_flipFl = false; } curBob->_animData = _vm->_animMan->_animBqe[idx]._data; curBob->_bobMode = 10; curBob->_spriteData = _vm->_animMan->Bank[bankIdx]._data; curBob->_bobModeChange = bobModeChange; curBob->_modeChangeCtr = newModeChangeCtr; curBob->_modeChangeUnused = modeChangeUnused; } void ObjectsManager::hideBob(int idx) { BobItem *curBob = &_bob[idx]; if ((curBob->_bobMode == 3) || (curBob->_bobMode == 10)) curBob->_bobMode++; } void ObjectsManager::setBobOffset(int idx, int offset) { _bob[idx]._oldX2 = offset; } void ObjectsManager::computeHideCounter(int idx) { HidingItem *hid = &_hidingItem[idx]; if (hid->_useCount == 0) return; for (int i = 0; i <= 20; i++) { BobItem *curBob = &_bob[i]; if ((curBob->_bobMode) && (!curBob->_disabledAnimationFl) && (!curBob->_disableFl) && (curBob->_frameIndex != 250)) { int oldRight = curBob->_oldX + curBob->_oldWidth; int oldBottom = curBob->_oldY + curBob->_oldHeight; int hiddenRight = hid->_x + hid->_width; if ((oldBottom > hid->_y) && (oldBottom < hid->_yOffset + hid->_height + hid->_y)) { if ((oldRight >= hid->_x && oldRight <= hiddenRight) // CHECKME: The original was doing the test two times. This looks like an // original bug // || (cachedRight >= curBob->_oldWidth && curBob->_oldWidth >= hid->_x) || (hiddenRight >= curBob->_oldWidth && curBob->_oldWidth >= hid->_x) || (curBob->_oldWidth >= hid->_x && oldRight <= hiddenRight) || (curBob->_oldWidth <= hid->_x && oldRight >= hiddenRight)) ++hid->_useCount; } } } } void ObjectsManager::initBobVariables(int idx) { BobItem *bob = &_bob[idx]; bob->_activeFl = false; if (bob->_isSpriteFl) { bob->_flipFl = false; bob->_zoomFactor = 0; } int spriteIdx = bob->_frameIndex; if (spriteIdx == 250) return; int deltaY, deltaX; if (bob->_flipFl) { deltaX = getOffsetX(bob->_spriteData, spriteIdx, true); deltaY = getOffsetY(bob->_spriteData, bob->_frameIndex, true); } else { deltaX = getOffsetX(bob->_spriteData, spriteIdx, false); deltaY = getOffsetY(bob->_spriteData, bob->_frameIndex, false); } int negZoom = 0; int posZoom = 0; if (bob->_zoomFactor < 0) negZoom = CLIP(-bob->_zoomFactor, 0, 95); else posZoom = bob->_zoomFactor; if (posZoom) { if (deltaX >= 0) deltaX = _vm->_graphicsMan->zoomIn(deltaX, posZoom); else deltaX = -_vm->_graphicsMan->zoomIn(-deltaX, posZoom); if (deltaY >= 0) deltaY = _vm->_graphicsMan->zoomIn(deltaY, posZoom); else deltaY = -_vm->_graphicsMan->zoomIn(abs(deltaX), posZoom); } if (negZoom) { if (deltaX >= 0) deltaX = _vm->_graphicsMan->zoomOut(deltaX, negZoom); else deltaX = -_vm->_graphicsMan->zoomOut(-deltaX, negZoom); if (deltaY >= 0) deltaY = _vm->_graphicsMan->zoomOut(deltaY, negZoom); else deltaY = -_vm->_graphicsMan->zoomOut(abs(deltaX), negZoom); } int newX = bob->_xp - deltaX; int newY = bob->_yp - deltaY; bob->_activeFl = true; bob->_oldX = newX; bob->_oldY = newY; bob->_zooInmFactor = posZoom; bob->_zoomOutFactor = negZoom; ListeItem *curList = &_liste2[idx]; curList->_visibleFl = true; curList->_posX = newX; curList->_posY = newY; int width = getWidth(bob->_spriteData, bob->_frameIndex); int height = getHeight(bob->_spriteData, bob->_frameIndex); if (posZoom) { width = _vm->_graphicsMan->zoomIn(width, posZoom); height = _vm->_graphicsMan->zoomIn(height, posZoom); } else if (negZoom) { width = _vm->_graphicsMan->zoomOut(width, negZoom); height = _vm->_graphicsMan->zoomOut(height, negZoom); } curList->_width = width; curList->_height = height; bob->_oldWidth = width; bob->_oldHeight = height; } void ObjectsManager::checkHidingItem() { for (int hidingItemIdx = 0; hidingItemIdx <= 19; hidingItemIdx++) { HidingItem *hid = &_hidingItem[hidingItemIdx]; if (hid->_useCount == 0) continue; int _oldUseCount = hid->_useCount; for (int spriteIdx = 0; spriteIdx <= 4; spriteIdx++) { const SpriteItem *spr = &_sprite[spriteIdx]; if (spr->_animationType == 1 && spr->_spriteIndex != 250) { int right = spr->_width + spr->_destX; int bottom = spr->_height + spr->_destY; int hidingRight = hid->_width + hid->_x; if (bottom > hid->_y && bottom < (hid->_yOffset + hid->_height + hid->_y)) { if ((right >= hid->_x && right <= hidingRight) // CHECKME: The original was doing the test two times. This looks like an // original bug // || (hidingRight >= spr->_destX && hid->_x <= spr->_destX) || (hidingRight >= spr->_destX && hid->_x <= spr->_destX) || (hid->_x <= spr->_destX && right <= hidingRight) || (hid->_x >= spr->_destX && right >= hidingRight)) ++hid->_useCount; } } } computeHideCounter(hidingItemIdx); if (hid->_useCount != _oldUseCount) { int priority = hid->_yOffset + hid->_height + hid->_y; if (priority > 440) priority = 500; beforeSort(SORT_HIDING, hidingItemIdx, priority); hid->_useCount = 1; hid->_resetUseCount = true; } else if (hid->_resetUseCount) { hid->_resetUseCount = false; hid->_useCount = 1; } } } void ObjectsManager::showSprite(int idx) { SpriteItem *spr = &_sprite[idx]; if (!spr->_activeFl) return; if (spr->_rleFl) _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, spr->_spriteData, spr->_destX + 300, spr->_destY + 300, spr->_spriteIndex); else _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, spr->_spriteData, spr->_destX + 300, spr->_destY + 300, spr->_spriteIndex, spr->_reducePct, spr->_zoomPct, spr->_flipFl); ListeItem *list = &_liste[idx]; list->_width = spr->_width; list->_height = spr->_height; if (list->_posX < _vm->_graphicsMan->_minX) { list->_width -= _vm->_graphicsMan->_minX - list->_posX; list->_posX = _vm->_graphicsMan->_minX; } if (list->_posY < _vm->_graphicsMan->_minY) { list->_height -= _vm->_graphicsMan->_minY - list->_posY; list->_posY = _vm->_graphicsMan->_minY; } list->_width = MIN(list->_width, _vm->_graphicsMan->_maxX - list->_posX); list->_height = MIN(list->_height, _vm->_graphicsMan->_maxY - list->_posY); if (list->_width <= 0 || list->_height <= 0) list->_visibleFl = false; if (list->_visibleFl) _vm->_graphicsMan->addDirtyRect( list->_posX, list->_posY, list->_posX + list->_width, list->_posY + list->_height); } void ObjectsManager::displayHiding(int idx) { HidingItem *hid = &_hidingItem[idx]; _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _hidingItemData[1], hid->_x + 300, hid->_y + 300, hid->_spriteIndex); _vm->_graphicsMan->addDirtyRect(hid->_x, hid->_y, hid->_x + hid->_width, hid->_y + hid->_height); } // Compute Sprite void ObjectsManager::computeSprite(int idx) { SpriteItem *spr = &_sprite[idx]; spr->_activeFl = false; int spriteIndex = spr->_spriteIndex; if (spriteIndex == 250) return; int offX; int offY; if (spr->_flipFl) { offX = getOffsetX(spr->_spriteData, spriteIndex, true); offY = getOffsetY(spr->_spriteData, spr->_spriteIndex, true); } else { offX = getOffsetX(spr->_spriteData, spriteIndex, false); offY = getOffsetY(spr->_spriteData, spr->_spriteIndex, false); } int tmpX = spr->_deltaX + offX; int deltaX = tmpX; int tmpY = spr->_deltaY + offY; int deltaY = tmpY; int zoomPercent = 0; int reducePercent = 0; if (spr->_zoomFactor < 0) { reducePercent = -spr->_zoomFactor; if (reducePercent > 95) reducePercent = 95; } else zoomPercent = spr->_zoomFactor; if (zoomPercent) { if (tmpX >= 0) deltaX = _vm->_graphicsMan->zoomIn(tmpX, zoomPercent); else deltaX = -_vm->_graphicsMan->zoomIn(-tmpX, zoomPercent); if (tmpY >= 0) { deltaY = _vm->_graphicsMan->zoomIn(tmpY, zoomPercent); } else { tmpY = abs(tmpX); deltaY = -_vm->_graphicsMan->zoomIn(tmpY, zoomPercent); } } else if (reducePercent) { if (tmpX >= 0) deltaX = _vm->_graphicsMan->zoomOut(tmpX, reducePercent); else deltaX = -_vm->_graphicsMan->zoomOut(-tmpX, reducePercent); if (tmpY >= 0) { deltaY = _vm->_graphicsMan->zoomOut(tmpY, reducePercent); } else { tmpY = abs(tmpX); deltaY = -_vm->_graphicsMan->zoomOut(tmpY, reducePercent); } } int newPosX = spr->_spritePos.x - deltaX; int newPosY = spr->_spritePos.y - deltaY; spr->_destX = newPosX; spr->_destY = newPosY; spr->_activeFl = true; spr->_zoomPct = zoomPercent; spr->_reducePct = reducePercent; _liste[idx]._visibleFl = true; _liste[idx]._posX = newPosX; _liste[idx]._posY = newPosY; int width = getWidth(spr->_spriteData, spr->_spriteIndex); int height = getHeight(spr->_spriteData, spr->_spriteIndex); if (zoomPercent) { width = _vm->_graphicsMan->zoomIn(width, zoomPercent); height = _vm->_graphicsMan->zoomIn(height, zoomPercent); } else if (reducePercent) { height = _vm->_graphicsMan->zoomOut(height, reducePercent); width = _vm->_graphicsMan->zoomOut(width, reducePercent); } spr->_width = width; spr->_height = height; } // Before Sort void ObjectsManager::beforeSort(SortMode sortMode, int index, int priority) { ++_sortedDisplayCount; assert(_sortedDisplayCount <= 48); _sortedDisplay[_sortedDisplayCount]._sortMode = sortMode; _sortedDisplay[_sortedDisplayCount]._index = index; _sortedDisplay[_sortedDisplayCount]._priority = priority; } // Display BOB Anim void ObjectsManager::displayBobAnim() { for (int idx = 1; idx <= 35; idx++) { BobItem *bob = &_bob[idx]; if (idx <= 20 && _charactersEnabledFl) { bob->_bobMode10 = false; continue; } if (bob->_bobMode != 10) continue; bob->_bobMode10 = false; if (bob->_animData == NULL || bob->_disabledAnimationFl || bob->_modeChangeCtr == 0 || bob->_modeChangeCtr < -1) { if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2) bob->_bobMode10 = true; continue; } if (bob->_moveChange1 == bob->_moveChange2) { bob->_bobMode10 = true; } else { bob->_moveChange2++; bob->_bobMode10 = false; } if (!bob->_bobMode10) { if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2) bob->_bobMode10 = true; continue; } byte *dataPtr = bob->_animData + 20; int dataIdx = bob->_animDataIdx; bob->_xp = READ_LE_INT16(dataPtr + 2 * dataIdx); if (_lockedAnims[idx]._enableFl) bob->_xp = _lockedAnims[idx]._posX; if ( _charactersEnabledFl && idx > 20) bob->_xp += _vm->_events->_startPos.x; bob->_yp = READ_LE_INT16(dataPtr + 2 * dataIdx + 2); bob->_moveChange1 = READ_LE_INT16(dataPtr + 2 * dataIdx + 4); bob->_zoomFactor = READ_LE_INT16(dataPtr + 2 * dataIdx + 6); bob->_frameIndex = dataPtr[2 * dataIdx + 8]; bob->_flipFl = (dataPtr[2 * dataIdx + 9] != 0); bob->_animDataIdx += 5; if (bob->_moveChange1 > 0) { bob->_moveChange1 /= _vm->_globals->_speed; if (bob->_moveChange1 > 0) { bob->_moveChange2 = 1; if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2) bob->_bobMode10 = true; continue; } bob->_moveChange1 = 1; } if (!bob->_moveChange1) { if (bob->_modeChangeCtr > 0) bob->_modeChangeCtr--; if (bob->_modeChangeCtr != -1 && bob->_modeChangeCtr <= 0) { bob->_bobMode = 11; } else { bob->_animDataIdx = 0; byte *bobData = bob->_animData + 20; bob->_xp = READ_LE_INT16(bobData); if (_lockedAnims[idx]._enableFl) bob->_xp = _lockedAnims[idx]._posX; if (_charactersEnabledFl && idx > 20) bob->_xp += _vm->_events->_startPos.x; bob->_yp = READ_LE_INT16(bobData + 2); bob->_moveChange1 = READ_LE_INT16(bobData + 4); bob->_zoomFactor = READ_LE_INT16(bobData + 6); bob->_frameIndex = bobData[8]; bob->_flipFl = (bobData[9] != 0); bob->_animDataIdx += 5; if (bob->_moveChange1 > 0) { bob->_moveChange1 /= _vm->_globals->_speed; // Original code. It can't be negative, so the check is on == 0 if (bob->_moveChange1 <= 0) bob->_moveChange1 = 1; } } } bob->_moveChange2 = 1; if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2) bob->_bobMode10 = true; } if (!_charactersEnabledFl && _refreshBobMode10Fl) { for (int i = 0; i < 35; i++) { BobItem *curBob = &_bob[i]; if (curBob->_bobMode == 10 && !curBob->_disabledAnimationFl) curBob->_bobMode10 = true; } } _refreshBobMode10Fl = false; for (int i = 1; i <= 35; i++) { BobItem *curBob = &_bob[i]; ListeItem *curList = &_liste2[i]; if (i > 20 || !_charactersEnabledFl) { if ((curBob->_bobMode == 10) && (curBob->_bobMode10)) { if ((curBob->_bobModeChange != 2) && (curBob->_bobModeChange != 4)) { if (curList->_visibleFl) { _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, curList->_posX, curList->_posY, curList->_width, curList->_height, _vm->_graphicsMan->_frontBuffer, curList->_posX, curList->_posY); curList->_visibleFl = false; } } } if (curBob->_bobMode == 11) { if (curList->_visibleFl) { _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, curList->_posX, curList->_posY, curList->_width, curList->_height, _vm->_graphicsMan->_frontBuffer, curList->_posX, curList->_posY); curList->_visibleFl = false; } curBob->_bobMode = 0; } } } for (int i = 1; i <= 35; i++) { BobItem *curBob = &_bob[i]; curBob->_oldY = 0; if (curBob->_bobMode == 10 && !curBob->_disabledAnimationFl && curBob->_bobMode10) { initBobVariables(i); int priority = curBob->_oldX2 + curBob->_oldHeight + curBob->_oldY; if (priority > 450) priority = 600; if (curBob->_activeFl) beforeSort(SORT_BOB, i, priority); } } } // Display VBOB void ObjectsManager::displayVBob() { int width, height; for (int idx = 0; idx <= 29; idx++) { VBobItem *vbob = &_vBob[idx]; if (vbob->_displayMode == 4) { width = getWidth(vbob->_spriteData, vbob->_frameIndex); height = getHeight(vbob->_spriteData, vbob->_frameIndex); _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_backBuffer, vbob->_surface, vbob->_xp, vbob->_yp, width, height); _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, vbob->_surface, vbob->_xp, vbob->_yp, width, height); _vm->_graphicsMan->addDirtyRect(vbob->_xp, vbob->_yp, vbob->_xp + width, height + vbob->_yp); vbob->_surface = _vm->_globals->freeMemory(vbob->_surface); vbob->_displayMode = 0; vbob->_spriteData = NULL; vbob->_xp = 0; vbob->_yp = 0; vbob->_oldX = 0; vbob->_oldY = 0; vbob->_frameIndex = 0; vbob->_oldFrameIndex = 0; vbob->_oldSpriteData = NULL; } if (vbob->_displayMode == 3) { width = getWidth(vbob->_oldSpriteData, vbob->_oldFrameIndex); height = getHeight(vbob->_oldSpriteData, vbob->_oldFrameIndex); _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_backBuffer, vbob->_surface, vbob->_oldX, vbob->_oldY, width, height); _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, vbob->_surface, vbob->_oldX, vbob->_oldY, width, height); _vm->_graphicsMan->addDirtyRect(vbob->_oldX, vbob->_oldY, vbob->_oldX + width, vbob->_oldY + height); vbob->_displayMode = 1; vbob->_oldSpriteData = vbob->_spriteData; vbob->_surface = _vm->_globals->freeMemory(vbob->_surface); vbob->_oldX = vbob->_xp; vbob->_oldY = vbob->_yp; vbob->_oldFrameIndex = vbob->_frameIndex; } if (vbob->_displayMode == 1) { width = getWidth(vbob->_spriteData, vbob->_frameIndex); height = getHeight(vbob->_spriteData, vbob->_frameIndex); vbob->_surface = _vm->_globals->freeMemory(vbob->_surface); byte *surface = _vm->_globals->allocMemory(height * width); vbob->_surface = surface; _vm->_graphicsMan->copySurfaceRect(_vm->_graphicsMan->_backBuffer, surface, vbob->_xp, vbob->_yp, width, height); if (*vbob->_spriteData == 78) { _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_backBuffer, vbob->_spriteData, vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex, 0, 0, false); _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, vbob->_spriteData, vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex, 0, 0, false); } else { _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, vbob->_spriteData, vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex); _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_backBuffer, vbob->_spriteData, vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex); } _vm->_graphicsMan->addDirtyRect(vbob->_xp, vbob->_yp , vbob->_xp + width, vbob->_yp + height); vbob->_displayMode = 2; } } } /** * Get Sprite X coordinate */ int ObjectsManager::getSpriteX(int idx) { assert(idx <= MAX_SPRITE); return _sprite[idx]._spritePos.x; } /** * Get Sprite Y coordinate */ int ObjectsManager::getSpriteY(int idx) { assert(idx <= MAX_SPRITE); return _sprite[idx]._spritePos.y; } /** * Clear sprite structure */ void ObjectsManager::clearSprite() { for (int idx = 0; idx < MAX_SPRITE; idx++) { _sprite[idx]._spriteData = NULL; _sprite[idx]._animationType = 0; } for (int idx = 0; idx < MAX_SPRITE; idx++) { ListeItem *list = &_liste[idx]; list->_visibleFl = false; list->_posX = 0; list->_posY = 0; list->_width = 0; list->_height = 0; } } void ObjectsManager::animateSprite(int idx) { assert(idx <= MAX_SPRITE); _sprite[idx]._animationType = 1; } void ObjectsManager::addStaticSprite(const byte *spriteData, Common::Point pos, int idx, int spriteIndex, int zoomFactor, bool flipFl, int deltaX, int deltaY) { assert(idx <= MAX_SPRITE); SpriteItem *spr = &_sprite[idx]; spr->_spriteData = spriteData; spr->_spritePos = pos; spr->_spriteIndex = spriteIndex; spr->_zoomFactor = zoomFactor; spr->_flipFl = flipFl; spr->_deltaX = deltaX; spr->_deltaY = deltaY; spr->_animationType = 0; if (READ_BE_UINT24(spriteData) == MKTAG24('R', 'L', 'E')) { spr->_rleFl = true; spr->_zoomFactor = 0; spr->_flipFl = false; } else spr->_rleFl = false; } /** * Freeze sprite animation and free its memory */ void ObjectsManager::removeSprite(int idx) { // Type 3 was also used by freeSprite(), which has been removed as it wasn't used _sprite[idx]._animationType = 3; } /** * Set Sprite X coordinate */ void ObjectsManager::setSpriteX(int idx, int xp) { assert(idx <= MAX_SPRITE); _sprite[idx]._spritePos.x = xp; } /** * Set Sprite Y coordinate */ void ObjectsManager::setSpriteY(int idx, int yp) { assert(idx <= MAX_SPRITE); _sprite[idx]._spritePos.y = yp; } /** * Set Sprite Index */ void ObjectsManager::setSpriteIndex(int idx, int spriteIndex) { assert(idx <= MAX_SPRITE); _sprite[idx]._spriteIndex = spriteIndex; } // Set Sprite Size void ObjectsManager::setSpriteZoom(int idx, int zoomFactor) { assert(idx <= MAX_SPRITE); if (!_sprite[idx]._rleFl) _sprite[idx]._zoomFactor = zoomFactor; } void ObjectsManager::setFlipSprite(int idx, bool flipFl) { assert(idx <= MAX_SPRITE); if (!_sprite[idx]._rleFl) _sprite[idx]._flipFl = flipFl; } void ObjectsManager::goHome() { if (_vm->_linesMan->_route == NULL) return; if (_homeRateCounter > 1) { --_homeRateCounter; return; } int newPosX; int newPosY; Directions newDirection; int oldPosX = 0; int oldPosY = 0; int oldFrameIdx = 0; _homeRateCounter = 0; if (_oldDirection == DIR_NONE) { computeAndSetSpriteSize(); newPosX = _vm->_linesMan->_route->_x; newPosY = _vm->_linesMan->_route->_y; newDirection = _vm->_linesMan->_route->_dir; _vm->_linesMan->_route++; if (newPosX != -1 || newPosY != -1) { _oldDirection = newDirection; _oldDirectionSpriteIdx = newDirection + 59; _oldFrameIndex = 0; _oldCharacterPosX = newPosX; _oldCharacterPosY = newPosY; } else { setSpriteIndex(0, _oldDirection + 59); _vm->_globals->_actionDirection = DIR_NONE; int zoneId; if (_vm->_globals->_actionMoveTo) zoneId = _vm->_globals->_saveData->_data[svLastZoneNum]; else zoneId = _zoneNum; _vm->_linesMan->_route = NULL; computeAndSetSpriteSize(); setFlipSprite(0, false); _homeRateCounter = 0; _vm->_linesMan->_route = NULL; _oldDirection = DIR_NONE; if (zoneId > 0) { ZoneItem *curZone = &_vm->_linesMan->_zone[zoneId]; if (curZone->_destX && curZone->_destY && curZone->_destY != 31) { if (curZone->_spriteIndex == -1) { curZone->_destX = 0; curZone->_destY = 0; curZone->_spriteIndex = 0; } else { setSpriteIndex(0, curZone->_spriteIndex); _vm->_globals->_actionDirection = curZone->_spriteIndex - 59; } } } } _homeRateCounter = 0; return; } if (_oldDirection == DIR_RIGHT) { if (_oldFrameIndex < 24 || _oldFrameIndex > 35) { oldPosX = _oldCharacterPosX; oldPosY = _oldCharacterPosY; oldFrameIdx = 24; } else { int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX; int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY; if (_sprite[0]._zoomFactor < 0) { deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor); } else if (_sprite[0]._zoomFactor > 0) { deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor); } oldPosX = _oldCharacterPosX + deltaX; oldPosY = _oldCharacterPosY + deltaY; oldFrameIdx = _oldFrameIndex + 1; if (oldFrameIdx > 35) oldFrameIdx = 24; } _homeRateCounter = 5 / _vm->_globals->_speed; } if (_oldDirection == DIR_LEFT) { if (_oldFrameIndex < 24 || _oldFrameIndex > 35) { oldPosX = _oldCharacterPosX; oldPosY = _oldCharacterPosY; oldFrameIdx = 24; } else { int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX; int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY; if (_sprite[0]._zoomFactor < 0) { deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor); } else if (_sprite[0]._zoomFactor > 0) { deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor); } oldPosX = _oldCharacterPosX - deltaX; oldPosY = _oldCharacterPosY - deltaY; oldFrameIdx = _oldFrameIndex + 1; if (oldFrameIdx > 35) oldFrameIdx = 24; } _homeRateCounter = 5 / _vm->_globals->_speed; } if (_oldDirection == DIR_UP) { if (_oldFrameIndex > 11) { oldPosX = _oldCharacterPosX; oldPosY = _oldCharacterPosY; oldFrameIdx = 0; } else { int deltaY = abs(_vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY); if (_sprite[0]._zoomFactor < 0) { deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor); } else if (_sprite[0]._zoomFactor > 0) { deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor); } oldPosX = _oldCharacterPosX; oldPosY = _oldCharacterPosY - deltaY; oldFrameIdx = _oldFrameIndex + 1; if (oldFrameIdx > 11) oldFrameIdx = 0; } _homeRateCounter = 4 / _vm->_globals->_speed; } if (_oldDirection == DIR_DOWN) { if (_oldFrameIndex < 48 || _oldFrameIndex > 59) { oldPosX = _oldCharacterPosX; oldPosY = _oldCharacterPosY; oldFrameIdx = 48; } else { int deltaY = abs(_vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY); if (_sprite[0]._zoomFactor < 0) { deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor); } else if (_sprite[0]._zoomFactor > 0) { deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor); } oldPosX = _oldCharacterPosX; oldPosY = deltaY + _oldCharacterPosY; oldFrameIdx = _oldFrameIndex + 1; if (oldFrameIdx > 59) oldFrameIdx = 48; } _homeRateCounter = 4 / _vm->_globals->_speed; } if (_oldDirection == DIR_UP_RIGHT) { if (_oldFrameIndex < 12 || _oldFrameIndex > 23) { oldPosX = _oldCharacterPosX; oldPosY = _oldCharacterPosY; oldFrameIdx = 12; } else { int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX; int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY; if (_sprite[0]._zoomFactor < 0) { deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor); } if (_sprite[0]._zoomFactor > 0) { deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor); } oldPosX = deltaX + _oldCharacterPosX; oldPosY = _oldCharacterPosY + deltaY; oldFrameIdx = _oldFrameIndex + 1; if (oldFrameIdx > 23) oldFrameIdx = 12; } _homeRateCounter = 5 / _vm->_globals->_speed; } if (_oldDirection == DIR_UP_LEFT) { if (_oldFrameIndex < 12 || _oldFrameIndex > 23) { oldPosX = _oldCharacterPosX; oldPosY = _oldCharacterPosY; oldFrameIdx = 12; } else { int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX; int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY; if (_sprite[0]._zoomFactor < 0) { deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor); } else if (_sprite[0]._zoomFactor > 0) { deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor); } oldPosX = _oldCharacterPosX - deltaX; oldPosY = _oldCharacterPosY + deltaY; oldFrameIdx = _oldFrameIndex + 1; if (oldFrameIdx > 23) oldFrameIdx = 12; } _homeRateCounter = 5 / _vm->_globals->_speed; } if (_oldDirection == DIR_DOWN_RIGHT) { if (_oldFrameIndex < 36 || _oldFrameIndex > 47) { oldPosX = _oldCharacterPosX; oldPosY = _oldCharacterPosY; oldFrameIdx = 36; } else { int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX; int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY; if (_sprite[0]._zoomFactor < 0) { deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor); } if (_sprite[0]._zoomFactor > 0) { deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor); } oldPosX = deltaX + _oldCharacterPosX; oldPosY = _oldCharacterPosY + deltaY; oldFrameIdx = _oldFrameIndex + 1; if (oldFrameIdx > 47) oldFrameIdx = 36; } _homeRateCounter = 5 / _vm->_globals->_speed; } if (_oldDirection == DIR_DOWN_LEFT) { if (_oldFrameIndex < 36 || _oldFrameIndex > 47) { oldPosX = _oldCharacterPosX; oldPosY = _oldCharacterPosY; oldFrameIdx = 36; } else { int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX; int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY; if (_sprite[0]._zoomFactor < 0) { deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor); } if (_sprite[0]._zoomFactor > 0) { deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor); deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor); } oldPosX = _oldCharacterPosX - deltaX; oldPosY = _oldCharacterPosY + deltaY; oldFrameIdx = _oldFrameIndex + 1; if (oldFrameIdx > 47) oldFrameIdx = 36; } _homeRateCounter = 5 / _vm->_globals->_speed; } bool loopCond = false; do { newPosX = _vm->_linesMan->_route->_x; newPosY = _vm->_linesMan->_route->_y; newDirection = (Directions)_vm->_linesMan->_route->_dir; _vm->_linesMan->_route++; if (newPosX == -1 && newPosY == -1) { int zoneId; if (_vm->_globals->_actionMoveTo) zoneId = _vm->_globals->_saveData->_data[svLastZoneNum]; else zoneId = _zoneNum; setSpriteIndex(0, _oldDirection + 59); _vm->_globals->_actionDirection = DIR_NONE; _vm->_linesMan->_route = NULL; computeAndSetSpriteSize(); setFlipSprite(0, false); _homeRateCounter = 0; _oldDirection = DIR_NONE; _oldCharacterPosX = getSpriteX(0); _oldCharacterPosY = getSpriteY(0); if (zoneId > 0) { ZoneItem *curZone = &_vm->_linesMan->_zone[zoneId]; if (curZone->_destX && curZone->_destY && curZone->_destY != 31) { if ( curZone->_spriteIndex == -1) { curZone->_destX = 0; curZone->_destY = 0; curZone->_spriteIndex = 0; } else { setSpriteIndex(0, curZone->_spriteIndex); _vm->_globals->_actionDirection = curZone->_spriteIndex - 59; } } } _homeRateCounter = 0; return; } if (_oldDirection != newDirection) break; if ((newDirection == DIR_RIGHT && newPosX >= oldPosX) || (_oldDirection == DIR_LEFT && newPosX <= oldPosX) || (_oldDirection == DIR_UP && newPosY <= oldPosY) || (_oldDirection == DIR_DOWN && newPosY >= oldPosY) || (_oldDirection == DIR_UP_RIGHT && newPosX >= oldPosX) || (_oldDirection == DIR_UP_LEFT && newPosX <= oldPosX) || (_oldDirection == DIR_DOWN_RIGHT && newPosX >= oldPosX) || (_oldDirection == DIR_DOWN_LEFT && newPosX <= oldPosX)) loopCond = true; } while (!loopCond); if (loopCond) { computeAndSetSpriteSize(); if ((_oldDirection == DIR_DOWN_LEFT) || (_oldDirection == DIR_LEFT) || (_oldDirection == DIR_UP_LEFT)) setFlipSprite(0, true); if ((_oldDirection == DIR_UP) || (_oldDirection == DIR_UP_RIGHT) || (_oldDirection == DIR_RIGHT) || (_oldDirection == DIR_DOWN_RIGHT) || (_oldDirection == DIR_DOWN)) setFlipSprite(0, false); setSpriteX(0, newPosX); setSpriteY(0, newPosY); setSpriteIndex(0, oldFrameIdx); } else { if ((_oldDirection == DIR_DOWN_LEFT) || (_oldDirection == DIR_LEFT) || (_oldDirection == DIR_UP_LEFT)) setFlipSprite(0, true); if ((_oldDirection == DIR_UP) || (_oldDirection == DIR_UP_RIGHT) || (_oldDirection == DIR_RIGHT) || (_oldDirection == DIR_DOWN_RIGHT) || (_oldDirection == DIR_DOWN)) setFlipSprite(0, false); _homeRateCounter = 0; } _oldDirection = newDirection; _oldDirectionSpriteIdx = newDirection + 59; _oldFrameIndex = oldFrameIdx; _oldCharacterPosX = newPosX; _oldCharacterPosY = newPosY; } void ObjectsManager::goHome2() { if (_vm->_linesMan->_route == NULL) return; int realSpeed = 2; if (_vm->_globals->_speed == 2) realSpeed = 4; else if (_vm->_globals->_speed == 3) realSpeed = 6; int countColisionPixel = 0; for (;;) { int nexPosX = _vm->_linesMan->_route->_x; int newPosY = _vm->_linesMan->_route->_y; Directions newDirection = (Directions)_vm->_linesMan->_route->_dir; _vm->_linesMan->_route++; if ((nexPosX == -1) && (newPosY == -1)) break; ++countColisionPixel; if (countColisionPixel >= realSpeed) { _lastDirection = newDirection; setSpriteX(0, nexPosX); setSpriteY(0, newPosY); switch (_lastDirection) { case DIR_UP: setSpriteIndex(0, 4); break; case DIR_RIGHT: setSpriteIndex(0, 5); break; case DIR_DOWN: setSpriteIndex(0, 6); break; case DIR_LEFT: setSpriteIndex(0, 7); break; default: break; } return; } } switch (_lastDirection) { case DIR_UP: setSpriteIndex(0, 0); break; case DIR_RIGHT: setSpriteIndex(0, 1); break; case DIR_DOWN: setSpriteIndex(0, 2); break; case DIR_LEFT: setSpriteIndex(0, 3); break; default: break; } _vm->_linesMan->_route = NULL; } /** * Load Zone */ void ObjectsManager::loadZone(const Common::String &file) { for (int i = 1; i <= 100; i++) { ZoneItem *curZone = &_vm->_linesMan->_zone[i]; curZone->_destX = 0; curZone->_destY = 0; curZone->_spriteIndex = 0; curZone->_verbFl1 = 0; curZone->_verbFl2 = 0; curZone->_verbFl3 = 0; curZone->_verbFl4 = 0; curZone->_verbFl5 = 0; curZone->_verbFl6 = 0; curZone->_verbFl7 = 0; curZone->_verbFl8 = 0; curZone->_verbFl9 = 0; curZone->_verbFl10 = 0; curZone->_messageId = 0; curZone->_enabledFl = false; } Common::File f; if (!f.exists(file)) error("File not found : %s", file.c_str()); byte *ptr = _vm->_fileIO->loadFile(file); int bufId = 0; int zoneLineIdx = 0; int bobZoneIdx; do { bobZoneIdx = READ_LE_INT16((uint16 *)ptr + bufId); if (bobZoneIdx != -1) { _vm->_linesMan->addZoneLine( zoneLineIdx, READ_LE_UINT16((uint16 *)ptr + bufId + 1), READ_LE_UINT16((uint16 *)ptr + bufId + 2), READ_LE_UINT16((uint16 *)ptr + bufId + 3), READ_LE_UINT16((uint16 *)ptr + bufId + 4), bobZoneIdx); _vm->_linesMan->_zone[bobZoneIdx]._enabledFl = true; } bufId += 5; ++zoneLineIdx; } while (bobZoneIdx != -1); for (int i = 1; i <= 100; i++) { ZoneItem *curZone = &_vm->_linesMan->_zone[i]; curZone->_destX = READ_LE_INT16((uint16 *)ptr + bufId); curZone->_destY = READ_LE_INT16((uint16 *)ptr + bufId + 1); curZone->_spriteIndex = READ_LE_INT16((uint16 *)ptr + bufId + 2); bufId += 3; } byte *verbData = (ptr + 10 * zoneLineIdx + 606); bufId = 0; for (int i = 1; i <= 100; i++) { ZoneItem *curZone = &_vm->_linesMan->_zone[i]; curZone->_verbFl1 = verbData[bufId]; curZone->_verbFl2 = verbData[bufId + 1]; curZone->_verbFl3 = verbData[bufId + 2]; curZone->_verbFl4 = verbData[bufId + 3]; curZone->_verbFl5 = verbData[bufId + 4]; curZone->_verbFl6 = verbData[bufId + 5]; curZone->_verbFl7 = verbData[bufId + 6]; curZone->_verbFl8 = verbData[bufId + 7]; curZone->_verbFl9 = verbData[bufId + 8]; curZone->_verbFl10 = verbData[bufId + 9]; bufId += 10; } verbData += 1010; for (int i = 0; i < 100; i++) _vm->_linesMan->_zone[i + 1]._messageId = READ_LE_UINT16(verbData + 2 * i); _vm->_globals->freeMemory(ptr); _vm->_linesMan->initSquareZones(); } void ObjectsManager::handleCityMap() { _vm->_dialog->_inventFl = false; _vm->_events->_gameKey = KEY_NONE; _vm->_linesMan->setMaxLineIdx(1); _vm->_globals->_characterMaxPosY = 440; _vm->_globals->_cityMapEnabledFl = true; _vm->_graphicsMan->_noFadingFl = false; _vm->_globals->_freezeCharacterFl = false; _spritePtr = NULL; _vm->_globals->_exitId = 0; _vm->_globals->_checkDistanceFl = true; _vm->_soundMan->playSound(31); _vm->_globals->_eventMode = EVENTMODE_IGNORE; _vm->_graphicsMan->loadImage("PLAN"); _vm->_linesMan->loadLines("PLAN.OB2"); loadHidingItems("PLAN.CA2"); loadZone("PLAN.ZO2"); _spritePtr = _vm->_fileIO->loadFile("VOITURE.SPR"); _vm->_animMan->loadAnim("PLAN"); _vm->_graphicsMan->displayAllBob(); _vm->_graphicsMan->initScreen("PLAN", 2, false); for (int i = 0; i <= 15; i++) disableHidingItem(i); disableHidingItem(19); disableHidingItem(20); enableHidingBehavior(); if (!_mapCarPosX && !_mapCarPosY) { _mapCarPosX = 900; _mapCarPosY = 319; } addStaticSprite(_spritePtr, Common::Point(_mapCarPosX, _mapCarPosY), 0, 1, 0, false, 5, 5); _vm->_events->setMouseXY(_mapCarPosX, _mapCarPosY); _vm->_events->mouseOn(); _vm->_graphicsMan->scrollScreen(getSpriteX(0) - 320); _vm->_graphicsMan->_scrollOffset = getSpriteX(0) - 320; animateSprite(0); _vm->_linesMan->_route = NULL; _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0); for (int i = 0; i <= 4; i++) _vm->_events->refreshScreenAndEvents(); _vm->_globals->_eventMode = EVENTMODE_IGNORE; _vm->_graphicsMan->fadeInLong(); _vm->_events->changeMouseCursor(4); _vm->_graphicsMan->_noFadingFl = false; bool loopCond = false; do { int mouseButton = _vm->_events->getMouseButton(); if (mouseButton) { // First cop call : Go to the bank and free the hostages if (_vm->_globals->_saveData->_data[svBankAttackAnimPlayedFl] == 1 && !_vm->_globals->_saveData->_data[svCopCall1PlayedFl]) { _vm->_globals->_saveData->_data[svCopCall1PlayedFl] = 1; _vm->_globals->_introSpeechOffFl = true; _vm->_talkMan->startAnimatedCharacterDialogue("APPEL1.pe2"); _vm->_globals->_introSpeechOffFl = false; mouseButton = 0; } // Second cop call: Helico has been found in the empty lot if (_vm->_globals->_saveData->_data[svFreedHostageFl] == 1 && !_vm->_globals->_saveData->_data[svCopCall2PlayedFl]) { _vm->_globals->_saveData->_data[svCopCall2PlayedFl] = 1; _vm->_globals->_introSpeechOffFl = true; _vm->_talkMan->startAnimatedCharacterDialogue("APPEL2.pe2"); _vm->_globals->_introSpeechOffFl = false; mouseButton = 0; _vm->_events->_curMouseButton = 0; } if (mouseButton == 1) handleLeftButton(); } _vm->_linesMan->checkZone(); goHome2(); if (_vm->_linesMan->_route == NULL && _vm->_globals->_actionMoveTo) paradise(); _vm->_events->refreshScreenAndEvents(); if (_vm->_globals->_exitId) loopCond = true; } while (!_vm->shouldQuit() && !loopCond); if (!_vm->_graphicsMan->_noFadingFl) _vm->_graphicsMan->fadeOutLong(); _vm->_globals->_eventMode = EVENTMODE_DEFAULT; _vm->_graphicsMan->_noFadingFl = false; _mapCarPosX = getSpriteX(0); _mapCarPosY = getSpriteY(0); removeSprite(0); _spritePtr = _vm->_globals->freeMemory(_spritePtr); clearScreen(); _vm->_globals->_cityMapEnabledFl = false; } /** * Handle Left button */ void ObjectsManager::handleLeftButton() { _vm->_fontMan->hideText(9); int destX = _vm->_events->getMouseX(); int destY = _vm->_events->getMouseY(); if (!_vm->_dialog->_inventFl && !_vm->_globals->_cityMapEnabledFl && destX > _vm->_graphicsMan->_scrollOffset - 30 && destX < _vm->_graphicsMan->_scrollOffset + 50 && destY > -30 && destY < 50) { int oldMouseCursor = _vm->_events->_mouseCursorId; _vm->_dialog->_inventFl = true; _vm->_dialog->showInventory(); _vm->_dialog->_inventFl = false; _vm->_events->_gameKey = KEY_NONE; if (!_vm->_globals->_exitId) { _vm->_dialog->_inventFl = false; _vm->_events->_mouseCursorId = oldMouseCursor; } return; } if (_vm->_globals->_saveData->_data[svField354] == 1 && !_vm->_globals->_cityMapEnabledFl && destX >= 533 && destX <= 559 && destY >= 26 && destY <= 59) { changeCharacterHead(CHARACTER_HOPKINS_CLONE, CHARACTER_HOPKINS); return; } if (_vm->_globals->_saveData->_data[svField356] == 1 && !_vm->_globals->_cityMapEnabledFl && destX >= 533 && destX <= 559 && destY >= 26 && destY <= 48) { changeCharacterHead(CHARACTER_SAMANTHA, CHARACTER_HOPKINS); return; } if (_vm->_globals->_saveData->_data[svField357] == 1) { if (_vm->_globals->_saveData->_data[svField353] == 1 && !_vm->_globals->_cityMapEnabledFl && destX >= 533 && destX <= 559 && destY >= 26 && destY <= 59) { changeCharacterHead(CHARACTER_HOPKINS, CHARACTER_HOPKINS_CLONE); return; } if (_vm->_globals->_saveData->_data[svField355] == 1 && !_vm->_globals->_cityMapEnabledFl && destX >= 567 && destX <= 593 && destY >= 26 && destY <= 59) { changeCharacterHead(CHARACTER_HOPKINS, CHARACTER_SAMANTHA); return; } } if (_vm->_globals->_cityMapEnabledFl && _vm->_globals->_actionMoveTo) { _vm->_linesMan->checkZone(); if (_zoneNum <= 0) return; int routeIdx = 0; do { _vm->_linesMan->_testRoute2[routeIdx] = _vm->_linesMan->_route[routeIdx]; ++routeIdx; } while (_vm->_linesMan->_route[routeIdx]._x != -1); _vm->_linesMan->_testRoute2[routeIdx].invalidate(); } if (_vm->_globals->_actionMoveTo) { _vm->_linesMan->checkZone(); _vm->_globals->_actionMoveTo = false; _vm->_globals->_saveData->_data[svLastMouseCursor] = 0; _vm->_globals->_saveData->_data[svLastZoneNum] = 0; } if (_vm->_globals->_cityMapEnabledFl && (_vm->_events->_mouseCursorId != 4 || _zoneNum <= 0)) return; if (_zoneNum != -1 && _zoneNum != 0) { ZoneItem *curZone = &_vm->_linesMan->_zone[_zoneNum]; if (curZone->_destX && curZone->_destY && curZone->_destY != 31) { destX = curZone->_destX; destY = curZone->_destY; } } _vm->_globals->_actionMoveTo = false; RouteItem *oldRoute = _vm->_linesMan->_route; _vm->_linesMan->_route = NULL; if (_forestFl && _zoneNum >= 20 && _zoneNum <= 23) { if (getSpriteY(0) > 374 && getSpriteY(0) <= 410) { _vm->_linesMan->_route = NULL; setSpriteIndex(0, _oldDirectionSpriteIdx); _vm->_globals->_actionDirection = DIR_NONE; _vm->_linesMan->_route = NULL; computeAndSetSpriteSize(); setFlipSprite(0, false); _homeRateCounter = 0; _oldDirection = DIR_NONE; } else { _vm->_linesMan->_route = _vm->_linesMan->findRoute(getSpriteX(0), getSpriteY(0), getSpriteX(0), 390); if (_vm->_linesMan->_route) _vm->_linesMan->optimizeRoute(_vm->_linesMan->_route); _oldCharacterPosX = getSpriteX(0); _oldCharacterPosY = getSpriteY(0); _homeRateCounter = 0; if (_vm->_linesMan->_route || oldRoute == _vm->_linesMan->_route) { _oldDirection = DIR_NONE; } else { _vm->_linesMan->_route = oldRoute; } } } else { if (!_vm->_globals->_freezeCharacterFl && !_vm->_globals->_cityMapEnabledFl) { _vm->_linesMan->_route = _vm->_linesMan->findRoute(getSpriteX(0), getSpriteY(0), destX, destY); if (_vm->_linesMan->_route) _vm->_linesMan->optimizeRoute(_vm->_linesMan->_route); _oldCharacterPosX = getSpriteX(0); _oldCharacterPosY = getSpriteY(0); _homeRateCounter = 0; if (_vm->_linesMan->_route || oldRoute == _vm->_linesMan->_route) _oldDirection = DIR_NONE; else _vm->_linesMan->_route = oldRoute; } } if (!_vm->_globals->_freezeCharacterFl && _vm->_globals->_cityMapEnabledFl) _vm->_linesMan->_route = _vm->_linesMan->cityMapCarRoute(getSpriteX(0), getSpriteY(0), destX, destY); if (_zoneNum != -1 && _zoneNum != 0) { if (_vm->_events->_mouseCursorId == 23) _vm->_globals->_saveData->_data[svLastMouseCursor] = 5; else _vm->_globals->_saveData->_data[svLastMouseCursor] = _vm->_events->_mouseCursorId; if (_vm->_globals->_cityMapEnabledFl) _vm->_globals->_saveData->_data[svLastMouseCursor] = 6; _vm->_globals->_saveData->_data[svLastZoneNum] = _zoneNum; _vm->_globals->_saveData->_data[svLastObjectIndex] = _curObjectIndex; _vm->_globals->_actionMoveTo = true; } _vm->_fontMan->hideText(5); _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100); if (_vm->_globals->_screenId == 20 && _vm->_globals->_saveData->_data[svField132] == 1 && _curObjectIndex == 20 && _zoneNum == 12 && _vm->_events->_mouseCursorId == 23) { // Special case for throwing darts at the switch in Purgatory - the player shouldn't move _vm->_linesMan->_route = NULL; getSpriteX(0); getSpriteY(0); } } void ObjectsManager::paradise() { char result = _vm->_globals->_saveData->_data[svLastMouseCursor]; if (result && _vm->_globals->_saveData->_data[svLastZoneNum] && result != 4 && result > 3) { _vm->_fontMan->hideText(5); if (!_forestFl || _zoneNum < 20 || _zoneNum > 23) { if (_vm->_graphicsMan->_largeScreenFl) { _vm->_graphicsMan->_scrollStatus = 2; if (_vm->_events->_startPos.x + 320 - getSpriteX(0) > 160) { bool loopCond = false; do { _vm->_graphicsMan->_scrollPosX -= _vm->_graphicsMan->_scrollSpeed; if (_vm->_graphicsMan->_scrollPosX < 0) { _vm->_graphicsMan->_scrollPosX = 0; loopCond = true; } if (_vm->_graphicsMan->_scrollPosX > SCREEN_WIDTH) { _vm->_graphicsMan->_scrollPosX = SCREEN_WIDTH; loopCond = true; } if (_vm->_events->getMouseX() > _vm->_graphicsMan->_scrollPosX + 620) _vm->_events->setMouseXY(_vm->_events->_mousePos.x - 4, _vm->_events->getMouseY()); _vm->_events->refreshScreenAndEvents(); } while (!loopCond && _vm->_events->_startPos.x > getSpriteX(0) - 320); } else if (_vm->_events->_startPos.x + 320 - getSpriteX(0) < -160) { bool loopCond = false; do { _vm->_graphicsMan->_scrollPosX += _vm->_graphicsMan->_scrollSpeed; if (_vm->_graphicsMan->_scrollPosX < 0) { _vm->_graphicsMan->_scrollPosX = 0; loopCond = true; } if (_vm->_graphicsMan->_scrollPosX > SCREEN_WIDTH) { _vm->_graphicsMan->_scrollPosX = SCREEN_WIDTH; loopCond = true; } if (_vm->_events->getMouseX() < _vm->_graphicsMan->_scrollPosX + 10) _vm->_events->setMouseXY(_vm->_events->_mousePos.x + 4, _vm->_events->getMouseY()); _vm->_events->refreshScreenAndEvents(); } while (!loopCond && _vm->_events->_startPos.x < getSpriteX(0) - 320); } if (_vm->_events->getMouseX() > _vm->_graphicsMan->_scrollPosX + 620) _vm->_events->setMouseXY(_vm->_graphicsMan->_scrollPosX + 610, 0); if (_vm->_events->getMouseX() < _vm->_graphicsMan->_scrollPosX + 10) _vm->_events->setMouseXY(_vm->_graphicsMan->_scrollPosX + 10, 0); _vm->_events->refreshScreenAndEvents(); _vm->_graphicsMan->_scrollStatus = 0; } _vm->_talkMan->handleAnswer(_vm->_globals->_saveData->_data[svLastZoneNum], _vm->_globals->_saveData->_data[svLastMouseCursor]); } else { _vm->_talkMan->handleForestAnswser(_vm->_globals->_saveData->_data[svLastZoneNum], _vm->_globals->_saveData->_data[svLastMouseCursor]); } _vm->_events->changeMouseCursor(4); if (_zoneNum != -1 && _zoneNum != 0 && !_vm->_linesMan->_zone[_zoneNum]._enabledFl) { _zoneNum = -1; _forceZoneFl = true; } if (_zoneNum != _vm->_globals->_saveData->_data[svLastZoneNum] || _zoneNum == -1 || _zoneNum == 0) { _vm->_events->_mouseCursorId = 4; _changeVerbFl = false; } else { _vm->_events->_mouseCursorId = _vm->_globals->_saveData->_data[svLastMouseCursor]; if (_changeVerbFl) { nextVerbIcon(); _changeVerbFl = false; } if (_vm->_events->_mouseCursorId == 5) _vm->_events->_mouseCursorId = 4; } if (_vm->_events->_mouseCursorId != 23) _vm->_events->changeMouseCursor(_vm->_events->_mouseCursorId); _zoneNum = 0; _vm->_globals->_saveData->_data[svLastMouseCursor] = 0; _vm->_globals->_saveData->_data[svLastZoneNum] = 0; } if (_vm->_globals->_cityMapEnabledFl) { _vm->_events->_mouseCursorId = 0; _vm->_events->changeMouseCursor(0); } if (_vm->_globals->_freezeCharacterFl && _vm->_events->_mouseCursorId == 4) { if (_zoneNum != -1 && _zoneNum != 0) handleRightButton(); } _vm->_globals->_actionMoveTo = false; } /** * Clear Screen */ void ObjectsManager::clearScreen() { clearSprite(); _vm->_graphicsMan->endDisplayBob(); _vm->_fontMan->hideText(5); _vm->_fontMan->hideText(9); clearVBob(); _vm->_animMan->clearAnim(); _vm->_linesMan->clearAllZones(); _vm->_linesMan->resetLines(); resetHidingItems(); for (int i = 0; i <= 48; i++) { _vm->_linesMan->_bobZone[i] = 0; _vm->_linesMan->_bobZoneFl[i] = false; } _vm->_events->_mouseCursorId = 4; _verb = 4; _zoneNum = 0; _forceZoneFl = true; _vm->_linesMan->resetLinesNumb(); _vm->_linesMan->resetLastLine(); _vm->_linesMan->_route = NULL; _vm->_globals->_answerBuffer = _vm->_globals->freeMemory(_vm->_globals->_answerBuffer); _vm->_globals->_levelSpriteBuf = _vm->_globals->freeMemory(_vm->_globals->_levelSpriteBuf); _vm->_events->_startPos.x = 0; _vm->_events->_mouseSpriteId = 0; _vm->_globals->_saveData->_data[svLastMouseCursor] = 0; _vm->_globals->_saveData->_data[svLastZoneNum] = 0; _vm->_globals->_actionMoveTo = false; _forceZoneFl = true; _changeVerbFl = false; _vm->_linesMan->_route = NULL; _oldDirection = DIR_NONE; _vm->_graphicsMan->resetDirtyRects(); } /** * Change the currently active player face / Head * @param oldCharacter Previously played character * @param newCharacter New character to play */ void ObjectsManager::changeCharacterHead(PlayerCharacter oldCharacter, PlayerCharacter newCharacter) { CharacterLocation *loc; _changeHeadFl = true; _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, 532, 25, 65, 40, _vm->_graphicsMan->_frontBuffer, 532, 25); _vm->_graphicsMan->addDirtyRect(532, 25, 597, 65); _vm->_globals->_checkDistanceFl = true; _vm->_linesMan->_route = NULL; if (oldCharacter == CHARACTER_SAMANTHA && newCharacter == CHARACTER_HOPKINS && _vm->_globals->_saveData->_realHopkins._location == _vm->_globals->_screenId) { _changeHeadFl = false; loc = &_vm->_globals->_saveData->_samantha; loc->_pos.x = getSpriteX(0); loc->_pos.y = getSpriteY(0); loc->_startSpriteIndex = 64; loc->_location = _vm->_globals->_screenId; loc->_zoomFactor = _sprite[0]._zoomFactor; removeSprite(1); addStaticSprite(_headSprites, loc->_pos, 1, 3, loc->_zoomFactor, false, 20, 127); animateSprite(1); removeSprite(0); _vm->_globals->_saveData->_data[svField354] = 0; _vm->_globals->_saveData->_data[svField356] = 0; _vm->_globals->_saveData->_data[svField357] = 1; loc = &_vm->_globals->_saveData->_realHopkins; _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PERSO.SPR"); _vm->_globals->_characterType = CHARACTER_HOPKINS; addStaticSprite(_vm->_globals->_characterSpriteBuf, loc->_pos, 0, 64, loc->_zoomFactor, false, 34, 190); animateSprite(0); _vm->_globals->loadCharacterData(); } else if (oldCharacter == CHARACTER_HOPKINS && newCharacter == CHARACTER_SAMANTHA && _vm->_globals->_saveData->_samantha._location == _vm->_globals->_screenId) { _changeHeadFl = false; loc = &_vm->_globals->_saveData->_realHopkins; loc->_pos.x = getSpriteX(0); loc->_pos.y = getSpriteY(0); loc->_startSpriteIndex = 64; loc->_location = _vm->_globals->_screenId; loc->_zoomFactor = _sprite[0]._zoomFactor; removeSprite(1); addStaticSprite(_headSprites, loc->_pos, 1, 2, loc->_zoomFactor, false, 34, 190); animateSprite(1); removeSprite(0); _vm->_globals->_saveData->_data[svField354] = 0; _vm->_globals->_saveData->_data[svField356] = 1; _vm->_globals->_saveData->_data[svField357] = 0; loc = &_vm->_globals->_saveData->_samantha; _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PSAMAN.SPR"); _vm->_globals->_characterType = CHARACTER_SAMANTHA; addStaticSprite(_vm->_globals->_characterSpriteBuf, loc->_pos, 0, 64, loc->_zoomFactor, false, 20, 127); animateSprite(0); _vm->_globals->loadCharacterData(); } else { switch (oldCharacter) { case CHARACTER_HOPKINS: loc = &_vm->_globals->_saveData->_realHopkins; loc->_pos.x = getSpriteX(0); loc->_pos.y = getSpriteY(0); loc->_startSpriteIndex = 64; loc->_location = _vm->_globals->_screenId; loc->_zoomFactor = _sprite[0]._zoomFactor; break; case CHARACTER_HOPKINS_CLONE: loc = &_vm->_globals->_saveData->_cloneHopkins; loc->_pos.x = getSpriteX(0); loc->_pos.y = getSpriteY(0); loc->_startSpriteIndex = 64; loc->_location = _vm->_globals->_screenId; loc->_zoomFactor = _sprite[0]._zoomFactor; break; case CHARACTER_SAMANTHA: loc = &_vm->_globals->_saveData->_samantha; loc->_pos.x = getSpriteX(0); loc->_pos.y = getSpriteY(0); loc->_startSpriteIndex = 64; loc->_location = _vm->_globals->_screenId; loc->_zoomFactor = _sprite[0]._zoomFactor; break; default: break; } switch (newCharacter) { case CHARACTER_HOPKINS: _vm->_globals->_saveData->_data[svHopkinsCloneFl] = 0; _vm->_globals->_saveData->_data[svField354] = 0; _vm->_globals->_saveData->_data[svField356] = 0; _vm->_globals->_saveData->_data[svField357] = 1; _vm->_globals->_exitId = _vm->_globals->_saveData->_realHopkins._location; break; case CHARACTER_HOPKINS_CLONE: _vm->_globals->_saveData->_data[svHopkinsCloneFl] = 1; _vm->_globals->_saveData->_data[svField354] = 1; _vm->_globals->_saveData->_data[svField356] = 0; _vm->_globals->_saveData->_data[svField357] = 0; _vm->_globals->_exitId = _vm->_globals->_saveData->_cloneHopkins._location; break; case CHARACTER_SAMANTHA: _vm->_globals->_saveData->_data[svHopkinsCloneFl] = 0; _vm->_globals->_saveData->_data[svField354] = 0; _vm->_globals->_saveData->_data[svField356] = 1; _vm->_globals->_saveData->_data[svField357] = 0; _vm->_globals->_exitId = _vm->_globals->_saveData->_samantha._location; break; } } } // Check Size void ObjectsManager::computeAndSetSpriteSize() { int size = _vm->_globals->_spriteSize[getSpriteY(0)]; if (_vm->_globals->_characterType == CHARACTER_HOPKINS_CLONE) { size = 20 * (5 * abs(size) - 100) / -80; } else if (_vm->_globals->_characterType == CHARACTER_SAMANTHA) { size = 20 * (5 * abs(size) - 165) / -67; } setSpriteZoom(0, size); } /** * Get next verb icon (or text) */ void ObjectsManager::nextVerbIcon() { _vm->_events->_mouseCursorId++; for(;;) { if (_vm->_events->_mouseCursorId == 4) { if (!_vm->_globals->_freezeCharacterFl || _zoneNum == -1 || _zoneNum == 0) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 5 || _vm->_events->_mouseCursorId == 6) { _vm->_events->_mouseCursorId = 6; if (_vm->_linesMan->_zone[_zoneNum]._verbFl1 == 1) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 7) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl2 == 1) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 8) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl3 == 1) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 9) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl4 == 1) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 10) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl5 == 1) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 11) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl6 == 1) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 12) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl7 == 1) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 13) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl8 == 1) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 14) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl9 == 1) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 15) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl10 == 1) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 16) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl1 == 2) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 17) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl4 == 2) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 18) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl5 == 2) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 19) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl6 == 2) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 20) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl7 == 2) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 21) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl10 == 2) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 22) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl8 == 2) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 23) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl3 == 2) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 24) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl4 == 3) return; ++_vm->_events->_mouseCursorId; } if (_vm->_events->_mouseCursorId == 25) { if (_vm->_linesMan->_zone[_zoneNum]._verbFl9 == 2) return; } _vm->_events->_mouseCursorId = 4; } } /** * Handle Right button */ void ObjectsManager::handleRightButton() { if (_zoneNum != -1 && _zoneNum != 0) { nextVerbIcon(); if (_vm->_events->_mouseCursorId != 23) _vm->_events->changeMouseCursor(_vm->_events->_mouseCursorId); _verb = _vm->_events->_mouseCursorId; } } /** * Prepare border used to highlight the place below mouse cursor, in the inventory. * Also set the mouse cursor */ void ObjectsManager::initBorder(int zoneIdx) { _oldBorderPos = _borderPos; _oldBorderSpriteIndex = _borderSpriteIndex; if (zoneIdx >= 1 && zoneIdx <= 6) _borderPos.y = 120; else if (zoneIdx >= 7 && zoneIdx <= 12) _borderPos.y = 158; else if (zoneIdx >= 13 && zoneIdx <= 18) _borderPos.y = 196; else if (zoneIdx >= 19 && zoneIdx <= 24) _borderPos.y = 234; else if (zoneIdx >= 25 && zoneIdx <= 29) _borderPos.y = 272; else if (zoneIdx == 30) _borderPos.y = 272; else if (zoneIdx == 31) _borderPos.y = 290; if (zoneIdx == 1 || zoneIdx == 7 || zoneIdx == 13 || zoneIdx == 19 || zoneIdx == 25) _borderPos.x = _vm->_graphicsMan->_scrollOffset + 158; else if (zoneIdx == 2 || zoneIdx == 8 || zoneIdx == 14 || zoneIdx == 20 || zoneIdx == 26) _borderPos.x = _vm->_graphicsMan->_scrollOffset + 212; else if (zoneIdx == 3 || zoneIdx == 9 || zoneIdx == 15 || zoneIdx == 21 || zoneIdx == 27) _borderPos.x = _vm->_graphicsMan->_scrollOffset + 266; else if (zoneIdx == 4 || zoneIdx == 10 || zoneIdx == 16 || zoneIdx == 22 || zoneIdx == 28) _borderPos.x = _vm->_graphicsMan->_scrollOffset + 320; else if (zoneIdx == 5 || zoneIdx == 11 || zoneIdx == 17 || zoneIdx == 23 || zoneIdx == 29) _borderPos.x = _vm->_graphicsMan->_scrollOffset + 374; else if (zoneIdx == 6 || zoneIdx == 12 || zoneIdx == 18 || zoneIdx == 24 || zoneIdx == 30 || zoneIdx == 31) _borderPos.x = _vm->_graphicsMan->_scrollOffset + 428; if (zoneIdx >= 1 && zoneIdx <= 29) _borderSpriteIndex = 0; else if (zoneIdx == 30 || zoneIdx == 31) _borderSpriteIndex = 2; else if (!zoneIdx || zoneIdx == 32) { _borderPos = Common::Point(0, 0); _borderSpriteIndex = 0; } if (!zoneIdx) _vm->_events->_mouseCursorId = 0; else if (zoneIdx >= 1 && zoneIdx <= 28) _vm->_events->_mouseCursorId = 8; else if (zoneIdx == 29) _vm->_events->_mouseCursorId = 1; else if (zoneIdx == 30) _vm->_events->_mouseCursorId = 2; else if (zoneIdx == 31) _vm->_events->_mouseCursorId = 3; else if (zoneIdx == 32) _vm->_events->_mouseCursorId = 16; if (zoneIdx >= 1 && zoneIdx <= 28 && !_vm->_globals->_inventory[zoneIdx]) { _vm->_events->_mouseCursorId = 0; _borderPos = Common::Point(0, 0); _borderSpriteIndex = 0; } if (_vm->_events->_mouseCursorId != 23) _vm->_events->changeMouseCursor(_vm->_events->_mouseCursorId); _vm->_events->getMouseX(); _vm->_events->getMouseY(); } /** * Get next icon for an object in the inventory */ void ObjectsManager::nextObjectIcon(int idx) { int cursorId = _vm->_events->_mouseCursorId; ObjectAuthIcon *curAuthIco = &_objectAuthIcons[_vm->_globals->_inventory[idx]]; if (cursorId == 0 || cursorId == 2 || cursorId == 3 || cursorId == 16) return; int nextCursorId = cursorId + 1; if (nextCursorId > 25) nextCursorId = 6; do { if (nextCursorId == 2 || nextCursorId == 5 || nextCursorId == 6) { _vm->_events->_mouseCursorId = 6; if (curAuthIco->_flag1 == 1) return; nextCursorId++; } if (nextCursorId == 7) { _vm->_events->_mouseCursorId = 7; if (curAuthIco->_flag2 == 1) return; nextCursorId++; } if (nextCursorId == 8) { _vm->_events->_mouseCursorId = 8; return; } if (nextCursorId == 9 || nextCursorId == 10) { _vm->_events->_mouseCursorId = 10; if (curAuthIco->_flag6 == 1) return; nextCursorId = 11; } if (nextCursorId == 11) { _vm->_events->_mouseCursorId = 11; if (curAuthIco->_flag3 == 1) return; nextCursorId++; } if (nextCursorId == 12 || nextCursorId == 13) { _vm->_events->_mouseCursorId = 13; if (curAuthIco->_flag4 == 1) return; nextCursorId = 14; } if (nextCursorId == 14 || nextCursorId == 15) { _vm->_events->_mouseCursorId = 15; if (curAuthIco->_flag5 == 1) return; nextCursorId = 23; } if (nextCursorId >= 16 && nextCursorId <= 23) { _vm->_events->_mouseCursorId = 23; if (curAuthIco->_flag5 == 2) return; nextCursorId = 24; } if (nextCursorId == 24 || nextCursorId == 25) { _vm->_events->_mouseCursorId = 25; } nextCursorId = 6; } while (curAuthIco->_flag6 != 2); } void ObjectsManager::takeInventoryObject(int idx) { if (_vm->_events->_mouseCursorId == 8) changeObject(idx); } void ObjectsManager::loadObjectIniFile() { byte *data; Common::String file; int lastOpcodeResult = 1; file = "OBJET1.ini"; bool fileFoundFl = false; data = _vm->_fileIO->searchCat(file, RES_INI, fileFoundFl); if (!fileFoundFl) { data = _vm->_fileIO->loadFile(file); if (data == NULL) error("INI file %s not found", file.c_str()); } if (READ_BE_UINT24(data) != MKTAG24('I', 'N', 'I')) error("File %s is not an INI file", file.c_str()); for (;;) { int opcodeType = _vm->_script->handleOpcode(data + 20 * lastOpcodeResult); if (opcodeType == -1 || _vm->shouldQuit()) return; if (opcodeType == 2) lastOpcodeResult = _vm->_script->handleGoto(data + 20 * lastOpcodeResult); else if (opcodeType == 3) lastOpcodeResult = _vm->_script->handleIf(data, lastOpcodeResult); if (lastOpcodeResult == -1) error("defective IFF function"); if (opcodeType == 1 || opcodeType == 4) ++lastOpcodeResult; else if (!opcodeType || opcodeType == 5) break; } _vm->_globals->freeMemory(data); } void ObjectsManager::handleSpecialGames() { byte *oldPalette; switch (_vm->_globals->_screenId) { case 5: if ((getSpriteY(0) > 399) || _vm->_globals->_saveData->_data[svField173]) break; _vm->_globals->_saveData->_data[svField173] = 1; _vm->_globals->_introSpeechOffFl = true; _vm->_talkMan->startAnimatedCharacterDialogue("flicspe1.pe2"); _vm->_globals->_introSpeechOffFl = false; if (_vm->_globals->_censorshipFl) break; oldPalette = _vm->_globals->allocMemory(1000); memcpy(oldPalette, _vm->_graphicsMan->_palette, 769); _vm->_graphicsMan->backupScreen(); if (!_vm->_graphicsMan->_lineNbr) _vm->_graphicsMan->_scrollOffset = 0; _vm->_graphicsMan->displayScreen(true); _vm->_soundMan->_specialSoundNum = 198; _charactersEnabledFl = true; _vm->_animMan->unsetClearAnimFlag(); _vm->_animMan->playAnim("OTAGE.ANM", "OTAGE.ANM", 1, 24, 500, true); _vm->_soundMan->_specialSoundNum = 0; _vm->_graphicsMan->displayScreen(false); _vm->_graphicsMan->restoreScreen(); _charactersEnabledFl = false; memcpy(_vm->_graphicsMan->_palette, oldPalette, 769); _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette); _vm->_globals->freeMemory(oldPalette); _vm->_graphicsMan->display8BitRect(_vm->_graphicsMan->_backBuffer, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); memcpy(_vm->_graphicsMan->_frontBuffer, _vm->_graphicsMan->_backBuffer, 614399); _vm->_graphicsMan->_scrollStatus = 0; _vm->_graphicsMan->updateScreen(); break; case 20: _vm->_globals->_saveData->_data[svField132] = (getSpriteX(0) > 65 && getSpriteX(0) <= 124 && getSpriteY(0) > 372 && getSpriteY(0) <= 398) ? 1 : 0; break; case 35: if (_vm->_globals->_prevScreenId == 16) handleForest(35, 500, 555, 100, 440, 1); else if (_vm->_globals->_prevScreenId == 36) handleForest(35, 6, 84, 100, 440, 4); break; case 36: if (_vm->_globals->_prevScreenId == 35) handleForest(36, 551, 633, 100, 440, 2); else if (_vm->_globals->_prevScreenId == 37) handleForest(36, 6, 84, 100, 440, 4); break; case 37: if (_vm->_globals->_prevScreenId == 36) handleForest(37, 551, 633, 100, 440, 1); else if (_vm->_globals->_prevScreenId == 38) handleForest(37, 392, 529, 100, 440, 2); break; case 38: if (_vm->_globals->_prevScreenId == 37) handleForest(38, 133, 252, 100, 440, 4); else if (_vm->_globals->_prevScreenId == 39) handleForest(38, 6, 84, 100, 440, 3); break; case 39: if (_vm->_globals->_prevScreenId == 38) handleForest(39, 551, 633, 100, 440, 2); else if (_vm->_globals->_prevScreenId == 40) handleForest(39, 6, 84, 100, 440, 3); break; case 40: if (_vm->_globals->_prevScreenId == 39) handleForest(40, 133, 252, 100, 440, 4); else if (_vm->_globals->_prevScreenId == 41) handleForest(40, 392, 529, 100, 440, 2); break; case 41: if (_vm->_globals->_prevScreenId == 40) handleForest(41, 551, 633, 100, 440, 1); else if (_vm->_globals->_prevScreenId == 17) handleForest(41, 6, 84, 100, 440, 3); break; case 57: _vm->_globals->_disableInventFl = true; if (_vm->_globals->_saveData->_data[svField261] == 1 && getBobAnimDataIdx(5) == 37) { stopBobAnimation(5); setBobAnimDataIdx(5, 0); setBobAnimation(6); _vm->_globals->_saveData->_data[svField261] = 2; _vm->_linesMan->disableZone(15); _vm->_soundMan->playSoundFile("SOUND75.WAV"); } if (_vm->_globals->_saveData->_data[svField261] == 2 && getBobAnimDataIdx(6) == 6) { stopBobAnimation(6); setBobAnimDataIdx(6, 0); setBobAnimation(7); _vm->_linesMan->enableZone(14); _vm->_globals->_saveData->_data[svField261] = 3; } _vm->_globals->_disableInventFl = false; break; case 93: if (_vm->_globals->_saveData->_data[svField333]) break; _vm->_globals->_disableInventFl = true; do _vm->_events->refreshScreenAndEvents(); while (getBobAnimDataIdx(8) != 3); _vm->_globals->_introSpeechOffFl = true; _vm->_talkMan->startAnimatedCharacterDialogue("GM3.PE2"); stopBobAnimation(8); _vm->_globals->_saveData->_data[svField333] = 1; _vm->_globals->_disableInventFl = false; break; } } void ObjectsManager::quickDisplayBobSprite(int idx) { int startPos = 10 * idx; if (!READ_LE_UINT16(_vm->_talkMan->_characterAnim + startPos + 4)) return; int xp = READ_LE_INT16(_vm->_talkMan->_characterAnim + startPos); int yp = READ_LE_INT16(_vm->_talkMan->_characterAnim + startPos + 2); int spriteIndex = _vm->_talkMan->_characterAnim[startPos + 8]; _vm->_graphicsMan->fastDisplay(_vm->_talkMan->_characterSprite, xp, yp, spriteIndex); } void ObjectsManager::initVbob(const byte *src, int idx, int xp, int yp, int frameIndex) { if (idx > 29) error("MAX_VBOB exceeded"); VBobItem *vbob = &_vBob[idx]; if (vbob->_displayMode <= 1) { vbob->_displayMode = 1; vbob->_xp = xp; vbob->_yp = yp; vbob->_frameIndex = frameIndex; vbob->_oldX = xp; vbob->_oldY = yp; vbob->_oldFrameIndex = frameIndex; vbob->_spriteData = src; vbob->_oldSpriteData = src; vbob->_surface = _vm->_globals->freeMemory(vbob->_surface); } else if (vbob->_displayMode == 2 || vbob->_displayMode == 4) { vbob->_displayMode = 3; vbob->_oldX = vbob->_xp; vbob->_oldY = vbob->_yp; vbob->_oldSpriteData = vbob->_spriteData; vbob->_oldFrameIndex = vbob->_frameIndex; vbob->_xp = xp; vbob->_yp = yp; vbob->_frameIndex = frameIndex; vbob->_spriteData = src; } } void ObjectsManager::disableVbob(int idx) { if (idx > 29) error("MAX_VBOB exceeded"); VBobItem *vbob = &_vBob[idx]; if (vbob->_displayMode <= 1) vbob->_displayMode = 0; else vbob->_displayMode = 4; } void ObjectsManager::doActionBack(int idx) { if (_curGestureFile != 1) { _gestureBuf = _vm->_globals->freeMemory(_gestureBuf); _curGestureFile = 1; _gestureBuf = _vm->_fileIO->loadFile("DOS.SPR"); } switch (idx) { case 1: showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 8, false); break; case 2: showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,13,-1,", 8, false); break; case 3: showSpecialActionAnimation(_gestureBuf, "12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8); break; case 4: showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,8,9,10,11,12,13,12,11,12,13,12,11,12,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8, false); break; case 5: showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,-1,", 8, false); break; case 6: showSpecialActionAnimation(_gestureBuf, "20,19,18,17,16,15,-1,", 8); break; case 7: showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,22,23,24,-1,", 8, false); break; case 8: showSpecialActionAnimation(_gestureBuf, "23,22,21,20,19,18,17,16,15,-1,", 8); break; case 9: showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,22,23,24,-1,", 8, false); break; case 10: showSpecialActionAnimation(_gestureBuf, "23,22,21,20,19,18,17,16,15,-1,", 8); break; } } void ObjectsManager::doActionRight(int idx) { if (_curGestureFile != 3) { _gestureBuf = _vm->_globals->freeMemory(_gestureBuf); _curGestureFile = 3; _gestureBuf = _vm->_fileIO->loadFile("PROFIL.SPR"); } switch (idx) { case 1: showActionAnimation(_gestureBuf, "20,19,18,17,16,15,14,13,13,13,13,13,14,15,16,17,18,19,20,-1,", 8, false); break; case 2: showSpecialActionAnimationWithFlip(_gestureBuf, "1,2,3,4,5,6,7,8,-1,", 8, false); break; case 3: showSpecialActionAnimation(_gestureBuf, "9,10,11,12,13,14,15,16,17,18,19,20,-1,", 8); break; case 4: showActionAnimation(_gestureBuf, "1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1,-1,", 8, false); break; case 5: showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,-1,", 8, false); break; case 6: showSpecialActionAnimation(_gestureBuf, "24,23,-1,", 8); break; case 7: showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,-1,", 8, false); break; case 8: showSpecialActionAnimation(_gestureBuf, "26,25,24,23,-1,", 8); break; case 9: showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,28,29,-1,", 8, false); break; case 10: showSpecialActionAnimation(_gestureBuf, "28,27,26,25,24,23,-1,", 8); break; } } void ObjectsManager::doActionDiagRight(int idx) { if (_curGestureFile != 4) { _gestureBuf = _vm->_globals->freeMemory(_gestureBuf); _curGestureFile = 4; _gestureBuf = _vm->_fileIO->loadFile("3Q.SPR"); } switch (idx) { case 1: showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 8, false); break; case 2: showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,-1,", 8, false); break; case 3: showSpecialActionAnimation(_gestureBuf, "11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8); break; case 4: showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,11,12,11,12,11,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8, false); break; case 5: showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,-1,", 8, false); break; case 6: showSpecialActionAnimation(_gestureBuf, "17,16,15,-1,", 8); break; case 7: showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,-1,", 8, false); break; case 8: showSpecialActionAnimation(_gestureBuf, "19,18,17,16,15,-1,", 8); break; case 9: showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,-1,", 8, false); break; case 10: showSpecialActionAnimation(_gestureBuf, "20,19,18,17,15,-1,", 8); break; } } void ObjectsManager::doActionFront(int idx) { if (_curGestureFile != 2) { _gestureBuf = _vm->_globals->freeMemory(_gestureBuf); _curGestureFile = 2; _gestureBuf = _vm->_fileIO->loadFile("FACE.SPR"); } switch (idx) { case 1: showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,9,9,9,9,9,9,7,6,5,4,3,2,1,0,-1,", 8, false); break; case 2: showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,9,10,11,12,13,14,15,-1,", 8, false); break; case 3: showSpecialActionAnimation(_gestureBuf, "14,13,12,11,10,9,7,6,5,4,3,2,1,0,-1,", 8); break; case 4: showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,9,10,11,12,13,14,13,12,11,10,9,7,6,5,4,3,2,1,0,-1,", 8, false); break; } } void ObjectsManager::doActionDiagLeft(int idx) { if (_curGestureFile != 4) { _gestureBuf = _vm->_globals->freeMemory(_gestureBuf); _curGestureFile = 4; _gestureBuf = _vm->_fileIO->loadFile("3Q.SPR"); } switch (idx) { case 1: showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 8, true); break; case 2: showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,-1,", 8, true); break; case 3: showSpecialActionAnimation(_gestureBuf, "11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8); break; case 4: showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,11,12,11,12,11,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8, true); break; case 5: showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,-1,", 8, true); break; case 6: showSpecialActionAnimation(_gestureBuf, "17,16,15,-1,", 8); break; case 7: showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,-1,", 8, true); break; case 8: showSpecialActionAnimation(_gestureBuf, "19,18,17,16,15,-1,", 8); break; case 9: showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,-1,", 8, true); break; case 10: showSpecialActionAnimation(_gestureBuf, "20,19,18,17,15,-1,", 8); break; } } void ObjectsManager::doActionLeft(int idx) { if (_curGestureFile != 3) { _gestureBuf = _vm->_globals->freeMemory(_gestureBuf); _curGestureFile = 3; _gestureBuf = _vm->_fileIO->loadFile("PROFIL.SPR"); } switch (idx) { case 1: showActionAnimation(_gestureBuf, "20,19,18,17,16,15,14,13,13,13,13,13,14,15,16,17,18,19,20,-1,", 8, true); break; case 2: showSpecialActionAnimationWithFlip(_gestureBuf, "1,2,3,4,5,6,7,8,-1,", 8, true); break; case 3: showSpecialActionAnimation(_gestureBuf, "9,10,11,12,13,14,15,16,17,18,19,20,-1,", 8); break; case 4: showActionAnimation(_gestureBuf, "1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1,-1,", 8, true); break; case 5: showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,-1,", 8, true); break; case 6: showSpecialActionAnimation(_gestureBuf, "24,23,-1,", 8); break; case 7: showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,-1,", 8, true); break; case 8: showSpecialActionAnimation(_gestureBuf, "26,25,24,23,-1,", 8); break; case 9: showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,28,29,-1,", 8, true); break; case 10: showSpecialActionAnimation(_gestureBuf, "28,27,26,25,24,23,-1,", 8); break; } } void ObjectsManager::setAndPlayAnim(int idx, int animIdx, int destPosi, bool animAction) { // Set Hopkins animation and position setBobAnimation(idx); setBobAnimDataIdx(idx, animIdx); // Make Hopkins walk to the expected place do { _vm->_events->refreshScreenAndEvents(); } while (destPosi != getBobAnimDataIdx(idx)); if (!animAction) stopBobAnimation(idx); else { BobItem *bob = &_bob[idx]; _vm->_graphicsMan->fastDisplay(bob->_spriteData, bob->_oldX, bob->_oldY, bob->_frameIndex); stopBobAnimation(idx); _vm->_events->refreshScreenAndEvents(); } } int ObjectsManager::getBobAnimDataIdx(int idx) { return _bob[idx]._animDataIdx / 5; } void ObjectsManager::setBobAnimDataIdx(int idx, int animIdx) { BobItem *bob = &_bob[idx]; bob->_animDataIdx = 5 * animIdx; bob->_moveChange1 = 0; bob->_moveChange2 = 0; } /** * Set Hopkins animation */ void ObjectsManager::setBobAnimation(int idx) { assert(idx < 36); BobItem *bob = &_bob[idx]; if (!bob->_disabledAnimationFl) return; bob->_disabledAnimationFl = false; bob->_animDataIdx = 5; bob->_frameIndex = 250; bob->_moveChange1 = 0; bob->_moveChange2 = 0; } /** * Stop Hopkins animation */ void ObjectsManager::stopBobAnimation(int idx) { assert(idx < 36); _bob[idx]._disabledAnimationFl = true; } /** * Get X position */ int ObjectsManager::getBobPosX(int idx) { return _bob[idx]._xp; } void ObjectsManager::loadLinkFile(const Common::String &file, bool skipDetails) { Common::File f; Common::String filename = file + ".LNK"; bool fileFoundFl = false; byte *ptr = _vm->_fileIO->searchCat(filename, RES_LIN, fileFoundFl); size_t nbytes = _vm->_fileIO->_catalogSize; if (!fileFoundFl) { if (!f.open(filename)) error("Error opening file - %s", filename.c_str()); nbytes = f.size(); ptr = _vm->_globals->allocMemory(nbytes); if (ptr == NULL) error("INILINK"); _vm->_fileIO->readStream(f, ptr, nbytes); f.close(); } if (!skipDetails) { for (int idx = 0; idx < 500; ++idx) _vm->_globals->_spriteSize[idx] = READ_LE_INT16((uint16 *)ptr + idx); resetHidingItems(); Common::String filename2 = Common::String((const char *)ptr + 1000); if (!filename2.empty()) { fileFoundFl = false; _hidingItemData[1] = _vm->_fileIO->searchCat(filename2, RES_SLI, fileFoundFl); if (!fileFoundFl) { _hidingItemData[1] = _vm->_fileIO->loadFile(filename2); } else { _hidingItemData[1] = _vm->_fileIO->loadFile("RES_SLI.RES"); } int curDataCacheId = 60; byte *curDataPtr = ptr + 1000; for (int hidingIdx = 0; hidingIdx <= 21; hidingIdx++) { HidingItem *hid = &_hidingItem[hidingIdx]; int curSpriteId = READ_LE_INT16(curDataPtr + 2 * curDataCacheId); hid->_spriteIndex = curSpriteId; hid->_x = READ_LE_INT16(curDataPtr + 2 * curDataCacheId + 2); hid->_y = READ_LE_INT16(curDataPtr + 2 * curDataCacheId + 4); hid->_yOffset = READ_LE_INT16(curDataPtr + 2 * curDataCacheId + 8); if (!_hidingItemData[1]) { hid->_useCount = 0; } else { hid->_spriteData = _hidingItemData[1]; hid->_width = getWidth(_hidingItemData[1], curSpriteId); hid->_height = getHeight(_hidingItemData[1], curSpriteId); hid->_useCount = 1; } if (!hid->_x && !hid->_y && !hid->_spriteIndex) hid->_useCount = 0; curDataCacheId += 5; } enableHidingBehavior(); } } _vm->_linesMan->resetLines(); for (size_t idx = 0; idx < nbytes - 3; idx++) { if (READ_BE_UINT24(&ptr[idx]) == MKTAG24('O', 'B', '2')) { byte *curDataPtr = &ptr[idx + 4]; int lineDataIdx = 0; int curLineIdx = 0; _vm->_linesMan->resetLinesNumb(); Directions curDirection; do { curDirection = (Directions)READ_LE_INT16(curDataPtr + 2 * lineDataIdx); if (curDirection != DIR_NONE) { _vm->_linesMan->addLine( curLineIdx, curDirection, READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 2), READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 4), READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 6), READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 8)); } lineDataIdx += 5; ++curLineIdx; } while (curDirection != DIR_NONE); _vm->_linesMan->initRoute(); } } if (!skipDetails) { for (size_t idx = 0; idx < nbytes - 3; idx++) { if (READ_BE_UINT24(&ptr[idx]) == MKTAG24('Z', 'O', '2')) { byte *curDataPtr = &ptr[idx + 4]; int curDataIdx = 0; for (int i = 1; i <= 100; i++) { ZoneItem *curZone = &_vm->_linesMan->_zone[i]; curZone->_destX = 0; curZone->_destY = 0; curZone->_spriteIndex = 0; curZone->_verbFl1 = 0; curZone->_verbFl2 = 0; curZone->_verbFl3 = 0; curZone->_verbFl4 = 0; curZone->_verbFl5 = 0; curZone->_verbFl6 = 0; curZone->_verbFl7 = 0; curZone->_verbFl8 = 0; curZone->_verbFl9 = 0; curZone->_verbFl10 = 0; curZone->_messageId = 0; } int curLineIdx = 0; for (;;) { int bobZoneId = READ_LE_INT16(curDataPtr + 2 * curDataIdx); if (bobZoneId != -1) { _vm->_linesMan->addZoneLine( curLineIdx, READ_LE_INT16(curDataPtr + 2 * curDataIdx + 2), READ_LE_INT16(curDataPtr + 2 * curDataIdx + 4), READ_LE_INT16(curDataPtr + 2 * curDataIdx + 6), READ_LE_INT16(curDataPtr + 2 * curDataIdx + 8), bobZoneId); _vm->_linesMan->_zone[bobZoneId]._enabledFl = true; } curDataIdx += 5; ++curLineIdx; if (bobZoneId == -1) break; } for (int i = 1; i <= 100; i++) { ZoneItem *curZone = &_vm->_linesMan->_zone[i]; curZone->_destX = READ_LE_INT16(curDataPtr + 2 * curDataIdx); curZone->_destY = READ_LE_INT16(curDataPtr + 2 * curDataIdx + 2); curZone->_spriteIndex = READ_LE_INT16(curDataPtr + 2 * curDataIdx + 4); curDataIdx += 3; } byte *verbData = ptr + idx + (10 * curLineIdx + 606) + 4; for (int i = 1; i <= 100; i++) { int j = (i - 1) * 10; ZoneItem *curZone = &_vm->_linesMan->_zone[i]; curZone->_verbFl1 = verbData[j]; curZone->_verbFl2 = verbData[j + 1]; curZone->_verbFl3 = verbData[j + 2]; curZone->_verbFl4 = verbData[j + 3]; curZone->_verbFl5 = verbData[j + 4]; curZone->_verbFl6 = verbData[j + 5]; curZone->_verbFl7 = verbData[j + 6]; curZone->_verbFl8 = verbData[j + 7]; curZone->_verbFl9 = verbData[j + 8]; curZone->_verbFl10 = verbData[j + 9]; } int dep = 1010; for (int i = 1; i <= 100; i++) { _vm->_linesMan->_zone[i]._messageId = READ_LE_INT16(verbData + dep); dep += 2; } _vm->_linesMan->initSquareZones(); } } } _vm->_globals->freeMemory(ptr); } void ObjectsManager::sceneSpecialIni() { switch (_vm->_globals->_screenId) { case 17: if (_vm->_globals->_prevScreenId == 20) { _vm->_globals->_disableInventFl = true; _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0); for (int i = 0; i <= 4; i++) _vm->_events->refreshScreenAndEvents(); _vm->_graphicsMan->fadeInLong(); animateSprite(0); for (int i = 0; i <= 4; i++) _vm->_events->refreshScreenAndEvents(); initVbob(_vm->_globals->_levelSpriteBuf, 5, 15, 28, 1); _vm->_fontMan->hideText(9); bool displayedTxtFl = false; if (!_vm->_soundMan->_textOffFl) { _vm->_fontMan->initTextBuffers(9, 383, _vm->_globals->_textFilename, 220, 72, 6, 36, 253); _vm->_fontMan->showText(9); displayedTxtFl = true; } if (!_vm->_soundMan->_voiceOffFl) _vm->_soundMan->mixVoice(383, 4, displayedTxtFl); _vm->_globals->_saveData->_data[svField270] = 1; _vm->_globals->_saveData->_data[svField300] = 1; _vm->_globals->_saveData->_data[svField320] = 1; if (_vm->_soundMan->_voiceOffFl) { for (int i = 0; i <= 199; i++) _vm->_events->refreshScreenAndEvents(); } _vm->_fontMan->hideText(9); disableVbob(5); for (int i = 0; i <= 3; i++) _vm->_events->refreshScreenAndEvents(); _vm->_graphicsMan->_noFadingFl = true; _vm->_globals->_disableInventFl = false; } break; case 18: if (_vm->_globals->_prevScreenId == 17) { _vm->_events->_mouseSpriteId = 4; for (int i = 0; i <= 4; i++) _vm->_events->refreshScreenAndEvents(); _vm->_graphicsMan->fadeInLong(); _vm->_globals->_eventMode = EVENTMODE_IGNORE; _vm->_globals->_disableInventFl = false; _vm->_graphicsMan->_noFadingFl = true; _vm->_globals->_introSpeechOffFl = true; _vm->_talkMan->startAnimatedCharacterDialogue("MAGE1.pe2"); _vm->_graphicsMan->_noFadingFl = true; _vm->_globals->_disableInventFl = false; } break; case 35: case 36: case 37: case 38: case 39: case 40: case 41: _vm->_linesMan->_bobZone[20] = 1; _vm->_linesMan->_bobZone[21] = 2; _vm->_linesMan->_bobZone[22] = 3; _vm->_linesMan->_bobZone[23] = 4; _vm->_linesMan->_bobZoneFl[20] = true; _vm->_linesMan->_bobZoneFl[21] = true; _vm->_linesMan->_bobZoneFl[22] = true; _vm->_linesMan->_bobZoneFl[23] = true; enableVerb(20, 5); enableVerb(21, 5); enableVerb(22, 5); enableVerb(23, 5); _vm->_linesMan->_zone[20]._messageId = 30; _vm->_linesMan->_zone[21]._messageId = 30; _vm->_linesMan->_zone[22]._messageId = 30; _vm->_linesMan->_zone[23]._messageId = 30; for (int i = svField200; i <= svField214; i++) { if (_vm->_globals->_saveData->_data[i] != 2) _vm->_globals->_saveData->_data[i] = 0; } break; case 73: if (!_vm->_globals->_saveData->_data[svSecondElevatorAvailableFl]) { resetHidingUseCount(0); resetHidingUseCount(1); } break; case 93: if (!_vm->_globals->_saveData->_data[svField333]) setBobAnimation(8); break; } } void ObjectsManager::setMultiBobAnim(int idx1, int idx2, int anim1Idx, int anim2Idx) { if (idx1 != -1) setBobAnimation(idx1); if (idx2 != -1) setBobAnimation(idx2); if (idx1 != -1) setBobAnimDataIdx(idx1, anim1Idx); if (idx2 != -1) setBobAnimDataIdx(idx2, anim2Idx); } void ObjectsManager::checkEventBobAnim(int idx, int animIdx, int animDataIdx, int a4) { _vm->_events->_curMouseButton = 0; _vm->_events->_mouseButton = 0; if (a4 != 3) { setBobAnimation(idx); setBobAnimDataIdx(idx, animIdx); } do { _vm->_events->refreshScreenAndEvents(); if (_vm->_events->_curMouseButton) break; } while (animDataIdx != getBobAnimDataIdx(idx)); if (!a4) stopBobAnimation(idx); } void ObjectsManager::disableVerb(int idx, int a2) { ZoneItem *curZone = &_vm->_linesMan->_zone[idx]; switch (a2) { case 6: case 16: curZone->_verbFl1 = 0; break; case 7: curZone->_verbFl2 = 0; break; case 5: case 8: curZone->_verbFl3 = 0; break; case 9: case 17: case 24: curZone->_verbFl4 = 0; break; case 10: case 18: curZone->_verbFl5 = 0; break; case 11: case 19: curZone->_verbFl6 = 0; break; case 12: case 20: curZone->_verbFl7 = 0; break; case 13: case 22: curZone->_verbFl8 = 0; break; case 14: case 21: case 25: curZone->_verbFl9 = 0; break; case 15: curZone->_verbFl10 = 0; break; } _changeVerbFl = true; } void ObjectsManager::enableVerb(int idx, int a2) { ZoneItem *curZone = &_vm->_linesMan->_zone[idx]; switch (a2) { case 5: curZone->_verbFl3 = 2; break; case 6: curZone->_verbFl1 = 1; break; case 7: curZone->_verbFl2 = 1; break; case 8: curZone->_verbFl3 = 1; break; case 9: curZone->_verbFl4 = 1; break; case 10: curZone->_verbFl5 = 1; break; case 11: curZone->_verbFl6 = 1; break; case 12: curZone->_verbFl7 = 1; break; case 13: curZone->_verbFl8 = 1; break; case 14: curZone->_verbFl8 = 1; break; case 15: curZone->_verbFl9 = 1; break; case 16: curZone->_verbFl1 = 2; break; case 17: curZone->_verbFl4 = 2; break; case 18: curZone->_verbFl5 = 2; break; case 19: curZone->_verbFl6 = 2; break; case 20: curZone->_verbFl7 = 2; break; case 21: curZone->_verbFl9 = 2; break; case 22: curZone->_verbFl8 = 2; break; case 24: curZone->_verbFl4 = 3; break; case 25: curZone->_verbFl9 = 2; break; } } void ObjectsManager::showActionAnimation(const byte *spriteData, const Common::String &actionStr, int speed, bool flipFl) { Common::String tmpStr = ""; int realSpeed = speed; if (_vm->_globals->_speed == 2) realSpeed = speed / 2; else if (_vm->_globals->_speed == 3) realSpeed = speed / 3; const byte *oldSpriteData = _sprite[0]._spriteData; int spriteIndex = _sprite[0]._spriteIndex; bool oldFlipFl = _sprite[0]._flipFl; _sprite[0]._flipFl = flipFl; int idx = 0; for (int strPos = 0; ; strPos++) { bool tokenCompleteFl = false; char curChar = actionStr[strPos]; if (curChar == ',') { idx = atoi(tmpStr.c_str()); tmpStr = ""; tokenCompleteFl = true; } else { tmpStr += curChar; } if (tokenCompleteFl) { if (idx == -1) { _sprite[0]._spriteData = oldSpriteData; _sprite[0]._spriteIndex = spriteIndex; _sprite[0]._flipFl = oldFlipFl; } else { _sprite[0]._spriteData = spriteData; _sprite[0]._spriteIndex = idx; } for (int i = 0; i < realSpeed; i++) _vm->_events->refreshScreenAndEvents(); if (idx == -1) break; } } } void ObjectsManager::showSpecialActionAnimationWithFlip(const byte *spriteData, const Common::String &animationSeq, int speed, bool flipFl) { Common::String tmpStr = ""; int realSpeed = speed; if (_vm->_globals->_speed == 2) realSpeed = speed / 2; else if (_vm->_globals->_speed == 3) realSpeed = speed / 3; _oldSpriteData = _sprite[0]._spriteData; _oldSpriteIndex = _sprite[0]._spriteIndex; _oldFlipFl = _sprite[0]._flipFl; _sprite[0]._flipFl = flipFl; uint strPos = 0; int spriteIndex = 0; do { bool completeTokenFl = false; do { char nextChar = animationSeq[strPos]; if ((animationSeq[strPos] == ',') || (strPos == animationSeq.size() - 1)) { // Safeguard: if the sequence doesn't end with a coma, simulate it's present. if (animationSeq[strPos] != ',') tmpStr += nextChar; spriteIndex = atoi(tmpStr.c_str()); tmpStr = ""; completeTokenFl = true; } else { tmpStr += nextChar; } ++strPos; } while (!completeTokenFl); if (spriteIndex != -1) { _sprite[0]._spriteData = spriteData; _sprite[0]._spriteIndex = spriteIndex; } for (int i = 0; i < realSpeed; i++) _vm->_events->refreshScreenAndEvents(); } while (spriteIndex != -1); } void ObjectsManager::showSpecialActionAnimation(const byte *spriteData, const Common::String &animString, int speed) { Common::String tmpStr = ""; int realSpeed = speed; if (_vm->_globals->_speed == 2) realSpeed = speed / 2; else if (_vm->_globals->_speed == 3) realSpeed = speed / 3; int spriteIndex = 0; for (int idx = 0; ; idx++) { bool completeTokenFl = false; char nextChar = animString[idx]; if (nextChar == ',') { spriteIndex = atoi(tmpStr.c_str()); tmpStr = ""; completeTokenFl = true; } else { tmpStr += nextChar; } if (completeTokenFl) { if (spriteIndex == -1) { _sprite[0]._spriteData = _oldSpriteData; _sprite[0]._spriteIndex = _oldSpriteIndex; _sprite[0]._flipFl = _oldFlipFl; } else { _sprite[0]._spriteData = spriteData; _sprite[0]._spriteIndex = spriteIndex; } for (int i = 0; i < realSpeed; i++) _vm->_events->refreshScreenAndEvents(); if (spriteIndex == -1) break; } } } void ObjectsManager::handleForest(int screenId, int minX, int maxX, int minY, int maxY, int idx) { int savegameIdx = screenId; if (_vm->_globals->_screenId != screenId) return; switch (_vm->_globals->_screenId) { case 35: if (idx > 2) savegameIdx = 201; else savegameIdx = 200; break; case 36: if (idx > 2) savegameIdx = 203; else savegameIdx = 202; break; case 37: if (idx > 2) savegameIdx = 205; else savegameIdx = 204; break; case 38: if (idx > 2) savegameIdx = 207; else savegameIdx = 206; break; case 39: if (idx > 2) savegameIdx = 209; else savegameIdx = 208; break; case 40: if (idx > 2) savegameIdx = 211; else savegameIdx = 210; break; case 41: if (idx > 2) savegameIdx = 213; else savegameIdx = 212; break; } if (_vm->_globals->_saveData->_data[savegameIdx] == 2) return; if (_vm->_globals->_saveData->_data[savegameIdx]) { if (_vm->_globals->_saveData->_data[savegameIdx] == 1) { if (((idx == 1 || idx == 2) && getBobAnimDataIdx(idx) == 26) || ((idx == 3 || idx == 4) && getBobAnimDataIdx(idx) == 27)) { _vm->_dialog->disableInvent(); _vm->_soundMan->playSample(1); _vm->_globals->_saveData->_data[savegameIdx] = 4; } } if (_vm->_globals->_saveData->_data[savegameIdx] == 4) { if (idx >= 1 && idx <= 4 && getBobAnimDataIdx(idx) > 30) _vm->_globals->_saveData->_data[savegameIdx] = 3; } if (_vm->_globals->_saveData->_data[savegameIdx] == 3) { _vm->_graphicsMan->_fadingFl = true; _vm->_animMan->playAnim("CREVE2.ANM", "CREVE2.ANM", 100, 24, 500); _vm->_globals->_exitId = 150; _vm->_graphicsMan->_noFadingFl = true; hideBob(1); hideBob(2); hideBob(3); hideBob(4); } } else if (minX < getSpriteX(0) && maxX > getSpriteX(0) && minY < getSpriteY(0) && maxY > getSpriteY(0)) { if (idx >= 1 && idx <= 4) setBobAnimation(idx); _vm->_globals->_saveData->_data[savegameIdx] = 1; } } void ObjectsManager::lockAnimX(int idx, int x) { _lockedAnims[idx]._enableFl = true; _lockedAnims[idx]._posX = x; } /** * Game scene control method */ void ObjectsManager::sceneControl(const Common::String &backgroundFile, const Common::String &linkFile, const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen) { _vm->_dialog->_inventFl = false; _vm->_events->_gameKey = KEY_NONE; _vm->_dialog->enableInvent(); _vm->_graphicsMan->_scrollOffset = 0; _vm->_globals->_cityMapEnabledFl = false; _vm->_globals->_eventMode = EVENTMODE_IGNORE; _vm->_soundMan->playSound(soundNum); _vm->_linesMan->_route = NULL; _vm->_globals->_freezeCharacterFl = true; _vm->_globals->_exitId = 0; if (!backgroundFile.empty()) _vm->_graphicsMan->loadImage(backgroundFile); if (!linkFile.empty()) loadLinkFile(linkFile); if (!animFile.empty()) _vm->_animMan->loadAnim(animFile); _vm->_graphicsMan->displayAllBob(); if (!s4.empty()) { if (initializeScreen) _vm->_graphicsMan->initScreen(s4, 0, initializeScreen); else _vm->_graphicsMan->initScreen(s4, 2, initializeScreen); } _vm->_events->mouseOn(); if (_vm->_globals->_screenId == 61) { addStaticSprite(_vm->_globals->_characterSpriteBuf, Common::Point(330, 418), 0, 60, 0, false, 34, 190); animateSprite(0); _vm->_linesMan->_route = NULL; computeAndSetSpriteSize(); } _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0); _vm->_events->changeMouseCursor(4); for (int i = 0; i <= 4; i++) _vm->_events->refreshScreenAndEvents(); _vm->_graphicsMan->fadeInLong(); if (_vm->_globals->_screenId == 61) { _vm->_animMan->playSequence("OUVRE.SEQ", 10, 4, 10, false, false); stopBobAnimation(3); _vm->_globals->_checkDistanceFl = true; _oldCharacterPosX = getSpriteX(0); _oldDirection = DIR_NONE; _homeRateCounter = 0; _vm->_linesMan->_route = NULL; _vm->_linesMan->_route = _vm->_linesMan->findRoute(getSpriteX(0), getSpriteY(0), 330, 345); _vm->_globals->_checkDistanceFl = true; do { goHome(); _vm->_events->refreshScreenAndEvents(); } while (_vm->_linesMan->_route); setSpriteIndex(0, 64); } do { int mouseButton = _vm->_events->getMouseButton(); if (mouseButton == 1) { handleLeftButton(); mouseButton = 1; } else if (mouseButton == 2) handleRightButton(); _vm->_dialog->testDialogOpening(); _vm->_linesMan->checkZone(); if (_vm->_globals->_actionMoveTo) paradise(); if (!_vm->_globals->_exitId) _vm->_events->refreshScreenAndEvents(); if (_vm->_globals->_exitId) break; } while (!_vm->shouldQuit()); if (_vm->shouldQuit()) return; _vm->_graphicsMan->fadeOutLong(); if (!animFile.empty()) _vm->_graphicsMan->endDisplayBob(); if (_vm->_globals->_screenId == 61) removeSprite(0); clearScreen(); _vm->_globals->_eventMode = EVENTMODE_DEFAULT; } /** * Game scene control method */ void ObjectsManager::sceneControl2(const Common::String &backgroundFile, const Common::String &linkFile, const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen) { _vm->_dialog->_inventFl = false; _vm->_events->_gameKey = KEY_NONE; _verb = 4; _vm->_graphicsMan->_scrollOffset = 0; _vm->_dialog->enableInvent(); _vm->_globals->_cityMapEnabledFl = false; _vm->_graphicsMan->_noFadingFl = false; _vm->_globals->_freezeCharacterFl = false; _vm->_globals->_exitId = 0; _vm->_globals->_checkDistanceFl = true; _vm->_soundMan->playSound(soundNum); _vm->_globals->_eventMode = EVENTMODE_IGNORE; if (!backgroundFile.empty()) _vm->_graphicsMan->loadImage(backgroundFile); if (!linkFile.empty()) loadLinkFile(linkFile); if (!animFile.empty()) { _vm->_animMan->loadAnim(animFile); _vm->_graphicsMan->displayAllBob(); } if (!s4.empty()) { if (initializeScreen) _vm->_graphicsMan->initScreen(s4, 0, initializeScreen); else _vm->_graphicsMan->initScreen(s4, 2, initializeScreen); } _vm->_events->mouseOn(); _vm->_events->_mouseCursorId = 4; _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100); _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0); if (_vm->_globals->_characterType != CHARACTER_HOPKINS && !_vm->_globals->_saveData->_data[svAlternateSpriteFl] && !_vm->_globals->_saveData->_data[svField356]) { _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PERSO.SPR"); _vm->_globals->_characterType = CHARACTER_HOPKINS; } if (_vm->_globals->_characterType == CHARACTER_HOPKINS && _vm->_globals->_saveData->_data[svAlternateSpriteFl] == 1) { _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("HOPFEM.SPR"); _vm->_globals->_characterType = CHARACTER_HOPKINS_CLONE; } if (_vm->_globals->_characterType != CHARACTER_SAMANTHA && _vm->_globals->_saveData->_data[svField356] == 1) { _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PSAMAN.SPR"); _vm->_globals->_characterType = CHARACTER_SAMANTHA; } _vm->_globals->loadCharacterData(); switch (_vm->_globals->_characterType) { case CHARACTER_HOPKINS: addStaticSprite(_vm->_globals->_characterSpriteBuf, _characterPos, 0, _startSpriteIndex, 0, false, 34, 190); break; case CHARACTER_HOPKINS_CLONE: addStaticSprite(_vm->_globals->_characterSpriteBuf, _characterPos, 0, _startSpriteIndex, 0, false, 28, 155); break; case CHARACTER_SAMANTHA: addStaticSprite(_vm->_globals->_characterSpriteBuf, _characterPos, 0, _startSpriteIndex, 0, false, 20, 127); break; } _vm->_events->setMouseXY(_characterPos); if (_vm->_graphicsMan->_largeScreenFl) _vm->_graphicsMan->_scrollPosX = (int16)getSpriteX(0) - 320; computeAndSetSpriteSize(); animateSprite(0); enableHidingBehavior(); _vm->_linesMan->_route = NULL; computeAndSetSpriteSize(); sceneSpecialIni(); _vm->_events->_mouseSpriteId = 4; _oldCharacterPosX = _characterPos.x; _oldCharacterPosY = _characterPos.y; _oldDirection = DIR_NONE; _homeRateCounter = 0; for (int idx = 0; idx < 5; ++idx) _vm->_events->refreshScreenAndEvents(); _vm->_globals->_eventMode = EVENTMODE_IGNORE; if (!_vm->_graphicsMan->_noFadingFl) _vm->_graphicsMan->fadeInLong(); _vm->_graphicsMan->_noFadingFl = false; _vm->_events->changeMouseCursor(4); int xCheck = 0; int yCheck = 0; bool breakFlag = false; while (!_vm->shouldQuit() && !breakFlag) { int mouseButtons = _vm->_events->getMouseButton(); if (mouseButtons) { if (mouseButtons == 1) { if (_verb == 16 && _vm->_events->_mouseCursorId == 16) { int xp = _vm->_events->getMouseX(); int yp = _vm->_events->getMouseY(); if ((xCheck == xp) && (yCheck == yp)) { _vm->_linesMan->_route = NULL; paradise(); if (_vm->_globals->_exitId) breakFlag = true; } xCheck = xp; yCheck = yp; } handleLeftButton(); } else if (mouseButtons == 2) { handleRightButton(); } } if (!_vm->_globals->_exitId) { _vm->_dialog->testDialogOpening(); _vm->_linesMan->checkZone(); if (_vm->_linesMan->_route == NULL || (goHome(), _vm->_linesMan->_route == NULL)) { if (_vm->_globals->_actionMoveTo) paradise(); } handleSpecialGames(); _vm->_events->refreshScreenAndEvents(); if (!_vm->_globals->_exitId) continue; } breakFlag = true; } if (_vm->_globals->_exitId != 8 || _vm->_globals->_screenId != 5 || !_helicopterFl) { if (!_vm->_graphicsMan->_noFadingFl) _vm->_graphicsMan->fadeOutLong(); _vm->_graphicsMan->_noFadingFl = false; removeSprite(0); if (_twoCharactersFl) { removeSprite(1); _twoCharactersFl = false; } if (!animFile.empty()) _vm->_graphicsMan->endDisplayBob(); clearScreen(); } else { _helicopterFl = false; } _vm->_globals->_eventMode = EVENTMODE_DEFAULT; } void ObjectsManager::setVerb(int id) { _verb = id; } void ObjectsManager::resetHidingUseCount(int idx) { _hidingItem[idx]._useCount = 0; } void ObjectsManager::setHidingUseCount(int idx) { _hidingItem[idx]._useCount = 1; } // Load Hiding Items void ObjectsManager::loadHidingItems(const Common::String &file) { resetHidingItems(); byte *ptr = _vm->_fileIO->loadFile(file); Common::String filename = Common::String((const char *)ptr); Common::File f; if (!f.exists(filename)) return; byte *spriteData = _vm->_fileIO->loadFile(filename); _hidingItemData[1] = spriteData; int curBufIdx = 60; for (int i = 0; i <= 21; i++) { HidingItem *hid = &_hidingItem[i]; hid->_spriteIndex = READ_LE_INT16((uint16 *)ptr + curBufIdx); hid->_x = READ_LE_INT16((uint16 *)ptr + curBufIdx + 1); hid->_y = READ_LE_INT16((uint16 *)ptr + curBufIdx + 2); hid->_yOffset = READ_LE_INT16((uint16 *)ptr + curBufIdx + 4); if (spriteData == NULL) { hid->_useCount = 0; } else { hid->_spriteData = spriteData; hid->_width = getWidth(spriteData, hid->_spriteIndex); hid->_height = getHeight(spriteData, hid->_spriteIndex); hid->_useCount = 1; } if ( !hid->_x && !hid->_y && !hid->_spriteIndex) hid->_useCount = 0; curBufIdx += 5; } enableHidingBehavior(); _vm->_globals->freeMemory(ptr); } void ObjectsManager::initVBob() { for (int idx = 0; idx < 30; ++idx) { VBobItem *vbob = &_vBob[idx]; vbob->_displayMode = 0; vbob->_xp = 0; vbob->_yp = 0; vbob->_frameIndex = 0; vbob->_surface = NULL; vbob->_spriteData = NULL; vbob->_oldSpriteData = NULL; } } void ObjectsManager::clearVBob() { for (int idx = 0; idx < 30; ++idx) { VBobItem *vbob = &_vBob[idx]; vbob->_displayMode = 0; vbob->_xp = 0; vbob->_yp = 0; vbob->_frameIndex = 0; vbob->_surface = _vm->_globals->freeMemory(vbob->_surface); vbob->_spriteData = NULL; vbob->_oldSpriteData = NULL; } } void ObjectsManager::disableHidingItem(int idx) { assert(idx < 36); _bob[idx]._disableFl = true; } void ObjectsManager::enableHidingBehavior() { _hidingActiveFl = true; } void ObjectsManager::disableHidingBehavior() { _hidingActiveFl = false; } } // End of namespace Hopkins