aboutsummaryrefslogtreecommitdiff
path: root/engines/fullpipe
diff options
context:
space:
mode:
Diffstat (limited to 'engines/fullpipe')
-rw-r--r--engines/fullpipe/behavior.cpp359
-rw-r--r--engines/fullpipe/behavior.h90
-rw-r--r--engines/fullpipe/configure.engine3
-rw-r--r--engines/fullpipe/console.cpp52
-rw-r--r--engines/fullpipe/console.h42
-rw-r--r--engines/fullpipe/constants.h1699
-rw-r--r--engines/fullpipe/detection.cpp170
-rw-r--r--engines/fullpipe/floaters.cpp255
-rw-r--r--engines/fullpipe/floaters.h75
-rw-r--r--engines/fullpipe/fullpipe.cpp547
-rw-r--r--engines/fullpipe/fullpipe.h331
-rw-r--r--engines/fullpipe/gameloader.cpp690
-rw-r--r--engines/fullpipe/gameloader.h134
-rw-r--r--engines/fullpipe/gfx.cpp1278
-rw-r--r--engines/fullpipe/gfx.h227
-rw-r--r--engines/fullpipe/init.cpp247
-rw-r--r--engines/fullpipe/input.cpp376
-rw-r--r--engines/fullpipe/input.h77
-rw-r--r--engines/fullpipe/interaction.cpp545
-rw-r--r--engines/fullpipe/interaction.h101
-rw-r--r--engines/fullpipe/inventory.cpp472
-rw-r--r--engines/fullpipe/inventory.h138
-rw-r--r--engines/fullpipe/lift.cpp518
-rw-r--r--engines/fullpipe/messagehandlers.cpp800
-rw-r--r--engines/fullpipe/messages.cpp975
-rw-r--r--engines/fullpipe/messages.h205
-rw-r--r--engines/fullpipe/mgm.cpp720
-rw-r--r--engines/fullpipe/mgm.h95
-rw-r--r--engines/fullpipe/modal.cpp1817
-rw-r--r--engines/fullpipe/modal.h295
-rw-r--r--engines/fullpipe/module.mk75
-rw-r--r--engines/fullpipe/motion.cpp3053
-rw-r--r--engines/fullpipe/motion.h419
-rw-r--r--engines/fullpipe/ngiarchive.cpp156
-rw-r--r--engines/fullpipe/ngiarchive.h69
-rw-r--r--engines/fullpipe/objectnames.h259
-rw-r--r--engines/fullpipe/objects.h99
-rw-r--r--engines/fullpipe/scene.cpp806
-rw-r--r--engines/fullpipe/scene.h111
-rw-r--r--engines/fullpipe/scenes.cpp1511
-rw-r--r--engines/fullpipe/scenes.h708
-rw-r--r--engines/fullpipe/scenes/scene01.cpp118
-rw-r--r--engines/fullpipe/scenes/scene02.cpp138
-rw-r--r--engines/fullpipe/scenes/scene03.cpp295
-rw-r--r--engines/fullpipe/scenes/scene04.cpp1565
-rw-r--r--engines/fullpipe/scenes/scene05.cpp386
-rw-r--r--engines/fullpipe/scenes/scene06.cpp770
-rw-r--r--engines/fullpipe/scenes/scene07.cpp175
-rw-r--r--engines/fullpipe/scenes/scene08.cpp546
-rw-r--r--engines/fullpipe/scenes/scene09.cpp747
-rw-r--r--engines/fullpipe/scenes/scene10.cpp220
-rw-r--r--engines/fullpipe/scenes/scene11.cpp786
-rw-r--r--engines/fullpipe/scenes/scene12.cpp85
-rw-r--r--engines/fullpipe/scenes/scene13.cpp380
-rw-r--r--engines/fullpipe/scenes/scene14.cpp849
-rw-r--r--engines/fullpipe/scenes/scene15.cpp209
-rw-r--r--engines/fullpipe/scenes/scene16.cpp484
-rw-r--r--engines/fullpipe/scenes/scene17.cpp285
-rw-r--r--engines/fullpipe/scenes/scene18and19.cpp932
-rw-r--r--engines/fullpipe/scenes/scene20.cpp155
-rw-r--r--engines/fullpipe/scenes/scene21.cpp148
-rw-r--r--engines/fullpipe/scenes/scene22.cpp395
-rw-r--r--engines/fullpipe/scenes/scene23.cpp555
-rw-r--r--engines/fullpipe/scenes/scene24.cpp129
-rw-r--r--engines/fullpipe/scenes/scene25.cpp723
-rw-r--r--engines/fullpipe/scenes/scene26.cpp355
-rw-r--r--engines/fullpipe/scenes/scene27.cpp759
-rw-r--r--engines/fullpipe/scenes/scene28.cpp474
-rw-r--r--engines/fullpipe/scenes/scene29.cpp1125
-rw-r--r--engines/fullpipe/scenes/scene30.cpp152
-rw-r--r--engines/fullpipe/scenes/scene31.cpp126
-rw-r--r--engines/fullpipe/scenes/scene32.cpp431
-rw-r--r--engines/fullpipe/scenes/scene33.cpp314
-rw-r--r--engines/fullpipe/scenes/scene34.cpp479
-rw-r--r--engines/fullpipe/scenes/scene35.cpp264
-rw-r--r--engines/fullpipe/scenes/scene36.cpp94
-rw-r--r--engines/fullpipe/scenes/scene37.cpp316
-rw-r--r--engines/fullpipe/scenes/scene38.cpp409
-rw-r--r--engines/fullpipe/scenes/sceneDbg.cpp108
-rw-r--r--engines/fullpipe/scenes/sceneFinal.cpp174
-rw-r--r--engines/fullpipe/scenes/sceneIntro.cpp110
-rw-r--r--engines/fullpipe/sound.cpp527
-rw-r--r--engines/fullpipe/sound.h77
-rw-r--r--engines/fullpipe/stateloader.cpp366
-rw-r--r--engines/fullpipe/statics.cpp2305
-rw-r--r--engines/fullpipe/statics.h273
-rw-r--r--engines/fullpipe/utils.cpp501
-rw-r--r--engines/fullpipe/utils.h157
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 */