/* 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 "fullpipe/fullpipe.h" #include "fullpipe/objects.h" #include "fullpipe/ngiarchive.h" #include "fullpipe/statics.h" #include "fullpipe/messages.h" #include "fullpipe/interaction.h" #include "fullpipe/motion.h" #include "fullpipe/constants.h" #include "fullpipe/objectnames.h" namespace Fullpipe { StepArray::StepArray() { _points = 0; _maxPointIndex = 0; _currPointIndex = 0; _pointsCount = 0; _isEos = 0; } StepArray::~StepArray() { if (_pointsCount) { for (int i = 0; i < _pointsCount; i++) delete _points[i]; delete _points; _points = 0; } } void StepArray::clear() { _currPointIndex = 0; _maxPointIndex = 0; _isEos = 0; for (int i = 0; i < _pointsCount; i++) { _points[i]->x = 0; _points[i]->y = 0; } } Common::Point *StepArray::getCurrPoint(Common::Point *point) { if (_isEos || _points == 0) { point->x = 0; point->y = 0; } else { point = _points[_currPointIndex]; } return point; } Common::Point *StepArray::getPoint(Common::Point *point, int index, int offset) { if (index == -1) index = _currPointIndex; if (index + offset > _maxPointIndex - 1) offset = _maxPointIndex - index; point->x = 0; point->y = 0; while (offset >= 1) { point->x += _points[index]->x; point->y += _points[index]->y; index++; offset--; } return point; } bool StepArray::gotoNextPoint() { if (_currPointIndex < _maxPointIndex) { _currPointIndex++; return true; } else { _isEos = 1; return false; } } void StepArray::insertPoints(Common::Point **points, int pointsCount) { if (_currPointIndex + pointsCount >= _pointsCount) { _points = (Common::Point **)realloc(_points, sizeof(Common::Point *) * (_currPointIndex + pointsCount)); if (!_points) { error("Out of memory at StepArray::insertPoints()"); } } _maxPointIndex = _currPointIndex + pointsCount; for (int i = 0; i < pointsCount; i++) { _points[_currPointIndex + i] = new Common::Point; *_points[_currPointIndex + i] = *points[i]; } } StaticANIObject::StaticANIObject() { _shadowsOn = 1; _field_30 = 0; _field_34 = 1; _initialCounter = 0; _messageQueueId = 0; _animExFlag = 0; _counter = 0; _movement = 0; _statics = 0; _flags = 0; _callback1 = 0; _callback2 = 0; _sceneId = -1; _someDynamicPhaseIndex = -1; _field_32 = 0; _field_96 = 0; _messageNum = 0; _objtype = kObjTypeStaticANIObject; } StaticANIObject::~StaticANIObject() { for (uint i = 0; i < _staticsList.size(); i++) delete _staticsList[i]; _staticsList.clear(); for (uint i = 0; i < _movements.size(); i++) delete _movements[i]; _movements.clear(); g_fp->_mgm->clear(); } StaticANIObject::StaticANIObject(StaticANIObject *src) : GameObject(src) { _shadowsOn = src->_shadowsOn; _field_30 = src->_field_30; _field_34 = 1; _initialCounter = 0; _field_32 = 0; _field_96 = 0; _messageNum = 0; _messageQueueId = 0; _animExFlag = 0; _counter = 0; _someDynamicPhaseIndex = -1; _sceneId = src->_sceneId; _callback1 = src->_callback1; _callback2 = src->_callback2; _objtype = kObjTypeStaticANIObject; for (uint i = 0; i < src->_staticsList.size(); i++) _staticsList.push_back(new Statics(src->_staticsList[i], 0)); _movement = 0; _statics = 0; for (uint i = 0; i < src->_movements.size(); i++) { Movement *newmov; if (src->_movements[i]->_currMovement) { // WORKAROUND: Original uses weird construction here: // new Movement(getMovementById(src->getMovementIdById(mov->_id)), this); newmov = new Movement(src->getMovementById(src->getMovementIdById(src->_movements[i]->_id)), this); newmov->_id = src->_movements[i]->_id; } else { newmov = new Movement(src->_movements[i], 0, -1, this); } _movements.push_back(newmov); } } bool StaticANIObject::load(MfcArchive &file) { debug(5, "StaticANIObject::load()"); GameObject::load(file); int count = file.readUint16LE(); for (int i = 0; i < count; i++) { Statics *st = new Statics(); st->load(file); _staticsList.push_back(st); } count = file.readUint16LE(); debug(7, "Movements: %d", count); for (int i = 0; i < count; i++) { int movNum = file.readUint16LE(); char *movname = genFileName(_id, movNum, "mov"); Common::SeekableReadStream *f = g_fp->_currArchive->createReadStreamForMember(movname); Movement *mov = new Movement(); MfcArchive archive(f); mov->load(archive, this); _movements.push_back(mov); delete f; free(movname); } Common::Point pt; if (count) { // We have movements _movements[0]->getCurrDynamicPhaseXY(pt); } else { pt.x = pt.y = 100; } setOXY(pt.x, pt.y); return true; } void StaticANIObject::setOXY(int x, int y) { _ox = x; _oy = y; if (_movement) _movement->setOXY(x, y); } void StaticANIObject::clearFlags() { _flags = 0; deleteFromGlobalMessageQueue(); _messageQueueId = 0; _movement = 0; _statics = 0; _animExFlag = 0; _counter = 0; _messageNum = 0; _stepArray.clear(); } void StaticANIObject::setFlags40(bool state) { if (state) { _flags |= 0x40; } else { if (_flags & 0x40) _flags ^= 0x40; } } void StaticANIObject::deleteFromGlobalMessageQueue() { while (_messageQueueId) { if (g_fp->_globalMessageQueueList->getMessageQueueById(_messageQueueId)) { if (!isIdle()) return; g_fp->_globalMessageQueueList->deleteQueueById(_messageQueueId); } else { _messageQueueId = 0; } } } bool StaticANIObject::queueMessageQueue(MessageQueue *mq) { if (_flags & 0x80) return false; if (isIdle()) { deleteFromGlobalMessageQueue(); _messageQueueId = 0; _messageNum = 0; if (_flags & 2) _flags ^= 2; if (mq) { _animExFlag = 0; if (_movement) _messageQueueId = mq->_id; else mq->sendNextCommand(); } else { _messageQueueId = 0; } } return true; } void StaticANIObject::restartMessageQueue(MessageQueue *mq) { ExCommand *ex = mq->getExCommandByIndex(0); if (ex) { while (ex->_messageKind != 1 || ex->_parentId != _id) { ex->_parId = 0; ex->_excFlags |= 2; ex->handleMessage(); mq->deleteExCommandByIndex(0, 0); ex = mq->getExCommandByIndex(0); if (!ex) return; } if (ex) { startAnim(ex->_messageNum, mq->_id, -1); mq->deleteExCommandByIndex(0, 1); } } } MessageQueue *StaticANIObject::getMessageQueue() { if (this->_messageQueueId <= 0) return 0; return g_fp->_globalMessageQueueList->getMessageQueueById(_messageQueueId); } bool StaticANIObject::trySetMessageQueue(int msgNum, int qId) { if (_messageQueueId || !msgNum) { updateGlobalMessageQueue(qId, _id); return false; } _flags |= 2; _messageNum = msgNum; _messageQueueId = qId; return true; } void StaticANIObject::startMQIfIdle(int qId, int flag) { MessageQueue *msg = g_fp->_currentScene->getMessageQueueById(qId); if (msg && isIdle() && !(_flags & 0x100)) { MessageQueue *mq = new MessageQueue(msg, 0, 0); mq->setFlags(mq->getFlags() | flag); ExCommand *ex = mq->getExCommandByIndex(0); if (ex) { while (ex->_messageKind != 1 || ex->_parentId != _id) { ex->_parId = 0; ex->_excFlags |= 2; ex->handleMessage(); mq->deleteExCommandByIndex(0, 0); ex = mq->getExCommandByIndex(0); if (!ex) return; } if (ex) { startAnim(ex->_messageNum, mq->_id, -1); mq->deleteExCommandByIndex(0, 1); } } } } bool StaticANIObject::isIdle() { if (_messageQueueId) { MessageQueue *m = g_fp->_globalMessageQueueList->getMessageQueueById(_messageQueueId); if (m && m->getFlags() & 1) return false; } return true; } Statics *StaticANIObject::getStaticsById(int itemId) { for (uint i = 0; i < _staticsList.size(); i++) if (_staticsList[i]->_staticsId == itemId) return _staticsList[i]; return 0; } Statics *StaticANIObject::getStaticsByName(char *name) { for (uint i = 0; i < _staticsList.size(); i++) if (!strcmp(_staticsList[i]->_staticsName, name)) return _staticsList[i]; return 0; } Movement *StaticANIObject::getMovementById(int itemId) { for (uint i = 0; i < _movements.size(); i++) if (_movements[i]->_id == itemId) return _movements[i]; return 0; } int StaticANIObject::getMovementIdById(int itemId) { for (uint i = 0; i < _movements.size(); i++) { Movement *mov = _movements[i]; if (mov->_currMovement) { if (mov->_id == itemId) return mov->_id; if (mov->_currMovement->_id == itemId) return mov->_id; } } return 0; } Movement *StaticANIObject::getMovementByName(char *name) { for (uint i = 0; i < _movements.size(); i++) if (!strcmp(_movements[i]->_objectName, name)) return _movements[i]; return 0; } bool StaticANIObject::getPixelAtPos(int x, int y, int *pixel) { bool res = false; Picture *pic; if (_movement) pic = _movement->_currDynamicPhase; else pic = _statics; if (!pic) return false; int ongoing; int xani, yani; int oxani, oyani; Common::Point point; if (_movement) ongoing = _movement->_currMovement != 0; else ongoing = _statics->_staticsId & 0x4000; if (_movement) { _movement->getCurrDynamicPhaseXY(point); xani = point.x; yani = point.y; oxani = _movement->_ox; oyani = _movement->_oy; } else { _statics->getSomeXY(point); xani = point.x; yani = point.y; oxani = _ox; oyani = _oy; } int xtarget = x - (oxani - xani); int ytarget = y - (oyani - yani); if (ongoing && _movement) xtarget = pic->getDimensions(&point)->x - xtarget; x = pic->_x; y = pic->_y; pic->_x = 0; pic->_y = 0; if (pic->isPixelHitAtPos(xtarget, ytarget)) { *pixel = pic->getPixelAtPos(xtarget, ytarget); res = true; } else { res = false; } pic->_x = x; pic->_y = y; return res; } void Movement::draw(bool flipFlag, int angle) { debug(3, "Movement::draw(%d, %d)", flipFlag, angle); Common::Point point; getCurrDynamicPhaseXY(point); int x = _ox - point.x; int y = _oy - point.y; if (_currDynamicPhase->getPaletteData()) g_fp->_globalPalette = _currDynamicPhase->getPaletteData(); if (_currDynamicPhase->getAlpha() < 0xFF) { warning("Movement::draw: alpha < 0xff: %d", _currDynamicPhase->getAlpha()); //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, _currDynamicPhase->getAlpha()); } Bitmap *bmp; if (_currMovement) { bmp = _currDynamicPhase->getPixelData()->reverseImage(); } else { bmp = _currDynamicPhase->getPixelData()->reverseImage(false); } if (flipFlag) { bmp->flipVertical()->drawShaded(1, x, y + 30 + _currDynamicPhase->_rect->bottom, _currDynamicPhase->_paletteData, _currDynamicPhase->_alpha); } if (angle) { bmp->drawRotated(x, y, angle, _currDynamicPhase->_paletteData, _currDynamicPhase->_alpha); } else { bmp->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData, _currDynamicPhase->_alpha); } if (_currDynamicPhase->_rect->top) { if (!_currDynamicPhase->_convertedBitmap) { //v12 = Picture_getPixelData(v5); //v13 = Bitmap_convertTo16Bit565(v12, (unsigned int *)&_currDynamicPhase->rect); //_currDynamicPhase->convertedBitmap = v13; } if (_currDynamicPhase->_convertedBitmap) { if (_currMovement) { //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top)); _currDynamicPhase->_convertedBitmap->reverseImage()->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData, _currDynamicPhase->_alpha); //vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); } else { //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top)); _currDynamicPhase->_convertedBitmap->reverseImage(false)->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData, _currDynamicPhase->_alpha); //vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); } } } } void StaticANIObject::loadMovementsPixelData() { for (uint i = 0; i < _movements.size(); i++) _movements[i]->loadPixelData(); } void StaticANIObject::freeMovementsPixelData() { for (uint i = 0; i < _movements.size(); i++) _movements[i]->freePixelData(); } Statics *StaticANIObject::addReverseStatics(Statics *st) { Statics *res = getStaticsById(st->_staticsId ^ 0x4000); if (!res) { res = new Statics(st, true); _staticsList.push_back(res); } return res; } void StaticANIObject::draw() { if ((_flags & 4) == 0) return; Common::Point point; Common::Rect rect; debug(6, "StaticANIObject::draw() (%s) [%d] [%d, %d]", transCyrillic((byte *)_objectName), _id, _ox, _oy); if (_shadowsOn && g_fp->_currentScene && g_fp->_currentScene->_shadows && (getCurrDimensions(point)->x != 1 || getCurrDimensions(point)->y != 1)) { DynamicPhase *dyn; if (!_movement || _flags & 0x20) dyn = _statics; else dyn = _movement->_currDynamicPhase; if (!dyn) { warning("HACK: StaticANIObject::draw(): dyn is missing"); return; } if (dyn->getDynFlags() & 4) { rect = *dyn->_rect; DynamicPhase *shd = g_fp->_currentScene->_shadows->findSize(rect.width(), rect.height()); if (shd) { shd->getDimensions(&point); int midx = _ox - point.x / 2 - dyn->_someX; int midy = _oy - point.y / 2 - dyn->_someY + rect.bottom - 3; int shdw = point.y; int px; if (!_movement || (_flags & 0x20)) px = _statics->getCenter(&point)->x; else px = _movement->getCenter(&point)->x; if (_shadowsOn != 1) midy = _shadowsOn - shdw / 2; shd->draw(px + midx, midy, 0, 0); } } } int angle = 0; if (_field_30 & 0xC000) { if (_field_30 & 0x8000) angle = -(_field_30 ^ 0x8000); else angle = _field_30 ^ 0x4000; } if (!_movement || (_flags & 0x20)) { _statics->getSomeXY(point); _statics->_x = _ox - point.x; _statics->_y = _oy - point.y; _statics->draw(_statics->_x, _statics->_y, 0, angle); } else { _movement->draw(0, angle); } } void StaticANIObject::draw2() { debug(6, "StatciANIObject::draw2(): id: (%s) %d [%d, %d]", transCyrillic((byte *)_objectName), _id, _ox, _oy); if ((_flags & 4) && (_flags & 0x10)) { if (_movement) { _movement->draw(1, 0); } else { Common::Point point; _statics->getSomeXY(point); _statics->draw(_ox - point.x, _oy - point.y, 1, 0); } } } MovTable *StaticANIObject::countMovements() { GameVar *preloadSubVar = g_fp->getGameLoaderGameVar()->getSubVarByName(getName())->getSubVarByName("PRELOAD"); if (!preloadSubVar || preloadSubVar->getSubVarsCount() == 0) return 0; MovTable *movTable = new MovTable; movTable->count = _movements.size(); movTable->movs = (int16 *)calloc(_movements.size(), sizeof(int16)); for (uint i = 0; i < _movements.size(); i++) { movTable->movs[i] = 2; for (GameVar *sub = preloadSubVar->_subVars; sub; sub = sub->_nextVarObj) { if (scumm_stricmp(_movements[i]->getName(), sub->_varName) == 0) { movTable->movs[i] = 1; break; } } } return movTable; } void StaticANIObject::setSpeed(int speed) { GameVar *var = g_fp->getGameLoaderGameVar()->getSubVarByName(getName())->getSubVarByName("SpeedUp"); if (!var) return; for (var = var->_subVars; var; var = var->_nextVarObj) { Movement *mov = getMovementById(var->_value.intValue); if (mov) { if (speed) { if (mov->_counterMax == 83) mov->_counterMax = 41; } else if (mov->_counterMax == 41) { mov->_counterMax = 83; } } } } void StaticANIObject::setAlpha(int alpha) { for (uint i = 0; i < _movements.size(); i++) _movements[i]->setAlpha(alpha); for (uint i = 0; i < _staticsList.size(); i++) _staticsList[i]->setAlpha(alpha); } void StaticANIObject::initMovements() { for (uint i = 0; i < _movements.size(); i++) _movements[i]->removeFirstPhase(); } void StaticANIObject::preloadMovements(MovTable *mt) { if (mt) { for (uint i = 0; i < _movements.size(); i++) { Movement *mov = _movements[i]; if (mt->movs[i] == 1) mov->loadPixelData(); else if (mt->movs[i] == 2) mov->freePixelData(); } } } Common::Point *StaticANIObject::getCurrDimensions(Common::Point &p) { Picture *pic; if (_movement) pic = _movement->_currDynamicPhase; else pic = _statics; if (pic) { Common::Point point; pic->getDimensions(&point); p.x = point.x; p.y = point.y; } else { p.x = 0; p.y = 0; } return &p; } Common::Point *StaticANIObject::getSomeXY(Common::Point &p) { if (_movement) { _movement->getCurrDynamicPhaseXY(p); return &p; } if (_statics) _statics->getSomeXY(p); return &p; } void StaticANIObject::update(int counterdiff) { int mqid; debug(6, "StaticANIObject::update() (%s) [%d] [%d, %d] fl: %x", transCyrillic((byte *)_objectName), _id, _ox, _oy, _flags); if (_flags & 2) { _messageNum--; if (_messageNum) return; mqid = _messageQueueId; _messageQueueId = 0; _flags ^= 2; updateGlobalMessageQueue(mqid, _id); return; } Common::Point point; ExCommand *ex, *newex; if (_movement) { _movement->_counter += counterdiff; if (_movement->_counter < _movement->_counterMax) return; _movement->_counter = 0; if (_flags & 1) { if (_counter) { _counter--; return; } DynamicPhase *dyn = _movement->_currDynamicPhase; if (dyn->_initialCountdown == dyn->_countdown) { ex = dyn->getExCommand(); if (ex && ex->_messageKind != 35) { newex = ex->createClone(); newex->_excFlags |= 2; if (newex->_messageKind == 17) { newex->_parentId = _id; newex->_keyCode = _okeyCode; } newex->sendMessage(); if (!_movement) return; } } if (dyn->_initialCountdown != dyn->_countdown || dyn->_field_68 == 0) { newex = new ExCommand(_id, 17, dyn->_field_68, 0, 0, 0, 1, 0, 0, 0); newex->_excFlags = 2; newex->_keyCode = _okeyCode; newex->sendMessage(); if (!_movement) return; } if (!_movement->gotoNextFrame(_callback1, _callback2)) { stopAnim_maybe(); } else { setOXY(_movement->_ox, _movement->_oy); _counter = _initialCounter; if (dyn->_initialCountdown == dyn->_countdown) { ex = dyn->getExCommand(); if (ex) { if (ex->_messageKind == 35) { newex = ex->createClone(); newex->_excFlags |= 2; newex->sendMessage(); } } } if (!_movement) return; _stepArray.getCurrPoint(&point); setOXY(point.x + _ox, point.y + _oy); _stepArray.gotoNextPoint(); if (_someDynamicPhaseIndex == _movement->_currDynamicPhaseIndex) adjustSomeXY(); } } else if (_flags & 0x20) { _flags ^= 0x20; _flags |= 1; _movement->gotoFirstFrame(); _movement->getCurrDynamicPhaseXY(point); Common::Point pointS; _statics->getSomeXY(pointS); _movement->setOXY(_ox + point.x + _movement->_mx - pointS.x, _oy + point.y + _movement->_my - pointS.y); } } else { if (_statics) { if (_messageQueueId) { if (_statics->_countdown) { _statics->_countdown--; return; } mqid = _messageQueueId; _messageQueueId = 0; updateGlobalMessageQueue(mqid, _id); } } } } void StaticANIObject::updateStepPos() { Common::Point point; int ox = _movement->_ox; int oy = _movement->_oy; _movement->calcSomeXY(point, 1, _someDynamicPhaseIndex); int x = point.x; int y = point.y; _stepArray.getPoint(&point, -1, _stepArray.getPointsCount()); x += point.x; y += point.y; _statics = _movement->_staticsObj2; _movement = 0; setOXY(ox + x, oy + y); } Common::Point *StaticANIObject::calcNextStep(Common::Point *pRes) { if (!_movement) { pRes->x = 0; pRes->y = 0; return pRes; } Common::Point point; _movement->calcSomeXY(point, 1, _someDynamicPhaseIndex); int resX = point.x; int resY = point.y; int pointN, offset; if (_someDynamicPhaseIndex <= 0) { pointN = _stepArray.getCurrPointIndex(); offset = _stepArray.getPointsCount() - _stepArray.getCurrPointIndex(); } else { pointN = _stepArray.getCurrPointIndex(); offset = 1 - _movement->_currDynamicPhaseIndex + _someDynamicPhaseIndex; } if (pointN >= 0) { _stepArray.getPoint(&point, pointN, offset); resX += point.x; resY += point.y; } pRes->x = resX; pRes->y = resY; return pRes; } void StaticANIObject::stopAnim_maybe() { debug(6, "StaticANIObject::stopAnim_maybe()"); if (!(_flags & 1)) return; _flags ^= 1; int oid = 0; int oldmqid = _messageQueueId; Common::Point point; if (_movement) { setOXY(_movement->_ox, _movement->_oy); if (_flags & 0x40) { if (!_movement->_currMovement && !_movement->_currDynamicPhaseIndex) { _statics = _movement->_staticsObj1; _movement->getCurrDynamicPhaseXY(point); _ox -= point.x; _oy -= point.y; _ox -= _movement->_mx; _oy -= _movement->_my; _statics->getSomeXY(point); if (_movement->_currMovement) { _oy += point.y; _ox -= point.x; _ox += _statics->getDimensions(&point)->x; } else { _ox += point.x; _oy += point.y; } } else { _statics = _movement->_staticsObj2; } } else { _statics = _movement->_staticsObj2; } _statics->getSomeXY(point); _statics->_x = _ox - point.x; _statics->_y = _oy - point.y; oid = _movement->_id; _movement = 0; ExCommand *ex = new ExCommand(_id, 17, 24, 0, 0, 0, 1, 0, 0, 0); ex->_keyCode = _okeyCode; ex->_excFlags = 2; ex->postMessage(); } int mqid = _messageQueueId; if (_animExFlag) { _messageQueueId = 0; startAnimEx(oid, mqid, -1, -1); } else { if (_messageQueueId == oldmqid) { _messageQueueId = 0; if (_field_34 == 1) updateGlobalMessageQueue(mqid, _id); } } } void StaticANIObject::adjustSomeXY() { if (_movement) { Common::Point point; _movement->calcSomeXY(point, 0, -1); int diff = abs(point.y) - abs(point.x); _movement->calcSomeXY(point, 1, -1); if (diff > 0) _ox += point.x; else _oy += point.y; _statics = _movement->_staticsObj2; _movement = 0; _someDynamicPhaseIndex = -1; } } MessageQueue *StaticANIObject::changeStatics1(int msgNum) { g_fp->_mgm->addItem(_id); MessageQueue *mq = g_fp->_mgm->genMQ(this, msgNum, 0, 0, 0); if (!mq) return 0; if (mq->getCount() <= 0) { g_fp->_globalMessageQueueList->addMessageQueue(mq); if (_flags & 1) _messageQueueId = mq->_id; } else { if (!queueMessageQueue(mq)) { delete mq; return 0; } g_fp->_globalMessageQueueList->addMessageQueue(mq); } return mq; } void StaticANIObject::changeStatics2(int objId) { _animExFlag = 0; deleteFromGlobalMessageQueue(); if (_movement || _statics) { g_fp->_mgm->addItem(_id); g_fp->_mgm->updateAnimStatics(this, objId); } else { _statics = getStaticsById(objId); } if (_messageQueueId) { if (g_fp->_globalMessageQueueList->getMessageQueueById(_messageQueueId)) g_fp->_globalMessageQueueList->deleteQueueById(_messageQueueId); _messageQueueId = 0; } } void StaticANIObject::hide() { if (!_messageQueueId) { if (_flags & 4) _flags ^= 4; } } void StaticANIObject::show1(int x, int y, int movId, int mqId) { debug(6, "StaticANIObject::show1(%d, %d, %d, %d)", x, y, movId, mqId); if (_messageQueueId) return; if (movId == -1) { _flags |= 4u; if (x != -1 && y != -1) { setOXY(x, y); } return; } Movement *mov = getMovementById(movId); if (!mov) return; if (x != -1 && y != -1) { setOXY(x, y); } _statics = mov->_staticsObj1; Common::Point point; mov->_staticsObj1->getSomeXY(point); _statics->_x = x - point.x; _statics->_y = y - point.y; _statics->_countdown = _statics->_initialCountdown; _flags |= 4; _ox = x; _oy = y; _movement = 0; if (mov->_currMovement) _flags |= 8; else if (_flags & 8) _flags ^= 8; if (_flags & 1) _flags ^= 1; _messageQueueId = mqId; } void StaticANIObject::show2(int x, int y, int movementId, int mqId) { if (movementId == -1) { _flags |= 4u; return; } if (!_messageQueueId) { _messageQueueId = mqId; Movement *mov = getMovementById(movementId); if (mov) { _statics = mov->_staticsObj1; _movement = mov; mov->gotoLastFrame(); mov->setOXY(x, y); mov->gotoFirstFrame(); Common::Point point; mov->getCurrDynamicPhaseXY(point); _statics->_x = mov->_ox - point.x - mov->_mx; _statics->_y = mov->_oy - point.y - mov->_my; _statics->getSomeXY(point); _flags |= 4; _ox = _statics->_x + point.x; _oy = _statics->_y + point.y; if (mov->_currMovement) { _flags |= 8; } else { if (_flags & 8) _flags ^= 8; } if (_flags & 1) _flags ^= 1; _flags |= 0x20; } } } void StaticANIObject::playIdle() { if (isIdle()) adjustSomeXY(); } void StaticANIObject::startAnimSteps(int movementId, int messageQueueId, int x, int y, Common::Point **points, int pointsCount, int someDynamicPhaseIndex) { Movement *mov = 0; if (!(_flags & 0x80)) { if (!_messageQueueId) for (uint i = 0; i < _movements.size(); i++) { if (_movements[i]->_id == movementId) { mov = _movements[i]; break; } } } if (!mov) { updateGlobalMessageQueue(messageQueueId, _id); return; } if (_movement || !_statics) return; Common::Point point; _statics->getSomeXY(point); int newx = _ox - point.x; int newy = _oy - point.y; _movement = mov; if (_flags & 0x40) _movement->gotoLastFrame(); else _movement->gotoFirstFrame(); _stepArray.clear(); _stepArray.insertPoints(points, pointsCount); if (!(_flags & 0x40)) { if (!_movement->_currDynamicPhaseIndex) { _stepArray.getCurrPoint(&point); newx += point.x + _movement->_mx; newy += point.y + _movement->_my; _stepArray.gotoNextPoint(); ExCommand *ex = _movement->_currDynamicPhase->getExCommand(); if (ex) { if (ex->_messageKind == 35) { ExCommand *newEx = ex->createClone(); newEx->_excFlags |= 2u; newEx->sendMessage(); } } } } _movement->getCurrDynamicPhaseXY(point); setOXY(point.x + newx, point.y + newy); if ((_movement->_staticsObj2->_staticsId >> 8) & 0x40) _flags |= 8; else _flags &= 0xFFF7; _flags |= 1; _messageQueueId = messageQueueId; _movement->_currDynamicPhase->_countdown = _movement->_currDynamicPhase->_initialCountdown; _movement->_counter = 0; _counter = _initialCounter; _someDynamicPhaseIndex = someDynamicPhaseIndex; ExCommand *ex = new ExCommand(_id, 17, 23, 0, 0, movementId, 1, 0, 0, 0); ex->_keyCode = _okeyCode; ex->_excFlags = 2; ex->postMessage(); } bool StaticANIObject::startAnimEx(int movid, int parId, int flag1, int flag2) { bool res = startAnim(movid, parId, -1); if (res) _animExFlag = 1; _someDynamicPhaseIndex = -1; return res; } bool StaticANIObject::startAnim(int movementId, int messageQueueId, int dynPhaseIdx) { if (_flags & 0x80) return false; debug(4, "StaticANIObject::startAnim(%d, %d, %d) (%s [%d]) [%d, %d]", movementId, messageQueueId, dynPhaseIdx, transCyrillic((byte *)_objectName), _id, _ox, _oy); if (_messageQueueId) { updateGlobalMessageQueue(messageQueueId, _id); return false; } Movement *mov = 0; for (uint i = 0; i < _movements.size(); i++) { if (_movements[i]->_id == movementId) { mov = _movements[i]; break; } } if (!mov) { updateGlobalMessageQueue(messageQueueId, _id); return false; } if (mov == _movement) { _flags |= 1; _messageQueueId = messageQueueId; return true; } int newx = _ox; int newy = _oy; Common::Point point; if (_movement) { _movement->getCurrDynamicPhaseXY(point); newx -= point.x; newy -= point.y; } else if (_statics) { _statics->getSomeXY(point); newx -= point.x; newy -= point.y; } _movement = mov; _stepArray.clear(); if (_flags & 0x40) _movement->gotoLastFrame(); else _movement->gotoFirstFrame(); if (!(_flags & 0x40)) { if (!_movement->_currDynamicPhaseIndex) { _stepArray.getCurrPoint(&point); newx += point.x + _movement->_mx; newy += point.y + _movement->_my; _stepArray.gotoNextPoint(); ExCommand *ex = _movement->_currDynamicPhase->getExCommand(); if (ex) { if (ex->_messageKind == 35) { ExCommand *newex = ex->createClone(); newex->_excFlags |= 2; newex->sendMessage(); } } } } _movement->getCurrDynamicPhaseXY(point); setOXY(point.x + newx, point.y + newy); if (_movement->_staticsObj2->_staticsId & 0x4000) _flags |= 8; else _flags &= 0xFFF7; _flags |= 1; _messageQueueId = messageQueueId; _movement->_currDynamicPhase->_countdown = _movement->_currDynamicPhase->_initialCountdown; _movement->_counter = 0; _counter = _initialCounter; _someDynamicPhaseIndex = dynPhaseIdx; _stepArray.clear(); ExCommand *newex = new ExCommand(_id, 17, 23, 0, 0, movementId, 1, 0, 0, 0); newex->_keyCode = _okeyCode; newex->_excFlags = 2; newex->postMessage(); return true; } Common::Point *StaticANIObject::calcStepLen(Common::Point *p) { if (_movement) { Common::Point point; _movement->calcSomeXY(point, 0, _movement->_currDynamicPhaseIndex); p->x = point.x; p->y = point.y; int idx = _stepArray.getCurrPointIndex() - _movement->_currDynamicPhaseIndex - 1; if (idx >= 0) { _stepArray.getPoint(&point, idx, _movement->_currDynamicPhaseIndex + 2); p->x += point.x; p->y += point.y; } } else { p->x = 0; p->y = 0; } return p; } Statics::Statics() { _staticsId = 0; _picture = 0; _staticsName = 0; } Statics::~Statics() { delete _picture; free(_staticsName); } Statics::Statics(Statics *src, bool reverse) : DynamicPhase(src, reverse) { _staticsId = src->_staticsId; if (reverse) { _staticsId ^= 0x4000; int newlen = strlen(src->_staticsName) + strlen(sO_MirroredTo) + 1; _staticsName = (char *)calloc(newlen, 1); snprintf(_staticsName, newlen, "%s%s", sO_MirroredTo, src->_staticsName); } else { _staticsName = (char *)calloc(strlen(src->_staticsName) + 1, 1); strncpy(_staticsName, src->_staticsName, strlen(src->_staticsName) + 1); } _memfilename = (char *)calloc(strlen(src->_memfilename) + 1, 1); strncpy(_memfilename, src->_memfilename, strlen(src->_memfilename) + 1); _picture = new Picture(); } bool Statics::load(MfcArchive &file) { debug(5, "Statics::load()"); DynamicPhase::load(file); _staticsId = file.readUint16LE(); _staticsName = file.readPascalString(); debug(7, "statics: <%s> id: %d (%x)", transCyrillic((byte *)_staticsName), _staticsId, _staticsId); _picture = new Picture(); _picture->load(file); return true; } void Statics::init() { Picture::init(); if (_staticsId & 0x4000) _bitmap->reverseImage(); } Common::Point *Statics::getSomeXY(Common::Point &p) { p.x = _someX; p.y = _someY; return &p; } Common::Point *Statics::getCenter(Common::Point *p) { Common::Rect rect; rect = *_rect; if (_staticsId & 0x4000) { Common::Point point; getDimensions(&point); rect.moveTo(point.x - _rect->right, _rect->top); } p->x = rect.left + _rect->width() / 2; p->y = rect.top + _rect->height() / 2; return p; } Movement::Movement() { _lastFrameSpecialFlag = 0; _flipFlag = 0; _updateFlag1 = 0; _staticsObj1 = 0; _staticsObj2 = 0; _mx = 0; _my = 0; _m2x = 0; _m2y = 0; _field_50 = 1; _field_78 = 0; _framePosOffsets = 0; _field_84 = 0; _currDynamicPhase = 0; _field_8C = 0; _currDynamicPhaseIndex = 0; _field_94 = 0; _currMovement = 0; _counter = 0; _counterMax = 83; _somePoint.x = 0; _somePoint.y = 0; } Movement::~Movement() { for (uint i = 0; i < _dynamicPhases.size(); i++) delete _framePosOffsets[i]; if (!_currMovement ) { if (_updateFlag1) _dynamicPhases.remove_at(0); _dynamicPhases.clear(); } free(_framePosOffsets); } Movement::Movement(Movement *src, StaticANIObject *ani) { _lastFrameSpecialFlag = 0; _flipFlag = src->_flipFlag; _updateFlag1 = src->_updateFlag1; _staticsObj1 = 0; _staticsObj2 = 0; _mx = 0; _my = 0; _m2x = 0; _m2y = 0; _field_78 = 0; _framePosOffsets = 0; _field_84 = 0; _currDynamicPhase = 0; _field_8C = 0; _currDynamicPhaseIndex = src->_currDynamicPhaseIndex; _field_94 = 0; _somePoint.x = 0; _somePoint.y = 0; _currMovement = src; _ox = src->_ox; _oy = src->_oy; initStatics(ani); _counterMax = src->_counterMax; _counter = src->_counter; _field_50 = src->_field_50; updateCurrDynamicPhase(); } Movement::Movement(Movement *src, int *oldIdxs, int newSize, StaticANIObject *ani) : GameObject(src) { _lastFrameSpecialFlag = 0; _updateFlag1 = 1; _staticsObj1 = 0; _staticsObj2 = 0; _mx = 0; _my = 0; _m2x = 0; _m2y = 0; _counter = 0; _counterMax = 0; _field_78 = 0; _framePosOffsets = 0; _field_84 = 0; _currDynamicPhase = 0; _field_8C = 0; _currDynamicPhaseIndex = 0; _field_94 = 0; _somePoint.x = 0; _somePoint.y = 0; _field_50 = src->_field_50; _flipFlag = src->_flipFlag; _currMovement = 0; _mx = src->_mx; _my = src->_my; _m2x = src->_m2x; _m2y = src->_m2y; if (newSize != -1) { if (newSize >= (int)src->_dynamicPhases.size() + 1) newSize = src->_dynamicPhases.size() + 1; } else { newSize = src->_dynamicPhases.size(); } if (!newSize) { warning("Movement::Movement: newSize = 0"); return; } _framePosOffsets = (Common::Point **)calloc(newSize, sizeof(Common::Point *)); for (int i = 0; i < newSize; i++) _framePosOffsets[i] = new Common::Point(); if (oldIdxs) { for (int i = 0; i < newSize - 1; i++, oldIdxs++) { if (oldIdxs[i] == -1) { _dynamicPhases.push_back(src->_staticsObj1); _framePosOffsets[i]->x = 0; _framePosOffsets[i]->y = 0; } else { src->setDynamicPhaseIndex(oldIdxs[i]); _dynamicPhases.push_back(src->_currDynamicPhase); _framePosOffsets[i]->x = src->_framePosOffsets[oldIdxs[i]]->x; _framePosOffsets[i]->y = src->_framePosOffsets[oldIdxs[i]]->y; } } _staticsObj1 = (Statics *)_dynamicPhases.front(); _staticsObj2 = (Statics *)_dynamicPhases.back(); } else { for (int i = 0; i < newSize; i++) { src->setDynamicPhaseIndex(i); if (i < newSize - 1) _dynamicPhases.push_back(new DynamicPhase(src->_currDynamicPhase, 0)); _framePosOffsets[i]->x = src->_framePosOffsets[i]->x; _framePosOffsets[i]->y = src->_framePosOffsets[i]->y; } _staticsObj1 = ani->getStaticsById(src->_staticsObj1->_staticsId); _staticsObj2 = ani->getStaticsById(src->_staticsObj2->_staticsId); _dynamicPhases.push_back(_staticsObj2); this->_updateFlag1 = src->_updateFlag1; } updateCurrDynamicPhase(); removeFirstPhase(); _counterMax = src->_counterMax; _counter = src->_counter; } bool Movement::load(MfcArchive &file) { warning("STUB: Movement::load"); return true; } bool Movement::load(MfcArchive &file, StaticANIObject *ani) { GameObject::load(file); int dynCount = file.readUint16LE(); debug(7, "dynCount: %d _id: %d", dynCount, _id); if (dynCount != 0xffff || _id == MV_MAN_TURN_LU) { _framePosOffsets = (Common::Point **)calloc(dynCount + 2, sizeof(Common::Point *)); for (int i = 0; i < dynCount + 2; i++) _framePosOffsets[i] = new Common::Point(); for (int i = 0; i < dynCount; i++) { DynamicPhase *ph = new DynamicPhase(); ph->load(file); _dynamicPhases.push_back(ph); _framePosOffsets[i]->x = ph->_x; _framePosOffsets[i]->y = ph->_y; } int staticsid = file.readUint16LE(); _staticsObj1 = ani->getStaticsById(staticsid); if (!_staticsObj1 && (staticsid & 0x4000)) { Statics *s = ani->getStaticsById(staticsid ^ 0x4000); _staticsObj1 = ani->addReverseStatics(s); } _mx = file.readUint32LE(); _my = file.readUint32LE(); staticsid = file.readUint16LE(); _staticsObj2 = ani->getStaticsById(staticsid); if (!_staticsObj2 && (staticsid & 0x4000)) { Statics *s = ani->getStaticsById(staticsid ^ 0x4000); _staticsObj2 = ani->addReverseStatics(s); } _m2x = file.readUint32LE(); _m2y = file.readUint32LE(); if (_staticsObj2) { _dynamicPhases.push_back(_staticsObj2); _framePosOffsets[_dynamicPhases.size() - 1]->x = _m2x; _framePosOffsets[_dynamicPhases.size() - 1]->y = _m2y; } } else { int movid = file.readUint16LE(); _currMovement = ani->getMovementById(movid); _staticsObj1 = 0; _staticsObj2 = 0; initStatics(ani); } if (_staticsObj1 && _staticsObj2) { if ((_staticsObj1->_staticsId ^ _staticsObj2->_staticsId) & 0x4000) _flipFlag = 1; } if (g_fp->_gameProjectVersion >= 8) _field_50 = file.readUint32LE(); if (g_fp->_gameProjectVersion < 12) _counterMax = 83; else _counterMax = file.readUint32LE(); _counter = 0; updateCurrDynamicPhase(); return true; } Common::Point *Movement::getCurrDynamicPhaseXY(Common::Point &p) { p.x = _currDynamicPhase->_someX; p.y = _currDynamicPhase->_someY; return &p; } Common::Point *Movement::calcSomeXY(Common::Point &p, int idx, int dynidx) { int oldox = _ox; int oldoy = _oy; int oldidx = _currDynamicPhaseIndex; int x = 0; int y = 0; if (!idx) { Common::Point point; _staticsObj1->getSomeXY(point); int y1 = _my - point.y; int x1 = _mx - point.x; setDynamicPhaseIndex(0); x = _currDynamicPhase->_someX + x1; y = _currDynamicPhase->_someY + y1; } setOXY(x, y); while (_currDynamicPhaseIndex != dynidx && gotoNextFrame(0, 0)) ; p.x = _ox; p.y = _oy; setDynamicPhaseIndex(oldidx); setOXY(oldox, oldoy); return &p; } void Movement::setAlpha(int alpha) { if (_currMovement) for (uint i = 0; i < _currMovement->_dynamicPhases.size(); i++) { _currMovement->_dynamicPhases[i]->setAlpha(alpha); } else for (uint i = 0; i < _dynamicPhases.size(); i++) { _dynamicPhases[i]->setAlpha(alpha); } } Common::Point *Movement::getDimensionsOfPhase(Common::Point *p, int phaseIndex) { int idx = phaseIndex; if (idx == -1) idx = _currDynamicPhaseIndex; DynamicPhase *dyn; if (_currMovement) dyn = _currMovement->_dynamicPhases[idx]; else dyn = _dynamicPhases[idx]; Common::Point point; dyn->getDimensions(&point); *p = point; return p; } void Movement::initStatics(StaticANIObject *ani) { if (!_currMovement) return; debug(7, "Movement::initStatics()"); _staticsObj2 = ani->addReverseStatics(_currMovement->_staticsObj2); _staticsObj1 = ani->addReverseStatics(_currMovement->_staticsObj1); _mx = _currMovement->_mx; _my = _currMovement->_my; _currMovement->setDynamicPhaseIndex(_currMovement->_updateFlag1 != 0 ? 1 : 0); Common::Point point; int x1 = _currMovement->_staticsObj1->getDimensions(&point)->x - _mx; _mx = x1 - _currMovement->_currDynamicPhase->getDimensions(&point)->x; _currMovement->setDynamicPhaseIndex(_currMovement->_currDynamicPhaseIndex); _m2x = _currMovement->_m2x; _m2y = _currMovement->_m2y; _currMovement->gotoLastFrame(); x1 = _currMovement->_staticsObj2->getDimensions(&point)->x; _m2x = _currMovement->_currDynamicPhase->getDimensions(&point)->x - _m2x - x1; } void Movement::updateCurrDynamicPhase() { debug(7, "Movement::updateCurrDynamicPhase()"); if (_currMovement) { if (_currMovement->_dynamicPhases.size() == 0 || (uint)_currDynamicPhaseIndex >= _currMovement->_dynamicPhases.size()) return; if (_currMovement->_dynamicPhases[_currDynamicPhaseIndex]) _currDynamicPhase = _currMovement->_dynamicPhases[_currDynamicPhaseIndex]; } else { if (_dynamicPhases.size() == 0 || (uint)_currDynamicPhaseIndex >= _dynamicPhases.size()) return; if (_dynamicPhases[_currDynamicPhaseIndex]) _currDynamicPhase = _dynamicPhases[_currDynamicPhaseIndex]; } } int Movement::calcDuration() { int res = 0; if (_currMovement) for (uint i = 0; i < _currMovement->_dynamicPhases.size(); i++) { res += _currMovement->_dynamicPhases[i]->_initialCountdown; } else for (uint i = 0; i < _dynamicPhases.size(); i++) { res += _dynamicPhases[i]->_initialCountdown; } return res; } int Movement::countPhasesWithFlag(int maxidx, int flag) { int res = 0; int sz; if (_currMovement) sz = _currMovement->_dynamicPhases.size(); else sz = _dynamicPhases.size(); if (maxidx < 0) maxidx = sz; for (int i = 0; i < maxidx && i < sz; i++) if (getDynamicPhaseByIndex(i)->_dynFlags & flag) res++; return res; } void Movement::setDynamicPhaseIndex(int index) { debug(7, "Movement::setDynamicPhaseIndex(%d)", index); while (_currDynamicPhaseIndex < index) gotoNextFrame(0, 0); while (_currDynamicPhaseIndex > index) gotoPrevFrame(); } DynamicPhase *Movement::getDynamicPhaseByIndex(int idx) { debug(7, "Movement::updateCurrDynamicPhase()"); if (_currMovement) { if (_currMovement->_dynamicPhases.size() == 0 || (uint)idx >= _currMovement->_dynamicPhases.size()) return 0; return _currMovement->_dynamicPhases[idx]; } else { if (_dynamicPhases.size() == 0 || (uint)idx >= _dynamicPhases.size()) return 0; return _dynamicPhases[idx]; } } void Movement::loadPixelData() { Movement *mov = this; for (Movement *i = _currMovement; i; i = i->_currMovement) mov = i; for (uint i = 0; i < _dynamicPhases.size(); i++) { if ((Statics *)_dynamicPhases[i] != mov->_staticsObj2 || !(mov->_staticsObj2->_staticsId & 0x4000)) _dynamicPhases[i]->getPixelData(); } if (!(mov->_staticsObj1->_staticsId & 0x4000)) mov->_staticsObj1->getPixelData(); } void Movement::freePixelData() { if (!_currMovement) for (uint i = 0; i < _dynamicPhases.size(); i++) _dynamicPhases[i]->freePixelData(); if (_staticsObj1) _staticsObj1->freePixelData(); } void Movement::removeFirstPhase() { if (_updateFlag1) { if (!_currDynamicPhaseIndex) gotoNextFrame(0, 0); if (!_currMovement) { _dynamicPhases.remove_at(0); for (uint i = 0; i < _dynamicPhases.size(); i++) { _framePosOffsets[i - 1]->x = _framePosOffsets[i]->x; _framePosOffsets[i - 1]->y = _framePosOffsets[i]->y; } } _currDynamicPhaseIndex--; } updateCurrDynamicPhase(); _updateFlag1 = 0; } bool Movement::gotoNextFrame(void (*callback1)(int, Common::Point *point, int, int), void (*callback2)(int *)) { debug(8, "Movement::gotoNextFrame()"); if (!callback2) { if (_currMovement) { if ((uint)_currDynamicPhaseIndex == _currMovement->_dynamicPhases.size() - 1 && !(_currMovement->_dynamicPhases.back()->_countdown)) { return false; } } else if ((uint)_currDynamicPhaseIndex == _dynamicPhases.size() - 1 && !(_dynamicPhases.back()->_countdown)) { return false; } } if (_currDynamicPhase->_countdown) { _currDynamicPhase->_countdown--; return true; } Common::Point point; getCurrDynamicPhaseXY(point); _ox -= point.x; _oy -= point.y; int deltax = 0; if (_currMovement) deltax = _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; int oldDynIndex = _currDynamicPhaseIndex; if (callback2) callback2(&_currDynamicPhaseIndex); else _currDynamicPhaseIndex++; bool result = true; if (_currMovement) { if (_currMovement->_dynamicPhases.size() <= (uint)_currDynamicPhaseIndex) { _currDynamicPhaseIndex = _currMovement->_dynamicPhases.size() - 1; result = (callback2 == 0); } if (_currDynamicPhaseIndex < 0) { _currDynamicPhaseIndex = 0; result = false; } if (_currMovement->_framePosOffsets) { if (callback1) { point = *_currMovement->_framePosOffsets[_currDynamicPhaseIndex]; callback1(_currDynamicPhaseIndex, &point, _ox, _oy); _ox += deltax - point.x; _oy += point.y; _ox -= _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; } else if (oldDynIndex >= _currDynamicPhaseIndex) { while (oldDynIndex > _currDynamicPhaseIndex) { _ox += deltax; deltax = _currMovement->getDimensionsOfPhase(&point, oldDynIndex)->x; _ox += _currMovement->_framePosOffsets[oldDynIndex]->x; _oy -= _currMovement->_framePosOffsets[oldDynIndex]->y; oldDynIndex--; _ox -= _currMovement->getDimensionsOfPhase(&point, oldDynIndex)->x; } } else { for (int i = oldDynIndex + 1; i <= _currDynamicPhaseIndex; i++) { _ox += deltax; deltax = _currMovement->getDimensionsOfPhase(&point, i)->x; _ox -= _currMovement->_framePosOffsets[i]->x; _oy += _currMovement->_framePosOffsets[i]->y; _ox -= _currMovement->getDimensionsOfPhase(&point, i)->x; } } } } else { if (_dynamicPhases.size() <= (uint)_currDynamicPhaseIndex) { _currDynamicPhaseIndex = _dynamicPhases.size() - 1; result = (callback2 == 0); } if (_currDynamicPhaseIndex < 0) { _currDynamicPhaseIndex = 0; result = false; } if (_framePosOffsets) { if (callback1) { point.x = _framePosOffsets[_currDynamicPhaseIndex]->x; point.y = _framePosOffsets[_currDynamicPhaseIndex]->y; callback1(_currDynamicPhaseIndex, &point, _ox, _oy); _ox += point.x; _oy += point.y; } else if (oldDynIndex >= _currDynamicPhaseIndex) { for (int i = oldDynIndex; i > _currDynamicPhaseIndex; i--) { _ox -= _framePosOffsets[i]->x; _oy -= _framePosOffsets[i]->y; } } else { for (int i = oldDynIndex + 1; i <= _currDynamicPhaseIndex; i++) { _ox += _framePosOffsets[i]->x; _oy += _framePosOffsets[i]->y; } } } } updateCurrDynamicPhase(); getCurrDynamicPhaseXY(point); _ox += point.x; _oy += point.y; _currDynamicPhase->_countdown = _currDynamicPhase->_initialCountdown; return result; } bool Movement::gotoPrevFrame() { debug(8, "Movement::gotoPrevFrame()"); if (!_currDynamicPhaseIndex) { gotoLastFrame(); return false; } Common::Point point; getCurrDynamicPhaseXY(point); _ox -= point.x; _oy -= point.y; if (_currMovement) { if (_currMovement->_framePosOffsets) { _ox += _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; _ox += _currMovement->_framePosOffsets[_currDynamicPhaseIndex]->x; _oy -= _currMovement->_framePosOffsets[_currDynamicPhaseIndex]->y; } _currDynamicPhaseIndex--; if (_currDynamicPhaseIndex < 0) _currDynamicPhaseIndex = _currMovement->_dynamicPhases.size() - 1; _ox -= _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; } else { if (_framePosOffsets) { _ox -= _framePosOffsets[_currDynamicPhaseIndex]->x; _oy -= _framePosOffsets[_currDynamicPhaseIndex]->y; } _currDynamicPhaseIndex--; if (_currDynamicPhaseIndex < 0) _currDynamicPhaseIndex = _dynamicPhases.size() - 1; } updateCurrDynamicPhase(); getCurrDynamicPhaseXY(point); _ox += point.x; _oy += point.y; return true; } void Movement::gotoFirstFrame() { while (_currDynamicPhaseIndex) gotoPrevFrame(); } void Movement::gotoLastFrame() { if (_currMovement) { while ((uint)_currDynamicPhaseIndex != _currMovement->_dynamicPhases.size() - 1) gotoNextFrame(0, 0); } else { while ((uint)_currDynamicPhaseIndex != _dynamicPhases.size() - 1) gotoNextFrame(0, 0); } } Common::Point *Movement::getCenter(Common::Point *p) { Common::Rect rect; rect = *_currDynamicPhase->_rect; if (_currMovement) { Common::Point point; _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex); rect.moveTo(point.x - _currDynamicPhase->_rect->right, _currDynamicPhase->_rect->top); } p->x = rect.left + _currDynamicPhase->_rect->width() / 2; p->y = rect.top + _currDynamicPhase->_rect->height() / 2; return p; } DynamicPhase::DynamicPhase() { _someX = 0; _rect = 0; _field_7C = 0; _field_7E = 0; _dynFlags = 0; _someY = 0; } DynamicPhase::~DynamicPhase() { delete _rect; } DynamicPhase::DynamicPhase(DynamicPhase *src, bool reverse) { _field_7C = src->_field_7C; _field_7E = 0; _rect = new Common::Rect(); debug(1, "DynamicPhase::DynamicPhase(src, %d)", reverse); if (reverse) { if (!src->_bitmap) src->init(); _bitmap = src->_bitmap->reverseImage(); _data = _bitmap->_pixels; _dataSize = src->_dataSize; if (g_fp->_currArchive) { _mfield_14 = 0; _libHandle = g_fp->_currArchive; } _mflags |= 1; _someX = src->_someX; _someY = src->_someY; } else { _mfield_14 = src->_mfield_14; _mfield_8 = src->_mfield_8; _mflags = src->_mflags; _memfilename = (char *)calloc(strlen(src->_memfilename) + 1, 1); strncpy(_memfilename, src->_memfilename, strlen(src->_memfilename) + 1); _dataSize = src->_dataSize; _mfield_10 = src->_mfield_10; _libHandle = src->_libHandle; _bitmap = src->_bitmap; if (_bitmap) { _field_54 = 1; _bitmap = src->_bitmap->reverseImage(false); } _someX = src->_someX; _someY = src->_someY; } *_rect = *src->_rect; _width = src->_width; _height = src->_height; _field_7C = src->_field_7C; if (src->getExCommand()) _exCommand = src->getExCommand()->createClone(); else _exCommand = 0; _initialCountdown = src->_initialCountdown; _field_6A = src->_field_6A; _dynFlags = src->_dynFlags; setPaletteData(src->getPaletteData()); copyMemoryObject2(src); } bool DynamicPhase::load(MfcArchive &file) { debug(5, "DynamicPhase::load()"); StaticPhase::load(file); _field_7C = file.readUint16LE(); _rect = new Common::Rect(); _rect->left = file.readUint32LE(); _rect->top = file.readUint32LE(); _rect->right = file.readUint32LE(); _rect->bottom = file.readUint32LE(); assert (g_fp->_gameProjectVersion >= 1); _someX = file.readUint32LE(); _someY = file.readUint32LE(); assert (g_fp->_gameProjectVersion >= 12); _dynFlags = file.readUint32LE(); return true; } StaticPhase::StaticPhase() { _field_6A = 1; _initialCountdown = 0; _countdown = 0; _field_68 = 0; _exCommand = 0; } StaticPhase::~StaticPhase() { delete _exCommand; } bool StaticPhase::load(MfcArchive &file) { debug(5, "StaticPhase::load()"); Picture::load(file); _initialCountdown = file.readUint16LE(); _field_6A = file.readUint16LE(); if (g_fp->_gameProjectVersion >= 12) { _exCommand = (ExCommand *)file.readClass(); return true; } assert (g_fp->_gameProjectVersion >= 12); warning("StaticPhase::load(): Code continues here"); return true; } } // End of namespace Fullpipe