diff options
Diffstat (limited to 'engines/fullpipe')
88 files changed, 41570 insertions, 0 deletions
diff --git a/engines/fullpipe/behavior.cpp b/engines/fullpipe/behavior.cpp new file mode 100644 index 0000000000..14e9c33bdf --- /dev/null +++ b/engines/fullpipe/behavior.cpp @@ -0,0 +1,359 @@ +/* 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/behavior.h" +#include "fullpipe/statics.h" +#include "fullpipe/messages.h" + +namespace Fullpipe { + +BehaviorManager::BehaviorManager() { + _scene = 0; + _isActive = 1; +} + +BehaviorManager::~BehaviorManager() { + clear(); +} + +void BehaviorManager::clear() { + for (uint i = 0; i < _behaviors.size(); i++) { + for (int j = 0; j < _behaviors[i]->_itemsCount; j++) + delete _behaviors[i]->_bheItems[j]; + + delete _behaviors[i]; + } + _behaviors.clear(); +} + +void BehaviorManager::initBehavior(Scene *sc, GameVar *var) { + clear(); + _scene = sc; + + BehaviorInfo *behinfo; + + GameVar *behvar = var->getSubVarByName("BEHAVIOR"); + if (!behvar) + return; + + for (GameVar *subvar = behvar->_subVars; subvar; subvar = subvar->_nextVarObj) { + if (!strcmp(subvar->_varName, "AMBIENT")) { + behinfo = new BehaviorInfo; + behinfo->initAmbientBehavior(subvar, sc); + + _behaviors.push_back(behinfo); + } else { + StaticANIObject *ani = sc->getStaticANIObject1ByName(subvar->_varName, -1); + if (ani) + for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) + if (((StaticANIObject *)sc->_staticANIObjectList1[i])->_id == ani->_id) { + behinfo = new BehaviorInfo; + behinfo->initObjectBehavior(subvar, sc, ani); + behinfo->_ani = (StaticANIObject *)sc->_staticANIObjectList1[i]; + + _behaviors.push_back(behinfo); + } + } + } +} + +void BehaviorManager::updateBehaviors() { + if (!_isActive) + return; + + debug(4, "BehaviorManager::updateBehaviors()"); + for (uint i = 0; i < _behaviors.size(); i++) { + BehaviorInfo *beh = _behaviors[i]; + + if (!beh->_ani) { + beh->_counter++; + if (beh->_counter >= beh->_counterMax) + updateBehavior(beh, beh->_bheItems[0]); + + continue; + } + + if (beh->_ani->_movement || !(beh->_ani->_flags & 4) || (beh->_ani->_flags & 2)) { + beh->_staticsId = 0; + continue; + } + + if (beh->_ani->_statics->_staticsId == beh->_staticsId) { + beh->_counter++; + if (beh->_counter >= beh->_counterMax) { + if (beh->_subIndex >= 0 && !(beh->_flags & 1) && beh->_ani->_messageQueueId <= 0) + updateStaticAniBehavior(beh->_ani, beh->_counter, beh->_bheItems[beh->_subIndex]); + } + } else { + beh->_staticsId = beh->_ani->_statics->_staticsId; + beh->_counter = 0; + beh->_subIndex = -1; + + for (int j = 0; j < beh->_itemsCount; j++) + if (beh->_bheItems[j]->_staticsId == beh->_staticsId) { + beh->_subIndex = j; + break; + } + + } + } +} + +void BehaviorManager::updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *entry) { + debug(4, "BehaviorManager::updateBehavior() %d", entry->_itemsCount); + for (int i = 0; i < entry->_itemsCount; i++) { + BehaviorEntryInfo *bhi = entry->_items[i]; + if (!(bhi->_flags & 1)) { + if (bhi->_flags & 2) { + MessageQueue *mq = new MessageQueue(bhi->_messageQueue, 0, 1); + + mq->sendNextCommand(); + + bhi->_flags &= 0xFFFFFFFD; + } else if (behaviorInfo->_counter >= bhi->_delay && bhi->_percent && g_fp->_rnd->getRandomNumber(32767) <= entry->_items[i]->_percent) { + MessageQueue *mq = new MessageQueue(bhi->_messageQueue, 0, 1); + + mq->sendNextCommand(); + + behaviorInfo->_counter = 0; + } + } + } +} + +void BehaviorManager::updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorEntry *bhe) { + debug(4, "BehaviorManager::updateStaticAniBehavior(%s)", transCyrillic((byte *)ani->_objectName)); + + MessageQueue *mq = 0; + + if (bhe->_flags & 1) { + uint rnd = g_fp->_rnd->getRandomNumber(32767); + uint runPercent = 0; + for (int i = 0; i < bhe->_itemsCount; i++) { + if (!(bhe->_items[i]->_flags & 1) && bhe->_items[i]->_percent) { + if ((rnd >= runPercent && rnd <= runPercent + bhe->_items[i]->_percent) || i == bhe->_itemsCount - 1) { + mq = new MessageQueue(bhe->_items[i]->_messageQueue, 0, 1); + break; + } + runPercent += bhe->_items[i]->_percent; + } + } + } else { + for (int i = 0; i < bhe->_itemsCount; i++) { + if (!(bhe->_items[i]->_flags & 1) && delay >= bhe->_items[i]->_delay) { + if (bhe->_items[i]->_percent) { + if (g_fp->_rnd->getRandomNumber(32767) <= bhe->_items[i]->_percent) { + mq = new MessageQueue(bhe->_items[i]->_messageQueue, 0, 1); + break; + } + } + } + } + } + + if (mq) { + mq->replaceKeyCode(-1, ani->_okeyCode); + mq->chain(ani); + } +} + +bool BehaviorManager::setBehaviorEnabled(StaticANIObject *obj, int aniId, int quId, int flag) { + BehaviorEntryInfo *entry = getBehaviorEntryInfoByMessageQueueDataId(obj, aniId, quId); + + if (entry) { + if (flag) + entry->_flags &= 0xFFFFFFFE; + else + entry->_flags |= 1; + } else + return false; + + return true; +} + +void BehaviorManager::setFlagByStaticAniObject(StaticANIObject *ani, int flag) { + for (uint i = 0; i < _behaviors.size(); i++) { + BehaviorInfo *beh = _behaviors[i]; + + if (ani == beh->_ani) { + if (flag) + beh->_flags &= 0xfe; + else + beh->_flags |= 1; + } + } +} + +BehaviorEntryInfo *BehaviorManager::getBehaviorEntryInfoByMessageQueueDataId(StaticANIObject *ani, int id1, int id2) { + for (uint i = 0; i < _behaviors.size(); i++) { + if (_behaviors[i]->_ani == ani) { + for (uint j = 0; j < _behaviors[i]->_bheItems.size(); j++) { + if (_behaviors[i]->_bheItems[j]->_staticsId == id1) { + for (int k = 0; k < _behaviors[i]->_bheItems[j]->_itemsCount; k++) { + if (_behaviors[i]->_bheItems[j]->_items[k]->_messageQueue->_dataId == id2) + return _behaviors[i]->_bheItems[j]->_items[k]; + } + } + } + } + } + + return 0; +} + +void BehaviorInfo::clear() { + _ani = 0; + _staticsId = 0; + _counter = 0; + _counterMax = 0; + _flags = 0; + _subIndex = 0; + _itemsCount = 0; + + _bheItems.clear(); +} + +void BehaviorInfo::initAmbientBehavior(GameVar *var, Scene *sc) { + debug(4, "BehaviorInfo::initAmbientBehavior(%s)", transCyrillic((byte *)var->_varName)); + + clear(); + _itemsCount = 1; + _counterMax = -1; + + BehaviorEntry *bi = new BehaviorEntry(); + + _bheItems.push_back(bi); + + bi->_itemsCount = var->getSubVarsCount(); + + bi->_items = (BehaviorEntryInfo**)calloc(bi->_itemsCount, sizeof(BehaviorEntryInfo *)); + + for (int i = 0; i < bi->_itemsCount; i++) { + int delay; + bi->_items[i] = new BehaviorEntryInfo(var->getSubVarByIndex(i), sc, &delay); + + if (bi->_items[i]->_delay <_counterMax) + _counterMax = bi->_items[i]->_delay; + } +} + +void BehaviorInfo::initObjectBehavior(GameVar *var, Scene *sc, StaticANIObject *ani) { + debug(4, "BehaviorInfo::initObjectBehavior(%s)", transCyrillic((byte *)var->_varName)); + + clear(); + + _itemsCount = var->getSubVarsCount(); + _counterMax = -1; + + while (var->_varType == 2) { + if (strcmp(var->_value.stringValue, "ROOT")) + break; + + GameVar *v1 = g_fp->getGameLoaderGameVar()->getSubVarByName("BEHAVIOR")->getSubVarByName(ani->getName()); + if (v1 == var) + return; + + sc = g_fp->accessScene(ani->_sceneId); + clear(); + var = v1; + _itemsCount = var->getSubVarsCount(); + _counterMax = -1; + } + + for (int i = 0; i < _itemsCount; i++) { + int maxDelay = 0; + + _bheItems.push_back(new BehaviorEntry(var->getSubVarByIndex(i), sc, ani, &maxDelay)); + + if (maxDelay < _counterMax) + _counterMax = maxDelay; + } +} + +BehaviorEntry::BehaviorEntry() { + _staticsId = 0; + _itemsCount = 0; + _flags = 0; + _items = 0; +} + +BehaviorEntry::BehaviorEntry(GameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay) { + _staticsId = 0; + _itemsCount = 0; + + *minDelay = 100000000; + + int totalPercent = 0; + _flags = 0; + _items = 0; + + Statics *st = ani->getStaticsByName(var->_varName); + if (st) + _staticsId = st->_staticsId; + + _itemsCount = var->getSubVarsCount(); + if (_itemsCount) { + _items = (BehaviorEntryInfo**)calloc(_itemsCount, sizeof(BehaviorEntryInfo *)); + + for (int i = 0; i < _itemsCount; i++) { + GameVar *subvar = var->getSubVarByIndex(i); + int delay = 0; + + _items[i] = new BehaviorEntryInfo(subvar, sc, &delay); + totalPercent += delay; + + if (_items[i]->_delay < *minDelay) + *minDelay = _items[i]->_delay; + } + + if (!*minDelay && totalPercent == 1000) + _flags |= 1; + } +} + +BehaviorEntryInfo::BehaviorEntryInfo(GameVar *subvar, Scene *sc, int *delay) { + _messageQueue = 0; + _delay = 0; + _percent = 0; + _flags = 0; + _messageQueue = sc->getMessageQueueByName(subvar->_varName); + + GameVar *vart = subvar->getSubVarByName("dwDelay"); + if (vart) + _delay = vart->_value.intValue; + + *delay = 0; + vart = subvar->getSubVarByName("dwPercent"); + if (vart) { + _percent = 0x7FFF * vart->_value.intValue / 1000; + *delay = vart->_value.intValue; + } + + vart = subvar->getSubVarByName("dwFlags"); + if (vart && vart->_varType == 2 && strstr(vart->_value.stringValue, "QDESC_AUTOSTART")) + _flags |= 2; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/behavior.h b/engines/fullpipe/behavior.h new file mode 100644 index 0000000000..1ec98d5bf2 --- /dev/null +++ b/engines/fullpipe/behavior.h @@ -0,0 +1,90 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_BEHAVIOR_H +#define FULLPIPE_BEHAVIOR_H + +namespace Fullpipe { + +struct BehaviorEntryInfo { + MessageQueue *_messageQueue; + int _delay; + uint32 _percent; + int _flags; + + BehaviorEntryInfo(GameVar *subvar, Scene *sc, int *delay); +}; + +struct BehaviorEntry { + int _staticsId; + int _itemsCount; + int _flags; + BehaviorEntryInfo **_items; + + BehaviorEntry(); + BehaviorEntry(GameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay); +}; + +struct BehaviorInfo { + StaticANIObject *_ani; + int _staticsId; + int _counter; + int _counterMax; + int _flags; + int _subIndex; + int _itemsCount; + Common::Array<BehaviorEntry *> _bheItems; + + BehaviorInfo() { clear(); } + + void clear(); + void initAmbientBehavior(GameVar *var, Scene *sc); + void initObjectBehavior(GameVar *var, Scene *sc, StaticANIObject *ani); +}; + +class BehaviorManager : public CObject { + Common::Array<BehaviorInfo *> _behaviors; + Scene *_scene; + bool _isActive; + + public: + BehaviorManager(); + ~BehaviorManager(); + + void clear(); + + void initBehavior(Scene *scene, GameVar *var); + + void updateBehaviors(); + void updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *entry); + void updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorEntry *beh); + + bool setBehaviorEnabled(StaticANIObject *obj, int aniId, int quId, int flag); + + void setFlagByStaticAniObject(StaticANIObject *ani, int flag); + + BehaviorEntryInfo *getBehaviorEntryInfoByMessageQueueDataId(StaticANIObject *ani, int id1, int id2); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_BEHAVIOR_H */ diff --git a/engines/fullpipe/configure.engine b/engines/fullpipe/configure.engine new file mode 100644 index 0000000000..a9042449db --- /dev/null +++ b/engines/fullpipe/configure.engine @@ -0,0 +1,3 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine fullpipe "Full Pipe" no "" "" "16bit" diff --git a/engines/fullpipe/console.cpp b/engines/fullpipe/console.cpp new file mode 100644 index 0000000000..dd3d1bf693 --- /dev/null +++ b/engines/fullpipe/console.cpp @@ -0,0 +1,52 @@ +/* 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/constants.h" +#include "fullpipe/fullpipe.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/scene.h" + +namespace Fullpipe { + +Console::Console(FullpipeEngine *vm) : GUI::Debugger(), _vm(vm) { + registerCmd("scene", WRAP_METHOD(Console, Cmd_Scene)); +} + +bool Console::Cmd_Scene(int argc, const char **argv) { + if (argc != 2) { + int sceneTag = _vm->_currentScene->_sceneId; + debugPrintf("Current scene: %d (scene tag: %d)\n", _vm->getSceneFromTag(sceneTag), sceneTag); + debugPrintf("Use %s <scene> to change the current scene\n", argv[0]); + return true; + } else { + int scene = _vm->convertScene(atoi(argv[1])); + _vm->_gameLoader->loadScene(726); + _vm->_gameLoader->gotoScene(726, TrubaLeft); + + if (scene != 726) + _vm->_gameLoader->preloadScene(726, _vm->getSceneEntrance(scene)); + + return false; + } +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/console.h b/engines/fullpipe/console.h new file mode 100644 index 0000000000..24f213a50f --- /dev/null +++ b/engines/fullpipe/console.h @@ -0,0 +1,42 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_CONSOLE_H +#define FULLPIPE_CONSOLE_H + +namespace Fullpipe { + +class FullpipeEngine; + +class Console : public GUI::Debugger { +public: + Console(FullpipeEngine *vm); + +private: + FullpipeEngine *_vm; + + bool Cmd_Scene(int argc, const char **argv); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_CONSOLE_H */ diff --git a/engines/fullpipe/constants.h b/engines/fullpipe/constants.h new file mode 100644 index 0000000000..b257fca949 --- /dev/null +++ b/engines/fullpipe/constants.h @@ -0,0 +1,1699 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_CONSTANTS_H +#define FULLPIPE_CONSTANTS_H + +namespace Fullpipe { + +// Common +#define ANI_FLY 4916 +#define ANI_INV_MAP 5321 +#define ANI_LIFTBUTTON 2751 +#define ANI_MAN 322 +#define ANI_PBAR 896 +#define MSG_CMN_WINARCADE 4778 +#define MSG_DISABLESAVES 5201 +#define MSG_ENABLESAVES 5202 +#define MSG_HMRKICK_METAL 4764 +#define MSG_HMRKICK_STUCCO 4765 +#define MSG_MANSHADOWSOFF 5196 +#define MSG_MANSHADOWSON 5197 +#define MV_FLY_FLY 4917 +#define MV_LFT_CLOSE 1053 +#define MV_LFT_OPEN 1048 +#define MV_MAN_GOLADDER 451 +#define MV_MAN_GOLADDER2 2844 +#define MV_MAN_HMRKICK 1028 +#define MV_MAN_HMRKICK_COINLESS 1445 +#define MV_MAN_LIFTDOWN 1052 +#define MV_MAN_LIFTUP 1051 +#define MV_MAN_LOOKUP 4773 +#define rMV_MAN_LOOKUP 4775 +#define MV_MAN_TOLADDER 448 +#define MV_MAN_TOLADDER2 2841 +#define MV_MAN_STARTD 478 +#define MV_MAN_STARTLADDER 452 +#define MV_MAN_STARTLADDER2 2842 +#define MV_MAN_STOPLADDER 454 +#define MV_MAN_STOPLADDER2 2845 +#define MV_MAN_TURN_LU 486 +#define MV_PBAR_RUN 897 +#define PIC_CSR_DEFAULT 4891 +#define PIC_CSR_DEFAULT_INV 4892 +#define PIC_CSR_ITN 4893 +#define PIC_CSR_ITN_INV 4894 +#define PIC_CSR_GOFAR_L 4895 +#define PIC_CSR_GOFAR_R 4896 +#define PIC_CSR_ARCADE1 4901 +#define PIC_CSR_ARCADE2 4902 +#define PIC_CSR_ARCADE2_D 4903 +#define PIC_CSR_ARCADE3 4904 +#define PIC_CSR_ARCADE4 4905 +#define PIC_CSR_ARCADE5 4906 +#define PIC_CSR_ARCADE6 4907 +#define PIC_CSR_ARCADE6_D 4908 +#define PIC_CSR_ARCADE7 4909 +#define PIC_CSR_ARCADE7_D 4910 +#define PIC_CSR_ARCADE8 4911 +#define PIC_CSR_DEFAULT 4891 +#define PIC_CSR_DEFAULT_INV 4892 +#define PIC_CSR_GOD 4900 +#define PIC_CSR_GOFAR_L 4895 +#define PIC_CSR_GOFAR_R 4896 +#define PIC_CSR_GOL 4897 +#define PIC_CSR_GOR 4898 +#define PIC_CSR_GOU 4899 +#define PIC_CSR_HELPERBGR 5331 +#define PIC_CSR_ITN 4893 +#define PIC_CSR_ITN_GREEN 5330 +#define PIC_CSR_ITN_INV 4894 +#define PIC_CSR_ITN_RED 5329 +#define PIC_CSR_LIFT 5176 +#define PIC_CSR_MAP 5339 +#define PIC_HLP_BGR 3562 +#define PIC_IN1_GAMETITLE 5169 +#define PIC_IN1_PIPETITLE 5167 +#define PIC_INV_MENU 991 +#define PIC_MAP_A01 5263 +#define PIC_MAP_A02 5264 +#define PIC_MAP_A03 5265 +#define PIC_MAP_A04 5266 +#define PIC_MAP_A05 5267 +#define PIC_MAP_A06 5268 +#define PIC_MAP_A07 5269 +#define PIC_MAP_A08 5270 +#define PIC_MAP_A09 5271 +#define PIC_MAP_A10 5272 +#define PIC_MAP_A11 5273 +#define PIC_MAP_A12 5274 +#define PIC_MAP_A13 5275 +#define PIC_MAP_A14 5276 +#define PIC_MAP_I01 5295 +#define PIC_MAP_I02 5296 +#define PIC_MAP_P01 5277 +#define PIC_MAP_P02 5278 +#define PIC_MAP_P03 5279 +#define PIC_MAP_P04 5280 +#define PIC_MAP_P05 5281 +#define PIC_MAP_P06 5282 +#define PIC_MAP_P07 5283 +#define PIC_MAP_P08 5284 +#define PIC_MAP_P09 5285 +#define PIC_MAP_P10 5286 +#define PIC_MAP_P11 5287 +#define PIC_MAP_P12 5288 +#define PIC_MAP_P13 5289 +#define PIC_MAP_P14 5290 +#define PIC_MAP_P15 5291 +#define PIC_MAP_P16 5292 +#define PIC_MAP_P17 5293 +#define PIC_MAP_P18 5294 +#define PIC_MAP_S01 5223 +#define PIC_MAP_S02 5224 +#define PIC_MAP_S03 5225 +#define PIC_MAP_S04 5226 +#define PIC_MAP_S05 5227 +#define PIC_MAP_S06 5228 +#define PIC_MAP_S07 5229 +#define PIC_MAP_S08 5231 +#define PIC_MAP_S09 5230 +#define PIC_MAP_S10 5232 +#define PIC_MAP_S11 5233 +#define PIC_MAP_S12 5234 +#define PIC_MAP_S13 5235 +#define PIC_MAP_S14 5236 +#define PIC_MAP_S15 5237 +#define PIC_MAP_S16 5238 +#define PIC_MAP_S17 5239 +#define PIC_MAP_S1819 5240 +#define PIC_MAP_S20 5241 +#define PIC_MAP_S21 5242 +#define PIC_MAP_S22 5243 +#define PIC_MAP_S23_1 5244 +#define PIC_MAP_S23_2 5245 +#define PIC_MAP_S24 5246 +#define PIC_MAP_S25 5247 +#define PIC_MAP_S26 5248 +#define PIC_MAP_S27 5249 +#define PIC_MAP_S28 5250 +#define PIC_MAP_S29 5251 +#define PIC_MAP_S30 5252 +#define PIC_MAP_S31_1 5253 +#define PIC_MAP_S31_2 5254 +#define PIC_MAP_S32_1 5255 +#define PIC_MAP_S32_2 5256 +#define PIC_MAP_S33 5257 +#define PIC_MAP_S34 5258 +#define PIC_MAP_S35 5259 +#define PIC_MAP_S36 5260 +#define PIC_MAP_S37 5261 +#define PIC_MAP_S38 5262 +#define PIC_TTL_CREDITS 5172 +#define QU_INTR_STARTINTRO 5133 +#define SC_1 301 +#define SC_2 302 +#define SC_3 303 +#define SC_4 304 +#define SC_5 305 +#define SC_6 649 +#define SC_7 650 +#define SC_8 651 +#define SC_9 652 +#define SC_10 653 +#define SC_11 654 +#define SC_12 655 +#define SC_13 1137 +#define SC_14 1138 +#define SC_15 1139 +#define SC_16 1140 +#define SC_17 1141 +#define SC_18 1142 +#define SC_19 1143 +#define SC_20 1144 +#define SC_21 1546 +#define SC_22 1547 +#define SC_23 1548 +#define SC_24 1549 +#define SC_25 1550 +#define SC_26 1551 +#define SC_27 1552 +#define SC_28 2062 +#define SC_29 2063 +#define SC_30 2064 +#define SC_31 2065 +#define SC_32 2066 +#define SC_33 2067 +#define SC_34 2068 +#define SC_35 2069 +#define SC_36 2070 +#define SC_37 2071 +#define SC_38 2072 +#define SC_COMMON 321 +#define SC_DBGMENU 726 +#define SC_FINAL1 4999 +#define SC_FINAL2 5000 +#define SC_FINAL3 5001 +#define SC_FINAL4 2460 +#define SC_INTRO1 3896 +#define SC_INTRO2 3907 +#define SC_INV 858 +#define SC_LDR 635 +#define SC_MAINMENU 4620 +#define SC_MAP 5222 +#define SC_TITLES 5166 +#define SND_CMN_015 3139 +#define SND_CMN_031 3516 +#define SND_CMN_032 3517 +#define SND_CMN_054 4762 +#define SND_CMN_055 4763 +#define SND_CMN_060 4921 +#define SND_CMN_061 4922 +#define SND_CMN_070 5199 +#define SND_INTR_019 5220 +#define ST_EGTR_SLIMSORROW 340 +#define ST_FLY_FLY 4918 +#define ST_LBN_0H 2835 +#define ST_LBN_1H 2791 +#define ST_LBN_2H 2793 +#define ST_LBN_3H 2795 +#define ST_LBN_4H 2797 +#define ST_LBN_5H 2799 +#define ST_LBN_6H 2801 +#define ST_LBN_7H 2803 +#define ST_LBN_8H 2805 +#define ST_LBN_9H 2807 +#define ST_LBN_0N 2832 +#define ST_LBN_1N 2753 +#define ST_LBN_2N 2756 +#define ST_LBN_3N 2759 +#define ST_LBN_4N 2762 +#define ST_LBN_5N 2765 +#define ST_LBN_6N 2768 +#define ST_LBN_7N 2771 +#define ST_LBN_8N 2774 +#define ST_LBN_9N 2777 +#define ST_LBN_0P 2833 +#define ST_LBN_1P 2754 +#define ST_LBN_2P 2757 +#define ST_LBN_3P 2760 +#define ST_LBN_4P 2763 +#define ST_LBN_5P 2766 +#define ST_LBN_6P 2769 +#define ST_LBN_7P 2772 +#define ST_LBN_8P 2775 +#define ST_LBN_9P 2778 +#define ST_LFT_CLOSED 1049 +#define ST_LFT_OPEN_NEW 1071 +#define ST_MAN_EMPTY 476 +#define ST_MAN_GOU 459 +#define ST_MAN_RIGHT 325 +#define TrubaDown 697 +#define TrubaLeft 474 +#define TrubaUp 680 + +// Main Menu +#define PIC_MNU_AUTHORS_L 4624 +#define PIC_MNU_CONTINUE_L 4626 +#define PIC_MNU_DEBUG_L 4632 +#define PIC_MNU_EXIT_L 4622 +#define PIC_MNU_LOAD_L 4628 +#define PIC_MNU_MUSICSLIDER_D 4914 +#define PIC_MNU_MUSICSLIDER_L 4915 +#define PIC_MNU_RESTART_L 5299 +#define PIC_MNU_SAVE_L 4630 +#define PIC_MNU_SLIDER_D 4913 +#define PIC_MNU_SLIDER_L 4912 + +// Query dialog +#define PIC_MEX_BGR 5300 +#define PIC_MEX_CANCEL 5302 +#define PIC_MEX_OK 5301 +#define PIC_MOV_BGR 5343 +#define PIC_MOV_CANCEL 5345 +#define PIC_MOV_OK 5344 + +// Saveload dialog +#define PIC_MLD_BGR 4645 +#define PIC_MLD_CANCEL_D 4648 +#define PIC_MLD_CANCEL_L 4649 +#define PIC_MLD_OK_D 4646 +#define PIC_MLD_OK_L 4647 +#define PIC_MSV_0_D 4643 +#define PIC_MSV_0_L 4644 +#define PIC_MSV_1_D 4651 +#define PIC_MSV_1_L 4660 +#define PIC_MSV_2_D 4652 +#define PIC_MSV_2_L 4661 +#define PIC_MSV_3_D 4653 +#define PIC_MSV_3_L 4662 +#define PIC_MSV_4_D 4654 +#define PIC_MSV_4_L 4663 +#define PIC_MSV_5_D 4655 +#define PIC_MSV_5_L 4664 +#define PIC_MSV_6_D 4656 +#define PIC_MSV_6_L 4665 +#define PIC_MSV_7_D 4657 +#define PIC_MSV_7_L 4666 +#define PIC_MSV_8_D 4658 +#define PIC_MSV_8_L 4667 +#define PIC_MSV_9_D 4659 +#define PIC_MSV_9_L 4668 +#define PIC_MSV_BGR 4634 +#define PIC_MSV_CANCEL_D 4637 +#define PIC_MSV_CANCEL_L 4638 +#define PIC_MSV_DOTS_D 4670 +#define PIC_MSV_DOTS_L 4669 +#define PIC_MSV_DOT_D 5188 +#define PIC_MSV_DOT_L 5189 +#define PIC_MSV_EMPTY_D 4639 +#define PIC_MSV_EMPTY_L 4640 +#define PIC_MSV_FULL_D 4641 +#define PIC_MSV_FULL_L 4642 +#define PIC_MSV_OK_D 4635 +#define PIC_MSV_OK_L 4636 +#define PIC_MSV_SPACE_D 5190 +#define PIC_MSV_SPACE_L 5191 + +// Intro +#define ANI_IN1MAN 5110 +#define MSG_INTR_ENDINTRO 5139 +#define MSG_INTR_GETUPMAN 5135 +#define MSG_INTR_SWITCHTO1 5145 +#define MSG_INTR_SWITCHTO2 5134 +#define MV_IN1MAN_SLEEP 5111 +#define QU_IN2_DO 5144 +#define QU_INTR_FINISH 5138 +#define QU_INTR_GETUPMAN 5136 +#define ST_IN1MAN_SLEEP 5112 + +// Scene 1 +#define ANI_BOOT_1 4231 +#define MSG_SC1_SHOWOSK 1019 +#define MSG_SC1_SHOWOSK2 468 +#define MSG_SC1_UTRUBACLICK 1100 +#define PIC_SC1_KUCHKA 1321 +#define PIC_SC1_LADDER 1091 +#define PIC_SC1_OSK 1018 +#define PIC_SC1_OSK2 2932 +#define TrubaRight 696 + +// Scene 2 +#define ANI_SC2_BOX 1020 +#define ANI_DADAYASHIK 306 +#define MSG_SC2_HIDELADDER 1023 +#define MSG_SC2_LADDERCLICK 1101 +#define MSG_SC2_PUTMANUP 1026 +#define MSG_SC2_SHOWLADDER 1027 +#define PIC_SC2_DTRUBA 841 +#define PIC_SC2_LADDER 412 +#define ST_DYAS_LIES 318 + +// Scene 3 +#define ANI_DOMINO_3 2732 +#define ANI_EGGEATER 334 +#define ANI_INV_COIN 875 +#define ANI_INV_EGGAPL 1564 +#define ANI_INV_EGGBOOT 1570 +#define ANI_INV_EGGCOIN 1567 +#define ANI_INV_EGGDOM 1561 +#define ANI_INV_EGGGLS 1573 +#define MSG_LIFT_CLICKBUTTON 2780 +#define MSG_LIFT_CLOSEDOOR 5194 +#define MSG_LIFT_EXITLIFT 5187 +#define MSG_LIFT_GO 1065 +#define MSG_LIFT_STARTEXITQUEUE 5186 +#define MSG_SC3_HIDEDOMINO 3177 +#define MSG_SC3_ONTAKECOIN 5338 +#define MSG_SC3_RELEASEEGG 2681 +#define MSG_SC3_TAKEEGG 1583 +#define MSG_SC3_TESTFAT 1582 +#define MSG_SC3_UTRUBACLICK 1103 +#define MV_EGTR_FATASK 5332 +#define PIC_SC3_DOMIN 5182 +#define PIC_SC3_LADDER 1102 +#define ST_EGTR_MID1 2863 +#define ST_EGTR_MID2 2869 +#define ST_EGTR_SLIM 336 +#define QU_EGTR_MD2_SHOW 4698 +#define QU_EGTR_MD1_SHOW 4697 +#define QU_EGTR_SLIMSHOW 4883 +#define QU_SC3_ENTERLIFT 2779 +#define QU_SC3_EXITLIFT 2808 + +// Scene 4 +#define ANI_BIGBALL 4923 +#define ANI_BUTTON 598 +#define ANI_CLOCK 588 +#define ANI_HAND 601 +#define ANI_KOZAWKA 495 +#define ANI_MAMASHA_4 660 +#define ANI_PLANK 501 +#define ANI_SC4_BOOT 1035 +#define ANI_SC4_COIN 690 +#define ANI_SPEAKER_4 3275 +#define ANI_SPRING 542 +#define MSG_GOTOLADDER 618 +#define MSG_KOZAWRESTART 546 +#define MSG_SC4_COINOUT 2895 +#define MSG_SC4_COINPUT 1032 +#define MSG_SC4_CLICKLADDER 1439 +#define MSG_SC4_DROPBOTTLE 2896 +#define MSG_SC4_HANDOVER 2960 +#define MSG_SC4_HIDEBOOT 4563 +#define MSG_SC4_KOZAWFALL 2858 +#define MSG_SC4_MANFROMBOTTLE 2854 +#define MSG_SC4_MANTOBOTTLE 2852 +#define MSG_SHAKEBOTTLE 584 +#define MSG_SHOOTKOZAW 557 +#define MSG_STARTHAND 612 +#define MSG_CLICKBOTTLE 569 +#define MSG_CLICKBUTTON 609 +#define MSG_CLICKPLANK 549 +#define MSG_LOWERPLANK 540 +#define MSG_RAISEPLANK 547 +#define MSG_SHOWCOIN 1033 +#define MSG_TAKEBOTTLE 614 +#define MSG_TAKEKOZAW 611 +#define MSG_TESTPLANK 538 +#define MSG_UPDATEBOTTLE 613 +#define MV_BTN_CLICK 599 +#define MV_CLK_GO 589 +#define MV_HND_POINT 602 +#define MV_KZW_GOR 564 +#define rMV_KZW_GOR 566 +#define MV_KZW_JUMP 558 +#define MV_KZW_JUMPROTATE 561 +#define MV_KZW_TOHOLERV 537 +#define MV_KZW_WALKPLANK 500 +#define MV_KZW_JUMPHIT 2857 +#define MV_KZW_JUMPOUT 586 +#define MV_KZW_RAISEHEAD 577 +#define MV_KZW_STANDUP 563 +#define MV_KZW_TURN 562 +#define MV_MAN_FROMLADDER 493 +#define MV_MAN_GOD 481 +#define MV_MAN_GOU 460 +#define MV_MAN_JUMPONPLANK 551 +#define MV_MAN_LOOKLADDER 520 +#define MV_MAN_PLANKTOLADDER 553 +#define MV_MAN_STARTLADDERD 457 +#define MV_PNK_WEIGHTLEFT 541 +#define MV_PNK_WEIGHTRIGHT 502 +#define MV_SC4_COIN_default 1029 +#define MV_SPK4_PLAY 3276 +#define MV_SPR_LOWER 543 +#define PIC_MAP_P03 5279 +#define PIC_SC4_BOTTLE 568 +#define PIC_SC4_BOTTLE2 2936 +#define PIC_SC4_DOWNTRUBA 619 +#define PIC_SC4_LADDER 1438 +#define PIC_SC4_LRTRUBA 616 +#define PIC_SC4_MASK 585 +#define PIC_SC4_PLANK 5183 +#define QU_BALL_WALKL 4920 +#define QU_BALL_WALKR 4919 +#define QU_HND_TAKE0 1440 +#define QU_HND_TAKE1 1441 +#define QU_HND_TAKE2 1442 +#define QU_HND_TAKEBOTTLE 1443 +#define QU_KOZAW_WALK 505 +#define QU_PNK_CLICK 550 +#define QU_SC4_GOCLOCK 595 +#define QU_SC4_MANFROMBOTTLE 2851 +#define QU_SC4_MANTOBOTTLE 2850 +#define SND_4_010 3125 +#define SND_4_012 3127 +#define SND_4_033 4990 +#define ST_CLK_CLOSED 590 +#define ST_HND_EMPTY 603 +#define ST_KZW_EMPTY 498 +#define ST_KZW_JUMPOUT 587 +#define ST_KZW_RIGHT 559 +#define ST_KZW_SIT 560 +#define ST_MAN_GOLADDER 450 +#define ST_MAN_GOLADDER2 2843 +#define MV_MAN_LOOKLADDERRV 556 +#define ST_MAN_LADDERDOWN 521 +#define ST_MAN_LOOKPLANK 555 +#define ST_MAN_ONPLANK 552 +#define ST_MAN_SIT 1164 +#define ST_MAN_STANDLADDER 453 +#define ST_MAN_UP 449 +#define ST_PNK_WEIGHTLEFT 503 +#define ST_PNK_WEIGHTRIGHT 504 +#define ST_SPR_UP 544 + +// Scene 5 +#define ANI_BIGLUK 909 +#define ANI_HANDLE 622 +#define ANI_OTMOROZ 419 +#define MSG_SC5_BGRSOUNDOFF 5315 +#define MSG_SC5_BGRSOUNDON 5314 +#define MSG_SC5_HANDLEDOWN 916 +#define MSG_SC5_HANDLEUP 915 +#define MSG_SC5_HIDEHANDLE 917 +#define MSG_SC5_MAKEMANFLIGHT 1136 +#define MSG_SC5_MAKEOTMFEEDBACK 1169 +#define MSG_SC5_SHOWHANDLE 918 +#define MSG_SC5_TESTLUK 914 +#define MV_BLK_CLOSE 911 +#define MV_BLK_OPEN 910 +#define MV_MANHDL_HANDLEDOWN 630 +#define MV_MANHDL_HANDLEUP 631 +#define MV_OTM_BOXHANDLEDOWN 626 +#define MV_OTM_BOXHANDLEUP 627 +#define MV_OTM_HANDLEDOWN 620 +#define MV_OTM_HANDLEUP 621 +#define QU_SC5_MANBUMP 1167 +#define QU_SC5_MANFLY 1168 +#define SND_5_026 5316 +#define ST_BLK_CLOSED 912 +#define ST_BLK_OPEN 913 +#define ST_HDL_BROKEN 3342 +#define ST_HDL_DOWN 625 +#define ST_HDL_UP 624 +#define ST_OTM_BOX_LEFT 429 +#define ST_OTM_GLS_LEFT 421 +#define ST_OTM_VNT_LEFT 434 + +// Scene 6 +#define ANI_BALLDROP 2685 +#define ANI_BUTTON_6 2988 +#define ANI_EGGIE 4929 +#define ANI_INV_HANDLE 893 +#define ANI_MAMASHA 656 +#define ANI_NEWBALL 1073 +#define MSG_SC6_BTNPUSH 1017 +#define MSG_SC6_ENABLEDROPS 687 +#define MSG_SC6_INSTHANDLE 1012 +#define MSG_SC6_JUMPBK 2900 +#define MSG_SC6_JUMPFW 2901 +#define MSG_SC6_RESTORESCROLL 2906 +#define MSG_SC6_SHOWNEXTBALL 790 +#define MSG_SC6_STARTDROPS 2897 +#define MSG_SC6_TAKEBALL 682 +#define MSG_SC6_TESTNUMBALLS 2904 +#define MSG_SC6_UTRUBACLICK 1105 +#define MSG_SPINHANDLE 2398 +#define MV_MAN6_TAKEBALL 2691 +#define MV_MAN6_THROWBALL 2692 +#define MV_MOM_CYCLEBK 3012 +#define MV_MOM_JUMPBK 662 +#define MV_MOM_JUMPFW 661 +#define MV_MOM_STARTBK 3010 +#define MV_MOM_STOPBK 3013 +#define MV_MOM_TAKE1 2885 +#define MV_MOM_TAKE2 2886 +#define MV_MOM_TAKE3 2887 +#define MV_MOM_TAKE4 2888 +#define MV_MOM_TAKE5 2889 +#define PIC_SC6_LADDER 1104 +#define QU_EGG6_GOL 4936 +#define QU_EGG6_GOR 4935 +#define QU_MOM_JUMPBK 671 +#define QU_MOM_JUMPFW 670 +#define QU_MOM_PUTBALL 2903 +#define QU_MOM_SITDOWN 685 +#define QU_MOM_STANDUP 2899 +#define QU_MOM_TOLIFT 2902 +#define QU_SC6_DROPS 2898 +#define QU_SC6_DROPS3 2955 +#define QU_SC6_ENTERLIFT 1054 +#define QU_SC6_EXITLIFT 1055 +#define QU_SC6_FALLBALL 2690 +#define QU_SC6_FALLHANDLE 2995 +#define QU_SC6_SHOWHANDLE 1689 +#define QU_SC6_SHOWNEXTBALL 2689 +#define ST_HDL_PLUGGED 2397 +#define ST_MAN6_BALL 2688 +#define ST_MOM_SITS 659 +#define ST_MOM_STANDS 658 +#define ST_NBL_NORM 1076 + +// Scene 7 +#define ANI_CORNERSITTER 71 +#define ANI_HOOLIGAN 808 +#define ANI_LUKE 803 +#define ANI_PLUSMINUS 2938 +#define ANI_SC7_BOX 791 +#define MSG_SC7_CLOSELUKE 822 +#define MSG_SC7_HIDEBOX 817 +#define MSG_SC7_HIDELUKE 821 +#define MSG_SC7_OPENLUKE 823 +#define MSG_SC7_PULL 2943 +#define MSG_SC7_SHOWBOX 816 +#define MV_CST_CLOSELUKE 807 +#define MV_SC7_BOX_default 792 +#define QU_CST_CLOSELUKE 820 +#define ST_CST_HANDLELESS 794 +#define ST_HGN_LOOK 811 +#define ST_HGN_LUKE 810 +#define ST_LUK_CLOSED 805 +#define ST_LUK_OPEN 806 +#define ST_PMS_MINUS 2942 +#define ST_PMS_PLUS 2941 + +// Scene 8 +#define ANI_BATUTA 737 +#define ANI_CLOCK_8 2989 +#define ANI_VMYATS 764 +#define MSG_SC8_ARCADENOW 1044 +#define MSG_SC8_ENTERUP 3037 +#define MSG_SC8_GETHIMUP 789 +#define MSG_SC8_HIDELADDER_D 1107 +#define MSG_SC8_RESUMEFLIGHT 784 +#define MSG_SC8_STANDUP 2976 +#define MSG_STARTARCADE 781 +#define MV_CLK8_GO 2990 +#define MV_MAN_FROMLADDERUP 1522 +#define MV_MAN_TOLADDERD 1524 +#define MV_MAN8_BADLUCK 783 +#define MV_MAN8_DRYGDOWN 770 +#define MV_MAN8_DRYGUP 768 +#define MV_MAN8_HANDSDOWN 772 +#define MV_MAN8_HANDSUP 777 +#define MV_MAN8_JUMP 775 +#define MV_MAN8_JUMPOFF 2969 +#define MV_MAN8_SITDOWN 2968 +#define MV_VMT_DEF 765 +#define PIC_SC8_ARCADENOW 1043 +#define PIC_SC8_LADDER 754 +#define PIC_SC8_LADDER_D 755 +#define PIC_SC8_LADDERD 1106 +#define QU_SC8_FINISH 788 +#define QU_SC8_STANDUP 2975 +#define SND_8_014 3624 +#define ST_BTT_CHESHET 746 +#define ST_BTT_NOSPOON 739 +#define ST_BTT_SLEEPS 748 +#define ST_BTT_SPOON 741 +#define ST_MAN8_FLYDOWN 771 +#define ST_MAN8_FLYUP 769 +#define ST_MAN8_HANDSUP 773 +#define ST_MAN8_STAND 774 +#define ST_VMT_MIN 766 + +// Scene 9 +#define ANI_BALL9 933 +#define ANI_GLOTATEL 924 +#define ANI_GRIT_9 2719 +#define ANI_PLEVATEL 919 +#define ANI_VISUNCHIK 904 +#define MSG_SC9_EATBALL 941 +#define MSG_SC9_FLOWN 943 +#define MSG_SC9_FROMLADDER 4207 +#define MSG_SC9_PLVCLICK 965 +#define MSG_SC9_SETSCROLL 964 +#define MSG_SC9_SHOWBALL 936 +#define MSG_SC9_STARTTIOTIA 4942 +#define MSG_SC9_TOLADDER 4206 +#define MV_BALL9_EXPLODE 939 +#define MV_GLT_FLYAWAY 931 +#define MV_MAN9_SHOOT 922 +#define MV_VSN_CYCLE2 2987 +#define PIC_SC9_LADDER_R 2700 +#define QU_SC9_BALLEXPLODE 938 +#define QU_SC9_EATBALL 942 +#define QU_TTA9_GOL 4937 +#define SND_9_006 3650 +#define SND_9_018 4200 +#define SND_9_019 4201 +#define ST_GLT_SIT 926 +#define ST_GRT9_GRIT 2722 +#define ST_GRT9_NORM 2721 +#define ST_PLV_SIT 921 +#define ST_VSN_NORMAL 906 + +// Scene 10 +#define ANI_GUM 978 +#define ANI_NADUVATEL 944 +#define ANI_PACHKA 975 +#define ANI_PACHKA2 3008 +#define MSG_SC10_CLICKGUM 992 +#define MSG_SC10_HIDEGUM 993 +#define MSG_SC10_LADDERTOBACK 3002 +#define MSG_SC10_LADDERTOFORE 3004 +#define MSG_SC10_SHOWGUM 994 +#define MV_NDV_BLOW2 2855 +#define MV_NDV_DENIES 952 +#define MV_NDV_DENY_NOGUM 3022 +#define PIC_SC10_DTRUBA 974 +#define PIC_SC10_LADDER 995 +#define QU_SC10_ENTERLIFT 1067 +#define QU_SC10_EXITLIFT 2809 +#define QU_SC10_TAKEGUM 3026 +#define ST_NDV_SIT 946 + +// Scene 11 +#define ANI_BOOTS_11 2704 +#define ANI_KACHELI 1094 +#define ANI_MAN11 1108 +#define ANI_SWINGER 1113 +#define MSG_SC11_HITMAN 3019 +#define MSG_SC11_MANCRY 4691 +#define MSG_SC11_MANTOSWING 1128 +#define MSG_SC11_PUTBOOT 1117 +#define MSG_SC11_RESTARTMAN 1133 +#define MSG_SC11_SHOWSWING 1124 +#define MSG_SC11_SITSWINGER 5198 +#define MV_KCH_MOVE2 1099 +#define MV_KCH_START 1121 +#define MV_MAN11_JUMPHIT 1129 +#define MV_MAN11_JUMPFROMSWING 5209 +#define MV_MAN11_JUMPOVER 1131 +#define MV_MAN11_SWING_0 1109 +#define MV_MAN11_SWING_1 1111 +#define MV_MAN11_SWING_2 1112 +#define PIC_SC11_HINT 5170 +#define QU_SC11_MANFALL 3017 +#define QU_SC11_PUTBOOT1 2709 +#define QU_SC11_PUTBOOT2 2710 +#define QU_SC11_RESTARTMAN 1134 +#define QU_SWR_JUMPDOWN 1123 +#define SND_11_020 3704 +#define SND_11_022 3706 +#define SND_11_024 3708 +#define SND_11_031 5171 +#define ST_BTS11_2 2707 +#define ST_BTS11_ONE 2706 +#define ST_KCH_0 1096 +#define ST_KCH_EMPTY 1132 +#define ST_KCH_STATIC 1122 +#define ST_MAN_1PIX 518 +#define ST_MAN11_EMPTY 1110 +#define ST_MAN11_SWING 1127 +#define ST_SWR_SIT 1147 +#define ST_SWR_SITBALD 1153 +#define ST_SWR_STAND3 3014 + +// Scene 13 +#define ANI_BRIDGE 1378 +#define ANI_HANDLE_L 1209 +#define ANI_HANDLE_R 1196 +#define ANI_STOROZH 1172 +#define ANI_WHIRLGIG_13 1383 +#define MSG_SC13_CHEW 1220 +#define MSG_SC13_CLOSEBRIDGE 3046 +#define MSG_SC13_CLOSEFAST 1267 +#define MSG_SC13_EATGUM 1219 +#define MSG_SC13_OPENBRIDGE 3064 +#define MSG_SC13_OPENFAST 1266 +#define MSG_SC13_SHOWGUM 1215 +#define MSG_SC13_STARTWHIRLGIG 1388 +#define MSG_SC13_STOPWHIRLGIG 1387 +#define MSG_SC13_TESTCLOSE 3065 +#define MSG_SC13_TESTOPEN 3048 +#define MSG_SC13_UNEATGUM 1218 +#define MSG_SC13_UPDATEBRIDGE 1217 +#define MV_BDG_CLOSE 1382 +#define MV_BDG_OPEN 1379 +#define MV_WHR13_SPIN 1384 +#define QU_SC13_CLOSEFAIL 3063 +#define QU_SC13_CLOSESUCCESS 3062 +#define QU_SC13_OPENFAIL 3042 +#define QU_SC13_OPENSUCCESS 3047 +#define QU_SC13_SHOWGUM 1216 +#define QU_STR_CHEW 1190 +#define QU_STR_LTOR 3054 +#define QU_STR_PLUU 1189 +#define QU_STR_RTOL 3053 +#define QU_STR_TURNR 1186 +#define QU_STR_TURNR_L 3059 +#define SND_13_018 3763 +#define SND_13_033 4685 +#define SND_13_034 4686 +#define SND_13_037 5335 +#define ST_BDG_CLOSED 1380 +#define ST_BDG_OPEN2 1381 +#define ST_HDLL_FIRECAN 1310 +#define ST_HDLL_HAMMER 3205 +#define ST_HDLL_UP 1211 +#define ST_HDLR_DOWN 1199 +#define ST_HDLR_DOWN_GUM 3044 +#define ST_HDLR_GUM 1201 +#define ST_STR_LEFT 1175 +#define ST_STR_RIGHT 1174 + +// Scene 14 +#define ANI_BALL14 1246 +#define ANI_GRANDMA 1227 +#define MSG_SC14_ENDARCADE 3250 +#define MSG_SC14_GMAJUMP 1250 +#define MSG_SC14_GMATOTRUBA 3249 +#define MSG_SC14_HIDEBALLLAST 3251 +#define MSG_SC14_HIDEPINK 3248 +#define MSG_SC14_MANKICKBALL 1257 +#define MSG_SC14_RESTORESCROLL 4769 +#define MSG_SC14_SCROLLLEFT 4768 +#define MSG_SC14_SHOWBALLFLY 1253 +#define MSG_SC14_SHOWBALLGMADIVE 1260 +#define MSG_SC14_SHOWBALLGMAHIT 1259 +#define MSG_SC14_SHOWBALLGMAHIT2 3245 +#define MSG_SC14_SHOWBALLLAST 3246 +#define MSG_SC14_SHOWBALLMAN 1254 +#define MSG_SC14_STARTARCADE 3252 +#define MV_BAL14_FALL 1258 +#define MV_BAL14_SPIN 1247 +#define MV_BAL14_TOGMA 3214 +#define MV_GMA_BACKOFF 1233 +#define MV_GMA_BACKOFF2 3217 +#define MV_GMA_JUMPFW 1230 +#define MV_GMA_THROW 1232 +#define MV_MAN14_DECLINE 1239 +#define MV_MAN14_FALL 1236 +#define MV_MAN14_KICK 1237 +#define MV_MAN14_KICKAIR 1256 +#define MV_MAN14_STEPFW 1240 +#define PIC_SC14_RTRUBA 1221 +#define ST_GMA_SIT 1229 +#define QU_GMA_BLINK 1252 +#define QU_GMA_JUMPBK 1251 +#define QU_GMA_JUMPFW 1249 +#define QU_GMA_THROW 1255 +#define QU_SC14_ENDARCADE 1391 +#define QU_SC14_ENTERLIFT 1225 +#define QU_SC14_EXITLIFT 1226 +#define QU_SC14_STARTARCADE 1390 +#define QU_SC14_WINARCADE 3247 + +// Scene 15 +#define ANI_BOOT_15 4779 +#define ANI_INV_BOOT 881 +#define ANI_GRANDMA_ASS 1265 +#define MSG_SC15_ASSDRYG 4755 +#define MSG_SC15_LADDERTOBACK 3259 +#define MSG_SC15_PULL 2940 +#define MSG_SC15_STOPCHANTING 4753 +#define MV_SWR_SWING 1114 +#define PIC_SC15_DTRUBA 1263 +#define PIC_SC15_LADDER 3253 +#define PIC_SC15_LTRUBA 1261 +#define QU_SC15_ENTERLIFT 2811 +#define QU_SC15_EXITLIFT 2812 +#define SND_15_001 3798 +#define SND_15_006 3808 +#define SND_15_011 4754 +#define ST_GMS_BOOT 1270 +#define ST_GMS_BOOTLESS2 3316 + +// Scene 16 +#define ANI_BEARDED_CMN 3420 +#define ANI_BOOT_16 3285 +#define ANI_BOY 1327 +#define ANI_GIRL 1328 +#define ANI_JETTIE 1392 +#define ANI_MUG 1296 +#define ANI_WIRE16 1344 +#define MSG_SC16_FILLMUG 1363 +#define MSG_SC16_HIDEMAN 1357 +#define MSG_SC16_HIDEMUG 1351 +#define MSG_SC16_HIDEWIRE 1349 +#define MSG_SC16_LAUGHSOUND 4993 +#define MSG_SC16_MUGCLICK 1366 +#define MSG_SC16_SHOWBEARDED 4956 +#define MSG_SC16_SHOWMAN 1358 +#define MSG_SC16_SHOWMUG 1352 +#define MSG_SC16_SHOWMUGFULL 1396 +#define MSG_SC16_SHOWWIRE 1350 +#define MSG_SC16_STARTLAUGH 1374 +#define MV_BOY_DRINK 1333 +#define MV_BT16_FILL 3286 +#define MV_GRL_DRINK 1339 +#define MV_GRL_FALL 3115 +#define MV_GRL_LAUGH_POPA 3278 +#define MV_JTI_FLOWBY 1393 +#define MV_JTI_FLOWIN 1394 +#define MV_MAN16_TAKEMUG 1362 +#define PIC_SC16_TUMBA 1368 +#define QU_BRD16_STARTBEARDED 4948 +#define QU_SC16_BOYKICK 1367 +#define QU_SC16_BOYOUT 1364 +#define QU_SC16_GIRLLAUGH 1375 +#define QU_SC16_GIRLOUT 1365 +#define QU_SC16_GOBOY 1347 +#define QU_SC16_GOGIRL 1348 +#define QU_SC16_MANDRINK 5200 +#define QU_SC16_SHOWMUG 1361 +#define QU_SC16_TAKEMUG 1435 +#define SND_16_034 3854 +#define SND_16_035 3855 +#define SND_16_037 3857 +#define ST_BOY_STAND 1331 +#define ST_GRL_LAUGH 1342 +#define ST_GRL_STAND 1337 +#define ST_MUG_EMPTY 1298 +#define ST_MUG_FULL 1360 + +// Scene 17 +#define ANI_BOOT_17 4220 +#define ANI_HAND17 1446 +#define ANI_INV_BOTTLE 1418 +#define ANI_INV_SUGAR 1410 +#define ANI_JET_17 2746 +#define ANI_MUG_17 2737 +#define ANI_SAMOGONSHCHIK 1397 +#define MSG_SC17_DROP 3414 +#define MSG_SC17_FILLBOTTLE 1436 +#define MSG_SC17_HIDESUGAR 1417 +#define MSG_SC17_SHOWBOTTLE 1432 +#define MSG_SC17_SHOWSUGAR 1416 +#define MSG_SC17_TESTTRUBA 1458 +#define MSG_SC17_UPDATEHAND 1560 +#define MV_HND17_FIGA 1449 +#define PIC_SC17_RTRUBA 1323 +#define PIC_SC17_RTRUBA2 5297 +#define QU_HND17_ASK 1456 +#define QU_HND17_ATTRACT 1455 +#define QU_HND17_TOCYCLE 1454 +#define QU_JET17_DROP 3295 +#define QU_JET17_FLOW 3294 +#define QU_SC17_FILLBOOT 4237 +#define QU_SC17_FILLBOTTLE 1437 +#define QU_SC17_FILLMUG 2750 +#define QU_SC17_FILLMUG_DROP 3415 +#define QU_SC17_SHOWBOTTLE 1429 +#define QU_SC17_SHOWSUGAR 1415 +#define QU_SMG_FILLBOTTLE 1433 +#define ST_HND17_ATTRACT 1451 +#define ST_HND17_EMPTY 1448 +#define ST_MUG17_EMPTY 2739 +#define ST_SMG_SIT 1399 + +// Scene 18 +#define ANI_BOY18 1477 +#define ANI_DOMINO_18 3174 +#define ANI_GIRL18 1484 +#define ANI_KRESLO 1459 +#define ANI_WHIRLIGIG_18 829 +#define MSG_SC18_CLICKBOARD 3297 +#define MSG_SC18_MANCLIMBEDDOWN 1540 +#define MSG_SC18_MANCLIMBEDUP 1539 +#define MSG_SC18_MANREADY 1507 +#define MSG_SC18_SHOWBOYJUMP 1495 +#define MSG_SC18_SHOWBOYJUMPTO 1497 +#define MSG_SC18_SHOWGIRLJUMP 1496 +#define MSG_SC18_SHOWGIRLJUMPTO 1499 +#define MSG_SC18_SHOWMANJUMP 1510 +#define MSG_SC18_SHOWMANJUMPTO 1508 +#define MV_BOY18_JUMPFROM 1478 +#define MV_BOY18_JUMPTO 1481 +#define MV_GRL18_JUMPFROM 1485 +#define MV_GRL18_JUMPTO 1488 +#define MV_KSL_CALMDOWN 1476 +#define MV_KSL_INBOY 1491 +#define MV_KSL_INGIRL 1493 +#define MV_KSL_INMAN 1504 +#define MV_KSL_JUMPBOY 1473 +#define MV_KSL_JUMPGIRL 1475 +#define MV_KSL_JUMPMAN 1509 +#define MV_KSL_SWING 1460 +#define MV_KSL_SWINGBOY 1462 +#define MV_KSL_SWINGGIRL 1464 +#define MV_KSL_SWINGMAN 1502 +#define MV_MAN18_JUMPTOTRUBA 1511 +#define MV_MAN18_STANDKRESLO 1500 +#define MV_WHR18_SPIN 1300 +#define PIC_SC18_DOMIN 5184 +#define PIC_SC18_LADDER1 1471 +#define PIC_SC18_LADDER2 1472 +#define PIC_SC18_LADDER3 3299 +#define PIC_SC18_RTRUBA 1520 +#define QU_SC19_MANJUMP1 1516 +#define QU_SC19_MANJUMP2 1517 +#define QU_SC19_MANJUMP3 1518 +#define SND_18_006 3906 +#define SND_18_010 4994 +#define ST_KSL_BOY 1463 +#define ST_KSL_GIRL 1465 +#define ST_KSL_JUMPBOY 1492 +#define ST_KSL_JUMPGIRL 1494 +#define ST_KSL_JUMPMAN 1505 +#define ST_KSL_MAN 1503 +#define ST_KSL_REACT 1474 + +// Scene 19 +#define ANI_CORDIE 1529 +#define ANI_WHIRLGIG_19 1302 +#define MSG_SC19_UPDATENUMRIDES 5203 +#define MV_WHR19_SPIN 1317 +#define PIC_SC19_RTRUBA1 1513 +#define PIC_SC19_RTRUBA2 1514 +#define PIC_SC19_RTRUBA3 1515 +#define PIC_SC19_RTRUBA31 5320 +#define SND_19_015 3928 +#define SND_19_016 4995 +#define ST_CDI_EMPTY2 1543 +#define ST_KSL_NORM 1461 + +// Scene 20 +#define ANI_GRANDMA_20 2427 +#define MSG_SC20_UPDATELOCKABLE 5217 +#define ST_GMA20_FLOOR 2429 +#define ST_GMA20_STAND 2436 +#define ST_GMA20_STOOL 2432 + +// Scene 21 +#define ANI_GIRAFFE_BOTTOM 1633 +#define ANI_INV_BOX 890 +#define ANI_INV_STOOL 1780 +#define MSG_SC21_UPDATEASS 4211 +#define PIC_SC21_DTRUBA 1823 +#define ST_GRFB_SIT 1687 +#define ST_GRFB_HANG 1638 + +// Scene 22 +#define ANI_GIRAFFE_MIDDLE 1981 +#define ANI_MESHOK 1754 +#define ANI_TABURETTE 1745 +#define MSG_SC22_CHECKGMABOOT 4782 +#define MSG_SC22_CRANEOUT_GMA 5218 +#define MSG_SC22_FROMSTOOL 1799 +#define MSG_SC22_HANDLEDOWN 1796 +#define MSG_SC22_HIDESTOOL 2503 +#define MSG_SC22_ONSTOOL 1798 +#define MSG_SC22_SHOWSTOOL 2495 +#define QU_MSH_CRANEOUT 1811 +#define QU_MSH_CRANEOUT_GMA 5219 +#define QU_SC22_FALLBROOM 1786 +#define QU_SC22_FALLSACK 1791 +#define QU_SC22_FALLSACK_GMA 2613 +#define QU_SC22_FROMSTOOL 1800 +#define QU_SC22_HANDLEDOWN 1804 +#define QU_SC22_PUTSTOOL 1803 +#define QU_SC22_SHOWSTOOL 1793 +#define QU_SC22_TOSTOOL 1801 +#define QU_SC22_TOSTOOL_R 3332 +#define QU_SC22_TRYBOX 5311 +#define QU_SC22_TRYHANDLE 1802 +#define QU_MSH_MOVE 1812 +#define rMV_MAN_TURN_SRL 1090 +#define ST_GRFM_AFTER 3472 +#define ST_GRFM_NORM 1983 +#define ST_MSH_SIT 1756 + +// Scene 23 +#define ANI_CALENDWHEEL 1702 +#define ANI_GIRAFFE_TOP 1645 +#define ANI_GIRAFFEE 1672 +#define ANI_HANDLE23 1978 +#define ANI_INV_LEVERHANDLE 1777 +#define ANI_LUK23_D 1813 +#define ANI_LUK23_U 1817 +#define MSG_SC23_CLICKBTN1 1736 +#define MSG_SC23_CLICKBTN2 1737 +#define MSG_SC23_CLICKBTN3 1738 +#define MSG_SC23_CLICKBTN4 1739 +#define MSG_SC23_FROMSTOOL 3339 +#define MSG_SC23_HIDEGIRAFFEE 4650 +#define MSG_SC23_ONSTOOL 3334 +#define MSG_SC23_SPINWHEEL1 1740 +#define MSG_SC23_SPINWHEEL2 1741 +#define MSG_SC23_SPINWHEEL3 1742 +#define MSG_SC23_SPINWHEEL4 1743 +#define MV_CND_0_1 1703 +#define MV_CND_1_2 1706 +#define MV_CND_2_3 1708 +#define MV_CND_3_4 1710 +#define MV_CND_4_5 1712 +#define MV_CND_5_6 1714 +#define MV_CND_6_7 1716 +#define MV_CND_7_8 1718 +#define MV_CND_8_9 1720 +#define MV_CND_9_0 1722 +#define MV_MAN23_PUSH1 1724 +#define MV_MAN23_PUSH2 1725 +#define MV_MAN23_PUSH3 1726 +#define MV_MAN23_PUSH4 1727 +#define PIC_SC23_BOXCLOSED 1728 +#define PIC_SC23_BOXOPEN 1723 +#define PIC_SC23_BTN1 1729 +#define PIC_SC23_BTN2 1730 +#define PIC_SC23_BTN3 1731 +#define PIC_SC23_BTN4 1732 +#define PIC_SC23_LADDER 1628 +#define PIC_SC23_LADDERU 3411 +#define QU_GRFU_TURN_UD 1664 +#define QU_GRFU_TURN_UL 1662 +#define QU_SC23_FROMCALENDAR 1734 +#define QU_SC23_FROMCALENDAREXIT 1735 +#define QU_SC23_FROMSTOOL 3338 +#define QU_SC23_SHOWSTOOL 3335 +#define QU_SC23_STARTKISS 1822 +#define QU_SC23_TOCALENDAR 1733 +#define ST_CND_0 1704 +#define ST_CND_1 1705 +#define ST_CND_2 1707 +#define ST_CND_3 1709 +#define ST_CND_4 1711 +#define ST_CND_5 1713 +#define ST_CND_6 1715 +#define ST_CND_7 1717 +#define ST_CND_8 1719 +#define ST_CND_9 1721 +#define ST_GRFG_BALD 1675 +#define ST_GRFG_EMPTY 1674 +#define ST_GRFU_KISS 1681 +#define ST_GRFU_UP 1648 +#define ST_LUK23_OPEN 1816 +#define ST_LUK23_WHANDLE2 1977 +#define ST_LUK23U_CLOSED 1819 +#define ST_LUK23U_OPEN 1820 + +// Scene 24 +#define ANI_DROP_24 3505 +#define ANI_INV_HAMMER 884 +#define ANI_JET24 1837 +#define ANI_WATER24 1834 +#define MV_MAN_TURN_RL 332 +#define MV_WTR24_FLOW 1835 +#define MV_WTR24_FLOWLOWER 1844 +#define MV_JET24_FLOW 1838 +#define QU_DRP24_TOFLOOR 3510 +#define QU_DRP24_TOWATER 3509 +#define QU_DRP24_TOWATER2 4046 +#define SND_24_006 4041 +#define SND_24_007 4042 +#define ST_DRP24_EMPTY 3507 +#define ST_WTR24_FLOWLOWER 1843 + +// Scene 25 +#define ANI_BEARDED_CMN 3420 +#define ANI_BOARD25 1898 +#define ANI_DROP_25 3499 +#define ANI_INV_BOARD 1872 +#define ANI_INV_BROOM 1774 +#define ANI_INV_LOPAT 1920 +#define ANI_INV_SWAB 1917 +#define ANI_WATER25 1856 +#define MSG_BRD_TURN 4877 +#define MSG_SC25_ENTERMAN 1861 +#define MSG_SC25_ENTERTRUBA 4214 +#define MSG_SC25_STARTBEARDEDS 3423 +#define MSG_SC25_STOPBEARDEDS 3424 +#define MSG_SC25_TOLADDER 4215 +#define MV_MAN_GOLADDERDOWN 455 +#define MV_MAN25_CHIH 1886 +#define rMV_MAN25_CHIH 3343 +#define MV_BRD25_RIGHT 1899 +#define rMV_BRD25_RIGHT 1903 +#define MV_MAN25_ONBOARD 1885 +#define rMV_MAN25_ONBOARD 1966 +#define MV_WTR25_FLOW 1857 +#define PIC_SC25_LADDERDOWN 1855 +#define PIC_SC25_LADDERUP 1854 +#define PIC_SC25_RTRUBA 1853 +#define QU_DRP25_TOFLOOR 3502 +#define QU_DRP25_TOWATER 3504 +#define QU_SC25_BACKTOLADDER 1955 +#define QU_SC25_BACKTOTRUBA 2061 +#define QU_SC25_BEARDED 3425 +#define QU_SC25_BEARDED2 3426 +#define QU_SC25_BEARDED3 3427 +#define QU_SC25_BOARDTOLADDER 1911 +#define QU_SC25_ENTERUP_FLOOR 1904 +#define QU_SC25_ENTERUP_WATER 1895 +#define QU_SC25_LADDERUP 1925 +#define QU_SC25_MANTOTRUBA 1905 +#define QU_SC25_MANTOTRUBA_R 4218 +#define QU_SC25_PUTBOARD 1896 +#define QU_SC25_ROWTOLADDER 1910 +#define QU_SC25_ROWTOTRUBA 1897 +#define QU_SC25_TRUBATOBOARD 1909 +#define QU_SC25_TRYBROOM 1912 +#define QU_SC25_TRYHAND 4219 +#define QU_SC25_TRYROWHAND 3493 +#define QU_SC25_TRYROWHAND_R 3494 +#define QU_SC25_TRYSPADE 3498 +#define QU_SC25_TRYSWAB 1913 +#define QU_SC25_TRYWATER 1906 +#define SND_25_006 4059 +#define SND_25_025 4874 +#define SND_25_026 4875 +#define SND_25_027 4876 +#define SND_25_028 5173 +#define SND_25_029 5174 +#define SND_25_030 5175 +#define ST_BRD25_RIGHT2 1902 +#define ST_BRDCMN_EMPTY 3422 +#define ST_DRP25_EMPTY 3501 +#define ST_MAN_GOLADDERD 456 +#define ST_MAN_LADDERDOWN_R 3419 +#define ST_MAN25_ONBOARD 1879 + +// Scene 26 +#define ANI_CHHI 1957 +#define ANI_DROP_26 3345 +#define ANI_INV_SOCK 1698 +#define ANI_INV_VENT 1968 +#define ANI_LUK26 1867 +#define ANI_SOCK_26 4553 +#define ANI_VENT 1927 +#define MSG_SC26_CLICKVENT 1947 +#define MSG_SC26_HIDECHI 1967 +#define MSG_SC26_HIDEVENT 1945 +#define MSG_SC26_SHOWCHI 3495 +#define MSG_SC26_SHOWVENT 1946 +#define MSG_SC26_TESTVENT 1952 +#define MSG_SC26_UPDATEDROP 3496 +#define MSG_SC26_UPDATEPOOL 1956 +#define PIC_SC26_LTRUBA 1864 +#define PIC_SC26_SOCK 5312 +#define QU_CHI_HIDE 1965 +#define QU_CHI_SHOW 1964 +#define QU_SC26_AUTOCLOSE1 1949 +#define QU_SC26_AUTOCLOSE2 1950 +#define QU_SC26_AUTOCLOSE3 1951 +#define QU_SC26_CLOSE1 1936 +#define QU_SC26_CLOSE2 1938 +#define QU_SC26_CLOSE3 1940 +#define QU_SC26_CLOSE4 1942 +#define QU_SC26_CLOSE5 1944 +#define QU_SC26_OPEN1 1935 +#define QU_SC26_OPEN2 1937 +#define QU_SC26_OPEN3 1939 +#define QU_SC26_OPEN4 1941 +#define QU_SC26_OPEN5 1943 +#define SND_26_003 4079 +#define SND_26_018 5340 +#define SND_26_019 5341 +#define SND_26_020 5342 +#define ST_CHI_EMPTY 1959 +#define ST_CHI_NORM 1960 +#define ST_VNT26_RIGHT2 3348 +#define ST_VNT26_UP2 1948 + +// Scene 27 +#define ANI_BITA 2026 +#define ANI_BITAHANDLER 3349 +#define ANI_MAID 2015 +#define ANI_VODILLA 1994 +#define MSG_SC27_CLICKBET 2048 +#define MSG_SC27_HANDLERTOBACK 3372 +#define MSG_SC27_HANDLERTOFRONT 3371 +#define MSG_SC27_SHOWNEXTBET 3369 +#define MSG_SC27_STARTBET 2047 +#define MSG_SC27_STARTWIPE 2057 +#define MSG_SC27_TAKEVENT 4584 +#define MV_BTA_FALL 2049 +#define MV_BTH_1_0 3366 +#define MV_BTH_2_1 3364 +#define MV_BTH_3_2 3362 +#define MV_BTH_4_3 3360 +#define MV_BTH_5_4 3358 +#define MV_MAN27_FLOW 1990 +#define MV_MAN27_THROWBET 1989 +#define PIC_SC27_HITZONE2 4756 +#define QU_DRV_GIVEVENT 2040 +#define QU_DRV_PUSHBUTTON 2056 +#define QU_DRV_PUSHBUTTON_NOVENT 4578 +#define QU_MID_CLEANVENT 4583 +#define QU_MID_SWITCHBACK 2044 +#define QU_SC27_RESTARTBETS 3370 +#define QU_SC27_SHOWBET 3368 +#define SND_27_026 4127 +#define SND_27_027 4128 +#define SND_27_044 4687 +#define ST_BTA_FALL 2054 +#define ST_BTA_HILITE 2052 +#define ST_BTA_NORM 2028 +#define ST_BTH_1 3365 +#define ST_BTH_2 3363 +#define ST_BTH_3 3361 +#define ST_BTH_4 3359 +#define ST_BTH_5 3357 +#define ST_DRV_SITNOVENT 1999 +#define ST_DRV_VENT 1996 +#define ST_MID_BROOM 2022 +#define ST_MID_SPADE 3489 +#define ST_MID_SWAB 2017 +#define ST_MID_SWAB2 2019 + +// Scene 28 +#define ANI_LIFT 982 +#define ANI_LIFT_28 4238 +#define ANI_MAN_28 4247 +#define ANI_TIOTIA 4286 +#define MSG_SC28_CLICKLIFT 4258 +#define MSG_SC28_ENDCABIN 3456 +#define MSG_SC28_ENDLIFT1 4259 +#define MSG_SC28_ENDLIFT6 4244 +#define MSG_SC28_LIFT1_SHOWAFTER 4261 +#define MSG_SC28_LIFT6INSIDE 5354 +#define MSG_SC28_LIFT6MUSIC 5355 +#define MSG_SC28_MAKEFACES 4684 +#define MSG_SC28_STARTWORK1 4255 +#define MSG_SC28_TRYVTORPERS 4961 +#define MSG_SC28_TURNOFF_0 4678 +#define MSG_SC28_TURNOFF_1 4279 +#define MSG_SC28_TURNOFF_2 4277 +#define MSG_SC28_TURNOFF_3 4275 +#define MSG_SC28_TURNOFF_4 4282 +#define MSG_SC28_TURNOFF_6 4273 +#define MSG_SC28_TURNON4 4280 +#define MSG_SC28_TURNON_0 4677 +#define MSG_SC28_TURNON_1 4278 +#define MSG_SC28_TURNON_2 4276 +#define MSG_SC28_TURNON_3 4274 +#define MSG_SC28_TURNON_4 4281 +#define MSG_SC28_TURNON_6 4272 +#define MV_WMN28_IN_1 3443 +#define MV_WMN28_IN_2 3445 +#define MV_WMN28_IN_3 3446 +#define MV_WMN28_IN_4 3447 +#define MV_WMN28_IN_5 3448 +#define PIC_SC28_DARK0 4675 +#define PIC_SC28_DARK1 4266 +#define PIC_SC28_DARK2 4267 +#define PIC_SC28_DARK3 4268 +#define PIC_SC28_DARK4 4269 +#define PIC_SC28_DARK5 4270 +#define PIC_SC28_DARK6 4271 +#define QU_BRD28_GOL 4960 +#define QU_BRD28_GOR 4959 +#define QU_GLV28_GOL 4958 +#define QU_GLV28_GOR 4957 +#define QU_SC28_LIFT0_START 4676 +#define QU_SC28_LIFT1_START 4254 +#define QU_SC28_LIFT1_WORK 4256 +#define QU_SC28_LIFT2_START 4246 +#define QU_SC28_LIFT3_START 4245 +#define QU_SC28_LIFT5_START 4674 +#define QU_SC28_LIFT6_END 3563 +#define QU_SC28_LIFT6_START 4243 +#define QU_SC28_LIFT6_START2 4295 +#define QU_SC28_WMN_START 3452 +#define ST_MAN28_RIGHT 4249 + +// Scene 29 +#define ANI_ASS 2120 +#define ANI_PORTER 2082 +#define ANI_SHELL_GREEN 2116 +#define ANI_SHELL_RED 2130 +#define ANI_SHOOTER1 2108 +#define ANI_SHOOTER2 2111 +#define MSG_SC29_DISABLEPORTER 2097 +#define MSG_SC29_DISABLERIDEBACK 2106 +#define MSG_SC29_ENABLEPORTER 2096 +#define MSG_SC29_ENABLERIDEBACK 2105 +#define MSG_SC29_LAUGH 4760 +#define MSG_SC29_SHOOTGREEN 2119 +#define MSG_SC29_SHOOTRED 2137 +#define MSG_SC29_SHOWLASTGREEN 2730 +#define MSG_SC29_SHOWLASTRED 2731 +#define MSG_SC29_STOPRIDE 2107 +#define MV_ASS_HITGREEN 2138 +#define MV_ASS_HITRED 2139 +#define MV_BRDCMN_GOR 4735 +#define MV_MAN29_BEND 2091 +#define MV_MAN29_HIT 2088 +#define MV_MAN29_JUMP 2090 +#define MV_MAN29_RUN 2095 +#define MV_MAN29_STANDUP 2092 +#define MV_MAN29_STANDUP_NORM 2093 +#define MV_PTR_MOVEFAST 2102 +#define MV_SHG_HITASS 2151 +#define MV_SHG_HITMAN 2147 +#define MV_SHG_NORM 2117 +#define MV_SHR_HITASS 2152 +#define MV_SHR_HITMAN 2149 +#define MV_SHR_NORM 2131 +#define MV_STR1_SHOOT 2109 +#define MV_STR2_SHOOT 2112 +#define PIC_SC29_LTRUBA 2081 +#define QU_SC29_BRD1 4741 +#define QU_SC29_BRD2 4742 +#define QU_SC29_BRDOUT1 4743 +#define QU_SC29_BRDOUT2 4744 +#define QU_SC29_ESCAPE 2129 +#define QU_SC29_MANFROM_L 2101 +#define QU_SC29_MANFROM_R 2104 +#define QU_SC29_MANTO_L 2103 +#define QU_SC29_MANTO_R 2100 +#define SND_29_014 4348 +#define SND_29_027 4757 +#define SND_29_028 4758 +#define SND_29_029 4759 +#define ST_ASS_NORM 2122 +#define ST_BRDCMN_GOR 4734 +#define ST_BRDCMN_RIGHT 4732 +#define ST_MAN29_RUNR 2140 +#define ST_MAN29_SITR 2141 +#define ST_STR1_RIGHT 2143 +#define ST_STR2_RIGHT 2144 +#define ST_STR1_STAND 2110 +#define ST_STR2_STAND 2113 + +// Scene 30 +#define ANI_LEG 2322 +#define MSG_SC30_UPDATEPATH 2358 +#define PIC_SC30_LTRUBA 2354 +#define QU_SC30_ENTERLIFT 2823 +#define QU_SC30_EXITLIFT 2824 +#define ST_LEG_DOWN 2325 +#define ST_LEG_DOWN1 2330 +#define ST_LEG_DOWN2 2334 +#define ST_LEG_EMPTY 2338 +#define ST_LEG_UP 2324 + +// Scene 31 +#define LiftDown 1058 +#define LiftUp 1057 +#define ANI_CACTUS_31 2456 +#define MSG_SC31_PULL 2944 +#define MSG_SC31_TESTCACTUS 5095 +#define SND_31_001 4377 +#define ST_CTS31_GROWN2 2472 + +// Scene 32 +#define ANI_BUTTON_32 5347 +#define ANI_CACTUS 2267 +#define ANI_FLAG 2257 +#define ANI_KADKA 2670 +#define ANI_TESTO_BLUE 2659 +#define ANI_TESTO_GREEN 2662 +#define ANI_TESTO_ORANGE 2656 +#define MSG_SC32_ONLADDER 2270 +#define MSG_SC32_SPIN 2405 +#define MSG_SC32_STARTCACTUS 2414 +#define MSG_SC32_STARTFLAGLEFT 2310 +#define MSG_SC32_STARTFLAGRIGHT 2309 +#define MSG_SC32_STOPFLAG 2311 +#define MSG_SC32_TRUBATOBACK 5181 +#define MSG_SC32_TRUBATOFRONT 5180 +#define MSG_SC32_TRYSIT 2294 +#define MV_CTS_DEFAULT 4299 +#define MV_FLG_CYCLEL 2262 +#define MV_FLG_CYCLER 2266 +#define MV_FLG_STARTL 2258 +#define MV_FLG_STARTR 2263 +#define MV_FLG_STOPL 2261 +#define MV_FLG_STOPR 2265 +#define MV_MAN32_SITDOWN 2276 +#define MV_MAN32_STANDUP 2313 +#define MV_TSTG_FLOW 2663 +#define MV_TSTO_FLOW 2657 +#define PIC_SC32_LADDER 4296 +#define PIC_SC32_RTRUBA 2292 +#define QU_CTS_BACK 2415 +#define QU_CTS_GROW 2416 +#define QU_CTS_GROWMAN 2417 +#define QU_KBK32_GO 4977 +#define QU_KBK32_START 4982 +#define QU_KDK_DRIZZLE 4301 +#define QU_SC32_ENTERLIFT 2827 +#define QU_SC32_EXITLIFT 2828 +#define QU_SC32_FALLHANDLE 5351 +#define QU_SC32_FROMLADDER 4300 +#define QU_SC32_SHOWHANDLE 2399 +#define ST_BTN32_OFF 5349 +#define ST_BTN32_ON 5350 +#define ST_CTS_EMPTY 2269 +#define ST_CTS_GROWUP 2467 +#define ST_FLG_LEFT 2260 +#define ST_FLG_NORM 2259 +#define ST_FLG_RIGHT 2264 +#define ST_HDL_LAID 3039 +#define ST_MAN32_SIT 2277 + +// Scene 33 +#define ANI_KUBIK 4963 +#define ANI_JETTIE_FLOW 2627 +#define ANI_MUG_33 2623 +#define ANI_VENT_33 2637 +#define MSG_SC33_HANDLEDOWN 2643 +#define MSG_SC33_POUR 2645 +#define MSG_SC33_TESTMUG 5185 +#define MSG_SC33_TRYKUBIK 4980 +#define MSG_SC33_UPDATEKUBIK 5346 +#define MV_JTI33_FLOW 2628 +#define MV_JTI33_POUR 2630 +#define MV_JTI33_POURFULL 4455 +#define MV_VNT33_TURND 2638 +#define MV_VNT33_TURNR 2641 +#define PIC_SC33_LTRUBA 2618 +#define PIC_SC33_ZONES 5298 +#define QU_KBK33_GO 4978 +#define QU_KBK33_START 4983 +#define QU_SC33_STARTWATER 2644 +#define ST_MUG33_EMPTY 2625 +#define ST_MUG33_FULL 2626 +#define ST_VNT33_DOWN 2640 +#define ST_VNT33_RIGHT 2639 + +// Scene 34 +#define ANI_BOOT_34 4560 +#define ANI_BOX_34 2498 +#define ANI_CACTUS_34 2381 +#define ANI_LUK_34 2541 +#define ANI_STOOL_34 2486 +#define ANI_VENT_34 2473 +#define MSG_SC34_CLIMB 2490 +#define MSG_SC34_CLIMBBOX 4571 +#define MSG_SC34_FROMCACTUS 4313 +#define MSG_SC34_LEAVEBOARD 2576 +#define MSG_SC34_ONBOARD 2550 +#define MSG_SC34_ONBUMP 5313 +#define MSG_SC34_ONCACTUS 2482 +#define MSG_SC34_RETRYVENT 5210 +#define MSG_SC34_SHOWBOX 2497 +#define MSG_SC34_SHOWVENT 2481 +#define MSG_SC34_TESTVENT 2557 +#define MSG_SC34_UNCLIMB 2492 +#define MV_MAN34_TRY 2485 +#define MV_MAN34_TRYTABUR 2489 +#define MV_MAN34_TURNVENT_L 4307 +#define MV_MAN34_TURNVENT_R 2500 +#define QU_SC34_ENTERLIFT 2819 +#define QU_SC34_EXITLIFT 2820 +#define QU_SC34_FROMBOX 2494 +#define QU_SC34_FROMBOX_FLOOR 4572 +#define QU_SC34_FROMCACTUS 4312 +#define QU_SC34_FROMSTOOL 2491 +#define QU_SC34_LEAVEBOARD 2575 +#define QU_SC34_SHOWSTOOL 2496 +#define QU_CTS34_FALLEFT 4316 +#define QU_CTS34_FALLRIGHT 4317 +#define QU_LUK34_CLOSE 2547 +#define QU_LUK34_OPEN 2546 +#define ST_CTS34_EMPTY 2383 +#define ST_CTS34_GROWNEMPTY2 2475 +#define ST_LUK34_CLOSED 2543 +#define ST_LUK34_OPEN 2544 +#define ST_STL34_BOX2 4305 +#define ST_VNT34_RIGHT3 4318 +#define ST_VNT34_UP2 4310 + +// Scene 35 +#define ANI_HOSE 2424 +#define ANI_PUZODUV 2418 +#define MSG_SC35_CHECKPIPESOUND 4761 +#define MSG_SC35_PLUGHOSE 2524 +#define MSG_SC35_SHRINK 2570 +#define MSG_SC35_STARTFLOW 2523 +#define MSG_SC35_STOPFLOW 4864 +#define MSG_SC35_TRYFLY 4985 +#define QU_PDV_SML_BLINK 2553 +#define QU_PDV_SML_TRY 2554 +#define QU_SC35_EATHOZE 2540 +#define QU_SC35_ENTERLIFT 2815 +#define QU_SC35_EXITLIFT 2816 +#define SND_35_011 4509 +#define SND_35_012 4510 +#define SND_35_026 4863 +#define ST_HZE_NORM 2426 +#define ST_PDV_LARGE 2421 +#define ST_PDV_SMALL 2420 + +// Scene 36 +#define ANI_SCISSORS_36 2647 +#define ANI_ROTOHRUST 2360 +#define PIC_SC36_MASK 5221 +#define ST_RHT_OPEN 2362 + +// Scene 37 +#define ANI_GUARD_37 2588 +#define ANI_RING 2604 +#define MSG_SC37_EXITLEFT 5006 +#define MSG_SC37_PULL 2945 +#define MV_GRD37_PULL 2589 +#define MV_RNG_CLOSE 2605 +#define MV_RNG_OPEN 4612 +#define PIC_SC37_MASK 2608 +#define SND_37_007 4547 +#define ST_GRD37_STAND 2590 +#define ST_RNG_CLOSED2 4865 +#define ST_RNG_OPEN 2606 + +// Scene 38 +#define ANI_BOTTLE38 2188 +#define ANI_DOMINO38 2200 +#define ANI_DOMINOS 3317 +#define ANI_DYLDA 2169 +#define ANI_GLAVAR 2154 +#define ANI_MALYSH 2165 +#define MSG_SC38_DRINK 2225 +#define MSG_SC38_HMRKICK 2224 +#define MSG_SC38_POINT 2226 +#define MSG_SC38_POSTHMRKICK 2256 +#define MSG_SC38_PROPOSE 2287 +#define MSG_SC38_TRYTAKEBOTTLE 3179 +#define MV_DMS_FOUR 3322 +#define MV_DMS_THREE 3321 +#define MV_GLV_LOOKMAN 2167 +#define ST_BTL38_FULL 3172 +#define ST_DMN38_6 2288 +#define ST_DMN38_NORM3 2251 +#define ST_DMN38_NORM4 2253 +#define ST_DMS_3 3319 +#define ST_DMS_4 3320 +#define ST_GLV_HAMMER 2156 +#define ST_GLV_NOHAMMER 2159 +#define ST_GLV_SLEEP2 2166 +#define ST_MLS_LEFT2 2291 +#define ST_MLS_RIGHT2 3323 +#define QU_DLD_BLINK 2216 +#define QU_DLD_DENY 2218 +#define QU_DLD_GLOT 2217 +#define QU_DLD_ICK 2219 +#define QU_DLD_TAKE1 2214 +#define QU_DLD_TAKE2 2215 +#define QU_GLV_DRINK 2210 +#define QU_GLV_DRINKBOTTLE 2286 +#define QU_GLV_DRINK_NOHMR 2211 +#define QU_GLV_HMRKICK 2207 +#define QU_GLV_PROPOSE 2280 +#define QU_GLV_PROPOSE_NOHMR 2281 +#define QU_GLV_TAKEDOMINO 2170 +#define QU_GLV_TAKEDOMINO_NOHMR 3182 +#define QU_GLV_TOSMALL 2208 +#define QU_GLV_TOSMALL_NOHMR 2209 +#define QU_MLS_BLINK 2222 +#define QU_MLS_HAND 2223 +#define QU_MLS_TURNL 2220 +#define QU_MLS_TURNR 2221 +#define QU_SC38_SHOWBOTTLE 2199 +#define QU_SC38_SHOWBOTTLE_ONTABLE 2838 +#define QU_SC38_ENTERLIFT 2836 +#define QU_SC38_EXITLIFT 2837 + +// Final scene +#define ANI_FIN_COIN 5014 +#define MSG_FIN_ENDFINAL 5109 +#define MSG_FIN_GOTO2 5024 +#define MSG_FIN_GOTO3 5071 +#define MSG_FIN_GOTO4 5075 +#define MSG_FIN_STARTFINAL 5025 +#define MSG_FN4_STARTMUSIC 5356 +#define QU_FIN1_FALLCOIN 5018 +#define QU_FIN1_TAKECOIN 5023 +#define QU_FN2_DOFINAL 5066 +#define QU_FN3_DOFINAL 5072 +#define QU_FN4_DOFINAL 5108 +#define ST_FCN_NORM 5017 + +// Debug scene +#define MSG_RESTARTGAME 4767 +#define PIC_SCD_1 727 +#define PIC_SCD_2 728 +#define PIC_SCD_3 729 +#define PIC_SCD_4 730 +#define PIC_SCD_5 731 +#define PIC_SCD_6 732 +#define PIC_SCD_7 733 +#define PIC_SCD_8 756 +#define PIC_SCD_9 907 +#define PIC_SCD_10 981 +#define PIC_SCD_11 1098 +#define PIC_SCD_12 857 +#define PIC_SCD_13 1195 +#define PIC_SCD_14 1224 +#define PIC_SCD_15 1278 +#define PIC_SCD_16 1299 +#define PIC_SCD_17 1305 +#define PIC_SCD_18 1306 +#define PIC_SCD_19 1319 +#define PIC_SCD_20 1622 +#define PIC_SCD_21 1623 +#define PIC_SCD_22 1624 +#define PIC_SCD_23 1625 +#define PIC_SCD_24 1845 +#define PIC_SCD_25 1846 +#define PIC_SCD_26 1847 +#define PIC_SCD_27 1916 +#define PIC_SCD_28 2098 +#define PIC_SCD_29 2099 +#define PIC_SCD_30 2359 +#define PIC_SCD_31 2566 +#define PIC_SCD_32 2312 +#define PIC_SCD_33 2636 +#define PIC_SCD_34 2389 +#define PIC_SCD_35 2412 +#define PIC_SCD_36 2567 +#define PIC_SCD_37 2568 +#define PIC_SCD_38 2228 +#define PIC_SCD_FIN 5026 +#define PIC_SCD_SEL 734 + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_CONSTANTS_H */ diff --git a/engines/fullpipe/detection.cpp b/engines/fullpipe/detection.cpp new file mode 100644 index 0000000000..de0ed04d25 --- /dev/null +++ b/engines/fullpipe/detection.cpp @@ -0,0 +1,170 @@ +/* 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 "base/plugins.h" + +#include "engines/advancedDetector.h" +#include "common/file.h" + +#include "fullpipe/fullpipe.h" +#include "fullpipe/gameloader.h" + + +namespace Fullpipe { + +const char *FullpipeEngine::getGameId() const { + return _gameDescription->gameid; +} + +} + +static const PlainGameDescriptor fullpipeGames[] = { + {"fullpipe", "Full Pipe"}, + {0, 0} +}; + +namespace Fullpipe { + +static const ADGameDescription gameDescriptions[] = { + + // Fullpipe Russian version + { + "fullpipe", + 0, + AD_ENTRY1s("0654.sc2", "099f54f86d33ad2395f3b854b7e05058", 2272), + Common::RU_RUS, + Common::kPlatformWindows, + ADGF_DROPPLATFORM, + GUIO1(GUIO_NONE) + }, + + // Fullpipe German version + { + "fullpipe", + 0, + AD_ENTRY1s("0654.sc2", "d8743351fc53d205f42d91f6d791e51b", 2272), + Common::RU_RUS, + Common::kPlatformWindows, + ADGF_DROPPLATFORM, + GUIO1(GUIO_NONE) + }, + + AD_TABLE_END_MARKER +}; + +} // End of namespace Fullpipe + +class FullpipeMetaEngine : public AdvancedMetaEngine { +public: + FullpipeMetaEngine() : AdvancedMetaEngine(Fullpipe::gameDescriptions, sizeof(ADGameDescription), fullpipeGames) { + _singleid = "fullpipe"; + } + + virtual const char *getName() const { + return "Fullpipe Engine"; + } + + virtual const char *getOriginalCopyright() const { + return "Fullpipe Engine (C) Pipe Studio"; + } + + virtual bool hasFeature(MetaEngineFeature f) const; + virtual int getMaximumSaveSlot() const { return 8; } + virtual SaveStateList listSaves(const char *target) const; + virtual void removeSaveState(const char *target, int slot) const; + virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; +}; + +bool FullpipeMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSavesSupportCreationDate) || + (f == kSupportsLoadingDuringStartup); +} + +SaveStateList FullpipeMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray filenames; + Common::String pattern("fullpipe.s??"); + + filenames = saveFileMan->listSavefiles(pattern); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last 2 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 2); + + if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) { + Common::InSaveFile *in = saveFileMan->openForLoading(*file); + if (in) { + Fullpipe::FullpipeSavegameHeader header; + Fullpipe::readSavegameHeader(in, header); + saveList.push_back(SaveStateDescriptor(slotNum, header.saveName)); + delete header.thumbnail; + delete in; + } + } + } + + return saveList; +} + +void FullpipeMetaEngine::removeSaveState(const char *target, int slot) const { + g_system->getSavefileManager()->removeSavefile(Fullpipe::getSavegameFile(slot)); +} + +SaveStateDescriptor FullpipeMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading( + Fullpipe::getSavegameFile(slot)); + + if (f) { + Fullpipe::FullpipeSavegameHeader header; + Fullpipe::readSavegameHeader(f, header); + delete f; + + // Create the return descriptor + SaveStateDescriptor desc(slot, header.saveName); + desc.setThumbnail(header.thumbnail); + + return desc; + } + + return SaveStateDescriptor(); +} + +bool FullpipeMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) { + *engine = new Fullpipe::FullpipeEngine(syst, desc); + } + return desc != 0; +} + +#if PLUGIN_ENABLED_DYNAMIC(FULLPIPE) + REGISTER_PLUGIN_DYNAMIC(FULLPIPE, PLUGIN_TYPE_ENGINE, FullpipeMetaEngine); +#else + REGISTER_PLUGIN_STATIC(FULLPIPE, PLUGIN_TYPE_ENGINE, FullpipeMetaEngine); +#endif diff --git a/engines/fullpipe/floaters.cpp b/engines/fullpipe/floaters.cpp new file mode 100644 index 0000000000..eb29706f72 --- /dev/null +++ b/engines/fullpipe/floaters.cpp @@ -0,0 +1,255 @@ +/* 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/floaters.h" +#include "fullpipe/utils.h" +#include "fullpipe/objects.h" +#include "fullpipe/motion.h" +#include "fullpipe/statics.h" +#include "fullpipe/scene.h" +#include "fullpipe/constants.h" +#include "fullpipe/objectnames.h" + +namespace Fullpipe { + +Floaters::~Floaters() { + delete _hRgn; +} + +void Floaters::init(GameVar *var) { + _array1.clear(); + _array2.clear(); + + GameVar *varFliers = var->getSubVarByName(sO_Fliers); + + if (!varFliers) + return; + + GameVar *sub = varFliers->getSubVarByName("flyIdleRegion"); + + if (sub) { + _hRgn = new ReactPolygonal(); + + _hRgn->_pointCount = sub->getSubVarsCount(); + _hRgn->_points = (Common::Point **)malloc(sizeof(Common::Point *) * _hRgn->_pointCount); + + sub = sub->_subVars; + + int idx = 0; + + while (sub) { + _hRgn->_points[idx] = new Common::Point; + _hRgn->_points[idx]->x = sub->_subVars->_value.intValue; + _hRgn->_points[idx]->y = sub->_subVars->_nextVarObj->_value.intValue; + + idx++; + sub = sub->_nextVarObj; + } + } + + sub = varFliers->getSubVarByName("flyIdlePath"); + + if (sub) { + _array1.reserve(sub->getSubVarsCount()); + + sub = sub->_subVars; + + int idx = 0; + + while (sub) { + FloaterArray1 *f = new FloaterArray1; + + f->val1 = sub->_subVars->_value.intValue; + f->val2 = sub->_subVars->_nextVarObj->_value.intValue; + + _array1.push_back(f); + + idx++; + sub = sub->_nextVarObj; + } + + } +} + +void Floaters::genFlies(Scene *sc, int x, int y, int priority, int flags) { + StaticANIObject *ani = new StaticANIObject(g_fp->accessScene(SC_COMMON)->getStaticANIObject1ById(ANI_FLY, -1)); + + ani->_statics = ani->getStaticsById(ST_FLY_FLY); + ani->_movement = 0; + ani->setOXY(x, y); + ani->_flags |= 4; + ani->_priority = priority; + + sc->addStaticANIObject(ani, 1); + + ani->startAnim(MV_FLY_FLY, 0, -1); + + int nummoves; + + if (ani->_movement->_currMovement) + nummoves = ani->_movement->_currMovement->_dynamicPhases.size(); + else + nummoves = ani->_movement->_dynamicPhases.size(); + + ani->_movement->setDynamicPhaseIndex(g_fp->_rnd->getRandomNumber(nummoves - 1)); + + FloaterArray2 *arr2 = new FloaterArray2; + + arr2->ani = ani; + arr2->val11 = 15.0; + arr2->val3 = y; + arr2->val5 = y; + arr2->val2 = x; + arr2->val4 = x; + arr2->fflags = flags; + + _array2.push_back(arr2); +} + +void Floaters::update() { + for (uint i = 0; i < _array2.size(); ++i) { + if (_array2[i]->val13 <= 0) { + if (_array2[i]->val4 != _array2[i]->val2 || _array2[i]->val5 != _array2[i]->val3) { + if (_array2[i]->val9 < 2.0) + _array2[i]->val9 = 2.0; + + int dy = _array2[i]->val3 - _array2[i]->val5; + int dx = _array2[i]->val2 - _array2[i]->val4; + double dst = sqrt((double)(dy * dy + dx * dx)); + double at = atan2((double)dx, (double)dy); + int newX = (int)(cos(at) * _array2[i]->val9); + int newY = (int)(sin(at) * _array2[i]->val9); + + if (dst < _array2[i]->val9) { + newX = _array2[i]->val2 - _array2[i]->val4; + newY = _array2[i]->val3 - _array2[i]->val5; + } + if (dst <= 30.0) { + if (dst < 30.0) { + _array2[i]->val9 = _array2[i]->val9 - _array2[i]->val9 * 0.5; + + if (_array2[i]->val9 < 2.0) + _array2[i]->val9 = 2.0; + } + } else { + _array2[i]->val9 = _array2[i]->val9 * 0.5 + _array2[i]->val9; + + if (_array2[i]->val9 > _array2[i]->val11) + _array2[i]->val9 = _array2[i]->val11; + } + + _array2[i]->val4 += newX; + _array2[i]->val5 += newY; + _array2[i]->ani->setOXY(newX + _array2[i]->ani->_ox, newY + _array2[i]->ani->_oy); + + if (_array2[i]->val4 == _array2[i]->val2 && _array2[i]->val5 == _array2[i]->val3) { + _array2[i]->val9 = 0.0; + + _array2[i]->val13 = g_fp->_rnd->getRandomNumber(200) + 20; + + if (_array2[i]->fflags & 1) { + g_fp->_currentScene->deleteStaticANIObject(_array2[i]->ani); + + if (_array2[i]->ani) + delete _array2[i]->ani; + + _array2.remove_at(i); + + i--; + + if (!_array2.size()) + g_fp->stopAllSoundInstances(SND_CMN_060); + + continue; + } + } + } else { + if ((_array2[i]->fflags & 4) && _array2[i]->countdown < 1) { + _array2[i]->fflags |= 1; + _array2[i]->val2 = _array2[i]->val6; + _array2[i]->val3 = _array2[i]->val7; + } else { + if (_array2[i]->fflags & 2) { + int idx1 = g_fp->_rnd->getRandomNumber(_array1.size() - 1); + + _array2[i]->val2 = _array1[idx1]->val1; + _array2[i]->val3 = _array1[idx1]->val2; + } else { + Common::Rect rect; + + if (!_hRgn) + error("Floaters::update(): empty fliers region"); + + _hRgn->getBBox(&rect); + + int x2 = rect.left + g_fp->_rnd->getRandomNumber(rect.right - rect.left); + int y2 = rect.top + g_fp->_rnd->getRandomNumber(rect.bottom - rect.top); + + if (_hRgn->pointInRegion(x2, y2)) { + int dx = _array2[i]->val2 - x2; + int dy = _array2[i]->val3 - y2; + double dst = sqrt((double)(dy * dy + dx * dx)); + + if (dst < 300.0 || !_hRgn->pointInRegion(_array2[i]->val4, _array2[i]->val5)) { + _array2[i]->val2 = x2; + _array2[i]->val3 = y2; + } + } + } + + g_fp->playSound(SND_CMN_061, 0); + + if (_array2[i]->fflags & 4) + _array2[i]->countdown--; + } + } + } else { + _array2[i]->val13--; + } + + if (!_array2[i]->ani->_movement && _array2[i]->ani->_statics->_staticsId == ST_FLY_FLY) { + if (!_array2[i]->val15) { + g_fp->playSound(SND_CMN_060, 1); + + _array2[i]->val15 = 1; + } + + _array2[i]->ani->startAnim(MV_FLY_FLY, 0, -1); + } + } +} + +void Floaters::stopAll() { + for (uint i = 0; i < _array2.size(); i++) { + g_fp->_currentScene->deleteStaticANIObject(_array2[i]->ani); + + delete _array2[i]->ani; + } + + _array2.clear(); + + g_fp->stopAllSoundInstances(SND_CMN_060); +} + + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/floaters.h b/engines/fullpipe/floaters.h new file mode 100644 index 0000000000..bd7b7ffd2c --- /dev/null +++ b/engines/fullpipe/floaters.h @@ -0,0 +1,75 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_FLOATERS_H +#define FULLPIPE_FLOATERS_H + +namespace Fullpipe { + +class StaticANIObject; +class Scene; +class ReactPolygonal; + +struct FloaterArray1 { + int val1; + int val2; + + FloaterArray1() { val1 = 0; val2 = 0; } +}; + +struct FloaterArray2 { + StaticANIObject *ani; + int val2; + int val3; + int val4; + int val5; + int val6; + int val7; + int val8; + double val9; + double val11; + int val13; + int countdown; + int val15; + int fflags; + + FloaterArray2() : ani(0), val2(0), val3(0), val4(0), val5(0), val6(0), val7(0), val8(0), + val9(0.0), val11(0.0), val13(0), countdown(0), val15(0), fflags(0) {} +}; + +class Floaters { +public: + ReactPolygonal *_hRgn; + Common::Array<FloaterArray1 *> _array1; + Common::Array<FloaterArray2 *> _array2; + + Floaters() { _hRgn = 0; } + ~Floaters(); + void init(GameVar *var); + void genFlies(Scene *sc, int x, int y, int priority, int flags); + void update(); + void stopAll(); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_FLOATERS_H */ diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp new file mode 100644 index 0000000000..ebaff32550 --- /dev/null +++ b/engines/fullpipe/fullpipe.cpp @@ -0,0 +1,547 @@ +/* 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 "base/plugins.h" + +#include "common/archive.h" +#include "common/config-manager.h" + +#include "engines/util.h" + +#include "fullpipe/fullpipe.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/messages.h" +#include "fullpipe/behavior.h" +#include "fullpipe/modal.h" +#include "fullpipe/input.h" +#include "fullpipe/motion.h" +#include "fullpipe/statics.h" +#include "fullpipe/scenes.h" +#include "fullpipe/floaters.h" +#include "fullpipe/console.h" +#include "fullpipe/constants.h" + +namespace Fullpipe { + +FullpipeEngine *g_fp = 0; +Vars *g_vars = 0; + +FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { + // Setup mixer + if (!_mixer->isReady()) { + warning("Sound initialization failed."); + } + + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + + _rnd = new Common::RandomSource("fullpipe"); + _console = 0; + + _gameProjectVersion = 0; + _pictureScale = 8; + _scrollSpeed = 0; + _currSoundListCount = 0; + _globalPalette = 0; + + _updateTicks = 0; + _lastInputTicks = 0; + _lastButtonUpTicks = 0; + + _currArchive = 0; + + _soundEnabled = true; + _flgSoundList = true; + + _sfxVolume = 0; + _musicVolume = 0; + + _inputController = 0; + _inputDisabled = false; + + _normalSpeed = true; + + _currentCheat = -1; + _currentCheatPos = 0; + + _modalObject = 0; + _origFormat = 0; + + _liftEnterMQ = 0; + _liftExitMQ = 0; + _lift = 0; + _lastLiftButton = 0; + _liftX = 0; + _liftY = 0; + + _gameContinue = true; + _needRestart = false; + _flgPlayIntro = true; + _gamePaused = false; + _inputArFlag = false; + _recordEvents = false; + _mainMenu_debugEnabled = false; + + _flgGameIsRunning = true; + + _isProcessingMessages = false; + + _musicAllowed = -1; + _musicGameVar = 0; + _musicMinDelay = 0; + _musicMaxDelay = 0; + _musicLocal = 0; + _trackStartDelay = 0; + + memset(_sceneTracks, 0, sizeof(_sceneTracks)); + memset(_trackName, 0, sizeof(_trackName)); + memset(_sceneTracksCurrentTrack, 0, sizeof(_sceneTracksCurrentTrack)); + + _numSceneTracks = 0; + _sceneTrackHasSequence = false; + _sceneTrackIsPlaying = false; + + _aniMan = 0; + _aniMan2 = 0; + _currentScene = 0; + _loaderScene = 0; + _scene2 = 0; + _scene3 = 0; + _movTable = 0; + _floaters = 0; + _mgm = 0; + + _globalMessageQueueList = 0; + _messageHandlers = 0; + + _updateScreenCallback = 0; + _updateCursorCallback = 0; + + _msgX = 0; + _msgY = 0; + _msgObjectId2 = 0; + _msgId = 0; + _mouseVirtX = 0; + _mouseVirtY = 0; + + _currSelectedInventoryItemId = 0; + + _behaviorManager = 0; + + _cursorId = 0; + + _keyState = Common::KEYCODE_INVALID; + _buttonState = 0; + + _gameLoader = 0; + _gameProject = 0; + + _updateFlag = true; + _flgCanOpenMap = true; + + _sceneWidth = 1; + _sceneHeight = 1; + + for (int i = 0; i < 11; i++) + _currSoundList1[i] = 0; + + for (int i = 0; i < 200; i++) + _mapTable[i] = 0; + + _inventoryScene = 0; + _inventory = 0; + + _minCursorId = 0xffff; + _maxCursorId = 0; + _objectAtCursor = 0; + _objectIdAtCursor = 0; + + _arcadeOverlay = 0; + _arcadeOverlayHelper = 0; + _arcadeOverlayX = 0; + _arcadeOverlayY = 0; + _arcadeOverlayMidX = 0; + _arcadeOverlayMidY = 0; + + _isSaveAllowed = true; + + g_fp = this; + g_vars = new Vars; +} + +FullpipeEngine::~FullpipeEngine() { + delete _rnd; + delete _console; + delete _globalMessageQueueList; +} + +void FullpipeEngine::initialize() { + _globalMessageQueueList = new GlobalMessageQueueList; + _behaviorManager = new BehaviorManager; + + _sceneRect.left = 0; + _sceneRect.top = 0; + _sceneRect.right = 799; + _sceneRect.bottom = 599; + + _floaters = new Floaters; + _mgm = new MGM; +} + +void FullpipeEngine::restartGame() { + _floaters->stopAll(); + + clearGlobalMessageQueueList(); + clearMessages(); + + initObjectStates(); + + if (_scene2) { + _scene2->getAniMan(); + _scene2 = 0; + } + + if (_currentScene) { + _gameLoader->unloadScene(_currentScene->_sceneId); + + _currentScene = 0; + } + + _gameLoader->restoreDefPicAniInfos(); + + getGameLoaderInventory()->clear(); + getGameLoaderInventory()->addItem(ANI_INV_MAP, 1); + getGameLoaderInventory()->rebuildItemRects(); + + initMap(); + + if (_flgPlayIntro) { + _gameLoader->loadScene(SC_INTRO1); + _gameLoader->gotoScene(SC_INTRO1, TrubaUp); + } else { + _gameLoader->loadScene(SC_1); + _gameLoader->gotoScene(SC_1, TrubaLeft); + } +} + +Common::Error FullpipeEngine::run() { + const Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0); + // Initialize backend + initGraphics(800, 600, true, &format); + + _backgroundSurface.create(800, 600, format); + + _origFormat = new Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); + + _console = new Console(this); + + initialize(); + + _isSaveAllowed = false; + + int scene = 0; + if (ConfMan.hasKey("boot_param")) + scene = convertScene(ConfMan.getInt("boot_param")); + + if (!loadGam("fullpipe.gam", scene)) + return Common::kNoGameDataFoundError; + +#if 0 + loadAllScenes(); +#endif + + _gameContinue = true; + + while (_gameContinue) { + updateEvents(); + + updateScreen(); + + if (_needRestart) { + if (_modalObject) { + delete _modalObject; + _modalObject = 0; + } + + freeGameLoader(); + _currentScene = 0; + _updateTicks = 0; + + loadGam("fullpipe.gam"); + _needRestart = false; + } + + if (_normalSpeed) + _system->delayMillis(10); + _system->updateScreen(); + } + + freeGameLoader(); + + cleanup(); + + return Common::kNoError; +} + +void FullpipeEngine::updateEvents() { + Common::Event event; + Common::EventManager *eventMan = _system->getEventManager(); + ExCommand *ex; + + while (eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + _keyState = event.kbd.keycode; + + switch (event.kbd.keycode) { + case Common::KEYCODE_SPACE: + if (_gamePaused) { + if (_modalObject) { + if (_modalObject->init(42)) { + _modalObject->update(); + } else { + _modalObject->saveload(); + BaseModalObject *obj = _modalObject->_parentObj; + if (obj) + delete _modalObject; + _modalObject = obj; + } + } else { + _gameLoader->updateSystems(42); + } + return; + } + + ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = 32; + ex->_excFlags |= 3; + ex->handle(); + break; + case Common::KEYCODE_s: + if (_gamePaused) { + _gamePaused = 0; + _flgGameIsRunning = true; + return; + } + + ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = event.kbd.keycode; + ex->_excFlags |= 3; + ex->handle(); + break; + case Common::KEYCODE_q: + return; + break; + default: + if (event.kbd.keycode == Common::KEYCODE_d && event.kbd.hasFlags(Common::KBD_CTRL)) { + // Start the debugger + getDebugger()->attach(); + getDebugger()->onFrame(); + } + ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = event.kbd.keycode; + ex->_excFlags |= 3; + ex->handle(); + break; + } + break; + case Common::EVENT_KEYUP: + if (!_inputArFlag) { + ex = new ExCommand(0, 17, 37, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->handle(); + } + _keyState = Common::KEYCODE_INVALID; + break; + case Common::EVENT_MOUSEMOVE: + if (_recordEvents) { + ex = new ExCommand(0, 17, 31, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->handle(); + } + + _mouseScreenPos = event.mouse; + break; + case Common::EVENT_QUIT: + _gameContinue = false; + break; + case Common::EVENT_RBUTTONDOWN: + if (!_inputArFlag && (_updateTicks - _lastInputTicks) >= 2) { + ex = new ExCommand(0, 17, 107, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + _lastInputTicks = _updateTicks; + ex->handle(); + } + break; + case Common::EVENT_LBUTTONDOWN: + if (!_inputArFlag && (_updateTicks - _lastInputTicks) >= 2) { + ex = new ExCommand(0, 17, 29, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0); + + ex->_sceneClickX = _sceneRect.left + ex->_x; + ex->_sceneClickY = _sceneRect.top + ex->_y; + ex->_keyCode = getGameLoaderInventory()->getSelectedItemId(); + ex->_excFlags |= 3; + _lastInputTicks = _updateTicks; + ex->handle(); + } + break; + case Common::EVENT_LBUTTONUP: + if (!_inputArFlag && (_updateTicks - _lastButtonUpTicks) >= 2) { + ex = new ExCommand(0, 17, 30, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + _lastButtonUpTicks = _updateTicks; + ex->handle(); + } + break; + default: + break; + } + } + + // pollEvent() is implemented only for video player. So skip it. + //if (event.kbd.keycode == MSG_SC11_SHOWSWING && _modalObject) { + // _modalObject->pollEvent(); + //} +} + +void FullpipeEngine::freeGameLoader() { + setCursor(0); + delete _movTable; + _floaters->stopAll(); + delete _gameLoader; + _currentScene = 0; + _scene2 = 0; + _loaderScene = 0; +} + +void FullpipeEngine::cleanup() { + //cleanRecorder(); + clearMessageHandlers(); + clearMessages(); + _globalMessageQueueList->compact(); + + for (uint i = 0; i < _globalMessageQueueList->size(); i++) + delete (*_globalMessageQueueList)[i]; + + stopAllSoundStreams(); + + delete _origFormat; +} + +void FullpipeEngine::updateScreen() { + debug(4, "FullpipeEngine::updateScreen()"); + + _mouseVirtX = _mouseScreenPos.x + _sceneRect.left; + _mouseVirtY = _mouseScreenPos.y + _sceneRect.top; + + //if (inputArFlag) + // updateGame_inputArFlag(); + + if (_modalObject || (_flgGameIsRunning && (_gameLoader->updateSystems(42), _modalObject != 0))) { + if (_flgGameIsRunning) { + if (_modalObject->init(42)) { + _modalObject->update(); + } else { + _modalObject->saveload(); + BaseModalObject *tmp = _modalObject->_parentObj; + + delete _modalObject; + + _modalObject = tmp; + } + } + } else if (_currentScene) { + _currentScene->draw(); + + if (_inventoryScene) + _inventory->draw(); + + if (_updateScreenCallback) + _updateScreenCallback(); + + //if (inputArFlag && _currentScene) { + // vrtTextOut(*(_DWORD *)g_vrtHandle, smallNftData, "DEMO", 4, 380, 580); + // vrtTextOut(*(_DWORD *)g_vrtHandle, smallNftData, "Alt+F4 - exit", 14, 695, 580); + //} + } else { + //vrtRectangle(*(_DWORD *)g_vrtHandle, 0, 0, 0, 800, 600); + } + _inputController->drawCursor(_mouseScreenPos.x, _mouseScreenPos.y); + + ++_updateTicks; +} + +int FullpipeEngine::getObjectEnumState(const char *name, const char *state) { + GameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + + if (!var) { + var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0); + } + + var = var->getSubVarByName(name); + if (var) { + var = var->getSubVarByName("ENUMSTATES"); + if (var) + return var->getSubVarAsInt(state); + } + + return 0; +} + +int FullpipeEngine::getObjectState(const char *objname) { + GameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + + if (var) + return var->getSubVarAsInt(objname); + + return 0; +} + +void FullpipeEngine::setObjectState(const char *name, int state) { + GameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + + if (!var) { + var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0); + } + + var->setSubVarAsInt(name, state); +} + +void FullpipeEngine::disableSaves(ExCommand *ex) { + if (_isSaveAllowed) { + _isSaveAllowed = false; + + if (_globalMessageQueueList->size() && (*_globalMessageQueueList)[0] != 0) { + for (uint i = 0; i < _globalMessageQueueList->size(); i++) { + if ((*_globalMessageQueueList)[i]->_flags & 1) + if ((*_globalMessageQueueList)[i]->_id != ex->_parId && !(*_globalMessageQueueList)[i]->_isFinished) + return; + } + } + + if (_currentScene) + _gameLoader->writeSavegame(_currentScene, "savetmp.sav"); + } +} + + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h new file mode 100644 index 0000000000..7f20a6d6af --- /dev/null +++ b/engines/fullpipe/fullpipe.h @@ -0,0 +1,331 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_FULLPIPE_H +#define FULLPIPE_FULLPIPE_H + +#include "common/scummsys.h" +#include "common/events.h" +#include "common/keyboard.h" +#include "common/random.h" +#include "common/savefile.h" +#include "common/system.h" + +#include "audio/mixer.h" + +#include "graphics/transparent_surface.h" + +#include "engines/engine.h" + +#include "gui/debugger.h" +#include "fullpipe/console.h" + +struct ADGameDescription; + +namespace Fullpipe { + +enum FullpipeGameFeatures { +}; + +class BehaviorManager; +class BaseModalObject; +class GameLoader; +class GameVar; +class InputController; +class Inventory2; +struct CursorInfo; +struct EntranceInfo; +class ExCommand; +class Floaters; +class GameProject; +class GameObject; +class GlobalMessageQueueList; +struct MessageHandler; +class MessageQueue; +struct MovTable; +class MGM; +class NGIArchive; +class PictureObject; +struct PreloadItem; +class Scene; +class SoundList; +class StaticANIObject; +class Vars; + +int global_messageHandler1(ExCommand *cmd); +int global_messageHandler2(ExCommand *cmd); +int global_messageHandler3(ExCommand *cmd); +int global_messageHandler4(ExCommand *cmd); +void global_messageHandler_handleSound(ExCommand *cmd); + + +class FullpipeEngine : public ::Engine { +protected: + + Common::Error run(); + +public: + FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc); + virtual ~FullpipeEngine(); + + Console *_console; + GUI::Debugger *getDebugger() { return _console; } + + void initialize(); + void restartGame(); + + void setMusicAllowed(int val) { _musicAllowed = val; } + + // Detection related functions + const ADGameDescription *_gameDescription; + const char *getGameId() const; + Common::Platform getPlatform() const; + + Common::RandomSource *_rnd; + + Common::KeyCode _keyState; + uint16 _buttonState; + + void updateEvents(); + + Graphics::Surface _backgroundSurface; + Graphics::PixelFormat *_origFormat; + + GameLoader *_gameLoader; + GameProject *_gameProject; + bool loadGam(const char *fname, int scene = 0); + + GameVar *getGameLoaderGameVar(); + InputController *getGameLoaderInputController(); + + int _gameProjectVersion; + int _pictureScale; + int _scrollSpeed; + bool _updateFlag; + bool _flgCanOpenMap; + bool _gamePaused; + bool _flgGameIsRunning; + bool _inputArFlag; + bool _recordEvents; + bool _mainMenu_debugEnabled; + + Common::Rect _sceneRect; + int _sceneWidth; + int _sceneHeight; + Scene *_currentScene; + Scene *_loaderScene; + Scene *_scene2; + Scene *_scene3; + StaticANIObject *_aniMan; + StaticANIObject *_aniMan2; + byte *_globalPalette; + + InputController *_inputController; + bool _inputDisabled; + + int _currentCheat; + int _currentCheatPos; + + void defHandleKeyDown(int key); + + SoundList *_currSoundList1[11]; + int _currSoundListCount; + bool _soundEnabled; + bool _flgSoundList; + char _sceneTracks[10][260]; + int _numSceneTracks; + bool _sceneTrackHasSequence; + int _musicMinDelay; + int _musicMaxDelay; + int _musicLocal; + char _trackName[2600]; + int _trackStartDelay; + char _sceneTracksCurrentTrack[260]; + bool _sceneTrackIsPlaying; + + void stopAllSounds(); + void toggleMute(); + void playSound(int id, int flag); + void playTrack(GameVar *sceneVar, const char *name, bool delayed); + int getSceneTrack(); + void startSceneTrack(); + void startSoundStream1(char *trackName); + void stopSoundStream2(); + void stopAllSoundStreams(); + void stopAllSoundInstances(int id); + void updateSoundVolume(); + void setMusicVolume(int vol); + + int _sfxVolume; + int _musicVolume; + + GlobalMessageQueueList *_globalMessageQueueList; + MessageHandler *_messageHandlers; + + int _msgX; + int _msgY; + int _msgObjectId2; + int _msgId; + + Common::List<ExCommand *> _exCommandList; + bool _isProcessingMessages; + + int _mouseVirtX; + int _mouseVirtY; + Common::Point _mouseScreenPos; + + BehaviorManager *_behaviorManager; + + MovTable *_movTable; + + Floaters *_floaters; + MGM *_mgm; + + Common::Array<Common::Point *> _arcadeKeys; + + void initMap(); + void updateMap(PreloadItem *pre); + void updateMapPiece(int mapId, int update); + void updateScreen(); + + void freeGameLoader(); + void cleanup(); + + bool _gameContinue; + bool _needRestart; + bool _flgPlayIntro; + int _musicAllowed; + bool _normalSpeed; + + void enableSaves() { _isSaveAllowed = true; } + void disableSaves(ExCommand *ex); + + void initObjectStates(); + void setLevelStates(); + void setSwallowedEggsState(); + void loadAllScenes(); + + void initCursors(); + void addCursor(CursorInfo *cursorInfo, Scene *inv, int pictureId, int hotspotX, int hotspotY, int itemPictureOffsX, int itemPictureOffsY); + + int32 _mapTable[200]; + + Scene *_inventoryScene; + Inventory2 *_inventory; + int _currSelectedInventoryItemId; + + int32 _updateTicks; + int32 _lastInputTicks; + int32 _lastButtonUpTicks; + + BaseModalObject *_modalObject; + + int (*_updateScreenCallback)(); + int (*_updateCursorCallback)(); + + void drawAlphaRectangle(int x1, int y1, int x2, int y2, int alpha); + void sceneFade(Scene *sc, bool direction); + + int _cursorId; + int _minCursorId; + int _maxCursorId; + Common::Array<int> _objectIdCursors; + GameObject *_objectAtCursor; + int _objectIdAtCursor; + + void setCursor(int id); + void updateCursorCommon(); + + int getObjectState(const char *objname); + void setObjectState(const char *name, int state); + int getObjectEnumState(const char *name, const char *state); + + bool sceneSwitcher(EntranceInfo *entrance); + Scene *accessScene(int sceneId); + void setSceneMusicParameters(GameVar *var); + int convertScene(int scene); + int getSceneEntrance(int scene); + int getSceneFromTag(int tag); + + NGIArchive *_currArchive; + + void openMap(); + void openHelp(); + void openMainMenu(); + + PictureObject *_arcadeOverlay; + PictureObject *_arcadeOverlayHelper; + int _arcadeOverlayX; + int _arcadeOverlayY; + int _arcadeOverlayMidX; + int _arcadeOverlayMidY; + + void initArcadeKeys(const char *varname); + void processArcade(ExCommand *ex); + void winArcade(); + void setArcadeOverlay(int picId); + int drawArcadeOverlay(int adjust); + + void getAllInventory(); + + StaticANIObject *_lastLiftButton; + MessageQueue *_liftEnterMQ; + MessageQueue *_liftExitMQ; + StaticANIObject *_lift; + int _liftX; + int _liftY; + + int lift_getButtonIdP(int objid); + int lift_getButtonIdH(int objid); + int lift_getButtonIdN(int objid); + void lift_setButton(const char *name, int state); + void lift_init(Scene *sc, int qu1, int qu2); + void lift_setButtonStatics(Scene *sc, int buttonId); + void lift_exitSeq(ExCommand *ex); + void lift_closedoorSeq(); + void lift_clickButton(); + void lift_walkAndGo(); + void lift_goAnimation(); + void lift_animateButton(StaticANIObject *button); + void lift_startExitQueue(); + void lift_hoverButton(ExCommand *ex); + bool lift_checkButton(const char *varname); + void lift_openLift(); + + GameVar *_musicGameVar; + Audio::SoundHandle _sceneTrackHandle; + +public: + + bool _isSaveAllowed; + + bool canLoadGameStateCurrently() { return _isSaveAllowed; } + bool canSaveGameStateCurrently() { return _isSaveAllowed; } + +}; + +extern FullpipeEngine *g_fp; +extern Vars *g_vars; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_FULLPIPE_H */ diff --git a/engines/fullpipe/gameloader.cpp b/engines/fullpipe/gameloader.cpp new file mode 100644 index 0000000000..68b63d398a --- /dev/null +++ b/engines/fullpipe/gameloader.cpp @@ -0,0 +1,690 @@ +/* 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 "graphics/thumbnail.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/scene.h" +#include "fullpipe/input.h" +#include "fullpipe/statics.h" +#include "fullpipe/interaction.h" +#include "fullpipe/motion.h" +#include "fullpipe/constants.h" +#include "fullpipe/scenes.h" +#include "fullpipe/floaters.h" + +namespace Fullpipe { + +Inventory2 *getGameLoaderInventory() { + return &g_fp->_gameLoader->_inventory; +} + +MctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId) { + for (uint i = 0; i < g_fp->_gameLoader->_sc2array.size(); i++) + if (g_fp->_gameLoader->_sc2array[i]._sceneId == sceneId) + return (MctlCompound *)g_fp->_gameLoader->_sc2array[i]._motionController; + + return 0; +} + +InteractionController *getGameLoaderInteractionController() { + return g_fp->_gameLoader->_interactionController; +} + +GameLoader::GameLoader() { + _interactionController = new InteractionController(); + _inputController = new InputController(); + + _gameProject = 0; + _gameName = 0; + + addMessageHandlerByIndex(global_messageHandler2, 0, 0); + insertMessageHandler(global_messageHandler3, 0, 128); + insertMessageHandler(global_messageHandler4, 0, 1); + + _field_FA = 0; + _field_F8 = 0; + _sceneSwitcher = 0; + _preloadCallback = 0; + _readSavegameCallback = 0; + _gameVar = 0; + _preloadSceneId = 0; + _preloadEntranceId = 0; + _updateCounter = 0; + + g_fp->_msgX = 0; + g_fp->_msgY = 0; + g_fp->_msgObjectId2 = 0; + g_fp->_msgId = 0; +} + +GameLoader::~GameLoader() { + free(_gameName); + delete _gameProject; + delete _interactionController; + delete _inputController; + + g_fp->_gameLoader = 0; + + for (uint i = 0; i < _sc2array.size(); i++) { + if (_sc2array[i]._defPicAniInfos) + delete _sc2array[i]._defPicAniInfos; + + if (_sc2array[i]._picAniInfos) + delete _sc2array[i]._picAniInfos; + + if (_sc2array[i]._motionController) + delete _sc2array[i]._motionController; + + if (_sc2array[i]._data1) + free(_sc2array[i]._data1); + + if (_sc2array[i]._entranceData) + free(_sc2array[i]._entranceData); + } + + delete _gameVar; + _gameVar = 0; + + _sc2array.clear(); +} + +bool GameLoader::load(MfcArchive &file) { + debug(5, "GameLoader::load()"); + + _gameName = file.readPascalString(); + debug(6, "_gameName: %s", _gameName); + + _gameProject = new GameProject(); + + _gameProject->load(file); + + g_fp->_gameProject = _gameProject; + + if (g_fp->_gameProjectVersion < 12) { + error("Old gameProjectVersion: %d", g_fp->_gameProjectVersion); + } + + _gameName = file.readPascalString(); + debug(6, "_gameName: %s", _gameName); + + _inventory.load(file); + + _interactionController->load(file); + + debug(6, "sceneTag count: %d", _gameProject->_sceneTagList->size()); + + _sc2array.resize(_gameProject->_sceneTagList->size()); + + int i = 0; + for (SceneTagList::const_iterator it = _gameProject->_sceneTagList->begin(); it != _gameProject->_sceneTagList->end(); ++it, i++) { + char tmp[12]; + + snprintf(tmp, 11, "%04d.sc2", it->_sceneId); + + debug(2, "sc: %s", tmp); + + _sc2array[i].loadFile((const char *)tmp); + } + + _preloadItems.load(file); + + _field_FA = file.readUint16LE(); + _field_F8 = file.readUint16LE(); + + _gameVar = (GameVar *)file.readClass(); + + return true; +} + +bool GameLoader::loadScene(int sceneId) { + SceneTag *st; + + int idx = getSceneTagBySceneId(sceneId, &st); + + if (idx < 0) + return false; + + if (!st->_scene) + st->loadScene(); + + if (st->_scene) { + st->_scene->init(); + + applyPicAniInfos(st->_scene, _sc2array[idx]._defPicAniInfos, _sc2array[idx]._defPicAniInfosCount); + applyPicAniInfos(st->_scene, _sc2array[idx]._picAniInfos, _sc2array[idx]._picAniInfosCount); + + _sc2array[idx]._scene = st->_scene; + _sc2array[idx]._isLoaded = 1; + + return true; + } + + return false; +} + +bool GameLoader::gotoScene(int sceneId, int entranceId) { + SceneTag *st; + + int sc2idx = getSceneTagBySceneId(sceneId, &st); + + if (sc2idx < 0) + return false; + + if (!_sc2array[sc2idx]._isLoaded) + return false; + + if (_sc2array[sc2idx]._entranceDataCount < 1) { + g_fp->_currentScene = st->_scene; + return true; + } + + if (_sc2array[sc2idx]._entranceDataCount <= 0) + return false; + + int entranceIdx = 0; + if (sceneId != 726) // WORKAROUND + for (entranceIdx = 0; _sc2array[sc2idx]._entranceData[entranceIdx]->_field_4 != entranceId; entranceIdx++) { + if (entranceIdx >= _sc2array[sc2idx]._entranceDataCount) + return false; + } + + GameVar *sg = _gameVar->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME"); + + if (sg || (sg = _gameVar->getSubVarByName("OBJSTATES")->addSubVarAsInt("SAVEGAME", 0)) != 0) + sg->setSubVarAsInt("Entrance", entranceId); + + if (!g_fp->sceneSwitcher(_sc2array[sc2idx]._entranceData[entranceIdx])) + return false; + + g_fp->_msgObjectId2 = 0; + g_fp->_msgY = -1; + g_fp->_msgX = -1; + + g_fp->_currentScene = st->_scene; + + MessageQueue *mq1 = g_fp->_currentScene->getMessageQueueById(_sc2array[sc2idx]._entranceData[entranceIdx]->_messageQueueId); + if (mq1) { + MessageQueue *mq = new MessageQueue(mq1, 0, 0); + + StaticANIObject *stobj = g_fp->_currentScene->getStaticANIObject1ById(_field_FA, -1); + if (stobj) { + stobj->_flags &= 0x100; + + ExCommand *ex = new ExCommand(stobj->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_14 = 256; + ex->_messageNum = 0; + ex->_excFlags |= 3; + + mq->addExCommandToEnd(ex); + } + + mq->setFlags(mq->getFlags() | 1); + + if (!mq->chain(0)) { + delete mq; + + return false; + } + } else { + StaticANIObject *stobj = g_fp->_currentScene->getStaticANIObject1ById(_field_FA, -1); + if (stobj) + stobj->_flags &= 0xfeff; + } + + return true; +} + +bool preloadCallback(PreloadItem &pre, int flag) { + if (flag) { + if (flag == 50) + g_fp->_aniMan->preloadMovements(g_fp->_movTable); + + StaticANIObject *pbar = g_fp->_loaderScene->getStaticANIObject1ById(ANI_PBAR, -1); + + if (pbar) { + int sz; + + if (pbar->_movement->_currMovement) + sz = pbar->_movement->_currMovement->_dynamicPhases.size(); + else + sz = pbar->_movement->_dynamicPhases.size(); + + pbar->_movement->setDynamicPhaseIndex(flag * (sz - 1) / 100); + } + + g_fp->updateMap(&pre); + + g_fp->_currentScene = g_fp->_loaderScene; + + g_fp->_loaderScene->draw(); + + g_fp->_system->updateScreen(); + } else { + if (g_fp->_scene2) { + g_fp->_aniMan = g_fp->_scene2->getAniMan(); + g_fp->_scene2 = 0; + setInputDisabled(1); + } + + g_fp->_floaters->stopAll(); + + if (g_fp->_soundEnabled) { + g_fp->_currSoundListCount = 1; + g_fp->_currSoundList1[0] = g_fp->accessScene(SC_COMMON)->_soundList; + } + + g_vars->scene18_inScene18p1 = false; + + if ((pre.preloadId1 != SC_18 || pre.sceneId != SC_19) && (pre.preloadId1 != SC_19 || (pre.sceneId != SC_18 && pre.sceneId != SC_19))) { + if (g_fp->_scene3) { + if (pre.preloadId1 != SC_18) + g_fp->_gameLoader->unloadScene(SC_18); + + g_fp->_scene3 = 0; + } + } else { + scene19_setMovements(g_fp->accessScene(pre.preloadId1), pre.keyCode); + + g_vars->scene18_inScene18p1 = true; + + if (pre.preloadId1 == SC_18) { + g_fp->_gameLoader->saveScenePicAniInfos(SC_18); + + scene18_preload(); + } + } + + if (((pre.sceneId == SC_19 && pre.keyCode == TrubaRight) || (pre.sceneId == SC_18 && pre.keyCode == TrubaRight)) && !pre.preloadId2) { + pre.sceneId = SC_18; + pre.keyCode = TrubaLeft; + } + + if (!g_fp->_loaderScene) { + g_fp->_gameLoader->loadScene(SC_LDR); + g_fp->_loaderScene = g_fp->accessScene(SC_LDR); + } + + StaticANIObject *pbar = g_fp->_loaderScene->getStaticANIObject1ById(ANI_PBAR, -1); + + if (pbar) { + pbar->show1(ST_EGTR_SLIMSORROW, ST_MAN_GOU, MV_PBAR_RUN, 0); + pbar->startAnim(MV_PBAR_RUN, 0, -1); + } + + g_fp->_inventoryScene = 0; + g_fp->_updateCursorCallback = 0; + + g_fp->_sceneRect.translate(-g_fp->_sceneRect.left, -g_fp->_sceneRect.top); + + g_fp->_system->delayMillis(10); + + Scene *oldsc = g_fp->_currentScene; + + g_fp->_currentScene = g_fp->_loaderScene; + + g_fp->_loaderScene->draw(); + + g_fp->_system->updateScreen(); + + g_fp->_currentScene = oldsc; + } + + return true; +} + +bool GameLoader::preloadScene(int sceneId, int entranceId) { + debug(0, "preloadScene(%d, %d), ", sceneId, entranceId); + + if (_preloadSceneId != sceneId || _preloadEntranceId != entranceId) { + _preloadSceneId = sceneId; + _preloadEntranceId = entranceId; + return true; + } + + int idx = -1; + + for (uint i = 0; i < _preloadItems.size(); i++) + if (_preloadItems[i]->preloadId1 == sceneId && _preloadItems[i]->preloadId2 == entranceId) { + idx = i; + break; + } + + if (idx == -1) { + _preloadSceneId = 0; + _preloadEntranceId = 0; + return false; + } + + if (_preloadCallback) { + if (!_preloadCallback(*_preloadItems[idx], 0)) + return false; + } + + if (g_fp->_currentScene && g_fp->_currentScene->_sceneId == sceneId) + g_fp->_currentScene = 0; + + saveScenePicAniInfos(sceneId); + clearGlobalMessageQueueList1(); + unloadScene(sceneId); + + if (_preloadCallback) + _preloadCallback(*_preloadItems[idx], 50); + + loadScene(_preloadItems[idx]->sceneId); + + ExCommand *ex = new ExCommand(_preloadItems[idx]->sceneId, 17, 62, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags = 2; + ex->_keyCode = _preloadItems[idx]->keyCode; + + _preloadSceneId = 0; + _preloadEntranceId = 0; + + if (_preloadCallback) + _preloadCallback(*_preloadItems[idx], 100); + + ex->postMessage(); + + return true; +} + +bool GameLoader::unloadScene(int sceneId) { + SceneTag *tag; + int sceneTag = getSceneTagBySceneId(sceneId, &tag); + + if (sceneTag < 0) + return false; + + if (_sc2array[sceneTag]._isLoaded) + saveScenePicAniInfos(sceneId); + + _sc2array[sceneTag]._motionController->detachAllObjects(); + + delete tag->_scene; + tag->_scene = 0; + + _sc2array[sceneTag]._isLoaded = 0; + _sc2array[sceneTag]._scene = 0; + + return true; +} + +int GameLoader::getSceneTagBySceneId(int sceneId, SceneTag **st) { + if (_sc2array.size() > 0 && _gameProject->_sceneTagList->size() > 0) { + for (uint i = 0; i < _sc2array.size(); i++) { + if (_sc2array[i]._sceneId == sceneId) { + int num = 0; + for (SceneTagList::iterator s = _gameProject->_sceneTagList->begin(); s != _gameProject->_sceneTagList->end(); ++s, num++) { + if (s->_sceneId == sceneId) { + *st = &(*s); + return num; + } + } + } + } + } + + *st = 0; + return -1; +} + +void GameLoader::applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAniInfoCount) { + if (picAniInfoCount <= 0) + return; + + debug(0, "GameLoader::applyPicAniInfos(sc, ptr, %d)", picAniInfoCount); + + PictureObject *pict; + StaticANIObject *ani; + + for (int i = 0; i < picAniInfoCount; i++) { + debug(7, "PicAniInfo: id: %d type: %d", picAniInfo[i]->objectId, picAniInfo[i]->type); + if (picAniInfo[i]->type & 2) { + pict = sc->getPictureObjectById(picAniInfo[i]->objectId, picAniInfo[i]->field_8); + if (pict) { + pict->setPicAniInfo(picAniInfo[i]); + continue; + } + pict = sc->getPictureObjectById(picAniInfo[i]->objectId, 0); + if (pict) { + PictureObject *pictNew = new PictureObject(pict); + + sc->_picObjList.push_back(pictNew); + pictNew->setPicAniInfo(picAniInfo[i]); + continue; + } + } else { + if (!(picAniInfo[i]->type & 1)) + continue; + + Scene *scNew = g_fp->accessScene(picAniInfo[i]->sceneId); + if (!scNew) + continue; + + ani = sc->getStaticANIObject1ById(picAniInfo[i]->objectId, picAniInfo[i]->field_8); + if (ani) { + ani->setPicAniInfo(picAniInfo[i]); + continue; + } + + ani = scNew->getStaticANIObject1ById(picAniInfo[i]->objectId, 0); + if (ani) { + StaticANIObject *aniNew = new StaticANIObject(ani); + + sc->addStaticANIObject(aniNew, 1); + + aniNew->setPicAniInfo(picAniInfo[i]); + continue; + } + } + } +} + +void GameLoader::saveScenePicAniInfos(int sceneId) { + warning("STUB: GameLoader::saveScenePicAniInfos(%d)", sceneId); +} + +void GameLoader::updateSystems(int counterdiff) { + if (g_fp->_currentScene) { + g_fp->_currentScene->update(counterdiff); + + _exCommand._messageKind = 17; + _updateCounter++; + _exCommand._messageNum = 33; + _exCommand._excFlags = 0; + _exCommand.postMessage(); + } + + processMessages(); + + if (_preloadSceneId) { + processMessages(); + preloadScene(_preloadSceneId, _preloadEntranceId); + } +} + +void GameLoader::readSavegame(const char *fname) { + warning("STUB: readSavegame(%s)", fname); +} + +void GameLoader::writeSavegame(Scene *sc, const char *fname) { + warning("STUB: writeSavegame(sc, %s)", fname); +} + +Sc2::Sc2() { + _sceneId = 0; + _field_2 = 0; + _scene = 0; + _motionController = 0; + _data1 = 0; + _count1 = 0; + _defPicAniInfos = 0; + _defPicAniInfosCount = 0; + _picAniInfos = 0; + _picAniInfosCount = 0; + _isLoaded = 0; + _entranceData = 0; + _entranceDataCount = 0; +} + +bool Sc2::load(MfcArchive &file) { + debug(5, "Sc2::load()"); + + _sceneId = file.readUint16LE(); + + _motionController = (MotionController *)file.readClass(); + + _count1 = file.readUint32LE(); + debug(4, "count1: %d", _count1); + if (_count1 > 0) { + _data1 = (int32 *)malloc(_count1 * sizeof(int32)); + + for (int i = 0; i < _count1; i++) { + _data1[i] = file.readUint32LE(); + } + } else { + _data1 = 0; + } + + _defPicAniInfosCount = file.readUint32LE(); + debug(4, "defPicAniInfos: %d", _defPicAniInfosCount); + if (_defPicAniInfosCount > 0) { + _defPicAniInfos = (PicAniInfo **)malloc(_defPicAniInfosCount * sizeof(PicAniInfo *)); + + for (int i = 0; i < _defPicAniInfosCount; i++) { + _defPicAniInfos[i] = new PicAniInfo(); + + _defPicAniInfos[i]->load(file); + } + } else { + _defPicAniInfos = 0; + } + + _picAniInfos = 0; + _picAniInfosCount = 0; + + _entranceDataCount = file.readUint32LE(); + debug(4, "_entranceData: %d", _entranceDataCount); + + if (_entranceDataCount > 0) { + _entranceData = (EntranceInfo **)malloc(_entranceDataCount * sizeof(EntranceInfo *)); + + for (int i = 0; i < _entranceDataCount; i++) { + _entranceData[i] = new EntranceInfo(); + _entranceData[i]->load(file); + } + } else { + _entranceData = 0; + } + + if (file.size() - file.pos() > 0) + error("Sc2::load(): (%d bytes left)", file.size() - file.pos()); + + return true; +} + +bool PreloadItems::load(MfcArchive &file) { + debug(5, "PreloadItems::load()"); + + int count = file.readCount(); + + clear(); + + for (int i = 0; i < count; i++) { + PreloadItem *t = new PreloadItem(); + t->preloadId1 = file.readUint32LE(); + t->preloadId2 = file.readUint32LE(); + t->sceneId = file.readUint32LE(); + t->keyCode = file.readUint32LE(); + + push_back(t); + } + + return true; +} + +const char *getSavegameFile(int saveGameIdx) { + static char buffer[20]; + sprintf(buffer, "fullpipe.s%02d", saveGameIdx); + return buffer; +} + +bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header) { + char saveIdentBuffer[6]; + header.thumbnail = NULL; + + // Validate the header Id + in->read(saveIdentBuffer, 6); + if (strcmp(saveIdentBuffer, "SVMCR")) + return false; + + header.version = in->readByte(); + if (header.version != FULLPIPE_SAVEGAME_VERSION) + return false; + + // Read in the string + header.saveName.clear(); + char ch; + while ((ch = (char)in->readByte()) != '\0') header.saveName += ch; + + // Get the thumbnail + header.thumbnail = Graphics::loadThumbnail(*in); + if (!header.thumbnail) + return false; + + return true; +} + +void GameLoader::restoreDefPicAniInfos() { + for (uint i = 0; i < _sc2array.size(); i++) { + if (_sc2array[i]._picAniInfos) { + free(_sc2array[i]._picAniInfos); + _sc2array[i]._picAniInfos = 0; + _sc2array[i]._picAniInfosCount = 0; + } + + if (_sc2array[i]._scene) + applyPicAniInfos(_sc2array[i]._scene, _sc2array[i]._defPicAniInfos, _sc2array[i]._defPicAniInfosCount); + } +} + +GameVar *FullpipeEngine::getGameLoaderGameVar() { + if (_gameLoader) + return _gameLoader->_gameVar; + else + return 0; +} + +InputController *FullpipeEngine::getGameLoaderInputController() { + if (_gameLoader) + return _gameLoader->_inputController; + else + return 0; +} + +MctlCompound *getCurrSceneSc2MotionController() { + return getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/gameloader.h b/engines/fullpipe/gameloader.h new file mode 100644 index 0000000000..772cc51130 --- /dev/null +++ b/engines/fullpipe/gameloader.h @@ -0,0 +1,134 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_GAMELOADER_H +#define FULLPIPE_GAMELOADER_H + +#include "fullpipe/objects.h" +#include "fullpipe/inventory.h" +#include "fullpipe/messages.h" + +namespace Fullpipe { + +#define FULLPIPE_SAVEGAME_VERSION 1 + +class SceneTag; +class MctlCompound; +class InputController; +class InteractionController; +class MotionController; + +class Sc2 : public CObject { + public: + int16 _sceneId; + int16 _field_2; + Scene *_scene; + MotionController *_motionController; + int32 *_data1; // FIXME, could be a struct + int _count1; + PicAniInfo **_defPicAniInfos; + int _defPicAniInfosCount; + PicAniInfo **_picAniInfos; + int _picAniInfosCount; + int _isLoaded; + EntranceInfo **_entranceData; + int _entranceDataCount; + + public: + Sc2(); + virtual bool load(MfcArchive &file); +}; + +typedef Common::Array<Sc2> Sc2Array; + +struct PreloadItem { + int preloadId1; + int preloadId2; + int sceneId; + int keyCode; +}; + +bool preloadCallback(PreloadItem &pre, int flag); + +class PreloadItems : public Common::Array<PreloadItem *>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +struct FullpipeSavegameHeader { + uint8 version; + Common::String saveName; + Graphics::Surface *thumbnail; +}; + +class GameLoader : public CObject { + public: + GameLoader(); + virtual ~GameLoader(); + + virtual bool load(MfcArchive &file); + bool loadScene(int sceneId); + bool gotoScene(int sceneId, int entranceId); + bool preloadScene(int sceneId, int entranceId); + bool unloadScene(int sceneId); + + void updateSystems(int counterdiff); + + int getSceneTagBySceneId(int sceneId, SceneTag **st); + void applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAniInfoCount); + void saveScenePicAniInfos(int sceneId); + + void readSavegame(const char *fname); + void writeSavegame(Scene *sc, const char *fname); + + void restoreDefPicAniInfos(); + + GameProject *_gameProject; + InteractionController *_interactionController; + InputController *_inputController; + Inventory2 _inventory; + Sc2Array _sc2array; + void *_sceneSwitcher; + bool (*_preloadCallback)(PreloadItem &pre, int flag); + void *_readSavegameCallback; + int16 _field_F8; + int16 _field_FA; + PreloadItems _preloadItems; + GameVar *_gameVar; + char *_gameName; + ExCommand _exCommand; + int _updateCounter; + int _preloadSceneId; + int _preloadEntranceId; +}; + +const char *getSavegameFile(int saveGameIdx); +bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header); + +Inventory2 *getGameLoaderInventory(); +InteractionController *getGameLoaderInteractionController(); +MctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId); +MctlCompound *getCurrSceneSc2MotionController(); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_GAMELOADER_H */ diff --git a/engines/fullpipe/gfx.cpp b/engines/fullpipe/gfx.cpp new file mode 100644 index 0000000000..42846850ca --- /dev/null +++ b/engines/fullpipe/gfx.cpp @@ -0,0 +1,1278 @@ +/* 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/gfx.h" +#include "fullpipe/statics.h" +#include "fullpipe/scene.h" +#include "fullpipe/interaction.h" +#include "fullpipe/gameloader.h" + +#include "common/memstream.h" + +namespace Fullpipe { + +Background::Background() { + _x = 0; + _y = 0; + _messageQueueId = 0; + _bigPictureArray1Count = 0; + _bigPictureArray2Count = 0; + _bigPictureArray = 0; + _bgname = 0; + _palette = 0; +} + +Background::~Background() { + _picObjList.clear(); + + for (int i = 0; i < _bigPictureArray1Count; i++) { + for (int j = 0; j < _bigPictureArray2Count; j++) + delete _bigPictureArray[i][j]; + + free(_bigPictureArray[i]); + } + + free(_bigPictureArray); +} + +bool Background::load(MfcArchive &file) { + debug(5, "Background::load()"); + _bgname = file.readPascalString(); + + int count = file.readUint16LE(); + + for (int i = 0; i < count; i++) { + PictureObject *pct = new PictureObject(); + + pct->load(file, i == 0); + addPictureObject(pct); + } + + assert(g_fp->_gameProjectVersion >= 4); + + _bigPictureArray1Count = file.readUint32LE(); + + assert(g_fp->_gameProjectVersion >= 5); + + _bigPictureArray2Count = file.readUint32LE(); + + _bigPictureArray = (BigPicture ***)calloc(_bigPictureArray1Count, sizeof(BigPicture **)); + + debug(6, "bigPictureArray[%d][%d]", _bigPictureArray1Count, _bigPictureArray2Count); + + for (int i = 0; i < _bigPictureArray1Count; i++) { + _bigPictureArray[i] = (BigPicture **)calloc(_bigPictureArray2Count, sizeof(BigPicture *)); + for (int j = 0; j < _bigPictureArray2Count; j++) { + _bigPictureArray[i][j] = new BigPicture(); + + _bigPictureArray[i][j]->load(file); + } + } + + return true; +} + +void Background::addPictureObject(PictureObject *pct) { + if (pct->_okeyCode) + pct->renumPictures(&_picObjList); + + bool inserted = false; + for (uint i = 1; i < _picObjList.size(); i++) { + if (_picObjList[i]->_priority <= pct->_priority) { + _picObjList.insert_at(i, pct); + inserted = true; + break; + } + } + + if (!inserted) { + _picObjList.push_back(pct); + } +} + +PictureObject::PictureObject() { + _ox = 0; + _oy = 0; + _picture = 0; + _ox2 = 0; + _oy2 = 0; + _pictureObject2List = 0; + _objtype = kObjTypePictureObject; +} + +PictureObject::~PictureObject() { + delete _picture; + _pictureObject2List->clear(); + delete _pictureObject2List; +} + +PictureObject::PictureObject(PictureObject *src) : GameObject(src) { + _picture = src->_picture; + _ox2 = _ox; + _oy2 = _oy; + _pictureObject2List = src->_pictureObject2List; + _objtype = kObjTypePictureObject; +} + +bool PictureObject::load(MfcArchive &file, bool bigPicture) { + debug(5, "PictureObject::load()"); + GameObject::load(file); + + if (bigPicture) + _picture = new BigPicture(); + else + _picture = new Picture(); + + _picture->load(file); + + _pictureObject2List = new Common::Array<GameObject *>; + + int count = file.readUint16LE(); + + if (count > 0) { + GameObject *o = new GameObject(); + + o->load(file); + _pictureObject2List->push_back(o); + } + + _ox2 = _ox; + _oy2 = _oy; + +#if 0 + _picture->displayPicture(); +#endif + + return true; +} + +Common::Point *PictureObject::getDimensions(Common::Point *p) { + _picture->getDimensions(p); + + return p; +} + +void PictureObject::draw() { + if (_flags & 1) + _picture->draw(_ox, _oy, 2, 0); + else + _picture->draw(_ox, _oy, 0, 0); +} + +void PictureObject::drawAt(int x, int y) { + if (x == -1) + x = _ox; + if (y == -1) + y = _oy; + + _picture->_x = x; + _picture->_y = y; + + if (_flags & 1) + _picture->draw(x, y, 2, 0); + else + _picture->draw(x, y, 0, 0); +} + +bool PictureObject::setPicAniInfo(PicAniInfo *picAniInfo) { + if (!(picAniInfo->type & 2) || (picAniInfo->type & 1)) { + error("PictureObject::setPicAniInfo(): Wrong type: %d", picAniInfo->type); + + return false; + } + + if (picAniInfo->type & 2) { + setOXY(picAniInfo->ox, picAniInfo->oy); + _priority = picAniInfo->priority; + _okeyCode = picAniInfo->field_8; + setFlags(picAniInfo->flags); + _field_8 = picAniInfo->field_24; + + return true; + } + + return false; +} + +bool PictureObject::isPointInside(int x, int y) { + bool res; + int oldx = _picture->_x; + int oldy = _picture->_y; + + _picture->_x = _ox; + _picture->_y = _oy; + + res = _picture->isPointInside(x, y); + + _picture->_x = oldx; + _picture->_y = oldy; + + return res; +} + +bool PictureObject::isPixelHitAtPos(int x, int y) { + int oldx = _picture->_x; + int oldy = _picture->_y; + + _picture->_x = _ox; + _picture->_y = _oy; + bool res = _picture->isPixelHitAtPos(x, y); + _picture->_x = oldx; + _picture->_y = oldy; + + return res; +} + +void PictureObject::setOXY2() { + _ox2 = _ox; + _oy2 = _oy; +} + +GameObject::GameObject() { + _okeyCode = 0; + _flags = 0; + _id = 0; + _ox = 0; + _oy = 0; + _priority = 0; + _field_20 = 0; + _field_8 = 0; + _objectName = 0; +} + +GameObject::GameObject(GameObject *src) { + _okeyCode = 1; + _flags = 0; + _id = src->_id; + + _objectName = (char *)calloc(strlen(src->_objectName) + 1, 1); + strncpy(_objectName, src->_objectName, strlen(src->_objectName)); + + _ox = src->_ox; + _oy = src->_oy; + _priority = src->_priority; + _field_20 = 1; + _field_8 = src->_field_8; +} + +GameObject::~GameObject() { + free(_objectName); +} + +bool GameObject::load(MfcArchive &file) { + debug(5, "GameObject::load()"); + _okeyCode = 0; + _flags = 0; + _field_20 = 0; + + _id = file.readUint16LE(); + + _objectName = file.readPascalString(); + _ox = file.readUint32LE(); + _oy = file.readUint32LE(); + _priority = file.readUint16LE(); + + if (g_fp->_gameProjectVersion >= 11) { + _field_8 = file.readUint32LE(); + } + + return true; +} + +void GameObject::setOXY(int x, int y) { + _ox = x; + _oy = y; +} + +void GameObject::renumPictures(Common::Array<StaticANIObject *> *lst) { + int *buf = (int *)calloc(lst->size() + 2, sizeof(int)); + + for (uint i = 0; i < lst->size(); i++) { + if (_id == ((GameObject *)((*lst)[i]))->_id) + buf[((GameObject *)((*lst)[i]))->_okeyCode] = 1; + } + + if (buf[_okeyCode]) { + uint count; + for (count = 1; buf[count] && count < lst->size() + 2; count++) + ; + _okeyCode = count; + } + + free(buf); +} + +void GameObject::renumPictures(Common::Array<PictureObject *> *lst) { + int *buf = (int *)calloc(lst->size() + 2, sizeof(int)); + + for (uint i = 0; i < lst->size(); i++) { + if (_id == ((GameObject *)((*lst)[i]))->_id) + buf[((GameObject *)((*lst)[i]))->_okeyCode] = 1; + } + + if (buf[_okeyCode]) { + uint count; + for (count = 1; buf[count] && count < lst->size() + 2; count++) + ; + _okeyCode = count; + } + + free(buf); +} + +bool GameObject::getPicAniInfo(PicAniInfo *info) { + if (_objtype == kObjTypePictureObject) { + info->type = 2; + info->objectId = _id; + info->sceneId = 0; + info->field_8 = _okeyCode; + info->flags = _flags; + info->field_24 = _field_8; + info->ox = _ox; + info->oy = _oy; + info->priority = _priority; + warning("Yep %d", _id); + + return true; + } + + if (_objtype == kObjTypeStaticANIObject) { + StaticANIObject *ani = (StaticANIObject *)this; + + info->type = (ani->_messageQueueId << 16) | 1; + info->objectId = ani->_id; + info->field_8 = ani->_okeyCode; + info->sceneId = ani->_sceneId; + info->flags = ani->_flags; + info->field_24 = ani->_field_8; + if (ani->_movement) { + info->ox = ani->_movement->_ox; + info->oy = ani->_movement->_oy; + } else { + info->ox = ani->_ox; + info->oy = ani->_oy; + } + info->priority = ani->_priority; + + if (ani->_statics) + info->staticsId = ani->_statics->_staticsId; + + if (ani->_movement) { + info->movementId = ani->_movement->_id; + info->dynamicPhaseIndex = ani->_movement->_currDynamicPhaseIndex; + } + + info->someDynamicPhaseIndex = ani->_someDynamicPhaseIndex; + + return true; + } + + return false; +} + +bool GameObject::setPicAniInfo(PicAniInfo *picAniInfo) { + if (!(picAniInfo->type & 3)) { + warning("StaticANIObject::setPicAniInfo(): Wrong type: %d", picAniInfo->type); + + return false; + } + + if (picAniInfo->type & 3) { + setOXY(picAniInfo->ox, picAniInfo->oy); + _priority = picAniInfo->priority; + _okeyCode = picAniInfo->field_8; + setFlags(picAniInfo->flags); + _field_8 = picAniInfo->field_24; + } + + if (picAniInfo->type & 1) { + StaticANIObject *ani = (StaticANIObject *)this; + + ani->_messageQueueId = (picAniInfo->type >> 16) & 0xffff; + + if (picAniInfo->staticsId) { + ani->_statics = ani->getStaticsById(picAniInfo->staticsId); + } else { + ani->_statics = 0; + } + + if (picAniInfo->movementId) { + ani->_movement = ani->getMovementById(picAniInfo->movementId); + if (ani->_movement) + ani->_movement->setDynamicPhaseIndex(picAniInfo->dynamicPhaseIndex); + } else { + ani->_movement = 0; + } + + ani->setSomeDynamicPhaseIndex(picAniInfo->someDynamicPhaseIndex); + } + + return true; +} + +Picture::Picture() { + _x = 0; + _y = 0; + _field_44 = 0; + _field_54 = 0; + _bitmap = 0; + _alpha = -1; + _paletteData = 0; + _convertedBitmap = 0; + _memoryObject2 = 0; + _width = 0; + _height = 0; +} + +Picture::~Picture() { + freePicture(); + + _bitmap = 0; + + if (_memoryObject2) + delete _memoryObject2; + + if (_paletteData) + free(_paletteData); + + if (_convertedBitmap) { + delete _convertedBitmap; + _convertedBitmap = 0; + } +} + +void Picture::freePicture() { + debug(5, "Picture::freePicture(): file: %s", _memfilename); + + if (_bitmap) { + if (testFlags() && !_field_54) { + freeData(); + //free(_bitmap); + _bitmap = 0; + } + } + + if (_bitmap) { + _bitmap = 0; + _data = 0; + } + + if (_convertedBitmap) { + free(_convertedBitmap->_pixels); + delete _convertedBitmap; + _convertedBitmap = 0; + } +} + +void Picture::freePixelData() { + freePicture(); + freeData(); +} + +bool Picture::load(MfcArchive &file) { + debug(5, "Picture::load()"); + MemoryObject::load(file); + + _x = file.readUint32LE(); + _y = file.readUint32LE(); + _field_44 = file.readUint16LE(); + + assert(g_fp->_gameProjectVersion >= 2); + + _width = file.readUint32LE(); + _height = file.readUint32LE(); + + _mflags |= 1; + + _memoryObject2 = new MemoryObject2; + _memoryObject2->load(file); + + if (_memoryObject2->_data) { + setAOIDs(); + } + + assert (g_fp->_gameProjectVersion >= 12); + + _alpha = file.readUint32LE() & 0xff; + + int havePal = file.readUint32LE(); + + if (havePal > 0) { + _paletteData = (byte *)calloc(1024, 1); + file.read(_paletteData, 1024); + } + + getData(); + + debug(5, "Picture::load: loaded <%s>", _memfilename); + + return true; +} + +void Picture::setAOIDs() { + int w = (g_fp->_pictureScale + _width - 1) / g_fp->_pictureScale; + int h = (g_fp->_pictureScale + _height - 1) / g_fp->_pictureScale; + + _memoryObject2->_rows = (byte **)malloc(w * sizeof(int *)); + + int pitch = 2 * h; + byte *ptr = _memoryObject2->getData(); + for (int i = 0; i < w; i++) { + _memoryObject2->_rows[i] = ptr; + ptr += pitch; + } +} + +void Picture::init() { + debug(5, "Picture::init(), %s", _memfilename); + + MemoryObject::getData(); + + _bitmap = new Bitmap(); + + getDibInfo(); + + _bitmap->_flags |= 0x1000000; +} + +Common::Point *Picture::getDimensions(Common::Point *p) { + p->x = _width; + p->y = _height; + + return p; +} + +void Picture::getDibInfo() { + int off = _dataSize & ~0xf; + + debug(9, "Picture::getDibInfo: _dataSize: %d", _dataSize); + + if (!_dataSize) { + warning("Picture::getDibInfo(): Empty data size"); + return; + } + + if (_dataSize != off) { + warning("Uneven data size: 0x%x", _dataSize); + } + + if (!_data) { + warning("Picture::getDibInfo: data is empty <%s>", _memfilename); + + MemoryObject::load(); + } + + Common::MemoryReadStream *s = new Common::MemoryReadStream(_data + off - 32, 32); + + _bitmap->load(s); + _bitmap->_pixels = _data; + + _bitmap->decode((int32 *)(_paletteData ? _paletteData : g_fp->_globalPalette)); + + _bitmap->_pixels = 0; +} + +Bitmap *Picture::getPixelData() { + if (!_bitmap) + init(); + + return _bitmap; +} + +void Picture::draw(int x, int y, int style, int angle) { + int x1 = x; + int y1 = y; + + debug(7, "Picture::draw(%d, %d, %d, %d) (%s)", x, y, style, angle, _memfilename); + + if (x != -1) + x1 = x; + + if (y != -1) + y1 = y; + + if (!_bitmap) + init(); + + if (!_bitmap) + return; + + if ((_alpha & 0xff) < 0xff) { + debug(7, "Picture:draw: alpha = %0x", _alpha); + } + + byte *pal = _paletteData; + + if (!pal) { + //warning("Picture:draw: using global palette"); + pal = g_fp->_globalPalette; + } + + Common::Point point; + + switch (style) { + case 1: + //flip + getDimensions(&point); + _bitmap->flipVertical()->drawShaded(1, x1, y1 + 30 + point.y, pal, _alpha); + break; + case 2: + //vrtSetFadeRatio(g_vrtDrawHandle, 0.34999999); + //vrtSetFadeTable(g_vrtDrawHandle, &unk_477F88, 1.0, 1000.0, 0, 0); + _bitmap->drawShaded(2, x1, y1, pal, _alpha); + //vrtSetFadeRatio(g_vrtDrawHandle, 0.0); + //vrtSetFadeTable(g_vrtDrawHandle, &unk_477F90, 1.0, 1000.0, 0, 0); + break; + default: + if (angle) + drawRotated(x1, y1, angle); + else { + _bitmap->putDib(x1, y1, (int32 *)pal, _alpha); + } + } +} + +void Picture::drawRotated(int x, int y, int angle) { + warning("STUB: Picture::drawRotated(%d, %d, %d)", x, y, angle); +} + +void Picture::displayPicture() { + if (!g_fp->_gameContinue) + return; + + getData(); + init(); + + if (!_dataSize) + return; + + g_fp->_backgroundSurface.fillRect(Common::Rect(0, 0, 800, 600), 0); + g_fp->_system->copyRectToScreen(g_fp->_backgroundSurface.getBasePtr(0, 0), g_fp->_backgroundSurface.pitch, 0, 0, 800, 600); + + draw(0, 0, 0, 0); + + g_fp->updateEvents(); + g_fp->_system->delayMillis(10); + g_fp->_system->updateScreen(); + + while (g_fp->_gameContinue) { + g_fp->updateEvents(); + g_fp->_system->delayMillis(10); + g_fp->_system->updateScreen(); + + if (g_fp->_keyState == ' ') { + g_fp->_keyState = Common::KEYCODE_INVALID; + break; + } + } +} + +void Picture::setPaletteData(byte *pal) { + if (_paletteData) + free(_paletteData); + + if (pal) { + _paletteData = (byte *)malloc(1024); + memcpy(_paletteData, pal, 1024); + } +} + +void Picture::copyMemoryObject2(Picture *src) { + if (_width == src->_width && _height == src->_height) { + if (src->_memoryObject2 && src->_memoryObject2->_rows && _memoryObject2) { + byte *data = loadData(); + _memoryObject2->copyData(data, _dataSize); + setAOIDs(); + } + } +} + +bool Picture::isPointInside(int x, int y) { + if (x >= _x) { + if (y >= _y && x < _x + _width && y < _y + _height) + return true; + } + return false; +} + +bool Picture::isPixelHitAtPos(int x, int y) { + if (x < _x || y < _y || x >= _x + _width || y >= _y + _height) + return false; + + if (!_bitmap) + init(); + + _bitmap->_x = _x; + _bitmap->_y = _y; + + return _bitmap->isPixelHitAtPos(x, y); +} + +int Picture::getPixelAtPos(int x, int y) { + return getPixelAtPosEx(x / g_fp->_pictureScale, y / g_fp->_pictureScale); + + return false; +} + +int Picture::getPixelAtPosEx(int x, int y) { + if (x < 0 || y < 0) + return 0; + + if (x < (g_fp->_pictureScale + _width - 1) / g_fp->_pictureScale && + y < (g_fp->_pictureScale + _height - 1) / g_fp->_pictureScale && + _memoryObject2 != 0 && _memoryObject2->_rows != 0) + return _memoryObject2->_rows[x][2 * y]; + + return 0; +} + +Bitmap::Bitmap() { + _x = 0; + _y = 0; + _width = 0; + _height = 0; + _pixels = 0; + _type = 0; + _dataSize = 0; + _flags = 0; + _surface = 0; + _flipping = Graphics::FLIP_NONE; +} + +Bitmap::Bitmap(Bitmap *src) { + _x = src->_x; + _y = src->_y; + _flags = src->_flags; + _dataSize = src->_dataSize; + _type = src->_type; + _width = src->_width; + _height = src->_height; + _pixels = src->_pixels; + _surface = new Graphics::TransparentSurface(*src->_surface); + _flipping = src->_flipping; +} + +Bitmap::~Bitmap() { + if (_pixels) + free(_pixels); + + delete _surface; + + _pixels = 0; +} + +void Bitmap::load(Common::ReadStream *s) { + debug(5, "Bitmap::load()"); + + _x = s->readUint32LE(); + _y = s->readUint32LE(); + _width = s->readUint32LE(); + _height = s->readUint32LE(); + s->readUint32LE(); // pixels + _type = s->readUint32LE(); + _dataSize = s->readUint32LE(); + _flags = s->readUint32LE(); + + debug(8, "Bitmap: x: %d y: %d w: %d h: %d dataSize: 0x%x", _x, _y, _width, _height, _dataSize); + debug(8, "Bitmap: type: %s (0x%04x) flags: 0x%x", Common::tag2string(_type).c_str(), _type, _flags); +} + +bool Bitmap::isPixelHitAtPos(int x, int y) { + if (x < _x || x >= _width + _x || y < _y || y >= _y + _height) + return false; + + if (!_surface) + return false; + + return ((*((int32 *)_surface->getBasePtr(x, y)) & 0xff000000) != 0); +} + +void Bitmap::decode(int32 *palette) { + _surface = new Graphics::TransparentSurface; + + _surface->create(_width, _height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); + + if (_type == MKTAG('R', 'B', '\0', '\0')) + putDibRB(palette); + else + putDibCB(palette); +} + +void Bitmap::putDib(int x, int y, int32 *palette, int alpha) { + debug(7, "Bitmap::putDib(%d, %d)", x, y); + + int x1 = x - g_fp->_sceneRect.left; + int y1 = y - g_fp->_sceneRect.top; + + if (!_width || !_height || !_surface) + return; + + Common::Rect sub(0, 0, _width, _height); + + if (x1 < 0) { + sub.left = -x1; + x1 = 0; + } + + if (y1 < 0) { + sub.top = -y1; + y1 = 0; + } + + if (x1 + sub.width() > 799) + sub.right -= x1 + sub.width() - 799; + + if (y1 + sub.height() > 599) + sub.bottom -= y1 + sub.height() - 599; + + if (sub.width() <= 0 || sub.height() <= 0) + return; + + int alphac = TS_ARGB(0xff, alpha, 0xff, 0xff); + + _surface->blit(g_fp->_backgroundSurface, x1, y1, _flipping, &sub, alphac); + g_fp->_system->copyRectToScreen(g_fp->_backgroundSurface.getBasePtr(x1, y1), g_fp->_backgroundSurface.pitch, x1, y1, sub.width(), sub.height()); +} + +bool Bitmap::putDibRB(int32 *palette) { + uint32 *curDestPtr; + int endy; + int x; + int start1; + int fillLen; + uint16 pixel; + int y; + uint16 *srcPtr2; + uint16 *srcPtr; + + if (!palette) { + debug(2, "Bitmap::putDibRB(): Both global and local palettes are empty"); + return false; + } + + debug(8, "Bitmap::putDibRB()"); + + endy = _height - 1; + + int startx = 0; + int starty = 0; + + y = endy; + + srcPtr = (uint16 *)_pixels; + + bool breakup = false; + for (y = endy; y >= starty && !breakup; y--) { + x = startx; + + while ((pixel = *srcPtr++) != 0) { + if (pixel == 0x100) { + breakup = true; + break; + } + + while (pixel == 0x200 && y >= starty) { + uint16 value = *srcPtr++; + + x += (byte)(value & 0xff); + y -= (byte)((value >> 8) & 0xff); + + pixel = *srcPtr++; + } + + if (y < starty || pixel == 0) + break; + + start1 = x; + fillLen = (byte)(pixel & 0xff); + + if (fillLen) { + x += fillLen; + + if (start1 < 0) { + fillLen += start1; + + if (fillLen > 0) + start1 = 0; + } + + if (fillLen > 0 || start1 >= 0) { + if (x <= 799 + 1 || (fillLen += 799 - x + 1, fillLen > 0)) { + if (y <= endy) { + int bgcolor = palette[(pixel >> 8) & 0xff]; + curDestPtr = (uint32 *)_surface->getBasePtr(start1, y); + colorFill(curDestPtr, fillLen, bgcolor); + } + } + } + } else { + fillLen = (pixel >> 8) & 0xff; + srcPtr2 = srcPtr; + x += fillLen; + srcPtr += (fillLen + 1) >> 1; + + if (start1 < 0) { + fillLen += start1; + if (fillLen > 0) { + srcPtr2 = (uint16 *)((byte *)srcPtr2 - start1); + start1 = 0; + } + } + + if (x > 799 + 1) { + fillLen += 799 - x + 1; + if (fillLen <= 0) + continue; + } + + if (y <= endy) { + curDestPtr = (uint32 *)_surface->getBasePtr(start1, y); + paletteFill(curDestPtr, (byte *)srcPtr2, fillLen, (int32 *)palette); + } + } + } + } + + return false; +} + +void Bitmap::putDibCB(int32 *palette) { + uint32 *curDestPtr; + int endx; + int endy; + int bpp; + uint pitch; + bool cb05_format; + + endx = _width - 1; + endy = _height - 1; + + cb05_format = (_type == MKTAG('C', 'B', '\05', 'e')); + + if (!palette && !cb05_format) + error("Bitmap::putDibCB(): Both global and local palettes are empty"); + + bpp = cb05_format ? 2 : 1; + pitch = (bpp * _width + 3) & 0xFFFFFFFC; + + byte *srcPtr = &_pixels[pitch * endy]; + + if (endy < _height) + srcPtr = &_pixels[pitch * (_height - 1)]; + + int starty = 0; + int startx = 0; + + if (_flags & 0x1000000) { + for (int y = starty; y <= endy; srcPtr -= pitch, y++) { + curDestPtr = (uint32 *)_surface->getBasePtr(startx, y); + copierKeyColor(curDestPtr, srcPtr, endx - startx + 1, _flags & 0xff, (int32 *)palette, cb05_format); + } + } else { + for (int y = starty; y <= endy; srcPtr -= pitch, y++) { + curDestPtr = (uint32 *)_surface->getBasePtr(startx, y); + copier(curDestPtr, srcPtr, endx - startx + 1, (int32 *)palette, cb05_format); + } + } +} + +void Bitmap::colorFill(uint32 *dest, int len, int32 color) { +#if 0 + if (blendMode) { + if (blendMode != 1) + error("vrtPutDib : RLE Fill : Invalid alpha blend mode"); + + colorFill = ptralphaFillColor16bit; + } else { + colorFill = ptrfillColor16bit; + } +#endif + byte r, g, b; + + g_fp->_origFormat->colorToRGB(color, r, g, b); + + uint32 c = TS_ARGB(0xff, r, g, b); + + for (int i = 0; i < len; i++) + *dest++ = c; +} + +void Bitmap::paletteFill(uint32 *dest, byte *src, int len, int32 *palette) { +#if 0 + if (blendMode) { + if (blendMode != 1) + error("vrtPutDib : RLE Fill : Invalid alpha blend mode"); + + paletteFill = ptrcopierWithPaletteAlpha; + } else { + paletteFill = ptrcopierWithPalette; + } +#endif + + byte r, g, b; + + for (int i = 0; i < len; i++) { + g_fp->_origFormat->colorToRGB(READ_LE_UINT32(&palette[*src++]) & 0xffff, r, g, b); + + *dest++ = TS_ARGB(0xff, r, g, b); + } +} + +void Bitmap::copierKeyColor(uint32 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format) { +#if 0 + if (blendMode) { + if (blendMode == 1) { + if (cb05_format) + copierKeyColor = ptrcopier16bitKeycolorAlpha; + else + copierKeyColor = ptrcopierKeycolorAlpha; + } else { + copier = 0; + } + } else if (cb05_format) { + copierKeyColor = ptrcopier16bitKeycolor; + } else { + copierKeyColor = ptrkeyColor16bit; + } +#endif + + byte r, g, b; + + if (!cb05_format) { + for (int i = 0; i < len; i++) { + if (*src != keyColor) { + g_fp->_origFormat->colorToRGB(READ_LE_UINT32(&palette[*src]) & 0xffff, r, g, b); + *dest = TS_ARGB(0xff, r, g, b); + } + + dest++; + src++; + } + } else { + int16 *src16 = (int16 *)src; + + for (int i = 0; i < len; i++) { + if (*src16 != 0) { + g_fp->_origFormat->colorToRGB(READ_LE_UINT16(src16) & 0xffff, r, g, b); + *dest = TS_ARGB(0xff, r, g, b); + } + + dest++; + src16++; + } + } +} + +void Bitmap::copier(uint32 *dest, byte *src, int len, int32 *palette, bool cb05_format) { +#if 0 + if (blendMode) { + if (blendMode == 1) { + if (cb05_format) + copier = ptrcopier16bitAlpha; + else + copier = ptrcopierWithPaletteAlpha; + } else { + copier = 0; + } + } else if (cb05_format) { + copier = ptrcopier16bit; + } else { + copier = ptrcopierWithPalette; + } +#endif + + byte r, g, b; + + if (!cb05_format) { + for (int i = 0; i < len; i++) { + g_fp->_origFormat->colorToRGB(READ_LE_UINT32(&palette[*src++]) & 0xffff, r, g, b); + + *dest++ = TS_ARGB(0xff, r, g, b); + } + } else { + int16 *src16 = (int16 *)src; + + for (int i = 0; i < len; i++) { + g_fp->_origFormat->colorToRGB(READ_LE_UINT32(src16++) & 0xffff, r, g, b); + *dest++ = TS_ARGB(0xff, r, g, b); + } + } +} + +Bitmap *Bitmap::reverseImage(bool flip) { + if (flip) + _flipping = Graphics::FLIP_H; + else + _flipping = Graphics::FLIP_NONE; + + return this; +} + +Bitmap *Bitmap::flipVertical() { + _flipping = Graphics::FLIP_V; + + return this; +} + +void Bitmap::drawShaded(int type, int x, int y, byte *palette, int alpha) { + warning("STUB: Bitmap::drawShaded(%d, %d, %d)", type, x, y); + + putDib(x, y, (int32 *)palette, alpha); +} + +void Bitmap::drawRotated(int x, int y, int angle, byte *palette, int alpha) { + warning("STUB: Bitmap::drawShaded(%d, %d, %d)", x, y, angle); + + putDib(x, y, (int32 *)palette, alpha); +} + +bool BigPicture::load(MfcArchive &file) { + debug(5, "BigPicture::load()"); + Picture::load(file); + + return true; +} + +void BigPicture::draw(int x, int y, int style, int angle) { + if (!_bitmap) + init(); + + if (_bitmap) { + _bitmap->_flags &= 0xFEFFFFFF; + + int nx = _x; + int ny = _y; + + if (x != -1) + nx = x; + + if (y != -1) + ny = y; + + if (_alpha < 0xFF) { + //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, v9); + } + + _bitmap->putDib(nx, ny, 0, 0xff); + + if (_alpha < 0xFF) { + //vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); + } + } +} + +Shadows::Shadows() { + _staticAniObjectId = 0; + _movementId = 0; + _sceneId = 0; +} + +bool Shadows::load(MfcArchive &file) { + debug(5, "Shadows::load()"); + _sceneId = file.readUint32LE(); + _staticAniObjectId = file.readUint32LE(); + _movementId = file.readUint32LE(); + + return true; +} + +void Shadows::init() { + Scene *scene = g_fp->accessScene(_sceneId); + + StaticANIObject *st; + Movement *mov; + + if (scene && (st = scene->getStaticANIObject1ById(_staticAniObjectId, -1)) != 0 + && ((mov = st->getMovementById(_movementId)) != 0)) + initMovement(mov); +} + +void Shadows::initMovement(Movement *mov) { + uint num; + + if (mov->_currMovement) + num = mov->_currMovement->_dynamicPhases.size(); + else + num = mov->_dynamicPhases.size(); + + _items.clear(); + _items.resize(num); + + Common::Point point; + + _items[0].dynPhase = (DynamicPhase *)mov->_staticsObj1; + _items[0].dynPhase->getDimensions(&point); + _items[0].width = point.x; + _items[0].height = point.y; + + for (uint i = 1; i < num; i++) { + _items[i].dynPhase = mov->getDynamicPhaseByIndex(i - 1); + _items[i].dynPhase->getDimensions(&point); + _items[i].width = point.x; + _items[i].height = point.y; + } +} + +DynamicPhase *Shadows::findSize(int width, int height) { + int idx = 0; + int min = 1000; + + if (!_items.size()) + return 0; + + for (uint i = 0; i < _items.size(); i++) { + int w = abs(width - _items[i].width); + if (w < min) { + min = w; + idx = i; + } + } + return _items[idx].dynPhase; +} + +void FullpipeEngine::drawAlphaRectangle(int x1, int y1, int x2, int y2, int alpha) { + warning("STUB: FullpipeEngine::drawAlphaRectangle()"); +} + +void FullpipeEngine::sceneFade(Scene *sc, bool direction) { + warning("STUB: FullpipeEngine::sceneFade()"); + +#if 0 + for (int dim = 0; dim < 255; dim += 20) { + v5 = GetTickCount(); + vrtSetAlphaBlendMode(*(_DWORD *)virt, 0, 255); + sc->draw(); + drawAlphaRectangle(0, 0, 800, 600, direction ? 255 - dim : dim); + vrtFlush(*(_DWORD *)virt); + v7 = GetTickCount(); + if ( v7 - v5 < 42 ) + Sleep(v5 - v7 + 42); + } + vrtSetAlphaBlendMode(*(_DWORD *)virt, 0, 255); +#endif + +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/gfx.h b/engines/fullpipe/gfx.h new file mode 100644 index 0000000000..d94dd40452 --- /dev/null +++ b/engines/fullpipe/gfx.h @@ -0,0 +1,227 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_GFX_H +#define FULLPIPE_GFX_H + +namespace Fullpipe { + +class DynamicPhase; +class Movement; +struct PicAniInfo; + +struct Bitmap { + int _x; + int _y; + int _width; + int _height; + byte *_pixels; + int _type; + int _dataSize; + int _flags; + Graphics::TransparentSurface *_surface; + int _flipping; + + Bitmap(); + Bitmap(Bitmap *src); + ~Bitmap(); + + void load(Common::ReadStream *s); + void decode(int32 *palette); + void putDib(int x, int y, int32 *palette, int alpha); + bool putDibRB(int32 *palette); + void putDibCB(int32 *palette); + + void colorFill(uint32 *dest, int len, int32 color); + void paletteFill(uint32 *dest, byte *src, int len, int32 *palette); + void copierKeyColor(uint32 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format); + void copier(uint32 *dest, byte *src, int len, int32 *palette, bool cb05_format); + + Bitmap *reverseImage(bool flip = true); + Bitmap *flipVertical(); + + void drawShaded(int type, int x, int y, byte *palette, int alpha); + void drawRotated(int x, int y, int angle, byte *palette, int alpha); + + bool isPixelHitAtPos(int x, int y); +}; + +class Picture : public MemoryObject { + public: + Common::Rect _rect; + Bitmap *_convertedBitmap; + int _x; + int _y; + int _field_44; + int _width; + int _height; + Bitmap *_bitmap; + int _field_54; + MemoryObject2 *_memoryObject2; + int _alpha; + byte *_paletteData; + + void displayPicture(); + + public: + Picture(); + virtual ~Picture(); + + void freePicture(); + void freePixelData(); + + virtual bool load(MfcArchive &file); + void setAOIDs(); + virtual void init(); + void getDibInfo(); + Bitmap *getPixelData(); + virtual void draw(int x, int y, int style, int angle); + void drawRotated(int x, int y, int angle); + + byte getAlpha() { return (byte)_alpha; } + void setAlpha(byte alpha) { _alpha = alpha; } + + Common::Point *getDimensions(Common::Point *p); + bool isPointInside(int x, int y); + bool isPixelHitAtPos(int x, int y); + int getPixelAtPos(int x, int y); + int getPixelAtPosEx(int x, int y); + + byte *getPaletteData() { return _paletteData; } + void setPaletteData(byte *pal); + + void copyMemoryObject2(Picture *src); +}; + +class BigPicture : public Picture { + public: + BigPicture() {} + virtual ~BigPicture() {} + + virtual bool load(MfcArchive &file); + virtual void draw(int x, int y, int style, int angle); +}; + +class GameObject : public CObject { + public: + int16 _okeyCode; + int _field_8; + int16 _flags; + int16 _id; + char *_objectName; + int _ox; + int _oy; + int _priority; + int _field_20; + + public: + GameObject(); + GameObject(GameObject *src); + ~GameObject(); + + virtual bool load(MfcArchive &file); + void setOXY(int x, int y); + void renumPictures(Common::Array<StaticANIObject *> *lst); + void renumPictures(Common::Array<PictureObject *> *lst); + void setFlags(int16 flags) { _flags = flags; } + void clearFlags() { _flags = 0; } + const char *getName() { return _objectName; } + + bool getPicAniInfo(PicAniInfo *info); + bool setPicAniInfo(PicAniInfo *info); +}; + +class PictureObject : public GameObject { + public: + Picture *_picture; + Common::Array<GameObject *> *_pictureObject2List; + int _ox2; + int _oy2; + + public: + PictureObject(); + + PictureObject(PictureObject *src); + virtual ~PictureObject(); + + virtual bool load(MfcArchive &file, bool bigPicture); + virtual bool load(MfcArchive &file) { assert(0); return false; } // Disable base class + + Common::Point *getDimensions(Common::Point *p); + void draw(); + void drawAt(int x, int y); + + bool setPicAniInfo(PicAniInfo *picAniInfo); + bool isPointInside(int x, int y); + bool isPixelHitAtPos(int x, int y); + void setOXY2(); +}; + +class Background : public CObject { + public: + Common::Array<PictureObject *> _picObjList; + + char *_bgname; + int _x; + int _y; + int16 _messageQueueId; + MemoryObject *_palette; + int _bigPictureArray1Count; + int _bigPictureArray2Count; + BigPicture ***_bigPictureArray; + + public: + Background(); + virtual ~Background(); + + virtual bool load(MfcArchive &file); + void addPictureObject(PictureObject *pct); + + BigPicture *getBigPicture(int x, int y) { return _bigPictureArray[x][y]; } +}; + +struct ShadowsItem { + int width; + int height; + DynamicPhase *dynPhase; +}; + +typedef Common::Array<ShadowsItem> ShadowsItemArray; + +class Shadows : public CObject { + int _sceneId; + int _staticAniObjectId; + int _movementId; + ShadowsItemArray _items; + + public: + Shadows(); + virtual bool load(MfcArchive &file); + void init(); + + void initMovement(Movement *mov); + DynamicPhase *findSize(int width, int height); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_GFX_H */ diff --git a/engines/fullpipe/init.cpp b/engines/fullpipe/init.cpp new file mode 100644 index 0000000000..9602803010 --- /dev/null +++ b/engines/fullpipe/init.cpp @@ -0,0 +1,247 @@ +/* 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/gameloader.h" +#include "fullpipe/objectnames.h" +#include "fullpipe/input.h" + +#include "fullpipe/constants.h" + +namespace Fullpipe { + +void FullpipeEngine::initObjectStates() { + setLevelStates(); + + setObjectState(sO_Dude, getObjectEnumState(sO_Dude, sO_NotCarryingEgg)); + setObjectState(sO_EggCracker, getObjectEnumState(sO_EggCracker, sO_DidNotCrackEgg)); + setObjectState(sO_GuvTheDrawer, getObjectEnumState(sO_GuvTheDrawer, sO_Awaken)); + setObjectState(sO_EggGulper, getObjectEnumState(sO_EggGulper, sO_First)); + setObjectState(sO_EggGulperGaveCoin, getObjectEnumState(sO_EggGulperGaveCoin, sO_No)); + setObjectState(sO_Jar_4, getObjectEnumState(sO_Jar_4, sO_OnTheSpring)); + setObjectState(sO_GulpedEggs, getObjectEnumState(sO_GulpedEgg, sO_NotPresent)); + + setSwallowedEggsState(); + + setObjectState(sO_WeirdWacko, getObjectEnumState(sO_WeirdWacko, sO_InGlasses)); + setObjectState(sO_TummyTrampie, getObjectEnumState(sO_TummyTrampie, sO_IsDrinking)); + setObjectState(sO_StairsUp_8, getObjectEnumState(sO_StairsUp_8, sO_NotBroken)); + setObjectState(sO_HareTheNooksiter, getObjectEnumState(sO_HareTheNooksiter, sO_WithHandle)); + setObjectState(sO_Elephantine, getObjectEnumState(sO_Elephantine, sO_WithBoot)); + setObjectState(sO_Fly_12, 0); + setObjectState(sO_ClockAxis, getObjectEnumState(sO_ClockAxis, sO_IsNotAvailable)); + setObjectState(sO_ClockHandle, getObjectEnumState(sO_ClockHandle, sO_In_7)); + setObjectState(sO_BigMumsy, getObjectEnumState(sO_BigMumsy, sO_IsSleeping)); + setObjectState(sO_CoinSlot_1, getObjectEnumState(sO_CoinSlot_1, sO_Empty)); + setObjectState(sO_FriesPit, getObjectEnumState(sO_FriesPit, sO_WithApple)); + setObjectState(sO_Jug, getObjectEnumState(sO_Jug, sO_Blocked)); + setObjectState(sO_RightStairs_9, getObjectEnumState(sO_RightStairs_9, sO_IsClosed)); + setObjectState(sO_Pipe_9, getObjectEnumState(sO_Pipe_9, sO_WithJug)); + setObjectState(sO_Inflater, getObjectEnumState(sO_Inflater, sO_WithGum)); + setObjectState(sO_Swingie, getObjectEnumState(sO_Swingie, sO_IsSwinging)); + setObjectState(sO_DudeHasJumped, getObjectEnumState(sO_DudeHasJumped, sO_No)); + setObjectState(sO_Bridge, getObjectEnumState(sO_Bridge, sO_Convoluted)); + setObjectState(sO_Guardian, getObjectEnumState(sO_Guardian, sO_OnRight)); + setObjectState(sO_Grandma, getObjectEnumState(sO_Grandma, sO_In_14)); + setObjectState(sO_Boot_15, getObjectEnumState(sO_Boot_15, sO_NotPresent)); + setObjectState(sO_LeftPipe_15, getObjectEnumState(sO_LeftPipe_15, sO_IsOpened)); + setObjectState(sO_Pedestal_16, getObjectEnumState(sO_Pedestal_16, sO_IsFree)); + setObjectState(sO_Cup, getObjectEnumState(sO_Cup, sO_InSmokeRoom)); + setObjectState(sO_Pedestal_17, getObjectEnumState(sO_Pedestal_17, sO_IsFree)); + setObjectState(sO_UsherHand, getObjectEnumState(sO_UsherHand, sO_WithoutCoin)); + setObjectState(sO_RightPipe_17, getObjectEnumState(sO_RightPipe_17, sO_IsClosed)); + setObjectState(sO_Fly_17, 1); + setObjectState(sO_DudeSwinged, 0); + setObjectState(sO_Girl, getObjectEnumState(sO_Girl, sO_IsSwinging)); + setObjectState(sO_Sugar, getObjectEnumState(sO_Sugar, sO_Present)); + setObjectState(sO_Janitors, getObjectEnumState(sO_Janitors, sO_Together)); + setObjectState(sO_Bag_22, getObjectEnumState(sO_Bag_22, sO_NotFallen)); + setObjectState(sO_Grandpa, getObjectEnumState(sO_Grandpa, sO_InSock)); + setObjectState(sO_CoinSlot_22, getObjectEnumState(sO_CoinSlot_22, sO_Empty)); + setObjectState(sO_UpperHatch_23, getObjectEnumState(sO_UpperHatch_23, sO_Closed)); + setObjectState(sO_LowerHatch_23, getObjectEnumState(sO_LowerHatch_23, sO_Closed)); + setObjectState(sO_Lever_23, getObjectEnumState(sO_Lever_23, sO_NotTaken)); + setObjectState(sO_LeverHandle_23, getObjectEnumState(sO_LeverHandle_23, sO_WithoutStool)); + setObjectState(sO_LowerPipe_21, getObjectEnumState(sO_LowerPipe_21, sO_IsClosed)); + setObjectState(sO_StairsDown_24, getObjectEnumState(sO_StairsDown_24, sO_IsOpened)); + setObjectState(sO_Hatch_26, getObjectEnumState(sO_Hatch_26, sO_Closed)); + setObjectState(sO_Sock_26, getObjectEnumState(sO_Sock_26, sO_NotHanging)); + setObjectState(sO_LeftPipe_26, getObjectEnumState(sO_LeftPipe_26, sO_IsClosed)); + setObjectState(sO_Valve1_26, getObjectEnumState(sO_Valve1_26, sO_Opened)); + setObjectState(sO_Valve2_26, getObjectEnumState(sO_Valve2_26, sO_Closed)); + setObjectState(sO_Valve3_26, getObjectEnumState(sO_Valve3_26, sO_Closed)); + setObjectState(sO_Valve4_26, getObjectEnumState(sO_Valve4_26, sO_Closed)); + setObjectState(sO_Valve5_26, getObjectEnumState(sO_Valve5_26, sO_Opened)); + setObjectState(sO_Pool, getObjectEnumState(sO_Pool, sO_Overfull)); + setObjectState(sO_Board_25, getObjectEnumState(sO_Board_25, sO_NearDudesStairs)); + setObjectState(sO_Driver, getObjectEnumState(sO_Driver, sO_WithSteering)); + setObjectState(sO_Maid, getObjectEnumState(sO_Maid, sO_WithSwab)); + setObjectState(sO_LeftPipe_29, getObjectEnumState(sO_LeftPipe_29, sO_IsClosed)); + setObjectState(sO_LeftPipe_30, getObjectEnumState(sO_LeftPipe_30, sO_IsClosed)); + setObjectState(sO_Leg, getObjectEnumState(sO_Leg, sO_ShowingHeel)); + setObjectState(sO_Tub, getObjectEnumState(sO_Tub, sO_EmptyShe)); + setObjectState(sO_Cactus, getObjectEnumState(sO_Cactus, sO_NotGrown)); + setObjectState(sO_Fireman, getObjectEnumState(sO_Fireman, sO_WithHose)); + setObjectState(sO_Cube, getObjectEnumState(sO_Cube, sO_In_33)); + setObjectState(sO_MommyOfHandle_32, getObjectEnumState(sO_MommyOfHandle_32, sO_WithoutHandle)); + setObjectState(sO_Pedestal_33, getObjectEnumState(sO_Pedestal_33, sO_IsFree)); + setObjectState(sO_Valve_34, getObjectEnumState(sO_Valve_34, sO_WithNothing)); + setObjectState(sO_Stool_34, getObjectEnumState(sO_Stool_34, sO_WithoutDrawer)); + setObjectState(sO_Plank_34, getObjectEnumState(sO_Plank_34, sO_Passive)); + setObjectState(sO_Hatch_34, getObjectEnumState(sO_Hatch_34, sO_Closed)); + setObjectState(sO_Valve_35, getObjectEnumState(sO_Valve_35, sO_TurnedOff)); + setObjectState(sO_Carpet_35, getObjectEnumState(sO_Carpet_35, sO_CannotTake)); + setObjectState(sO_CoinSlot_35, getObjectEnumState(sO_CoinSlot_35, sO_WithCoin)); + setObjectState(sO_BellyInflater, getObjectEnumState(sO_BellyInflater, sO_WithCork)); + setObjectState(sO_Jawcrucnher, getObjectEnumState(sO_Jawcrucnher, sO_WithoutCarpet)); + setObjectState(sO_Guard_1, getObjectEnumState(sO_Guard_1, sO_On)); + setObjectState(sO_Guard_2, getObjectEnumState(sO_Guard_2, sO_On)); + setObjectState(sO_Guard_3, getObjectEnumState(sO_Guard_3, sO_On)); + setObjectState(sO_Bottle_38, getObjectEnumState(sO_Bottle_38, sO_OnTheTable)); + setObjectState(sO_Boss, getObjectEnumState(sO_Boss, sO_WithHammer)); +} + +void FullpipeEngine::setLevelStates() { + GameVar *v = _gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons); + + if (v) { + v->setSubVarAsInt(sO_Level0, 2833); + v->setSubVarAsInt(sO_Level1, 2754); + v->setSubVarAsInt(sO_Level2, 2757); + v->setSubVarAsInt(sO_Level3, 2760); + v->setSubVarAsInt(sO_Level4, 2763); + v->setSubVarAsInt(sO_Level5, 2766); + v->setSubVarAsInt(sO_Level6, 2769); + v->setSubVarAsInt(sO_Level7, 2772); + v->setSubVarAsInt(sO_Level8, 2775); + v->setSubVarAsInt(sO_Level9, 2778); + } +} + +void FullpipeEngine::addCursor(CursorInfo *cursorInfo, Scene *inv, int pictureId, int hotspotX, int hotspotY, int itemPictureOffsX, int itemPictureOffsY) { + cursorInfo->pictureId = pictureId; + cursorInfo->picture = inv->getPictureObjectById(pictureId, 0)->_picture; + cursorInfo->hotspotX = hotspotX; + cursorInfo->hotspotY = hotspotY; + cursorInfo->itemPictureOffsX = itemPictureOffsX; + cursorInfo->itemPictureOffsY = itemPictureOffsY; + + getGameLoaderInputController()->addCursor(cursorInfo); +} + +void FullpipeEngine::initCursors() { + CursorInfo crs; + Scene *inv = accessScene(SC_INV); + + addCursor(&crs, inv, PIC_CSR_DEFAULT, 15, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_DEFAULT_INV, 18, 18, 23, 23); + addCursor(&crs, inv, PIC_CSR_ITN, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ITN_RED, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ITN_GREEN, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ITN_INV, 23, 17, 23, 17); + addCursor(&crs, inv, PIC_CSR_GOU, 15, 17, 10, 10); + addCursor(&crs, inv, PIC_CSR_GOD, 15, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_GOL, 26, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_GOR, 15, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_GOFAR_L, 1, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_GOFAR_R, 39, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE1, 12, 24, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE2, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE2_D, 22, 15, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE3, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE4, 18, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE5, 23, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE6, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE6_D, 0, 0, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE7, 21, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE7_D, 7, 20, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE8, 23, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_LIFT, 6, 13, 10, 10); + + getGameLoaderInputController()->setCursorMode(0); +} + +void FullpipeEngine::initMap() { + memset(_mapTable, 0, sizeof(_mapTable)); + + updateMapPiece(PIC_MAP_S01, 1); + updateMapPiece(PIC_MAP_A13, 1u); +} + +void FullpipeEngine::loadAllScenes() { + accessScene(301); + accessScene(302); + accessScene(303); + accessScene(304); + accessScene(305); + accessScene(321); + accessScene(635); + accessScene(649); + accessScene(650); + accessScene(651); + accessScene(652); + accessScene(653); + accessScene(654); + accessScene(655); + accessScene(726); + accessScene(858); + accessScene(903); + accessScene(1137); + accessScene(1138); + accessScene(1139); + accessScene(1140); + accessScene(1141); + accessScene(1142); + accessScene(1143); + accessScene(1144); + accessScene(1546); + accessScene(1547); + accessScene(1548); + accessScene(1549); + accessScene(1550); + accessScene(1551); + accessScene(1552); + accessScene(2062); + accessScene(2063); + accessScene(2064); + accessScene(2065); + accessScene(2066); + accessScene(2067); + accessScene(2068); + accessScene(2069); + accessScene(2070); + accessScene(2071); + accessScene(2072); + accessScene(2460); + accessScene(3896); + accessScene(3907); + accessScene(4620); + accessScene(4999); + accessScene(5000); + accessScene(5001); + accessScene(5166); + accessScene(5222); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/input.cpp b/engines/fullpipe/input.cpp new file mode 100644 index 0000000000..b681f4fbe7 --- /dev/null +++ b/engines/fullpipe/input.cpp @@ -0,0 +1,376 @@ +/* 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/input.h" +#include "fullpipe/gfx.h" +#include "fullpipe/scene.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/statics.h" +#include "fullpipe/interaction.h" +#include "fullpipe/constants.h" + +namespace Fullpipe { + +InputController::InputController() { + g_fp->_inputController = this; + + _flag = 0; + _cursorHandle = 0; + _hCursor = 0; + _field_14 = 0; + _cursorId = 0; + _cursorIndex = -1; + _inputFlags = 1; + + _cursorBounds.left = 0; + _cursorBounds.top = 0; + _cursorBounds.right = 0; + _cursorBounds.bottom = 0; + + _cursorItemPicture = 0; +} + +InputController::~InputController() { + removeMessageHandler(126, -1); + + g_fp->_inputController = 0; +} + +void InputController::setInputDisabled(bool state) { + _flag = state; + g_fp->_inputDisabled = state; +} + +void setInputDisabled(bool state) { + g_fp->_inputController->setInputDisabled(state); +} + +void InputController::addCursor(CursorInfo *cursor) { + CursorInfo *newc = new CursorInfo(cursor); + Common::Point p; + + cursor->picture->getDimensions(&p); + + newc->width = p.x; + newc->height = p.y; + + newc->picture->_x = -1; + newc->picture->_y = -1; + + _cursorsArray.push_back(newc); +} + +void InputController::setCursorMode(bool enabled) { + if (enabled) + _inputFlags |= 1; + else + _inputFlags &= ~1; +} + +void InputController::drawCursor(int x, int y) { + if (_cursorIndex == -1) + return; + + _cursorBounds.left = g_fp->_sceneRect.left + x - _cursorsArray[_cursorIndex]->hotspotX; + _cursorBounds.top = g_fp->_sceneRect.top + y - _cursorsArray[_cursorIndex]->hotspotY; + _cursorBounds.right = _cursorBounds.left + _cursorsArray[_cursorIndex]->width; + _cursorBounds.bottom = _cursorBounds.top + _cursorsArray[_cursorIndex]->height; + + _cursorsArray[_cursorIndex]->picture->draw(_cursorBounds.left, _cursorBounds.top, 0, 0); + + if (_cursorItemPicture) + _cursorItemPicture->draw(_cursorBounds.left + _cursorsArray[_cursorIndex]->itemPictureOffsX, + _cursorBounds.top + _cursorsArray[_cursorIndex]->itemPictureOffsY, 0, 0); +} + +void InputController::setCursor(int cursorId) { + if (_cursorIndex == -1 || _cursorsArray[_cursorIndex]->pictureId != cursorId) { + _cursorIndex = -1; + + for (uint i = 0; i < _cursorsArray.size(); i++) { + if (_cursorsArray[i]->pictureId == cursorId) { + _cursorIndex = i; + break; + } + } + } +} + +CursorInfo::CursorInfo() { + pictureId = 0; + picture = 0; + hotspotX = 0; + hotspotY = 0; + itemPictureOffsX = 0; + itemPictureOffsY = 0; + width = 0; + height = 0; +} + +CursorInfo::CursorInfo(CursorInfo *src) { + pictureId = src->pictureId; + picture = src->picture; + hotspotX = src->hotspotX; + hotspotY = src->hotspotY; + itemPictureOffsX = src->itemPictureOffsX; + itemPictureOffsY = src->itemPictureOffsY; + width = src->width; + height = src->height; +} + +void FullpipeEngine::setCursor(int id) { + if (_inputController) + _inputController->setCursor(id); +} + +const char *input_cheats[] = { + "HELP", + "STUFF", + "FASTER", + "OHWAIT", + "MUSOFF", + "" +}; + +void FullpipeEngine::defHandleKeyDown(int key) { + if (_currentCheat == -1) { + for (int i = 0; input_cheats[i][0]; i++) + if (toupper(key) == input_cheats[i][0]) { + _currentCheat = i; + _currentCheatPos = 1; + } + + return; + } + + if (toupper(key) != input_cheats[_currentCheat][_currentCheatPos]) { + _currentCheat = -1; + + return; + } + + _currentCheatPos++; + + if (!input_cheats[_currentCheat][_currentCheatPos]) { + switch (_currentCheat) { + case 0: // HELP + winArcade(); + break; + case 1: // STUFF + getAllInventory(); + break; + case 2: // FASTER + _normalSpeed = !_normalSpeed; + break; + case 3: // OHWAIT + _gamePaused = 1; + _flgGameIsRunning = 0; + break; + case 4: // MUSOFF + if (_musicAllowed & 2) + setMusicAllowed(_musicAllowed & 0xFFFFFFFD); + else + setMusicAllowed(_musicAllowed | 2); + break; + default: + break; + } + + _currentCheatPos = 0; + _currentCheat = -1; + } +} + +void FullpipeEngine::winArcade() { + ExCommand *ex = new ExCommand(0, 17, MSG_CMN_WINARCADE, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + + ex->postMessage(); + +} + +void FullpipeEngine::updateCursorCommon() { + GameObject *ani = _currentScene->getStaticANIObjectAtPos(_mouseVirtX, _mouseVirtY); + + GameObject *pic = _currentScene->getPictureObjectAtPos(_mouseVirtX, _mouseVirtY); + if (!ani || (pic && pic->_priority < ani->_priority)) + ani = pic; + + int selId = getGameLoaderInventory()->getSelectedItemId(); + + _objectAtCursor = ani; + + if (ani) { + _objectIdAtCursor = ani->_id; + + if (!selId && ani->_id >= _minCursorId && ani->_id <= _maxCursorId) { + selId = _objectIdCursors[ani->_id - _minCursorId]; + if (selId) { + _cursorId = selId; + return; + } + } + if (canInteractAny(_aniMan, ani, selId)) { + _cursorId = selId > 0 ? PIC_CSR_ITN_INV : PIC_CSR_ITN; + return; + } + if (selId) { + _cursorId = PIC_CSR_DEFAULT_INV; + return; + } + if (_objectIdAtCursor == ANI_LIFTBUTTON && lift_getButtonIdP(((StaticANIObject *)ani)->_statics->_staticsId)) { + _cursorId = PIC_CSR_LIFT; + return; + } + if (_sceneRect.right - _mouseVirtX < 47 && _sceneRect.right < _sceneWidth - 1) { + _cursorId = PIC_CSR_GOFAR_R; + return; + } + if (_mouseVirtX - _sceneRect.left < 47 && _sceneRect.left > 0) { + _cursorId = PIC_CSR_GOFAR_L; + return; + } + _cursorId = PIC_CSR_DEFAULT; + return; + } else { + _objectIdAtCursor = 0; + + if (selId) { + _cursorId = PIC_CSR_DEFAULT_INV; + return; + } + if (_sceneRect.right - _mouseVirtX < 47 && _sceneRect.right < _sceneWidth - 1) { + _cursorId = PIC_CSR_GOFAR_R; + return; + } + if (_mouseVirtX - _sceneRect.left < 47 && _sceneRect.left > 0) { + _cursorId = PIC_CSR_GOFAR_L; + return; + } + } + + _cursorId = PIC_CSR_DEFAULT; +} + +void FullpipeEngine::initArcadeKeys(const char *varname) { + _arcadeKeys.clear(); + + GameVar *var = getGameLoaderGameVar()->getSubVarByName(varname)->getSubVarByName("KEYPOS"); + + if (!var) + return; + + int cnt = var->getSubVarsCount(); + + for (int i = 0; i < cnt; i++) { + Common::Point *point = new Common::Point; + + GameVar *sub = var->getSubVarByIndex(i); + + point->x = sub->getSubVarAsInt("X"); + point->y = sub->getSubVarAsInt("Y"); + + _arcadeKeys.push_back(point); + } +} + +void FullpipeEngine::processArcade(ExCommand *cmd) { + if (!g_fp->_aniMan2) + return; + + int idx; + + if (cmd->_sceneClickX <= g_fp->_aniMan2->_ox) { + for (idx = (int)_arcadeKeys.size() - 1; idx >= 0; idx--) { + if (_arcadeKeys[idx]->x < g_fp->_aniMan2->_ox) + break; + } + + if (idx < 0) + return; + } else { + for (idx = 0; idx < (int)_arcadeKeys.size(); idx++) { + if (_arcadeKeys[idx]->x > g_fp->_aniMan2->_ox) + break; + } + + if (idx >= (int)_arcadeKeys.size()) + return; + } + + cmd->_sceneClickX = _arcadeKeys[idx]->x; + cmd->_sceneClickY = _arcadeKeys[idx]->y; + + cmd->_x = cmd->_sceneClickX - g_fp->_sceneRect.left; + cmd->_y = cmd->_sceneClickY - g_fp->_sceneRect.top; +} + +void FullpipeEngine::setArcadeOverlay(int picId) { + Common::Point point; + Common::Point point2; + + _arcadeOverlayX = 800; + _arcadeOverlayY = 545; + + _arcadeOverlayHelper = accessScene(SC_INV)->getPictureObjectById(PIC_CSR_HELPERBGR, 0); + _arcadeOverlay = accessScene(SC_INV)->getPictureObjectById(picId, 0); + + _arcadeOverlay->getDimensions(&point); + _arcadeOverlayHelper->getDimensions(&point2); + + _arcadeOverlayMidX = (point2.x - point.x) / 2; + _arcadeOverlayMidY = abs(point2.y - point.y) / 2; +} + +int FullpipeEngine::drawArcadeOverlay(int adjust) { + _arcadeOverlayHelper->drawAt(_sceneRect.left + _arcadeOverlayX, _sceneRect.top + _arcadeOverlayY); + _arcadeOverlay->drawAt(_sceneRect.left + _arcadeOverlayX + _arcadeOverlayMidX, _sceneRect.top + _arcadeOverlayY + _arcadeOverlayMidY); + + if (adjust) { + if (_arcadeOverlayX > 745) { + _arcadeOverlayX -= 15; + + if (_arcadeOverlayX < 745) + _arcadeOverlayX = 745; + } + + return 1; + } + + if (_arcadeOverlayX >= 800) { + return 0; + } else { + _arcadeOverlayX += 15; + + if (_arcadeOverlayX <= 800) + return 1; + + _arcadeOverlayX = 800; + } + + return 1; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/input.h b/engines/fullpipe/input.h new file mode 100644 index 0000000000..6a1d0f8b07 --- /dev/null +++ b/engines/fullpipe/input.h @@ -0,0 +1,77 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_INPUT_H +#define FULLPIPE_INPUT_H + +namespace Fullpipe { + +class Picture; + +void setInputDisabled(bool state); + +struct CursorInfo { + int pictureId; + Picture *picture; + int hotspotX; + int hotspotY; + int itemPictureOffsX; + int itemPictureOffsY; + int width; + int height; + + CursorInfo(); + CursorInfo(CursorInfo *src); +}; + +typedef Common::Array<CursorInfo *> CursorsArray; + +class InputController { + //CObject obj; + int _flag; + int _inputFlags; + int _cursorHandle; + int _hCursor; + int _field_14; + int _cursorId; + int _cursorIndex; + CursorsArray _cursorsArray; + Common::Rect _cursorBounds; + Picture *_cursorItemPicture; + + public: + InputController(); + ~InputController(); + + void setInputDisabled(bool state); + void addCursor(CursorInfo *cursor); + void setCursorMode(bool mode); + + void drawCursor(int x, int y); + void setCursor(int id); + + void setCursorItemPicture(Picture *pic) { _cursorItemPicture = pic; } +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_INPUT_H */ diff --git a/engines/fullpipe/interaction.cpp b/engines/fullpipe/interaction.cpp new file mode 100644 index 0000000000..4aac3485f4 --- /dev/null +++ b/engines/fullpipe/interaction.cpp @@ -0,0 +1,545 @@ +/* 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/interaction.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/statics.h" +#include "fullpipe/motion.h" + +namespace Fullpipe { + +int handleObjectInteraction(StaticANIObject *subject, GameObject *object, int invId) { + return getGameLoaderInteractionController()->handleInteraction(subject, object, invId); +} + +bool canInteractAny(GameObject *obj1, GameObject *obj2, int invId) { + int sceneId = 0; + + if (g_fp->_currentScene) + sceneId = g_fp->_currentScene->_sceneId; + + InteractionController *intC = getGameLoaderInteractionController(); + for (ObList::iterator i = intC->_interactions.begin(); i != intC->_interactions.end(); ++i) { + Interaction *intr = (Interaction *)*i; + + if (intr->_sceneId > 0 && intr->_sceneId != sceneId) + break; + + if (invId == -3) { + invId = getGameLoaderInventory()->getSelectedItemId(); + } + if (intr->canInteract(obj1, obj2, invId)) + return true; + } + return false; +} + +InteractionController::~InteractionController() { + _interactions.clear(); + + removeMessageHandler(124, -1); +} + +bool InteractionController::load(MfcArchive &file) { + debug(5, "InteractionController::load()"); + + return _interactions.load(file); +} + +int static_compSceneId = 0; + +bool InteractionController::compareInteractions(const void *p1, const void *p2) { + const Interaction *i1 = (const Interaction *)p1; + const Interaction *i2 = (const Interaction *)p2; + + if (i2->_sceneId < i1->_sceneId) { + if (i1->_sceneId != static_compSceneId) + return false; + } + if (i2->_sceneId != i1->_sceneId) { + if (i1->_sceneId > 0 && i2->_sceneId == static_compSceneId) + return false; + if (i2->_sceneId != i1->_sceneId) + return true; + } + if (i2->_objectId3 == -1) + return true; + + if (i1->_objectId3 == i2->_objectId3) + return true; + + if (i1->_objectId3 == -1 || i1->_objectId3 == -2) + return false; + + return true; +} + +void InteractionController::sortInteractions(int sceneId) { + static_compSceneId = sceneId; + + Common::sort(_interactions.begin(), _interactions.end(), InteractionController::compareInteractions); +} + +bool InteractionController::handleInteraction(StaticANIObject *subj, GameObject *obj, int invId) { + if (subj) { + if (!subj->isIdle() || (subj->_flags & 0x100)) + return false; + } + + if (!_interactions.size()) + return false; + + Interaction *inter = 0; + Interaction *previnter = 0; + int dur = 0; + int mindur = 0xFFFF; + + MessageQueue *mq; + ExCommand *ex; + + for (ObList::iterator i = _interactions.begin(); i != _interactions.end(); ++i) { + Interaction *cinter = (Interaction *)*i; + + if (!cinter->canInteract(subj, obj, invId)) + continue; + + if ((inter || cinter->_objectId2) && (!obj || cinter->_objectId3 != obj->_id)) { + if (cinter->_messageQueue) + cinter->_messageQueue->calcDuration(subj); + + PicAniInfo aniInfo; + + obj->getPicAniInfo(&aniInfo); + + if (cinter->_staticsId1) { + StaticANIObject *ani = (StaticANIObject *)obj; + ani->_messageQueueId = 0; + ani->changeStatics2(cinter->_staticsId1); + } + int xpos = cinter->_xOffs + obj->_ox; + int ypos = cinter->_yOffs + obj->_oy; + + obj->setPicAniInfo(&aniInfo); + + if (abs(xpos - subj->_ox) > 1 || abs(ypos - subj->_oy) > 1) { + mq = getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->doWalkTo(subj, xpos, ypos, 1, cinter->_staticsId2); + if (mq) { + dur = mq->calcDuration(subj); + delete mq; + } else { + dur = 0x10000; + } + inter = previnter; + } else { + dur = 0; + } + if (dur < mindur) { + inter = cinter; + mindur = dur; + previnter = cinter; + } + } else { + inter = cinter; + break; + } + } + + if (!inter) + return false; + + if (!inter->_objectId2) { + StaticANIObject *ani = (StaticANIObject *)obj; + + if (!ani->isIdle()) + return false; + + if (ani->_flags & 0x100) + return false; + + if (!inter->_staticsId1 || !(inter->_flags & 1)) + goto LABEL_38; + + if (ani->_movement || ani->_statics == 0 || ani->_statics->_staticsId != inter->_staticsId1) { + mq = ani->changeStatics1(inter->_staticsId1); + if (!mq) + return false; + + ex = new ExCommand((subj ? subj->_id : 0), 55, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_x = obj->_id; + ex->_y = obj->_okeyCode; + ex->_keyCode = subj ? subj->_okeyCode : 0; + ex->_excFlags = 3; + ex->_field_14 = (obj->_objtype != kObjTypePictureObject); + ex->_field_20 = invId; + mq->addExCommandToEnd(ex); + + if (mq->_isFinished) { + mq->_isFinished = 0; + ani->queueMessageQueue(mq); + } + } else { + if (ani->getMessageQueue()) + ani->queueMessageQueue(0); +LABEL_38: + if (inter->_messageQueue) { + mq = new MessageQueue(inter->_messageQueue, 0, 1); + mq->changeParam28ForObjectId(ani->_id, -1, ani->_okeyCode); + + if (!mq->chain(0)) + return false; + } + } + return true; + } + + if (obj && !subj) + return true; + + if (!obj || inter->_objectId3 == obj->_id) { + if (subj) { + if (inter->_messageQueue) { + if (subj->isIdle()) { + mq = new MessageQueue(inter->_messageQueue, 0, 1); + + if (!mq->chain(subj)) { + delete mq; + + return false; + } + } + } + } + return true; + } + + if (inter->isOverlapping(subj, obj)) { + if (obj->_objtype == kObjTypeStaticANIObject) { + StaticANIObject *ani = (StaticANIObject *)obj; + + ani->queueMessageQueue(0); + + if (inter->_staticsId1) + ani->changeStatics2(inter->_staticsId1); + + if (!(inter->_flags & 0x10000)) + obj->_flags |= 0x80; + } + + if (!inter->_messageQueue) + return false; + + subj->setOXY(inter->_xOffs + obj->_ox, inter->_yOffs + obj->_oy); + + mq = new MessageQueue(inter->_messageQueue, 0, 1); + mq->changeParam28ForObjectId(obj->_id, -1, obj->_okeyCode); + mq->_flags |= 1; + + if (!(inter->_flags & 0x10000)) { + ex = new ExCommand(obj->_id, 34, 0x80, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = obj->_okeyCode; + ex->_field_14 = 0x100; + ex->_messageNum = 0; + ex->_excFlags = 3; + mq->addExCommandToEnd(ex); + } + + ex = new ExCommand(obj->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = obj->_okeyCode; + ex->_field_14 = 0x100; + ex->_messageNum = 0; + ex->_excFlags = 3; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(subj->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = subj->_okeyCode; + ex->_field_14 = 0x100; + ex->_messageNum = 0; + ex->_excFlags = 3; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(subj->_id, 17, 0x40, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_keyCode = 0; + mq->addExCommandToEnd(ex); + + if (!mq->chain(subj)) { + delete mq; + + return false; + } + + subj->_flags |= 1; + obj->_flags |= 1; + } else { + bool someFlag = false; + PicAniInfo aniInfo; + + obj->getPicAniInfo(&aniInfo); + + if (obj->_objtype == kObjTypeStaticANIObject && inter->_staticsId1) { + StaticANIObject *ani = (StaticANIObject *)obj; + + ani->_messageQueueId = 0; + ani->changeStatics2(inter->_staticsId1); + } + + int xpos = inter->_yOffs + obj->_ox; + int ypos = inter->_yOffs + obj->_oy; + + obj->setPicAniInfo(&aniInfo); + + if (abs(xpos - subj->_ox) > 1 || abs(ypos - subj->_oy) > 1 + || (inter->_staticsId2 != 0 && (subj->_statics == 0 || subj->_statics->_staticsId != inter->_staticsId2))) { + mq = getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->startMove(subj, xpos, ypos, 1, inter->_staticsId2); + + if (!mq) + return false; + + ex = new ExCommand(subj->_id, 55, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_x = obj->_id; + ex->_y = obj->_okeyCode; + ex->_keyCode = subj->_okeyCode; + ex->_excFlags = 3; + ex->_field_20 = invId; + ex->_field_14 = (obj->_objtype != kObjTypePictureObject); + mq->addExCommandToEnd(ex); + + someFlag = true; + + ex = new ExCommand(subj->_id, 17, 0x40, 0, 0, 0, 1, 0, 0, 0); + ex->_x = xpos; + ex->_y = ypos; + ex->_excFlags |= 3; + ex->_keyCode = 6; + ex->_field_14 = obj->_id; + ex->_field_20 = obj->_okeyCode; + ex->postMessage(); + } + + if (!inter->_staticsId1 || !(inter->_flags & 1)) + return true; + + StaticANIObject *ani = (StaticANIObject *)obj; + + if (!ani->isIdle()) + return false; + + if (ani->getMessageQueue()) + ani->queueMessageQueue(0); + + if (!ani->_statics || ani->_statics->_staticsId != inter->_staticsId1 || ani->_movement) { + mq = ani->changeStatics1(inter->_staticsId1); + + if (!mq) + return false; + + if (someFlag) { + if (!(inter->_flags & 0x10000)) { + if (mq->_isFinished) { + ani->_flags |= 0x80u; + } else { + ex = new ExCommand(ani->_id, 34, 0x80, 0, 0, 0, 1, 0, 0, 0); + ex->_field_14 = 0x80; + ex->_keyCode = ani->_okeyCode; + ex->_excFlags = 3; + mq->addExCommandToEnd(ex); + } + } + ex = new ExCommand(ani->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = ani->_okeyCode; + ex->_field_14 = 0x100; + ex->_excFlags = 3; + mq->addExCommandToEnd(ex); + } else { + ex = new ExCommand(subj->_id, 55, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_x = ani->_id; + ex->_y = ani->_okeyCode; + ex->_keyCode = subj->_okeyCode; + ex->_excFlags = 2; + ex->_field_14 = (obj->_objtype != kObjTypePictureObject); + ex->_field_20 = invId; + mq->addExCommandToEnd(ex); + + if (!mq->_isFinished) + return true; + + mq->_isFinished = 0; + ani->queueMessageQueue(mq); + } + } else { + obj->_flags |= 1; + + if (inter->_flags & 0x10000) + return true; + + obj->_flags |= 0x80; + } + } + + return true; +} + +Interaction *InteractionController::getInteractionByObjectIds(int obId, int obId2, int obId3) { + for (ObList::iterator i = _interactions.begin(); i != _interactions.end(); ++i) { + Interaction *intr = (Interaction *)*i; + + if (intr->_objectId1 == obId && intr->_objectId2 == obId2 && intr->_objectId3 == obId3) + return intr; + } + + return 0; +} + +Interaction::Interaction() { + _objectId1 = 0; + _objectId2 = 0; + _staticsId1 = 0; + _objectId3 = 0; + _objectState2 = 0; + _objectState1 = 0; + _messageQueue = 0; + _flags = 0; + _yOffs = 0; + _xOffs = 0; + _staticsId2 = 0; + _field_28 = 0; + _sceneId = -1; + _actionName = 0; +} + +Interaction::~Interaction() { + if (_messageQueue) { + while (_messageQueue->getExCommandByIndex(0)) + _messageQueue->deleteExCommandByIndex(0, 1); + } + + delete _messageQueue; + + free(_actionName); +} + +bool Interaction::load(MfcArchive &file) { + debug(5, "Interaction::load()"); + + _objectId1 = file.readUint16LE(); + _objectId2 = file.readUint16LE(); + _staticsId1 = file.readUint16LE(); + _staticsId2 = file.readUint16LE(); + _objectId3 = file.readUint16LE(); + _objectState2 = file.readUint32LE(); + _objectState1 = file.readUint32LE(); + _xOffs = file.readUint32LE(); + _yOffs = file.readUint32LE(); + _sceneId = file.readUint32LE(); + _flags = file.readUint32LE(); + _actionName = file.readPascalString(); + + _messageQueue = (MessageQueue *)file.readClass(); + + return true; +} + +bool Interaction::canInteract(GameObject *obj1, GameObject *obj2, int invId) { + if (_sceneId > 0 && g_fp->_currentScene && g_fp->_currentScene->_sceneId != _sceneId) + return false; + + if (_flags & 0x20000) + return false; + + if (!obj2) + return false; + + if (obj2->_id != _objectId1) + return false; + + if ((_flags & 8) && (_flags & 1)) { + if (obj2->_objtype != kObjTypeStaticANIObject) + return false; + + StaticANIObject *st = (StaticANIObject *)obj2; + + if (!st->_statics) + return false; + + if (st->_statics->_staticsId != _staticsId1) { + if (_staticsId1) + return false; + } + } + + if ((_objectId3 != invId && _objectId3 != -1 && _objectId3 != -2) || (!invId && _objectId3 == -2)) + return false; + + if (_objectState1) { + if (_flags & 0x10) { + if ((g_fp->getObjectState(obj1->getName()) & _objectState1) == 0) + return false; + } else { + if (g_fp->getObjectState(obj1->getName()) != _objectState1) + return false; + } + } + + if (_objectState2) { + if (_flags & 0x10) { + if ((g_fp->getObjectState(obj2->getName()) & _objectState2) == 0) + return false; + } else { + if (g_fp->getObjectState(obj2->getName()) != _objectState2) + return false; + } + } + + if (_objectId2 && (!obj1 || _objectId2 != obj1->_id)) + return false; + + return true; +} + +bool Interaction::isOverlapping(StaticANIObject *subj, GameObject *obj) { + StaticANIObject *ani = (StaticANIObject *)obj; + + if (abs(_xOffs + obj->_ox - subj->_ox) <= 1 + && abs(obj->_oy + _yOffs - subj->_oy) <= 1) { + if (!_staticsId2 || (subj->_statics != 0 && subj->_statics->_staticsId == _staticsId2)) { + if (!_staticsId1 || !(_flags & 1) || (ani->_statics != 0 && ani->_statics->_staticsId == _staticsId1)) + return true; + } + } + return false; +} + +bool EntranceInfo::load(MfcArchive &file) { + debug(5, "EntranceInfo::load()"); + + _sceneId = file.readUint32LE(); + _field_4 = file.readUint32LE(); + _messageQueueId = file.readUint32LE(); + file.read(_gap_C, 292); // FIXME, Ugh + _field_130 = file.readUint32LE(); + + return true; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/interaction.h b/engines/fullpipe/interaction.h new file mode 100644 index 0000000000..cb1eac002a --- /dev/null +++ b/engines/fullpipe/interaction.h @@ -0,0 +1,101 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_INTERACTION_H +#define FULLPIPE_INTERACTION_H + +#include "fullpipe/utils.h" + +namespace Fullpipe { + +class GameObject; +class MessageQueue; +class StaticANIObject; + +int handleObjectInteraction(StaticANIObject *subject, GameObject *object, int invId); +bool canInteractAny(GameObject *obj1, GameObject *obj2, int invId); + + +class Interaction : public CObject { + public: + int16 _objectId1; + int16 _objectId2; + int16 _objectId3; + int16 _staticsId1; + int16 _staticsId2; + int _objectState1; + int _objectState2; + int _xOffs; + int _yOffs; + MessageQueue *_messageQueue; + int _sceneId; + int _field_28; + int _flags; + char *_actionName; + + public: + Interaction(); + virtual ~Interaction(); + + virtual bool load(MfcArchive &file); + bool canInteract(GameObject *obj1, GameObject *obj2, int invId); + bool isOverlapping(StaticANIObject *subj, GameObject *obj); +}; + +class InteractionController : public CObject { + public: + ObList _interactions; + int16 _field_20; + bool _flag24; + + private: + static bool compareInteractions(const void *p1, const void *p2); + + public: + InteractionController() : _field_20(0), _flag24(true) {} + virtual ~InteractionController(); + + virtual bool load(MfcArchive &file); + + void enableFlag24() { _flag24 = true; } + void disableFlag24() { _flag24 = false; } + + void sortInteractions(int sceneId); + + bool handleInteraction(StaticANIObject *subj, GameObject *obj, int invId); + + Interaction *getInteractionByObjectIds(int obId, int obId2, int obId3); +}; + +struct EntranceInfo { + int32 _sceneId; + int32 _field_4; + int32 _messageQueueId; + byte _gap_C[292]; // FIXME + int32 _field_130; + + bool load(MfcArchive &file); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_INTERACTION_H */ diff --git a/engines/fullpipe/inventory.cpp b/engines/fullpipe/inventory.cpp new file mode 100644 index 0000000000..f9b507c50b --- /dev/null +++ b/engines/fullpipe/inventory.cpp @@ -0,0 +1,472 @@ +/* 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/utils.h" +#include "fullpipe/inventory.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/statics.h" +#include "fullpipe/input.h" + +namespace Fullpipe { + +Inventory::~Inventory() { + _itemsPool.clear(); +} + +bool Inventory::load(MfcArchive &file) { + debug(5, "Inventory::load()"); + + _sceneId = file.readUint16LE(); + int numInvs = file.readUint32LE(); + + for (int i = 0; i < numInvs; i++) { + InventoryPoolItem *t = new InventoryPoolItem(); + t->id = file.readUint16LE(); + t->pictureObjectNormal = file.readUint16LE(); + t->pictureObjectId1 = file.readUint16LE(); + t->pictureObjectHover = file.readUint16LE(); + t->pictureObjectSelected = file.readUint16LE(); + t->flags = file.readUint32LE(); + t->field_C = 0; + t->field_A = -536; + _itemsPool.push_back(t); + } + + return true; +} + +int Inventory::getInventoryPoolItemIndexById(int itemId) { + if (_itemsPool.size() <= 0) + return -1; + + for (uint i = 0; i < _itemsPool.size(); i++) { + if (_itemsPool[i]->id == itemId) + return i; + } + + return 0; +} + +bool Inventory::setItemFlags(int itemId, int flags) { + int idx = getInventoryPoolItemIndexById(itemId); + + if (idx < 0) + return false; + else + _itemsPool[idx]->flags = flags; + + return true; +} + +Inventory2::Inventory2() { + _selectedId = -1; + _field_48 = -1; + _scene = 0; + _picture = 0; + _isInventoryOut = false; + _isLocked = 0; + _topOffset = -65; +} + +Inventory2::~Inventory2() { + removeMessageHandler(125, -1); +} + +bool Inventory2::loadPartial(MfcArchive &file) { // Inventory2_SerializePartially + int numInvs = file.readUint32LE(); + + for (int i = 0; i < numInvs; i++) { + InventoryItem *t = new InventoryItem(); + t->itemId = file.readUint16LE(); + t->count = file.readUint16LE(); + _inventoryItems.push_back(t); + } + + return true; +} + +void Inventory2::addItem(int itemId, int count) { + if (getInventoryPoolItemIndexById(itemId) >= 0) + _inventoryItems.push_back(new InventoryItem(itemId, count)); +} + +void Inventory2::addItem2(StaticANIObject *obj) { + if (getInventoryPoolItemIndexById(obj->_id) >= 0 && getInventoryPoolItemFieldCById(obj->_id) != 2) { + addItem(obj->_id, 1); + obj->hide(); + } +} + +void Inventory2::removeItem(int itemId, int count) { + warning("STUB: Inventory2::removeItem(%d, %d)", itemId, count); +} + +void Inventory2::removeItem2(Scene *sceneObj, int itemId, int x, int y, int priority) { + int idx = getInventoryItemIndexById(itemId); + + if (idx >= 0) { + if (_inventoryItems[idx]->count) { + removeItem(itemId, 1); + + Scene *sc = g_fp->accessScene(_sceneId); + + if (sc) { + StaticANIObject *ani = new StaticANIObject(sc->getStaticANIObject1ById(itemId, -1)); + + sceneObj->addStaticANIObject(ani, 1); + + ani->_statics = (Statics *)ani->_staticsList[0]; + ani->setOXY(x, y); + ani->_priority = priority; + } + } + } +} + +int Inventory2::getCountItemsWithId(int itemId) { + int res = 0; + + for (uint i = 0; i < _inventoryItems.size(); i++) { + if (_inventoryItems[i]->itemId == itemId) + res += _inventoryItems[i]->count; + } + + return res; +} + +int Inventory2::getInventoryItemIndexById(int itemId) { + for (uint i = 0; i < _inventoryItems.size(); i++) { + if (_inventoryItems[i]->itemId == itemId) + return i; + } + + return -1; +} + +int Inventory2::getInventoryPoolItemIdAtIndex(int itemId) { + return _itemsPool[itemId]->id; +} + +int Inventory2::getInventoryPoolItemFieldCById(int itemId) { + for (uint i = 0; i < _itemsPool.size(); i++) { + if (_itemsPool[i]->id == itemId) + return _itemsPool[i]->field_C; + } + + return 0; +} + +int Inventory2::getItemFlags(int itemId) { + int idx = getInventoryPoolItemIndexById(itemId); + + if (idx < 0) + return 0; + + return _itemsPool[idx]->flags; +} + +void Inventory2::rebuildItemRects() { + _scene = g_fp->accessScene(_sceneId); + + if (!_scene) + return; + + _picture = _scene->getBigPicture(0, 0); + _picture->setAlpha(50); + + int itemX = 9; + int itemY = 0; + + for (uint i = 0; i < _scene->_picObjList.size(); i++) { + PictureObject *pic = (PictureObject *)_scene->_picObjList[i]; + + for (uint j = 0; j < _itemsPool.size(); j++) { + if (_itemsPool[j]->pictureObjectNormal == pic->_id) { + if (pic->_okeyCode) + _scene->deletePictureObject(pic); + else + pic->_flags &= 0xFFFB; + } + } + } + + for (uint i = 0; i < _inventoryItems.size(); i++) { + Common::Point point; + + int idx = getInventoryPoolItemIndexById(_inventoryItems[i]->itemId); + + InventoryIcon *icn = new InventoryIcon(); + + icn->inventoryItemId = _itemsPool[idx]->id; + + icn->pictureObjectNormal = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectNormal, 0); + icn->pictureObjectHover = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectHover, 0); + icn->pictureObjectSelected = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectSelected, 0); + + icn->pictureObjectNormal->getDimensions(&point); + + if (_itemsPool[idx]->flags & 0x10000) { + icn->x1 = 730; + icn->y1 = itemY; + icn->x2 = point.x + 730; + icn->y2 = point.y + itemY + 10; + } else { + icn->x1 = itemX; + icn->y1 = itemY; + icn->x2 = itemX + point.x; + itemX = icn->x2 + 1; + icn->y2 = point.y + itemY + 10; + } + + _inventoryIcons.push_back(icn); + + if (itemX >= 2 * (icn->x1 - icn->x2) + 800) { + itemX = 9; + itemY = icn->y2 + 1; + } + } +} + +void Inventory2::draw() { + if (!_scene) + return; + + int oldScLeft = g_fp->_sceneRect.left; + int oldScTop = g_fp->_sceneRect.top; + + g_fp->_sceneRect.top = -_topOffset; + g_fp->_sceneRect.left = 0; + + _picture->draw(-1, -1, 0, 0); + + for (uint i = 0; i < _inventoryIcons.size(); i++) { + InventoryIcon *icn = _inventoryIcons[i]; + + if (icn->isSelected) { + icn->pictureObjectSelected->drawAt(icn->x1, icn->y1 + 10); + } else { + if (icn->isMouseHover) + icn->pictureObjectHover->drawAt(icn->x1, icn->y1 + 10); + else + icn->pictureObjectNormal->drawAt(icn->x1, icn->y1 + 10); + } + } + + if (!_isInventoryOut) + goto LABEL_30; + + int v10, v11, v12; + + if (_topOffset != -10) { + if (_topOffset < -10) { + v10 = -10; + goto LABEL_13; + } + if (_topOffset + 10 >= 20) { + v11 = -20; +cont: + _topOffset += v11; + goto reset; + } + v12 = -10; + goto LABEL_25; + } + if (!_isInventoryOut) { +LABEL_30: + if (_topOffset != -65) { + if (_topOffset < -65) { + v10 = -65; +LABEL_13: + v11 = v10 - _topOffset; + if (v11 >= 20) + v11 = 20; + goto cont; + } + if (_topOffset + 65 >= 20) { + v11 = -20; + goto cont; + } + v12 = -65; +LABEL_25: + v11 = v12 - _topOffset; + goto cont; + } + } + +reset: + + g_fp->_sceneRect.top = oldScTop; + g_fp->_sceneRect.left = oldScLeft; + +} + +void Inventory2::slideIn() { + _isInventoryOut = false; + + ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_2C = 10; + ex->_field_14 = _isInventoryOut; + ex->_field_20 = !_isInventoryOut; + ex->_excFlags |= 3; + ex->postMessage(); +} + +void Inventory2::slideOut() { + _isInventoryOut = true; + + ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_2C = 10; + ex->_field_14 = _isInventoryOut; + ex->_field_20 = !_isInventoryOut; + ex->_excFlags |= 3; + ex->postMessage(); +} + +bool Inventory2::handleLeftClick(ExCommand *cmd) { + if (!_isInventoryOut) + return false; + + bool res = false; + + for (uint i = 0; i < _inventoryIcons.size(); i++) { + if (cmd->_x >= _inventoryIcons[i]->x1 && cmd->_x <= _inventoryIcons[i]->x2 && + cmd->_y >= _inventoryIcons[i]->y1 && cmd->_y <= _inventoryIcons[i]->y2) { + if (getSelectedItemId()) { + if (getSelectedItemId() != _inventoryIcons[i]->inventoryItemId) + unselectItem(0); + } + if (getItemFlags(_inventoryIcons[i]->inventoryItemId) & 1) { + ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0); + ex->_field_2C = 11; + ex->_field_14 = _inventoryIcons[i]->inventoryItemId; + ex->_excFlags |= 3; + ex->postMessage(); + } + if (!(getItemFlags(_inventoryIcons[i]->inventoryItemId) & 2)) { + selectItem(_inventoryIcons[i]->inventoryItemId); + _inventoryIcons[i]->isSelected = true; + } + res = true; + } + } + + if (!res) + unselectItem(0); + + return res; +} + +int Inventory2::selectItem(int itemId) { + if (getInventoryItemIndexById(itemId) < 0) + return -1; + + unselectItem(0); + + _selectedId = itemId; + + if (_scene) { + int idx = getInventoryPoolItemIndexById(itemId); + + Picture *pic = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectId1, 0)->_picture; + g_fp->getGameLoaderInputController()->setCursorItemPicture(pic); + } + + return _selectedId; +} + +bool Inventory2::unselectItem(bool flag) { + if (_selectedId < 0) + return false; + + _selectedId = -1; + + for (uint i = 0; i < _inventoryIcons.size(); i++) { + if (_inventoryIcons[i]->isSelected) + _inventoryIcons[i]->isSelected = false; + } + + g_fp->getGameLoaderInputController()->setCursorItemPicture(0); + + return true; +} + +int Inventory2::getHoveredItem(Common::Point *point) { + int selId = getSelectedItemId(); + + if (point->y <= 20 && !_isInventoryOut && !_isLocked) + slideOut(); + + if (!selId && point->y >= 55) { + if (!_isInventoryOut) + return 0; + + if (!_isLocked) + slideIn(); + } + + if (!_isInventoryOut) + return 0; + + for (uint i = 0; i < _inventoryIcons.size(); i++) { + InventoryIcon *icn = _inventoryIcons[i]; + if (selId || + point->x < icn->x1 || + point->x > icn->x2 || + point->y < _topOffset + icn->y1 || + point->y > _topOffset + icn->y2) { + icn->isMouseHover = false; + } else { + icn->isMouseHover = true; + return icn->inventoryItemId; + } + } + + return 0; +} + +void Inventory2::clear() { + unselectItem(0); + + for (uint i = 0; i < _inventoryItems.size(); i++) + getInventoryPoolItemFieldCById(_inventoryItems[i]->itemId); + + _inventoryItems.clear(); +} + +void FullpipeEngine::getAllInventory() { + Inventory2 *inv = getGameLoaderInventory(); + + for (uint i = 0; i < inv->getItemsPoolCount(); ++i ) { + int id = inv->getInventoryPoolItemIdAtIndex(i); + + if (inv->getCountItemsWithId(id) < 1) + inv->addItem(id, 1); + } + + inv->rebuildItemRects(); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/inventory.h b/engines/fullpipe/inventory.h new file mode 100644 index 0000000000..46b55c5669 --- /dev/null +++ b/engines/fullpipe/inventory.h @@ -0,0 +1,138 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_INVENTORY_H +#define FULLPIPE_INVENTORY_H + +namespace Fullpipe { + +class Scene; +class BigPicture; + +struct InventoryPoolItem { + int16 id; + int16 pictureObjectNormal; + int16 pictureObjectId1; + int16 pictureObjectHover; + int16 pictureObjectSelected; + int16 field_A; + int field_C; + int obj; + int flags; +}; + +typedef Common::Array<InventoryPoolItem *> InventoryPoolItems; + +class Inventory : public CObject { + protected: + int16 _sceneId; + InventoryPoolItems _itemsPool; + + public: + Inventory() { _sceneId = 0; } + virtual ~Inventory(); + + virtual bool load(MfcArchive &file); + + int getInventoryPoolItemIndexById(int itemId); + uint getItemsPoolCount() { return _itemsPool.size(); } + bool setItemFlags(int itemId, int flags); +}; + +struct InventoryItem { + int16 itemId; + int16 count; + + InventoryItem() { itemId = count = 0; } + InventoryItem(int id, int cnt) : itemId(id), count(cnt) {} +}; + +typedef Common::Array<InventoryItem *> InventoryItems; + +class PictureObject; + +struct InventoryIcon { + PictureObject *pictureObjectNormal; + PictureObject *pictureObjectHover; + PictureObject *pictureObjectSelected; + int x1; + int y1; + int x2; + int y2; + int16 inventoryItemId; + bool isSelected; + bool isMouseHover; +}; + +typedef Common::Array<InventoryIcon *> InventoryIcons; + +class Inventory2 : public Inventory { + InventoryItems _inventoryItems; + InventoryIcons _inventoryIcons; + int _selectedId; + int _field_48; + bool _isInventoryOut; + bool _isLocked; + int _topOffset; + Scene *_scene; + BigPicture *_picture; + + public: + Inventory2(); + virtual ~Inventory2(); + + bool loadPartial(MfcArchive &file); + void addItem(int itemId, int count); + void addItem2(StaticANIObject *obj); + void removeItem(int itemId, int count); + void removeItem2(Scene *sceneObj, int itemId, int x, int y, int priority); + + int getInventoryItemIndexById(int itemId); + int getInventoryPoolItemIdAtIndex(int itemId); + int getInventoryPoolItemFieldCById(int itemId); + int getCountItemsWithId(int itemId); + int getItemFlags(int itemId); + + void rebuildItemRects(); + + Scene *getScene() { return _scene; } + bool getIsLocked() { return _isLocked; } + void setIsLocked(bool val) { _isLocked = val; } + bool getIsInventoryOut() { return _isInventoryOut; } + + int getSelectedItemId() { return _selectedId < 0 ? 0 : _selectedId; } + int getHoveredItem(Common::Point *point); + void slideIn(); + void slideOut(); + + bool handleLeftClick(ExCommand *cmd); + int selectItem(int itemId); + bool unselectItem(bool flag); + + void draw(); + + void clear(); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_INVENTORY_H */ diff --git a/engines/fullpipe/lift.cpp b/engines/fullpipe/lift.cpp new file mode 100644 index 0000000000..d066c89d4a --- /dev/null +++ b/engines/fullpipe/lift.cpp @@ -0,0 +1,518 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/scene.h" +#include "fullpipe/statics.h" +#include "fullpipe/messages.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" + +namespace Fullpipe { + +int FullpipeEngine::lift_getButtonIdP(int objid) { + switch (objid) { + case ST_LBN_0N: + return ST_LBN_0P; + + case ST_LBN_1N: + return ST_LBN_1P; + + case ST_LBN_2N: + return ST_LBN_2P; + + case ST_LBN_3N: + return ST_LBN_3P; + + case ST_LBN_4N: + return ST_LBN_4P; + + case ST_LBN_5N: + return ST_LBN_5P; + + case ST_LBN_6N: + return ST_LBN_6P; + + case ST_LBN_7N: + return ST_LBN_7P; + + case ST_LBN_8N: + return ST_LBN_8P; + + case ST_LBN_9N: + return ST_LBN_9P; + + default: + return 0; + } +} + +int FullpipeEngine::lift_getButtonIdH(int objid) { + switch (objid) { + case ST_LBN_0P: + return ST_LBN_0H; + + case ST_LBN_1P: + return ST_LBN_1H; + + case ST_LBN_2P: + return ST_LBN_2H; + + case ST_LBN_3P: + return ST_LBN_3H; + + case ST_LBN_4P: + return ST_LBN_4H; + + case ST_LBN_5P: + return ST_LBN_5H; + + case ST_LBN_6P: + return ST_LBN_6H; + + case ST_LBN_7P: + return ST_LBN_7H; + + case ST_LBN_8P: + return ST_LBN_8H; + + case ST_LBN_9P: + return ST_LBN_9H; + + default: + return 0; + } +} + +int FullpipeEngine::lift_getButtonIdN(int objid) { + switch (objid) { + case ST_LBN_0H: + case ST_LBN_0N: + case ST_LBN_0P: + return ST_LBN_0N; + + case ST_LBN_1H: + case ST_LBN_1N: + case ST_LBN_1P: + return ST_LBN_1N; + + case ST_LBN_2H: + case ST_LBN_2N: + case ST_LBN_2P: + return ST_LBN_2N; + + case ST_LBN_3H: + case ST_LBN_3N: + case ST_LBN_3P: + return ST_LBN_3N; + + case ST_LBN_4H: + case ST_LBN_4N: + case ST_LBN_4P: + return ST_LBN_4N; + + case ST_LBN_5H: + case ST_LBN_5N: + case ST_LBN_5P: + return ST_LBN_5N; + + case ST_LBN_6H: + case ST_LBN_6N: + case ST_LBN_6P: + return ST_LBN_6N; + + case ST_LBN_7H: + case ST_LBN_7N: + case ST_LBN_7P: + return ST_LBN_7N; + + case ST_LBN_8H: + case ST_LBN_8N: + case ST_LBN_8P: + return ST_LBN_8N; + + case ST_LBN_9H: + case ST_LBN_9N: + case ST_LBN_9P: + return ST_LBN_9N; + + default: + return 0; + } +} + +void FullpipeEngine::lift_setButton(const char *name, int state) { + GameVar *var = g_fp->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons); + + if (var) + var->setSubVarAsInt(name, state); +} + +void FullpipeEngine::lift_init(Scene *sc, int enterSeq, int exitSeq) { + _lastLiftButton = 0; + + _liftEnterMQ = sc->getMessageQueueById(enterSeq); + if (!_liftEnterMQ) + return; + + _liftExitMQ = sc->getMessageQueueById(exitSeq); + + if (!_liftExitMQ) + return; + + ExCommand *ex = _liftEnterMQ->getExCommandByIndex(0); + + if (!ex) + return; + + _liftX = ex->_x; + _liftY = ex->_y; + + _lift = sc->getStaticANIObject1ById(ANI_LIFT, -1); + + for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) { + StaticANIObject *ani = (StaticANIObject *)sc->_staticANIObjectList1[i]; + + if (ani->_id == ANI_LIFTBUTTON) + ani->_statics = ani->getStaticsById(lift_getButtonIdP(ani->_statics->_staticsId)); + } + + GameVar *var = getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons); + if (var) { + for (var = var->_subVars; var; var = var->_nextVarObj) { + for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) { + StaticANIObject *ani = (StaticANIObject *)sc->_staticANIObjectList1[i]; + + if (ani->_id == ANI_LIFTBUTTON) { + int id = lift_getButtonIdN(ani->_statics->_staticsId); + + if (id == var->_value.intValue) + ani->_statics = ani->getStaticsById(id); + } + + } + } + } +} + +void FullpipeEngine::lift_exitSeq(ExCommand *cmd) { + if (cmd) { + MessageQueue *mq = _globalMessageQueueList->getMessageQueueById(cmd->_parId); + + if (mq) + mq->activateExCommandsByKind(34); + } + + _lift->changeStatics2(ST_LFT_CLOSED); + + MessageQueue *mq = new MessageQueue(_globalMessageQueueList->compact()); + + ExCommand *ex = new ExCommand(_aniMan->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_14 = 256; + ex->_messageNum = 256; + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + + if (!cmd) { + ex = new ExCommand(_aniMan->_id, 2, 40, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = _aniMan->_okeyCode; + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + } + + ex = new ExCommand(_lift->_id, 1, MV_LFT_OPEN, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = _lift->_okeyCode; + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(_aniMan->_id, 1, MV_MAN_STARTD, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = _aniMan->_okeyCode; + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(_aniMan->_id, 5, -1, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = _aniMan->_okeyCode; + ex->_field_14 = 10; + ex->_x = -1; + ex->_y = -1; + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(_aniMan->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_field_14 = 256; + ex->_messageNum = 0; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(0, 17, MSG_LIFT_STARTEXITQUEUE, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(_lift->_id, 1, MV_LFT_CLOSE, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = _lift->_okeyCode; + ex->_excFlags |= 2; + + mq->addExCommandToEnd(ex); + + mq->chain(0); +} + +void FullpipeEngine::lift_closedoorSeq() { + if (_lift->_movement) { + if (_lift->_movement->_id == MV_LFT_CLOSE) { + _lift->queueMessageQueue(0); + } else if (_lift->_movement->_id == MV_LFT_OPEN) { + int ph = _lift->_movement->_currDynamicPhaseIndex; + + _lift->changeStatics2(ST_LFT_OPEN_NEW); + _lift->startAnim(MV_LFT_CLOSE, 0, -1); + + if (_lift->_movement->_currMovement) + _lift->_movement->setDynamicPhaseIndex(_lift->_movement->_currMovement->_dynamicPhases.size() - ph); + else + _lift->_movement->setDynamicPhaseIndex(_lift->_movement->_dynamicPhases.size() - ph); + } else { + _lift->changeStatics2(ST_LFT_OPEN_NEW); + + _lift->startAnim(MV_LFT_CLOSE, 0, -1); + } + } else { + if (_lift->_statics->_staticsId == ST_LFT_CLOSED ) { + _lift->changeStatics2(ST_LFT_CLOSED); + } else { + _lift->startAnim(MV_LFT_CLOSE, 0, -1); + } + } + + MessageQueue *mq = new MessageQueue(_globalMessageQueueList->compact()); + ExCommand *ex = new ExCommand(0, 17, MSG_LIFT_GO, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + + if (!mq->chain(_lift)) + delete mq; +} + +void FullpipeEngine::lift_walkAndGo() { + MessageQueue *mq; + ExCommand *ex; + + if (abs(_liftX - _aniMan->_ox) > 1 || abs(_liftY - _aniMan->_oy) > 1 || _aniMan->_movement || _aniMan->_statics->_staticsId != ST_MAN_UP) { + mq = getCurrSceneSc2MotionController()->startMove(_aniMan, _liftX, _liftY, 1, ST_MAN_UP); + + if (mq) { + ex = new ExCommand(0, 17, MSG_LIFT_CLICKBUTTON, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + + mq->addExCommandToEnd(ex); + } + } else { + lift_openLift(); + + mq = new MessageQueue(_liftEnterMQ, 0, 0); + + mq->setFlags(mq->getFlags() | 1); + + ex = new ExCommand(_aniMan->_id, 2, 15, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = _aniMan->_okeyCode; + ex->_excFlags |= 2; + mq->addExCommand(ex); + + ex = new ExCommand(_aniMan->_id, 5, -1, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = _aniMan->_okeyCode; + ex->_field_14 = _lift->_priority + 1; + ex->_x = -1; + ex->_y = -1; + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(0, 17, MSG_LIFT_CLOSEDOOR, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + + mq->chain(0); + + _aniMan->_flags |= 1; + } +} + +void FullpipeEngine::lift_openLift() { + if (_lift->_movement) { + if (_lift->_movement->_id == MV_LFT_OPEN) { + _lift->queueMessageQueue(0); + } else if (_lift->_movement->_id == MV_LFT_CLOSE) { + int idx = _lift->_movement->_currDynamicPhaseIndex; + + _lift->changeStatics2(ST_LFT_CLOSED); + _lift->startAnim(MV_LFT_OPEN, 0, -1); + + if (_lift->_movement->_currMovement) + _lift->_movement->setDynamicPhaseIndex(_lift->_movement->_currMovement->_dynamicPhases.size() - idx); + else + _lift->_movement->setDynamicPhaseIndex(_lift->_movement->_dynamicPhases.size() - idx); + } else { + _lift->changeStatics2(ST_LFT_CLOSED); + _lift->startAnim(MV_LFT_OPEN, 0, -1); + } + } else if (_lift->_statics->_staticsId == ST_LFT_OPEN_NEW) { + _lift->changeStatics2(ST_LFT_OPEN_NEW); + } else { + _lift->startAnim(MV_LFT_OPEN, 0, -1); + } +} + +void FullpipeEngine::lift_clickButton() { + if (_lastLiftButton) + lift_walkAndGo(); +} + +void FullpipeEngine::lift_goAnimation() { if (_lastLiftButton) { + int parentId = _currentScene->_sceneId; + int buttonId = lift_getButtonIdN(_lastLiftButton->_statics->_staticsId); + + if (!buttonId) + return; + + int numItems = _gameLoader->_preloadItems.size(); + + for (int i = 0; i < numItems; i++) { + PreloadItem *pre = _gameLoader->_preloadItems[i]; + + if (pre->preloadId2 == buttonId && pre->preloadId1 == _currentScene->_sceneId) { + MessageQueue *mq = new MessageQueue(_globalMessageQueueList->compact()); + + ExCommand *ex = new ExCommand(ANI_MAN, 1, (pre->keyCode != LiftDown ? MV_MAN_LIFTDOWN : MV_MAN_LIFTUP), 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = -1; + ex->_field_24 = 1; + ex->_excFlags |= 2; + + mq->addExCommandToEnd(ex); + + ex = new ExCommand(parentId, 17, 61, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = buttonId; + ex->_excFlags |= 3; + + mq->addExCommandToEnd(ex); + + _aniMan->_flags &= 0xFEFF; + + if (!mq->chain(_aniMan)) + delete mq; + + _aniMan->_flags |= 1; + } + } + } + + lift_exitSeq(0); + + if (_lastLiftButton) { + _lastLiftButton->_statics = _lastLiftButton->getStaticsById(lift_getButtonIdN(_lastLiftButton->_statics->_staticsId)); + _lastLiftButton = 0; + } +} + +void FullpipeEngine::lift_animateButton(StaticANIObject *button) { + int butId = lift_getButtonIdP(button->_statics->_staticsId); + + if (butId && butId != button->_statics->_staticsId) { + if (button == _lastLiftButton) { + playSound(SND_CMN_032, 0); + } else { + if (_lastLiftButton) { + int id = lift_getButtonIdN(_lastLiftButton->_statics->_staticsId); + + if (id) + _lastLiftButton->_statics = _lastLiftButton->getStaticsById(id); + + _lastLiftButton = 0; + } + + if (_aniMan->isIdle() && !(_aniMan->_flags & 0x100)) { + _lastLiftButton = button; + button->_statics = button->getStaticsById(butId); + + ExCommand *ex = new ExCommand(0, 35, SND_CMN_032, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_field_14 = 1; + ex->postMessage(); + + int id = lift_getButtonIdH(_lastLiftButton->_statics->_staticsId); + + if (id) { + _lastLiftButton->_statics = _lastLiftButton->getStaticsById(id); + + lift_walkAndGo(); + } + } + } + } +} + +void FullpipeEngine::lift_startExitQueue() { + MessageQueue *mq = new MessageQueue(_liftExitMQ, 0, 0); + + mq->chain(0); +} + +void FullpipeEngine::lift_hoverButton(ExCommand *cmd) { + if (_lastLiftButton) { + if (!(cmd->_keyCode & 2) || _liftX != cmd->_x || _liftY != cmd->_y) { + _lastLiftButton->_statics = _lastLiftButton->getStaticsById(lift_getButtonIdN(_lastLiftButton->_statics->_staticsId)); + _lastLiftButton = 0; + } + } +} + +bool FullpipeEngine::lift_checkButton(const char *varName) { + GameVar *var = g_fp->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons); + + if (var) + return lift_getButtonIdP(var->getSubVarByName(varName)->_value.intValue) > 0; + + return false; +} + +void FullpipeEngine::lift_setButtonStatics(Scene *sc, int buttonId) { + for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) { + StaticANIObject *ani = (StaticANIObject *)sc->_staticANIObjectList1[i]; + + if (ani->_id == ANI_LIFTBUTTON) { + int id = lift_getButtonIdN(ani->_statics->_staticsId); + + if (id == buttonId) + ani->_statics = ani->getStaticsById(id); + } + } +} + + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/messagehandlers.cpp b/engines/fullpipe/messagehandlers.cpp new file mode 100644 index 0000000000..94754ad22a --- /dev/null +++ b/engines/fullpipe/messagehandlers.cpp @@ -0,0 +1,800 @@ +/* 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/messages.h" +#include "fullpipe/statics.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/interaction.h" +#include "fullpipe/motion.h" +#include "fullpipe/input.h" + +#include "fullpipe/constants.h" + +namespace Fullpipe { + +void global_messageHandler_KickStucco() { + Movement *mov = g_fp->_aniMan->getMovementById(MV_MAN_HMRKICK); + int end = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + bool flip = false; + + for (int i = 0; i < end; i++) { + ExCommand *ex = mov->getDynamicPhaseByIndex(i)->_exCommand; + + if (ex) + if (ex->_messageKind == 35) + if (ex->_messageNum == SND_CMN_015) { + if (flip) { + ex->_messageNum = SND_CMN_055; + } else { + ex->_messageNum = SND_CMN_054; + flip = true; + } + } + } + + mov = g_fp->_aniMan->getMovementById(MV_MAN_HMRKICK_COINLESS); + end = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + flip = false; + + for (int i = 0; i < end; i++) { + ExCommand *ex = mov->getDynamicPhaseByIndex(i)->_exCommand; + + if (ex) + if (ex->_messageKind == 35) + if (ex->_messageNum == SND_CMN_015) { + if (flip) { + ex->_messageNum = SND_CMN_055; + } else { + ex->_messageNum = SND_CMN_054; + flip = true; + } + } + } +} + +void global_messageHandler_KickMetal() { + Movement *mov = g_fp->_aniMan->getMovementById(MV_MAN_HMRKICK); + int end = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + + for (int i = 0; i < end; i++) { + ExCommand *ex = mov->getDynamicPhaseByIndex(i)->_exCommand; + + if (ex) + if (ex->_messageKind == 35) + if (ex->_messageNum == SND_CMN_054 || ex->_messageNum == SND_CMN_055) + ex->_messageNum = SND_CMN_015; + } + + mov = g_fp->_aniMan->getMovementById(MV_MAN_HMRKICK_COINLESS); + end = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + + for (int i = 0; i < end; i++) { + ExCommand *ex = mov->getDynamicPhaseByIndex(i)->_exCommand; + + if (ex) + if (ex->_messageKind == 35) + if (ex->_messageNum == SND_CMN_054 || ex->_messageNum == SND_CMN_055) + ex->_messageNum = SND_CMN_015; + } +} + +int global_messageHandler1(ExCommand *cmd) { + debug(5, "global_messageHandler1: %d %d", cmd->_messageKind, cmd->_messageNum); + + if (cmd->_excFlags & 0x10000) { + if (cmd->_messageNum == MV_MAN_TOLADDER) + cmd->_messageNum = MV_MAN_TOLADDER2; + if (cmd->_messageNum == MV_MAN_STARTLADDER) + cmd->_messageNum = MV_MAN_STARTLADDER2; + if (cmd->_messageNum == MV_MAN_GOLADDER) + cmd->_messageNum = MV_MAN_GOLADDER2; + if (cmd->_messageNum == MV_MAN_STOPLADDER) + cmd->_messageNum = MV_MAN_STOPLADDER2; + } + + if (g_fp->_inputDisabled) { + if (cmd->_messageKind == 17) { + switch (cmd->_messageNum) { + case 29: + case 30: + case 36: + case 106: + cmd->_messageKind = 0; + break; + default: + break; + } + } + } else if (cmd->_messageKind == 17) { + switch (cmd->_messageNum) { + case MSG_MANSHADOWSON: + g_fp->_aniMan->_shadowsOn = 1; + break; + case MSG_HMRKICK_STUCCO: + global_messageHandler_KickStucco(); + break; + case MSG_MANSHADOWSOFF: + g_fp->_aniMan->_shadowsOn = 0; + break; + case MSG_DISABLESAVES: + g_fp->disableSaves(cmd); + break; + case MSG_ENABLESAVES: + g_fp->enableSaves(); + break; + case MSG_HMRKICK_METAL: + global_messageHandler_KickMetal(); + break; + case 29: // left mouse + if (g_fp->_inventoryScene) { + if (getGameLoaderInventory()->handleLeftClick(cmd)) + cmd->_messageKind = 0; + } + break; + case 107: // right mouse + if (getGameLoaderInventory()->getSelectedItemId()) { + getGameLoaderInventory()->unselectItem(0); + cmd->_messageKind = 0; + } + break; + case 36: // keydown + g_fp->defHandleKeyDown(cmd->_keyCode); + + switch (cmd->_keyCode) { + case '\x1B': // ESC + if (g_fp->_currentScene) { + getGameLoaderInventory()->unselectItem(0); + g_fp->openMainMenu(); + cmd->_messageKind = 0; + } + break; + case 't': + g_fp->stopAllSounds(); + cmd->_messageKind = 0; + break; + case 'u': + g_fp->toggleMute(); + cmd->_messageKind = 0; + break; + case ' ': + if (getGameLoaderInventory()->getIsLocked()) { + if (getGameLoaderInventory()->getIsInventoryOut()) { + getGameLoaderInventory()->setIsLocked(0); + } + } else { + getGameLoaderInventory()->slideOut(); + getGameLoaderInventory()->setIsLocked(1); + } + break; + case '\t': + if (g_fp->_flgCanOpenMap) + g_fp->openMap(); + cmd->_messageKind = 0; + break; + case 'p': + if (g_fp->_flgCanOpenMap) + g_fp->openHelp(); + cmd->_messageKind = 0; + break; + default: + break; + } + break; + case 33: + if (!g_fp->_inventoryScene) + break; + + int invItem; + + if (g_fp->_updateFlag && (invItem = g_fp->_inventory->getHoveredItem(&g_fp->_mouseScreenPos))) { + g_fp->_cursorId = PIC_CSR_ITN; + if (!g_fp->_currSelectedInventoryItemId && !g_fp->_aniMan->_movement && + !(g_fp->_aniMan->_flags & 0x100) && g_fp->_aniMan->isIdle()) { + int st = g_fp->_aniMan->_statics->_staticsId; + ExCommand *newex = 0; + + if (st == ST_MAN_RIGHT) { + newex = new ExCommand(g_fp->_aniMan->_id, 1, rMV_MAN_LOOKUP, 0, 0, 0, 1, 0, 0, 0); + } else if (st == (0x4000 | ST_MAN_RIGHT)) { + newex = new ExCommand(g_fp->_aniMan->_id, 1, MV_MAN_LOOKUP, 0, 0, 0, 1, 0, 0, 0); + } + + if (newex) { + newex->_keyCode = g_fp->_aniMan->_okeyCode; + newex->_excFlags |= 3; + newex->postMessage(); + } + } + + if (g_fp->_currSelectedInventoryItemId != invItem) + g_fp->playSound(SND_CMN_070, 0); + + g_fp->_currSelectedInventoryItemId = invItem; + g_fp->setCursor(g_fp->_cursorId); + break; + } + if (g_fp->_updateCursorCallback) + g_fp->_updateCursorCallback(); + + g_fp->_currSelectedInventoryItemId = 0; + g_fp->setCursor(g_fp->_cursorId); + break; + case 65: // open map + if (cmd->_field_2C == 11 && cmd->_field_14 == ANI_INV_MAP && g_fp->_flgCanOpenMap) + g_fp->openMap(); + break; + default: + break; + } + } + + if (cmd->_messageKind == 56) { + getGameLoaderInventory()->rebuildItemRects(); + + ExCommand *newex = new ExCommand(0, 35, SND_CMN_031, 0, 0, 0, 1, 0, 0, 0); + + newex->_field_14 = 1; + newex->_excFlags |= 3; + newex->postMessage(); + + return 1; + } else if (cmd->_messageKind == 57) { + getGameLoaderInventory()->rebuildItemRects(); + + return 1; + } + + return 0; +} + +void staticANIObjectCallback(int *arg) { + (*arg)--; +} + +int global_messageHandler2(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + int res = 0; + StaticANIObject *ani; + + switch (cmd->_messageNum) { + case 0x44c8: + error("0x44c8"); + // Unk3_sub_4477A0(&unk3, _parentId, _field_14 != 0); + break; + + case 28: + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (ani) + ani->_priority = cmd->_field_14; + break; + + case 25: + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (ani) { + if (cmd->_field_14) { + ani->setFlags40(true); + ani->_callback2 = staticANIObjectCallback; + } else { + ani->setFlags40(false); + ani->_callback2 = 0; + } + } + break; + + case 26: + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (ani) { + Movement *mov = ani->_movement; + if (mov) + mov->_currDynamicPhase->_field_68 = 0; + } + break; + + default: +#if 0 + // We never put anything into _defMsgArray + while (::iterator it = g_fp->_defMsgArray.begin(); it != g_fp->_defMsgArray.end(); ++it) + if (((ExCommand *)*it)->_field_24 == _messageNum) { + ((ExCommand *)*it)->firef34(v13); + res = 1; + } +#endif + + //debug_msg(_messageNum); + + if (!g_fp->_soundEnabled || cmd->_messageNum != 33 || g_fp->_currSoundListCount <= 0) + return res; + + for (int snd = 0; snd < g_fp->_currSoundListCount; snd++) { + SoundList *s = g_fp->_currSoundList1[snd]; + int ms = s->getCount(); + for (int i = 0; i < ms; i++) { + s->getSoundByIndex(i)->setPanAndVolumeByStaticAni(); + } + } + } + + return res; +} + +int global_messageHandler3(ExCommand *cmd) { + int result = 0; + + if (cmd->_messageKind == 17) { + switch (cmd->_messageNum) { + case 29: + case 30: + case 31: + case 32: + case 36: + if (g_fp->_inputDisabled) + cmd->_messageKind = 0; + break; + default: + break; + } + } + + StaticANIObject *ani, *ani2; + + switch (cmd->_messageKind) { + case 17: + switch (cmd->_messageNum) { + case 61: + debug(0, "preload: { %d, %d },", cmd->_parentId, cmd->_keyCode); + return g_fp->_gameLoader->preloadScene(cmd->_parentId, cmd->_keyCode); + case 62: + return g_fp->_gameLoader->gotoScene(cmd->_parentId, cmd->_keyCode); + case 64: + if (g_fp->_currentScene && g_fp->_msgObjectId2 + && (!(cmd->_keyCode & 4) || g_fp->_msgObjectId2 != cmd->_field_14 || g_fp->_msgId != cmd->_field_20)) { + ani = g_fp->_currentScene->getStaticANIObject1ById(g_fp->_msgObjectId2, g_fp->_msgId); + if (ani) { + ani->_flags &= 0xFF7F; + ani->_flags &= 0xFEFF; + ani->deleteFromGlobalMessageQueue(); + } + } + g_fp->_msgX = 0; + g_fp->_msgY = 0; + g_fp->_msgObjectId2 = 0; + g_fp->_msgId = 0; + if ((cmd->_keyCode & 1) || (cmd->_keyCode & 2)) { + g_fp->_msgX = cmd->_x; + g_fp->_msgY = cmd->_y; + } + if (cmd->_keyCode & 4) { + g_fp->_msgObjectId2 = cmd->_field_14; + g_fp->_msgId = cmd->_field_20; + } + return result; + case 29: + if (g_fp->_gameLoader->_interactionController->_flag24 && g_fp->_currentScene) { + ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + ani2 = g_fp->_currentScene->getStaticANIObject1ById(g_fp->_gameLoader->_field_FA, -1); + + if (ani) { + if (g_fp->_msgObjectId2 == ani->_id && g_fp->_msgId == ani->_okeyCode) { + cmd->_messageKind = 0; + return result; + } + if (canInteractAny(ani2, ani, cmd->_keyCode)) { + handleObjectInteraction(ani2, ani, cmd->_keyCode); + return 1; + } + } else { + int id = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(id, 0); + if (pic) { + if (g_fp->_msgObjectId2 == pic->_id && g_fp->_msgId == pic->_okeyCode) { + cmd->_messageKind = 0; + return result; + } + if (!ani2 || canInteractAny(ani2, pic, cmd->_keyCode)) { + if (!ani2 || (ani2->isIdle() && !(ani2->_flags & 0x80) && !(ani2->_flags & 0x100))) + handleObjectInteraction(ani2, pic, cmd->_keyCode); + return 1; + } + } + } + } + if (getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->_isEnabled && cmd->_keyCode <= 0) { + if (g_fp->_msgX != cmd->_sceneClickX || g_fp->_msgY != cmd->_sceneClickY) { + ani = g_fp->_currentScene->getStaticANIObject1ById(g_fp->_gameLoader->_field_FA, -1); + if (!ani || (ani->isIdle() && !(ani->_flags & 0x80) && !(ani->_flags & 0x100))) { + result = startWalkTo(g_fp->_gameLoader->_field_FA, -1, cmd->_sceneClickX, cmd->_sceneClickY, 0); + if (result) { + ExCommand *ex = new ExCommand(g_fp->_gameLoader->_field_FA, 17, 64, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = 1; + ex->_excFlags |= 3; + ex->_x = cmd->_sceneClickX; + ex->_y = cmd->_sceneClickY; + ex->postMessage(); + } + } + } else { + cmd->_messageKind = 0; + } + } + return result; + default: + return result; + } + case 58: + g_fp->setCursor(cmd->_keyCode); + return result; + case 59: + setInputDisabled(1); + return result; + case 60: + setInputDisabled(0); + return result; + case 56: + if (cmd->_field_2C) { + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (ani) { + getGameLoaderInventory()->addItem2(ani); + result = 1; + } + } else { + result = 1; + getGameLoaderInventory()->addItem(cmd->_parentId, 1); + } + getGameLoaderInventory()->rebuildItemRects(); + return result; + case 57: + if (cmd->_field_2C) { + if (!cmd->_field_20) { + getGameLoaderInventory()->removeItem2(g_fp->_currentScene, cmd->_parentId, cmd->_x, cmd->_y, cmd->_field_14); + getGameLoaderInventory()->rebuildItemRects(); + return 1; + } + ani = g_fp->_currentScene->getStaticANIObject1ById(g_fp->_gameLoader->_field_FA, -1); + if (ani) { + getGameLoaderInventory()->removeItem2(g_fp->_currentScene, cmd->_parentId, ani->_ox + cmd->_x, ani->_oy + cmd->_y, ani->_priority + cmd->_field_14); + getGameLoaderInventory()->rebuildItemRects(); + return 1; + } + } else { + getGameLoaderInventory()->removeItem(cmd->_parentId, 1); + } + getGameLoaderInventory()->rebuildItemRects(); + return 1; + case 55: + if (g_fp->_currentScene) { + GameObject *obj; + if (cmd->_field_14) + obj = g_fp->_currentScene->getStaticANIObject1ById(cmd->_x, cmd->_y); + else + obj = g_fp->_currentScene->getPictureObjectById(cmd->_x, cmd->_y); + handleObjectInteraction(g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode), obj, cmd->_field_20); + result = 1; + } + return result; + case 51: + return startWalkTo(cmd->_parentId, cmd->_keyCode, cmd->_x, cmd->_y, cmd->_field_20); + case 52: + return doSomeAnimation(cmd->_parentId, cmd->_keyCode, cmd->_field_20); + case 53: + return doSomeAnimation2(cmd->_parentId, cmd->_keyCode); + case 63: + if (cmd->_objtype == kObjTypeObjstateCommand) { + ObjstateCommand *c = (ObjstateCommand *)cmd; + result = 1; + g_fp->setObjectState(c->_objCommandName, c->_value); + } + return result; + default: + return result; + } +} + +int global_messageHandler4(ExCommand *cmd) { + StaticANIObject *ani = 0; + + switch (cmd->_messageKind) { + case 18: { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(cmd->_messageNum), cmd->_parId, 0); + + if (cmd->_excFlags & 1) + mq->_flag1 = 1; + else + mq->_flag1 = 0; + + mq->sendNextCommand(); + break; + } + case 2: + if (!g_fp->_currentScene) + break; + + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->trySetMessageQueue(cmd->_messageNum, cmd->_parId); + break; + + case 1: { + if (!g_fp->_currentScene) + break; + + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + int flags = cmd->_field_14; + if (flags <= 0) + flags = -1; + + if (cmd->_excFlags & 1) + ani->startAnim(cmd->_messageNum, 0, flags); + else + ani->startAnim(cmd->_messageNum, cmd->_parId, flags); + + break; + } + case 8: + if (!g_fp->_currentScene) + break; + + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->startAnimEx(cmd->_messageNum, cmd->_parId, -1, -1); + break; + + case 20: { + if (!g_fp->_currentScene) + break; + + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + int flags = cmd->_field_14; + if (flags <= 0) + flags = -1; + + ExCommand2 *cmd2 = (ExCommand2 *)cmd; + + if (cmd->_excFlags & 1) { + ani->startAnimSteps(cmd->_messageNum, 0, cmd->_x, cmd->_y, cmd2->_points, cmd2->_pointsSize, flags); + } else { + ani->startAnimSteps(cmd->_messageNum, cmd->_parId, cmd->_x, cmd->_y, cmd2->_points, cmd2->_pointsSize, flags); + } + break; + } + case 21: + if (!g_fp->_currentScene) + break; + + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->queueMessageQueue(0); + ani->playIdle(); + break; + case 9: + // Nop in original + break; + case 3: + g_fp->_currentScene->_y = cmd->_messageNum - cmd->_messageNum % g_fp->_scrollSpeed; + break; + + case 4: + g_fp->_currentScene->_x = cmd->_messageNum - cmd->_messageNum % g_fp->_scrollSpeed; + break; + + case 19: { + if (!g_fp->_currentScene) + break; + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + MessageQueue *mq = ani->getMessageQueue(); + MessageQueue *mq2 = ani->changeStatics1(cmd->_messageNum); + + if (!mq2 || !mq2->getExCommandByIndex(0) || !mq) + break; + + mq2->_parId = mq->_id; + mq2->_flag1 = (cmd->_field_24 == 0); + break; + } + case 22: + if (!g_fp->_currentScene) + break; + + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->_flags |= 4; + ani->changeStatics2(cmd->_messageNum); + break; + + case 6: + if (!g_fp->_currentScene) + break; + + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->hide(); + break; + + case 27: + if (!g_fp->_currentScene || g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode) == 0) { + ani = g_fp->accessScene(cmd->_field_20)->getStaticANIObject1ById(cmd->_parentId, -1); + if (ani) { + ani = new StaticANIObject(ani); + g_fp->_currentScene->addStaticANIObject(ani, 1); + } + } + + // fall through + case 5: + if (g_fp->_currentScene) + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + + if (!ani) + break; + + if (cmd->_field_14 >= 0) + ani->_priority = cmd->_field_14; + + ani->show1(cmd->_x, cmd->_y, cmd->_messageNum, cmd->_parId); + break; + + case 10: + if (!g_fp->_currentScene) + break; + + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + if (cmd->_field_14 >= 0) + ani->_priority = cmd->_field_14; + + ani->show2(cmd->_x, cmd->_y, cmd->_messageNum, cmd->_parId); + break; + + case 7: { + if (!g_fp->_currentScene->_picObjList.size()) + break; + + int offX = g_fp->_scrollSpeed * (cmd->_x / g_fp->_scrollSpeed); + int offY = g_fp->_scrollSpeed * (cmd->_y / g_fp->_scrollSpeed); + + if (cmd->_messageNum) { + g_fp->_currentScene->_x = offX - g_fp->_sceneRect.left; + g_fp->_currentScene->_y = offY - g_fp->_sceneRect.top; + + if (cmd->_field_24) { + g_fp->_currentScene->_messageQueueId = cmd->_parId; + } + } else { + g_fp->_sceneRect.translate(offX - g_fp->_sceneRect.left, offY - g_fp->_sceneRect.top); + + g_fp->_currentScene->_x = 0; + g_fp->_currentScene->_y = 0; + + g_fp->_currentScene->updateScrolling2(); + } + break; + } + case 34: + if (!g_fp->_currentScene) + break; + + ani = g_fp->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->_flags = cmd->_messageNum | (ani->_flags & ~cmd->_field_14); + + break; + + case 35: + global_messageHandler_handleSound(cmd); + break; + + case 11: + case 12: + break; + default: + return 0; + break; + } + + return 1; +} + +int MovGraph_messageHandler(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + if (cmd->_messageNum != 33) + return 0; + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(g_fp->_gameLoader->_field_FA, -1); + + if (!getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)) + return 0; + + if (getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->_objtype != kObjTypeMovGraph || !ani) + return 0; + + MovGraph *gr = (MovGraph *)getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId); + + MovGraphLink *link = 0; + double mindistance = 1.0e10; + Common::Point point; + + for (ObList::iterator i = gr->_links.begin(); i != gr->_links.end(); ++i) { + point.x = ani->_ox; + point.y = ani->_oy; + + double dst = gr->calcDistance(&point, (MovGraphLink *)(*i), 0); + if (dst >= 0.0 && dst < mindistance) { + mindistance = dst; + link = (MovGraphLink *)(*i); + } + } + + int top; + + if (link) { + MovGraphNode *node = link->_movGraphNode1; + + double sq = (ani->_oy - node->_y) * (ani->_oy - node->_y) + (ani->_ox - node->_x) * (ani->_ox - node->_x); + int off = (node->_field_14 >> 16) & 0xFF; + double off2 = ((link->_movGraphNode2->_field_14 >> 8) & 0xff) - off; + + top = off + (int)(sqrt(sq) * off2 / link->_z); + } else { + top = (gr->calcOffset(ani->_ox, ani->_oy)->_field_14 >> 8) & 0xff; + } + + if (ani->_movement) { + ani->_movement->_currDynamicPhase->_rect->top = 255 - top; + return 0; + } + + if (ani->_statics) + ani->_statics->_rect->top = 255 - top; + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/messages.cpp b/engines/fullpipe/messages.cpp new file mode 100644 index 0000000000..a7337b98ed --- /dev/null +++ b/engines/fullpipe/messages.cpp @@ -0,0 +1,975 @@ +/* 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/messages.h" +#include "fullpipe/modal.h" +#include "fullpipe/statics.h" +#include "fullpipe/gameloader.h" + +namespace Fullpipe { + +ExCommand::ExCommand() { + _field_3C = 1; + _messageNum = 0; + _excFlags = 0; + _parId = 0; +} + +ExCommand::ExCommand(ExCommand *src) : Message(src) { + _field_3C = 1; + _messageNum = src->_messageNum; + _excFlags = src->_excFlags; + _parId = src->_parId; +} + +ExCommand *ExCommand::createClone() { + return new ExCommand(this); +} + +ExCommand::ExCommand(int16 parentId, int messageKind, int messageNum, int x, int y, int a7, int a8, int sceneClickX, int sceneClickY, int a11) : + Message(parentId, messageKind, x, y, a7, a8, sceneClickX, sceneClickY, a11) { + _field_3C = 1; + _messageNum = messageNum; + _excFlags = 0; + _parId = 0; +} + +bool ExCommand::load(MfcArchive &file) { + debug(5, "ExCommand::load()"); + + _parentId = file.readUint16LE(); + _messageKind = file.readUint32LE(); + _x = file.readUint32LE(); + _y = file.readUint32LE(); + _field_14 = file.readUint32LE(); + _sceneClickX = file.readUint32LE(); + _sceneClickY = file.readUint32LE(); + _field_20 = file.readUint32LE(); + _field_24 = file.readUint32LE(); + _keyCode = file.readUint32LE(); + _field_2C = file.readUint32LE(); + _field_30 = file.readUint32LE(); + _field_34 = file.readUint32LE(); + + _messageNum = file.readUint32LE(); + + _field_3C = 0; + + if (g_fp->_gameProjectVersion >= 12) { + _excFlags = file.readUint32LE(); + _parId = file.readUint32LE(); + } + + _objtype = kObjTypeExCommand; + + return true; +} + +bool ExCommand::handleMessage() { + int cnt = 0; + for (MessageHandler *m = g_fp->_messageHandlers; m; m = m->nextItem) + cnt += m->callback(this); + + if (_messageKind == 17 || (_excFlags & 1)) { + if (_parId) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(_parId); + if (mq) + mq->update(); + } + } + + if (_excFlags & 2) + delete this; + + return (cnt > 0); +} + +void ExCommand::sendMessage() { + g_fp->_exCommandList.push_back(this); + + processMessages(); +} + +void ExCommand::postMessage() { + g_fp->_exCommandList.push_back(this); +} + +void ExCommand::handle() { + if (g_fp->_modalObject) { + g_fp->_modalObject->handleMessage(this); + + delete this; + } else { + postMessage(); + } +} + +void ExCommand::setf3c(int val) { + if (val != -1) + _field_3C = val; + + _field_34 = 1; +} + +void ExCommand::firef34() { + if (_field_34) { + if (_field_3C >= _keyCode) { + _field_34 = 0; + + sendMessage(); + + if (!_field_30 ) + setf3c(_field_2C); + } + } +} + +ExCommand2::ExCommand2(int messageKind, int parentId, Common::Point **points, int pointsSize) : ExCommand(parentId, messageKind, 0, 0, 0, 0, 1, 0, 0, 0) { + _objtype = kObjTypeExCommand2; + + _pointsSize = pointsSize; + _points = (Common::Point **)malloc(sizeof(Common::Point *) * pointsSize); + + for (int i = 0; i < pointsSize; i++) { + _points[i] = new Common::Point; + + *_points[i] = *points[i]; + } +} + +ExCommand2::ExCommand2(ExCommand2 *src) : ExCommand(src) { + _pointsSize = src->_pointsSize; + _points = (Common::Point **)malloc(sizeof(Common::Point *) * _pointsSize); + + for (int i = 0; i < _pointsSize; i++) { + _points[i] = new Common::Point; + + *_points[i] = *src->_points[i]; + } +} + +ExCommand2::~ExCommand2() { + for (int i = 0; i < _pointsSize; i++) + delete _points[i]; + + free(_points); +} + +ExCommand2 *ExCommand2::createClone() { + return new ExCommand2(this); +} + +Message::Message() { + _messageKind = 0; + _parentId = 0; + + _x = 0; + _y = 0; + _field_14 = 0; + _sceneClickX = 0; + _sceneClickY = 0; + _field_20 = 0; + _field_24 = 0; + _keyCode = 0; + _field_2C = 0; + _field_30 = 0; + _field_34 = 0; +} + +Message::Message(Message *src) { + _parentId = src->_parentId; + _messageKind = src->_messageKind; + _x = src->_x; + _y = src->_y; + _field_14 = src->_field_14; + _sceneClickX = src->_sceneClickX; + _sceneClickY = src->_sceneClickY; + _field_20 = src->_field_20; + _field_24 = src->_field_24; + _keyCode = src->_keyCode; + _field_2C = src->_field_2C; + _field_30 = src->_field_30; + _field_34 = src->_field_34; +} + +Message::Message(int16 parentId, int messageKind, int x, int y, int a6, int a7, int sceneClickX, int sceneClickY, int a10) { + _messageKind = messageKind; + _parentId = parentId; + _x = x; + _y = y; + _field_14 = a6; + _sceneClickX = sceneClickX; + _sceneClickY = sceneClickY; + _field_24 = a7; + _field_20 = a10; + _keyCode = 0; + _field_2C = 0; + _field_30 = 0; + _field_34 = 0; +} + +ObjstateCommand::ObjstateCommand() { + _value = 0; + _objCommandName = 0; +} + +ObjstateCommand::ObjstateCommand(ObjstateCommand *src) : ExCommand(src) { + _value = src->_value; + _objCommandName = (char *)calloc(strlen(src->_objCommandName) + 1, 1); + + strncpy(_objCommandName, src->_objCommandName, strlen(src->_objCommandName)); +} + +ObjstateCommand::~ObjstateCommand() { + free(_objCommandName); +} + +bool ObjstateCommand::load(MfcArchive &file) { + debug(5, "ObjStateCommand::load()"); + + _objtype = kObjTypeObjstateCommand; + + ExCommand::load(file); + + _value = file.readUint32LE(); + + _objCommandName = file.readPascalString(); + + return true; +} + +ObjstateCommand *ObjstateCommand::createClone() { + return new ObjstateCommand(this); +} + +MessageQueue::MessageQueue() { + _field_14 = 0; + _parId = 0; + _dataId = 0; + _id = 0; + _isFinished = 0; + _flags = 0; + _queueName = 0; + _counter = 0; + _field_38 = 0; + _flag1 = 0; +} + +MessageQueue::MessageQueue(int dataId) { + _field_14 = 0; + _parId = 0; + _dataId = dataId; + _id = g_fp->_globalMessageQueueList->compact(); + _isFinished = 0; + _flags = 0; + _queueName = 0; + _counter = 0; + _field_38 = 0; + _flag1 = 0; +} + +MessageQueue::MessageQueue(MessageQueue *src, int parId, int field_38) { + _counter = 0; + _field_38 = (field_38 == 0); + + for (Common::List<ExCommand *>::iterator it = src->_exCommands.begin(); it != src->_exCommands.end(); ++it) { + ExCommand *ex = (*it)->createClone(); + ex->_excFlags |= 2; + + _exCommands.push_back(ex); + } + _field_14 = src->_field_14; + + if (parId) + _parId = parId; + else + _parId = src->_parId; + + _id = g_fp->_globalMessageQueueList->compact(); + _dataId = src->_dataId; + _flags = src->_flags; + _queueName = 0; + + g_fp->_globalMessageQueueList->addMessageQueue(this); + + _isFinished = 0; + _flag1 = 0; +} + +MessageQueue::~MessageQueue() { + for (Common::List<ExCommand *>::iterator it = _exCommands.begin(); it != _exCommands.end(); ++it) { + ExCommand *ex = (ExCommand *)*it; + + if (ex && ex->_excFlags & 2) + delete ex; + } + + _exCommands.clear(); + + if (_field_14) + delete _field_14; + + if (_flags & 2) { + g_fp->_globalMessageQueueList->removeQueueById(_id); + } + + finish(); + + free(_queueName); +} + +bool MessageQueue::load(MfcArchive &file) { + debug(5, "MessageQueue::load()"); + + _dataId = file.readUint16LE(); + + int count = file.readUint16LE(); + + assert(g_fp->_gameProjectVersion >= 12); + + _queueName = file.readPascalString(); + + for (int i = 0; i < count; i++) { + ExCommand *tmp = (ExCommand *)file.readClass(); + + _exCommands.push_back(tmp); + } + + _id = -1; + _field_14 = 0; + _parId = 0; + _isFinished = 0; + + return true; +} + +bool MessageQueue::chain(StaticANIObject *ani) { + if (checkGlobalExCommandList1() && checkGlobalExCommandList2()) { + if (!(getFlags() & 2)) { + g_fp->_globalMessageQueueList->addMessageQueue(this); + _flags |= 2; + } + if (ani) { + ani->queueMessageQueue(this); + return true; + } else { + sendNextCommand(); + return true; + } + } + return false; +} + +void MessageQueue::update() { + if (_counter > 0) + _counter--; + + if (getCount()) { + sendNextCommand(); + } else if (_counter == 0) { + _isFinished = 1; + finish(); + } +} + +void MessageQueue::messageQueueCallback1(int par) { + if (g_fp->_isSaveAllowed && par == 16) { + if (g_fp->_globalMessageQueueList->size() && (*g_fp->_globalMessageQueueList)[0] != 0) { + for (uint i = 0; i < g_fp->_globalMessageQueueList->size(); i++) { + if ((*g_fp->_globalMessageQueueList)[i]->_flags & 1) + if ((*g_fp->_globalMessageQueueList)[i] != this && !(*g_fp->_globalMessageQueueList)[i]->_isFinished) + return; + } + } + + if (g_fp->_currentScene) + g_fp->_gameLoader->writeSavegame(g_fp->_currentScene, "savetmp.sav"); + } +} + +void MessageQueue::addExCommand(ExCommand *ex) { + _exCommands.push_front(ex); +} + +void MessageQueue::addExCommandToEnd(ExCommand *ex) { + _exCommands.push_back(ex); +} + +void MessageQueue::insertExCommandAt(int pos, ExCommand *ex) { + Common::List<ExCommand *>::iterator it = _exCommands.begin(); + + for (int i = pos; i > 0; i--) + ++it; + + _exCommands.insert(it, ex); +} + +ExCommand *MessageQueue::getExCommandByIndex(uint idx) { + if (idx >= getCount()) + return 0; + + Common::List<ExCommand *>::iterator it = _exCommands.begin(); + + while (idx) { + ++it; + idx--; + } + + return *it; +} + +void MessageQueue::deleteExCommandByIndex(uint idx, bool doFree) { + if (idx >= getCount()) + return; + + Common::List<ExCommand *>::iterator it = _exCommands.begin(); + + while (idx) { + ++it; + idx--; + } + + if (doFree) + delete *it; + + _exCommands.erase(it); +} + +void MessageQueue::transferExCommands(MessageQueue *mq) { + while (mq->_exCommands.size()) { + _exCommands.push_back(mq->_exCommands.front()); + mq->_exCommands.pop_front(); + } +} + +void MessageQueue::sendNextCommand() { + if (getCount()) { + if (!(_flags & 4) && (_flags & 1)) { + messageQueueCallback1(16); + } + ExCommand *ex = _exCommands.front(); + + _exCommands.pop_front(); + + _counter++; + ex->_parId = _id; + ex->_excFlags |= (ex->_field_24 == 0 ? 1 : 0) | (ex->_field_3C != 0 ? 2 : 0); + + _flags |= 4; + ex->sendMessage(); + } else if (_counter <= 0) { + _isFinished = 1; + finish(); + } +} + +bool MessageQueue::checkGlobalExCommandList1() { + ExCommand *ex, *ex1; + + for (uint i = 0; i < getCount(); i++) { + ex = getExCommandByIndex(i); + + if (ex->_messageKind != 1 && ex->_messageKind != 20 && ex->_messageKind != 5 && ex->_messageKind != 27) + continue; + + for (Common::List<ExCommand *>::iterator it = g_fp->_exCommandList.begin(); it != g_fp->_exCommandList.end(); it++) { + ex1 = *it; + + if (ex1->_messageKind != 1 && ex1->_messageKind != 20 && ex1->_messageKind != 5 && ex1->_messageKind != 27) + continue; + + if (ex1->_keyCode != ex->_keyCode && ex1->_keyCode != -1 && ex->_keyCode != -1) + continue; + + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(ex1->_parId); + + if (mq) { + if (mq->getFlags() & 1) + return false; + } + } + } + return true; +} + +bool MessageQueue::checkGlobalExCommandList2() { + ExCommand *ex, *ex1; + + for (uint i = 0; i < getCount(); i++) { + ex = getExCommandByIndex(i); + + if (ex->_messageKind != 1 && ex->_messageKind != 20 && ex->_messageKind != 5 && ex->_messageKind != 27) + continue; + + for (Common::List<ExCommand *>::iterator it = g_fp->_exCommandList.begin(); it != g_fp->_exCommandList.end();) { + ex1 = *it; + + if (ex1->_messageKind != 1 && ex1->_messageKind != 20 && ex1->_messageKind != 5 && ex1->_messageKind != 27) { + it++; + continue; + } + + if (ex1->_keyCode != ex->_keyCode && ex1->_keyCode != -1 && ex->_keyCode != -1) { + it++; + continue; + } + + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(ex1->_parId); + + if (mq) { + if (mq->getFlags() & 1) + return false; + + delete mq; + } + + it = g_fp->_exCommandList.erase(it); + + if (ex1->_excFlags & 2) { + delete ex1; + } + } + } + return true; +} + +void MessageQueue::finish() { + if (!_parId) + return; + + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(_parId); + + _parId = 0; + + if (!mq) + return; + + if (!_flag1) { + mq->update(); + return; + } + + mq->_counter--; + + if (!mq->_counter && !mq->_exCommands.size()) + mq->update(); +} + +void MessageQueue::replaceKeyCode(int key1, int key2) { + for (uint i = 0; i < getCount(); i++) { + ExCommand *ex = getExCommandByIndex(i); + int k = ex->_messageKind; + if ((k == 1 || k == 20 || k == 5 || k == 6 || k == 2 || k == 18 || k == 19 || k == 22 || k == 55) + && ex->_keyCode == key1) + ex->_keyCode = key2; + } +} + +int MessageQueue::calcDuration(StaticANIObject *obj) { + int res = 0; + ExCommand *ex; + Movement *mov; + + for (uint i = 0; i < getCount(); i++) { + ex = getExCommandByIndex(i); + if (ex->_parentId == obj->_id) { + if (ex->_messageKind == 1 || ex->_messageKind == 20) { + if ((mov = obj->getMovementById(ex->_messageNum)) != 0) { + if (ex->_field_14 >= 1) + res += ex->_field_14; + else + res += mov->calcDuration(); + } + } + } + } + + return res; +} + +void MessageQueue::changeParam28ForObjectId(int objId, int oldParam28, int newParam28) { + for (uint i = 0; i < getCount(); i++) { + ExCommand *ex = getExCommandByIndex(i); + int k = ex->_messageKind; + + if ((k == 1 || k == 20 || k == 5 || k == 6 || k == 2 || k == 18 || k == 19 || k == 22 || k == 55) + && ex->_keyCode == oldParam28 + && ex->_parentId == objId) + ex->_keyCode = newParam28; + } +} + +int MessageQueue::activateExCommandsByKind(int kind) { + int res = 0; + + for (uint i = 0; i < getCount(); i++) { + ExCommand *ex = getExCommandByIndex(i); + + if (ex->_messageKind == kind) { + ex->_messageKind = 0; + ex->_excFlags |= 1; + + res++; + } + } + + return res; +} + +MessageQueue *GlobalMessageQueueList::getMessageQueueById(int id) { + for (Common::Array<MessageQueue *>::iterator s = begin(); s != end(); ++s) { + if ((*s)->_id == id) + return *s; + } + + return 0; +} + +void GlobalMessageQueueList::deleteQueueById(int id) { + for (uint i = 0; i < size(); i++) + if (_storage[i]->_id == id) { + remove_at(i); + + disableQueueById(id); + return; + } +} + +void GlobalMessageQueueList::removeQueueById(int id) { + for (uint i = 0; i < size(); i++) + if (_storage[i]->_id == id) { + _storage[i]->_flags &= 0xFD; // It is quite pointless + remove_at(i); + + disableQueueById(id); + return; + } +} + +void GlobalMessageQueueList::disableQueueById(int id) { + for (Common::Array<MessageQueue *>::iterator s = begin(); s != end(); ++s) { + if ((*s)->_parId == id) + (*s)->_parId = 0; + } +} + +int GlobalMessageQueueList::compact() { + int *useList = new int[size() + 2]; + + for (uint i = 0; i < size() + 2; i++) + useList[i] = 0; + + for (uint i = 0; i < size();) { + if (((MessageQueue *)_storage[i])->_isFinished) { + disableQueueById(_storage[i]->_id); + remove_at(i); + } else { + if ((uint)_storage[i]->_id < size() + 2) + useList[_storage[i]->_id] = 1; + i++; + } + } + + uint i; + + for (i = 1; i < size() + 2; i++) { + if (!useList[i]) + break; + } + + delete [] useList; + + return i; +} + +void GlobalMessageQueueList::addMessageQueue(MessageQueue *msg) { + msg->setFlags(msg->getFlags() | 2); + + push_back(msg); +} + +void clearGlobalMessageQueueList() { + g_fp->_globalMessageQueueList->clear(); +} + +void clearGlobalMessageQueueList1() { + clearMessages(); + + g_fp->_globalMessageQueueList->clear(); +} + +void clearMessages() { + while (g_fp->_exCommandList.size()) { + ExCommand *ex = g_fp->_exCommandList.front(); + + g_fp->_exCommandList.pop_front(); + + if (ex->_excFlags & 2) + delete ex; + } +} + +bool removeMessageHandler(int16 id, int pos) { + if (g_fp->_messageHandlers) { + MessageHandler *curItem = g_fp->_messageHandlers; + MessageHandler *prevItem = 0; + int curPos = 0; + + while (id != curItem->id) { + prevItem = curItem; + curItem = curItem->nextItem; + curPos++; + + if (!curItem) + return false; + } + + if (pos == -1 || curPos == pos) { + prevItem->nextItem = curItem->nextItem; + delete curItem; + updateMessageHandlerIndex(prevItem->nextItem, -1); + + return true; + } + } + + return false; +} + +void updateMessageHandlerIndex(MessageHandler *msg, int offset) { + for (; msg; msg = msg->nextItem) + msg->index += offset; +} + +void addMessageHandler(int (*callback)(ExCommand *), int16 id) { + if (getMessageHandlerById(id)) + return; + + MessageHandler *curItem = g_fp->_messageHandlers; + + if (!curItem) + return; + + int index = 0; + for (MessageHandler *i = g_fp->_messageHandlers->nextItem; i; i = i->nextItem) { + curItem = i; + index++; + } + + allocMessageHandler(curItem, id, callback, index); + + if (curItem) + updateMessageHandlerIndex(curItem->nextItem->nextItem, 1); +} + +MessageHandler *getMessageHandlerById(int16 id) { + MessageHandler *curItem = g_fp->_messageHandlers; + + if (!curItem) + return 0; + + while (id != curItem->id) { + curItem = curItem->nextItem; + + if (!curItem) + return 0; + } + + return curItem; +} + +bool allocMessageHandler(MessageHandler *where, int16 id, int (*callback)(ExCommand *), int index) { + MessageHandler *msg = new MessageHandler; + + if (where) { + msg->nextItem = where->nextItem; + where->nextItem = msg; + msg->id = id; + msg->callback = callback; + msg->index = index; + } else { + msg->nextItem = 0; + msg->id = id; + msg->callback = callback; + msg->index = 0; + + g_fp->_messageHandlers = msg; + } + + return true; +} + +int getMessageHandlersCount() { + int result; + MessageHandler *curItem = g_fp->_messageHandlers; + + for (result = 0; curItem; result++) + curItem = curItem->nextItem; + + return result; +} + +bool addMessageHandlerByIndex(int (*callback)(ExCommand *), int index, int16 id) { + if (getMessageHandlerById(id)) + return false; + + if (index) { + MessageHandler *curItem = g_fp->_messageHandlers; + + for (int i = index - 1; i > 0; i--) + if (curItem) + curItem = curItem->nextItem; + + if (!curItem) + return false; + + bool res = allocMessageHandler(curItem, id, callback, index); + + if (res) + updateMessageHandlerIndex(curItem->nextItem->nextItem, 1); + + return res; + } else { + MessageHandler *newItem = new MessageHandler; + + newItem->nextItem = g_fp->_messageHandlers; + newItem->id = id; + newItem->callback = callback; + newItem->index = 0; + + updateMessageHandlerIndex(g_fp->_messageHandlers, 1); + g_fp->_messageHandlers = newItem; + + return true; + } +} + +bool insertMessageHandler(int (*callback)(ExCommand *), int index, int16 id) { + if (getMessageHandlerById(id)) + return false; + + MessageHandler *curItem = g_fp->_messageHandlers; + + for (int i = index; i > 0; i--) + if (curItem) + curItem = curItem->nextItem; + + bool res = allocMessageHandler(curItem, id, callback, index + 1); + if (curItem) + updateMessageHandlerIndex(curItem->nextItem->nextItem, 1); + + return res; +} + +void clearMessageHandlers() { + MessageHandler *curItem; + MessageHandler *nextItem; + + curItem = g_fp->_messageHandlers; + if (curItem) { + do { + nextItem = curItem->nextItem; + + delete curItem; + + curItem = nextItem; + } while (nextItem); + + g_fp->_messageHandlers = 0; + } +} + +void processMessages() { + if (!g_fp->_isProcessingMessages) { + g_fp->_isProcessingMessages = true; + + while (g_fp->_exCommandList.size()) { + ExCommand *ex = g_fp->_exCommandList.front(); + g_fp->_exCommandList.pop_front(); + ex->handleMessage(); + } + g_fp->_isProcessingMessages = false; + } +} + +void updateGlobalMessageQueue(int id, int objid) { + MessageQueue *m = g_fp->_globalMessageQueueList->getMessageQueueById(id); + if (m) { + m->update(); + } +} + +bool chainQueue(int queueId, int flags) { + MessageQueue *mq = g_fp->_currentScene->getMessageQueueById(queueId); + + if (!mq) + return false; + + MessageQueue *nmq = new MessageQueue(mq, 0, 0); + + nmq->_flags |= flags; + + if (!nmq->chain(0)) { + delete nmq; + + return false; + } + + return true; +} + +bool chainObjQueue(StaticANIObject *obj, int queueId, int flags) { + MessageQueue *mq = g_fp->_currentScene->getMessageQueueById(queueId); + + if (!mq) + return false; + + MessageQueue *nmq = new MessageQueue(mq, 0, 0); + + nmq->_flags |= flags; + + if (!nmq->chain(obj)) { + delete nmq; + + return false; + } + + return true; +} + +void postExCommand(int parentId, int keyCode, int x, int y, int f20, int f14) { + ExCommand *ex = new ExCommand(parentId, 17, 64, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = keyCode; + ex->_excFlags |= 3; + ex->_x = x; + ex->_y = y; + ex->_field_20 = f20; + ex->_field_14 = f14; + + ex->postMessage(); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/messages.h b/engines/fullpipe/messages.h new file mode 100644 index 0000000000..e6f7f05150 --- /dev/null +++ b/engines/fullpipe/messages.h @@ -0,0 +1,205 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_MESSAGEQUEUE_H +#define FULLPIPE_MESSAGEQUEUE_H + +#include "fullpipe/utils.h" +#include "fullpipe/inventory.h" +#include "fullpipe/gfx.h" +#include "fullpipe/sound.h" +#include "fullpipe/scene.h" + +namespace Fullpipe { + +class Message : public CObject { + public: + int _messageKind; + int16 _parentId; + int _x; + int _y; + int _field_14; + int _sceneClickX; + int _sceneClickY; + int _field_20; + int _field_24; + int _keyCode; + int _field_2C; + int _field_30; + int _field_34; + + public: + Message(); + Message(Message *src); + virtual ~Message() {} + + Message(int16 parentId, int messageKind, int x, int y, int a6, int a7, int sceneClickX, int sceneClickY, int a10); +}; + +class ExCommand : public Message { + public: + int _messageNum; + int _field_3C; + int _excFlags; + int _parId; + + ExCommand(); + ExCommand(ExCommand *src); + ExCommand(int16 parentId, int messageKind, int messageNum, int x, int y, int a7, int a8, int sceneClickX, int sceneClickY, int a11); + virtual ~ExCommand() {} + + virtual bool load(MfcArchive &file); + + virtual ExCommand *createClone(); + + bool handleMessage(); + void sendMessage(); + void postMessage(); + void handle(); + + void firef34(); + void setf3c(int val); +}; + +class ExCommand2 : public ExCommand { + public: + Common::Point **_points; + int _pointsSize; + + ExCommand2(int messageKind, int parentId, Common::Point **points, int pointsSize); + ExCommand2(ExCommand2 *src); + virtual ~ExCommand2(); + + virtual ExCommand2 *createClone(); +}; + +class ObjstateCommand : public ExCommand { + public: + char *_objCommandName; + int _value; + + public: + ObjstateCommand(); + ObjstateCommand(ObjstateCommand *src); + virtual ~ObjstateCommand(); + + virtual bool load(MfcArchive &file); + + virtual ObjstateCommand *createClone(); +}; + +class MessageQueue : public CObject { + public: + int _id; + int _flags; + char *_queueName; + int16 _dataId; + CObject *_field_14; + int _counter; + int _field_38; + int _isFinished; + int _parId; + int _flag1; + + private: + Common::List<ExCommand *> _exCommands; + + public: + MessageQueue(); + MessageQueue(int dataId); + MessageQueue(MessageQueue *src, int parId, int field_38); + virtual ~MessageQueue(); + + virtual bool load(MfcArchive &file); + + int getFlags() { return _flags; } + void setFlags(int flags) { _flags = flags; } + + uint getCount() { return _exCommands.size(); } + + void addExCommand(ExCommand *ex); + void addExCommandToEnd(ExCommand *ex); + void insertExCommandAt(int pos, ExCommand *ex); + ExCommand *getExCommandByIndex(uint idx); + void deleteExCommandByIndex(uint idx, bool doFree); + + void transferExCommands(MessageQueue *mq); + + void replaceKeyCode(int key1, int key2); + + bool chain(StaticANIObject *ani); + void update(); + void sendNextCommand(); + void finish(); + + void messageQueueCallback1(int par); + + bool checkGlobalExCommandList1(); + bool checkGlobalExCommandList2(); + + int calcDuration(StaticANIObject *obj); + void changeParam28ForObjectId(int objId, int oldParam28, int newParam28); + + int activateExCommandsByKind(int kind); +}; + +class GlobalMessageQueueList : public Common::Array<MessageQueue *> { + public: + MessageQueue *getMessageQueueById(int id); + void deleteQueueById(int id); + void removeQueueById(int id); + void disableQueueById(int id); + void addMessageQueue(MessageQueue *msg); + + int compact(); +}; + +struct MessageHandler { + int (*callback)(ExCommand *cmd); + int16 id; + int16 field_6; + int index; + MessageHandler *nextItem; +}; + +bool removeMessageHandler(int16 id, int pos); +void updateMessageHandlerIndex(MessageHandler *msg, int offset); +void addMessageHandler(int (*callback)(ExCommand *), int16 id); +MessageHandler *getMessageHandlerById(int16 id); +bool allocMessageHandler(MessageHandler *where, int16 id, int (*callback)(ExCommand *), int index); +int getMessageHandlersCount(); +bool addMessageHandlerByIndex(int (*callback)(ExCommand *), int index, int16 id); +bool insertMessageHandler(int (*callback)(ExCommand *), int index, int16 id); +void clearMessageHandlers(); +void processMessages(); +void updateGlobalMessageQueue(int id, int objid); +void clearMessages(); +void clearGlobalMessageQueueList(); +void clearGlobalMessageQueueList1(); + +bool chainQueue(int queueId, int flags); +bool chainObjQueue(StaticANIObject *obj, int queueId, int flags); +void postExCommand(int parentId, int keyCode, int x, int y, int f20, int f16); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MESSAGEQUEUE_H */ diff --git a/engines/fullpipe/mgm.cpp b/engines/fullpipe/mgm.cpp new file mode 100644 index 0000000000..1c8ca2a7b1 --- /dev/null +++ b/engines/fullpipe/mgm.cpp @@ -0,0 +1,720 @@ +/* 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/utils.h" +#include "fullpipe/statics.h" +#include "fullpipe/motion.h" +#include "fullpipe/messages.h" + +namespace Fullpipe { + +void MGM::clear() { + _items.clear(); +} + +MessageQueue *MGM::genMQ(StaticANIObject *ani, int staticsIndex, int staticsId, int *resStatId, Common::Point **pointArr) { + int idx = getItemIndexById(ani->_id); + + if (idx == -1) + return 0; + + int stid = staticsId; + + if (!staticsId) { + if (ani->_movement) { + stid = ani->_movement->_staticsObj2->_staticsId; + } else { + if (!ani->_statics) + return 0; + + stid = ani->_statics->_staticsId; + } + } + + if (stid == staticsIndex) + return new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + int startidx = getStaticsIndexById(idx, stid); + int endidx = getStaticsIndexById(idx, staticsIndex); + int subidx = startidx + endidx * _items[idx]->statics.size(); + + if (!_items[idx]->subItems[subidx]->movement) { + clearMovements2(idx); + recalcOffsets(idx, startidx, endidx, 0, 1); + } + + if (!_items[idx]->subItems[subidx]->movement) + return 0; + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + Common::Point point; + ExCommand *ex; + + int i = 0; + do { + subidx = startidx + endidx * _items[idx]->statics.size(); + + _items[idx]->subItems[subidx]->movement->calcSomeXY(point, 0, -1); + + if (pointArr) { + int sz; + + if (_items[idx]->subItems[subidx]->movement->_currMovement) + sz = _items[idx]->subItems[subidx]->movement->_currMovement->_dynamicPhases.size(); + else + sz = _items[idx]->subItems[subidx]->movement->_dynamicPhases.size(); + + ex = new ExCommand2(20, ani->_id, &pointArr[i], sz); + + ex->_messageNum = _items[idx]->subItems[subidx]->movement->_id; + } else { + ex = new ExCommand(ani->_id, 1, _items[idx]->subItems[subidx]->movement->_id, 0, 0, 0, 1, 0, 0, 0); + } + + ex->_keyCode = ani->_okeyCode; + ex->_field_3C = 1; + ex->_field_24 = 1; + + mq->addExCommandToEnd(ex); + + if (resStatId) + *resStatId = _items[idx]->subItems[subidx]->movement->_id; + + startidx = _items[idx]->subItems[subidx]->staticsIndex; + + uint step; + + if (_items[idx]->subItems[subidx]->movement->_currMovement) + step = _items[idx]->subItems[subidx]->movement->_currMovement->_dynamicPhases.size(); + else + step = _items[idx]->subItems[subidx]->movement->_dynamicPhases.size(); + + i += step; + } while (startidx != endidx); + + return mq; +} + +MGMItem::MGMItem() { + objId = 0; +} + +MGMSubItem::MGMSubItem() { + movement = 0; + staticsIndex = 0; + field_8 = 0; + field_C = 0; + x = 0; + y = 0; +} + +void MGM::addItem(int objId) { + if (getItemIndexById(objId) == -1) { + MGMItem *item = new MGMItem(); + + item->objId = objId; + _items.push_back(item); + } + rebuildTables(objId); +} + +void MGM::rebuildTables(int objId) { + int idx = getItemIndexById(objId); + + if (idx == -1) + return; + + _items[idx]->subItems.clear(); + _items[idx]->statics.clear(); + _items[idx]->movements1.clear(); + _items[idx]->movements2.clear(); + + StaticANIObject *obj = g_fp->_currentScene->getStaticANIObject1ById(objId, -1); + + if (!obj) + return; + + for (uint i = 0; i < obj->_staticsList.size(); i++) { + _items[idx]->statics.push_back((Statics *)obj->_staticsList[i]); + + _items[idx]->subItems.push_back(new MGMSubItem); + } + + for (uint i = 0; i < obj->_movements.size(); i++) + _items[idx]->movements1.push_back((Movement *)obj->_movements[i]); +} + +int MGM::getItemIndexById(int objId) { + for (uint i = 0; i < _items.size(); i++) + if (_items[i]->objId == objId) + return i; + + return -1; +} + +MessageQueue *MGM::genMovement(MGMInfo *mgminfo) { + if (!mgminfo->ani) + return 0; + + Movement *mov = mgminfo->ani->_movement; + + if (!mov && !mgminfo->ani->_statics) + return 0; + + if (!(mgminfo->flags & 1)) { + if (mov) + mgminfo->staticsId1 = mov->_staticsObj2->_staticsId; + else + mgminfo->staticsId1 = mgminfo->ani->_statics->_staticsId; + } + + Common::Point point; + + if (!(mgminfo->flags & 0x10) || !(mgminfo->flags & 0x20)) { + int nx = mgminfo->ani->_ox; + int ny = mgminfo->ani->_oy; + + if (mgminfo->ani->_movement) { + mgminfo->ani->calcNextStep(&point); + + nx += point.x; + ny += point.y; + } + + if (!(mgminfo->flags & 0x10)) + mgminfo->x2 = nx; + + if (!(mgminfo->flags & 0x20)) + mgminfo->y2 = ny; + } + + mov = mgminfo->ani->getMovementById(mgminfo->movementId); + + if (!mov) + return 0; + + int itemIdx = getItemIndexById(mgminfo->ani->_id); + int subIdx = getStaticsIndexById(itemIdx, mgminfo->staticsId1); + int st2idx = getStaticsIndexById(itemIdx, mov->_staticsObj1->_staticsId); + int st1idx = getStaticsIndexById(itemIdx, mov->_staticsObj2->_staticsId); + int subOffset = getStaticsIndexById(itemIdx, mgminfo->staticsId2); + + clearMovements2(itemIdx); + recalcOffsets(itemIdx, subIdx, st2idx, 0, 1); + clearMovements2(itemIdx); + recalcOffsets(itemIdx, st1idx, subOffset, 0, 1); + + MGMSubItem *sub1 = _items[itemIdx]->subItems[subIdx + st2idx * _items[itemIdx]->statics.size()]; + MGMSubItem *sub2 = _items[itemIdx]->subItems[st1idx + subOffset * _items[itemIdx]->statics.size()]; + + if (subIdx != st2idx && !sub1->movement) + return 0; + + if (st1idx != subOffset && !sub2->movement) + return 0; + + int n1x = mgminfo->x1 - mgminfo->x2 - sub1->x - sub2->x; + int n1y = mgminfo->y1 - mgminfo->y2 - sub1->y - sub2->y; + + Common::Point point1; + + mov->calcSomeXY(point1, 0, -1); + + int n2x = point1.x; + int n2y = point1.y; + int mult; + int len = -1; + + if (mgminfo->flags & 0x40) { + mult = mgminfo->field_10; + len = -1; + n2x *= mult; + n2y *= mult; + } else { + calcLength(&point, mov, n1x, n1y, &mult, &len, 1); + n2x = point.x; + n2y = point.y; + } + + if (!(mgminfo->flags & 2)) { + len = -1; + n2x = mult * point1.x; + n1x = mult * point1.x; + mgminfo->x1 = mgminfo->x2 + mult * point1.x + sub1->x + sub2->x; + } + + if (!(mgminfo->flags & 4)) { + n2y = mult * point1.y; + n1y = mult * point1.y; + len = -1; + mgminfo->y1 = mgminfo->y2 + mult * point1.y + sub1->y + sub2->y; + } + + int px = 0; + int py = 0; + + if (sub1->movement) { + px = countPhases(itemIdx, subIdx, st2idx, 1); + py = countPhases(itemIdx, subIdx, st2idx, 2); + } + + if (mult > 1) { + px += (mult - 1) * mov->countPhasesWithFlag(-1, 1); + py += (mult - 1) * mov->countPhasesWithFlag(-1, 2); + } + + if (mult > 0) { + px += mov->countPhasesWithFlag(len, 1); + py += mov->countPhasesWithFlag(len, 2); + } + + if (sub2->movement) { + px += countPhases(itemIdx, st1idx, subOffset, 1); + py += countPhases(itemIdx, st1idx, subOffset, 2); + } + + int dx1 = n1x - n2x; + int dy1 = n1y - n2y; + int x1, y1; + + if (px) { + x1 = (int)((double)dx1 / (double)px); + } else { + x1 = 0; + } + + if (py) { + y1 = (int)((double)dy1 / (double)py); + } else { + y1 = 0; + } + + Common::Point x2, y2; + + y2.x = dx1 - px * x1; + y2.y = dy1 - py * y1; + + if (n1x - n2x == px * x1) + x2.x = 0; + else + x2.x = (dx1 - px * x1) / abs(dx1 - px * x1); + + if (dy1 == py * y1) + x2.y = 0; + else + x2.y = (dy1 - py * y1) / abs(dy1 - py * y1); + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + ExCommand2 *ex2; + + for (int i = subIdx; i != st2idx;) { + MGMSubItem *s = _items[itemIdx]->subItems[i + subOffset * _items[itemIdx]->statics.size()]; + + ex2 = buildExCommand2(s->movement, mgminfo->ani->_id, x1, y1, &x2, &y2, -1); + ex2->_parId = mq->_id; + ex2->_keyCode = mgminfo->ani->_okeyCode; + + mq->addExCommandToEnd(ex2); + + i = s->staticsIndex; + } + + for (int i = 0; i < mult; ++i) { + int plen; + + if (i == mult - 1) + plen = len; + else + plen = -1; + + ex2 = buildExCommand2(mov, mgminfo->ani->_id, x1, y1, &x2, &y2, plen); + ex2->_parId = mq->_id; + ex2->_keyCode = mgminfo->ani->_okeyCode; + + mq->addExCommandToEnd(ex2); + } + + for (int j = st1idx; j != subOffset;) { + MGMSubItem *s = _items[itemIdx]->subItems[j + subOffset * _items[itemIdx]->statics.size()]; + + ex2 = buildExCommand2(s->movement, mgminfo->ani->_id, x1, y1, &x2, &y2, -1); + ex2->_parId = mq->_id; + ex2->_keyCode = mgminfo->ani->_okeyCode; + + mq->addExCommandToEnd(ex2); + + j = s->staticsIndex; + } + + ExCommand *ex = new ExCommand(mgminfo->ani->_id, 5, -1, mgminfo->x1, mgminfo->y1, 0, 1, 0, 0, 0); + + ex->_field_14 = mgminfo->field_1C; + ex->_keyCode = mgminfo->ani->_okeyCode; + ex->_field_24 = 0; + ex->_excFlags |= 3; + + mq->addExCommandToEnd(ex); + + return mq; +} + +int MGM::countPhases(int idx, int subIdx, int endIdx, int flag) { + int res = 0; + + if (endIdx < 0) + return 0; + + while (subIdx != endIdx) { + if (subIdx < 0) + break; + + res += _items[idx]->subItems[subIdx + endIdx * _items[idx]->statics.size()]->movement->countPhasesWithFlag(-1, flag); + + subIdx = _items[idx]->subItems[subIdx + 6 * endIdx * _items[idx]->statics.size()]->staticsIndex; + } + + return res; +} +void MGM::updateAnimStatics(StaticANIObject *ani, int staticsId) { + if (getItemIndexById(ani->_id) == -1) + return; + + if (ani->_movement) { + ani->queueMessageQueue(0); + ani->_movement->gotoLastFrame(); + ani->_statics = ani->_movement->_staticsObj2; + + int x = ani->_movement->_ox; + int y = ani->_movement->_oy; + + ani->_movement = 0; + + ani->setOXY(x, y); + } + + if (ani->_statics) { + Common::Point point; + + getPoint(&point, ani->_id, ani->_statics->_staticsId, staticsId); + + ani->setOXY(ani->_ox + point.x, ani->_oy + point.y); + + ani->_statics = ani->getStaticsById(staticsId); + } +} + +Common::Point *MGM::getPoint(Common::Point *point, int objectId, int staticsId1, int staticsId2) { + int idx = getItemIndexById(objectId); + + if (idx == -1) { + point->x = -1; + point->y = -1; + } else { + int st1idx = getStaticsIndexById(idx, staticsId1); + int st2idx = getStaticsIndexById(idx, staticsId2); + + if (st1idx == st2idx) { + point->x = 0; + point->y = 0; + } else { + int subidx = st1idx + st2idx * _items[idx]->statics.size(); + + if (!_items[idx]->subItems[subidx]->movement) { + clearMovements2(idx); + recalcOffsets(idx, st1idx, st2idx, false, true); + + if (!_items[idx]->subItems[subidx]->movement) { + clearMovements2(idx); + recalcOffsets(idx, st1idx, st2idx, true, false); + } + } + + MGMSubItem *sub = _items[idx]->subItems[subidx]; + + if (sub->movement) { + point->x = sub->x; + point->y = sub->y; + } else { + point->x = 0; + point->y = 0; + } + } + } + + return point; +} + +int MGM::getStaticsIndexById(int idx, int16 id) { + if (!_items[idx]->statics.size()) + return -1; + + for (uint i = 0; i < _items[idx]->statics.size(); i++) { + if (_items[idx]->statics[i]->_staticsId == id) + return i; + } + + return 0; +} + +int MGM::getStaticsIndex(int idx, Statics *st) { + if (!_items[idx]->statics.size()) + return -1; + + for (uint i = 0; i < _items[idx]->statics.size(); i++) { + if (_items[idx]->statics[i] == st) + return i; + } + + return 0; +} + +void MGM::clearMovements2(int idx) { + _items[idx]->movements2.clear(); +} + +int MGM::recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop) { + MGMItem *item = _items[idx]; + int subIdx = st1idx + st2idx * item->statics.size(); + + if (st1idx == st2idx) { + memset(&item->subItems[subIdx], 0, sizeof(item->subItems[subIdx])); + return 0; + } + + if (item->subItems[subIdx]) + return item->subItems[subIdx]->field_8; + + Common::Point point; + + for (uint i = 0; i < item->movements1.size(); i++) { + Movement *mov = item->movements1[i]; + + if (mov->_staticsObj1 == item->statics[st1idx]) { + if (!item->movements2[i] && (!flop || mov->_field_50)) { + item->movements2[i] = 1; + + int stidx = getStaticsIndex(idx, item->movements1[i]->_staticsObj2); + int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop); + int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + int newsz = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C; + + if (recalc >= 0) { + if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1 || + (item->subItems[subIdx]->field_8 == recalc + 1 && item->subItems[subIdx]->field_C > newsz)) { + item->subItems[subIdx]->movement = mov; + item->subItems[subIdx]->staticsIndex = stidx; + item->subItems[subIdx]->field_8 = recalc + 1; + item->subItems[subIdx]->field_C = newsz; + + mov->calcSomeXY(point, 0, -1); + + item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x + point.x; + item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y + point.y; + } + } + } + } else if (flip) { + if (mov->_staticsObj2 == item->statics[st1idx]) { + if (!item->movements2[i] && (!flop || mov->_field_50)) { + item->movements2[i] = 1; + + int stidx = getStaticsIndex(idx, mov->_staticsObj1); + int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop); + + if (recalc >= 0) { + if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1) { + item->subItems[subIdx]->movement = mov; + item->subItems[subIdx]->staticsIndex = stidx; + item->subItems[subIdx]->field_8 = recalc + 1; + + int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + + item->subItems[subIdx]->field_C = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C; + + mov->calcSomeXY(point, 0, -1); + + item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x - point.x; + item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y - point.y; + } + } + } + } + } + } + + if (item->subItems[subIdx]->movement) + return item->subItems[subIdx]->field_8; + + return -1; +} + +int MGM::refreshOffsets(int objectId, int idx1, int idx2) { + int idx = getItemIndexById(objectId); + + if (idx != -1) { + int from = getStaticsIndexById(idx, idx1); + int to = getStaticsIndexById(idx, idx2); + + MGMSubItem *sub = _items[idx]->subItems[from + to * _items[idx]->statics.size()]; + + if (sub->movement) { + idx = sub->field_8; + } else { + clearMovements2(idx); + idx = recalcOffsets(idx, from, to, 0, 1); + } + } + + return idx; +} + +Common::Point *MGM::calcLength(Common::Point *pRes, Movement *mov, int x, int y, int *mult, int *len, int flag) { + Common::Point point; + + mov->calcSomeXY(point, 0, -1); + int p1x = point.x; + int p1y = point.y; + + int newmult = 0; + int oldlen = *len; + + if (abs(p1y) > abs(p1x)) { + if (mov->calcSomeXY(point, 0, -1)->y) + newmult = (int)((double)y / mov->calcSomeXY(point, 0, -1)->y); + } else if (mov->calcSomeXY(point, 0, -1)->x) { + newmult = (int)((double)x / mov->calcSomeXY(point, 0, -1)->x); + } + + if (newmult < 0) + newmult = 0; + + *mult = newmult; + + int phase = 1; + int sz; + + if (flag) { + if (abs(p1y) > abs(p1x)) { + while (abs(p1y * newmult + mov->calcSomeXY(point, 0, phase)->y) < abs(y)) { + sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + + if (phase > sz) + break; + + phase++; + } + } else { + while (abs(p1x * newmult + mov->calcSomeXY(point, 0, phase)->x) < abs(x)) { + sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + + if (phase >= sz) + break; + + phase++; + } + } + + *len = phase - 1; + } else { + *len = -1; + } + + int p2x = 0; + int p2y = 0; + + if (!oldlen) + oldlen = -1; + + if (oldlen > 0) { + ++*mult; + + mov->calcSomeXY(point, 0, oldlen); + p2x = point.x; + p2y = point.y; + + if (abs(p1y) > abs(p1x)) + p2x = p1x; + else + p2y = p1y; + } + + pRes->x = p2x + p1x * newmult; + pRes->y = p2y + p1y * newmult; + + return pRes; +} + +ExCommand2 *MGM::buildExCommand2(Movement *mov, int objId, int x1, int y1, Common::Point *x2, Common::Point *y2, int len) { + uint cnt; + + if (mov->_currMovement) + cnt = mov->_currMovement->_dynamicPhases.size(); + else + cnt = mov->_dynamicPhases.size(); + + if (len > 0 && cnt > (uint)len) + cnt = len; + + Common::Point **points = (Common::Point **)malloc(sizeof(Common::Point *) * cnt); + + for (uint i = 0; i < cnt; i++) { + int flags = mov->getDynamicPhaseByIndex(i)->getDynFlags(); + + points[i] = new Common::Point; + + if (flags & 1) { + points[i]->x = x1 + x2->x; + + y2->x -= x2->x; + + if (!y2->x) + x2->x = 0; + } + + if (flags & 2) { + points[i]->y = y1 + x2->y; + + y2->y -= x2->y; + + if (!y2->y) + x2->y = 0; + } + } + + ExCommand2 *ex = new ExCommand2(20, objId, points, cnt); + ex->_excFlags = 2; + ex->_messageNum = mov->_id; + ex->_field_14 = len; + ex->_field_24 = 1; + ex->_keyCode = -1; + + for (uint i = 0; i < cnt; i++) + delete points[i]; + + free(points); + + return ex; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/mgm.h b/engines/fullpipe/mgm.h new file mode 100644 index 0000000000..13195891da --- /dev/null +++ b/engines/fullpipe/mgm.h @@ -0,0 +1,95 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_MGM_H +#define FULLPIPE_MGM_H + +namespace Fullpipe { + +class ExCommand2; +class Movement; +class Statics; + +struct MGMSubItem { + Movement *movement; + int staticsIndex; + int field_8; + int field_C; + int x; + int y; + + MGMSubItem(); +}; + +struct MGMItem { + int16 objId; + Common::Array<MGMSubItem *> subItems; + Common::Array<Statics *> statics; + Common::Array<Movement *> movements1; + Common::Array<int> movements2; + + MGMItem(); +}; + +struct MGMInfo { + StaticANIObject *ani; + int staticsId1; + int staticsId2; + int movementId; + int field_10; + int x1; + int y1; + int field_1C; + int x2; + int y2; + int flags; + + MGMInfo() { memset(this, 0, sizeof(MGMInfo)); } +}; + +class MGM : public CObject { +public: + Common::Array<MGMItem *> _items; + +public: + void clear(); + void addItem(int objId); + void rebuildTables(int objId); + int getItemIndexById(int objId); + + MessageQueue *genMovement(MGMInfo *mgminfo); + void updateAnimStatics(StaticANIObject *ani, int staticsId); + Common::Point *getPoint(Common::Point *point, int aniId, int staticsId1, int staticsId2); + int getStaticsIndexById(int idx, int16 id); + int getStaticsIndex(int idx, Statics *st); + void clearMovements2(int idx); + int recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop); + Common::Point *calcLength(Common::Point *point, Movement *mov, int x, int y, int *mult, int *len, int flag); + ExCommand2 *buildExCommand2(Movement *mov, int objId, int x1, int y1, Common::Point *x2, Common::Point *y2, int len); + MessageQueue *genMQ(StaticANIObject *ani, int staticsIndex, int staticsId, int *resStatId, Common::Point **pointArr); + int countPhases(int idx, int subIdx, int subOffset, int flag); + int refreshOffsets(int objectId, int idx1, int idx2); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MGM_H */ diff --git a/engines/fullpipe/modal.cpp b/engines/fullpipe/modal.cpp new file mode 100644 index 0000000000..096323781f --- /dev/null +++ b/engines/fullpipe/modal.cpp @@ -0,0 +1,1817 @@ +/* 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/messages.h" +#include "fullpipe/constants.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/statics.h" +#include "fullpipe/modal.h" + +#include "fullpipe/constants.h" + +#include "graphics/palette.h" +#include "video/avi_decoder.h" + +#include "engines/savestate.h" + +namespace Fullpipe { + +ModalIntro::ModalIntro() { + _field_8 = 0; + _countDown = 0; + _stillRunning = 0; + + if (g_vars->sceneIntro_skipIntro) { + _introFlags = 4; + } else { + _introFlags = 33; + _countDown = 150; + + PictureObject *pict = g_fp->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_PIPETITLE, 0); + pict->setFlags(pict->_flags & 0xFFFB); + } + + g_vars->sceneIntro_skipIntro = false; + _sfxVolume = g_fp->_sfxVolume; +} + +ModalIntro::~ModalIntro() { + g_fp->stopAllSounds(); + g_fp->_sfxVolume = _sfxVolume; +} + +bool ModalIntro::handleMessage(ExCommand *message) { + if (message->_messageKind != 17) + return false; + + if (message->_messageNum != 36) + return false; + + if (message->_keyCode != 13 && message->_keyCode != 27 && message->_keyCode != 32) + return false; + + if (_stillRunning) { + if (!(_introFlags & 0x10)) { + _countDown = 0; + g_vars->sceneIntro_needBlackout = true; + return true; + } + g_vars->sceneIntro_playing = false; + g_vars->sceneIntro_needBlackout = true; + } + + return true; +} + +bool ModalIntro::init(int counterdiff) { + if (!g_vars->sceneIntro_playing) { + if (!_stillRunning) { + finish(); + return false; + } + + if (_introFlags & 0x10) + g_fp->_gameLoader->updateSystems(42); + + _introFlags |= 2; + + return true; + } + + if (_introFlags & 4) { + ModalVideoPlayer *player = new ModalVideoPlayer(); + + g_fp->_modalObject = player; + player->_parentObj = this; + player->play("intro.avi"); + + _countDown--; + + if (_countDown > 0 ) + return true; + + if (_stillRunning <= 0) { + _countDown = 0; + _stillRunning = 0; + _introFlags = (_introFlags & 0xfb) | 0x40; + + return true; + } + + _introFlags |= 2; + return true; + } + + if (_introFlags & 0x40) { + ModalVideoPlayer *player = new ModalVideoPlayer(); + + g_fp->_modalObject = player; + player->_parentObj = this; + player->play("intro2.avi"); + + _countDown--; + if (_countDown > 0) + return true; + + if (_stillRunning <= 0) { + _countDown = 50; + _stillRunning = 0; + _introFlags = (_introFlags & 0xbf) | 9; + + return true; + } + + _introFlags |= 2; + return true; + } + + if (_introFlags & 8) { + _countDown--; + + if (_countDown > 0 ) + return true; + + if (_stillRunning > 0) { + _introFlags |= 2; + return true; + } + + _countDown = 150; + _introFlags = (_introFlags & 0xf7) | 0x21; + g_fp->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_PIPETITLE, 0)->_flags &= 0xfffb; + } + + if (!(_introFlags & 0x20)) { + if (_introFlags & 0x10) { + if (!_stillRunning) { + _introFlags |= 1; + + g_fp->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_PIPETITLE, 0)->_flags &= 0xfffb; + g_fp->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_GAMETITLE, 0)->_flags &= 0xfffb; + + chainQueue(QU_INTR_STARTINTRO, 1); + } + g_fp->_gameLoader->updateSystems(42); + } + return true; + } + + _countDown--; + + if (_countDown <= 0) { + if (_stillRunning > 0) { + _introFlags |= 2; + + return true; + } + + _introFlags = (_introFlags & 0xdf) | 0x10; + + g_fp->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_GAMETITLE, 0)->_flags &= 0xfffb; + + _stillRunning = 0; + } + + return true; +} + +void ModalIntro::update() { + if (g_fp->_currentScene) { + if (_introFlags & 1) { + g_fp->sceneFade(g_fp->_currentScene, true); + _stillRunning = 255; + _introFlags &= 0xfe; + + if (_introFlags & 0x20) + g_fp->playSound(SND_INTR_019, 0); + } else if (_introFlags & 2) { + if (g_vars->sceneIntro_needBlackout) { + g_fp->drawAlphaRectangle(0, 0, 800, 600, 0); + g_vars->sceneIntro_needBlackout = 0; + _stillRunning = 0; + _introFlags &= 0xfd; + } else { + g_fp->sceneFade(g_fp->_currentScene, false); + _stillRunning = 0; + _introFlags &= 0xfd; + } + } else if (_stillRunning) { + g_fp->_currentScene->draw(); + } + } +} + +void ModalIntro::finish() { + g_fp->_gameLoader->unloadScene(SC_INTRO2); + g_fp->_currentScene = g_fp->accessScene(SC_INTRO1); + g_fp->_gameLoader->preloadScene(SC_INTRO1, TrubaDown); + + if (g_fp->_currentScene) + g_fp->_gameLoader->updateSystems(42); +} + +void ModalVideoPlayer::play(const char *filename) { + // TODO: Videos are encoded using Intel Indeo 5 (IV50), which isn't supported yet + + Video::AVIDecoder *aviDecoder = new Video::AVIDecoder(); + + if (!aviDecoder->loadFile(filename)) + return; + + uint16 x = (g_system->getWidth() - aviDecoder->getWidth()) / 2; + uint16 y = (g_system->getHeight() - aviDecoder->getHeight()) / 2; + bool skipVideo = false; + + aviDecoder->start(); + + while (!g_fp->shouldQuit() && !aviDecoder->endOfVideo() && !skipVideo) { + if (aviDecoder->needsUpdate()) { + const Graphics::Surface *frame = aviDecoder->decodeNextFrame(); + if (frame) { + g_fp->_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, frame->w, frame->h); + + if (aviDecoder->hasDirtyPalette()) + g_fp->_system->getPaletteManager()->setPalette(aviDecoder->getPalette(), 0, 256); + + g_fp->_system->updateScreen(); + } + } + + Common::Event event; + while (g_fp->_system->getEventManager()->pollEvent(event)) { + if ((event.type == Common::EVENT_KEYDOWN && (event.kbd.keycode == Common::KEYCODE_ESCAPE || + event.kbd.keycode == Common::KEYCODE_RETURN || + event.kbd.keycode == Common::KEYCODE_SPACE)) + || event.type == Common::EVENT_LBUTTONUP) + skipVideo = true; + } + + g_fp->_system->delayMillis(aviDecoder->getTimeToNextFrame()); + } +} + +ModalMap::ModalMap() { + _mapScene = 0; + _pic = 0; + _isRunning = false; + _rect1 = g_fp->_sceneRect; + _x = g_fp->_currentScene->_x; + _y = g_fp->_currentScene->_y; + _flag = 0; + _mouseX = 0; + _mouseY = 0; + _field_38 = 0; + _field_3C = 0; + _field_40 = 12; + _rect2.top = 0; + _rect2.left = 0; + _rect2.bottom = 600; + _rect2.right = 800; +} + +ModalMap::~ModalMap() { + g_fp->_gameLoader->unloadScene(SC_MAP); + + g_fp->_sceneRect = _rect1; + + g_fp->_currentScene->_x = _x; + g_fp->_currentScene->_y = _y; +} + +bool ModalMap::init(int counterdiff) { + g_fp->setCursor(PIC_CSR_ITN); + + if (_flag) { + _rect2.left = _mouseX + _field_38 - g_fp->_mouseScreenPos.x; + _rect2.top = _mouseY + _field_3C - g_fp->_mouseScreenPos.y; + _rect2.right = _rect2.left + 800; + _rect2.bottom = _rect2.top + 600; + + g_fp->_sceneRect =_rect2; + + _mapScene->updateScrolling2(); + + _rect2 = g_fp->_sceneRect; + } + + _field_40--; + + if (_field_40 <= 0) { + _field_40 = 12; + + if (_pic) + _pic->_flags ^= 4; + } + + return _isRunning; +} + +void ModalMap::update() { + g_fp->_sceneRect = _rect2; + + _mapScene->draw(); + + g_fp->drawArcadeOverlay(1); +} + +bool ModalMap::handleMessage(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return false; + + switch (cmd->_messageNum) { + case 29: + _flag = 1; + _mouseX = g_fp->_mouseScreenPos.x; + _mouseY = g_fp->_mouseScreenPos.x; + + _field_3C = _rect2.top; + _field_38 = _rect2.left; + + break; + + case 30: + _flag = 0; + break; + + case 36: + if (cmd->_keyCode != 9 && cmd->_keyCode != 27 ) + return false; + + break; + + case 107: + break; + + default: + return false; + } + + _isRunning = 0; + + return true; +} + +void ModalMap::initMap() { + _isRunning = 1; + + _mapScene = g_fp->accessScene(SC_MAP); + + if (!_mapScene) + error("ModalMap::initMap(): error accessing scene SC_MAP"); + + PictureObject *pic; + + for (int i = 0; i < 200; i++) { + if (!(g_fp->_mapTable[i] >> 16)) + break; + + pic = _mapScene->getPictureObjectById(g_fp->_mapTable[i] >> 16, 0); + + if ((g_fp->_mapTable[i] & 0xffff) == 1) + pic->_flags |= 4; + else + pic->_flags &= 0xfffb; + } + + pic = getScenePicture(); + + Common::Point point; + Common::Point point2; + + if (pic) { + pic->getDimensions(&point); + + _rect2.left = point.x / 2 + pic->_ox - 400; + _rect2.top = point.y / 2 + pic->_oy - 300; + _rect2.right = _rect2.left + 800; + _rect2.bottom = _rect2.top + 600; + + _mapScene->updateScrolling2(); + + _pic = _mapScene->getPictureObjectById(PIC_MAP_I02, 0); + _pic->getDimensions(&point2); + + _pic->setOXY(pic->_ox + point.x / 2 - point2.x / 2, point.y - point2.y / 2 + pic->_oy - 24); + _pic->_flags |= 4; + + _pic = _mapScene->getPictureObjectById(PIC_MAP_I01, 0); + _pic->getDimensions(&point2); + + _pic->setOXY(pic->_ox + point.x / 2 - point2.x / 2, point.y - point2.y / 2 + pic->_oy - 25); + _pic->_flags |= 4; + } + + g_fp->setArcadeOverlay(PIC_CSR_MAP); +} + +PictureObject *ModalMap::getScenePicture() { + int picId = 0; + + switch (g_fp->_currentScene->_sceneId) { + case SC_1: + picId = PIC_MAP_S01; + break; + case SC_2: + picId = PIC_MAP_S02; + break; + case SC_3: + picId = PIC_MAP_S03; + break; + case SC_4: + picId = PIC_MAP_S04; + break; + case SC_5: + picId = PIC_MAP_S05; + break; + case SC_6: + picId = PIC_MAP_S06; + break; + case SC_7: + picId = PIC_MAP_S07; + break; + case SC_8: + picId = PIC_MAP_S08; + break; + case SC_9: + picId = PIC_MAP_S09; + break; + case SC_10: + picId = PIC_MAP_S10; + break; + case SC_11: + picId = PIC_MAP_S11; + break; + case SC_12: + picId = PIC_MAP_S12; + break; + case SC_13: + picId = PIC_MAP_S13; + break; + case SC_14: + picId = PIC_MAP_S14; + break; + case SC_15: + picId = PIC_MAP_S15; + break; + case SC_16: + picId = PIC_MAP_S16; + break; + case SC_17: + picId = PIC_MAP_S17; + break; + case SC_18: + case SC_19: + picId = PIC_MAP_S1819; + break; + case SC_20: + picId = PIC_MAP_S20; + break; + case SC_21: + picId = PIC_MAP_S21; + break; + case SC_22: + picId = PIC_MAP_S22; + break; + case SC_23: + picId = PIC_MAP_S23_1; + break; + case SC_24: + picId = PIC_MAP_S24; + break; + case SC_25: + picId = PIC_MAP_S25; + break; + case SC_26: + picId = PIC_MAP_S26; + break; + case SC_27: + picId = PIC_MAP_S27; + break; + case SC_28: + picId = PIC_MAP_S28; + break; + case SC_29: + picId = PIC_MAP_S29; + break; + case SC_30: + picId = PIC_MAP_S30; + break; + case SC_31: + picId = PIC_MAP_S31_1; + break; + case SC_32: + picId = PIC_MAP_S32_1; + break; + case SC_33: + picId = PIC_MAP_S33; + break; + case SC_34: + picId = PIC_MAP_S34; + break; + case SC_35: + picId = PIC_MAP_S35; + break; + case SC_36: + picId = PIC_MAP_S36; + break; + case SC_37: + picId = PIC_MAP_S37; + break; + case SC_38: + picId = PIC_MAP_S38; + break; + case SC_FINAL1: + picId = PIC_MAP_S38; + break; + } + + if (picId) + return _mapScene->getPictureObjectById(picId, 0); + + error("ModalMap::getScenePicture(): Unknown scene id: %d", g_fp->_currentScene->_sceneId); +} + +void FullpipeEngine::openMap() { + if (!_modalObject) { + ModalMap *map = new ModalMap; + + _modalObject = map; + + map->initMap(); + } +} + +ModalFinal::ModalFinal() { + _flags = 0; + _counter = 255; + _sfxVolume = g_fp->_sfxVolume; +} + +ModalFinal::~ModalFinal() { + if (g_vars->sceneFinal_var01) { + g_fp->_gameLoader->unloadScene(SC_FINAL2); + g_fp->_gameLoader->unloadScene(SC_FINAL3); + g_fp->_gameLoader->unloadScene(SC_FINAL4); + + g_fp->_currentScene = g_fp->accessScene(SC_FINAL1); + + g_fp->stopAllSounds(); + + g_vars->sceneFinal_var01 = 0; + } + + g_fp->_sfxVolume = _sfxVolume; +} + +bool ModalFinal::init(int counterdiff) { + if (g_vars->sceneFinal_var01) { + g_fp->_gameLoader->updateSystems(42); + + return true; + } + + if (_counter > 0) { + _flags |= 2u; + + g_fp->_gameLoader->updateSystems(42); + + return true; + } + + unloadScenes(); + + g_fp->_modalObject = new ModalCredits(); + + return true; +} + +void ModalFinal::unloadScenes() { + g_fp->_gameLoader->unloadScene(SC_FINAL2); + g_fp->_gameLoader->unloadScene(SC_FINAL3); + g_fp->_gameLoader->unloadScene(SC_FINAL4); + + g_fp->_currentScene = g_fp->accessScene(SC_FINAL1); + + g_fp->stopAllSounds(); +} + +bool ModalFinal::handleMessage(ExCommand *cmd) { + if (cmd->_messageKind == 17 && cmd->_messageNum == 36 && cmd->_keyCode == 27) { + g_fp->_modalObject = new ModalMainMenu(); + g_fp->_modalObject->_parentObj = this; + + return true; + } + + return false; +} + +void ModalFinal::update() { + if (g_fp->_currentScene) { + g_fp->_currentScene->draw(); + + if (_flags & 1) { + g_fp->drawAlphaRectangle(0, 0, 800, 600, 0xff - _counter); + + _counter += 10; + + if (_counter >= 255) { + _counter = 255; + _flags &= 0xfe; + } + } else { + if (!(_flags & 2)) + return; + + g_fp->drawAlphaRectangle(0, 0, 800, 600, 0xff - _counter); + _counter -= 10; + + if (_counter <= 0) { + _counter = 0; + _flags &= 0xFD; + } + } + + g_fp->_sfxVolume = _counter * (_sfxVolume + 3000) / 255 - 3000; + + g_fp->updateSoundVolume(); + } +} + +ModalCredits::ModalCredits() { + Common::Point point; + + _sceneTitles = g_fp->accessScene(SC_TITLES); + + _creditsPic = _sceneTitles->getPictureObjectById(PIC_TTL_CREDITS, 0); + _creditsPic->_flags |= 4; + + _fadeIn = true; + _fadeOut = false; + + _creditsPic->getDimensions(&point); + + _countdown = point.y / 2 + 470; + _sfxVolume = g_fp->_sfxVolume; + + _currY = 630; + _maxY = -1000 - point.y; + + _currX = 400 - point.x / 2; + + _creditsPic->setOXY(_currX, _currY); +} + +ModalCredits::~ModalCredits() { + g_fp->_gameLoader->unloadScene(SC_TITLES); + + g_fp->_sfxVolume = _sfxVolume; +} + +bool ModalCredits::handleMessage(ExCommand *cmd) { + if (cmd->_messageKind == 17 && cmd->_messageNum == 36 && cmd->_keyCode == 27) { + _fadeIn = false; + + return true; + } + + return false; +} + +bool ModalCredits::init(int counterdiff) { + if (_fadeIn || _fadeOut) { + _countdown--; + + if (_countdown < 0) + _fadeIn = false; + + _creditsPic->setOXY(_currX, _currY); + + if (_currY > _maxY) + _currY -= 2; + } else { + if (_parentObj) + return 0; + + ModalMainMenu *menu = new ModalMainMenu; + + g_fp->_modalObject = menu; + + menu->_mfield_34 = 1; + } + + return true; +} + +void ModalCredits::update() { + if (_fadeOut) { + if (_fadeIn) { + _sceneTitles->draw(); + + return; + } + } else if (_fadeIn) { + g_fp->sceneFade(_sceneTitles, true); + _fadeOut = 1; + + return; + } + + if (_fadeOut) { + g_fp->sceneFade(_sceneTitles, false); + _fadeOut = 0; + return; + } + + _sceneTitles->draw(); +} + +ModalMainMenu::ModalMainMenu() { + _areas.clear(); + + _lastArea = 0; + _hoverAreaId = 0; + _mfield_34 = 0; + _scene = g_fp->accessScene(SC_MAINMENU); + _debugKeyCount = 0; + _sliderOffset = 0; + _screct.left = g_fp->_sceneRect.left; + _screct.top = g_fp->_sceneRect.top; + _screct.right = g_fp->_sceneRect.right; + _screct.bottom = g_fp->_sceneRect.bottom; + + if (g_fp->_currentScene) { + _bgX = g_fp->_currentScene->_x; + _bgY = g_fp->_currentScene->_y; + } else { + _bgX = 0; + _bgY = 0; + } + + g_fp->_sceneRect.top = 0; + g_fp->_sceneRect.left = 0; + g_fp->_sceneRect.right = 800; + g_fp->_sceneRect.bottom = 600; + + MenuArea *area; + + area = new MenuArea(); + area->picIdL = PIC_MNU_EXIT_L; + area->picObjD = 0; + area->picObjL = _scene->getPictureObjectById(area->picIdL, 0); + area->picObjL->_flags &= 0xFFFB; + _areas.push_back(area); + + area = new MenuArea(); + area->picIdL = PIC_MNU_CONTINUE_L; + area->picObjD = 0; + area->picObjL = _scene->getPictureObjectById(area->picIdL, 0); + area->picObjL->_flags &= 0xFFFB; + _areas.push_back(area); + + if (isSaveAllowed()) { + area = new MenuArea(); + area->picIdL = PIC_MNU_SAVE_L; + area->picObjD = 0; + area->picObjL = _scene->getPictureObjectById(area->picIdL, 0); + area->picObjL->_flags &= 0xFFFB; + _areas.push_back(area); + } + + area = new MenuArea(); + area->picIdL = PIC_MNU_LOAD_L; + area->picObjD = 0; + area->picObjL = _scene->getPictureObjectById(area->picIdL, 0); + area->picObjL->_flags &= 0xFFFB; + _areas.push_back(area); + + area = new MenuArea(); + area->picIdL = PIC_MNU_RESTART_L; + area->picObjD = 0; + area->picObjL = _scene->getPictureObjectById(area->picIdL, 0); + area->picObjL->_flags &= 0xFFFB; + _areas.push_back(area); + + area = new MenuArea(); + area->picIdL = PIC_MNU_AUTHORS_L; + area->picObjD = 0; + area->picObjL = _scene->getPictureObjectById(area->picIdL, 0); + area->picObjL->_flags &= 0xFFFB; + _areas.push_back(area); + + area = new MenuArea(); + area->picIdL = PIC_MNU_SLIDER_L; + area->picObjD = _scene->getPictureObjectById(PIC_MNU_SLIDER_D, 0); + area->picObjD->_flags |= 4; + area->picObjL = _scene->getPictureObjectById(area->picIdL, 0); + area->picObjL->_flags &= 0xFFFB; + _areas.push_back(area); + _menuSliderIdx = _areas.size() - 1; + + area = new MenuArea(); + area->picIdL = PIC_MNU_MUSICSLIDER_L; + area->picObjD = _scene->getPictureObjectById(PIC_MNU_MUSICSLIDER_D, 0); + area->picObjD->_flags |= 4; + area->picObjL = _scene->getPictureObjectById(area->picIdL, 0); + area->picObjL->_flags &= 0xFFFB; + _areas.push_back(area); + _musicSliderIdx = _areas.size() - 1; + + if (g_fp->_mainMenu_debugEnabled) + enableDebugMenuButton(); + + setSliderPos(); +} + +void ModalMainMenu::update() { + _scene->draw(); +} + +bool ModalMainMenu::handleMessage(ExCommand *message) { + if (message->_messageKind != 17) + return false; + + Common::Point point; + + if (message->_messageNum == 29) { + point.x = message->_x; + point.y = message->_y; + + int numarea = checkHover(point); + + if (numarea >= 0) { + if (numarea == _menuSliderIdx) { + _lastArea = _areas[_menuSliderIdx]; + _sliderOffset = _lastArea->picObjL->_ox - point.x; + + return false; + } + + if (numarea == _musicSliderIdx) { + _lastArea = _areas[_musicSliderIdx]; + _sliderOffset = _lastArea->picObjL->_ox - point.x; + + return false; + } + + _hoverAreaId = _areas[numarea]->picIdL; + } + + return false; + } + + if (message->_messageNum == 30) { + if (_lastArea) + _lastArea = 0; + + return false; + } + + if (message->_messageNum != 36) + return false; + + if (message->_keyCode == 27) + _hoverAreaId = PIC_MNU_CONTINUE_L; + else + enableDebugMenu(message->_keyCode); + + return false; +} + +bool ModalMainMenu::init(int counterdiff) { + switch (_hoverAreaId) { + case PIC_MNU_RESTART_L: + g_fp->restartGame(); + + if (this == g_fp->_modalObject) + return false; + + delete this; + break; + + case PIC_MNU_EXIT_L: + { + ModalQuery *mq = new ModalQuery(); + + g_fp->_modalObject = mq; + + mq->_parentObj = this; + mq->create(_scene, _scene, PIC_MEX_BGR); + + _hoverAreaId = 0; + + return true; + } + + case PIC_MNU_DEBUG_L: + g_fp->_gameLoader->unloadScene(SC_MAINMENU); + g_fp->_sceneRect = _screct; + + if (!g_fp->_currentScene) + error("ModalMainMenu::init: Bad state"); + + g_fp->_currentScene->_x = _bgX; + g_fp->_currentScene->_y = _bgY; + + g_fp->_gameLoader->preloadScene(g_fp->_currentScene->_sceneId, SC_DBGMENU); + + return false; + + case PIC_MNU_CONTINUE_L: + if (!_mfield_34) { + g_fp->_gameLoader->unloadScene(SC_MAINMENU); + g_fp->_sceneRect = _screct; + + if (g_fp->_currentScene) { + g_fp->_currentScene->_x = _bgX; + g_fp->_currentScene->_y = _bgY; + } + + return false; + } + + g_fp->restartGame(); + + if (this == g_fp->_modalObject) + return false; + + delete this; + break; + + case PIC_MNU_AUTHORS_L: + g_fp->_modalObject = new ModalCredits(); + g_fp->_modalObject->_parentObj = this; + + _hoverAreaId = 0; + + return true; + + case PIC_MNU_SAVE_L: + case PIC_MNU_LOAD_L: + { + ModalSaveGame *sg = new ModalSaveGame(); + + g_fp->_modalObject = sg; + g_fp->_modalObject->_parentObj = _parentObj; + + int mode = 0; + if (_hoverAreaId == PIC_MNU_SAVE_L) + mode = 1; + + sg->setup(g_fp->accessScene(SC_MAINMENU), mode); + sg->setScene(g_fp->accessScene(SC_MAINMENU)); + + sg->_rect = _screct; + sg->_oldBgX = _bgX; + sg->_oldBgY = _bgY; + + delete this; + } + + break; + + default: + if (_lastArea) { + updateSliderPos(); + } else { + g_fp->_cursorId = PIC_CSR_DEFAULT; + + int idx = checkHover(g_fp->_mouseScreenPos); + + if (idx < 0) + goto LABEL_40; + + g_fp->_cursorId = PIC_CSR_DEFAULT; + + if (idx != this->_menuSliderIdx && idx != this->_musicSliderIdx ) + goto LABEL_40; + } + + g_fp->_cursorId = PIC_CSR_LIFT; + + LABEL_40: + g_fp->setCursor(g_fp->_cursorId); + + updateVolume(); + + return true; + } + + return true; +} + +void ModalMainMenu::updateVolume() { + if (g_fp->_soundEnabled ) { + for (int s = 0; s < g_fp->_currSoundListCount; s++) + for (int i = 0; i < g_fp->_currSoundList1[s]->getCount(); i++) { + updateSoundVolume(g_fp->_currSoundList1[s]->getSoundByIndex(i)); + } + } +} + +void ModalMainMenu::updateSoundVolume(Sound *snd) { + if (!snd->_objectId) + return; + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(snd->_objectId, -1); + if (!ani) + return; + + int a, b; + + if (ani->_ox >= _screct.left) { + int par, pan; + + if (ani->_ox <= _screct.right) { + int dx; + + if (ani->_oy <= _screct.bottom) { + if (ani->_oy >= _screct.top) { + snd->setPanAndVolume(g_fp->_sfxVolume, 0); + + return; + } + dx = _screct.top - ani->_oy; + } else { + dx = ani->_oy - _screct.bottom; + } + + par = 0; + + if (dx > 800) { + snd->setPanAndVolume(-3500, 0); + return; + } + + pan = -3500; + a = g_fp->_sfxVolume - (-3500); + b = 800 - dx; + } else { + int dx = ani->_ox - _screct.right; + + if (dx > 800) { + snd->setPanAndVolume(-3500, 0); + return; + } + + pan = -3500; + par = dx * (-3500) / -800; + a = g_fp->_sfxVolume - (-3500); + b = 800 - dx; + } + + int32 pp = b * a; + + snd->setPanAndVolume(pan + pp / 800, par); + + return; + } + + int dx = _screct.left - ani->_ox; + if (dx <= 800) { + int32 s = (800 - dx) * (g_fp->_sfxVolume - (-3500)); + int32 p = -3500 + s / 800; + + if (p > g_fp->_sfxVolume) + p = g_fp->_sfxVolume; + + snd->setPanAndVolume(p, dx * (-3500) / 800); + } else { + snd->setPanAndVolume(-3500, 0); + } +} + +void ModalMainMenu::updateSliderPos() { + if (_lastArea->picIdL == PIC_MNU_SLIDER_L) { + int x = g_fp->_mouseScreenPos.x + _sliderOffset; + + if (x >= 65) { + if (x > 238) + x = 238; + } else { + x = 65; + } + + _lastArea->picObjD->setOXY(x, _lastArea->picObjD->_oy); + _lastArea->picObjL->setOXY(x, _lastArea->picObjD->_oy); + + int vol = 1000 * (3 * x - 195); + g_fp->_sfxVolume = vol / 173 - 3000; + + if (!(vol / 173)) + g_fp->_sfxVolume = -10000; + + g_fp->updateSoundVolume(); + } else if (_lastArea->picIdL == PIC_MNU_MUSICSLIDER_L) { + int x = g_fp->_mouseScreenPos.x + _sliderOffset; + + if (x >= 65) { + if (x > 238) + x = 238; + } else { + x = 65; + } + + _lastArea->picObjD->setOXY(x, _lastArea->picObjD->_oy); + _lastArea->picObjL->setOXY(x, _lastArea->picObjD->_oy); + + g_fp->setMusicVolume(255 * (x - 65) / 173); + } +} + +int ModalMainMenu::checkHover(Common::Point &point) { + for (uint i = 0; i < _areas.size(); i++) { + if (_areas[i]->picObjL->isPixelHitAtPos(point.x, point.y)) { + _areas[i]->picObjL->_flags |= 4; + + return i; + } else { + _areas[i]->picObjL->_flags &= 0xFFFB; + } + } + + if (isOverArea(_areas[_menuSliderIdx]->picObjL, &point)) { + _areas[_menuSliderIdx]->picObjL->_flags |= 4; + + return _menuSliderIdx; + } + + if (isOverArea(_areas[_musicSliderIdx]->picObjL, &point)) { + _areas[_musicSliderIdx]->picObjL->_flags |= 4; + + return _musicSliderIdx; + } + + return -1; +} + +bool ModalMainMenu::isOverArea(PictureObject *obj, Common::Point *point) { + Common::Point p; + + obj->getDimensions(&p); + + int left = point->x - 8; + int right = point->x + 12; + int down = point->y - 11; + int up = point->y + 9; + + if (left >= obj->_ox && right < obj->_ox + p.x && down >= obj->_oy && up < obj->_oy + p.y) + return true; + + return false; +} + +bool ModalMainMenu::isSaveAllowed() { + if (!g_fp->_isSaveAllowed) + return false; + + if (g_fp->_aniMan->_flags & 0x100) + return false; + + for (Common::Array<MessageQueue *>::iterator s = g_fp->_globalMessageQueueList->begin(); s != g_fp->_globalMessageQueueList->end(); ++s) { + if (!(*s)->_isFinished && ((*s)->getFlags() & 1)) + return false; + } + + return true; +} + +void ModalMainMenu::enableDebugMenu(char c) { + const char deb[] = "DEBUGER"; + + if (c == deb[_debugKeyCount]) { + _debugKeyCount++; + + if (deb[_debugKeyCount] ) + return; + + enableDebugMenuButton(); + } + + _debugKeyCount = 0; +} + +void ModalMainMenu::enableDebugMenuButton() { + MenuArea *area; + + for (uint i = 0; i < _areas.size(); i++) + if (_areas[i]->picIdL == PIC_MNU_DEBUG_L) + return; + + area = new MenuArea(); + area->picIdL = PIC_MNU_DEBUG_L; + area->picObjD = 0; + area->picObjL = _scene->getPictureObjectById(area->picIdL, 0); + area->picObjL->_flags &= 0xFFFB; + _areas.push_back(area); +} + +void ModalMainMenu::setSliderPos() { + int x = 173 * (g_fp->_sfxVolume + 3000) / 3000 + 65; + PictureObject *obj = _areas[_menuSliderIdx]->picObjD; + + if (x >= 65) { + if (x > 238) + x = 238; + } else { + x = 65; + } + + obj->setOXY(x, obj->_oy); + _areas[_menuSliderIdx]->picObjL->setOXY(x, obj->_oy); + + x = 173 * g_fp->_musicVolume / 255 + 65; + obj = _areas[_musicSliderIdx]->picObjD; + + if (x >= 65) { + if (x > 238) + x = 238; + } else { + x = 65; + } + + obj->setOXY(x, obj->_oy); + _areas[_musicSliderIdx]->picObjL->setOXY(x, obj->_oy); +} + +ModalHelp::ModalHelp() { + _mainMenuScene = 0; + _bg = 0; + _isRunning = false; + _rect = g_fp->_sceneRect; + _hx = g_fp->_currentScene->_x; + _hy = g_fp->_currentScene->_y; + + g_fp->_sceneRect.left = 0; + g_fp->_sceneRect.bottom = 600; + g_fp->_sceneRect.top = 0; + g_fp->_sceneRect.right = 800; +} + +ModalHelp::~ModalHelp() { + g_fp->_gameLoader->unloadScene(SC_MAINMENU); + + g_fp->_sceneRect = _rect; + + g_fp->_currentScene->_x = _hx; + g_fp->_currentScene->_y = _hy; +} + +bool ModalHelp::handleMessage(ExCommand *cmd) { + if (cmd->_messageKind == 17) { + int msg = cmd->_messageNum; + + if (msg == 29 || msg == 36 || msg == 107) { + _isRunning = 0; + + return true; + } + } + + return false; +} + +bool ModalHelp::init(int counterdiff) { + g_fp->setCursor(PIC_CSR_DEFAULT); + + return _isRunning; +} + +void ModalHelp::update() { + g_fp->_sceneRect.left = 0; + g_fp->_sceneRect.top = 0; + g_fp->_sceneRect.right = 800; + g_fp->_sceneRect.bottom = 600; + + _bg->draw(0, 0, 0, 0); +} + +void ModalHelp::launch() { + _mainMenuScene = g_fp->accessScene(SC_MAINMENU); + + if (_mainMenuScene) { + _bg = _mainMenuScene->getPictureObjectById(PIC_HLP_BGR, 0)->_picture; + _isRunning = 1; + } +} + +ModalQuery::ModalQuery() { + _bgScene = 0; + _bg = 0; + _okBtn = 0; + _cancelBtn = 0; + _queryResult = -1; +} + +ModalQuery::~ModalQuery() { + _bg->_flags &= 0xFFFB; + _cancelBtn->_flags &= 0xFFFB; + _okBtn->_flags &= 0xFFFB; +} + +bool ModalQuery::create(Scene *sc, Scene *bgScene, int id) { + if (id == PIC_MEX_BGR) { + _bg = sc->getPictureObjectById(PIC_MEX_BGR, 0); + + if (!_bg) + return false; + + _okBtn = sc->getPictureObjectById(PIC_MEX_OK, 0); + + if (!_okBtn) + return false; + + _cancelBtn = sc->getPictureObjectById(PIC_MEX_CANCEL, 0); + + if (!_cancelBtn) + return 0; + } else { + if (id != PIC_MOV_BGR) + return false; + + _bg = sc->getPictureObjectById(PIC_MOV_BGR, 0); + + if (!_bg) + return false; + + _okBtn = sc->getPictureObjectById(PIC_MOV_OK, 0); + + if (!_okBtn) + return false; + + _cancelBtn = sc->getPictureObjectById(PIC_MOV_CANCEL, 0); + + if (!_cancelBtn) + return false; + } + + _queryResult = -1; + _bgScene = bgScene; + + return true; +} + +void ModalQuery::update() { + if (_bgScene) + _bgScene->draw(); + + _bg->draw(); + + if (_okBtn->_flags & 4) + _okBtn->draw(); + + if (_cancelBtn->_flags & 4) + _cancelBtn->draw(); +} + +bool ModalQuery::handleMessage(ExCommand *cmd) { + if (cmd->_messageKind == 17) { + if (cmd->_messageNum == 29) { + if (_okBtn->isPointInside(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y)) { + _queryResult = 1; + + return false; + } + + if (_cancelBtn->isPointInside(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y)) + _queryResult = 0; + } else if (cmd->_messageNum == 36 && cmd->_keyCode == 27) { + _queryResult = 0; + + return false; + } + } + + return false; +} + +bool ModalQuery::init(int counterdiff) { + if (_okBtn->isPointInside(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y)) + _okBtn->_flags |= 4; + else + _okBtn->_flags &= 0xFFFB; + + if (_cancelBtn->isPointInside(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y)) + _cancelBtn->_flags |= 4; + else + _cancelBtn->_flags &= 0xFFFB; + + if (_queryResult == -1) { + return true; + } else { + if (_bg->_id == PIC_MEX_BGR) { + _cancelBtn->_flags &= 0xFFFB; + _okBtn->_flags &= 0xFFFB; + + if (_queryResult == 1) { + if (_bgScene) + g_fp->sceneFade(_bgScene, false); + + warning("STUB: ModalQuery::init()"); + + // Quit game + //if (inputArFlag) { + // g_needRestart = 1; + // return 0; + //} + //SendMessageA(hwndCallback, WM_DESTROY, 0, 0); + } + } + } + + return false; +} + +ModalSaveGame::ModalSaveGame() { + _oldBgX = 0; + _oldBgY = 0; + + _bgr = 0; + _okD = 0; + _okL = 0; + _cancelD = 0; + _cancelL = 0; + _emptyD = 0; + _emptyL = 0; + _fullD = 0; + _fullL = 0; + _menuScene = 0; + _queryRes = -1; + _rect = g_fp->_sceneRect; + _queryDlg = 0; + _mode = 1; + + _objtype = kObjTypeModalSaveGame; +} + +ModalSaveGame::~ModalSaveGame() { + g_fp->_sceneRect = _rect; + + _arrayD.clear(); + _arrayL.clear(); + + for (uint i = 0; i < _files.size(); i++) + free(_files[i]); + + _files.clear(); +} + +void ModalSaveGame::setScene(Scene *sc) { + _queryRes = -1; + _menuScene = sc; +} + +void ModalSaveGame::processKey(int key) { + if (key == 27) + _queryRes = 0; +} + +bool ModalSaveGame::init(int counterdiff) { + if (_queryDlg) { + if (!_queryDlg->init(counterdiff)) { + if (!_queryDlg->getQueryResult()) + _queryRes = -1; + + delete _queryDlg; + _queryDlg = 0; + } + + return true; + } + + if (_queryRes == -1) + return true; + + g_fp->_sceneRect = _rect; + + if (g_fp->_currentScene) { + g_fp->_currentScene->_x = _oldBgX; + g_fp->_currentScene->_y = _oldBgY; + } + + if (!_queryRes) { + ModalMainMenu *m = new ModalMainMenu; + + g_fp->_modalObject = m; + + m->_parentObj = _parentObj; + m->_screct = _rect; + m->_bgX = _oldBgX; + m->_bgY = _oldBgY; + + delete this; + + return true; + } + + return false; +} + +void ModalSaveGame::setup(Scene *sc, int mode) { + _files.clear(); + _arrayL.clear(); + _arrayD.clear(); + _mode = mode; + + if (mode) { + _bgr = sc->getPictureObjectById(PIC_MSV_BGR, 0); + _cancelD = sc->getPictureObjectById(PIC_MSV_CANCEL_D, 0); + _cancelL = sc->getPictureObjectById(PIC_MSV_CANCEL_L, 0); + _okD = sc->getPictureObjectById(PIC_MSV_OK_D, 0); + _okL = sc->getPictureObjectById(PIC_MSV_OK_L, 0); + _emptyD = sc->getPictureObjectById(PIC_MSV_EMPTY_D, 0); + _emptyL = sc->getPictureObjectById(PIC_MSV_EMPTY_L, 0); + } else { + _bgr = sc->getPictureObjectById(PIC_MLD_BGR, 0); + _cancelD = sc->getPictureObjectById(PIC_MLD_CANCEL_D, 0); + _cancelL = sc->getPictureObjectById(PIC_MLD_CANCEL_L, 0); + _okD = sc->getPictureObjectById(PIC_MLD_OK_D, 0); + _okL = sc->getPictureObjectById(PIC_MLD_OK_L, 0); + _emptyD = sc->getPictureObjectById(PIC_MSV_EMPTY_D, 0); + _emptyL = sc->getPictureObjectById(PIC_MSV_EMPTY_D, 0); + } + + _fullD = sc->getPictureObjectById(PIC_MSV_FULL_D, 0); + _fullL = sc->getPictureObjectById(PIC_MSV_FULL_L, 0); + _queryRes = -1; + + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_0_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_0_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_1_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_1_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_2_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_2_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_3_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_3_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_4_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_4_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_5_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_5_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_6_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_6_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_7_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_7_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_8_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_8_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_9_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_9_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_DOTS_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_DOTS_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_DOT_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_DOT_L, 0)); + _arrayL.push_back(sc->getPictureObjectById(PIC_MSV_SPACE_D, 0)); + _arrayD.push_back(sc->getPictureObjectById(PIC_MSV_SPACE_L, 0)); + + Common::Point point; + + int x = _bgr->_ox + _bgr->getDimensions(&point)->x / 2; + int y = _bgr->_oy + 90; + int w; + FileInfo *fileinfo; + + for (int i = 0; i < 7; i++) { + fileinfo = new FileInfo; + memset(fileinfo, 0, sizeof(FileInfo)); + + Common::strlcpy(fileinfo->filename, getSavegameFile(i), 160); + + if (!getFileInfo(i, fileinfo)) { + fileinfo->empty = true; + w = _emptyD->getDimensions(&point)->x; + } else { + w = 0; + + for (int j = 0; j < 16; j++) { + _arrayL[j]->getDimensions(&point); + w += point.x + 2; + } + } + + fileinfo->fx1 = x - w / 2; + fileinfo->fx2 = x + w / 2; + fileinfo->fy1 = y; + fileinfo->fy2 = y + _emptyD->getDimensions(&point)->y; + + _files.push_back(fileinfo); + + y = fileinfo->fy2 + 3; + } +} + +char *ModalSaveGame::getSaveName() { + if (_queryRes < 0) + return 0; + + return _files[_queryRes]->filename; +} + +bool ModalSaveGame::getFileInfo(int slot, FileInfo *fileinfo) { + Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading( + Fullpipe::getSavegameFile(slot)); + + if (!f) + return false; + + Fullpipe::FullpipeSavegameHeader header; + Fullpipe::readSavegameHeader(f, header); + delete f; + + // Create the return descriptor + SaveStateDescriptor desc(slot, header.saveName); + char res[17]; + + snprintf(res, 17, "%s %s", desc.getSaveDate().c_str(), desc.getSaveTime().c_str()); + + for (int i = 0; i < 16; i++) { + switch(res[i]) { + case '.': + fileinfo->date[i] = 11; + break; + case ' ': + fileinfo->date[i] = 12; + break; + case ':': + fileinfo->date[i] = 10; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + fileinfo->date[i] = res[i] - '0'; + break; + default: + error("Incorrect date format: %s", res); + } + } + + return true; +} + +void ModalSaveGame::update() { + if (_menuScene) + _menuScene->draw(); + + _bgr->draw(); + + if (_queryDlg) { + _queryDlg->update(); + + return; + } + + g_fp->_cursorId = PIC_CSR_DEFAULT; + + g_fp->setCursor(g_fp->_cursorId); + + Common::Point point; + + for (uint i = 0; i < _files.size(); i++) { + if (g_fp->_mouseScreenPos.x < _files[i]->fx1 || g_fp->_mouseScreenPos.x > _files[i]->fx2 || + g_fp->_mouseScreenPos.y < _files[i]->fy1 || g_fp->_mouseScreenPos.y > _files[i]->fy2 ) { + if (_files[i]->empty) { + _emptyD->setOXY(_files[i]->fx1, _files[i]->fy1); + _emptyD->draw(); + } else { + int x = _files[i]->fx1; + + for (int j = 0; j < 16; j++) { + _arrayL[_files[i]->date[j]]->setOXY(x + 1, _files[i]->fy1); + _arrayL[_files[i]->date[j]]->draw(); + + x += _arrayL[_files[i]->date[j]]->getDimensions(&point)->x + 2; + } + } + } else { + if (_files[i]->empty) { + _emptyL->setOXY(_files[i]->fx1, _files[i]->fy1); + _emptyL->draw(); + } else { + int x = _files[i]->fx1; + + for (int j = 0; j < 16; j++) { + _arrayD[_files[i]->date[j]]->setOXY(x + 1, _files[i]->fy1); + _arrayD[_files[i]->date[j]]->draw(); + + x += _arrayD[_files[i]->date[j]]->getDimensions(&point)->x + 2; + } + } + } + } + if (_cancelL->isPixelHitAtPos(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y)) + _cancelL->draw(); + else if (_okL->isPixelHitAtPos(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y)) + _okL->draw(); +} + +bool ModalSaveGame::handleMessage(ExCommand *cmd) { + if (_queryDlg) + return _queryDlg->handleMessage(cmd); + + if (cmd->_messageNum == 29) + processMouse(cmd->_x, cmd->_y); + else if (cmd->_messageNum == 36) + processKey(cmd->_keyCode); + + return false; +} + +void ModalSaveGame::processMouse(int x, int y) { + for (uint i = 0; i < _files.size(); i++) { + if (x >= _files[i]->fx1 && x <= _files[i]->fx2 && y >= _files[i]->fy1 && y <= _files[i]->fy2) { + _queryRes = i + 1; + + if (_mode) { + if (!_files[i]->empty) { + _queryDlg = new ModalQuery; + + _queryDlg->create(_menuScene, 0, PIC_MOV_BGR); + } + } + + return; + } + } + + if (_cancelL->isPixelHitAtPos(x, y)) + _queryRes = 0; +} + +void ModalSaveGame::saveload() { + if (_objtype != kObjTypeModalSaveGame) + return; + + if (_mode) { + if (getSaveName()) { + bool allowed = true; + + for (Common::Array<MessageQueue *>::iterator s = g_fp->_globalMessageQueueList->begin(); s != g_fp->_globalMessageQueueList->end(); ++s) { + if (!(*s)->_isFinished && ((*s)->getFlags() & 1)) + allowed = false; + } + + if (g_fp->_isSaveAllowed && allowed) + g_fp->_gameLoader->writeSavegame(g_fp->_currentScene, getSaveName()); + } + } else { + if (getSaveName()) { + if (_parentObj) { + delete _parentObj; + + _parentObj = 0; + } + + g_fp->stopAllSoundStreams(); + g_fp->stopSoundStream2(); + + g_fp->_gameLoader->readSavegame(getSaveName()); + } + } +} + +void FullpipeEngine::openHelp() { + if (!_modalObject) { + ModalHelp *help = new ModalHelp; + + _modalObject = help; + + help->launch(); + } +} + +void FullpipeEngine::openMainMenu() { + ModalMainMenu *menu = new ModalMainMenu; + + menu->_parentObj = g_fp->_modalObject; + + g_fp->_modalObject = menu; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/modal.h b/engines/fullpipe/modal.h new file mode 100644 index 0000000000..a08cb3bce2 --- /dev/null +++ b/engines/fullpipe/modal.h @@ -0,0 +1,295 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_MODAL_H +#define FULLPIPE_MODAL_H + +namespace Fullpipe { + +class PictureObject; +class Picture; +class Sound; + +struct FileInfo { + char filename[260]; + bool empty; + char date[16]; + int fx1; + int fx2; + int fy1; + int fy2; +}; + +class BaseModalObject { + public: + + BaseModalObject *_parentObj; + ObjType _objtype; + + public: + BaseModalObject() : _parentObj(0) { _objtype = kObjTypeDefault; } + virtual ~BaseModalObject() {} + + + virtual bool pollEvent() = 0; + virtual bool handleMessage(ExCommand *message) = 0; + virtual bool init(int counterdiff) = 0; + virtual void update() = 0; + + virtual void saveload() = 0; +}; + +class ModalIntro : public BaseModalObject { + int _field_8; + int _introFlags; + int _countDown; + int _stillRunning; + int _sfxVolume; + + public: + ModalIntro(); + virtual ~ModalIntro(); + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload() {} + + void finish(); +}; + +class ModalVideoPlayer : public BaseModalObject { +public: + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message) { return true; } + virtual bool init(int counterdiff) { return false; } + virtual void update() {} + virtual void saveload() {} + + void play(const char *fname); +}; + +class ModalMap : public BaseModalObject { + Scene *_mapScene; + PictureObject *_pic; + bool _isRunning; + Common::Rect _rect1; + int _x; + int _y; + int _flag; + int _mouseX; + int _mouseY; + int _field_38; + int _field_3C; + int _field_40; + Common::Rect _rect2; + + public: + ModalMap(); + virtual ~ModalMap(); + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload() {} + + void initMap(); + PictureObject *getScenePicture(); +}; + +class ModalFinal : public BaseModalObject { + int _flags; + int _counter; + int _sfxVolume; + + public: + ModalFinal(); + virtual ~ModalFinal(); + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload() {} + + void unloadScenes(); +}; + +class ModalCredits : public BaseModalObject { + Scene *_sceneTitles; + PictureObject *_creditsPic; + bool _fadeIn; + bool _fadeOut; + int _countdown; + int _sfxVolume; + int _currX; + int _currY; + int _maxY; + + public: + ModalCredits(); + virtual ~ModalCredits(); + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload() {} +}; + +struct MenuArea { + int picIdL; + PictureObject *picObjD; + PictureObject *picObjL; +}; + +class ModalMainMenu : public BaseModalObject { +public: + Scene *_scene; + int _hoverAreaId; + Common::Array<MenuArea *> _areas; + int _menuSliderIdx; + int _musicSliderIdx; + MenuArea *_lastArea; + int _sliderOffset; + int _mfield_34; + Common::Rect _screct; + int _bgX; + int _bgY; + int _debugKeyCount; + +public: + ModalMainMenu(); + virtual ~ModalMainMenu() {} + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload() {} + +private: + bool isSaveAllowed(); + void enableDebugMenuButton(); + void setSliderPos(); + void enableDebugMenu(char c); + int checkHover(Common::Point &point); + void updateVolume(); + void updateSoundVolume(Sound *snd); + void updateSliderPos(); + bool isOverArea(PictureObject *obj, Common::Point *point); +}; + +class ModalHelp : public BaseModalObject { +public: + Scene *_mainMenuScene; + Picture *_bg; + bool _isRunning; + Common::Rect _rect; + int _hx; + int _hy; + +public: + ModalHelp(); + virtual ~ModalHelp(); + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload() {} + + void launch(); +}; + +class ModalQuery : public BaseModalObject { +public: + ModalQuery(); + virtual ~ModalQuery(); + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload() {} + + bool create(Scene *sc, Scene *bgScene, int picId); + int getQueryResult() { return _queryResult; } + + +private: + Scene *_bgScene; + PictureObject *_bg; + PictureObject *_okBtn; + PictureObject *_cancelBtn; + int _queryResult; + +}; + +class ModalSaveGame : public BaseModalObject { +public: + ModalSaveGame(); + virtual ~ModalSaveGame(); + + virtual bool pollEvent() { return true; } + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual void update(); + virtual void saveload(); + + void processMouse(int x, int y); + + void setScene(Scene *sc); + void setup(Scene *sc, int mode); + void processKey(int key); + + char *getSaveName(); + bool getFileInfo(int slot, FileInfo *fileinfo); + + Common::Rect _rect; + int _oldBgX; + int _oldBgY; + PictureObject *_bgr; + PictureObject *_okD; + PictureObject *_okL; + PictureObject *_cancelD; + PictureObject *_cancelL; + PictureObject *_emptyD; + PictureObject *_emptyL; + PictureObject *_fullD; + PictureObject *_fullL; + Scene *_menuScene; + int _mode; + ModalQuery *_queryDlg; + Common::Array <FileInfo *> _files; + Common::Array <PictureObject *> _arrayL; + Common::Array <PictureObject *> _arrayD; + int _queryRes; +}; + + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MODAL_H */ diff --git a/engines/fullpipe/module.mk b/engines/fullpipe/module.mk new file mode 100644 index 0000000000..96bd91fd39 --- /dev/null +++ b/engines/fullpipe/module.mk @@ -0,0 +1,75 @@ +MODULE := engines/fullpipe + +MODULE_OBJS = \ + behavior.o \ + console.o \ + detection.o \ + floaters.o \ + fullpipe.o \ + gameloader.o \ + gfx.o \ + init.o \ + input.o \ + interaction.o \ + inventory.o \ + lift.o \ + messagehandlers.o \ + messages.o \ + mgm.o \ + modal.o \ + motion.o \ + ngiarchive.o \ + scene.o \ + scenes.o \ + sound.o \ + stateloader.o \ + statics.o \ + utils.o \ + scenes/sceneIntro.o \ + scenes/scene01.o \ + scenes/scene02.o \ + scenes/scene03.o \ + scenes/scene04.o \ + scenes/scene05.o \ + scenes/scene06.o \ + scenes/scene07.o \ + scenes/scene08.o \ + scenes/scene09.o \ + scenes/scene10.o \ + scenes/scene11.o \ + scenes/scene12.o \ + scenes/scene13.o \ + scenes/scene14.o \ + scenes/scene15.o \ + scenes/scene16.o \ + scenes/scene17.o \ + scenes/scene18and19.o \ + scenes/scene20.o \ + scenes/scene21.o \ + scenes/scene22.o \ + scenes/scene23.o \ + scenes/scene24.o \ + scenes/scene25.o \ + scenes/scene26.o \ + scenes/scene27.o \ + scenes/scene28.o \ + scenes/scene29.o \ + scenes/scene30.o \ + scenes/scene31.o \ + scenes/scene32.o \ + scenes/scene33.o \ + scenes/scene34.o \ + scenes/scene35.o \ + scenes/scene36.o \ + scenes/scene37.o \ + scenes/scene38.o \ + scenes/sceneFinal.o \ + scenes/sceneDbg.o + +# This module can be built as a plugin +ifeq ($(ENABLE_FULLPIPE), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp new file mode 100644 index 0000000000..1a61cb742a --- /dev/null +++ b/engines/fullpipe/motion.cpp @@ -0,0 +1,3053 @@ +/* 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/utils.h" +#include "fullpipe/statics.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" + +namespace Fullpipe { + +bool MotionController::load(MfcArchive &file) { + // Is originally empty file.readClass(); + + debug(5, "MotionController::load()"); + + return true; +} + +void MotionController::enableLinks(const char *linkName, bool enable) { + warning("STUB: MotionController::enableLinks()"); +} + +MovGraphLink *MotionController::getLinkByName(const char *name) { + if (_objtype == kObjTypeMctlCompound) { + MctlCompound *obj = (MctlCompound *)this; + + for (uint i = 0; i < obj->getMotionControllerCount(); i++) { + MotionController *con = obj->getMotionController(i); + + if (con->_objtype == kObjTypeMovGraph) { + MovGraph *gr = (MovGraph *)con; + + for (ObList::iterator l = gr->_links.begin(); l != gr->_links.end(); ++l) { + assert(((CObject *)*l)->_objtype == kObjTypeMovGraphLink); + + MovGraphLink *lnk = (MovGraphLink *)*l; + + if (!strcmp(lnk->_name, name)) + return lnk; + } + } + } + } + + if (_objtype == kObjTypeMovGraph) { + MovGraph *gr = (MovGraph *)this; + + for (ObList::iterator l = gr->_links.begin(); l != gr->_links.end(); ++l) { + assert(((CObject *)*l)->_objtype == kObjTypeMovGraphLink); + + MovGraphLink *lnk = (MovGraphLink *)*l; + + if (!strcmp(lnk->_name, name)) + return lnk; + } + } + + return 0; +} + +bool MctlCompound::load(MfcArchive &file) { + debug(5, "MctlCompound::load()"); + + int count = file.readUint32LE(); + + debug(6, "MctlCompound::count = %d", count); + + for (int i = 0; i < count; i++) { + debug(6, "CompoundArray[%d]", i); + MctlItem *obj = new MctlItem(); + + obj->_motionControllerObj = (MotionController *)file.readClass(); + + int count1 = file.readUint32LE(); + + debug(6, "ConnectionPoint::count: %d", count1); + for (int j = 0; j < count1; j++) { + debug(6, "ConnectionPoint[%d]", j); + MctlConnectionPoint *obj1 = (MctlConnectionPoint *)file.readClass(); + + obj->_connectionPoints.push_back(obj1); + } + + obj->_field_20 = file.readUint32LE(); + obj->_field_24 = file.readUint32LE(); + + debug(6, "graphReact"); + obj->_movGraphReactObj = (MovGraphReact *)file.readClass(); + + _motionControllers.push_back(obj); + } + + return true; +} + +void MctlCompound::attachObject(StaticANIObject *obj) { + for (uint i = 0; i < _motionControllers.size(); i++) + _motionControllers[i]->_motionControllerObj->attachObject(obj); +} + +int MctlCompound::detachObject(StaticANIObject *obj) { + for (uint i = 0; i < _motionControllers.size(); i++) + _motionControllers[i]->_motionControllerObj->detachObject(obj); + + return 1; +} + +void MctlCompound::initMovGraph2() { + if (_objtype != kObjTypeMctlCompound) + return; + + for (uint i = 0; i < _motionControllers.size(); i++) { + if (_motionControllers[i]->_motionControllerObj->_objtype != kObjTypeMovGraph) + continue; + + MovGraph *gr = (MovGraph *)_motionControllers[i]->_motionControllerObj; + + MovGraph2 *newgr = new MovGraph2(); + + newgr->_links = gr->_links; + newgr->_nodes = gr->_nodes; + + gr->_links.clear(); + gr->_nodes.clear(); + + delete gr; + + _motionControllers[i]->_motionControllerObj = newgr; + } +} + +void MctlCompound::detachAllObjects() { + for (uint i = 0; i < _motionControllers.size(); i++) + _motionControllers[i]->_motionControllerObj->detachAllObjects(); +} + +MessageQueue *MctlCompound::startMove(StaticANIObject *ani, int sourceX, int sourceY, int fuzzyMatch, int staticsId) { + int idx = -1; + int sourceIdx = -1; + + if (!ani) + return 0; + + for (uint i = 0; i < _motionControllers.size(); i++) { + if (_motionControllers[i]->_movGraphReactObj) { + if (_motionControllers[i]->_movGraphReactObj->pointInRegion(ani->_ox, ani->_oy)) { + idx = i; + break; + } + } + } + + for (uint i = 0; i < _motionControllers.size(); i++) { + if (_motionControllers[i]->_movGraphReactObj) { + if (_motionControllers[i]->_movGraphReactObj->pointInRegion(sourceX, sourceY)) { + sourceIdx = i; + break; + } + } + } + + if (idx == -1) + return 0; + + if (sourceIdx == -1) + return 0; + + if (idx == sourceIdx) + return _motionControllers[idx]->_motionControllerObj->startMove(ani, sourceX, sourceY, fuzzyMatch, staticsId); + + double dist; + MctlConnectionPoint *cp = findClosestConnectionPoint(ani->_ox, ani->_oy, idx, sourceX, sourceY, sourceIdx, &dist); + + if (!cp) + return 0; + + MessageQueue *mq = _motionControllers[idx]->_motionControllerObj->doWalkTo(ani, cp->_connectionX, cp->_connectionY, 1, cp->_mctlmirror); + + if (!mq) + return 0; + + for (uint i = 0; i < cp->_messageQueueObj->getCount(); i++) { + ExCommand *ex = new ExCommand(cp->_messageQueueObj->getExCommandByIndex(i)); + + ex->_excFlags |= 2; + + mq->addExCommandToEnd(ex); + } + + ExCommand *ex = new ExCommand(ani->_id, 51, 0, sourceX, sourceY, 0, 1, 0, 0, 0); + + ex->_excFlags |= 2; + ex->_field_20 = fuzzyMatch; + ex->_keyCode = ani->_okeyCode; + + mq->addExCommandToEnd(ex); + + if (!mq->chain(ani)) { + delete mq; + return 0; + } + + return mq; +} + +MessageQueue *MctlCompound::doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { + int match1 = -1; + int match2 = -1; + + if (!subj) + return 0; + + for (uint i = 0; i < _motionControllers.size(); i++) { + if (_motionControllers[i]->_movGraphReactObj) { + if (_motionControllers[i]->_movGraphReactObj->pointInRegion(subj->_ox, subj->_oy)) { + match1 = i; + break; + } + } + } + + if (match1 == -1) + return 0; + + for (uint i = 0; i < _motionControllers.size(); i++) { + if (_motionControllers[i]->_movGraphReactObj) { + if (_motionControllers[i]->_movGraphReactObj->pointInRegion(xpos, ypos)) { + match2 = i; + break; + } + } + } + + if (match2 == -1) + return 0; + + if (match1 == match2) + return _motionControllers[match1]->_motionControllerObj->doWalkTo(subj, xpos, ypos, fuzzyMatch, staticsId); + + double dist; + MctlConnectionPoint *closestP = findClosestConnectionPoint(subj->_ox, subj->_oy, match1, xpos, ypos, match2, &dist); + + if (!closestP) + return 0; + + MessageQueue *mq = _motionControllers[match1]->_motionControllerObj->doWalkTo(subj, closestP->_connectionX, closestP->_connectionY, 1, closestP->_mctlmirror); + + ExCommand *ex; + + if (mq) { + for (uint i = 0; i < closestP->_messageQueueObj->getCount(); i++) { + ex = closestP->_messageQueueObj->getExCommandByIndex(i)->createClone(); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + } + + ex = new ExCommand(subj->_id, 51, 0, xpos, ypos, 0, 1, 0, 0, 0); + + ex->_field_20 = fuzzyMatch; + ex->_keyCode = subj->_okeyCode; + ex->_excFlags |= 2; + + mq->addExCommandToEnd(ex); + } + + return mq; +} + +MctlItem::~MctlItem() { + delete _movGraphReactObj; + delete _motionControllerObj; +} + +MctlLadder::MctlLadder() { + _width = 0; + _ladderX = 0; + _height = 0; + _ladderY = 0; + _ladder_field_14 = 0; + + _ladder_field_20 = 0; + _ladder_field_24 = 0; +} + +MctlLadder::~MctlLadder() { + detachAllObjects(); +} + +int MctlLadder::collisionDetection(StaticANIObject *man) { + if (findObjectPos(man) < 0) + return 0; + + double delta; + + if ((double)(man->_oy - _ladderY) / (double)_height < 0.0) + delta = -0.5; + else + delta = 0.5; + + int res = (int)((double)(man->_oy - _ladderY) / (double)_height + delta); + + if (res < 0) + return 0; + + return res; +} + +void MctlLadder::attachObject(StaticANIObject *obj) { + if (findObjectPos(obj) < 0) { + MctlLadderMovement *movement = new MctlLadderMovement; + + if (initMovement(obj, movement)) { + _mgm.addItem(obj->_id); + _ladmovements.push_back(movement); + } else { + delete movement; + } + } +} + +int MctlLadder::findObjectPos(StaticANIObject *obj) { + for (uint i = 0; i < _ladmovements.size(); i++) + if (_ladmovements[i]->objId == obj->_id) + return i; + + return -1; +} + +bool MctlLadder::initMovement(StaticANIObject *ani, MctlLadderMovement *movement) { + GameVar *v = g_fp->getGameLoaderGameVar()->getSubVarByName(ani->getName()); + + if (!v) + return false; + + v = v->getSubVarByName("Test_Ladder"); + + if (!v) + return false; + + movement->staticIdsSize = 6; + movement->movVars = new MctlLadderMovementVars; + movement->staticIds = new int[movement->staticIdsSize]; + + v = v->getSubVarByName("Up"); + + if (!v) + return false; + + movement->movVars->varUpStart = v->getSubVarAsInt("Start"); + movement->movVars->varUpGo = v->getSubVarAsInt("Go"); + movement->movVars->varUpStop = v->getSubVarAsInt("Stop"); + + movement->staticIds[0] = ani->getMovementById(movement->movVars->varUpStart)->_staticsObj1->_staticsId; + movement->staticIds[2] = ani->getMovementById(movement->movVars->varUpGo)->_staticsObj1->_staticsId; + + v = v->getSubVarByName("Down"); + + if (!v) + return false; + + movement->movVars->varDownStart = v->getSubVarAsInt("Start"); + movement->movVars->varDownGo = v->getSubVarAsInt("Go"); + movement->movVars->varDownStop = v->getSubVarAsInt("Stop"); + + movement->staticIds[1] = ani->getMovementById(movement->movVars->varDownStart)->_staticsObj1->_staticsId; + movement->staticIds[3] = ani->getMovementById(movement->movVars->varDownGo)->_staticsObj1->_staticsId; + + movement->objId = ani->_id; + + return true; +} + +void MctlLadder::detachAllObjects() { + _mgm.clear(); + + for (uint i = 0; i < _ladmovements.size(); i++) { + delete _ladmovements[i]->movVars; + delete[] _ladmovements[i]->staticIds; + } + + _ladmovements.clear(); +} + +MessageQueue *MctlLadder::startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { + MessageQueue *mq = doWalkTo(subj, xpos, ypos, fuzzyMatch, staticsId); + + if (mq) { + if (mq->chain(subj)) + return mq; + } + + return 0; +} + +MessageQueue *MctlLadder::doWalkTo(StaticANIObject *ani, int xpos, int ypos, int fuzzyMatch, int staticsId) { + int pos = findObjectPos(ani); + + if (pos < 0) + return 0; + + double dh = _height; + double corr = (double)(ani->_oy - _ladderY) / dh; + int dl = (int)(corr + (corr < 0.0 ? -0.5 : 0.5)); + + corr = (double)(ypos - _ladderY) / dh; + int dl2 = (int)(corr + (corr < 0.0 ? -0.5 : 0.5)); + + int normx = _ladderX + dl2 * _width; + int normy = _ladderY + dl2 * _height; + + if (dl == dl2 || dl2 < 0) + return 0; + + int direction = (normy - ani->_oy) < 0 ? 0 : 1; + + MGMInfo mgminfo; + PicAniInfo picinfo; + MessageQueue *mq; + ExCommand *ex; + Common::Point point; + + if (ani->_movement) { + ani->getPicAniInfo(&picinfo); + + int ox = ani->_ox; + int oy = ani->_oy; + + ani->_movement->calcSomeXY(point, 1, ani->_someDynamicPhaseIndex); + ani->_statics = ani->_movement->_staticsObj2; + ani->_movement = 0; + ani->setOXY(point.x + ox, point.y + oy); + + mq = doWalkTo(ani, normx, normy, fuzzyMatch, staticsId); + + ani->setPicAniInfo(&picinfo); + + return mq; + } + + if (ani->_statics->_staticsId == _ladmovements[pos]->staticIds[0]) { + mgminfo.ani = ani; + + if (staticsId) + mgminfo.staticsId2 = staticsId; + else + mgminfo.staticsId2 = _ladmovements[pos]->staticIds[direction]; + + mgminfo.x1 = normx; + mgminfo.y1 = normy; + mgminfo.field_1C = _ladder_field_14; + mgminfo.flags = 14; + mgminfo.movementId = direction ? _ladmovements[pos]->movVars->varDownGo : _ladmovements[pos]->movVars->varUpGo; + + return _mgm.genMovement(&mgminfo); + } + + if (ani->_statics->_staticsId == _ladmovements[pos]->staticIds[2]) { + if (!direction) { + mgminfo.ani = ani; + + if (staticsId) + mgminfo.staticsId2 = staticsId; + else + mgminfo.staticsId2 = _ladmovements[pos]->staticIds[0]; + + mgminfo.x1 = normx; + mgminfo.y1 = normy; + mgminfo.field_1C = _ladder_field_14; + mgminfo.flags = 14; + mgminfo.movementId = _ladmovements[pos]->movVars->varUpGo; + + return _mgm.genMovement(&mgminfo); + } + + int ox = ani->_ox; + int oy = ani->_oy; + + ani->getMovementById(_ladmovements[pos]->movVars->varUpStop)->calcSomeXY(point, 0, -1); + + mgminfo.ani = ani; + + if (staticsId) + mgminfo.staticsId2 = staticsId; + else + mgminfo.staticsId2 = _ladmovements[pos]->staticIds[1]; + + mgminfo.field_1C = _ladder_field_14; + mgminfo.x1 = normx; + mgminfo.y1 = normy; + mgminfo.y2 = point.y + oy; + mgminfo.x2 = point.x + ox; + mgminfo.flags = 63; + mgminfo.staticsId1 = _ladmovements[pos]->staticIds[0]; + mgminfo.movementId = _ladmovements[pos]->movVars->varDownGo; + + mq = _mgm.genMovement(&mgminfo); + + ex = new ExCommand(ani->_id, 1, _ladmovements[pos]->movVars->varUpStop, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = ani->_okeyCode; + ex->_excFlags |= 2; + + mq->insertExCommandAt(0, ex); + + return mq; + } + + if (ani->_statics->_staticsId != _ladmovements[pos]->staticIds[3]) { + mq = _mgm.genMQ(ani, _ladmovements[pos]->staticIds[0], 0, 0, 0); + + if (!mq) + return 0; + + int nx = ani->_ox; + int ny = ani->_oy; + + _mgm.getPoint(&point, ani->_id, ani->_statics->_staticsId, _ladmovements[pos]->staticIds[0]); + + nx += point.x; + ny += point.y; + + ani->getPicAniInfo(&picinfo); + + ani->_statics = ani->getStaticsById(_ladmovements[pos]->staticIds[0]); + ani->_movement = 0; + ani->setOXY(nx, ny); + + MessageQueue *newmq = doWalkTo(ani, normx, normy, fuzzyMatch, staticsId); + + mq->transferExCommands(newmq); + + delete newmq; + + ani->setPicAniInfo(&picinfo); + + return mq; + } + + if (!direction) { + int nx = ani->_ox; + int ny = ani->_oy; + + ani->getMovementById(_ladmovements[pos]->movVars->varDownStop)->calcSomeXY(point, 0, -1); + + nx += point.x; + ny += point.y; + + mgminfo.ani = ani; + if (staticsId) + mgminfo.staticsId2 = staticsId; + else + mgminfo.staticsId2 = _ladmovements[pos]->staticIds[0]; + + mgminfo.field_1C = _ladder_field_14; + mgminfo.x1 = normx; + mgminfo.y1 = normy; + mgminfo.y2 = ny; + mgminfo.x2 = nx; + mgminfo.flags = 63; + mgminfo.staticsId1 = _ladmovements[pos]->staticIds[1]; + mgminfo.movementId = _ladmovements[pos]->movVars->varUpGo; + + mq = _mgm.genMovement(&mgminfo); + + ex = new ExCommand(ani->_id, 1, _ladmovements[pos]->movVars->varDownStop, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = ani->_okeyCode; + ex->_excFlags |= 2; + + mq->insertExCommandAt(0, ex); + + return mq; + } + + + mgminfo.ani = ani; + + if (staticsId) + mgminfo.staticsId2 = staticsId; + else + mgminfo.staticsId2 = _ladmovements[pos]->staticIds[1]; + + mgminfo.x1 = normx; + mgminfo.y1 = normy; + mgminfo.field_1C = _ladder_field_14; + mgminfo.flags = 14; + mgminfo.movementId = _ladmovements[pos]->movVars->varDownGo; + + return _mgm.genMovement(&mgminfo); +} + +MessageQueue *MctlLadder::controllerWalkTo(StaticANIObject *ani, int off) { + return doWalkTo(ani, _ladderX + off * _width, _ladderY + off * _height, 1, 0); +} + +MctlConnectionPoint *MctlCompound::findClosestConnectionPoint(int ox, int oy, int destIndex, int connectionX, int connectionY, int sourceIdx, double *minDistancePtr) { + if (destIndex == sourceIdx) { + *minDistancePtr = sqrt((double)((oy - connectionY) * (oy - connectionY) + (ox - connectionX) * (ox - connectionX))); + + return 0; + } + + double currDistance = 0.0; + double minDistance = 1.0e10; + MctlConnectionPoint *minConnectionPoint = 0; + + for (uint i = 0; i < _motionControllers[sourceIdx]->_connectionPoints.size(); i++) { + for (uint j = 0; j < _motionControllers.size(); j++) { + if (_motionControllers[j]->_movGraphReactObj) { + MctlConnectionPoint *pt = _motionControllers[sourceIdx]->_connectionPoints[i]; + + if (_motionControllers[j]->_movGraphReactObj->pointInRegion(pt->_connectionX, pt->_connectionY)) { + MctlConnectionPoint *npt = findClosestConnectionPoint(ox, oy, destIndex, pt->_connectionX, pt->_connectionY, j, &currDistance); + + if (currDistance < minDistance) { + minDistance = currDistance; + + if (npt) + minConnectionPoint = npt; + else + minConnectionPoint = pt; + } + } + } + } + } + + *minDistancePtr = minDistance; + + return minConnectionPoint; +} + +void MctlCompound::replaceNodeX(int from, int to) { + for (uint i = 0; i < _motionControllers.size(); i++) { + if (_motionControllers[i]->_motionControllerObj->_objtype == kObjTypeMovGraph) { + MovGraph *gr = (MovGraph *)_motionControllers[i]->_motionControllerObj; + + for (ObList::iterator n = gr->_nodes.begin(); n != gr->_nodes.end(); ++n) { + MovGraphNode *node = (MovGraphNode *)*n; + + if (node->_x == from) + node->_x = to; + } + + gr->recalcLinkParams(); + } + } +} + +MctlConnectionPoint::MctlConnectionPoint() { + _connectionX = 0; + _connectionY = 0; + _mctlflags = 0; + _mctlstatic = 0; + _mctlmirror = 0; + _messageQueueObj = 0; + _motionControllerObj = 0; +} + +MctlConnectionPoint::~MctlConnectionPoint() { + delete _messageQueueObj; +} + +MovInfo1::MovInfo1(MovInfo1 *src) { + index = src->index; + pt1 = src->pt1; + pt2 = src->pt2; + distance1 = src->distance1; + distance2 = src->distance2; + subIndex = src->subIndex; + item1Index = src->item1Index; + items = src->items; + itemsCount = src->itemsCount; + flags = src->flags; +} + +void MovInfo1::clear() { + index = 0; + pt1.x = pt1.y = 0; + pt2.x = pt2.y = 0; + distance1 = 0; + distance2 = 0; + subIndex = 0; + item1Index = 0; + items.clear(); + itemsCount = 0; + flags = 0; +} + +bool MctlCompoundArray::load(MfcArchive &file) { + debug(5, "MctlCompoundArray::load()"); + + int count = file.readUint32LE(); + + debug(0, "MctlCompoundArray::count = %d", count); + + assert(0); + + return true; +} + +MovGraphItem::MovGraphItem() { + ani = 0; + field_4 = 0; + movitems = 0; + count = 0; + field_30 = 0; + field_34 = 0; + field_38 = 0; + field_3C = 0; +} + +void MovGraphItem::free() { + for (uint i = 0; i < movitems->size(); i++) { + (*movitems)[i]->movarr->_movSteps.clear(); + delete (*movitems)[i]->movarr; + } + + delete movitems; + + movitems = 0; +} + +int MovGraph_messageHandler(ExCommand *cmd); + +MovArr *movGraphCallback(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter) { + int residx = 0; + int itemidx = 0; + + while (counter > 1) { + if ((*items)[itemidx]->_mfield_4 > (*items)[itemidx + 1]->_mfield_4) + residx = itemidx; + + counter--; + itemidx++; + } + + return (*items)[residx]->movarr; +} + +MovGraph::MovGraph() { + _callback1 = movGraphCallback; + _field_44 = 0; + insertMessageHandler(MovGraph_messageHandler, getMessageHandlersCount() - 1, 129); + + _objtype = kObjTypeMovGraph; +} + +MovGraph::~MovGraph() { + warning("STUB: MovGraph::~MovGraph()"); +} + +bool MovGraph::load(MfcArchive &file) { + debug(5, "MovGraph::load()"); + + _links.load(file); + _nodes.load(file); + + return true; +} + +void MovGraph::attachObject(StaticANIObject *obj) { + _mgm.clear(); + _mgm.addItem(obj->_id); + + for (uint i = 0; i < _items.size(); i++) + if (_items[i]->ani == obj) + return; + + MovGraphItem *item = new MovGraphItem(); + + item->ani = obj; + + _items.push_back(item); + + _mgm.addItem(obj->_id); // FIXME: Is it really needed? +} + +int MovGraph::detachObject(StaticANIObject *obj) { + warning("STUB: MovGraph::detachObject()"); + + return 0; +} + +void MovGraph::detachAllObjects() { + for (uint i = 0; i < _items.size(); i++) { + _items[i]->free(); + + _items[i]->movarr._movSteps.clear(); + } + + _items.clear(); +} + +Common::Array<MovItem *> *MovGraph::getPaths(StaticANIObject *ani, int x, int y, int flag1, int *rescount) { + *rescount = 0; + + if (_items.size() <= 0) + return 0; + + uint idx = 0; + + while (_items[idx]->ani != ani) { + idx++; + + if (idx >= _items.size()) + return 0; + } + _items[idx]->free(); + + recalcLinkParams(); + + _items[idx]->movarr._movSteps.clear(); + + Common::Point point; + + point.x = ani->_ox; + point.y = ani->_oy; + + if (!calcChunk(idx, ani->_ox, ani->_oy, &_items[idx]->movarr, 0)) + getNearestPoint(idx, &point, &_items[idx]->movarr); + + _items[idx]->count = 0; + + delete _items[idx]->movitems; + _items[idx]->movitems = 0; + + int arrSize; + Common::Array<MovArr *> *movarr = genMovArr(x, y, &arrSize, flag1, 0); + + if (movarr) { + for (int i = 0; i < arrSize; i++) { + int sz; + Common::Array<MovItem *> *movitems = calcMovItems(&_items[idx]->movarr, (*movarr)[i], &sz); + + if (sz > 0) { + for (int j = 0; j < sz; j++) + _items[idx]->movitems->push_back(movitems[j]); + + delete movitems; + } + } + + delete movarr; + } + + if (_items[idx]->count) { + *rescount = _items[idx]->count; + + return _items[idx]->movitems; + } + + return 0; +} + +bool MovGraph::setPosImmediate(StaticANIObject *obj, int x, int y) { + obj->setOXY(x, y); + return resetPosition(obj, 1); +} + +MessageQueue *MovGraph::startMove(StaticANIObject *ani, int xpos, int ypos, int fuzzyMatch, int staticsId) { + if (!ani) { + if (!_items.size()) + return 0; + + ani = _items[0]->ani; + } + + if (ABS(ani->_ox - xpos) < 50 && ABS(ani->_oy - ypos) < 50) + return 0; + + if (!ani->isIdle()) + return 0; + + if (ani->_flags & 0x100) + return 0; + + int count; + Common::Array<MovItem *> *movitems = getPaths(ani, xpos, ypos, fuzzyMatch, &count); + + if (!movitems) + return 0; + + if (ani->_movement) { + Common::Point point; + + ani->calcStepLen(&point); + + MessageQueue *mq = sub1(ani, ani->_ox - point.x, ani->_oy - point.y, ani->_movement->_staticsObj1->_staticsId, xpos, ypos, 0, fuzzyMatch); + + if (!mq || !mq->getExCommandByIndex(0)) + return 0; + + ExCommand *ex = mq->getExCommandByIndex(0); + + if ((ex->_messageKind != 1 && ex->_messageKind != 20) || ex->_messageNum != ani->_movement->_id || + (ex->_field_14 >= 1 && ex->_field_14 <= ani->_movement->_currDynamicPhaseIndex)) { + mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + ex = new ExCommand(ani->_id, 21, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = ani->_okeyCode; + ex->_field_3C = 1; + ex->_field_24 = 0; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ani->_id, 51, 0, xpos, ypos, 0, 1, 0, 0, 0); + ex->_keyCode = ani->_okeyCode; + ex->_field_3C = 1; + ex->_field_24 = 0; + ex->_field_20 = fuzzyMatch; + mq->addExCommandToEnd(ex); + + if (mq->chain(0)) + return mq; + + delete mq; + + return 0; + } + + int count2; + + ani->setSomeDynamicPhaseIndex(ex->_field_14); + getPaths(ani, xpos, ypos, fuzzyMatch, &count2); + + int idx = getObjectIndex(ani); + count = _items[idx]->count; + movitems = _items[idx]->movitems; + } + + return method50(ani, _callback1(ani, movitems, count), staticsId); +} + +void MovGraph::setSelFunc(MovArr *(*callback1)(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter)) { + _callback1 = callback1; +} + +bool MovGraph::resetPosition(StaticANIObject *ani, int flag) { + int idx = getObjectIndex(ani); + + if (idx == -1) + return false; + + Common::Point point; + MovArr movarr; + + point.x = ani->_ox; + point.y = ani->_oy; + + getNearestPoint(idx, &point, &movarr); + ani->setOXY(point.x, point.y); + + if (flag) { + Statics *st; + + if (ani->_statics) { + int t = _mgm.refreshOffsets(ani->_id, ani->_statics->_staticsId, movarr._link->_dwordArray2[_field_44]); + if (t > _mgm.refreshOffsets(ani->_id, ani->_statics->_staticsId, movarr._link->_dwordArray2[_field_44 + 1])) + st = ani->getStaticsById(movarr._link->_dwordArray2[_field_44 + 1]); + else + st = ani->getStaticsById(movarr._link->_dwordArray2[_field_44]); + } else { + ani->stopAnim_maybe(); + st = ani->getStaticsById(movarr._link->_dwordArray2[_field_44]); + } + + ani->_statics = st; + } + + return true; +} + +bool MovGraph::canDropInventory(StaticANIObject *ani, int x, int y) { + int idx = getObjectIndex(ani); + MovArr m; + + if (idx != -1) { + if (x != -1 || y != -1) { + int counter; + + Common::Array<MovItem *> *movitem = getPaths(ani, x, y, 0, &counter); + + if (movitem) { + MovArr *movarr = _callback1(ani, movitem, counter); + int cnt = movarr->_movStepCount; + + if (cnt > 0) { + if (movarr->_movSteps[cnt - 1]->link->_flags & 0x4000000) + return true; + } + } + } else if (calcChunk(idx, ani->_ox, ani->_oy, &m, 0) && m._link && (m._link->_flags & 0x4000000)) { + return true; + } + } + + return false; +} + +MessageQueue *MovGraph::doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { + PicAniInfo picAniInfo; + int ss; + + Common::Array<MovItem *> *movitem = getPaths(subj, xpos, ypos, fuzzyMatch, &ss); + + subj->getPicAniInfo(&picAniInfo); + + if (movitem) { + MovArr *goal = _callback1(subj, movitem, ss); + int idx = getObjectIndex(subj); + + for (int i = 0; i < _items[idx]->count; i++) { + if ((*_items[idx]->movitems)[i]->movarr == goal) { + if (subj->_movement) { + Common::Point point; + + subj->calcStepLen(&point); + + MessageQueue *mq = sub1(subj, subj->_ox - point.x, subj->_oy - point.y, subj->_movement->_staticsObj1->_staticsId, xpos, ypos, 0, fuzzyMatch); + + if (!mq || !mq->getExCommandByIndex(0)) + return 0; + + ExCommand *ex = mq->getExCommandByIndex(0); + + if ((ex->_messageKind != 1 && ex->_messageKind != 20) || + ex->_messageNum != subj->_movement->_id || + (ex->_field_14 >= 1 && ex->_field_14 <= subj->_movement->_currDynamicPhaseIndex)) + subj->playIdle(); + } + } + } + } + + movitem = getPaths(subj, xpos, ypos, fuzzyMatch, &ss); + if (movitem) { + MovArr *goal = _callback1(subj, movitem, ss); + int idx = getObjectIndex(subj); + + if (_items[idx]->count > 0) { + int arridx = 0; + + while ((*_items[idx]->movitems)[arridx]->movarr != goal) { + arridx++; + + if (arridx >= _items[idx]->count) { + subj->setPicAniInfo(&picAniInfo); + return 0; + } + } + + _items[idx]->movarr._movSteps.clear(); + _items[idx]->movarr = *(*_items[idx]->movitems)[arridx]->movarr; + _items[idx]->movarr._movSteps = (*_items[idx]->movitems)[arridx]->movarr->_movSteps; + _items[idx]->movarr._afield_8 = -1; + _items[idx]->movarr._link = 0; + + MessageQueue *mq = fillMGMinfo(_items[idx]->ani, &_items[idx]->movarr, staticsId); + if (mq) { + ExCommand *ex = new ExCommand(); + ex->_messageKind = 17; + ex->_messageNum = 54; + ex->_parentId = subj->_id; + ex->_field_3C = 1; + mq->addExCommandToEnd(ex); + } + subj->setPicAniInfo(&picAniInfo); + + return mq; + } + } + + subj->setPicAniInfo(&picAniInfo); + + return 0; +} + +MessageQueue *MovGraph::sub1(StaticANIObject *ani, int x, int y, int stid, int x1, int y1, int stid2, int flag1) { + PicAniInfo picinfo; + + ani->getPicAniInfo(&picinfo); + + ani->_statics = ani->getStaticsById(stid); + ani->_movement = 0; + ani->setOXY(x, y); + + int rescount; + + Common::Array<MovItem *> *movitems = getPaths(ani, x1, y1, flag1, &rescount); + + if (!movitems) { + ani->setPicAniInfo(&picinfo); + + return 0; + } + + MessageQueue *res = 0; + + MovArr *goal = _callback1(ani, movitems, rescount); + int idx = getObjectIndex(ani); + + MovGraphItem *movgitem = _items[idx]; + int cnt = movgitem->count; + + for (int nidx = 0; nidx < cnt; nidx++) { + if ((*movgitem->movitems)[nidx]->movarr == goal) { + movgitem->movarr._movSteps.clear(); + _items[idx]->movarr = *(*movgitem->movitems)[nidx]->movarr; + _items[idx]->movarr._movSteps = (*movgitem->movitems)[nidx]->movarr->_movSteps; + _items[idx]->movarr._afield_8 = -1; + _items[idx]->movarr._link = 0; + + res = fillMGMinfo(_items[idx]->ani, &_items[idx]->movarr, stid2); + + break; + } + } + + ani->setPicAniInfo(&picinfo); + + return res; +} + +MessageQueue *MovGraph::fillMGMinfo(StaticANIObject *ani, MovArr *movarr, int staticsId) { + if (!movarr->_movStepCount) + return 0; + + MessageQueue *mq = 0; + int ox = ani->_ox; + int oy = ani->_oy; + int id1 = 0; + int id2; + + for (int i = 0; i < movarr->_movStepCount; i++) { + while (i < movarr->_movStepCount - 1) { + if (movarr->_movSteps[i ]->link->_dwordArray1[movarr->_movSteps[i - 1]->sfield_0 + _field_44] != + movarr->_movSteps[i + 1]->link->_dwordArray1[movarr->_movSteps[i ]->sfield_0 + _field_44]) + break; + i++; + } + + MovStep *st = movarr->_movSteps[i]; + + ani->getMovementById(st->link->_dwordArray1[_field_44 + st->sfield_0]); + + if (i == movarr->_movStepCount - 1 && staticsId) { + id2 = staticsId; + } else { + if (i < movarr->_movStepCount - 1) + id2 = ani->getMovementById(movarr->_movSteps[i + 1]->link->_dwordArray1[_field_44 + st->sfield_0])->_staticsObj1->_staticsId; + else + id2 = st->link->_dwordArray2[_field_44 + st->sfield_0]; + } + + int nx, ny, nd; + + if (i == movarr->_movStepCount - 1) { + nx = movarr->_point.x; + ny = movarr->_point.y; + nd = st->link->_movGraphNode1->_z; + } else { + if (st->sfield_0) { + nx = st->link->_movGraphNode1->_x; + ny = st->link->_movGraphNode1->_y; + nd = st->link->_movGraphNode1->_z; + } else { + nx = st->link->_movGraphNode2->_x; + ny = st->link->_movGraphNode2->_y; + nd = st->link->_movGraphNode2->_z; + } + } + + MGMInfo mgminfo; + + memset(&mgminfo, 0, sizeof(mgminfo)); + mgminfo.ani = ani; + mgminfo.staticsId2 = id2; + mgminfo.staticsId1 = id1; + mgminfo.x1 = nx; + mgminfo.x2 = ox; + mgminfo.y2 = oy; + mgminfo.y1 = ny; + mgminfo.field_1C = nd; + mgminfo.movementId = st->link->_dwordArray1[_field_44 + st->sfield_0]; + + mgminfo.flags = 0xe; + if (mq) + mgminfo.flags |= 0x31; + + MessageQueue *newmq = _mgm.genMovement(&mgminfo); + + if (mq) { + if (newmq) { + mq->transferExCommands(newmq); + + delete newmq; + } + } else { + mq = newmq; + } + + ox = nx; + oy = ny; + id1 = id2; + } + + return mq; +} + +MessageQueue *MovGraph::method50(StaticANIObject *ani, MovArr *movarr, int staticsId) { + if (_items.size() == 0) + return 0; + + uint idx; + int movidx = 0; + bool done = false; + + for (idx = 0; idx <= _items.size() && !done; idx++) { + if (idx == _items.size()) + return 0; + + if (_items[idx]->ani == ani) { + if (!_items[idx]->movitems) + return 0; + + if (_items[idx]->count < 1) + return 0; + + for (movidx = 0; movidx < _items[idx]->count; movidx++) { + if ((*_items[idx]->movitems)[movidx]->movarr == movarr) { + done = true; + + break; + } + } + } + } + + _items[idx]->movarr._movSteps.clear(); + _items[idx]->movarr = *(*_items[idx]->movitems)[movidx]->movarr; + _items[idx]->movarr._movSteps = (*_items[idx]->movitems)[movidx]->movarr->_movSteps; + _items[idx]->movarr._afield_8 = -1; + _items[idx]->movarr._link = 0; + + MessageQueue *mq = fillMGMinfo(_items[idx]->ani, &_items[idx]->movarr, 0); + + if (!mq) + return 0; + + ExCommand *ex = new ExCommand(); + + ex->_messageKind = 17; + ex->_messageNum = 54; + ex->_parentId = ani->_id; + ex->_field_3C = 1; + mq->addExCommandToEnd(ex); + + if (!mq->chain(ani)) { + delete mq; + + return 0; + } + + return mq; +} + +double MovGraph::calcDistance(Common::Point *point, MovGraphLink *link, int fuzzyMatch) { + int n1x = link->_movGraphNode1->_x; + int n1y = link->_movGraphNode1->_y; + int n2x = link->_movGraphNode2->_x; + int n2y = link->_movGraphNode2->_y; + double dist1x = (double)(point->x - n1x); + double dist1y = (double)(n1y - point->y); + double dist2x = (double)(n2x - n1x); + double dist2y = (double)(n2y - n1y); + double dist1 = sqrt(dist1y * dist1y + dist1x * dist1x); + double dist2 = ((double)(n1y - n2y) * dist1y + dist2x * dist1x) / link->_z / dist1; + double distm = dist2 * dist1; + double res = sqrt(1.0 - dist2 * dist2) * dist1; + + if (dist2 <= 0.0 || distm >= link->_z) { + if (fuzzyMatch) { + if (dist2 > 0.0) { + if (distm >= link->_z) { + point->x = n2x; + point->y = n2y; + } + } else { + point->x = n1x; + point->y = n1y; + } + } else { + return -1.0; + } + } else { + point->x = (int)(n1x + (dist2x * distm / link->_z)); + point->y = (int)(n1y + (dist2y * distm / link->_z)); + } + + return res; +} + +void MovGraph::recalcLinkParams() { + for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) { + assert(((CObject *)*i)->_objtype == kObjTypeMovGraphLink); + + MovGraphLink *lnk = (MovGraphLink *)*i; + + lnk->_flags &= 0x7FFFFFFF; + + lnk->recalcLength(); + } +} + +bool MovGraph::getNearestPoint(int unusedArg, Common::Point *p, MovArr *movarr) { + MovGraphLink *link = 0; + double mindist = 1.0e20; + int resx = 0, resy = 0; + + for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) { + MovGraphLink *lnk = (MovGraphLink *)*i; + + if ((lnk->_flags & 0x10000000) && !(lnk->_flags & 0x20000000) ) { + double dx1 = lnk->_movGraphNode1->_x - p->x; + double dy1 = lnk->_movGraphNode1->_y - p->y; + double dx2 = lnk->_movGraphNode2->_x - p->x; + double dy2 = lnk->_movGraphNode2->_y - p->y; + double dx3 = lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x; + double dy3 = lnk->_movGraphNode2->_y - lnk->_movGraphNode1->_y; + double sq1 = sqrt(dy1 * dy1 + dx1 * dx1); + double sdist = (dy3 * dy1 + dx3 * dx1) / lnk->_z / sq1; + double ldist = sdist * sq1; + double dist = sqrt(1.0 - sdist * sdist) * sq1; + + if (ldist < 0.0) { + ldist = 0.0; + dist = sqrt(dx1 * dx1 + dy1 * dy1); + } + + if (ldist > lnk->_z) { + ldist = lnk->_z; + dist = sqrt(dx2 * dx2 + dy2 * dy2); + } + + if (ldist >= 0.0 && ldist <= lnk->_z && dist < mindist) { + resx = lnk->_movGraphNode1->_x + (int)(dx3 * ldist / lnk->_z); + resy = lnk->_movGraphNode1->_y + (int)(dy3 * ldist / lnk->_z); + + mindist = dist; + link = lnk; + } + } + } + + if (mindist < 1.0e20) { + if (movarr) + movarr->_link = link; + + if (p) { + p->x = resx; + p->y = resy; + } + + return true; + } + + return false; +} + +int MovGraph::getObjectIndex(StaticANIObject *ani) { + for (uint i = 0; i < _items.size(); i++) + if (_items[i]->ani == ani) + return i; + + return -1; +} + +Common::Array<MovArr *> *MovGraph::genMovArr(int x, int y, int *arrSize, int flag1, int flag2) { + if (!_links.size()) { + *arrSize = 0; + + return 0; + } + + Common::Array<MovArr *> *arr = new Common::Array<MovArr *>; + MovArr *movarr; + + for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) { + MovGraphLink *lnk = (MovGraphLink *)*i; + + if (flag1) { + Common::Point point(x, y); + double dist = calcDistance(&point, lnk, 0); + + if (dist >= 0.0 && dist < 2.0) { + movarr = new MovArr; + + movarr->_link = lnk; + movarr->_dist = ((double)(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y) * (double)(lnk->_movGraphNode1->_y - point.y) + + (double)(lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x) * (double)(point.x - lnk->_movGraphNode1->_x)) / + lnk->_z / lnk->_z; + movarr->_point = point; + + arr->push_back(movarr); + } + } else { + if (lnk->_movGraphReact) { + if (lnk->_movGraphReact->pointInRegion(x, y)) { + if (!(lnk->_flags & 0x10000000) || lnk->_flags & 0x20000000) { + if (!flag2) { + movarr = new MovArr; + movarr->_link = lnk; + movarr->_dist = 0.0; + movarr->_point.x = lnk->_movGraphNode1->_x; + movarr->_point.y = lnk->_movGraphNode1->_y; + arr->push_back(movarr); + + movarr = new MovArr; + movarr->_link = lnk; + movarr->_dist = 1.0; + movarr->_point.x = lnk->_movGraphNode1->_x; + movarr->_point.y = lnk->_movGraphNode1->_y; + arr->push_back(movarr); + } + } else { + movarr = new MovArr; + movarr->_link = lnk; + movarr->_dist = ((double)(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y) * (double)(lnk->_movGraphNode1->_y - y) + + (double)(lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x) * (double)(x - lnk->_movGraphNode1->_x)) / + lnk->_z / lnk->_z; + movarr->_point.x = x; + movarr->_point.y = y; + + calcDistance(&movarr->_point, lnk, 0); + + arr->push_back(movarr); + } + } + } + } + } + + *arrSize = arr->size(); + + return arr; +} + +void MovGraph::findAllPaths(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &allPaths) { + if (lnk == lnk2) { + for (uint i = 0; i < tempObList1.size(); i++) + allPaths.push_back(tempObList1[i]); + + allPaths.push_back(lnk); + } else { + lnk->_flags |= 0x80000000; + + tempObList1.push_back(lnk); + + for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) { + MovGraphLink *l = (MovGraphLink *)*i; + + if (l->_movGraphNode1 != lnk->_movGraphNode1) { + if (l->_movGraphNode2 != lnk->_movGraphNode1) { + if (l->_movGraphNode1 != lnk->_movGraphNode2 && l->_movGraphNode2 != lnk->_movGraphNode2) + continue; + } + } + + if (!(l->_flags & 0xA0000000)) + findAllPaths(l, lnk2, tempObList1, allPaths); + } + + lnk->_flags &= 0x7FFFFFFF; + } +} + +// Returns a list of possible paths two points in graph space +Common::Array<MovItem *> *MovGraph::calcMovItems(MovArr *currPos, MovArr *destPos, int *pathCount) { + Common::Array<MovGraphLink *> tempObList1; + Common::Array<MovGraphLink *> allPaths; + + // Get all paths between two edges of the graph + findAllPaths(currPos->_link, destPos->_link, tempObList1, allPaths); + + *pathCount = 0; + + if (!allPaths.size()) + return 0; + + *pathCount = allPaths.size(); + + Common::Array<MovItem *> *res = new Common::Array<MovItem *>; + + for (int i = 0; i < *pathCount; i++) { + MovItem *r = new MovItem; + + genMovItem(r, allPaths[i], currPos, destPos); + + res->push_back(r); + + delete allPaths[i]; + } + + // Start the resulting path from current position + destPos->_link = currPos->_link; + + return res; +} + +void MovGraph::genMovItem(MovItem *movitem, MovGraphLink *grlink, MovArr *movarr1, MovArr *movarr2) { + warning("STUB: MovGraph::genMovItem()"); +} + +bool MovGraph::calcChunk(int idx, int x, int y, MovArr *arr, int a6) { + int staticsId; + + if (_items[idx]->ani->_statics) { + staticsId = _items[idx]->ani->_statics->_staticsId; + } else { + if (!_items[idx]->ani->_movement->_staticsObj2) + return 0; + + staticsId = _items[idx]->ani->_movement->_staticsObj2->_staticsId; + } + + int arrSize; + + Common::Array<MovArr *> *movarr = genMovArr(x, y, &arrSize, 0, 1); + + if (!movarr) + return getNearestPoint(idx, 0, arr); + + bool res = false; + + int idxmin = -1; + int offmin = 100; + + for (int i = 0; i < arrSize; i++) { + int off = _mgm.refreshOffsets(_items[idx]->ani->_id, staticsId, (*movarr)[i]->_link->_dwordArray2[_field_44]); + + if (off < offmin) { + offmin = off; + idxmin = i; + } + + off = _mgm.refreshOffsets(_items[idx]->ani->_id, staticsId, (*movarr)[i]->_link->_dwordArray2[_field_44 + 1]); + if (off < offmin) { + offmin = off; + idxmin = i; + } + } + + if (idxmin != -1) { + *arr = *(*movarr)[idxmin]; + + res = true; + } + + delete movarr; + + return res; +} + +void MovGraph::setEnds(MovStep *step1, MovStep *step2) { + if (step1->link->_movGraphNode1 == step2->link->_movGraphNode2) { + step1->sfield_0 = 1; + step2->sfield_0 = 1; + + return; + } + + if (step1->link->_movGraphNode1 == step2->link->_movGraphNode1) { + step1->sfield_0 = 1; + step2->sfield_0 = 0; + } else { + step1->sfield_0 = 0; + + if (step1->link->_movGraphNode2 != step2->link->_movGraphNode1) { + step2->sfield_0 = 1; + } else { + step2->sfield_0 = 0; + } + } +} + +int MovGraph2::getItemIndexByGameObjectId(int objectId) { + for (uint i = 0; i < _items2.size(); i++) + if (_items2[i]->_objectId == objectId) + return i; + + return -1; +} + +int MovGraph2::getItemSubIndexByStaticsId(int idx, int staticsId) { + for (int i = 0; i < 4; i++) + if (_items2[idx]->_subItems[i]._staticsId1 == staticsId || _items2[idx]->_subItems[i]._staticsId2 == staticsId) + return i; + + return -1; +} + +int MovGraph2::getItemSubIndexByMovementId(int idx, int movId) { + for (int i = 0; i < 4; i++) + if (_items2[idx]->_subItems[i]._walk[0]._movementId == movId || _items2[idx]->_subItems[i]._turn[0]._movementId == movId || + _items2[idx]->_subItems[i]._turnS[0]._movementId == movId) + return i; + + return -1; +} + +int MovGraph2::getItemSubIndexByMGM(int index, StaticANIObject *ani) { + if (findNode(ani->_ox, ani->_oy, 0) || findLink1(ani->_ox, ani->_oy, -1, 0) || findLink2(ani->_ox, ani->_oy)) { + int minidx = -1; + int min = 0; + + for (int i = 0; i < 4; i++) { + int tmp = _mgm.refreshOffsets(ani->_id, ani->_statics->_staticsId, _items2[index]->_subItems[i]._staticsId1); + + if (tmp >= 0 && (minidx == -1 || tmp < min)) { + minidx = i; + min = tmp; + } + } + + return minidx; + } + + return -1; +} + +bool MovGraph2::initDirections(StaticANIObject *obj, MovGraph2Item *item) { + item->_obj = obj; + item->_objectId = obj->_id; + + GameVar *var = g_fp->getGameLoaderGameVar()->getSubVarByName(obj->_objectName); + if (!var) + return false; + + var = var->getSubVarByName("Test_walk"); + + if (!var) + return false; + + GameVar *varD = 0; + Common::Point point; + + for (int dir = 0; dir < 4; dir++) { + switch (dir) { + case 0: + varD = var->getSubVarByName("Right"); + break; + case 1: + varD = var->getSubVarByName("Left"); + break; + case 2: + varD = var->getSubVarByName("Up"); + break; + case 3: + varD = var->getSubVarByName("Down"); + break; + } + + if (!varD) + return false; + + for (int act = 0; act < 3; act++) { + int idx = 0; + + switch(act) { + case 0: + idx = varD->getSubVarAsInt("Start"); + break; + case 1: + idx = varD->getSubVarAsInt("Go"); + break; + case 2: + idx = varD->getSubVarAsInt("Stop"); + break; + } + + item->_subItems[dir]._walk[act]._movementId = idx; + + Movement *mov = obj->getMovementById(idx); + + item->_subItems[dir]._walk[act]._mov = mov; + if (mov) { + mov->calcSomeXY(point, 0, -1); + item->_subItems[dir]._walk[act]._mx = point.x; + item->_subItems[dir]._walk[act]._my = point.y; + } + } + + for (int act = 0; act < 4; act++) { + int idx = 0; + + switch(act) { + case 0: + idx = varD->getSubVarAsInt("TurnR"); + break; + case 1: + idx = varD->getSubVarAsInt("TurnL"); + break; + case 2: + idx = varD->getSubVarAsInt("TurnU"); + break; + case 3: + idx = varD->getSubVarAsInt("TurnD"); + break; + } + + item->_subItems[dir]._turn[act]._movementId = idx; + + Movement *mov = obj->getMovementById(idx); + + item->_subItems[dir]._turn[act]._mov = mov; + if (mov) { + mov->calcSomeXY(point, 0, -1); + item->_subItems[dir]._turn[act]._mx = point.x; + item->_subItems[dir]._turn[act]._my = point.y; + } + } + + for (int act = 0; act < 4; act++) { + int idx = 0; + + switch(act) { + case 0: + idx = varD->getSubVarAsInt("TurnSR"); + break; + case 1: + idx = varD->getSubVarAsInt("TurnSL"); + break; + case 2: + idx = varD->getSubVarAsInt("TurnSU"); + break; + case 3: + idx = varD->getSubVarAsInt("TurnSD"); + break; + } + + item->_subItems[dir]._turnS[act]._movementId = idx; + + Movement *mov = obj->getMovementById(idx); + + item->_subItems[dir]._turnS[act]._mov = mov; + if (mov) { + mov->calcSomeXY(point, 0, -1); + item->_subItems[dir]._turnS[act]._mx = point.x; + item->_subItems[dir]._turnS[act]._my = point.y; + } + } + + item->_subItems[dir]._staticsId1 = item->_subItems[dir]._walk[0]._mov->_staticsObj1->_staticsId; + item->_subItems[dir]._staticsId2 = item->_subItems[dir]._walk[0]._mov->_staticsObj2->_staticsId; + + } + return true; +} + +void MovGraph2::attachObject(StaticANIObject *obj) { + MovGraph::attachObject(obj); + + int id = getItemIndexByGameObjectId(obj->_id); + + if (id >= 0) { + _items2[id]->_obj = obj; + } else { + MovGraph2Item *item = new MovGraph2Item; + + if (initDirections(obj, item)) { + _items2.push_back(item); + } else { + delete item; + } + } +} + +void MovGraph2::buildMovInfo1SubItems(MovInfo1 *movinfo, Common::Array<MovGraphLink *> *linkList, LinkInfo *lnkSrc, LinkInfo *lnkDst) { + MovInfo1Sub *elem; + Common::Point point; + Common::Rect rect; + + int subIndex = movinfo->subIndex; + + movinfo->items.clear(); + + elem = new MovInfo1Sub; + elem->subIndex = subIndex; + elem->x = movinfo->pt1.x; + elem->y = movinfo->pt1.y; + elem->distance = -1; + + movinfo->items.push_back(elem); + + int prevSubIndex = movinfo->subIndex; + + for (uint i = 0; i < linkList->size(); i++) { + int idx1; + + if (linkList->size() <= 1) { + if (linkList->size() == 1) + idx1 = getShortSide((*linkList)[0], movinfo->pt2.x - movinfo->pt1.x, movinfo->pt2.y - movinfo->pt1.y); + else + idx1 = getShortSide(0, movinfo->pt2.x - movinfo->pt1.x, movinfo->pt2.y - movinfo->pt1.y); + + point.y = -1; + rect.bottom = -1; + rect.right = -1; + rect.top = -1; + rect.left = -1; + } else { + idx1 = findLink(linkList, i, &rect, &point); + } + + if (idx1 != prevSubIndex) { + prevSubIndex = idx1; + subIndex = idx1; + + elem = new MovInfo1Sub; + elem->subIndex = subIndex; + elem->x = rect.left; + elem->y = rect.top; + elem->distance = -1; + + movinfo->items.push_back(elem); + } + + if (i != linkList->size() - 1) { + while (1) { + i++; + if (findLink(linkList, i, &rect, 0) != prevSubIndex) { + i--; + findLink(linkList, i, &rect, &point); + + break; + } + + if (i == linkList->size() - 1) + break; + } + } + + if (movinfo->items.back()->subIndex != 10) { + subIndex = prevSubIndex; + + elem = new MovInfo1Sub; + elem->subIndex = 10; + elem->x = -1; + elem->y = -1; + elem->distance = -1; + + movinfo->items.push_back(elem); + + if (i == linkList->size()) { + elem = new MovInfo1Sub; + elem->subIndex = prevSubIndex; + elem->x = movinfo->pt2.x; + elem->y = movinfo->pt2.y; + elem->distance = movinfo->distance2; + + movinfo->items.push_back(elem); + } else { + elem = new MovInfo1Sub; + elem->subIndex = prevSubIndex; + elem->x = rect.right; + elem->y = rect.bottom; + elem->distance = point.y; + + movinfo->items.push_back(elem); + } + } + } + + if (subIndex != movinfo->item1Index) { + elem = new MovInfo1Sub; + elem->subIndex = movinfo->item1Index; + elem->x = movinfo->pt2.x; + elem->y = movinfo->pt2.y; + elem->distance = movinfo->distance2; + + movinfo->items.push_back(elem); + } + + movinfo->itemsCount = movinfo->items.size(); +} + +MessageQueue *MovGraph2::buildMovInfo1MessageQueue(MovInfo1 *movInfo) { + MovInfo1 movinfo(movInfo); + + int curX = movInfo->pt1.x; + int curY = movInfo->pt1.y; + int curDistance = movInfo->distance1; + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + for (int i = 0; i < movInfo->itemsCount - 1; i++) { + if (movInfo->items[i + 1]->subIndex != 10) { + MG2I *mg2i; + + if (i >= movInfo->itemsCount - 2 || movInfo->items[i + 2]->subIndex != 10) { + movinfo.flags = 0; + mg2i = &_items2[movInfo->index]->_subItems[movInfo->items[i]->subIndex]._turnS[movInfo->items[i + 1]->subIndex]; + } else { + movinfo.flags = 2; + mg2i = &_items2[movInfo->index]->_subItems[movInfo->items[i]->subIndex]._turn[movInfo->items[i + 1]->subIndex]; + } + if (i < movInfo->itemsCount - 2 + || (movInfo->items[i]->x == movInfo->items[i + 1]->x + && movInfo->items[i]->y == movInfo->items[i + 1]->y) + || movInfo->items[i]->x == -1 + || movInfo->items[i]->y == -1 + || movInfo->items[i + 1]->x == -1 + || movInfo->items[i + 1]->y == -1) { + + ExCommand *ex = new ExCommand(_items2[movInfo->index]->_objectId, 1, mg2i->_movementId, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags |= 2; + ex->_keyCode = _items2[movInfo->index]->_obj->_okeyCode; + ex->_field_24 = 1; + ex->_field_14 = -1; + mq->addExCommandToEnd(ex); + + curX += mg2i->_mx; + curY += mg2i->_my; + } else { + MGMInfo mgminfo; + + memset(&mgminfo, 0, sizeof(mgminfo)); + + mgminfo.ani = _items2[movInfo->index]->_obj; + mgminfo.staticsId2 = mg2i->_mov->_staticsObj2->_staticsId; + mgminfo.x1 = movInfo->items[i + 1]->x; + mgminfo.y1 = movInfo->items[i + 1]->y; + mgminfo.field_1C = movInfo->items[i + 1]->distance; + mgminfo.staticsId1 = mg2i->_mov->_staticsObj1->_staticsId; + + mgminfo.x2 = movInfo->items[i]->x; + mgminfo.y2 = movInfo->items[i]->y; + mgminfo.field_10 = 1; + mgminfo.flags = 0x7f; + mgminfo.movementId = mg2i->_movementId; + + MessageQueue *mq2 = _mgm.genMovement(&mgminfo); + mq->transferExCommands(mq2); + + delete mq2; + + curX = movInfo->items[i + 1]->x; + curY = movInfo->items[i + 1]->y; + } + } else { + movinfo.item1Index = movInfo->items[i]->subIndex; + movinfo.subIndex = movinfo.item1Index; + movinfo.pt1.y = curY; + movinfo.pt1.x = curX; + + movinfo.distance1 = curDistance; + movinfo.pt2.x = movInfo->items[i + 2]->x; + movinfo.pt2.y = movInfo->items[i + 2]->y; + movinfo.distance2 = movInfo->items[i + 2]->distance; + + if (i >= movInfo->itemsCount - 4 + || movInfo->items[i + 2]->subIndex == 10 + || movInfo->items[i + 3]->subIndex == 10 + || movInfo->items[i + 2]->subIndex == movInfo->items[i + 3]->subIndex + || movInfo->items[i + 4]->subIndex != 10) { + if (i >= movInfo->itemsCount - 3 + || movInfo->items[i + 2]->subIndex == 10 + || movInfo->items[i + 3]->subIndex == 10 + || movInfo->items[i + 2]->subIndex == movInfo->items[i + 3]->subIndex) { + movinfo.flags &= 3; + } else { + MG2I *m = &_items2[movInfo->index]->_subItems[movInfo->items[i + 2]->subIndex]._turnS[movInfo->items[i + 3]->subIndex]; + movinfo.pt2.x -= m->_mx; + movinfo.pt2.y -= m->_my; + movinfo.flags &= 3; + } + } else { + MG2I *m = &_items2[movInfo->index]->_subItems[movInfo->items[i + 2]->subIndex]._turn[movInfo->items[i + 3]->subIndex]; + + if (movinfo.item1Index && movinfo.item1Index != 1) { + movinfo.pt2.y -= m->_my; + movinfo.flags = (movinfo.flags & 2) | 1; + } else { + movinfo.pt2.x -= m->_mx; + movinfo.flags = (movinfo.flags & 2) | 1; + } + } + i++; // intentional + + MessageQueue *mq2 = genMovement(&movinfo); + + if (!mq2) { + delete mq; + return 0; + } + + mq->transferExCommands(mq2); + + delete mq2; + + curX = movinfo.pt2.x; + curY = movinfo.pt2.y; + curDistance = movinfo.distance2; + } + } + + movInfo->pt2.x = movinfo.pt2.x; + movInfo->pt2.y = movinfo.pt2.y; + + return mq; +} + +int MovGraph2::detachObject(StaticANIObject *obj) { + warning("STUB: MovGraph2::detachObject()"); + + return 0; +} + +void MovGraph2::detachAllObjects() { + for (uint i = 0; i < _items2.size(); i++) + delete _items2[i]; + + _items2.clear(); +} + +MessageQueue *MovGraph2::startMove(StaticANIObject *ani, int xpos, int ypos, int fuzzyMatch, int staticsId) { + if (!ani->isIdle()) + return 0; + + if (ani->_flags & 0x100) + return 0; + + MessageQueue *mq = doWalkTo(ani, xpos, ypos, fuzzyMatch, staticsId); + + if (!mq) + return 0; + + if (ani->_movement) { + if (mq->getCount() <= 1 || mq->getExCommandByIndex(0)->_messageKind != 22) { + PicAniInfo picAniInfo; + + ani->getPicAniInfo(&picAniInfo); + ani->updateStepPos(); + MessageQueue *mq1 = doWalkTo(ani, xpos, ypos, fuzzyMatch, staticsId); + + ani->setPicAniInfo(&picAniInfo); + + if (mq1) { + delete mq; + + mq = mq1; + } + } else { + ani->_movement = 0; + } + } + + if (!mq->chain(ani)) { + delete mq; + + return 0; + } + + return mq; +} + +MessageQueue *MovGraph2::doWalkTo(StaticANIObject *obj, int xpos, int ypos, int fuzzyMatch, int staticsId) { + LinkInfo linkInfoDest; + LinkInfo linkInfoSource; + MovInfo1 movInfo1; + PicAniInfo picAniInfo; + Common::Point point; + + debug(0, "MovGraph2::doWalkTo(%d, %d, %d, %d, %d)", obj->_id, xpos, ypos, fuzzyMatch, staticsId); + + int idx = getItemIndexByGameObjectId(obj->_id); + + if (idx < 0) + return 0; + + linkInfoSource.link = 0; + linkInfoSource.node = 0; + + linkInfoDest.link = 0; + linkInfoDest.node = 0; + + point.x = 0; + + obj->getPicAniInfo(&picAniInfo); + + int idxsub; + + if (obj->_movement) + idxsub = getItemSubIndexByMovementId(idx, obj->_movement->_id); + else + idxsub = getItemSubIndexByStaticsId(idx, obj->_statics->_staticsId); + + bool subMgm = false; + + if (idxsub == -1) { + idxsub = getItemSubIndexByMGM(idx, obj); + subMgm = true; + + if (idxsub == -1) + return 0; + } + + if (obj->_movement) { + int newx, newy; + + if (subMgm) { + obj->_messageQueueId = 0; + obj->changeStatics2(_items2[idx]->_subItems[idxsub]._staticsId1); + newx = obj->_ox; + newy = obj->_oy; + } else { + obj->_movement->calcSomeXY(point, 0, picAniInfo.dynamicPhaseIndex); + newx = obj->_movement->_ox - point.x; + newy = obj->_movement->_oy - point.y; + if (idxsub != 1 && idxsub) { + if (idxsub == 2 || idxsub == 3) { + newy = obj->_movement->_oy; + } + } else { + newx = obj->_movement->_ox; + } + } + + obj->_movement = 0; + obj->setOXY(newx, newy); + } + + if (obj->_ox == xpos && obj->_oy == ypos) { + g_fp->_globalMessageQueueList->compact(); + + MessageQueue *mq = new MessageQueue(); + + if (staticsId && obj->_statics->_staticsId != staticsId) { + int idxwalk = getItemSubIndexByStaticsId(idx, staticsId); + if (idxwalk == -1) { + obj->setPicAniInfo(&picAniInfo); + + delete mq; + + return 0; + } + + ExCommand *ex = new ExCommand(picAniInfo.objectId, 1, _items2[idx]->_subItems[idxsub]._walk[idxwalk]._movementId, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_24 = 1; + ex->_keyCode = picAniInfo.field_8; + ex->_excFlags |= 2; + + mq->addExCommandToEnd(ex); + } else { + ExCommand *ex = new ExCommand(picAniInfo.objectId, 22, obj->_statics->_staticsId, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = picAniInfo.field_8; + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(picAniInfo.objectId, 5, -1, obj->_ox, obj->_oy, 0, 1, 0, 0, 0); + + ex->_field_14 = -1; + ex->_keyCode = picAniInfo.field_8; + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + } + + obj->setPicAniInfo(&picAniInfo); + + return mq; + } + + linkInfoSource.node = findNode(obj->_ox, obj->_oy, 0); + + if (!linkInfoSource.node) { + linkInfoSource.link = findLink1(obj->_ox, obj->_oy, idxsub, 0); + + if (!linkInfoSource.link) { + linkInfoSource.link = findLink2(obj->_ox, obj->_oy); + + if (!linkInfoSource.link) { + obj->setPicAniInfo(&picAniInfo); + + return 0; + } + } + } + + linkInfoDest.node = findNode(xpos, ypos, fuzzyMatch); + + if (!linkInfoDest.node) { + linkInfoDest.link = findLink1(xpos, ypos, idxsub, fuzzyMatch); + + if (!linkInfoDest.link) { + obj->setPicAniInfo(&picAniInfo); + + return 0; + } + } + + Common::Array<MovGraphLink *> tempLinkList; + double minPath = findMinPath(&linkInfoSource, &linkInfoDest, &tempLinkList); + + debug(0, "MovGraph2::doWalkTo(): path: %g parts: %d", minPath, tempLinkList.size()); + + if (minPath < 0.0 || ((linkInfoSource.node != linkInfoDest.node || !linkInfoSource.node) && !tempLinkList.size())) + return 0; + + movInfo1.clear(); + + movInfo1.subIndex = idxsub; + movInfo1.pt1.x = obj->_ox; + movInfo1.pt1.y = obj->_oy; + + int dx1 = obj->_ox; + int dy1 = obj->_oy; + int dx2, dy2; + + if (linkInfoSource.node) + movInfo1.distance1 = linkInfoSource.node->_z; + else + movInfo1.distance1 = linkInfoSource.link->_movGraphNode1->_z; + + if (linkInfoDest.node) { + dx2 = linkInfoDest.node->_x; + dy2 = linkInfoDest.node->_y; + + movInfo1.pt2.x = linkInfoDest.node->_x; + movInfo1.pt2.y = linkInfoDest.node->_y; + + movInfo1.distance2 = linkInfoDest.node->_z; + } else { + movInfo1.pt2.x = xpos; + movInfo1.pt2.y = ypos; + + MovGraphNode *nod = linkInfoDest.link->_movGraphNode1; + double dst1 = sqrt((double)((ypos - nod->_y) * (ypos - nod->_y) + (xpos - nod->_x) * (xpos - nod->_x))); + int dst = linkInfoDest.link->_movGraphNode2->_z - nod->_z; + + movInfo1.distance2 = (int)(nod->_z + (dst1 * (double)dst / linkInfoDest.link->_z)); + + calcDistance(&movInfo1.pt2, linkInfoDest.link, 1); + + dx1 = movInfo1.pt1.x; + dy1 = movInfo1.pt1.y; + dx2 = movInfo1.pt2.x; + dy2 = movInfo1.pt2.y; + } + + if (staticsId) { + movInfo1.item1Index = getItemSubIndexByStaticsId(idx, staticsId); + } else if (tempLinkList.size() <= 1) { + if (tempLinkList.size() == 1) + movInfo1.item1Index = getShortSide(tempLinkList[0], dx2 - dx1, dy2 - dy1); + else + movInfo1.item1Index = getShortSide(0, dx2 - dx1, dy2 - dy1); + } else { + movInfo1.item1Index = findLink(&tempLinkList, tempLinkList.size() - 1, 0, 0); + } + + movInfo1.flags = fuzzyMatch != 0; + + if (_items2[idx]->_subItems[idxsub]._staticsId1 != obj->_statics->_staticsId) + movInfo1.flags |= 2; + + buildMovInfo1SubItems(&movInfo1, &tempLinkList, &linkInfoSource, &linkInfoDest); + + MessageQueue *mq = buildMovInfo1MessageQueue(&movInfo1); + + linkInfoDest.node = findNode(movInfo1.pt2.x, movInfo1.pt2.y, fuzzyMatch); + + if (!linkInfoDest.node) + linkInfoDest.link = findLink1(movInfo1.pt2.x, movInfo1.pt2.y, movInfo1.item1Index, fuzzyMatch); + + if (fuzzyMatch || linkInfoDest.link || linkInfoDest.node) { + if (mq && mq->getCount() > 0 && picAniInfo.movementId) { + ExCommand *ex = mq->getExCommandByIndex(0); + + if (ex && (ex->_messageKind == 1 || ex->_messageKind == 20) + && picAniInfo.movementId == ex->_messageNum + && picAniInfo.someDynamicPhaseIndex == ex->_field_14) { + mq->deleteExCommandByIndex(0, 1); + } else { + ex = new ExCommand(picAniInfo.objectId, 5, ex->_messageNum, obj->_ox, obj->_oy, 0, 1, 0, 0, 0); + ex->_field_14 = -1; + ex->_keyCode = picAniInfo.field_8; + ex->_excFlags |= 2; + mq->addExCommand(ex); + + ex = new ExCommand(picAniInfo.objectId, 22, _items2[idx]->_subItems[idxsub]._staticsId1, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = picAniInfo.field_8; + ex->_excFlags |= 3; + mq->addExCommand(ex); + } + } + } else { + if (mq) + delete mq; + mq = 0; + } + + obj->setPicAniInfo(&picAniInfo); + + return mq; +} + +MovGraphNode *MovGraph2::findNode(int x, int y, int fuzzyMatch) { + for (ObList::iterator i = _nodes.begin(); i != _nodes.end(); ++i) { + assert(((CObject *)*i)->_objtype == kObjTypeMovGraphNode); + + MovGraphNode *node = (MovGraphNode *)*i; + + if (fuzzyMatch) { + if (abs(node->_x - x) < 15 && abs(node->_y - y) < 15) + return node; + } else { + if (node->_x == x && node->_y == y) + return node; + } + } + + return 0; +} + +int MovGraph2::getShortSide(MovGraphLink *lnk, int x, int y) { + bool cond; + + if (lnk) + cond = abs(lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x) > abs(lnk->_movGraphNode2->_y - lnk->_movGraphNode1->_y); + else + cond = abs(x) > abs(y); + + if (cond) + return x <= 0; + else + return ((y > 0) + 2); +} + +int MovGraph2::findLink(Common::Array<MovGraphLink *> *linkList, int idx, Common::Rect *rect, Common::Point *point) { + MovGraphNode *node1 = (*linkList)[idx]->_movGraphNode1; + MovGraphNode *node2 = (*linkList)[idx]->_movGraphNode2; + MovGraphNode *node3 = node1; + + if (idx != 0) { + MovGraphLink *lnk = (*linkList)[idx - 1]; + + if (lnk->_movGraphNode2 != node1) { + if (lnk->_movGraphNode1 != node1) { + if (lnk->_movGraphNode2 == node2 || lnk->_movGraphNode1 == node2) { + node3 = node2; + node2 = node1; + } + goto LABEL_7; + } + } + node3 = node1; + } else if (idx != (int)(linkList->size() - 1)) { + MovGraphLink *lnk = (*linkList)[idx + 1]; + + if (lnk->_movGraphNode2 == node1 || lnk->_movGraphNode1 == node1) { + node3 = node2; + node2 = node1; + } else if (lnk->_movGraphNode2 == node2 || lnk->_movGraphNode1 == node2) { + node3 = node1; + } + } + + LABEL_7: + if (rect) { + rect->left = node3->_x; + rect->top = node3->_y; + rect->right = node2->_x; + rect->bottom = node2->_y; + } + if (point) { + point->x = node3->_z; + point->y = node2->_z; + } + + if (abs(node3->_x - node2->_x) <= abs(node3->_y - node2->_y)) + return (node3->_y < node2->_x) + 2; + else + return node3->_x >= node2->_x; +} + +MessageQueue *MovGraph2::genMovement(MovInfo1 *info) { + int mx1 = 0; + int my1 = 0; + + if (!(info->flags & 2)) { + mx1 = _items2[info->index]->_subItems[info->subIndex]._walk[0]._mx; + my1 = _items2[info->index]->_subItems[info->subIndex]._walk[0]._my; + } + + int mx2 = 0; + int my2 = 0; + + if (!(info->flags & 4)) { + mx2 = _items2[info->index]->_subItems[info->subIndex]._walk[2]._mx; + my2 = _items2[info->index]->_subItems[info->subIndex]._walk[2]._my; + } + + Common::Point point; + + int y = info->pt2.y - info->pt1.y - my2 - my1; + int x = info->pt2.x - info->pt1.x - mx2 - mx1; + int a2 = 0; + int mgmLen; + + _mgm.calcLength(&point, _items2[info->index]->_subItems[info->subIndex]._walk[1]._mov, x, y, &mgmLen, &a2, info->flags & 1); + + int x1 = point.x; + int y1 = point.y; + + if (!(info->flags & 1)) { + if (info->subIndex == 1 || info->subIndex == 0) { + a2 = -1; + x1 = mgmLen * _items2[info->index]->_subItems[info->subIndex]._walk[1]._mx; + x = x1; + info->pt2.x = x1 + info->pt1.x + mx1 + mx2; + } + } + + if (!(info->flags & 1)) { + if (info->subIndex == 2 || info->subIndex == 3) { + a2 = -1; + y1 = mgmLen * _items2[info->index]->_subItems[info->subIndex]._walk[1]._my; + y = y1; + info->pt2.y = y1 + info->pt1.y + my1 + my2; + } + } + + int cntX = 0; + int cntY = 0; + + if (!(info->flags & 2)) { + cntX = _items2[info->index]->_subItems[info->subIndex]._walk[0]._mov->countPhasesWithFlag(-1, 1); + cntY = _items2[info->index]->_subItems[info->subIndex]._walk[0]._mov->countPhasesWithFlag(-1, 2); + } + + if (mgmLen > 1) { + cntX += (mgmLen - 1) * _items2[info->index]->_subItems[info->subIndex]._walk[1]._mov->countPhasesWithFlag(-1, 1); + cntY += (mgmLen - 1) * _items2[info->index]->_subItems[info->subIndex]._walk[1]._mov->countPhasesWithFlag(-1, 2); + } + + if (mgmLen > 0) { + cntX += _items2[info->index]->_subItems[info->subIndex]._walk[1]._mov->countPhasesWithFlag(a2, 1); + cntY += _items2[info->index]->_subItems[info->subIndex]._walk[1]._mov->countPhasesWithFlag(a2, 2); + } + + if (!(info->flags & 4)) { + cntX += _items2[info->index]->_subItems[info->subIndex]._walk[2]._mov->countPhasesWithFlag(-1, 1); + cntY += _items2[info->index]->_subItems[info->subIndex]._walk[2]._mov->countPhasesWithFlag(-1, 2); + } + + int dx1 = x - x1; + int dy1 = y - y1; + + if (cntX) + x1 = (int)((double)dx1 / (double)cntX); + else + x1 = 0; + + if (cntY) + y1 = (int)((double)dy1 / (double)cntY); + else + y1 = 0; + + int v34 = dx1 - cntX * x1; + int v35 = dy1 - cntY * y1; + Common::Point x2; + Common::Point y2(v34, v35); + + if (v34) + x2.x = v34 / abs(v34); + else + x2.x = 0; + + if (v35) + x2.y = v35 / abs(v35); + else + x2.y = 0; + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + ExCommand *ex; + + if (info->flags & 2) { + ex = new ExCommand( + _items2[info->index]->_objectId, + 5, + _items2[info->index]->_subItems[info->subIndex]._walk[1]._movementId, + info->pt1.x, + info->pt1.y, + 0, + 1, + 0, + 0, + 0); + + ex->_field_14 = info->distance1; + + ex->_keyCode = _items2[info->index]->_obj->_okeyCode; + ex->_field_24 = 1; + ex->_excFlags |= 2; + } else { + ex = new ExCommand( + _items2[info->index]->_objectId, + 5, + _items2[info->index]->_subItems[info->subIndex]._walk[0]._movementId, + info->pt1.x, + info->pt1.y, + 0, + 1, + 0, + 0, + 0); + + ex->_field_14 = info->distance1; + + ex->_keyCode = _items2[info->index]->_obj->_okeyCode; + ex->_field_24 = 1; + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = _mgm.buildExCommand2( + _items2[info->index]->_subItems[info->subIndex]._walk[0]._mov, + _items2[info->index]->_objectId, + x1, + y1, + &x2, + &y2, + -1); + ex->_parId = mq->_id; + ex->_keyCode = _items2[info->index]->_obj->_okeyCode; + } + + mq->addExCommandToEnd(ex); + + for (int i = 0; i < mgmLen; ++i) { + int par; + + if (i == mgmLen - 1) + par = a2; + else + par = -1; + + ex = _mgm.buildExCommand2( + _items2[info->index]->_subItems[info->subIndex]._walk[1]._mov, + _items2[info->index]->_objectId, + x1, + y1, + &x2, + &y2, + par); + ex->_parId = mq->_id; + ex->_keyCode = _items2[info->index]->_obj->_okeyCode; + mq->addExCommandToEnd(ex); + } + + if (!(info->flags & 4)) { + ex = _mgm.buildExCommand2( + _items2[info->index]->_subItems[info->subIndex]._walk[2]._mov, + _items2[info->index]->_objectId, + x1, + y1, + &x2, + &y2, + -1); + ex->_parId = mq->_id; + ex->_keyCode = _items2[info->index]->_obj->_okeyCode; + + mq->addExCommandToEnd(ex); + } + + ex = new ExCommand(_items2[info->index]->_objectId, 5, -1, info->pt2.x, info->pt2.y, 0, 1, 0, 0, 0); + ex->_field_14 = info->distance2; + + ex->_keyCode = _items2[info->index]->_obj->_okeyCode; + ex->_field_24 = 0; + ex->_excFlags |= 2; + + mq->addExCommandToEnd(ex); + + return mq; +} + +MovGraphLink *MovGraph2::findLink1(int x, int y, int idx, int fuzzyMatch) { + Common::Point point; + MovGraphLink *res = 0; + + for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) { + assert(((CObject *)*i)->_objtype == kObjTypeMovGraphLink); + + MovGraphLink *lnk = (MovGraphLink *)*i; + + if (fuzzyMatch) { + point.x = x; + point.y = y; + double dst = calcDistance(&point, lnk, 0); + + if (dst >= 0.0 && dst < 2.0) + return lnk; + } else if (!(lnk->_flags & 0x20000000)) { + if (lnk->_movGraphReact->pointInRegion(x, y)) { + if (abs(lnk->_movGraphNode1->_x - lnk->_movGraphNode2->_x) <= abs(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y)) { + if (idx == 2 || idx == 3) + return lnk; + res = lnk; + } else { + if (idx == 1 || !idx) + return lnk; + res = lnk; + } + } + } + } + + return res; +} + +MovGraphLink *MovGraph2::findLink2(int x, int y) { + double mindist = 1.0e20; + MovGraphLink *res = 0; + + for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) { + assert(((CObject *)*i)->_objtype == kObjTypeMovGraphLink); + + MovGraphLink *lnk = (MovGraphLink *)*i; + + if (!(lnk->_flags & 0x20000000)) { + double n1x = lnk->_movGraphNode1->_x; + double n1y = lnk->_movGraphNode1->_y; + double n2x = lnk->_movGraphNode2->_x; + double n2y = lnk->_movGraphNode2->_y; + double n1dx = n1x - x; + double n1dy = n1y - y; + double dst1 = sqrt(n1dy * n1dy + n1dx * n1dx); + double coeff1 = ((n1y - n2y) * n1dy + (n2x - n1x) * n1dx) / lnk->_z / dst1; + double dst3 = coeff1 * dst1; + double dst2 = sqrt(1.0 - coeff1 * coeff1) * dst1; + + if (coeff1 * dst1 < 0.0) { + dst3 = 0.0; + dst2 = sqrt(n1dy * n1dy + n1dx * n1dx); + } + if (dst3 > lnk->_z) { + dst3 = lnk->_z; + dst2 = sqrt((n2x - x) * (n2x - x) + (n2y - y) * (n2y - y)); + } + if (dst3 >= 0.0 && dst3 <= lnk->_z && dst2 < mindist) { + mindist = dst2; + res = lnk; + } + } + } + + if (mindist < 1.0e20) + return res; + else + return 0; +} + +double MovGraph2::findMinPath(LinkInfo *linkInfoSource, LinkInfo *linkInfoDest, Common::Array<MovGraphLink *> *listObj) { + LinkInfo linkInfoWorkSource; + + if (linkInfoSource->link != linkInfoDest->link || linkInfoSource->node != linkInfoDest->node) { + double minDistance = -1.0; + + if (linkInfoSource->node) { + for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) { + MovGraphLink *lnk = (MovGraphLink *)*i; + + if ((lnk->_movGraphNode1 == linkInfoSource->node || lnk->_movGraphNode2 == linkInfoSource->node) && !(lnk->_flags & 0xA0000000)) { + linkInfoWorkSource.node = 0; + linkInfoWorkSource.link = lnk; + + Common::Array<MovGraphLink *> tmpList; + + lnk->_flags |= 0x80000000; + + double newDistance = findMinPath(&linkInfoWorkSource, linkInfoDest, &tmpList); + + if (newDistance >= 0.0 && (minDistance < 0.0 || newDistance + lnk->_z < minDistance)) { + listObj->clear(); + listObj->push_back(tmpList); + + minDistance = newDistance + lnk->_z; + } + + lnk->_flags &= 0x7FFFFFFF; + } + } + } else if (linkInfoSource->link) { + linkInfoWorkSource.node = linkInfoSource->link->_movGraphNode1; + linkInfoWorkSource.link = 0; + + Common::Array<MovGraphLink *> tmpList; + + double newDistance = findMinPath(&linkInfoWorkSource, linkInfoDest, &tmpList); + + if (newDistance >= 0.0) { + listObj->clear(); + + listObj->push_back(linkInfoSource->link); + listObj->push_back(tmpList); + + minDistance = newDistance; + } + + linkInfoWorkSource.link = 0; + linkInfoWorkSource.node = linkInfoSource->link->_movGraphNode2; + + tmpList.clear(); + + newDistance = findMinPath(&linkInfoWorkSource, linkInfoDest, &tmpList); + + if (newDistance >= 0 && (minDistance < 0.0 || newDistance < minDistance)) { + listObj->push_back(linkInfoSource->link); + listObj->push_back(tmpList); + + minDistance = newDistance; + } + } + + return minDistance; + } else { + if (linkInfoSource->link) + listObj->push_back(linkInfoSource->link); + + return 0.0; + } +} + +MovGraphNode *MovGraph::calcOffset(int ox, int oy) { + MovGraphNode *res = 0; + double mindist = 1.0e10; + + for (ObList::iterator i = _nodes.begin(); i != _nodes.end(); ++i) { + assert(((CObject *)*i)->_objtype == kObjTypeMovGraphNode); + + MovGraphNode *node = (MovGraphNode *)*i; + + double dist = sqrt((double)((node->_x - oy) * (node->_x - oy) + (node->_x - ox) * (node->_x - ox))); + if (dist < mindist) { + mindist = dist; + res = node; + } + } + + return res; +} + +MovGraphLink::MovGraphLink() { + _z = 0; + _angle = 0; + _flags = 0x10000000; + _movGraphNode2 = 0; + _movGraphNode1 = 0; + _field_3C = 0; + _field_38 = 0; + _movGraphReact = 0; + _name = 0; + + _objtype = kObjTypeMovGraphLink; +} + +MovGraphLink::~MovGraphLink() { + delete _movGraphReact; + + _dwordArray1.clear(); + _dwordArray2.clear(); +} + + +bool MovGraphLink::load(MfcArchive &file) { + debug(5, "MovGraphLink::load()"); + + _dwordArray1.load(file); + _dwordArray2.load(file); + + _flags = file.readUint32LE(); + + debug(8, "GraphNode1"); + _movGraphNode1 = (MovGraphNode *)file.readClass(); + debug(8, "GraphNode2"); + _movGraphNode2 = (MovGraphNode *)file.readClass(); + + _z = file.readDouble(); + _angle = file.readDouble(); + + debug(8, "distance: %g, angle: %g", _z, _angle); + + _movGraphReact = (MovGraphReact *)file.readClass(); + _name = file.readPascalString(); + + return true; +} + +void MovGraphLink::recalcLength() { + if (_movGraphNode1) { + double dx = _movGraphNode2->_x - _movGraphNode1->_x; + double dy = _movGraphNode2->_y - _movGraphNode1->_y; + + _z = sqrt(dy * dy + dx * dx); + _angle = atan2(dx, dy); + } +} + +bool MovGraphNode::load(MfcArchive &file) { + debug(5, "MovGraphNode::load()"); + + _field_14 = file.readUint32LE(); + _x = file.readUint32LE(); + _y = file.readUint32LE(); + _z = file.readUint32LE(); + + return true; +} + +ReactParallel::ReactParallel() { + _x1 = 0; + _x2 = 0; + _dy = 0; + _dx = 0; + _y1 = 0; + _y2 = 0; +} + +bool ReactParallel::load(MfcArchive &file) { + debug(5, "ReactParallel::load()"); + + _x1 = file.readUint32LE(); + _y1 = file.readUint32LE(); + _x2 = file.readUint32LE(); + _y2 = file.readUint32LE(); + _dx = file.readUint32LE(); + _dy = file.readUint32LE(); + + createRegion(); + + return true; +} + +void ReactParallel::createRegion() { + _points = (Common::Point **)malloc(sizeof(Common::Point *) * 4); + + for (int i = 0; i < 4; i++) + _points[i] = new Common::Point; + + double at = atan2((double)(_x1 - _x2), (double)(_y1 - _y2)) + 1.570796; // pi/2 + double sn = sin(at); + double cs = cos(at); + + _points[0]->x = (int16)(_x1 - _dx * cs); + _points[0]->y = (int16)(_y1 - _dx * sn); + + _points[1]->x = (int16)(_x2 - _dx * cs); + _points[1]->y = (int16)(_y2 - _dx * sn); + + _points[2]->x = (int16)(_x2 + _dy * cs); + _points[2]->y = (int16)(_y2 + _dy * sn); + + _points[3]->x = (int16)(_x1 + _dy * cs); + _points[3]->y = (int16)(_y1 + _dy * sn); + + _pointCount = 4; + // GdiObject::Attach(_rgn, CreatePolygonRgn(_points, 4, 2); +} + +void ReactParallel::setCenter(int x1, int y1, int x2, int y2) { + _x1 = x1; + _y1 = y1; + _x2 = x2; + _y2 = y2; +} + +ReactPolygonal::ReactPolygonal() { + _centerX = 0; + _centerY = 0; + _bbox = 0; +} + +ReactPolygonal::~ReactPolygonal() { + delete _bbox; +} + +bool ReactPolygonal::load(MfcArchive &file) { + debug(5, "ReactPolygonal::load()"); + + _centerX = file.readUint32LE(); + _centerY = file.readUint32LE(); + _pointCount = file.readUint32LE(); + + if (_pointCount > 0) { + _points = (Common::Point **)malloc(sizeof(Common::Point *) * _pointCount); + + for (int i = 0; i < _pointCount; i++) { + _points[i] = new Common::Point; + + _points[i]->x = file.readUint32LE(); + _points[i]->y = file.readUint32LE(); + } + + } + + createRegion(); + + return true; +} + +void ReactPolygonal::createRegion() { + if (_points) { + + // GdiObject::Attach(_rgn, CreatePolygonRgn(_points, _pointCount, 2); + } +} + +void ReactPolygonal::setCenter(int x1, int y1, int x2, int y2) { + int cX = (x2 + x1) / 2; + int cY = (y2 + y1) / 2; + + if (_points) { + for (int i = 0; i < _pointCount; i++) { + _points[i]->x += cX - _centerX; + _points[i]->y += cY - _centerY; + } + } + + _centerX = cX; + _centerY = cY; +} + +void ReactPolygonal::getBBox(Common::Rect *rect) { + if (!_pointCount) + return; + + if (_bbox) { + *rect = *_bbox; + return; + } + + rect->left = _points[0]->x; + rect->top = _points[0]->y; + rect->right = _points[0]->x; + rect->bottom = _points[0]->y; + + for (int i = 1; i < _pointCount; i++) { + if (rect->left > _points[i]->x) + rect->left = _points[i]->x; + + if (rect->top < _points[i]->y) + rect->top = _points[i]->y; + + if (rect->right < _points[i]->x) + rect->right = _points[i]->x; + + if (rect->bottom > _points[i]->y) + rect->bottom = _points[i]->y; + } + + _bbox = new Common::Rect; + *_bbox = *rect; +} + + +bool MovGraphReact::pointInRegion(int x, int y) { + if (_pointCount < 3) { + return false; + } + + int counter = 0; + double xinters; + Common::Point p, p1, p2; + + p.x = x; + p.y = y; + + p1.x = _points[0]->x; + p1.y = _points[0]->y; + + for (int i = 1; i <= _pointCount; i++) { + p2.x = _points[i % _pointCount]->x; + p2.y = _points[i % _pointCount]->y; + + if (p.y > MIN(p1.y, p2.y)) { + if (p.y <= MAX(p1.y, p2.y)) { + if (p.x <= MAX(p1.x, p2.x)) { + if (p1.y != p2.y) { + xinters = (p.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x; + if (p1.x == p2.x || p.x <= xinters) { + counter++; + } + } + } + } + } + p1 = p2; + } + + if (counter % 2 == 0) { + return false; + } else { + return true; + } +} + +int startWalkTo(int objId, int objKey, int x, int y, int fuzzyMatch) { + MctlCompound *mc = getCurrSceneSc2MotionController(); + + if (mc) + return (mc->startMove(g_fp->_currentScene->getStaticANIObject1ById(objId, objKey), x, y, fuzzyMatch, 0) != 0); + + return 0; +} + +bool doSomeAnimation(int objId, int objKey, int a3) { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(objId, objKey); + MctlCompound *cmp = getCurrSceneSc2MotionController(); + + if (ani && cmp) + return cmp->resetPosition(ani, a3); + + return false; +} + +bool doSomeAnimation2(int objId, int objKey) { + return doSomeAnimation(objId, objKey, 0); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/motion.h b/engines/fullpipe/motion.h new file mode 100644 index 0000000000..a40d810ffa --- /dev/null +++ b/engines/fullpipe/motion.h @@ -0,0 +1,419 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_MOTION_H +#define FULLPIPE_MOTION_H + +#include "fullpipe/mgm.h" + +namespace Fullpipe { + +class MctlConnectionPoint; +class MovGraphLink; +class MessageQueue; +struct MovArr; +struct MovItem; + +int startWalkTo(int objId, int objKey, int x, int y, int a5); +bool doSomeAnimation(int objId, int objKey, int a3); +bool doSomeAnimation2(int objId, int objKey); + +class MotionController : public CObject { +public: + int _field_4; + bool _isEnabled; + +public: + MotionController() : _isEnabled(true), _field_4(0) {} + virtual ~MotionController() {} + virtual bool load(MfcArchive &file); + virtual void methodC() {} + virtual void method10() {} + virtual void deactivate() { _isEnabled = false; } + virtual void activate() { _isEnabled = true; } + virtual void attachObject(StaticANIObject *obj) {} + virtual int detachObject(StaticANIObject *obj) { return 0; } + virtual void detachAllObjects() {} + virtual Common::Array<MovItem *> *getPaths(StaticANIObject *ani, int x, int y, int flag1, int *rescount) { return 0; } + virtual bool setPosImmediate(StaticANIObject *obj, int x, int y) { return false; } + virtual int method30() { return 0; } + virtual MessageQueue *startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { return 0; } + virtual void setSelFunc(MovArr *(*_callback1)(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter)) {} + virtual bool resetPosition(StaticANIObject *ani, int flag) { return 0; } + virtual int method40() { return 0; } + virtual bool canDropInventory(StaticANIObject *ani, int x, int y) { return false; } + virtual int method48() { return -1; } + virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId) { return 0; } + + void enableLinks(const char *linkName, bool enable); + MovGraphLink *getLinkByName(const char *name); +}; + +class MovGraphReact : public CObject { +public: + int _pointCount; + Common::Point **_points; + +public: + MovGraphReact() : _pointCount(0), _points(0) {} + ~MovGraphReact() { free(_points); } + + virtual void setCenter(int x1, int y1, int x2, int y2) {} + virtual void createRegion() {} + virtual bool pointInRegion(int x, int y); +}; + +class MctlItem : public CObject { +public: + MotionController *_motionControllerObj; + MovGraphReact *_movGraphReactObj; + Common::Array<MctlConnectionPoint *> _connectionPoints; + int _field_20; + int _field_24; + int _field_28; + +public: + MctlItem() : _movGraphReactObj(0), _motionControllerObj(0), _field_20(0), _field_24(0), _field_28(0) {} + ~MctlItem(); +}; + +class MctlCompoundArray : public Common::Array<MctlItem *>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class MctlCompound : public MotionController { +public: + MctlCompoundArray _motionControllers; + + MctlCompound() { _objtype = kObjTypeMctlCompound; } + + virtual bool load(MfcArchive &file); + + virtual void attachObject(StaticANIObject *obj); + virtual int detachObject(StaticANIObject *obj); + virtual void detachAllObjects(); + virtual MessageQueue *startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); + virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); + + void initMovGraph2(); + MctlConnectionPoint *findClosestConnectionPoint(int ox, int oy, int destIndex, int connectionX, int connectionY, int sourceIndex, double *minDistancePtr); + void replaceNodeX(int from, int to); + + uint getMotionControllerCount() { return _motionControllers.size(); } + MotionController *getMotionController(int num) { return _motionControllers[num]->_motionControllerObj; } +}; + +struct MctlLadderMovementVars { + int varUpGo; + int varDownGo; + int varUpStop; + int varDownStop; + int varUpStart; + int varDownStart; +}; + +struct MctlLadderMovement { + int objId; + int staticIdsSize; + MctlLadderMovementVars *movVars; + int *staticIds; +}; + +class MctlLadder : public MotionController { +public: + int _ladderX; + int _ladderY; + int _ladder_field_14; + int _width; + int _height; + int _ladder_field_20; + int _ladder_field_24; + Common::Array<MctlLadderMovement *> _ladmovements; + MGM _mgm; + +public: + MctlLadder(); + virtual ~MctlLadder(); + int collisionDetection(StaticANIObject *man); + + virtual void attachObject(StaticANIObject *obj); + virtual int detachObject(StaticANIObject *obj) { return 1; } + virtual void detachAllObjects(); + virtual MessageQueue *startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); + virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); + + MessageQueue *controllerWalkTo(StaticANIObject *ani, int off); + +private: + int findObjectPos(StaticANIObject *obj); + bool initMovement(StaticANIObject *ani, MctlLadderMovement *movement); +}; + +class MovGraphNode : public CObject { +public: + int _x; + int _y; + int _z; + int16 _field_10; + int _field_14; + +public: + MovGraphNode() : _x(0), _y(0), _z(0), _field_10(0), _field_14(0) { _objtype = kObjTypeMovGraphNode; } + virtual bool load(MfcArchive &file); +}; + +class ReactParallel : public MovGraphReact { + //CRgn _rgn; + int _x1; + int _y1; + int _x2; + int _y2; + int _dx; + int _dy; + +public: + ReactParallel(); + virtual bool load(MfcArchive &file); + + virtual void setCenter(int x1, int y1, int x2, int y2); + virtual void createRegion(); +}; + +class ReactPolygonal : public MovGraphReact { + Common::Rect *_bbox; + int _centerX; + int _centerY; + +public: + ReactPolygonal(); + ~ReactPolygonal(); + + virtual bool load(MfcArchive &file); + + virtual void setCenter(int x1, int y1, int x2, int y2); + virtual void createRegion(); + + void getBBox(Common::Rect *rect); +}; + +class MovGraphLink : public CObject { + public: + MovGraphNode *_movGraphNode1; + MovGraphNode *_movGraphNode2; + DWordArray _dwordArray1; + DWordArray _dwordArray2; + int _flags; + int _field_38; + int _field_3C; + double _z; + double _angle; + MovGraphReact *_movGraphReact; + char *_name; + + public: + MovGraphLink(); + virtual ~MovGraphLink(); + + virtual bool load(MfcArchive &file); + + void recalcLength(); +}; + +struct MovStep { + int sfield_0; + MovGraphLink *link; +}; + +struct MovArr { + Common::Array<MovStep *> _movSteps; + int _movStepCount; + int _afield_8; + MovGraphLink *_link; + double _dist; + Common::Point _point; +}; + +struct MovItem { + MovArr *movarr; + int _mfield_4; + int _mfield_8; + int _mfield_C; +}; + +struct MovGraphItem { + StaticANIObject *ani; + int field_4; + MovArr movarr; + Common::Array<MovItem *> *movitems; + int count; + int field_30; + int field_34; + int field_38; + int field_3C; + + MovGraphItem(); + void free(); +}; + +class MovGraph : public MotionController { +public: + ObList _nodes; + ObList _links; + int _field_44; + Common::Array<MovGraphItem *> _items; + MovArr *(*_callback1)(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter); + MGM _mgm; + +public: + MovGraph(); + virtual ~MovGraph(); + + virtual bool load(MfcArchive &file); + + virtual void attachObject(StaticANIObject *obj); + virtual int detachObject(StaticANIObject *obj); + virtual void detachAllObjects(); + virtual Common::Array<MovItem *> *getPaths(StaticANIObject *ani, int x, int y, int flag1, int *rescount); + virtual bool setPosImmediate(StaticANIObject *obj, int x, int y); + virtual MessageQueue *startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); + virtual void setSelFunc(MovArr *(*_callback1)(StaticANIObject *ani, Common::Array<MovItem *> *items, signed int counter)); + virtual bool resetPosition(StaticANIObject *ani, int flag); + virtual bool canDropInventory(StaticANIObject *ani, int x, int y); + virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); + virtual MessageQueue *method50(StaticANIObject *ani, MovArr *movarr, int staticsId); + + double calcDistance(Common::Point *point, MovGraphLink *link, int fuzzyMatch); + void recalcLinkParams(); + bool getNearestPoint(int unusedArg, Common::Point *p, MovArr *movarr); + MovGraphNode *calcOffset(int ox, int oy); + int getObjectIndex(StaticANIObject *ani); + Common::Array<MovArr *> *genMovArr(int x, int y, int *arrSize, int flag1, int flag2); + void findAllPaths(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &tempObList2); + Common::Array<MovItem *> *calcMovItems(MovArr *movarr1, MovArr *movarr2, int *listCount); + void genMovItem(MovItem *movitem, MovGraphLink *grlink, MovArr *movarr1, MovArr *movarr2); + bool calcChunk(int idx, int x, int y, MovArr *arr, int a6); + MessageQueue *sub1(StaticANIObject *ani, int x, int y, int a5, int x1, int y1, int a8, int a9); + MessageQueue *fillMGMinfo(StaticANIObject *ani, MovArr *movarr, int staticsId); + void setEnds(MovStep *step1, MovStep *step2); +}; + +class Movement; + +struct MG2I { + int _movementId; + Movement *_mov; + int _mx; + int _my; +}; + +struct MovGraph2ItemSub { + int _staticsId2; + int _staticsId1; + MG2I _walk[3]; + MG2I _turn[4]; + MG2I _turnS[4]; +}; + +struct LinkInfo { + MovGraphLink *link; + MovGraphNode *node; +}; + +struct MovInfo1Sub { + int subIndex; + int x; + int y; + int distance; +}; + +struct MovInfo1 { + int index; + Common::Point pt1; + Common::Point pt2; + int distance1; + int distance2; + int subIndex; + int item1Index; + Common::Array<MovInfo1Sub *> items; + int itemsCount; + int flags; + + MovInfo1() { clear(); } + MovInfo1(MovInfo1 *src); + void clear(); +}; + +struct MovGraph2Item { // 744 + int _objectId; + StaticANIObject *_obj; + MovGraph2ItemSub _subItems[4]; // 184 +}; + +class MovGraph2 : public MovGraph { +public: + Common::Array<MovGraph2Item *> _items2; + +public: + virtual void attachObject(StaticANIObject *obj); + virtual int detachObject(StaticANIObject *obj); + virtual void detachAllObjects(); + virtual MessageQueue *startMove(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); + virtual MessageQueue *doWalkTo(StaticANIObject *subj, int xpos, int ypos, int fuzzyMatch, int staticsId); + + int getItemIndexByGameObjectId(int objectId); + int getItemSubIndexByStaticsId(int index, int staticsId); + int getItemSubIndexByMovementId(int index, int movId); + int getItemSubIndexByMGM(int idx, StaticANIObject *ani); + + int getShortSide(MovGraphLink *lnk, int x, int y); + int findLink(Common::Array<MovGraphLink *> *linkList, int idx, Common::Rect *a3, Common::Point *a4); + + bool initDirections(StaticANIObject *obj, MovGraph2Item *item); + void buildMovInfo1SubItems(MovInfo1 *movinfo, Common::Array<MovGraphLink *> *linkList, LinkInfo *lnkSrc, LinkInfo *lnkDst); + MessageQueue *buildMovInfo1MessageQueue(MovInfo1 *movInfo); + + MovGraphNode *findNode(int x, int y, int fuzzyMatch); + MovGraphLink *findLink1(int x, int y, int idx, int fuzzyMatch); + MovGraphLink *findLink2(int x, int y); + double findMinPath(LinkInfo *linkInfoSource, LinkInfo *linkInfoDest, Common::Array<MovGraphLink *> *listObj); + + MessageQueue *genMovement(MovInfo1 *movinfo); +}; + +class MctlConnectionPoint : public CObject { +public: + int _connectionX; + int _connectionY; + int _mctlflags; + int _mctlstatic; + int16 _mctlmirror; + MessageQueue *_messageQueueObj; + int _motionControllerObj; + + MctlConnectionPoint(); + ~MctlConnectionPoint(); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MOTION_H */ diff --git a/engines/fullpipe/ngiarchive.cpp b/engines/fullpipe/ngiarchive.cpp new file mode 100644 index 0000000000..132f4758d3 --- /dev/null +++ b/engines/fullpipe/ngiarchive.cpp @@ -0,0 +1,156 @@ +/* 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 "common/archive.h" + +#include "common/file.h" +#include "common/hash-str.h" +#include "common/memstream.h" +#include "common/bufferedstream.h" +#include "common/textconsole.h" + +#include "fullpipe/ngiarchive.h" + +namespace Fullpipe { + +NGIArchive::NGIArchive(const Common::String &filename) : _ngiFilename(filename) { + Common::File ngiFile; + + if (!ngiFile.open(_ngiFilename)) { + warning("NGIArchive::NGIArchive(): Could not find the archive file"); + return; + } + + ngiFile.seek(4, SEEK_SET); + + unsigned int count = ngiFile.readUint16LE(); // How many entries? + + ngiFile.seek(20, SEEK_SET); + + unsigned int key = ngiFile.readUint16LE(); + + byte key1, key2; + + key1 = key & 0xff; + key2 = (key >> 8) & 0xff; + + int fatSize = count * 32; + + ngiFile.seek(32, SEEK_SET); + + byte *fat = (byte *)calloc(fatSize, 1); + + ngiFile.read(fat, fatSize); + + for (int i = 0; i < fatSize; i++) { + key1 = (key1 << 1) ^ key2; + key2 = (key2 >> 1) ^ key1; + + fat[i] ^= key1; + } + + NgiHeader header; + NgiHeader *head; + + for (uint i = 0; i < count; i++) { + memcpy(header.filename, &fat[i * 32], 12); + header.filename[12] = 0; + header.flags = READ_LE_UINT32(&fat[i * 32 + 16]); + header.extVal = READ_LE_UINT32(&fat[i * 32 + 20]); + header.pos = READ_LE_UINT32(&fat[i * 32 + 24]); + header.size = READ_LE_UINT32(&fat[i * 32 + 28]); + + if (header.flags & 0x1e0) { + warning("File has flags: %.8x\n", header.flags & 0x1e0); + } + + head = new NgiHeader(header); + + _headers[header.filename] = head; + } + + free(fat); + + g_fp->_currArchive = this; + + debug(0, "NGIArchive::NGIArchive(%s): Located %d files", filename.c_str(), _headers.size()); +} + +NGIArchive::~NGIArchive() { + debug(0, "NGIArchive Destructor Called"); + NgiHeadersMap::iterator it = _headers.begin(); + for ( ; it != _headers.end(); ++it) { + delete it->_value; + } + + g_fp->_currArchive = 0; +} + +bool NGIArchive::hasFile(const Common::String &name) const { + return _headers.contains(name); +} + + int NGIArchive::listMembers(Common::ArchiveMemberList &list) const { + int matches = 0; + + NgiHeadersMap::const_iterator it = _headers.begin(); + for ( ; it != _headers.end(); ++it) { + list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(it->_value->filename, this))); + matches++; + } + + return matches; +} + +const Common::ArchiveMemberPtr NGIArchive::getMember(const Common::String &name) const { + if (!hasFile(name)) + return Common::ArchiveMemberPtr(); + + return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this)); +} + +Common::SeekableReadStream *NGIArchive::createReadStreamForMember(const Common::String &name) const { + if (!_headers.contains(name)) { + return 0; + } + + NgiHeader *hdr = _headers[name]; + + Common::File archiveFile; + archiveFile.open(_ngiFilename); + archiveFile.seek(hdr->pos, SEEK_SET); + + byte *data = (byte *)malloc(hdr->size); + assert(data); + + int32 len = archiveFile.read(data, hdr->size); + assert(len == hdr->size); + + return new Common::MemoryReadStream(data, hdr->size, DisposeAfterUse::YES); +} + +Common::Archive *makeNGIArchive(const Common::String &name) { + return new NGIArchive(name); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/ngiarchive.h b/engines/fullpipe/ngiarchive.h new file mode 100644 index 0000000000..a5b05a2e50 --- /dev/null +++ b/engines/fullpipe/ngiarchive.h @@ -0,0 +1,69 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_NGIARCHIVE_H +#define FULLPIPE_NGIARCHIVE_H + +#include "common/str.h" + +namespace Fullpipe { + +class Archive; + +#define NGI_FILENAME_MAX 13 + +struct NgiHeader { + int32 pos; + int32 extVal; + int32 flags; + int32 size; + char filename[NGI_FILENAME_MAX]; +}; + +typedef Common::HashMap<Common::String, NgiHeader*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> NgiHeadersMap; + +class NGIArchive : public Common::Archive { + NgiHeadersMap _headers; + Common::String _ngiFilename; + +public: + NGIArchive(const Common::String &name); + virtual ~NGIArchive(); + + // Archive implementation + virtual bool hasFile(const Common::String &name) const; + virtual int listMembers(Common::ArchiveMemberList &list) const; + virtual const Common::ArchiveMemberPtr getMember(const Common::String &name) const; + virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; +}; + +/** + * This factory method creates an Archive instance corresponding to the content + * of the NGI compressed file with the given name. + * + * May return 0 in case of a failure. + */ +Common::Archive *makeNGIArchive(const Common::String &name); + +} // End of namespace Fullpipe + +#endif diff --git a/engines/fullpipe/objectnames.h b/engines/fullpipe/objectnames.h new file mode 100644 index 0000000000..0baf83b175 --- /dev/null +++ b/engines/fullpipe/objectnames.h @@ -0,0 +1,259 @@ +/* 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. + * + */ + +// This file is used in order to avoid usage of constants in Russian accross the code + +#ifndef FULLPIPE_OBJECTNAMES_H +#define FULLPIPE_OBJECTNAMES_H + +namespace Fullpipe { + +#define sO_Grandma "\xc1\xe0\xe1\xf3\xeb\xff" // "Бабуля" +#define sO_Jar_4 "\xc1\xe0\xed\xea\xe0_4" // "Банка_4" +#define sO_Pool "\xc1\xe0\xf1\xf1\xe5\xe9\xed" // "Бассейн" +#define sO_TummyTrampie "\xc1\xe0\xf2\xf3\xf2\xe0" // "Батута" +#define sO_WithoutBoot "\xc1\xe5\xe7 \xe1\xee\xf2\xe8\xed\xea\xe0" // "Без ботинка" +#define sO_WithoutJugs "\xc1\xe5\xe7 \xe3\xee\xf0\xf8\xea\xee\xe2" // "Без горшков" +#define sO_WithoutCarpet "\xc1\xe5\xe7 \xea\xee\xe2\xf0\xe8\xea\xe0" // "Без коврика" +#define sO_WithoutCoin "\xc1\xe5\xe7 \xec\xee\xed\xe5\xf2\xfb" // "Без монеты" +#define sO_WithNothing "\xc1\xe5\xe7 \xed\xe8\xf7\xe5\xe3\xee" // "Без ничего" +#define sO_WithoutHandle "\xc1\xe5\xe7 \xf0\xf3\xf7\xea\xe8" // "Без ручки" +#define sO_WithoutStool "\xc1\xe5\xe7 \xf2\xe0\xe1\xf3\xf0\xe5\xf2\xea\xe8" // "Без табуретки" +#define sO_WithoutDrawer "\xc1\xe5\xe7 \xff\xf9\xe8\xea\xe0" // "Без ящика" +#define sO_Nearby "\xc1\xeb\xe8\xe7\xea\xee" // "Близко" +#define sO_Blocked "\xc1\xeb\xee\xea\xe8\xf0\xee\xe2\xe0\xed" // "Блокирован" +#define sO_BlockedShe "\xc1\xeb\xee\xea\xe8\xf0\xee\xe2\xe0\xed\xe0" // "Блокирована" +#define sO_Awaken "\xc1\xee\xe4\xf0\xf1\xf2\xe2\xf3\xe5\xf2" // "Бодрствует" +#define sO_Boot_15 "\xc1\xee\xf2\xe8\xed\xee\xea_15" // "Ботинок_15" +#define sO_Bottle_38 "\xc1\xf3\xf2\xfb\xeb\xea\xe0_38" // "Бутылка_38" +#define sO_InSmokeRoom "\xc2 \xea\xf3\xf0\xe8\xeb\xea\xe5" // "В курилке" +#define sO_InSock "\xc2 \xed\xee\xf1\xea\xe5" // "В носке" +#define sO_InGlasses "\xc2 \xee\xf7\xea\xe0\xf5" // "В очках" +#define sO_In_14 "\xc2_14" // "В_14" +#define sO_In_15 "\xc2_15" // "В_15" +#define sO_In_15_1 "\xc2_15_1" // "В_15_1" +#define sO_In_15_2 "\xc2_15_2" // "В_15_2" +#define sO_In_15_3 "\xc2_15_3" // "В_15_3" +#define sO_In_16 "\xc2_16" // "В_16" +#define sO_In_32 "\xc2_32" // "В_32" +#define sO_In_32_Lies "\xc2_32 \xeb\xe5\xe6\xe8\xf2" // "В_32 лежит" +#define sO_In_32_Sticks "\xc2_32 \xf2\xee\xf0\xf7\xe8\xf2" // "В_32 торчит" +#define sO_In_33 "\xc2_33" // "В_33" +#define sO_In_7 "\xc2_7" // "В_7" +#define sO_Together "\xc2\xe4\xe2\xee\xe5\xec" // "Вдвоем" +#define sO_Valve1_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x31_26" // "Вентиль1_26" +#define sO_Valve2_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x32_26" // "Вентиль2_26" +#define sO_Valve3_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x33_26" // "Вентиль3_26" +#define sO_Valve4_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x34_26" // "Вентиль4_26" +#define sO_Valve5_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x35_26" // "Вентиль5_26" +#define sO_Valve_34 "\xc2\xe5\xed\xf2\xe8\xeb\xfc_34" // "Вентиль_34" +#define sO_UpperHatch_23 "\xc2\xe5\xf0\xf5\xed\xe8\xe9 \xeb\xfe\xea_23" // "Верхний люк_23" +#define sO_Taken "\xc2\xe7\xff\xf2" // "Взят" +#define sO_HangsOnPipe "\xc2\xe8\xf1\xe8\xf2 \xed\xe0 \xf2\xf0\xf3\xe1\xe5" // "Висит на трубе" +#define sO_On "\xc2\xea\xeb" // "Вкл" +#define sO_TurnedOn "\xc2\xea\xeb\xfe\xf7\xe5\xed" // "Включен" +#define sO_Driver "\xc2\xee\xe4\xe8\xeb\xe0" // "Водила" +#define sO_HareTheNooksiter "\xc2\xf3\xe3\xeb\xf3\xf1\xe5\xe4" // "Вуглусед" +#define sO_Off "\xc2\xfb\xea\xeb" // "Выкл" +#define sO_TurnedOff "\xc2\xfb\xea\xeb\xfe\xf7\xe5\xed" // "Выключен" +#define sO_HasGrown "\xc2\xfb\xf0\xee\xf1" // "Вырос" +#define sO_Boss "\xc3\xeb\xe0\xe2\xe0\xf0\xfc" // "Главарь" +#define sO_Jug "\xc3\xee\xf0\xf8\xee\xea" // "Горшок" +#define sO_Strolling "\xc3\xf3\xeb\xff\xe5\xf2" // "Гуляет" +#define sO_Yes "\xc4\xe0" // "Да" +#define sO_FarAway "\xc4\xe0\xeb\xe5\xea\xee" // "Далеко" +#define sO_Girl "\xc4\xe5\xe2\xee\xf7\xea\xe0" // "Девочка" +#define sO_Elephantine "\xc4\xe5\xe2\xee\xf7\xea\xe0-\xf1\xeb\xee\xed\xe8\xea" // "Девочка-слоник" +#define sO_Grandpa "\xc4\xe5\xe4\xf3\xf8\xea\xe0" // "Дедушка" +#define sO_Board_25 "\xc4\xee\xf1\xea\xe0_25" // "Доска_25" +#define sO_Plank_34 "\xc4\xee\xf1\xea\xe0_34" // "Доска_34" +#define sO_DudeHasJumped "\xc4\xff\xe4\xff \xef\xf0\xfb\xe3\xe0\xeb" // "Дядя прыгал" +#define sO_Dude "\xc4\xff\xe4\xff" // "Дядя" +#define sO_GuvTheDrawer "\xc4\xff\xe4\xff-\xff\xf9\xe8\xea" // "Дядя-ящик" +#define sO_DudeSwinged "\xc4\xff\xe4\xff_\xea\xe0\xf2\xe0\xeb\xf1\xff" // "Дядя_катался" +#define sO_IsEating "\xc5\xf1\xf2" // "Ест" +#define sO_Present "\xc5\xf1\xf2\xfc" // "Есть" +#define sO_CloseThing1 "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5 1" // "Закрываемое 1" +#define sO_CloseThing2 "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5 2" // "Закрываемое 2" +#define sO_CloseThing3 "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5 3" // "Закрываемое 3" +#define sO_CloseThing "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5" // "Закрываемое" +#define sO_Closed "\xc7\xe0\xea\xf0\xfb\xf2" // "Закрыт" +#define sO_ClosedWithBoot "\xc7\xe0\xea\xf0\xfb\xf2\xe0 \xf1 \xe1\xee\xf2\xe8\xed\xea\xee\xec" // "Закрыта с ботинком" +#define sO_IsClosed "\xc7\xe0\xea\xf0\xfb\xf2\xe0" // "Закрыта" +#define sO_HalfFull "\xc7\xe0\xef\xee\xeb\xed\xe5\xed \xed\xe0\xef\xee\xeb\xee\xe2\xe8\xed\xf3" // "Заполнен наполовину" +#define sO_Full "\xc7\xe0\xef\xee\xeb\xed\xe5\xed \xf6\xe5\xeb\xe8\xea\xee\xec" // "Заполнен целиком" +#define sO_MirroredTo "\xc7\xe5\xf0\xea\xe0\xeb\xfc\xed\xe0\xff \xea" // "Зеркальная к" +#define sO_IsPlaying "\xc8\xe3\xf0\xe0\xe5\xf2" // "Играет" +#define sO_Tub "\xca\xe0\xe4\xea\xe0" // "Кадка" +#define sO_Cactus "\xca\xe0\xea\xf2\xf3\xf1" // "Кактус" +#define sO_IsSwingingWithBoot "\xca\xe0\xf2\xe0\xe5\xf2\xf1\xff \xf1 \xe1\xee\xf2\xe8\xed\xea\xee\xec" // "Катается с ботинком" +#define sO_IsSwinging "\xca\xe0\xf2\xe0\xe5\xf2\xf1\xff" // "Катается" +#define sO_Swingie "\xca\xe0\xf7\xe5\xeb\xe5\xed\xff" // "Качеленя" +#define sO_LiftButtons "\xca\xed\xee\xef\xea\xe8 \xeb\xe8\xf4\xf2\xe0" // "Кнопки лифта" +#define sO_Carpet_35 "\xca\xee\xe2\xf0\xe8\xea_35" // "Коврик_35" +#define sO_Valve_35 "\xca\xf0\xe0\xed_35" // "Кран_35" +#define sO_Cup "\xca\xf0\xf3\xe6\xea\xe0" // "Кружка" +#define sO_Cube "\xca\xf3\xe1\xe8\xea" // "Кубик" +#define sO_LeftPipe_15 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_15" // "Левая труба_15" +#define sO_LeftPipe_26 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_26" // "Левая труба_26" +#define sO_LeftPipe_29 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_29" // "Левая труба_29" +#define sO_LeftPipe_30 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_30" // "Левая труба_30" +#define sO_LeftPipe_37 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_37" // "Левая труба_37" +#define sO_StairsDown_24 "\xcb\xe5\xf1\xf2\xed\xe8\xf6\xe0 \xe2\xed\xe8\xe7_24" // "Лестница вниз_24" +#define sO_StairsUp_8 "\xcb\xe5\xf1\xf2\xed\xe8\xf6\xe0 \xf1\xe2\xe5\xf0\xf5\xf3_8" // "Лестница сверху_8" +#define sO_Stairway "\xcb\xe5\xf1\xf2\xed\xe8\xf6\xe0" // "Лестница" +#define sO_Fliers "\xcb\xe5\xf2\xf3\xed\xfb" // "Летуны" +#define sO_Hatch_26 "\xcb\xfe\xea_26" // "Люк_26" +#define sO_Hatch_34 "\xcb\xfe\xea_34" // "Люк_34" +#define sO_MommyOfHandle_32 "\xcc\xe0\xec\xe0 \xf0\xf3\xf7\xea\xe8_32" // "Мама ручки_32" +#define sO_BigMumsy "\xcc\xe0\xec\xe0\xf8\xe0" // "Мамаша" +#define sO_Bag_22 "\xcc\xe5\xf8\xee\xea_22" // "Мешок_22" +#define sO_CoinSlot_1 "\xcc\xee\xed\xe5\xf2\xee\xef\xf0\xe8\xe5\xec\xed\xe8\xea 1" // "Монетоприемник 1" +#define sO_CoinSlot_22 "\xcc\xee\xed\xe5\xf2\xee\xef\xf0\xe8\xe5\xec\xed\xe8\xea_22" // "Монетоприемник_22" +#define sO_CoinSlot_35 "\xcc\xee\xed\xe5\xf2\xee\xef\xf0\xe8\xe5\xec\xed\xe8\xea_35" // "Монетоприемник_35" +#define sO_Bridge "\xcc\xee\xf1\xf2" // "Мост" +#define sO_Fly_12 "\xcc\xf3\xf5\xe0_12" // "Муха_12" +#define sO_Fly_17 "\xcc\xf3\xf5\xe0_17" // "Муха_17" +#define sO_OnTheFloor "\xcd\xe0 \xef\xee\xeb\xf3" // "На полу" +#define sO_OnTheSpring "\xcd\xe0 \xef\xf0\xf3\xe6\xe8\xed\xe5" // "На пружине" +#define sO_OnTheTable "\xcd\xe0 \xf1\xf2\xee\xeb\xe5" // "На столе" +#define sO_OnStool "\xcd\xe0 \xf2\xe0\xe1\xf3\xf0\xe5\xf2\xea\xe5" // "На табуретке" +#define sO_Inflater "\xcd\xe0\xe4\xf3\xe2\xe0\xf2\xe5\xeb\xfc" // "Надуватель" +#define sO_NotTaken "\xcd\xe5 \xe2\xe7\xff\xf2" // "Не взят" +#define sO_NotHanging "\xcd\xe5 \xe2\xe8\xf1\xe8\xf2" // "Не висит" +#define sO_NotGrown "\xcd\xe5 \xe2\xfb\xf0\xee\xf1" // "Не вырос" +#define sO_DidNotCrackEgg "\xcd\xe5 \xea\xee\xeb\xee\xeb \xff\xe9\xf6\xee" // "Не колол яйцо" +#define sO_NotFallen "\xcd\xe5 \xef\xe0\xe4\xe0\xeb" // "Не падал" +#define sO_IsNotAvailable "\xcd\xe5\xe4\xee\xf1\xf2\xf3\xef\xed\xe0" // "Недоступна" +#define sO_CannotTake "\xcd\xe5\xeb\xfc\xe7\xff \xe2\xe7\xff\xf2\xfc" // "Нельзя взять" +#define sO_No "\xcd\xe5\xf2" // "Нет" +#define sO_LowerHatch_23 "\xcd\xe8\xe6\xed\xe8\xe9 \xeb\xfe\xea_23" // "Нижний люк_23" +#define sO_LowerPipe "\xcd\xe8\xe6\xed\xff\xff \xf2\xf0\xf3\xe1\xe0" // "Нижняя труба" +#define sO_LowerPipe_21 "\xcd\xe8\xe6\xed\xff\xff \xf2\xf0\xf3\xe1\xe0_21" // "Нижняя труба_21" +#define sO_WantsNothing "\xcd\xe8\xf7\xe5\xe3\xee \xed\xe5 \xf5\xee\xf7\xe5\xf2" // "Ничего не хочет" +#define sO_Leg "\xcd\xee\xe3\xe0" // "Нога" +#define sO_FriesPit "\xcd\xee\xf0\xea\xe0 \xea\xee\xe7\xff\xe2\xea\xe8" // "Норка козявки" +#define sO_Sock_26 "\xcd\xee\xf1\xee\xea_26" // "Носок_26" +#define sO_ClockAxis "\xce\xf1\xfc \xf7\xe0\xf1\xee\xe2" // "Ось часов" +#define sO_Opened "\xce\xf2\xea\xf0\xfb\xf2" // "Открыт" +#define sO_OpenedWithBoot "\xce\xf2\xea\xf0\xfb\xf2\xe0 \xf1 \xe1\xee\xf2\xe8\xed\xea\xee\xec" // "Открыта с ботинком" +#define sO_IsOpened "\xce\xf2\xea\xf0\xfb\xf2\xe0" // "Открыта" +#define sO_WeirdWacko "\xce\xf2\xec\xee\xf0\xee\xe6\xe5\xed\xed\xfb\xe9" // "Отмороженный" +#define sO_NotPresent "\xce\xf2\xf1\xf3\xf2\xf1\xf2\xe2\xf3\xe5\xf2" // "Отсутствует" +#define sO_Error "\xce\xf8\xe8\xe1\xea\xe0" // "Ошибка" +#define sO_Passive "\xcf\xe0\xf1\xf1\xe8\xe2\xed\xe0" // "Пассивна" +#define sO_First "\xcf\xe5\xf0\xe2\xfb\xe9" // "Первый" +#define sO_UpsideDown "\xcf\xe5\xf0\xe5\xe2\xe5\xf0\xed\xf3\xf2\xe0" // "Перевернута" +#define sO_Overfull "\xcf\xe5\xf0\xe5\xef\xee\xeb\xed\xe5\xed" // "Переполнен" +#define sO_Fireman "\xcf\xee\xe6\xe0\xf0\xed\xe8\xea" // "Пожарник" +#define sO_ShowingHeel "\xcf\xee\xea\xe0\xe7\xfb\xe2\xe0\xe5\xf2 \xef\xff\xf2\xea\xf3" // "Показывает пятку" +#define sO_FullPipe "\xcf\xee\xeb\xed\xe0\xff \xd2\xf0\xf3\xe1\xe0" // "Полная Труба" +#define sO_RightStairs_9 "\xcf\xf0\xe0\xe2\xe0\xff \xeb\xe5\xf1\xf2\xed\xe8\xf6\xe0_9" // "Правая лестница_9" +#define sO_RightPipe_17 "\xcf\xf0\xe0\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_17" // "Правая труба_17" +#define sO_IsPresent "\xcf\xf0\xe8\xf1\xf3\xf2\xf1\xf2\xe2\xf3\xe5\xf2" // "Присутствует" +#define sO_GulpedEgg "\xcf\xf0\xee\xe3\xeb\xee\xf7\xe5\xed\xed\xee\xe5 \xff\xe9\xf6\xee" // "Проглоченное яйцо" +#define sO_GulpedEggs "\xcf\xf0\xee\xe3\xeb\xee\xf7\xe5\xed\xed\xfb\xe5 \xff\xe9\xf6\xe0" // "Проглоченные яйца" +#define sO_BellyInflater "\xcf\xf3\xe7\xee\xe4\xf3\xe2" // "Пузодув" +#define sO_Empty "\xcf\xf3\xf1\xf2" // "Пуст" +#define sO_EmptyShe "\xcf\xf3\xf1\xf2\xe0\xff" // "Пустая" +#define sO_WayToPipe "\xcf\xf3\xf2\xfc \xea \xf2\xf0\xf3\xe1\xe5" // "Путь к трубе" +#define sO_IsDrinking "\xcf\xfc\xe5\xf2" // "Пьет" +#define sO_Broken "\xd0\xe0\xe7\xe1\xe8\xf2\xe0" // "Разбита" +#define sO_Unblocked "\xd0\xe0\xe7\xe1\xeb\xee\xea\xe8\xf0\xee\xe2\xe0\xed" // "Разблокирован" +#define sO_Unconvoluted "\xd0\xe0\xe7\xe2\xe5\xf0\xed\xf3\xf2" // "Развернут" +#define sO_Jawcrucnher "\xd0\xee\xf2\xee\xf5\xf0\xf3\xf1" // "Ротохрус" +#define sO_UsherHand "\xd0\xf3\xea\xe0 \xc1\xe8\xeb\xe5\xf2\xe5\xf0\xf8\xe8" // "Рука Билетерши" +#define sO_LeverHandle_23 "\xd0\xf3\xea\xee\xff\xf2\xea\xe0 \xf0\xfb\xf7\xe0\xe3\xe0_23" // "Рукоятка рычага_23" +#define sO_ClockHandle "\xd0\xf3\xf7\xea\xe0 \xee\xf2 \xf7\xe0\xf1\xee\xe2" // "Ручка от часов" +#define sO_Lever_23 "\xd0\xfb\xf7\xe0\xe3_23" // "Рычаг_23" +#define sO_WithDudeOnLeft "\xd1 \xc4\xff\xe4\xe5\xe9 \xf1\xeb\xe5\xe2\xe0" // "С Дядей слева" +#define sO_WithDudeOnRight "\xd1 \xc4\xff\xe4\xe5\xe9 \xf1\xef\xf0\xe0\xe2\xe0" // "С Дядей справа" +#define sO_WithBoot "\xd1 \xe1\xe0\xf8\xec\xe0\xea\xee\xec" // "С башмаком" +#define sO_WithBig "\xd1 \xe1\xee\xeb\xfc\xf8\xe8\xec" // "С большим" +#define sO_WithPlunger "\xd1 \xe2\xe0\xed\xf2\xf3\xe7\xee\xec" // "С вантузом" +#define sO_WithJug "\xd1 \xe3\xee\xf0\xf8\xea\xee\xec" // "С горшком" +#define sO_WithGum "\xd1 \xe6\xe2\xe0\xf7\xea\xee\xe9" // "С жвачкой" +#define sO_WithSpade "\xd1 \xeb\xee\xef\xe0\xf2\xee\xe9" // "С лопатой" +#define sO_WithSmall "\xd1 \xec\xe0\xeb\xfb\xec" // "С малым" +#define sO_WithHammer "\xd1 \xec\xee\xeb\xee\xf2\xea\xee\xec" // "С молотком" +#define sO_WithCoin "\xd1 \xec\xee\xed\xe5\xf2\xee\xe9" // "С монетой" +#define sO_WithSock "\xd1 \xed\xee\xf1\xea\xee\xec" // "С носком" +#define sO_WithCork "\xd1 \xef\xf0\xee\xe1\xea\xee\xe9" // "С пробкой" +#define sO_WithSteering "\xd1 \xf0\xf3\xeb\xe5\xec" // "С рулем" +#define sO_WithHandle "\xd1 \xf0\xf3\xf7\xea\xee\xe9" // "С ручкой" +#define sO_WithApple "\xd1 \xff\xe1\xeb\xee\xea\xee\xec" // "С яблоком" +#define sO_WithDrawer "\xd1 \xff\xf9\xe8\xea\xee\xec" // "С ящиком" +#define sO_Sugar "\xd1\xe0\xf5\xe0\xf0\xee\xea" // "Сахарок" +#define sO_Convoluted "\xd1\xe2\xe5\xf0\xed\xf3\xf2" // "Свернут" +#define sO_IsFree "\xd1\xe2\xee\xe1\xee\xe4\xed\xe0" // "Свободна" +#define sO_IsSitting "\xd1\xe8\xe4\xe8\xf2" // "Сидит" +#define sO_IsLaughing "\xd1\xec\xe5\xe5\xf2\xf1\xff" // "Смеется" +#define sO_WithAll "\xd1\xee \xe2\xf1\xe5\xec\xe8" // "Со всеми" +#define sO_WithSwab "\xd1\xee \xf8\xe2\xe0\xe1\xf0\xee\xe9" // "Со шваброй" +#define sO_WithHose "\xd1\xee \xf8\xeb\xe0\xed\xe3\xee\xec" // "Со шлангом" +#define sO_WithBroom "\xd1\xee \xf9\xe5\xf2\xea\xee\xe9" // "Со щеткой" +#define sO_IsSleeping "\xd1\xef\xe8\xf2" // "Спит" +#define sO_OnRight "\xd1\xef\xf0\xe0\xe2\xe0" // "Справа" +#define sO_IsStandingInBoots "\xd1\xf2\xee\xe8\xf2 \xe2 \xe1\xee\xf2\xe8\xed\xea\xe0\xf5" // "Стоит в ботинках" +#define sO_IsStandingInCorner "\xd1\xf2\xee\xe8\xf2 \xe2 \xf3\xe3\xeb\xf3" // "Стоит в углу" +#define sO_Guardian "\xd1\xf2\xee\xf0\xee\xe6" // "Сторож" +#define sO_Guard_1 "\xd1\xf2\xf0\xe0\xe6 1" // "Страж 1" +#define sO_Guard_2 "\xd1\xf2\xf0\xe0\xe6 2" // "Страж 2" +#define sO_Guard_3 "\xd1\xf2\xf0\xe0\xe6 3" // "Страж 3" +#define sO_Stool_34 "\xd2\xe0\xe1\xf3\xf0\xe5\xf2_34" // "Табурет_34" +#define sO_Pipe_9 "\xd2\xf0\xf3\xe1\xe0_9" // "Труба_9" +#define sO_Pedestal_16 "\xd2\xf3\xec\xe1\xe0_16" // "Тумба_16" +#define sO_Pedestal_17 "\xd2\xf3\xec\xe1\xe0_17" // "Тумба_17" +#define sO_Pedestal_33 "\xd2\xf3\xec\xe1\xe0_33" // "Тумба_33" +#define sO_NearDudesStairs "\xd3 \xc4\xff\xe4\xe8 \xed\xe0 \xeb\xe5\xf1\xf2\xed\xe8\xf6\xe5" // "У Дяди на лестнице" +#define sO_DudeHas "\xd3 \xc4\xff\xe4\xe8" // "У Дяди" +#define sO_NearPipeWithStool "\xd3 \xf2\xf0\xf3\xe1\xfb \xf1 \xf2\xe0\xe1\xf3\xf0\xe5\xf2\xea\xee\xe9" // "У трубы с табуреткой" +#define sO_NearPipe "\xd3 \xf2\xf0\xf3\xe1\xfb" // "У трубы" +#define sO_Janitors "\xd3\xe1\xee\xf0\xf9\xe8\xea\xe8" // "Уборщики" +#define sO_Maid "\xd3\xe1\xee\xf0\xf9\xe8\xf6\xe0" // "Уборщица" +#define sO_IsGone "\xd3\xe5\xf5\xe0\xeb\xe0" // "Уехала" +#define sO_FallenTwice "\xd3\xef\xe0\xeb \xe4\xe2\xe0" // "Упал два" +#define sO_FallenOnce "\xd3\xef\xe0\xeb \xf0\xe0\xe7" // "Упал раз" +#define sO_BrushHasFallen "\xd3\xef\xe0\xeb\xe0 \xf9\xe5\xf2\xea\xe0" // "Упала щетка" +#define sO_NotBroken "\xd6\xe5\xeb\xe0" // "Цела" +#define sO_IsScratchingBelly "\xd7\xe5\xf8\xe5\xf2 \xef\xf3\xe7\xee" // "Чешет пузо" +#define sO_Level0 "\xdd\xf2\xe0\xe6 0" // "Этаж 0" +#define sO_Level1 "\xdd\xf2\xe0\xe6 1" // "Этаж 1" +#define sO_Level2 "\xdd\xf2\xe0\xe6 2" // "Этаж 2" +#define sO_Level3 "\xdd\xf2\xe0\xe6 3" // "Этаж 3" +#define sO_Level4 "\xdd\xf2\xe0\xe6 4" // "Этаж 4" +#define sO_Level5 "\xdd\xf2\xe0\xe6 5" // "Этаж 5" +#define sO_Level6 "\xdd\xf2\xe0\xe6 6" // "Этаж 6" +#define sO_Level7 "\xdd\xf2\xe0\xe6 7" // "Этаж 7" +#define sO_Level8 "\xdd\xf2\xe0\xe6 8" // "Этаж 8" +#define sO_Level9 "\xdd\xf2\xe0\xe6 9" // "Этаж 9" +#define sO_EggGulperGaveCoin "\xdf\xe9\xf6\xe5\xe3\xeb\xee\xf2 \xee\xf2\xe4\xe0\xeb \xec\xee\xed\xe5\xf2\xf3" // "Яйцеглот отдал монету" +#define sO_EggGulper "\xdf\xe9\xf6\xe5\xe3\xeb\xee\xf2" // "Яйцеглот" +#define sO_EggCracker "\xdf\xe9\xf6\xe5\xea\xee\xeb" // "Яйцекол" +#define sO_NotCarryingEgg "\xdf\xe9\xf6\xee \xed\xe5 \xed\xe5\xf1\xe5\xf2" // "Яйцо не несет" +#define sO_Egg1 "\xdf\xe9\xf6\xee\x31" // "Яйцо1" +#define sO_Egg2 "\xdf\xe9\xf6\xee\x32" // "Яйцо2" +#define sO_Egg3 "\xdf\xe9\xf6\xee\x33" // "Яйцо3" + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_OBJECTNAMES_H */ diff --git a/engines/fullpipe/objects.h b/engines/fullpipe/objects.h new file mode 100644 index 0000000000..1849bcb96e --- /dev/null +++ b/engines/fullpipe/objects.h @@ -0,0 +1,99 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_OBJECTS_H +#define FULLPIPE_OBJECTS_H + +#include "fullpipe/utils.h" + +namespace Fullpipe { + +class MessageQueue; +class SceneTagList; + +class GameProject : public CObject { + public: + int _field_4; + char *_headerFilename; + SceneTagList *_sceneTagList; + int _field_10; + + public: + GameProject(); + ~GameProject(); + virtual bool load(MfcArchive &file); +}; + +struct PicAniInfo { + int32 type; + int16 objectId; + int16 field_6; + int32 field_8; + int16 sceneId; + int16 field_E; + int32 ox; + int32 oy; + int32 priority; + int16 staticsId; + int16 movementId; + int16 dynamicPhaseIndex; + int16 flags; + int32 field_24; + int32 someDynamicPhaseIndex; + + bool load(MfcArchive &file); +}; + +union VarValue { + float floatValue; + int32 intValue; + char *stringValue; +}; + +class GameVar : public CObject { + public: + GameVar *_nextVarObj; + GameVar *_prevVarObj; + GameVar *_parentVarObj; + GameVar *_subVars; + GameVar *_field_14; + char *_varName; + VarValue _value; + int _varType; + + public: + GameVar(); + virtual ~GameVar(); + + virtual bool load(MfcArchive &file); + GameVar *getSubVarByName(const char *name); + bool setSubVarAsInt(const char *name, int value); + int getSubVarAsInt(const char *name); + GameVar *addSubVarAsInt(const char *name, int value); + bool addSubVar(GameVar *subvar); + int getSubVarsCount(); + GameVar *getSubVarByIndex(int idx); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_OBJECTS_H */ diff --git a/engines/fullpipe/scene.cpp b/engines/fullpipe/scene.cpp new file mode 100644 index 0000000000..5a3fbe34b6 --- /dev/null +++ b/engines/fullpipe/scene.cpp @@ -0,0 +1,806 @@ +/* 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/gameloader.h" + +#include "fullpipe/constants.h" + +#include "common/algorithm.h" + +namespace Fullpipe { + +Scene *FullpipeEngine::accessScene(int sceneId) { + SceneTag *t = 0; + + for (SceneTagList::iterator s = _gameProject->_sceneTagList->begin(); s != _gameProject->_sceneTagList->end(); ++s) { + if (s->_sceneId == sceneId) { + t = &(*s); + break; + } + } + + if (!t) + return 0; + + if (!t->_scene) { + t->loadScene(); + } + + return t->_scene; +} + +bool SceneTagList::load(MfcArchive &file) { + debug(5, "SceneTagList::load()"); + + int numEntries = file.readUint16LE(); + + for (int i = 0; i < numEntries; i++) { + SceneTag *t = new SceneTag(); + t->load(file); + push_back(*t); + } + + return true; +} + +SceneTag::SceneTag() { + _field_4 = 0; + _scene = 0; + _tag = 0; + _sceneId = 0; +} + +bool SceneTag::load(MfcArchive &file) { + debug(5, "SceneTag::load()"); + + _field_4 = 0; + _scene = 0; + + _sceneId = file.readUint16LE(); + + _tag = file.readPascalString(); + + debug(6, "sceneId: %d tag: %s", _sceneId, _tag); + + return true; +} + +SceneTag::~SceneTag() { + free(_tag); + + delete _scene; + delete _field_4; +} + +void SceneTag::loadScene() { + char *archname = genFileName(0, _sceneId, "nl"); + + Common::Archive *arch = makeNGIArchive(archname); + + char *fname = genFileName(0, _sceneId, "sc"); + + Common::SeekableReadStream *file = arch->createReadStreamForMember(fname); + + _scene = new Scene(); + + MfcArchive archive(file); + + _scene->load(archive); + + if (_scene->_shadows) + _scene->_shadows->init(); + + delete file; + + g_fp->_currArchive = 0; + + free(fname); + free(archname); +} + +Scene::Scene() { + _sceneId = 0; + _field_BC = 0; + _shadows = 0; + _soundList = 0; + _libHandle = 0; + _sceneName = 0; +} + +Scene::~Scene() { + delete _soundList; + delete _shadows; + delete _palette; + + // _faObjlist is not used + + for (uint i = 0; i < _messageQueueList.size(); i++) + delete _messageQueueList[i]; + + _messageQueueList.clear(); + + for (uint i = 0; i < _staticANIObjectList1.size(); i++) + delete _staticANIObjectList1[i]; + + _staticANIObjectList1.clear(); + + delete _libHandle; + + // delete _field_BC; + + free(_sceneName); +} + +bool Scene::load(MfcArchive &file) { + debug(5, "Scene::load()"); + + Background::load(file); + + _sceneId = file.readUint16LE(); + + _sceneName = file.readPascalString(); + debug(0, "scene: <%s> %d", transCyrillic((byte *)_sceneName), _sceneId); + + int count = file.readUint16LE(); + debug(7, "scene.ani: %d", count); + + for (int i = 0; i < count; i++) { + int aniNum = file.readUint16LE(); + char *aniname = genFileName(0, aniNum, "ani"); + + Common::SeekableReadStream *f = g_fp->_currArchive->createReadStreamForMember(aniname); + + StaticANIObject *ani = new StaticANIObject(); + + MfcArchive archive(f); + + ani->load(archive); + ani->_sceneId = _sceneId; + + _staticANIObjectList1.push_back(ani); + + delete f; + free(aniname); + } + + count = file.readUint16LE(); + debug(7, "scene.mq: %d", count); + + for (int i = 0; i < count; i++) { + int qNum = file.readUint16LE(); + char *qname = genFileName(0, qNum, "qu"); + + Common::SeekableReadStream *f = g_fp->_currArchive->createReadStreamForMember(qname); + MfcArchive archive(f); + + archive.readUint16LE(); // Skip 2 bytes + + MessageQueue *mq = new MessageQueue(); + + mq->load(archive); + + _messageQueueList.push_back(mq); + + delete f; + free(qname); + } + + count = file.readUint16LE(); + debug(7, "scene.fa: %d", count); + + for (int i = 0; i < count; i++) { + // There are no .FA files + assert(0); + } + + _libHandle = g_fp->_currArchive; + + if (_picObjList.size() > 0 && _bgname && strlen(_bgname) > 1) { + char fname[260]; + + strcpy(fname, _bgname); + strcpy(strrchr(fname, '.') + 1, "col"); + + MemoryObject *col = new MemoryObject(); + col->loadFile(fname); + + _palette = col; + } + + char *shdname = genFileName(0, _sceneId, "shd"); + + Shadows *shd = new Shadows(); + + if (shd->loadFile(shdname)) + _shadows = shd; + + free(shdname); + + char *slsname = genFileName(0, _sceneId, "sls"); + + if (g_fp->_soundEnabled) { + _soundList = new SoundList(); + + if (g_fp->_flgSoundList) { + char *nlname = genFileName(17, _sceneId, "nl"); + + _soundList->loadFile(slsname, nlname); + + free(nlname); + } else { + _soundList->loadFile(slsname, 0); + } + } + + free(slsname); + + initStaticANIObjects(); + + if (file.size() - file.pos() > 0) + error("Scene::load (%d bytes left)", file.size() - file.pos()); + + return true; +} + +void Scene::initStaticANIObjects() { + for (uint i = 0; i < _staticANIObjectList1.size(); i++) + _staticANIObjectList1[i]->initMovements(); +} + +void Scene::init() { + _x = 0; + _y = 0; + + g_fp->_sceneRect.moveTo(0, 0); + + for (uint i = 0; i < _picObjList.size(); i++) + ((PictureObject *)_picObjList[i])->clearFlags(); + + for (uint i = 0; i < _staticANIObjectList1.size(); i++) + _staticANIObjectList1[i]->clearFlags(); + + if (_staticANIObjectList2.size() != _staticANIObjectList1.size()) { + _staticANIObjectList2.clear(); + + for (uint i = 0; i < _staticANIObjectList1.size(); i++) + _staticANIObjectList2.push_back(_staticANIObjectList1[i]); + } +} + +StaticANIObject *Scene::getAniMan() { + StaticANIObject *aniMan = getStaticANIObject1ById(ANI_MAN, -1); + + deleteStaticANIObject(aniMan); + + return aniMan; +} + +StaticANIObject *Scene::getStaticANIObject1ById(int obj, int a3) { + for (uint i = 0; i < _staticANIObjectList1.size(); i++) { + if (_staticANIObjectList1[i]->_id == obj && (a3 == -1 || _staticANIObjectList1[i]->_okeyCode == a3)) + return _staticANIObjectList1[i]; + } + + return 0; +} + +StaticANIObject *Scene::getStaticANIObject1ByName(char *name, int a3) { + for (uint i = 0; i < _staticANIObjectList1.size(); i++) { + if (!strcmp(_staticANIObjectList1[i]->_objectName, name) && (a3 == -1 || _staticANIObjectList1[i]->_okeyCode == a3)) + return _staticANIObjectList1[i]; + } + + return 0; +} + +void Scene::deleteStaticANIObject(StaticANIObject *obj) { + for (uint i = 0; i < _staticANIObjectList1.size(); i++) + if (_staticANIObjectList1[i] == obj) { + _staticANIObjectList1.remove_at(i); + break; + } + + for (uint i = 0; i < _staticANIObjectList2.size(); i++) + if (_staticANIObjectList2[i] == obj) { + _staticANIObjectList2.remove_at(i); + break; + } +} + +void Scene::addStaticANIObject(StaticANIObject *obj, bool addList2) { + if (obj->_okeyCode) + obj->renumPictures(&_staticANIObjectList1); + + _staticANIObjectList1.push_back(obj); + + if (addList2) { + if (!obj->_okeyCode) + obj->clearFlags(); + + _staticANIObjectList2.push_back(obj); + } +} + +void Scene::setPictureObjectsFlag4() { + for (uint i = 0; i < _picObjList.size(); i++) { + ((PictureObject *)_picObjList[i])->_flags |= 4; + } +} + +void Scene::stopAllSounds() { + for (int i = 0; i < _soundList->getCount(); i++) + _soundList->getSoundByIndex(i)->stop(); +} + +PictureObject *Scene::getPictureObjectById(int objId, int flags) { + for (uint i = 1; i < _picObjList.size(); i++) { + if (((PictureObject *)_picObjList[i])->_id == objId && ((PictureObject *)_picObjList[i])->_okeyCode == flags) + return (PictureObject *)_picObjList[i]; + } + + return 0; +} + +PictureObject *Scene::getPictureObjectByName(const char *objName, int flags) { + for (uint i = 0; i < _picObjList.size(); i++) { + if (!strcmp(((PictureObject *)_picObjList[i])->_objectName, objName) && (((PictureObject *)_picObjList[i])->_okeyCode == flags || flags == -1)) + return (PictureObject *)_picObjList[i]; + } + + return 0; +} + +void Scene::deletePictureObject(PictureObject *obj) { + for (uint i = 0; i < _picObjList.size(); i++) { + if (((PictureObject *)_picObjList[i]) == obj) { + _picObjList.remove_at(i); + delete obj; + + return; + } + } +} + +MessageQueue *Scene::getMessageQueueById(int messageId) { + for (uint i = 0; i < _messageQueueList.size(); i++) + if (_messageQueueList[i]->_dataId == messageId) + return _messageQueueList[i]; + + return 0; +} + +MessageQueue *Scene::getMessageQueueByName(char *name) { + for (uint i = 0; i < _messageQueueList.size(); i++) + if (!strcmp(_messageQueueList[i]->_queueName, name)) + return _messageQueueList[i]; + + return 0; +} + +void Scene::preloadMovements(GameVar *var) { + GameVar *preload = var->getSubVarByName("PRELOAD"); + if (!preload) + return; + + for (GameVar *i = preload->_subVars; i; i = i->_nextVarObj) { + StaticANIObject *ani = getStaticANIObject1ByName(i->_varName, -1); + + if (ani) { + GameVar *subVars = i->_subVars; + + if (subVars) { + for (;subVars; subVars = subVars->_nextVarObj) { + Movement *mov = ani->getMovementByName(subVars->_varName); + + if (mov) + mov->loadPixelData(); + } + } else { + ani->loadMovementsPixelData(); + } + } + } +} + +void Scene::initObjectCursors(const char *varname) { + GameVar *cursorsVar = g_fp->getGameLoaderGameVar()->getSubVarByName(varname)->getSubVarByName("CURSORS"); + + if (!cursorsVar || !cursorsVar->_subVars) + return; + + int maxId = 0; + int minId = 0xffff; + + for (GameVar *sub = cursorsVar->_subVars; sub; sub = sub->_nextVarObj) { + GameObject *obj = getPictureObjectByName(sub->_varName, -1); + + if (obj || (obj = getStaticANIObject1ByName(sub->_varName, -1)) != 0) { + if (obj->_id < minId) + minId = obj->_id; + if (obj->_id > maxId) + maxId = obj->_id; + } + } + + g_fp->_minCursorId = minId; + g_fp->_maxCursorId = maxId; + + g_fp->_objectIdCursors.resize(maxId - minId + 1); + + for (GameVar *sub = cursorsVar->_subVars; sub; sub = sub->_nextVarObj) { + GameObject *obj = getPictureObjectByName(sub->_varName, -1); + + if (!obj) + obj = getStaticANIObject1ByName(sub->_varName, -1); + + PictureObject *pic = getGameLoaderInventory()->getScene()->getPictureObjectByName(sub->_value.stringValue, -1); + + if (obj && pic) + g_fp->_objectIdCursors[obj->_id - minId] = pic->_id; + } +} + +bool Scene::compareObjPriority(const void *p1, const void *p2) { + if (((const GameObject *)p1)->_priority > ((const GameObject *)p2)->_priority) + return true; + + return false; +} + +void Scene::objectList_sortByPriority(Common::Array<StaticANIObject *> &list, bool skipFirst) { + if (skipFirst) { + Common::Array<StaticANIObject *>::iterator s = list.begin(); + + ++s; + + Common::sort(s, list.end(), Scene::compareObjPriority); + } else { + Common::sort(list.begin(), list.end(), Scene::compareObjPriority); + } +} + +void Scene::objectList_sortByPriority(Common::Array<PictureObject *> &list, bool skipFirst) { + if (skipFirst) { + Common::Array<PictureObject *>::iterator s = list.begin(); + + ++s; + + Common::sort(s, list.end(), Scene::compareObjPriority); + } else { + Common::sort(list.begin(), list.end(), Scene::compareObjPriority); + } +} + +void Scene::draw() { + debug(6, ">>>>> Scene::draw()"); + updateScrolling(); + + // Clean previous stuff + g_fp->_backgroundSurface.fillRect(Common::Rect(0, 0, 800, 600), 0); + + drawContent(60000, 0, true); + + objectList_sortByPriority(_staticANIObjectList2); + + for (uint i = 0; i < _staticANIObjectList2.size(); i++) + _staticANIObjectList2[i]->draw2(); + + int priority = -1; + for (uint i = 0; i < _staticANIObjectList2.size(); i++) { + drawContent(_staticANIObjectList2[i]->_priority, priority, false); + _staticANIObjectList2[i]->draw(); + + priority = _staticANIObjectList2[i]->_priority; + } + + drawContent(-1, priority, false); +} + +void Scene::updateScrolling() { + if (_messageQueueId && !_x && !_y) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(_messageQueueId); + + if (mq) + mq->update(); + + _messageQueueId = 0; + } + + if (_x || _y) { + int offsetX = 0; + int offsetY = 0; + + if (_x < 0) { + if (!g_fp->_sceneRect.left && !(((PictureObject *)_picObjList[0])->_flags & 2)) + _x = 0; + + if (_x <= -g_fp->_scrollSpeed) { + offsetX = -g_fp->_scrollSpeed; + _x += g_fp->_scrollSpeed; + } + } else if (_x >= g_fp->_scrollSpeed) { + offsetX = g_fp->_scrollSpeed; + _x -= g_fp->_scrollSpeed; + } else { + _x = 0; + } + + if (_y > 0) { + offsetY = g_fp->_scrollSpeed; + _y -= g_fp->_scrollSpeed; + } + + if (_y < 0) { + offsetY -= g_fp->_scrollSpeed; + _y += g_fp->_scrollSpeed; + } + + g_fp->_sceneRect.translate(offsetX, offsetY); + } + + updateScrolling2(); +} + +void Scene::updateScrolling2() { + if (_picObjList.size()) { + Common::Point point; + int offsetY = 0; + int offsetX = 0; + + ((PictureObject *)_picObjList[0])->getDimensions(&point); + + int flags = ((PictureObject *)_picObjList[0])->_flags; + + if (g_fp->_sceneRect.left < 0 && !(flags & 2)) + offsetX = -g_fp->_sceneRect.left; + + if (g_fp->_sceneRect.top < 0 && !(flags & 0x20)) + offsetY = -g_fp->_sceneRect.top; + + if (g_fp->_sceneRect.right > point.x - 1 && g_fp->_sceneRect.left > 0 && !(flags & 2)) + offsetX = point.x - g_fp->_sceneRect.right - 1; + + if (g_fp->_sceneRect.bottom > point.y - 1 && g_fp->_sceneRect.top > 0 && !(flags & 0x20)) + offsetY = point.y - g_fp->_sceneRect.bottom - 1; + + g_fp->_sceneRect.translate(offsetX, offsetY); + } +} + +StaticANIObject *Scene::getStaticANIObjectAtPos(int x, int y) { + StaticANIObject *res = 0; + + for (uint i = 0; i < _staticANIObjectList1.size(); i++) { + StaticANIObject *p = _staticANIObjectList1[i]; + int pixel; + + if ((p->_field_8 & 0x100) && (p->_flags & 4) && + p->getPixelAtPos(x, y, &pixel) && + (!res || res->_priority >= p->_priority)) + res = p; + } + + return res; +} + +PictureObject *Scene::getPictureObjectAtPos(int x, int y) { + PictureObject *res = 0; + + for (uint i = 0; i < _picObjList.size(); i++) { + PictureObject *p = (PictureObject *)_picObjList[i]; + if ((p->_field_8 & 0x100) && (p->_flags & 4) && + p->isPixelHitAtPos(x, y) && + (!res || res->_priority >= p->_priority)) + res = p; + } + + return res; +} + +int Scene::getPictureObjectIdAtPos(int x, int y) { + PictureObject *resp = 0; + int res = 0; + + for (uint i = 0; i < _picObjList.size(); i++) { + PictureObject *p = (PictureObject *)_picObjList[i]; + if ((p->_field_8 & 0x100) && (p->_flags & 4) && + p->isPixelHitAtPos(x, y) && + (!res || resp->_priority >= p->_priority)) { + resp = p; + res = p->_id; + } + } + + return res; +} + +void Scene::update(int counterdiff) { + debug(6, "Scene::update(%d)", counterdiff); + + for (uint i = 0; i < _staticANIObjectList2.size(); i++) + _staticANIObjectList2[i]->update(counterdiff); +} + +void Scene::drawContent(int minPri, int maxPri, bool drawBg) { + if (!_picObjList.size() && !_bigPictureArray1Count) + return; + + if (_palette) { + g_fp->_globalPalette = _palette->_data; + } + + debug(1, "Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); + + if (_picObjList.size() > 2) { // We need to z-sort them + objectList_sortByPriority(_picObjList, true); + } + + if (minPri == -1 && _picObjList.size()) + minPri = ((PictureObject *)_picObjList.back())->_priority - 1; + + if (maxPri == -1) + maxPri = 60000; + + debug(1, "-> Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); + + Common::Point point; + + debug(1, "_bigPict: %d objlist: %d", _bigPictureArray1Count, _picObjList.size()); + + if (drawBg && _bigPictureArray1Count && _picObjList.size()) { + + _bigPictureArray[0][0]->getDimensions(&point); + + int width = point.x; + int height = point.y; + + debug(8, "w: %d h:%d", width, height); + + ((PictureObject *)_picObjList[0])->getDimensions(&point); + + debug(8, "w2: %d h2:%d", point.x, point.y); + + int bgStX = g_fp->_sceneRect.left % point.x; + + if (bgStX < 0) + bgStX += point.x; + + int bgNumX = bgStX / width; + int bgOffsetX = bgStX % width; + + int bgStY = g_fp->_sceneRect.top % point.y; + + if (bgStY < 0) + bgStY += point.y; + + int bgNumY = bgStY / height; + int bgOffsetY = bgStY % height; + + int bgPosX = g_fp->_sceneRect.left - bgOffsetX; + + if (bgPosX < g_fp->_sceneRect.right - 1) { + while (1) { + int v25 = bgNumY; + for (int y = g_fp->_sceneRect.top - bgOffsetY; y < g_fp->_sceneRect.bottom - 1;) { + BigPicture *v27 = _bigPictureArray[bgNumX][v25]; + v27->draw(bgPosX, y, 0, 0); + y += v27->getDimensions(&point)->y; + v25++; + + if (v25 >= _bigPictureArray2Count) { + if (!(((PictureObject *)_picObjList[0])->_flags & 0x20)) + break; + v25 = 0; + } + } + _bigPictureArray[bgNumX][0]->getDimensions(&point); + int oldx = point.x + bgPosX; + bgPosX += point.x; + bgNumX++; + + if (bgNumX >= _bigPictureArray1Count) { + if (!(((PictureObject *)_picObjList[0])->_flags & 0x2)) + break; + bgNumX = 0; + } + if (oldx >= g_fp->_sceneRect.right - 1) + break; + } + } + } + + + for (uint i = 1; i < _picObjList.size(); i++) { + PictureObject *obj = (PictureObject *)_picObjList[i]; + + if (obj->_priority < minPri || obj->_priority >= maxPri) + continue; + + int objX = obj->_ox; + int objY = obj->_oy; + + debug(8, "obj: %d %d", objX, objY); + + obj->getDimensions(&point); + + int width = point.x; + int height = point.y; + + if (obj->_flags & 8) { + while (objX > g_fp->_sceneRect.right) { + objX -= width; + obj->setOXY(objX, objY); + } + for (int j = width + objX; width + objX < g_fp->_sceneRect.left; j = width + objX) { + objX = j; + obj->setOXY(j, objY); + } + } + + if (obj->_flags & 0x10) { + while (objY > g_fp->_sceneRect.bottom) { + objY -= height; + obj->setOXY(objX, objY); + } + for (int j = objY + height; objY + height < g_fp->_sceneRect.top; j = objY + height) { + objY = j; + obj->setOXY(objX, j); + } + } + if (obj->_flags & 4) + obj->draw(); + + if (obj->_flags & 2) { + if (objX > g_fp->_sceneRect.left) { + obj->setOXY(objX - width, objY); + obj->draw(); + obj->setOXY(objX, objY); + } + if (width + objX < g_fp->_sceneRect.right) { + obj->setOXY(width + objX, objY); + obj->draw(); + obj->setOXY(objX, objY); + } + } + + if (obj->_flags & 0x20) { + if (objY > g_fp->_sceneRect.top) { + obj->setOXY(objX, objY - height); + obj->draw(); + obj->setOXY(objX, objY); + } + if (height + objY < g_fp->_sceneRect.bottom) { + obj->setOXY(objX, height + objY); + obj->draw(); + obj->setOXY(objX, objY); + } + } + } +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scene.h b/engines/fullpipe/scene.h new file mode 100644 index 0000000000..1e2dae81fe --- /dev/null +++ b/engines/fullpipe/scene.h @@ -0,0 +1,111 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_SCENE_H +#define FULLPIPE_SCENE_H + +#include "fullpipe/gfx.h" + +namespace Fullpipe { + +class MessageQueue; + +class Scene : public Background { + public: + Common::Array<StaticANIObject *> _staticANIObjectList1; + Common::Array<StaticANIObject *> _staticANIObjectList2; + Common::Array<MessageQueue *> _messageQueueList; + // PtrList _faObjectList; // not used + Shadows *_shadows; + SoundList *_soundList; + int16 _sceneId; + char *_sceneName; + int _field_BC; + NGIArchive *_libHandle; + + public: + Scene(); + virtual ~Scene(); + + virtual bool load(MfcArchive &file); + + void initStaticANIObjects(); + void init(); + void draw(); + void drawContent(int minPri, int maxPri, bool drawBG); + void updateScrolling(); + void updateScrolling2(); + + void update(int counterdiff); + + StaticANIObject *getAniMan(); + StaticANIObject *getStaticANIObject1ById(int obj, int a3); + StaticANIObject *getStaticANIObject1ByName(char *name, int a3); + MessageQueue *getMessageQueueById(int messageId); + MessageQueue *getMessageQueueByName(char *name); + + void deleteStaticANIObject(StaticANIObject *obj); + void addStaticANIObject(StaticANIObject *obj, bool addList2); + + void setPictureObjectsFlag4(); + PictureObject *getPictureObjectById(int objId, int flags); + PictureObject *getPictureObjectByName(const char *name, int keyCode); + void deletePictureObject(PictureObject *obj); + void preloadMovements(GameVar *var); + + StaticANIObject *getStaticANIObjectAtPos(int x, int y); + PictureObject *getPictureObjectAtPos(int x, int y); + int getPictureObjectIdAtPos(int x, int y); + + void initObjectCursors(const char *name); + + void stopAllSounds(); + + private: + static bool compareObjPriority(const void *p1, const void *p2); + void objectList_sortByPriority(Common::Array<StaticANIObject *> &list, bool skipFirst = false); + void objectList_sortByPriority(Common::Array<PictureObject *> &list, bool skipFirst = false); +}; + +class SceneTag : public CObject { + public: + CObject *_field_4; + char *_tag; + Scene *_scene; + int16 _sceneId; + + public: + SceneTag(); + ~SceneTag(); + + virtual bool load(MfcArchive &file); + void loadScene(); +}; + +class SceneTagList : public Common::List<SceneTag>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_SCENE_H */ diff --git a/engines/fullpipe/scenes.cpp b/engines/fullpipe/scenes.cpp new file mode 100644 index 0000000000..32aa955a61 --- /dev/null +++ b/engines/fullpipe/scenes.cpp @@ -0,0 +1,1511 @@ +/* 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/utils.h" +#include "fullpipe/objects.h" +#include "fullpipe/statics.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/input.h" +#include "fullpipe/behavior.h" + +#include "fullpipe/constants.h" +#include "fullpipe/objectnames.h" +#include "fullpipe/scenes.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +Vars::Vars() { + sceneIntro_aniin1man = 0; + sceneIntro_needSleep = true; + sceneIntro_needGetup = false; + sceneIntro_skipIntro = true; + sceneIntro_playing = false; + sceneIntro_needBlackout = false; + + swallowedEgg1 = 0; + swallowedEgg2 = 0; + swallowedEgg3 = 0; + + scene01_picSc01Osk = 0; + scene01_picSc01Osk2 = 0; + + scene02_guvTheDrawer = 0; + scene02_boxDelay = 0; + scene02_boxOpen = false; + + scene03_eggeater = 0; + scene03_domino = 0; + + scene04_bottle = 0; + scene04_hand = 0; + scene04_plank = 0; + scene04_clock = 0; + scene04_hand = 0; + scene04_spring = 0; + scene04_mamasha = 0; + scene04_boot = 0; + scene04_speaker = 0; + + scene04_ladder = 0; + scene04_coinPut = false; + scene04_soundPlaying = false; + scene04_dynamicPhaseIndex = 0; + scene04_dudeOnLadder = false; + + scene04_sceneClickX = 0; + scene04_sceneClickY = 0; + + scene04_dudePosX = 0; + scene04_dudePosY = 0; + + scene04_bottleIsTaken = false; + scene04_kozyawkaOnLadder = false; + scene04_walkingKozyawka = 0; + scene04_bottleWeight = 0; + scene04_var07 = false; + scene04_ladderClickable = false; + scene04_handIsDown = false; + scene04_dudeInBottle = false; + scene04_kozHeadRaised = false; + scene04_bottleIsDropped = false; + scene04_bigBallIn = false; + scene04_bigBallCounter = 0; + scene04_bigBallFromLeft = false; + scene04_speakerVariant = 0; + scene04_speakerPhase = 0; + scene04_clockCanGo = false; + scene04_objectIsTaken = false; + scene04_springOffset = 0; + scene04_lastKozyawka = 0; + scene04_springDelay = 0; + scene04_bottleY = 0; + scene04_ladderOffset = 0; + + scene05_handle = 0; + scene05_wacko = 0; + scene05_bigHatch = 0; + scene05_wackoTicker = 0; + scene05_handleFlipper = 0; + scene05_floatersTicker = 0; + + scene06_manX = 0; + scene06_manY = 0; + scene06_ballX = 0; + scene06_ballY = 0; + scene06_mumsy = 0; + scene06_someBall = 0; + scene06_invHandle = 0; + scene06_liftButton = 0; + scene06_ballDrop = 0; + scene06_arcadeEnabled = false; + scene06_aimingBall = false; + scene06_currentBall = 0; + scene06_ballInHands = 0; + scene06_flyingBall = 0; + scene06_numBallsGiven = 0; + scene06_mumsyNumBalls = 0; + scene06_eggieTimeout = 0; + scene06_eggieDirection = true; + scene06_mumsyGotBall = 0; + scene06_ballDeltaX = 0; + scene06_ballDeltaY = 0; + scene06_sceneClickX = 0; + scene06_sceneClickY = 0; + scene06_mumsyPos = 0; + scene06_mumsyJumpBk = 0; + scene06_mumsyJumpFw = 0; + scene06_mumsyJumpBkPercent = 0; + scene06_mumsyJumpFwPercent = 0; + + scene07_lukeAnim = 0; + scene07_lukePercent = 0; + scene07_plusMinus = 0; + + scene08_batuta = 0; + scene08_vmyats = 0; + scene08_clock = 0; + scene08_inAir = false; + scene08_flyingUp = false; + scene08_onBelly = false; + scene08_stairsOffset = -37; + scene08_snoringCountdown = -1; + scene08_inArcade = false; + scene08_stairsVisible = true; + scene08_manOffsetY = 0; + + scene09_flyingBall = 0; + scene09_numSwallenBalls = 0; + scene09_gulper = 0; + scene09_spitter = 0; + scene09_grit = 0; + scene09_dudeY = 0; + scene09_gulperIsPresent = true; + scene09_dudeIsOnLadder = false; + scene09_interactingHanger = -1; + scene09_intHangerPhase = -1; + scene09_intHangerMaxPhase = -1000; + scene09_numMovingHangers = 0; + scene09_clickY = 0; + scene09_hangerOffsets[0].x = 0; + scene09_hangerOffsets[0].y = -15; + scene09_hangerOffsets[1].x = 15; + scene09_hangerOffsets[1].y = 0; + scene09_hangerOffsets[2].x = 0; + scene09_hangerOffsets[2].y = 0; + scene09_hangerOffsets[3].x = 0; + scene09_hangerOffsets[3].y = 0; + + scene10_gum = 0; + scene10_packet = 0; + scene10_packet2 = 0; + scene10_inflater = 0; + scene10_ladder = 0; + scene10_hasGum = 0; + + scene11_swingie = 0; + scene11_boots = 0; + scene11_dudeOnSwing = 0; + scene11_hint = 0; + scene11_arcadeIsOn = false; + scene11_scrollIsEnabled = false; + scene11_scrollIsMaximized = false; + scene11_hintCounter = 0; + scene11_swingieScreenEdge = 0; + scene11_crySound = 0; + scene11_swingAngle = 1.0; + scene11_swingOldAngle = 1.0; + scene11_swingSpeed = 1.0; + scene11_swingAngleDiff = 1.0; + scene11_swingInertia = 0.0; + scene11_swingCounter = 0; + scene11_swingCounterPrevTurn = 0; + scene11_swingDirection = 0; + scene11_swingDirectionPrevTurn = 0; + scene11_swingIsSwinging = false; + scene11_swingieStands = false; + scene11_dudeX = 0; + scene11_dudeY = 0; + scene11_swingMaxAngle = 45; + + scene12_fly = 0; + scene12_flyCountdown = 0; + + scene13_whirlgig = 0; + scene13_guard = 0; + scene13_handleR = 0; + scene13_handleL = 0; + scene13_bridge = 0; + scene13_guardDirection = false; + scene13_dudeX = 0; + + scene14_grandma = 0; + scene14_sceneDeltaX = 0; + scene14_sceneDeltaY = 0; + scene14_arcadeIsOn = false; + scene14_dudeIsKicking = false; + scene14_ballIsFlying = false; + scene14_dudeCanKick = false; + scene14_sceneDiffX = 0; + scene14_sceneDiffY = 0; + scene14_pink = 0; + scene14_flyingBall = 0; + scene14_balls.clear(); + scene14_grandmaIsHere = false; + scene14_dudeX = 0; + scene14_dudeY = 0; + scene14_grandmaX = 0; + scene14_grandmaY = 0; + scene14_dude2X = 0; + scene14_ballDeltaX = 0; + scene14_ballDeltaY = 0; + scene14_ballX = 0; + scene14_ballY = 0; + scene14_hitsLeft = 0; + + scene15_chantingCountdown = 0; + scene15_plusminus = 0; + scene15_ladder = 0; + scene15_boot = 0; + + scene16_figures.clear(); + scene16_walkingBoy = 0; + scene16_walkingGirl = 0; + scene16_walkingCount = 0; + scene16_wire = 0; + scene16_mug = 0; + scene16_jettie = 0; + scene16_boot = 0; + scene16_girlIsLaughing = false; + scene16_sound = 0; + scene16_placeIsOccupied = false; + + scene17_flyState = 0; + scene17_sugarIsShown = false; + scene17_sceneOldEdgeX = 0; + scene17_flyCountdown = 0; + scene17_hand = 0; + scene17_handPhase = false; + scene17_sceneEdgeX = 0; + + scene18_inScene18p1 = false; + scene18_whirlgig = 0; + scene18_wheelCenterX = 0; + scene18_wheelCenterY = 0; + scene18_bridgeIsConvoluted = false; + scene18_whirlgigMovMum = 0; + scene18_girlIsSwinging = false; + scene18_rotationCounter = 0; + scene18_manY = 0; + scene18_wheelFlipper = false; + scene18_wheelIsTurning = true; + scene18_kidIsOnWheel = -1; + scene18_boyIsOnWheel = 0; + scene18_girlIsOnWheel = 0; + scene18_boyJumpedOff = true; + scene18_jumpDistance = -1; + scene18_jumpAngle = -1; + scene18_manIsReady = false; + scene18_enteredTrubaRight = false; + scene18_manWheelPos = 0; + scene18_manWheelPosTo = -1; + scene18_kidWheelPos = 0; + scene18_kidWheelPosTo = 0; + scene18_boy = 0; + scene18_girl = 0; + scene18_domino = 0; + scene18_boyJumpX = 290; + scene18_boyJumpY = -363; + scene18_girlJumpX = 283; + scene18_girlJumpY = -350; + + scene19_enteredTruba3 = false; + + scene20_fliesCountdown = 0; + scene20_grandma = 0; + + scene21_giraffeBottom = 0; + scene21_giraffeBottomX = 0; + scene21_giraffeBottomY = 0; + scene21_pipeIsOpen = false; + scene21_wigglePos = 0.0; + scene21_wiggleTrigger = 0; + + scene22_bag = 0; + scene22_giraffeMiddle = 0; + scene22_dudeIsOnStool = false; + scene22_interactionIsDisabled = false; + scene22_craneIsOut = true; + scene22_numBagFalls = 1; + + scene23_calend0 = 0; + scene23_calend1 = 0; + scene23_calend2 = 0; + scene23_calend3 = 0; + scene23_topReached = false; + scene23_isOnStool = false; + scene23_someVar = 0; + scene23_giraffeTop = 0; + scene23_giraffee = 0; + + scene24_jetIsOn = false; + scene24_flowIsLow = false; + scene24_waterIsOn = false; + scene24_water = 0; + scene24_jet = 0; + scene24_drop = 0; + + scene25_water = 0; + scene25_board = 0; + scene25_drop = 0; + scene25_dudeIsOnBoard = false; + scene25_waterIsPresent = false; + scene25_boardIsSelectable = false; + scene25_beardersAreThere = false; + scene25_beardersCounter = 0; + scene25_bearders.clear(); + scene25_sneezeFlipper = false; + + scene26_chhi = 0; + scene26_drop = 0; + scene26_sockPic = 0; + scene26_sock = 0; + scene26_activeVent = 0; + + scene27_hitZone = 0; + scene27_driver = 0; + scene27_maid = 0; + scene27_batHandler = 0; + scene27_driverHasVent = true; + scene27_bat = 0; + scene27_dudeIsAiming = false; + scene27_maxPhaseReached = false; + scene27_wipeIsNeeded = false; + scene27_driverPushedButton = false; + scene27_numLostBats = 0; + scene27_knockCount = 0; + scene27_aimStartX = 0; + scene27_aimStartY = 0; + scene27_launchPhase = 0; + + scene28_fliesArePresent = true; + scene28_beardedDirection = true; + scene28_darkeningObject = 0; + scene28_lighteningObject = 0; + scene28_headDirection = false; + scene28_headBeardedFlipper = false; + scene28_lift6inside = false; + + scene29_porter = 0; + scene29_shooter1 = 0; + scene29_shooter2 = 0; + scene29_ass = 0; + scene29_manIsRiding = false; + scene29_arcadeIsOn = false; + scene29_reachedFarRight = false; + scene29_rideBackEnabled = false; + scene29_shootCountdown = 0; + scene29_shootDistance = 75; + scene29_manIsHit = 0; + scene29_scrollSpeed = 0; + scene29_scrollingDisabled = 0; + scene29_hitBall = 0; + scene29_manX = 0; + scene29_manY = 0; + + scene30_leg = 0; + scene30_liftFlag = 1; + + scene31_chantingCountdown = 0; + scene31_cactus = 0; + scene31_plusMinus = 0; + + scene32_flagIsWaving = false; + scene32_flagNeedsStopping = false; + scene32_dudeIsSitting = false; + scene32_cactusCounter = -1; + scene32_dudeOnLadder = false; + scene32_cactusIsGrowing = false; + scene32_flag = 0; + scene32_cactus = 0; + scene32_massOrange = 0; + scene32_massBlue = 0; + scene32_massGreen = 0; + scene32_button = 0; + + scene33_mug = 0; + scene33_jettie = 0; + scene33_cube = 0; + scene33_cubeX = -1; + scene33_handleIsDown = false; + + for (int i = 0; i < 9; i++) { + scene33_ventsX[i] = 0; + scene33_ventsState[i] = 0; + } + + scene34_cactus = 0; + scene34_vent = 0; + scene34_hatch = 0; + scene34_boot = 0; + scene34_dudeClimbed = false; + scene34_dudeOnBoard = false; + scene34_dudeOnCactus = false; + scene34_fliesCountdown = 0; + + scene35_hose = 0; + scene35_bellyInflater = 0; + scene35_flowCounter = 0; + scene35_fliesCounter = 0; + + scene36_rotohrust = 0; + scene36_scissors = 0; + + scene37_rings.clear(); + scene37_lastDudeX = -1; + scene37_cursorIsLocked = 0; + scene37_plusMinus1 = 0; + scene37_plusMinus2 = 0; + scene37_plusMinus3 = 0; + scene37_soundFlipper = 0; + scene37_dudeX = 0; + + scene38_boss = 0; + scene38_tally = 0; + scene38_shorty = 0; + scene38_domino0 = 0; + scene38_dominos = 0; + scene38_domino1 = 0; + scene38_bottle = 0; + scene38_bossCounter = 0; + scene38_lastBossAnim = 0; + scene38_bossAnimCounter = 0; + scene38_tallyCounter = 0; + scene38_lastTallyAnim = 0; + scene38_tallyAnimCounter = 0; + scene38_shortyCounter = 0; + scene38_lastShortyAnim = 0; + scene38_shortyAnimCounter = 0; + + sceneFinal_var01 = 0; + sceneFinal_var02 = 0; + sceneFinal_var03 = 0; + + selector = 0; +} + +static int scenes[] = { + SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7, SC_8, SC_9, SC_10, + SC_11, SC_12, SC_13, SC_14, SC_15, SC_16, SC_17, SC_18, SC_19, SC_20, + SC_21, SC_22, SC_23, SC_24, SC_25, SC_26, SC_27, SC_28, SC_29, SC_30, + SC_31, SC_32, SC_33, SC_34, SC_35, SC_36, SC_37, SC_38, SC_FINAL1, SC_DBGMENU +}; + +static int scenesD[] = { + PIC_SCD_1, PIC_SCD_2, PIC_SCD_3, PIC_SCD_4, PIC_SCD_5, PIC_SCD_6, PIC_SCD_7, PIC_SCD_8, PIC_SCD_9, PIC_SCD_10, + PIC_SCD_11, PIC_SCD_12, PIC_SCD_13, PIC_SCD_14, PIC_SCD_15, PIC_SCD_16, PIC_SCD_17, PIC_SCD_18, PIC_SCD_19, PIC_SCD_20, + PIC_SCD_21, PIC_SCD_22, PIC_SCD_23, PIC_SCD_24, PIC_SCD_25, PIC_SCD_26, PIC_SCD_27, PIC_SCD_28, PIC_SCD_29, PIC_SCD_30, + PIC_SCD_31, PIC_SCD_32, PIC_SCD_33, PIC_SCD_34, PIC_SCD_35, PIC_SCD_36, PIC_SCD_37, PIC_SCD_38, PIC_SCD_FIN, 0 +}; + +int FullpipeEngine::convertScene(int scene) { + if (!scene || scene >= SC_1) + return scene; + + if (scene < 1 || scene > 40) + return SC_1; + + return scenes[scene - 1]; +} + +int FullpipeEngine::getSceneEntrance(int scene) { + for (int i = 0; i < 40; i++) + if (scenes[i] == scene) + return scenesD[i]; + + return 0; +} + +int FullpipeEngine::getSceneFromTag(int tag) { + for (int i = 0; i < ARRAYSIZE(scenes); i++) { + if (scenes[i] == tag) + return i + 1; + } + + return 1; +} + +bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) { + GameVar *sceneVar; + Common::Point sceneDim; + + Scene *scene = accessScene(entrance->_sceneId); + + if (!scene) + return 0; + + ((PictureObject *)scene->_picObjList.front())->getDimensions(&sceneDim); + _sceneWidth = sceneDim.x; + _sceneHeight = sceneDim.y; + + _sceneRect.top = 0; + _sceneRect.left = 0; + _sceneRect.right = 799; + _sceneRect.bottom = 599; + + scene->_x = 0; + scene->_y = 0; + + _aniMan->setOXY(0, 0); + _aniMan->clearFlags(); + _aniMan->_callback1 = 0; + _aniMan->_callback2 = 0; + _aniMan->_shadowsOn = 1; + + _scrollSpeed = 8; + + _isSaveAllowed = true; + _updateFlag = true; + _flgCanOpenMap = true; + + if (entrance->_sceneId == SC_DBGMENU) { + _inventoryScene = 0; + } else { + _gameLoader->loadScene(SC_INV); + getGameLoaderInventory()->rebuildItemRects(); + _inventoryScene = getGameLoaderInventory()->getScene(); + } + if (_soundEnabled) { + if (scene->_soundList) { + _currSoundListCount = 2; + _currSoundList1[0] = accessScene(SC_COMMON)->_soundList; + _currSoundList1[1] = scene->_soundList; + + for (int i = 0; i < scene->_soundList->getCount(); i++) { + scene->_soundList->getSoundByIndex(i)->updateVolume(); + } + } else { + _currSoundListCount = 1; + _currSoundList1[0] = accessScene(SC_COMMON)->_soundList; + } + } + + getGameLoaderInteractionController()->sortInteractions(scene->_sceneId); + _currentScene = scene; + scene->addStaticANIObject(_aniMan, 1); + _scene2 = scene; + _aniMan->_movement = 0; + _aniMan->_statics = _aniMan->getStaticsById(ST_MAN_EMPTY); + _aniMan->setOXY(0, 0); + + _aniMan2 = _aniMan; + MctlCompound *cmp = getSc2MctlCompoundBySceneId(entrance->_sceneId); + cmp->initMovGraph2(); + cmp->attachObject(_aniMan); + cmp->activate(); + getGameLoaderInteractionController()->enableFlag24(); + setInputDisabled(0); + + scene->setPictureObjectsFlag4(); + + for (uint i = 0; i < scene->_staticANIObjectList1.size(); i++) + scene->_staticANIObjectList1[i]->_flags &= 0xFE7F; + + PictureObject *p = accessScene(SC_INV)->getPictureObjectById(PIC_INV_MENU, 0); + p->setFlags(p->_flags & 0xFFFB); + + removeMessageHandler(2, -1); + _updateScreenCallback = 0; + + switch (entrance->_sceneId) { + case SC_INTRO1: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_INTRO1"); + scene->preloadMovements(sceneVar); + sceneIntro_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_INTRO1"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandlerIntro, 2); + _updateCursorCallback = sceneIntro_updateCursor; + break; + + case SC_1: + scene01_fixEntrance(); + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_1"); + scene->preloadMovements(sceneVar); + scene01_initScene(scene, entrance->_field_4); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_1"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler01, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_2: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_2"); + scene->preloadMovements(sceneVar); + scene02_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_2"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler02, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_3: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_3"); + scene->preloadMovements(sceneVar); + scene03_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_3"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler03, 2); + scene03_setEaterState(); + _updateCursorCallback = scene03_updateCursor; + break; + + case SC_4: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_4"); + scene->preloadMovements(sceneVar); + scene04_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_4"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler04, 2, 2); + _updateCursorCallback = scene04_updateCursor; + break; + + case SC_5: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_5"); + scene->preloadMovements(sceneVar); + scene05_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_5"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler05, 2, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_6: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_6"); + scene->preloadMovements(sceneVar); + scene06_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_6"); + setSceneMusicParameters(sceneVar); + scene06_initMumsy(); + insertMessageHandler(sceneHandler06, 2, 2); + _updateCursorCallback = scene06_updateCursor; + break; + + case SC_7: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_7"); + scene->preloadMovements(sceneVar); + scene07_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_7"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler07, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_8: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_8"); + scene->preloadMovements(sceneVar); + scene08_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_8"); + setSceneMusicParameters(sceneVar); + scene08_setupMusic(); + addMessageHandler(sceneHandler08, 2); + _updateCursorCallback = scene08_updateCursor; + break; + + case SC_9: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_9"); + scene->preloadMovements(sceneVar); + scene09_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_9"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler09, 2, 2); + _updateCursorCallback = scene09_updateCursor; + break; + + case SC_10: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_10"); + scene->preloadMovements(sceneVar); + scene10_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_10"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler10, 2, 2); + _updateCursorCallback = scene10_updateCursor; + break; + + case SC_11: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_11"); + scene->preloadMovements(sceneVar); + scene11_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_11"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler11, 2, 2); + scene11_setupMusic(); + _updateCursorCallback = scene11_updateCursor; + break; + + case SC_12: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_12"); + scene->preloadMovements(sceneVar); + scene12_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_12"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler12, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_13: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_13"); + scene->preloadMovements(sceneVar); + scene13_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_13"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler13, 2, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_14: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_14"); + scene->preloadMovements(sceneVar); + scene14_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_14"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler14, 2, 2); + scene14_setupMusic(); + _updateCursorCallback = scene14_updateCursor; + break; + + case SC_15: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_15"); + scene->preloadMovements(sceneVar); + scene15_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_15"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler15, 2, 2); + _updateCursorCallback = scene15_updateCursor; + break; + + case SC_16: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_16"); + scene->preloadMovements(sceneVar); + scene16_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_16"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler16, 2); + _updateCursorCallback = scene16_updateCursor; + break; + + case SC_17: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_17"); + scene->preloadMovements(sceneVar); + scene17_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_17"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler17, 2); + scene17_restoreState(); + _updateCursorCallback = scene17_updateCursor; + break; + + case SC_18: + scene18_setupEntrance(); + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_18"); + scene->preloadMovements(sceneVar); + g_fp->stopAllSounds(); + + if (g_vars->scene18_inScene18p1) + scene18_initScene1(scene); + else + scene18_initScene2(scene); + + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_18"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler18, 2, 2); + _updateCursorCallback = scene18_updateCursor; + break; + + case SC_19: + if (!g_fp->_scene3) { + g_fp->_scene3 = accessScene(SC_18); + g_fp->_gameLoader->loadScene(SC_18); + + scene18_initScene2(g_fp->_scene3); + scene18_preload(); + scene19_setMovements(g_fp->_scene3, entrance->_field_4); + + g_vars->scene18_inScene18p1 = true; + } + + scene19_preload(); + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_19"); + scene->preloadMovements(sceneVar); + g_fp->stopAllSounds(); + + if (g_vars->scene18_inScene18p1) + scene18_initScene1(scene); + else + scene19_initScene2(); + + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_19"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler19, 2); + scene19_setSugarState(scene); + _updateCursorCallback = scene19_updateCursor; + break; + + case SC_20: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_20"); + scene->preloadMovements(sceneVar); + scene20_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_20"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler20, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_21: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_21"); + scene->preloadMovements(sceneVar); + scene21_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_21"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler21, 2, 2); + _updateCursorCallback = scene21_updateCursor; + break; + + case SC_22: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_22"); + scene->preloadMovements(sceneVar); + scene22_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_22"); + setSceneMusicParameters(sceneVar); + scene22_setBagState(); + insertMessageHandler(sceneHandler22, 2, 2); + _updateCursorCallback = scene22_updateCursor; + break; + + case SC_23: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_23"); + scene->preloadMovements(sceneVar); + scene23_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_23"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler23, 2, 2); + scene23_setGiraffeState(); + _updateCursorCallback = scene23_updateCursor; + break; + + case SC_24: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_24"); + scene->preloadMovements(sceneVar); + scene24_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_24"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler24, 2); + scene24_setPoolState(); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_25: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_25"); + scene->preloadMovements(sceneVar); + scene25_initScene(scene, entrance->_field_4); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_25"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler25, 2); + scene25_setupWater(scene, entrance->_field_4); + _updateCursorCallback = scene25_updateCursor; + break; + + case SC_26: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_26"); + scene->preloadMovements(sceneVar); + scene26_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_26"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler26, 2, 2); + scene26_setupDrop(scene); + _updateCursorCallback = scene26_updateCursor; + break; + + case SC_27: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_27"); + scene->preloadMovements(sceneVar); + scene27_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_27"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler27, 2); + _updateCursorCallback = scene27_updateCursor; + break; + + case SC_28: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_28"); + scene->preloadMovements(sceneVar); + scene28_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_28"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler28, 2, 2); + _updateCursorCallback = scene28_updateCursor; + break; + + case SC_29: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_29"); + scene->preloadMovements(sceneVar); + scene29_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_29"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler29, 2); + _updateCursorCallback = scene29_updateCursor; + break; + + case SC_30: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_30"); + scene->preloadMovements(sceneVar); + scene30_initScene(scene, entrance->_field_4); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_30"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler30, 2); + _updateCursorCallback = scene30_updateCursor; + break; + + case SC_31: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_31"); + scene->preloadMovements(sceneVar); + scene31_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_31"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler31, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_32: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_32"); + scene->preloadMovements(sceneVar); + scene32_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_32"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler32, 2, 2); + scene32_setupMusic(); + _updateCursorCallback = scene32_updateCursor; + break; + + case SC_33: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_33"); + scene->preloadMovements(sceneVar); + scene33_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_33"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler33, 2, 2); + scene33_setupMusic(); + _updateCursorCallback = scene33_updateCursor; + break; + + case SC_34: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_34"); + scene->preloadMovements(sceneVar); + scene34_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_34"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler34, 2, 2); + scene34_initBeh(); + _updateCursorCallback = scene34_updateCursor; + break; + + case SC_35: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_35"); + scene->preloadMovements(sceneVar); + scene35_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_35"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler35, 2, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_36: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_36"); + scene->preloadMovements(sceneVar); + scene36_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_36"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler36, 2); + _updateCursorCallback = scene36_updateCursor; + break; + + case SC_37: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_37"); + scene->preloadMovements(sceneVar); + scene37_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_37"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler37, 2, 2); + _updateCursorCallback = scene37_updateCursor; + break; + + case SC_38: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_38"); + scene->preloadMovements(sceneVar); + scene38_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_38"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler38, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_FINAL1: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_FINAL1"); + scene->preloadMovements(sceneVar); + sceneFinal_initScene(); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_FINAL1"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandlerFinal, 2); + _updateCursorCallback = sceneFinal_updateCursor; + break; + + case SC_DBGMENU: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_DBGMENU"); + scene->preloadMovements(sceneVar); + sceneDbgMenu_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_DBGMENU"); + addMessageHandler(sceneHandlerDbgMenu, 2); + break; + + default: + error("Unknown scene %d", entrance->_sceneId); + break; + } + + return true; +} + +int defaultUpdateCursor() { + g_fp->updateCursorCommon(); + + return g_fp->_cursorId; +} + +void FullpipeEngine::updateMapPiece(int mapId, int update) { + for (int i = 0; i < 200; i++) { + int hiWord = (_mapTable[i] >> 16) & 0xffff; + + if (hiWord == mapId) { + _mapTable[i] |= update; + return; + } + if (!hiWord) { + _mapTable[i] = (mapId << 16) | update; + return; + } + } +} + +void FullpipeEngine::updateMap(PreloadItem *pre) { + switch (pre->sceneId) { + case SC_1: + updateMapPiece(PIC_MAP_S01, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_P01, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_A13, 1); + break; + + case SC_2: + updateMapPiece(PIC_MAP_S02, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_P01, 1); + + break; + + case SC_3: + updateMapPiece(PIC_MAP_S03, 1); + break; + + case SC_4: + updateMapPiece(PIC_MAP_S04, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_P04, 1); + + break; + + case SC_5: + updateMapPiece(PIC_MAP_S05, 1); + + if (pre->keyCode == TrubaLeft) { + updateMapPiece(PIC_MAP_P04, 1); + } + + if (pre->keyCode == TrubaUp) { + updateMapPiece(PIC_MAP_P05, 1); + updateMapPiece(PIC_MAP_A11, 1); + } + + break; + + case SC_6: + updateMapPiece(PIC_MAP_S06, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_A12, 1); + + break; + + case SC_7: + updateMapPiece(PIC_MAP_S07, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_P18, 1); + + break; + + case SC_8: + updateMapPiece(PIC_MAP_S08, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_P11, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_P18, 1); + + return; + + case SC_9: + updateMapPiece(PIC_MAP_S09, 1); + + if (pre->keyCode == TrubaDown) + updateMapPiece(PIC_MAP_P11, 1); + + return; + + case SC_10: + updateMapPiece(PIC_MAP_S10, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_P02, 1); + + break; + + case SC_11: + updateMapPiece(PIC_MAP_S11, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_P02, 1); + + break; + + case SC_12: + updateMapPiece(PIC_MAP_S12, 1); + break; + + case SC_13: + updateMapPiece(PIC_MAP_S13, 1); + + if (pre->keyCode == TrubaUp) { + updateMapPiece(PIC_MAP_P06, 1); + updateMapPiece(PIC_MAP_A10, 1); + } + break; + + case SC_14: + updateMapPiece(PIC_MAP_S14, 1); + break; + + case SC_15: + updateMapPiece(PIC_MAP_S15, 1); + + if (pre->keyCode == TrubaUp) { + updateMapPiece(PIC_MAP_P08, 1); + updateMapPiece(PIC_MAP_A14, 1); + } + + break; + + case SC_16: + updateMapPiece(PIC_MAP_S16, 1); + break; + + case SC_17: + updateMapPiece(PIC_MAP_S17, 1); + break; + + case SC_18: + updateMapPiece(PIC_MAP_S1819, 1); + + if (pre->keyCode == PIC_SC18_RTRUBA) + updateMapPiece(PIC_MAP_P14, 1); + + break; + + case SC_19: + updateMapPiece(PIC_MAP_S1819, 1); + + if (pre->keyCode == PIC_SC19_RTRUBA3) { + updateMapPiece(PIC_MAP_P15, 1); + updateMapPiece(PIC_MAP_A09, 1); + } + + break; + + case SC_20: + updateMapPiece(PIC_MAP_S20, 1); + break; + + case SC_21: + updateMapPiece(PIC_MAP_S21, 1); + + if (pre->keyCode == TrubaLeft) { + updateMapPiece(PIC_MAP_P15, 1); + updateMapPiece(PIC_MAP_A09, 1); + } + + if (pre->keyCode == TrubaDown) + updateMapPiece(PIC_MAP_A08, 1); + + break; + + case SC_22: + updateMapPiece(PIC_MAP_S22, 1); + break; + + case SC_23: + if (getObjectState(sO_UpperHatch_23) == getObjectEnumState(sO_UpperHatch_23, sO_Opened)) { + updateMapPiece(PIC_MAP_S23_1, 0); + updateMapPiece(PIC_MAP_S23_2, 1); + updateMapPiece(PIC_MAP_P07, 1); + } else { + updateMapPiece(PIC_MAP_S23_1, 1); + updateMapPiece(PIC_MAP_S23_2, 0); + } + break; + + case SC_24: + updateMapPiece(PIC_MAP_S24, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_A08, 1); + + if (pre->keyCode == TrubaDown) { + updateMapPiece(PIC_MAP_P13, 1); + updateMapPiece(PIC_MAP_A07, 1); + } + break; + + case SC_25: + updateMapPiece(PIC_MAP_S25, 1); + break; + + case SC_26: + updateMapPiece(PIC_MAP_S26, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_A06, 1); + + if (pre->keyCode == TrubaUp) { + updateMapPiece(PIC_MAP_P13, 1); + updateMapPiece(PIC_MAP_A07, 1); + } + + break; + + case SC_27: + updateMapPiece(PIC_MAP_S27, 1); + break; + + case SC_28: + updateMapPiece(PIC_MAP_S28, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_A06, 1); + + break; + + case SC_29: + updateMapPiece(PIC_MAP_S29, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_A05, 1); + + break; + + case SC_30: + updateMapPiece(PIC_MAP_S30, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_P09, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_A04, 1); + + break; + + case SC_31: + updateMapPiece(PIC_MAP_S31_2, 1); + + if (getObjectState(sO_Cactus) == getObjectEnumState(sO_Cactus, sO_HasGrown)) + updateMapPiece(PIC_MAP_S31_1, 1); + + if (pre->keyCode == TrubaRight) + updateMapPiece(PIC_MAP_P09, 1); + + break; + + case SC_32: + updateMapPiece(PIC_MAP_S32_2, 1); + + if (getObjectState(sO_Cactus) == getObjectEnumState(sO_Cactus, sO_HasGrown)) + updateMapPiece(PIC_MAP_S32_1, 1); + + break; + + case SC_33: + updateMapPiece(PIC_MAP_S33, 1); + break; + + case SC_34: + updateMapPiece(PIC_MAP_S34, 1); + + if (pre->keyCode == TrubaUp) + updateMapPiece(PIC_MAP_A03, 1); + + break; + + case SC_35: + updateMapPiece(PIC_MAP_S35, 1); + + if (pre->keyCode == TrubaLeft) + updateMapPiece(PIC_MAP_A02, 1); + + if (pre->keyCode == TrubaDown) + updateMapPiece(PIC_MAP_A03, 1); + + break; + + case SC_36: + updateMapPiece(PIC_MAP_S36, 1); + break; + + case SC_37: + updateMapPiece(PIC_MAP_S37, 1); + updateMapPiece(PIC_MAP_A01, 1); + break; + + case SC_38: + updateMapPiece(PIC_MAP_S38, 1); + + switch (pre->preloadId1) { + case SC_15: + updateMapPiece(PIC_MAP_P16, 1); + break; + + case SC_1: + updateMapPiece(PIC_MAP_P10, 1); + break; + + case SC_10: + updateMapPiece(PIC_MAP_P17, 1); + break; + + case SC_19: + updateMapPiece(PIC_MAP_P12, 1); + break; + } + break; + } +} + +void BallChain::init(Ball **ball) { + *ball = pTail; + pTail = (Ball *)ball; + numBalls--; + + if (!numBalls) { + for (Ball *i = pHead; i; i = i->p0 ) + ; + numBalls = 0; + pTail = 0; + field_8 = 0; + pHead = 0; + free(cPlex); + cPlex = 0; + } +} + +Ball *BallChain::sub04(Ball *ballP, Ball *ballN) { + if (!pTail) { + if (!cPlexLen) + error("BallChain::sub04: cPlexLen is 0"); + + cPlex = (byte *)calloc(cPlexLen, sizeof(Ball)); + + Ball *runPtr = (Ball *)&cPlex[(cPlexLen - 1) * sizeof(Ball)]; + + for (int i = 0; i < cPlexLen; i++) { + runPtr->p0 = pTail; + pTail = runPtr; + + runPtr--; + } + } + + Ball *res = pTail; + + pTail = res->p0; + res->p1 = ballP; + res->p0 = ballN; + numBalls++; + res->ani = 0; + + return res; +} + +void BallChain::removeBall(Ball *ball) { + if (ball == pHead) + pHead = ball->p0; + else + ball->p1->p0 = ball->p0; + + if (ball == field_8) + field_8 = ball->p1; + else + ball->p0->p1 = ball->p1; + + ball->p0 = pTail; + pTail = ball; + + numBalls--; + + if (!numBalls) { + numBalls = 0; + pTail = 0; + field_8 = 0; + pHead = 0; + free(cPlex); + cPlex = 0; + } +} + + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes.h b/engines/fullpipe/scenes.h new file mode 100644 index 0000000000..0b7c4e7c8f --- /dev/null +++ b/engines/fullpipe/scenes.h @@ -0,0 +1,708 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_SCENES_H +#define FULLPIPE_SCENES_H + +namespace Fullpipe { + +struct Bat; +struct BehaviorEntryInfo; +struct Hanger; +class MGM; +class MctlLadder; +struct Ring; +class StaticANIObject; +struct Swinger; +struct WalkingBearder; + +int defaultUpdateCursor(); + +int sceneIntro_updateCursor(); +void sceneIntro_initScene(Scene *sc); +int sceneHandlerIntro(ExCommand *cmd); + +void scene01_fixEntrance(); +void scene01_initScene(Scene *sc, int entrance); +int sceneHandler01(ExCommand *cmd); + +void scene02_initScene(Scene *sc); +int sceneHandler02(ExCommand *ex); + +void scene03_setEaterState(); +int scene03_updateCursor(); +void scene03_initScene(Scene *sc); +int sceneHandler03(ExCommand *cmd); + +int scene04_updateCursor(); +void scene04_initScene(Scene *sc); +int sceneHandler04(ExCommand *cmd); + +void scene05_initScene(Scene *sc); +int sceneHandler05(ExCommand *cmd); + +void scene06_initScene(Scene *sc); +void scene06_initMumsy(); +int sceneHandler06(ExCommand *cmd); +int scene06_updateCursor(); + +void scene07_initScene(Scene *sc); +int sceneHandler07(ExCommand *cmd); + +void scene08_initScene(Scene *sc); +void scene08_setupMusic(); +int sceneHandler08(ExCommand *cmd); +int scene08_updateCursor(); + +int scene09_updateCursor(); +void scene09_initScene(Scene *sc); +int sceneHandler09(ExCommand *cmd); + +void scene10_initScene(Scene *sc); +int sceneHandler10(ExCommand *cmd); +int scene10_updateCursor(); + +void scene11_initScene(Scene *sc); +void scene11_setupMusic(); +int sceneHandler11(ExCommand *cmd); +int scene11_updateCursor(); + +void scene12_initScene(Scene *sc); +int sceneHandler12(ExCommand *ex); + +void scene13_initScene(Scene *sc); +int sceneHandler13(ExCommand *ex); + +void scene14_initScene(Scene *sc); +void scene14_setupMusic(); +int sceneHandler14(ExCommand *cmd); +int scene14_updateCursor(); + +int scene15_updateCursor(); +void scene15_initScene(Scene *sc); +int sceneHandler15(ExCommand *cmd); + +void scene16_initScene(Scene *sc); +int sceneHandler16(ExCommand *cmd); +int scene16_updateCursor(); + +void scene17_initScene(Scene *sc); +void scene17_restoreState(); +int sceneHandler17(ExCommand *cmd); +int scene17_updateCursor(); + +void scene18_preload(); +void scene18_setupEntrance(); +void scene18_initScene1(Scene *sc); +void scene18_initScene2(Scene *sc); +int sceneHandler18(ExCommand *cmd); +int scene18_updateCursor(); + +void scene19_preload(); +void scene19_setMovements(Scene *sc, int entranceId); +void scene19_initScene2(); +void scene19_setMovements(Scene *sc, int key); +int sceneHandler19(ExCommand *cmd); +int scene19_updateCursor(); +void scene19_setSugarState(Scene *sc); + +void scene20_initScene(Scene *sc); +int sceneHandler20(ExCommand *ex); + +int scene21_updateCursor(); +void scene21_initScene(Scene *sc); +int sceneHandler21(ExCommand *cmd); + +void scene22_initScene(Scene *sc); +void scene22_setBagState(); +int sceneHandler22(ExCommand *cmd); +int scene22_updateCursor(); + +void scene23_initScene(Scene *sc); +void scene23_setGiraffeState(); +int sceneHandler23(ExCommand *cmd); +int scene23_updateCursor(); + +void scene24_initScene(Scene *sc); +void scene24_setPoolState(); +int sceneHandler24(ExCommand *cmd); + +void scene25_initScene(Scene *sc, int entrance); +void scene25_setupWater(Scene *sc, int entrance); +int sceneHandler25(ExCommand *cmd); +int scene25_updateCursor(); + +void scene26_initScene(Scene *sc); +void scene26_setupDrop(Scene *sc); +int sceneHandler26(ExCommand *cmd); +int scene26_updateCursor(); + +void scene27_initScene(Scene *sc); +int sceneHandler27(ExCommand *ex); +int scene27_updateCursor(); + +void scene28_initScene(Scene *sc); +int sceneHandler28(ExCommand *ex); +int scene28_updateCursor(); + +int scene29_updateCursor(); +void scene29_initScene(Scene *sc); +int sceneHandler29(ExCommand *cmd); + +int scene30_updateCursor(); +void scene30_initScene(Scene *sc, int flag); +int sceneHandler30(ExCommand *cmd); + +void scene31_initScene(Scene *sc); +int sceneHandler31(ExCommand *ex); + +void scene32_initScene(Scene *sc); +void scene32_setupMusic(); +int sceneHandler32(ExCommand *cmd); +int scene32_updateCursor(); + +void scene33_initScene(Scene *sc); +void scene33_setupMusic(); +int sceneHandler33(ExCommand *cmd); +int scene33_updateCursor(); + +void scene34_initScene(Scene *sc); +void scene34_initBeh(); +int sceneHandler34(ExCommand *cmd); +int scene34_updateCursor(); + +void scene35_initScene(Scene *sc); +int sceneHandler35(ExCommand *cmd); + +int scene36_updateCursor(); +void scene36_initScene(Scene *sc); +int sceneHandler36(ExCommand *cmd); + +void scene37_initScene(Scene *sc); +int sceneHandler37(ExCommand *ex); +int scene37_updateCursor(); + +void scene38_initScene(Scene *sc); +int sceneHandler38(ExCommand *ex); + +int sceneFinal_updateCursor(); +void sceneFinal_initScene(); +int sceneHandlerFinal(ExCommand *cmd); + +void sceneDbgMenu_initScene(Scene *sc); +int sceneHandlerDbgMenu(ExCommand *cmd); + +struct Ball { + Ball *p0; + Ball *p1; + StaticANIObject *ani; + + Ball() : p0(0), p1(0), ani(0) {} +}; + +struct BallChain { + Ball *pHead; + Ball *field_8; + int numBalls; + Ball *pTail; + byte *cPlex; + int cPlexLen; + + BallChain() : pHead(0), field_8(0), pTail(0), numBalls(0), cPlex(0), cPlexLen(0) {} + ~BallChain() { free(cPlex); } + + void init(Ball **ball); + Ball *sub04(Ball *ballP, Ball *ballN); + void removeBall(Ball *ball); + void reset() { pHead = 0; pTail = 0; field_8 = 0; numBalls = 0; free(cPlex); cPlex = 0; cPlexLen = 0; } +}; + +class Vars { +public: + Vars(); + + GameVar *swallowedEgg1; + GameVar *swallowedEgg2; + GameVar *swallowedEgg3; + + StaticANIObject *sceneIntro_aniin1man; + bool sceneIntro_needSleep; + bool sceneIntro_needGetup; + bool sceneIntro_skipIntro; + bool sceneIntro_playing; + bool sceneIntro_needBlackout; + + PictureObject *scene01_picSc01Osk; + PictureObject *scene01_picSc01Osk2; + + StaticANIObject *scene02_guvTheDrawer; + int scene02_boxDelay; + bool scene02_boxOpen; + + StaticANIObject *scene03_eggeater; + StaticANIObject *scene03_domino; + + PictureObject *scene04_bottle; + StaticANIObject *scene04_hand; + StaticANIObject *scene04_plank; + StaticANIObject *scene04_clock; + StaticANIObject *scene04_spring; + StaticANIObject *scene04_mamasha; + StaticANIObject *scene04_boot; + StaticANIObject *scene04_speaker; + + Common::Point scene04_jumpingKozyawki[20]; + Common::Point scene04_jumpRotateKozyawki[20]; + + Common::List<StaticANIObject *> scene04_kozyawkiObjList; + Common::List<GameObject *> scene04_bottleObjList; + Common::List<StaticANIObject *> scene04_kozyawkiAni; + + MctlLadder *scene04_ladder; + int scene04_ladderOffset; + + bool scene04_coinPut; + bool scene04_soundPlaying; + bool scene04_dudeOnLadder; + + int scene04_dynamicPhaseIndex; + int scene04_sceneClickX; + int scene04_sceneClickY; + int scene04_dudePosX; + int scene04_dudePosY; + int scene04_bottleY; + + StaticANIObject *scene04_walkingKozyawka; + + int scene04_speakerVariant; + int scene04_speakerPhase; + + bool scene04_bottleIsTaken; + bool scene04_kozyawkaOnLadder; + int scene04_bottleWeight; + bool scene04_var07; + bool scene04_ladderClickable; + bool scene04_handIsDown; + bool scene04_dudeInBottle; + bool scene04_kozHeadRaised; + bool scene04_bottleIsDropped; + bool scene04_bigBallIn; + int scene04_bigBallCounter; + bool scene04_bigBallFromLeft; + bool scene04_clockCanGo; + bool scene04_objectIsTaken; + int scene04_springOffset; + StaticANIObject *scene04_lastKozyawka; + int scene04_springDelay; + + StaticANIObject *scene05_handle; + StaticANIObject *scene05_wacko; + StaticANIObject *scene05_bigHatch; + int scene05_wackoTicker; + int scene05_handleFlipper; + int scene05_floatersTicker; + + StaticANIObject *scene06_mumsy; + int scene06_manX; + int scene06_manY; + int scene06_ballX; + int scene06_ballY; + StaticANIObject *scene06_someBall; + StaticANIObject *scene06_invHandle; + StaticANIObject *scene06_liftButton; + StaticANIObject *scene06_ballDrop; + bool scene06_arcadeEnabled; + bool scene06_aimingBall; + StaticANIObject *scene06_currentBall; + StaticANIObject *scene06_ballInHands; + StaticANIObject *scene06_flyingBall; + Common::Array<StaticANIObject *> scene06_balls; + int scene06_numBallsGiven; + int scene06_mumsyNumBalls; + int scene06_eggieTimeout; + int scene06_eggieDirection; + int scene06_mumsyGotBall; + int scene06_ballDeltaX; + int scene06_ballDeltaY; + int scene06_sceneClickX; + int scene06_sceneClickY; + int scene06_mumsyPos; + BehaviorEntryInfo *scene06_mumsyJumpBk; + BehaviorEntryInfo *scene06_mumsyJumpFw; + int scene06_mumsyJumpBkPercent; + int scene06_mumsyJumpFwPercent; + + BehaviorEntryInfo *scene07_lukeAnim; + int scene07_lukePercent; + StaticANIObject *scene07_plusMinus; + + StaticANIObject *scene08_batuta; + StaticANIObject *scene08_vmyats; + StaticANIObject *scene08_clock; + bool scene08_inAir; + bool scene08_flyingUp; + int scene08_onBelly; + int scene08_stairsOffset; + int scene08_snoringCountdown; + bool scene08_inArcade; + bool scene08_stairsVisible; + int scene08_manOffsetY; + + int scene09_dudeY; + StaticANIObject *scene09_flyingBall; + int scene09_numSwallenBalls; + StaticANIObject *scene09_gulper; + StaticANIObject *scene09_spitter; + StaticANIObject *scene09_grit; + bool scene09_gulperIsPresent; + bool scene09_dudeIsOnLadder; + int scene09_interactingHanger; + int scene09_intHangerPhase; + int scene09_intHangerMaxPhase; + BallChain scene09_balls; + Common::Array<Hanger *> scene09_hangers; + BallChain scene09_flyingBalls; + int scene09_numMovingHangers; + int scene09_clickY; + Common::Point scene09_hangerOffsets[4]; + + StaticANIObject *scene10_gum; + StaticANIObject *scene10_packet; + StaticANIObject *scene10_packet2; + StaticANIObject *scene10_inflater; + PictureObject *scene10_ladder; + int scene10_hasGum; + + StaticANIObject *scene11_swingie; + StaticANIObject *scene11_boots; + StaticANIObject *scene11_dudeOnSwing; + PictureObject *scene11_hint; + MGM scene11_mgm; + bool scene11_arcadeIsOn; + bool scene11_scrollIsEnabled; + bool scene11_scrollIsMaximized; + int scene11_hintCounter; + int scene11_swingieScreenEdge; + int scene11_crySound; + double scene11_swingAngle; + double scene11_swingOldAngle; + double scene11_swingSpeed; + double scene11_swingAngleDiff; + double scene11_swingInertia; + int scene11_swingCounter; + int scene11_swingCounterPrevTurn; + int scene11_swingDirection; + int scene11_swingDirectionPrevTurn; + bool scene11_swingIsSwinging; + bool scene11_swingieStands; + int scene11_dudeX; + int scene11_dudeY; + int scene11_swingMaxAngle; + + int scene12_fly; + int scene12_flyCountdown; + + StaticANIObject *scene13_whirlgig; + StaticANIObject *scene13_guard; + StaticANIObject *scene13_handleR; + StaticANIObject *scene13_handleL; + StaticANIObject *scene13_bridge; + bool scene13_guardDirection; + int scene13_dudeX; + + StaticANIObject *scene14_grandma; + int scene14_sceneDeltaX; + int scene14_sceneDeltaY; + bool scene14_arcadeIsOn; + bool scene14_dudeIsKicking; + bool scene14_ballIsFlying; + bool scene14_dudeCanKick; + int scene14_sceneDiffX; + int scene14_sceneDiffY; + StaticANIObject *scene14_pink; + StaticANIObject *scene14_flyingBall; + Common::List<StaticANIObject *> scene14_balls; + bool scene14_grandmaIsHere; + int scene14_dudeX; + int scene14_dudeY; + int scene14_grandmaX; + int scene14_grandmaY; + int scene14_dude2X; + int scene14_ballDeltaX; + int scene14_ballDeltaY; + int scene14_ballX; + int scene14_ballY; + int scene14_hitsLeft; + Common::Point scene14_mouseCursorPos; + + int scene15_chantingCountdown; + StaticANIObject *scene15_plusminus; + PictureObject *scene15_ladder; + StaticANIObject *scene15_boot; + + Common::List<StaticANIObject *> scene16_figures; + StaticANIObject *scene16_walkingBoy; + StaticANIObject *scene16_walkingGirl; + int scene16_walkingCount; + StaticANIObject *scene16_wire; + StaticANIObject *scene16_mug; + StaticANIObject *scene16_jettie; + StaticANIObject *scene16_boot; + bool scene16_girlIsLaughing; + int scene16_sound; + bool scene16_placeIsOccupied; + + int scene17_flyState; + bool scene17_sugarIsShown; + int scene17_sceneOldEdgeX; + int scene17_flyCountdown; + StaticANIObject *scene17_hand; + bool scene17_handPhase; + int scene17_sceneEdgeX; + + bool scene18_inScene18p1; + StaticANIObject *scene18_whirlgig; + Common::Array<Swinger *> scene18_swingers; + int scene18_wheelCenterX; + int scene18_wheelCenterY; + bool scene18_bridgeIsConvoluted; + int scene18_whirlgigMovMum; + bool scene18_girlIsSwinging; + int scene18_rotationCounter; + int scene18_manY; + bool scene18_wheelFlipper; + bool scene18_wheelIsTurning; + int scene18_kidIsOnWheel; + int scene18_boyIsOnWheel; + int scene18_girlIsOnWheel; + bool scene18_boyJumpedOff; + int scene18_manWheelPos; + int scene18_manWheelPosTo; + int scene18_kidWheelPos; + int scene18_kidWheelPosTo; + int scene18_jumpDistance; + int scene18_jumpAngle; + bool scene18_manIsReady; + bool scene18_enteredTrubaRight; + StaticANIObject *scene18_boy; + StaticANIObject *scene18_girl; + StaticANIObject *scene18_domino; + int scene18_boyJumpX; + int scene18_boyJumpY; + int scene18_girlJumpX; + int scene18_girlJumpY; + + bool scene19_enteredTruba3; + + int scene20_fliesCountdown; + StaticANIObject *scene20_grandma; + + StaticANIObject *scene21_giraffeBottom; + int scene21_giraffeBottomX; + int scene21_giraffeBottomY; + int scene21_pipeIsOpen; + double scene21_wigglePos; + bool scene21_wiggleTrigger; + + StaticANIObject *scene22_bag; + StaticANIObject *scene22_giraffeMiddle; + bool scene22_dudeIsOnStool; + bool scene22_interactionIsDisabled; + bool scene22_craneIsOut; + int scene22_numBagFalls; + + StaticANIObject *scene23_calend0; + StaticANIObject *scene23_calend1; + StaticANIObject *scene23_calend2; + StaticANIObject *scene23_calend3; + bool scene23_topReached; + bool scene23_isOnStool; + int scene23_someVar; + StaticANIObject *scene23_giraffeTop; + StaticANIObject *scene23_giraffee; + + bool scene24_jetIsOn; + bool scene24_flowIsLow; + bool scene24_waterIsOn; + StaticANIObject *scene24_water; + StaticANIObject *scene24_jet; + StaticANIObject *scene24_drop; + + StaticANIObject *scene25_water; + StaticANIObject *scene25_board; + StaticANIObject *scene25_drop; + bool scene25_dudeIsOnBoard; + bool scene25_waterIsPresent; + bool scene25_boardIsSelectable; + bool scene25_beardersAreThere; + int scene25_beardersCounter; + Common::Array<StaticANIObject *> scene25_bearders; + bool scene25_sneezeFlipper; + + StaticANIObject *scene26_chhi; + StaticANIObject *scene26_drop; + PictureObject *scene26_sockPic; + StaticANIObject *scene26_sock; + StaticANIObject *scene26_activeVent; + + PictureObject *scene27_hitZone; + StaticANIObject *scene27_driver; + StaticANIObject *scene27_maid; + StaticANIObject *scene27_batHandler; + bool scene27_driverHasVent; + StaticANIObject *scene27_bat; + bool scene27_dudeIsAiming; + bool scene27_maxPhaseReached; + bool scene27_wipeIsNeeded; + bool scene27_driverPushedButton; + int scene27_numLostBats; + int scene27_knockCount; + int scene27_aimStartX; + int scene27_aimStartY; + int scene27_launchPhase; + BallChain scene27_balls; + Common::Array<Bat *> scene27_bats; + Common::Array<Bat *> scene27_var07; + + bool scene28_fliesArePresent; + bool scene28_beardedDirection; + PictureObject *scene28_darkeningObject; + PictureObject *scene28_lighteningObject; + bool scene28_headDirection; + bool scene28_headBeardedFlipper; + bool scene28_lift6inside; + + StaticANIObject *scene29_porter; + StaticANIObject *scene29_shooter1; + StaticANIObject *scene29_shooter2; + StaticANIObject *scene29_ass; + BallChain scene29_balls; + BallChain scene29_redBalls; + BallChain scene29_flyingRedBalls; + BallChain scene29_greenBalls; + bool scene29_manIsRiding; + bool scene29_arcadeIsOn; + bool scene29_reachedFarRight; + bool scene29_rideBackEnabled; + int scene29_shootCountdown; + int scene29_shootDistance; + int scene29_manIsHit; + int scene29_scrollSpeed; + bool scene29_scrollingDisabled; + int scene29_hitBall; + Common::Array<WalkingBearder *> scene29_bearders; + int scene29_manX; + int scene29_manY; + MGM scene29_mgm; + + StaticANIObject *scene30_leg; + int scene30_liftFlag; + + int scene31_chantingCountdown; + StaticANIObject *scene31_cactus; + StaticANIObject *scene31_plusMinus; + + bool scene32_flagIsWaving; + bool scene32_flagNeedsStopping; + bool scene32_dudeIsSitting; + int scene32_cactusCounter; + bool scene32_dudeOnLadder; + bool scene32_cactusIsGrowing; + StaticANIObject *scene32_flag; + StaticANIObject *scene32_cactus; + StaticANIObject *scene32_massOrange; + StaticANIObject *scene32_massBlue; + StaticANIObject *scene32_massGreen; + StaticANIObject *scene32_button; + + StaticANIObject *scene33_mug; + StaticANIObject *scene33_jettie; + StaticANIObject *scene33_cube; + int scene33_cubeX; + bool scene33_handleIsDown; + int scene33_ventsX[9]; + int scene33_ventsState[9]; + + StaticANIObject *scene34_cactus; + StaticANIObject *scene34_vent; + StaticANIObject *scene34_hatch; + StaticANIObject *scene34_boot; + bool scene34_dudeClimbed; + bool scene34_dudeOnBoard; + bool scene34_dudeOnCactus; + int scene34_fliesCountdown; + + StaticANIObject *scene35_hose; + StaticANIObject *scene35_bellyInflater; + int scene35_flowCounter; + int scene35_fliesCounter; + + StaticANIObject *scene36_rotohrust; + StaticANIObject *scene36_scissors; + + Common::Array<Ring *> scene37_rings; + int scene37_lastDudeX; + bool scene37_cursorIsLocked; + StaticANIObject *scene37_plusMinus1; + StaticANIObject *scene37_plusMinus2; + StaticANIObject *scene37_plusMinus3; + int scene37_soundFlipper; + int scene37_dudeX; + + StaticANIObject *scene38_boss; + StaticANIObject *scene38_tally; + StaticANIObject *scene38_shorty; + StaticANIObject *scene38_domino0; + StaticANIObject *scene38_dominos; + StaticANIObject *scene38_domino1; + StaticANIObject *scene38_bottle; + int scene38_bossCounter; + int scene38_lastBossAnim; + int scene38_bossAnimCounter; + int scene38_tallyCounter; + int scene38_lastTallyAnim; + int scene38_tallyAnimCounter; + int scene38_shortyCounter; + int scene38_lastShortyAnim; + int scene38_shortyAnimCounter; + + int sceneFinal_var01; + int sceneFinal_var02; + int sceneFinal_var03; + + PictureObject *selector; +}; + +struct Ring { + StaticANIObject *ani; + int x; + int y; + int numSubRings; + int subRings[10]; + bool state; + + Ring(); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_SCENES_H */ diff --git a/engines/fullpipe/scenes/scene01.cpp b/engines/fullpipe/scenes/scene01.cpp new file mode 100644 index 0000000000..e24eb1fa45 --- /dev/null +++ b/engines/fullpipe/scenes/scene01.cpp @@ -0,0 +1,118 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene01_fixEntrance() { + GameVar *var = g_fp->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME"); + if (var->getSubVarAsInt("Entrance") == TrubaLeft) + var->setSubVarAsInt("Entrance", TrubaRight); +} + +void scene01_initScene(Scene *sc, int entrance) { + g_vars->scene01_picSc01Osk = sc->getPictureObjectById(PIC_SC1_OSK, 0); + g_vars->scene01_picSc01Osk->_flags &= 0xFFFB; + + g_vars->scene01_picSc01Osk2 = sc->getPictureObjectById(PIC_SC1_OSK2, 0); + g_vars->scene01_picSc01Osk2->_flags &= 0xFFFB; + + if (g_fp->getObjectState(sO_EggCracker) == g_fp->getObjectEnumState(sO_EggCracker, sO_DidNotCrackEgg)) { + PictureObject *pic = sc->getPictureObjectById(PIC_SC1_KUCHKA, 0); + if (pic) + pic->_flags &= 0xFFFB; + } + + if (entrance != TrubaLeft) { + StaticANIObject *bootAnim = sc->getStaticANIObject1ById(ANI_BOOT_1, -1); + if (bootAnim) + bootAnim->_flags &= ~0x04; + } + + g_fp->lift_setButton(sO_Level2, ST_LBN_2N); +} + +int sceneHandler01(ExCommand *cmd) { + int res = 0; + + if (cmd->_messageKind != 17) + return 0; + + if (cmd->_messageNum > MSG_SC1_SHOWOSK) { + if (cmd->_messageNum == MSG_SC1_UTRUBACLICK) + handleObjectInteraction(g_fp->_aniMan, g_fp->_currentScene->getPictureObjectById(PIC_SC1_LADDER, 0), 0); + + return 0; + } + + if (cmd->_messageNum == MSG_SC1_SHOWOSK) { + g_vars->scene01_picSc01Osk->_flags |= 4; + + g_vars->scene01_picSc01Osk->_priority = 20; + g_vars->scene01_picSc01Osk2->_priority = 21; + + return 0; + } + + if (cmd->_messageNum != 0x21) { + if (cmd->_messageNum == MSG_SC1_SHOWOSK2) { + g_vars->scene01_picSc01Osk2->_flags |= 4; + g_vars->scene01_picSc01Osk2->_priority = 20; + g_vars->scene01_picSc01Osk->_priority = 21; + + return 0; + } + + return 0; + } + + if (g_fp->_aniMan2) { + if (g_fp->_aniMan2->_ox < g_fp->_sceneRect.left + 200) { + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.left - 300; + } + + if (g_fp->_aniMan2->_ox > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.right + 300; + + res = 1; + } + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + return res; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene02.cpp b/engines/fullpipe/scenes/scene02.cpp new file mode 100644 index 0000000000..fd542d580d --- /dev/null +++ b/engines/fullpipe/scenes/scene02.cpp @@ -0,0 +1,138 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" +#include "fullpipe/floaters.h" + + +namespace Fullpipe { + +void scene02_initScene(Scene *sc) { + g_vars->scene02_guvTheDrawer = sc->getStaticANIObject1ById(ANI_DADAYASHIK, -1); + + if (g_fp->getObjectState(sO_GuvTheDrawer) == g_fp->getObjectEnumState(sO_GuvTheDrawer, sO_IsSleeping)) { + Scene *s = g_fp->_currentScene; + + g_fp->_currentScene = sc; + g_vars->scene02_guvTheDrawer->changeStatics2(ST_DYAS_LIES); + g_fp->_currentScene = s; + } + + g_vars->scene02_boxDelay = 0; + + StaticANIObject *box = sc->getStaticANIObject1ById(ANI_SC2_BOX, -1); + + if (box && box->_flags & 4) { + g_vars->scene02_boxOpen = false; + } else { + g_vars->scene02_boxOpen = true; + g_vars->scene02_boxDelay = 100 * g_fp->_rnd->getRandomNumber(32767) + 150; + } + + g_fp->_floaters->init(g_fp->_gameLoader->_gameVar->getSubVarByName("SC_2")); +} + +void sceneHandler02_ladderClick() { + handleObjectInteraction(g_fp->_aniMan2, g_fp->_currentScene->getPictureObjectById(PIC_SC2_DTRUBA, 0), 0); +} + +void sceneHandler02_showLadder() { + g_fp->_currentScene->getPictureObjectById(PIC_SC2_LADDER, 0)->_flags |= 4; +} + +void sceneHandler02_hideLadder() { + g_fp->_currentScene->getPictureObjectById(PIC_SC2_LADDER, 0)->_flags &= 0xfffb; + g_fp->_aniMan2->_priority = 25; +} + +int sceneHandler02(ExCommand *ex) { + int res = 0; + + if (ex->_messageKind != 17) + return 0; + + switch(ex->_messageNum) { + case MSG_SC2_LADDERCLICK: + sceneHandler02_ladderClick(); + return 0; + + case MSG_SC2_SHOWLADDER: + sceneHandler02_showLadder(); + return 0; + + case MSG_SC2_PUTMANUP: + g_fp->_aniMan2->_priority = 0; + return 0; + + case MSG_SC2_HIDELADDER: + sceneHandler02_hideLadder(); + return 0; + + case 33: + if (g_fp->_aniMan2) { + if (g_fp->_aniMan2->_ox < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.left - 300; + + if (g_fp->_aniMan2->_ox > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.right + 300; + + res = 1; + } + + if (g_vars->scene02_boxOpen) { + if (g_vars->scene02_boxDelay >= 1) { + --g_vars->scene02_boxDelay; + } else if (g_fp->_floaters->_array2.size() >= 1) { + if (g_fp->_floaters->_array2[0]->val5 == -50) { + g_fp->_floaters->stopAll(); + g_vars->scene02_boxOpen = false; + g_vars->scene02_boxDelay = 100 * g_fp->_rnd->getRandomNumber(32767) + 150; + } else { + g_fp->_floaters->_array2[0]->val3 = -50; + } + } else { + g_fp->_floaters->genFlies(g_fp->_currentScene, g_fp->_rnd->getRandomNumber(700) + 100, -50, 0, 0); + g_vars->scene02_boxDelay = 500 * g_fp->_rnd->getRandomNumber(32767) + 1000; + } + } + + g_fp->_floaters->update(); + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + } + + return res; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene03.cpp b/engines/fullpipe/scenes/scene03.cpp new file mode 100644 index 0000000000..e6c9fa3bbd --- /dev/null +++ b/engines/fullpipe/scenes/scene03.cpp @@ -0,0 +1,295 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + +namespace Fullpipe { + +void FullpipeEngine::setSwallowedEggsState() { + GameVar *v = _gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_GulpedEggs); + + g_vars->swallowedEgg1 = v->getSubVarByName(sO_Egg1); + g_vars->swallowedEgg2 = v->getSubVarByName(sO_Egg2); + g_vars->swallowedEgg3 = v->getSubVarByName(sO_Egg3); + + g_vars->swallowedEgg1->_value.intValue = 0; + g_vars->swallowedEgg2->_value.intValue = 0; + g_vars->swallowedEgg3->_value.intValue = 0; +} + +void scene03_initScene(Scene *sc) { + g_vars->scene03_eggeater = sc->getStaticANIObject1ById(ANI_EGGEATER, -1); + g_vars->scene03_domino = sc->getStaticANIObject1ById(ANI_DOMINO_3, -1); + + GameVar *v = g_fp->_gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_GulpedEggs); + + g_vars->swallowedEgg1 = v->getSubVarByName(sO_Egg1); + g_vars->swallowedEgg2 = v->getSubVarByName(sO_Egg2); + g_vars->swallowedEgg3 = v->getSubVarByName(sO_Egg3); + + g_fp->lift_setButton(sO_Level2, ST_LBN_2N); + + g_fp->lift_init(sc, QU_SC3_ENTERLIFT, QU_SC3_EXITLIFT); +} + +void scene03_setEaterState() { + if (g_fp->getObjectState(sO_EggGulperGaveCoin) == g_fp->getObjectEnumState(sO_EggGulperGaveCoin, sO_Yes)) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene03_eggeater, ST_EGTR_SLIM, QU_EGTR_SLIMSHOW, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene03_eggeater, ST_EGTR_MID1, QU_EGTR_MD1_SHOW, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene03_eggeater, ST_EGTR_MID2, QU_EGTR_MD2_SHOW, 0); + } +} + +int scene03_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_cursorId == PIC_CSR_DEFAULT && g_fp->_objectIdAtCursor == PIC_SC3_DOMIN && g_vars->scene03_domino) { + if (g_vars->scene03_domino->_flags & 4) + g_fp->_cursorId = PIC_CSR_ITN; + } + + return g_fp->_cursorId; +} + +void sceneHandler03_eaterFat() { + g_vars->scene03_eggeater->_flags &= 0xFF7F; + + g_vars->scene03_eggeater->startAnim(MV_EGTR_FATASK, 0, -1); +} + +void sceneHandler03_swallowEgg(int item) { + if (!g_vars->swallowedEgg1->_value.intValue) { + g_vars->swallowedEgg1->_value.intValue = item; + } else if (!g_vars->swallowedEgg2->_value.intValue) { + g_vars->swallowedEgg2->_value.intValue = item; + } else if (!g_vars->swallowedEgg3->_value.intValue) { + g_vars->swallowedEgg3->_value.intValue = item; + + g_fp->setObjectState(sO_EggGulperGaveCoin, g_fp->getObjectEnumState(sO_EggGulperGaveCoin, sO_Yes)); + + scene03_setEaterState(); + } +} + +void sceneHandler03_giveItem(ExCommand *ex) { + if (ex->_parentId == ANI_INV_EGGAPL || ex->_parentId == ANI_INV_EGGDOM || + ex->_parentId == ANI_INV_EGGCOIN || ex->_parentId == ANI_INV_EGGBOOT || + ex->_parentId == ANI_INV_EGGGLS) + sceneHandler03_swallowEgg(ex->_parentId); +} + +int sceneHandler03_swallowedEgg1State() { + return g_vars->swallowedEgg1->_value.intValue; +} + +void sceneHandler03_giveCoin(ExCommand *ex) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(ex->_parId); + + if (mq && mq->getCount() > 0) { + ExCommand *ex0 = mq->getExCommandByIndex(0); + ExCommand *ex1 = mq->getExCommandByIndex(1); + + if (sceneHandler03_swallowedEgg1State()) { + ex0->_messageKind = 1; + ex1->_messageKind = 1; + + getGameLoaderInventory()->removeItem(ANI_INV_COIN, 1); + } else { + ex0->_messageKind = 0; + ex0->_excFlags |= 1; + + ex1->_messageKind = 0; + ex1->_excFlags |= 1; + + g_vars->scene03_eggeater->_flags &= 0xFF7Fu; + } + } +} + +void sceneHandler03_goLadder() { + handleObjectInteraction(g_fp->_aniMan, g_fp->_currentScene->getPictureObjectById(PIC_SC3_LADDER, 0), 0); +} + +void sceneHandler03_pushEggStack() { + g_vars->swallowedEgg1->_value.intValue = g_vars->swallowedEgg2->_value.intValue; + g_vars->swallowedEgg2->_value.intValue = g_vars->swallowedEgg3->_value.intValue; + g_vars->swallowedEgg3->_value.intValue = 0; + + if (g_vars->swallowedEgg2->_value.intValue == ANI_INV_EGGBOOT + && g_vars->swallowedEgg1->_value.intValue == ANI_INV_EGGAPL) { + g_vars->swallowedEgg1->_value.intValue = ANI_INV_EGGBOOT; + g_vars->swallowedEgg2->_value.intValue = ANI_INV_EGGAPL; + } +} + +void sceneHandler03_releaseEgg() { + g_vars->scene03_eggeater->_flags &= 0xFF7F; + + g_vars->scene03_eggeater->show1(-1, -1, -1, 0); +} + +void sceneHandler03_takeEgg(ExCommand *ex) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(ex->_parId); + + if (mq && mq->getCount() > 0) { + ExCommand *ex0 = mq->getExCommandByIndex(0); + ExCommand *ex1 = mq->getExCommandByIndex(1); + + int egg1 = sceneHandler03_swallowedEgg1State(); + + if (egg1 && ex0) { + ex0->_parentId = egg1; + sceneHandler03_pushEggStack(); + } + + if ( g_vars->swallowedEgg1->_value.intValue == ANI_INV_EGGAPL + && !g_vars->swallowedEgg2->_value.intValue + && !g_vars->swallowedEgg3->_value.intValue + && ex1) { + + if (ex1->_objtype == kObjTypeObjstateCommand) { + ObjstateCommand *com = (ObjstateCommand *)ex1; + + com->_value = g_fp->getObjectEnumState(sO_EggGulper, sO_WantsNothing); + } + } + } +} + +int sceneHandler03(ExCommand *ex) { + if (ex->_messageKind != 17) { + if (ex->_messageKind == 57) + sceneHandler03_giveItem(ex); + return 0; + } + + switch (ex->_messageNum) { + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(ex); + break; + + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_SC3_ONTAKECOIN: + sceneHandler03_eaterFat(); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_SC3_RELEASEEGG: + sceneHandler03_releaseEgg(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC3_HIDEDOMINO: + g_vars->scene03_domino->_flags &= 0xFFFB; + break; + + case MSG_SC3_TAKEEGG: + sceneHandler03_takeEgg(ex); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case MSG_SC3_UTRUBACLICK: + sceneHandler03_goLadder(); + break; + + case MSG_SC3_TESTFAT: + sceneHandler03_giveCoin(ex); + break; + + case 64: + g_fp->lift_hoverButton(ex); + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(ex->_sceneClickX, ex->_sceneClickY); + if (ani && ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_animateButton(ani); + ex->_messageKind = 0; + + return 0; + } + + if (g_fp->_currentScene->getPictureObjectIdAtPos(ex->_sceneClickX, ex->_sceneClickY) == PIC_SC3_DOMIN) { + if (g_vars->scene03_domino) + if (g_vars->scene03_domino->_flags & 4) + if (g_fp->_aniMan->isIdle()) + if (!(g_fp->_aniMan->_flags & 0x100) && g_fp->_msgObjectId2 != g_vars->scene03_domino->_id) { + handleObjectInteraction(g_fp->_aniMan, g_vars->scene03_domino, ex->_keyCode); + ex->_messageKind = 0; + + return 0; + } + } + + break; + } + + case 33: + { + int res = 0; + + if (g_fp->_aniMan2) { + if (g_fp->_aniMan2->_ox < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.left - 300; + + if (g_fp->_aniMan2->_ox > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.right + 300; + + res = 1; + } + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + return res; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene04.cpp b/engines/fullpipe/scenes/scene04.cpp new file mode 100644 index 0000000000..c0f0960aba --- /dev/null +++ b/engines/fullpipe/scenes/scene04.cpp @@ -0,0 +1,1565 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" +#include "fullpipe/utils.h" +#include "fullpipe/gfx.h" +#include "fullpipe/messages.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" +#include "fullpipe/scene.h" +#include "fullpipe/interaction.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/behavior.h" + +namespace Fullpipe { + +static const int scene04_speakerPhases[] = { + 0, 1, 2, 3, -1, -1, + 0, 2, 3, -1, -1, -1, + 0, 2, -1, -1, -1, -1 +}; + +void scene04_speakerCallback(int *phase) { + if (g_vars->scene04_soundPlaying) { + if (g_vars->scene04_speakerPhase >= 0) { + *phase = scene04_speakerPhases[g_vars->scene04_speakerPhase + 6 * g_vars->scene04_speakerVariant]; + + g_vars->scene04_speakerPhase++; + + if (scene04_speakerPhases[g_vars->scene04_speakerPhase + 6 * g_vars->scene04_speakerVariant] < 0) { + g_vars->scene04_speakerPhase = 0; + g_vars->scene04_speakerVariant = g_fp->_rnd->getRandomNumber(2); + } + } else { + ++g_vars->scene04_speakerPhase; + } + } +} + +void scene04_initScene(Scene *sc) { + g_vars->scene04_dudeOnLadder = false; + g_vars->scene04_bottle = sc->getPictureObjectById(PIC_SC4_BOTTLE, 0); + g_vars->scene04_hand = sc->getStaticANIObject1ById(ANI_HAND, -1); + g_vars->scene04_plank = sc->getStaticANIObject1ById(ANI_PLANK, -1); + g_vars->scene04_clock = sc->getStaticANIObject1ById(ANI_CLOCK, -1); + g_vars->scene04_spring = sc->getStaticANIObject1ById(ANI_SPRING, -1); + g_vars->scene04_mamasha = sc->getStaticANIObject1ById(ANI_MAMASHA_4, -1); + g_vars->scene04_boot = sc->getStaticANIObject1ById(ANI_SC4_BOOT, -1); + g_vars->scene04_ladder = 0; + + StaticANIObject *koz = sc->getStaticANIObject1ById(ANI_KOZAWKA, -1); + + if (koz) { + Movement *kozmov = koz->getMovementById(MV_KZW_JUMP); + if (kozmov) { + uint kozsize = kozmov->_currMovement ? kozmov->_currMovement->_dynamicPhases.size() : kozmov->_dynamicPhases.size(); + + for (uint i = 0; i < kozsize; i++) { + kozmov->setDynamicPhaseIndex(i); + + if (kozmov->_framePosOffsets) { + g_vars->scene04_jumpingKozyawki[i] = *kozmov->_framePosOffsets[kozmov->_currDynamicPhaseIndex]; + } else { + kozmov->_somePoint.x = 0; + kozmov->_somePoint.y = 0; + g_vars->scene04_jumpingKozyawki[i] = kozmov->_somePoint; + } + } + } + + kozmov = koz->getMovementById(MV_KZW_JUMPROTATE); + if (kozmov) { + uint kozsize = kozmov->_currMovement ? kozmov->_currMovement->_dynamicPhases.size() : kozmov->_dynamicPhases.size(); + + for (uint i = 0; i < kozsize; i++) { + kozmov->setDynamicPhaseIndex(i); + + if (kozmov->_framePosOffsets) { + g_vars->scene04_jumpRotateKozyawki[i] = *kozmov->_framePosOffsets[kozmov->_currDynamicPhaseIndex]; + } else { + kozmov->_somePoint.x = 0; + kozmov->_somePoint.y = 0; + g_vars->scene04_jumpRotateKozyawki[i] = kozmov->_somePoint; + } + } + } + } + + Interaction *plank = getGameLoaderInteractionController()->getInteractionByObjectIds(ANI_PLANK, 0, 0); + if (plank) + plank->_flags |= 8; + + if (g_fp->getObjectState(sO_Jar_4) == g_fp->getObjectEnumState(sO_Jar_4, sO_UpsideDown)) { + g_vars->scene04_bottleObjList.clear(); + g_vars->scene04_kozyawkiObjList.clear(); + + sc->getPictureObjectById(PIC_SC4_BOTTLE, 0)->_flags &= 0xfffb; + sc->getPictureObjectById(PIC_SC4_MASK, 0)->_flags &= 0xfffb; + sc->getStaticANIObject1ById(ANI_SPRING, 0)->_flags &= 0xfffb; + + g_vars->scene04_clockCanGo = false; + g_vars->scene04_objectIsTaken = false; + } else { + StaticANIObject *spring = sc->getStaticANIObject1ById(ANI_SPRING, -1); + + if (spring) + spring->_callback2 = 0; + + g_vars->scene04_bottleObjList.clear(); + g_vars->scene04_bottleObjList.push_back(sc->getPictureObjectById(PIC_SC4_BOTTLE, 0)); + g_vars->scene04_bottleObjList.push_back(sc->getPictureObjectById(PIC_SC4_MASK, 0)); + + g_vars->scene04_kozyawkiObjList.clear(); + + if (koz) { + koz->loadMovementsPixelData(); + + koz->_statics = koz->getStaticsById(ST_KZW_EMPTY); + koz->setOXY(0, 0); + koz->hide(); + + g_vars->scene04_kozyawkiObjList.push_back(koz); + + for (int i = 0; i < 6; i++) { + StaticANIObject *koz1 = new StaticANIObject(koz); + + sc->addStaticANIObject(koz1, 1); + koz1->_statics = koz->getStaticsById(ST_KZW_EMPTY); + koz1->setOXY(0, 0); + koz1->hide(); + g_vars->scene04_kozyawkiObjList.push_back(koz1); + } + } + sc->getPictureObjectById(PIC_SC4_BOTTLE2, 0)->_flags &= 0xfffb; + + g_vars->scene04_clockCanGo = true; + g_vars->scene04_objectIsTaken = true; + } + + g_vars->scene04_bottleIsTaken = false; + g_vars->scene04_soundPlaying = false; + g_vars->scene04_kozyawkaOnLadder = false; + g_vars->scene04_walkingKozyawka = 0; + g_vars->scene04_bottleWeight = 2; + g_vars->scene04_dynamicPhaseIndex = 0; + + g_vars->scene04_kozyawkiAni.clear(); + + g_fp->setObjectState(sO_LowerPipe, g_fp->getObjectEnumState(sO_LowerPipe, sO_IsClosed)); + + g_vars->scene04_var07 = false; + g_vars->scene04_ladderClickable = false; + g_vars->scene04_coinPut = false; + g_vars->scene04_handIsDown = false; + g_vars->scene04_dudeInBottle = false; + g_vars->scene04_kozHeadRaised = false; + g_vars->scene04_bottleIsDropped = false; + g_vars->scene04_bigBallIn = true; + g_vars->scene04_bigBallCounter = 0; + g_vars->scene04_bigBallFromLeft = true; + + if (g_fp->getObjectState(sO_BigMumsy) != g_fp->getObjectEnumState(sO_BigMumsy, sO_IsGone)) + g_vars->scene04_mamasha->hide(); + + g_vars->scene04_speaker = sc->getStaticANIObject1ById(ANI_SPEAKER_4, -1); + g_vars->scene04_speaker->_callback2 = scene04_speakerCallback; + g_vars->scene04_speaker->startAnim(MV_SPK4_PLAY, 0, -1); + + g_vars->scene04_speakerVariant = 0; + g_vars->scene04_speakerPhase = 0; + + g_fp->initArcadeKeys("SC_4"); +} + +bool sceneHandler04_friesAreWalking() { + if (g_vars->scene04_dudeOnLadder && g_fp->_aniMan->isIdle() && !(g_fp->_aniMan->_flags & 0x100)) { + int col = g_vars->scene04_ladder->collisionDetection(g_fp->_aniMan); + if (col >= 3 && col <= 6 ) { + Movement *koz; + + if (!g_vars->scene04_walkingKozyawka + || (koz = g_vars->scene04_walkingKozyawka->_movement) == 0 + || koz->_id != MV_KZW_WALKPLANK + || koz->_currDynamicPhaseIndex < 10 + || koz->_currDynamicPhaseIndex > 41) + return true; + } + } + + return false; +} + +int scene04_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_objectIdAtCursor == PIC_SC4_LRTRUBA) { + if (!g_vars->scene04_objectIsTaken) { + g_fp->_cursorId = PIC_CSR_DEFAULT; + + return g_fp->_cursorId; + } + } else if (g_fp->_objectIdAtCursor == ANI_PLANK || g_fp->_objectIdAtCursor == PIC_SC4_PLANK) { + if (g_fp->_objectIdAtCursor == ANI_PLANK && g_fp->_cursorId != PIC_CSR_ITN) + return g_fp->_cursorId; + + if (g_fp->_objectIdAtCursor == ANI_PLANK || (g_fp->_objectIdAtCursor == PIC_SC4_PLANK && g_fp->_cursorId == PIC_CSR_DEFAULT)) { + if (sceneHandler04_friesAreWalking()) { + g_fp->_cursorId = PIC_CSR_ARCADE1; + return g_fp->_cursorId; + } + if (g_vars->scene04_soundPlaying) { + g_fp->_cursorId = PIC_CSR_DEFAULT; + return g_fp->_cursorId; + } + } + } + + if (g_fp->_objectIdAtCursor == PIC_CSR_ITN && g_fp->_objectIdAtCursor == PIC_SC4_DOWNTRUBA) + g_fp->_cursorId = PIC_CSR_GOD; + + return g_fp->_cursorId; +} + +void sceneHandler04_checkBigBallClick() { + StaticANIObject *ball = g_fp->_currentScene->getStaticANIObject1ById(ANI_BIGBALL, -1); + + if (ball) + for (uint i = 0; i < ball->_movements.size(); i++) + ((Movement *)ball->_movements[i])->_counterMax = 73; + + g_vars->scene04_bigBallIn = true; +} + +void sceneHandler04_clickBottle() { + if (!g_vars->scene04_bottleIsTaken) + g_vars->scene04_springOffset += 5; +} + +void sceneHandler04_clickButton() { + StaticANIObject *but = g_fp->_currentScene->getStaticANIObject1ById(ANI_BUTTON, -1); + + if (but) { + if (!g_vars->scene04_clock->_movement || + (g_vars->scene04_clock->_movement->_id == MV_CLK_GO && g_vars->scene04_clock->_movement->_currDynamicPhaseIndex > 3 && + g_vars->scene04_clock->_movement->_currDynamicPhaseIndex < 105)) { + if (!g_vars->scene04_hand->_movement && !g_vars->scene04_bottleIsTaken) { + but->startAnim(MV_BTN_CLICK, 0, -1); + g_vars->scene04_hand->startAnim(MV_HND_POINT, 0, -1); + } + } + } +} + +void sceneHandler04_downLadder(int x, int y) { + g_vars->scene04_ladder->startMove(g_fp->_aniMan, x + g_vars->scene04_ladder->_ladder_field_20, y + g_vars->scene04_ladder->_ladder_field_24, 0, 0); +} + +void sceneHandler04_walkClimbLadder(ExCommand *ex) { + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + ExCommand *ex1 = new ExCommand(ANI_MAN, 1, MV_MAN_TOLADDER, 0, 0, 0, 1, 0, 0, 0); + + ex1->_keyCode = g_fp->_aniMan->_okeyCode; + ex1->_excFlags |= 2; + + mq->addExCommandToEnd(ex1); + + ExCommand *ex2 = new ExCommand(ANI_MAN, 1, MV_MAN_STOPLADDER, 0, 0, 0, 1, 0, 0, 0); + + ex2->_keyCode = g_fp->_aniMan->_okeyCode; + ex2->_excFlags |= 2; + + mq->addExCommandToEnd(ex2); + + ExCommand *ex3; + + if (ex) { + ex3 = ex->createClone(); + } else { + ex3 = new ExCommand(0, 17, MSG_SC4_CLICKLADDER, 0, 0, 0, 1, 0, 0, 0); + ex3->_excFlags |= 3; + } + + mq->addExCommandToEnd(ex3); + + mq->setFlags(mq->getFlags() | 1); + + mq->chain(0); + + g_vars->scene04_dudeOnLadder = 1; + + g_vars->scene04_ladder = new MctlLadder; + g_vars->scene04_ladder->_ladderX = 1089; + g_vars->scene04_ladder->_ladderY = 406; + g_vars->scene04_ladder->_ladder_field_14 = 12; + g_vars->scene04_ladder->_width = 0; + g_vars->scene04_ladder->_height = -40; + g_vars->scene04_ladder->_ladder_field_20 = 0; + g_vars->scene04_ladder->_ladder_field_24 = -60; + + g_vars->scene04_ladder->attachObject(g_fp->_aniMan); + + if (g_vars->scene04_soundPlaying) { + g_vars->scene04_ladder->_ladmovements.front()->movVars->varUpStart = MV_MAN_STARTLADDER2; + g_vars->scene04_ladder->_ladmovements.front()->movVars->varUpGo = MV_MAN_GOLADDER2; + g_vars->scene04_ladder->_ladmovements.front()->movVars->varUpStop = MV_MAN_STOPLADDER2; + g_vars->scene04_ladder->_ladmovements.front()->staticIds[2] = ST_MAN_GOLADDER2; + } else { + g_vars->scene04_ladder->_ladmovements.front()->movVars->varUpStart = MV_MAN_STARTLADDER; + g_vars->scene04_ladder->_ladmovements.front()->movVars->varUpGo = MV_MAN_GOLADDER; + g_vars->scene04_ladder->_ladmovements.front()->movVars->varUpStop = MV_MAN_STOPLADDER; + g_vars->scene04_ladder->_ladmovements.front()->staticIds[2] = ST_MAN_GOLADDER; + } + + g_fp->_aniMan->_priority = 12; + + getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); +} + +void sceneHandler04_clickLadder() { + g_vars->scene04_dudePosX = g_fp->_aniMan->_ox; + g_vars->scene04_dudePosY = g_fp->_aniMan->_oy; + + if (g_vars->scene04_dudeOnLadder) { + if (!g_fp->_aniMan->isIdle() || (g_fp->_aniMan->_flags & 0x100)) { + g_vars->scene04_ladderClickable = true; + } else { + int h3 = 3 * g_vars->scene04_ladder->_height; + int half = abs(g_vars->scene04_ladder->_height) / 2; + int start = g_vars->scene04_ladder->_ladderY - g_vars->scene04_ladder->_ladder_field_24; + int min = 2 * h3 + start + half + 1; + int max = h3 + start - half - 1; + + if (g_vars->scene04_sceneClickY > max) + g_vars->scene04_sceneClickY = max; + + if (g_vars->scene04_sceneClickY < min) + g_vars->scene04_sceneClickY = min; + + sceneHandler04_downLadder(g_vars->scene04_sceneClickX, g_vars->scene04_sceneClickY); + + g_vars->scene04_ladderClickable = false; + } + } else { + if (g_fp->_aniMan->isIdle() && !(g_fp->_aniMan->_flags & 0x100)) { + if (abs(1095 - g_vars->scene04_dudePosX) > 1 || abs(434 - g_vars->scene04_dudePosY) > 1) { + MessageQueue *mq = getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->startMove(g_fp->_aniMan, 1095, 434, 1, ST_MAN_UP); + if (mq) { + ExCommand *ex = new ExCommand(0, 17, MSG_SC4_CLICKLADDER, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags = 3; + mq->addExCommandToEnd(ex); + + postExCommand(g_fp->_aniMan->_id, 2, 1095, 434, 0, -1); + } + } else { + sceneHandler04_walkClimbLadder(0); + } + } + } +} + +void sceneHandler04_jumpOnLadder() { + if (g_fp->_aniMan->_movement && g_fp->_aniMan->_movement->_id != MV_MAN_LOOKLADDER) + return; + + if (g_fp->_aniMan->_statics->_staticsId != ST_MAN_STANDLADDER && g_fp->_aniMan->_statics->_staticsId != ST_MAN_LADDERDOWN) + return; + + g_fp->_aniMan->changeStatics2(ST_MAN_LADDERDOWN); + + g_fp->_aniMan->_flags |= 1; + + MGM mgm; + MGMInfo mgminfo; + + mgm.addItem(ANI_MAN); + + mgminfo.ani = g_fp->_aniMan; + mgminfo.staticsId2 = ST_MAN_ONPLANK; + mgminfo.x1 = 938; + mgminfo.y1 = 442; + mgminfo.field_1C = 10; + mgminfo.field_10 = 1; + mgminfo.flags = 78; + mgminfo.movementId = MV_MAN_JUMPONPLANK; + + MessageQueue *mq = mgm.genMovement(&mgminfo); + + if (mq) { + mq->_flags |= 1; + + if (!mq->chain(g_fp->_aniMan)) + delete mq; + + g_fp->_aniMan->_priority = 10; + } + + g_vars->scene04_ladderOffset = g_vars->scene04_ladder->collisionDetection(g_fp->_aniMan); +} + +void sceneHandler04_clickPlank() { + if (sceneHandler04_friesAreWalking()) + sceneHandler04_jumpOnLadder(); + else if (g_vars->scene04_dudeOnLadder) + g_fp->playSound(SND_4_033, 0); + else if (!g_vars->scene04_soundPlaying) + chainQueue(QU_PNK_CLICK, 0); +} + +void sceneHandler04_dropBottle() { + g_vars->scene04_bottleIsDropped = true; + g_vars->scene04_bottleY = 10; + g_vars->scene04_bottleWeight = 0; + + while (g_vars->scene04_kozyawkiAni.size()) { + StaticANIObject *koz = g_vars->scene04_kozyawkiAni.front(); + g_vars->scene04_kozyawkiAni.pop_front(); + + for (Common::List<GameObject *>::iterator it = g_vars->scene04_bottleObjList.begin(); it != g_vars->scene04_bottleObjList.end(); ++it) + if (*it == koz) { + g_vars->scene04_bottleObjList.erase(it); + break; + } + + koz->queueMessageQueue(0); + koz->hide(); + + g_vars->scene04_kozyawkiObjList.push_back(koz); + } + + g_vars->scene04_hand->changeStatics2(ST_HND_EMPTY); + + g_vars->scene04_hand->setOXY(429, 21); + g_vars->scene04_hand->_priority = 15; +} + +void sceneHandler04_gotoLadder(ExCommand *ex) { + MGM mgm; + MGMInfo mgminfo; + + mgm.addItem(ANI_MAN); + + mgminfo.ani = g_fp->_aniMan; + mgminfo.staticsId2 = ST_MAN_UP; + mgminfo.x1 = 1095; + mgminfo.y1 = 434; + mgminfo.field_1C = 12; + mgminfo.field_10 = 1; + mgminfo.flags = 78; + mgminfo.movementId = MV_MAN_PLANKTOLADDER; + + MessageQueue *mq = mgm.genMovement(&mgminfo); + + if (mq) { + mq->deleteExCommandByIndex(mq->getCount() - 1, 1); + + ExCommand *ex1 = new ExCommand(ANI_MAN, 1, MV_MAN_TOLADDER, 0, 0, 0, 1, 0, 0, 0); + ex1->_excFlags = 2; + ex1->_field_24 = 1; + ex1->_keyCode = -1; + mq->addExCommandToEnd(ex1); + + ExCommand *ex2 = new ExCommand(ANI_MAN, 1, MV_MAN_STOPLADDER, 0, 0, 0, 1, 0, 0, 0); + ex2->_excFlags = 2; + ex2->_field_24 = 1; + ex2->_keyCode = -1; + mq->addExCommandToEnd(ex2); + + ExCommand *ex3 = new ExCommand(g_fp->_aniMan->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); + ex3->_field_14 = 256; + ex3->_messageNum = 0; + ex3->_excFlags |= 3; + mq->addExCommandToEnd(ex3); + + if (ex) { + ExCommand *ex4 = ex->createClone(); + + mq->addExCommandToEnd(ex4); + } + + mq->setFlags(mq->getFlags() | 1); + + if (mq->chain(g_fp->_aniMan)) { + g_fp->_aniMan->_priority = 12; + g_fp->_aniMan->_flags |= 1; + } else { + delete mq; + } + } + + g_vars->scene04_kozyawkaOnLadder = false; +} + +void sceneHandler04_lowerPlank() { + g_vars->scene04_plank->startAnim(MV_PNK_WEIGHTRIGHT, 0, -1); +} + +void sceneHandler04_manFromBottle() { + for (Common::List<GameObject *>::iterator it = g_vars->scene04_bottleObjList.begin(); it != g_vars->scene04_bottleObjList.end(); ++it) + if (*it == g_fp->_aniMan) { + g_vars->scene04_bottleObjList.erase(it); + g_vars->scene04_bottleWeight -= 9; + break; + } + + if (g_vars->scene04_ladder) + delete g_vars->scene04_ladder; + + g_vars->scene04_ladder = 0; + + getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->activate(); + getGameLoaderInteractionController()->enableFlag24(); +} + +void sceneHandler04_manToBottle() { + g_vars->scene04_bottleObjList.push_back(g_fp->_aniMan); + g_vars->scene04_springOffset = 5; + g_vars->scene04_bottleWeight += 9; + g_fp->_aniMan2 = g_fp->_aniMan; + g_vars->scene04_dudeInBottle = 1; +} + +void sceneHandler04_raisePlank() { + g_vars->scene04_plank->startAnim(MV_PNK_WEIGHTLEFT, 0, -1); +} + +MessageQueue *sceneHandler04_kozFly3(StaticANIObject *ani, double phase) { + MGM mgm; + MGMInfo mgminfo; + + mgm.addItem(ANI_KOZAWKA); + + mgminfo.ani = ani; + mgminfo.staticsId2 = ST_KZW_SIT; + mgminfo.x1 = (int)(723.0 - phase * 185.0); + mgminfo.y1 = 486; + mgminfo.field_1C = 10; + mgminfo.field_10 = 1; + mgminfo.flags = 78; + mgminfo.movementId = MV_KZW_JUMP; + + MessageQueue *mq = mgm.genMovement(&mgminfo); + + if (mq) { + ExCommand *ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_STANDUP, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_TURN, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + + for (int i = 0; i < 5; i++) { + ex = new ExCommand(ANI_KOZAWKA, 1, rMV_KZW_GOR, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + } + + ex = new ExCommand(ANI_KOZAWKA, 6, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_KOZAWKA, 17, MSG_KOZAWRESTART, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + } + + return mq; +} + +MessageQueue *sceneHandler04_kozFly5(StaticANIObject *ani, double phase) { + MGM mgm; + MGMInfo mgminfo; + + mgm.addItem(ANI_KOZAWKA); + + mgminfo.ani = ani; + mgminfo.staticsId2 = ST_KZW_JUMPOUT; + mgminfo.x1 = 525; + mgminfo.y1 = (int)(344.0 - (double)(320 - g_vars->scene04_bottle->_oy) * phase); + mgminfo.field_1C = 10; + mgminfo.field_10 = 1; + mgminfo.flags = 78; + mgminfo.movementId = MV_KZW_JUMPHIT; + + MessageQueue *mq1 = mgm.genMovement(&mgminfo); + + memset(&mgminfo, 0, sizeof(mgminfo)); + mgminfo.ani = ani; + mgminfo.staticsId1 = ST_KZW_JUMPOUT; + mgminfo.staticsId2 = ST_KZW_SIT; + mgminfo.x2 = 525; + mgminfo.y2 = (int)(344.0 - (double)(320 - g_vars->scene04_bottle->_oy) * phase); + mgminfo.y1 = 486; + mgminfo.field_1C = 10; + mgminfo.field_10 = 1; + mgminfo.flags = 117; + mgminfo.movementId = MV_KZW_JUMPOUT; + + MessageQueue *mq2 = mgm.genMovement(&mgminfo); + + if (mq1 && mq2) { + mq1->addExCommandToEnd(mq2->getExCommandByIndex(0)->createClone()); + + delete mq2; + mq2 = 0; + + ExCommand *ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_STANDUP, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq1->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_TURN, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq1->addExCommandToEnd(ex); + + for (int i = 0; i < 5; i++) { + ex = new ExCommand(ANI_KOZAWKA, 1, rMV_KZW_GOR, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq1->addExCommandToEnd(ex); + } + + ex = new ExCommand(ANI_KOZAWKA, 6, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_keyCode = ani->_okeyCode; + mq1->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_KOZAWKA, 17, MSG_KOZAWRESTART, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_keyCode = ani->_okeyCode; + mq1->addExCommandToEnd(ex); + } + + if (mq2) + delete mq2; + + return mq1; +} + +MessageQueue *sceneHandler04_kozFly6(StaticANIObject *ani) { + MGM mgm; + MGMInfo mgminfo; + + mgm.addItem(ANI_KOZAWKA); + + mgminfo.ani = ani; + mgminfo.staticsId2 = ST_KZW_SIT; + mgminfo.x1 = 397 - 4 * g_fp->_rnd->getRandomNumber(1); + mgminfo.field_1C = ani->_priority; + mgminfo.y1 = g_vars->scene04_bottle->_oy - 4 * g_fp->_rnd->getRandomNumber(1) + 109; + mgminfo.field_10 = 1; + mgminfo.flags = 78; + mgminfo.movementId = MV_KZW_JUMPROTATE; + + MessageQueue *mq = mgm.genMovement(&mgminfo); + + if (mq) { + mq->deleteExCommandByIndex(mq->getCount() - 1, 1); + + ExCommand *ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_STANDUP, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_GOR, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_RAISEHEAD, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + + g_vars->scene04_kozHeadRaised = true; + } + + return mq; +} + +void sceneHandler04_kozMove(Movement *mov, int from, int to, Common::Point *points, double phase) { + for (int i = from; i < to; i++) { + mov->setDynamicPhaseIndex(i); + + Common::Point *p; + if (mov->_framePosOffsets) { + p = mov->_framePosOffsets[mov->_currDynamicPhaseIndex]; + } else { + p = &mov->_somePoint; + p->x = 0; + p->y = 0; + } + + p->y = (int)((double)points[i].y * phase); + } +} + +MessageQueue *sceneHandler04_kozFly7(StaticANIObject *ani, double phase) { + MGM mgm; + MGMInfo mgminfo; + + mgm.addItem(ANI_KOZAWKA); + + mgminfo.ani = ani; + mgminfo.staticsId2 = 560; + mgminfo.x1 = (int)(250.0 - phase * 100.0); + mgminfo.y1 = 455; + mgminfo.field_1C = 10; + mgminfo.field_10 = 1; + mgminfo.flags = 78; + mgminfo.movementId = MV_KZW_JUMPROTATE; + + MessageQueue *mq = mgm.genMovement(&mgminfo); + + if (mq) { + sceneHandler04_kozMove(ani->getMovementById(MV_KZW_JUMPROTATE), 1, 9, g_vars->scene04_jumpRotateKozyawki, phase * 0.5 + 1.5); + + ani->_priority = 10; + + ExCommand *ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_STANDUP, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_TURN, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + + for (int i = 0; i < 2; i++) { + ex = new ExCommand(ANI_KOZAWKA, 1, rMV_KZW_GOR, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + } + + ex = new ExCommand(ANI_KOZAWKA, 6, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_KOZAWKA, 17, MSG_KOZAWRESTART, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_keyCode = ani->_okeyCode; + mq->addExCommandToEnd(ex); + } + + return mq; +} + +static const int kozTrajectory3[] = { + 3, 2, 0, + 3, 2, 0, + 3, 2, 0 +}; + +static const int kozTrajectory4[] = { + 5, 3, 1, + 5, 4, 1, + 5, 3, 1 +}; + +static const int kozTrajectory5[] = { + 6, 5, 4, + 6, 5, 4, + 6, 5, 4 +}; + +static const int kozTrajectory6[] = { + 7, 6, 5, + 7, 6, 5, + 7, 6, 5 +}; + +void sceneHandler04_shootKozyawka() { + g_vars->scene04_plank->changeStatics2(ST_PNK_WEIGHTRIGHT); + + if (!g_vars->scene04_walkingKozyawka) + return; + + if (g_vars->scene04_walkingKozyawka->_movement) { + if (g_vars->scene04_walkingKozyawka->_movement->_id == MV_KZW_WALKPLANK) { + int dphase = g_vars->scene04_walkingKozyawka->_movement->_currDynamicPhaseIndex; + + if (dphase < 41) { + int col = 3 * dphase / 15; + if (col > 2) + col = 2; + + int row = g_vars->scene04_kozyawkiAni.size(); + if (row > 2) + row = 2; + + int idx = 3 * row + col; + int phase; + + if (g_vars->scene04_ladderOffset == 3) { + phase = kozTrajectory3[idx]; + } else if (g_vars->scene04_ladderOffset == 4) { + phase = kozTrajectory4[idx]; + } else { + if (g_vars->scene04_ladderOffset == 5) + phase = kozTrajectory5[idx]; + else + phase = kozTrajectory6[idx]; + } + + g_vars->scene04_walkingKozyawka->queueMessageQueue(0); + g_vars->scene04_walkingKozyawka->_movement = 0; + g_vars->scene04_walkingKozyawka->_statics = g_vars->scene04_walkingKozyawka->getStaticsById(ST_KZW_RIGHT); + + MessageQueue *mq; + + if (phase > 2) { + if (phase > 5) { + if (phase == 6) + mq = sceneHandler04_kozFly6(g_vars->scene04_walkingKozyawka); + else + mq = sceneHandler04_kozFly7(g_vars->scene04_walkingKozyawka, (double)(phase - 6) * 0.3333333333333333); + } else { + mq = sceneHandler04_kozFly5(g_vars->scene04_walkingKozyawka, (double)(phase - 2) * 0.3333333333333333); + } + } else { + mq = sceneHandler04_kozFly3(g_vars->scene04_walkingKozyawka, (double)phase * 0.5); + } + + if (mq) { + g_vars->scene04_lastKozyawka = g_vars->scene04_walkingKozyawka; + + if (!mq->chain(g_vars->scene04_walkingKozyawka) ) + delete mq; + } + } + } + } + + if (g_vars->scene04_ladderOffset > 3) + g_fp->_aniMan->changeStatics1(ST_MAN_LOOKPLANK); + + g_vars->scene04_kozyawkaOnLadder = true; +} + +void sceneHandler04_showCoin() { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_SC4_COIN, -1); + + if (ani) { + ani->show1(MV_BDG_OPEN, MV_MAN_GOU, MV_SC4_COIN_default, 0); + + ani->_priority = 40; + } +} + +void sceneHandler04_stopSound() { + g_vars->scene04_soundPlaying = false; + + warning("STUB: sceneHandler04_stopSound()"); +} + +void sceneHandler04_animOutOfBottle(ExCommand *ex) { + g_fp->_aniMan->changeStatics2(ST_MAN_SIT); + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC4_MANFROMBOTTLE), 0, 0); + + if (ex) { + ExCommand *newex = ex->createClone(); + + mq->addExCommandToEnd(newex); + } + + mq->_flags |= 1; + mq->chain(0); + + g_vars->scene04_dudeInBottle = false; + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); +} + +void sceneHandler04_walkKozyawka() { + if (g_vars->scene04_kozyawkiObjList.size()) { + g_vars->scene04_walkingKozyawka = g_vars->scene04_kozyawkiObjList.front(); + g_vars->scene04_kozyawkiObjList.pop_front(); + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_KOZAW_WALK), 0, 1); + mq->replaceKeyCode(-1, g_vars->scene04_walkingKozyawka->_okeyCode); + mq->chain(0); + } +} + +void sceneHandler04_bottleUpdateObjects(int off) { + for (Common::List<GameObject *>::iterator it = g_vars->scene04_bottleObjList.begin(); it != g_vars->scene04_bottleObjList.end(); ++it) { + GameObject *obj = *it; + + obj->setOXY(obj->_ox, off + obj->_oy); + } +} + +void sceneHandler04_springWobble() { + int oldDynIndex = g_vars->scene04_dynamicPhaseIndex; + int newdelta = g_vars->scene04_springOffset + g_vars->scene04_dynamicPhaseIndex; + + g_vars->scene04_dynamicPhaseIndex += g_vars->scene04_springOffset; + + if (newdelta < 0) { + newdelta = 0; + g_vars->scene04_dynamicPhaseIndex = 0; + g_vars->scene04_springOffset = 0; + } + + if (newdelta > 14) { + newdelta = 14; + g_vars->scene04_dynamicPhaseIndex = 14; + g_vars->scene04_springOffset = 0; + } + + if (g_vars->scene04_bottleWeight > newdelta) + g_vars->scene04_springOffset++; + + if (g_vars->scene04_bottleWeight < newdelta) + g_vars->scene04_springOffset--; + + if ((oldDynIndex <= g_vars->scene04_bottleWeight && newdelta > g_vars->scene04_bottleWeight) || newdelta <= g_vars->scene04_bottleWeight) { + g_vars->scene04_springDelay++; + + if (g_vars->scene04_springOffset && g_vars->scene04_springDelay > 1) { + g_vars->scene04_springDelay = 0; + g_vars->scene04_springOffset = g_vars->scene04_springOffset - g_vars->scene04_springOffset / abs(g_vars->scene04_springOffset); + } + } + + Common::Point point; + + int oldpos = g_vars->scene04_spring->getCurrDimensions(point)->y - oldDynIndex; + + if (g_vars->scene04_dynamicPhaseIndex) { + if (!g_vars->scene04_spring->_movement) + g_vars->scene04_spring->startAnim(MV_SPR_LOWER, 0, -1); + + g_vars->scene04_spring->_movement->setDynamicPhaseIndex(g_vars->scene04_dynamicPhaseIndex); + } else { + g_vars->scene04_spring->changeStatics2(ST_SPR_UP); + } + + if (g_vars->scene04_dynamicPhaseIndex != oldDynIndex) { + sceneHandler04_bottleUpdateObjects(oldpos - (g_vars->scene04_spring->getCurrDimensions(point)->y - g_vars->scene04_dynamicPhaseIndex)); + } +} + +void sceneHandler04_leaveScene() { + g_fp->_aniMan2 = 0; + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC4_MANTOBOTTLE), 0, 0); + ExCommand *ex = 0; + + for (uint i = 0; i < mq->getCount(); i++) { + if (mq->getExCommandByIndex(i)->_messageKind == 27) { + ex = mq->getExCommandByIndex(i); + break; + } + } + + if (!ex) { + error("sceneHandler04_leaveScene(): Cannot find exit"); + } + + ex->_y = g_vars->scene04_bottle->_oy - 304; + + mq->chain(0); + + g_vars->scene04_var07 = false; + g_vars->scene04_dudeOnLadder = 0; + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + + g_fp->updateMapPiece(PIC_MAP_P03, 1); +} + +void sceneHandler04_liftBottle() { + int newy = g_vars->scene04_bottleY + g_vars->scene04_spring->_oy; + + g_vars->scene04_bottleY += 5; + + sceneHandler04_bottleUpdateObjects(newy - g_vars->scene04_spring->_oy); + + g_vars->scene04_spring->setOXY(g_vars->scene04_spring->_ox, newy); + + if (g_vars->scene04_bottle->_oy >= 226) { + sceneHandler04_bottleUpdateObjects(226 - g_vars->scene04_bottle->_oy); + + g_vars->scene04_spring->setOXY(g_vars->scene04_spring->_ox, 437); + g_vars->scene04_bottleIsDropped = false; + g_vars->scene04_handIsDown = false; + g_vars->scene04_objectIsTaken = true; + g_vars->scene04_bottleWeight = 2; + g_vars->scene04_springOffset = 10; + g_vars->scene04_bottleIsTaken = false; + + g_fp->setObjectState(sO_LowerPipe, g_fp->getObjectEnumState(sO_LowerPipe, sO_IsClosed)); + } +} + +void sceneHandler04_startSounds(const char *snd1, const char *snd2, const char *snd3) { + warning("STUB: sceneHandler04_startSounds()"); + + // playFile(snd1); + // playFile(snd2); + // playFile(snd3); +} + +void sceneHandler04_goClock() { + sceneHandler04_walkKozyawka(); + chainQueue(QU_SC4_GOCLOCK, 0); + g_vars->scene04_soundPlaying = true; + g_vars->scene04_coinPut = false; + + g_fp->stopAllSoundStreams(); + + sceneHandler04_startSounds("sc4_start.ogg", "sc4_loop.ogg", "sc4_stop2.ogg"); + + g_vars->scene04_bigBallCounter = 0; +} + +void sceneHandler04_bigBallOut() { + StaticANIObject *ball = g_fp->_currentScene->getStaticANIObject1ById(ANI_BIGBALL, -1); + + if (ball && ball->_flags & 4) + for (uint i = 0; i < ball->_movements.size(); i++) + ((Movement *)ball->_movements[i])->_counterMax = 0; + + g_vars->scene04_bigBallIn = false; +} + +void sceneHandler04_leaveLadder(ExCommand *ex) { + if (!g_fp->_aniMan->isIdle()) + return; + + if (!(g_fp->_aniMan->_flags & 0x100)) { + if (getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->_objtype == kObjTypeMctlCompound) { + MctlCompound *mc = (MctlCompound *)getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId); + + if (mc->_motionControllers[0]->_movGraphReactObj->pointInRegion(g_fp->_sceneRect.left + ex->_x, g_fp->_sceneRect.top + ex->_y)) { + if (g_vars->scene04_ladder->collisionDetection(g_fp->_aniMan)) { + MessageQueue *mq = g_vars->scene04_ladder->controllerWalkTo(g_fp->_aniMan, 0); + + if (mq) { + mq->addExCommandToEnd(ex->createClone()); + + if (mq->chain(g_fp->_aniMan) ) + ex->_messageKind = 0; + else + delete mq; + + if (g_vars->scene04_bigBallIn) { + sceneHandler04_bigBallOut(); + return; + } + } + } else { + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + ExCommand *ex1; + + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN_LADDERDOWN) { + ex1 = new ExCommand(ANI_MAN, 1, MV_MAN_LOOKLADDERRV, 0, 0, 0, 1, 0, 0, 0); + ex1->_keyCode = g_fp->_aniMan->_okeyCode; + ex1->_excFlags |= 2; + mq->addExCommandToEnd(ex1); + } + + ex1 = new ExCommand(ANI_MAN, 1, MV_MAN_STARTLADDERD, 0, 0, 0, 1, 0, 0, 0); + ex1->_keyCode = g_fp->_aniMan->_okeyCode; + ex1->_excFlags |= 2; + mq->addExCommandToEnd(ex1); + + ex1 = new ExCommand(ANI_MAN, 1, MV_MAN_FROMLADDER, 0, 0, 0, 1, 0, 0, 0); + ex1->_keyCode = g_fp->_aniMan->_okeyCode; + ex1->_excFlags |= 2; + mq->addExCommandToEnd(ex1); + + ex1 = ex->createClone(); + mq->addExCommandToEnd(ex1); + + mq->setFlags(mq->getFlags() | 1); + + if (mq->chain(g_fp->_aniMan)) { + if (g_vars->scene04_ladder) + delete g_vars->scene04_ladder; + + g_vars->scene04_ladder = 0; + g_vars->scene04_dudeOnLadder = 0; + + ex->_messageKind = 0; + + mc->activate(); + getGameLoaderInteractionController()->enableFlag24(); + } else { + delete mq; + } + + if (g_vars->scene04_bigBallIn) { + sceneHandler04_bigBallOut(); + return; + } + } + } + } + } +} + +void sceneHandler04_handTake() { + g_vars->scene04_clock->changeStatics2(ST_CLK_CLOSED); + + if (g_vars->scene04_kozyawkiAni.size()) { + if (g_vars->scene04_kozyawkiAni.size() == 1) { + chainQueue(QU_HND_TAKE1, 0); + g_vars->scene04_objectIsTaken = false; + } else { + chainQueue((g_vars->scene04_kozyawkiAni.size() != 2) ? QU_HND_TAKEBOTTLE : QU_HND_TAKE2, 0); + g_vars->scene04_objectIsTaken = false; + } + } else { + chainQueue(QU_HND_TAKE0, 0); + g_vars->scene04_objectIsTaken = false; + } +} + +void sceneHandler04_putKozyawkaBack(StaticANIObject *ani) { + g_vars->scene04_bottleObjList.push_back(ani); + g_vars->scene04_kozyawkiAni.push_back(ani); + + g_vars->scene04_bottleWeight += 2; + g_vars->scene04_walkingKozyawka = 0; + g_vars->scene04_lastKozyawka = 0; + + if (g_vars->scene04_kozyawkiAni.size() > 1 ) + g_vars->scene04_objectIsTaken = false; + + if (g_vars->scene04_kozyawkiAni.size() <= 2 || g_vars->scene04_hand->_movement) { + sceneHandler04_walkKozyawka(); + } else { + sceneHandler04_handTake(); + sceneHandler04_stopSound(); + } +} + +void sceneHandler04_bigBallWalkIn() { + StaticANIObject *ball = g_fp->_currentScene->getStaticANIObject1ById(ANI_BIGBALL, -1); + + if (g_vars->scene04_dudeOnLadder + && (!ball || !(ball->_flags & 4)) + && g_vars->scene04_ladder->collisionDetection(g_fp->_aniMan) > 3) { + + if (!g_fp->_rnd->getRandomNumber(49)) { + if (g_vars->scene04_bigBallFromLeft) + chainQueue(QU_BALL_WALKR, 0); + else + chainQueue(QU_BALL_WALKL, 0); + + g_vars->scene04_bigBallFromLeft = !g_vars->scene04_bigBallFromLeft; + + sceneHandler04_checkBigBallClick(); + + g_vars->scene04_bigBallCounter = 0; + } + } +} + +void sceneHandler04_takeBottle() { + g_vars->scene04_bottleIsTaken = true; + g_vars->scene04_hand->_priority = 5; + + g_fp->setObjectState(sO_LowerPipe, g_fp->getObjectEnumState(sO_LowerPipe, sO_IsOpened)); +} + +void sceneHandler04_takeKozyawka() { + if (g_vars->scene04_kozyawkiAni.size() > 0) { + if (g_vars->scene04_kozyawkiAni.size() == 1) + g_vars->scene04_objectIsTaken = true; + + StaticANIObject *koz = g_vars->scene04_kozyawkiAni.front(); + g_vars->scene04_kozyawkiAni.pop_front(); + + if (koz) { + koz->queueMessageQueue(0); + koz->hide(); + + g_vars->scene04_kozyawkiObjList.push_back(koz); + + for (Common::List<GameObject *>::iterator it = g_vars->scene04_bottleObjList.begin(); it != g_vars->scene04_bottleObjList.end(); ++it) + if (*it == koz) { + g_vars->scene04_bottleObjList.erase(it); + break; + } + + g_vars->scene04_bottleWeight -= 2; + } + } +} + +void sceneHandler04_testPlank(ExCommand *ex) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(ex->_parId); + + if (!mq) + return; + + if (g_vars->scene04_plank->_movement || !g_vars->scene04_plank->_statics || g_vars->scene04_plank->_statics->_staticsId != ST_PNK_WEIGHTLEFT) { + mq->getExCommandByIndex(0)->_messageNum = MV_KZW_TOHOLERV; + } else { + mq->getExCommandByIndex(0)->_messageNum = MV_KZW_WALKPLANK; + } +} + +void sceneHandler04_updateBottle() { + Common::Point point; + + int yoff; + + if (g_vars->scene04_hand->_movement) + yoff = g_vars->scene04_hand->_movement->_oy; + else + yoff = g_vars->scene04_hand->_oy; + + int newy = g_vars->scene04_hand->getSomeXY(point)->y + yoff + 140; + + sceneHandler04_bottleUpdateObjects(newy - g_vars->scene04_spring->_oy); + + g_vars->scene04_spring->setOXY(g_vars->scene04_spring->_ox, newy); +} + +void sceneHandler04_winArcade() { + if (g_fp->getObjectState(sO_LowerPipe) == g_fp->getObjectEnumState(sO_LowerPipe, sO_IsClosed) + && g_vars->scene04_soundPlaying) { + g_vars->scene04_clock->changeStatics2(ST_CLK_CLOSED); + g_vars->scene04_hand->changeStatics2(ST_HND_EMPTY); + + chainQueue(QU_HND_TAKEBOTTLE, 1); + + if (g_vars->scene04_walkingKozyawka) { + g_vars->scene04_kozyawkiObjList.push_back(g_vars->scene04_walkingKozyawka); + + g_vars->scene04_walkingKozyawka->changeStatics2(ST_KZW_EMPTY); + g_vars->scene04_walkingKozyawka->hide(); + g_vars->scene04_walkingKozyawka = 0; + } + + g_vars->scene04_objectIsTaken = false; + g_vars->scene04_soundPlaying = false; + + getSc2MctlCompoundBySceneId(g_fp->_currentScene->_sceneId)->activate(); + + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->stopSoundStream2(); + } +} + +int sceneHandler04(ExCommand *ex) { + if (ex->_messageKind != 17) + return 0; + + switch (ex->_messageNum) { + case MSG_UPDATEBOTTLE: + sceneHandler04_updateBottle(); + break; + + case MSG_CLICKBOTTLE: + sceneHandler04_clickBottle(); + break; + + case MSG_SHOOTKOZAW: + sceneHandler04_shootKozyawka(); + break; + + case MSG_SHAKEBOTTLE: + if (!g_vars->scene04_bottleIsTaken) + ++g_vars->scene04_springOffset; + break; + + case MSG_STARTHAND: + g_vars->scene04_handIsDown = true; + g_vars->scene04_coinPut = false; + + if (g_vars->scene04_dudeInBottle) + sceneHandler04_animOutOfBottle(0); + + sceneHandler04_handTake(); + sceneHandler04_stopSound(); + break; + + case MSG_TAKEKOZAW: + sceneHandler04_takeKozyawka(); + break; + + case MSG_CLICKBUTTON: + sceneHandler04_clickButton(); + break; + + case MSG_CLICKPLANK: + sceneHandler04_clickPlank(); + break; + + case MSG_RAISEPLANK: + sceneHandler04_raisePlank(); + break; + + case MSG_KOZAWRESTART: + if (g_vars->scene04_walkingKozyawka) { + g_vars->scene04_kozyawkiObjList.push_back(g_vars->scene04_walkingKozyawka); + g_vars->scene04_walkingKozyawka->hide(); + g_vars->scene04_walkingKozyawka = 0; + } + + if (g_vars->scene04_soundPlaying) + sceneHandler04_walkKozyawka(); + + break; + + case MSG_LOWERPLANK: + sceneHandler04_lowerPlank(); + break; + + case MSG_TESTPLANK: + sceneHandler04_testPlank(ex); + break; + + case 33: + { + g_vars->scene04_dudePosX = g_fp->_aniMan->_ox; + g_vars->scene04_dudePosY = g_fp->_aniMan->_oy; + + int res = 0; + + if (g_fp->_aniMan2) { + if (g_fp->_aniMan->_ox < g_fp->_sceneRect.left + 200) { + g_fp->_currentScene->_x = g_fp->_aniMan->_ox - g_fp->_sceneRect.left - 300; + g_fp->_aniMan->_ox = g_vars->scene04_dudePosX; + } + if (g_fp->_aniMan->_ox > g_fp->_sceneRect.right - 200) { + g_fp->_currentScene->_x = g_fp->_aniMan->_ox - g_fp->_sceneRect.right + 300; + } + + res = 1; + + if (g_vars->scene04_soundPlaying) { + if (g_fp->_aniMan->_movement) { + if (g_fp->_aniMan->_movement->_id == MV_MAN_TOLADDER) { + g_fp->_aniMan2 = 0; + + if (g_fp->_sceneRect.left > 380) + g_fp->_currentScene->_x = 380 - g_fp->_sceneRect.left; + } + } + } + } else { + if (g_fp->_aniMan->_movement && g_fp->_aniMan->_movement->_id == MV_MAN_GOD) + g_fp->_aniMan2 = g_fp->_aniMan; + } + + sceneHandler04_springWobble(); + + if (g_vars->scene04_var07 && !g_vars->scene04_handIsDown) + sceneHandler04_leaveScene(); + + if (g_vars->scene04_bottleIsDropped) + sceneHandler04_liftBottle(); + + if (g_vars->scene04_ladderClickable) + sceneHandler04_clickLadder(); + + if (g_vars->scene04_dudeInBottle && g_vars->scene04_hand->_movement) + sceneHandler04_animOutOfBottle(0); + + if (g_vars->scene04_coinPut && g_vars->scene04_clockCanGo && !g_vars->scene04_handIsDown && !g_vars->scene04_soundPlaying) + sceneHandler04_goClock(); + + if (g_vars->scene04_dudeOnLadder) { + if (!g_vars->scene04_soundPlaying) { + g_fp->startSceneTrack(); + + g_fp->_behaviorManager->updateBehaviors(); + return res; + } + + g_vars->scene04_bigBallCounter++; + + if (g_vars->scene04_bigBallCounter > 600) + sceneHandler04_bigBallWalkIn(); + } + + if (g_vars->scene04_soundPlaying) { + g_fp->_behaviorManager->updateBehaviors(); + + return res; + } + + g_fp->startSceneTrack(); + + g_fp->_behaviorManager->updateBehaviors(); + + return res; + } + + case 29: + { + int picid = g_fp->_currentScene->getPictureObjectIdAtPos(ex->_sceneClickX, ex->_sceneClickY); + + if (g_vars->scene04_dudeInBottle) { + sceneHandler04_animOutOfBottle(ex); + + break; + } + + if (picid == PIC_SC4_LADDER) { + if (!g_vars->scene04_kozyawkaOnLadder) { + g_vars->scene04_sceneClickX = ex->_sceneClickX; + g_vars->scene04_sceneClickY = ex->_sceneClickY; + + sceneHandler04_clickLadder(); + + ex->_messageKind = 0; + + break; + } + + sceneHandler04_gotoLadder(0); + + break; + } + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(ex->_sceneClickX, ex->_sceneClickY); + + if ((ani && ani->_id == ANI_PLANK) || picid == PIC_SC4_PLANK) { + sceneHandler04_clickPlank(); + + ex->_messageKind = 0; + } else if (g_vars->scene04_dudeOnLadder) { + sceneHandler04_leaveLadder(ex); + } else if (!ani || !canInteractAny(g_fp->_aniMan, ani, ex->_keyCode)) { + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picid, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic,ex->_keyCode)) { + if ((g_fp->_sceneRect.right - ex->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (ex->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) + g_fp->processArcade(ex); + } + } + } + + break; + + case MSG_SC4_HIDEBOOT: + g_vars->scene04_boot->_flags &= 0xfffb; + break; + + case MSG_CMN_WINARCADE: + sceneHandler04_winArcade(); + break; + + case MSG_SC4_HANDOVER: + g_vars->scene04_handIsDown = false; + g_vars->scene04_objectIsTaken = true; + break; + + case MSG_SC4_DROPBOTTLE: + sceneHandler04_dropBottle(); + break; + + case MSG_SC4_COINOUT: + g_vars->scene04_clock->changeStatics2(ST_CLK_CLOSED); + g_vars->scene04_coinPut = false; + sceneHandler04_stopSound(); + + if (g_vars->scene04_kozyawkiAni.size() && !g_vars->scene04_bottleIsTaken) { + g_vars->scene04_handIsDown = true; + + if (g_vars->scene04_dudeInBottle) + sceneHandler04_animOutOfBottle(0); + + sceneHandler04_handTake(); + } + + break; + + case MSG_SC4_KOZAWFALL: + { + ExCommand *exnew; + + if (g_vars->scene04_kozHeadRaised) { + sceneHandler04_putKozyawkaBack(g_vars->scene04_lastKozyawka); + + g_vars->scene04_kozHeadRaised = 0; + + exnew = new ExCommand(0, 35, SND_4_010, 0, 0, 0, 1, 0, 0, 0); + } else { + exnew = new ExCommand(0, 35, SND_4_012, 0, 0, 0, 1, 0, 0, 0); + } + + exnew->_field_14 = 5; + exnew->_excFlags |= 2; + exnew->postMessage(); + break; + } + + case MSG_SC4_MANFROMBOTTLE: + sceneHandler04_manFromBottle(); + break; + + case MSG_SC4_CLICKLADDER: + sceneHandler04_clickLadder(); + break; + + case MSG_SC4_MANTOBOTTLE: + sceneHandler04_manToBottle(); + break; + + case MSG_SHOWCOIN: + sceneHandler04_showCoin(); + break; + + case MSG_TAKEBOTTLE: + sceneHandler04_takeBottle(); + break; + + case MSG_GOTOLADDER: + sceneHandler04_gotoLadder(0); + break; + + case MSG_SC4_COINPUT: + g_vars->scene04_coinPut = true; + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene05.cpp b/engines/fullpipe/scenes/scene05.cpp new file mode 100644 index 0000000000..8864794691 --- /dev/null +++ b/engines/fullpipe/scenes/scene05.cpp @@ -0,0 +1,386 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" +#include "fullpipe/statics.h" +#include "fullpipe/scene.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/messages.h" +#include "fullpipe/floaters.h" +#include "fullpipe/behavior.h" + +namespace Fullpipe { + +void scene05_initScene(Scene *sc) { + g_vars->scene05_handle = sc->getStaticANIObject1ById(ANI_HANDLE, -1); + g_vars->scene05_wacko = sc->getStaticANIObject1ById(ANI_OTMOROZ, -1); + g_vars->scene05_bigHatch = sc->getStaticANIObject1ById(ANI_BIGLUK, -1); + + + g_vars->scene05_wackoTicker = 0; + g_vars->scene05_handleFlipper = 1; + g_vars->scene05_floatersTicker = 1000; + + Scene *oldscene = g_fp->_currentScene; + + g_fp->_currentScene = sc; + + if (g_fp->getObjectState(sO_WeirdWacko) == g_fp->getObjectEnumState(sO_WeirdWacko, sO_InGlasses)) { + g_vars->scene05_wacko->changeStatics2(ST_OTM_GLS_LEFT); + g_vars->scene05_bigHatch->changeStatics2(ST_BLK_CLOSED); + + g_vars->scene05_handle->changeStatics2(ST_HDL_UP); + g_vars->scene05_handle->_flags |= 4; + } else if (g_fp->getObjectState(sO_WeirdWacko) == g_fp->getObjectEnumState(sO_WeirdWacko, sO_WithDrawer)) { + g_vars->scene05_wacko->changeStatics2(ST_OTM_BOX_LEFT); + g_vars->scene05_bigHatch->changeStatics2(ST_BLK_CLOSED); + g_vars->scene05_handle->changeStatics2(ST_HDL_UP); + g_vars->scene05_handle->_flags |= 4; + } else { + g_vars->scene05_wacko->changeStatics2(ST_OTM_VNT_LEFT); + + if (g_fp->getObjectState(sO_WeirdWacko) != g_fp->getObjectEnumState(sO_WeirdWacko, sO_WithPlunger)) { + g_vars->scene05_handle->changeStatics2(ST_HDL_BROKEN); + g_vars->scene05_bigHatch->changeStatics2(ST_BLK_CLOSED); + } + } + + g_fp->_currentScene = oldscene; +} + +void sceneHandler05_makeManFlight() { + int qid; + + if (!g_vars->scene05_bigHatch->_statics || g_vars->scene05_bigHatch->_statics->_staticsId != ST_BLK_OPEN) + qid = QU_SC5_MANBUMP; + else + qid = QU_SC5_MANFLY; + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(qid), 0, 0); + + mq->setFlags(mq->getFlags() | 1); + + mq->chain(0); +} + +void sceneHandler05_makeWackoFeedback() { + int staticsId1; + int staticsId2; + + if (g_fp->getObjectState(sO_WeirdWacko) == g_fp->getObjectEnumState(sO_WeirdWacko, sO_InGlasses)) { + staticsId1 = ST_OTM_GLS_LEFT; + staticsId2 = (g_vars->scene05_handle->_statics->_staticsId == ST_HDL_DOWN) ? MV_OTM_HANDLEUP : MV_OTM_HANDLEDOWN; + } else if (g_fp->getObjectState(sO_WeirdWacko) != g_fp->getObjectEnumState(sO_WeirdWacko, sO_WithDrawer)) { + return; + } else { + staticsId1 = ST_OTM_BOX_LEFT; + staticsId2 = (g_vars->scene05_handle->_statics->_staticsId == ST_HDL_DOWN) ? MV_OTM_BOXHANDLEUP : MV_OTM_BOXHANDLEDOWN; + } + + if (g_vars->scene05_wacko->_movement) + g_vars->scene05_wacko->changeStatics2(g_vars->scene05_wacko->_movement->_staticsObj2->_staticsId); + + if (staticsId1 == g_vars->scene05_wacko->_statics->_staticsId) { + g_vars->scene05_wacko->startAnim(staticsId2, 0, -1); + } else { + MessageQueue *mq = g_vars->scene05_wacko->changeStatics1(staticsId1); + + if (mq) { + mq->setFlags(mq->getFlags() | 1); + + ExCommand *ex = new ExCommand(0, 17, MSG_SC5_MAKEOTMFEEDBACK, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags |= 2; + + mq->addExCommandToEnd(ex); + mq->_isFinished = 0; + } + } +} + +void sceneHandler05_resetTicks() { + if (g_fp->_aniMan->_movement && (g_fp->_aniMan->_movement->_id == MV_MANHDL_HANDLEUP + || g_fp->_aniMan->_movement->_id == MV_MANHDL_HANDLEDOWN)) + g_vars->scene05_wackoTicker = g_fp->_updateTicks; + else + g_vars->scene05_wackoTicker = 0; +} + +void sceneHandler05_genFlies() { + if (g_vars->scene05_floatersTicker <= 1000) + return; + + if (g_fp->_rnd->getRandomNumber(1)) { + int numFlies = g_fp->_rnd->getRandomNumber(3) + 1; + + for (int i = 0; i < numFlies; i++) { + int x = g_fp->_rnd->getRandomNumber(55) + 538; + int y = g_fp->_rnd->getRandomNumber(60) + i * 30 + 520; + + g_fp->_floaters->genFlies(g_fp->_currentScene, x, y, 5, 1); + g_fp->_floaters->_array2.back()->val2 = 585; + g_fp->_floaters->_array2.back()->val3 = -70; + g_fp->_floaters->_array2.back()->val11 = 8.0; + } + } + + g_vars->scene05_floatersTicker = 0; +} + +void sceneHandler05_showHandle() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_HANDLE, -1)->show1(-1, -1, -1, 0); +} + +void sceneHandler05_handleDown() { + StaticANIObject *hatch = g_fp->_currentScene->getStaticANIObject1ById(ANI_BIGLUK, -1); + + hatch->changeStatics2(ST_BLK_CLOSED); + hatch->startAnim(MV_BLK_OPEN, 0, -1); + + sceneHandler05_resetTicks(); + sceneHandler05_genFlies(); +} + +void sceneHandler05_hideHandle() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_HANDLE, -1)->hide(); +} + +void sceneHandler05_handleUp() { + StaticANIObject *hatch = g_fp->_currentScene->getStaticANIObject1ById(ANI_BIGLUK, -1); + + hatch->changeStatics2(ST_BLK_OPEN); + hatch->startAnim(MV_BLK_CLOSE, 0, -1); + + sceneHandler05_resetTicks(); +} + +void sceneHandler05_testHatch(ExCommand *inex) { + ExCommand *ex; + + if (g_fp->_currentScene->getStaticANIObject1ById(ANI_BIGLUK, -1)->_statics->_staticsId == ST_BLK_CLOSED) { + ex = new ExCommand(SC_5, 17, 61, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = TrubaLeft; + ex->_excFlags |= 2; + ex->postMessage(); + + return; + } + + StaticANIObject *wacko = g_fp->_currentScene->getStaticANIObject1ById(ANI_OTMOROZ, -1); + + if (wacko->_movement) + wacko->changeStatics2(wacko->_movement->_staticsObj2->_staticsId); + + if (g_fp->getObjectState(sO_WeirdWacko) == g_fp->getObjectEnumState(sO_WeirdWacko, sO_InGlasses)) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(inex->_parId); + + if (mq) + mq->deleteExCommandByIndex(mq->getCount() - 1, 1); + + if (wacko->_statics->_staticsId != ST_OTM_GLS_LEFT) { + mq = wacko->changeStatics1(ST_OTM_GLS_LEFT); + + if (!mq) { + wacko->changeStatics2(ST_OTM_GLS_LEFT); + mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + } + + mq->setFlags(mq->getFlags() | 1); + + ex = new ExCommand(ANI_OTMOROZ, 1, MV_OTM_HANDLEUP, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2u; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(SC_5, 17, 61, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = TrubaLeft; + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + mq->_isFinished = 0; + return; + } + + mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + mq->setFlags(mq->getFlags() | 1); + + ex = new ExCommand(ANI_OTMOROZ, 1, MV_OTM_HANDLEUP, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(SC_5, 17, 61, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = TrubaLeft; + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + if (!mq->chain(wacko)) + delete mq; + } else if (g_fp->getObjectState(sO_WeirdWacko) == g_fp->getObjectEnumState(sO_WeirdWacko, sO_WithDrawer)) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(inex->_parId); + + if (mq) + mq->deleteExCommandByIndex(mq->getCount() - 1, 1); + + if (wacko->_statics->_staticsId != ST_OTM_BOX_LEFT) { + mq = wacko->changeStatics1(ST_OTM_BOX_LEFT); + if (!mq) { + wacko->changeStatics2(ST_OTM_BOX_LEFT); + mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + } + + mq->setFlags(mq->getFlags() | 1); + + ex = new ExCommand(ANI_OTMOROZ, 1, MV_OTM_BOXHANDLEUP, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(SC_5, 17, 61, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = TrubaLeft; + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + mq->_isFinished = 0; + + return; + } + + mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + mq->setFlags(mq->getFlags() | 1); + + ex = new ExCommand(ANI_OTMOROZ, 1, MV_OTM_BOXHANDLEUP, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(SC_5, 17, 61, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = TrubaLeft; + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + if (!mq->chain(wacko)) + delete mq; + + return; + } else { + ex = new ExCommand(SC_5, 17, 61, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = TrubaLeft; + ex->_excFlags |= 2; + ex->postMessage(); + + return; + } +} + + +int sceneHandler05(ExCommand *ex) { + if (ex->_messageKind != 17) + return 0; + + switch (ex->_messageNum) { + case MSG_SC5_BGRSOUNDOFF: + g_fp->stopAllSoundInstances(SND_5_026); + break; + + case MSG_SC5_BGRSOUNDON: + g_fp->playSound(SND_5_026, 1); + break; + + case MSG_SC5_MAKEMANFLIGHT: + sceneHandler05_makeManFlight(); + break; + + case MSG_SC5_MAKEOTMFEEDBACK: + if (!g_fp->_aniMan->_movement || (g_fp->_aniMan->_movement->_id != MV_MANHDL_HANDLEUP + && g_fp->_aniMan->_movement->_id != MV_MANHDL_HANDLEDOWN)) { + sceneHandler05_makeWackoFeedback(); + g_vars->scene05_wackoTicker = 0; + } + break; + + case MSG_SC5_SHOWHANDLE: + sceneHandler05_showHandle(); + break; + + case MSG_SC5_HANDLEDOWN: + g_vars->scene05_handle->changeStatics2(ST_HDL_DOWN); + sceneHandler05_handleDown(); + break; + + case MSG_SC5_HIDEHANDLE: + sceneHandler05_hideHandle(); + break; + + case MSG_SC5_HANDLEUP: + g_vars->scene05_handle->changeStatics2(ST_HDL_UP); + sceneHandler05_handleUp(); + break; + + case MSG_SC5_TESTLUK: + sceneHandler05_testHatch(ex); + break; + + case 33: + { + int res = 0; + if (g_fp->_aniMan2) { + if (g_fp->_aniMan2->_ox < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.left - 300; + + if (g_fp->_aniMan2->_ox > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.right + 300; + + res = 1; + } + + if (g_vars->scene05_wackoTicker) { + if ((g_fp->_updateTicks - g_vars->scene05_wackoTicker) > 62) { + if (!g_fp->_aniMan->_movement || (g_fp->_aniMan->_movement->_id != MV_MANHDL_HANDLEUP + && g_fp->_aniMan->_movement->_id != MV_MANHDL_HANDLEDOWN)) { + if (g_vars->scene05_handleFlipper % 2) + sceneHandler05_makeWackoFeedback(); + + g_vars->scene05_wackoTicker = 0; + + ++g_vars->scene05_handleFlipper; + } + } + } + + ++g_vars->scene05_floatersTicker; + + g_fp->_floaters->update(); + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + return res; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene06.cpp b/engines/fullpipe/scenes/scene06.cpp new file mode 100644 index 0000000000..e9cecc42f0 --- /dev/null +++ b/engines/fullpipe/scenes/scene06.cpp @@ -0,0 +1,770 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" +#include "fullpipe/gfx.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" +#include "fullpipe/scene.h" +#include "fullpipe/messages.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/behavior.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +void scene06_initMumsy() { + g_vars->scene06_mumsyJumpFw = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene06_mumsy, ST_MOM_STANDS, QU_MOM_JUMPFW); + g_vars->scene06_mumsyJumpBk = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene06_mumsy, ST_MOM_STANDS, QU_MOM_JUMPBK); + g_vars->scene06_mumsyJumpFwPercent = g_vars->scene06_mumsyJumpFw->_percent; + g_vars->scene06_mumsyJumpBkPercent = g_vars->scene06_mumsyJumpBk->_percent; +} + +int scene06_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_vars->scene06_arcadeEnabled) { + if (g_vars->scene06_aimingBall) { + g_fp->_cursorId = PIC_CSR_ARCADE2_D; + + return PIC_CSR_ARCADE2_D; + } + if (g_fp->_aniMan == (StaticANIObject *)g_fp->_objectAtCursor) { + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN6_BALL && g_fp->_cursorId == PIC_CSR_DEFAULT) { + g_fp->_cursorId = PIC_CSR_ITN; + + return PIC_CSR_ITN; + } + } else if (g_fp->_objectAtCursor && (StaticANIObject *)g_fp->_objectAtCursor == g_vars->scene06_currentBall + && g_fp->_cursorId == PIC_CSR_DEFAULT) { + g_fp->_cursorId = PIC_CSR_ITN; + } + } + + return g_fp->_cursorId; +} + +void sceneHandler06_setExits(Scene *sc) { + MotionController *mc = getSc2MctlCompoundBySceneId(sc->_sceneId); + + mc->enableLinks(sO_CloseThing, (g_fp->getObjectState(sO_BigMumsy) != g_fp->getObjectEnumState(sO_BigMumsy, sO_IsGone))); + mc->enableLinks(sO_CloseThing2, g_vars->scene06_arcadeEnabled); +} + +void sceneHandler06_winArcade() { + g_fp->setObjectState(sO_BigMumsy, g_fp->getObjectEnumState(sO_BigMumsy, sO_IsGone)); + + if (g_fp->getObjectState(sO_ClockAxis) == g_fp->getObjectEnumState(sO_ClockAxis, sO_IsNotAvailable)) + g_fp->setObjectState(sO_ClockAxis, g_fp->getObjectEnumState(sO_ClockAxis, sO_WithoutHandle)); + + if (g_vars->scene06_arcadeEnabled) { + g_fp->_aniMan->_callback2 = 0; + + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT | 0x4000); + + if (g_vars->scene06_someBall) { + g_vars->scene06_someBall->_flags &= 0xFFFB; + + g_vars->scene06_balls.push_back(g_vars->scene06_someBall); + + g_vars->scene06_someBall = 0; + } + + if (g_vars->scene06_flyingBall) { + g_vars->scene06_flyingBall->_flags &= 0xFFFB; + + g_vars->scene06_balls.push_back(g_vars->scene06_flyingBall); + + g_vars->scene06_flyingBall = 0; + } + + if (g_vars->scene06_ballInHands) { + g_vars->scene06_ballInHands->_flags &= 0xFFFB; + + g_vars->scene06_balls.push_back(g_vars->scene06_ballInHands); + + g_vars->scene06_ballInHands = 0; + } + + g_vars->scene06_arcadeEnabled = false; + g_vars->scene06_aimingBall = false; + } + + g_vars->scene06_mumsy->_flags &= 0xFFFB; + + sceneHandler06_setExits(g_fp->_currentScene); + + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); +} + +void sceneHandler06_enableDrops() { + chainQueue(QU_SC6_DROPS, 0); + + g_vars->scene06_mumsy->changeStatics2(ST_MOM_SITS); + g_fp->setObjectState(sO_BigMumsy, g_fp->getObjectEnumState(sO_BigMumsy, sO_IsPlaying)); + + chainQueue(QU_MOM_STANDUP, 1); + + g_vars->scene06_arcadeEnabled = true; + g_vars->scene06_numBallsGiven = 0; + g_vars->scene06_mumsyPos = 0; + g_vars->scene06_mumsyNumBalls = 0; + g_vars->scene06_mumsyGotBall = false; + + sceneHandler06_setExits(g_fp->_currentScene); +} + +void sceneHandler06_mumsyBallTake() { + int momAni = 0; + + switch (g_vars->scene06_mumsyNumBalls) { + case 1: + momAni = MV_MOM_TAKE1; + break; + case 2: + momAni = MV_MOM_TAKE2; + break; + case 3: + momAni = MV_MOM_TAKE3; + break; + case 4: + momAni = MV_MOM_TAKE4; + break; + case 5: + momAni = MV_MOM_TAKE5; + break; + } + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + ExCommand *ex = new ExCommand(ANI_MAMASHA, 2, 50, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags = 2u; + mq->addExCommandToEnd(ex); + + if (g_vars->scene06_mumsyNumBalls >= 5) { + g_fp->setObjectState(sO_BigMumsy, g_fp->getObjectEnumState(sO_BigMumsy, sO_IsGone)); + + if (g_fp->getObjectState(sO_ClockAxis) == g_fp->getObjectEnumState(sO_ClockAxis, sO_IsNotAvailable)) + g_fp->setObjectState(sO_ClockAxis, g_fp->getObjectEnumState(sO_ClockAxis, sO_WithoutHandle)); + + ex = new ExCommand(ANI_MAMASHA, 1, momAni, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + if (g_vars->scene06_mumsyPos + 3 >= 0) { + ex = new ExCommand(ANI_MAMASHA, 1, MV_MOM_STARTBK, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2u; + mq->addExCommandToEnd(ex); + + for (int i = 0; i < g_vars->scene06_mumsyPos + 3; i++) { + ex = new ExCommand(ANI_MAMASHA, 1, MV_MOM_CYCLEBK, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + } + + ex = new ExCommand(ANI_MAMASHA, 1, MV_MOM_STOPBK, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + } + + ex = new ExCommand(0, 18, QU_MOM_TOLIFT, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + } else { + if (momAni) { + ex = new ExCommand(ANI_MAMASHA, 1, momAni, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + } + + if (g_vars->scene06_mumsyPos < 0) { + for (int i = 0; i > g_vars->scene06_mumsyPos; i--) { + ex = new ExCommand(ANI_MAMASHA, 1, MV_MOM_JUMPFW, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + } + } else if (g_vars->scene06_mumsyPos > 0) { + for (int i = 0; i < g_vars->scene06_mumsyPos; i++) { + ex = new ExCommand(ANI_MAMASHA, 1, MV_MOM_JUMPBK, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + } + } + + ex = new ExCommand(0, 18, QU_MOM_SITDOWN, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3u; + mq->addExCommandToEnd(ex); + } + + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + + g_vars->scene06_mumsyNumBalls = 0; + g_vars->scene06_arcadeEnabled = false; + + g_fp->_aniMan2 = 0; +} + +void sceneHandler06_spinHandle() { + int tummy = g_fp->getObjectState(sO_TummyTrampie); + + if (tummy == g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsEating)) + g_fp->setObjectState(sO_TummyTrampie, g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsSleeping)); + else if (tummy == g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsSleeping)) + g_fp->setObjectState(sO_TummyTrampie, g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsDrinking)); + else if (tummy == g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsDrinking)) + g_fp->setObjectState(sO_TummyTrampie, g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsScratchingBelly)); + else if (tummy == g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsScratchingBelly)) + g_fp->setObjectState(sO_TummyTrampie, g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsEating)); +} + +void sceneHandler06_uPipeClick() { + if (getGameLoaderInteractionController()->_flag24) + handleObjectInteraction(g_fp->_aniMan2, g_fp->_currentScene->getPictureObjectById(PIC_SC6_LADDER, 0), 0); +} + +void sceneHandler06_buttonPush() { + g_vars->scene06_invHandle = g_fp->_currentScene->getStaticANIObject1ById(ANI_INV_HANDLE, -1); + + if (g_vars->scene06_invHandle) + if (g_vars->scene06_invHandle->_flags & 4) + if (g_vars->scene06_invHandle->_statics) + if (g_vars->scene06_invHandle->_statics->_staticsId == ST_HDL_PLUGGED) + chainQueue(QU_SC6_FALLHANDLE, 1); +} + +void sceneHandler06_showNextBall() { + if (g_vars->scene06_balls.size()) { + g_vars->scene06_currentBall = new StaticANIObject(g_vars->scene06_balls.front()); + g_vars->scene06_balls.remove_at(0); + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC6_SHOWNEXTBALL), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene06_currentBall->_okeyCode); + mq->chain(0); + + ++g_vars->scene06_numBallsGiven; + } +} + +void sceneHandler06_installHandle() { + chainQueue(QU_SC6_SHOWHANDLE, 0); +} + +int sceneHandler06_updateScreenCallback() { + int res; + + res = g_fp->drawArcadeOverlay(g_vars->scene06_arcadeEnabled); + + if (!res) + g_fp->_updateScreenCallback = 0; + + return res; +} + +void sceneHandler06_startAiming() { + if (g_vars->scene06_currentBall) { + g_vars->scene06_currentBall->hide(); + + g_fp->_aniMan->startAnim(MV_MAN6_TAKEBALL, 0, -1); + + g_vars->scene06_ballInHands = g_vars->scene06_currentBall; + g_vars->scene06_currentBall = 0; + + if (getCurrSceneSc2MotionController()->_isEnabled) + g_fp->_updateScreenCallback = sceneHandler06_updateScreenCallback; + + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + g_vars->scene06_ballDrop->queueMessageQueue(0); + } +} + +void sceneHandler06_takeBall() { + if (g_vars->scene06_currentBall && !g_vars->scene06_currentBall->_movement && g_vars->scene06_currentBall->_statics->_staticsId == ST_NBL_NORM) { + if (abs(1158 - g_fp->_aniMan->_ox) > 1 + || abs(452 - g_fp->_aniMan->_oy) > 1 + || g_fp->_aniMan->_movement + || g_fp->_aniMan->_statics->_staticsId != (0x4000 | ST_MAN_RIGHT)) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 1158, 452, 1, (0x4000 | ST_MAN_RIGHT)); + + if (mq) { + ExCommand *ex = new ExCommand(0, 17, MSG_SC6_TAKEBALL, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + + postExCommand(g_fp->_aniMan->_id, 2, 1158, 452, 0, -1); + } + } else { + sceneHandler06_startAiming(); + } + } +} + +void sceneHandler06_aiming() { + if (g_vars->scene06_ballInHands) { + g_vars->scene06_ballDeltaX = 4 * g_fp->_aniMan->_movement->_currDynamicPhaseIndex + 16; + g_vars->scene06_ballDeltaY = 5 * (g_fp->_aniMan->_movement->_currDynamicPhaseIndex + 4); + + if (g_fp->_aniMan->_movement->_currDynamicPhaseIndex < 4) { + g_fp->_aniMan->_movement->setDynamicPhaseIndex(11); + + g_vars->scene06_aimingBall = false; + + return; + } + + g_fp->_aniMan->_movement->setDynamicPhaseIndex(9); + } + + g_vars->scene06_aimingBall = false; +} + +void sceneHandler06_ballStartFly() { + if (g_vars->scene06_ballInHands) { + g_vars->scene06_flyingBall = g_vars->scene06_ballInHands; + g_vars->scene06_ballInHands = 0; + g_vars->scene06_flyingBall->show1(g_fp->_aniMan->_ox - 60, g_fp->_aniMan->_oy - 60, -1, 0); + + g_vars->scene06_flyingBall->_priority = 27; + } +} + +void sceneHandler06_throwCallback(int *arg) { + if (g_vars->scene06_aimingBall) { + int dist = (g_fp->_mouseVirtY - g_vars->scene06_sceneClickY) + * (g_fp->_mouseVirtY - g_vars->scene06_sceneClickY) + + (g_fp->_mouseVirtX - g_vars->scene06_sceneClickX) + * (g_fp->_mouseVirtX - g_vars->scene06_sceneClickX); + + *arg = (int)(sqrt((double)dist) * 0.1); + + if (*arg > 8) + *arg = 8; + } else { + *arg = *arg + 1; + if (*arg == 12) + sceneHandler06_ballStartFly(); + } +} + +void sceneHandler06_throwBall() { + g_fp->_aniMan->_callback2 = sceneHandler06_throwCallback; + g_fp->_aniMan->startAnim(MV_MAN6_THROWBALL, 0, -1); + + g_vars->scene06_aimingBall = true; +} + +void sceneHandler06_eggieWalk() { + if (15 - g_vars->scene06_numBallsGiven >= 4 && !g_fp->_rnd->getRandomNumber(9)) { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_EGGIE, -1); + + if (!ani || !(ani->_flags & 4)) { + if (g_vars->scene06_eggieDirection) + chainQueue(QU_EGG6_GOR, 0); + else + chainQueue(QU_EGG6_GOL, 0); + + g_vars->scene06_eggieTimeout = 0; + g_vars->scene06_eggieDirection = !g_vars->scene06_eggieDirection; + } + } +} + +void sceneHandler06_dropBall() { + if (g_vars->scene06_numBallsGiven >= 15 || g_vars->scene06_mumsyNumBalls >= 5) + g_vars->scene06_ballDrop->hide(); + else + chainQueue(QU_SC6_DROPS3, 0); +} + +void sceneHandler06_fallBall() { + g_vars->scene06_ballY = 475; + + g_vars->scene06_flyingBall->setOXY(g_vars->scene06_ballX, g_vars->scene06_ballY); + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC6_FALLBALL), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene06_flyingBall->_okeyCode); + mq->chain(0); + + g_vars->scene06_balls.push_back(g_vars->scene06_flyingBall); + + g_vars->scene06_flyingBall = 0; + + sceneHandler06_dropBall(); + sceneHandler06_eggieWalk(); +} + +void sceneHandler06_catchBall() { + if (g_vars->scene06_flyingBall) { + g_vars->scene06_flyingBall->hide(); + + g_vars->scene06_balls.push_back(g_vars->scene06_flyingBall); + + g_vars->scene06_flyingBall = 0; + + g_vars->scene06_mumsyNumBalls++; + + if (g_vars->scene06_mumsy->_movement) { + Common::Point point; + + if (g_vars->scene06_mumsy->_movement->_id == MV_MOM_JUMPFW) { + if (g_vars->scene06_mumsy->_movement->_currDynamicPhaseIndex <= 5) { + g_vars->scene06_mumsy->_movement->calcSomeXY(point, 0, g_vars->scene06_mumsy->_movement->_currDynamicPhaseIndex); + + point.x = -point.x; + point.y = -point.y; + } else { + g_vars->scene06_mumsy->_movement->calcSomeXY(point, 1, -1); + + g_vars->scene06_mumsyPos++; + } + } else if (g_vars->scene06_mumsy->_movement->_id == MV_MOM_JUMPBK) { + if (g_vars->scene06_mumsy->_movement->_currDynamicPhaseIndex <= 4) { + g_vars->scene06_mumsy->_movement->calcSomeXY(point, 0, g_vars->scene06_mumsy->_movement->_currDynamicPhaseIndex); + + point.x = -point.x; + point.y = -point.y; + } else { + g_vars->scene06_mumsy->_movement->calcSomeXY(point, 1, -1); + + g_vars->scene06_mumsyPos--; + } + } + + g_vars->scene06_mumsy->changeStatics2(ST_MOM_STANDS); + g_vars->scene06_mumsy->setOXY(point.x + g_vars->scene06_mumsy->_ox, + point.y + g_vars->scene06_mumsy->_oy); + } else { + g_vars->scene06_mumsy->changeStatics2(ST_MOM_STANDS); + } + + chainQueue(QU_MOM_PUTBALL, 1); + g_vars->scene06_mumsyGotBall = true; + + sceneHandler06_dropBall(); + } +} + +void sceneHandler06_checkBallTarget(int par) { + int pixel; + + if (g_vars->scene06_ballY <= 475) { + if (g_vars->scene06_mumsy->getPixelAtPos(g_vars->scene06_ballX, g_vars->scene06_ballY, &pixel)) { + if (pixel) { + chainObjQueue(g_vars->scene06_mumsy, QU_MOM_JUMPBK, 0); + + sceneHandler06_catchBall(); + } + } + } else { + sceneHandler06_fallBall(); + } +} + +void scene06_initScene(Scene *sc) { + g_vars->scene06_mumsy = sc->getStaticANIObject1ById(ANI_MAMASHA, -1); + g_vars->scene06_someBall = 0; + g_vars->scene06_invHandle = sc->getStaticANIObject1ById(ANI_INV_HANDLE, -1); + g_vars->scene06_liftButton = sc->getStaticANIObject1ById(ANI_BUTTON_6, -1); + g_vars->scene06_ballDrop = sc->getStaticANIObject1ById(ANI_BALLDROP, -1); + g_vars->scene06_arcadeEnabled = false; + g_vars->scene06_aimingBall = false; + g_vars->scene06_currentBall = 0; + g_vars->scene06_ballInHands = 0; + g_vars->scene06_flyingBall = 0; + g_vars->scene06_balls.clear(); + g_vars->scene06_numBallsGiven = 0; + g_vars->scene06_mumsyNumBalls = 0; + g_vars->scene06_eggieTimeout = 0; + g_vars->scene06_eggieDirection = true; + + StaticANIObject *ball = sc->getStaticANIObject1ById(ANI_NEWBALL, -1); + + ball->hide(); + ball->_statics = ball->getStaticsById(ST_NBL_NORM); + g_vars->scene06_balls.push_back(ball); + + for (int i = 0; i < 3; i++) { + StaticANIObject *ball2 = new StaticANIObject(ball); + + ball2->hide(); + ball2->_statics = ball2->getStaticsById(ST_NBL_NORM); + + sc->addStaticANIObject(ball2, 1); + + g_vars->scene06_balls.push_back(ball2); + } + + if (g_fp->getObjectState(sO_BigMumsy) == g_fp->getObjectEnumState(sO_BigMumsy, sO_IsPlaying)) + g_fp->setObjectState(sO_BigMumsy, g_fp->getObjectEnumState(sO_BigMumsy, sO_IsSleeping)); + + if (g_fp->getObjectState(sO_BigMumsy) != g_fp->getObjectEnumState(sO_BigMumsy, sO_IsSleeping)) + g_vars->scene06_mumsy->hide(); + + g_fp->lift_setButton(sO_Level3, ST_LBN_3N); + g_fp->lift_init(sc, QU_SC6_ENTERLIFT, QU_SC6_EXITLIFT); + g_fp->initArcadeKeys("SC_6"); + + sceneHandler06_setExits(sc); + + g_fp->setArcadeOverlay(PIC_CSR_ARCADE2); +} + +int sceneHandler06(ExCommand *ex) { + if (ex->_messageKind != 17) + return 0; + + switch(ex->_messageNum) { + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(ex); + break; + + case MSG_CMN_WINARCADE: + sceneHandler06_winArcade(); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_SC6_RESTORESCROLL: + g_fp->_aniMan2 = g_fp->_aniMan; + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + sceneHandler06_setExits(g_fp->_currentScene); + break; + + case MSG_SC6_STARTDROPS: + if (g_fp->getObjectState(sO_BigMumsy) == g_fp->getObjectEnumState(sO_BigMumsy, sO_IsSleeping)) + sceneHandler06_enableDrops(); + break; + + case MSG_SC6_TESTNUMBALLS: + g_vars->scene06_mumsyGotBall = false; + + if (g_vars->scene06_mumsyNumBalls < 5 || !g_vars->scene06_arcadeEnabled) + return 0; + + sceneHandler06_mumsyBallTake(); + break; + + case MSG_SC6_JUMPFW: + ++g_vars->scene06_mumsyPos; + break; + + case MSG_SC6_JUMPBK: + --g_vars->scene06_mumsyPos; + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SPINHANDLE: + sceneHandler06_spinHandle(); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case MSG_SC6_UTRUBACLICK: + sceneHandler06_uPipeClick(); + break; + + case MSG_SC6_BTNPUSH: + sceneHandler06_buttonPush(); + break; + + case MSG_SC6_SHOWNEXTBALL: + sceneHandler06_showNextBall(); + break; + + case MSG_SC6_INSTHANDLE: + sceneHandler06_installHandle(); + break; + + case MSG_SC6_ENABLEDROPS: + sceneHandler06_enableDrops(); + break; + + case 64: + g_fp->lift_hoverButton(ex); + break; + + case MSG_SC6_TAKEBALL: + sceneHandler06_takeBall(); + break; + + case 30: + if (g_vars->scene06_aimingBall) { + sceneHandler06_aiming(); + break; + } + + if (!g_vars->scene06_arcadeEnabled) { + // Do nothing + break; + } + break; + + case 29: + { + StaticANIObject *st = g_fp->_currentScene->getStaticANIObjectAtPos(ex->_sceneClickX, ex->_sceneClickY); + + if (st) { + if (!g_vars->scene06_arcadeEnabled && st->_id == ANI_LIFTBUTTON) { + g_fp->lift_animateButton(st); + ex->_messageKind = 0; + return 0; + } + + if (g_vars->scene06_currentBall == st) { + if (g_vars->scene06_numBallsGiven == 1) + sceneHandler06_takeBall(); + + ex->_messageKind = 0; + } else if (g_vars->scene06_ballInHands && g_fp->_aniMan == st && !g_fp->_aniMan->_movement && g_fp->_aniMan->_statics->_staticsId == ST_MAN6_BALL) { + g_vars->scene06_sceneClickX = ex->_sceneClickX; + g_vars->scene06_sceneClickY = ex->_sceneClickY; + + sceneHandler06_throwBall(); + } + } + + if (!st || !canInteractAny(g_fp->_aniMan, st, ex->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(ex->_sceneClickX, ex->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, ex->_keyCode)) { + if ((g_fp->_sceneRect.right - ex->_sceneClickX < 47 + && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (ex->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(ex); + return 0; + } + } + } + } + + break; + + case 33: + { + int res = 0; + + if (g_fp->_aniMan2) { + int ox = g_fp->_aniMan2->_ox; + int oy = g_fp->_aniMan2->_oy; + + g_vars->scene06_manX = ox; + g_vars->scene06_manY = oy; + + if (g_vars->scene06_arcadeEnabled && oy <= 470 && ox >= 1088) { + if (ox < g_fp->_sceneRect.left + 600) { + g_fp->_currentScene->_x = ox - g_fp->_sceneRect.left - 700; + ox = g_vars->scene06_manX; + } + + if (ox > g_fp->_sceneRect.right - 50) + g_fp->_currentScene->_x = ox - g_fp->_sceneRect.right + 70; + } else { + if (ox < g_fp->_sceneRect.left + 200) { + g_fp->_currentScene->_x = ox - g_fp->_sceneRect.left - 300; + ox = g_vars->scene06_manX; + } + + if (ox > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = ox - g_fp->_sceneRect.right + 300; + } + + res = 1; + } + if (g_vars->scene06_arcadeEnabled) { + if (g_vars->scene06_mumsyPos > -3) + g_vars->scene06_mumsyJumpBk->_percent = g_vars->scene06_mumsyJumpBkPercent; + else + g_vars->scene06_mumsyJumpBk->_percent = 0; + + if (g_vars->scene06_mumsyPos < 4) + g_vars->scene06_mumsyJumpFw->_percent = g_vars->scene06_mumsyJumpFwPercent; + else + g_vars->scene06_mumsyJumpFw->_percent = 0; + + if (g_vars->scene06_aimingBall) { + g_vars->scene06_eggieTimeout++; + + if (g_vars->scene06_eggieTimeout >= 600) + sceneHandler06_eggieWalk(); + } + } else { + g_vars->scene06_mumsyJumpFw->_percent = 0; + g_vars->scene06_mumsyJumpBk->_percent = 0; + } + + if (g_vars->scene06_flyingBall) { + g_vars->scene06_ballX = g_vars->scene06_flyingBall->_ox - g_vars->scene06_ballDeltaX; + g_vars->scene06_ballY = g_vars->scene06_flyingBall->_oy - g_vars->scene06_ballDeltaY; + + g_vars->scene06_flyingBall->setOXY(g_vars->scene06_ballX, g_vars->scene06_ballY); + + if (g_vars->scene06_ballDeltaX >= 2) + g_vars->scene06_ballDeltaX -= 2; + + g_vars->scene06_ballDeltaY -= 5; + + sceneHandler06_checkBallTarget(g_vars->scene06_ballDeltaX); + } + if (g_vars->scene06_arcadeEnabled + && !g_vars->scene06_currentBall + && !g_vars->scene06_ballInHands + && !g_vars->scene06_flyingBall + && g_vars->scene06_numBallsGiven >= 15 + && !g_vars->scene06_ballDrop->_movement + && !g_vars->scene06_mumsy->_movement + && !g_vars->scene06_mumsyGotBall) + sceneHandler06_mumsyBallTake(); + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + return res; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene07.cpp b/engines/fullpipe/scenes/scene07.cpp new file mode 100644 index 0000000000..6db8c30932 --- /dev/null +++ b/engines/fullpipe/scenes/scene07.cpp @@ -0,0 +1,175 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/scene.h" +#include "fullpipe/statics.h" +#include "fullpipe/messages.h" +#include "fullpipe/behavior.h" + +namespace Fullpipe { + +void scene07_initScene(Scene *sc) { + g_vars->scene07_lukeAnim = 0; + g_vars->scene07_lukePercent = 0; + g_vars->scene07_plusMinus = sc->getStaticANIObject1ById(ANI_PLUSMINUS, -1); + + if (g_fp->getObjectState(sO_Guard_1) == g_fp->getObjectEnumState(sO_Guard_1, sO_Off)) + g_vars->scene07_plusMinus->_statics = g_vars->scene07_plusMinus->getStaticsById(ST_PMS_MINUS); + else + g_vars->scene07_plusMinus->_statics = g_vars->scene07_plusMinus->getStaticsById(ST_PMS_PLUS); + + if (g_fp->getObjectState(sO_HareTheNooksiter) == g_fp->getObjectEnumState(sO_HareTheNooksiter, sO_WithoutHandle)) { + Scene *oldsc = g_fp->_currentScene; + + g_fp->_currentScene = sc; + + sc->getStaticANIObject1ById(ANI_CORNERSITTER, -1)->changeStatics2(ST_CST_HANDLELESS); + + g_fp->_currentScene = oldsc; + } +} + +void sceneHandler07_openLuke() { + StaticANIObject *luke = g_fp->_currentScene->getStaticANIObject1ById(ANI_LUKE, -1); + + luke->changeStatics2(ST_LUK_OPEN); + luke->show1(-1, -1, -1, 0); + + if (g_vars->scene07_lukeAnim) { + g_vars->scene07_lukeAnim->_percent = g_vars->scene07_lukePercent; + } else { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_CORNERSITTER, -1); + + g_vars->scene07_lukeAnim = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(ani, ST_CST_HANDLELESS, QU_CST_CLOSELUKE); + + g_vars->scene07_lukeAnim->_percent = g_vars->scene07_lukePercent; + } +} + +void sceneHandler07_closeLuke() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_LUKE, -1)->changeStatics2(ST_LUK_CLOSED); + + if (!g_vars->scene07_lukeAnim) { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_CORNERSITTER, -1); + + g_vars->scene07_lukeAnim = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(ani, ST_CST_HANDLELESS, QU_CST_CLOSELUKE); + } + + g_vars->scene07_lukePercent = g_vars->scene07_lukeAnim->_percent; + g_vars->scene07_lukeAnim->_percent = 0; + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_HOOLIGAN, -1); + + ani->changeStatics2(ST_HGN_LUKE); + ani->show1(-1, -1, -1, 0); +} + +void sceneHandler07_hideLuke() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_LUKE, -1)->hide(); + + Movement *mov = g_fp->_currentScene->getStaticANIObject1ById(ANI_CORNERSITTER, -1)->_movement; + + if (mov) { + if (mov->_id == MV_CST_CLOSELUKE) { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_HOOLIGAN, -1); + + ani->changeStatics2(ST_HGN_LOOK); + ani->_flags &= 0xFFFB; + } + } +} + +void sceneHandler07_showBox() { + StaticANIObject *box = g_fp->_currentScene->getStaticANIObject1ById(ANI_SC7_BOX, -1); + + box->show1(492, 474, MV_SC7_BOX_default, 0); + box->_priority = 25; +} + +void sceneHandler07_hideBox() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_SC7_BOX, -1)->hide(); +} + +int sceneHandler07(ExCommand *ex) { + if (ex->_messageKind != 17) + return 0; + + switch(ex->_messageNum) { + case MSG_SC7_OPENLUKE: + sceneHandler07_openLuke(); + break; + + case MSG_SC7_PULL: + if (g_vars->scene07_plusMinus->_statics->_staticsId == ST_PMS_MINUS) + g_vars->scene07_plusMinus->_statics = g_vars->scene07_plusMinus->getStaticsById(ST_PMS_PLUS); + else + g_vars->scene07_plusMinus->_statics = g_vars->scene07_plusMinus->getStaticsById(ST_PMS_MINUS); + + break; + + case MSG_SC7_CLOSELUKE: + sceneHandler07_closeLuke(); + break; + + case MSG_SC7_HIDELUKE: + sceneHandler07_hideLuke(); + break; + + case MSG_SC7_SHOWBOX: + sceneHandler07_showBox(); + break; + + case MSG_SC7_HIDEBOX: + sceneHandler07_hideBox(); + break; + + case 33: + { + int res = 0; + + if (g_fp->_aniMan2) { + if (g_fp->_aniMan2->_ox < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.left - 300; + + if (g_fp->_aniMan2->_ox > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.right + 300; + + res = 1; + } + + g_fp->_behaviorManager->updateBehaviors(); + + return res; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene08.cpp b/engines/fullpipe/scenes/scene08.cpp new file mode 100644 index 0000000000..d64df8688e --- /dev/null +++ b/engines/fullpipe/scenes/scene08.cpp @@ -0,0 +1,546 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/scene.h" +#include "fullpipe/statics.h" +#include "fullpipe/floaters.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/behavior.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +void scene08_initScene(Scene *sc) { + g_vars->scene08_inArcade = false; + g_vars->scene08_inAir = false; + g_vars->scene08_flyingUp = false; + g_vars->scene08_onBelly = false; + g_vars->scene08_batuta = sc->getStaticANIObject1ById(ANI_BATUTA, -1); + g_vars->scene08_vmyats = sc->getStaticANIObject1ById(ANI_VMYATS, -1); + g_vars->scene08_clock = sc->getStaticANIObject1ById(ANI_CLOCK_8, -1); + g_vars->scene08_stairsOffset = -37; + g_vars->scene08_snoringCountdown = -1; + + Scene *oldsc = g_fp->_currentScene; + g_fp->_currentScene = sc; + + int batuta = g_fp->getObjectState(sO_TummyTrampie); + MovGraphLink *lock = getSc2MctlCompoundBySceneId(sc->_sceneId)->getLinkByName(sO_CloseThing); + + if (lock) + lock->_flags &= 0xDFFFFFFF; + + if (batuta == g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsEating)) { + g_vars->scene08_batuta->changeStatics2(ST_BTT_SPOON); + } else if (batuta == g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsDrinking)) { + g_vars->scene08_batuta->changeStatics2(ST_BTT_NOSPOON); + + g_vars->scene08_clock->startAnim(MV_CLK8_GO, 0, -1); + g_vars->scene08_clock->_movement->setDynamicPhaseIndex(3); + } else if (batuta== g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsScratchingBelly)) { + g_vars->scene08_batuta->changeStatics2(ST_BTT_CHESHET); + + g_vars->scene08_clock->startAnim(MV_CLK8_GO, 0, -1); + g_vars->scene08_clock->_movement->setDynamicPhaseIndex(8); + } else if (batuta == g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsSleeping)) { + g_vars->scene08_batuta->changeStatics2(ST_BTT_SLEEPS); + + g_vars->scene08_clock->startAnim(MV_CLK8_GO, 0, -1); + g_vars->scene08_clock->_movement->setDynamicPhaseIndex(2); + + if (lock) + lock->_flags |= 0x20000000; + + g_vars->scene08_snoringCountdown = 71; + } + + g_vars->scene08_clock->_callback2 = 0; + + if (g_fp->getObjectState(sO_StairsUp_8) == g_fp->getObjectEnumState(sO_StairsUp_8, sO_Broken)) { + g_vars->scene08_stairsVisible = false; + + sc->getPictureObjectById(PIC_SC8_LADDER, 0)->_flags &= 0xFFFB; + + g_vars->scene08_stairsOffset = -39; + } else { + g_vars->scene08_stairsVisible = true; + } + + sc->getPictureObjectById(PIC_SC8_ARCADENOW, 0)->_flags &= 0xFFFB; + + g_fp->_currentScene = oldsc; + + g_fp->_floaters->init(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_8")); + g_fp->_floaters->genFlies(sc, 100, 100, 0, 0); + + g_fp->setArcadeOverlay(PIC_CSR_ARCADE3); +} + +void scene08_setupMusic() { + if (g_fp->getObjectState(sO_TummyTrampie) == g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsSleeping)) + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_8"), "MUSIC_ARCADE", 1); +} + +int scene08_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_vars->scene08_inArcade) { + if (g_vars->scene08_onBelly) { + if (g_fp->_objectIdAtCursor == PIC_SC8_LADDERD && g_fp->_cursorId == PIC_CSR_ITN) + g_fp->_cursorId = PIC_CSR_GOU; + } else { + g_fp->_cursorId = -1; + } + } else { + if (g_fp->_objectIdAtCursor == PIC_SC8_LADDERD && g_fp->_cursorId == PIC_CSR_ITN) { + if (g_fp->_aniMan2->_oy >= 520) { + if (g_fp->_aniMan2->_oy <= 750) + g_fp->_cursorId = PIC_CSR_GOU; + } else { + g_fp->_cursorId = PIC_CSR_GOD; + } + } + } + + return g_fp->_cursorId; +} + +void sceneHandler08_enterUp() { + g_fp->_currentScene->getPictureObjectById(PIC_SC8_LADDER, 0)->_flags &= 0xFFFB; + + g_fp->_aniMan->changeStatics2(ST_MAN8_HANDSUP); + g_fp->_aniMan->setOXY(386, 236); + g_fp->_aniMan->_priority = 10; + g_fp->_aniMan->_flags = 4; + + chainObjQueue(g_fp->_aniMan, QU_SC8_FINISH, 1); + + g_vars->scene08_inAir = false; +} + +void sceneHandler08_winArcade() { + if (g_vars->scene08_inArcade) { + g_vars->scene08_inArcade = false; + g_fp->_sceneRect.top = 0; + g_fp->_sceneRect.bottom = 600; + + sceneHandler08_enterUp(); + } +} + +void sceneHandler08_hideLadder() { + g_fp->_currentScene->getPictureObjectById(PIC_SC8_LADDER_D, 0)->_flags &= 0xFFFB; +} + +void sceneHandler08_arcadeNow() { + MovGraphLink *lnk = getCurrSceneSc2MotionController()->getLinkByName(sO_Stairway); + + g_fp->setObjectState(sO_TummyTrampie, g_fp->getObjectEnumState(sO_TummyTrampie, sO_IsSleeping)); + + g_vars->scene08_batuta->changeStatics2(ST_BTT_SLEEPS); + + if (lnk) + lnk->_flags |= 0x20000000; +} + +void sceneHandler08_resumeFlight() { + g_vars->scene08_manOffsetY = 3; + g_vars->scene08_stairsOffset = -39; + g_vars->scene08_inAir = true; + g_vars->scene08_stairsVisible = false; +} + +int sceneHandler08_calcOffset(int off, int flag) { + if (off > 0) { + if (flag) + return off * 31 / 10; // off * 3.1 + else + return 5 * off; + } else { + return 5 * off; + } +} + +void sceneHandler08_pushCallback(int *par) { + Common::Point point; + + int y = g_fp->_aniMan->_oy + g_fp->_aniMan->getSomeXY(point)->y; + + if (g_fp->_aniMan->_statics && g_fp->_aniMan->_statics->_staticsId == ST_MAN8_FLYDOWN) + y -= 25; + + *par = (y - 703) / 10; + if (*par > 11) { + *par = 11; + g_vars->scene08_manOffsetY = 0; + } + if (*par >= 0) + g_vars->scene08_manOffsetY -= sceneHandler08_calcOffset(*par, g_vars->scene08_manOffsetY < 0); + else + *par = 0; +} + +int sceneHandler08_updateScreenCallback() { + int res; + + res = g_fp->drawArcadeOverlay(g_vars->scene08_inArcade); + + if (!res) + g_fp->_updateScreenCallback = 0; + + return res; +} + +void sceneHandler08_startArcade() { + g_vars->scene08_inArcade = true; + g_vars->scene08_inAir = true; + g_vars->scene08_flyingUp = false; + g_vars->scene08_onBelly = false; + + getGameLoaderInteractionController()->disableFlag24(); + getCurrSceneSc2MotionController()->deactivate(); + + g_vars->scene08_batuta->stopAnim_maybe(); + + g_vars->scene08_vmyats->_statics = g_vars->scene08_vmyats->getStaticsById(ST_VMT_MIN); + g_vars->scene08_vmyats->setOXY(382, 703); + g_vars->scene08_vmyats->_priority = 29; + g_vars->scene08_vmyats->_callback2 = sceneHandler08_pushCallback; + + g_fp->_aniMan = g_fp->_currentScene->getStaticANIObject1ById(ANI_MAN, -1); + + g_vars->scene08_manOffsetY = 15; + + g_fp->_currentScene->_y = 0; + + g_fp->_updateScreenCallback = sceneHandler08_updateScreenCallback; +} + +void sceneHandler08_airMoves() { + if (g_fp->_aniMan->isIdle() && !(g_fp->_aniMan->_flags & 0x100)) { + int x = g_fp->_aniMan->_ox; + int y = g_fp->_aniMan->_oy; + Common::Point point; + + if (703 - g_fp->_aniMan->getSomeXY(point)->y - y < 150) { + if (g_fp->_aniMan->_statics) { + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN8_FLYDOWN) { + y -= 25; + + g_fp->_aniMan->setOXY(x, y); + } + } + + g_fp->_aniMan->changeStatics2(ST_MAN8_STAND); + g_fp->_aniMan->setOXY(380, y); + g_fp->_aniMan->startAnim(MV_MAN8_JUMP, 0, -1); + + } else if (g_fp->_aniMan->_statics) { + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN8_FLYUP) { + g_fp->_aniMan->startAnim(MV_MAN8_DRYGUP, 0, -1); + + } else if (g_fp->_aniMan->_statics->_staticsId == ST_MAN8_FLYDOWN) { + g_fp->_aniMan->startAnim(MV_MAN8_DRYGDOWN, 0, -1); + } + } + } +} + +void sceneHandler08_finishArcade() { + g_vars->scene08_inArcade = false; + + getGameLoaderInteractionController()->enableFlag24(); + getCurrSceneSc2MotionController()->activate(); +} + +void sceneHandler08_jumpOff(ExCommand *cmd) { + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + mq->addExCommandToEnd(cmd->createClone()); + mq->setFlags(mq->getFlags() | 1); + + g_fp->_globalMessageQueueList->addMessageQueue(mq); + + g_fp->_aniMan->startAnim(MV_MAN8_JUMPOFF, mq->_id, -1); + + sceneHandler08_finishArcade(); +} + +void sceneHandler08_standUp() { + chainQueue(QU_SC8_STANDUP, 1); + g_vars->scene08_onBelly = false; +} + +void sceneHandler08_jumpLogic(ExCommand *cmd) { + if (g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY) == PIC_SC8_LADDERD) { + sceneHandler08_jumpOff(cmd); + + cmd->_messageKind = 0; + } else { + sceneHandler08_standUp(); + } +} + +void sceneHandler08_badLuck() { + g_fp->_currentScene->getPictureObjectById(PIC_SC8_LADDER, 0)->_flags &= 0xFFFB; + + g_fp->_aniMan->changeStatics2(ST_MAN8_HANDSUP); + g_fp->_aniMan->setOXY(376, 280); + g_fp->_aniMan->_priority = 10; + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + ExCommand *ex = new ExCommand(g_fp->_aniMan->_id, 1, MV_MAN8_BADLUCK, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + ex->_keyCode = g_fp->_aniMan->_okeyCode; + mq->addExCommandToEnd(ex); + + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + + g_fp->setObjectState(sO_StairsUp_8, g_fp->getObjectEnumState(sO_StairsUp_8, sO_NotBroken)); + + g_vars->scene08_inAir = false; +} + +void sceneHandler08_sitDown() { + g_fp->_aniMan->setOXY(380, g_fp->_aniMan->_oy); + + g_fp->_aniMan->changeStatics2(ST_MAN8_FLYDOWN); + g_fp->_aniMan->startAnim(MV_MAN8_SITDOWN, 0, -1); + + g_vars->scene08_vmyats->changeStatics2(ST_VMT_MIN); + g_vars->scene08_vmyats->hide(); + + g_vars->scene08_inAir = false; + g_vars->scene08_onBelly = true; +} + +void sceneHandler08_calcFlight() { + Common::Point point; + int y = g_vars->scene08_manOffsetY + g_fp->_aniMan->_oy; + + g_fp->_aniMan->setOXY(g_fp->_aniMan->_ox, y); + + g_vars->scene08_manOffsetY += 2; + + if (g_vars->scene08_manOffsetY < g_vars->scene08_stairsOffset) + g_vars->scene08_manOffsetY = g_vars->scene08_stairsOffset; + + y = y + g_fp->_aniMan->getSomeXY(point)->y; + + if (g_fp->_aniMan->_statics && g_fp->_aniMan->_statics->_staticsId == ST_MAN8_FLYDOWN) + y -= 25; + + if (y <= g_vars->scene08_vmyats->_oy) { + g_vars->scene08_vmyats->hide(); + } else { + g_vars->scene08_vmyats->show1(-1, -1, -1, 0); + + if (!g_vars->scene08_vmyats->_movement) + g_vars->scene08_vmyats->startAnim(MV_VMT_DEF, 0, -1); + } + + if (g_fp->_aniMan->_oy <= 280 && g_vars->scene08_stairsVisible + && g_fp->_aniMan->_statics && g_fp->_aniMan->_statics->_staticsId == ST_MAN8_HANDSUP) { + sceneHandler08_badLuck(); + } else if (g_fp->_aniMan->_oy > 236 || g_vars->scene08_stairsVisible + || !g_fp->_aniMan->_statics || g_fp->_aniMan->_statics->_staticsId != ST_MAN8_HANDSUP) { + if (g_fp->_aniMan->_movement || g_fp->_aniMan->_oy < 660 + || (g_vars->scene08_vmyats->_movement && g_vars->scene08_vmyats->_movement->_currDynamicPhaseIndex > 0) + || abs(g_vars->scene08_manOffsetY) > 2) { + if (g_vars->scene08_manOffsetY >= 0 && !g_fp->_aniMan->_movement) { + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN8_HANDSUP) + g_fp->_aniMan->startAnim(MV_MAN8_HANDSDOWN, 0, -1); + else + g_fp->_aniMan->changeStatics2(ST_MAN8_FLYDOWN); + } + + if (g_fp->_aniMan->_oy < 500 && !g_fp->_aniMan->_movement && g_fp->_aniMan->_statics->_staticsId == ST_MAN8_FLYUP && g_vars->scene08_manOffsetY < 0) + g_fp->_aniMan->startAnim(MV_MAN8_HANDSUP, 0, -1); + } else { + sceneHandler08_sitDown(); + } + } else { + sceneHandler08_enterUp(); + } +} + +void sceneHandler08_checkEndArcade() { + if (g_vars->scene08_flyingUp) { + int x = g_fp->_aniMan->_ox; + int y = g_vars->scene08_manOffsetY + g_fp->_aniMan->_oy; + + if (!((g_vars->scene08_manOffsetY + g_fp->_aniMan->_oy) % 3)) + g_vars->scene08_manOffsetY--; + + g_fp->_aniMan->setOXY(x, y); + + if (y < 80) { + sceneHandler08_finishArcade(); + + ExCommand *ex = new ExCommand(SC_8, 17, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_messageNum = 61; + ex->_excFlags |= 2; + ex->_keyCode = TrubaUp; + + ex->postMessage(); + } + } +} + +int sceneHandler08(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_CMN_WINARCADE: + sceneHandler08_winArcade(); + break; + + case MSG_SC8_ENTERUP: + sceneHandler08_enterUp(); + break; + + case MSG_SC8_HIDELADDER_D: + sceneHandler08_hideLadder(); + break; + + case MSG_SC8_STANDUP: + g_vars->scene08_manOffsetY = -10; + g_vars->scene08_vmyats->changeStatics2(ST_VMT_MIN); + g_vars->scene08_vmyats->setOXY(382, 703); + g_vars->scene08_vmyats->_priority = 29; + g_vars->scene08_vmyats->_callback2 = sceneHandler08_pushCallback; + g_vars->scene08_inAir = true; + break; + + case MSG_SC8_ARCADENOW: + sceneHandler08_arcadeNow(); + break; + + case MSG_SC8_RESUMEFLIGHT: + sceneHandler08_resumeFlight(); + break; + + case MSG_SC8_GETHIMUP: + g_vars->scene08_manOffsetY = 0; + g_vars->scene08_flyingUp = true; + break; + + case MSG_STARTARCADE: + sceneHandler08_startArcade(); + break; + + case 29: + if (g_vars->scene08_inArcade) { + if (g_vars->scene08_inAir) { + sceneHandler08_airMoves(); + break; + } + if (g_vars->scene08_onBelly) { + sceneHandler08_jumpLogic(cmd); + break; + } + } + break; + + case 33: + { + int res = 0; + + if (g_fp->_aniMan2) { + if (g_vars->scene08_inArcade) { + int scHeight = g_fp->_sceneRect.bottom - g_fp->_sceneRect.top; + + if (g_fp->_aniMan2->_oy < g_fp->_sceneRect.top + 200) { + g_fp->_sceneRect.top = g_fp->_aniMan2->_oy - 200; + + if (g_fp->_sceneRect.top < 0) + g_fp->_sceneRect.top = 0; + + g_fp->_sceneRect.bottom = scHeight + g_fp->_sceneRect.top; + } + + if (g_fp->_aniMan2->_oy > g_fp->_sceneRect.bottom - 350) { + g_fp->_sceneRect.bottom = g_fp->_aniMan2->_oy + 350; + g_fp->_sceneRect.top = g_fp->_aniMan2->_oy + 350 - scHeight; + } + } else { + if (g_fp->_aniMan2->_ox < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.left - 300; + + if (g_fp->_aniMan2->_ox > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.right + 300; + + res = 1; + } + } + + g_fp->_floaters->update(); + + if (g_vars->scene08_inArcade) { + if (g_vars->scene08_inAir) + sceneHandler08_calcFlight(); + } else { + Movement *mov = g_fp->_aniMan->_movement; + + if (mov) { + if (mov->_id == MV_MAN_TOLADDERD && mov->_currDynamicPhaseIndex == 8) + g_fp->_aniMan->_priority = 2; + + if (mov && mov->_id == MV_MAN_FROMLADDERUP && mov->_currDynamicPhaseIndex == 13) + g_fp->_aniMan->_priority = 20; + } + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + } + + if (g_vars->scene08_flyingUp) + sceneHandler08_checkEndArcade(); + + if (g_vars->scene08_snoringCountdown > 0) { + g_vars->scene08_snoringCountdown--; + + if (!g_vars->scene08_snoringCountdown) { + g_fp->playSound(SND_8_014, 0); + + g_vars->scene08_snoringCountdown = 71; + } + } + + return res; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene09.cpp b/engines/fullpipe/scenes/scene09.cpp new file mode 100644 index 0000000000..ffe8a1b2de --- /dev/null +++ b/engines/fullpipe/scenes/scene09.cpp @@ -0,0 +1,747 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +struct Hanger { + StaticANIObject *ani; + int field_4; + int field_8; + int phase; +}; + +void scene09_setupGrit(Scene *sc) { + if (g_vars->scene09_grit->_statics->_staticsId == ST_GRT9_GRIT) { + if (!getGameLoaderInventory()->getCountItemsWithId(ANI_INV_COIN)) { + if (g_fp->getObjectState(sO_CoinSlot_1) == g_fp->getObjectEnumState(sO_CoinSlot_1, sO_Empty) + && (g_vars->swallowedEgg1->_value.intValue == ANI_INV_EGGBOOT || g_vars->swallowedEgg2->_value.intValue == ANI_INV_EGGBOOT || g_vars->swallowedEgg3->_value.intValue == ANI_INV_EGGBOOT)) { + Scene *oldsc = g_fp->_currentScene; + g_fp->_currentScene = sc; + g_vars->scene09_grit->changeStatics2(ST_GRT9_NORM); + g_fp->_currentScene = oldsc; + } + } + } +} + +void scene09_initScene(Scene *sc) { + g_vars->scene09_flyingBall = 0; + g_vars->scene09_numSwallenBalls = 0; + g_vars->scene09_gulper = sc->getStaticANIObject1ById(ANI_GLOTATEL, -1); + g_vars->scene09_spitter = sc->getStaticANIObject1ById(ANI_PLEVATEL, -1); + g_vars->scene09_grit = sc->getStaticANIObject1ById(ANI_GRIT_9, -1); + g_vars->scene09_gulperIsPresent = true; + g_vars->scene09_dudeIsOnLadder = false; + g_vars->scene09_interactingHanger = -1; + g_vars->scene09_intHangerPhase = -1; + g_vars->scene09_intHangerMaxPhase = -1000; + + g_vars->scene09_balls.cPlexLen = 10; + g_vars->scene09_flyingBalls.cPlexLen = 10; + + while (g_vars->scene09_balls.numBalls) { + Ball *b = g_vars->scene09_balls.pHead->p0; + + g_vars->scene09_balls.pHead = g_vars->scene09_balls.pHead->p0; + + if (g_vars->scene09_balls.pHead) + g_vars->scene09_balls.pHead->p0->p1 = 0; + else + g_vars->scene09_balls.field_8 = 0; + + g_vars->scene09_balls.init(&b); + } + + g_vars->scene09_hangers.clear(); + g_vars->scene09_numMovingHangers = 4; + + StaticANIObject *hanger = sc->getStaticANIObject1ById(ANI_VISUNCHIK, -1); + Hanger *hng = new Hanger; + + hng->ani = hanger; + hng->phase = 0; + hng->field_4 = 0; + hng->field_8 = 0; + + g_vars->scene09_hangers.push_back(hng); + + int x = 75; + + for (int i = 1; x < 300; i++, x += 75) { + StaticANIObject *ani = new StaticANIObject(hanger); + + ani->show1(x + hanger->_ox, hanger->_oy, MV_VSN_CYCLE2, 0); + sc->addStaticANIObject(hanger, 1); + + hng = new Hanger; + + hng->ani = ani; + hng->phase = 0; + hng->field_4 = 0; + hng->field_8 = 0; + + g_vars->scene09_hangers.push_back(hng); + } + + while (g_vars->scene09_flyingBalls.numBalls) { + Ball *ohead = g_vars->scene09_flyingBalls.pHead; + + g_vars->scene09_flyingBalls.pHead = g_vars->scene09_flyingBalls.pHead->p0; + + if (g_vars->scene09_flyingBalls.pHead) + ohead->p0->p1 = 0; + else + g_vars->scene09_flyingBalls.field_8 = 0; + + ohead->p0 = g_vars->scene09_flyingBalls.pTail; + + g_vars->scene09_flyingBalls.pTail = ohead; + + g_vars->scene09_flyingBalls.numBalls--; + } + + g_vars->scene09_flyingBalls.reset(); + + Ball *b9 = g_vars->scene09_flyingBalls.sub04(g_vars->scene09_flyingBalls.field_8, 0); + + b9->ani = sc->getStaticANIObject1ById(ANI_BALL9, -1); + b9->ani->setAlpha(0xc8); + + if (g_vars->scene09_flyingBalls.field_8) { + g_vars->scene09_flyingBalls.field_8->p0 = b9; + g_vars->scene09_flyingBalls.field_8 = b9; + } else { + g_vars->scene09_flyingBalls.pHead = b9; + g_vars->scene09_flyingBalls.field_8 = b9; + } + + for (int i = 0; i < 4; i++) { + StaticANIObject *newball = new StaticANIObject(b9->ani); + + newball->setAlpha(0xc8); + + Ball *runPtr = g_vars->scene09_flyingBalls.pTail; + Ball *lastP = g_vars->scene09_flyingBalls.field_8; + + if (!g_vars->scene09_flyingBalls.pTail) { + g_vars->scene09_flyingBalls.cPlex = (byte *)calloc(g_vars->scene09_flyingBalls.cPlexLen, sizeof(Ball)); + + byte *p1 = g_vars->scene09_flyingBalls.cPlex + (g_vars->scene09_flyingBalls.cPlexLen - 1) * sizeof(Ball); + + if (g_vars->scene09_flyingBalls.cPlexLen - 1 < 0) { + runPtr = g_vars->scene09_flyingBalls.pTail; + } else { + runPtr = g_vars->scene09_flyingBalls.pTail; + + for (int j = 0; j < g_vars->scene09_flyingBalls.cPlexLen; j++) { + ((Ball *)p1)->p1 = runPtr; + runPtr = (Ball *)p1; + + p1 -= sizeof(Ball); + } + + g_vars->scene09_flyingBalls.pTail = runPtr; + } + } + + g_vars->scene09_flyingBalls.pTail = runPtr->p0; + runPtr->p1 = lastP; + runPtr->p0 = 0; + runPtr->ani = newball; + + g_vars->scene09_flyingBalls.numBalls++; + + if (g_vars->scene09_flyingBalls.field_8) + g_vars->scene09_flyingBalls.field_8->p0 = runPtr; + else + g_vars->scene09_flyingBalls.pHead = runPtr; + + g_vars->scene09_flyingBalls.field_8 = runPtr; + + sc->addStaticANIObject(newball, 1); + } + + g_fp->setObjectState(sO_RightStairs_9, g_fp->getObjectEnumState(sO_RightStairs_9, sO_IsClosed)); + + GameVar *eggvar = g_fp->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_GulpedEggs); + + g_vars->swallowedEgg1 = eggvar->getSubVarByName(sO_Egg1); + g_vars->swallowedEgg2 = eggvar->getSubVarByName(sO_Egg2); + g_vars->swallowedEgg3 = eggvar->getSubVarByName(sO_Egg3); + + scene09_setupGrit(sc); + + g_fp->initArcadeKeys("SC_9"); + + g_fp->lift_setButton(sO_Level1, ST_LBN_1N); + + g_fp->setArcadeOverlay(PIC_CSR_ARCADE4); +} + +int sceneHandler09_updateScreenCallback() { + int res = g_fp->drawArcadeOverlay(g_fp->_objectIdAtCursor == ANI_VISUNCHIK || g_vars->scene09_interactingHanger >= 0); + + if (!res) + g_fp->_updateScreenCallback = 0; + + return res; +} + +int scene09_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_vars->scene09_interactingHanger < 0) { + if (g_fp->_objectIdAtCursor == ANI_VISUNCHIK) { + if (g_fp->_cursorId == PIC_CSR_ITN) + g_fp->_updateScreenCallback = sceneHandler09_updateScreenCallback; + } else { + if (g_fp->_objectIdAtCursor == PIC_SC9_LADDER_R && g_fp->_cursorId == PIC_CSR_ITN) + g_fp->_cursorId = (g_vars->scene09_dudeY < 350) ? PIC_CSR_GOD : PIC_CSR_GOU; + } + } else { + g_fp->_cursorId = PIC_CSR_ITN; + } + + return g_fp->_cursorId; +} + +void sceneHandler09_winArcade() { + if (g_vars->scene09_gulper->_flags & 4) { + g_vars->scene09_gulper->changeStatics2(ST_GLT_SIT); + g_vars->scene09_gulper->startAnim(MV_GLT_FLYAWAY, 0, -1); + + g_fp->setObjectState(sO_Jug, g_fp->getObjectEnumState(sO_Jug, sO_Unblocked)); + g_fp->setObjectState(sO_RightStairs_9, g_fp->getObjectEnumState(sO_RightStairs_9, sO_IsOpened)); + + g_vars->scene09_gulperIsPresent = false; + } +} + +void sceneHandler09_startAuntie() { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_TTA9_GOL), 0, 1); + + mq->getExCommandByIndex(0)->_x = g_fp->_sceneRect.right + 30; + mq->chain(0); +} + +void sceneHandler09_spitterClick() { + if (g_vars->scene09_spitter->_flags & 4) { + PicAniInfo info; + + g_vars->scene09_spitter->getPicAniInfo(&info); + g_vars->scene09_spitter->_messageQueueId = 0; + g_vars->scene09_spitter->changeStatics2(ST_PLV_SIT); + + int x = g_vars->scene09_spitter->_ox - 10; + int y = g_vars->scene09_spitter->_oy + 145; + + g_vars->scene09_spitter->setPicAniInfo(&info); + + if (ABS(x - g_fp->_aniMan->_ox) > 1 || ABS(y - g_fp->_aniMan->_oy) > 1) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, x, y, 1, ST_MAN_UP); + + if (mq) { + ExCommand *ex = new ExCommand(0, 17, MSG_SC9_PLVCLICK, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags = 2; + mq->addExCommandToEnd(ex); + + postExCommand(g_fp->_aniMan->_id, 2, x, y, 0, -1); + } + } else { + if (!g_fp->_aniMan->_movement) { + g_vars->scene09_spitter->changeStatics2(ST_PLV_SIT); + g_vars->scene09_spitter->hide(); + + g_fp->_aniMan->startAnim(MV_MAN9_SHOOT, 0, -1); + + g_fp->stopAllSoundInstances(SND_9_006); + } + + g_fp->_aniMan2 = 0; + + if (g_fp->_sceneRect.left < 800) + g_fp->_currentScene->_x = 800 - g_fp->_sceneRect.left; + } + } +} + +void sceneHandler09_eatBall() { + if (g_vars->scene09_flyingBall) { + g_vars->scene09_flyingBall->hide(); + + Ball *ball = g_vars->scene09_balls.pHead; + + if (ball) { + while (ball && ball->ani != g_vars->scene09_flyingBall) + ball = ball->p0; + + if (ball) { + if (ball == g_vars->scene09_balls.pHead) + g_vars->scene09_balls.pHead = ball->p0; + else + ball->p1->p0 = ball->p0; + + if (ball == g_vars->scene09_balls.field_8) + g_vars->scene09_balls.field_8 = ball->p1; + else + ball->p0->p1 = ball->p1; + + ball->p0 = g_vars->scene09_balls.pTail; + g_vars->scene09_balls.pTail = ball; + + g_vars->scene09_balls.numBalls--; + + if (!g_vars->scene09_balls.numBalls) + g_vars->scene09_balls.reset(); + } + } + + ball = g_vars->scene09_flyingBalls.sub04(g_vars->scene09_flyingBalls.field_8, 0); + ball->ani = g_vars->scene09_flyingBall; + + if (g_vars->scene09_flyingBalls.field_8) + g_vars->scene09_flyingBalls.field_8->p0 = ball; + else + g_vars->scene09_flyingBalls.pHead = ball; + + g_vars->scene09_flyingBalls.field_8 = ball; + + g_vars->scene09_flyingBall = 0; + g_vars->scene09_numSwallenBalls++; + + if (g_vars->scene09_numSwallenBalls >= 3) { + MessageQueue *mq = g_vars->scene09_gulper->getMessageQueue(); + + if (mq) { + ExCommand *ex = new ExCommand(ANI_GLOTATEL, 1, MV_GLT_FLYAWAY, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + + mq->addExCommandToEnd(ex); + } + + g_fp->setObjectState(sO_Jug, g_fp->getObjectEnumState(sO_Jug, sO_Unblocked)); + g_fp->setObjectState(sO_RightStairs_9, g_fp->getObjectEnumState(sO_RightStairs_9, sO_IsOpened)); + + g_vars->scene09_gulperIsPresent = false; + } + } +} + +void sceneHandler09_showBall() { + if (g_vars->scene09_flyingBalls.numBalls) { + StaticANIObject *ani = g_vars->scene09_flyingBalls.pHead->ani; + Ball *ph = g_vars->scene09_flyingBalls.pHead; + g_vars->scene09_flyingBalls.pHead = ph->p0; + + if (g_vars->scene09_flyingBalls.pHead) + ph->p0->p1 = 0; + else + g_vars->scene09_flyingBalls.field_8 = 0; + + ph->p0 = g_vars->scene09_flyingBalls.pTail; + + g_vars->scene09_flyingBalls.pTail = ph; + g_vars->scene09_flyingBalls.numBalls--; + + if (!g_vars->scene09_flyingBalls.numBalls) { + g_vars->scene09_flyingBalls.numBalls = 0; + g_vars->scene09_flyingBalls.pTail = 0; + g_vars->scene09_flyingBalls.field_8 = 0; + g_vars->scene09_flyingBalls.pHead = 0; + + free(g_vars->scene09_flyingBalls.cPlex); + g_vars->scene09_flyingBalls.cPlex = 0; + } + + Ball *ball = g_vars->scene09_balls.sub04(g_vars->scene09_balls.field_8, 0); + ball->ani = ani; + + if (g_vars->scene09_balls.field_8) + g_vars->scene09_balls.field_8->p0 = ball; + else + g_vars->scene09_balls.pHead = ball; + + g_vars->scene09_balls.field_8 = ball; + + ani->show1(g_fp->_aniMan->_ox + 94, g_fp->_aniMan->_oy - 162, MV_BALL9_EXPLODE, 0); + } +} + +void sceneHandler09_cycleHangers() { + for (int i = 0; i < g_vars->scene09_numMovingHangers; i++) { + Movement *mov = g_vars->scene09_hangers[i]->ani->_movement; + + if (mov && mov->_id == MV_VSN_CYCLE2) { + int idx; + + if (g_vars->scene09_hangers[i]->phase >= 0) + idx = 18 - g_vars->scene09_hangers[i]->phase / 5; + else + idx = 18 - g_vars->scene09_hangers[i]->phase * 10 / 43; + + if (idx > 38) + idx = 38; + + if (idx < 1) + idx = 1; + + mov->setDynamicPhaseIndex(idx); + } + } +} + +void sceneHandler09_limitHangerPhase() { + for (int i = 0; i < g_vars->scene09_numMovingHangers; i++) { + if (i != g_vars->scene09_interactingHanger) { + g_vars->scene09_hangers[i]->phase += g_vars->scene09_hangers[i]->field_8; + + if (g_vars->scene09_hangers[i]->phase > 85) + g_vars->scene09_hangers[i]->phase = 85; + + if (g_vars->scene09_hangers[i]->phase < -85) + g_vars->scene09_hangers[i]->phase = -85; + + if (g_vars->scene09_hangers[i]->phase < 0) + g_vars->scene09_hangers[i]->field_8++; + + if (g_vars->scene09_hangers[i]->phase > 0) + g_vars->scene09_hangers[i]->field_8--; + } + } +} + +void sceneHandler09_collideBall(Ball *ball) { + if (g_vars->scene09_gulperIsPresent) { + g_vars->scene09_flyingBall = ball->ani; + + if (g_vars->scene09_gulper) { + g_vars->scene09_gulper->changeStatics2(ST_GLT_SIT); + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC9_EATBALL), 0, 0); + + mq->setFlags(mq->getFlags() | 1); + + if (!mq->chain(g_vars->scene09_gulper)) + delete mq; + } + } +} + +void sceneHandler09_ballExplode(Ball *ball) { + if (ball == g_vars->scene09_balls.pHead) + g_vars->scene09_balls.pHead = ball->p0; + else + ball->p1->p0 = ball->p0; + + if (ball == g_vars->scene09_balls.field_8) + g_vars->scene09_balls.field_8 = ball->p1; + else + ball->p0->p1 = ball->p1; + + ball->p0 = g_vars->scene09_balls.pTail; + + g_vars->scene09_balls.pTail = ball; + g_vars->scene09_balls.numBalls--; + + if (!g_vars->scene09_balls.numBalls) { + g_vars->scene09_balls.pTail = 0; + g_vars->scene09_balls.field_8 = 0; + g_vars->scene09_balls.pHead = 0; + free(g_vars->scene09_balls.cPlex); + g_vars->scene09_balls.cPlex = 0; + } + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC9_BALLEXPLODE), 0, 1); + + mq->replaceKeyCode(-1, ball->ani->_okeyCode); + + if (!mq->chain(ball->ani)) + delete mq; + + Ball *runPtr = g_vars->scene09_flyingBalls.pTail; + Ball *lastP = g_vars->scene09_flyingBalls.field_8; + + if (!g_vars->scene09_flyingBalls.pTail) { + g_vars->scene09_flyingBalls.cPlex = (byte *)calloc(g_vars->scene09_flyingBalls.cPlexLen, sizeof(Ball)); + + byte *p1 = g_vars->scene09_flyingBalls.cPlex + (g_vars->scene09_flyingBalls.cPlexLen - 1) * sizeof(Ball); + + if (g_vars->scene09_flyingBalls.cPlexLen - 1 < 0) { + runPtr = g_vars->scene09_flyingBalls.pTail; + } else { + runPtr = g_vars->scene09_flyingBalls.pTail; + + for (int j = 0; j < g_vars->scene09_flyingBalls.cPlexLen; j++) { + ((Ball *)p1)->p1 = runPtr; + runPtr = (Ball *)p1; + + p1 -= sizeof(Ball); + } + + g_vars->scene09_flyingBalls.pTail = runPtr; + } + } + + g_vars->scene09_flyingBalls.pTail = runPtr->p0; + runPtr->p1 = lastP; + runPtr->p0 = 0; + runPtr->ani = ball->ani; + + g_vars->scene09_flyingBalls.numBalls++; + + if (g_vars->scene09_flyingBalls.field_8) { + g_vars->scene09_flyingBalls.field_8->p0 = runPtr; + g_vars->scene09_flyingBalls.field_8 = runPtr; + } else { + g_vars->scene09_flyingBalls.pHead = runPtr; + g_vars->scene09_flyingBalls.field_8 = runPtr; + } +} + +void sceneHandler09_checkHangerCollide() { + for (Ball *ball = g_vars->scene09_balls.pHead; ball; ball = ball->p0) { + int newx = ball->ani->_ox + 5; + + ball->ani->setOXY(newx, ball->ani->_oy); + + if (newx <= 1398 || g_vars->scene09_flyingBall) { + if (g_vars->scene09_gulperIsPresent) + goto LABEL_11; + } else if (g_vars->scene09_gulperIsPresent) { + sceneHandler09_collideBall(ball); + continue; + } + + if (newx > 1600) { + sceneHandler09_ballExplode(ball); + continue; + } + + LABEL_11: + int pixel; + + for (int i = 0; i < g_vars->scene09_numMovingHangers; i++) { + for (int j = 0; j < 4; j++) { + g_vars->scene09_hangers[i]->ani->getPixelAtPos(newx + g_vars->scene09_hangerOffsets[j].x, ball->ani->_oy + g_vars->scene09_hangerOffsets[j].y, &pixel); + + if (pixel) { + sceneHandler09_ballExplode(ball); + break; + } + } + } + } +} + +void sceneHandler09_hangerStartCycle() { + StaticANIObject *ani = g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->ani; + + if (ani->_movement) { + ani->startAnim(MV_VSN_CYCLE2, 0, -1); + g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->field_8 = 0; + g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->phase = g_vars->scene09_intHangerPhase + (g_fp->_mouseScreenPos.y - g_vars->scene09_clickY) / 2; + + if (g_vars->scene09_intHangerMaxPhase != -1000 && g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->phase != g_vars->scene09_intHangerMaxPhase) { + ExCommand *ex = new ExCommand(0, 35, SND_9_019, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_14 = 1; + ex->_excFlags |= 2; + ex->postMessage(); + + g_vars->scene09_intHangerMaxPhase = -1000; + } + } else { + g_vars->scene09_interactingHanger = -1; + } +} + +int sceneHandler09(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_CMN_WINARCADE: + sceneHandler09_winArcade(); + break; + + case MSG_SC9_STARTTIOTIA: + sceneHandler09_startAuntie(); + break; + + case MSG_SC9_FROMLADDER: + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + g_vars->scene09_dudeIsOnLadder = false; + break; + + case MSG_SC9_TOLADDER: + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + g_vars->scene09_dudeIsOnLadder = true; + break; + + case MSG_SC9_PLVCLICK: + sceneHandler09_spitterClick(); + break; + + case MSG_SC9_FLOWN: + g_vars->scene09_gulperIsPresent = false; + break; + + case MSG_SC9_EATBALL: + sceneHandler09_eatBall(); + break; + + case MSG_SC9_SHOWBALL: + sceneHandler09_showBall(); + break; + + case 33: + { + int res = 0; + + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + g_vars->scene09_dudeY = g_fp->_aniMan2->_oy; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - g_fp->_sceneRect.left - 300; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x - g_fp->_sceneRect.right + 300; + + res = 1; + } else { + if (g_fp->_aniMan->_movement && g_fp->_aniMan->_movement->_id != MV_MAN9_SHOOT) + g_fp->_aniMan2 = g_fp->_aniMan; + } + + sceneHandler09_cycleHangers(); + sceneHandler09_limitHangerPhase(); + sceneHandler09_checkHangerCollide(); + + if (g_vars->scene09_interactingHanger >= 0) + sceneHandler09_hangerStartCycle(); + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + return res; + } + + case 30: + if (g_vars->scene09_interactingHanger >= 0) { + if (ABS(g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->phase) < 15) { + g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->ani->_callback2 = 0; + g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->ani->changeStatics2(ST_VSN_NORMAL); + } + } + + g_vars->scene09_interactingHanger = -1; + + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (ani) { + if (ani->_id == ANI_PLEVATEL) { + sceneHandler09_spitterClick(); + break; + } + + if (ani->_id == ANI_VISUNCHIK) { + if (g_vars->scene09_numMovingHangers > 0) { + int hng = 0; + + while (g_vars->scene09_hangers[hng]->ani != ani) { + ++hng; + + if (hng >= g_vars->scene09_numMovingHangers) + break; + } + + g_vars->scene09_interactingHanger = hng; + g_vars->scene09_intHangerPhase = g_vars->scene09_hangers[hng]->phase; + g_vars->scene09_intHangerMaxPhase = g_vars->scene09_hangers[hng]->phase; + + g_vars->scene09_clickY = cmd->_y; + + if (!g_vars->scene09_hangers[hng]->ani->_movement || g_vars->scene09_hangers[hng]->ani->_movement->_id != MV_VSN_CYCLE2) { + g_vars->scene09_hangers[hng]->ani->changeStatics2(ST_VSN_NORMAL); + g_vars->scene09_hangers[hng]->ani->startAnim(MV_VSN_CYCLE2, 0, -1); + g_vars->scene09_hangers[hng]->ani->_callback2 = 0; + } + + ExCommand *ex = new ExCommand(0, 35, SND_9_018, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_14 = 1; + ex->_excFlags |= 2; + ex->postMessage(); + } + + break; + } + } + + if (g_vars->scene09_dudeIsOnLadder && g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY) == PIC_SC9_LADDER_R + && !cmd->_keyCode && !g_fp->_aniMan->_movement) { + handleObjectInteraction(g_fp->_aniMan, g_fp->_currentScene->getPictureObjectById(PIC_SC9_LADDER_R, 0), 0); + } + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) + g_fp->processArcade(cmd); + } + } + + break; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene10.cpp b/engines/fullpipe/scenes/scene10.cpp new file mode 100644 index 0000000000..3e2a918b64 --- /dev/null +++ b/engines/fullpipe/scenes/scene10.cpp @@ -0,0 +1,220 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/behavior.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +void scene10_initScene(Scene *sc) { + g_vars->scene10_gum = sc->getStaticANIObject1ById(ANI_GUM, -1); + g_vars->scene10_packet = sc->getStaticANIObject1ById(ANI_PACHKA, -1); + g_vars->scene10_packet2 = sc->getStaticANIObject1ById(ANI_PACHKA2, -1); + g_vars->scene10_inflater = sc->getStaticANIObject1ById(ANI_NADUVATEL, -1); + g_vars->scene10_ladder = sc->getPictureObjectById(PIC_SC10_LADDER, 0); + + g_fp->lift_setButton(sO_Level1, ST_LBN_1N); + g_fp->lift_init(sc, QU_SC10_ENTERLIFT, QU_SC10_EXITLIFT); + + if (g_fp->getObjectState(sO_Inflater) == g_fp->getObjectEnumState(sO_Inflater, sO_WithGum)) { + g_vars->scene10_hasGum = 1; + } else { + g_vars->scene10_hasGum = 0; + g_vars->scene10_gum->hide(); + } +} + +bool sceneHandler10_inflaterIsBlind() { + return g_vars->scene10_inflater->_movement + && g_vars->scene10_inflater->_movement->_id == MV_NDV_BLOW2 + && g_vars->scene10_inflater->_movement->_currDynamicPhaseIndex < 42; +} + +int scene10_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_objectIdAtCursor == ANI_PACHKA || g_fp->_objectIdAtCursor == ANI_GUM) { + if (g_fp->_cursorId == PIC_CSR_ITN) { + if (g_vars->scene10_hasGum) + g_fp->_cursorId = (sceneHandler10_inflaterIsBlind() != 0) ? PIC_CSR_ITN_RED : PIC_CSR_ITN_GREEN; + else + g_fp->_cursorId = PIC_CSR_DEFAULT; + } + } + + return g_fp->_cursorId; +} + +void sceneHandler10_clickGum() { + if (g_vars->scene10_hasGum) { + if (sceneHandler10_inflaterIsBlind()) { + if (g_vars->scene10_hasGum) { + int x = g_vars->scene10_gum->_ox - 139; + int y = g_vars->scene10_gum->_oy - 48; + + if (abs(x - g_fp->_aniMan->_ox) > 1 || abs(y - g_fp->_aniMan->_oy) > 1) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, x, y, 1, ST_MAN_RIGHT); + if (mq) { + ExCommand *ex = new ExCommand(0, 17, MSG_SC10_CLICKGUM, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags = 2; + mq->addExCommandToEnd(ex); + + postExCommand(g_fp->_aniMan->_id, 2, x, y, 0, -1); + } + } else { + g_vars->scene10_hasGum = 0; + + chainQueue(QU_SC10_TAKEGUM, 1); + } + } + } else { + g_vars->scene10_inflater->changeStatics2(ST_NDV_SIT); + + if (g_fp->getObjectState(sO_Inflater) == g_fp->getObjectEnumState(sO_Inflater, sO_WithGum)) + g_vars->scene10_inflater->startAnim(MV_NDV_DENIES, 0, -1); + else + g_vars->scene10_inflater->startAnim(MV_NDV_DENY_NOGUM, 0, -1); + } + } +} + +void sceneHandler10_hideGum() { + g_vars->scene10_gum->hide(); + g_vars->scene10_packet->hide(); + g_vars->scene10_packet2->hide(); +} + +void sceneHandler10_showGum() { + if (g_vars->scene10_hasGum) + g_vars->scene10_gum->show1(-1, -1, -1, 0); + + g_vars->scene10_packet->show1(-1, -1, -1, 0); + g_vars->scene10_packet2->show1(-1, -1, -1, 0); +} + + +int sceneHandler10(ExCommand *ex) { + if (ex->_messageKind != 17) + return 0; + + switch(ex->_messageNum) { + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(ex); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC10_LADDERTOBACK: + g_vars->scene10_ladder->_priority = 49; + break; + + case MSG_SC10_LADDERTOFORE: + g_vars->scene10_ladder->_priority = 0; + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case MSG_SC10_CLICKGUM: + sceneHandler10_clickGum(); + + ex->_messageKind = 0; + break; + + case MSG_SC10_HIDEGUM: + sceneHandler10_hideGum(); + break; + + case MSG_SC10_SHOWGUM: + sceneHandler10_showGum(); + break; + + case 64: + g_fp->lift_hoverButton(ex); + break; + + case 29: + { + if (g_fp->_currentScene->getPictureObjectIdAtPos(ex->_sceneClickX, ex->_sceneClickY) == PIC_SC10_LADDER) { + handleObjectInteraction(g_fp->_aniMan, g_fp->_currentScene->getPictureObjectById(PIC_SC10_DTRUBA, 0), ex->_keyCode); + ex->_messageKind = 0; + + return 0; + } + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(ex->_sceneClickX, ex->_sceneClickY); + + if (ani && ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_animateButton(ani); + ex->_messageKind = 0; + + return 0; + } + } + break; + + case 33: + { + int res = 0; + + if (g_fp->_aniMan2) { + if (g_fp->_aniMan2->_ox < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.left - 300; + + if (g_fp->_aniMan2->_ox > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.right + 300; + + res = 1; + } + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + return res; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene11.cpp b/engines/fullpipe/scenes/scene11.cpp new file mode 100644 index 0000000000..1fa5cabc15 --- /dev/null +++ b/engines/fullpipe/scenes/scene11.cpp @@ -0,0 +1,786 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene11_dudeSwingCallback(int *arg) { + int oldarg = *arg; + + *arg = 45 - (int)(g_vars->scene11_swingAngle * -29.66666666666666); + + if (*arg < 1) + *arg = 1; + + if (*arg > 90) + *arg = 90; + + g_vars->scene11_swingAngleDiff = (g_vars->scene11_swingAngle - g_vars->scene11_swingOldAngle) * -490.0000000000001; + g_vars->scene11_swingSpeed = g_vars->scene11_swingAngleDiff * 0.0042 + g_vars->scene11_swingSpeed - g_vars->scene11_swingInertia * (g_vars->scene11_swingAngleDiff * 0.0042 + g_vars->scene11_swingSpeed); + g_vars->scene11_swingAngle = g_vars->scene11_swingSpeed * 0.0042 + g_vars->scene11_swingAngle; + + if (g_vars->scene11_swingAngle < -1.5) { + g_vars->scene11_swingAngle = -1.5; //1.0004882812500000; + g_vars->scene11_swingSpeed = 0.0; + g_vars->scene11_swingAngleDiff = 0.0; + } + + if (g_vars->scene11_swingAngle > 1.5) { + g_vars->scene11_swingAngle = 1.5; //1.9990234375; + g_vars->scene11_swingSpeed = 0.0; + g_vars->scene11_swingAngleDiff = 0.0; + } + + if (g_vars->scene11_swingMaxAngle == *arg && 0.0 != g_vars->scene11_swingSpeed && fabs(g_vars->scene11_swingSpeed) < 2.5) { + g_vars->scene11_swingSpeed = 0.0; + g_vars->scene11_swingAngleDiff = 0.0; + g_vars->scene11_swingAngle = g_vars->scene11_swingOldAngle; + } + + g_vars->scene11_swingCounter++; + + if (g_vars->scene11_arcadeIsOn) { + if (g_vars->scene11_hintCounter <= 720) { + g_vars->scene11_hintCounter++; + + if (g_vars->scene11_hintCounter == 720) + g_vars->scene11_hint->_flags |= 4; + } + } + + if ((oldarg >= 45) != (*arg >= 45) && g_vars->scene11_arcadeIsOn) { + if (oldarg >= *arg) + g_fp->playSound(SND_11_031, 0); + else + g_fp->playSound(SND_11_020, 0); + } +} + +void scene11_setupMusic() { + if (g_fp->getObjectState(sO_DudeHasJumped) == g_fp->getObjectEnumState(sO_DudeHasJumped, sO_Yes)) + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_11"), "MUSIC2", 1); +} + +void scene11_initScene(Scene *sc) { + g_vars->scene11_swingie = sc->getStaticANIObject1ById(ANI_SWINGER, -1); + g_vars->scene11_boots = sc->getStaticANIObject1ById(ANI_BOOTS_11, -1); + g_vars->scene11_mgm.clear(); + g_vars->scene11_dudeOnSwing = sc->getStaticANIObject1ById(ANI_MAN11, -1); + g_vars->scene11_dudeOnSwing->_callback2 = scene11_dudeSwingCallback; + g_vars->scene11_dudeOnSwing = sc->getStaticANIObject1ById(ANI_KACHELI, -1); + g_vars->scene11_dudeOnSwing->_callback2 = scene11_dudeSwingCallback; + g_vars->scene11_hint = sc->getPictureObjectById(PIC_SC11_HINT, 0); + g_vars->scene11_hint->_flags &= 0xFFFB; + + g_vars->scene11_arcadeIsOn = false; + g_vars->scene11_scrollIsEnabled = false; + g_vars->scene11_scrollIsMaximized = false; + g_vars->scene11_hintCounter = 0; + g_vars->scene11_swingieScreenEdge = 0; + g_vars->scene11_crySound = 0; + g_vars->scene11_swingAngle = 0.0; + g_vars->scene11_swingOldAngle = 0.0; + g_vars->scene11_swingSpeed = 0.0; + g_vars->scene11_swingAngleDiff = 0.0; + g_vars->scene11_swingInertia = 1.28; //1.9849218750000000; + g_vars->scene11_swingCounter = 0; + g_vars->scene11_swingCounterPrevTurn = 0; + g_vars->scene11_swingDirection = 0; + g_vars->scene11_swingDirectionPrevTurn = 0; + + Scene *oldsc = g_fp->_currentScene; + + g_fp->_currentScene = sc; + + int swingie = g_fp->getObjectState(sO_Swingie); + + if (swingie == g_fp->getObjectEnumState(sO_Swingie, sO_IsSwinging) + || swingie == g_fp->getObjectEnumState(sO_Swingie, sO_IsSwingingWithBoot)) { + g_vars->scene11_swingIsSwinging = true; + g_vars->scene11_swingieStands = false; + + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing1, 1); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing2, 1); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing3, 0); + + ((MctlCompound *)getCurrSceneSc2MotionController())->replaceNodeX(805, 905); + + getSc2MctlCompoundBySceneId(sc->_sceneId)->replaceNodeX(303, 353); + } else if (swingie == g_fp->getObjectEnumState(sO_Swingie, sO_IsStandingInBoots) + || swingie == g_fp->getObjectEnumState(sO_Swingie, sO_IsStandingInCorner)) { + g_vars->scene11_swingIsSwinging = false; + g_vars->scene11_swingieStands = true; + + g_vars->scene11_swingie->changeStatics2(ST_SWR_STAND3); + + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing1, 0); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing2, 1); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing3, 0); + + ((MctlCompound *)getCurrSceneSc2MotionController())->replaceNodeX(905, 805); + } else { + g_vars->scene11_swingIsSwinging = false; + g_vars->scene11_swingieStands = false; + + if (swingie == g_fp->getObjectEnumState(sO_Swingie, sO_IsSitting)) { + g_vars->scene11_swingie->_movement = 0; + g_vars->scene11_swingie->_statics = g_vars->scene11_swingie->getStaticsById(ST_SWR_SIT); + g_vars->scene11_swingie->setOXY(144, 389); + + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing1, 0); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing2, 0); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing3, 1); + } else { + g_vars->scene11_swingie->_movement = 0; + g_vars->scene11_swingie->_statics = g_vars->scene11_swingie->getStaticsById(ST_SWR_SITBALD); + g_vars->scene11_swingie->setOXY(144, 415); + + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing1, 0); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing2, 0); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing3, 1); + } + } + + if (!g_vars->scene11_swingIsSwinging) { + g_vars->scene11_dudeOnSwing->changeStatics2(ST_KCH_STATIC); + g_vars->scene11_dudeOnSwing->setOXY(691, 371); + g_vars->scene11_dudeOnSwing->_priority = 20; + + g_vars->scene11_dudeOnSwing->_flags |= 4; + } + + g_fp->_currentScene = oldsc; + + g_fp->initArcadeKeys("SC_11"); + g_fp->setArcadeOverlay(PIC_CSR_ARCADE5); +} + +void sceneHandler11_restartMan() { + chainObjQueue(0, QU_SC11_RESTARTMAN, 1); + + getGameLoaderInteractionController()->enableFlag24(); + getCurrSceneSc2MotionController()->activate(); + + g_vars->scene11_scrollIsEnabled = false; +} + +void sceneHandler11_hitMan() { + if (g_fp->_aniMan->_ox > 345 && g_fp->_aniMan->_ox < 355) { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT); + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC11_MANFALL), 0, 0); + + mq->setFlags(mq->getFlags() | 1); + if (!mq->chain(g_fp->_aniMan)) + delete mq; + + getCurrSceneSc2MotionController()->replaceNodeX(353, 303); + } +} + +int scene11_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_vars->scene11_arcadeIsOn) { + if (g_fp->_cursorId != PIC_CSR_DEFAULT_INV && g_fp->_cursorId != PIC_CSR_ITN_INV) + g_fp->_cursorId = -1; + } else if (g_vars->scene11_swingie == g_fp->_objectAtCursor && g_fp->_inventory->getSelectedItemId() == ANI_INV_BOOT) + g_fp->_cursorId = PIC_CSR_ITN_INV; + + return g_fp->_cursorId; +} + +int sceneHandler11_updateScreenCallback() { + int res = g_fp->drawArcadeOverlay(g_vars->scene11_arcadeIsOn); + + if (!res) + g_fp->_updateScreenCallback = 0; + + return res; +} + +void sceneHandler11_manToSwing() { + g_vars->scene11_arcadeIsOn = true; + + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_aniMan2->hide(); + + g_vars->scene11_swingCounter = 0; + g_vars->scene11_swingInertia = 1.28; //1.9849218; + + g_vars->scene11_dudeOnSwing->_flags &= 0xFFFB; + g_vars->scene11_dudeOnSwing = g_fp->_currentScene->getStaticANIObject1ById(ANI_MAN11, -1); + g_vars->scene11_dudeOnSwing->_statics = g_vars->scene11_dudeOnSwing->getStaticsById(ST_MAN11_EMPTY); + g_vars->scene11_dudeOnSwing->_movement = 0; + g_vars->scene11_dudeOnSwing->show1(690, 215, MV_MAN11_SWING_0, 0); + g_vars->scene11_dudeOnSwing->_priority = 20; + g_vars->scene11_dudeOnSwing->startAnim(MV_MAN11_SWING_0, 0, -1); + g_vars->scene11_dudeOnSwing->_movement->setDynamicPhaseIndex(45); + + g_vars->scene11_mgm.addItem(g_fp->_aniMan->_id); + + g_fp->_currentScene->_x = 1400 - g_fp->_sceneRect.right; + + g_vars->scene11_scrollIsEnabled = true; + g_fp->_updateScreenCallback = sceneHandler11_updateScreenCallback; +} + +void sceneHandler11_putABoot() { + if (g_vars->scene11_boots->_flags & 4) { + if (g_vars->scene11_boots->_statics->_staticsId == ST_BTS11_ONE) + chainObjQueue(0, QU_SC11_PUTBOOT2, 1); + } else { + chainObjQueue(0, QU_SC11_PUTBOOT1, 1); + } +} + +void sceneHandler11_putBoot() { + if (abs(353 - g_fp->_aniMan->_ox) > 1 || abs(498 - g_fp->_aniMan->_oy) > 1 + || g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 353, 498, 1, ST_MAN_RIGHT); + + if (mq) { + ExCommand *ex = new ExCommand(0, 17, MSG_SC11_PUTBOOT, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + + mq->addExCommandToEnd(ex); + + postExCommand(g_fp->_aniMan->_id, 2, 353, 498, 0, -1); + } + } else { + sceneHandler11_putABoot(); + } +} + +void sceneHandler11_showSwing() { + g_vars->scene11_dudeOnSwing = g_fp->_currentScene->getStaticANIObject1ById(ANI_KACHELI, -1); + g_vars->scene11_dudeOnSwing->_statics = g_vars->scene11_dudeOnSwing->getStaticsById(ST_KCH_0); + g_vars->scene11_dudeOnSwing->_movement = 0; + g_vars->scene11_dudeOnSwing->show1(691, 371, MV_KCH_START, 0); + g_vars->scene11_dudeOnSwing->_priority = 20; +} + +void sceneHandler11_jumpFromSwing() { + g_vars->scene11_arcadeIsOn = false; + g_vars->scene11_hint->_flags &= 0xFFFB; + g_vars->scene11_scrollIsEnabled = false; + + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + g_vars->scene11_swingOldAngle = 0.0; + g_vars->scene11_swingAngleDiff = 0.0; + g_vars->scene11_swingSpeed = 0.0; + g_vars->scene11_swingAngle = 0.0; + + g_vars->scene11_dudeOnSwing = g_fp->_currentScene->getStaticANIObject1ById(ANI_MAN11, -1); + g_vars->scene11_dudeOnSwing->_flags &= 0xFFFB; + g_vars->scene11_dudeOnSwing = g_fp->_currentScene->getStaticANIObject1ById(ANI_KACHELI, -1); + g_vars->scene11_dudeOnSwing->changeStatics2(ST_KCH_STATIC); + g_vars->scene11_dudeOnSwing->setOXY(691, 371); + g_vars->scene11_dudeOnSwing->_priority = 20; + g_vars->scene11_dudeOnSwing->_flags |= 4; + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + ExCommand *ex = new ExCommand(g_fp->_aniMan->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); + ex->_field_14 = 256; + ex->_messageNum = 0; + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + mq->setFlags(mq->getFlags() | 1); + + g_fp->_globalMessageQueueList->addMessageQueue(mq); + + g_fp->_aniMan->_flags |= 0x104; + g_fp->_aniMan->changeStatics2(ST_MAN11_SWING); + g_fp->_aniMan->setOXY(685, 373); + g_fp->_aniMan->startAnim(MV_MAN11_JUMPFROMSWING, mq->_id, -1); + + g_fp->_aniMan2 = g_fp->_aniMan; +} + +void sceneHandler11_swing0() { + g_vars->scene11_dudeOnSwing->_statics = g_vars->scene11_dudeOnSwing->getStaticsById(ST_MAN11_EMPTY); + g_vars->scene11_dudeOnSwing->_movement = 0; + g_vars->scene11_dudeOnSwing->show1(690, 215, MV_MAN11_SWING_0, 0); + g_vars->scene11_dudeOnSwing->startAnim(MV_MAN11_SWING_0, 0, -1); + g_vars->scene11_dudeOnSwing->_movement->setDynamicPhaseIndex(g_vars->scene11_dudeOnSwing->_movement->_currDynamicPhaseIndex); + + g_vars->scene11_swingDirection = 0; + g_vars->scene11_swingMaxAngle = 45; + g_vars->scene11_swingOldAngle = 0.0; +} + +void sceneHandler11_swing1() { + g_vars->scene11_dudeOnSwing->_statics = g_vars->scene11_dudeOnSwing->getStaticsById(ST_MAN11_EMPTY); + g_vars->scene11_dudeOnSwing->_movement = 0; + g_vars->scene11_dudeOnSwing->show1(690, 215, MV_MAN11_SWING_1, 0); + g_vars->scene11_dudeOnSwing->startAnim(MV_MAN11_SWING_1, 0, -1); + g_vars->scene11_dudeOnSwing->_movement->setDynamicPhaseIndex(g_vars->scene11_dudeOnSwing->_movement->_currDynamicPhaseIndex); + + g_vars->scene11_swingDirection = 1; + g_vars->scene11_swingMaxAngle = 42; + g_vars->scene11_swingOldAngle = -(fabs(g_vars->scene11_swingAngle) * 0.075 + 0.12); +} + +void sceneHandler11_swing2() { + g_vars->scene11_dudeOnSwing->_statics = g_vars->scene11_dudeOnSwing->getStaticsById(ST_MAN11_EMPTY); + g_vars->scene11_dudeOnSwing->_movement = 0; + g_vars->scene11_dudeOnSwing->show1(690, 215, MV_MAN11_SWING_2, 0); + g_vars->scene11_dudeOnSwing->startAnim(MV_MAN11_SWING_2, 0, -1); + g_vars->scene11_dudeOnSwing->_movement->setDynamicPhaseIndex(g_vars->scene11_dudeOnSwing->_movement->_currDynamicPhaseIndex); + + g_vars->scene11_swingDirection = 2; + g_vars->scene11_swingMaxAngle = 48; + g_vars->scene11_swingOldAngle = fabs(g_vars->scene11_swingAngle) * 0.075 + 0.12; +} + +void sceneHandler11_emptySwing() { + if (g_vars->scene11_swingDirection) + sceneHandler11_swing0(); + + g_vars->scene11_dudeOnSwing->stopAnim_maybe(); + g_vars->scene11_dudeOnSwing->hide(); + g_vars->scene11_dudeOnSwing = g_fp->_currentScene->getStaticANIObject1ById(ANI_KACHELI, -1); + g_vars->scene11_dudeOnSwing->show1(-1, -1, -1, 0); + g_vars->scene11_dudeOnSwing->changeStatics2(ST_KCH_EMPTY); + g_vars->scene11_dudeOnSwing->startAnim(MV_KCH_MOVE2, 0, -1); + g_vars->scene11_dudeOnSwing->_movement->setDynamicPhaseIndex(g_vars->scene11_dudeOnSwing->_movement->_currDynamicPhaseIndex); + + g_vars->scene11_swingInertia = 0.03; //1.9881250; +} + +void sceneHandler11_jumpHitAndWin() { + MGMInfo mgminfo; + + sceneHandler11_emptySwing(); + + g_fp->_aniMan->show1(690 - (int)(sin(g_vars->scene11_swingAngle) * -267.0), 215 - (int)(cos(g_vars->scene11_swingAngle) * -267.0), + MV_MAN11_JUMPHIT, 0); + g_fp->_aniMan->_priority = 10; + + mgminfo.field_1C = 10; + mgminfo.ani = g_fp->_aniMan; + mgminfo.staticsId2 = ST_MAN_1PIX; + mgminfo.x1 = 1400; + mgminfo.y1 = 0; + mgminfo.field_10 = 1; + mgminfo.flags = 66; + mgminfo.movementId = MV_MAN11_JUMPHIT; + + MessageQueue *mq = g_vars->scene11_mgm.genMovement(&mgminfo); + + if (mq) { + g_vars->scene11_crySound = SND_11_024; + ExCommand *ex = new ExCommand(ANI_MAN, 2, 36, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = -1; + ex->_excFlags = 2; + + mq->addExCommandToEnd(ex); + + ex = new ExCommand(SC_11, 17, 61, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = TrubaRight; + ex->_excFlags = 3; + + mq->addExCommandToEnd(ex); + + if (!mq->chain(g_fp->_aniMan)) + delete mq; + + + if (g_fp->getObjectState(sO_Swingie) == g_fp->getObjectEnumState(sO_Swingie, sO_IsStandingInCorner)) + g_fp->setObjectState(sO_Swingie, g_fp->getObjectEnumState(sO_Swingie, sO_IsSitting)); + + g_fp->setObjectState(sO_DudeHasJumped, g_fp->getObjectEnumState(sO_DudeHasJumped, sO_Yes)); + } +} + +void sceneHandler11_jumpOver(double angle) { + MGMInfo mgminfo; + + sceneHandler11_emptySwing(); + + g_fp->_aniMan->show1(690 - (int)(sin(g_vars->scene11_swingAngle) * -267.0), 215 - (int)(cos(g_vars->scene11_swingAngle) * -267.0), + MV_MAN11_JUMPOVER, 0); + g_fp->_aniMan->_priority = 0; + + mgminfo.staticsId2 = ST_MAN_1PIX; + mgminfo.ani = g_fp->_aniMan; + mgminfo.x1 = 1163; + mgminfo.y1 = 837 - (int)(angle * 153.0); + mgminfo.field_1C = 0; + mgminfo.field_10 = 1; + mgminfo.flags = 78; + mgminfo.movementId = MV_MAN11_JUMPOVER; + + MessageQueue *mq = g_vars->scene11_mgm.genMovement(&mgminfo); + + if (mq) { + g_vars->scene11_crySound = SND_11_022; + + ExCommand *ex = new ExCommand(0, 17, MSG_SC11_RESTARTMAN, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags = 2; + + mq->addExCommandToEnd(ex); + + if (!mq->chain(g_fp->_aniMan)) + delete mq; + } +} + +void sceneHandler11_jumpHit(double angle) { + MGMInfo mgminfo; + + sceneHandler11_emptySwing(); + + if (angle >= 0.0) { + if (angle > 1.0) + angle = 1.0; + } else { + angle = 0.0; + } + + g_fp->_aniMan->show1(690 - (int)(sin(g_vars->scene11_swingAngle) * -267.0), 215 - (int)(cos(g_vars->scene11_swingAngle) * -267.0), + MV_MAN11_JUMPOVER, 0); + g_fp->_aniMan->_priority = 0; + + mgminfo.staticsId2 = ST_MAN_1PIX; + mgminfo.ani = g_fp->_aniMan; + mgminfo.x1 = 1017 - (int)(angle * -214.0); + mgminfo.y1 = 700; + mgminfo.field_1C = 0; + mgminfo.field_10 = 1; + mgminfo.flags = 78; + mgminfo.movementId = MV_MAN11_JUMPHIT; + + MessageQueue *mq = g_vars->scene11_mgm.genMovement(&mgminfo); + + if (mq) { + g_vars->scene11_crySound = SND_11_022; + + ExCommand *ex = new ExCommand(0, 17, MSG_SC11_RESTARTMAN, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags = 2; + + mq->addExCommandToEnd(ex); + + if (!mq->chain(g_fp->_aniMan)) + delete mq; + + } +} + +void sceneHandler11_swingLogic() { + if (g_vars->scene11_dudeOnSwing->_movement) { + int ph = g_vars->scene11_dudeOnSwing->_movement->_currDynamicPhaseIndex; + if (ph > 53 && ph < 90) { + if (ph < 70 && g_vars->scene11_swingSpeed >= 22.0) { + sceneHandler11_jumpOver((double)ph * 0.01428571428571429); // = 1 / 70 + } else if (ph <= 80 && g_vars->scene11_swingSpeed >= 22.0) { + sceneHandler11_jumpHitAndWin(); + } else { + sceneHandler11_jumpHit((double)ph * g_vars->scene11_swingSpeed * 0.0006493506493506494); // = 1/1540 + } + + g_vars->scene11_arcadeIsOn = false; + g_vars->scene11_hint->_flags &= 0xFFFB; + return; + } + + if (ph > 38 && ph < 53 && fabs(g_vars->scene11_swingSpeed) <= 5.0) + sceneHandler11_jumpFromSwing(); + } +} + +void sceneHandler11_setSwingDirection() { + if (g_vars->scene11_swingDirection == 2) + g_vars->scene11_swingDirectionPrevTurn = 1; + else if (g_vars->scene11_swingDirection == 1) + g_vars->scene11_swingDirectionPrevTurn = 2; + else + g_vars->scene11_swingDirectionPrevTurn = (g_vars->scene11_dudeOnSwing->_movement->_currDynamicPhaseIndex <= 45) + 1; +} + +void sceneHandler11_swingieSit() { + if (g_fp->getObjectState(sO_Swingie) == g_fp->getObjectEnumState(sO_Swingie, sO_IsStandingInBoots)) { + g_vars->scene11_swingIsSwinging = false; + g_vars->scene11_swingieStands = false; + + g_vars->scene11_swingie->changeStatics2(ST_SWR_SIT); + g_vars->scene11_swingie->setOXY(144, 389); + + g_fp->setObjectState(sO_Swingie, g_fp->getObjectEnumState(sO_Swingie, sO_IsSitting)); + + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing1, 0); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing2, 0); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing3, 1); + } +} + +void sceneHandler11_swingieJumpDown() { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SWR_JUMPDOWN), 0, 0); + + mq->setFlags(mq->getFlags() | 1); + + if (!mq->chain(g_vars->scene11_swingie)) + delete mq; + + g_vars->scene11_swingIsSwinging = false; + g_vars->scene11_swingieStands = true; + g_vars->scene11_swingieScreenEdge = g_fp->_sceneRect.left; + + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing1, 0); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing2, 1); + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing3, 0); + + getCurrSceneSc2MotionController()->replaceNodeX(905, 805); +} + +void sceneHandler11_winArcade() { + if (g_vars->scene11_arcadeIsOn) { + g_vars->scene11_arcadeIsOn = false; + + sceneHandler11_emptySwing(); + + g_fp->_gameLoader->preloadScene(SC_11, TrubaRight); + } +} + +int sceneHandler11(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_CMN_WINARCADE: + sceneHandler11_winArcade(); + break; + + case MSG_SC11_SITSWINGER: + if (g_fp->getObjectState(sO_Swingie) == g_fp->getObjectEnumState(sO_Swingie, sO_IsStandingInBoots) + || g_fp->getObjectState(sO_Swingie) == g_fp->getObjectEnumState(sO_Swingie, sO_IsStandingInCorner)) { + g_fp->setObjectState(sO_Swingie, g_fp->getObjectEnumState(sO_Swingie, sO_IsSitting)); + } + break; + + case MSG_SC11_MANCRY: + g_fp->playSound(g_vars->scene11_crySound, 0); + + g_vars->scene11_crySound = 0; + break; + + case MSG_SC11_RESTARTMAN: + sceneHandler11_restartMan(); + break; + + case MSG_SC11_HITMAN: + sceneHandler11_hitMan(); + break; + + case MSG_SC11_MANTOSWING: + sceneHandler11_manToSwing(); + break; + + case MSG_SC11_PUTBOOT: + sceneHandler11_putBoot(); + break; + + case MSG_SC11_SHOWSWING: + sceneHandler11_showSwing(); + break; + + case 107: + if (g_vars->scene11_arcadeIsOn) + sceneHandler11_swingLogic(); + break; + + case 33: + { + int res = 0; + int x, y; + + if (!g_fp->_aniMan2) + goto LABEL_27; + + x = g_fp->_aniMan2->_ox; + y = g_fp->_aniMan2->_oy; + + g_vars->scene11_dudeX = x; + g_vars->scene11_dudeY = y; + + if (g_vars->scene11_scrollIsEnabled) { + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x - g_fp->_sceneRect.right + 300; + goto LABEL_26; + } + + if (g_vars->scene11_scrollIsMaximized) { + g_fp->_currentScene->_x = g_fp->_sceneWidth - x; + + if (g_vars->scene11_dudeX < 910) + g_vars->scene11_scrollIsMaximized = false; + + LABEL_26: + res = 1; + LABEL_27: + if (g_vars->scene11_swingieStands) { + if (g_fp->_sceneRect.left >= 534 && g_vars->scene11_swingieScreenEdge < 534) + sceneHandler11_swingieSit(); + + g_vars->scene11_swingieScreenEdge = g_fp->_sceneRect.left; + } + + if (!g_vars->scene11_arcadeIsOn) + goto LABEL_50; + + if (g_vars->scene11_swingCounterPrevTurn <= 0 || g_vars->scene11_swingCounter - g_vars->scene11_swingCounterPrevTurn <= 72) { + } else { + sceneHandler11_swing0(); + g_vars->scene11_swingDirectionPrevTurn = 0; + g_vars->scene11_swingCounterPrevTurn = 0; + } + + if (!g_vars->scene11_arcadeIsOn) + goto LABEL_50; + + if (g_vars->scene11_swingDirection == g_vars->scene11_swingDirectionPrevTurn || g_vars->scene11_swingCounterPrevTurn <= 0 || g_vars->scene11_swingCounter - g_vars->scene11_swingCounterPrevTurn <= 2) { + LABEL_49: + if (g_vars->scene11_arcadeIsOn) { + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + return res; + } + LABEL_50: + if (g_vars->scene11_swingIsSwinging + || (0.0 == g_vars->scene11_swingSpeed + && g_vars->scene11_dudeOnSwing->_movement != 0 + && g_vars->scene11_dudeOnSwing->_movement->_currDynamicPhaseIndex == 45 + && (g_vars->scene11_dudeOnSwing->changeStatics2(ST_KCH_STATIC), !g_vars->scene11_arcadeIsOn) + && g_vars->scene11_swingIsSwinging)) { + if (!g_vars->scene11_swingie->_movement) { + if ((g_vars->scene11_boots->_flags & 4) && g_vars->scene11_boots->_statics->_staticsId == ST_BTS11_2) { + sceneHandler11_swingieJumpDown(); + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + return res; + } + g_vars->scene11_swingie->startAnim(MV_SWR_SWING, 0, -1); + } + } + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + return res; + } + + if (g_vars->scene11_swingDirectionPrevTurn == 1) { + if (!g_vars->scene11_swingDirection) + sceneHandler11_swing1(); + else + sceneHandler11_swing0(); + } else if (g_vars->scene11_swingDirectionPrevTurn == 2) { + if (!g_vars->scene11_swingDirection) + sceneHandler11_swing2(); + else + sceneHandler11_swing0(); + } + + g_vars->scene11_swingCounterPrevTurn = g_vars->scene11_swingCounter; + goto LABEL_49; + } + if (x >= g_fp->_sceneRect.left + 200) { + if (x <= g_fp->_sceneRect.right - 200) { + LABEL_18: + if (y < g_fp->_sceneRect.top + 200) { + g_fp->_currentScene->_y = y - g_fp->_sceneRect.top - 300; + y = g_vars->scene11_dudeY; + x = g_vars->scene11_dudeX; + } + if (y > g_fp->_sceneRect.bottom - 300) { + g_fp->_currentScene->_y = y - g_fp->_sceneRect.bottom + 300; + x = g_vars->scene11_dudeX; + } + if (x >= 940) + g_vars->scene11_scrollIsMaximized = true; + goto LABEL_26; + } + g_fp->_currentScene->_x = x - g_fp->_sceneRect.right + 300; + } else { + g_fp->_currentScene->_x = x - g_fp->_sceneRect.left - 300; + } + y = g_vars->scene11_dudeY; + x = g_vars->scene11_dudeX; + goto LABEL_18; + } + + break; + + case 29: + if (g_vars->scene11_swingIsSwinging) { + if (g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y) == g_vars->scene11_swingie + && cmd->_keyCode == ANI_INV_BOOT) + sceneHandler11_putBoot(); + } else { + if (g_vars->scene11_arcadeIsOn) { + sceneHandler11_setSwingDirection(); + + g_vars->scene11_swingCounterPrevTurn = g_vars->scene11_swingCounter; + } + } + + if (!g_vars->scene11_arcadeIsOn) { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + + return 0; + } + } + } + return 0; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene12.cpp b/engines/fullpipe/scenes/scene12.cpp new file mode 100644 index 0000000000..f63bb9a9fd --- /dev/null +++ b/engines/fullpipe/scenes/scene12.cpp @@ -0,0 +1,85 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/scene.h" +#include "fullpipe/floaters.h" +#include "fullpipe/messages.h" +#include "fullpipe/statics.h" +#include "fullpipe/behavior.h" + +namespace Fullpipe { + +void scene12_initScene(Scene *sc) { + GameVar *var = g_fp->getGameLoaderGameVar()->getSubVarByName("SC_12"); + g_fp->_floaters->init(var); + + g_vars->scene12_fly = g_fp->getObjectState(sO_Fly_12); + + if (g_vars->scene12_fly) + g_vars->scene12_flyCountdown = g_fp->_rnd->getRandomNumber(600) + 600; + + g_fp->setObjectState(sO_Fly_12, g_fp->_rnd->getRandomNumber(1)); +} + +void sceneHandler12_updateFloaters() { + g_fp->_floaters->genFlies(g_fp->_currentScene, 397, -50, 100, 6); + + g_fp->_floaters->_array2[0]->countdown = g_fp->_rnd->getRandomNumber(6) + 4; + g_fp->_floaters->_array2[0]->val6 = 397; + g_fp->_floaters->_array2[0]->val7 = -50; +} + +int sceneHandler12(ExCommand *cmd) { + int res = 0; + + if (cmd->_messageKind == 17 && cmd->_messageNum == 33) { + if (g_fp->_aniMan2) { + if (g_fp->_aniMan2->_ox < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.left - 300; + + if (g_fp->_aniMan2->_ox > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = g_fp->_aniMan2->_ox - g_fp->_sceneRect.right + 300; + + res = 1; + } + + g_vars->scene12_flyCountdown--; + + if (!g_vars->scene12_flyCountdown) + sceneHandler12_updateFloaters(); + + g_fp->_floaters->update(); + + g_fp->_behaviorManager->updateBehaviors(); + } + + return res; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene13.cpp b/engines/fullpipe/scenes/scene13.cpp new file mode 100644 index 0000000000..c7b3c96b93 --- /dev/null +++ b/engines/fullpipe/scenes/scene13.cpp @@ -0,0 +1,380 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene13_initScene(Scene *sc) { + g_vars->scene13_whirlgig = sc->getStaticANIObject1ById(ANI_WHIRLGIG_13, -1); + g_vars->scene13_guard = sc->getStaticANIObject1ById(ANI_STOROZH, -1); + g_vars->scene13_handleR = sc->getStaticANIObject1ById(ANI_HANDLE_R, -1); + g_vars->scene13_handleL = sc->getStaticANIObject1ById(ANI_HANDLE_L, -1); + g_vars->scene13_bridge = sc->getStaticANIObject1ById(ANI_BRIDGE, -1); + g_vars->scene13_guardDirection = true; + + MovGraphLink *lnk = getSc2MctlCompoundBySceneId(sc->_sceneId)->getLinkByName(sO_Bridge); + Scene *oldsc = g_fp->_currentScene; + + g_fp->_currentScene = sc; + + if (g_fp->getObjectState(sO_Bridge) == g_fp->getObjectEnumState(sO_Bridge, sO_Convoluted)) { + g_vars->scene13_bridge->changeStatics2(ST_BDG_CLOSED); + + lnk->_flags |= 0x20000000u; + + g_fp->playSound(SND_13_018, 1); + + g_vars->scene13_whirlgig->_callback2 = 0; + } else { + g_vars->scene13_bridge->changeStatics2(ST_BDG_OPEN2); + + lnk->_flags &= 0xDFFFFFFF; + + g_vars->scene13_whirlgig->stopAnim_maybe(); + g_vars->scene13_whirlgig->_callback2 = 0; + g_vars->scene13_whirlgig->startAnim(MV_WHR13_SPIN, 0, -1); + + if (g_vars->scene13_whirlgig->_movement) + g_vars->scene13_whirlgig->_movement->setDynamicPhaseIndex(30); + + g_fp->playSound(SND_13_037, 1); + } + + g_vars->scene13_bridge->_flags &= 0xFFFD; + + g_fp->_currentScene = oldsc; + + g_fp->initArcadeKeys("SC_13"); +} + +void sceneHandler13_openBridge() { + Movement *mov = g_vars->scene13_bridge->_movement; + + if (mov && mov->_id == MV_BDG_CLOSE) { + int sz; + + if (mov->_currMovement) + sz = mov->_currMovement->_dynamicPhases.size(); + else + sz = mov->_dynamicPhases.size(); + + g_vars->scene13_bridge->changeStatics2(ST_BDG_CLOSED); + g_vars->scene13_bridge->startAnim(MV_BDG_OPEN, 0, -1); + + mov->setDynamicPhaseIndex(sz - mov->_currDynamicPhaseIndex); + } else { + g_vars->scene13_bridge->changeStatics2(ST_BDG_CLOSED); + g_vars->scene13_bridge->startAnim(MV_BDG_OPEN, 0, -1); + } +} + +void sceneHandler13_testClose() { + int id = g_vars->scene13_handleL->_statics->_staticsId; + + if (id == ST_HDLL_UP) + chainQueue(QU_SC13_CLOSEFAIL, 1); + else if (id == ST_HDLL_FIRECAN || id == ST_HDLL_HAMMER) + chainQueue(QU_SC13_CLOSESUCCESS, 1); +} + +void sceneHandler13_testOpen() { + switch (g_vars->scene13_handleR->_statics->_staticsId) { + case ST_HDLR_DOWN: + chainQueue(QU_SC13_OPENFAIL, 1); + break; + + case ST_HDLR_DOWN_GUM: + chainQueue(QU_SC13_OPENSUCCESS, 1); + break; + + case ST_HDLR_GUM: + g_vars->scene13_handleR->changeStatics2(ST_HDLR_DOWN_GUM); + + chainQueue(QU_SC13_OPENSUCCESS, 1); + break; + } +} + +void sceneHandler13_closeBridge() { + Movement *mov = g_vars->scene13_bridge->_movement; + + if (mov && mov->_id == MV_BDG_OPEN) { + int sz; + + if (mov->_currMovement) + sz = mov->_currMovement->_dynamicPhases.size(); + else + sz = mov->_dynamicPhases.size(); + + g_vars->scene13_bridge->changeStatics2(ST_BDG_OPEN2); + g_vars->scene13_bridge->startAnim(MV_BDG_CLOSE, 0, -1); + + mov->setDynamicPhaseIndex(sz - mov->_currDynamicPhaseIndex); + } else { + g_vars->scene13_bridge->changeStatics2(ST_BDG_OPEN2); + g_vars->scene13_bridge->startAnim(MV_BDG_CLOSE, 0, -1); + } +} + +void sceneHandler13_closeFast() { + g_vars->scene13_bridge->changeStatics2(ST_BDG_OPEN2); + g_vars->scene13_bridge->startAnim(MV_BDG_CLOSE, 0, -1); + g_vars->scene13_bridge->_movement->setDynamicPhaseIndex(21); +} + +void sceneHandler13_stopWhirlgig() { + g_vars->scene13_whirlgig->_callback2 = 0; + + g_fp->stopAllSoundInstances(SND_13_018); + g_fp->playSound(SND_13_033, 0); + g_fp->playSound(SND_13_037, 1); +} + +void sceneHandler13_startWhirlgig() { + g_vars->scene13_whirlgig->_callback2 = 0; + + g_fp->playSound(SND_13_018, 1); + g_fp->playSound(SND_13_034, 0); + + g_fp->stopAllSoundInstances(SND_13_037); +} + +void sceneHandler13_openFast() { + g_vars->scene13_bridge->changeStatics2(ST_BDG_CLOSED); + g_vars->scene13_bridge->startAnim(MV_BDG_OPEN, 0, -1); + g_vars->scene13_bridge->_movement->setDynamicPhaseIndex(15); +} + +void sceneHandler13_uneatGum() { + BehaviorEntryInfo *beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_CHEW); + + if (beh) { + beh->_percent = 0; + beh->_delay = 36; + } + + beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_PLUU); + if (beh) { + beh->_percent = 0; + beh->_delay = 36; + } +} + +void sceneHandler13_eatGum() { + BehaviorEntryInfo *beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_CHEW); + + if (beh) { + beh->_percent = 10922; + beh->_delay = 0; + } +} + +void sceneHandler13_updateBridge() { + MovGraphLink *lnk = getCurrSceneSc2MotionController()->getLinkByName(sO_Bridge); + + if (lnk) { + if (g_fp->getObjectState(sO_Bridge) == g_fp->getObjectEnumState(sO_Bridge, sO_Convoluted)) + lnk->_flags |= 0x20000000; + else + lnk->_flags &= 0xDFFFFFFF; + } +} + +void sceneHandler13_showGum() { + chainQueue(QU_SC13_SHOWGUM, 0); +} + +void sceneHandler13_setBehFlag(BehaviorEntryInfo *beh, bool flag) { + if (!flag) { + beh->_percent = 327; + beh->_flags |= 1; + beh->_delay = 36; + } else { + beh->_percent = 0x7FFF; + beh->_flags &= 0xFFFFFFFE; + beh->_delay = 0; + } +} + +void sceneHandler13_walkForward(bool flag) { + BehaviorEntryInfo *beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_RTOL); + + sceneHandler13_setBehFlag(beh, flag); + + beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_LEFT, QU_STR_TURNR); + + sceneHandler13_setBehFlag(beh, flag); + + beh->_flags &= 0xFE; +} + +void sceneHandler13_walkBackward(bool flag) { + BehaviorEntryInfo *beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT|0x4000, QU_STR_LTOR); + + sceneHandler13_setBehFlag(beh, flag); + + beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_LEFT|0x4000, QU_STR_TURNR_L); + + sceneHandler13_setBehFlag(beh, flag); + + beh->_flags &= 0xFE; +} + +int sceneHandler13(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch(cmd->_messageNum) { + case MSG_SC13_OPENBRIDGE: + sceneHandler13_openBridge(); + break; + + case MSG_SC13_TESTCLOSE: + sceneHandler13_testClose(); + break; + + case MSG_SC13_TESTOPEN: + sceneHandler13_testOpen(); + break; + + case MSG_SC13_CLOSEBRIDGE: + sceneHandler13_closeBridge(); + break; + + case MSG_SC13_CLOSEFAST: + sceneHandler13_closeFast(); + break; + + case MSG_SC13_STOPWHIRLGIG: + sceneHandler13_stopWhirlgig(); + break; + + case MSG_SC13_STARTWHIRLGIG: + sceneHandler13_startWhirlgig(); + break; + + case MSG_SC13_OPENFAST: + sceneHandler13_openFast(); + break; + + case MSG_SC13_UNEATGUM: + sceneHandler13_uneatGum(); + break; + + case MSG_SC13_EATGUM: + sceneHandler13_eatGum(); + break; + + case MSG_SC13_CHEW: + g_vars->scene13_guard->_flags &= 0xFF7Fu; + break; + + case MSG_SC13_UPDATEBRIDGE: + sceneHandler13_updateBridge(); + break; + + case MSG_SC13_SHOWGUM: + sceneHandler13_showGum(); + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 + && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + } + } + } + break; + } + + case 33: + { + int res = 0; + int x; + + if (g_fp->_aniMan2) { + x = g_fp->_aniMan2->_ox; + g_vars->scene13_dudeX = x; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - g_fp->_sceneRect.left - 300; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x - g_fp->_sceneRect.right + 300; + + res = 1; + } else { + x = g_vars->scene13_dudeX; + } + + if (g_vars->scene13_guardDirection) { + if (x < 1022) { + sceneHandler13_walkForward(1); + sceneHandler13_walkBackward(0); + + g_vars->scene13_guardDirection = false; + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + return res; + } + } else if (x > 1022) { + sceneHandler13_walkForward(0); + sceneHandler13_walkBackward(1); + + g_vars->scene13_guardDirection = true; + } + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + return res; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene14.cpp b/engines/fullpipe/scenes/scene14.cpp new file mode 100644 index 0000000000..dc919c6d7f --- /dev/null +++ b/engines/fullpipe/scenes/scene14.cpp @@ -0,0 +1,849 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" +#include "fullpipe/input.h" + +namespace Fullpipe { + +void scene14_initScene(Scene *sc) { + g_vars->scene14_grandma = sc->getStaticANIObject1ById(ANI_GRANDMA, -1); + g_vars->scene14_sceneDeltaX = 200; + g_vars->scene14_sceneDeltaY = 200; + g_vars->scene14_arcadeIsOn = false; + g_vars->scene14_dudeIsKicking = false; + g_vars->scene14_ballIsFlying = false; + g_vars->scene14_dudeCanKick = false; + g_vars->scene14_sceneDiffX = 300; + g_vars->scene14_sceneDiffY = 300; + g_vars->scene14_pink = 0; + g_vars->scene14_flyingBall = 0; + g_vars->scene14_balls.clear(); + + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_In_14)) { + g_vars->scene14_grandmaIsHere = true; + + StaticANIObject *ball = sc->getStaticANIObject1ById(ANI_BALL14, -1); + + ball->_flags &= 0xFFFB; + g_vars->scene14_balls.push_back(ball); + + for (uint i = 0; i < 3; i++) { + ball = new StaticANIObject(ball); // create a copy + + ball->_flags &= 0xFFFB; + g_vars->scene14_balls.push_back(ball); + + sc->addStaticANIObject(ball, 1); + } + } else { + g_vars->scene14_grandmaIsHere = false; + g_vars->scene14_grandma->hide(); + } + + g_fp->lift_setButton(sO_Level4, ST_LBN_4N); + g_fp->lift_init(sc, QU_SC14_ENTERLIFT, QU_SC14_EXITLIFT); + + g_fp->initArcadeKeys("SC_14"); + g_fp->setArcadeOverlay(PIC_CSR_ARCADE6); +} + +void scene14_setupMusic() { + if (!g_vars->scene14_grandmaIsHere) + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_14"), "MUSIC2", 0); +} + +int scene14_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_vars->scene14_arcadeIsOn) { + if (g_vars->scene14_dudeIsKicking) { + g_fp->_cursorId = PIC_CSR_ARCADE2_D; + } else { + if (g_fp->_aniMan != g_fp->_objectAtCursor || g_fp->_aniMan->_movement || g_fp->_cursorId != PIC_CSR_DEFAULT) { + if (g_fp->_cursorId != PIC_CSR_DEFAULT_INV && g_fp->_cursorId != PIC_CSR_ITN_INV) { + g_fp->_cursorId = PIC_CSR_DEFAULT; + } + } else { + g_fp->_cursorId = PIC_CSR_ITN; + } + } + } + + return g_fp->_cursorId; +} + +int sceneHandler14_updateScreenCallback() { + int res; + + res = g_fp->drawArcadeOverlay(g_vars->scene14_arcadeIsOn); + if (!res) + g_fp->_updateScreenCallback = 0; + + return res; +} + +void sceneHandler14_showBallGrandmaHit2() { + if (g_vars->scene14_flyingBall) { + g_vars->scene14_flyingBall->show1(g_vars->scene14_grandmaX + 223, g_vars->scene14_grandmaY + 35, MV_BAL14_SPIN, 0); + g_vars->scene14_flyingBall->_priority = 27; + + g_vars->scene14_pink = g_vars->scene14_flyingBall; + + g_vars->scene14_flyingBall = 0; + } +} + +void sceneHandler14_showBallGrandmaDive() { + if (g_vars->scene14_flyingBall) { + g_vars->scene14_flyingBall->show1(g_vars->scene14_grandmaX + 506, g_vars->scene14_grandmaY - 29, -1, 0); + + g_vars->scene14_balls.push_back(g_vars->scene14_flyingBall); + g_vars->scene14_flyingBall = 0; + } + + g_fp->_aniMan2 = g_fp->_aniMan; +} + +void sceneHandler14_showBallGrandmaHit() { + if (g_vars->scene14_flyingBall) { + g_vars->scene14_flyingBall->show1(g_vars->scene14_grandmaX + 190, g_vars->scene14_grandmaY + 56, MV_BAL14_TOGMA, 0); + g_vars->scene14_flyingBall->_priority = 27; + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + ExCommand *ex = new ExCommand(ANI_BALL14, 1, MV_BAL14_TOGMA, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = g_vars->scene14_flyingBall->_okeyCode; + ex->_excFlags |= 2; + ex->_field_24 = 1; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_BALL14, 6, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = g_vars->scene14_flyingBall->_okeyCode; + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + mq->chain(0); + + g_vars->scene14_balls.push_back(g_vars->scene14_flyingBall); + g_vars->scene14_flyingBall = 0; + } +} + +void sceneHandler14_exitScene() { + g_vars->scene14_arcadeIsOn = false; + + if (g_fp->_aniMan->_movement) + g_fp->_aniMan->_movement->gotoLastFrame(); + + g_fp->_aniMan->stopAnim_maybe(); + + handleObjectInteraction(g_fp->_aniMan, g_fp->_currentScene->getPictureObjectById(PIC_SC14_RTRUBA, 0), 0); + + g_vars->scene14_grandma->changeStatics2(ST_GMA_SIT); + + chainQueue(QU_SC14_ENDARCADE, 0); + + getGameLoaderInteractionController()->disableFlag24(); + getCurrSceneSc2MotionController()->deactivate(); +} + +void sceneHandler14_showBallMan() { + if (g_vars->scene14_flyingBall) { + g_vars->scene14_flyingBall->show1(g_vars->scene14_dudeX - 166, g_vars->scene14_dudeY + 40, MV_BAL14_TOGMA, 0); + g_vars->scene14_flyingBall->_priority = 27; + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + ExCommand *ex = new ExCommand(ANI_BALL14, 1, MV_BAL14_TOGMA, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = g_vars->scene14_flyingBall->_okeyCode; + ex->_excFlags |= 2; + ex->_field_24 = 1; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_BALL14, 6, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = g_vars->scene14_flyingBall->_okeyCode; + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + mq->chain(0); + + g_vars->scene14_flyingBall->startAnim(MV_BAL14_TOGMA, 0, -1); + + g_vars->scene14_balls.push_back(g_vars->scene14_flyingBall); + g_vars->scene14_flyingBall = 0; + + if (g_vars->scene14_dudeX >= 1300) + sceneHandler14_exitScene(); + } +} + +void sceneHandler14_manKickBall() { + int val = (g_vars->scene14_grandmaX + 65 - (g_vars->scene14_dudeX - 85)) / -32; + int den = val; + + g_vars->scene14_ballX = g_vars->scene14_dudeX - 85; + g_vars->scene14_ballY = g_vars->scene14_dudeY - 76; + g_vars->scene14_ballDeltaX = -32; + + if (!val) + den = 1; + + g_vars->scene14_ballDeltaY = (g_vars->scene14_grandmaY - 102 - val * val / 2 - (g_vars->scene14_dudeY - 76)) / den; + + g_vars->scene14_flyingBall->show1(g_vars->scene14_dudeX - 85, g_vars->scene14_dudeY - 76, -1, 0); + g_vars->scene14_flyingBall->startAnim(MV_BAL14_SPIN, 0, -1); + g_vars->scene14_flyingBall->_priority = 5; + + g_vars->scene14_ballIsFlying = true; +} + +void sceneHandler14_showBallFly() { + if (g_vars->scene14_balls.size()) { + g_vars->scene14_flyingBall = g_vars->scene14_balls.front(); + g_vars->scene14_balls.pop_front(); + } + + int x, y; + + if (g_vars->scene14_grandma->_movement) { + x = g_vars->scene14_grandma->_movement->_ox; + g_vars->scene14_ballX = x; + y = g_vars->scene14_grandma->_movement->_oy; + } else { + x = g_vars->scene14_grandmaX; + y = g_vars->scene14_grandmaY; + } + + x = x + 38; + y = y - 77; + + g_vars->scene14_ballDeltaX = 32; + + int dist = (g_vars->scene14_dudeX - 16 - x) / 32; + int den = dist; + + if (!dist) + den = 1; + + g_vars->scene14_ballX = x + 32; + g_vars->scene14_ballDeltaY = (g_vars->scene14_dudeY - 40 - dist * dist / 2 - y) / den; + g_vars->scene14_ballY = g_vars->scene14_ballDeltaY + y; + + g_vars->scene14_flyingBall->show1(x + 32, g_vars->scene14_ballDeltaY + y, MV_BAL14_SPIN, 0); + g_vars->scene14_flyingBall->_priority = 5; + g_vars->scene14_flyingBall->startAnim(MV_BAL14_SPIN, 0, -1); + + g_vars->scene14_ballIsFlying = true; +} + +void sceneHandler14_grandmaJump() { + BehaviorEntryInfo *beh1 = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_JUMPFW); + BehaviorEntryInfo *beh2 = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_JUMPBK); + + if (beh1) { + if (beh2) { + int p = beh1->_percent; + beh1->_percent = beh2->_percent; + beh2->_percent = p; + } + } +} + +void sceneHandler14_endArcade() { + g_vars->scene14_arcadeIsOn = false; + + setInputDisabled(0); + + getGameLoaderInteractionController()->enableFlag24(); + getCurrSceneSc2MotionController()->activate(); + + BehaviorEntryInfo *beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_BLINK); + if (beh) + beh->_percent = 327; + + beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_THROW); + if (beh) + beh->_percent = 0; + + g_vars->scene14_sceneDeltaX = 200; + g_vars->scene14_sceneDeltaY = 200; + + g_fp->_aniMan2 = g_fp->_aniMan; + + g_vars->scene14_sceneDiffX = 300; + g_vars->scene14_sceneDiffY = 300; +} + +void sceneHandler14_winArcade() { + if (g_vars->scene14_arcadeIsOn) { + if (g_vars->scene14_dudeIsKicking) { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + + g_vars->scene14_dudeIsKicking = false; + } + + if (g_vars->scene14_flyingBall) { + g_vars->scene14_balls.push_back(g_vars->scene14_flyingBall); + + g_vars->scene14_flyingBall->_flags &= 0xFFFB; + g_vars->scene14_flyingBall = 0; + } + + g_vars->scene14_ballIsFlying = false; + + sceneHandler14_endArcade(); + + g_vars->scene14_grandmaIsHere = false; + + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_In_14)) { + g_fp->setObjectState(sO_Grandma, g_fp->getObjectEnumState(sO_Grandma, sO_In_15)); + g_vars->scene14_grandma->changeStatics2(ST_GMA_SIT); + g_vars->scene14_grandma->_flags &= 0xFFFB; + } + + if (g_fp->_currentScene->_messageQueueId) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(g_fp->_currentScene->_messageQueueId); + if (mq) + delete mq; + + g_fp->_currentScene->_messageQueueId = 0; + } + } +} + +void sceneHandler14_showBallLast() { + if (g_vars->scene14_pink) { + g_vars->scene14_pink->show1(693, 491, MV_BAL14_SPIN, 0); + g_vars->scene14_pink->_priority = 27; + } +} + +void sceneHandler14_hideBallLast() { + if (g_vars->scene14_pink) { + g_vars->scene14_pink->hide(); + g_vars->scene14_balls.push_back(g_vars->scene14_pink); + g_vars->scene14_pink = 0; + } +} + +void sceneHandler14_startArcade() { + g_vars->scene14_arcadeIsOn = true; + g_vars->scene14_dudeCanKick = true; + + if (g_fp->_aniMan->_movement) { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT | 0x4000); + g_fp->_aniMan->setOXY(1237, 451); + g_fp->_aniMan->_priority = 25; + } + + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_aniMan2 = 0; + g_vars->scene14_sceneDeltaX = 50; + g_vars->scene14_sceneDiffX = 100; + g_vars->scene14_hitsLeft = 4; + g_vars->scene14_pink = 0; + + chainQueue(QU_SC14_STARTARCADE, 0); + + g_fp->_updateScreenCallback = sceneHandler14_updateScreenCallback; +} + +void sceneHandler14_clearCallback() { + g_fp->_aniMan->_callback2 = 0; + g_vars->scene14_dudeIsKicking = false; +} + +void sceneHandler14_kickAnimation() { + if (g_fp->_aniMan->_movement) { + sceneHandler14_clearCallback(); + + if (g_vars->scene14_flyingBall && g_vars->scene14_dudeX - g_vars->scene14_flyingBall->_ox < 180) { + g_fp->_aniMan->changeStatics2(g_fp->_aniMan->_movement->_staticsObj2->_staticsId); + g_fp->_aniMan->startAnim(MV_MAN14_KICK, 0, -1); + + g_vars->scene14_ballIsFlying = false; + + g_vars->scene14_flyingBall->stopAnim_maybe(); + g_vars->scene14_flyingBall->hide(); + } else { + g_fp->_aniMan->changeStatics2(g_fp->_aniMan->_movement->_staticsObj2->_staticsId); + g_fp->_aniMan->startAnim(MV_MAN14_KICKAIR, 0, -1); + } + } +} + +void sceneHandler14_declineCallback(int *arg) { + Common::Point point; + + if (g_vars->scene14_dudeIsKicking) { + *arg = (int)(sqrt((double)(g_fp->_mouseVirtY - g_vars->scene14_mouseCursorPos.y) + * (g_fp->_mouseVirtY - g_vars->scene14_mouseCursorPos.y) + + (g_fp->_mouseVirtX - g_vars->scene14_mouseCursorPos.x) + * (g_fp->_mouseVirtX - g_vars->scene14_mouseCursorPos.x)) * 0.1); + + if (*arg > 11) + *arg = 11; + } else { + ++*arg; + } +} + +void sceneHandler14_dudeDecline() { + g_vars->scene14_mouseCursorPos.x = g_fp->_mouseVirtX; + g_vars->scene14_mouseCursorPos.y = g_fp->_mouseVirtY; + + g_fp->_aniMan->_callback2 = sceneHandler14_declineCallback; + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + g_fp->_aniMan->startAnim(MV_MAN14_DECLINE, 0, -1); + + g_vars->scene14_dudeIsKicking = true; +} + +bool sceneHandler14_arcadeProcessClick(ExCommand *cmd) { + if (!getCurrSceneSc2MotionController()->_isEnabled) + return 0; + + if (!g_vars->scene14_grandmaIsHere) { + if (!cmd->_keyCode) { + if (g_vars->scene14_pink) { + if (g_vars->scene14_pink->_flags & 4) { + if (cmd->_sceneClickX < g_vars->scene14_pink->_ox + 40) { + handleObjectInteraction(g_fp->_aniMan, g_vars->scene14_pink, 0); + cmd->_messageKind = 0; + return true; + } + } + } + } + return false; + } + + if (getCurrSceneSc2MotionController()->_objtype != kObjTypeMctlCompound) + return false; + + if (!getCurrSceneSc2MotionController()->_motionControllers[0]->_movGraphReactObj->pointInRegion(cmd->_sceneClickX, cmd->_sceneClickY)) + return false; + + if (cmd->_sceneClickX > 1237) + return false; + + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 1237, 451, 1, 0); + + if (!mq) + return false; + + ExCommand *ex = new ExCommand(0, 17, MSG_SC14_STARTARCADE, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + mq->setFlags(mq->getFlags() | 1); + + postExCommand(g_fp->_aniMan->_id, 2, 1237, 451, 0, -1); + + cmd->_messageKind = 0; + + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + return true; +} + +void sceneHandler14_grandmaThrow() { + g_vars->scene14_grandma->changeStatics2(ST_GMA_SIT); + + MessageQueue *mq = new MessageQueue; + ExCommand *ex = new ExCommand(ANI_GRANDMA, 2, 30, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_GRANDMA, 1, MV_GMA_THROW, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + mq->chain(0); +} + +void sceneHandler14_passToGrandma() { + g_vars->scene14_flyingBall->stopAnim_maybe(); + g_vars->scene14_flyingBall->_priority = 27; + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + ExCommand *ex = new ExCommand(ANI_BALL14, 1, MV_BAL14_FALL, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = g_vars->scene14_flyingBall->_okeyCode; + ex->_excFlags |= 2; + ex->_field_24 = 1; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_BALL14, 6, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = g_vars->scene14_flyingBall->_okeyCode; + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + mq->chain(0); + + g_vars->scene14_balls.push_back(g_vars->scene14_flyingBall); + g_vars->scene14_flyingBall = 0; + + sceneHandler14_grandmaThrow(); +} + +void sceneHandler14_grandmaJumpThrow() { + g_vars->scene14_grandma->changeStatics2(ST_GMA_SIT); + + MessageQueue *mq = new MessageQueue; + ExCommand *ex = new ExCommand(ANI_GRANDMA, 2, 30, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_GRANDMA, 1, MV_GMA_JUMPFW, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_GRANDMA, 1, MV_GMA_THROW, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + mq->chain(0); + + g_vars->scene14_dude2X += 71; + g_fp->_currentScene->_x = 71; + + g_fp->_aniMan2 = g_fp->_aniMan; +} + +void sceneHandler14_dudeFall() { + if (!g_fp->_aniMan->_movement || g_fp->_aniMan->_movement->_id != MV_MAN14_FALL) { + sceneHandler14_clearCallback(); + + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + g_fp->_aniMan->startAnim(MV_MAN14_FALL, 0, -1); + g_vars->scene14_flyingBall->stopAnim_maybe(); + g_vars->scene14_flyingBall->hide(); + + sceneHandler14_grandmaJumpThrow(); + } + ++g_vars->scene14_hitsLeft; +} + +void sceneHandler14_grandmaStepForward() { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + g_fp->_aniMan->startAnim(MV_MAN14_STEPFW, 0, -1); + + g_vars->scene14_dude2X -= 71; + + g_fp->_currentScene->_x = -71; + g_fp->_aniMan2 = g_vars->scene14_grandma; +} + +void sceneHandler14_arcadeLogic() { + g_vars->scene14_flyingBall->stopAnim_maybe(); + g_vars->scene14_flyingBall->hide(); + + if (g_vars->scene14_dudeIsKicking) + sceneHandler14_clearCallback(); + + if (g_vars->scene14_hitsLeft <= 1) { + setInputDisabled(1); + + sceneHandler14_clearCallback(); + + g_vars->scene14_dudeCanKick = false; + g_fp->_aniMan2 = 0; + + chainQueue(QU_SC14_WINARCADE, 1); + + --g_vars->scene14_hitsLeft; + } else { + ExCommand *ex; + + g_vars->scene14_grandma->changeStatics2(ST_GMA_SIT); + + if (g_vars->scene14_hitsLeft != 3 || g_vars->scene14_pink) { + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + ex = new ExCommand(ANI_GRANDMA, 1, MV_GMA_BACKOFF, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_GRANDMA, 1, MV_GMA_THROW, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + mq->chain(0); + } else { + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + ex = new ExCommand(ANI_GRANDMA, 1, MV_GMA_BACKOFF2, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(ANI_GRANDMA, 1, MV_GMA_THROW, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + mq->chain(0); + } + + sceneHandler14_grandmaStepForward(); + --g_vars->scene14_hitsLeft; + } +} + +void sceneHandler14_animateBall() { + int x = g_vars->scene14_ballDeltaX + g_vars->scene14_ballX; + int y = g_vars->scene14_ballDeltaY + g_vars->scene14_ballY; + + g_vars->scene14_ballX += g_vars->scene14_ballDeltaX; + g_vars->scene14_ballY += g_vars->scene14_ballDeltaY; + + g_vars->scene14_ballDeltaY++; + + if (g_vars->scene14_ballDeltaY - 1 + g_vars->scene14_ballY > 517) { + if (x <= g_vars->scene14_dudeX - 16 ) { + if ( g_vars->scene14_ballDeltaX >= 0 || x >= g_vars->scene14_grandmaX + 65 || x <= g_vars->scene14_grandmaX - 135 || y <= g_vars->scene14_grandmaY - 102 ) { + if (g_vars->scene14_flyingBall->_movement) + g_vars->scene14_flyingBall->_movement->setOXY(x, y); + else + g_vars->scene14_flyingBall->setOXY(x, y); + } else { + sceneHandler14_arcadeLogic(); + g_vars->scene14_ballIsFlying = false; + } + } else { + sceneHandler14_dudeFall(); + g_vars->scene14_ballIsFlying = false; + } + } else { + sceneHandler14_passToGrandma(); + g_vars->scene14_ballIsFlying = false; + } +} + +int sceneHandler14(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch(cmd->_messageNum) { + case MSG_SC14_SHOWBALLGMAHIT2: + sceneHandler14_showBallGrandmaHit2(); + break; + + case MSG_SC14_SHOWBALLGMADIVE: + sceneHandler14_showBallGrandmaDive(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC14_SHOWBALLGMAHIT: + sceneHandler14_showBallGrandmaHit(); + break; + + case MSG_SC14_SHOWBALLMAN: + sceneHandler14_showBallMan(); + break; + + case MSG_SC14_MANKICKBALL: + sceneHandler14_manKickBall(); + break; + + case MSG_SC14_SHOWBALLFLY: + sceneHandler14_showBallFly(); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case MSG_SC14_GMAJUMP: + sceneHandler14_grandmaJump(); + break; + + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(cmd); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_SC14_RESTORESCROLL: + g_fp->_aniMan2 = g_fp->_aniMan; + g_fp->_scrollSpeed = 8; + break; + + case MSG_CMN_WINARCADE: + sceneHandler14_winArcade(); + break; + + case MSG_SC14_SCROLLLEFT: + g_fp->_aniMan2 = 0; + g_fp->_currentScene->_x = -g_fp->_sceneRect.left; + g_fp->_scrollSpeed = 24; + break; + + case MSG_SC14_SHOWBALLLAST: + sceneHandler14_showBallLast(); + break; + + case MSG_SC14_HIDEBALLLAST: + sceneHandler14_hideBallLast(); + break; + + case MSG_SC14_HIDEPINK: + if (!g_vars->scene14_pink) + break; + + g_vars->scene14_pink->hide(); + break; + + case MSG_SC14_GMATOTRUBA: + g_fp->_currentScene->_x = -g_fp->_sceneRect.left; + break; + + case MSG_SC14_STARTARCADE: + sceneHandler14_startArcade(); + break; + + case MSG_SC14_ENDARCADE: + sceneHandler14_endArcade(); + + g_vars->scene14_grandmaIsHere = false; + break; + + case 64: + g_fp->lift_hoverButton(cmd); + break; + + case 33: + { + Movement *mov = g_fp->_aniMan->_movement; + + if (mov) { + g_vars->scene14_dudeX = mov->_ox; + g_vars->scene14_dudeY = mov->_oy; + + if (mov->_id == MV_MAN14_KICK) + g_vars->scene14_dudeX = mov->_ox + 2 * g_fp->_aniMan->_movement->_currDynamicPhaseIndex; + } else { + g_vars->scene14_dudeX = g_fp->_aniMan->_ox; + g_vars->scene14_dudeY = g_fp->_aniMan->_oy; + } + + mov = g_vars->scene14_grandma->_movement; + if (mov) { + g_vars->scene14_grandmaX = mov->_ox; + g_vars->scene14_grandmaY = mov->_oy; + } else { + g_vars->scene14_grandmaX = g_vars->scene14_grandma->_ox; + g_vars->scene14_grandmaY = g_vars->scene14_grandma->_oy; + } + + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + g_vars->scene14_dude2X = x; + + if (x < g_fp->_sceneRect.left + g_vars->scene14_sceneDeltaX) { + g_fp->_currentScene->_x = x - g_vars->scene14_sceneDiffX - g_fp->_sceneRect.left; + x = g_vars->scene14_dude2X; + } + + if (x > g_fp->_sceneRect.right - g_vars->scene14_sceneDeltaX) + g_fp->_currentScene->_x = x + g_vars->scene14_sceneDiffX - g_fp->_sceneRect.right; + } + + if (g_vars->scene14_ballIsFlying) + sceneHandler14_animateBall(); + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + break; + } + + case 30: + if (g_vars->scene14_dudeIsKicking) { + sceneHandler14_kickAnimation(); + break; + } + + if (!g_vars->scene14_arcadeIsOn) { + break; + } + break; + + case 29: + if (g_vars->scene14_arcadeIsOn) { + int pixel; + + if (g_vars->scene14_dudeCanKick && g_fp->_aniMan->getPixelAtPos(cmd->_sceneClickX, cmd->_sceneClickY, &pixel) && !g_fp->_aniMan->_movement) { + sceneHandler14_dudeDecline(); + break; + } + } else { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (ani && ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_animateButton(ani); + cmd->_messageKind = 0; + break; + } + + if (!sceneHandler14_arcadeProcessClick(cmd) && (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode))) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + sceneHandler14_arcadeProcessClick(cmd); + break; + } + } + } + } + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene15.cpp b/engines/fullpipe/scenes/scene15.cpp new file mode 100644 index 0000000000..efc69a5fa6 --- /dev/null +++ b/engines/fullpipe/scenes/scene15.cpp @@ -0,0 +1,209 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene15_initScene(Scene *sc) { + g_vars->scene15_chantingCountdown = 0; + + StaticANIObject *grandma = sc->getStaticANIObject1ById(ANI_GRANDMA_ASS, -1); + + Scene *oldsc = g_fp->_currentScene; + g_fp->_currentScene = sc; + + int grandmaState = g_fp->getObjectState(sO_Grandma); + + if (grandmaState == g_fp->getObjectEnumState(sO_Grandma, sO_In_15)) { + grandma->changeStatics2(ST_GMS_BOOT); + grandma->setOXY(97, 399); + g_fp->setObjectState(sO_LeftPipe_15, g_fp->getObjectEnumState(sO_LeftPipe_15, sO_IsClosed)); + } else if (grandmaState == g_fp->getObjectEnumState(sO_Grandma, sO_In_15_1)) { + grandma->changeStatics2(ST_GMS_BOOT); + grandma->setOXY(86, 399); + g_fp->setObjectState(sO_LeftPipe_15, g_fp->getObjectEnumState(sO_LeftPipe_15, sO_IsClosed)); + } else if (grandmaState == g_fp->getObjectEnumState(sO_Grandma, sO_In_15_2)) { + grandma->changeStatics2(ST_GMS_BOOT); + grandma->setOXY(71, 399); + g_fp->setObjectState(sO_LeftPipe_15, g_fp->getObjectEnumState(sO_LeftPipe_15, sO_IsClosed)); + } else if (grandmaState == g_fp->getObjectEnumState(sO_Grandma, sO_In_15_3)) { + grandma->changeStatics2(ST_GMS_BOOT); + grandma->setOXY(49, 399); + g_fp->setObjectState(sO_LeftPipe_15, g_fp->getObjectEnumState(sO_LeftPipe_15, sO_IsClosed)); + } else if (grandmaState == g_fp->getObjectEnumState(sO_Grandma, sO_WithoutBoot)) { + grandma->changeStatics2(ST_GMS_BOOT); + grandma->setOXY(97, 399); + grandma->changeStatics2(ST_GMS_BOOTLESS2); + g_fp->setObjectState(sO_LeftPipe_15, g_fp->getObjectEnumState(sO_LeftPipe_15, sO_IsClosed)); + } else { + grandma->hide(); + g_fp->setObjectState(sO_LeftPipe_15, g_fp->getObjectEnumState(sO_LeftPipe_15, sO_IsOpened)); + } + + g_vars->scene15_plusminus = sc->getStaticANIObject1ById(ANI_PLUSMINUS, -1); + + if (g_fp->getObjectState(sO_Guard_2) == g_fp->getObjectEnumState(sO_Guard_2, sO_Off)) + g_vars->scene15_plusminus->_statics = g_vars->scene15_plusminus->getStaticsById(ST_PMS_MINUS); + else + g_vars->scene15_plusminus->_statics = g_vars->scene15_plusminus->getStaticsById(ST_PMS_PLUS); + + g_vars->scene15_ladder = sc->getPictureObjectById(PIC_SC15_LADDER, 0); + g_vars->scene15_boot = sc->getStaticANIObject1ById(ANI_BOOT_15, -1); + + if (g_fp->getObjectState(sO_Boot_15) != g_fp->getObjectEnumState(sO_Boot_15, sO_IsPresent)) + g_vars->scene15_boot->_flags &= 0xFFFB; + + g_fp->_currentScene = oldsc; + + g_fp->lift_setButton(sO_Level5, ST_LBN_5N); + g_fp->lift_init(sc, QU_SC15_ENTERLIFT, QU_SC15_EXITLIFT); +} + +int scene15_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_cursorId == PIC_CSR_ITN && g_fp->_objectIdAtCursor == PIC_SC15_LTRUBA) + g_fp->_cursorId = PIC_CSR_GOL; + + return g_fp->_cursorId; +} + +int sceneHandler15(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch(cmd->_messageNum) { + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(cmd); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_SC4_HIDEBOOT: + g_vars->scene15_boot->_flags &= 0xFFFB; + break; + + case MSG_SC15_STOPCHANTING: + g_fp->stopAllSoundInstances(SND_15_001); + + g_vars->scene15_chantingCountdown = 120; + break; + + case MSG_SC15_ASSDRYG: + if (g_fp->_rnd->getRandomNumber(1)) + g_fp->playSound(SND_15_011, 0); + else + g_fp->playSound(SND_15_006, 0); + + break; + + case MSG_SC15_LADDERTOBACK: + g_vars->scene15_ladder->_priority = 60; + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC15_PULL: + if (g_vars->scene15_plusminus->_statics->_staticsId == ST_PMS_MINUS) + g_vars->scene15_plusminus->_statics = g_vars->scene15_plusminus->getStaticsById(ST_PMS_PLUS); + else + g_vars->scene15_plusminus->_statics = g_vars->scene15_plusminus->getStaticsById(ST_PMS_MINUS); + + break; + + case 64: + g_fp->lift_hoverButton(cmd); + break; + + case 29: + { + if (g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY) == PIC_SC15_LADDER) { + handleObjectInteraction(g_fp->_aniMan, g_fp->_currentScene->getPictureObjectById(PIC_SC15_DTRUBA, 0), cmd->_keyCode); + cmd->_messageKind = 0; + + return 0; + } + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (ani && ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_animateButton(ani); + + cmd->_messageKind = 0; + } + break; + } + + case 30: + // nop + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene15_chantingCountdown > 0) { + g_vars->scene15_chantingCountdown--; + + if (!g_vars->scene15_chantingCountdown) + g_fp->playSound(SND_15_001, 1); + } + + g_fp->_behaviorManager->updateBehaviors(); + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene16.cpp b/engines/fullpipe/scenes/scene16.cpp new file mode 100644 index 0000000000..5079863b4e --- /dev/null +++ b/engines/fullpipe/scenes/scene16.cpp @@ -0,0 +1,484 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene16_initScene(Scene *sc) { + g_vars->scene16_figures.clear(); + g_vars->scene16_walkingBoy = 0; + g_vars->scene16_walkingGirl = 0; + g_vars->scene16_walkingCount = 200; + g_vars->scene16_wire = sc->getStaticANIObject1ById(ANI_WIRE16, -1); + g_vars->scene16_mug = sc->getStaticANIObject1ById(ANI_MUG, -1); + g_vars->scene16_jettie = sc->getStaticANIObject1ById(ANI_JETTIE, -1); + g_vars->scene16_boot = sc->getStaticANIObject1ById(ANI_BOOT_16, -1); + g_vars->scene16_girlIsLaughing = false; + g_vars->scene16_sound = SND_16_034; + + if (g_fp->getObjectState(sO_Bridge) == g_fp->getObjectEnumState(sO_Bridge, sO_Convoluted)) { + g_vars->scene16_placeIsOccupied = true; + + StaticANIObject *boy[2]; + boy[0] = sc->getStaticANIObject1ById(ANI_BOY, -1); + boy[0]->loadMovementsPixelData(); + + boy[1] = new StaticANIObject(boy[0]); + sc->addStaticANIObject(boy[1], 1); + + int idx = 0; + + for (int i = 0; i < 3; i++) { + g_vars->scene16_figures.push_back(boy[idx]); + + idx++; + + if (idx >= 2) + idx = 0; + } + + g_vars->scene16_figures.push_back(sc->getStaticANIObject1ById(ANI_GIRL, -1)); + + for (int i = 0; i < 4; i++) { + g_vars->scene16_figures.push_back(boy[idx]); + + idx++; + + if (idx >= 2) + idx = 0; + } + } else { + g_fp->setObjectState(sO_Girl, g_fp->getObjectEnumState(sO_Girl, sO_IsSwinging)); + + g_vars->scene16_placeIsOccupied = false; + + StaticANIObject *ani = new StaticANIObject(g_fp->accessScene(SC_COMMON)->getStaticANIObject1ById(ANI_BEARDED_CMN, -1)); + ani->_movement = 0; + ani->_statics = (Statics *)ani->_staticsList[0]; + sc->addStaticANIObject(ani, 1); + } + + if (g_fp->getObjectState(sO_Girl) == g_fp->getObjectEnumState(sO_Girl, sO_IsLaughing)) { + StaticANIObject *girl = sc->getStaticANIObject1ById(ANI_GIRL, -1); + + girl->show1(554, 432, MV_GRL_LAUGH_POPA, 0); + girl->_priority = 20; + } + + if (g_fp->getObjectState(sO_Cup) == g_fp->getObjectEnumState(sO_Cup, sO_In_16)) { + g_vars->scene16_mug->_statics = g_vars->scene16_mug->getStaticsById(ST_MUG_EMPTY); + g_vars->scene16_mug->_movement = 0; + g_vars->scene16_mug->setOXY(409, 459); + g_vars->scene16_mug->_priority = 5; + g_vars->scene16_mug->_flags |= 4; + } +} + +int scene16_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_objectIdAtCursor == PIC_SC16_TUMBA) { + if (g_fp->_cursorId == PIC_CSR_DEFAULT) + g_fp->_cursorId = PIC_CSR_ITN; + } else { + if (g_fp->_objectIdAtCursor == ANI_MUG && g_fp->_cursorId == PIC_CSR_ITN && g_vars->scene16_mug->_statics->_staticsId == ST_MUG_FULL) + g_fp->_cursorId = PIC_CSR_ITN_GREEN; + } + + return g_fp->_cursorId; +} + +void sceneHandler16_laughSound() { + int snd = SND_16_035; + + switch (g_vars->scene16_sound) { + case SND_16_034: + snd = SND_16_035; + break; + + case SND_16_035: + snd = SND_16_037; + break; + + case SND_16_037: + snd = SND_16_034; + break; + } + + g_vars->scene16_sound = snd; + + g_fp->playSound(snd, 0); +} + +void sceneHandler16_showBearded() { + if (g_fp->getObjectState(sO_Bridge) == g_fp->getObjectEnumState(sO_Bridge, sO_Unconvoluted)) { + StaticANIObject *brd = g_fp->_currentScene->getStaticANIObject1ById(ANI_BEARDED_CMN, -1); + + if (!brd || !(brd->_flags & 4)) + chainQueue(QU_BRD16_STARTBEARDED, 0); + } +} + +void sceneHandler16_showMugFull() { + g_vars->scene16_mug->changeStatics2(ST_MUG_FULL); +} + +void sceneHandler16_fillMug() { + if (g_vars->scene16_mug->_flags & 4) { + g_vars->scene16_jettie->_priority = 2; + g_vars->scene16_jettie->startAnim(MV_JTI_FLOWIN, 0, -1); + + if (g_fp->_aniMan->_movement) { + if (g_fp->_aniMan->_movement->_id == MV_MAN16_TAKEMUG) { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT); + + g_vars->scene16_mug->show1(-1, -1, -1, 0); + + g_fp->setObjectState(sO_Cup, g_fp->getObjectEnumState(sO_Cup, sO_DudeHas)); + } + } + return; + } + + MessageQueue *mq; + + if (!(g_vars->scene16_boot->_flags & 4)) { + g_vars->scene16_jettie->_priority = 15; + g_vars->scene16_jettie->startAnim(MV_JTI_FLOWBY, 0, -1); + + if (g_vars->scene16_walkingBoy) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_BOYOUT), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene16_walkingBoy->_okeyCode); + if (mq->chain(g_vars->scene16_walkingBoy)) + return; + } else { + if (!g_vars->scene16_walkingGirl) + return; + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_GIRLOUT), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene16_walkingGirl->_okeyCode); + if (mq->chain(g_vars->scene16_walkingGirl)) + return; + } + delete mq; + + return; + } + + g_vars->scene16_jettie->_priority = 15; + + g_vars->scene16_boot->startAnim(MV_BT16_FILL, 0, -1); + + StaticANIObject *ani; + + if (g_vars->scene16_walkingBoy) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_BOYOUT), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene16_walkingBoy->_okeyCode); + + ani = g_vars->scene16_walkingBoy; + } else { + if (!g_vars->scene16_walkingGirl) + return; + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_GIRLOUT), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene16_walkingGirl->_okeyCode); + ani = g_vars->scene16_walkingGirl; + } + + if (!mq->chain(ani)) + delete mq; +} + +void sceneHandler16_startLaugh() { + StaticANIObject *girl = g_fp->_currentScene->getStaticANIObject1ById(ANI_GIRL, -1); + + girl->changeStatics2(ST_GRL_STAND); + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_GIRLLAUGH), 0, 1); + + mq->replaceKeyCode(-1, girl->_okeyCode); + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + + g_fp->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->setSubVarAsInt(sO_DudeSwinged, 0); + + g_vars->scene16_girlIsLaughing = true; +} + +void sceneHandler16_drink() { + if (g_vars->scene16_mug->_flags & 4) { + if (!g_vars->scene16_jettie->_movement) { + if (!g_vars->scene16_walkingBoy || !g_vars->scene16_walkingBoy->_movement || g_vars->scene16_walkingBoy->_movement->_id != MV_BOY_DRINK) { + if (!g_vars->scene16_walkingGirl || !g_vars->scene16_walkingGirl->_movement || g_vars->scene16_walkingGirl->_movement->_id != MV_GRL_DRINK) { + if (g_vars->scene16_mug->_statics->_staticsId == ST_MUG_FULL) { + MessageQueue *mq; + ExCommand *ex; + + if (g_vars->scene16_walkingBoy) { + g_fp->_aniMan->_flags |= 0x180; + + g_vars->scene16_walkingBoy->changeStatics2(ST_BOY_STAND); + g_vars->scene16_walkingBoy->queueMessageQueue(0); + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_BOYKICK), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene16_walkingBoy->_okeyCode); + + ex = new ExCommand(ANI_MAN, 34, 384, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3u; + ex->_field_14 = 384; + ex->_messageNum = 0; + + mq->insertExCommandAt(2, ex); + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + } else { + g_fp->_aniMan->_flags |= 1; + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_MANDRINK), 0, 1); + + ex = new ExCommand(ANI_MAN, 34, 256, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3u; + ex->_field_14 = 256; + ex->_messageNum = 0; + + mq->addExCommandToEnd(ex); + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + + g_fp->_currentScene->getStaticANIObject1ById(ANI_GIRL, -1)->changeStatics2(ST_GRL_STAND); + } + + g_fp->_currentScene->getStaticANIObject1ById(ANI_WIRE16, -1)->show1(-1, -1, -1, 0); + } else { + chainObjQueue(g_fp->_aniMan, QU_SC16_TAKEMUG, 1); + } + } + } + } + } +} + +void sceneHandler16_mugClick() { + if (abs(310 - g_fp->_aniMan->_ox) >= 1 || abs(449 - g_fp->_aniMan->_oy) >= 1 + || g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 310, 449, 1, ST_MAN_RIGHT); + + if (mq) { + ExCommand *ex = new ExCommand(0, 17, MSG_SC16_MUGCLICK, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags = 2; + mq->addExCommandToEnd(ex); + + postExCommand(g_fp->_aniMan->_id, 2, 310, 449, 0, -1); + } + } else { + sceneHandler16_drink(); + } +} + +void sceneHandler16_showMan() { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT); + g_fp->_aniMan->show1(-1, -1, -1, 0); + + g_vars->scene16_mug->show1(-1, -1, -1, 0); +} + +void sceneHandler16_showMug() { + chainQueue(QU_SC16_SHOWMUG, 0); +} + +void sceneHandler16_hideMan() { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT); + g_fp->_aniMan->hide(); + + g_vars->scene16_mug->hide(); +} + +void sceneHandler16_hideMug() { + g_vars->scene16_mug->hide(); +} + +void sceneHandler16_hideWire() { + g_vars->scene16_wire->hide(); +} + +void sceneHandler16_showWire() { + g_vars->scene16_wire->show1(-1, -1, -1, 0); +} + +void sceneHandler16_putOnWheel() { + StaticANIObject *ani = g_vars->scene16_walkingBoy; + + if (!ani) + ani = g_vars->scene16_walkingGirl; + + if (ani) + g_vars->scene16_figures.push_back(ani); + + ani = g_vars->scene16_figures.front(); + + g_vars->scene16_figures.pop_front(); + + if (ani) { + MessageQueue *mq; + + if (ani->_id == ANI_BOY) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_GOBOY), 0, 1); + + mq->replaceKeyCode(-1, ani->_okeyCode); + mq->chain(0); + + g_vars->scene16_walkingBoy = ani; + g_vars->scene16_walkingGirl = 0; + } else if (ani->_id == ANI_GIRL) { + if (g_fp->getObjectState(sO_Girl) == g_fp->getObjectEnumState(sO_Girl, sO_IsSwinging)) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_GOGIRL), 0, 1); + + mq->replaceKeyCode(-1, ani->_okeyCode); + mq->chain(0); + + g_vars->scene16_walkingBoy = 0; + g_vars->scene16_walkingGirl = ani; + } + } + } +} + +void sceneHandler16_girlROTFL() { + StaticANIObject *girl = g_fp->_currentScene->getStaticANIObject1ById(ANI_GIRL, -1); + + girl->changeStatics2(ST_GRL_LAUGH); + girl->startAnim(MV_GRL_FALL, 0, -1); + + g_vars->scene16_girlIsLaughing = false; +} + +int sceneHandler16(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch(cmd->_messageNum) { + case MSG_SC16_LAUGHSOUND: + sceneHandler16_laughSound(); + break; + + case MSG_SC16_SHOWBEARDED: + sceneHandler16_showBearded(); + break; + + case MSG_SC16_SHOWMUGFULL: + sceneHandler16_showMugFull(); + break; + + case MSG_SC16_FILLMUG: + sceneHandler16_fillMug(); + break; + + case MSG_SC16_STARTLAUGH: + sceneHandler16_startLaugh(); + break; + + case MSG_SC16_MUGCLICK: + if (!g_fp->_aniMan->isIdle() || g_fp->_aniMan->_flags & 0x100) + cmd->_messageKind = 0; + else + sceneHandler16_mugClick(); + + break; + + case MSG_SC16_SHOWMAN: + sceneHandler16_showMan(); + break; + + case MSG_SC16_SHOWMUG: + sceneHandler16_showMug(); + break; + + case MSG_SC16_HIDEMAN: + sceneHandler16_hideMan(); + break; + + case MSG_SC16_HIDEMUG: + sceneHandler16_hideMug(); + break; + + case MSG_SC16_HIDEWIRE: + sceneHandler16_hideWire(); + break; + + case MSG_SC16_SHOWWIRE: + sceneHandler16_showWire(); + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene16_placeIsOccupied) { + g_vars->scene16_walkingCount++; + + if (g_vars->scene16_walkingCount < 280) { + sceneHandler16_putOnWheel(); + + g_vars->scene16_walkingCount = 0; + } + } + + if (g_vars->scene16_girlIsLaughing) { + if (g_fp->_aniMan->_movement) + if (g_fp->_aniMan->_movement->_id == MV_MAN_TURN_RL) + sceneHandler16_girlROTFL(); + } + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene17.cpp b/engines/fullpipe/scenes/scene17.cpp new file mode 100644 index 0000000000..d40f8cf816 --- /dev/null +++ b/engines/fullpipe/scenes/scene17.cpp @@ -0,0 +1,285 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" +#include "fullpipe/floaters.h" + +namespace Fullpipe { + +void scene17_initScene(Scene *sc) { + g_vars->scene17_flyState = 1; + g_vars->scene17_sugarIsShown = false; + g_vars->scene17_sceneOldEdgeX = 0; + g_vars->scene17_flyCountdown = 0; + g_vars->scene17_hand = sc->getStaticANIObject1ById(ANI_HAND17, -1); +} + +void scene17_restoreState() { + if (g_fp->getObjectState(sO_UsherHand) == g_fp->getObjectEnumState(sO_UsherHand, sO_WithCoin)) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_ASK, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_TOCYCLE, 0); + + g_vars->scene17_handPhase = false; + } else { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_ASK, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_TOCYCLE, 1); + + g_vars->scene17_handPhase = true; + } + + g_fp->_floaters->init(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_17")); + + g_vars->scene17_flyState = g_fp->getObjectState(sO_Fly_17); + + if (g_vars->scene17_flyState <= 0 ) { + g_vars->scene17_flyCountdown = g_fp->_rnd->getRandomNumber(600) + 600; + + g_vars->scene17_flyState = g_fp->_rnd->getRandomNumber(4) + 1; + } + + g_fp->setObjectState(sO_Fly_17, g_vars->scene17_flyState - 1); +} + +int scene17_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_objectIdAtCursor != PIC_SC17_RTRUBA2 && g_fp->_objectIdAtCursor != PIC_SC17_RTRUBA) + return g_fp->_cursorId; + + if (!g_vars->scene17_handPhase) + return g_fp->_cursorId; + + int item = g_fp->_inventory->getSelectedItemId(); + + if ((g_fp->_cursorId != PIC_CSR_DEFAULT_INV || item != ANI_INV_COIN) && item != ANI_INV_BOOT && item != ANI_INV_HAMMER) + ; // empty + else + g_fp->_cursorId = PIC_CSR_ITN_INV; + + return g_fp->_cursorId; +} + +void sceneHandler17_drop() { + StaticANIObject *mug = g_fp->_currentScene->getStaticANIObject1ById(ANI_MUG_17, -1); + StaticANIObject *jet = g_fp->_currentScene->getStaticANIObject1ById(ANI_JET_17, -1); + + if (mug && mug->_flags & 4) { + mug->changeStatics2(ST_MUG17_EMPTY); + chainQueue(QU_SC17_FILLMUG_DROP, 0); + } else if (jet) { + jet->queueMessageQueue(0); + chainQueue(QU_JET17_DROP, 0); + } +} + +void sceneHandler17_fillBottle() { + StaticANIObject *bottle = g_fp->_currentScene->getStaticANIObject1ById(ANI_INV_BOTTLE, -1); + StaticANIObject *mug = g_fp->_currentScene->getStaticANIObject1ById(ANI_MUG_17, -1); + StaticANIObject *boot = g_fp->_currentScene->getStaticANIObject1ById(ANI_BOOT_17, -1); + + if (bottle && (bottle->_flags & 4)) + chainQueue(QU_SC17_FILLBOTTLE, 1); + else if (mug && (mug->_flags & 4) && mug->_statics->_staticsId == ST_MUG17_EMPTY) + chainQueue(QU_SC17_FILLMUG, 1); + else if (boot && (boot->_flags & 4)) + chainQueue(QU_SC17_FILLBOOT, 1); + else + chainQueue(QU_JET17_FLOW, 1); +} + +void sceneHandler17_testTruba() { + if (g_vars->scene17_hand->isIdle()) { + if (!g_vars->scene17_hand->_movement || g_vars->scene17_hand->_movement->_id != MV_HND17_FIGA) { + g_vars->scene17_hand->changeStatics2(ST_HND17_EMPTY); + g_vars->scene17_hand->startAnim(MV_HND17_FIGA, 0, -1); + } + } +} + +void sceneHandler17_showBottle() { + chainQueue(QU_SC17_SHOWBOTTLE, 0); +} + +void sceneHandler17_hideSugar() { + StaticANIObject *sugar = g_fp->_currentScene->getStaticANIObject1ById(ANI_INV_SUGAR, -1); + + if (sugar) + sugar->hide(); +} + +void sceneHandler17_showSugar() { + chainQueue(QU_SC17_SHOWSUGAR, 0); + + g_vars->scene17_sugarIsShown = true; +} + +void sceneHandler17_moonshineFill() { + StaticANIObject *moonshiner = g_fp->_currentScene->getStaticANIObject1ById(ANI_SAMOGONSHCHIK, -1); + + if (!(moonshiner->_flags & 0x80)) { + moonshiner->changeStatics2(ST_SMG_SIT); + chainObjQueue(moonshiner, QU_SMG_FILLBOTTLE, 1); + + g_vars->scene17_sugarIsShown = false; + } +} + +void sceneHandler17_updateFlies() { + g_fp->_floaters->genFlies(g_fp->_currentScene, 239, -50, 20, 4); + + g_fp->_floaters->_array2[0]->countdown = g_fp->_rnd->getRandomNumber(5) + 6; + g_fp->_floaters->_array2[0]->val6 = 239; + g_fp->_floaters->_array2[0]->val7 = -50; +} + + +int sceneHandler17(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC17_DROP: + sceneHandler17_drop(); + break; + + case MSG_SC17_UPDATEHAND: + if (g_fp->getObjectState(sO_UsherHand) == g_fp->getObjectEnumState(sO_UsherHand, sO_WithCoin)) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_ASK, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_TOCYCLE, 0); + + g_vars->scene17_handPhase = false; + } else { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_ASK, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_TOCYCLE, 1); + + g_vars->scene17_handPhase = true; + } + break; + + case MSG_SC17_FILLBOTTLE: + sceneHandler17_fillBottle(); + break; + + case MSG_SC17_TESTTRUBA: + sceneHandler17_testTruba(); + break; + + case MSG_SC17_SHOWBOTTLE: + sceneHandler17_showBottle(); + break; + + case MSG_SC17_HIDESUGAR: + sceneHandler17_hideSugar(); + break; + + case MSG_SC17_SHOWSUGAR: + sceneHandler17_showSugar(); + break; + + case 29: + { + int pic = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (pic == PIC_SC17_RTRUBA2 || pic == PIC_SC17_RTRUBA) { + if (cmd->_keyCode == ANI_INV_COIN || cmd->_keyCode == ANI_INV_BOOT || cmd->_keyCode == ANI_INV_HAMMER) { + if (g_vars->scene17_handPhase) { + if (g_fp->_aniMan->isIdle()) { + if (!(g_fp->_aniMan->_flags & 0x100)) { + handleObjectInteraction(g_fp->_aniMan, g_vars->scene17_hand, cmd->_keyCode); + break; + } + } + } + } + } + } + break; + + case 33: + { + int x = g_vars->scene17_sceneEdgeX; + g_vars->scene17_sceneOldEdgeX = g_vars->scene17_sceneEdgeX; + + if (g_fp->_aniMan2) { + x = g_fp->_aniMan2->_ox; + + g_vars->scene17_sceneEdgeX = x; + + if (x < g_fp->_sceneRect.left + 200) { + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + x = g_vars->scene17_sceneEdgeX; + } + + if (x > g_fp->_sceneRect.right - 200) { + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + x = g_vars->scene17_sceneEdgeX; + } + } + + if (g_vars->scene17_sugarIsShown) { + sceneHandler17_moonshineFill(); + x = g_vars->scene17_sceneEdgeX; + } + + if (g_vars->scene17_handPhase) { + if (g_vars->scene17_sceneOldEdgeX < 410 && x >= 410) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_TOCYCLE, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_ATTRACT, QU_HND17_ATTRACT, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_ASK, 1); + } else if (g_vars->scene17_sceneOldEdgeX > 410 && x <= 410) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_TOCYCLE, 1); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_ATTRACT, QU_HND17_ATTRACT, 1); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene17_hand, ST_HND17_EMPTY, QU_HND17_ASK, 0); + } + } + + --g_vars->scene17_flyCountdown; + + if (!g_vars->scene17_flyCountdown) + sceneHandler17_updateFlies(); + + g_fp->_floaters->update(); + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene18and19.cpp b/engines/fullpipe/scenes/scene18and19.cpp new file mode 100644 index 0000000000..5af7ef9043 --- /dev/null +++ b/engines/fullpipe/scenes/scene18and19.cpp @@ -0,0 +1,932 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +struct Swinger { + StaticANIObject *ani; + int sfield_4; + double angle; + int sx; + int sy; + int ix; + int iy; + int sflags; + int sfield_24; +}; + + +#define ANGLE(x) ((x) * M_PI / 180) + +void scene18_preload() { + g_fp->_scene3 = 0; + + for (SceneTagList::iterator s = g_fp->_gameProject->_sceneTagList->begin(); s != g_fp->_gameProject->_sceneTagList->end(); ++s) { + if (s->_sceneId == SC_18) { + g_fp->_scene3 = s->_scene; + s->_scene = 0; + + g_fp->_scene3->getStaticANIObject1ById(ANI_WHIRLIGIG_18, -1)->freeMovementsPixelData(); + + break; + } + } +} + +void scene18_setupEntrance() { + GameVar *var = g_fp->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME"); + + if (var->getSubVarAsInt("Entrance") == TrubaRight) + var->setSubVarAsInt("Entrance", TrubaLeft); +} + +void scene19_setSugarState(Scene *sc) { + if (g_fp->getObjectState(sO_Sugar) != g_fp->getObjectEnumState(sO_Sugar, sO_Present)) { + Scene *oldsc = g_fp->_currentScene; + + g_fp->_currentScene = sc; + sc->getStaticANIObject1ById(ANI_CORDIE, -1)->changeStatics2(ST_CDI_EMPTY2); + g_fp->_currentScene = oldsc; + } +} + +void scene19_setMovements(Scene *sc, int entranceId) { + if (entranceId == TrubaRight) { + g_vars->scene18_enteredTrubaRight = true; + } else { + g_vars->scene18_enteredTrubaRight = false; + g_vars->scene19_enteredTruba3 = (entranceId == PIC_SC19_RTRUBA3); + } + + for (uint i = 0; i < g_vars->scene18_swingers.size(); i++) { + if (!g_vars->scene18_enteredTrubaRight && (g_vars->scene18_swingers[i]->sflags & 0x20)) { + Scene *oldsc = g_fp->_currentScene; + + g_vars->scene18_swingers[i]->sflags = 1; + + g_fp->_currentScene = sc; + g_vars->scene18_swingers[i]->ani->changeStatics2(ST_KSL_NORM); + g_vars->scene18_swingers[i]->ani->_priority = 30; + g_fp->_currentScene = oldsc; + } + + sc->deleteStaticANIObject(g_vars->scene18_swingers[i]->ani); + } + + if (g_vars->scene18_whirlgig->_movement) { + g_vars->scene18_whirlgigMovMum = g_vars->scene18_whirlgig->_movement->_currDynamicPhaseIndex + 1; + + int mx; + + if (g_vars->scene18_whirlgig->_movement->_currMovement) + mx = g_vars->scene18_whirlgig->_movement->_currMovement->_dynamicPhases.size(); + else + mx = g_vars->scene18_whirlgig->_movement->_dynamicPhases.size(); + + if (g_vars->scene18_whirlgigMovMum > mx - 1) + g_vars->scene18_whirlgigMovMum = -1; + } else { + g_vars->scene18_whirlgigMovMum = 0; + } + + sc->deleteStaticANIObject(g_vars->scene18_boy); + sc->deleteStaticANIObject(g_vars->scene18_girl); + sc->stopAllSounds(); +} + +void scene19_preload() { + for (SceneTagList::iterator s = g_fp->_gameProject->_sceneTagList->begin(); s != g_fp->_gameProject->_sceneTagList->end(); ++s) { + if (s->_sceneId == SC_18) { + s->_scene = g_fp->_scene3; + + break; + } + } +} + +void scene18_setupSwingers(StaticANIObject *ani, Scene *sc) { + Swinger *swinger; + + g_vars->scene18_swingers.clear(); + + Scene *oldsc = g_fp->_currentScene; + g_fp->_currentScene = sc; + + for (int i = 0; i < 8; i++) { + swinger = new Swinger; + + swinger->angle = (double)i * ANGLE(45); + swinger->sx = g_vars->scene18_wheelCenterX - (int)(cos(swinger->angle) * -575.0); + swinger->sy = g_vars->scene18_wheelCenterY - (int)(sin(swinger->angle) * -575.0) + 87; + swinger->ix = swinger->sx; + swinger->iy = swinger->sy; + + if (i) { + StaticANIObject *newani = new StaticANIObject(ani); + + ani = newani; + + swinger->ani = newani; + swinger->sflags = 2; + + sc->addStaticANIObject(newani, 1); + } else { + swinger->ani = ani; + swinger->sflags = g_vars->scene18_girlIsSwinging ? 4 : 1; + } + + ani->_statics = ani->getStaticsById(ST_KSL_NORM); + //ani->_movement = 0; + ani->setOXY(swinger->sx, swinger->sy); + ani->_priority = 30; + ani->_flags |= 4; + + if (swinger->sflags & 2) + ani->startAnim(MV_KSL_SWINGBOY, 0, -1); + else if (swinger->sflags & 4) + ani->startAnim(MV_KSL_SWINGGIRL, 0, -1); + else + ani->startAnim(MV_KSL_SWING, 0, -1); + + ani->_movement->setDynamicPhaseIndex(g_fp->_rnd->getRandomNumber(17)); + + g_vars->scene18_swingers.push_back(swinger); + } + + g_fp->_currentScene = oldsc; +} + +void scene18_initScene1(Scene *sc) { + PicAniInfo info; + + int oldx = g_vars->scene18_wheelCenterX; + int oldy = g_vars->scene18_wheelCenterY; + + g_vars->scene18_girlIsSwinging = (g_fp->getObjectState(sO_Girl) == g_fp->getObjectEnumState(sO_Girl, sO_IsSwinging)); + + if (sc->_sceneId == SC_18) { + g_vars->scene18_whirlgig = sc->getStaticANIObject1ById(ANI_WHIRLIGIG_18, -1); + g_vars->scene18_wheelCenterX = 1032; + g_vars->scene18_wheelCenterY = -318; + } else { + g_vars->scene18_whirlgig = sc->getStaticANIObject1ById(ANI_WHIRLGIG_19, -1); + g_vars->scene18_wheelCenterX = 1024; + g_vars->scene18_wheelCenterY = 242; + } + + int newx = g_vars->scene18_wheelCenterX - oldx; + int newy = g_vars->scene18_wheelCenterY - oldy; + + g_vars->scene18_boyJumpX += newx; + g_vars->scene18_boyJumpY += newy; + g_vars->scene18_girlJumpX += newx; + g_vars->scene18_girlJumpY += newy; + + for (uint i = 0; i < g_vars->scene18_swingers.size(); i++) { + g_vars->scene18_swingers[i]->ani->getPicAniInfo(&info); + sc->addStaticANIObject(g_vars->scene18_swingers[i]->ani, 1); + g_vars->scene18_swingers[i]->ani->setPicAniInfo(&info); + + g_vars->scene18_swingers[i]->sx += newx; + g_vars->scene18_swingers[i]->sy += newy; + g_vars->scene18_swingers[i]->ix += newx; + g_vars->scene18_swingers[i]->iy += newy; + + GameObject *go; + + if (g_vars->scene18_swingers[i]->ani->_movement) + go = g_vars->scene18_swingers[i]->ani->_movement; + else + go = g_vars->scene18_swingers[i]->ani; + + go->setOXY(newx + go->_ox, newy + go->_oy); + } + + if (g_vars->scene18_bridgeIsConvoluted && g_vars->scene18_whirlgigMovMum != -1) { + g_vars->scene18_whirlgig->startAnim(sc->_sceneId != SC_18 ? MV_WHR19_SPIN : MV_WHR18_SPIN, 0, -1); + g_vars->scene18_whirlgig->_movement->setDynamicPhaseIndex(g_vars->scene18_whirlgigMovMum); + } + + int sndid; + + if (sc->_sceneId == SC_19) { + if (g_vars->scene18_bridgeIsConvoluted) + sndid = SND_19_015; + else + sndid = SND_19_016; + } else { + if (g_vars->scene18_bridgeIsConvoluted) + sndid = SND_18_006; + else + sndid = SND_18_010; + } + + g_fp->playSound(sndid, 1); + + g_vars->scene18_boy->getPicAniInfo(&info); + sc->addStaticANIObject(g_vars->scene18_boy, 1); + g_vars->scene18_boy->setPicAniInfo(&info); + + int x, y; + + if (g_vars->scene18_boy->_movement) { + x = g_vars->scene18_boy->_movement->_ox; + y = g_vars->scene18_boy->_movement->_oy; + } else { + x = g_vars->scene18_boy->_ox; + y = g_vars->scene18_boy->_oy; + } + + g_vars->scene18_boy->setOXY(newx + x, newy + y); + + g_vars->scene18_girl->getPicAniInfo(&info); + sc->addStaticANIObject(g_vars->scene18_girl, 1); + g_vars->scene18_girl->setPicAniInfo(&info); + + if (g_vars->scene18_girl->_movement) { + x = g_vars->scene18_girl->_movement->_ox; + y = g_vars->scene18_girl->_movement->_oy; + } else { + x = g_vars->scene18_girl->_ox; + y = g_vars->scene18_girl->_oy; + } + + g_vars->scene18_girl->setOXY(newx + x, newy + y); + + g_vars->scene18_wheelFlipper = false; + g_vars->scene18_jumpDistance = -1; + g_vars->scene18_jumpAngle = -1; + + if (g_vars->scene18_enteredTrubaRight) { + if (sc->_sceneId == SC_19) + g_fp->_aniMan2 = 0; + else + g_fp->_aniMan2 = g_vars->scene18_swingers[g_vars->scene18_manWheelPosTo]->ani; + } else { + g_fp->_aniMan2 = g_fp->_aniMan; + } +} + +void scene18_initScene2(Scene *sc) { + g_vars->scene18_whirlgig = sc->getStaticANIObject1ById(ANI_WHIRLIGIG_18, -1); + g_vars->scene18_wheelCenterX = 1032; + g_vars->scene18_wheelCenterY = -318; + + StaticANIObject *armchair = sc->getStaticANIObject1ById(ANI_KRESLO, -1); + + armchair->loadMovementsPixelData(); + + g_vars->scene18_girlIsSwinging = (g_fp->getObjectState(sO_Girl) == g_fp->getObjectEnumState(sO_Girl, sO_IsSwinging)); + + if (g_fp->getObjectState(sO_Bridge) == g_fp->getObjectEnumState(sO_Bridge, sO_Convoluted)) { + g_vars->scene18_bridgeIsConvoluted = true; + g_fp->playSound(SND_18_006, 1); + } else { + g_vars->scene18_bridgeIsConvoluted = false; + g_fp->playSound(SND_18_010, 1); + } + + scene18_setupSwingers(armchair, sc); + + g_vars->scene18_rotationCounter = 0; + g_vars->scene18_wheelFlipper = false; + g_vars->scene18_wheelIsTurning = true; + g_vars->scene18_kidIsOnWheel = -1; + g_vars->scene18_boyIsOnWheel = 0; + g_vars->scene18_girlIsOnWheel = 0; + g_vars->scene18_boyJumpedOff = true; + g_vars->scene18_manWheelPosTo = -1; + g_vars->scene18_jumpDistance = -1; + g_vars->scene18_jumpAngle = -1; + g_vars->scene18_manIsReady = false; + g_vars->scene18_enteredTrubaRight = 0; + g_vars->scene18_boy = sc->getStaticANIObject1ById(ANI_BOY18, -1); + g_vars->scene18_girl = sc->getStaticANIObject1ById(ANI_GIRL18, -1); + g_vars->scene18_domino = sc->getStaticANIObject1ById(ANI_DOMINO_18, -1); + g_vars->scene18_boyJumpX = 290; + g_vars->scene18_boyJumpY = -363; + g_vars->scene18_girlJumpX = 283; + g_vars->scene18_girlJumpY = -350; + + g_fp->initArcadeKeys("SC_18"); +} + +void scene19_initScene2() { + g_fp->_aniMan2 = 0; +} + +int scene18_updateCursor() { + if (g_vars->scene18_enteredTrubaRight) { + g_fp->_cursorId = PIC_CSR_DEFAULT; + } else { + g_fp->updateCursorCommon(); + + if (g_fp->_cursorId == PIC_CSR_ITN) { + if (g_fp->_objectIdAtCursor == PIC_SC18_LADDER1) { + g_fp->_cursorId = (g_vars->scene18_manY <= 250) ? PIC_CSR_GOD : PIC_CSR_GOU; + } else if (g_fp->_objectIdAtCursor == PIC_SC18_LADDER2 || g_fp->_objectIdAtCursor == PIC_SC18_LADDER3) { + g_fp->_cursorId = PIC_CSR_GOU; + } + } else if (g_fp->_cursorId == PIC_CSR_DEFAULT && g_fp->_objectIdAtCursor == PIC_SC18_DOMIN && g_vars->scene18_domino && (g_vars->scene18_domino->_flags & 4)) { + g_fp->_cursorId = PIC_CSR_ITN; + } + } + + return g_fp->_cursorId; +} + +int scene19_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_objectIdAtCursor == PIC_SC19_RTRUBA31) + g_fp->_cursorId = g_vars->scene19_enteredTruba3 ? PIC_CSR_GOR : PIC_CSR_DEFAULT; + + return g_fp->_cursorId; +} + +void sceneHandler18_clickBoard() { + if (ABS(967 - g_fp->_aniMan->_ox) > 1 || ABS(379 - g_fp->_aniMan->_oy) > 1 || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 967, 379, 1, ST_MAN_RIGHT); + ExCommand *ex = new ExCommand(0, 17, MSG_SC18_MANREADY, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags = 2; + + mq->addExCommandToEnd(ex); + + postExCommand(g_fp->_aniMan->_id, 2, 967, 379, 0, -1); + } else { + g_vars->scene18_manIsReady = true; + } +} + +void sceneHandler18_showManJumpTo() { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT); + g_fp->_aniMan->_flags &= 0xFFFB; + g_fp->_aniMan->_flags &= 0xFEFF; + g_vars->scene18_swingers[g_vars->scene18_manWheelPosTo]->sflags = 0x20; + + g_vars->scene18_swingers[g_vars->scene18_manWheelPosTo]->ani->changeStatics2(ST_KSL_JUMPMAN); + g_vars->scene18_swingers[g_vars->scene18_manWheelPosTo]->ani->startAnim(MV_KSL_INMAN, 0, -1); + g_vars->scene18_swingers[g_vars->scene18_manWheelPosTo]->ani->_priority = 20; + + g_vars->scene18_manIsReady = false; + g_vars->scene18_enteredTrubaRight = true; + + g_fp->_aniMan2 = g_vars->scene18_swingers[g_vars->scene18_manWheelPosTo]->ani; +} + +void sceneHandler18and19_showManJump() { + int x, y; + + if (g_vars->scene18_swingers[g_vars->scene18_manWheelPos]->ani->_movement) { + x = g_vars->scene18_swingers[g_vars->scene18_manWheelPos]->ani->_movement->_ox; + y = g_vars->scene18_swingers[g_vars->scene18_manWheelPos]->ani->_movement->_oy; + } else { + x = g_vars->scene18_swingers[g_vars->scene18_manWheelPos]->ani->_ox; + y = g_vars->scene18_swingers[g_vars->scene18_manWheelPos]->ani->_oy; + } + + g_fp->_aniMan->show1(x + 62, y + 5, MV_MAN18_JUMPTOTRUBA, 0); + g_fp->_aniMan->_priority = 35; + + int mqid = 0; + + if (g_vars->scene18_jumpDistance == 1) { + mqid = QU_SC19_MANJUMP1; + } else if (g_vars->scene18_jumpDistance == 2) { + mqid = QU_SC19_MANJUMP2; + } else if (g_vars->scene18_jumpDistance == 3) { + mqid = QU_SC19_MANJUMP3; + } + + if (mqid) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(mqid), 0, 0); + + g_fp->_aniMan2 = g_fp->_aniMan; + g_vars->scene18_enteredTrubaRight = false; + + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + } + + g_vars->scene18_swingers[g_vars->scene18_manWheelPos]->sflags = 1; + + g_vars->scene18_swingers[g_vars->scene18_manWheelPos]->ani->changeStatics2(ST_KSL_NORM); + g_vars->scene18_swingers[g_vars->scene18_manWheelPos]->ani->_priority = 30; +} + +void sceneHandler18and19_showGirlJumpTo() { + g_vars->scene18_girl->stopAnim_maybe(); + g_vars->scene18_girl->hide(); + + g_vars->scene18_swingers[g_vars->scene18_kidWheelPosTo]->sflags = 4; + + g_vars->scene18_swingers[g_vars->scene18_kidWheelPosTo]->ani->changeStatics2(ST_KSL_JUMPGIRL); + g_vars->scene18_swingers[g_vars->scene18_kidWheelPosTo]->ani->startAnim(MV_KSL_INGIRL, 0, -1); + + g_vars->scene18_kidIsOnWheel--; + g_vars->scene18_girlIsOnWheel--; +} + +void sceneHandler18and19_showGirlJump() { + StaticANIObject *ani = g_vars->scene18_swingers[g_vars->scene18_kidWheelPos]->ani; + int x, y; + + if (ani->_movement) { + x = ani->_movement->_ox; + y = ani->_movement->_oy; + } else { + x = ani->_ox; + y = ani->_oy; + } + + g_vars->scene18_girl->show1(x - 62, y - 10, MV_GRL18_JUMPFROM, 0); + g_vars->scene18_girl->_priority = 50; + g_vars->scene18_girl->startAnim(MV_GRL18_JUMPFROM, 0, -1); + + g_vars->scene18_swingers[g_vars->scene18_kidWheelPos]->sflags = 1; + + g_vars->scene18_swingers[g_vars->scene18_kidWheelPos]->ani->changeStatics2(ST_KSL_REACT); + g_vars->scene18_swingers[g_vars->scene18_kidWheelPos]->ani->startAnim(MV_KSL_CALMDOWN, 0, -1); + + g_vars->scene18_kidIsOnWheel = 1; + g_vars->scene18_girlIsOnWheel++; +} + +void sceneHandler18and19_showBoyJumpTo() { + g_vars->scene18_boy->stopAnim_maybe(); + g_vars->scene18_boy->hide(); + + g_vars->scene18_swingers[g_vars->scene18_kidWheelPosTo]->sflags = 2; + g_vars->scene18_swingers[g_vars->scene18_kidWheelPosTo]->ani->changeStatics2(ST_KSL_JUMPBOY); + g_vars->scene18_swingers[g_vars->scene18_kidWheelPosTo]->ani->startAnim(MV_KSL_INBOY, 0, -1); + + g_vars->scene18_kidIsOnWheel--; + g_vars->scene18_boyIsOnWheel--; +} + +void sceneHandler18and19_showBoyJump() { + StaticANIObject *ani = g_vars->scene18_swingers[g_vars->scene18_kidWheelPos]->ani; + int x, y; + + if (ani->_movement) { + x = ani->_movement->_ox; + y = ani->_movement->_oy; + } else { + x = ani->_ox; + y = ani->_oy; + } + + g_vars->scene18_boy->show1(x - 48, y + 8, MV_BOY18_JUMPFROM, 0); + g_vars->scene18_boy->_priority = 50; + g_vars->scene18_boy->startAnim(MV_BOY18_JUMPFROM, 0, -1); + + g_vars->scene18_swingers[g_vars->scene18_kidWheelPos]->sflags = 1; + + g_vars->scene18_swingers[g_vars->scene18_kidWheelPos]->ani->changeStatics2(ST_KSL_REACT); + g_vars->scene18_swingers[g_vars->scene18_kidWheelPos]->ani->startAnim(MV_KSL_CALMDOWN, 0, -1); + + g_vars->scene18_boyJumpedOff = true; +} + +void sceneHandler18and19_boyJumpTo() { + g_vars->scene18_boy->stopAnim_maybe(); + g_vars->scene18_boy->show1(g_vars->scene18_boyJumpX, g_vars->scene18_boyJumpY, MV_BOY18_JUMPTO, 0); + g_vars->scene18_boy->_priority = 50; + g_vars->scene18_boy->startAnim(MV_BOY18_JUMPTO, 0, -1); +} + +void sceneHandler18and19_girlJumpTo() { + g_vars->scene18_girl->stopAnim_maybe(); + g_vars->scene18_girl->show1(g_vars->scene18_girlJumpX, g_vars->scene18_girlJumpY, MV_GRL18_JUMPTO, 0); + g_vars->scene18_girl->_priority = 50; + g_vars->scene18_girl->startAnim(MV_GRL18_JUMPTO, 0, -1); +} + +void sceneHandler18and19_manStandArmchair() { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT); + g_fp->_aniMan->_flags |= 1; + g_fp->_aniMan->_priority = 35; + g_fp->_aniMan->startAnim(MV_MAN18_STANDKRESLO, 0, -1); +} + +void sceneHandler18and19_drawRiders() { + g_vars->scene18_rotationCounter++; + + if (g_vars->scene18_rotationCounter >= 359) + g_vars->scene18_rotationCounter = 0; + + for (uint i = 0; i < g_vars->scene18_swingers.size(); i++) { + Swinger *swinger = g_vars->scene18_swingers[i]; + + double oldangle = swinger->angle; + + swinger->angle += ANGLE(1); + + if (swinger->angle > ANGLE(360)) { + swinger->angle -= ANGLE(360); + oldangle -= ANGLE(360); + } + + int ix = g_vars->scene18_wheelCenterX - (int)(cos(swinger->angle) * -575.0); + int iy = g_vars->scene18_wheelCenterY - (int)(sin(swinger->angle) * -575.0) + 87; + + if (!g_vars->scene18_rotationCounter) { + ix = swinger->sx; + iy = swinger->sy; + swinger->angle = (double)i * ANGLE(45); + } + + if (swinger->ani->_movement) + swinger->ani->setOXY(ix - swinger->ix + swinger->ani->_movement->_ox, iy - swinger->iy + swinger->ani->_movement->_oy); + else + swinger->ani->setOXY(ix - swinger->ix + swinger->ani->_ox, iy - swinger->iy + swinger->ani->_oy); + + swinger->ix = ix; + swinger->iy = iy; + + if (!swinger->ani->_movement) { + int mv = 0; + + if (swinger->sflags & 2) { + mv = MV_KSL_SWINGBOY; + } else if (swinger->sflags & 4) { + mv = MV_KSL_SWINGGIRL; + } else if (swinger->sflags & 0x20) { + mv = MV_KSL_SWINGMAN; + } else if (swinger->sflags & 1) { + mv = MV_KSL_SWING; + } + + if (mv) + swinger->ani->startAnim(mv, 0, -1); + + if (swinger->ani->_movement) + swinger->ani->_movement->_counter = 0; + } + + if (g_vars->scene18_wheelIsTurning) { + if ((swinger->sflags & 2) && swinger->angle >= ANGLE(160) && oldangle < ANGLE(160)) { + swinger->sflags = 8; + swinger->ani->changeStatics2(ST_KSL_BOY); + swinger->ani->startAnim(MV_KSL_JUMPBOY, 0, -1); + g_vars->scene18_kidWheelPos = i; + } else if ((swinger->sflags & 4) && swinger->angle >= ANGLE(162) && oldangle < ANGLE(162)) { + swinger->sflags = 16; + swinger->ani->changeStatics2(ST_KSL_GIRL); + swinger->ani->startAnim(MV_KSL_JUMPGIRL, 0, -1); + g_vars->scene18_kidWheelPos = i; + } else if (g_vars->scene18_kidIsOnWheel) { + if (g_vars->scene18_boyIsOnWheel > 0 && (swinger->sflags & 1) && swinger->angle >= ANGLE(185) && oldangle < ANGLE(185)) { + g_vars->scene18_kidWheelPosTo = i; + sceneHandler18and19_boyJumpTo(); + } + } else if (g_vars->scene18_girlIsOnWheel > 0 && (swinger->sflags & 1) && swinger->angle >= ANGLE(187) && oldangle < ANGLE(187)) { + g_vars->scene18_kidWheelPosTo = i; + sceneHandler18and19_girlJumpTo(); + } + + if (swinger->angle >= ANGLE(200) && oldangle < ANGLE(200)) { + if (g_vars->scene18_boyJumpedOff) + g_vars->scene18_boyIsOnWheel++; + + g_vars->scene18_boyJumpedOff = false; + } + } + + if (g_vars->scene18_manIsReady && (swinger->sflags & 1) && swinger->angle >= ANGLE(83) && oldangle < ANGLE(83)) { + g_vars->scene18_manWheelPosTo = i; + sceneHandler18and19_manStandArmchair(); + } + + if (!g_vars->scene18_enteredTrubaRight) + continue; + + if ((int)i == g_vars->scene18_manWheelPosTo) { + if (swinger->angle >= ANGLE(170) && oldangle < ANGLE(170)) { + g_fp->_gameLoader->preloadScene(SC_18, TrubaRight); + } else if (swinger->angle >= ANGLE(25) && oldangle < ANGLE(25)) { + g_fp->_gameLoader->preloadScene(SC_19, TrubaRight); + } else if (swinger->angle >= ANGLE(270) && oldangle < ANGLE(270)) { + g_fp->_sceneRect.translate(1200, 0); + } + } + + if (g_vars->scene18_jumpDistance > 0) { + if (swinger->sflags & 0x20) { + double newa = (double)g_vars->scene18_jumpAngle * ANGLE(1); + + if (newa <= swinger->angle && oldangle < newa) { + swinger->ani->changeStatics2(ST_KSL_MAN); + swinger->ani->startAnim(MV_KSL_JUMPMAN, 0, -1); + swinger->ani->_priority = 35; + + g_vars->scene18_manWheelPos = i; + } + } + } + } +} + +void sceneHandler18and19_animateRiders() { + for (uint i = 0; i < g_vars->scene18_swingers.size(); i++) { + Swinger *swinger = g_vars->scene18_swingers[i]; + + if (!swinger->ani->_movement) { + int mv = 0; + + if (swinger->sflags & 2) + mv = MV_KSL_SWINGBOY; + else if (swinger->sflags & 4) + mv = MV_KSL_SWINGGIRL; + else if (swinger->sflags & 0x20) + mv = MV_KSL_SWINGMAN; + + if (mv) + swinger->ani->startAnim(mv, 0, -1); + + if (swinger->ani->_movement) + swinger->ani->_movement->_counter = 0; + } + } +} + +int sceneHandler18(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC18_CLICKBOARD: + sceneHandler18_clickBoard(); + break; + + case MSG_SC3_HIDEDOMINO: + g_vars->scene18_domino->_flags &= 0xFFFB; + break; + + case MSG_SC18_SHOWMANJUMP: + sceneHandler18and19_showManJump(); + break; + + case MSG_SC18_MANREADY: + g_vars->scene18_manIsReady = true; + break; + + case MSG_SC18_SHOWMANJUMPTO: + sceneHandler18_showManJumpTo(); + break; + + case MSG_SC18_SHOWGIRLJUMPTO: + sceneHandler18and19_showGirlJumpTo(); + break; + + case MSG_SC18_SHOWGIRLJUMP: + sceneHandler18and19_showGirlJump(); + break; + + case MSG_SC18_SHOWBOYJUMPTO: + sceneHandler18and19_showBoyJumpTo(); + break; + + case MSG_SC18_SHOWBOYJUMP: + sceneHandler18and19_showBoyJump(); + break; + + case 29: + { + if (g_vars->scene18_enteredTrubaRight) { + cmd->_messageKind = 0; + + break; + } + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (pic && pic->_id == PIC_SC18_DOMIN && g_vars->scene18_domino + && (g_vars->scene18_domino->_flags & 4) && g_fp->_aniMan->isIdle()) { + if (!(g_fp->_aniMan->_flags & 0x100) && g_fp->_msgObjectId2 != g_vars->scene18_domino->_id) { + handleObjectInteraction(g_fp->_aniMan, g_vars->scene18_domino, cmd->_keyCode); + cmd->_messageKind = 0; + + break; + } + } + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + + g_vars->scene18_manIsReady = false; + + break; + } + } + } + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + g_vars->scene18_manY = g_fp->_aniMan2->_oy; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene18_manIsReady && g_fp->_aniMan->_movement) + g_vars->scene18_manIsReady = false; + + if (g_vars->scene18_bridgeIsConvoluted) { + if (!g_vars->scene18_wheelFlipper) + sceneHandler18and19_drawRiders(); + + g_vars->scene18_wheelFlipper = !g_vars->scene18_wheelFlipper; + + if (!g_vars->scene18_whirlgig->_movement) { + g_vars->scene18_whirlgig->startAnim(MV_WHR18_SPIN, 0, -1); + g_fp->_behaviorManager->updateBehaviors(); + + break; + } + } else { + sceneHandler18and19_animateRiders(); + } + + g_fp->_behaviorManager->updateBehaviors(); + + break; + } + + return 0; +} + +void sceneHandler19_updateNumRides() { + int numRides = g_fp->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarAsInt(sO_DudeSwinged) + 1; + + if (numRides > 1) { + g_fp->setObjectState(sO_Girl, g_fp->getObjectEnumState(sO_Girl, sO_IsSwinging)); + + g_vars->scene18_kidIsOnWheel = 1; + g_vars->scene18_girlIsOnWheel++; + + numRides = 0; + } + + g_fp->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->setSubVarAsInt(sO_DudeSwinged, numRides); +} + +int sceneHandler19(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC18_SHOWMANJUMP: + sceneHandler18and19_showManJump(); + break; + + case MSG_SC19_UPDATENUMRIDES: + sceneHandler19_updateNumRides(); + break; + + case MSG_SC18_SHOWGIRLJUMPTO: + sceneHandler18and19_showGirlJumpTo(); + break; + + case MSG_SC18_SHOWBOYJUMPTO: + sceneHandler18and19_showBoyJumpTo(); + break; + + case MSG_SC18_SHOWGIRLJUMP: + sceneHandler18and19_showGirlJump(); + break; + + case MSG_SC18_SHOWBOYJUMP: + sceneHandler18and19_showBoyJump(); + break; + + case 29: + if (g_vars->scene18_enteredTrubaRight) { + switch (g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY)) { + case PIC_SC19_RTRUBA1: + g_vars->scene18_jumpDistance = 1; + g_vars->scene18_jumpAngle = 331; + cmd->_messageKind = 0; + break; + + case PIC_SC19_RTRUBA2: + g_vars->scene18_jumpDistance = 2; + g_vars->scene18_jumpAngle = 350; + cmd->_messageKind = 0; + break; + + case PIC_SC19_RTRUBA3: + g_vars->scene18_jumpDistance = 3; + g_vars->scene18_jumpAngle = 9; + cmd->_messageKind = 0; + break; + + default: + g_vars->scene18_jumpDistance = -1; + g_vars->scene18_jumpAngle = -1; + cmd->_messageKind = 0; + break; + } + break; + } + + if (g_vars->scene19_enteredTruba3) { + if (g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY) == PIC_SC19_RTRUBA3) { + if (g_fp->_aniMan->isIdle()) { + if (!(g_fp->_aniMan->_flags & 0x100)) { + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(PIC_SC19_RTRUBA31, 0); + + handleObjectInteraction(g_fp->_aniMan, pic, cmd->_keyCode); + break; + } + } + } + } + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + g_vars->scene18_manY = g_fp->_aniMan2->_oy; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene18_bridgeIsConvoluted) { + if (!g_vars->scene18_wheelFlipper) + sceneHandler18and19_drawRiders(); + + g_vars->scene18_wheelFlipper = !g_vars->scene18_wheelFlipper; + + if (!g_vars->scene18_whirlgig->_movement) { + g_vars->scene18_whirlgig->startAnim(MV_WHR19_SPIN, 0, -1); + + g_fp->_behaviorManager->updateBehaviors(); + + break; + } + } else { + sceneHandler18and19_animateRiders(); + } + + g_fp->_behaviorManager->updateBehaviors(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene20.cpp b/engines/fullpipe/scenes/scene20.cpp new file mode 100644 index 0000000000..7f19f175cc --- /dev/null +++ b/engines/fullpipe/scenes/scene20.cpp @@ -0,0 +1,155 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" +#include "fullpipe/floaters.h" + +namespace Fullpipe { + +void scene20_setExits(Scene *sc) { + int thingpar; + + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_OnStool) + || g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_OnTheFloor)) + thingpar = 1; + else if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_NearPipe) + || g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_NearPipeWithStool)) { + getSc2MctlCompoundBySceneId(sc->_sceneId)->enableLinks(sO_CloseThing, 1); + getSc2MctlCompoundBySceneId(sc->_sceneId)->enableLinks(sO_CloseThing2, 1); + getSc2MctlCompoundBySceneId(sc->_sceneId)->enableLinks(sO_CloseThing3, 0); + + return; + } else { + thingpar = 0; + } + + getSc2MctlCompoundBySceneId(sc->_sceneId)->enableLinks(sO_CloseThing, thingpar); + getSc2MctlCompoundBySceneId(sc->_sceneId)->enableLinks(sO_CloseThing2, 0); + getSc2MctlCompoundBySceneId(sc->_sceneId)->enableLinks(sO_CloseThing3, 1); +} + +void scene20_initScene(Scene *sc) { + Scene *oldsc = g_fp->_currentScene; + + g_vars->scene20_grandma = sc->getStaticANIObject1ById(ANI_GRANDMA_20, -1); + + g_fp->_currentScene = sc; + + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_OnTheFloor)) + g_fp->setObjectState(sO_Grandma, g_fp->getObjectEnumState(sO_Grandma, sO_NearPipe)); + + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_OnStool)) { + g_vars->scene20_grandma->changeStatics2(ST_GMA20_STOOL); + } else if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_OnTheFloor)) { + g_vars->scene20_grandma->changeStatics2(ST_GMA20_FLOOR); + } else if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_NearPipe) + || g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_NearPipeWithStool)) { + g_vars->scene20_grandma->changeStatics2(ST_GMA20_STAND); + } else { + g_vars->scene20_grandma->hide(); + } + + scene20_setExits(sc); + + g_fp->_floaters->init(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_20")); + + for (int i = 0; i < 3; i++) { + g_fp->_floaters->genFlies(sc, g_fp->_rnd->getRandomNumber(101) + 70, g_fp->_rnd->getRandomNumber(51) + 175, 100, 0); + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val13 = g_fp->_rnd->getRandomNumber(9); + } + + g_fp->_currentScene = oldsc; + + g_vars->scene20_fliesCountdown = g_fp->_rnd->getRandomNumber(200) + 400; +} + +void sceneHandler20_updateFlies() { + int sz = g_fp->_floaters->_array2.size(); + + if (sz < 3) { + g_fp->_floaters->genFlies(g_fp->_currentScene, 253, 650, 200, 0); + g_fp->_floaters->_array2[sz - 1]->val2 = 250; + g_fp->_floaters->_array2[sz - 1]->val3 = 200; + } else { + int idx = g_fp->_rnd->getRandomNumber(sz); + + g_fp->_floaters->_array2[idx]->countdown = 0; + g_fp->_floaters->_array2[idx]->fflags |= 4u; + g_fp->_floaters->_array2[idx]->val2 = 250; + g_fp->_floaters->_array2[idx]->val3 = 200; + g_fp->_floaters->_array2[idx]->val6 = 253; + g_fp->_floaters->_array2[idx]->val7 = 650; + g_fp->_floaters->_array2[idx]->ani->_priority = 200; + } + + g_vars->scene20_fliesCountdown = g_fp->_rnd->getRandomNumber(200) + 400; +} + +int sceneHandler20(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC20_UPDATELOCKABLE: + scene20_setExits(g_fp->_currentScene); + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + --g_vars->scene20_fliesCountdown; + + if (g_vars->scene20_fliesCountdown <= 0) + sceneHandler20_updateFlies(); + + g_fp->_floaters->update(); + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene21.cpp b/engines/fullpipe/scenes/scene21.cpp new file mode 100644 index 0000000000..8918515431 --- /dev/null +++ b/engines/fullpipe/scenes/scene21.cpp @@ -0,0 +1,148 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene21_initScene(Scene *sc) { + Scene *oldsc = g_fp->_currentScene; + + g_vars->scene21_giraffeBottom = sc->getStaticANIObject1ById(ANI_GIRAFFE_BOTTOM, -1); + g_fp->_currentScene = sc; + + if (g_fp->getObjectState(sO_LowerPipe_21) == g_fp->getObjectEnumState(sO_LowerPipe_21, sO_IsOpened)) { + g_vars->scene21_giraffeBottom->changeStatics2(ST_GRFB_HANG); + g_vars->scene21_pipeIsOpen = true; + g_vars->scene21_wigglePos = 0.0; + g_vars->scene21_giraffeBottomX = g_vars->scene21_giraffeBottom->_ox; + g_vars->scene21_giraffeBottomY = g_vars->scene21_giraffeBottom->_oy; + g_vars->scene21_wiggleTrigger = false; + } else { + g_vars->scene21_pipeIsOpen = false; + } + g_fp->_currentScene = oldsc; + g_fp->initArcadeKeys("SC_21"); +} + +int scene21_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_cursorId == PIC_CSR_ITN && g_fp->_objectIdAtCursor == PIC_SC21_DTRUBA) + + g_fp->_cursorId = PIC_CSR_GOD; + + return g_fp->_cursorId; +} + +void sceneHandler21_doWiggle() { + g_vars->scene21_giraffeBottom->setOXY((int)(cos(g_vars->scene21_wigglePos) * 4.0) + g_vars->scene21_giraffeBottom->_ox, + g_vars->scene21_giraffeBottom->_oy); + + g_vars->scene21_wigglePos += 0.19635; + + if (g_vars->scene21_wigglePos > 6.2831853) { + g_vars->scene21_wigglePos = 0; + + if (!g_vars->scene21_giraffeBottom->_movement) + g_vars->scene21_giraffeBottom->setOXY(g_vars->scene21_giraffeBottomX, g_vars->scene21_giraffeBottomY); + } +} + +int sceneHandler21(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC21_UPDATEASS: + if (g_fp->getObjectState(sO_LowerPipe_21) == g_fp->getObjectEnumState(sO_LowerPipe_21, sO_IsOpened)) { + g_vars->scene21_giraffeBottom->changeStatics2(ST_GRFB_HANG); + g_vars->scene21_giraffeBottom->setOXY(g_vars->scene21_giraffeBottomX, g_vars->scene21_giraffeBottomY); + g_vars->scene21_giraffeBottom->changeStatics2(ST_GRFB_SIT); + + g_vars->scene21_pipeIsOpen = false; + + g_fp->setObjectState(sO_LowerPipe_21, g_fp->getObjectEnumState(sO_LowerPipe_21, sO_IsClosed)); + } + + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode) ) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) + g_fp->processArcade(cmd); + } + } + + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x <= g_fp->_sceneWidth - 460) { + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + } else { + g_fp->_currentScene->_x = g_fp->_sceneWidth - x; + } + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene21_pipeIsOpen && !g_vars->scene21_wiggleTrigger) + sceneHandler21_doWiggle(); + + g_vars->scene21_wiggleTrigger = !g_vars->scene21_wiggleTrigger; + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene22.cpp b/engines/fullpipe/scenes/scene22.cpp new file mode 100644 index 0000000000..f51469da69 --- /dev/null +++ b/engines/fullpipe/scenes/scene22.cpp @@ -0,0 +1,395 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene22_initScene(Scene *sc) { + g_vars->scene22_bag = sc->getStaticANIObject1ById(ANI_MESHOK, -1); + + Scene *oldsc = g_fp->_currentScene; + g_fp->_currentScene = sc; + + g_vars->scene22_giraffeMiddle = sc->getStaticANIObject1ById(ANI_GIRAFFE_MIDDLE, -1); + g_vars->scene22_dudeIsOnStool = false; + g_vars->scene22_interactionIsDisabled = false; + g_vars->scene22_craneIsOut = true; + + if (g_fp->getObjectState(sO_Bag_22) == g_fp->getObjectEnumState(sO_Bag_22, sO_NotFallen)) + g_vars->scene22_numBagFalls = 0; + else if (g_fp->getObjectState(sO_Bag_22) == g_fp->getObjectEnumState(sO_Bag_22, sO_FallenOnce)) + g_vars->scene22_numBagFalls = 1; + else if ( g_fp->getObjectState(sO_Bag_22) == g_fp->getObjectEnumState(sO_Bag_22, sO_FallenTwice)) + g_vars->scene22_numBagFalls = 2; + else { + g_vars->scene22_numBagFalls = 3; + g_vars->scene22_craneIsOut = false; + } + + + if ( g_fp->getObjectState(sO_LowerPipe_21) == g_fp->getObjectEnumState(sO_LowerPipe_21, sO_IsOpened)) + g_vars->scene22_giraffeMiddle->changeStatics2(ST_GRFM_AFTER); + else + g_vars->scene22_giraffeMiddle->changeStatics2(ST_GRFM_NORM); + + g_fp->_currentScene = oldsc; + + g_fp->initArcadeKeys("SC_22"); +} + +int scene22_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_objectIdAtCursor != ANI_HANDLE_L) + return g_fp->_cursorId; + + int sel = g_fp->_inventory->getSelectedItemId(); + + if (!sel) { + g_fp->_cursorId = PIC_CSR_ITN; + return g_fp->_cursorId; + } + + if (g_vars->scene22_dudeIsOnStool || (sel != ANI_INV_STOOL && sel != ANI_INV_BOX)) + ; //empty + else + g_fp->_cursorId = PIC_CSR_ITN_INV; + + return g_fp->_cursorId; +} + +void scene22_setBagState() { + if (g_vars->scene22_craneIsOut) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene22_bag, ST_MSH_SIT, QU_MSH_CRANEOUT, 1); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene22_bag, ST_MSH_SIT, QU_MSH_MOVE, 0); + } else { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene22_bag, ST_MSH_SIT, QU_MSH_CRANEOUT, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene22_bag, ST_MSH_SIT, QU_MSH_MOVE, 1); + } +} + +void sceneHandler22_showStool() { + chainQueue(QU_SC22_SHOWSTOOL, 0); +} + +void sceneHandler22_hideStool() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_TABURETTE, -1)->hide(); +} + +void sceneHandler22_handleDown() { + if (g_vars->scene22_bag->_statics->_staticsId == ST_MSH_SIT) { + chainQueue(QU_MSH_CRANEOUT, 1); + g_vars->scene22_interactionIsDisabled = false; + } else { + ++g_vars->scene22_numBagFalls; + + int qid; + + if (g_vars->scene22_numBagFalls == 3) { + chainQueue(QU_SC22_FALLSACK_GMA, 1); + qid = QU_SC22_FALLBROOM; + } else { + qid = QU_SC22_FALLSACK; + } + + chainQueue(qid, 1); + + int state; + + if (g_vars->scene22_numBagFalls) { + if (g_vars->scene22_numBagFalls == 1) { + state = g_fp->getObjectEnumState(sO_Bag_22, sO_FallenOnce); + } else if (g_vars->scene22_numBagFalls == 2) { + state = g_fp->getObjectEnumState(sO_Bag_22, sO_FallenTwice); + } else { + state = g_fp->getObjectEnumState(sO_Bag_22, sO_BrushHasFallen); + } + } else { + state = g_fp->getObjectEnumState(sO_Bag_22, sO_NotFallen); + } + + g_fp->setObjectState(sO_Bag_22, state); + } + + g_vars->scene22_craneIsOut = true; + + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene22_bag, ST_MSH_SIT, QU_MSH_CRANEOUT, 1); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene22_bag, ST_MSH_SIT, QU_MSH_MOVE, 0); +} + +void sceneHandler22_fromStool(ExCommand *cmd) { + if (g_fp->_aniMan->isIdle() && !(g_fp->_aniMan->_flags & 0x100)) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC22_FROMSTOOL), 0, 0); + + mq->addExCommandToEnd(cmd->createClone()); + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + } +} + +void sceneHandler22_stoolLogic(ExCommand *cmd) { + StaticANIObject *ani; + MessageQueue *mq; + int xpos; + int manId; + + if (g_fp->_aniMan->isIdle() && !(g_fp->_aniMan->_flags & 0x100)) { + if (cmd->_keyCode == ANI_INV_STOOL) { + if (abs(841 - g_fp->_aniMan->_ox) <= 1) { + if (abs(449 - g_fp->_aniMan->_oy) <= 1) { + chainQueue(QU_SC22_PUTSTOOL, 1); + g_vars->scene22_interactionIsDisabled = true; + + return; + } + } + goto LABEL_13; + } + + if (cmd->_keyCode == ANI_INV_BOX) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_TABURETTE, -1); + if (!ani || !(ani->_flags & 4)) { + if (abs(841 - g_fp->_aniMan->_ox) <= 1) { + if (abs(449 - g_fp->_aniMan->_oy) <= 1) { + chainObjQueue(g_fp->_aniMan, QU_SC22_TRYBOX, 1); + return; + } + } + LABEL_13: + xpos = 841; + manId = ST_MAN_RIGHT; + LABEL_31: + mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, xpos, 449, 1, manId); + + if (!mq) + return; + + mq->addExCommandToEnd(cmd->createClone()); + + postExCommand(g_fp->_aniMan->_id, 2, 841, 449, 0, -1); + return; + } + } else { + if (cmd->_keyCode) + return; + + if (g_vars->scene22_dudeIsOnStool) { + if (g_fp->_aniMan->_movement) + return; + + chainQueue(QU_SC22_HANDLEDOWN, 1); + + g_vars->scene22_interactionIsDisabled = true; + return; + } + + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_TABURETTE, -1); + if (ani && (ani->_flags & 4)) { + int x = g_fp->_aniMan->_ox; + int y = g_fp->_aniMan->_ox; + + if (sqrt((double)((841 - x) * (841 - x) + (449 - y) * (449 - y))) + < sqrt((double)((1075 - x) * (1075 - x) + (449 - y) * (449 - y)))) { + if (abs(841 - x) <= 1) { + if (abs(449 - y) <= 1) { + chainQueue(QU_SC22_TOSTOOL, 1); + + g_vars->scene22_interactionIsDisabled = true; + return; + } + } + goto LABEL_13; + } + + if (abs(1075 - x) > 1 || abs(449 - y) > 1) { + xpos = 1075; + manId = ST_MAN_RIGHT | 0x4000; + goto LABEL_31; + } + + MGM mgm; + MGMInfo mgminfo; + + mgm.addItem(ANI_MAN); + mgminfo.ani = g_fp->_aniMan; + mgminfo.staticsId2 = ST_MAN_RIGHT; + mgminfo.x1 = 934; + mgminfo.y1 = 391; + mgminfo.field_1C = 10; + mgminfo.staticsId1 = 0x4145; + mgminfo.x2 = 981; + mgminfo.y2 = 390; + mgminfo.field_10 = 1; + mgminfo.flags = 127; + mgminfo.movementId = rMV_MAN_TURN_SRL; + + mq = mgm.genMovement(&mgminfo); + + ExCommand *ex = mq->getExCommandByIndex(0); + + mq->deleteExCommandByIndex(0, 0); + + delete mq; + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC22_TOSTOOL_R), 0, 0); + + mq->insertExCommandAt(2, ex); + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + + g_vars->scene22_interactionIsDisabled = true; + } else { + if (abs(1010 - g_fp->_aniMan->_ox) <= 1) { + if (abs(443 - g_fp->_aniMan->_oy) <= 1) { + chainQueue(QU_SC22_TRYHANDLE, 1); + return; + } + } + + mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 1010, 443, 1, ST_MAN_UP); + + if (mq) { + mq->addExCommandToEnd(cmd->createClone()); + + postExCommand(g_fp->_aniMan->_id, 2, 1010, 443, 0, -1); + return; + } + } + } + } +} + +int sceneHandler22(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC22_CRANEOUT_GMA: + chainQueue(QU_MSH_CRANEOUT_GMA, 1); + break; + + case MSG_SC22_CHECKGMABOOT: + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_In_15)) + g_fp->setObjectState(sO_Boot_15, g_fp->getObjectEnumState(sO_Boot_15, sO_IsPresent)); + + break; + + case MSG_SC22_SHOWSTOOL: + sceneHandler22_showStool(); + break; + + case MSG_SC22_HIDESTOOL: + sceneHandler22_hideStool(); + break; + + case MSG_SC22_FROMSTOOL: + g_vars->scene22_dudeIsOnStool = false; + g_vars->scene22_interactionIsDisabled = false; + + getCurrSceneSc2MotionController()->activate(); + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); + break; + + case MSG_SC22_ONSTOOL: + g_vars->scene22_dudeIsOnStool = true; + getCurrSceneSc2MotionController()->deactivate(); + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + break; + + case MSG_SC22_HANDLEDOWN: + sceneHandler22_handleDown(); + break; + + case 29: + if (!g_vars->scene22_interactionIsDisabled) { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (ani && ani->_id == ANI_HANDLE_L) { + sceneHandler22_stoolLogic(cmd); + return 0; + } + + if (!g_vars->scene22_dudeIsOnStool) { + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + return 0; + } + } + } + return 0; + } + + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN_RIGHT && !g_fp->_aniMan->_movement) { + sceneHandler22_fromStool(cmd); + + return 0; + } + } + + cmd->_messageKind = 0; + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x <= g_fp->_sceneWidth - 460) { + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + } else { + g_fp->_currentScene->_x = g_fp->_sceneWidth - x; + } + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + } + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene23.cpp b/engines/fullpipe/scenes/scene23.cpp new file mode 100644 index 0000000000..d6075c271b --- /dev/null +++ b/engines/fullpipe/scenes/scene23.cpp @@ -0,0 +1,555 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" +#include "fullpipe/floaters.h" + +namespace Fullpipe { + +bool sceneHandler23_testCalendar() { + int cal0, cal1, cal2, cal3; + + if (g_vars->scene23_calend0->_movement) + cal0 = g_vars->scene23_calend0->_movement->_staticsObj2->_staticsId; + else + cal0 = g_vars->scene23_calend0->_statics->_staticsId; + + if (g_vars->scene23_calend1->_movement) + cal1 = g_vars->scene23_calend1->_movement->_staticsObj2->_staticsId; + else + cal1 = g_vars->scene23_calend1->_statics->_staticsId; + + if (g_vars->scene23_calend2->_movement) + cal2 = g_vars->scene23_calend2->_movement->_staticsObj2->_staticsId; + else + cal2 = g_vars->scene23_calend2->_statics->_staticsId; + + if (g_vars->scene23_calend3->_movement) + cal3 = g_vars->scene23_calend3->_movement->_staticsObj2->_staticsId; + else + cal3 = g_vars->scene23_calend3->_statics->_staticsId; + + return (cal0 == ST_CND_1 && cal1 == ST_CND_4 && cal2 == ST_CND_0 && cal3 == ST_CND_2 && (g_vars->scene23_giraffee->_flags & 4)); +} + +void scene23_initScene(Scene *sc) { + g_vars->scene23_calend0 = sc->getStaticANIObject1ById(ANI_CALENDWHEEL, 0); + g_vars->scene23_calend1 = sc->getStaticANIObject1ById(ANI_CALENDWHEEL, 1); + g_vars->scene23_calend2 = sc->getStaticANIObject1ById(ANI_CALENDWHEEL, 2); + g_vars->scene23_calend3 = sc->getStaticANIObject1ById(ANI_CALENDWHEEL, 3); + g_vars->scene23_topReached = false; + g_vars->scene23_isOnStool = false; + g_vars->scene23_someVar = 0; + g_vars->scene23_giraffeTop = sc->getStaticANIObject1ById(ANI_GIRAFFE_TOP, -1); + g_vars->scene23_giraffee = sc->getStaticANIObject1ById(ANI_GIRAFFEE, -1); + + g_fp->_floaters->init(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_23")); + + Scene *oldsc = g_fp->_currentScene; + g_fp->_currentScene = sc; + + if (g_fp->getObjectState(sO_UpperHatch_23) == g_fp->getObjectEnumState(sO_UpperHatch_23, sO_Opened)) { + sc->getPictureObjectById(PIC_SC23_BOXOPEN, 0)->_flags |= 4; + sc->getPictureObjectById(PIC_SC23_BOXCLOSED, 0)->_flags &= 0xFFFB; + sc->getPictureObjectById(PIC_SC23_BTN1, 0)->_flags |= 4; + sc->getPictureObjectById(PIC_SC23_BTN2, 0)->_flags |= 4; + sc->getPictureObjectById(PIC_SC23_BTN3, 0)->_flags |= 4; + sc->getPictureObjectById(PIC_SC23_BTN4, 0)->_flags |= 4; + + if (g_vars->scene23_giraffee->_statics->_staticsId == ST_GRFG_EMPTY || !(g_vars->scene23_giraffee->_flags & 4)) { + g_vars->scene23_giraffee->changeStatics2(ST_GRFG_BALD); + g_vars->scene23_giraffee->_flags |= 4; + } + g_vars->scene23_calend0->show1(-1, -1, -1, 0); + g_vars->scene23_calend1->show1(-1, -1, -1, 0); + g_vars->scene23_calend2->show1(-1, -1, -1, 0); + g_vars->scene23_calend3->show1(-1, -1, -1, 0); + + sc->getStaticANIObject1ById(ANI_LUK23_U, -1)->changeStatics2(ST_LUK23U_OPEN); + } else { + sc->getPictureObjectById(PIC_SC23_BOXOPEN, 0)->_flags &= 0xFFFB; + sc->getPictureObjectById(PIC_SC23_BOXCLOSED, 0)->_flags |= 4; + sc->getPictureObjectById(PIC_SC23_BTN1, 0)->_flags &= 0xFFFB; + sc->getPictureObjectById(PIC_SC23_BTN2, 0)->_flags &= 0xFFFB; + sc->getPictureObjectById(PIC_SC23_BTN3, 0)->_flags &= 0xFFFB; + sc->getPictureObjectById(PIC_SC23_BTN4, 0)->_flags &= 0xFFFB; + + g_vars->scene23_giraffee->hide(); + g_vars->scene23_calend0->hide(); + g_vars->scene23_calend1->hide(); + g_vars->scene23_calend2->hide(); + g_vars->scene23_calend3->hide(); + + sc->getStaticANIObject1ById(ANI_LUK23_U, -1)->changeStatics2(ST_LUK23U_CLOSED); + + g_fp->_floaters->genFlies(sc, 600, 90, 0, 0); + } + + if (g_fp->getObjectState(sO_LowerHatch_23) == g_fp->getObjectEnumState(sO_LowerHatch_23, sO_Opened)) { + g_vars->scene23_giraffeTop->show1(-1, -1, -1, 0); + g_vars->scene23_giraffeTop->changeStatics2(ST_GRFU_UP); + + if (g_fp->getObjectState(sO_LowerPipe_21) == g_fp->getObjectEnumState(sO_LowerPipe_21, sO_IsOpened)) { + g_vars->scene23_giraffeTop->changeStatics2(ST_GRFU_KISS); + g_vars->scene23_giraffee->hide(); + } else { + if (g_fp->getObjectState(sO_UpperHatch_23) == g_fp->getObjectEnumState(sO_UpperHatch_23, sO_Opened) + && (g_vars->scene23_giraffee->_flags & 4)) + g_vars->scene23_giraffeTop->setOXY(614, 362); + else + g_vars->scene23_giraffeTop->setOXY(618, 350); + + if (sceneHandler23_testCalendar()) + g_vars->scene23_calend1->_statics = g_vars->scene23_calend1->getStaticsById(ST_CND_5); + } + + sc->getStaticANIObject1ById(ANI_LUK23_D, -1)->changeStatics2(ST_LUK23_OPEN); + + if (g_fp->getObjectState(sO_Lever_23) == g_fp->getObjectEnumState(sO_Lever_23, sO_Taken)) + sc->getStaticANIObject1ById(ANI_INV_LEVERHANDLE, -1)->hide(); + + sc->getStaticANIObject1ById(ANI_HANDLE23, -1)->hide(); + } else { + g_vars->scene23_giraffeTop->hide(); + + sc->getStaticANIObject1ById(ANI_LUK23_D, -1)->changeStatics2(ST_LUK23_WHANDLE2); + + sc->getStaticANIObject1ById(ANI_INV_LEVERHANDLE, -1)->hide(); + } + + g_fp->_currentScene = oldsc; +} + +void scene23_setGiraffeState() { + if (g_fp->getObjectState(sO_UpperHatch_23) == g_fp->getObjectEnumState(sO_UpperHatch_23, sO_Opened)) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene23_giraffeTop, ST_GRFU_UP, QU_GRFU_TURN_UL, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene23_giraffeTop, ST_GRFU_UP, QU_GRFU_TURN_UD, 0); + } +} + +int scene23_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_objectIdAtCursor == PIC_SC23_LADDERU) { + if (g_vars->scene23_topReached) + return g_fp->_cursorId; + + g_fp->_cursorId = getGameLoaderInventory()->getSelectedItemId() ? PIC_CSR_GOU : PIC_CSR_ITN; // FIXME check + } + + if (g_fp->_objectIdAtCursor == PIC_SC23_BTN1 || g_fp->_objectIdAtCursor == PIC_SC23_BTN2 + || g_fp->_objectIdAtCursor == PIC_SC23_BTN3 || g_fp->_objectIdAtCursor == PIC_SC23_BTN4 + || g_fp->_objectIdAtCursor == ANI_CALENDWHEEL) + g_fp->_cursorId = PIC_CSR_LIFT; + + return g_fp->_cursorId; +} + +void sceneHandler23_showStool() { + chainQueue(QU_SC23_SHOWSTOOL, 0); +} + +void sceneHandler23_hideStool() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_TABURETTE, -1)->hide(); +} + +void sceneHandler23_startKiss() { + g_vars->scene23_giraffeTop->changeStatics2(ST_GRFU_UP); + g_vars->scene23_giraffeTop->startMQIfIdle(QU_SC23_STARTKISS, 0); +} + +void sceneHandler23_spinWheel1() { + int mv = 0; + + switch (g_vars->scene23_calend0->_statics->_staticsId) { + case ST_CND_0: + mv = MV_CND_0_1; + break; + + case ST_CND_1: + mv = MV_CND_1_2; + break; + + case ST_CND_2: + mv = MV_CND_2_3; + break; + + case ST_CND_3: + g_vars->scene23_calend0->changeStatics2(ST_CND_9); + mv = MV_CND_9_0; + break; + + default: + break; + } + + if (mv) + g_vars->scene23_calend0->startAnim(mv, 0, -1); + + if (sceneHandler23_testCalendar()) + sceneHandler23_startKiss(); +} + +void sceneHandler23_spinWheel2and4(StaticANIObject *ani) { + int mv = 0; + + switch (ani->_statics->_staticsId) { + case ST_CND_0: + mv = MV_CND_0_1; + break; + + case ST_CND_1: + mv = MV_CND_1_2; + break; + + case ST_CND_2: + mv = MV_CND_2_3; + break; + + case ST_CND_3: + mv = MV_CND_3_4; + break; + + case ST_CND_4: + mv = MV_CND_4_5; + break; + + case ST_CND_5: + mv = MV_CND_5_6; + break; + + case ST_CND_6: + mv = MV_CND_6_7; + break; + + case ST_CND_7: + mv = MV_CND_7_8; + break; + + case ST_CND_8: + mv = MV_CND_8_9; + break; + + case ST_CND_9: + mv = MV_CND_9_0; + break; + + default: + break; + } + + if (mv) + ani->startAnim(mv, 0, -1); + + if (sceneHandler23_testCalendar()) + sceneHandler23_startKiss(); +} + +void sceneHandler23_spinWheel3() { + if (g_vars->scene23_calend2->_statics->_staticsId == ST_CND_0) { + g_vars->scene23_calend2->startAnim(MV_CND_0_1, 0, -1); + } else if (g_vars->scene23_calend2->_statics->_staticsId == ST_CND_1) { + g_vars->scene23_calend2->changeStatics2(ST_CND_9); + g_vars->scene23_calend2->startAnim(MV_CND_9_0, 0, -1); + } + + if (sceneHandler23_testCalendar()) + sceneHandler23_startKiss(); +} + +void sceneHandler23_pushButton(ExCommand *cmd) { + if (g_fp->_aniMan->isIdle() || !(g_fp->_aniMan->_flags & 0x100)) { + if (!g_vars->scene23_topReached) { + if (g_fp->_aniMan->_ox != 405 || g_fp->_aniMan->_oy != 220) { + if (g_fp->_aniMan->_ox != 276 || g_fp->_aniMan->_oy != 438 + || g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) { + if (g_fp->_msgX == 276 && g_fp->_msgY == 438 ) + return; + + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 276, 438, 1, ST_MAN_RIGHT); + + if (mq) { + mq->addExCommandToEnd(cmd->createClone()); + + postExCommand(g_fp->_aniMan->_id, 2, 276, 438, 0, -1); + } + } else { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC23_TOCALENDAR), 0, 0); + + mq->addExCommandToEnd(cmd->createClone()); + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + } + + if (!g_vars->scene23_topReached) + return; + } else { + g_vars->scene23_topReached = true; + } + } + + if (!g_fp->_aniMan->_movement && g_fp->_aniMan->_statics->_staticsId == ST_MAN_STANDLADDER) { + int mv = 0; + + switch (cmd->_messageNum) { + case MSG_SC23_CLICKBTN1: + mv = MV_MAN23_PUSH1; + break; + + case MSG_SC23_CLICKBTN2: + mv = MV_MAN23_PUSH2; + break; + + case MSG_SC23_CLICKBTN3: + mv = MV_MAN23_PUSH3; + break; + + case MSG_SC23_CLICKBTN4: + mv = MV_MAN23_PUSH4; + break; + + default: + return; + } + + if (mv) + g_fp->_aniMan->startAnim(mv, 0, -1); + + } + } +} + +void sceneHandler23_sendClick(StaticANIObject *ani) { + int msg = 0; + switch (ani->_okeyCode) { + case 0: + msg = MSG_SC23_CLICKBTN1; + break; + case 1: + msg = MSG_SC23_CLICKBTN2; + break; + case 2: + msg = MSG_SC23_CLICKBTN3; + break; + case 3: + msg = MSG_SC23_CLICKBTN4; + break; + default: + break; + } + + ExCommand *ex = new ExCommand(0, 17, msg, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + + ex->postMessage(); +} + +void sceneHandler23_checkReachingTop() { + if (g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_STANDLADDER + || g_fp->_aniMan->_ox != 405 || g_fp->_aniMan->_oy != 220) + g_vars->scene23_topReached = false; + else + g_vars->scene23_topReached = true; +} + +void sceneHandler23_exitCalendar() { + if (!g_fp->_aniMan->_movement && g_fp->_aniMan->_statics->_staticsId == ST_MAN_STANDLADDER + && !g_fp->_aniMan->getMessageQueue() && !(g_fp->_aniMan->_flags & 0x100)) { + chainQueue(QU_SC23_FROMCALENDAREXIT, 1); + g_vars->scene23_someVar = 2; + } +} + +void sceneHandler23_fromCalendar(ExCommand *cmd) { + if (!g_fp->_aniMan->_movement && g_fp->_aniMan->_statics->_staticsId == ST_MAN_STANDLADDER + && !g_fp->_aniMan->getMessageQueue() && !(g_fp->_aniMan->_flags & 0x100)) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC23_FROMCALENDAR), 0, 0); + + mq->addExCommandToEnd(cmd->createClone()); + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + + g_vars->scene23_topReached = false; + g_vars->scene23_someVar = 0; + } +} + +void sceneHandler23_fromStool(ExCommand *cmd) { + if (!g_fp->_aniMan->getMessageQueue() && !(g_fp->_aniMan->_flags & 0x100)) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC23_FROMSTOOL), 0, 0); + + mq->addExCommandToEnd(cmd->createClone()); + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + + cmd->_messageKind = 0; + } +} + +int sceneHandler23(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC23_FROMSTOOL: + g_vars->scene23_isOnStool = false; + + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); + break; + + case MSG_SC23_HIDEGIRAFFEE: + g_vars->scene23_giraffee->queueMessageQueue(0); + g_vars->scene23_giraffee->_flags &= 0xFFFB; + break; + + case MSG_SC23_ONSTOOL: + g_vars->scene23_isOnStool = true; + + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + break; + + case MSG_SC22_SHOWSTOOL: + sceneHandler23_showStool(); + break; + + case MSG_SC22_HIDESTOOL: + sceneHandler23_hideStool(); + break; + + case MSG_SC23_SPINWHEEL1: + sceneHandler23_spinWheel1(); + break; + + case MSG_SC23_SPINWHEEL2: + sceneHandler23_spinWheel2and4(g_vars->scene23_calend1); + break; + + case MSG_SC23_SPINWHEEL3: + sceneHandler23_spinWheel3(); + break; + + case MSG_SC23_SPINWHEEL4: + sceneHandler23_spinWheel2and4(g_vars->scene23_calend3); + break; + + case MSG_SC23_CLICKBTN1: + case MSG_SC23_CLICKBTN2: + case MSG_SC23_CLICKBTN3: + case MSG_SC23_CLICKBTN4: + sceneHandler23_pushButton(cmd); + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + g_fp->_floaters->update(); + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + int picId; + + if (ani && ani->_id == ANI_CALENDWHEEL) { + sceneHandler23_sendClick(ani); + cmd->_messageKind = 0; + } + + sceneHandler23_checkReachingTop(); + + if (g_vars->scene23_topReached) { + picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (picId == PIC_SC23_LADDER) { + sceneHandler23_exitCalendar(); + + cmd->_messageKind = 0; + break; + } + + if (cmd->_sceneClickY > 450) { + sceneHandler23_fromCalendar(cmd); + + cmd->_messageKind = 0; + break; + } + break; + } + + if (!g_vars->scene23_isOnStool) { + picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (picId == PIC_SC23_LADDERU && !g_vars->scene23_topReached) { + sceneHandler23_pushButton(cmd); + + cmd->_messageKind = 0; + break; + } + break; + } + + if (ani && ani->_id == ANI_HANDLE23) { + handleObjectInteraction(g_fp->_aniMan, ani, cmd->_keyCode); + cmd->_messageKind = 0; + } else { + sceneHandler23_fromStool(cmd); + + cmd->_messageKind = 0; + } + + break; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene24.cpp b/engines/fullpipe/scenes/scene24.cpp new file mode 100644 index 0000000000..2eb536df3f --- /dev/null +++ b/engines/fullpipe/scenes/scene24.cpp @@ -0,0 +1,129 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene24_initScene(Scene *sc) { + g_vars->scene24_water = sc->getStaticANIObject1ById(ANI_WATER24, -1); + g_vars->scene24_jet = sc->getStaticANIObject1ById(ANI_JET24, -1); + g_vars->scene24_drop = sc->getStaticANIObject1ById(ANI_DROP_24, -1); + + g_vars->scene24_water->setAlpha(0xa0); + g_vars->scene24_jet->setAlpha(0xa0); + g_vars->scene24_drop->setAlpha(0xa0); + + Scene *oldsc = g_fp->_currentScene; + g_fp->_currentScene = sc; + + if (g_fp->getObjectState(sO_Pool) == g_fp->getObjectEnumState(sO_Pool, sO_Overfull)) { + g_vars->scene24_jetIsOn = true; + g_vars->scene24_flowIsLow = false; + } else { + g_vars->scene24_jet->hide(); + + g_vars->scene24_jetIsOn = false; + + g_vars->scene24_water->changeStatics2(ST_WTR24_FLOWLOWER); + + g_vars->scene24_flowIsLow = true; + } + + if (g_fp->getObjectState(sO_Pool) < g_fp->getObjectEnumState(sO_Pool, sO_Full)) { + g_vars->scene24_waterIsOn = false; + + g_vars->scene24_water->hide(); + + g_fp->setObjectState(sO_StairsDown_24, g_fp->getObjectEnumState(sO_StairsDown_24, sO_IsOpened)); + } else { + g_vars->scene24_waterIsOn = true; + + g_fp->setObjectState(sO_StairsDown_24, g_fp->getObjectEnumState(sO_StairsDown_24, sO_IsClosed)); + } + + g_fp->_currentScene = oldsc; +} + +void scene24_setPoolState() { + if (g_fp->getObjectState(sO_Pool) == g_fp->getObjectEnumState(sO_Pool, sO_Overfull)) { + g_fp->_behaviorManager->setFlagByStaticAniObject(g_vars->scene24_drop, 0); + + g_fp->playSound(SND_24_007, 1); + } else if (g_fp->getObjectState(sO_Pool) == g_fp->getObjectEnumState(sO_Pool, sO_Full)) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene24_drop, ST_DRP24_EMPTY, QU_DRP24_TOFLOOR, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene24_drop, ST_DRP24_EMPTY, QU_DRP24_TOWATER, 1); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene24_drop, ST_DRP24_EMPTY, QU_DRP24_TOWATER2, 0); + + g_fp->playSound(SND_24_006, 1); + } else if (g_fp->getObjectState(sO_Pool) == g_fp->getObjectEnumState(sO_Pool, sO_HalfFull)) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene24_drop, ST_DRP24_EMPTY, QU_DRP24_TOFLOOR, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene24_drop, ST_DRP24_EMPTY, QU_DRP24_TOWATER, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene24_drop, ST_DRP24_EMPTY, QU_DRP24_TOWATER2, 1); + } else { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene24_drop, ST_DRP24_EMPTY, QU_DRP24_TOFLOOR, 1); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene24_drop, ST_DRP24_EMPTY, QU_DRP24_TOWATER, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene24_drop, ST_DRP24_EMPTY, QU_DRP24_TOWATER2, 0); + } +} + +int sceneHandler24(ExCommand *cmd) { + if (cmd->_messageKind == 17 && cmd->_messageNum == 33) { + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) { + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + } + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene24_waterIsOn && !g_vars->scene24_water->_movement) { + if (g_vars->scene24_flowIsLow) + g_vars->scene24_water->startAnim(MV_WTR24_FLOWLOWER, 0, -1); + else + g_vars->scene24_water->startAnim(MV_WTR24_FLOW, 0, -1); + } + + if (g_vars->scene24_jetIsOn && !g_vars->scene24_jet->_movement) + g_vars->scene24_jet->startAnim(MV_JET24_FLOW, 0, -1); + + g_fp->_behaviorManager->updateBehaviors(); + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene25.cpp b/engines/fullpipe/scenes/scene25.cpp new file mode 100644 index 0000000000..07eda73cf2 --- /dev/null +++ b/engines/fullpipe/scenes/scene25.cpp @@ -0,0 +1,723 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene25_showBoardOnRightFar() { + g_vars->scene25_board->show1(453, 557, MV_BRD25_RIGHT, 0); + g_vars->scene25_board->_priority = 28; +} + +void scene25_showBoardOnRightClose() { + g_vars->scene25_board->show1(632, 557, rMV_BRD25_RIGHT, 0); + g_vars->scene25_board->_priority = 28; +} + +void scene25_initScene(Scene *sc, int entranceId) { + g_vars->scene25_water = sc->getStaticANIObject1ById(ANI_WATER25, -1); + g_vars->scene25_board = sc->getStaticANIObject1ById(ANI_BOARD25, -1); + g_vars->scene25_drop = sc->getStaticANIObject1ById(ANI_DROP_25, -1); + g_vars->scene25_water->setAlpha(0xa0); + g_vars->scene25_drop->setAlpha(0xa0); + g_vars->scene25_dudeIsOnBoard = false; + + if (g_fp->getObjectState(sO_Pool) < g_fp->getObjectEnumState(sO_Pool, sO_HalfFull)) { + g_vars->scene25_waterIsPresent = false; + + g_vars->scene25_water->hide(); + } else { + g_vars->scene25_waterIsPresent = true; + + g_fp->playSound(SND_25_006, 1); + } + + int boardState = g_fp->getObjectState(sO_Board_25); + + if (entranceId == TrubaRight) { + if (boardState == g_fp->getObjectEnumState(sO_Board_25, sO_FarAway)) { + scene25_showBoardOnRightFar(); + + g_fp->playSound(SND_25_029, 0); + + g_vars->scene25_boardIsSelectable = false; + } else { + if (boardState == g_fp->getObjectEnumState(sO_Board_25, sO_Nearby) + || boardState == g_fp->getObjectEnumState(sO_Board_25, sO_WithDudeOnRight)) + scene25_showBoardOnRightClose(); + g_vars->scene25_boardIsSelectable = false; + } + } else { + if (boardState == g_fp->getObjectEnumState(sO_Board_25, sO_WithDudeOnLeft)) { + if (!getGameLoaderInventory()->getCountItemsWithId(ANI_INV_BOARD)) { + getGameLoaderInventory()->addItem(ANI_INV_BOARD, 1); + getGameLoaderInventory()->rebuildItemRects(); + } + } else { + g_vars->scene25_boardIsSelectable = true; + } + } + + g_vars->scene25_beardersAreThere = false; + g_vars->scene25_beardersCounter = 0; +} + +int scene25_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_vars->scene25_waterIsPresent) { + int inv = getGameLoaderInventory()->getSelectedItemId(); + + if (g_fp->_objectIdAtCursor == ANI_WATER25) { + if ((g_vars->scene25_boardIsSelectable && (!inv || inv == ANI_INV_BOARD)) || (g_vars->scene25_dudeIsOnBoard && (inv == ANI_INV_LOPAT || !inv))) + g_fp->_cursorId = (g_fp->_cursorId != PIC_CSR_DEFAULT) ? PIC_CSR_ITN : PIC_CSR_ITN_INV; // FIXME check + } else if (g_fp->_objectIdAtCursor == ANI_BOARD25 && (!inv || inv == ANI_INV_SWAB || inv == ANI_INV_BROOM || inv == ANI_INV_LOPAT)) { + g_fp->_cursorId = (g_fp->_cursorId != PIC_CSR_DEFAULT) ? PIC_CSR_ITN : PIC_CSR_ITN_INV; + } + } + + return g_fp->_cursorId; +} + +void scene25_setupWater(Scene *a1, int entranceId) { + if (g_vars->scene25_waterIsPresent) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene25_drop, ST_DRP25_EMPTY, QU_DRP25_TOFLOOR, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene25_drop, ST_DRP25_EMPTY, QU_DRP25_TOWATER, 1); + + if (entranceId != TrubaRight) + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_25"), "MUSIC2", 0); + } else { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene25_drop, ST_DRP25_EMPTY, QU_DRP25_TOFLOOR, 1); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene25_drop, ST_DRP25_EMPTY, QU_DRP25_TOWATER, 0); + } +} + +void sceneHandler25_stopBearders() { + g_vars->scene25_beardersAreThere = false; + + g_vars->scene25_bearders.clear(); +} + +void sceneHandler25_startBearders() { + g_vars->scene25_bearders.clear(); + g_vars->scene25_beardersCounter = 0; + + StaticANIObject *bearded = g_fp->accessScene(SC_COMMON)->getStaticANIObject1ById(ANI_BEARDED_CMN, -1); + + for (int i = 0; i < 3; i++) { + StaticANIObject *ani = new StaticANIObject(bearded); + + g_vars->scene25_bearders.push_back(ani); + + ani->_statics = ani->getStaticsById(ST_BRDCMN_EMPTY); + + g_fp->_currentScene->addStaticANIObject(ani, 1); + } + + g_vars->scene25_beardersAreThere = true; +} + +void sceneHandler25_enterMan() { + if (g_vars->scene25_waterIsPresent) { + chainQueue(QU_SC25_ENTERUP_WATER, 1); + + getCurrSceneSc2MotionController()->deactivate(); + } else { + chainQueue(QU_SC25_ENTERUP_FLOOR, 1); + } +} + +void sceneHandler25_enterTruba() { + PicAniInfo info; + + g_fp->_aniMan->getPicAniInfo(&info); + g_fp->_aniMan->_messageQueueId = 0; + g_fp->_aniMan->changeStatics2(g_fp->_aniMan->_statics->_staticsId); + + int x = g_fp->_aniMan->_ox; + int y = g_fp->_aniMan->_oy; + + g_fp->_aniMan->setPicAniInfo(&info); + + int id = g_fp->_aniMan->_statics->_staticsId; + int qid = 0; + + if (id == ST_MAN25_ONBOARD && x == 634 && y == 502) { + g_fp->_aniMan->changeStatics2(ST_MAN25_ONBOARD); + + qid = QU_SC25_MANTOTRUBA; + } else if (id == (ST_MAN25_ONBOARD|0x4000) && x == 632 && y == 502) { + g_fp->_aniMan->changeStatics2(ST_MAN25_ONBOARD|0x4000); + + qid = QU_SC25_MANTOTRUBA_R; + } + + if (qid) { + chainQueue(qid, 1); + g_vars->scene25_sneezeFlipper = false; + } +} + +void sceneHandler25_saveEntrance(int value) { + g_fp->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME")->setSubVarAsInt("Entrance", value); +} + +void sceneHandler25_toLadder() { + PicAniInfo info; + + g_fp->_aniMan->getPicAniInfo(&info); + g_fp->_aniMan->_messageQueueId = 0; + g_fp->_aniMan->changeStatics2(g_fp->_aniMan->_statics->_staticsId); + + int x = g_fp->_aniMan->_ox; + int y = g_fp->_aniMan->_oy; + + g_fp->_aniMan->setPicAniInfo(&info); + + int id = g_fp->_aniMan->_statics->_staticsId; + int qid = 0; + + if (id == ST_MAN25_ONBOARD && x == 307 && y == 502) { + g_fp->_aniMan->changeStatics2(ST_MAN25_ONBOARD); + + qid = QU_SC25_BACKTOLADDER; + } else if (id == (ST_MAN25_ONBOARD|0x4000) && x == 192 && y == 502) { + g_fp->_aniMan->changeStatics2(ST_MAN25_ONBOARD|0x4000); + + qid = QU_SC25_BOARDTOLADDER; + } + + if (qid) { + chainQueue(qid, 1); + g_vars->scene25_dudeIsOnBoard = false; + g_vars->scene25_boardIsSelectable = true; + g_vars->scene25_sneezeFlipper = false; + + sceneHandler25_saveEntrance(TrubaUp); + } +} + +void sceneHandler25_animateBearders() { + if (g_fp->_rnd->getRandomNumber(32767) < 218) { + MessageQueue *mq; + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC25_BEARDED), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene25_bearders[0]->_okeyCode); + mq->getExCommandByIndex(0)->_x = g_fp->_rnd->getRandomNumber(650) + 100; + mq->chain(0); + + g_vars->scene25_beardersCounter = 0; + + if (g_fp->_rnd->getRandomNumber(32767) < 0x1FFF) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC25_BEARDED2), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene25_bearders[1]->_okeyCode); + mq->getExCommandByIndex(0)->_x = g_fp->_rnd->getRandomNumber(650) + 100; + mq->chain(0); + + if (g_fp->_rnd->getRandomNumber(32767) < 8191) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC25_BEARDED3), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene25_bearders[2]->_okeyCode); + mq->getExCommandByIndex(0)->_x = g_fp->_rnd->getRandomNumber(650) + 100; + mq->chain(0); + } + } + } +} + +void sceneHandler25_sneeze() { + if (g_fp->_rnd->getRandomNumber(32767) % 10) { + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN25_ONBOARD) { + g_fp->_aniMan->startAnim(MV_MAN25_ONBOARD, 0, -1); + } else if (g_fp->_aniMan->_statics->_staticsId == (ST_MAN25_ONBOARD|0x4000)) { + g_fp->_aniMan->startAnim(rMV_MAN25_ONBOARD, 0, -1); + } + } else if (g_fp->_aniMan->_statics->_staticsId == ST_MAN25_ONBOARD) { + g_fp->_aniMan->startAnim(MV_MAN25_CHIH, 0, -1); + } else if (g_fp->_aniMan->_statics->_staticsId == (ST_MAN25_ONBOARD|0x4000)) { + g_fp->_aniMan->startAnim(rMV_MAN25_CHIH, 0, -1); + } +} + +void sceneHandler25_rowShovel() { + PicAniInfo info; + + g_fp->_aniMan->getPicAniInfo(&info); + g_fp->_aniMan->_messageQueueId = 0; + g_fp->_aniMan->changeStatics2(g_fp->_aniMan->_statics->_staticsId); + + int x = g_fp->_aniMan->_ox; + int y = g_fp->_aniMan->_oy; + + g_fp->_aniMan->setPicAniInfo(&info); + + int id = g_fp->_aniMan->_statics->_staticsId; + int qid = 0; + + if (id == ST_MAN25_ONBOARD && x == 370 && y == 502) { + g_fp->_aniMan->changeStatics2(ST_MAN25_ONBOARD); + + qid = QU_SC25_ROWTOTRUBA; + } else if (id == (ST_MAN25_ONBOARD|0x4000) && x == 632 && y == 502) { + g_fp->_aniMan->changeStatics2(ST_MAN25_ONBOARD|0x4000); + + qid = QU_SC25_ROWTOLADDER; + + g_fp->playSound(SND_25_030, 0); + } + + if (qid) { + chainQueue(qid, 1); + + g_vars->scene25_sneezeFlipper = false; + } +} + +void sceneHandler25_rowHand() { + PicAniInfo info; + + g_fp->_aniMan->getPicAniInfo(&info); + g_fp->_aniMan->_messageQueueId = 0; + g_fp->_aniMan->changeStatics2(g_fp->_aniMan->_statics->_staticsId); + + int x = g_fp->_aniMan->_ox; + int y = g_fp->_aniMan->_oy; + + g_fp->_aniMan->setPicAniInfo(&info); + + int id = g_fp->_aniMan->_statics->_staticsId; + int qid = 0; + + if (id == ST_MAN25_ONBOARD && x == 370 && y == 502) { + g_fp->_aniMan->changeStatics2(ST_MAN25_ONBOARD); + + qid = QU_SC25_TRYROWHAND; + } else if (id == (ST_MAN25_ONBOARD|0x4000) && x == 632 && y == 502) { + g_fp->_aniMan->changeStatics2(ST_MAN25_ONBOARD|0x4000); + + qid = QU_SC25_TRYROWHAND_R; + } + + if (qid) { + chainObjQueue(g_fp->_aniMan, qid, 1); + g_vars->scene25_sneezeFlipper = false; + } +} + +void sceneHandler25_putBoard() { + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN_STANDLADDER + || g_fp->_aniMan->_statics->_staticsId == ST_MAN_LADDERDOWN_R) { + g_fp->_aniMan->changeStatics2(ST_MAN_STANDLADDER); + g_fp->_aniMan->setOXY(281, 481); + + chainQueue(QU_SC25_PUTBOARD, 1); + + g_vars->scene25_dudeIsOnBoard = true; + g_vars->scene25_sneezeFlipper = false; + g_vars->scene25_boardIsSelectable = false; + } +} + +void sceneHandler25_tryWater() { + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN_STANDLADDER + || g_fp->_aniMan->_statics->_staticsId == ST_MAN_LADDERDOWN_R) { + g_fp->_aniMan->changeStatics2(ST_MAN_STANDLADDER); + + chainQueue(QU_SC25_TRYWATER, 1); + } +} + +void sceneHandler25_tryRow(int obj) { + PicAniInfo info; + + g_fp->_aniMan->getPicAniInfo(&info); + g_fp->_aniMan->_messageQueueId = 0; + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + + int x = g_fp->_aniMan->_ox; + int y = g_fp->_aniMan->_oy; + + g_fp->_aniMan->setPicAniInfo(&info); + + int qid = 0; + + if (x == 788 && y == 468) { + if (g_vars->scene25_board->_statics->_staticsId == ST_BRD25_RIGHT2) { + if (obj == ANI_INV_BROOM) { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + + qid = QU_SC25_TRYBROOM; + } + if (obj == ANI_INV_LOPAT) { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + + qid = QU_SC25_TRYSPADE; + } + + if (qid) { + chainQueue(qid, 1); + + g_fp->playSound(SND_25_028, 0); + + return; + } + + if (obj == ANI_INV_SWAB) { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + + chainQueue(QU_SC25_TRYSWAB, 1); + } else if (!obj) { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + + chainObjQueue(g_fp->_aniMan, QU_SC25_TRYHAND, 1); + + g_fp->playSound(SND_25_028, 0); + } + } else if (g_vars->scene25_board->_statics->_staticsId == (ST_MAN_RIGHT|0x4000) && !obj) { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + + chainQueue(QU_SC25_TRUBATOBOARD, 1); + + g_vars->scene25_dudeIsOnBoard = true; + } + } +} + +void sceneHandler25_ladderUp() { + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN_STANDLADDER + || g_fp->_aniMan->_statics->_staticsId == ST_MAN_LADDERDOWN_R) { + g_fp->_aniMan->changeStatics2(ST_MAN_STANDLADDER); + + chainQueue(QU_SC25_LADDERUP, 1); + } +} + +void sceneHandler25_backToPipe() { + if (!g_fp->_aniMan->_movement && g_fp->_aniMan->_statics->_staticsId == (ST_MAN_RIGHT|0x4000)) { + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT|0x4000); + + chainQueue(QU_SC25_BACKTOTRUBA, 1); + } +} + +void sceneHandler25_walkOnLadder(StaticANIObject *ani, Common::Point *pnt, MessageQueue *mq, int flag) { + int aniY = ani->_oy; + int newx = 0, newy = 0; + Common::Point point; + ExCommand *ex; + + if (flag) { + if (ani->_movement) { + ani->_movement->calcSomeXY(point, 0, ani->_movement->_currDynamicPhaseIndex); + newx = point.x; + aniY = ani->_oy - point.y; + } + } + + int pntx = pnt->x; + int pnty = pnt->y; + int numObsolete = -1; + int minDistance = 20000; + ExCommand *lastEx = 0; + + for (uint i = 0; i < mq->getCount(); i++) { + int curDistance = abs(pnty - aniY); + + ex = mq->getExCommandByIndex(i); + + if (ex->_messageKind == 1 && ani->_id == ex->_parentId) { + if (ex->_excFlags & 0x10000) { + if (ex->_messageNum == MV_MAN_TOLADDER) + ex->_messageNum = MV_MAN_TOLADDER2; + if (ex->_messageNum == MV_MAN_STARTLADDER) + ex->_messageNum = MV_MAN_STARTLADDER2; + if (ex->_messageNum == MV_MAN_GOLADDER) + ex->_messageNum = MV_MAN_GOLADDER2; + if (ex->_messageNum == MV_MAN_STOPLADDER) + ex->_messageNum = MV_MAN_STOPLADDER2; + } + + if (curDistance < minDistance || numObsolete < 0) { + numObsolete = i; + minDistance = curDistance; + lastEx = ex; + newx = pntx; + newy = pnty; + } + + ani->getMovementById(ex->_messageNum)->calcSomeXY(point, 0, -1); + pntx += point.x; + pnty += point.y; + } + } + + for (int i = 0; i < numObsolete; i++) + mq->deleteExCommandByIndex(0, 1); + + ex = new ExCommand(ani->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_14 = 256; + ex->_messageNum = 0; + ex->_excFlags |= 3; + + mq->addExCommandToEnd(ex); + + if (flag && ani->_movement && ani->_movement->_id == mq->getExCommandByIndex(0)->_messageNum) { + mq->deleteExCommandByIndex(0, 1); + + int movId = ani->_movement->_id; + int idx = ani->_movement->_currDynamicPhaseIndex; + + ani->changeStatics2(ani->_movement->_staticsObj1->_staticsId); + ani->setOXY(newx, newy); + + ani->startAnim(movId, mq->_id, -1); + + ani->_movement->setDynamicPhaseIndex(idx); + } else { + if (!lastEx) + error("sceneHandler25_walkOnLadder(): Incorrect state. Please report this to sev"); + + ani->changeStatics2(ani->getMovementById(lastEx->_messageNum)->_staticsObj1->_staticsId); + ani->setOXY(newx, newy); + ani->restartMessageQueue(mq); + } + + ani->_flags |= 1; +} + +bool sceneHandler25_isOnLadder(ExCommand *cmd) { + if ((g_fp->_aniMan->_movement && g_fp->_aniMan->_movement->_id == MV_MAN_GOLADDERDOWN) + || g_fp->_aniMan->_statics->_staticsId == ST_MAN_GOLADDERD) { + Interaction *inter = getGameLoaderInteractionController()->getInteractionByObjectIds(PIC_SC25_LADDERDOWN, ANI_MAN, cmd->_keyCode); + + if (!inter) + return 0; + + MessageQueue *mq = new MessageQueue(inter->_messageQueue, 0, 1); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(PIC_SC25_LADDERDOWN, 0); + Common::Point point; + + point.x = inter->_xOffs + pic->_ox; + point.y = inter->_yOffs + pic->_oy; + + mq->setFlags(mq->getFlags() | 1); + + sceneHandler25_walkOnLadder(g_fp->_aniMan, &point, mq, 0); + + return true; + } else { + return false; + } +} + +void sceneHandler25_sub03() { + warning("STUB: sceneHandler25_sub03()"); +} + +int sceneHandler25(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC25_STOPBEARDEDS: + sceneHandler25_stopBearders(); + break; + + case MSG_SC25_STARTBEARDEDS: + sceneHandler25_startBearders(); + break; + + case MSG_SC25_ENTERMAN: + sceneHandler25_enterMan(); + break; + + case MSG_SC25_ENTERTRUBA: + sceneHandler25_enterTruba(); + break; + + case MSG_SC25_TOLADDER: + sceneHandler25_toLadder(); + break; + + case MSG_BRD_TURN: + switch (g_fp->_rnd->getRandomNumber(3)) { + case 0: + g_fp->playSound(SND_25_025, 0); + break; + + case 1: + g_fp->playSound(SND_25_026, 0); + break; + + default: + g_fp->playSound(SND_25_027, 0); + break; + } + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + int y = g_fp->_aniMan2->_oy; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + + if (!g_vars->scene25_waterIsPresent) { + if (y < g_fp->_sceneRect.top + 200) + g_fp->_currentScene->_y = y - 300 - g_fp->_sceneRect.top; + + if (y > g_fp->_sceneRect.bottom - 200) + g_fp->_currentScene->_y = y + 300 - g_fp->_sceneRect.bottom; + } + } + + if (g_vars->scene25_beardersAreThere) { + g_vars->scene25_beardersCounter++; + + if (g_vars->scene25_beardersCounter >= 120) + sceneHandler25_animateBearders(); + } + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + if (g_vars->scene25_waterIsPresent && !g_vars->scene25_water->_movement) + g_vars->scene25_water->startAnim(MV_WTR25_FLOW, 0, -1); + + if (g_vars->scene25_dudeIsOnBoard && !g_fp->_aniMan->_movement && g_vars->scene25_sneezeFlipper) + sceneHandler25_sneeze(); + + g_vars->scene25_sneezeFlipper = true; + + if (g_vars->scene25_board->_flags & 4) { + if (!g_vars->scene25_board->_movement) { + if (g_vars->scene25_board->_statics->_staticsId & 0x4000) + g_vars->scene25_board->startAnim(rMV_BRD25_RIGHT, 0, -1); + else + g_vars->scene25_board->startAnim(MV_BRD25_RIGHT, 0, -1); + } + } + break; + + case 29: + { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (!g_vars->scene25_waterIsPresent) { + if ((picId == PIC_SC25_LADDERUP || picId == PIC_SC25_LADDERDOWN) && sceneHandler25_isOnLadder(cmd)) + cmd->_messageKind = 0; + + break; + } + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (ani) { + if (g_fp->_aniMan != ani) { + if (g_fp->_aniMan->isIdle()) { + if (!(g_fp->_aniMan->_flags & 0x100)) { + if (ani->_id == ANI_WATER25) { + if (g_vars->scene25_dudeIsOnBoard) { + if (cmd->_keyCode == ANI_INV_LOPAT) + sceneHandler25_rowShovel(); + + if (!cmd->_keyCode) + sceneHandler25_rowHand(); + } else { + if (cmd->_keyCode == ANI_INV_BOARD) + sceneHandler25_putBoard(); + + if (!cmd->_keyCode) + sceneHandler25_tryWater(); + } + } else if (ani->_id == ANI_BOARD25) { + sceneHandler25_tryRow(cmd->_keyCode); + break; + } + break; + } + } + } + } + + if (picId == PIC_SC25_LADDERUP && sceneHandler25_isOnLadder(cmd)) + cmd->_messageKind = 0; + + if (!g_fp->_aniMan->isIdle() || (g_fp->_aniMan->_flags & 0x100)) + break; + + if (g_vars->scene25_dudeIsOnBoard) { + if (picId == PIC_SC25_RTRUBA && !cmd->_keyCode) { + sceneHandler25_enterTruba(); + break; + } + } else { + if (picId != PIC_SC25_RTRUBA) { + if (picId == PIC_SC25_LADDERUP && !cmd->_keyCode) + sceneHandler25_ladderUp(); + break; + } + + if (!cmd->_keyCode) { + sceneHandler25_backToPipe(); + break; + } + } + if (g_vars->scene25_dudeIsOnBoard) { + if (picId != PIC_SC25_LADDERUP || cmd->_keyCode) + break; + + sceneHandler25_toLadder(); + break; + } + + if (picId == PIC_SC25_LADDERUP && !cmd->_keyCode) + sceneHandler25_ladderUp(); + + break; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene26.cpp b/engines/fullpipe/scenes/scene26.cpp new file mode 100644 index 0000000000..baed928d00 --- /dev/null +++ b/engines/fullpipe/scenes/scene26.cpp @@ -0,0 +1,355 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene26_initScene(Scene *sc) { + g_vars->scene26_chhi = sc->getStaticANIObject1ById(ANI_CHHI, -1); + g_vars->scene26_drop = sc->getStaticANIObject1ById(ANI_DROP_26, -1); + g_vars->scene26_sockPic = sc->getPictureObjectById(PIC_SC26_SOCK, 0); + g_vars->scene26_sock = sc->getStaticANIObject1ById(ANI_SOCK_26, -1); + + if (g_fp->getObjectState(sO_Hatch_26) == g_fp->getObjectEnumState(sO_Hatch_26, sO_WithSock)) { + g_fp->setObjectState(sO_Hatch_26, g_fp->getObjectEnumState(sO_Hatch_26, sO_Closed)); + g_fp->setObjectState(sO_Sock_26, g_fp->getObjectEnumState(sO_Sock_26, sO_HangsOnPipe)); + } + + Interaction *inter = getGameLoaderInteractionController()->getInteractionByObjectIds(ANI_LUK26, ANI_MAN, ANI_INV_SOCK); + + if (getGameLoaderInventory()->getCountItemsWithId(ANI_INV_VENT) == 0) + inter->_flags &= 0xFFFDFFFF; + else + inter->_flags |= 0x20000; + + if (g_fp->getObjectState(sO_Sock_26) == g_fp->getObjectEnumState(sO_Sock_26, sO_HangsOnPipe)) + g_vars->scene26_sockPic->_flags |= 4; + else + g_vars->scene26_sockPic->_flags &= 0xFFFB; + + if (g_fp->getObjectState(sO_Valve1_26) == g_fp->getObjectEnumState(sO_Valve1_26, sO_Opened)) + g_fp->playSound(SND_26_018, 1); +} + +int scene26_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_objectIdAtCursor != ANI_VENT || g_fp->_cursorId != PIC_CSR_DEFAULT) { + if (g_fp->_cursorId == PIC_CSR_ITN && g_fp->_objectIdAtCursor == PIC_SC26_LTRUBA) + g_fp->_cursorId = PIC_CSR_GOL; + } else { + g_fp->_cursorId = PIC_CSR_ITN; + } + + return g_fp->_cursorId; +} + +void sceneHandler26_updateDrop() { + if (g_fp->getObjectState(sO_Valve5_26) == g_fp->getObjectEnumState(sO_Valve5_26, sO_Closed)) + g_fp->_behaviorManager->setFlagByStaticAniObject(g_vars->scene26_drop, 0); + else + g_fp->_behaviorManager->setFlagByStaticAniObject(g_vars->scene26_drop, 1); +} + +void scene26_setupDrop(Scene *sc) { + sceneHandler26_updateDrop(); +} + +void sceneHandler26_showChi() { + g_vars->scene26_chhi->changeStatics2(ST_CHI_EMPTY); + + chainQueue(QU_CHI_SHOW, 1); +} + +void sceneHandler26_updatePool() { + if (g_fp->getObjectState(sO_Valve1_26) == g_fp->getObjectEnumState(sO_Valve1_26, sO_Valve1_26)) + g_fp->setObjectState(sO_Pool, g_fp->getObjectEnumState(sO_Pool, sO_Overfull)); + else if (g_fp->getObjectState(sO_Pool) == g_fp->getObjectEnumState(sO_Pool, sO_Overfull)) + g_fp->setObjectState(sO_Pool, g_fp->getObjectEnumState(sO_Pool, sO_Full)); + + if (g_fp->getObjectState(sO_Valve2_26) == g_fp->getObjectEnumState(sO_Valve2_26, sO_Valve1_26)) { + if (g_fp->getObjectState(sO_Pool) >= g_fp->getObjectEnumState(sO_Pool, sO_Full)) + g_fp->setObjectState(sO_Pool, g_fp->getObjectEnumState(sO_Pool, sO_HalfFull)); + } + + if (g_fp->getObjectState(sO_Valve3_26) == g_fp->getObjectEnumState(sO_Valve3_26, sO_Valve1_26)) { + if (g_fp->getObjectState(sO_Pool) >= g_fp->getObjectEnumState(sO_Pool, sO_HalfFull)) + g_fp->setObjectState(sO_Pool, g_fp->getObjectEnumState(sO_Pool, sO_Empty)); + } +} + +void sceneHandler26_hideChi() { + g_vars->scene26_chhi->changeStatics2(ST_CHI_NORM); + + chainQueue(QU_CHI_HIDE, 1); +} + +void sceneHandler26_testVent() { + if (!g_vars->scene26_activeVent) + return; + + if (g_vars->scene26_activeVent->_okeyCode == 0) { + if (g_fp->getObjectState(sO_Valve1_26) == g_fp->getObjectEnumState(sO_Valve1_26, sO_Opened)) + g_fp->stopAllSoundInstances(SND_26_018); + else + g_fp->playSound(SND_26_018, 1); + + if (g_fp->getObjectState(sO_Valve2_26) == g_fp->getObjectEnumState(sO_Valve2_26, sO_Opened)) { + chainQueue(QU_SC26_AUTOCLOSE2, 0); + + g_fp->playSound(SND_26_020, 0); + } + + if (g_fp->getObjectState(sO_Valve3_26) == g_fp->getObjectEnumState(sO_Valve3_26, sO_Opened)) { + chainQueue(QU_SC26_AUTOCLOSE3, 0); + + g_fp->playSound(SND_26_020, 0); + } + } else if (g_vars->scene26_activeVent->_okeyCode == 1) { + if (g_fp->getObjectState(sO_Valve2_26) == g_fp->getObjectEnumState(sO_Valve2_26, sO_Opened)) + g_fp->playSound(SND_26_020, 0); + else + g_fp->playSound(SND_26_019, 0); + + if (g_fp->getObjectState(sO_Pool) == g_fp->getObjectEnumState(sO_Pool, sO_Overfull) + || g_fp->getObjectState(sO_Pool) == g_fp->getObjectEnumState(sO_Pool, sO_Full)) + g_fp->playSound(SND_26_003, 0); + + if (g_fp->getObjectState(sO_Valve1_26) == g_fp->getObjectEnumState(sO_Valve1_26, sO_Opened)) { + g_fp->stopAllSoundInstances(SND_26_018); + + chainQueue(QU_SC26_AUTOCLOSE1, 0); + } + } else if (g_vars->scene26_activeVent->_okeyCode == 2) { + if (g_fp->getObjectState(sO_Valve3_26) == g_fp->getObjectEnumState(sO_Valve3_26, sO_Opened)) + g_fp->playSound(SND_26_020, 0); + else + g_fp->playSound(SND_26_019, 0); + + if (g_fp->getObjectState(sO_Pool) == g_fp->getObjectEnumState(sO_Pool, sO_Overfull) + || g_fp->getObjectState(sO_Pool) == g_fp->getObjectEnumState(sO_Pool, sO_Full) + || g_fp->getObjectState(sO_Pool) == g_fp->getObjectEnumState(sO_Pool, sO_HalfFull)) + g_fp->playSound(SND_26_003, 0); + + if (g_fp->getObjectState(sO_Valve1_26) == g_fp->getObjectEnumState(sO_Valve1_26, sO_Opened)) { + g_fp->stopAllSoundInstances(SND_26_018); + + chainQueue(QU_SC26_AUTOCLOSE1, 0); + } + } +} + +void sceneHandler26_showVent() { + if (g_vars->scene26_activeVent) { + int id = g_vars->scene26_activeVent->_statics->_staticsId; + + if (id == ST_VNT26_UP2) { + g_vars->scene26_activeVent->changeStatics2(ST_VNT26_RIGHT2); + } else { + if (id != ST_VNT26_RIGHT2) + return; + + g_vars->scene26_activeVent->changeStatics2(ST_VNT26_UP2); + } + g_vars->scene26_activeVent->show1(-1, -1, -1, 0); + } +} + +void sceneHandler26_hideVent() { + if (g_vars->scene26_activeVent) + g_vars->scene26_activeVent->hide(); +} + +void sceneHandler26_animateVents(StaticANIObject *ani) { + int qId = 0; + + switch (ani->_okeyCode) { + case 0: + if (g_fp->getObjectState(sO_Valve1_26) == g_fp->getObjectEnumState(sO_Valve1_26, sO_Closed)) + qId = QU_SC26_OPEN1; + else + qId = QU_SC26_CLOSE1; + + break; + + case 1: + if (g_fp->getObjectState(sO_Valve2_26) == g_fp->getObjectEnumState(sO_Valve2_26, sO_Closed)) + qId = QU_SC26_OPEN2; + else + qId = QU_SC26_CLOSE2; + + break; + + case 2: + if (g_fp->getObjectState(sO_Valve3_26) == g_fp->getObjectEnumState(sO_Valve3_26, sO_Closed)) + qId = QU_SC26_OPEN3; + else + qId = QU_SC26_CLOSE3; + + break; + + case 3: + if (g_fp->getObjectState(sO_Valve4_26) == g_fp->getObjectEnumState(sO_Valve4_26, sO_Closed)) + qId = QU_SC26_OPEN4; + else + qId = QU_SC26_CLOSE4; + + break; + + case 4: + if (g_fp->getObjectState(sO_Valve5_26) == g_fp->getObjectEnumState(sO_Valve5_26, sO_Closed)) + qId = QU_SC26_OPEN5; + else + qId = QU_SC26_CLOSE5; + + break; + + default: + return; + } + + if (qId) { + MessageQueue *mq = g_fp->_currentScene->getMessageQueueById(qId); + + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + } +} + +void sceneHandler26_clickVent(StaticANIObject *ani, ExCommand *cmd) { + if (ani->_okeyCode || g_fp->getObjectState(sO_Hatch_26) == g_fp->getObjectEnumState(sO_Hatch_26, sO_Opened)) { + if (g_fp->_aniMan->isIdle() && !(g_fp->_aniMan->_flags & 0x100)) { + g_vars->scene26_activeVent = ani; + + int x = ani->_ox - 20; + int y = ani->_oy + 61; + + if (abs(x - g_fp->_aniMan->_ox) > 1 || abs(y - g_fp->_aniMan->_oy) > 1 || g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_UP) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, x, y, 1, ST_MAN_UP); + + if (mq) { + ExCommand *ex = new ExCommand(0, 17, MSG_SC26_CLICKVENT, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags |= 3; + ex->_keyCode = ani->_okeyCode; + + mq->addExCommandToEnd(ex); + + postExCommand(g_fp->_aniMan->_id, 2, x, y, 0, -1); + } + } else { + sceneHandler26_animateVents(ani); + } + } + } + + cmd->_messageKind = 0; +} + +int sceneHandler26(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC26_UPDATEDROP: + sceneHandler26_updateDrop(); + break; + + case MSG_SC26_SHOWCHI: + sceneHandler26_showChi(); + break; + + case MSG_SC26_UPDATEPOOL: + sceneHandler26_updatePool(); + break; + + case MSG_SC26_HIDECHI: + sceneHandler26_hideChi(); + break; + + case MSG_SC26_TESTVENT: + sceneHandler26_testVent(); + break; + + case MSG_SC26_SHOWVENT: + sceneHandler26_showVent(); + break; + + case MSG_SC26_CLICKVENT: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT, cmd->_keyCode); + + if (ani && ani->_id == ANI_VENT) + sceneHandler26_clickVent(ani, cmd); + + break; + } + + case MSG_SC26_HIDEVENT: + sceneHandler26_hideVent(); + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (ani && ani->_id == ANI_VENT) + sceneHandler26_clickVent(ani, cmd); + + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene27.cpp b/engines/fullpipe/scenes/scene27.cpp new file mode 100644 index 0000000000..9570d30913 --- /dev/null +++ b/engines/fullpipe/scenes/scene27.cpp @@ -0,0 +1,759 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + +#define DBG 0 + +namespace Fullpipe { + +struct Bat { + StaticANIObject *ani; + int field_4; + double power; + double field_10; + double currX; + double currY; + double powerCos; + double powerSin; +}; + +void scene27_initScene(Scene *sc) { + g_vars->scene27_hitZone = sc->getPictureObjectById(PIC_SC27_HITZONE2, 0); + g_vars->scene27_driver = sc->getStaticANIObject1ById(ANI_VODILLA, -1); + g_vars->scene27_maid = sc->getStaticANIObject1ById(ANI_MAID, -1); + g_vars->scene27_batHandler = sc->getStaticANIObject1ById(ANI_BITAHANDLER, -1); + + g_vars->scene27_balls.numBalls = 0; + g_vars->scene27_balls.pTail = 0; + g_vars->scene27_balls.field_8 = 0; + g_vars->scene27_balls.pHead = 0; + g_vars->scene27_balls.cPlexLen = 10; + + free(g_vars->scene27_balls.cPlex); + g_vars->scene27_balls.cPlex = 0; + + g_vars->scene27_bats.clear(); + g_vars->scene27_var07.clear(); + + g_vars->scene27_driverHasVent = true; + g_vars->scene27_bat = sc->getStaticANIObject1ById(ANI_BITA, -1); + + for (int i = 0; i < 4; i++) { + StaticANIObject *newbat = new StaticANIObject(g_vars->scene27_bat); + + Ball *runPtr = g_vars->scene27_balls.pTail; + Ball *lastP = g_vars->scene27_balls.field_8; + + if (!g_vars->scene27_balls.pTail) { + g_vars->scene27_balls.cPlex = (byte *)calloc(g_vars->scene27_balls.cPlexLen, sizeof(Ball)); + + byte *p1 = g_vars->scene27_balls.cPlex + (g_vars->scene27_balls.cPlexLen - 1) * sizeof(Ball); + + if (g_vars->scene27_balls.cPlexLen - 1 < 0) { + runPtr = g_vars->scene27_balls.pTail; + } else { + runPtr = g_vars->scene27_balls.pTail; + + for (int j = 0; j < g_vars->scene27_balls.cPlexLen; j++) { + ((Ball *)p1)->p1 = runPtr; + runPtr = (Ball *)p1; + + p1 -= sizeof(Ball); + } + + g_vars->scene27_balls.pTail = runPtr; + } + } + + g_vars->scene27_balls.pTail = runPtr->p0; + runPtr->p1 = lastP; + runPtr->p0 = 0; + runPtr->ani = newbat; + + g_vars->scene27_balls.numBalls++; + + if (g_vars->scene27_balls.field_8) + g_vars->scene27_balls.field_8->p0 = runPtr; + else + g_vars->scene27_balls.pHead = runPtr; + + g_vars->scene27_balls.field_8 = runPtr; + + sc->addStaticANIObject(newbat, 1); + } + + g_vars->scene27_dudeIsAiming = false; + g_vars->scene27_maxPhaseReached = false; + g_vars->scene27_wipeIsNeeded = false; + g_vars->scene27_driverPushedButton = false; + g_vars->scene27_numLostBats = 0; + g_vars->scene27_knockCount = 0; + g_vars->scene27_launchPhase = 0; + + Scene *oldsc = g_fp->_currentScene; + g_fp->_currentScene = sc; + + if (g_fp->getObjectState(sO_Maid) == g_fp->getObjectEnumState(sO_Maid, sO_WithSwab)) { + g_vars->scene27_maid->changeStatics2(ST_MID_SWAB2); + } else if (g_fp->getObjectState(sO_Maid) == g_fp->getObjectEnumState(sO_Maid, sO_WithBroom)) { + g_vars->scene27_maid->changeStatics2(ST_MID_BROOM); + } else if (g_fp->getObjectState(sO_Maid) == g_fp->getObjectEnumState(sO_Maid, sO_WithSpade)) { + g_vars->scene27_maid->changeStatics2(ST_MID_SPADE); + } + + g_fp->_currentScene = oldsc; + + g_fp->setArcadeOverlay(PIC_CSR_ARCADE7); +} + +int scene27_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_vars->scene27_dudeIsAiming) { + if (g_fp->_cursorId != PIC_CSR_DEFAULT_INV && g_fp->_cursorId != PIC_CSR_ITN_INV) + g_fp->_cursorId = PIC_CSR_ARCADE7_D; + + } else if (g_fp->_objectIdAtCursor == ANI_MAN) { + if (g_vars->scene27_maxPhaseReached) + if (g_fp->_cursorId == PIC_CSR_DEFAULT) + g_fp->_cursorId = PIC_CSR_ITN; + } + + return g_fp->_cursorId; +} + +void sceneHandler27_driverGiveVent() { + g_vars->scene27_driver->changeStatics2(ST_DRV_VENT); + g_vars->scene27_driver->startMQIfIdle(QU_DRV_GIVEVENT, 1); + + g_vars->scene27_driverHasVent = false; + + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); +} + +void sceneHandler27_winArcade() { + if (g_fp->getObjectState(sO_Driver) == g_fp->getObjectEnumState(sO_Driver, sO_WithSteering)) { + g_vars->scene27_dudeIsAiming = false; + + g_fp->_aniMan->_callback2 = 0; + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT); + + sceneHandler27_driverGiveVent(); + } +} + +void sceneHandler27_takeVent() { + if (g_fp->getObjectState(sO_Maid) == g_fp->getObjectEnumState(sO_Maid, sO_WithSwab)) { + if (g_vars->scene27_maid->isIdle()) { + if (g_vars->scene27_maid->_flags & 4) { + g_vars->scene27_maid->changeStatics2(ST_MID_SWAB2); + g_vars->scene27_maid->startMQIfIdle(QU_MID_CLEANVENT, 1); + } + } + } +} + +void sceneHandler27_showNextBat() { + if (g_vars->scene27_bat) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC27_SHOWBET), 0, 1); + + mq->replaceKeyCode(-1, g_vars->scene27_bat->_okeyCode); + mq->chain(0); + } + + g_vars->scene27_batHandler->_priority = 1045; +} + +int sceneHandler27_updateScreenCallback() { + int res; + + res = g_fp->drawArcadeOverlay(getGameLoaderInteractionController()->_flag24 == 0); + + if (!res) + g_fp->_updateScreenCallback = 0; + + return res; +} + +void sceneHandler27_aniManCallback(int *phase) { + if (!g_vars->scene27_maxPhaseReached) { + if (*phase >= 5) + g_vars->scene27_maxPhaseReached = true; + else + ++*phase; + } +} + +void sceneHandler27_throwBat() { + if (getGameLoaderInteractionController()->_flag24) + g_fp->_updateScreenCallback = sceneHandler27_updateScreenCallback; + + g_fp->_aniMan->_callback2 = sceneHandler27_aniManCallback; + + g_fp->_aniMan->startAnim(MV_MAN27_THROWBET, 0, -1); + + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + + g_vars->scene27_maxPhaseReached = false; + + g_vars->scene27_bat->hide(); +} + +void sceneHandler27_clickBat(ExCommand *cmd) { + int bx = g_vars->scene27_bat->_ox - 5; + int by = g_vars->scene27_bat->_oy - 71; + +#if DBG + sceneHandler27_throwBat(); + return; +#endif + + if (ABS(bx - g_fp->_aniMan->_ox) > 1 || ABS(by - g_fp->_aniMan->_oy) > 1 + || g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, bx, by, 1, ST_MAN_RIGHT); + + if (mq) { + mq->addExCommandToEnd(cmd->createClone()); + + postExCommand(g_fp->_aniMan->_id, 2, bx, by, 0, -1); + } + } else { + sceneHandler27_throwBat(); + } +} + +void sceneHandler27_maidSwab() { +#if DBG + return; +#endif + if (g_fp->getObjectState(sO_Maid) == g_fp->getObjectEnumState(sO_Maid, sO_WithSwab)) + g_vars->scene27_maid->changeStatics2(ST_MID_SWAB); +} + +void sceneHandler27_startBat(StaticANIObject *bat) { + Bat *newbat = new Bat; + + newbat->power = g_vars->scene27_launchPhase * 2.5 + 8.0; + newbat->field_10 = 0; + newbat->ani = bat; + newbat->powerCos = newbat->power * cos(0.0); + newbat->powerSin = newbat->power * sin(0.0); + newbat->currX = newbat->powerCos + (double)g_fp->_aniMan->_ox + 42.0; + newbat->currY = newbat->powerSin + (double)g_fp->_aniMan->_oy + 58.0; + + bat->_statics = (Statics *)bat->_staticsList[0]; + bat->setOXY((int)newbat->currX, (int)newbat->currY); + bat->_flags |= 4; + + g_vars->scene27_bats.push_back(newbat); + + sceneHandler27_maidSwab(); +} + +void sceneHandler27_startAiming() { + g_vars->scene27_dudeIsAiming = false; + g_vars->scene27_maxPhaseReached = false; + + g_fp->_aniMan->_callback2 = 0; + + g_vars->scene27_launchPhase = g_fp->_aniMan->_movement->_currDynamicPhaseIndex - 6; + + int phase = 21 - g_vars->scene27_launchPhase; + + if (phase < 14) + phase = 14; + + if (phase > 20) + phase = 20; + + g_fp->playSound(SND_27_044, 0); + + g_fp->_aniMan->_movement->setDynamicPhaseIndex(phase); +} + +void sceneHandler27_initAiming(ExCommand *cmd) { + g_vars->scene27_aimStartX = cmd->_x; + g_vars->scene27_aimStartY = cmd->_y; + g_vars->scene27_dudeIsAiming = true; + g_vars->scene27_maxPhaseReached = false; +} + +void sceneHandler27_aimDude() { + int phase = (g_vars->scene27_aimStartX - g_fp->_mouseScreenPos.x) / 20 + 6; + + if (phase < 6) + phase = 6; + + if (phase > 11) + phase = 11; + + if (g_fp->_aniMan->_movement) + g_fp->_aniMan->_movement->setDynamicPhaseIndex(phase); +} + +void sceneHandler27_wipeDo() { + for (uint i = 0; i < g_vars->scene27_bats.size(); i++) { + if (g_vars->scene27_bats[i]->currX < 800.0) { + g_vars->scene27_bats[i]->field_10 = atan2(800.0 - g_vars->scene27_bats[i]->currX, 520.0 - g_vars->scene27_bats[i]->currY); + g_vars->scene27_bats[i]->power += 1.0; + } + } +} + +bool sceneHandler27_batFallLogic(uint batn) { + Bat *bat = g_vars->scene27_bats[batn]; + + int y = (int)((bat->currY - 458.0) * 0.4848484848484849 + 734.0); + + if (y >= bat->currX) + return false; + + if (bat->currX - y > 15.0 || bat->ani->_statics->_staticsId == ST_BTA_FALL) { + bat->ani->_priority = 2020; + + g_vars->scene27_var07.push_back(bat); + + if (batn != g_vars->scene27_var07.size() - 1) + g_vars->scene27_var07.remove_at(batn); + } else if (!bat->ani->_movement) { + bat->ani->startAnim(MV_BTA_FALL, 0, -1); + } + + return true; +} + +bool sceneHandler27_batCalcDistance(int bat1, int bat2) { + double at = atan2(g_vars->scene27_bats[bat1]->currX - g_vars->scene27_bats[bat2]->currX, g_vars->scene27_bats[bat1]->currY - g_vars->scene27_bats[bat2]->currY); + double dy = g_vars->scene27_bats[bat1]->currY - g_vars->scene27_bats[bat2]->currY; + double dx = g_vars->scene27_bats[bat1]->currX - g_vars->scene27_bats[bat2]->currX; + double ay = cos(at); + double ax = sin(at); + + return sqrt(ax * ax * 0.25 + ay * ay) * 54.0 > sqrt(dx * dx + dy * dy); +} + +void sceneHandler27_knockBats(int bat1n, int bat2n) { + Bat *bat1 = g_vars->scene27_bats[bat1n]; + Bat *bat2 = g_vars->scene27_bats[bat2n]; + + if (0.0 != bat1->power) { + double rndF = (double)g_fp->_rnd->getRandomNumber(32767) * 0.0000009155552842799158 - 0.015 + + atan2(bat2->currX - bat1->currX, bat2->currY - bat1->currY); + double rndCos = cos(rndF); + double rndSin = sin(rndF); + + double pow1x = cos(bat1->field_10 - rndF) * (double)((int)(bat2->currX - bat1->currX) >= 0 ? 1 : -1) * bat1->power; + double pow1y = sin(bat1->field_10 - rndF) * (double)((int)(bat2->currY - bat1->currY) >= 0 ? 1 : -1) * bat1->power; + + bat1->powerCos -= pow1x * 1.1; + bat1->powerSin -= pow1y * 1.1; + + rndF = ((double)g_fp->_rnd->getRandomNumber(32767) * 0.0000009155552842799158 - 0.015 + + atan2(bat1->currX - bat2->currX, bat1->currY - bat2->currY)); + double pow2x = cos(bat2->field_10 - rndF) * (double)((int)(bat1->currX - bat2->currX) >= 0 ? 1 : -1) * bat2->power; + double pow2y = sin(bat2->field_10 - rndF) * (double)((int)(bat1->currY - bat2->currY) >= 0 ? 1 : -1) * bat2->power; + + bat2->powerCos -= pow2x * 1.1; + bat2->powerSin -= pow2y * 1.1; + + double dy = bat1->currY - bat2->currY; + double dx = bat1->currX - bat2->currX; + double dist = (sqrt(rndSin * rndSin * 0.25 + rndCos * rndCos) * 54.0 - sqrt(dx * dx + dy * dy)) / cos(rndF - bat1->field_10); + bat1->currX -= cos(bat1->field_10) * (dist + 1.0); + bat1->currY -= sin(bat1->field_10) * (dist + 1.0); + bat1->powerCos += pow2x * 0.64; + + if (bat1->currX <= 500.0) + bat1->powerSin = 0.0; + else + bat1->powerSin += pow2y * 0.64; + + bat1->field_10 = atan2(bat1->powerCos, bat1->powerSin); + bat1->power = sqrt(bat1->powerCos * bat1->powerCos + bat1->powerSin * bat1->powerSin); + bat2->powerCos += pow1x * 0.64; + + if (bat2->currX <= 500.0) + bat2->powerSin = 0; + else + bat2->powerSin += pow1y * 0.64; + + bat2->field_10 = atan2(bat2->powerCos, bat2->powerSin); + bat2->power = sqrt(bat2->powerCos * bat2->powerCos + bat2->powerSin * bat2->powerSin); + + g_fp->playSound(SND_27_026, 0); + } +} + +void sceneHandler27_batSetColors(int batn) { + Bat *bat = g_vars->scene27_bats[batn]; + + if (g_vars->scene27_hitZone->isPixelHitAtPos((int)bat->currX, (int)bat->currY) ) { + if (bat->ani->_statics->_staticsId == ST_BTA_NORM) { + if (!bat->ani->_movement) + bat->ani->_statics = bat->ani->getStaticsById(ST_BTA_HILITE); + } + } else { + if (bat->ani->_statics->_staticsId == ST_BTA_HILITE) { + if (!bat->ani->_movement) + bat->ani->_statics = bat->ani->getStaticsById(ST_BTA_NORM); + } + } +} + +void sceneHandler27_driverPushButton() { + if (g_fp->getObjectState(sO_Driver) == g_fp->getObjectEnumState(sO_Driver, sO_WithSteering)) { + g_vars->scene27_driver->changeStatics2(ST_DRV_VENT); + chainQueue(QU_DRV_PUSHBUTTON, 1); + + g_vars->scene27_driverPushedButton = true; + } else { + g_vars->scene27_driver->changeStatics2(ST_DRV_SITNOVENT); + + + chainQueue(QU_DRV_PUSHBUTTON_NOVENT, 1); + + g_vars->scene27_driverPushedButton = true; + } +} + +void sceneHandler27_maidSwitchback() { +#ifndef DBG + if (g_fp->getObjectState(sO_Maid) == g_fp->getObjectEnumState(sO_Maid, sO_WithSwab)) { + g_vars->scene27_maid->changeStatics2(ST_MID_SWAB); + g_vars->scene27_maid->startMQIfIdle(QU_MID_SWITCHBACK, 1); + } +#endif +} + +void sceneHandler27_batLogic() { + if (g_vars->scene27_balls.numBalls) { + g_vars->scene27_bat = g_vars->scene27_balls.pHead->ani; + + g_vars->scene27_balls.pHead = g_vars->scene27_balls.pHead->p0; + + if (g_vars->scene27_balls.pHead) + g_vars->scene27_balls.pHead->p0->p1 = 0; + else + g_vars->scene27_balls.field_8 = 0; + + g_vars->scene27_balls.init(&g_vars->scene27_balls.pHead->p0); + + int mv; + + switch (g_vars->scene27_batHandler->_statics->_staticsId) { + case ST_BTH_5: + mv = MV_BTH_5_4; + break; + + case ST_BTH_4: + mv = MV_BTH_4_3; + break; + + case ST_BTH_3: + mv = MV_BTH_3_2; + break; + + case ST_BTH_2: + mv = MV_BTH_2_1; + break; + + case ST_BTH_1: + mv = MV_BTH_1_0; + break; + + default: + chainQueue(QU_SC27_RESTARTBETS, 1); + + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); + + return; + } + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + mq->setFlags(mq->getFlags() | 1); + + ExCommand *ex = new ExCommand(g_vars->scene27_batHandler->_id, 1, mv, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 2; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(0, 17, MSG_SC27_CLICKBET, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + mq->addExCommandToEnd(ex); + + mq->chain(0); + } else { + g_vars->scene27_bat = 0; + } +} + +void sceneHandler27_calcWinArcade() { + if (!g_vars->scene27_wipeIsNeeded && !g_vars->scene27_driverPushedButton) { + int numHilite = 0; + + for (uint i = 0; i < g_vars->scene27_bats.size(); i++) { + if (g_vars->scene27_bats[i]->ani->_statics->_staticsId == ST_BTA_HILITE) + numHilite++; + } + + if (numHilite >= 3) { + if (g_fp->getObjectState(sO_Driver) == g_fp->getObjectEnumState(sO_Driver, sO_WithSteering)) { + sceneHandler27_driverGiveVent(); + sceneHandler27_maidSwitchback(); + + return; + } + } + + if (!g_vars->scene27_balls.numBalls) { + sceneHandler27_driverPushButton(); + sceneHandler27_maidSwitchback(); + return; + } + + sceneHandler27_batLogic(); + } + + sceneHandler27_maidSwitchback(); +} + +void sceneHandler27_regenBats() { + g_vars->scene27_wipeIsNeeded = false; + + for (uint i = 0; i < g_vars->scene27_var07.size(); i++) { + g_vars->scene27_var07[i]->ani->hide(); + + Ball *runPtr = g_vars->scene27_balls.pTail; + Ball *lastP = g_vars->scene27_balls.field_8; + StaticANIObject *newbat = g_vars->scene27_var07[i]->ani; + + if (!g_vars->scene27_balls.pTail) { + g_vars->scene27_balls.cPlex = (byte *)calloc(g_vars->scene27_balls.cPlexLen, sizeof(Ball)); + + byte *p1 = g_vars->scene27_balls.cPlex + (g_vars->scene27_balls.cPlexLen - 1) * sizeof(Ball); + + if (g_vars->scene27_balls.cPlexLen - 1 < 0) { + runPtr = g_vars->scene27_balls.pTail; + } else { + runPtr = g_vars->scene27_balls.pTail; + + for (int j = 0; j < g_vars->scene27_balls.cPlexLen; j++) { + ((Ball *)p1)->p1 = runPtr; + runPtr = (Ball *)p1; + + p1 -= sizeof(Ball); + } + + g_vars->scene27_balls.pTail = runPtr; + } + } + + g_vars->scene27_balls.pTail = runPtr->p0; + runPtr->p1 = lastP; + runPtr->p0 = 0; + runPtr->ani = newbat; + + g_vars->scene27_balls.numBalls++; + + if (g_vars->scene27_balls.field_8) + g_vars->scene27_balls.field_8->p0 = runPtr; + else + g_vars->scene27_balls.pHead = runPtr; + + g_vars->scene27_balls.field_8 = runPtr; + } + + g_vars->scene27_var07.clear(); + + sceneHandler27_batLogic(); + + g_vars->scene27_driverPushedButton = false; +} + +void sceneHandler27_animateBats() { + int oldCount = g_vars->scene27_knockCount; + + g_vars->scene27_numLostBats = 0; + g_vars->scene27_knockCount = 0; + + for (uint i = 0; i < g_vars->scene27_bats.size(); i++) { + Bat *bat = g_vars->scene27_bats[i]; + + bat->currX = cos(bat->field_10) * bat->power + bat->currX; + bat->currY = sin(bat->field_10) * bat->power + bat->currY; + + bat->ani->setOXY((int)bat->currX, (int)bat->currY); + bat->ani->_priority = (int)(600.0 - bat->currY); + + double powerDelta; + + if (cos(bat->field_10) >= 0.0 || bat->currX >= 362.0) + powerDelta = bat->power * 0.035; + else + powerDelta = bat->power * 0.4; + + bat->power -= powerDelta; + bat->powerCos = cos(bat->field_10) * bat->power; + bat->powerSin = sin(bat->field_10) * bat->power; + + if (bat->power >= 0.5) + g_vars->scene27_knockCount++; + else + bat->power = 0; + + sceneHandler27_batSetColors(i); + + if (!sceneHandler27_batFallLogic(i) && !g_vars->scene27_wipeIsNeeded) { + for (uint j = 0; j < g_vars->scene27_bats.size(); j++) { + if (i != j && sceneHandler27_batCalcDistance(i, j)) + sceneHandler27_knockBats(i, j); + } + } + } + + for (uint i = 0; i < g_vars->scene27_var07.size(); i++) { + Bat *bat = g_vars->scene27_var07[i]; + + if (bat->currY >= 700.0) { + g_vars->scene27_numLostBats++; + } else { + bat->currX = bat->powerCos + bat->currX; + bat->currY = bat->powerSin + bat->currY; + bat->ani->setOXY((int)bat->currX, (int)bat->currY); + bat->powerSin = bat->powerSin + 1.0; + } + } + + if (oldCount != g_vars->scene27_knockCount && !g_vars->scene27_knockCount) + sceneHandler27_calcWinArcade(); + + if (g_vars->scene27_wipeIsNeeded) { + if (g_vars->scene27_numLostBats == 5) + sceneHandler27_regenBats(); + } +} + +int sceneHandler27(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_CMN_WINARCADE: + sceneHandler27_winArcade(); + break; + + case MSG_SC27_TAKEVENT: + sceneHandler27_takeVent(); + break; + + case MSG_SC27_SHOWNEXTBET: + sceneHandler27_showNextBat(); + break; + + case MSG_SC27_HANDLERTOFRONT: + g_vars->scene27_batHandler->_priority = 1005; + break; + + case MSG_SC27_STARTWIPE: + g_vars->scene27_wipeIsNeeded = true; + + g_fp->playSound(SND_27_027, 0); + + break; + + case MSG_SC27_CLICKBET: + sceneHandler27_clickBat(cmd); + break; + + case MSG_SC27_STARTBET: + if (g_vars->scene27_bat) + sceneHandler27_startBat(g_vars->scene27_bat); + + break; + + case 30: + if (g_vars->scene27_dudeIsAiming) + sceneHandler27_startAiming(); + + break; + + case 29: + if (g_fp->_aniMan == g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y) + && g_vars->scene27_maxPhaseReached) + sceneHandler27_initAiming(cmd); + + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene27_dudeIsAiming) + sceneHandler27_aimDude(); + + if (g_vars->scene27_wipeIsNeeded) { + sceneHandler27_wipeDo(); + + if (!g_fp->_aniMan->_movement && g_fp->_aniMan->_statics->_staticsId == ST_MAN_RIGHT) + g_fp->_aniMan->startAnim(MV_MAN27_FLOW, 0, -1); + } + + sceneHandler27_animateBats(); + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene28.cpp b/engines/fullpipe/scenes/scene28.cpp new file mode 100644 index 0000000000..75ba2567b2 --- /dev/null +++ b/engines/fullpipe/scenes/scene28.cpp @@ -0,0 +1,474 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" +#include "fullpipe/floaters.h" + +namespace Fullpipe { + +void scene28_initScene(Scene *sc) { + g_vars->scene28_fliesArePresent = true; + g_vars->scene28_beardedDirection = true; + g_vars->scene28_darkeningObject = 0; + g_vars->scene28_lighteningObject = 0; + g_vars->scene28_headDirection = false; + g_vars->scene28_headBeardedFlipper = false; + g_vars->scene28_lift6inside = false; + + g_fp->_floaters->init(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_28")); + + g_fp->initArcadeKeys("SC_28"); +} + +int scene28_updateCursor() { + g_fp->updateCursorCommon(); + if (g_fp->_objectIdAtCursor == ANI_LIFT || g_fp->_objectIdAtCursor == ANI_LIFT_28) + if (g_fp->_cursorId == PIC_CSR_DEFAULT) + g_fp->_cursorId = PIC_CSR_ITN; + + return g_fp->_cursorId; +} + +void sceneHandler28_lift1ShowAfter() { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_MAN_28, -1); + + g_fp->_aniMan->_statics = g_fp->_aniMan->getStaticsById(ST_MAN_SIT|0x4000); + g_fp->_aniMan->setOXY(ani->_ox + 7, ani->_oy); + g_fp->_aniMan->_priority = ani->_priority; + g_fp->_aniMan->show1(-1, -1, -1, 0); +} + +void sceneHandler28_makeFaces(ExCommand *cmd) { + g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK4, 0)->_flags &= 0xFFFB; + + g_vars->scene28_lighteningObject = 0; + + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(cmd->_parId); + if (mq) { + int frames[5]; + + frames[0] = MV_WMN28_IN_1; + frames[1] = MV_WMN28_IN_2; + frames[2] = MV_WMN28_IN_3; + frames[3] = MV_WMN28_IN_4; + frames[4] = MV_WMN28_IN_5; + + for (int i = 0; i < 5; i++) { + int pos; + + while (frames[pos = g_fp->_rnd->getRandomNumber(4)] == 0) + ; + + mq->getExCommandByIndex(i)->_messageNum = frames[pos]; + + frames[pos] = 0; + } + } +} + +void sceneHandler28_trySecondaryPers() { + MessageQueue *mq; + int x; + + if (g_vars->scene28_headBeardedFlipper) { + if (g_vars->scene28_beardedDirection) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_BRD28_GOR), 0, 1); + + mq->getExCommandByIndex(0)->_x = g_fp->_sceneRect.left - 20; + mq->getExCommandByIndex(0)->_keyCode = 1; + mq->replaceKeyCode(-1, 1); + mq->chain(0); + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_BRD28_GOR), 0, 1); + + mq->getExCommandByIndex(0)->_x = g_fp->_sceneRect.left - 40; + mq->getExCommandByIndex(0)->_y += 20; + mq->getExCommandByIndex(0)->_keyCode = 2; + mq->replaceKeyCode(-1, 2); + mq->chain(0); + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_BRD28_GOR), 0, 1); + + x = g_fp->_sceneRect.left - 60; + } else { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_BRD28_GOL), 0, 1); + + mq->getExCommandByIndex(0)->_x = g_fp->_sceneRect.right + 20; + mq->getExCommandByIndex(0)->_keyCode = 1; + mq->replaceKeyCode(-1, 1); + mq->chain(0); + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_BRD28_GOL), 0, 1); + + mq->getExCommandByIndex(0)->_x = g_fp->_sceneRect.right + 40; + mq->getExCommandByIndex(0)->_y += 20; + mq->getExCommandByIndex(0)->_keyCode = 2; + mq->replaceKeyCode(-1, 2); + mq->chain(0); + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_BRD28_GOL), 0, 1); + + x = g_fp->_sceneRect.right + 60; + } + + mq->getExCommandByIndex(0)->_x = x; + mq->getExCommandByIndex(0)->_y += 40; + mq->getExCommandByIndex(0)->_keyCode = 3; + mq->replaceKeyCode(-1, 3); + mq->chain( 0); + + g_vars->scene28_beardedDirection = !g_vars->scene28_beardedDirection; + } else { + if (g_vars->scene28_headDirection) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_GLV28_GOR), 0, 1); + + x = g_fp->_sceneRect.left - 40; + } else { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_GLV28_GOL), 0, 1); + + x = g_fp->_sceneRect.right + 40; + } + + mq->getExCommandByIndex(0)->_x = x; + mq->chain(0); + + g_vars->scene28_headDirection = !g_vars->scene28_headDirection; + } + + g_vars->scene28_headBeardedFlipper = !g_vars->scene28_headBeardedFlipper; +} + +void sceneHandler28_turnOn2() { + if (g_vars->scene28_fliesArePresent) { + g_fp->_floaters->genFlies(g_fp->_currentScene, 1013, 329, 60, 4); + + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val15 = 30; + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->countdown = g_fp->_rnd->getRandomNumber(12) + 12; + + g_fp->_floaters->genFlies(g_fp->_currentScene, 1074, 311, 60, 4); + + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val15 = 30; + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->countdown = g_fp->_rnd->getRandomNumber(12) + 12; + } + + g_vars->scene28_fliesArePresent = false; +} + +void sceneHandler28_startWork1() { + g_fp->_aniMan->hide(); + + StaticANIObject *man = g_fp->_currentScene->getStaticANIObject1ById(ANI_MAN_28, -1); + + man->_statics = man->getStaticsById(ST_MAN28_RIGHT); + man->setOXY(g_fp->_aniMan->_ox, g_fp->_aniMan->_oy); + man->_priority = g_fp->_aniMan->_priority; + man->show1(-1, -1, -1, 0); + + chainQueue(QU_SC28_LIFT1_WORK, 1); +} + +void sceneHandler28_lift0Start() { + chainQueue(QU_SC28_LIFT0_START, 1); +} + +void sceneHandler28_lift1Start() { + g_fp->_aniMan->_flags |= 1; + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + + chainQueue(QU_SC28_LIFT1_START, 1); +} + +void sceneHandler28_lift2Start() { + chainQueue(QU_SC28_LIFT2_START, 1); +} + +void sceneHandler28_lift3Start() { + chainQueue(QU_SC28_LIFT3_START, 1); +} + +void sceneHandler28_lift4Start() { + g_fp->_aniMan->_flags |= 1; + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + + chainQueue(QU_SC28_WMN_START, 1); +} + +void sceneHandler28_lift5Start() { + chainQueue(QU_SC28_LIFT5_START, 1); +} + +void sceneHandler28_lift6Start() { + g_fp->_aniMan->_flags |= 1; + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + + StaticANIObject *woman = g_fp->_currentScene->getStaticANIObject1ById(ANI_TIOTIA, -1); + + if (woman && (woman->_flags & 4)) + chainQueue(QU_SC28_LIFT6_START2, 1); + else + chainQueue(QU_SC28_LIFT6_START, 1); +} + +void sceneHandler28_clickLift(int keycode) { + int x = 0; + + switch (keycode) { + case 0: x = 600; break; + case 1: x = 824; break; + case 2: x = 1055; break; + case 3: x = 1286; break; + case 4: x = 1517; break; + case 5: x = 1748; break; + case 6: x = 1979; break; + } + + if (abs(x - g_fp->_aniMan->_ox) > 1 || abs(472 - g_fp->_aniMan->_oy) > 1 + || g_fp->_aniMan->_movement + || g_fp->_aniMan->_statics->_staticsId != ST_MAN_UP) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, x, 472, 1, ST_MAN_UP); + if (mq) { + ExCommand *ex = new ExCommand(0, 17, MSG_SC28_CLICKLIFT, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + + mq->addExCommandToEnd(ex); + + postExCommand(g_fp->_aniMan->_id, 2, x, 472, 0, -1); + } + } else { + switch (keycode) { + case 0: + sceneHandler28_lift0Start(); + break; + case 1: + sceneHandler28_lift1Start(); + break; + case 2: + sceneHandler28_lift2Start(); + break; + case 3: + sceneHandler28_lift3Start(); + break; + case 4: + sceneHandler28_lift4Start(); + break; + case 5: + sceneHandler28_lift5Start(); + break; + case 6: + sceneHandler28_lift6Start(); + break; + default: + return; + } + } +} + +int sceneHandler28(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC28_LIFT6MUSIC: + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_28"), "MUSIC_TIOTIA", 1); + break; + + case MSG_SC28_LIFT6INSIDE: + g_vars->scene28_lift6inside = true; + break; + + case MSG_SC28_LIFT1_SHOWAFTER: + sceneHandler28_lift1ShowAfter(); + break; + + case MSG_SC28_MAKEFACES: + sceneHandler28_makeFaces(cmd); + break; + + case MSG_SC28_TRYVTORPERS: + sceneHandler28_trySecondaryPers(); + break; + + case MSG_SC28_TURNOFF_0: + g_vars->scene28_lighteningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK0, 0); + g_vars->scene28_lighteningObject->_flags |= 4; + break; + + case MSG_SC28_TURNON_0: + g_vars->scene28_darkeningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK0, 0); + break; + + case MSG_SC28_TURNON_1: + g_vars->scene28_darkeningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK1, 0); + break; + + case MSG_SC28_TURNOFF_1: + g_vars->scene28_lighteningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK1, 0); + g_vars->scene28_lighteningObject->_flags |= 4; + break; + + case MSG_SC28_TURNON_2: + g_vars->scene28_darkeningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK2, 0); + sceneHandler28_turnOn2(); + break; + + case MSG_SC28_TURNOFF_2: + g_vars->scene28_lighteningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK2, 0); + g_vars->scene28_lighteningObject->_flags |= 4; + break; + + case MSG_SC28_TURNON_3: + g_vars->scene28_darkeningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK3, 0); + break; + + case MSG_SC28_TURNOFF_3: + g_vars->scene28_lighteningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK3, 0); + g_vars->scene28_lighteningObject->_flags |= 4; + break; + + case MSG_SC28_TURNON_4: + g_vars->scene28_darkeningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK4, 0); + break; + + case MSG_SC28_TURNOFF_4: + g_vars->scene28_lighteningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK4, 0); + g_vars->scene28_lighteningObject->_flags |= 4; + break; + + case MSG_SC28_TURNON_6: + g_vars->scene28_darkeningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK6, 0); + break; + + case MSG_SC28_TURNOFF_6: + g_vars->scene28_lighteningObject = g_fp->_currentScene->getPictureObjectById(PIC_SC28_DARK6, 0); + g_vars->scene28_lighteningObject->_flags |= 4; + break; + + case MSG_SC28_STARTWORK1: + sceneHandler28_startWork1(); + break; + + case MSG_SC28_CLICKLIFT: + sceneHandler28_clickLift(cmd->_keyCode); + break; + + case MSG_SC28_ENDLIFT1: + case MSG_SC28_ENDLIFT6: + case MSG_SC28_ENDCABIN: + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); + g_fp->_aniMan->_flags &= 0xFEFF; + break; + + case 29: + { + if (g_vars->scene28_lift6inside) { + chainObjQueue(g_fp->_aniMan, QU_SC28_LIFT6_END, 1); + + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_28"), "MUSIC", 1); + + g_vars->scene28_lift6inside = false; + } + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (ani) + if (ani->_id == ANI_LIFT || ani->_id == ANI_LIFT_28 ) { + sceneHandler28_clickLift(ani->_okeyCode); + + cmd->_messageKind = 0; + break; + } + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) + g_fp->processArcade(cmd); + } + } + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene28_darkeningObject) { + if (g_vars->scene28_darkeningObject->_picture->getAlpha() > 10) { + g_vars->scene28_darkeningObject->_picture->setAlpha(g_vars->scene28_darkeningObject->_picture->getAlpha() - 10); + } else { + g_vars->scene28_darkeningObject->_flags &= 0xFFFB; + + g_vars->scene28_darkeningObject = 0; + } + } + + if (g_vars->scene28_lighteningObject) { + if (g_vars->scene28_lighteningObject->_picture->getAlpha() < 0xF9u) { + g_vars->scene28_lighteningObject->_picture->setAlpha(g_vars->scene28_lighteningObject->_picture->getAlpha() + 6); + } else { + g_vars->scene28_lighteningObject->_picture->setAlpha(0xff); + + g_vars->scene28_lighteningObject = 0; + } + } + + g_fp->_floaters->update(); + + for (uint i = 0; i < g_fp->_floaters->_array2.size(); i++) + if (g_fp->_floaters->_array2[i]->val13 == 1) + g_fp->_floaters->_array2[i]->ani->_priority = 15; + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene29.cpp b/engines/fullpipe/scenes/scene29.cpp new file mode 100644 index 0000000000..a03671a4d0 --- /dev/null +++ b/engines/fullpipe/scenes/scene29.cpp @@ -0,0 +1,1125 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +struct WalkingBearder { + StaticANIObject *ani; + int wbflag; + int wbcounter; +}; + +void scene29_initScene(Scene *sc) { + g_vars->scene29_porter = sc->getStaticANIObject1ById(ANI_PORTER, -1); + g_vars->scene29_shooter1 = sc->getStaticANIObject1ById(ANI_SHOOTER1, -1); + g_vars->scene29_shooter2 = sc->getStaticANIObject1ById(ANI_SHOOTER2, -1); + g_vars->scene29_ass = sc->getStaticANIObject1ById(ANI_ASS, -1); + + g_vars->scene29_balls.numBalls = 0; + g_vars->scene29_balls.pTail = 0; + g_vars->scene29_balls.field_8 = 0; + g_vars->scene29_balls.pHead = 0; + + free(g_vars->scene29_balls.cPlex); + g_vars->scene29_balls.cPlex = 0; + + StaticANIObject *ani; + + g_vars->scene29_greenBalls.numBalls = 0; + g_vars->scene29_greenBalls.pTail = 0; + g_vars->scene29_greenBalls.field_8 = 0; + g_vars->scene29_greenBalls.pHead = 0; + + free(g_vars->scene29_greenBalls.cPlex); + g_vars->scene29_greenBalls.cPlex = 0; + + ani = sc->getStaticANIObject1ById(ANI_SHELL_GREEN, -1); + Ball *b = g_vars->scene29_balls.sub04(g_vars->scene29_balls.field_8, 0); + b->ani = ani; + + if (g_vars->scene29_balls.field_8) + g_vars->scene29_balls.field_8->p0 = b; + else + g_vars->scene29_balls.pHead = b; + + g_vars->scene29_balls.field_8 = b; + + for (int i = 0; i < 2; i++) { + StaticANIObject *newani = new StaticANIObject(ani); + + sc->addStaticANIObject(newani, 1); + + b = g_vars->scene29_balls.sub04(g_vars->scene29_balls.field_8, 0); + b->ani = ani; + + if (g_vars->scene29_balls.field_8) + g_vars->scene29_balls.field_8->p0 = b; + else + g_vars->scene29_balls.pHead = b; + + g_vars->scene29_balls.field_8 = b; + } + + g_vars->scene29_redBalls.numBalls = 0; + g_vars->scene29_redBalls.pTail = 0; + g_vars->scene29_redBalls.field_8 = 0; + g_vars->scene29_redBalls.pHead = 0; + + free(g_vars->scene29_redBalls.cPlex); + g_vars->scene29_redBalls.cPlex = 0; + + g_vars->scene29_flyingRedBalls.numBalls = 0; + g_vars->scene29_flyingRedBalls.pTail = 0; + g_vars->scene29_flyingRedBalls.field_8 = 0; + g_vars->scene29_flyingRedBalls.pHead = 0; + + free(g_vars->scene29_flyingRedBalls.cPlex); + g_vars->scene29_flyingRedBalls.cPlex = 0; + + ani = sc->getStaticANIObject1ById(ANI_SHELL_RED, -1); + + b = g_vars->scene29_redBalls.sub04(g_vars->scene29_redBalls.field_8, 0); + b->ani = ani; + + if (g_vars->scene29_redBalls.field_8) + g_vars->scene29_redBalls.field_8->p0 = b; + else + g_vars->scene29_redBalls.pHead = b; + + g_vars->scene29_redBalls.field_8 = b; + + for (int i = 0; i < 2; i++) { + StaticANIObject *newani = new StaticANIObject(ani); + + sc->addStaticANIObject(newani, 1); + + b = g_vars->scene29_redBalls.sub04(g_vars->scene29_redBalls.field_8, 0); + b->ani = ani; + + if (g_vars->scene29_redBalls.field_8) + g_vars->scene29_redBalls.field_8->p0 = b; + else + g_vars->scene29_redBalls.pHead = b; + + g_vars->scene29_redBalls.field_8 = b; + } + + g_vars->scene29_bearders.clear(); + + ani = new StaticANIObject(g_fp->accessScene(SC_COMMON)->getStaticANIObject1ById(ANI_BEARDED_CMN, -1)); + + ani->_statics = ani->getStaticsById(ST_BRDCMN_EMPTY); + + sc->addStaticANIObject(ani, 1); + + WalkingBearder *wb = new WalkingBearder; + + wb->ani = ani; + wb->wbflag = 0; + wb->wbcounter = 0; + + g_vars->scene29_bearders.push_back(wb); + + g_vars->scene29_manIsRiding = false; + g_vars->scene29_arcadeIsOn = false; + g_vars->scene29_reachedFarRight = false; + g_vars->scene29_rideBackEnabled = false; + g_vars->scene29_shootCountdown = 0; + g_vars->scene29_shootDistance = 75; + g_vars->scene29_manIsHit = false; + g_vars->scene29_scrollSpeed = 0; + g_vars->scene29_scrollingDisabled = false; + g_vars->scene29_hitBall = 0; + + g_fp->setArcadeOverlay(PIC_CSR_ARCADE8); +} + +void sceneHandler29_winArcade() { + if (g_vars->scene29_shooter2->_flags & 4) { + g_vars->scene29_shootCountdown = 0; + + g_vars->scene29_shooter1->changeStatics2(ST_STR1_STAND); + g_vars->scene29_shooter2->changeStatics2(ST_STR2_STAND); + + g_vars->scene29_shooter2->_flags &= 0xFFFB; + + StaticANIObject *ani; + Ball *newball, *ball, *oldp0; + + while (g_vars->scene29_greenBalls.numBalls) { + ball = g_vars->scene29_greenBalls.pHead; + ani = g_vars->scene29_greenBalls.pHead->ani; + oldp0 = g_vars->scene29_greenBalls.pHead->p0; + g_vars->scene29_greenBalls.pHead = g_vars->scene29_greenBalls.pHead->p0; + + if (g_vars->scene29_greenBalls.pHead) + oldp0->p1 = 0; + else + g_vars->scene29_greenBalls.field_8 = 0; + + ball->p0 = g_vars->scene29_greenBalls.pTail; + g_vars->scene29_greenBalls.pTail = ball; + g_vars->scene29_greenBalls.numBalls--; + + if (!g_vars->scene29_greenBalls.numBalls) + g_vars->scene29_greenBalls.reset(); + + ani->hide(); + + newball = g_vars->scene29_balls.sub04(g_vars->scene29_balls.field_8, 0); + newball->ani = ani; + + if (g_vars->scene29_balls.field_8) + g_vars->scene29_balls.field_8->p0 = newball; + else + g_vars->scene29_balls.pHead = newball; + + g_vars->scene29_balls.field_8 = newball; + } + + while (g_vars->scene29_flyingRedBalls.numBalls) { + ball = g_vars->scene29_flyingRedBalls.pHead; + ani = g_vars->scene29_flyingRedBalls.pHead->ani; + oldp0 = g_vars->scene29_flyingRedBalls.pHead->p0; + g_vars->scene29_flyingRedBalls.pHead = g_vars->scene29_flyingRedBalls.pHead->p0; + + if (g_vars->scene29_flyingRedBalls.pHead) + oldp0->p1 = 0; + else + g_vars->scene29_flyingRedBalls.field_8 = 0; + + ball->p0 = g_vars->scene29_flyingRedBalls.pTail; + g_vars->scene29_flyingRedBalls.pTail = ball; + g_vars->scene29_flyingRedBalls.numBalls--; + + if (!g_vars->scene29_flyingRedBalls.numBalls) { + g_vars->scene29_flyingRedBalls.numBalls = 0; + g_vars->scene29_flyingRedBalls.pTail = 0; + g_vars->scene29_flyingRedBalls.field_8 = 0; + g_vars->scene29_flyingRedBalls.pHead = 0; + + free(g_vars->scene29_flyingRedBalls.cPlex); + + g_vars->scene29_flyingRedBalls.cPlex = 0; + } + + ani->hide(); + + newball = g_vars->scene29_redBalls.sub04(g_vars->scene29_redBalls.field_8, 0); + newball->ani = ani; + + if (g_vars->scene29_redBalls.field_8) + g_vars->scene29_redBalls.field_8->p0 = newball; + else + g_vars->scene29_redBalls.pHead = newball; + + g_vars->scene29_redBalls.field_8 = newball; + } + + g_vars->scene29_ass->queueMessageQueue(0); + g_vars->scene29_ass->_flags &= 0xFFFB; + + chainQueue(QU_SC29_ESCAPE, 1); + } + + g_fp->setObjectState(sO_LeftPipe_29, g_fp->getObjectEnumState(sO_LeftPipe_29, sO_IsOpened)); +} + +void sceneHandler29_shootGreen() { + if (g_vars->scene29_balls.numBalls) { + int x = g_vars->scene29_shooter1->_ox - 113; + int y = g_vars->scene29_shooter1->_oy - 48; + StaticANIObject *ani = g_vars->scene29_balls.pHead->ani; + Ball *oldhead = g_vars->scene29_balls.pHead; + Ball *oldp0 = g_vars->scene29_balls.pHead->p0; + + g_vars->scene29_balls.pHead = g_vars->scene29_balls.pHead->p0; + + if (g_vars->scene29_balls.pHead) + oldp0->p1 = 0; + else + g_vars->scene29_balls.field_8 = 0; + + oldhead->p0 = g_vars->scene29_balls.pTail; + + g_vars->scene29_balls.pTail = oldhead; + g_vars->scene29_balls.numBalls--; + + if (!g_vars->scene29_balls.numBalls) { + g_vars->scene29_balls.numBalls = 0; + g_vars->scene29_balls.pTail = 0; + g_vars->scene29_balls.field_8 = 0; + g_vars->scene29_balls.pHead = 0; + + free(g_vars->scene29_balls.cPlex); + g_vars->scene29_balls.cPlex = 0; + } + + ani->show1(x, y, MV_SHG_NORM, 0); + ani->_priority = 5; + + Ball *runPtr = g_vars->scene29_greenBalls.pTail; + Ball *lastP = g_vars->scene29_greenBalls.field_8; + + if (!g_vars->scene29_greenBalls.pTail) { + g_vars->scene29_greenBalls.cPlex = (byte *)calloc(g_vars->scene29_greenBalls.cPlexLen, sizeof(Ball)); + + byte *p1 = g_vars->scene29_greenBalls.cPlex + (g_vars->scene29_greenBalls.cPlexLen - 1) * sizeof(Ball); + + if (g_vars->scene29_greenBalls.cPlexLen - 1 < 0) { + runPtr = g_vars->scene29_greenBalls.pTail; + } else { + runPtr = g_vars->scene29_greenBalls.pTail; + + for (int j = 0; j < g_vars->scene29_greenBalls.cPlexLen; j++) { + ((Ball *)p1)->p1 = runPtr; + runPtr = (Ball *)p1; + + p1 -= sizeof(Ball); + } + + g_vars->scene29_greenBalls.pTail = runPtr; + } + } + g_vars->scene29_greenBalls.pTail = runPtr->p0; + runPtr->p1 = lastP; + runPtr->p0 = 0; + runPtr->ani = ani; + + g_vars->scene29_greenBalls.numBalls++; + + if (g_vars->scene29_greenBalls.field_8) { + g_vars->scene29_greenBalls.field_8->p0 = runPtr; + g_vars->scene29_greenBalls.field_8 = runPtr; + } else { + g_vars->scene29_greenBalls.pHead = runPtr; + g_vars->scene29_greenBalls.field_8 = runPtr; + } + } +} + +void sceneHandler29_shootRed() { + if (g_vars->scene29_balls.numBalls) { + int x = g_vars->scene29_shooter1->_ox - 101; + int y = g_vars->scene29_shooter1->_oy - 14; + StaticANIObject *ani = g_vars->scene29_balls.pHead->ani; + Ball *oldhead = g_vars->scene29_balls.pHead; + Ball *oldp0 = g_vars->scene29_balls.pHead->p0; + + g_vars->scene29_balls.pHead = g_vars->scene29_balls.pHead->p0; + + if (g_vars->scene29_balls.pHead) + oldp0->p1 = 0; + else + g_vars->scene29_balls.field_8 = 0; + + oldhead->p0 = g_vars->scene29_balls.pTail; + + g_vars->scene29_balls.pTail = oldhead; + g_vars->scene29_balls.numBalls--; + + if (!g_vars->scene29_balls.numBalls) { + g_vars->scene29_balls.numBalls = 0; + g_vars->scene29_balls.pTail = 0; + g_vars->scene29_balls.field_8 = 0; + g_vars->scene29_balls.pHead = 0; + + free(g_vars->scene29_balls.cPlex); + g_vars->scene29_balls.cPlex = 0; + } + + ani->show1(x, y, MV_SHR_NORM, 0); + ani->_priority = 5; + + Ball *runPtr = g_vars->scene29_flyingRedBalls.pTail; + Ball *lastP = g_vars->scene29_flyingRedBalls.field_8; + + if (!g_vars->scene29_flyingRedBalls.pTail) { + g_vars->scene29_flyingRedBalls.cPlex = (byte *)calloc(g_vars->scene29_flyingRedBalls.cPlexLen, sizeof(Ball)); + + byte *p1 = g_vars->scene29_flyingRedBalls.cPlex + (g_vars->scene29_flyingRedBalls.cPlexLen - 1) * sizeof(Ball); + + if (g_vars->scene29_flyingRedBalls.cPlexLen - 1 < 0) { + runPtr = g_vars->scene29_flyingRedBalls.pTail; + } else { + runPtr = g_vars->scene29_flyingRedBalls.pTail; + + for (int j = 0; j < g_vars->scene29_flyingRedBalls.cPlexLen; j++) { + ((Ball *)p1)->p1 = runPtr; + runPtr = (Ball *)p1; + + p1 -= sizeof(Ball); + } + + g_vars->scene29_flyingRedBalls.pTail = runPtr; + } + } + g_vars->scene29_flyingRedBalls.pTail = runPtr->p0; + runPtr->p1 = lastP; + runPtr->p0 = 0; + runPtr->ani = ani; + + g_vars->scene29_flyingRedBalls.numBalls++; + + if (g_vars->scene29_flyingRedBalls.field_8) { + g_vars->scene29_flyingRedBalls.field_8->p0 = runPtr; + g_vars->scene29_flyingRedBalls.field_8 = runPtr; + } else { + g_vars->scene29_flyingRedBalls.pHead = runPtr; + g_vars->scene29_flyingRedBalls.field_8 = runPtr; + } + } +} + +void sceneHandler29_manJump() { + if (!g_fp->_aniMan->_movement || g_fp->_aniMan->_movement->_id == MV_MAN29_RUN || g_fp->_aniMan->_movement->_id == MV_MAN29_STANDUP) { + g_vars->scene29_rideBackEnabled = false; + g_vars->scene29_manIsHit = false; + g_vars->scene29_reachedFarRight = true; + + g_fp->_aniMan->changeStatics2(ST_MAN29_RUNR); + g_fp->_aniMan->startAnim(MV_MAN29_JUMP, 0, -1); + } + + g_vars->scene29_manX = g_fp->_aniMan->_ox; + g_vars->scene29_manY = g_fp->_aniMan->_oy; +} + +void sceneHandler29_manBend() { + if (!g_fp->_aniMan->_movement || g_fp->_aniMan->_movement->_id == MV_MAN29_RUN || g_fp->_aniMan->_movement->_id == MV_MAN29_STANDUP) { + g_vars->scene29_rideBackEnabled = false; + g_vars->scene29_manIsHit = false; + g_vars->scene29_reachedFarRight = true; + + g_fp->_aniMan->changeStatics2(ST_MAN29_RUNR); + g_fp->_aniMan->startAnim(MV_MAN29_BEND, 0, -1); + } + + g_vars->scene29_manX = g_fp->_aniMan->_ox; + g_vars->scene29_manY = g_fp->_aniMan->_oy; +} + +bool sceneHandler29_checkRedBallHit(StaticANIObject *ani, int maxx) { + if (!g_vars->scene29_arcadeIsOn || g_vars->scene29_manIsHit) + return false; + + if ((ani->_ox >= g_vars->scene29_manX + 42 || ani->_ox <= g_vars->scene29_manX + 8) + && (ani->_ox < g_vars->scene29_manX + 8 || maxx > g_vars->scene29_manX + 27)) + return false; + + if (!g_fp->_aniMan->_movement) + return true; + + int phase = g_fp->_aniMan->_movement->_currDynamicPhaseIndex; + + if (g_fp->_aniMan->_movement->_id != MV_MAN29_BEND && g_fp->_aniMan->_movement->_id != MV_MAN29_RUN + && (g_fp->_aniMan->_movement->_id != MV_MAN29_JUMP || (phase >= 3 && phase <= 6))) + return false; + else + return true; +} + +bool sceneHandler29_checkGreenBallHit(StaticANIObject *ani, int maxx) { + if (!g_vars->scene29_arcadeIsOn || g_vars->scene29_manIsHit) + return false; + + if (ani->_ox >= g_vars->scene29_manX + 40) { + if (maxx > g_vars->scene29_manX + 27) + return false; + } else { + if (ani->_ox <= g_vars->scene29_manX + 10) { + if (ani->_ox < g_vars->scene29_manX + 40) + return false; + + if (maxx > g_vars->scene29_manX + 27) + return false; + } + } + + if (!g_fp->_aniMan->_movement) + return true; + + if (g_fp->_aniMan->_movement->_id == MV_MAN29_JUMP) + return true; + + if (g_fp->_aniMan->_movement->_id == MV_MAN29_RUN) + return true; + + if (g_fp->_aniMan->_movement->_id == MV_MAN29_BEND) { + if (g_fp->_aniMan->_movement->_currDynamicPhaseIndex < 1 || g_fp->_aniMan->_movement->_currDynamicPhaseIndex > 5) + return true; + } + + return false; +} + +void sceneHandler29_manHit() { + MGMInfo mgminfo; + + g_vars->scene29_manIsHit = true; + + g_fp->_aniMan->changeStatics2(ST_MAN29_RUNR); + g_fp->_aniMan->setOXY(g_vars->scene29_manX, g_vars->scene29_manY); + + mgminfo.ani = g_fp->_aniMan; + mgminfo.staticsId2 = ST_MAN29_SITR; + mgminfo.y1 = 463; + mgminfo.x1 = g_vars->scene29_manX <= 638 ? 351 : 0; + mgminfo.field_1C = 10; + mgminfo.field_10 = 1; + mgminfo.flags = (g_vars->scene29_manX <= 638 ? 2 : 0) | 0x44; + mgminfo.movementId = MV_MAN29_HIT; + + MessageQueue *mq = g_vars->scene29_mgm.genMovement(&mgminfo); + ExCommand *ex; + + if (mq) { + if (g_vars->scene29_manX <= 638) { + ex = new ExCommand(ANI_MAN, 1, MV_MAN29_STANDUP_NORM, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags = 2; + ex->_keyCode = g_fp->_aniMan->_okeyCode; + mq->addExCommandToEnd(ex); + + ex = new ExCommand(0, 17, MSG_SC29_STOPRIDE, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags = 2; + mq->addExCommandToEnd(ex); + + g_vars->scene29_manIsRiding = false; + g_vars->scene29_arcadeIsOn = false; + g_vars->scene29_reachedFarRight = false; + g_vars->scene29_rideBackEnabled = false; + } else { + ex = new ExCommand(ANI_MAN, 1, MV_MAN29_STANDUP, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags = 2; + ex->_keyCode = g_fp->_aniMan->_okeyCode; + mq->addExCommandToEnd(ex); + } + + mq->setFlags(mq->getFlags() | 1); + + if (!mq->chain(g_fp->_aniMan)) + delete mq; + } +} + +void sceneHandler29_assHitRed() { + if (g_vars->scene29_ass->_statics->_staticsId == ST_ASS_NORM) { + g_vars->scene29_ass->changeStatics2(ST_ASS_NORM); + g_vars->scene29_ass->startAnim(MV_ASS_HITRED, 0, -1); + } +} + +void sceneHandler29_assHitGreen() { + if (g_vars->scene29_ass->_statics->_staticsId == ST_ASS_NORM) { + g_vars->scene29_ass->changeStatics2(ST_ASS_NORM); + g_vars->scene29_ass->startAnim(MV_ASS_HITGREEN, 0, -1); + } +} + +void sceneHandler29_ballHitCheck() { + Ball *ball = g_vars->scene29_greenBalls.pHead; + Ball *newball; + int x, y; + + while (ball) { + x = ball->ani->_ox - 30; + y = ball->ani->_oy; + + if (x >= 186) { + if (sceneHandler29_checkGreenBallHit(ball->ani, x)) { + newball = g_vars->scene29_balls.sub04(g_vars->scene29_balls.field_8, 0); + newball->ani = ball->ani; + + if (g_vars->scene29_balls.field_8) + g_vars->scene29_balls.field_8->p0 = newball; + else + g_vars->scene29_balls.pHead = newball; + + g_vars->scene29_balls.field_8 = newball; + + if (ball == g_vars->scene29_greenBalls.pHead) + g_vars->scene29_greenBalls.pHead = ball->p0; + else + ball->p1->p0 = ball->p0; + + if (ball == g_vars->scene29_greenBalls.field_8) + g_vars->scene29_greenBalls.field_8 = ball->p1; + else + ball->p0->p1 = ball->p1; + + g_vars->scene29_greenBalls.init(&ball); + + sceneHandler29_manHit(); + + g_fp->playSound(SND_29_014, 0); + + ball->ani->startAnim(MV_SHG_HITMAN, 0, -1); + + g_vars->scene29_hitBall = ball->ani->_id; + } else { + ball->ani->setOXY(x, y); + } + } else { + newball = g_vars->scene29_balls.sub04(g_vars->scene29_balls.field_8, 0); + newball->ani = ball->ani; + + if (g_vars->scene29_balls.field_8) + g_vars->scene29_balls.field_8->p0 = newball; + else + g_vars->scene29_balls.pHead = newball; + + g_vars->scene29_balls.field_8 = newball; + + ball->ani->hide(); + + if (ball == g_vars->scene29_greenBalls.pHead) + g_vars->scene29_greenBalls.pHead = ball->p0; + else + ball->p1->p0 = ball->p0; + + if (ball == g_vars->scene29_greenBalls.field_8) + g_vars->scene29_greenBalls.field_8 = ball->p1; + else + ball->p0->p1 = ball->p1; + + g_vars->scene29_greenBalls.init(&ball); + + sceneHandler29_assHitGreen(); + } + + ball = ball->p0; + } + + ball = g_vars->scene29_flyingRedBalls.pHead; + + while (ball) { + x = ball->ani->_ox - 30; + y = ball->ani->_oy; + + if (x >= 147) { + if (sceneHandler29_checkRedBallHit(ball->ani, x)) { + newball = g_vars->scene29_redBalls.sub04(g_vars->scene29_redBalls.field_8, 0); + newball->ani = ball->ani; + + if (g_vars->scene29_redBalls.field_8) + g_vars->scene29_redBalls.field_8->p0 = newball; + else + g_vars->scene29_redBalls.pHead = newball; + + g_vars->scene29_redBalls.field_8 = newball; + + g_vars->scene29_flyingRedBalls.removeBall(ball); + + sceneHandler29_manHit(); + + g_fp->playSound(SND_29_027, 0); + + ball->ani->startAnim(MV_SHR_HITMAN, 0, -1); + + g_vars->scene29_hitBall = ball->ani->_id; + } else { + ball->ani->setOXY(x, y); + } + } else { + newball = g_vars->scene29_redBalls.sub04(g_vars->scene29_redBalls.field_8, 0); + newball->ani = ball->ani; + + if (g_vars->scene29_redBalls.field_8) + g_vars->scene29_redBalls.field_8->p0 = newball; + else + g_vars->scene29_redBalls.pHead = newball; + + g_vars->scene29_redBalls.field_8 = newball; + + ball->ani->hide(); + + if (ball == g_vars->scene29_flyingRedBalls.pHead) + g_vars->scene29_flyingRedBalls.pHead = ball->p0; + else + ball->p1->p0 = ball->p0; + + if (ball == g_vars->scene29_flyingRedBalls.field_8) + g_vars->scene29_flyingRedBalls.field_8 = ball->p1; + else + ball->p0->p1 = ball->p1; + + g_vars->scene29_flyingRedBalls.init(&ball); + + sceneHandler29_assHitRed(); + } + + ball = ball->p0; + } +} + +void sceneHandler29_manFromL() { + if (g_vars->scene29_manX < 497 && !g_vars->scene29_scrollingDisabled) { + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT | 0x4000); + chainQueue(QU_SC29_MANFROM_L, 1); + + g_vars->scene29_scrollingDisabled = true; + + g_fp->_scrollSpeed = g_vars->scene29_scrollSpeed; + } +} + +void sceneHandler29_manFromR() { + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + chainQueue(QU_SC29_MANFROM_R, 1); + + g_vars->scene29_arcadeIsOn = false; + g_vars->scene29_rideBackEnabled = false; +} + +int sceneHandler29_updateScreenCallback() { + int res; + + res = g_fp->drawArcadeOverlay(g_vars->scene29_arcadeIsOn); + + if (!res) + g_fp->_updateScreenCallback = 0; + + return res; +} + +void sceneHandler29_manToL() { + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + chainQueue(QU_SC29_MANTO_L, 1); + + g_vars->scene29_arcadeIsOn = true; + + g_vars->scene29_mgm.addItem(g_fp->_aniMan->_id); + + g_fp->_updateScreenCallback = sceneHandler29_updateScreenCallback; + + g_fp->_msgY = -1; + g_fp->_msgX = -1; +} + +void sceneHandler29_manToR() { + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + chainQueue(QU_SC29_MANTO_R, 1); + + g_vars->scene29_manIsRiding = true; + g_fp->_msgY = -1; + g_fp->_msgX = -1; + + g_vars->scene29_scrollingDisabled = false; + + g_vars->scene29_scrollSpeed = g_fp->_scrollSpeed; + g_fp->_scrollSpeed = 4; +} + +void sceneHandler29_clickPorter(ExCommand *cmd) { + if (!g_fp->_aniMan->isIdle() || g_fp->_aniMan->_flags & 0x100) { + cmd->_messageKind = 0; + + return; + } + + if (g_vars->scene29_manX <= g_vars->scene29_porter->_ox) { + if (ABS(351 - g_vars->scene29_manX) > 1 || ABS(443 - g_vars->scene29_manY) > 1 + || g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) { + if (g_fp->_msgX != 351 || g_fp->_msgY != 443) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 351, 443, 1, ST_MAN_RIGHT); + + if (mq) { + mq->addExCommandToEnd(cmd->createClone()); + + postExCommand(g_fp->_aniMan->_id, 2, 351, 443, 0, -1); + } + } + } else { + sceneHandler29_manToL(); + } + } else { + g_vars->scene29_manX = g_fp->_aniMan->_ox; + g_vars->scene29_manY = g_fp->_aniMan->_oy; + + if (ABS(1582 - g_vars->scene29_manX) > 1 || ABS(445 - g_fp->_aniMan->_oy) > 1 + || g_fp->_aniMan->_movement || g_fp->_aniMan->_statics->_staticsId != (0x4000 | ST_MAN_RIGHT)) { + if (g_fp->_msgX != 1582 || g_fp->_msgY != 445) { + MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, 1582, 445, 1, (0x4000 | ST_MAN_RIGHT)); + + if (mq) { + mq->addExCommandToEnd(cmd->createClone()); + + postExCommand(g_fp->_aniMan->_id, 2, 1582, 445, 0, -1); + } + } + } else { + sceneHandler29_manToR(); + } + } +} + +void sceneHandler29_shootersProcess() { + if (g_fp->_aniMan->_statics->_staticsId == ST_MAN29_RUNR) { + if (g_vars->scene29_manX > 1436) { + sceneHandler29_manFromR(); + } else { + g_vars->scene29_shootDistance = (1310 - g_vars->scene29_manX) * 5213 / 100000 + 25; + + if (!g_vars->scene29_manIsHit) + g_fp->_aniMan->startAnim(MV_MAN29_RUN, 0, -1); + } + } + + g_vars->scene29_manX = g_fp->_aniMan->_ox; + g_vars->scene29_manY = g_fp->_aniMan->_oy; +} + +void sceneHandler29_shootersEscape() { + if (g_vars->scene29_arcadeIsOn) { + g_vars->scene29_manX += 2; + + g_fp->_aniMan->setOXY(g_vars->scene29_manX, g_vars->scene29_manY); + + if (g_vars->scene29_manX > 1310 && !g_vars->scene29_shooter1->_movement && !g_vars->scene29_shooter2->_movement + && g_vars->scene29_shooter1->_statics->_staticsId == ST_STR1_RIGHT) { + g_vars->scene29_shootCountdown = 0; + + g_vars->scene29_shooter1->changeStatics2(ST_STR1_STAND); + g_vars->scene29_shooter2->changeStatics2(ST_STR2_STAND); + + chainQueue(QU_SC29_ESCAPE, 1); + + g_vars->scene29_ass->queueMessageQueue(0); + g_vars->scene29_ass->hide(); + + g_fp->setObjectState(sO_LeftPipe_29, g_fp->getObjectEnumState(sO_LeftPipe_29, sO_IsOpened)); + } + } else if (g_vars->scene29_manIsRiding) { + g_vars->scene29_manX -= 4; + + g_fp->_aniMan->setOXY(g_vars->scene29_manX, g_vars->scene29_manY); + } +} + +void sceneHandler29_manRideBack() { + g_vars->scene29_manX -= 2; + + g_fp->_aniMan->setOXY(g_vars->scene29_manX, g_vars->scene29_manY); +} + +void sceneHandler29_shoot() { + if (g_vars->scene29_arcadeIsOn && g_vars->scene29_manX < 1310) { + if (g_fp->_rnd->getRandomNumber(1) || g_vars->scene29_shooter1->_movement || g_vars->scene29_shooter1->_statics->_staticsId != ST_STR1_RIGHT) { + if (!g_vars->scene29_shooter2->_movement && g_vars->scene29_shooter2->_statics->_staticsId == ST_STR2_RIGHT) { + if (g_vars->scene29_shooter2->_flags & 4) { + g_vars->scene29_shooter2->startAnim(MV_STR2_SHOOT, 0, -1); + + g_vars->scene29_shootCountdown = 0; + } + } + } else { + g_vars->scene29_shooter1->startAnim(MV_STR1_SHOOT, 0, -1); + + g_vars->scene29_shootCountdown = 0; + } + } +} + +void sceneHandler29_animBearded() { + MessageQueue *mq; + + for (uint i = 0; i < g_vars->scene29_bearders.size(); i++) { + StaticANIObject *ani = g_vars->scene29_bearders[i]->ani; + + if (g_vars->scene29_bearders[i]->wbflag) { + int x = ani->_ox; + int y = ani->_oy; + + if (!ani->_movement && ani->_statics->_staticsId == (ST_BRDCMN_RIGHT | 0x4000)) { + x -= 4; + + if (x - g_vars->scene29_manX < 100 || !g_vars->scene29_arcadeIsOn) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC29_BRDOUT1), 0, 1); + + mq->replaceKeyCode(-1, ani->_okeyCode); + mq->chain(0); + + g_vars->scene29_bearders[i]->wbflag = 0; + g_vars->scene29_bearders[i]->wbcounter = 0; + } + } + + if (!ani->_movement && ani->_statics->_staticsId == ST_BRDCMN_GOR) + ani->startAnim(MV_BRDCMN_GOR, 0, -1); + + if (ani->_movement) { + if (ani->_movement->_id == MV_BRDCMN_GOR) { + x -= 4; + + if (g_vars->scene29_manX - x < 60 || x - g_vars->scene29_manX < -260 || !g_vars->scene29_arcadeIsOn) { + ani->changeStatics2(ST_BRDCMN_RIGHT); + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC29_BRDOUT2), 0, 1); + + mq->replaceKeyCode(-1, ani->_okeyCode); + mq->chain(0); + + g_vars->scene29_bearders[i]->wbflag = 0; + g_vars->scene29_bearders[i]->wbcounter = 0; + } + } + } + + ani->setOXY(x, y); + continue; + } + + if (g_vars->scene29_arcadeIsOn && g_vars->scene29_bearders[i]->wbcounter > 30) { + int newx; + + if (g_fp->_rnd->getRandomNumber(1)) + goto dostuff; + + if (g_vars->scene29_manX <= 700) { + g_vars->scene29_bearders[i]->wbcounter++; + continue; + } + + if (g_vars->scene29_manX >= 1100) { + dostuff: + if (g_vars->scene29_manX <= 700 || g_vars->scene29_manX >= 1350) { + g_vars->scene29_bearders[i]->wbcounter++; + continue; + } + + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC29_BRD2), 0, 1); + + newx = g_vars->scene29_manX - 200; + } else { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC29_BRD1), 0, 1); + + newx = g_vars->scene29_manX + 350; + } + + mq->getExCommandByIndex(0)->_x = newx; + mq->replaceKeyCode(-1, ani->_okeyCode); + mq->chain(0); + + g_vars->scene29_bearders[i]->wbflag = 1; + g_vars->scene29_bearders[i]->wbcounter = 0; + } + + g_vars->scene29_bearders[i]->wbcounter++; + } +} + + + +int sceneHandler29(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_CMN_WINARCADE: + sceneHandler29_winArcade(); + break; + + case MSG_SC29_LAUGH: + if (g_vars->scene29_hitBall == ANI_SHELL_GREEN) { + g_fp->playSound(SND_29_028, 0); + break; + } + + g_fp->playSound(SND_29_029, 0); + + break; + + case MSG_SC29_SHOWLASTRED: + if (g_vars->scene29_redBalls.numBalls) { // original uses scene29_balls which looks like a copy/paste error + g_vars->scene29_redBalls.field_8->ani->show1(-1, -1, -1, 0); + g_vars->scene29_redBalls.field_8->ani->startAnim(MV_SHR_HITASS, 0, -1); + } + + break; + + case MSG_SC29_SHOOTGREEN: + sceneHandler29_shootGreen(); + break; + + case MSG_SC29_SHOOTRED: + sceneHandler29_shootRed(); + break; + + case MSG_SC29_SHOWLASTGREEN: + if (g_vars->scene29_balls.numBalls) { + g_vars->scene29_balls.field_8->ani->show1(-1, -1, -1, 0); + g_vars->scene29_balls.field_8->ani->startAnim(MV_SHG_HITASS, 0, -1); + } + + break; + + case MSG_SC29_STOPRIDE: + g_vars->scene29_manIsRiding = false; + g_vars->scene29_arcadeIsOn = false; + g_vars->scene29_reachedFarRight = false; + g_vars->scene29_rideBackEnabled = false; + + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + break; + + case MSG_SC29_DISABLERIDEBACK: + g_vars->scene29_rideBackEnabled = false; + break; + + case MSG_SC29_ENABLERIDEBACK: + g_vars->scene29_rideBackEnabled = true; + g_vars->scene29_reachedFarRight = false; + break; + + case MSG_SC29_DISABLEPORTER: + g_vars->scene29_reachedFarRight = false; + break; + + case MSG_SC29_ENABLEPORTER: + g_vars->scene29_reachedFarRight = true; + g_vars->scene29_rideBackEnabled = false; + g_vars->scene29_manIsHit = false; + break; + + case 29: + if (!g_vars->scene29_manIsRiding || g_vars->scene29_arcadeIsOn) { + if (!g_vars->scene29_arcadeIsOn) { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (ani && ani == g_vars->scene29_porter) { + sceneHandler29_clickPorter(cmd); + + cmd->_messageKind = 0; + break; + } + break; + } + + sceneHandler29_manJump(); + + cmd->_messageKind = 0; + break; + } + break; + + case 107: + if (g_vars->scene29_arcadeIsOn) + sceneHandler29_manBend(); + + break; + + case 33: + if (g_vars->scene29_arcadeIsOn) { + if (g_vars->scene29_manX > g_fp->_sceneRect.right - 500) + g_fp->_currentScene->_x = g_fp->_sceneRect.right - g_vars->scene29_manX - 350; + + if (g_vars->scene29_manX < g_fp->_sceneRect.left + 100) + g_fp->_currentScene->_x = g_vars->scene29_manX - g_fp->_sceneRect.left - 100; + + } else if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 300) + g_fp->_currentScene->_x = x - 400 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 300) + g_fp->_currentScene->_x = x + 400 - g_fp->_sceneRect.right; + } + + g_vars->scene29_manX = g_fp->_aniMan->_ox; + g_vars->scene29_manY = g_fp->_aniMan->_oy; + + sceneHandler29_ballHitCheck(); + + if (!g_vars->scene29_porter->_movement) + g_vars->scene29_porter->startAnim(MV_PTR_MOVEFAST, 0, -1); + + if (g_vars->scene29_manIsRiding) + sceneHandler29_manFromL(); + else if (g_vars->scene29_arcadeIsOn && !g_fp->_aniMan->_movement) + sceneHandler29_shootersProcess(); + + if (g_vars->scene29_reachedFarRight) + sceneHandler29_shootersEscape(); + else if (g_vars->scene29_rideBackEnabled) + sceneHandler29_manRideBack(); + + g_vars->scene29_shootCountdown++; + + if (g_vars->scene29_shootCountdown > g_vars->scene29_shootDistance) + sceneHandler29_shoot(); + + sceneHandler29_animBearded(); + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +int scene29_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_vars->scene29_arcadeIsOn) { + if (g_fp->_cursorId != PIC_CSR_DEFAULT_INV && g_fp->_cursorId != PIC_CSR_ITN_INV) + g_fp->_cursorId = -1; + } else if (g_vars->scene29_manIsRiding) { + if (g_fp->_cursorId != PIC_CSR_DEFAULT_INV && g_fp->_cursorId != PIC_CSR_ITN_INV) + g_fp->_cursorId = PIC_CSR_DEFAULT; + } else if (g_fp->_objectIdAtCursor == ANI_PORTER) { + if (g_fp->_cursorId == PIC_CSR_DEFAULT) + g_fp->_cursorId = PIC_CSR_ITN; + } else { + if (g_fp->_objectIdAtCursor == PIC_SC29_LTRUBA && g_fp->_cursorId == PIC_CSR_ITN) + g_fp->_cursorId = PIC_CSR_GOL; + } + return g_fp->_cursorId; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene30.cpp b/engines/fullpipe/scenes/scene30.cpp new file mode 100644 index 0000000000..ca2324e647 --- /dev/null +++ b/engines/fullpipe/scenes/scene30.cpp @@ -0,0 +1,152 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene30_enablePass(Scene *sc) { + MovGraphLink *lnk = getSc2MctlCompoundBySceneId(sc->_sceneId)->getLinkByName(sO_WayToPipe); + + if (g_fp->getObjectState(sO_Leg) == g_fp->getObjectEnumState(sO_Leg, sO_WithAll)) + lnk->_flags &= 0xDFFFFFFF; + else + lnk->_flags |= 0x20000000; +} + +void scene30_initScene(Scene *sc, int flag) { + Scene *oldsc = g_fp->_currentScene; + + g_vars->scene30_leg = sc->getStaticANIObject1ById(ANI_LEG, -1); + g_fp->_currentScene = sc; + + if (g_fp->getObjectState(sO_Leg) == g_fp->getObjectEnumState(sO_Leg, sO_ShowingHeel)) + g_vars->scene30_leg->changeStatics2(ST_LEG_UP); + else if (g_fp->getObjectState(sO_Leg) == g_fp->getObjectEnumState(sO_Leg, sO_WithoutJugs)) + g_vars->scene30_leg->changeStatics2(ST_LEG_DOWN); + else if (g_fp->getObjectState(sO_Leg) == g_fp->getObjectEnumState(sO_Leg, sO_WithBig)) + g_vars->scene30_leg->changeStatics2(ST_LEG_DOWN1); + else if (g_fp->getObjectState(sO_Leg) == g_fp->getObjectEnumState(sO_Leg, sO_WithSmall)) + g_vars->scene30_leg->changeStatics2(ST_LEG_DOWN2); + else if (g_fp->getObjectState(sO_Leg) == g_fp->getObjectEnumState(sO_Leg, sO_WithAll)) + g_vars->scene30_leg->changeStatics2(ST_LEG_EMPTY); + + g_fp->_currentScene = oldsc; + + scene30_enablePass(sc); + + if (flag == LiftUp || flag == LiftDown) + g_vars->scene30_liftFlag = 0; + else + g_vars->scene30_liftFlag = 1; + + g_fp->lift_setButton(sO_Level8, ST_LBN_8N); + + g_fp->lift_init(sc, QU_SC30_ENTERLIFT, QU_SC30_EXITLIFT); +} + +int scene30_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_cursorId == PIC_CSR_ITN && g_fp->_objectIdAtCursor == PIC_SC30_LTRUBA) { + g_fp->_cursorId = PIC_CSR_GOL; + } + return g_fp->_cursorId; +} + +int sceneHandler30(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch(cmd->_messageNum) { + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(cmd); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC30_UPDATEPATH: + scene30_enablePass(g_fp->_currentScene); + break; + + case 64: + g_fp->lift_hoverButton(cmd); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (ani && ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_animateButton(ani); + + cmd->_messageKind = 0; + } + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + g_fp->_behaviorManager->updateBehaviors(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene31.cpp b/engines/fullpipe/scenes/scene31.cpp new file mode 100644 index 0000000000..3f507e62b7 --- /dev/null +++ b/engines/fullpipe/scenes/scene31.cpp @@ -0,0 +1,126 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene31_initScene(Scene *sc) { + g_vars->scene31_chantingCountdown = 0; + g_vars->scene31_cactus = sc->getStaticANIObject1ById(ANI_CACTUS_31, -1); + + if (g_fp->getObjectState(sO_Cactus) == g_fp->getObjectEnumState(sO_Cactus, sO_HasGrown)) { + Scene *oldsc = g_fp->_currentScene; + g_fp->_currentScene = sc; + + g_vars->scene31_cactus->changeStatics2(ST_CTS31_GROWN2); + g_vars->scene31_cactus->_priority = 22; + + g_fp->_currentScene = oldsc; + } else { + g_vars->scene31_cactus->hide(); + } + + g_vars->scene31_plusMinus = sc->getStaticANIObject1ById(ANI_PLUSMINUS, -1); + + if (g_fp->getObjectState(sO_Guard_3) == g_fp->getObjectEnumState(sO_Guard_3, sO_Off)) + g_vars->scene31_plusMinus->_statics = g_vars->scene31_plusMinus->getStaticsById(ST_PMS_MINUS); + else + g_vars->scene31_plusMinus->_statics = g_vars->scene31_plusMinus->getStaticsById(ST_PMS_PLUS); +} + +void sceneHandler31_testCactus(ExCommand *cmd) { + if ((g_vars->scene31_cactus->_flags & 4) && g_vars->scene31_cactus->_statics->_staticsId == ST_CTS31_GROWN2) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(cmd->_parId); + + if (mq) { + mq->getExCommandByIndex(0)->_messageKind = 0; + mq->getExCommandByIndex(0)->_excFlags |= 1; + + mq->getExCommandByIndex(1)->_messageKind = 0; + mq->getExCommandByIndex(1)->_excFlags |= 1; + } + } +} + +int sceneHandler31(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC31_TESTCACTUS: + sceneHandler31_testCactus(cmd); + break; + + case MSG_SC15_STOPCHANTING: + g_fp->stopAllSoundInstances(SND_31_001); + + g_vars->scene31_chantingCountdown = 120; + break; + + case MSG_SC31_PULL: + if ( g_vars->scene31_plusMinus->_statics->_staticsId == ST_PMS_MINUS) + g_vars->scene31_plusMinus->_statics = g_vars->scene31_plusMinus->getStaticsById(ST_PMS_PLUS); + else + g_vars->scene31_plusMinus->_statics = g_vars->scene31_plusMinus->getStaticsById(ST_PMS_MINUS); + + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene31_chantingCountdown > 0) { + --g_vars->scene31_chantingCountdown; + + if (!g_vars->scene31_chantingCountdown) + g_fp->playSound(SND_31_001, 1); + } + + g_fp->_behaviorManager->updateBehaviors(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene32.cpp b/engines/fullpipe/scenes/scene32.cpp new file mode 100644 index 0000000000..05b78efb3d --- /dev/null +++ b/engines/fullpipe/scenes/scene32.cpp @@ -0,0 +1,431 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene32_initScene(Scene *sc) { + g_vars->scene32_flagIsWaving = false; + g_vars->scene32_flagNeedsStopping = false; + g_vars->scene32_dudeIsSitting = false; + g_vars->scene32_cactusCounter = -1; + g_vars->scene32_dudeOnLadder = false; + g_vars->scene32_cactusIsGrowing = false; + g_vars->scene32_flag = sc->getStaticANIObject1ById(ANI_FLAG, -1); + g_vars->scene32_cactus = sc->getStaticANIObject1ById(ANI_CACTUS, -1); + g_vars->scene32_massOrange = sc->getStaticANIObject1ById(ANI_TESTO_ORANGE, -1); + g_vars->scene32_massBlue = sc->getStaticANIObject1ById(ANI_TESTO_BLUE, -1); + g_vars->scene32_massGreen = sc->getStaticANIObject1ById(ANI_TESTO_GREEN, -1); + g_vars->scene32_button = sc->getStaticANIObject1ById(ANI_BUTTON_32, -1); + + g_vars->scene32_massOrange->startAnim(MV_TSTO_FLOW, 0, -1); + g_vars->scene32_massOrange->_movement->setDynamicPhaseIndex(15); + + g_vars->scene32_massGreen->startAnim(MV_TSTG_FLOW, 0, -1); + g_vars->scene32_massGreen->_movement->setDynamicPhaseIndex(26); + + Scene *oldsc = g_fp->_currentScene; + StaticANIObject *ani; + + if (g_fp->getObjectState(sO_ClockHandle) == g_fp->getObjectEnumState(sO_ClockHandle, sO_In_32_Lies)) { + ani = sc->getStaticANIObject1ById(ANI_INV_HANDLE, -1); + if (ani) { + g_fp->_currentScene = sc; + + ani->changeStatics2(ST_HDL_LAID); + } + } else { + if (g_fp->getObjectState(sO_ClockHandle) == g_fp->getObjectEnumState(sO_ClockHandle, sO_In_32_Sticks)) { + ani = sc->getStaticANIObject1ById(ANI_INV_HANDLE, -1); + + g_fp->_currentScene = sc; + + if (ani) + ani->changeStatics2(ST_HDL_PLUGGED); + + g_vars->scene32_button->changeStatics2(ST_BTN32_ON); + } + } + + g_fp->_currentScene = oldsc; + + if (g_fp->getObjectState(sO_Cube) == g_fp->getObjectEnumState(sO_Cube, sO_In_32)) { + MessageQueue *mq = new MessageQueue(sc->getMessageQueueById(QU_KBK32_START), 0, 0); + + mq->sendNextCommand(); + } + + g_fp->lift_setButton(sO_Level9, ST_LBN_9N); + g_fp->lift_init(sc, QU_SC32_ENTERLIFT, QU_SC32_EXITLIFT); + + g_fp->initArcadeKeys("SC_32"); +} + +void scene32_setupMusic() { + if (g_fp->lift_checkButton(sO_Level6)) + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_32"), "MUSIC2", 1); +} + +int scene32_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_objectIdAtCursor == PIC_SC32_LADDER && g_fp->_cursorId == PIC_CSR_ITN) + g_fp->_cursorId = g_vars->scene32_dudeOnLadder ? PIC_CSR_GOD : PIC_CSR_GOU; // TODO FIXME doublecheck + + return g_fp->_cursorId; +} + +void sceneHandler32_tryCube() { + if (g_fp->getObjectState(sO_Cube) == g_fp->getObjectEnumState(sO_Cube, sO_In_33)) + chainQueue(QU_KBK32_GO, 0); +} + +void sceneHandler32_startCactus() { + g_vars->scene32_cactusCounter = 48; + g_vars->scene32_cactusIsGrowing = false; +} + +void sceneHandler32_spin(ExCommand *cmd) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(cmd->_parId); + + if (!mq || mq->getCount() == 0) + return; + + ExCommand *ex = mq->getExCommandByIndex(0); + ExCommand *newex; + + if ((g_vars->scene32_cactus->_movement && g_vars->scene32_cactus->_movement->_id == MV_CTS_DEFAULT) + || g_vars->scene32_cactus->_statics->_staticsId == ST_CTS_GROWUP) { + for (int i = 0; i < 12; i++) { + newex = ex->createClone(); + newex->_excFlags |= 2; + mq->insertExCommandAt(1, newex); + } + + g_vars->scene32_cactus->changeStatics2(ST_CTS_GROWUP); + + chainQueue(QU_CTS_BACK, 1); + + g_vars->scene32_cactusIsGrowing = false; + + return; + } + + if (g_vars->scene32_cactus->_statics->_staticsId == ST_CTS_EMPTY && g_vars->scene32_cactusCounter < 0) { + for (int i = 0; i < 2; i++) { + newex = ex->createClone(); + newex->_excFlags |= 2; + mq->insertExCommandAt(1, newex); + } + + chainQueue(QU_KDK_DRIZZLE, 0); + } +} + +void sceneHandler32_startFlagLeft() { + g_vars->scene32_flag->changeStatics2(ST_FLG_NORM); + g_vars->scene32_flag->startAnim(MV_FLG_STARTL, 0, -1); + + g_vars->scene32_flagIsWaving = true; +} + +void sceneHandler32_startFlagRight() { + g_vars->scene32_flag->changeStatics2(ST_FLG_NORM); + g_vars->scene32_flag->startAnim(MV_FLG_STARTR, 0, -1); + + g_vars->scene32_flagIsWaving = true; +} + +void sceneHandler32_trySit(ExCommand *cmd) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(cmd->_parId); + + if (!mq || mq->getCount() == 0) + return; + + ExCommand *ex = mq->getExCommandByIndex(0); + + if (g_vars->scene32_cactusIsGrowing || g_vars->scene32_cactus->_movement + || g_vars->scene32_cactus->_statics->_staticsId != ST_CTS_EMPTY + || (g_vars->scene32_cactusCounter >= 0 && g_vars->scene32_cactusCounter <= 20)) { + ex->_messageKind = 0; + ex->_excFlags |= 1; + } else { + ex->_parentId = ANI_MAN; + ex->_messageKind = 1; + ex->_messageNum = MV_MAN32_SITDOWN; + ex->_keyCode = g_fp->_aniMan->_okeyCode; + + g_vars->scene32_dudeIsSitting = true; + + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + } +} + +void sceneHandler32_buttonPush() { + if (g_fp->getObjectState(sO_ClockHandle) == g_fp->getObjectEnumState(sO_ClockHandle, sO_In_32_Sticks)) { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_INV_HANDLE, -1); + if (ani) + ani->changeStatics2(ST_HDL_PLUGGED); + + chainQueue(QU_SC32_FALLHANDLE, 1); + + g_vars->scene32_button->changeStatics2(ST_BTN32_OFF); + } +} + +void sceneHandler32_installHandle() { + chainQueue(QU_SC32_SHOWHANDLE, 0); + + g_vars->scene32_button->changeStatics2(ST_BTN32_ON); +} + +void sceneHandler32_animateCactus() { + if (g_fp->_aniMan->_statics->_staticsId != ST_MAN32_SIT) + chainQueue(QU_CTS_GROW, 1); + else + chainQueue(QU_CTS_GROWMAN, 1); + + g_vars->scene32_cactusCounter = -1; + g_vars->scene32_cactusIsGrowing = true; +} + +void sceneHandler32_ladderLogic(ExCommand *cmd) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC32_FROMLADDER), 0, 0); + + if (g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY) != PIC_SC32_LADDER) + mq->addExCommandToEnd(cmd->createClone()); + + mq->setFlags(mq->getFlags() | 1); + + g_fp->_aniMan->changeStatics2(ST_MAN_STANDLADDER); + if (!mq->chain(g_fp->_aniMan)) + delete mq; + + g_vars->scene32_dudeOnLadder = false; + + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); +} + +void sceneHandler32_potLogic(ExCommand *cmd) { + if (g_vars->scene32_cactusCounter < 0 || g_vars->scene32_cactusCounter > 20) { + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + ExCommand *ex = new ExCommand(ANI_MAN, 1, MV_MAN32_STANDUP, 0, 0, 0, 1, 0, 0, 0); + + ex->_excFlags |= 2; + + mq->addExCommandToEnd(ex); + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (!ani || ani->_id != ANI_KADKA) + mq->addExCommandToEnd(cmd->createClone()); + + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + g_vars->scene32_dudeIsSitting = false; + } +} + +int sceneHandler32(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(cmd); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_SC32_TRUBATOBACK: + g_fp->_currentScene->getPictureObjectById(PIC_SC32_RTRUBA, 0)->_priority = 20; + break; + + case MSG_SC32_TRUBATOFRONT: + g_fp->_currentScene->getPictureObjectById(PIC_SC32_RTRUBA, 0)->_priority = 0; + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC33_TRYKUBIK: + sceneHandler32_tryCube(); + break; + + case MSG_SC32_STARTCACTUS: + sceneHandler32_startCactus(); + break; + + case MSG_SC32_STOPFLAG: + g_vars->scene32_flagIsWaving = false; + g_vars->scene32_flagNeedsStopping = true; + break; + + case MSG_SC32_SPIN: + sceneHandler32_spin(cmd); + break; + + case MSG_SC32_STARTFLAGLEFT : + sceneHandler32_startFlagLeft(); + break; + + case MSG_SC32_STARTFLAGRIGHT: + sceneHandler32_startFlagRight(); + break; + + case MSG_SC32_TRYSIT: + sceneHandler32_trySit(cmd); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case MSG_SC32_ONLADDER: + g_vars->scene32_dudeOnLadder = true; + + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + break; + + case MSG_SC6_BTNPUSH: + sceneHandler32_buttonPush(); + break; + + case 64: + g_fp->lift_hoverButton(cmd); + break; + + case MSG_SC6_INSTHANDLE: + sceneHandler32_installHandle(); + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (!g_vars->scene32_flag->_movement) { + if (g_vars->scene32_flagIsWaving) { + if (g_vars->scene32_flag->_statics->_staticsId == ST_FLG_RIGHT) + g_vars->scene32_flag->startAnim(MV_FLG_CYCLER, 0, -1); + else if (g_vars->scene32_flag->_statics->_staticsId == ST_FLG_LEFT) + g_vars->scene32_flag->startAnim(MV_FLG_CYCLEL, 0, -1); + } + + if (g_vars->scene32_flagNeedsStopping && !g_vars->scene32_flagIsWaving) { + if (g_vars->scene32_flag->_statics->_staticsId == ST_FLG_RIGHT) + g_vars->scene32_flag->startAnim(MV_FLG_STOPR, 0, -1); + else if (g_vars->scene32_flag->_statics->_staticsId == ST_FLG_LEFT) + g_vars->scene32_flag->startAnim(MV_FLG_STOPL, 0, -1); + + g_vars->scene32_flagNeedsStopping = false; + } + } + + if (g_vars->scene32_cactusCounter) { + if (g_vars->scene32_cactusCounter > 0) + --g_vars->scene32_cactusCounter; + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + } else { + sceneHandler32_animateCactus(); + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + } + break; + + case 29: + if (g_vars->scene32_dudeOnLadder) { + sceneHandler32_ladderLogic(cmd); + cmd->_messageKind = 0; + break; + } + + if (!g_vars->scene32_dudeIsSitting || g_fp->_aniMan->_movement) { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (ani && ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_animateButton(ani); + + cmd->_messageKind = 0; + break; + } + + if (g_fp->_cursorId == PIC_CSR_GOFAR_R || g_fp->_cursorId == PIC_CSR_GOFAR_L) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) + g_fp->processArcade(cmd); + } + break; + } + + if (!g_vars->scene32_cactusIsGrowing) + sceneHandler32_potLogic(cmd); + + cmd->_messageKind = 0; + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene33.cpp b/engines/fullpipe/scenes/scene33.cpp new file mode 100644 index 0000000000..90ea0a4f3f --- /dev/null +++ b/engines/fullpipe/scenes/scene33.cpp @@ -0,0 +1,314 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +const int ventsInit[9] = { 0, 0, 1, 0, 0, 1, 0, 0, 1 }; + +void scene33_initScene(Scene *sc) { + g_vars->scene33_mug = sc->getStaticANIObject1ById(ANI_MUG_33, -1); + g_vars->scene33_jettie = sc->getStaticANIObject1ById(ANI_JETTIE_FLOW, -1); + g_vars->scene33_cube = 0; + g_vars->scene33_cubeX = -1; + g_vars->scene33_handleIsDown = false; + + if (g_fp->getObjectState(sO_Cube) == g_fp->getObjectEnumState(sO_Cube, sO_In_33)) { + MessageQueue *mq = new MessageQueue(sc->getMessageQueueById(QU_KBK33_START), 0, 0); + + mq->sendNextCommand(); + } + + + for (int i = 0; i < 9; i++) { + g_vars->scene33_ventsX[i] = sc->getStaticANIObject1ById(ANI_VENT_33, i)->_ox; + + g_vars->scene33_ventsState[i] = ventsInit[i]; + } + + g_fp->initArcadeKeys("SC_33"); +} + +void scene33_setupMusic() { + if (g_fp->lift_checkButton(sO_Level6)) + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_33"), "MUSIC2", 1); +} + +int scene33_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_objectIdAtCursor == PIC_SC33_ZONES && g_fp->_cursorId == PIC_CSR_DEFAULT) + g_fp->_cursorId = PIC_CSR_ITN; + + return g_fp->_cursorId; +} + +void sceneHandler33_processJettie(ExCommand *cmd) { + MessageQueue *mq = g_fp->_globalMessageQueueList->getMessageQueueById(cmd->_parId); + + if (mq && g_vars->scene33_jettie->_movement) { + ExCommand *ex = mq->getExCommandByIndex(0); + + if (ex) { + ex->_messageKind = 0; + ex->_excFlags |= 1; + } + + ex = mq->getExCommandByIndex(1); + + if (ex) { + ex->_messageKind = 0; + ex->_excFlags |= 1; + } + } +} + +void sceneHandler33_switchVent(StaticANIObject *ani) { + int mv = 0; + + if (ani->_statics->_staticsId == ST_VNT33_DOWN) + mv = MV_VNT33_TURNR; + + if (ani->_statics->_staticsId == ST_VNT33_RIGHT) + mv = MV_VNT33_TURND; + + if (mv) + ani->startAnim(mv, 0, -1); + + g_vars->scene33_ventsState[ani->_okeyCode] = !g_vars->scene33_ventsState[ani->_okeyCode]; +} + +void sceneHandler33_processVents() { + for (int i = 0; i < 9; i++) + if (((g_vars->scene33_cubeX < g_vars->scene33_ventsX[i]) != (g_vars->scene33_cube->_ox < g_vars->scene33_ventsX[i])) + && g_vars->scene33_ventsState[i] != ventsInit[i]) + sceneHandler33_switchVent(g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, i)); + + g_vars->scene33_cubeX = g_vars->scene33_cube->_ox; +} + +void sceneHandler33_tryCube() { + if (g_fp->getObjectState(sO_Cube) == g_fp->getObjectEnumState(sO_Cube, sO_In_32)) + chainQueue(QU_KBK33_GO, 0); +} + +void sceneHandler33_pour() { + bool solved = true; + + for (int i = 0; i < 9; i++) + if (g_vars->scene33_ventsState[i] != ventsInit[i]) + solved = false; + + if (solved) { + if ((g_vars->scene33_mug->_flags & 4) && g_vars->scene33_mug->_statics->_staticsId == ST_MUG33_EMPTY) { + g_vars->scene33_jettie->startAnim(MV_JTI33_POUR, 0, -1); + + g_vars->scene33_handleIsDown = false; + + return; + } + + if ((g_vars->scene33_mug->_flags & 4) && g_vars->scene33_mug->_statics->_staticsId == ST_MUG33_FULL) { + g_vars->scene33_jettie->startAnim(MV_JTI33_POURFULL, 0, -1); + + g_vars->scene33_handleIsDown = false; + + return; + } + + g_vars->scene33_jettie->startAnim(MV_JTI33_FLOW, 0, -1); + } + + g_vars->scene33_handleIsDown = false; +} + +void sceneHandler33_handleDown() { + if (!g_vars->scene33_handleIsDown && !g_vars->scene33_jettie->_movement && !g_vars->scene33_jettie->getMessageQueue() ) { + chainQueue(QU_SC33_STARTWATER, 0); + + g_vars->scene33_handleIsDown = true; + } +} + +void sceneHandler33_zoneClickProcess(StaticANIObject *ani) { + if (!ani->_movement) { + sceneHandler33_switchVent(ani); + + StaticANIObject *vent1 = 0; + StaticANIObject *vent2 = 0; + + switch (ani->_okeyCode) { + case 0: + vent1 = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, 2); + vent2 = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, 3); + break; + + case 1: + vent1 = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, 3); + vent2 = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, 4); + break; + + case 2: + vent1 = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, 4); + vent2 = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, 0); + break; + + case 3: + vent1 = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, 0); + vent2 = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, 1); + break; + + case 4: + vent1 = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, 1); + vent2 = g_fp->_currentScene->getStaticANIObject1ById(ANI_VENT_33, 2); + break; + + default: + return; + } + + if (vent1) { + sceneHandler33_switchVent(vent1); + sceneHandler33_switchVent(vent2); + } + } +} + +void sceneHandler33_clickZones(ExCommand *cmd) { + StaticANIObject *closest = 0; + double mindist = 1e10; + + for (uint i = 0; i < g_fp->_currentScene->_staticANIObjectList1.size(); i++) { + StaticANIObject *ani = (StaticANIObject *)g_fp->_currentScene->_staticANIObjectList1[i]; + + if (ani->_id == ANI_VENT_33) { + int dx = ani->_ox - cmd->_sceneClickX; + int dy = ani->_oy - cmd->_sceneClickY; + double dist = sqrt((double)(dx * dx + dy * dy)); + + if (dist < mindist) { + mindist = dist; + closest = ani; + } + } + } + + if (closest) + sceneHandler33_zoneClickProcess(closest); +} + +int sceneHandler33(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC32_TRUBATOFRONT: + g_fp->_currentScene->getPictureObjectById(PIC_SC33_LTRUBA, 0)->_priority = 0; + break; + + case MSG_SC32_TRUBATOBACK: + g_fp->_currentScene->getPictureObjectById(PIC_SC33_LTRUBA, 0)->_priority = 20; + break; + + case MSG_SC33_TESTMUG: + sceneHandler33_processJettie(cmd); + break; + + case MSG_SC33_UPDATEKUBIK: + g_vars->scene33_cube = g_fp->_currentScene->getStaticANIObject1ById(ANI_KUBIK, -1); + + if (g_vars->scene33_cube) + g_vars->scene33_cubeX = g_vars->scene33_cube->_ox; + + break; + + case MSG_SC33_TRYKUBIK: + sceneHandler33_tryCube(); + break; + + case MSG_SC33_POUR: + sceneHandler33_pour(); + break; + + case MSG_SC33_HANDLEDOWN: + sceneHandler33_handleDown(); + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (pic && pic->_id == PIC_SC33_ZONES) { + sceneHandler33_clickZones(cmd); + break; + } + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) + g_fp->processArcade(cmd); + } + } + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene33_cube) + sceneHandler33_processVents(); + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene34.cpp b/engines/fullpipe/scenes/scene34.cpp new file mode 100644 index 0000000000..32fb192756 --- /dev/null +++ b/engines/fullpipe/scenes/scene34.cpp @@ -0,0 +1,479 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" +#include "fullpipe/floaters.h" + +namespace Fullpipe { + +void sceneHandler34_setExits() { + int state; + + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_NearPipeWithStool)) { + if (g_fp->getObjectState(sO_Hatch_34) == g_fp->getObjectEnumState(sO_Hatch_34, sO_Closed)) + state = g_fp->getObjectEnumState(sO_Plank_34, sO_ClosedWithBoot); + else + state = g_fp->getObjectEnumState(sO_Plank_34, sO_OpenedWithBoot); + } else { + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_OnStool)) { + if (g_fp->getObjectState(sO_Hatch_34) == g_fp->getObjectEnumState(sO_Hatch_34, sO_Closed)) + state = g_fp->getObjectEnumState(sO_Plank_34, sO_IsClosed); + else + state = g_fp->getObjectEnumState(sO_Plank_34, sO_IsOpened); + } else { + state = g_fp->getObjectEnumState(sO_Plank_34, sO_Passive); + } + } + + g_fp->setObjectState(sO_Plank_34, state); +} + +void scene34_initScene(Scene *sc) { + g_vars->scene34_cactus = sc->getStaticANIObject1ById(ANI_CACTUS_34, -1); + g_vars->scene34_vent = sc->getStaticANIObject1ById(ANI_VENT_34, -1); + g_vars->scene34_hatch = sc->getStaticANIObject1ById(ANI_LUK_34, -1); + g_vars->scene34_boot = sc->getStaticANIObject1ById(ANI_BOOT_34, -1); + + if (g_fp->getObjectState(sO_Cactus) == g_fp->getObjectEnumState(sO_Cactus, sO_HasGrown)) { + Scene *oldsc = g_fp->_currentScene; + + g_fp->_currentScene = sc; + + g_vars->scene34_cactus->changeStatics2(ST_CTS34_EMPTY); + g_vars->scene34_cactus->setOXY(506, 674); + g_vars->scene34_cactus->_priority = 30; + + g_vars->scene34_cactus->changeStatics2(ST_CTS34_GROWNEMPTY2); + g_vars->scene34_cactus->_flags |= 4; + + g_fp->_currentScene = oldsc; + } + + if (g_fp->getObjectState(sO_Grandma) == g_fp->getObjectEnumState(sO_Grandma, sO_Strolling)) + g_fp->setObjectState(sO_Grandma, g_fp->getObjectEnumState(sO_Grandma, sO_OnStool)); + + sceneHandler34_setExits(); + + g_vars->scene34_dudeClimbed = false; + g_vars->scene34_dudeOnBoard = false; + g_vars->scene34_dudeOnCactus = false; + g_vars->scene34_fliesCountdown = g_fp->_rnd->getRandomNumber(500) + 500; + + g_fp->_floaters->init(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_34")); + + g_fp->lift_setButton(sO_Level7, ST_LBN_7N); + g_fp->lift_init(sc, QU_SC34_ENTERLIFT, QU_SC34_EXITLIFT); + + g_fp->initArcadeKeys("SC_34"); +} + +void scene34_initBeh() { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene34_cactus, ST_CTS34_GROWNEMPTY2, QU_CTS34_FALLEFT, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene34_cactus, ST_CTS34_GROWNEMPTY2, QU_CTS34_FALLRIGHT, 0); +} + +int scene34_updateCursor() { + g_fp->updateCursorCommon(); + + if ((g_fp->_objectIdAtCursor != ANI_STOOL_34 || getGameLoaderInventory()->getSelectedItemId() != ANI_INV_BOX) + && (g_fp->_objectIdAtCursor != ANI_BOX_34 || getGameLoaderInventory()->getSelectedItemId() != ANI_INV_STOOL)) + ; // emtpy + else + g_fp->_cursorId = PIC_CSR_ITN_INV; + + return g_fp->_cursorId; +} + +void sceneHandler34_leaveBoard() { + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); + + g_vars->scene34_dudeOnBoard = false; +} + +void sceneHandler34_onBoard() { + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + + g_vars->scene34_dudeOnBoard = true; +} + +void sceneHandler34_testVent() { + if (g_fp->_aniMan->_movement->_id == MV_MAN34_TURNVENT_R) { + g_vars->scene34_hatch->changeStatics2(ST_LUK34_CLOSED); + + chainQueue(QU_LUK34_OPEN, 0); + } else if (g_fp->_aniMan->_movement->_id == MV_MAN34_TURNVENT_L) { + g_vars->scene34_hatch->changeStatics2(ST_LUK34_OPEN); + + chainQueue(QU_LUK34_CLOSE, 0); + } +} + +void sceneHandler34_hideStool() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_STOOL_34, -1)->hide(); +} + +void sceneHandler34_climb() { + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + + g_vars->scene34_dudeClimbed = true; +} + +void sceneHandler34_genFlies() { + g_fp->_floaters->genFlies(g_fp->_currentScene, 1072, -50, 100, 4); + + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->countdown = 1; + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val6 = 1072; + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val7 = -50; + + g_vars->scene34_fliesCountdown = g_fp->_rnd->getRandomNumber(500) + 500; +} + +void sceneHandler34_fromCactus(ExCommand *cmd) { + if (g_fp->_aniMan->_movement || g_vars->scene34_cactus->_movement || (g_fp->_aniMan->_flags & 0x100)) { + cmd->_messageKind = 0; + + return; + } + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC34_FROMCACTUS), 0, 0); + + ExCommand *ex = new ExCommand(ANI_MAN, 34, 256, 0, 0, 0, 1, 0, 0, 0); + + ex->_messageNum = 0; + ex->_excFlags |= 3; + ex->_field_14 = 256; + mq->addExCommandToEnd(ex); + + ex = cmd->createClone(); + mq->addExCommandToEnd(ex); + + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + + g_fp->_aniMan->_flags |= 1; +} + +void sceneHandler34_animateLeaveBoard(ExCommand *cmd) { + if (!g_fp->_aniMan->_movement) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC34_LEAVEBOARD), 0, 0); + + mq->addExCommandToEnd(cmd->createClone()); + mq->setFlags(mq->getFlags() | 1); + mq->chain(0); + } + + cmd->_messageKind = 0; +} + +void sceneHandler34_animateAction(ExCommand *cmd) { + if (g_fp->_aniMan->_movement) + return; + + int ox = g_fp->_aniMan->_ox; + int oy = g_fp->_aniMan->_oy; + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (!ani || ani->_id != ANI_VENT_34) { + int qId = 0; + + if (ox == 887) { + if (oy != 370) + return; + + qId = QU_SC34_FROMSTOOL; + } else { + if (ox != 916) + return; + + if (oy == 286) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC34_FROMBOX), 0, 0); + + mq->addExCommandToEnd(cmd->createClone()); + mq->chain(0); + + sceneHandler34_setExits(); + + return; + } + + if (oy != 345) + return; + + qId = QU_SC34_FROMBOX_FLOOR; + } + + if (qId) { + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(qId), 0, 0); + + mq->addExCommandToEnd(cmd->createClone()); + mq->chain(0); + } + + return; + } + + if (ox == 887) { + if (oy == 370) + g_fp->_aniMan->startAnim(MV_MAN34_TRYTABUR, 0, -1); + + } else if (ox == 916) { + if (oy == 286) { + int id = g_vars->scene34_vent->_statics->_staticsId; + if (id == ST_VNT34_UP2) { + g_fp->_aniMan->startAnim(MV_MAN34_TURNVENT_R, 0, -1); + } else if (id == ST_VNT34_RIGHT3) { + g_fp->_aniMan->startAnim(MV_MAN34_TURNVENT_L, 0, -1); + } + } else if (oy == 345) { + g_fp->_aniMan->startAnim(MV_MAN34_TRY, 0, -1); + } + } +} + +void sceneHandler34_showVent() { + if (g_vars->scene34_vent->_statics->_staticsId == ST_VNT34_UP2) + g_vars->scene34_vent->changeStatics2(ST_VNT34_RIGHT3); + else if (g_vars->scene34_vent->_statics->_staticsId == ST_VNT34_RIGHT3) + g_vars->scene34_vent->changeStatics2(ST_VNT34_UP2); + + g_vars->scene34_vent->show1(-1, -1, -1, 0); +} + +void sceneHandler34_showBox() { + g_fp->_currentScene->getStaticANIObject1ById(ANI_STOOL_34, -1)->changeStatics2(ST_STL34_BOX2); +} + +void sceneHandler34_showStool() { + chainQueue(QU_SC34_SHOWSTOOL, 0); +} + +void sceneHandler34_unclimb() { + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); + + g_vars->scene34_dudeClimbed = false; +} + +int sceneHandler34(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_SC4_HIDEBOOT: + g_vars->scene34_boot->_flags &= 0xFFFB; + break; + + case MSG_SC34_LEAVEBOARD: + sceneHandler34_leaveBoard(); + break; + + case MSG_SC34_ONBOARD: + sceneHandler34_onBoard(); + break; + + case MSG_SC34_TESTVENT: + sceneHandler34_testVent(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC34_FROMCACTUS: + g_vars->scene34_dudeOnCactus = false; + + getCurrSceneSc2MotionController()->activate(); + getGameLoaderInteractionController()->enableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 1); + + break; + + case MSG_SC34_RETRYVENT: + if (!g_fp->_aniMan->isIdle()) + break; + + g_fp->_aniMan->changeStatics2(ST_MAN_RIGHT); + g_fp->_aniMan->_flags &= 0xFEFF; + + getGameLoaderInteractionController()->handleInteraction(g_fp->_aniMan, g_vars->scene34_vent, cmd->_keyCode); + + break; + + case MSG_SC34_ONBUMP: + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene34_cactus, ST_CTS34_GROWNEMPTY2, QU_CTS34_FALLEFT, 1); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene34_cactus, ST_CTS34_GROWNEMPTY2, QU_CTS34_FALLRIGHT, 1); + break; + + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(cmd); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_SC22_HIDESTOOL: + sceneHandler34_hideStool(); + break; + + case MSG_SC34_CLIMB: + sceneHandler34_climb(); + break; + + case MSG_SC34_UNCLIMB: + sceneHandler34_unclimb(); + break; + + case MSG_SC22_SHOWSTOOL: + sceneHandler34_showStool(); + break; + + case MSG_SC34_SHOWBOX: + sceneHandler34_showBox(); + break; + + case MSG_SC34_ONCACTUS: + g_vars->scene34_dudeOnCactus = true; + + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_behaviorManager->setFlagByStaticAniObject(g_fp->_aniMan, 0); + break; + + case MSG_SC34_SHOWVENT: + sceneHandler34_showVent(); + break; + + case 64: + g_fp->lift_hoverButton(cmd); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case 29: + { + if (g_vars->scene34_dudeClimbed) { + sceneHandler34_animateAction(cmd); + break; + } + + if (g_vars->scene34_dudeOnBoard) { + sceneHandler34_animateLeaveBoard(cmd); + break; + } + + if (g_vars->scene34_dudeOnCactus) { + sceneHandler34_fromCactus(cmd); + break; + } + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (ani) { + if ((ani->_id == ANI_STOOL_34 && cmd->_keyCode == ANI_INV_BOX) || (ani->_id == ANI_BOX_34 && cmd->_keyCode == ANI_INV_STOOL)) { + getGameLoaderInteractionController()->handleInteraction(g_fp->_aniMan, g_vars->scene34_vent, cmd->_keyCode); + + cmd->_messageKind = 0; + } + + if (ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_animateButton(ani); + + cmd->_messageKind = 0; + + break; + } + } + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + break; + } + } + } + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + --g_vars->scene34_fliesCountdown; + + if (!g_vars->scene34_fliesCountdown) + sceneHandler34_genFlies(); + + g_fp->_floaters->update(); + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene35.cpp b/engines/fullpipe/scenes/scene35.cpp new file mode 100644 index 0000000000..53381fd555 --- /dev/null +++ b/engines/fullpipe/scenes/scene35.cpp @@ -0,0 +1,264 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + +#include "fullpipe/floaters.h" + +namespace Fullpipe { + +void scene35_initScene(Scene *sc) { + g_vars->scene35_hose = sc->getStaticANIObject1ById(ANI_HOSE, -1); + g_vars->scene35_bellyInflater = sc->getStaticANIObject1ById(ANI_PUZODUV, -1); + g_vars->scene35_flowCounter = 0; + g_vars->scene35_fliesCounter = 0; + + MovGraphLink *lnk = getSc2MctlCompoundBySceneId(sc->_sceneId)->getLinkByName(sO_CloseThing); + + if (g_vars->scene35_bellyInflater->_statics->_staticsId == ST_PDV_LARGE) + lnk->_flags |= 0x20000000; + else + lnk->_flags &= 0xDFFFFFFF; + + int sndId = 0; + + if (g_fp->getObjectState(sO_Valve_35) == g_fp->getObjectEnumState(sO_Valve_35, sO_TurnedOn)) { + if ((g_vars->scene35_hose->_flags & 4) && g_vars->scene35_hose->_statics->_staticsId == ST_HZE_NORM) { + sndId = SND_35_012; + } else if (g_vars->scene35_bellyInflater->_statics->_staticsId == ST_PDV_SMALL) { + sndId = SND_35_011; + } + } + + if (sndId) + g_fp->playSound(sndId, 1); + + g_fp->lift_setButton(sO_Level6, ST_LBN_6N); + g_fp->lift_init(sc, QU_SC35_ENTERLIFT, QU_SC35_EXITLIFT); + + g_fp->initArcadeKeys("SC_35"); + + g_fp->_floaters->init(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_35")); +} + +void sceneHandler35_stopFlow() { + g_fp->setObjectState(sO_Valve_35, g_fp->getObjectEnumState(sO_Valve_35, sO_TurnedOff)); + g_fp->stopAllSoundInstances(SND_35_011); + g_fp->playSound(SND_35_026, 0); +} + +void sceneHandler35_shrink() { + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing, 0); +} + +void sceneHandler35_startFlow() { + if (g_fp->getObjectState(sO_Valve_35) == g_fp->getObjectEnumState(sO_Valve_35, sO_TurnedOn)) { + if ((g_vars->scene35_hose->_flags & 4) && g_vars->scene35_hose->_statics->_staticsId == ST_HZE_NORM) { + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene35_bellyInflater, ST_PDV_SMALL, QU_PDV_SML_BLINK, 0); + g_fp->_behaviorManager->setBehaviorEnabled(g_vars->scene35_bellyInflater, ST_PDV_SMALL, QU_PDV_SML_TRY, 0); + + g_vars->scene35_bellyInflater->changeStatics2(ST_PDV_SMALL); + g_vars->scene35_bellyInflater->_flags &= 0xFEFF; + + MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC35_EATHOZE), 0, 0); + + mq->setFlags(mq->getFlags() | 1); + + ExCommand *cmd = new ExCommand(g_vars->scene35_bellyInflater->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); + + cmd->_excFlags |= 3; + cmd->_field_14 = 256; + cmd->_messageNum = 0; + + mq->addExCommandToEnd(cmd); + + if (!mq->chain(g_vars->scene35_bellyInflater)) + delete mq; + + g_vars->scene35_bellyInflater->_flags |= 1; + + getCurrSceneSc2MotionController()->enableLinks(sO_CloseThing, 1); + + g_fp->playSound(SND_35_012, 1); + } else { + if (!g_vars->scene35_flowCounter) + g_vars->scene35_flowCounter = 98; + + g_fp->playSound(SND_35_011, 1); + } + } +} + +void sceneHandler35_genFlies() { + StaticANIObject *fly = g_fp->_currentScene->getStaticANIObject1ById(ANI_FLY, -1); + + int xoff = 0; + if ((!fly || !(fly->_flags & 4)) && !(g_fp->_rnd->getRandomNumber(32767) % 30)) { + int x, y; + + if (g_fp->_rnd->getRandomNumber(1)) { + x = 600; + y = 0; + } else { + x = 0; + y = 600; + } + + int numFlies = g_fp->_rnd->getRandomNumber(3) + 1; + + while (numFlies--) { + g_fp->_floaters->genFlies(g_fp->_currentScene, g_fp->_rnd->getRandomNumber(55) + 1057, g_fp->_rnd->getRandomNumber(60) + x + xoff, 4, 1); + + xoff += 40; + + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val2 = 1084; + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val3 = y; + g_fp->_floaters->_array2[g_fp->_floaters->_array2.size() - 1]->val11 = 8.0; + } + + g_vars->scene35_fliesCounter = 0; + } +} + +int sceneHandler35(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(cmd); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC35_STOPFLOW: + sceneHandler35_stopFlow(); + break; + + case MSG_SC35_CHECKPIPESOUND: + if (g_fp->getObjectState(sO_Valve_35) == g_fp->getObjectEnumState(sO_Valve_35, sO_TurnedOn)) { + g_fp->stopAllSoundInstances(SND_35_011); + g_fp->playSound(SND_35_012, 1); + + g_vars->scene35_flowCounter = 0; + break; + } + break; + + case MSG_SC35_SHRINK: + sceneHandler35_shrink(); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case MSG_SC35_STARTFLOW: + case MSG_SC35_PLUGHOSE: + sceneHandler35_startFlow(); + break; + + case 64: + g_fp->lift_hoverButton(cmd); + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (ani) + if (ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_animateButton(ani); + cmd->_messageKind = 0; + break; + } + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + break; + } + } + } + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + if (g_vars->scene35_flowCounter > 0) { + --g_vars->scene35_flowCounter; + + if (!g_vars->scene35_flowCounter) + sceneHandler35_stopFlow(); + } + + g_vars->scene35_fliesCounter++; + + if (g_vars->scene35_fliesCounter >= 160) + sceneHandler35_genFlies(); + + g_fp->_floaters->update(); + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene36.cpp b/engines/fullpipe/scenes/scene36.cpp new file mode 100644 index 0000000000..44099faba0 --- /dev/null +++ b/engines/fullpipe/scenes/scene36.cpp @@ -0,0 +1,94 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene36_initScene(Scene *sc) { + g_vars->scene36_rotohrust = sc->getStaticANIObject1ById(ANI_ROTOHRUST, -1); + g_vars->scene36_scissors = sc->getStaticANIObject1ById(ANI_SCISSORS_36, -1); +} + +int scene36_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_cursorId != PIC_CSR_ITN || g_fp->_objectIdAtCursor != ANI_ROTOHRUST) { + if (g_fp->_objectIdAtCursor == PIC_SC36_MASK && g_fp->_cursorId == PIC_CSR_DEFAULT && (g_vars->scene36_scissors->_flags & 4)) + g_fp->_cursorId = PIC_CSR_ITN; + } else if (g_vars->scene36_rotohrust->_statics->_staticsId == ST_RHT_OPEN) + g_fp->_cursorId = PIC_CSR_GOL; + + return g_fp->_cursorId; +} + +int sceneHandler36(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case 29: + if (g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY) == PIC_SC36_MASK) + if (g_vars->scene36_scissors) + if (g_vars->scene36_scissors->_flags & 4) + if (g_fp->_aniMan->isIdle()) + if (!(g_fp->_aniMan->_flags & 0x100) && g_fp->_msgObjectId2 != g_vars->scene36_scissors->_id ) { + handleObjectInteraction(g_fp->_aniMan, g_vars->scene36_scissors, cmd->_keyCode); + + cmd->_messageKind = 0; + } + + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene37.cpp b/engines/fullpipe/scenes/scene37.cpp new file mode 100644 index 0000000000..324d3ac92d --- /dev/null +++ b/engines/fullpipe/scenes/scene37.cpp @@ -0,0 +1,316 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +Ring::Ring() { + ani = 0; + x = 0; + y = 0; + numSubRings = 0; + + for (int i = 0; i < 10; i++) + subRings[i] = 0; + + state = false; +} + +void scene37_initScene(Scene *sc) { + Ring *ring; + StaticANIObject *ani; + + g_vars->scene37_lastDudeX = -1; + + ring = new Ring(); + ani = sc->getStaticANIObject1ById(ANI_GUARD_37, 0); + ring->ani = ani; + ring->x = ani->_ox - 40; + ring->y = ani->_ox + 40; + ring->numSubRings = 3; + ring->subRings[0] = 1; + ring->subRings[1] = 4; + ring->subRings[2] = 8; + ring->state = false; + g_vars->scene37_rings.push_back(ring); + + ring = new Ring(); + ani = sc->getStaticANIObject1ById(ANI_GUARD_37, 1); + ring->ani = ani; + ring->x = ani->_ox - 40; + ring->y = ani->_ox + 40; + ring->numSubRings = 3; + ring->subRings[0] = 2; + ring->subRings[1] = 5; + ring->subRings[2] = 9; + ring->state = false; + g_vars->scene37_rings.push_back(ring); + + ring = new Ring(); + ani = sc->getStaticANIObject1ById(ANI_GUARD_37, 2); + ring->ani = ani; + ring->x = ani->_ox - 40; + ring->y = ani->_ox + 40; + ring->numSubRings = 3; + ring->subRings[0] = 3; + ring->subRings[1] = 7; + ring->subRings[2] = 11; + ring->state = false; + g_vars->scene37_rings.push_back(ring); + + g_fp->setObjectState(sO_LeftPipe_37, g_fp->getObjectEnumState(sO_LeftPipe_37, sO_IsClosed)); + + Scene *oldsc = g_fp->_currentScene; + + g_fp->_currentScene = sc; + + g_vars->scene37_cursorIsLocked = false; + + g_vars->scene37_plusMinus1 = sc->getStaticANIObject1ById(ANI_PLUSMINUS, 1); + + for (int i = 0; i < g_vars->scene37_rings[0]->numSubRings; i++) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_RING, g_vars->scene37_rings[0]->subRings[i]); + + if (g_fp->getObjectState(sO_Guard_1) == g_fp->getObjectEnumState(sO_Guard_1, sO_On)) { + g_vars->scene37_plusMinus1->_statics = g_vars->scene37_plusMinus1->getStaticsById(ST_PMS_PLUS); + ani->changeStatics2(ST_RNG_OPEN); + } else { + g_vars->scene37_plusMinus1->_statics = g_vars->scene37_plusMinus1->getStaticsById(ST_PMS_MINUS); + ani->changeStatics2(ST_RNG_CLOSED2); + } + } + + g_vars->scene37_plusMinus2 = sc->getStaticANIObject1ById(ANI_PLUSMINUS, 2); + + for (int i = 0; i < g_vars->scene37_rings[1]->numSubRings; i++) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_RING, g_vars->scene37_rings[1]->subRings[i]); + + if (g_fp->getObjectState(sO_Guard_2) == g_fp->getObjectEnumState(sO_Guard_2, sO_On)) { + g_vars->scene37_plusMinus2->_statics = g_vars->scene37_plusMinus2->getStaticsById(ST_PMS_PLUS); + ani->changeStatics2(ST_RNG_OPEN); + } else { + g_vars->scene37_plusMinus2->_statics = g_vars->scene37_plusMinus2->getStaticsById(ST_PMS_MINUS); + ani->changeStatics2(ST_RNG_CLOSED2); + } + } + + g_vars->scene37_plusMinus3 = sc->getStaticANIObject1ById(ANI_PLUSMINUS, 3); + + for (int i = 0; i < g_vars->scene37_rings[2]->numSubRings; i++) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_RING, g_vars->scene37_rings[2]->subRings[i]); + + if (g_fp->getObjectState(sO_Guard_3) == g_fp->getObjectEnumState(sO_Guard_3, sO_On)) { + g_vars->scene37_plusMinus3->_statics = g_vars->scene37_plusMinus3->getStaticsById(ST_PMS_PLUS); + ani->changeStatics2(ST_RNG_OPEN); + } else { + g_vars->scene37_plusMinus3->_statics = g_vars->scene37_plusMinus3->getStaticsById(ST_PMS_MINUS); + ani->changeStatics2(ST_RNG_CLOSED2); + } + } + + g_fp->_currentScene = oldsc; + + g_fp->initArcadeKeys("SC_37"); +} + +int scene37_updateCursor() { + g_fp->updateCursorCommon(); + + if (g_fp->_cursorId == PIC_CSR_ITN && g_fp->_objectIdAtCursor == PIC_SC37_MASK) { + if (g_vars->scene37_cursorIsLocked) + g_fp->_cursorId = PIC_CSR_GOL; + } + + return g_fp->_cursorId; +} + +void sceneHandler37_updateRing(int ringNum) { + g_vars->scene37_rings[ringNum]->ani->changeStatics2(ST_GRD37_STAND); + g_vars->scene37_rings[ringNum]->ani->startAnim(MV_GRD37_PULL, 0, -1); + g_vars->scene37_rings[ringNum]->state = !g_vars->scene37_rings[ringNum]->state; + + StaticANIObject *ani; + + for (int i = 0; i < g_vars->scene37_rings[ringNum]->numSubRings; i++) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_RING, g_vars->scene37_rings[ringNum]->subRings[i]); + + if ((ani->_movement && ani->_movement->_id != MV_RNG_CLOSE) || ani->_statics->_staticsId != ST_RNG_CLOSED2) { + ani->changeStatics2(ST_RNG_OPEN); + ani->startAnim(MV_RNG_CLOSE, 0, -1); + } else { + ani->changeStatics2(ST_RNG_CLOSED2); + ani->startAnim(MV_RNG_OPEN, 0, -1); + } + } + + g_vars->scene37_cursorIsLocked = true; + + for (uint j = 0; j < g_vars->scene37_rings.size(); j++) { + for (int i = 0; i < g_vars->scene37_rings[ringNum]->numSubRings; i++) { + ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_RING, g_vars->scene37_rings[j]->subRings[i]); + + if ((ani->_movement && ani->_movement->_id != MV_RNG_CLOSE) || ani->_statics->_staticsId != ST_RNG_CLOSED2) + g_vars->scene37_cursorIsLocked = false; + } + } + + int state; + + if (g_vars->scene37_cursorIsLocked) + state = g_fp->getObjectEnumState(sO_LeftPipe_37, sO_IsOpened); + else + state = g_fp->getObjectEnumState(sO_LeftPipe_37, sO_IsClosed); + + g_fp->setObjectState(sO_LeftPipe_37, state); +} + +void sceneHandler37_setRingsState() { + if (g_vars->scene37_lastDudeX == -1) { + g_vars->scene37_lastDudeX = g_vars->scene37_dudeX; + } else { + for (uint i = 0; i < g_vars->scene37_rings.size(); i++) { + int x = g_vars->scene37_rings[i]->x; + + if (g_vars->scene37_lastDudeX > x && g_vars->scene37_dudeX <= x && !g_vars->scene37_rings[i]->state) + sceneHandler37_updateRing(i); + + x = g_vars->scene37_rings[i]->y; + + if (g_vars->scene37_lastDudeX < x && g_vars->scene37_dudeX >= x) { + if (g_vars->scene37_rings[i]->state) + sceneHandler37_updateRing(i); + } + } + + g_vars->scene37_lastDudeX = g_vars->scene37_dudeX; + } +} + +int sceneHandler37(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch(cmd->_messageNum) { + case MSG_SC37_EXITLEFT: + sceneHandler37_updateRing(0); + sceneHandler37_updateRing(1); + sceneHandler37_updateRing(2); + + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + + if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_keyCode)) { + int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); + + if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_keyCode)) { + if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) + || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) { + g_fp->processArcade(cmd); + break; + } + } + } + } + + break; + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + g_vars->scene37_dudeX = x; + + if (x >= 500) { + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + } else { + g_fp->_currentScene->_x = -g_fp->_sceneRect.left; + } + x = g_vars->scene37_dudeX; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + sceneHandler37_setRingsState(); + + g_fp->_behaviorManager->updateBehaviors(); + g_fp->startSceneTrack(); + + ++g_vars->scene37_soundFlipper; + + break; + + case MSG_SC37_PULL: + if (g_vars->scene37_rings[0]->ani->_movement && g_vars->scene37_rings[0]->ani->_movement->_id == MV_GRD37_PULL) { + if ((g_fp->getObjectState(sO_Guard_1) == g_fp->getObjectEnumState(sO_Guard_1, sO_On) && !g_vars->scene37_rings[0]->state) + || (g_fp->getObjectState(sO_Guard_1) == g_fp->getObjectEnumState(sO_Guard_1, sO_Off) && g_vars->scene37_rings[0]->state)) { + g_vars->scene37_plusMinus1->_statics = g_vars->scene37_plusMinus1->getStaticsById(ST_PMS_PLUS); + } else { + g_vars->scene37_plusMinus1->_statics = g_vars->scene37_plusMinus1->getStaticsById(ST_PMS_MINUS); + } + } else if (g_vars->scene37_rings[1]->ani->_movement && g_vars->scene37_rings[1]->ani->_movement->_id == MV_GRD37_PULL) { + if ((g_fp->getObjectState(sO_Guard_2) == g_fp->getObjectEnumState(sO_Guard_2, sO_On) && !g_vars->scene37_rings[1]->state) + || (g_fp->getObjectState(sO_Guard_2) == g_fp->getObjectEnumState(sO_Guard_2, sO_Off) && g_vars->scene37_rings[1]->state)) { + g_vars->scene37_plusMinus2->_statics = g_vars->scene37_plusMinus2->getStaticsById(ST_PMS_PLUS); + } else { + g_vars->scene37_plusMinus2->_statics = g_vars->scene37_plusMinus2->getStaticsById(ST_PMS_MINUS); + } + } else if (g_vars->scene37_rings[2]->ani->_movement && g_vars->scene37_rings[2]->ani->_movement->_id == MV_GRD37_PULL) { + if ((g_fp->getObjectState(sO_Guard_3) == g_fp->getObjectEnumState(sO_Guard_3, sO_On) && !g_vars->scene37_rings[2]->state) + || (g_fp->getObjectState(sO_Guard_3) == g_fp->getObjectEnumState(sO_Guard_3, sO_Off) && g_vars->scene37_rings[2]->state)) { + g_vars->scene37_plusMinus3->_statics = g_vars->scene37_plusMinus3->getStaticsById(ST_PMS_PLUS); + } else { + g_vars->scene37_plusMinus3->_statics = g_vars->scene37_plusMinus3->getStaticsById(ST_PMS_MINUS); + } + } + + if (g_vars->scene37_soundFlipper) { + g_fp->playSound(SND_37_007, 0); + + g_vars->scene37_soundFlipper = 0; + } + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/scene38.cpp b/engines/fullpipe/scenes/scene38.cpp new file mode 100644 index 0000000000..2bdae1ce66 --- /dev/null +++ b/engines/fullpipe/scenes/scene38.cpp @@ -0,0 +1,409 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + + +namespace Fullpipe { + +void scene38_setBottleState(Scene *sc) { + ExCommand *ex = sc->getMessageQueueById(QU_SC38_SHOWBOTTLE_ONTABLE)->getExCommandByIndex(0); + + if (g_vars->scene38_bottle->_ox == ex->_x && g_vars->scene38_bottle->_oy == ex->_y) { + if (g_fp->lift_checkButton(sO_Level5) ) { + ex = sc->getMessageQueueById(QU_SC38_SHOWBOTTLE)->getExCommandByIndex(0); + + g_vars->scene38_bottle->setOXY(ex->_x, ex->_y); + g_vars->scene38_bottle->_priority = ex->_field_14; + + g_fp->setObjectState(sO_Bottle_38, g_fp->getObjectEnumState(sO_Bottle_38, sO_Blocked)); + } + } +} + +void scene38_initScene(Scene *sc) { + g_vars->scene38_boss = sc->getStaticANIObject1ById(ANI_GLAVAR, -1); + g_vars->scene38_tally = sc->getStaticANIObject1ById(ANI_DYLDA, -1); + g_vars->scene38_shorty = sc->getStaticANIObject1ById(ANI_MALYSH, -1); + g_vars->scene38_domino0 = sc->getStaticANIObject1ById(ANI_DOMINO38, 0); + g_vars->scene38_dominos = sc->getStaticANIObject1ById(ANI_DOMINOS, 0); + g_vars->scene38_domino1 = sc->getStaticANIObject1ById(ANI_DOMINO38, 1); + g_vars->scene38_bottle = sc->getStaticANIObject1ById(ANI_BOTTLE38, 0); + g_vars->scene38_bossCounter = 0; + g_vars->scene38_lastBossAnim = 0; + g_vars->scene38_bossAnimCounter = 0; + g_vars->scene38_tallyCounter = 15; + g_vars->scene38_lastTallyAnim = 0; + g_vars->scene38_tallyAnimCounter = 0; + g_vars->scene38_shortyCounter = 30; + g_vars->scene38_lastShortyAnim = 0; + g_vars->scene38_shortyAnimCounter = 0; + + scene38_setBottleState(sc); + + if (g_fp->getObjectState(sO_Boss) == g_fp->getObjectEnumState(sO_Boss, sO_IsSleeping)) { + g_vars->scene38_shorty->_flags &= 0xFFFB; + + g_vars->scene38_tally->stopAnim_maybe(); + g_vars->scene38_tally->_flags &= 0xFFFB; + + g_vars->scene38_domino0->_flags &= 0xFFFB; + g_vars->scene38_dominos->_flags &= 0xFFFB; + g_vars->scene38_domino1->_flags &= 0xFFFB; + } + + g_fp->lift_init(sc, QU_SC38_ENTERLIFT, QU_SC38_EXITLIFT); + g_fp->lift_setButtonStatics(sc, ST_LBN_0N); +} + +void sceneHandler38_tryTakeBottle() { + g_vars->scene38_boss->changeStatics2(ST_GLV_NOHAMMER); + g_vars->scene38_boss->startAnim(MV_GLV_LOOKMAN, 0, -1); + + g_vars->scene38_bossCounter = 0; +} + +void sceneHandler38_postHammerKick() { + g_vars->scene38_domino1->setOXY(g_vars->scene38_domino1->_ox, g_vars->scene38_domino1->_oy + 2); +} + +void sceneHandler38_propose() { + if (!g_vars->scene38_tally->_movement) { + if (g_vars->scene38_tally->_flags & 4) { + if (!(g_vars->scene38_tally->_flags & 2) && g_vars->scene38_tallyCounter > 0 + && g_fp->_rnd->getRandomNumber(32767) < 32767) { + chainQueue(QU_DLD_DENY, 0); + g_vars->scene38_tallyCounter = 0; + } + } + } +} + +void sceneHandler38_point() { + if ((!g_vars->scene38_boss->_movement && ((g_vars->scene38_boss->_flags & 4) || !(g_vars->scene38_boss->_flags & 2))) + && g_vars->scene38_bossCounter > 0 + && g_fp->_rnd->getRandomNumber(32767) < 32767) { + if (g_vars->scene38_boss->_statics->_staticsId == ST_GLV_HAMMER) { + chainQueue(QU_GLV_TOSMALL, 0); + g_vars->scene38_bossCounter = 0; + } else { + if (g_vars->scene38_boss->_statics->_staticsId == ST_GLV_NOHAMMER) + chainQueue(QU_GLV_TOSMALL_NOHMR, 0); + + g_vars->scene38_bossCounter = 0; + } + } +} + +void sceneHandler38_hammerKick() { + if (!g_vars->scene38_shorty->_movement) { + if (g_vars->scene38_shorty->_flags & 4) { + if (!(g_vars->scene38_shorty->_flags & 2) && g_vars->scene38_shortyCounter > 1 + && g_vars->scene38_shorty->_statics->_staticsId == ST_MLS_LEFT2 + && g_fp->_rnd->getRandomNumber(32767) < 3276) { + chainQueue(QU_MLS_TURNR, 0); + g_vars->scene38_shortyCounter = 0; + } + } + } + + g_vars->scene38_domino1->setOXY(g_vars->scene38_domino1->_ox, g_vars->scene38_domino1->_oy - 2); + + if (g_vars->scene38_dominos->_statics->_staticsId == ST_DMS_3) + g_vars->scene38_dominos->startAnim(MV_DMS_THREE, 0, -1); + else if (g_vars->scene38_dominos->_statics->_staticsId == ST_DMS_4) + g_vars->scene38_dominos->startAnim(MV_DMS_FOUR, 0, -1); +} + +void sceneHandler38_drink() { + if (!g_vars->scene38_shorty->_movement) { + if (g_vars->scene38_shorty->_flags & 4) { + if (!(g_vars->scene38_shorty->_flags & 2) && g_vars->scene38_shortyCounter > 0 + && g_vars->scene38_shorty->_statics->_staticsId == ST_MLS_LEFT2 + && g_fp->_rnd->getRandomNumber(32767) < 3276) { + chainQueue(QU_MLS_TURNR, 0); + g_vars->scene38_shortyCounter = 0; + } + } + } +} + +void sceneHandler38_animateAlcoholics() { + MessageQueue *mq; + + if (g_vars->scene38_boss->_movement || !(g_vars->scene38_boss->_flags & 4) || (g_vars->scene38_boss->_flags & 2)) { + g_vars->scene38_bossCounter = 0; + } else { + g_vars->scene38_bossCounter++; + } + + if (g_vars->scene38_bossCounter >= 50) { + int bossSt = g_vars->scene38_boss->_statics->_staticsId; + + if (bossSt == ST_GLV_SLEEP2) { + g_vars->scene38_bossCounter = 0; + } else if ((g_vars->scene38_domino0->_flags & 4) && g_vars->scene38_domino0->_statics->_staticsId == ST_DMN38_6) { + if (bossSt == ST_GLV_HAMMER) { + chainQueue(QU_GLV_TAKEDOMINO, 1); + g_vars->scene38_bossCounter = 0; + } + + if (bossSt == ST_GLV_NOHAMMER) { + chainQueue(QU_GLV_TAKEDOMINO_NOHMR, 1); + g_vars->scene38_bossCounter = 0; + } + } else { + if ((g_vars->scene38_bottle->_flags & 4) && g_vars->scene38_bottle->_statics->_staticsId == ST_BTL38_FULL && bossSt == ST_GLV_NOHAMMER) { + chainQueue(QU_GLV_DRINKBOTTLE, 1); + g_vars->scene38_bossCounter = 0; + } else { + int bossAnim = 0; + + if (g_fp->_rnd->getRandomNumber(32767) >= 1310 || g_vars->scene38_boss->_statics->_staticsId != ST_GLV_HAMMER) { + if (g_fp->_rnd->getRandomNumber(32767) >= 1310) { + if (g_fp->_rnd->getRandomNumber(32767) < 1310) { + if (bossSt == ST_GLV_HAMMER) + bossAnim = QU_GLV_DRINK; + else if (bossSt == ST_GLV_NOHAMMER) + bossAnim = QU_GLV_DRINK_NOHMR; + } + } else { + if (bossSt == ST_GLV_HAMMER) + bossAnim = QU_GLV_PROPOSE; + else if (bossSt == ST_GLV_NOHAMMER) + bossAnim = QU_GLV_PROPOSE_NOHMR; + } + } else { + bossAnim = QU_GLV_HMRKICK; + } + + if (g_vars->scene38_lastBossAnim == bossAnim) { + g_vars->scene38_bossAnimCounter++; + + if (g_vars->scene38_bossAnimCounter > 2) + bossAnim = 0; + } else { + g_vars->scene38_lastBossAnim = bossAnim; + g_vars->scene38_bossAnimCounter = 1; + } + + if (bossAnim > 0) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(bossAnim), 0, 0); + + mq->chain(0); + + g_vars->scene38_bossCounter = 0; + } + } + } + } + + if (g_vars->scene38_tally->_movement || !(g_vars->scene38_tally->_flags & 4) || (g_vars->scene38_tally->_flags & 2)) { + g_vars->scene38_tallyCounter = 0; + } else { + g_vars->scene38_tallyCounter++; + } + + if (g_vars->scene38_tallyCounter >= 50) { + int tallyAnim = 0; + + if (g_fp->_rnd->getRandomNumber(32767) >= 1310) { + if (g_fp->_rnd->getRandomNumber(32767) >= 1310) { + if (g_fp->_rnd->getRandomNumber(32767) >= 1310) { + if (g_fp->_rnd->getRandomNumber(32767) < 1310) + tallyAnim = QU_DLD_ICK; + } else { + tallyAnim = QU_DLD_GLOT; + } + } else { + tallyAnim = QU_DLD_BLINK; + } + } else { + if (g_vars->scene38_domino1->_statics->_staticsId == ST_DMN38_NORM3) { + tallyAnim = QU_DLD_TAKE1; + } else if (g_vars->scene38_domino1->_statics->_staticsId == ST_DMN38_NORM4) { + tallyAnim = QU_DLD_TAKE2; + } + } + + if (g_vars->scene38_lastTallyAnim == tallyAnim) { + g_vars->scene38_tallyAnimCounter++; + + if (g_vars->scene38_tallyAnimCounter++ > 2) + tallyAnim = 0; + } else { + g_vars->scene38_lastTallyAnim = tallyAnim; + g_vars->scene38_tallyAnimCounter = 1; + } + if (tallyAnim > 0) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(tallyAnim), 0, 0); + + mq->chain(0); + g_vars->scene38_tallyCounter = 0; + } + } + + if (g_vars->scene38_shorty->_movement || !(g_vars->scene38_shorty->_flags & 4) || (g_vars->scene38_shorty->_flags & 2)) { + g_vars->scene38_shortyCounter = 0; + return; + } + + g_vars->scene38_shortyCounter++; + + if (g_vars->scene38_shortyCounter < 50) + return; + + int shortyAnim = 0; + + if (g_fp->_rnd->getRandomNumber(32767) >= 1310) { + if (g_fp->_rnd->getRandomNumber(32767) >= 1310 || g_vars->scene38_shorty->_statics->_staticsId != ST_MLS_LEFT2) { + if (g_vars->scene38_boss->_statics->_staticsId != ST_GLV_SLEEP2 && g_vars->scene38_bossCounter > 30 && g_fp->_rnd->getRandomNumber(32767) < 0x3FFF && g_vars->scene38_shorty->_statics->_staticsId == ST_MLS_LEFT2) + shortyAnim = QU_MLS_HAND; + } else { + shortyAnim = QU_MLS_BLINK; + } + } else { + if (g_vars->scene38_shorty->_statics->_staticsId == ST_MLS_RIGHT2) { + shortyAnim = QU_MLS_TURNL; + } else if (g_vars->scene38_shorty->_statics->_staticsId == ST_MLS_LEFT2) { + shortyAnim = QU_MLS_TURNR; + } + } + + if (g_vars->scene38_lastShortyAnim == shortyAnim) { + g_vars->scene38_shortyAnimCounter++; + if (g_vars->scene38_shortyAnimCounter > 2) + return; + } else { + g_vars->scene38_lastShortyAnim = shortyAnim; + g_vars->scene38_shortyAnimCounter = 1; + } + + if (shortyAnim > 0) { + mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(shortyAnim), 0, 0); + + mq->chain(0); + + g_vars->scene38_shortyCounter = 0; + } +} + +int sceneHandler38(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_LIFT_EXITLIFT: + g_fp->lift_exitSeq(cmd); + break; + + case MSG_LIFT_CLOSEDOOR: + g_fp->lift_closedoorSeq(); + break; + + case MSG_LIFT_STARTEXITQUEUE: + g_fp->lift_startExitQueue(); + break; + + case MSG_SC38_TRYTAKEBOTTLE: + sceneHandler38_tryTakeBottle(); + break; + + case MSG_SC38_POSTHMRKICK: + sceneHandler38_postHammerKick(); + break; + + case MSG_SC38_PROPOSE: + sceneHandler38_propose(); + break; + + case MSG_LIFT_CLICKBUTTON: + g_fp->lift_clickButton(); + break; + + case MSG_SC38_POINT: + sceneHandler38_point(); + break; + + case MSG_LIFT_GO: + g_fp->lift_goAnimation(); + break; + + case MSG_SC38_HMRKICK: + sceneHandler38_hammerKick(); + break; + + case MSG_SC38_DRINK: + sceneHandler38_drink(); + break; + + case 64: + g_fp->lift_hoverButton(cmd); + break; + + case 29: + { + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); + + if (ani && ani->_id == ANI_LIFTBUTTON) { + g_fp->lift_animateButton(ani); + + cmd->_messageKind = 0; + } + break; + } + + case 33: + if (g_fp->_aniMan2) { + int x = g_fp->_aniMan2->_ox; + + if (x < g_fp->_sceneRect.left + 200) + g_fp->_currentScene->_x = x - 300 - g_fp->_sceneRect.left; + + if (x > g_fp->_sceneRect.right - 200) + g_fp->_currentScene->_x = x + 300 - g_fp->_sceneRect.right; + } + + sceneHandler38_animateAlcoholics(); + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/sceneDbg.cpp b/engines/fullpipe/scenes/sceneDbg.cpp new file mode 100644 index 0000000000..bd53f5749f --- /dev/null +++ b/engines/fullpipe/scenes/sceneDbg.cpp @@ -0,0 +1,108 @@ +/* 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/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" +#include "fullpipe/input.h" + +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +void sceneDbgMenu_initScene(Scene *sc) { + g_vars->selector = sc->getPictureObjectById(PIC_SCD_SEL, 0); + getGameLoaderInteractionController()->disableFlag24(); + setInputDisabled(0); +} + +GameObject *sceneHandlerDbgMenu_getObjectAtXY(int x, int y) { + if (g_fp->_currentScene) + for (uint i = 0; i < g_fp->_currentScene->_picObjList.size(); i++) { + PictureObject *pic = (PictureObject *)g_fp->_currentScene->_picObjList[i]; + + if (x >= pic->_ox && y >= pic->_oy) { + Common::Point point; + + pic->getDimensions(&point); + + if (x <= pic->_ox + point.x && y <= pic->_oy + point.y && pic != g_vars->selector) + return pic; + } + } + + return 0; +} + +int sceneHandlerDbgMenu(ExCommand *ex) { + if (ex->_messageKind != 17) + return 0; + + int mx = g_fp->_mouseScreenPos.x + g_fp->_sceneRect.left; + int my = g_fp->_mouseScreenPos.y + g_fp->_sceneRect.top; + + if (ex->_messageNum == 29) { + GameObject *obj = sceneHandlerDbgMenu_getObjectAtXY(mx, my); + if (obj && canInteractAny(0, obj, -3) ) { + getGameLoaderInteractionController()->enableFlag24(); + handleObjectInteraction(0, obj, 0); + } + return 0; + } + if (ex->_messageNum != 33) { + if (ex->_messageNum == MSG_RESTARTGAME) { + g_fp->_needRestart = true; + return 0; + } + return 0; + } + + g_fp->_cursorId = PIC_CSR_DEFAULT; + GameObject *obj = g_fp->_currentScene->getStaticANIObjectAtPos(mx, my); + if (obj) { + if (canInteractAny(0, obj, -3)) { + g_fp->_cursorId = PIC_CSR_DEFAULT; + g_fp->setCursor(PIC_CSR_DEFAULT); + return 0; + } + } else { + obj = sceneHandlerDbgMenu_getObjectAtXY(mx, my); + if (obj && canInteractAny(0, obj, -3) ) { + g_vars->selector->_flags |= 4; + g_vars->selector->setOXY(obj->_ox, obj->_oy); + g_fp->_cursorId = PIC_CSR_DEFAULT; + g_fp->setCursor(PIC_CSR_DEFAULT); + return 0; + } + g_vars->selector->_flags &= 0xFFFB; + } + g_fp->setCursor(g_fp->_cursorId); + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/sceneFinal.cpp b/engines/fullpipe/scenes/sceneFinal.cpp new file mode 100644 index 0000000000..8b3ecb1025 --- /dev/null +++ b/engines/fullpipe/scenes/sceneFinal.cpp @@ -0,0 +1,174 @@ +/* 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/objectnames.h" +#include "fullpipe/constants.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/statics.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/behavior.h" + +#include "fullpipe/modal.h" + + +namespace Fullpipe { + +void sceneFinal_initScene() { + g_fp->_gameLoader->loadScene(SC_FINAL2); + g_fp->accessScene(SC_FINAL2)->setPictureObjectsFlag4(); + g_fp->_gameLoader->loadScene(SC_FINAL3); + g_fp->accessScene(SC_FINAL3)->setPictureObjectsFlag4(); + g_fp->_gameLoader->loadScene(SC_FINAL4); + g_fp->accessScene(SC_FINAL4)->setPictureObjectsFlag4(); + + getGameLoaderInventory()->setIsLocked(0); + getGameLoaderInventory()->slideIn(); + + g_fp->_updateFlag = 0; + g_fp->_flgCanOpenMap = 0; + + g_vars->sceneFinal_var01 = 0; + g_vars->sceneFinal_var02 = 0; + g_vars->sceneFinal_var03 = 0; +} + +int sceneFinal_updateCursor() { + if (g_vars->sceneFinal_var01) + g_fp->_cursorId = 0; + else + g_fp->updateCursorCommon(); + + return g_fp->_cursorId; +} + +void sceneHandlerFinal_endFinal() { + g_vars->sceneFinal_var01 = 0; +} + +void sceneHandlerFinal_startMusic(const char *track) { + warning("STUB: sceneHandlerFinal_startMusic()"); +} + +void sceneHandlerFinal_goto4() { + g_fp->_currentScene = g_fp->accessScene(SC_FINAL4); + + g_fp->_gameLoader->loadScene(SC_FINAL4); + + chainQueue(QU_FN4_DOFINAL, 1); +} + +void sceneHandlerFinal_goto3() { + g_fp->_currentScene = g_fp->accessScene(SC_FINAL3); + + chainQueue(QU_FN3_DOFINAL, 1); +} + +void sceneHandlerFinal_goto2() { + g_fp->_currentScene = g_fp->accessScene(SC_FINAL2); + + chainQueue(QU_FN2_DOFINAL, 1); +} + +void sceneHandlerFinal_startFinal() { + g_vars->sceneFinal_var01 = 1; + + getCurrSceneSc2MotionController()->deactivate(); + getGameLoaderInteractionController()->disableFlag24(); + + g_fp->_aniMan2 = 0; + + g_fp->_aniMan->_flags &= 0xFFFB; + + chainQueue(QU_FIN1_TAKECOIN, 1); + + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_FINAL1"), "MUSIC2", 1); + + g_fp->_modalObject = new ModalFinal; +} + +void sceneHandlerFinal_fallCoin() { + StaticANIObject *coin = g_fp->_currentScene->getStaticANIObject1ById(ANI_FIN_COIN, -1); + + if (!coin->_movement) { + if (!coin->_statics || coin->_statics->_staticsId != ST_FCN_NORM) + chainQueue(QU_FIN1_FALLCOIN, 1); + } +} + +int sceneHandlerFinal(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + switch (cmd->_messageNum) { + case MSG_FIN_ENDFINAL: + sceneHandlerFinal_endFinal(); + break; + + case MSG_FN4_STARTMUSIC: + sceneHandlerFinal_startMusic("track16.ogg"); + break; + + case MSG_FIN_GOTO4: + sceneHandlerFinal_goto4(); + + g_fp->playTrack(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_FINAL1"), "MUSIC3", 1); + break; + + case MSG_FIN_GOTO3: + sceneHandlerFinal_goto3(); + break; + + case MSG_FIN_GOTO2: + sceneHandlerFinal_goto2(); + break; + + case MSG_FIN_STARTFINAL: + sceneHandlerFinal_startFinal(); + break; + + case 33: + if (g_fp->_aniMan2) { + g_vars->sceneFinal_var03 = g_fp->_aniMan2->_ox; + + if (g_vars->sceneFinal_var03 < 450 && g_vars->sceneFinal_var02 >= 450 ) + sceneHandlerFinal_fallCoin(); + + g_vars->sceneFinal_var02 = g_vars->sceneFinal_var03; + } + + g_fp->_behaviorManager->updateBehaviors(); + + g_fp->startSceneTrack(); + + break; + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes/sceneIntro.cpp b/engines/fullpipe/scenes/sceneIntro.cpp new file mode 100644 index 0000000000..5e69cf1d7a --- /dev/null +++ b/engines/fullpipe/scenes/sceneIntro.cpp @@ -0,0 +1,110 @@ +/* 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/constants.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/motion.h" +#include "fullpipe/scenes.h" +#include "fullpipe/modal.h" +#include "fullpipe/statics.h" + +namespace Fullpipe { + +int sceneIntro_updateCursor() { + g_fp->_cursorId = 0; + + return 0; +} + +void sceneIntro_initScene(Scene *sc) { + g_fp->_gameLoader->loadScene(SC_INTRO2); + + g_vars->sceneIntro_aniin1man = sc->getStaticANIObject1ById(ANI_IN1MAN, -1); + g_vars->sceneIntro_needSleep = true; + g_vars->sceneIntro_needGetup = false; + g_vars->sceneIntro_playing = true; + g_vars->sceneIntro_needBlackout = false; + + if (g_fp->_recordEvents || g_fp->_inputArFlag) + g_vars->sceneIntro_skipIntro = false; + + g_fp->_modalObject = new ModalIntro; +} + +void sceneHandlerIntro_part1() { + g_fp->_currentScene = g_fp->accessScene(SC_INTRO1); + chainQueue(QU_INTR_FINISH, 0); +} + +void sceneHandlerIntro_part2() { + g_fp->_currentScene = g_fp->accessScene(SC_INTRO2); + chainQueue(QU_IN2_DO, 0); +} + +int sceneHandlerIntro(ExCommand *ex) { + if (ex->_messageKind != 17) + return 0; + + switch (ex->_messageNum) { + case MSG_INTR_ENDINTRO: + g_vars->sceneIntro_playing = 0; + return 0; + + case MSG_INTR_SWITCHTO1: + sceneHandlerIntro_part1(); + return 0; + + case MSG_INTR_GETUPMAN: + g_vars->sceneIntro_needSleep = 0; + g_vars->sceneIntro_needGetup = 1; + return 0; + + case MSG_INTR_SWITCHTO2: + sceneHandlerIntro_part2(); + return 0; + + case 33: + // fall through + break; + + default: + return 0; + } + + if (g_vars->sceneIntro_needSleep) { + if (!g_vars->sceneIntro_aniin1man->_movement && g_vars->sceneIntro_aniin1man->_statics->_staticsId == ST_IN1MAN_SLEEP) + g_vars->sceneIntro_aniin1man->startAnim(MV_IN1MAN_SLEEP, 0, -1); + } else if (g_vars->sceneIntro_needGetup && !g_vars->sceneIntro_aniin1man->_movement && + g_vars->sceneIntro_aniin1man->_statics->_staticsId == ST_IN1MAN_SLEEP) { + g_vars->sceneIntro_needGetup = 0; + + chainQueue(QU_INTR_GETUPMAN, 0); + } + + g_fp->startSceneTrack(); + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/sound.cpp b/engines/fullpipe/sound.cpp new file mode 100644 index 0000000000..230d6c39a9 --- /dev/null +++ b/engines/fullpipe/sound.cpp @@ -0,0 +1,527 @@ +/* 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/scene.h" +#include "fullpipe/sound.h" +#include "fullpipe/ngiarchive.h" +#include "fullpipe/messages.h" +#include "fullpipe/statics.h" + +#include "common/memstream.h" +#include "audio/audiostream.h" +#include "audio/decoders/vorbis.h" +#include "audio/decoders/wave.h" + +namespace Fullpipe { + +SoundList::SoundList() { + _soundItems = 0; + _soundItemsCount = 0; + _libHandle = 0; +} + +bool SoundList::load(MfcArchive &file, char *fname) { + debug(5, "SoundList::load()"); + + _soundItemsCount = file.readUint32LE(); + _soundItems = (Sound **)calloc(_soundItemsCount, sizeof(Sound *)); + + if (fname) { + _libHandle = (NGIArchive *)makeNGIArchive(fname); + } else { + _libHandle = 0; + } + + for (int i = 0; i < _soundItemsCount; i++) { + Sound *snd = new Sound(); + + _soundItems[i] = snd; + snd->load(file, _libHandle); + } + + return true; + +} + +bool SoundList::loadFile(const char *fname, char *libname) { + Common::File file; + + if (!file.open(fname)) + return false; + + MfcArchive archive(&file); + + return load(archive, libname); +} + +Sound *SoundList::getSoundItemById(int id) { + if (_soundItemsCount == 0) { + return _soundItems[0]->getId() != id ? 0 : _soundItems[0]; + } + + for (int i = 0; i < _soundItemsCount; i++) { + if (_soundItems[i]->getId() == id) + return _soundItems[i]; + } + return NULL; +} + +Sound::Sound() { + _id = 0; + _directSoundBuffer = 0; + _soundData = 0; + _objectId = 0; + memset(_directSoundBuffers, 0, sizeof(_directSoundBuffers)); + _description = 0; + _volume = 100; +} + +Sound::~Sound() { + freeSound(); + + free(_description); +} + +bool Sound::load(MfcArchive &file, NGIArchive *archive) { + debug(5, "Sound::load()"); + + MemoryObject::load(file); + + _id = file.readUint32LE(); + _description = file.readPascalString(); + + assert(g_fp->_gameProjectVersion >= 6); + + _objectId = file.readUint16LE(); + + if (archive && archive->hasFile(_memfilename)) { + Common::SeekableReadStream *s = archive->createReadStreamForMember(_memfilename); + + _soundData = (byte *)calloc(s->size(), 1); + + s->read(_soundData, s->size()); + + delete s; + } + + return true; +} + +void Sound::updateVolume() { + debug(3, "STUB Sound::updateVolume()"); +} + +void Sound::setPanAndVolumeByStaticAni() { + if (!_objectId) + return; + + StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(_objectId, -1); + if (!ani) + return; + + int a, b; + + if (ani->_ox >= g_fp->_sceneRect.left) { + int par, pan; + + if (ani->_ox <= g_fp->_sceneRect.right) { + int dx; + + if (ani->_oy <= g_fp->_sceneRect.bottom) { + if (ani->_oy >= g_fp->_sceneRect.top) { + setPanAndVolume(g_fp->_sfxVolume, 0); + + return; + } + dx = g_fp->_sceneRect.top - ani->_oy; + } else { + dx = ani->_oy - g_fp->_sceneRect.bottom; + } + + par = 0; + + if (dx > 800) { + setPanAndVolume(-3500, 0); + return; + } + + pan = -3500; + a = g_fp->_sfxVolume - (-3500); + b = 800 - dx; + } else { + int dx = ani->_ox - g_fp->_sceneRect.right; + + if (dx > 800) { + setPanAndVolume(-3500, 0); + return; + } + + pan = -3500; + par = dx * (-3500) / -800; + a = g_fp->_sfxVolume - (-3500); + b = 800 - dx; + } + + int32 pp = b * a; + + setPanAndVolume(pan + pp / 800, par); + + return; + } + + int dx = g_fp->_sceneRect.left - ani->_ox; + if (dx <= 800) { + int32 s = (800 - dx) * (g_fp->_sfxVolume - (-3500)); + int32 p = -3500 + s / 800; + + if (p > g_fp->_sfxVolume) + p = g_fp->_sfxVolume; + + setPanAndVolume(p, dx * (-3500) / 800); + } else { + setPanAndVolume(-3500, 0); + } +} + +void Sound::setPanAndVolume(int vol, int pan) { + g_fp->_mixer->setChannelVolume(_handle, vol / 39); // 0..10000 + g_fp->_mixer->setChannelBalance(_handle, pan / 78); // -10000..10000 +} + +void Sound::play(int flag) { + Audio::SoundHandle handle = getHandle(); + + if (g_fp->_mixer->isSoundHandleActive(handle)) + return; + + byte *soundData = loadData(); + Common::MemoryReadStream *dataStream = new Common::MemoryReadStream(soundData, getDataSize()); + Audio::RewindableAudioStream *wav = Audio::makeWAVStream(dataStream, DisposeAfterUse::YES); + Audio::AudioStream *audioStream = new Audio::LoopingAudioStream(wav, (flag == 1) ? 0 : 1); + + g_fp->_mixer->playStream(Audio::Mixer::kSFXSoundType, &handle, audioStream); +} + +void Sound::freeSound() { + stop(); + + free(_soundData); +} + +int Sound::getVolume() { + return g_fp->_mixer->getChannelVolume(_handle) * 39; // 0..10000 +} + +void Sound::stop() { + g_fp->_mixer->stopHandle(_handle); +} + +void FullpipeEngine::setSceneMusicParameters(GameVar *gvar) { + warning("STUB: FullpipeEngine::setSceneMusicParameters()"); +#if 0 + stopSoundStream2(); + + if (soundStream3) + FSOUND_Stream_Stop(soundStream4); +#endif + + if (_musicLocal) + stopAllSoundStreams(); + + GameVar *var = gvar->getSubVarByName("MUSIC"); + + memset(_sceneTracks, 0, sizeof(_sceneTracks)); + + _numSceneTracks = 0; + _sceneTrackHasSequence = false; + + if (!var) + return; + + _musicGameVar = var; + + GameVar *tr = var->getSubVarByName("TRACKS"); + if (tr) { + GameVar *sub = tr->_subVars; + + while (sub) { + if (_musicAllowed & sub->_value.intValue) { + Common::strlcpy(_sceneTracks[_numSceneTracks], sub->_varName, 260); + + _numSceneTracks++; + } + + sub = sub->_nextVarObj; + } + } + + _musicMinDelay = var->getSubVarAsInt("MINDELAY"); + _musicMaxDelay = var->getSubVarAsInt("MAXDELAY"); + _musicLocal = var->getSubVarAsInt("LOCAL"); + + GameVar *seq = var->getSubVarByName("SEQUENCE"); + + if (seq) { + _sceneTrackHasSequence = true; + + Common::strlcpy(_trackName, seq->_value.stringValue, 2600); + } + + if (_musicLocal) + stopAllSoundStreams(); + + if (!_sceneTrackIsPlaying || _musicLocal) + _trackStartDelay = var->getSubVarAsInt("STARTDELAY"); +} + +void FullpipeEngine::startSceneTrack() { + if (!_sceneTrackIsPlaying && _numSceneTracks > 0) { + if (_trackStartDelay > 0) { + _trackStartDelay--; + } else { + int trackNum = getSceneTrack(); + + if (trackNum == -1) { + strcpy(_sceneTracksCurrentTrack, "silence"); + + _trackStartDelay = 2880; + _sceneTrackIsPlaying = 0; + } else { + strcpy(_sceneTracksCurrentTrack, _sceneTracks[trackNum]); + + startSoundStream1(_sceneTracksCurrentTrack); + + _sceneTrackIsPlaying = true; + } + } + } +} + +int FullpipeEngine::getSceneTrack() { + int res; + + if (_sceneTrackHasSequence) { + int num = _musicGameVar->getSubVarAsInt("TRACKS"); + + if (_trackName[num + 1] == 's') { // 'silence' + res = -1; + } else { + res = _trackName[num + 1] - '0'; + + if (res < 0 || res >= _numSceneTracks) + res = 0; + } + + int track = num + 1; + + if (!_trackName[num + 2]) + track = 0; + + _musicGameVar->setSubVarAsInt("TRACKS", track); + } else { + res = _numSceneTracks * (_updateTicks % 10) / 10; + } + + return res; +} + +void FullpipeEngine::startSoundStream1(char *trackName) { + warning("STUB: FullpipeEngine::startSoundStream1(%s)", trackName); + + stopAllSoundStreams(); + +#ifdef USE_VORBIS + if (_mixer->isSoundHandleActive(_sceneTrackHandle)) + return; + + Common::File *track = new Common::File(); + if (!track->open(trackName)) { + warning("Could not open %s", trackName); + delete track; + return; + } + Audio::RewindableAudioStream *ogg = Audio::makeVorbisStream(track, DisposeAfterUse::YES); + _mixer->playStream(Audio::Mixer::kMusicSoundType, &_sceneTrackHandle, ogg); +#endif +} + +void FullpipeEngine::stopAllSounds() { + // _mixer->stopAll(); + + for (int i = 0; i < _currSoundListCount; i++) + for (int j = 0; j < _currSoundList1[i]->getCount(); j++) { + _currSoundList1[i]->getSoundByIndex(j)->stop(); + } +} + +void FullpipeEngine::toggleMute() { + if (_soundEnabled) { + _sfxVolume = _sfxVolume != -10000 ? -10000 : 0; + + updateSoundVolume(); + } +} + +void FullpipeEngine::playSound(int id, int flag) { + Sound *sound = 0; + + for (int i = 0; i < _currSoundListCount; i++) { + sound = _currSoundList1[i]->getSoundItemById(id); + + if (sound) + break; + } + + if (!sound) { + warning("playSound: Can't find sound with ID %d", id); + return; + } + + sound->play(flag); +} + +void FullpipeEngine::playTrack(GameVar *sceneVar, const char *name, bool delayed) { + warning("STUB: FullpipeEngine::playTrack(var, %s, %d)", name, delayed); +#if 0 + stopSoundStream2(); + + if (soundStream3) + FSOUND_Stream_Stop(soundStream4); +#endif + + if (_musicLocal) + stopAllSoundStreams(); + + GameVar *var = sceneVar->getSubVarByName(name); + + memset(_sceneTracks, 0, sizeof(_sceneTracks)); + + _numSceneTracks = 0; + _sceneTrackHasSequence = false; + + if (!var) + return; + + _musicGameVar = var; + + GameVar *tr = var->getSubVarByName("TRACKS"); + if (tr) { + GameVar *sub = tr->_subVars; + + while (sub) { + if (_musicAllowed & sub->_value.intValue) { + Common::strlcpy(_sceneTracks[_numSceneTracks], sub->_varName, 260); + + _numSceneTracks++; + } + + sub = sub->_nextVarObj; + } + } + + _musicMinDelay = var->getSubVarAsInt("MINDELAY"); + _musicMaxDelay = var->getSubVarAsInt("MAXDELAY"); + _musicLocal = var->getSubVarAsInt("LOCAL"); + + GameVar *seq = var->getSubVarByName("SEQUENCE"); + + if (seq) { + _sceneTrackHasSequence = true; + + Common::strlcpy(_trackName, seq->_value.stringValue, 2600); + } + + if (delayed) { + if (_sceneTrackIsPlaying && _numSceneTracks == 1) { + if (strcmp(_sceneTracksCurrentTrack, _sceneTracks[0])) + stopAllSoundStreams(); + } + + _trackStartDelay = var->getSubVarAsInt("STARTDELAY"); + } +} + +void global_messageHandler_handleSound(ExCommand *cmd) { + if (!g_fp->_soundEnabled) + return; + + Sound *snd = 0; + + for (int i = 0; i < g_fp->_currSoundListCount; i++) + snd = g_fp->_currSoundList1[i]->getSoundItemById(cmd->_messageNum); + + if (!snd) + return; + + if (cmd->_field_14 & 1) { + if (!g_fp->_flgSoundList && (cmd->_field_14 & 4)) + snd->freeSound(); + + snd->updateVolume(); + + if (snd->_objectId && g_fp->_currentScene->getStaticANIObject1ById(snd->_objectId, -1)) + snd->setPanAndVolumeByStaticAni(); + else + snd->setPanAndVolume(g_fp->_sfxVolume, 0); + + if (snd->getVolume() > -3500) + snd->play(cmd->_keyCode); + } else if (cmd->_field_14 & 2) { + snd->stop(); + } +} + +void FullpipeEngine::stopSoundStream2() { + warning("STUB: FullpipeEngine::stopSoundStream2()"); +} + +void FullpipeEngine::stopAllSoundStreams() { + // TODO: Differences from stopAllSounds() + _mixer->stopAll(); +} + +void FullpipeEngine::stopAllSoundInstances(int id) { + for (int i = 0; i < _currSoundListCount; i++) { + Sound *sound = _currSoundList1[i]->getSoundItemById(id); + + if (sound) + sound->stop(); + } +} + +void FullpipeEngine::updateSoundVolume() { + for (int i = 0; i < _currSoundListCount; i++) + for (int j = 0; i < _currSoundList1[i]->getCount(); j++) { + _currSoundList1[i]->getSoundByIndex(j)->setPanAndVolume(_sfxVolume, 0); + } +} + +void FullpipeEngine::setMusicVolume(int vol) { + _musicVolume = vol; + + g_fp->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/sound.h b/engines/fullpipe/sound.h new file mode 100644 index 0000000000..14e766f5bb --- /dev/null +++ b/engines/fullpipe/sound.h @@ -0,0 +1,77 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_SOUND_H +#define FULLPIPE_SOUND_H + +namespace Fullpipe { + +class Sound : public MemoryObject { + int _id; + char *_description; + int _directSoundBuffer; + int _directSoundBuffers[7]; + byte *_soundData; + Audio::SoundHandle _handle; + int _volume; + +public: + int16 _objectId; + +public: + Sound(); + virtual ~Sound(); + + virtual bool load(MfcArchive &file, NGIArchive *archive); + virtual bool load(MfcArchive &file) { assert(0); return false; } // Disable base class + void updateVolume(); + int getId() const { return _id; } + Audio::SoundHandle getHandle() const { return _handle; } + + void play(int flag); + void freeSound(); + int getVolume(); + void stop(); + + void setPanAndVolumeByStaticAni(); + void setPanAndVolume(int vol, int pan); +}; + +class SoundList : public CObject { + Sound **_soundItems; + int _soundItemsCount; + NGIArchive *_libHandle; + + public: + SoundList(); + virtual bool load(MfcArchive &file, char *fname); + virtual bool load(MfcArchive &file) { assert(0); return false; } // Disable base class + bool loadFile(const char *fname, char *libname); + + int getCount() { return _soundItemsCount; } + Sound *getSoundByIndex(int idx) { return _soundItems[idx]; } + Sound *getSoundItemById(int id); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_SOUND_H */ diff --git a/engines/fullpipe/stateloader.cpp b/engines/fullpipe/stateloader.cpp new file mode 100644 index 0000000000..141196c7d7 --- /dev/null +++ b/engines/fullpipe/stateloader.cpp @@ -0,0 +1,366 @@ +/* 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 "common/file.h" +#include "common/array.h" +#include "common/list.h" + +#include "fullpipe/objects.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/scene.h" +#include "fullpipe/statics.h" +#include "fullpipe/interaction.h" +#include "fullpipe/gameloader.h" + +#include "fullpipe/constants.h" + +namespace Fullpipe { + +bool FullpipeEngine::loadGam(const char *fname, int scene) { + _gameLoader = new GameLoader(); + + if (!_gameLoader->loadFile(fname)) + return false; + + _currSoundListCount = 0; + initObjectStates(); + // set_g_messageQueueCallback1(messageQueueCallback1); // substituted with direct call + + addMessageHandlerByIndex(global_messageHandler1, 0, 4); + + _inventory = getGameLoaderInventory(); + _inventory->setItemFlags(ANI_INV_MAP, 0x10003); + _inventory->addItem(ANI_INV_MAP, 1); + + _inventory->rebuildItemRects(); + + for (uint i = 0; i < _inventory->getScene()->_picObjList.size(); i++) + ((MemoryObject *)_inventory->getScene()->_picObjList[i]->_picture)->load(); + + // _sceneSwitcher = sceneSwitcher; // substituted with direct call + _gameLoader->_preloadCallback = preloadCallback; + // _readSavegameCallback = gameLoaderReadSavegameCallback; // TODO + + _aniMan = accessScene(SC_COMMON)->getAniMan(); + _scene2 = 0; + + _movTable = _aniMan->countMovements(); + + _aniMan->setSpeed(1); + + PictureObject *pic = accessScene(SC_INV)->getPictureObjectById(PIC_INV_MENU, 0); + + pic->setFlags(pic->_flags & 0xFFFB); + + // Not used in full game + //_evalVersionPic = accessScene(SC_COMMON)->getPictureObjectById(PIC_CMN_EVAL, 0); + + initMap(); + initCursors(); + + setMusicAllowed(_gameLoader->_gameVar->getSubVarAsInt("MUSIC_ALLOWED")); + + if (scene) { + _gameLoader->loadScene(726); + _gameLoader->gotoScene(726, TrubaLeft); + + if (scene != 726) + _gameLoader->preloadScene(726, getSceneEntrance(scene)); + } else { + if (_flgPlayIntro) { + _gameLoader->loadScene(SC_INTRO1); + _gameLoader->gotoScene(SC_INTRO1, TrubaUp); + } else { + _gameLoader->loadScene(SC_1); + _gameLoader->gotoScene(SC_1, TrubaLeft); + } + } + + if (!_currentScene) + return false; + + return true; +} + +GameProject::GameProject() { + _field_4 = 0; + _headerFilename = 0; + _field_10 = 12; + + _sceneTagList = 0; +} + +bool GameProject::load(MfcArchive &file) { + debug(5, "GameProject::load()"); + + _field_4 = 0; + _headerFilename = 0; + _field_10 = 12; + + g_fp->_gameProjectVersion = file.readUint32LE(); + g_fp->_pictureScale = file.readUint16LE(); + g_fp->_scrollSpeed = file.readUint32LE(); + + _headerFilename = file.readPascalString(); + + debug(1, "_gameProjectVersion = %d", g_fp->_gameProjectVersion); + debug(1, "_pictureScale = %d", g_fp->_pictureScale); + debug(1, "_scrollSpeed = %d", g_fp->_scrollSpeed); + debug(1, "_headerFilename = %s", _headerFilename); + + _sceneTagList = new SceneTagList(); + + _sceneTagList->load(file); + + if (g_fp->_gameProjectVersion >= 3) + _field_4 = file.readUint32LE(); + + if (g_fp->_gameProjectVersion >= 5) { + file.readUint32LE(); + file.readUint32LE(); + } + + return true; +} + +GameProject::~GameProject() { + free(_headerFilename); + + delete _sceneTagList; +} + +GameVar::GameVar() { + _subVars = 0; + _parentVarObj = 0; + _nextVarObj = 0; + _prevVarObj = 0; + _field_14 = 0; + _varType = 0; + _value.floatValue = 0; + _varName = 0; +} + +GameVar::~GameVar() { + if (_varType == 2) + free(_value.stringValue); + + if (_parentVarObj && !_prevVarObj ) { + if (_parentVarObj->_subVars == this) { + _parentVarObj->_subVars = _nextVarObj; + } else if (_parentVarObj->_field_14 == this) { + _parentVarObj->_field_14 = _nextVarObj; + } else { + _parentVarObj = 0; + } + } + + if (_prevVarObj) + _prevVarObj->_nextVarObj = _nextVarObj; + + if (_nextVarObj) + _nextVarObj->_prevVarObj = _prevVarObj; + + _prevVarObj = 0; + _nextVarObj = 0; + + GameVar *s = _subVars; + + while (s) { + delete s; + s = _subVars; + } + + s = _field_14; + + while (s) { + delete s; + s = _field_14; + } + + free(_varName); +} + +bool GameVar::load(MfcArchive &file) { + _varName = file.readPascalString(); + _varType = file.readUint32LE(); + + debugN(6, "[%03d] ", file.getLevel()); + for (int i = 0; i < file.getLevel(); i++) + debugN(6, " "); + + debugN(6, "<%s>: ", transCyrillic((byte *)_varName)); + + switch (_varType) { + case 0: + _value.intValue = file.readUint32LE(); + debug(6, "d --> %d", _value.intValue); + break; + case 1: + _value.intValue = file.readUint32LE(); // FIXME + debug(6, "f --> %f", _value.floatValue); + break; + case 2: + _value.stringValue = file.readPascalString(); + debug(6, "s --> %s", _value.stringValue); + break; + default: + error("Unknown var type: %d (0x%x)", _varType, _varType); + } + + file.incLevel(); + _parentVarObj = (GameVar *)file.readClass(); + _prevVarObj = (GameVar *)file.readClass(); + _nextVarObj = (GameVar *)file.readClass(); + _field_14 = (GameVar *)file.readClass(); + _subVars = (GameVar *)file.readClass(); + file.decLevel(); + + return true; +} + +GameVar *GameVar::getSubVarByName(const char *name) { + GameVar *sv = 0; + + if (_subVars != 0) { + sv = _subVars; + for (;sv && scumm_stricmp(sv->_varName, name); sv = sv->_nextVarObj) + ; + } + return sv; +} + +bool GameVar::setSubVarAsInt(const char *name, int value) { + GameVar *var = getSubVarByName(name); + + if (var) { + if (var->_varType == 0) { + var->_value.intValue = value; + + return true; + } + return false; + } + + var = new GameVar(); + var->_varType = 0; + var->_value.intValue = value; + var->_varName = (char *)calloc(strlen(name) + 1, 1); + strcpy(var->_varName, name); + + return addSubVar(var); +} + +int GameVar::getSubVarAsInt(const char *name) { + GameVar *var = getSubVarByName(name); + + if (var) + return var->_value.intValue; + else + return 0; +} + +GameVar *GameVar::addSubVarAsInt(const char *name, int value) { + if (getSubVarByName(name)) { + return 0; + } else { + GameVar *var = new GameVar(); + + var->_varType = 0; + var->_value.intValue = value; + + var->_varName = (char *)calloc(strlen(name) + 1, 1); + strcpy(var->_varName, name); + + return (addSubVar(var) != 0) ? var : 0; + } +} + +bool GameVar::addSubVar(GameVar *subvar) { + GameVar *var = _subVars; + + if (var) { + for (GameVar *i = var->_nextVarObj; i; i = i->_nextVarObj) + var = i; + + var->_nextVarObj = subvar; + subvar->_prevVarObj = var; + subvar->_parentVarObj = this; + + return true; + } else { + _subVars = subvar; + subvar->_parentVarObj = this; + + return true; + } + + return false; +} + +int GameVar::getSubVarsCount() { + int res; + GameVar *sub = _subVars; + + for (res = 0; sub; res++) + sub = sub->_nextVarObj; + + return res; +} + +GameVar *GameVar::getSubVarByIndex(int idx) { + GameVar *sub = _subVars; + + while (idx--) { + sub = sub->_nextVarObj; + + if (!sub) + return 0; + } + + return sub; +} + +bool PicAniInfo::load(MfcArchive &file) { + debug(5, "PicAniInfo::load()"); + + type = file.readUint32LE(); + objectId = file.readUint16LE(); + field_6 = file.readUint16LE(); + field_8 = file.readUint32LE(); + sceneId = file.readUint16LE(); + field_E = file.readUint16LE(); + ox = file.readUint32LE(); + oy = file.readUint32LE(); + priority = file.readUint32LE(); + staticsId = file.readUint16LE(); + movementId = file.readUint16LE(); + dynamicPhaseIndex = file.readUint16LE(); + flags = file.readUint16LE(); + field_24 = file.readUint32LE(); + someDynamicPhaseIndex = file.readUint32LE(); + + return true; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp new file mode 100644 index 0000000000..de3e1ea728 --- /dev/null +++ b/engines/fullpipe/statics.cpp @@ -0,0 +1,2305 @@ +/* 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)); + + _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; + + _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 diff --git a/engines/fullpipe/statics.h b/engines/fullpipe/statics.h new file mode 100644 index 0000000000..c7baac7502 --- /dev/null +++ b/engines/fullpipe/statics.h @@ -0,0 +1,273 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_STATICS_H +#define FULLPIPE_STATICS_H + +#include "fullpipe/gfx.h" + +namespace Fullpipe { + +class ExCommand; + +class StepArray : public CObject { + int _currPointIndex; + Common::Point **_points; + int _maxPointIndex; + int _pointsCount; + int _isEos; + + public: + StepArray(); + ~StepArray(); + void clear(); + + int getCurrPointIndex() { return _currPointIndex; } + int getPointsCount() { return _maxPointIndex; } + + Common::Point *getCurrPoint(Common::Point *point); + Common::Point *getPoint(Common::Point *point, int index, int offset); + bool gotoNextPoint(); + void insertPoints(Common::Point **points, int pointsCount); +}; + +class StaticPhase : public Picture { + public: + int16 _initialCountdown; + int16 _countdown; + int16 _field_68; + int16 _field_6A; + ExCommand *_exCommand; + + public: + StaticPhase(); + virtual ~StaticPhase(); + + virtual bool load(MfcArchive &file); + + ExCommand *getExCommand() { return _exCommand; } +}; + +class DynamicPhase : public StaticPhase { + public: + int _someX; + int _someY; + Common::Rect *_rect; + int16 _field_7C; + int16 _field_7E; + int _dynFlags; + + public: + DynamicPhase(); + DynamicPhase(DynamicPhase *src, bool reverse); + virtual ~DynamicPhase(); + + virtual bool load(MfcArchive &file); + + int getDynFlags() { return _dynFlags; } +}; + +class Statics : public DynamicPhase { + public: + int16 _staticsId; + char *_staticsName; + Picture *_picture; + + public: + Statics(); + Statics(Statics *src, bool reverse); + virtual ~Statics(); + + virtual bool load(MfcArchive &file); + virtual void init(); + Statics *getStaticsById(int itemId); + + Common::Point *getSomeXY(Common::Point &p); + Common::Point *getCenter(Common::Point *p); +}; + +class StaticANIObject; + +class Movement : public GameObject { + public: + Common::Point _somePoint; + int _lastFrameSpecialFlag; + int _flipFlag; + int _updateFlag1; + Statics *_staticsObj1; + Statics *_staticsObj2; + int _mx; + int _my; + int _m2x; + int _m2y; + int _field_50; + int _counterMax; + int _counter; + Common::Array<DynamicPhase *> _dynamicPhases; + int _field_78; + Common::Point **_framePosOffsets; + Movement *_currMovement; + int _field_84; + DynamicPhase *_currDynamicPhase; + int _field_8C; + int _currDynamicPhaseIndex; + int _field_94; + + public: + Movement(); + virtual ~Movement(); + + Movement(Movement *src, StaticANIObject *ani); + Movement(Movement *src, int *flag1, int flag2, StaticANIObject *ani); + + virtual bool load(MfcArchive &file); + bool load(MfcArchive &file, StaticANIObject *ani); + + Common::Point *getCurrDynamicPhaseXY(Common::Point &p); + Common::Point *getCenter(Common::Point *p); + Common::Point *getDimensionsOfPhase(Common::Point *p, int phaseIndex); + + Common::Point *calcSomeXY(Common::Point &p, int idx, int dynidx); + + void initStatics(StaticANIObject *ani); + void updateCurrDynamicPhase(); + + void setAlpha(int alpha); + + void setDynamicPhaseIndex(int index); + DynamicPhase *getDynamicPhaseByIndex(int idx); + + int calcDuration(); + int countPhasesWithFlag(int maxidx, int flag); + + void removeFirstPhase(); + bool gotoNextFrame(void (*_callback1)(int, Common::Point *point, int, int), void (*callback2)(int *)); + bool gotoPrevFrame(); + void gotoFirstFrame(); + void gotoLastFrame(); + + void loadPixelData(); + void freePixelData(); + + void draw(bool flipFlag, int angle); +}; + +class StaticANIObject : public GameObject { + public: + Movement *_movement; + Statics *_statics; + int _shadowsOn; + int16 _field_30; + int16 _field_32; + int _field_34; + int _initialCounter; + void (*_callback1)(int, Common::Point *point, int, int); + void (*_callback2)(int *); + Common::Array<Movement *> _movements; + Common::Array<Statics *> _staticsList; + StepArray _stepArray; + int16 _field_96; + int _messageQueueId; + int _messageNum; + int _animExFlag; + int _counter; + int _someDynamicPhaseIndex; + +public: + int16 _sceneId; + +public: + StaticANIObject(); + virtual ~StaticANIObject(); + StaticANIObject(StaticANIObject *src); + + virtual bool load(MfcArchive &file); + + void setOXY(int x, int y); + Statics *getStaticsById(int id); + Statics *getStaticsByName(char *name); + Movement *getMovementById(int id); + int getMovementIdById(int itemId); + Movement *getMovementByName(char *name); + Common::Point *getCurrDimensions(Common::Point &p); + + Common::Point *getSomeXY(Common::Point &p); + + void clearFlags(); + void setFlags40(bool state); + bool isIdle(); + void setAlpha(int alpha); + + void deleteFromGlobalMessageQueue(); + bool queueMessageQueue(MessageQueue *msg); + void restartMessageQueue(MessageQueue *msg); + MessageQueue *getMessageQueue(); + bool trySetMessageQueue(int msgNum, int qId); + void startMQIfIdle(int qId, int flag); + + void initMovements(); + void loadMovementsPixelData(); + void freeMovementsPixelData(); + void preloadMovements(MovTable *mt); + + void setSomeDynamicPhaseIndex(int val) { _someDynamicPhaseIndex = val; } + void adjustSomeXY(); + + bool startAnim(int movementId, int messageQueueId, int dynPhaseIdx); + bool startAnimEx(int movid, int parId, int flag1, int flag2); + void startAnimSteps(int movementId, int messageQueueId, int x, int y, Common::Point **points, int pointsCount, int someDynamicPhaseIndex); + + void hide(); + void show1(int x, int y, int movementId, int mqId); + void show2(int x, int y, int movementId, int mqId); + void playIdle(); + void update(int counterdiff); + + Statics *addReverseStatics(Statics *ani); + void draw(); + void draw2(); + + MovTable *countMovements(); + Common::Point *calcStepLen(Common::Point *p); + void setSpeed(int speed); + + void updateStepPos(); + void stopAnim_maybe(); + Common::Point *calcNextStep(Common::Point *point); + + MessageQueue *changeStatics1(int msgNum); + void changeStatics2(int objId); + + bool getPixelAtPos(int x, int y, int *pixel); +}; + +struct MovTable { + int count; + int16 *movs; + + MovTable() { count = 0; movs = 0; } + ~MovTable() { free(movs); } +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_STATICS_H */ diff --git a/engines/fullpipe/utils.cpp b/engines/fullpipe/utils.cpp new file mode 100644 index 0000000000..0cc8bd83f4 --- /dev/null +++ b/engines/fullpipe/utils.cpp @@ -0,0 +1,501 @@ +/* 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 "common/file.h" +#include "common/memstream.h" + +#include "fullpipe/objects.h" +#include "fullpipe/motion.h" +#include "fullpipe/ngiarchive.h" +#include "fullpipe/messages.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +bool CObject::loadFile(const char *fname) { + Common::File file; + + if (!file.open(fname)) + return false; + + MfcArchive archive(&file); + + return load(archive); +} + +bool ObList::load(MfcArchive &file) { + debug(5, "ObList::load()"); + int count = file.readCount(); + + debug(9, "ObList::count: %d:", count); + + for (int i = 0; i < count; i++) { + debug(9, "ObList::[%d]", i); + CObject *t = file.readClass(); + + push_back(t); + } + + return true; +} + +bool ObArray::load(MfcArchive &file) { + debug(5, "ObArray::load()"); + int count = file.readCount(); + + resize(count); + + for (int i = 0; i < count; i++) { + CObject *t = file.readClass(); + + push_back(*t); + } + + return true; +} + +bool DWordArray::load(MfcArchive &file) { + debug(5, "DWordArray::load()"); + int count = file.readCount(); + + debug(9, "DWordArray::count: %d", count); + + resize(count); + + for (int i = 0; i < count; i++) { + int32 t = file.readUint32LE(); + + push_back(t); + } + + return true; +} + +char *MfcArchive::readPascalString(bool twoByte) { + char *tmp; + int len; + + if (twoByte) + len = readUint16LE(); + else + len = readByte(); + + tmp = (char *)calloc(len + 1, 1); + read(tmp, len); + + debug(9, "readPascalString: %d <%s>", len, transCyrillic((byte *)tmp)); + + return tmp; +} + +MemoryObject::MemoryObject() { + _memfilename = 0; + _mfield_8 = 0; + _mfield_C = 0; + _mfield_10 = -1; + _mfield_14 = 1; + _dataSize = 0; + _mflags = 0; + _libHandle = 0; + _data = 0; +} + +MemoryObject::~MemoryObject() { + freeData(); + if (_memfilename) + free(_memfilename); +} + +bool MemoryObject::load(MfcArchive &file) { + debug(5, "MemoryObject::load()"); + _memfilename = file.readPascalString(); + + if (char *p = strchr(_memfilename, '\\')) { + for (char *d = _memfilename; *p;) { + p++; + *d++ = *p; + } + } + + if (g_fp->_currArchive) { + _mfield_14 = 0; + _libHandle = g_fp->_currArchive; + } + + return true; +} + +void MemoryObject::loadFile(char *filename) { + debug(5, "MemoryObject::loadFile(<%s>)", filename); + + if (!*filename) + return; + + if (!_data) { + NGIArchive *arr = g_fp->_currArchive; + + if (g_fp->_currArchive != _libHandle && _libHandle) + g_fp->_currArchive = _libHandle; + + Common::SeekableReadStream *s = g_fp->_currArchive->createReadStreamForMember(filename); + + if (s) { + assert(s->size() > 0); + + _dataSize = s->size(); + + debug(5, "Loading %s (%d bytes)", filename, _dataSize); + _data = (byte *)calloc(_dataSize, 1); + s->read(_data, _dataSize); + + delete s; + } else { + warning("MemoryObject::loadFile(): reading failure"); + } + + g_fp->_currArchive = arr; + } +} + +byte *MemoryObject::getData() { + load(); + + if (_mfield_14 || _mflags & 1) { + return _data; + } else { + error("Unhandled packed data"); + } +} + +byte *MemoryObject::loadData() { + load(); + return _data; +} + +void MemoryObject::freeData() { + debug(8, "MemoryObject::freeData(): file: %s", _memfilename); + + if (_data) + free(_data); + + _data = 0; +} + +bool MemoryObject::testFlags() { + if (_mfield_8) + return false; + + if (_mflags & 1) + return true; + + return false; +} + +MemoryObject2::MemoryObject2() { + _rows = 0; +} + +MemoryObject2::~MemoryObject2() { + if (_rows) + free(_rows); +} + +bool MemoryObject2::load(MfcArchive &file) { + debug(5, "MemoryObject2::load()"); + MemoryObject::load(file); + + _mflags |= 1; + + debug(5, "MemoryObject2::load: <%s>", _memfilename); + + if (_memfilename && *_memfilename) { + MemoryObject::loadFile(_memfilename); + } + + return true; +} + +void MemoryObject2::copyData(byte *src, int dataSize) { + if (_data) + freeData(); + + _dataSize = dataSize; + _data = (byte *)malloc(dataSize); + + memcpy(_data, src, _dataSize); +} + +int MfcArchive::readCount() { + int count = readUint16LE(); + + if (count == 0xffff) + count = readUint32LE(); + + return count; +} + +double MfcArchive::readDouble() { + // FIXME: This is utterly cruel and unportable + // Some articles on the matter: + // http://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability/ + // http://randomascii.wordpress.com/2012/01/11/tricks-with-the-floating-point-format/ + + union { + struct { + int32 a; + int32 b; + } i; + double d; + } tmp; + + tmp.i.a = readUint32LE(); + tmp.i.b = readUint32LE(); + + return tmp.d; +} + +enum { + kNullObject, + kInteraction, + kMessageQueue, + kExCommand, + kObjstateCommand, + kGameVar, + kMctlCompound, + kMovGraph, + kMovGraphLink, + kMovGraphNode, + kReactParallel, + kReactPolygonal +}; + +const struct { + const char *name; + int id; +} classMap[] = { + { "CInteraction", kInteraction }, + { "MessageQueue", kMessageQueue }, + { "ExCommand", kExCommand }, + { "CObjstateCommand", kObjstateCommand }, + { "CGameVar", kGameVar }, + { "CMctlCompound", kMctlCompound }, + { "CMovGraph", kMovGraph }, + { "CMovGraphLink", kMovGraphLink }, + { "CMovGraphNode", kMovGraphNode }, + { "CReactParallel", kReactParallel }, + { "CReactPolygonal", kReactPolygonal }, + { 0, 0 } +}; + +static const char *lookupObjectId(int id) { + for (int i = 0; classMap[i].name; i++) { + if (classMap[i].id == id) + return classMap[i].name; + } + + return ""; +} + +static CObject *createObject(int objectId) { + switch (objectId) { + case kNullObject: + return 0; + case kInteraction: + return new Interaction(); + case kMessageQueue: + return new MessageQueue(); + case kExCommand: + return new ExCommand(); + case kObjstateCommand: + return new ObjstateCommand(); + case kGameVar: + return new GameVar(); + case kMctlCompound: + return new MctlCompound(); + case kMovGraph: + return new MovGraph(); + case kMovGraphLink: + return new MovGraphLink(); + case kMovGraphNode: + return new MovGraphNode(); + case kReactParallel: + return new ReactParallel(); + case kReactPolygonal: + return new ReactPolygonal(); + default: + error("Unknown objectId: %d", objectId); + } + + return 0; +} + +MfcArchive::MfcArchive(Common::SeekableReadStream *stream) { + for (int i = 0; classMap[i].name; i++) { + _classMap[classMap[i].name] = classMap[i].id; + } + + _lastIndex = 1; + _level = 0; + + _stream = stream; + + _objectMap.push_back(0); + _objectIdMap.push_back(kNullObject); +} + +CObject *MfcArchive::readClass() { + bool isCopyReturned; + CObject *res = parseClass(&isCopyReturned); + + if (res && !isCopyReturned) + res->load(*this); + + return res; +} + +CObject *MfcArchive::parseClass(bool *isCopyReturned) { + char *name; + int objectId = 0; + CObject *res = 0; + + uint obTag = readUint16LE(); + + debug(7, "parseClass::obTag = %d (%04x) at 0x%08x", obTag, obTag, pos() - 2); + + if (obTag == 0xffff) { + int schema = readUint16LE(); + + debug(7, "parseClass::schema = %d", schema); + + name = readPascalString(true); + debug(7, "parseClass::class <%s>", name); + + if (!_classMap.contains(name)) { + error("Unknown class in MfcArchive: <%s>", name); + } + + objectId = _classMap[name]; + + debug(7, "tag: %d 0x%x (%x)", _objectMap.size() - 1, _objectMap.size() - 1, objectId); + + res = createObject(objectId); + _objectMap.push_back(res); + _objectIdMap.push_back(objectId); + + _objectMap.push_back(res); // Basically a hack, but behavior is all correct + _objectIdMap.push_back(objectId); + + *isCopyReturned = false; + } else if ((obTag & 0x8000) == 0) { + if (_objectMap.size() < obTag) { + error("Object index too big: %d at 0x%08x", obTag, pos() - 2); + } + debug(7, "parseClass::obTag <%s>", lookupObjectId(_objectIdMap[obTag])); + + res = _objectMap[obTag]; + + *isCopyReturned = true; + } else { + + obTag &= ~0x8000; + + if (_objectMap.size() < obTag) { + error("Object index too big: %d at 0x%08x", obTag, pos() - 2); + } + + debug(7, "parseClass::obTag <%s>", lookupObjectId(_objectIdMap[obTag])); + + objectId = _objectIdMap[obTag]; + + res = createObject(objectId); + _objectMap.push_back(res); + _objectIdMap.push_back(objectId); + + *isCopyReturned = false; + } + + return res; +} + +char *genFileName(int superId, int sceneId, const char *ext) { + char *s = (char *)calloc(256, 1); + + if (superId) { + snprintf(s, 255, "%04d%04d.%s", superId, sceneId, ext); + } else { + snprintf(s, 255, "%04d.%s", sceneId, ext); + } + + debug(7, "genFileName: %s", s); + + return s; +} + +// Translates cp-1251..utf-8 +byte *transCyrillic(byte *s) { + static byte tmp[1024]; + + static int trans[] = { 0xa8, 0xd081, 0xb8, 0xd191, 0xc0, 0xd090, + 0xc1, 0xd091, 0xc2, 0xd092, 0xc3, 0xd093, 0xc4, 0xd094, + 0xc5, 0xd095, 0xc6, 0xd096, 0xc7, 0xd097, 0xc8, 0xd098, + 0xc9, 0xd099, 0xca, 0xd09a, 0xcb, 0xd09b, 0xcc, 0xd09c, + 0xcd, 0xd09d, 0xce, 0xd09e, 0xcf, 0xd09f, 0xd0, 0xd0a0, + 0xd1, 0xd0a1, 0xd2, 0xd0a2, 0xd3, 0xd0a3, 0xd4, 0xd0a4, + 0xd5, 0xd0a5, 0xd6, 0xd0a6, 0xd7, 0xd0a7, 0xd8, 0xd0a8, + 0xd9, 0xd0a9, 0xda, 0xd0aa, 0xdb, 0xd0ab, 0xdc, 0xd0ac, + 0xdd, 0xd0ad, 0xde, 0xd0ae, 0xdf, 0xd0af, 0xe0, 0xd0b0, + 0xe1, 0xd0b1, 0xe2, 0xd0b2, 0xe3, 0xd0b3, 0xe4, 0xd0b4, + 0xe5, 0xd0b5, 0xe6, 0xd0b6, 0xe7, 0xd0b7, 0xe8, 0xd0b8, + 0xe9, 0xd0b9, 0xea, 0xd0ba, 0xeb, 0xd0bb, 0xec, 0xd0bc, + 0xed, 0xd0bd, 0xee, 0xd0be, 0xef, 0xd0bf, 0xf0, 0xd180, + 0xf1, 0xd181, 0xf2, 0xd182, 0xf3, 0xd183, 0xf4, 0xd184, + 0xf5, 0xd185, 0xf6, 0xd186, 0xf7, 0xd187, 0xf8, 0xd188, + 0xf9, 0xd189, 0xfa, 0xd18a, 0xfb, 0xd18b, 0xfc, 0xd18c, + 0xfd, 0xd18d, 0xfe, 0xd18e, 0xff, 0xd18f }; + + int i = 0; + + for (byte *p = s; *p; p++) { + if (*p < 128) { + tmp[i++] = *p; + } else { + int j; + for (j = 0; trans[j]; j += 2) { + if (trans[j] == *p) { + tmp[i++] = (trans[j + 1] >> 8) & 0xff; + tmp[i++] = trans[j + 1] & 0xff; + break; + } + } + + assert(trans[j]); + } + } + + tmp[i] = 0; + + return tmp; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/utils.h b/engines/fullpipe/utils.h new file mode 100644 index 0000000000..da3ab7ee4f --- /dev/null +++ b/engines/fullpipe/utils.h @@ -0,0 +1,157 @@ +/* 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. + * + */ + +#ifndef FULLPIPE_UTILS_H +#define FULLPIPE_UTILS_H + +#include "common/hash-str.h" +#include "common/array.h" +#include "common/file.h" + +namespace Fullpipe { + +class CObject; +class NGIArchive; + +typedef Common::HashMap<Common::String, int, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ClassMap; + +class MfcArchive : public Common::SeekableReadStream { + ClassMap _classMap; + Common::Array<CObject *> _objectMap; + Common::Array<int> _objectIdMap; + + int _lastIndex; + int _level; + + Common::SeekableReadStream *_stream; + + public: + MfcArchive(Common::SeekableReadStream *file); + + char *readPascalString(bool twoByte = false); + int readCount(); + double readDouble(); + CObject *parseClass(bool *isCopyReturned); + CObject *readClass(); + + void incLevel() { _level++; } + void decLevel() { _level--; } + int getLevel() { return _level; } + + virtual bool eos() const { return _stream->eos(); } + virtual uint32 read(void *dataPtr, uint32 dataSize) { return _stream->read(dataPtr, dataSize); } + virtual int32 pos() const { return _stream->pos(); } + virtual int32 size() const { return _stream->size(); } + virtual bool seek(int32 offset, int whence = SEEK_SET) { return _stream->seek(offset, whence); } +}; + +enum ObjType { + kObjTypeDefault, + kObjTypeExCommand, + kObjTypeExCommand2, + kObjTypeModalSaveGame, + kObjTypeMovGraph, + kObjTypeMovGraphLink, + kObjTypeMovGraphNode, + kObjTypeMctlCompound, + kObjTypeObjstateCommand, + kObjTypePictureObject, + kObjTypeStaticANIObject +}; + +class CObject { +public: + ObjType _objtype; + + CObject() : _objtype(kObjTypeDefault) {} + virtual bool load(MfcArchive &in) { return true; } + virtual ~CObject() {} + + bool loadFile(const char *fname); +}; + +class ObList : public Common::List<CObject *>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class MemoryObject : CObject { + friend class Picture; + friend class Scene; + + protected: + char *_memfilename; + int _mfield_8; + int _mfield_C; + int _mfield_10; + char _mfield_14; + byte *_data; + int _dataSize; + int _mflags; + NGIArchive *_libHandle; + + public: + MemoryObject(); + virtual ~MemoryObject(); + + virtual bool load(MfcArchive &file); + void loadFile(char *filename); + void load() { loadFile(_memfilename); } + byte *getData(); + byte *loadData(); + int getDataSize() const { return _dataSize; } + + bool testFlags(); + + void freeData(); +}; + +class MemoryObject2 : public MemoryObject { + friend class Picture; + + protected: + byte **_rows; + + public: + MemoryObject2(); + virtual ~MemoryObject2(); + virtual bool load(MfcArchive &file); + + void copyData(byte *src, int dataSize); +}; + +class ObArray : public Common::Array<CObject>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class DWordArray : public Common::Array<int32>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +char *genFileName(int superId, int sceneId, const char *ext); +byte *transCyrillic(byte *s); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_UTILS_H */ |
