diff options
author | RichieSams | 2013-09-16 00:46:19 -0500 |
---|---|---|
committer | RichieSams | 2013-09-16 00:46:19 -0500 |
commit | b5c762168edd83a6c5e1b442aee728150b447d98 (patch) | |
tree | 10e419dfaf4fabf75b1458c13383efadad348bd4 /engines | |
parent | a0a67a2d470816b13bab10371494652d77b23611 (diff) | |
parent | 914535a460aa3b3f23bf3ce807619ba388e14135 (diff) | |
download | scummvm-rg350-b5c762168edd83a6c5e1b442aee728150b447d98.tar.gz scummvm-rg350-b5c762168edd83a6c5e1b442aee728150b447d98.tar.bz2 scummvm-rg350-b5c762168edd83a6c5e1b442aee728150b447d98.zip |
Merge branch 'master' into zvision
Diffstat (limited to 'engines')
116 files changed, 16719 insertions, 1339 deletions
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index fd0c8dc2da..40783a2407 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -78,7 +78,7 @@ static Common::String generatePreferredTarget(const Common::String &id, const AD res = res + "-cd"; } - if (desc->platform != Common::kPlatformDOS && desc->platform != Common::kPlatformUnknown) { + if (desc->platform != Common::kPlatformDOS && desc->platform != Common::kPlatformUnknown && !(desc->flags & ADGF_DROPPLATFORM)) { res = res + "-" + getPlatformAbbrev(desc->platform); } diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h index 71d2c4a446..376a59e471 100644 --- a/engines/advancedDetector.h +++ b/engines/advancedDetector.h @@ -87,7 +87,8 @@ enum ADGameFlags { ADGF_ADDENGLISH = (1 << 24), ///< always add English as language option ADGF_MACRESFORK = (1 << 25), ///< the md5 for this entry will be calculated from the resource fork ADGF_USEEXTRAASTITLE = (1 << 26), ///< Extra field value will be used as main game title, not gameid - ADGF_DROPLANGUAGE = (1 << 28), ///< don't add language to gameid + ADGF_DROPLANGUAGE = (1 << 27), ///< don't add language to gameid + ADGF_DROPPLATFORM = (1 << 28), ///< don't add platform to gameid ADGF_CD = (1 << 29), ///< add "-cd" to gameid ADGF_DEMO = (1 << 30) ///< add "-demo" to gameid }; diff --git a/engines/agi/POTFILES b/engines/agi/POTFILES new file mode 100644 index 0000000000..414bf2250d --- /dev/null +++ b/engines/agi/POTFILES @@ -0,0 +1,2 @@ +engines/agi/detection.cpp +engines/agi/saveload.cpp diff --git a/engines/agos/POTFILES b/engines/agos/POTFILES new file mode 100644 index 0000000000..7045ed9afe --- /dev/null +++ b/engines/agos/POTFILES @@ -0,0 +1,2 @@ +engines/agos/saveload.cpp +engines/agos/animation.cpp diff --git a/engines/configure.engines b/engines/configure.engines index a3525576a2..8ef4e66dc3 100644 --- a/engines/configure.engines +++ b/engines/configure.engines @@ -13,6 +13,7 @@ add_engine cruise "Cinematique evo 2" yes add_engine draci "Dragon History" yes add_engine drascula "Drascula: The Vampire Strikes Back" yes add_engine dreamweb "Dreamweb" yes +add_engine fullpipe "Full Pipe" yes add_engine gob "Gobli*ns" yes add_engine groovie "Groovie" yes "groovie2" "7th Guest" add_engine groovie2 "Groovie 2 games" no diff --git a/engines/cruise/POTFILES b/engines/cruise/POTFILES new file mode 100644 index 0000000000..e3b25bdda8 --- /dev/null +++ b/engines/cruise/POTFILES @@ -0,0 +1 @@ +engines/cruise/menu.cpp diff --git a/engines/drascula/POTFILES b/engines/drascula/POTFILES new file mode 100644 index 0000000000..ea79f9e066 --- /dev/null +++ b/engines/drascula/POTFILES @@ -0,0 +1,2 @@ +engines/drascula/detection.cpp +engines/drascula/saveload.cpp diff --git a/engines/dreamweb/POTFILES b/engines/dreamweb/POTFILES new file mode 100644 index 0000000000..d05d239bb7 --- /dev/null +++ b/engines/dreamweb/POTFILES @@ -0,0 +1 @@ +engines/dreamweb/detection.cpp diff --git a/engines/engines.mk b/engines/engines.mk index e399713202..a3270007dc 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -61,6 +61,11 @@ DEFINES += -DENABLE_DREAMWEB=$(ENABLE_DREAMWEB) MODULES += engines/dreamweb endif +ifdef ENABLE_FULLPIPE +DEFINES += -DENABLE_FULLPIPE=$(ENABLE_FULLPIPE) +MODULES += engines/fullpipe +endif + ifdef ENABLE_GOB DEFINES += -DENABLE_GOB=$(ENABLE_GOB) MODULES += engines/gob @@ -250,4 +255,4 @@ endif ifdef ENABLE_ZVISION DEFINES += -DENABLE_ZVISION=$(ENABLE_ZVISION) MODULES += engines/zvision -endif
\ No newline at end of file +endif diff --git a/engines/fullpipe/behavior.cpp b/engines/fullpipe/behavior.cpp new file mode 100644 index 0000000000..6bfb400c24 --- /dev/null +++ b/engines/fullpipe/behavior.cpp @@ -0,0 +1,315 @@ +/* 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, CGameVar *var) { + clear(); + _scene = sc; + + BehaviorInfo *behinfo; + + CGameVar *behvar = var->getSubVarByName("BEHAVIOR"); + if (!behvar) + return; + + for (CGameVar *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(0, "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(0, "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_fullpipe->_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(0, "BehaviorManager::updateStaticAniBehavior(%s)", transCyrillic((byte *)ani->_objectName)); + + MessageQueue *mq = 0; + + if (bhe->_flags & 1) { + uint rnd = g_fullpipe->_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_fullpipe->_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); + } +} + +void BehaviorInfo::clear() { + _ani = 0; + _staticsId = 0; + _counter = 0; + _counterMax = 0; + _flags = 0; + _subIndex = 0; + _itemsCount = 0; + + _bheItems.clear(); +} + +void BehaviorInfo::initAmbientBehavior(CGameVar *var, Scene *sc) { + debug(0, "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(CGameVar *var, Scene *sc, StaticANIObject *ani) { + debug(0, "BehaviorInfo::initObjectBehavior(%s)", transCyrillic((byte *)var->_varName)); + + clear(); + + _itemsCount = var->getSubVarsCount(); + _counterMax = -1; + + while (var->_varType == 2) { + if (strcmp(var->_value.stringValue, "ROOT")) + break; + + CGameVar *v1 = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("BEHAVIOR")->getSubVarByName(ani->getName()); + if (v1 == var) + return; + + sc = g_fullpipe->accessScene(ani->_sceneId); + clear(); + var = v1; + _itemsCount = var->getSubVarsCount(); + _counterMax = -1; + } + + for (int i = 0; i < _itemsCount; i++) { + int maxDelay; + + _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(CGameVar *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++) { + CGameVar *subvar = var->getSubVarByIndex(i); + int delay; + + _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(CGameVar *subvar, Scene *sc, int *delay) { + _messageQueue = 0; + _delay = 0; + _percent = 0; + _flags = 0; + _messageQueue = sc->getMessageQueueByName(subvar->_varName); + + CGameVar *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..d9375d4d01 --- /dev/null +++ b/engines/fullpipe/behavior.h @@ -0,0 +1,84 @@ +/* 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(CGameVar *subvar, Scene *sc, int *delay); +}; + +struct BehaviorEntry { + int _staticsId; + int _itemsCount; + int _flags; + BehaviorEntryInfo **_items; + + BehaviorEntry(); + BehaviorEntry(CGameVar *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(CGameVar *var, Scene *sc); + void initObjectBehavior(CGameVar *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, CGameVar *var); + + void updateBehaviors(); + void updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *entry); + void updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorEntry *beh); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_BEHAVIOR_H */ diff --git a/engines/fullpipe/constants.h b/engines/fullpipe/constants.h new file mode 100644 index 0000000000..796764d0a9 --- /dev/null +++ b/engines/fullpipe/constants.h @@ -0,0 +1,180 @@ +/* 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 { + +#define ANI_BOOT_1 4231 +#define ANI_IN1MAN 5110 +#define ANI_INV_MAP 5321 +#define ANI_LIFTBUTTON 2751 +#define ANI_MAN 322 +#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 MSG_RESTARTGAME 4767 +#define MSG_SC1_SHOWOSK 1019 +#define MSG_SC1_SHOWOSK2 468 +#define MSG_SC1_UTRUBACLICK 1100 +#define MV_MAN_GOLADDER 451 +#define MV_MAN_GOLADDER2 2844 +#define MV_MAN_LOOKUP 4773 +#define MV_MAN_STARTLADDER 452 +#define MV_MAN_STARTLADDER2 2842 +#define MV_MAN_STOPLADDER 454 +#define MV_MAN_STOPLADDER2 2845 +#define MV_MAN_TOLADDER 448 +#define MV_MAN_TOLADDER2 2841 +#define MV_MAN_TURN_LU 486 +#define PIC_CMN_EVAL 3468 +#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_IN1_PIPETITLE 5167 +#define PIC_INV_MENU 991 +#define PIC_MAP_A13 5275 +#define PIC_MAP_S01 5223 +#define PIC_SC1_KUCHKA 1321 +#define PIC_SC1_LADDER 1091 +#define PIC_SC1_OSK 1018 +#define PIC_SC1_OSK2 2932 +#define PIC_SCD_SEL 734 +#define SC_1 301 +#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_2 302 +#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_3 303 +#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_4 304 +#define SC_5 305 +#define SC_6 649 +#define SC_7 650 +#define SC_8 651 +#define SC_9 652 +#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_TEST 903 +#define SC_TITLES 5166 +#define SND_CMN_031 3516 +#define SND_CMN_070 5199 +#define ST_LBN_0N 2832 +#define ST_LBN_0P 2833 +#define ST_LBN_1N 2753 +#define ST_LBN_1P 2754 +#define ST_LBN_2N 2756 +#define ST_LBN_2P 2757 +#define ST_LBN_3N 2759 +#define ST_LBN_3P 2760 +#define ST_LBN_4N 2762 +#define ST_LBN_4P 2763 +#define ST_LBN_5N 2765 +#define ST_LBN_5P 2766 +#define ST_LBN_6N 2768 +#define ST_LBN_6P 2769 +#define ST_LBN_7N 2771 +#define ST_LBN_7P 2772 +#define ST_LBN_8N 2774 +#define ST_LBN_8P 2775 +#define ST_LBN_9N 2777 +#define ST_LBN_9P 2778 +#define ST_MAN_EMPTY 476 +#define ST_MAN_RIGHT 325 +#define TrubaDown 697 +#define TrubaLeft 474 +#define TrubaRight 696 +#define TrubaUp 680 +#define rMV_MAN_LOOKUP 4775 + +} // 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..8c4a422333 --- /dev/null +++ b/engines/fullpipe/detection.cpp @@ -0,0 +1,112 @@ +/* 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" + + +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 bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; +}; + +bool FullpipeMetaEngine::hasFeature(MetaEngineFeature f) const { + return false; +} + +bool Fullpipe::FullpipeEngine::hasFeature(EngineFeature f) const { + return false; +} + +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/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp new file mode 100644 index 0000000000..6a4a587ff7 --- /dev/null +++ b/engines/fullpipe/fullpipe.cpp @@ -0,0 +1,447 @@ +/* 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/scenes.h" + +namespace Fullpipe { + +FullpipeEngine *g_fullpipe = 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"); + + _gameProjectVersion = 0; + _pictureScale = 8; + _scrollSpeed = 0; + _currSoundListCount = 0; + _globalPalette = 0; + + _updateTicks = 0; + _lastInputTicks = 0; + _lastButtonUpTicks = 0; + + _currArchive = 0; + + _soundEnabled = true; + _flgSoundList = true; + + _sfxVolume = 0; + + _inputController = 0; + _inputDisabled = false; + + _normalSpeed = true; + + _currentCheat = -1; + _currentCheatPos = 0; + + _modalObject = 0; + + _gameContinue = true; + _needRestart = false; + _flgPlayIntro = false; + _gamePaused = false; + _inputArFlag = false; + _recordEvents = false; + + _flgGameIsRunning = true; + + _isProcessingMessages = false; + + _musicAllowed = -1; + + _aniMan = 0; + _aniMan2 = 0; + _currentScene = 0; + _scene2 = 0; + _movTable = 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; + + _isSaveAllowed = true; + + g_fullpipe = this; + g_vars = new Vars; +} + +FullpipeEngine::~FullpipeEngine() { + delete _rnd; + delete _globalMessageQueueList; +} + +void FullpipeEngine::initialize() { + _globalMessageQueueList = new GlobalMessageQueueList; + _behaviorManager = new BehaviorManager; + + _sceneRect.left = 0; + _sceneRect.top = 0; + _sceneRect.right = 799; + _sceneRect.bottom = 599; +} + +Common::Error FullpipeEngine::run() { + const Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0); + // Initialize backend + initGraphics(800, 600, true, &format); + + _backgroundSurface.create(800, 600, format); + + initialize(); + + _isSaveAllowed = false; + + int scene = 0; + if (ConfMan.hasKey("boot_param")) + scene = 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(); + CBaseModalObject *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 = 83; + ex->_excFlags |= 3; + ex->handle(); + break; + case Common::KEYCODE_q: + return; + break; + default: + 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; + } + } + + +#if 0 + warning("STUB: FullpipeEngine::updateEvents() <mainWindowProc>"); + if (Msg == MSG_SC11_SHOWSWING && _modalObject) { + _modalObject->method14(); + } +#endif +} + +void FullpipeEngine::freeGameLoader() { + warning("STUB: FullpipeEngine::freeGameLoader()"); +} + +void FullpipeEngine::cleanup() { + warning("STUB: FullpipeEngine::cleanup()"); +} + +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(); + CBaseModalObject *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) { + CGameVar *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) { + CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + + if (var) + return var->getSubVarAsInt(objname); + + return 0; +} + +void FullpipeEngine::setObjectState(const char *name, int state) { + CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + + if (!var) { + var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0); + } + + var->setSubVarAsInt(name, state); +} + +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::disableSaves(ExCommand *ex) { + warning("STUB: FullpipeEngine::disableSaves()"); +} + + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h new file mode 100644 index 0000000000..348ac2c9c5 --- /dev/null +++ b/engines/fullpipe/fullpipe.h @@ -0,0 +1,248 @@ +/* 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/surface.h" + +#include "engines/engine.h" + +struct ADGameDescription; + +namespace Fullpipe { + +enum FullpipeGameFeatures { +}; + +class BehaviorManager; +class CBaseModalObject; +class CGameLoader; +class CGameVar; +class CInputController; +class CInventory2; +struct CursorInfo; +struct EntranceInfo; +class ExCommand; +class GameProject; +class GameObject; +class GlobalMessageQueueList; +struct MessageHandler; +struct MovTable; +class NGIArchive; +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(); + + void initialize(); + + void setMusicAllowed(int val) { _musicAllowed = val; } + + // Detection related functions + const ADGameDescription *_gameDescription; + const char *getGameId() const; + Common::Platform getPlatform() const; + bool hasFeature(EngineFeature f) const; + + Common::RandomSource *_rnd; + + Common::KeyCode _keyState; + uint16 _buttonState; + + void updateEvents(); + + Graphics::Surface _backgroundSurface; + + CGameLoader *_gameLoader; + GameProject *_gameProject; + bool loadGam(const char *fname, int scene = 0); + + CGameVar *getGameLoaderGameVar(); + CInputController *getGameLoaderInputController(); + + int _gameProjectVersion; + int _pictureScale; + int _scrollSpeed; + bool _updateFlag; + bool _flgCanOpenMap; + bool _gamePaused; + bool _flgGameIsRunning; + bool _inputArFlag; + bool _recordEvents; + + Common::Rect _sceneRect; + int _sceneWidth; + int _sceneHeight; + Scene *_currentScene; + Scene *_scene2; + StaticANIObject *_aniMan; + StaticANIObject *_aniMan2; + byte *_globalPalette; + + CInputController *_inputController; + bool _inputDisabled; + + int _currentCheat; + int _currentCheatPos; + + void defHandleKeyDown(int key); + + SoundList *_currSoundList1[11]; + int _currSoundListCount; + bool _soundEnabled; + bool _flgSoundList; + + void stopAllSounds(); + void toggleMute(); + void playSound(int id, int flag); + void startSceneTrack(); + + int _sfxVolume; + + 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; + + void initMap(); + 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; + CInventory2 *_inventory; + int _currSelectedInventoryItemId; + + int32 _updateTicks; + int32 _lastInputTicks; + int32 _lastButtonUpTicks; + + CBaseModalObject *_modalObject; + + int (*_updateScreenCallback)(); + int (*_updateCursorCallback)(); + + int _cursorId; + int _minCursorId; + int _maxCursorId; + Common::Array<int> _objectIdCursors; + GameObject *_objectAtCursor; + int _objectIdAtCursor; + + void setCursor(int id); + void updateCursorsCommon(); + + 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(CGameVar *var); + + NGIArchive *_currArchive; + + void openMap(); + void openHelp(); + void openMainMenu(); + + void winArcade(); + void getAllInventory(); + + int lift_getButtonIdP(int objid); + +public: + + bool _isSaveAllowed; + + bool canLoadGameStateCurrently() { return _isSaveAllowed; } + bool canSaveGameStateCurrently() { return _isSaveAllowed; } + +}; + +extern FullpipeEngine *g_fullpipe; +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..2a8f64dac9 --- /dev/null +++ b/engines/fullpipe/gameloader.cpp @@ -0,0 +1,513 @@ +/* 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/gameloader.h" +#include "fullpipe/scene.h" +#include "fullpipe/input.h" +#include "fullpipe/statics.h" +#include "fullpipe/interaction.h" +#include "fullpipe/motion.h" + +namespace Fullpipe { + +CInventory2 *getGameLoaderInventory() { + return &g_fullpipe->_gameLoader->_inventory; +} + +CMctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId) { + for (uint i = 0; i < g_fullpipe->_gameLoader->_sc2array.size(); i++) + if (g_fullpipe->_gameLoader->_sc2array[i]._sceneId == sceneId) + return (CMctlCompound *)g_fullpipe->_gameLoader->_sc2array[i]._motionController; + + return 0; +} + +CInteractionController *getGameLoaderInteractionController() { + return g_fullpipe->_gameLoader->_interactionController; +} + +CGameLoader::CGameLoader() { + _interactionController = new CInteractionController(); + _inputController = new CInputController(); + + _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_fullpipe->_msgX = 0; + g_fullpipe->_msgY = 0; + g_fullpipe->_msgObjectId2 = 0; + g_fullpipe->_msgId = 0; +} + +CGameLoader::~CGameLoader() { + free(_gameName); + delete _gameProject; + delete _interactionController; + delete _inputController; +} + +bool CGameLoader::load(MfcArchive &file) { + debug(5, "CGameLoader::load()"); + + _gameName = file.readPascalString(); + debug(6, "_gameName: %s", _gameName); + + _gameProject = new GameProject(); + + _gameProject->load(file); + + g_fullpipe->_gameProject = _gameProject; + + if (g_fullpipe->_gameProjectVersion < 12) { + error("Old gameProjectVersion: %d", g_fullpipe->_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 = (CGameVar *)file.readClass(); + + return true; +} + +bool CGameLoader::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 CGameLoader::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_fullpipe->_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; + } + + CGameVar *sg = _gameVar->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME"); + + if (sg || (sg = _gameVar->getSubVarByName("OBJSTATES")->addSubVarAsInt("SAVEGAME", 0)) != 0) + sg->setSubVarAsInt("Entrance", entranceId); + + if (!g_fullpipe->sceneSwitcher(_sc2array[sc2idx]._entranceData[entranceIdx])) + return false; + + g_fullpipe->_msgObjectId2 = 0; + g_fullpipe->_msgY = -1; + g_fullpipe->_msgX = -1; + + g_fullpipe->_currentScene = st->_scene; + + MessageQueue *mq1 = g_fullpipe->_currentScene->getMessageQueueById(_sc2array[sc2idx]._entranceData[entranceIdx]->_messageQueueId); + if (mq1) { + MessageQueue *mq = new MessageQueue(mq1, 0, 0); + + StaticANIObject *stobj = g_fullpipe->_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->_exCommands.push_back(ex); + } + + mq->setFlags(mq->getFlags() | 1); + + if (!mq->chain(0)) { + delete mq; + + return false; + } + } else { + StaticANIObject *stobj = g_fullpipe->_currentScene->getStaticANIObject1ById(_field_FA, -1); + if (stobj) + stobj->_flags &= 0xfeff; + } + + return true; +} + +bool preloadCallback(const PreloadItem &pre, int flag) { + warning("STUB: preloadCallback"); + + return true; +} + +bool CGameLoader::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_fullpipe->_currentScene && g_fullpipe->_currentScene->_sceneId == sceneId) + g_fullpipe->_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 CGameLoader::unloadScene(int sceneId) { + SceneTag *tag; + int sceneTag = getSceneTagBySceneId(sceneId, &tag); + + if (sceneTag < 0) + return false; + + if (_sc2array[sceneTag]._isLoaded) + saveScenePicAniInfos(sceneId); + + _sc2array[sceneTag]._motionController->freeItems(); + + delete tag->_scene; + tag->_scene = 0; + + _sc2array[sceneTag]._isLoaded = 0; + _sc2array[sceneTag]._scene = 0; + + return true; +} + +int CGameLoader::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 CGameLoader::applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAniInfoCount) { + if (picAniInfoCount <= 0) + return; + + debug(0, "CGameLoader::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_fullpipe->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 CGameLoader::saveScenePicAniInfos(int sceneId) { + warning("STUB: CGameLoader::saveScenePicAniInfos(%d)", sceneId); +} + +void CGameLoader::updateSystems(int counterdiff) { + if (g_fullpipe->_currentScene) { + g_fullpipe->_currentScene->update(counterdiff); + + _exCommand._messageKind = 17; + _updateCounter++; + _exCommand._messageNum = 33; + _exCommand._excFlags = 0; + _exCommand.postMessage(); + } + + processMessages(); + + if (_preloadSceneId) { + processMessages(); + preloadScene(_preloadSceneId, _preloadEntranceId); + } +} + +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 = (CMotionController *)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(); + + resize(count); + + 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; +} + +CGameVar *FullpipeEngine::getGameLoaderGameVar() { + if (_gameLoader) + return _gameLoader->_gameVar; + else + return 0; +} + +CInputController *FullpipeEngine::getGameLoaderInputController() { + if (_gameLoader) + return _gameLoader->_inputController; + else + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/gameloader.h b/engines/fullpipe/gameloader.h new file mode 100644 index 0000000000..2f1f57a5e2 --- /dev/null +++ b/engines/fullpipe/gameloader.h @@ -0,0 +1,117 @@ +/* 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 { + +class SceneTag; +class CMctlCompound; +class CInputController; +class CInteractionController; +class CMotionController; + +class Sc2 : public CObject { + public: + int16 _sceneId; + int16 _field_2; + Scene *_scene; + CMotionController *_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(const PreloadItem &pre, int flag); + +class PreloadItems : public Common::Array<PreloadItem *>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class CGameLoader : public CObject { + public: + CGameLoader(); + virtual ~CGameLoader(); + + 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); + + GameProject *_gameProject; + CInteractionController *_interactionController; + CInputController *_inputController; + CInventory2 _inventory; + Sc2Array _sc2array; + void *_sceneSwitcher; + bool (*_preloadCallback)(const PreloadItem &pre, int flag); + void *_readSavegameCallback; + int16 _field_F8; + int16 _field_FA; + PreloadItems _preloadItems; + CGameVar *_gameVar; + char *_gameName; + ExCommand _exCommand; + int _updateCounter; + int _preloadSceneId; + int _preloadEntranceId; +}; + +CInventory2 *getGameLoaderInventory(); +CInteractionController *getGameLoaderInteractionController(); +CMctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId); + +} // 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..2ab038b74d --- /dev/null +++ b/engines/fullpipe/gfx.cpp @@ -0,0 +1,1238 @@ +/* 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 { + +Bitmap::Bitmap() { + _x = 0; + _y = 0; + _width = 0; + _height = 0; + _pixels = 0; + _type = 0; + _dataSize = 0; + _flags = 0; +} + +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; +} + +Bitmap::~Bitmap() { + if (_pixels) + free(_pixels); +} + +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); +} + +Background::Background() { + _x = 0; + _y = 0; + _messageQueueId = 0; + _bigPictureArray1Count = 0; + _bigPictureArray2Count = 0; + _bigPictureArray = 0; + _bgname = 0; + _palette = 0; +} + +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_fullpipe->_gameProjectVersion >= 4); + + _bigPictureArray1Count = file.readUint32LE(); + + assert(g_fullpipe->_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 = 0; i < _picObjList.size(); i++) { + if (((PictureObject *)_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(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 CPtrList(); + + 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("Picture::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; +} + +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_fullpipe->_gameProjectVersion >= 11) { + _field_8 = file.readUint32LE(); + } + + return true; +} + +void GameObject::setOXY(int x, int y) { + _ox = x; + _oy = y; +} + +void GameObject::renumPictures(CPtrList *lst) { + int *buf = (int *)calloc(lst->size() + 2, sizeof(int)); + + for (uint i = 0; i < lst->size(); i++) { + if (_id == ((PictureObject *)((*lst)[i]))->_id) + buf[((PictureObject *)((*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; + + 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() { + if (_bitmap) { + if (testFlags() && !_field_54) { + freeData(); + delete _bitmap; + _bitmap = 0; + } + } + + if (_bitmap) { + _bitmap = 0; + _data = 0; + } + + if (_convertedBitmap) { + free(_convertedBitmap->_pixels); + delete _convertedBitmap; + _convertedBitmap = 0; + } +} + +bool Picture::load(MfcArchive &file) { + debug(5, "Picture::load()"); + MemoryObject::load(file); + + _x = file.readUint32LE(); + _y = file.readUint32LE(); + _field_44 = file.readUint16LE(); + + assert(g_fullpipe->_gameProjectVersion >= 2); + + _width = file.readUint32LE(); + _height = file.readUint32LE(); + + _mflags |= 1; + + _memoryObject2 = new MemoryObject2; + _memoryObject2->load(file); + + if (_memoryObject2->_data) { + setAOIDs(); + } + + assert (g_fullpipe->_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: <%s>", _memfilename); + + return true; +} + +void Picture::setAOIDs() { + int w = (g_fullpipe->_pictureScale + _width - 1) / g_fullpipe->_pictureScale; + int h = (g_fullpipe->_pictureScale + _height - 1) / g_fullpipe->_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() { + _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); + } + + Common::MemoryReadStream *s = new Common::MemoryReadStream(_data + off - 32, 32); + + _bitmap->load(s); + _bitmap->_pixels = _data; +} + +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(0, "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(0, "Picture:draw: alpha = %0x", _alpha); + } + + byte *pal = _paletteData; + + if (!pal) { + //warning("Picture:draw: using global palette"); + pal = g_fullpipe->_globalPalette; + } + + Common::Point point; + + switch (style) { + case 1: + //flip + getDimensions(&point); + _bitmap->flipVertical()->drawShaded(1, x1, y1 + 30 + point.y, pal); + 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); + //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); + } + } +} + +void Picture::drawRotated(int x, int y, int angle) { + warning("STUB: Picture::drawRotated(%d, %d, %d)", x, y, angle); +} + +void Picture::displayPicture() { + if (!g_fullpipe->_gameContinue) + return; + + getData(); + init(); + + if (!_dataSize) + return; + + g_fullpipe->_backgroundSurface.fillRect(Common::Rect(0, 0, 799, 599), 0); + g_fullpipe->_system->copyRectToScreen(g_fullpipe->_backgroundSurface.getBasePtr(0, 0), g_fullpipe->_backgroundSurface.pitch, 0, 0, 799, 599); + + draw(0, 0, 0, 0); + + g_fullpipe->updateEvents(); + g_fullpipe->_system->delayMillis(10); + g_fullpipe->_system->updateScreen(); + + while (g_fullpipe->_gameContinue) { + g_fullpipe->updateEvents(); + g_fullpipe->_system->delayMillis(10); + g_fullpipe->_system->updateScreen(); + + if (g_fullpipe->_keyState == ' ') { + g_fullpipe->_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_fullpipe->_pictureScale, y / g_fullpipe->_pictureScale); + + return false; +} + +int Picture::getPixelAtPosEx(int x, int y) { + if (x < 0 || y < 0) + return 0; + + if (x < (g_fullpipe->_pictureScale + _width - 1) / g_fullpipe->_pictureScale && + y < (g_fullpipe->_pictureScale + _height - 1) / g_fullpipe->_pictureScale && + _memoryObject2 != 0 && _memoryObject2->_rows != 0) + return _memoryObject2->_rows[x][2 * y]; + + return 0; +} + +bool Bitmap::isPixelHitAtPos(int x, int y) { + if (x < _x || x >= _width + _x || y < _y || y >= _y + _height) + return false; + + int off; + + if (_type == 'CB\x05e') + off = 2 * ((_width + 1) / 2); + else + off = 4 * ((_width + 3) / 4); + + off = x + off * (_y + _height - y - 1) - _x; + + if (_flags & 0x1000000) { + switch (_type) { + case 'CB\0\0': + if (_pixels[off] == (_flags & 0xff)) + return false; + break; + case 'CB\x05e': + if (!*(int16 *)&_pixels[2 * off]) + return false; + break; + case 'RB\0\0': + return isPixelAtHitPosRB(x, y); + } + } + return true; +} + +bool Bitmap::isPixelAtHitPosRB(int x, int y) { + int ox = _x; + int oy = _y; + + _x = _y = 0; + + bool res = putDibRB(0, x, y); + _x = ox; + _y = oy; + + return res; +} + +void Bitmap::putDib(int x, int y, int32 *palette) { + debug(0, "Bitmap::putDib(%d, %d)", x, y); + + _x = x - g_fullpipe->_sceneRect.left; + _y = y - g_fullpipe->_sceneRect.top; + + if (_type == MKTAG('R', 'B', '\0', '\0')) + putDibRB(palette); + else + putDibCB(palette); +} + +bool Bitmap::putDibRB(int32 *palette, int pX, int pY) { + uint16 *curDestPtr; + int endy; + int x; + int start1; + int fillLen; + uint16 pixel; + int endx; + int y; + uint16 *srcPtr2; + uint16 *srcPtr; + + if (!palette && pX == -1) { + warning("Bitmap::putDibRB(): Both global and local palettes are empty"); + return false; + } + + debug(8, "Bitmap::putDibRB()"); + + endx = _width + _x - 1; + endy = _height + _y - 1; + + if (_x > 799 || endx < 0 || _y > 599 || endy < 0) + return false; + + if (pX == -1) { + if (endy > 599) + endy = 599; + + if (endx > 799) + endx = 799; + } + + int startx = _x; + if (startx < 0) + startx = 0; + + int starty = _y; + if (starty < 0) + 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) { + if (pX == -1) { + int bgcolor = palette[(pixel >> 8) & 0xff]; + curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(start1, y); + colorFill(curDestPtr, fillLen, bgcolor); + } else { + if (y == pY && pX >= start1 && pX < start1 + fillLen) + return true; + } + } + } + } + } 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) { + if (pX == -1) { + curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(start1, y); + paletteFill(curDestPtr, (byte *)srcPtr2, fillLen, (int32 *)palette); + } else { + if (y == pY && pX >= start1 && pX < start1 + fillLen) + return true; + } + } + } + } + } + + if (pX == -1) + g_fullpipe->_system->copyRectToScreen(g_fullpipe->_backgroundSurface.getBasePtr(startx, starty), g_fullpipe->_backgroundSurface.pitch, startx, starty, endx + 1 - startx, endy + 1 - starty); + + return false; +} + +void Bitmap::putDibCB(int32 *palette) { + uint16 *curDestPtr; + int endx; + int endy; + int bpp; + uint pitch; + bool cb05_format; + + endx = _width + _x - 1; + endy = _height + _y - 1; + + debug(8, "Bitmap::putDibCB(): %d, %d, %d, %d [%d, %d]", _x, _y, endx, endy, _width, _height); + + if (_x > 799 || endx < 0 || _y > 599 || endy < 0) + return; + + if (endy > 599) + endy = 599; + + if (endx > 799) + endx = 799; + + 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 - _y)]; + + int starty = _y; + if (starty < 0) { + starty = 0; + srcPtr = &_pixels[pitch * (_height + _y)]; + } + + int startx = _x; + if (startx < 0) { + srcPtr += bpp * -_x; + startx = 0; + } + + if (_flags & 0x1000000) { + for (int y = starty; y < endy; srcPtr -= pitch, y++) { + curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.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 = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(startx, y); + copier(curDestPtr, srcPtr, endx - startx + 1, (int32 *)palette, cb05_format); + } + } + + g_fullpipe->_system->copyRectToScreen(g_fullpipe->_backgroundSurface.getBasePtr(startx, starty), g_fullpipe->_backgroundSurface.pitch, startx, starty, endx + 1 - startx, endy + 1 - starty); +} + +void Bitmap::colorFill(uint16 *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 + + for (int i = 0; i < len; i++) + *dest++ = (int16)(color & 0xffff); +} + +void Bitmap::paletteFill(uint16 *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 + + for (int i = 0; i < len; i++) + *dest++ = READ_LE_UINT32(&palette[*src++]) & 0xffff; +} + +void Bitmap::copierKeyColor(uint16 *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 + + if (!cb05_format) { + for (int i = 0; i < len; i++) { + if (*src != keyColor) + *dest = READ_LE_UINT32(&palette[*src]) & 0xffff; + + dest++; + src++; + } + } else { + int16 *src16 = (int16 *)src; + + for (int i = 0; i < len; i++) { + if (*src16 != 0) + *dest = *src16; + + dest++; + src16++; + } + } +} + +void Bitmap::copier(uint16 *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 + + if (!cb05_format) { + for (int i = 0; i < len; i++) + *dest++ = READ_LE_UINT32(&palette[*src++]) & 0xffff; + } else { + int16 *src16 = (int16 *)src; + + for (int i = 0; i < len; i++) + *dest++ = *src16++; + } +} + +Bitmap *Bitmap::reverseImage() { + switch (_type) { + case MKTAG('R', 'B', '\0', '\0'): + return reverseImageRB(); + case MKTAG('C', 'B', '\0', '\0'): + return reverseImageCB(); + case MKTAG('C', 'B', '\05', 'e'): + return reverseImageCB05(); + default: + error("Bitmap::reverseImage: Unknown image type: %x", _type); + } + + return 0; +} + +Bitmap *Bitmap::reverseImageRB() { + uint16 *newpixels = (uint16 *)calloc(((_dataSize + 15) & 0xfffffff0) + sizeof(Bitmap), 1); + uint16 *srcPtr = (uint16 *)_pixels; + + int idx = 0; + while (srcPtr[idx] != 0x100) { + uint16 *srcPtr2 = &srcPtr[idx]; + + int prevIdx = idx; + int i = idx; + + while (*srcPtr2) { + ++srcPtr2; + ++idx; + } + + int idx2 = idx; + + newpixels[idx] = srcPtr[idx]; + + while (i != idx) { + int fillLen = 2 - ((srcPtr[prevIdx] & 0xff) != 0 ? 1 : 0); + idx2 -= fillLen; + memcpy(&newpixels[idx2], &srcPtr[prevIdx], 2 * fillLen); + prevIdx = fillLen + i; + i += fillLen; + } + ++idx; + } + newpixels[idx] = 256; + + int oldBmp = ((_dataSize + 15) >> 1) & 0x7FFFFFF8; + memcpy(&newpixels[oldBmp], &srcPtr[oldBmp], sizeof(Bitmap)); + + Bitmap *res = new Bitmap(this); + res->_pixels = (byte *)newpixels; + + return res; +} + +Bitmap *Bitmap::reverseImageCB() { + warning("STUB: Bitmap::reverseImageCB()"); + + return this; +} + +Bitmap *Bitmap::reverseImageCB05() { + warning("STUB: Bitmap::reverseImageCB05()"); + + return this; +} + +Bitmap *Bitmap::flipVertical() { + warning("STUB: Bitmap::flipVertical()"); + + return this; +} + +void Bitmap::drawShaded(int type, int x, int y, byte *palette) { + warning("STUB: Bitmap::drawShaded(%d, %d, %d)", type, x, y); + + putDib(x, y, (int32 *)palette); +} + + void Bitmap::drawRotated(int x, int y, int angle, byte *palette) { + warning("STUB: Bitmap::drawShaded(%d, %d, %d)", x, y, angle); + + putDib(x, y, (int32 *)palette); +} + +bool BigPicture::load(MfcArchive &file) { + debug(5, "BigPicture::load()"); + Picture::load(file); + + return true; +} + +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_fullpipe->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; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/gfx.h b/engines/fullpipe/gfx.h new file mode 100644 index 0000000000..82e082d8cb --- /dev/null +++ b/engines/fullpipe/gfx.h @@ -0,0 +1,216 @@ +/* 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; + + Bitmap(); + Bitmap(Bitmap *src); + ~Bitmap(); + + void load(Common::ReadStream *s); + void putDib(int x, int y, int32 *palette); + bool putDibRB(int32 *palette, int x = -1, int y = -1); + void putDibCB(int32 *palette); + + void colorFill(uint16 *dest, int len, int32 color); + void paletteFill(uint16 *dest, byte *src, int len, int32 *palette); + void copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format); + void copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_format); + + Bitmap *reverseImage(); + Bitmap *reverseImageRB(); + Bitmap *reverseImageCB(); + Bitmap *reverseImageCB05(); + Bitmap *flipVertical(); + + void drawShaded(int type, int x, int y, byte *palette); + void drawRotated(int x, int y, int angle, byte *palette); + + bool isPixelHitAtPos(int x, int y); + bool isPixelAtHitPosRB(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(); + + virtual bool load(MfcArchive &file); + void setAOIDs(); + void init(); + void getDibInfo(); + Bitmap *getPixelData(); + 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 bool load(MfcArchive &file); +}; + +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(CPtrList *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; + CPtrList *_pictureObject2List; + int _ox2; + int _oy2; + + public: + PictureObject(); + PictureObject(PictureObject *src); + + bool load(MfcArchive &file, bool bigPicture); + 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); +}; + +class Background : public CObject { + public: + CPtrList _picObjList; + + char *_bgname; + int _x; + int _y; + int16 _messageQueueId; + MemoryObject *_palette; + int _bigPictureArray1Count; + int _bigPictureArray2Count; + BigPicture ***_bigPictureArray; + + public: + 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..c334542247 --- /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_TumyTrampie, getObjectEnumState(sO_TumyTrampie, sO_Drinking)); + 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_NotAvailable)); + setObjectState(sO_ClockHandle, getObjectEnumState(sO_ClockHandle, sO_In_7)); + setObjectState(sO_BigMumsy, getObjectEnumState(sO_BigMumsy, sO_Sleeping)); + 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_ClosedShe)); + 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_Swinging)); + setObjectState(sO_DudeJumped, getObjectEnumState(sO_DudeJumped, 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_OpenedShe)); + 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_ClosedShe)); + setObjectState(sO_Fly_17, 1); + setObjectState(sO_DudeSwinged, 0); + setObjectState(sO_Girl, getObjectEnumState(sO_Girl, sO_Swinging)); + 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_ClosedShe)); + setObjectState(sO_StarsDown_24, getObjectEnumState(sO_StarsDown_24, sO_OpenedShe)); + 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_ClosedShe)); + 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_Plank_25, getObjectEnumState(sO_Plank_25, sO_NearDudesStairs)); + setObjectState(sO_Driver, getObjectEnumState(sO_Driver, sO_WithSteering)); + setObjectState(sO_Janitress, getObjectEnumState(sO_Janitress, sO_WithMop)); + setObjectState(sO_LeftPipe_29, getObjectEnumState(sO_LeftPipe_29, sO_ClosedShe)); + setObjectState(sO_LeftPipe_30, getObjectEnumState(sO_LeftPipe_30, sO_ClosedShe)); + 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_Gurad_2, getObjectEnumState(sO_Gurad_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() { + CGameVar *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..c4af54ddc3 --- /dev/null +++ b/engines/fullpipe/input.cpp @@ -0,0 +1,279 @@ +/* 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 { + +CInputController::CInputController() { + g_fullpipe->_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; +} + +CInputController::~CInputController() { + removeMessageHandler(126, -1); + + g_fullpipe->_inputController = 0; +} + +void CInputController::setInputDisabled(bool state) { + _flag = state; + g_fullpipe->_inputDisabled = state; +} + +void setInputDisabled(bool state) { + g_fullpipe->_inputController->setInputDisabled(state); +} + +void CInputController::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 CInputController::setCursorMode(bool enabled) { + if (enabled) + _inputFlags |= 1; + else + _inputFlags &= ~1; +} + +void CInputController::drawCursor(int x, int y) { + if (_cursorIndex == -1) + return; + + _cursorBounds.left = g_fullpipe->_sceneRect.left + x - _cursorsArray[_cursorIndex]->hotspotX; + _cursorBounds.top = g_fullpipe->_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 CInputController::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; + } + + warning("%d %d", _currentCheat, _currentCheatPos); + if (toupper(key) != input_cheats[_currentCheat][_currentCheatPos]) { + _currentCheat = -1; + + return; + } + + _currentCheatPos++; + warning("%d %d", _currentCheat, _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::updateCursorsCommon() { + 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; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/input.h b/engines/fullpipe/input.h new file mode 100644 index 0000000000..4b32e510e3 --- /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 CInputController { + //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: + CInputController(); + ~CInputController(); + + 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..dcc7e90145 --- /dev/null +++ b/engines/fullpipe/interaction.cpp @@ -0,0 +1,517 @@ +/* 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_fullpipe->_currentScene) + sceneId = g_fullpipe->_currentScene->_sceneId; + + CInteractionController *intC = getGameLoaderInteractionController(); + for (CObList::iterator i = intC->_interactions.begin(); i != intC->_interactions.end(); ++i) { + CInteraction *intr = (CInteraction *)*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; +} + +bool CInteractionController::load(MfcArchive &file) { + debug(5, "CInteractionController::load()"); + + return _interactions.load(file); +} + +int static_compSceneId = 0; + +bool CInteractionController::compareInteractions(const void *p1, const void *p2) { + const CInteraction *i1 = (const CInteraction *)p1; + const CInteraction *i2 = (const CInteraction *)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 CInteractionController::sortInteractions(int sceneId) { + static_compSceneId = sceneId; + + Common::sort(_interactions.begin(), _interactions.end(), CInteractionController::compareInteractions); +} + +bool CInteractionController::handleInteraction(StaticANIObject *subj, GameObject *obj, int invId) { + if (subj) { + if (!subj->isIdle() || (subj->_flags & 0x100)) + return false; + } + + if (!_interactions.size()) + return false; + + CInteraction *inter = 0; + CInteraction *previnter = 0; + int dur = 0; + int mindur = 0xFFFF; + + MessageQueue *mq; + ExCommand *ex; + + for (CObList::iterator i = _interactions.begin(); i != _interactions.end(); ++i) { + CInteraction *cinter = (CInteraction *)*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_fullpipe->_currentScene->_sceneId)->method4C(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->_exCommands.push_back(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->_exCommands.push_back(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->_exCommands.push_back(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->_exCommands.push_back(ex); + + ex = new ExCommand(subj->_id, 17, 0x40, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_keyCode = 0; + mq->_exCommands.push_back(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_fullpipe->_currentScene->_sceneId)->method34(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->_exCommands.push_back(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->_exCommands.push_back(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->_exCommands.push_back(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->_exCommands.push_back(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; +} + +CInteraction::CInteraction() { + _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; +} + +bool CInteraction::load(MfcArchive &file) { + debug(5, "CInteraction::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 CInteraction::canInteract(GameObject *obj1, GameObject *obj2, int invId) { + if (_sceneId > 0 && g_fullpipe->_currentScene && g_fullpipe->_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_fullpipe->getObjectState(obj1->getName()) & _objectState1) == 0) + return false; + } else { + if (g_fullpipe->getObjectState(obj1->getName()) != _objectState1) + return false; + } + } + + if (_objectState2) { + if (_flags & 0x10) { + if ((g_fullpipe->getObjectState(obj2->getName()) & _objectState2) == 0) + return false; + } else { + if (g_fullpipe->getObjectState(obj2->getName()) != _objectState2) + return false; + } + } + + if (_objectId2 && (!obj1 || _objectId2 != obj1->_id)) + return false; + + return true; +} + +bool CInteraction::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..28a03fb496 --- /dev/null +++ b/engines/fullpipe/interaction.h @@ -0,0 +1,96 @@ +/* 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 CInteraction : 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: + CInteraction(); + virtual bool load(MfcArchive &file); + bool canInteract(GameObject *obj1, GameObject *obj2, int invId); + bool isOverlapping(StaticANIObject *subj, GameObject *obj); +}; + +class CInteractionController : public CObject { + public: + CObList _interactions; + int16 _field_20; + bool _flag24; + + private: + static bool compareInteractions(const void *p1, const void *p2); + + public: + CInteractionController() : _field_20(0), _flag24(true) {} + + 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); +}; + +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..ccedb57ce2 --- /dev/null +++ b/engines/fullpipe/inventory.cpp @@ -0,0 +1,437 @@ +/* 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 { + +bool CInventory::load(MfcArchive &file) { + debug(5, "CInventory::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 CInventory::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 CInventory::setItemFlags(int itemId, int flags) { + int idx = getInventoryPoolItemIndexById(itemId); + + if (idx < 0) + return false; + else + _itemsPool[idx]->flags = flags; + + return true; +} + +CInventory2::CInventory2() { + _selectedId = -1; + _field_48 = -1; + _scene = 0; + _picture = 0; + _isInventoryOut = false; + _isLocked = 0; + _topOffset = -65; +} + +bool CInventory2::loadPartial(MfcArchive &file) { // CInventory2_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 CInventory2::addItem(int itemId, int count) { + if (getInventoryPoolItemIndexById(itemId) >= 0) + _inventoryItems.push_back(new InventoryItem(itemId, count)); +} + +void CInventory2::addItem2(StaticANIObject *obj) { + if (getInventoryPoolItemIndexById(obj->_id) >= 0 && getInventoryPoolItemFieldCById(obj->_id) != 2) { + addItem(obj->_id, 1); + obj->hide(); + } +} + +void CInventory2::removeItem(int itemId, int count) { + warning("STUB: CInventory2::removeItem(%d, %d)", itemId, count); +} + +void CInventory2::removeItem2(Scene *sceneObj, int itemId, int x, int y, int priority) { + warning("STUB: void removeItem2(sc, %d, %d, %d, %d)", itemId, x, y, priority); +} + +int CInventory2::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 CInventory2::getInventoryItemIndexById(int itemId) { + for (uint i = 0; i < _inventoryItems.size(); i++) { + if (_inventoryItems[i]->itemId == itemId) + return i; + } + + return -1; +} + +int CInventory2::getInventoryPoolItemIdAtIndex(int itemId) { + return _itemsPool[itemId]->id; +} + +int CInventory2::getInventoryPoolItemFieldCById(int itemId) { + for (uint i = 0; i < _itemsPool.size(); i++) { + if (_itemsPool[i]->id == itemId) + return _itemsPool[i]->field_C; + } + + return 0; +} + +int CInventory2::getItemFlags(int itemId) { + int idx = getInventoryPoolItemIndexById(itemId); + + if (idx < 0) + return 0; + + return _itemsPool[idx]->flags; +} + +void CInventory2::rebuildItemRects() { + _scene = g_fullpipe->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 CInventory2::draw() { + if (!_scene) + return; + + int oldScLeft = g_fullpipe->_sceneRect.left; + int oldScTop = g_fullpipe->_sceneRect.top; + + g_fullpipe->_sceneRect.top = -_topOffset; + g_fullpipe->_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_fullpipe->_sceneRect.top = oldScTop; + g_fullpipe->_sceneRect.left = oldScLeft; + +} + +void CInventory2::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 CInventory2::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 CInventory2::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 CInventory2::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_fullpipe->getGameLoaderInputController()->setCursorItemPicture(pic); + } + + return _selectedId; +} + +bool CInventory2::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_fullpipe->getGameLoaderInputController()->setCursorItemPicture(0); + + return true; +} + +int CInventory2::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 FullpipeEngine::getAllInventory() { + CInventory2 *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..5f1030398c --- /dev/null +++ b/engines/fullpipe/inventory.h @@ -0,0 +1,132 @@ +/* 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 CInventory : public CObject { + protected: + int16 _sceneId; + InventoryPoolItems _itemsPool; + + public: + CInventory() { _sceneId = 0; } + 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 CInventory2 : public CInventory { + InventoryItems _inventoryItems; + InventoryIcons _inventoryIcons; + int _selectedId; + int _field_48; + bool _isInventoryOut; + bool _isLocked; + int _topOffset; + Scene *_scene; + BigPicture *_picture; + + public: + CInventory2(); + 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(); +}; + +} // 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..25dd2613fe --- /dev/null +++ b/engines/fullpipe/lift.cpp @@ -0,0 +1,67 @@ +/* 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" + +namespace Fullpipe { + +int FullpipeEngine::lift_getButtonIdP(int objid) { + switch (objid) { + case ST_LBN_0N: + return ST_LBN_0P; + break; + case ST_LBN_1N: + return ST_LBN_1P; + break; + case ST_LBN_2N: + return ST_LBN_2P; + break; + case ST_LBN_3N: + return ST_LBN_3P; + break; + case ST_LBN_4N: + return ST_LBN_4P; + break; + case ST_LBN_5N: + return ST_LBN_5P; + break; + case ST_LBN_6N: + return ST_LBN_6P; + break; + case ST_LBN_7N: + return ST_LBN_7P; + break; + case ST_LBN_8N: + return ST_LBN_8P; + break; + case ST_LBN_9N: + return ST_LBN_9P; + break; + default: + return 0; + break; + } +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/messages.cpp b/engines/fullpipe/messages.cpp new file mode 100644 index 0000000000..36fd1399ce --- /dev/null +++ b/engines/fullpipe/messages.cpp @@ -0,0 +1,727 @@ +/* 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" + +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(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_fullpipe->_gameProjectVersion >= 12) { + _excFlags = file.readUint32LE(); + _parId = file.readUint32LE(); + } + + return true; +} + +bool ExCommand::handleMessage() { + int cnt = 0; + for (MessageHandler *m = g_fullpipe->_messageHandlers; m; m = m->nextItem) + cnt += m->callback(this); + + if (_messageKind == 17 || (_excFlags & 1)) { + if (_parId) { + MessageQueue *mq = g_fullpipe->_globalMessageQueueList->getMessageQueueById(_parId); + if (mq) + mq->update(); + } + } + + if (_excFlags & 2) + delete this; + + return (cnt > 0); +} + +void ExCommand::sendMessage() { + g_fullpipe->_exCommandList.push_back(this); + + processMessages(); +} + +void ExCommand::postMessage() { + g_fullpipe->_exCommandList.push_back(this); +} + +void ExCommand::handle() { + if (g_fullpipe->_modalObject) { + g_fullpipe->_modalObject->handleMessage(this); + + delete this; + } else { + postMessage(); + } +} + +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; +} + +CObjstateCommand::CObjstateCommand() { + _value = 0; + _objCommandName = 0; +} + +bool CObjstateCommand::load(MfcArchive &file) { + debug(5, "CObjStateCommand::load()"); + + _objtype = kObjTypeObjstateCommand; + + _cmd.load(file); + + _value = file.readUint32LE(); + + _objCommandName = file.readPascalString(); + + return true; +} + +MessageQueue::MessageQueue() { + _field_14 = 0; + _parId = 0; + _dataId = 0; + _id = 0; + _isFinished = 0; + _flags = 0; + _queueName = 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 = new ExCommand(*it); + ex->_excFlags |= 2; + + _exCommands.push_back(ex); + } + _field_14 = src->_field_14; + + if (parId) + _parId = parId; + else + _parId = src->_parId; + + _id = g_fullpipe->_globalMessageQueueList->compact(); + _dataId = src->_dataId; + _flags = src->_flags; + + g_fullpipe->_globalMessageQueueList->addMessageQueue(this); + + _isFinished = 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_fullpipe->_globalMessageQueueList->removeQueueById(_id); + } + + finish(); + + free(_queueName); +} + +bool MessageQueue::load(MfcArchive &file) { + debug(5, "MessageQueue::load()"); + + _dataId = file.readUint16LE(); + + int count = file.readUint16LE(); + + assert(g_fullpipe->_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_fullpipe->_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 (_exCommands.size()) { + sendNextCommand(); + } else if (_counter == 0) { + _isFinished = 1; + finish(); + } +} + +void MessageQueue::messageQueueCallback1(int par) { + // Autosave + debug(3, "STUB: MessageQueue::messageQueueCallback1()"); +} + +ExCommand *MessageQueue::getExCommandByIndex(uint idx) { + if (idx > _exCommands.size()) + return 0; + + Common::List<ExCommand *>::iterator it = _exCommands.begin(); + + while (idx) { + ++it; + idx--; + } + + return *it; +} + +void MessageQueue::sendNextCommand() { + if (_exCommands.size()) { + 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_fullpipe->_exCommandList.begin(); it != g_fullpipe->_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_fullpipe->_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_fullpipe->_exCommandList.begin(); it != g_fullpipe->_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_fullpipe->_globalMessageQueueList->getMessageQueueById(ex1->_parId); + + if (mq) { + if (mq->getFlags() & 1) + return false; + + delete mq; + } + + it = g_fullpipe->_exCommandList.erase(it); + + if (ex1->_excFlags & 2) { + delete ex1; + } + } + } + return true; +} + +void MessageQueue::finish() { + if (!_parId) + return; + + MessageQueue *mq = g_fullpipe->_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; (ex = getExCommandByIndex(i)); 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 < _exCommands.size(); 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; + } +} + +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() { + for (uint i = 0; i < size();) { + if (((MessageQueue *)_storage[i])->_isFinished) { + disableQueueById(_storage[i]->_id); + remove_at(i); + } else { + i++; + } + } + + return size() + 1; +} + +void GlobalMessageQueueList::addMessageQueue(MessageQueue *msg) { + msg->setFlags(msg->getFlags() | 2); + + push_back(msg); +} + +void clearGlobalMessageQueueList1() { + warning("STUB: clearGlobalMessageQueueList1()"); +} + +bool removeMessageHandler(int16 id, int pos) { + if (g_fullpipe->_messageHandlers) { + MessageHandler *curItem = g_fullpipe->_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_fullpipe->_messageHandlers; + + if (!curItem) + return; + + int index = 0; + for (MessageHandler *i = g_fullpipe->_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_fullpipe->_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_fullpipe->_messageHandlers = msg; + } + + return true; +} + +int getMessageHandlersCount() { + int result; + MessageHandler *curItem = g_fullpipe->_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_fullpipe->_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_fullpipe->_messageHandlers; + newItem->id = id; + newItem->callback = callback; + newItem->index = 0; + + updateMessageHandlerIndex(g_fullpipe->_messageHandlers, 1); + g_fullpipe->_messageHandlers = newItem; + + return true; + } +} + +bool insertMessageHandler(int (*callback)(ExCommand *), int index, int16 id) { + if (getMessageHandlerById(id)) + return false; + + MessageHandler *curItem = g_fullpipe->_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_fullpipe->_messageHandlers; + if (curItem) { + do { + nextItem = curItem->nextItem; + + delete curItem; + + curItem = nextItem; + } while (nextItem); + + g_fullpipe->_messageHandlers = 0; + } +} + +void processMessages() { + if (!g_fullpipe->_isProcessingMessages) { + g_fullpipe->_isProcessingMessages = true; + + while (g_fullpipe->_exCommandList.size()) { + ExCommand *ex = g_fullpipe->_exCommandList.front(); + g_fullpipe->_exCommandList.pop_front(); + ex->handleMessage(); + } + g_fullpipe->_isProcessingMessages = false; + } +} + +void updateGlobalMessageQueue(int id, int objid) { + MessageQueue *m = g_fullpipe->_globalMessageQueueList->getMessageQueueById(id); + if (m) { + m->update(); + } +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/messages.h b/engines/fullpipe/messages.h new file mode 100644 index 0000000000..7ba9126d46 --- /dev/null +++ b/engines/fullpipe/messages.h @@ -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. + * + */ + +#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); + + bool handleMessage(); + void sendMessage(); + void postMessage(); + void handle(); +}; + +class ExCommand2 : public ExCommand { + public: + Common::Point **_points; + int _pointsSize; +}; + +class CObjstateCommand : public CObject { + public: + ExCommand _cmd; + char *_objCommandName; + int _value; + + public: + CObjstateCommand(); + virtual bool load(MfcArchive &file); +}; + +class MessageQueue : public CObject { + public: + int _id; + int _flags; + char *_queueName; + int16 _dataId; + int16 _field_12; + CObject *_field_14; + Common::List<ExCommand *> _exCommands; + int _counter; + int _field_38; + int _isFinished; + int _parId; + int _flag1; + + public: + MessageQueue(); + 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(); } + + ExCommand *getExCommandByIndex(uint idx); + + 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); +}; + +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 clearGlobalMessageQueueList1(); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MESSAGEQUEUE_H */ diff --git a/engines/fullpipe/modal.cpp b/engines/fullpipe/modal.cpp new file mode 100644 index 0000000000..6f1bc0cc1f --- /dev/null +++ b/engines/fullpipe/modal.cpp @@ -0,0 +1,106 @@ +/* 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/modal.h" +#include "fullpipe/messages.h" +#include "fullpipe/constants.h" +#include "fullpipe/scenes.h" + +namespace Fullpipe { + +bool CBaseModalObject::handleMessage(ExCommand *message) { + warning("STUB: CBaseModalObject::handleMessage()"); + + return true; +} + +bool CBaseModalObject::init(int counterdiff) { + warning("STUB: CBaseModalObject::init(%d)", counterdiff); + + return true; +} + +bool CBaseModalObject::update() { + warning("STUB: CBaseModalObject::update()"); + + return true; +} + +void CBaseModalObject::saveload() { + warning("STUB: CBaseModalObject::saveload()"); +} + + +CModalIntro::CModalIntro() { + _field_8 = 0; + _countDown = 0; + _needRedraw = 0; + if (g_vars->sceneIntro_skipIntro) { + _introFlags = 4; + } else { + _introFlags = 33; + _countDown = 150; + + PictureObject *pict = g_fullpipe->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_PIPETITLE, 0); + pict->setFlags(pict->_flags & 0xFFFB); + } + g_vars->sceneIntro_skipIntro = false; + _sfxVolume = g_fullpipe->_sfxVolume; +} + +bool CModalIntro::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 (_needRedraw) { + if (!(_introFlags & 0x10)) { + _countDown = 0; + g_vars->sceneIntro_needBlackout = true; + return true; + } + g_vars->sceneIntro_playing = false; + g_vars->sceneIntro_needBlackout = true; + } + + return true; +} + +void FullpipeEngine::openMap() { + warning("STUB: FullpipeEngine::openMap()"); +} + +void FullpipeEngine::openHelp() { + warning("STUB: FullpipeEngine::openHelp()"); +} + +void FullpipeEngine::openMainMenu() { + warning("STUB: FullpipeEngine::openMainMenu()"); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/modal.h b/engines/fullpipe/modal.h new file mode 100644 index 0000000000..73236e8e5b --- /dev/null +++ b/engines/fullpipe/modal.h @@ -0,0 +1,59 @@ +/* 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 CBaseModalObject { + public: + + CBaseModalObject *_parentObj; + + public: + CBaseModalObject() : _parentObj(0) {} + virtual ~CBaseModalObject() {} + + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual bool update(); + + void saveload(); +}; + +class CModalIntro : public CBaseModalObject { + int _field_8; + int _introFlags; + int _countDown; + int _needRedraw; + int _sfxVolume; + + public: + CModalIntro(); + + virtual bool handleMessage(ExCommand *message); +}; + +} // 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..380f582c08 --- /dev/null +++ b/engines/fullpipe/module.mk @@ -0,0 +1,31 @@ +MODULE := engines/fullpipe + +MODULE_OBJS = \ + behavior.o \ + detection.o \ + fullpipe.o \ + gameloader.o \ + gfx.o \ + init.o \ + input.o \ + interaction.o \ + inventory.o \ + lift.o \ + messages.o \ + modal.o \ + motion.o \ + ngiarchive.o \ + scene.o \ + scenes.o \ + sound.o \ + stateloader.o \ + statics.o \ + utils.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..514dde5185 --- /dev/null +++ b/engines/fullpipe/motion.cpp @@ -0,0 +1,280 @@ +/* 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/motion.h" + +namespace Fullpipe { + +bool CMotionController::load(MfcArchive &file) { + // Is originally empty file.readClass(); + + debug(5, "CMotionController::load()"); + + return true; +} + +bool CMctlCompound::load(MfcArchive &file) { + debug(5, "CMctlCompound::load()"); + + int count = file.readUint32LE(); + + debug(6, "CMctlCompound::count = %d", count); + + for (int i = 0; i < count; i++) { + debug(6, "CompoundArray[%d]", i); + CMctlCompoundArrayItem *obj = (CMctlCompoundArrayItem *)file.readClass(); + + int count1 = file.readUint32LE(); + + debug(6, "ConnectionPoint::count: %d", count1); + for (int j = 0; j < count1; j++) { + debug(6, "ConnectionPoint[%d]", j); + CMctlConnectionPoint *obj1 = (CMctlConnectionPoint *)file.readClass(); + + obj->_connectionPoints.push_back(*obj1); + } + + obj->_field_20 = file.readUint32LE(); + obj->_field_24 = file.readUint32LE(); + + debug(6, "graphReact"); + obj->_movGraphReactObj = (CMovGraphReact *)file.readClass(); + + _motionControllers.push_back(*obj); + } + + return true; +} + +void CMctlCompound::addObject(StaticANIObject *obj) { + warning("STUB: CMctlCompound::addObject()"); +} + +void CMctlCompound::initMovGraph2() { + warning("STUB: CMctlCompound::initMovGraph2()"); +} + +MessageQueue *CMctlCompound::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { + warning("STUB: CMctlCompound::method34()"); + + return 0; +} + +MessageQueue *CMctlCompound::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { + warning("STUB: CMctlCompound::method4C()"); + + return 0; +} + +bool CMctlCompoundArray::load(MfcArchive &file) { + debug(5, "CMctlCompoundArray::load()"); + + int count = file.readUint32LE(); + + debug(0, "CMctlCompoundArray::count = %d", count); + + assert(0); + + return true; +} + +CMovGraph::CMovGraph() { + warning("STUB: CMovGraph::CMovGraph()"); + _itemsCount = 0; + _items = 0; + //_callback1 = CMovGraphCallback1; // TODO + _field_44 = 0; + // insertMessageHandler(CMovGraph_messageHandler, getMessageHandlersCount() - 1, 129); +} + +bool CMovGraph::load(MfcArchive &file) { + debug(5, "CMovGraph::load()"); + + _links.load(file); + _nodes.load(file); + + return true; +} + +void CMovGraph::addObject(StaticANIObject *obj) { + warning("STUB: CMovGraph::addObject()"); +} + +CMovGraphLink::CMovGraphLink() { + _distance = 0; + _angle = 0; + _flags = 0x10000000; + _movGraphNode2 = 0; + _movGraphNode1 = 0; + _field_3C = 0; + _field_38 = 0; + _movGraphReact = 0; + _name = 0; +} + +bool CMovGraphLink::load(MfcArchive &file) { + debug(5, "CMovGraphLink::load()"); + + _dwordArray1.load(file); + _dwordArray2.load(file); + + _flags = file.readUint32LE(); + + debug(8, "GraphNode1"); + _movGraphNode1 = (CMovGraphNode *)file.readClass(); + debug(8, "GraphNode2"); + _movGraphNode2 = (CMovGraphNode *)file.readClass(); + + _distance = file.readDouble(); + _angle = file.readDouble(); + + debug(8, "distance: %g, angle: %g", _distance, _angle); + + _movGraphReact = (CMovGraphReact *)file.readClass(); + _name = file.readPascalString(); + + return true; +} + +bool CMovGraphNode::load(MfcArchive &file) { + debug(5, "CMovGraphNode::load()"); + + _field_14 = file.readUint32LE(); + _x = file.readUint32LE(); + _y = file.readUint32LE(); + _distance = file.readUint32LE(); + + return true; +} + +CReactParallel::CReactParallel() { + _x1 = 0; + _x2 = 0; + _dy = 0; + _dx = 0; + _points = 0; + _y1 = 0; + _y2 = 0; +} + +bool CReactParallel::load(MfcArchive &file) { + debug(5, "CReactParallel::load()"); + + _x1 = file.readUint32LE(); + _y1 = file.readUint32LE(); + _x2 = file.readUint32LE(); + _y2 = file.readUint32LE(); + _dx = file.readUint32LE(); + _dy = file.readUint32LE(); + + createRegion(); + + return true; +} + +void CReactParallel::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; + 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)(_x1 + _dy * cs); + _points[2]->y = (int16)(_y2 + _dy * sn); + + _points[3]->x = (int16)(_x1 + _dy * cs); + _points[3]->y = (int16)(_y1 + _dy * sn); + + // GdiObject::Attach(_rgn, CreatePolygonRgn(_points, 4, 2); +} + +CReactPolygonal::CReactPolygonal() { + _field_C = 0; + _points = 0; + _pointCount = 0; + _field_10 = 0; +} + +bool CReactPolygonal::load(MfcArchive &file) { + debug(5, "CReactPolygonal::load()"); + + _field_C = file.readUint32LE(); + _field_10 = 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 CReactPolygonal::createRegion() { + if (_points) { + + // GdiObject::Attach(_rgn, CreatePolygonRgn(_points, _pointCount, 2); + } +} + +int startWalkTo(int objId, int objKey, int x, int y, int a5) { + warning("STUB: startWalkTo(%d, %d, %d, %d, %d)", objId, objKey, x, y, a5); + + return 0; +} + +int doSomeAnimation(int objId, int objKey, int a3) { + warning("STUB: doSomeAnimation(%d, %d, %d)", objId, objKey, a3); + + return 0; +} + +int 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..85a52918f0 --- /dev/null +++ b/engines/fullpipe/motion.h @@ -0,0 +1,186 @@ +/* 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 + +namespace Fullpipe { + +int startWalkTo(int objId, int objKey, int x, int y, int a5); +int doSomeAnimation(int objId, int objKey, int a3); +int doSomeAnimation2(int objId, int objKey); + +class CMotionController : public CObject { + public: + int _field_4; + bool _isEnabled; + + public: + CMotionController() : _isEnabled(true) {} + virtual bool load(MfcArchive &file); + + void setEnabled() { _isEnabled = true; } + void clearEnabled() { _isEnabled = false; } + + virtual void addObject(StaticANIObject *obj) {} + virtual void freeItems() {} +}; + +class CMctlCompoundArray : public Common::Array<CObject>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class CMctlConnectionPointsArray : public Common::Array<CObject>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class CMctlCompound : public CMotionController { + CMctlCompoundArray _motionControllers; + + public: + virtual bool load(MfcArchive &file); + + virtual void addObject(StaticANIObject *obj); + void initMovGraph2(); + + MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); + MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); +}; + +class Unk2 : public CObject { + int _items; + int _count; + + public: + Unk2() : _items(0), _count(0) {} +}; + +class CMovGraphNode : public CObject { + int _x; + int _y; + int _distance; + int16 _field_10; + int _field_14; + + public: + CMovGraphNode() : _x(0), _y(0), _distance(0), _field_10(0), _field_14(0) {} + virtual bool load(MfcArchive &file); +}; + +class CMovGraphReact : public CObject { + // Empty +}; + +class CMctlCompoundArrayItem : public CObject { + friend class CMctlCompound; + + protected: + CMotionController *_motionControllerObj; + CMovGraphReact *_movGraphReactObj; + CMctlConnectionPointsArray _connectionPoints; + int _field_20; + int _field_24; + int _field_28; + + public: + CMctlCompoundArrayItem() : _movGraphReactObj(0) {} +}; + +class CReactParallel : public CMovGraphReact { + //CRgn _rgn; + int _x1; + int _y1; + int _x2; + int _y2; + int _dx; + int _dy; + Common::Point **_points; + + public: + CReactParallel(); + virtual bool load(MfcArchive &file); + void createRegion(); +}; + +class CReactPolygonal : public CMovGraphReact { + //CRgn _rgn; + int _field_C; + int _field_10; + int _pointCount; + Common::Point **_points; + + public: + CReactPolygonal(); + virtual bool load(MfcArchive &file); + void createRegion(); +}; + +class CMovGraphLink : public CObject { + CMovGraphNode *_movGraphNode1; + CMovGraphNode *_movGraphNode2; + CDWordArray _dwordArray1; + CDWordArray _dwordArray2; + int _flags; + int _field_38; + int _field_3C; + double _distance; + double _angle; + CMovGraphReact *_movGraphReact; + char *_name; + + public: + CMovGraphLink(); + virtual bool load(MfcArchive &file); +}; + +class CMovGraph : public CMotionController { + CObList _nodes; + CObList _links; + int _field_44; + int _items; + int _itemsCount; + int (*_callback1)(int, int, int); + Unk2 _unk2; + + public: + CMovGraph(); + virtual bool load(MfcArchive &file); + + virtual void addObject(StaticANIObject *obj); +}; + +class CMctlConnectionPoint : public CObject { + int _connectionX; + int _connectionY; + int _field_C; + int _field_10; + int16 _field_14; + int16 _field_16; + int _messageQueueObj; + int _motionControllerObj; +}; + +} // 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..5d895c17a0 --- /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_fullpipe->_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_fullpipe->_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..015df727e9 --- /dev/null +++ b/engines/fullpipe/objectnames.h @@ -0,0 +1,250 @@ +/* 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_TumyTrampie "\xc1\xe0\xf2\xf3\xf2\xe0" // "Батута" +#define sO_WithoutBoot "\xc1\xe5\xe7 \xe1\xee\xf2\xe8\xed\xea\xe0" // "Без ботинка" +#define sO_WithoutJug "\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_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_32_Lies "\xc2_32 \xeb\xe5\xe6\xe8\xf2" // "В_32 лежит" +#define sO_In_32_Stands "\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_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_Plank_25 "\xc4\xee\xf1\xea\xe0_25" // "Доска_25" +#define sO_Plank_34 "\xc4\xee\xf1\xea\xe0_34" // "Доска_34" +#define sO_DudeJumped "\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_Eats "\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_ClosedShe "\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_Playing "\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_SwingingWithBoot "\xca\xe0\xf2\xe0\xe5\xf2\xf1\xff \xf1 \xe1\xee\xf2\xe8\xed\xea\xee\xec" // "Катается с ботинком" +#define sO_Swinging "\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_StarsDown_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_NotAvailable "\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_OpenedShe "\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_Available "\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_Drinking "\xcf\xfc\xe5\xf2" // "Пьет" +#define sO_BrokenInPieces "\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_Unfolded "\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_WithShovel "\xd1 \xeb\xee\xef\xe0\xf2\xee\xe9" // "С лопатой" +#define sO_WithTiny "\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_Sitting "\xd1\xe8\xe4\xe8\xf2" // "Сидит" +#define sO_Laughing "\xd1\xec\xe5\xe5\xf2\xf1\xff" // "Смеется" +#define sO_WithEveryone "\xd1\xee \xe2\xf1\xe5\xec\xe8" // "Со всеми" +#define sO_WithMop "\xd1\xee \xf8\xe2\xe0\xe1\xf0\xee\xe9" // "Со шваброй" +#define sO_WithHose "\xd1\xee \xf8\xeb\xe0\xed\xe3\xee\xec" // "Со шлангом" +#define sO_WithBrush "\xd1\xee \xf9\xe5\xf2\xea\xee\xe9" // "Со щеткой" +#define sO_Sleeping "\xd1\xef\xe8\xf2" // "Спит" +#define sO_OnRight "\xd1\xef\xf0\xe0\xe2\xe0" // "Справа" +#define sO_StandsInBoots "\xd1\xf2\xee\xe8\xf2 \xe2 \xe1\xee\xf2\xe8\xed\xea\xe0\xf5" // "Стоит в ботинках" +#define sO_StandsInCorner "\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_Gurad_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_NearDude "\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_Janitress "\xd3\xe1\xee\xf0\xf9\xe8\xf6\xe0" // "Уборщица" +#define sO_Gone "\xd3\xe5\xf5\xe0\xeb\xe0" // "Уехала" +#define sO_FallenOnce "\xd3\xef\xe0\xeb \xf0\xe0\xe7" // "Упал раз" +#define sO_FallenBrush "\xd3\xef\xe0\xeb\xe0 \xf9\xe5\xf2\xea\xe0" // "Упала щетка" +#define sO_NotBroken "\xd6\xe5\xeb\xe0" // "Цела" +#define sO_ScratchingBelly "\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..9e7c7531a7 --- /dev/null +++ b/engines/fullpipe/objects.h @@ -0,0 +1,97 @@ +/* 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 CGameVar : public CObject { + public: + CGameVar *_nextVarObj; + CGameVar *_prevVarObj; + CGameVar *_parentVarObj; + CGameVar *_subVars; + CGameVar *_field_14; + char *_varName; + VarValue _value; + int _varType; + + public: + CGameVar(); + virtual bool load(MfcArchive &file); + CGameVar *getSubVarByName(const char *name); + bool setSubVarAsInt(const char *name, int value); + int getSubVarAsInt(const char *name); + CGameVar *addSubVarAsInt(const char *name, int value); + bool addSubVar(CGameVar *subvar); + int getSubVarsCount(); + CGameVar *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..6ac062fb37 --- /dev/null +++ b/engines/fullpipe/scene.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 "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; +} + +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); +} + +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_fullpipe->_currArchive = 0; + + free(fname); + free(archname); +} + +Scene::Scene() { + _sceneId = 0; + _field_BC = 0; + _shadows = 0; + _soundList = 0; + _libHandle = 0; + _sceneName = 0; +} + +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_fullpipe->_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_fullpipe->_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_fullpipe->_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_fullpipe->_soundEnabled) { + _soundList = new SoundList(); + + if (g_fullpipe->_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++) + ((StaticANIObject *)_staticANIObjectList1[i])->initMovements(); +} + +void Scene::init() { + _x = 0; + _y = 0; + + g_fullpipe->_sceneRect.moveTo(0, 0); + + for (uint i = 0; i < _picObjList.size(); i++) + ((PictureObject *)_picObjList[i])->clearFlags(); + + for (uint i = 0; i < _staticANIObjectList1.size(); i++) + ((StaticANIObject *)_staticANIObjectList1[i])->clearFlags(); + + if (_staticANIObjectList2.size() != _staticANIObjectList1.size()) { + _staticANIObjectList2.clear(); + + for (CPtrList::iterator s = _staticANIObjectList1.begin(); s != _staticANIObjectList1.end(); ++s) + _staticANIObjectList2.push_back(*s); + } +} + +StaticANIObject *Scene::getAniMan() { + StaticANIObject *aniMan = getStaticANIObject1ById(ANI_MAN, -1); + + deleteStaticANIObject(aniMan); + + return aniMan; +} + +StaticANIObject *Scene::getStaticANIObject1ById(int obj, int a3) { + for (CPtrList::iterator s = _staticANIObjectList1.begin(); s != _staticANIObjectList1.end(); ++s) { + StaticANIObject *o = (StaticANIObject *)*s; + if (o->_id == obj && (a3 == -1 || o->_okeyCode == a3)) + return o; + } + + return 0; +} + +StaticANIObject *Scene::getStaticANIObject1ByName(char *name, int a3) { + for (uint n = 0; n < _staticANIObjectList1.size(); n++) { + StaticANIObject *o = (StaticANIObject *)_staticANIObjectList1[n]; + if (!strcmp(o->_objectName, name) && (a3 == -1 || o->_okeyCode == a3)) + return o; + } + + return 0; +} + +void Scene::deleteStaticANIObject(StaticANIObject *obj) { + for (uint n = 0; n < _staticANIObjectList1.size(); n++) + if ((StaticANIObject *)_staticANIObjectList1[n] == obj) { + _staticANIObjectList1.remove_at(n); + break; + } + + for (uint n = 0; n < _staticANIObjectList2.size(); n++) + if ((StaticANIObject *)_staticANIObjectList2[n] == obj) { + _staticANIObjectList2.remove_at(n); + 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; + } +} + +PictureObject *Scene::getPictureObjectById(int objId, int flags) { + for (uint i = 0; 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 (((MessageQueue *)_messageQueueList[i])->_dataId == messageId) + return (MessageQueue *)_messageQueueList[i]; + + return 0; +} + +MessageQueue *Scene::getMessageQueueByName(char *name) { + for (uint i = 0; i < _messageQueueList.size(); i++) + if (!strcmp(((MessageQueue *)_messageQueueList[i])->_queueName, name)) + return (MessageQueue *)_messageQueueList[i]; + + return 0; +} + +void Scene::preloadMovements(CGameVar *var) { + CGameVar *preload = var->getSubVarByName("PRELOAD"); + if (!preload) + return; + + for (CGameVar *i = preload->_subVars; i; i = i->_nextVarObj) { + StaticANIObject *ani = getStaticANIObject1ByName(i->_varName, -1); + + if (ani) { + CGameVar *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) { + CGameVar *cursorsVar = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(varname)->getSubVarByName("CURSORS"); + + if (!cursorsVar || !cursorsVar->_subVars) + return; + + int maxId = 0; + int minId = 0xffff; + + for (CGameVar *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_fullpipe->_minCursorId = minId; + g_fullpipe->_maxCursorId = maxId; + + g_fullpipe->_objectIdCursors.resize(maxId - minId + 1); + + for (CGameVar *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_fullpipe->_objectIdCursors[obj->_id - minId] = pic->_id; + } +} + +bool Scene::compareObjPriority(const void *p1, const void *p2) { + if (((const StaticANIObject *)p1)->_priority > ((const StaticANIObject *)p2)->_priority) + return true; + + return false; +} + +void Scene::objectList_sortByPriority(CPtrList &list) { + Common::sort(list.begin(), list.end(), Scene::compareObjPriority); +} + +void Scene::draw() { + debug(0, ">>>>> Scene::draw()"); + updateScrolling(); + + drawContent(60000, 0, true); + + objectList_sortByPriority(_staticANIObjectList2); + + for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) { + ((StaticANIObject *)*s)->draw2(); + } + + int priority = -1; + for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) { + drawContent(((StaticANIObject *)*s)->_priority, priority, false); + ((StaticANIObject *)*s)->draw(); + + priority = ((StaticANIObject *)*s)->_priority; + } + + drawContent(-1, priority, false); +} + +void Scene::updateScrolling() { + debug(0, "STUB Scene::updateScrolling()"); +} + +void Scene::updateScrolling2() { + warning("STUB Scene::updateScrolling2()"); +} + +StaticANIObject *Scene::getStaticANIObjectAtPos(int x, int y) { + StaticANIObject *res = 0; + + for (uint i = 0; i < _staticANIObjectList1.size(); i++) { + StaticANIObject *p = (StaticANIObject *)_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(0, "Scene::update(%d)", counterdiff); + + for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) + ((StaticANIObject *)*s)->update(counterdiff); +} + +void Scene::drawContent(int minPri, int maxPri, bool drawBg) { + if (!_picObjList.size() && !_bigPictureArray1Count) + return; + + if (_palette) { + g_fullpipe->_globalPalette = _palette->_data; + } + + debug(8, "Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); + + if (_picObjList.size() > 2) { // We need to z-sort them + objectList_sortByPriority(_picObjList); + } + + if (minPri == -1 && _picObjList.size()) + minPri = ((PictureObject *)_picObjList.back())->_priority - 1; + + if (maxPri == -1) + maxPri = 60000; + + debug(8, "-> Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); + + Common::Point point; + + debug(8, "_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_fullpipe->_sceneRect.left % point.x; + + if (bgStX < 0) + bgStX += point.x; + + int bgNumX = bgStX / width; + int bgOffsetX = bgStX % width; + + int bgStY = g_fullpipe->_sceneRect.top % point.y; + + if (bgStY < 0) + bgStY += point.y; + + int bgNumY = bgStY / height; + int bgOffsetY = bgStY % height; + + int bgPosX = g_fullpipe->_sceneRect.left - bgOffsetX; + + if (bgPosX < g_fullpipe->_sceneRect.right - 1) { + while (1) { + int v25 = bgNumY; + for (int y = g_fullpipe->_sceneRect.top - bgOffsetY; y < g_fullpipe->_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 v32 = point.x + bgPosX; + bgPosX += point.x; + bgNumX++; + + if (bgNumX >= _bigPictureArray1Count) { + if (!(((PictureObject *)_picObjList[0])->_flags & 0x2)) + break; + bgNumX = 0; + } + if (v32 >= g_fullpipe->_sceneRect.right - 1) + break; + } + } + } + + + for (uint i = 1; i < _picObjList.size(); i++) { + PictureObject *obj = (PictureObject *)_picObjList[i]; + + debug(8, "pri: %d", obj->_priority); + 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_fullpipe->_sceneRect.right) { + objX -= width; + obj->setOXY(objX, objY); + } + for (int j = width + objX; width + objX < g_fullpipe->_sceneRect.left; j = width + objX) { + objX = j; + obj->setOXY(j, objY); + } + } + + if (obj->_flags & 0x10) { + while (objY > g_fullpipe->_sceneRect.bottom) { + objY -= height; + obj->setOXY(objX, objY); + } + for (int j = objY + height; objY + height < g_fullpipe->_sceneRect.top; j = objY + height) { + objY = j; + obj->setOXY(objX, j); + } + } + if (obj->_flags & 4) + obj->draw(); + + if (obj->_flags & 2) { + if (objX > g_fullpipe->_sceneRect.left) { + obj->setOXY(objX - width, objY); + obj->draw(); + obj->setOXY(objX, objY); + } + if (width + objX < g_fullpipe->_sceneRect.right) { + obj->setOXY(width + objX, objY); + obj->draw(); + obj->setOXY(objX, objY); + } + } + + if (obj->_flags & 0x20) { + if (objY > g_fullpipe->_sceneRect.top) { + obj->setOXY(objX, objY - height); + obj->draw(); + obj->setOXY(objX, objY); + } + if (height + objY < g_fullpipe->_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..c1c8d47ba8 --- /dev/null +++ b/engines/fullpipe/scene.h @@ -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. + * + */ + +#ifndef FULLPIPE_SCENE_H +#define FULLPIPE_SCENE_H + +#include "fullpipe/gfx.h" + +namespace Fullpipe { + +class MessageQueue; + +class Scene : public Background { + public: + CPtrList _staticANIObjectList1; + CPtrList _staticANIObjectList2; + CPtrList _messageQueueList; + CPtrList _faObjectList; + Shadows *_shadows; + SoundList *_soundList; + int16 _sceneId; + char *_sceneName; + int _field_BC; + NGIArchive *_libHandle; + + public: + 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(CGameVar *var); + + StaticANIObject *getStaticANIObjectAtPos(int x, int y); + PictureObject *getPictureObjectAtPos(int x, int y); + int getPictureObjectIdAtPos(int x, int y); + + void initObjectCursors(const char *name); + + private: + static bool compareObjPriority(const void *p1, const void *p2); + void objectList_sortByPriority(CPtrList &list); +}; + +class SceneTag : public CObject { + public: + int _field_4; + char *_tag; + Scene *_scene; + int16 _sceneId; + int16 _field_12; + + 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..f6620a2fc7 --- /dev/null +++ b/engines/fullpipe/scenes.cpp @@ -0,0 +1,1510 @@ +/* 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/gfx.h" +#include "fullpipe/objects.h" +#include "fullpipe/statics.h" +#include "fullpipe/scene.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/sound.h" +#include "fullpipe/motion.h" +#include "fullpipe/input.h" +#include "fullpipe/messages.h" +#include "fullpipe/behavior.h" + +#include "fullpipe/constants.h" +#include "fullpipe/objectnames.h" +#include "fullpipe/scenes.h" +#include "fullpipe/modal.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +int defaultUpdateCursor(); +void setElevatorButton(const char *name, int state); + +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 sceneDbgMenu_initScene(Scene *sc); +int sceneHandlerDbgMenu(ExCommand *cmd); + +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; + + selector = 0; +} + +bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) { + CGameVar *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); + + if (_aniMan) { + _aniMan2 = _aniMan; + CMctlCompound *cmp = getSc2MctlCompoundBySceneId(entrance->_sceneId); + cmp->initMovGraph2(); + cmp->addObject(_aniMan); + cmp->setEnabled(); + getGameLoaderInteractionController()->enableFlag24(); + setInputDisabled(0); + } else { + _aniMan2 = 0; + } + + scene->setPictureObjectsFlag4(); + + for (CPtrList::iterator s = scene->_staticANIObjectList1.begin(); s != scene->_staticANIObjectList1.end(); ++s) { + StaticANIObject *o = (StaticANIObject *)*s; + o->setFlags(o->_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; + +#if 0 + 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); + j_Scene_sc03_sub_40F160(scene); + _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); + sub_415300(); + 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); + sub_416890(); + 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_sub_41A980(); + _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_sub_41D2B0(); + _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_sub_41F060(); + _updateCursorCallback = scene17_updateCursor; + break; + + case SC_18: + sub_40E1B0(); + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_18"); + scene->preloadMovements(sceneVar); + sub_4062D0(); + if (dword_476C38) + 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_scene3) { + g_scene3 = accessScene(SC_18); + getGameLoader()->loadScene(SC_18); + scene18_initScene2(g_scene3); + sub_40C5F0(); + scene19_sub_420B10(g_scene3, entrance->field_4); + dword_476C38 = 1; + } + sub_40C650(); + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_19"); + scene->preloadMovements(sceneVar); + sub_4062D0(); + if (dword_476C38) + scene18_initScene1(scene); + else + scene19_initScene2(); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_19"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler19, 2); + scene19_sub_4211D0(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_sub_4228A0(); + 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_sub_423B00(); + _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_sub_423DD0(); + _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_sub_4253B0(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_sub_426140(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_sub_42C5C0(); + _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_sub_42CEF0(); + _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_sub_42DEE0(); + _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); + sceneFinal1_initScene(); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_FINAL1"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandlerFinal1, 2); + _updateCursorCallback = sceneFinal1_updateCursor; + break; +#endif + + 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: + _behaviorManager->initBehavior(0, 0); + break; + } + + return true; +} + +void setElevatorButton(const char *name, int state) { + CGameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons); + + if (var) + var->setSubVarAsInt(name, state); +} + +void global_messageHandler_KickStucco() { + warning("STUB: global_messageHandler_KickStucco()"); +} + +void global_messageHandler_KickMetal() { + warning("STUB: global_messageHandler_KickMetal()"); +} + +int global_messageHandler1(ExCommand *cmd) { + debug(0, "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_fullpipe->_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_fullpipe->_aniMan->_shadowsOn = 1; + break; + case MSG_HMRKICK_STUCCO: + global_messageHandler_KickStucco(); + break; + case MSG_MANSHADOWSOFF: + g_fullpipe->_aniMan->_shadowsOn = 0; + break; + case MSG_DISABLESAVES: + g_fullpipe->disableSaves(cmd); + break; + case MSG_ENABLESAVES: + g_fullpipe->enableSaves(); + break; + case MSG_HMRKICK_METAL: + global_messageHandler_KickMetal(); + break; + case 29: // left mouse + if (g_fullpipe->_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 + switch (cmd->_keyCode) { + case '\x1B': // ESC + if (g_fullpipe->_currentScene) { + getGameLoaderInventory()->unselectItem(0); + g_fullpipe->openMainMenu(); + cmd->_messageKind = 0; + } + break; + case 't': + g_fullpipe->stopAllSounds(); + cmd->_messageKind = 0; + break; + case 'u': + g_fullpipe->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_fullpipe->_flgCanOpenMap) + g_fullpipe->openMap(); + cmd->_messageKind = 0; + break; + case 'p': + if (g_fullpipe->_flgCanOpenMap) + g_fullpipe->openHelp(); + cmd->_messageKind = 0; + break; + default: + g_fullpipe->defHandleKeyDown(cmd->_keyCode); + break; + } + break; + case 33: + if (!g_fullpipe->_inventoryScene) + break; + + int invItem; + + if (g_fullpipe->_updateFlag && (invItem = g_fullpipe->_inventory->getHoveredItem(&g_fullpipe->_mouseScreenPos))) { + g_fullpipe->_cursorId = PIC_CSR_ITN; + if (!g_fullpipe->_currSelectedInventoryItemId && !g_fullpipe->_aniMan->_movement && + !(g_fullpipe->_aniMan->_flags & 0x100) && g_fullpipe->_aniMan->isIdle()) { + int st = g_fullpipe->_aniMan->_statics->_staticsId; + ExCommand *newex = 0; + + if (st == ST_MAN_RIGHT) { + newex = new ExCommand(g_fullpipe->_aniMan->_id, 1, rMV_MAN_LOOKUP, 0, 0, 0, 1, 0, 0, 0); + } else if (st == (0x4000 | ST_MAN_RIGHT)) { + newex = new ExCommand(g_fullpipe->_aniMan->_id, 1, MV_MAN_LOOKUP, 0, 0, 0, 1, 0, 0, 0); + } + + if (newex) { + newex->_keyCode = g_fullpipe->_aniMan->_okeyCode; + newex->_excFlags |= 3; + newex->postMessage(); + } + } + + if (g_fullpipe->_currSelectedInventoryItemId != invItem) + g_fullpipe->playSound(SND_CMN_070, 0); + + g_fullpipe->_currSelectedInventoryItemId = invItem; + g_fullpipe->setCursor(g_fullpipe->_cursorId); + break; + } + if (g_fullpipe->_updateCursorCallback) + g_fullpipe->_updateCursorCallback(); + + g_fullpipe->_currSelectedInventoryItemId = 0; + g_fullpipe->setCursor(g_fullpipe->_cursorId); + break; + case 65: // open map + if (cmd->_field_2C == 11 && cmd->_field_14 == ANI_INV_MAP && g_fullpipe->_flgCanOpenMap) + g_fullpipe->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_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (ani) + ani->_priority = cmd->_field_14; + break; + + case 25: + ani = g_fullpipe->_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_fullpipe->_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_fullpipe->_defMsgArray.begin(); it != g_fullpipe->_defMsgArray.end(); ++it) + if (((ExCommand *)*it)->_field_24 == _messageNum) { + ((ExCommand *)*it)->firef34(v13); + res = 1; + } +#endif + + //debug_msg(_messageNum); + + if (!g_fullpipe->_soundEnabled || cmd->_messageNum != 33 || g_fullpipe->_currSoundListCount <= 0) + return res; + + for (int snd = 0; snd < g_fullpipe->_currSoundListCount; snd++) { + SoundList *s = g_fullpipe->_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_fullpipe->_inputDisabled) + cmd->_messageKind = 0; + break; + default: + break; + } + } + + StaticANIObject *ani, *ani2; + + switch (cmd->_messageKind) { + case 17: + switch (cmd->_messageNum) { + case 61: + return g_fullpipe->_gameLoader->preloadScene(cmd->_parentId, cmd->_keyCode); + case 62: + return g_fullpipe->_gameLoader->gotoScene(cmd->_parentId, cmd->_keyCode); + case 64: + if (g_fullpipe->_currentScene && g_fullpipe->_msgObjectId2 + && (!(cmd->_keyCode & 4) || g_fullpipe->_msgObjectId2 != cmd->_field_14 || g_fullpipe->_msgId != cmd->_field_20)) { + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_msgObjectId2, g_fullpipe->_msgId); + if (ani) { + ani->_flags &= 0xFF7F; + ani->_flags &= 0xFEFF; + ani->deleteFromGlobalMessageQueue(); + } + } + g_fullpipe->_msgX = 0; + g_fullpipe->_msgY = 0; + g_fullpipe->_msgObjectId2 = 0; + g_fullpipe->_msgId = 0; + if ((cmd->_keyCode & 1) || (cmd->_keyCode & 2)) { + g_fullpipe->_msgX = cmd->_x; + g_fullpipe->_msgY = cmd->_y; + } + if (cmd->_keyCode & 4) { + g_fullpipe->_msgObjectId2 = cmd->_field_14; + g_fullpipe->_msgId = cmd->_field_20; + } + return result; + case 29: + if (!g_fullpipe->_currentScene) + return result; + + if (g_fullpipe->_gameLoader->_interactionController->_flag24) { + ani = g_fullpipe->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + ani2 = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_gameLoader->_field_FA, -1); + if (ani) { + if (g_fullpipe->_msgObjectId2 == ani->_id && g_fullpipe->_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_fullpipe->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fullpipe->_currentScene->getPictureObjectById(id, 0); + if (pic) { + if (g_fullpipe->_msgObjectId2 == pic->_id && g_fullpipe->_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_fullpipe->_currentScene->_sceneId)->_isEnabled && cmd->_keyCode <= 0) { + if (g_fullpipe->_msgX != cmd->_sceneClickX || g_fullpipe->_msgY != cmd->_sceneClickY) { + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_gameLoader->_field_FA, -1); + if (!ani || (ani->isIdle() && !(ani->_flags & 0x80) && !(ani->_flags & 0x100))) { + result = startWalkTo(g_fullpipe->_gameLoader->_field_FA, -1, cmd->_sceneClickX, cmd->_sceneClickY, 0); + if (result) { + ExCommand *ex = new ExCommand(g_fullpipe->_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_fullpipe->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_fullpipe->_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_fullpipe->_currentScene, cmd->_parentId, cmd->_x, cmd->_y, cmd->_field_14); + getGameLoaderInventory()->rebuildItemRects(); + return 1; + } + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_gameLoader->_field_FA, -1); + if (ani) { + getGameLoaderInventory()->removeItem2(g_fullpipe->_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_fullpipe->_currentScene) { + GameObject *obj; + if (cmd->_field_14) + obj = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_x, cmd->_y); + else + obj = g_fullpipe->_currentScene->getPictureObjectById(cmd->_x, cmd->_y); + handleObjectInteraction(g_fullpipe->_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) { + CObjstateCommand *c = (CObjstateCommand *)cmd; + result = 1; + g_fullpipe->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_fullpipe->_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_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->trySetMessageQueue(cmd->_messageNum, cmd->_parId); + break; + + case 1: { + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_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_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->startAnimEx(cmd->_messageNum, cmd->_parId, -1, -1); + break; + + case 20: { + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_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 >> 3, flags); + } else { + ani->startAnimSteps(cmd->_messageNum, cmd->_parId, cmd->_x, cmd->_y, cmd2->_points, cmd2->_pointsSize >> 3, flags); + } + break; + } + case 21: + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->queueMessageQueue(0); + ani->playIdle(); + break; + case 9: + // Nop in original + break; + case 3: + g_fullpipe->_currentScene->_y = cmd->_messageNum - cmd->_messageNum % g_fullpipe->_scrollSpeed; + break; + + case 4: + g_fullpipe->_currentScene->_x = cmd->_messageNum - cmd->_messageNum % g_fullpipe->_scrollSpeed; + break; + + case 19: { + if (!g_fullpipe->_currentScene) + break; + ani = g_fullpipe->_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_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->_flags |= 4; + ani->changeStatics2(cmd->_messageNum); + break; + + case 6: + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->hide(); + break; + + case 27: + if (!g_fullpipe->_currentScene || g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode) == 0) { + ani = g_fullpipe->accessScene(cmd->_field_20)->getStaticANIObject1ById(cmd->_parentId, -1); + if (ani) { + ani = new StaticANIObject(ani); + g_fullpipe->_currentScene->addStaticANIObject(ani, 1); + } + } + + // fall through + case 5: + if (g_fullpipe->_currentScene) + ani = g_fullpipe->_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_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_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_fullpipe->_currentScene->_picObjList.size()) + break; + + int offX = g_fullpipe->_scrollSpeed * (cmd->_x / g_fullpipe->_scrollSpeed); + int offY = g_fullpipe->_scrollSpeed * (cmd->_y / g_fullpipe->_scrollSpeed); + + if (cmd->_messageNum) { + g_fullpipe->_currentScene->_x = offX - g_fullpipe->_sceneRect.left; + g_fullpipe->_currentScene->_y = offY - g_fullpipe->_sceneRect.top; + + if (cmd->_field_24) { + g_fullpipe->_currentScene->_messageQueueId = cmd->_parId; + } + } else { + g_fullpipe->_sceneRect.moveTo(offX, offY); + + g_fullpipe->_currentScene->_x = 0; + g_fullpipe->_currentScene->_y = 0; + + g_fullpipe->_currentScene->updateScrolling2(); + } + break; + } + case 34: + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_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 defaultUpdateCursor() { + g_fullpipe->updateCursorsCommon(); + + return g_fullpipe->_cursorId; +} + +int sceneIntro_updateCursor() { + g_fullpipe->_cursorId = 0; + + return 0; +} + +void FullpipeEngine::setSwallowedEggsState() { + CGameVar *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 sceneIntro_initScene(Scene *sc) { + g_fullpipe->_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_fullpipe->_recordEvents || g_fullpipe->_inputArFlag) + g_vars->sceneIntro_skipIntro = false; + + g_fullpipe->_modalObject = new CModalIntro; +} + +int sceneHandlerIntro(ExCommand *cmd) { + warning("STUB: sceneHandlerIntro()"); + + return 0; +} + +void scene01_fixEntrance() { + CGameVar *var = g_fullpipe->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_fullpipe->getObjectState(sO_EggCracker) == g_fullpipe->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; + } + + setElevatorButton(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_fullpipe->_aniMan, g_fullpipe->_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_fullpipe->_aniMan2) { + if (g_fullpipe->_aniMan2->_ox < g_fullpipe->_sceneRect.left + 200) { + g_fullpipe->_currentScene->_x = g_fullpipe->_aniMan2->_ox - g_fullpipe->_sceneRect.left - 300; + } + + if (g_fullpipe->_aniMan2->_ox > g_fullpipe->_sceneRect.right - 200) + g_fullpipe->_currentScene->_x = g_fullpipe->_aniMan2->_ox - g_fullpipe->_sceneRect.right + 300; + + res = 1; + } + g_fullpipe->_behaviorManager->updateBehaviors(); + + g_fullpipe->startSceneTrack(); + + return res; +} + +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_fullpipe->_currentScene) + for (uint i = 0; i < g_fullpipe->_currentScene->_picObjList.size(); i++) { + PictureObject *pic = (PictureObject *)g_fullpipe->_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_fullpipe->_mouseScreenPos.x + g_fullpipe->_sceneRect.left; + int my = g_fullpipe->_mouseScreenPos.y + g_fullpipe->_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_fullpipe->_needRestart = true; + return 0; + } + return 0; + } + + g_fullpipe->_cursorId = PIC_CSR_DEFAULT; + GameObject *obj = g_fullpipe->_currentScene->getStaticANIObjectAtPos(mx, my); + if (obj) { + if (canInteractAny(0, obj, -3)) { + g_fullpipe->_cursorId = PIC_CSR_DEFAULT; + g_fullpipe->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_fullpipe->_cursorId = PIC_CSR_DEFAULT; + g_fullpipe->setCursor(PIC_CSR_DEFAULT); + return 0; + } + g_vars->selector->_flags &= 0xFFFB; + } + g_fullpipe->setCursor(g_fullpipe->_cursorId); + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes.h b/engines/fullpipe/scenes.h new file mode 100644 index 0000000000..be42838920 --- /dev/null +++ b/engines/fullpipe/scenes.h @@ -0,0 +1,53 @@ +/* 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 { + +class StaticANIObject; + +class Vars { + public: + Vars(); + + CGameVar *swallowedEgg1; + CGameVar *swallowedEgg2; + CGameVar *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; + + GameObject *selector; +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_SCENES_H */ diff --git a/engines/fullpipe/sound.cpp b/engines/fullpipe/sound.cpp new file mode 100644 index 0000000000..821049cd0f --- /dev/null +++ b/engines/fullpipe/sound.cpp @@ -0,0 +1,140 @@ +/* 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/sound.h" +#include "fullpipe/ngiarchive.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::Sound() { + _id = 0; + _directSoundBuffer = 0; + _soundData = 0; + _objectId = 0; + memset(_directSoundBuffers, 0, sizeof(_directSoundBuffers)); + _description = 0; +} + + +bool Sound::load(MfcArchive &file, NGIArchive *archive) { + debug(5, "Sound::load()"); + + MemoryObject::load(file); + + _id = file.readUint32LE(); + _description = file.readPascalString(); + + assert(g_fullpipe->_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() { + debug(3, "STUB Sound::setPanAndVolumeByStaticAni()"); +} + +void FullpipeEngine::setSceneMusicParameters(CGameVar *var) { + warning("STUB: FullpipeEngine::setSceneMusicParameters()"); +} + +void FullpipeEngine::startSceneTrack() { + debug(3, "STUB: FullpipeEngine::startSceneTrack()"); +} + +void FullpipeEngine::stopAllSounds() { + warning("STUB: FullpipeEngine::stopAllSounds()"); +} + +void FullpipeEngine::toggleMute() { + warning("STUB: FullpipeEngine::toggleMute()"); +} + +void FullpipeEngine::playSound(int id, int flag) { + warning("STUB: FullpipeEngine::playSounds(%d, %d)", id, flag); +} + +void global_messageHandler_handleSound(ExCommand *cmd) { + debug(0, "STUB: global_messageHandler_handleSound()"); +} + + + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/sound.h b/engines/fullpipe/sound.h new file mode 100644 index 0000000000..4014cdd94e --- /dev/null +++ b/engines/fullpipe/sound.h @@ -0,0 +1,61 @@ +/* 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; + int16 _objectId; + int16 _field_32; + int _directSoundBuffer; + int _directSoundBuffers[7]; + byte *_soundData; + + public: + Sound(); + bool load(MfcArchive &file, NGIArchive *archive); + void updateVolume(); + + void setPanAndVolumeByStaticAni(); +}; + +class SoundList : public CObject { + Sound **_soundItems; + int _soundItemsCount; + NGIArchive *_libHandle; + + public: + SoundList(); + bool load(MfcArchive &file, char *fname); + bool loadFile(const char *fname, char *libname); + + int getCount() { return _soundItemsCount; } + Sound *getSoundByIndex(int idx) { return _soundItems[idx]; } +}; + +} // 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..4c58d564dd --- /dev/null +++ b/engines/fullpipe/stateloader.cpp @@ -0,0 +1,321 @@ +/* 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/constants.h" + +namespace Fullpipe { + +bool FullpipeEngine::loadGam(const char *fname, int scene) { + _gameLoader = new CGameLoader(); + + 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 (CPtrList::iterator p = _inventory->getScene()->_picObjList.begin(); p != _inventory->getScene()->_picObjList.end(); ++p) { + ((MemoryObject *)((PictureObject *)*p)->_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(scene); + _gameLoader->gotoScene(scene, TrubaLeft); + } 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_fullpipe->_gameProjectVersion = file.readUint32LE(); + g_fullpipe->_pictureScale = file.readUint16LE(); + g_fullpipe->_scrollSpeed = file.readUint32LE(); + + _headerFilename = file.readPascalString(); + + debug(1, "_gameProjectVersion = %d", g_fullpipe->_gameProjectVersion); + debug(1, "_pictureScale = %d", g_fullpipe->_pictureScale); + debug(1, "_scrollSpeed = %d", g_fullpipe->_scrollSpeed); + debug(1, "_headerFilename = %s", _headerFilename); + + _sceneTagList = new SceneTagList(); + + _sceneTagList->load(file); + + if (g_fullpipe->_gameProjectVersion >= 3) + _field_4 = file.readUint32LE(); + + if (g_fullpipe->_gameProjectVersion >= 5) { + file.readUint32LE(); + file.readUint32LE(); + } + + return true; +} + +GameProject::~GameProject() { + free(_headerFilename); +} + +CGameVar::CGameVar() { + _subVars = 0; + _parentVarObj = 0; + _nextVarObj = 0; + _prevVarObj = 0; + _field_14 = 0; + _varType = 0; + _value.floatValue = 0; + _varName = 0; +} + +bool CGameVar::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 = (CGameVar *)file.readClass(); + _prevVarObj = (CGameVar *)file.readClass(); + _nextVarObj = (CGameVar *)file.readClass(); + _field_14 = (CGameVar *)file.readClass(); + _subVars = (CGameVar *)file.readClass(); + file.decLevel(); + + return true; +} + +CGameVar *CGameVar::getSubVarByName(const char *name) { + CGameVar *sv = 0; + + if (_subVars != 0) { + sv = _subVars; + for (;sv && scumm_stricmp(sv->_varName, name); sv = sv->_nextVarObj) + ; + } + return sv; +} + +bool CGameVar::setSubVarAsInt(const char *name, int value) { + CGameVar *var = getSubVarByName(name); + + if (var) { + if (var->_varType == 0) { + var->_value.intValue = value; + + return true; + } + return false; + } + + var = new CGameVar(); + var->_varType = 0; + var->_value.intValue = value; + var->_varName = (char *)calloc(strlen(name) + 1, 1); + strcpy(var->_varName, name); + + return addSubVar(var); +} + +int CGameVar::getSubVarAsInt(const char *name) { + CGameVar *var = getSubVarByName(name); + + if (var) + return var->_value.intValue; + else + return 0; +} + +CGameVar *CGameVar::addSubVarAsInt(const char *name, int value) { + if (getSubVarByName(name)) { + return 0; + } else { + CGameVar *var = new CGameVar(); + + 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 CGameVar::addSubVar(CGameVar *subvar) { + CGameVar *var = _subVars; + + if (var) { + for (CGameVar *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 CGameVar::getSubVarsCount() { + int res; + CGameVar *sub = _subVars; + + for (res = 0; sub; res++) + sub = sub->_nextVarObj; + + return res; +} + +CGameVar *CGameVar::getSubVarByIndex(int idx) { + CGameVar *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..ac80e809c1 --- /dev/null +++ b/engines/fullpipe/statics.cpp @@ -0,0 +1,1733 @@ +/* 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/constants.h" +#include "fullpipe/objectnames.h" + +namespace Fullpipe { + +CStepArray::CStepArray() { + _points = 0; + _maxPointIndex = 0; + _currPointIndex = 0; + _pointsCount = 0; + _isEos = 0; +} + +CStepArray::~CStepArray() { + if (_pointsCount) { + for (int i = 0; i < _pointsCount; i++) + delete _points[i]; + + delete _points; + + _points = 0; + } +} + +void CStepArray::clear() { + _currPointIndex = 0; + _maxPointIndex = 0; + _isEos = 0; + + for (int i = 0; i < _pointsCount; i++) { + _points[i]->x = 0; + _points[i]->y = 0; + } +} + +Common::Point *CStepArray::getCurrPoint(Common::Point *point) { + if (_isEos || _points == 0) { + point->x = 0; + point->y = 0; + } else { + point = _points[_currPointIndex]; + } + return point; +} + +bool CStepArray::gotoNextPoint() { + if (_currPointIndex < _maxPointIndex) { + _currPointIndex++; + return true; + } else { + _isEos = 1; + return false; + } +} + +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(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((Statics *)src->_staticsList[i], 0)); + + _movement = 0; + _statics = 0; + + for (uint i = 0; i < src->_movements.size(); i++) { + Movement *mov; + if (((Movement *)src->_movements[i])->_currMovement) { + mov = new Movement(getMovementById(src->getMovementIdById(((Movement *)src->_movements[i])->_id)), this); + mov->_id = ((Movement *)src->_movements[i])->_id; + } else { + mov = new Movement(((Movement *)src->_movements[i]), 0, -1, this); + } + + _movements.push_back(mov); + } +} + +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_fullpipe->_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 + ((Movement *)_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_fullpipe->_globalMessageQueueList->getMessageQueueById(_messageQueueId)) { + if (!isIdle()) + return; + + g_fullpipe->_globalMessageQueueList->deleteQueueById(_messageQueueId); + } else { + _messageQueueId = 0; + } + } +} + +void StaticANIObject::queueMessageQueue(MessageQueue *mq) { + if (isIdle() && !(_flags & 0x80)) { + 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; + } + } +} + +MessageQueue *StaticANIObject::getMessageQueue() { + if (this->_messageQueueId <= 0) + return 0; + + return g_fullpipe->_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; +} + +bool StaticANIObject::isIdle() { + if (_messageQueueId) { + MessageQueue *m = g_fullpipe->_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 (((Statics *)_staticsList[i])->_staticsId == itemId) + return (Statics *)_staticsList[i]; + + return 0; +} + +Statics *StaticANIObject::getStaticsByName(char *name) { + for (uint i = 0; i < _staticsList.size(); i++) + if (!strcmp(((Statics *)_staticsList[i])->_staticsName, name)) + return (Statics *)_staticsList[i]; + + return 0; +} + +Movement *StaticANIObject::getMovementById(int itemId) { + for (uint i = 0; i < _movements.size(); i++) + if (((Movement *)_movements[i])->_id == itemId) + return (Movement *)_movements[i]; + + return 0; +} + +int StaticANIObject::getMovementIdById(int itemId) { + for (uint i = 0; i < _movements.size(); i++) { + Movement *mov = (Movement *)_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(((Movement *)_movements[i])->_objectName, name)) + return (Movement *)_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_fullpipe->_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(); + } + + if (flipFlag) { + bmp->flipVertical()->drawShaded(1, x, y + 30 + _currDynamicPhase->_rect->bottom, _currDynamicPhase->_paletteData); + } if (angle) { + bmp->drawRotated(x, y, angle, _currDynamicPhase->_paletteData); + } else { + bmp->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); + } + + 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); + //vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); + } else { + //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top)); + _currDynamicPhase->_convertedBitmap->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); + //vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); + } + } + } +} + + +void StaticANIObject::loadMovementsPixelData() { + for (uint i = 0; i < _movements.size(); i++) + ((Movement *)_movements[i])->loadPixelData(); +} + +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(0, "StaticANIObject::draw() (%s) [%d] [%d, %d]", transCyrillic((byte *)_objectName), _id, _ox, _oy); + + if (_shadowsOn && g_fullpipe->_currentScene && g_fullpipe->_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_fullpipe->_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(0, "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() { + CGameVar *preloadSubVar = g_fullpipe->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++) { + GameObject *obj = (GameObject *)_movements[i]; + movTable->movs[i] = 2; + + for (CGameVar *sub = preloadSubVar->_subVars; sub; sub = sub->_nextVarObj) { + if (scumm_stricmp(obj->getName(), sub->_varName) == 0) { + movTable->movs[i] = 1; + break; + } + } + } + + return movTable; +} + +void StaticANIObject::setSpeed(int speed) { + CGameVar *var = g_fullpipe->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++) + ((Movement *)_movements[i])->setAlpha(alpha); + + for (uint i = 0; i < _staticsList.size(); i++) + ((Statics *)_staticsList[i])->setAlpha(alpha); +} + +void StaticANIObject::initMovements() { + for (uint i = 0; i < _movements.size(); i++) + ((Movement *)_movements[i])->removeFirstPhase(); +} + +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; +} + +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 = new ExCommand(ex); + 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 = new ExCommand(ex); + 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::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; + } + } + } + + if (_movement->_currDynamicPhaseIndex || !(_flags & 0x40)) + _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() { + warning("STUB: StaticANIObject::adjustSomeXY()"); +} + +MessageQueue *StaticANIObject::changeStatics1(int msgNum) { + warning("STUB: StaticANIObject::changeStatics1(%d)", msgNum); + + return 0; +} + +void StaticANIObject::changeStatics2(int objId) { + warning("STUB: StaticANIObject::changeStatics2(%d)", objId); +} + +void StaticANIObject::hide() { + if (!_messageQueueId) { + if (_flags & 4) + _flags ^= 4; + } +} + +void StaticANIObject::show1(int x, int y, int movId, int mqId) { + debug(0, "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) { + warning("STUB: StaticANIObject::show2(%d, %d, %d, %d)", x, y, movementId, mqId); +} + +void StaticANIObject::playIdle() { + if (isIdle()) + adjustSomeXY(); +} + +void StaticANIObject::startAnimSteps(int movementId, int messageQueueId, int x, int y, Common::Point **points, int pointsCount, int someDynamicPhaseIndex) { + warning("STUB: StaticANIObject::startAnimSteps()"); +} + +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(0, "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 (((Movement *)_movements[i])->_id == movementId) { + mov = (Movement *)_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; + + debug(0, "0 %d %d", newx, newy); + if (_movement) { + _movement->getCurrDynamicPhaseXY(point); + + newx -= point.x; + newy -= point.y; + + debug(0, "1 %d %d", newx, newy); + } else if (_statics) { + _statics->getSomeXY(point); + + newx -= point.x; + newy -= point.y; + debug(0, "2 %d %d - %d %d assa", newx, newy, point.x, 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; + + debug(0, "3 %d %d", newx, newy); + _stepArray.gotoNextPoint(); + + ExCommand *ex = _movement->_currDynamicPhase->getExCommand(); + if (ex) { + if (ex->_messageKind == 35) { + ExCommand *newex = new ExCommand(ex); + 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; +} + +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; +} + +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; + + _field_24 = 0; + _field_28 = 0; +} + +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; + + _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 *flag1, int flag2, StaticANIObject *ani) { + warning("STUB: Movement(src, %p, %d, ani)", (void *)flag1, flag2); +} + +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_fullpipe->_gameProjectVersion >= 8) + _field_50 = file.readUint32LE(); + + if (g_fullpipe->_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; +} + +void Movement::setAlpha(int alpha) { + if (_currMovement) + for (uint i = 0; i < _currMovement->_dynamicPhases.size(); i++) { + ((DynamicPhase *)_currMovement->_dynamicPhases[i])->setAlpha(alpha); + } + else + for (uint i = 0; i < _dynamicPhases.size(); i++) { + ((DynamicPhase *)_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 = (DynamicPhase *)_currMovement->_dynamicPhases[idx]; + else + dyn = (DynamicPhase *)_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 = (DynamicPhase *)_currMovement->_dynamicPhases[_currDynamicPhaseIndex]; + } else { + if (_dynamicPhases.size() == 0 || (uint)_currDynamicPhaseIndex >= _dynamicPhases.size()) + return; + + if (_dynamicPhases[_currDynamicPhaseIndex]) + _currDynamicPhase = (DynamicPhase *)_dynamicPhases[_currDynamicPhaseIndex]; + } +} + +int Movement::calcDuration() { + int res = 0; + + if (_currMovement) + for (uint i = 0; i < _currMovement->_dynamicPhases.size(); i++) { + res += ((DynamicPhase *)_currMovement->_dynamicPhases[i])->_initialCountdown; + } + else + for (uint i = 0; i < _dynamicPhases.size(); i++) { + res += ((DynamicPhase *)_dynamicPhases[i])->_initialCountdown; + } + + 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 (DynamicPhase *)_currMovement->_dynamicPhases[idx]; + } else { + if (_dynamicPhases.size() == 0 || (uint)idx >= _dynamicPhases.size()) + return 0; + + return (DynamicPhase *)_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)) + ((Statics *)_dynamicPhases[i])->getPixelData(); + } + + if (!(mov->_staticsObj1->_staticsId & 0x4000)) + mov->_staticsObj1->getPixelData(); +} + +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(int callback1, void (*callback2)(int *)) { + debug(8, "Movement::gotoNextFrame()"); + + if (!callback2) { + if (_currMovement) { + if ((uint)_currDynamicPhaseIndex == _currMovement->_dynamicPhases.size() - 1 + && !(((DynamicPhase *)(_currMovement->_dynamicPhases.back()))->_countdown)) { + return false; + } + } else if ((uint)_currDynamicPhaseIndex == _dynamicPhases.size() - 1 + && !(((DynamicPhase *)(_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 = _currMovement->_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(0, "DynamicPhase::DynamicPhase(src, %d)", reverse); + + if (reverse) { + if (!src->_bitmap) + src->init(); + + _bitmap = src->_bitmap->reverseImage(); + _data = _bitmap->_pixels; + _dataSize = src->_dataSize; + + if (g_fullpipe->_currArchive) { + _mfield_14 = 0; + _libHandle = g_fullpipe->_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; + + _someX = src->_someX; + _someY = src->_someY; + } + + *_rect = *src->_rect; + + _width = src->_width; + _height = src->_height; + _field_7C = src->_field_7C; + + if (src->getExCommand()) + _exCommand = new ExCommand(src->getExCommand()); + 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_fullpipe->_gameProjectVersion >= 1); + + _someX = file.readUint32LE(); + _someY = file.readUint32LE(); + + assert (g_fullpipe->_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_fullpipe->_gameProjectVersion >= 12) { + _exCommand = (ExCommand *)file.readClass(); + + return true; + } + + assert (g_fullpipe->_gameProjectVersion >= 12); + + return true; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/statics.h b/engines/fullpipe/statics.h new file mode 100644 index 0000000000..03d87c8e32 --- /dev/null +++ b/engines/fullpipe/statics.h @@ -0,0 +1,250 @@ +/* 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 CStepArray : public CObject { + int _currPointIndex; + Common::Point **_points; + int _maxPointIndex; + int _pointsCount; + int _isEos; + + public: + CStepArray(); + ~CStepArray(); + void clear(); + + int getCurrPointIndex() { return _currPointIndex; } + Common::Point *getCurrPoint(Common::Point *point); + bool gotoNextPoint(); +}; + +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); + Statics *getStaticsById(int itemId); + + Common::Point *getSomeXY(Common::Point &p); + Common::Point *getCenter(Common::Point *p); +}; + +class StaticANIObject; + +class Movement : public GameObject { + public: + int _field_24; + int _field_28; + 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; + CPtrList _dynamicPhases; + int _field_78; + Common::Point **_framePosOffsets; + Movement *_currMovement; + int _field_84; + DynamicPhase *_currDynamicPhase; + int _field_8C; + int _currDynamicPhaseIndex; + int _field_94; + + public: + 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); + + void initStatics(StaticANIObject *ani); + void updateCurrDynamicPhase(); + + void setAlpha(int alpha); + + void setDynamicPhaseIndex(int index); + DynamicPhase *getDynamicPhaseByIndex(int idx); + + int calcDuration(); + + void removeFirstPhase(); + bool gotoNextFrame(int callback1, void (*callback2)(int *)); + bool gotoPrevFrame(); + void gotoFirstFrame(); + void gotoLastFrame(); + + void loadPixelData(); + + 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; + int _callback1; + void (*_callback2)(int *); + CPtrList _movements; + CPtrList _staticsList; + CStepArray _stepArray; + int16 _field_96; + int _messageQueueId; + int _messageNum; + int _animExFlag; + int _counter; + int _someDynamicPhaseIndex; + + public: + int16 _sceneId; + + public: + 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); + + void clearFlags(); + void setFlags40(bool state); + bool isIdle(); + void setAlpha(int alpha); + + void deleteFromGlobalMessageQueue(); + void queueMessageQueue(MessageQueue *msg); + MessageQueue *getMessageQueue(); + bool trySetMessageQueue(int msgNum, int qId); + + void initMovements(); + void loadMovementsPixelData(); + + 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(); + void setSpeed(int speed); + + void stopAnim_maybe(); + + MessageQueue *changeStatics1(int msgNum); + void changeStatics2(int objId); + + bool getPixelAtPos(int x, int y, int *pixel); +}; + +struct MovTable { + int count; + int16 *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..ee73aeaa64 --- /dev/null +++ b/engines/fullpipe/utils.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 "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 CObList::load(MfcArchive &file) { + debug(5, "CObList::load()"); + int count = file.readCount(); + + debug(9, "CObList::count: %d:", count); + + for (int i = 0; i < count; i++) { + debug(9, "CObList::[%d]", i); + CObject *t = file.readClass(); + + push_back(t); + } + + return true; +} + +bool CObArray::load(MfcArchive &file) { + debug(5, "CObArray::load()"); + int count = file.readCount(); + + resize(count); + + for (int i = 0; i < count; i++) { + CObject *t = file.readClass(); + + push_back(*t); + } + + return true; +} + +bool CDWordArray::load(MfcArchive &file) { + debug(5, "CWordArray::load()"); + int count = file.readCount(); + + debug(9, "CDWordArray::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_fullpipe->_currArchive) { + _mfield_14 = 0; + _libHandle = g_fullpipe->_currArchive; + } + + return true; +} + +void MemoryObject::loadFile(char *filename) { + debug(5, "MemoryObject::loadFile(<%s>)", filename); + if (!_data) { + Common::SeekableReadStream *s = g_fullpipe->_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; + } + } +} + +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() { + 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, + kCInteraction, + kMessageQueue, + kExCommand, + kCObjstateCommand, + kCGameVar, + kCMctlCompound, + kCMovGraph, + kCMovGraphLink, + kCMovGraphNode, + kCReactParallel, + kCReactPolygonal +}; + +const struct { + const char *name; + int id; +} classMap[] = { + { "CInteraction", kCInteraction }, + { "MessageQueue", kMessageQueue }, + { "ExCommand", kExCommand }, + { "CObjstateCommand", kCObjstateCommand }, + { "CGameVar", kCGameVar }, + { "CMctlCompound", kCMctlCompound }, + { "CMovGraph", kCMovGraph }, + { "CMovGraphLink", kCMovGraphLink }, + { "CMovGraphNode", kCMovGraphNode }, + { "CReactParallel", kCReactParallel }, + { "CReactPolygonal", kCReactPolygonal }, + { 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 kCInteraction: + return new CInteraction(); + case kMessageQueue: + return new MessageQueue(); + case kExCommand: + return new ExCommand(); + case kCObjstateCommand: + return new CObjstateCommand(); + case kCGameVar: + return new CGameVar(); + case kCMctlCompound: + return new CMctlCompound(); + case kCMovGraph: + return new CMovGraph(); + case kCMovGraphLink: + return new CMovGraphLink(); + case kCMovGraphNode: + return new CMovGraphNode(); + case kCReactParallel: + return new CReactParallel(); + case kCReactPolygonal: + return new CReactPolygonal(); + 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); + } + 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..76a1ae944c --- /dev/null +++ b/engines/fullpipe/utils.h @@ -0,0 +1,154 @@ +/* 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, + kObjTypeObjstateCommand, + kObjTypeStaticANIObject, + kObjTypePictureObject +}; + +class CObject { + public: + ObjType _objtype; + + CObject() : _objtype(kObjTypeDefault) {} + virtual bool load(MfcArchive &in) { return true; } + virtual ~CObject() {} + + bool loadFile(const char *fname); +}; + +class CObList : 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; + char _mfield_15; + char _mfield_16; + char _mfield_17; + 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(); + + 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 CObArray : public Common::Array<CObject>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class CDWordArray : public Common::Array<int32>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +typedef Common::Array<void *> CPtrList; + +char *genFileName(int superId, int sceneId, const char *ext); +byte *transCyrillic(byte *s); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_UTILS_H */ diff --git a/engines/gob/POTFILES b/engines/gob/POTFILES new file mode 100644 index 0000000000..9a512469dd --- /dev/null +++ b/engines/gob/POTFILES @@ -0,0 +1,3 @@ +engines/gob/inter_playtoons.cpp +engines/gob/inter_v2.cpp +engines/gob/inter_v5.cpp diff --git a/engines/groovie/POTFILES b/engines/groovie/POTFILES new file mode 100644 index 0000000000..0bf4528a7d --- /dev/null +++ b/engines/groovie/POTFILES @@ -0,0 +1,2 @@ +engines/groovie/detection.cpp +engines/groovie/script.cpp diff --git a/engines/kyra/POTFILES b/engines/kyra/POTFILES new file mode 100644 index 0000000000..16888e2c5a --- /dev/null +++ b/engines/kyra/POTFILES @@ -0,0 +1,3 @@ +engines/kyra/detection.cpp +engines/kyra/lol.cpp +engines/kyra/sound_midi.cpp diff --git a/engines/lastexpress/data/scene.h b/engines/lastexpress/data/scene.h index 69a1417459..b99e56a74c 100644 --- a/engines/lastexpress/data/scene.h +++ b/engines/lastexpress/data/scene.h @@ -83,6 +83,7 @@ class Scene; class SceneHotspot { public: enum Action { + kActionNone = 0, kActionInventory = 1, kActionSavePoint = 2, kActionPlaySound = 3, @@ -152,8 +153,19 @@ public: byte cursor; uint32 next; - SceneHotspot() {} + SceneHotspot() { + coordsOffset = 0; + scene = kSceneNone; + location = 0; + action = kActionNone; + param1 = 0; + param2 = 0; + param3 = 0; + cursor = 0; + next = 0; + } ~SceneHotspot(); + static SceneHotspot *load(Common::SeekableReadStream *stream); bool isInside(const Common::Point &point); diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index db3a3e3962..7c83aff93d 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -487,7 +487,9 @@ bool Debugger::cmdPlaySeq(int argc, const char **argv) { // Handle right-click to interrupt sequence Common::Event ev; - _engine->getEventManager()->pollEvent(ev); + if (!_engine->getEventManager()->pollEvent(ev)) + break; + if (ev.type == Common::EVENT_RBUTTONUP) break; @@ -596,7 +598,9 @@ bool Debugger::cmdPlaySbe(int argc, const char **argv) { // Handle right-click to interrupt sequence Common::Event ev; - _engine->getEventManager()->pollEvent(ev); + if (!_engine->getEventManager()->pollEvent(ev)) + break; + if (ev.type == Common::EVENT_RBUTTONUP) break; diff --git a/engines/lastexpress/game/scenes.cpp b/engines/lastexpress/game/scenes.cpp index a2c7226b93..82688fff2e 100644 --- a/engines/lastexpress/game/scenes.cpp +++ b/engines/lastexpress/game/scenes.cpp @@ -587,8 +587,8 @@ void SceneManager::updateDoorsAndClock() { Common::String name = Common::String::format("633X%c-%02d.seq", (index - firstIndex) + 65, scene->position); Sequence *sequence = loadSequence1(name, 255); - // If the sequence doesn't exists, skip - if (!sequence || !sequence->isLoaded()) + // If the sequence doesn't exists or could not be loaded, skip index + if (!sequence) continue; // Adjust frame data and store in frame list diff --git a/engines/lastexpress/game/state.h b/engines/lastexpress/game/state.h index 2c484f6976..944f6d47b1 100644 --- a/engines/lastexpress/game/state.h +++ b/engines/lastexpress/game/state.h @@ -502,6 +502,7 @@ public: volume = _defaultVolume; //Game data + field_0 = 0; time = kTimeCityParis; timeDelta = _defaultTimeDelta; timeTicks = 0; diff --git a/engines/lastexpress/lastexpress.cpp b/engines/lastexpress/lastexpress.cpp index 01d2634dec..bc1624d171 100644 --- a/engines/lastexpress/lastexpress.cpp +++ b/engines/lastexpress/lastexpress.cpp @@ -165,10 +165,10 @@ Common::Error LastExpressEngine::run() { void LastExpressEngine::pollEvents() { Common::Event ev; - _eventMan->pollEvent(ev); + if (!_eventMan->pollEvent(ev)) + return; switch (ev.type) { - case Common::EVENT_LBUTTONUP: getGameLogic()->getGameState()->getGameFlags()->mouseLeftClick = true; break; diff --git a/engines/mohawk/POTFILES b/engines/mohawk/POTFILES new file mode 100644 index 0000000000..54d9dcaa3a --- /dev/null +++ b/engines/mohawk/POTFILES @@ -0,0 +1,3 @@ +engines/mohawk/dialogs.cpp +engines/mohawk/myst.cpp +engines/mohawk/riven.cpp diff --git a/engines/neverhood/POTFILES b/engines/neverhood/POTFILES new file mode 100644 index 0000000000..36628cf4dd --- /dev/null +++ b/engines/neverhood/POTFILES @@ -0,0 +1,2 @@ +engines/neverhood/detection.cpp +engines/neverhood/menumodule.cpp diff --git a/engines/neverhood/console.cpp b/engines/neverhood/console.cpp index 733d7dd8a4..a2ceed8a2e 100644 --- a/engines/neverhood/console.cpp +++ b/engines/neverhood/console.cpp @@ -24,7 +24,9 @@ #include "gui/debugger.h" #include "neverhood/neverhood.h" #include "neverhood/gamemodule.h" +#include "neverhood/navigationscene.h" #include "neverhood/scene.h" +#include "neverhood/smackerscene.h" #include "neverhood/sound.h" #include "neverhood/modules/module1600.h" @@ -32,24 +34,52 @@ namespace Neverhood { Console::Console(NeverhoodEngine *vm) : GUI::Debugger(), _vm(vm) { DCmd_Register("cheat", WRAP_METHOD(Console, Cmd_Cheat)); + DCmd_Register("checkresource", WRAP_METHOD(Console, Cmd_CheckResource)); + DCmd_Register("dumpresource", WRAP_METHOD(Console, Cmd_DumpResource)); DCmd_Register("dumpvars", WRAP_METHOD(Console, Cmd_Dumpvars)); - DCmd_Register("room", WRAP_METHOD(Console, Cmd_Room)); - DCmd_Register("surfaces", WRAP_METHOD(Console, Cmd_Surfaces)); DCmd_Register("playsound", WRAP_METHOD(Console, Cmd_PlaySound)); + DCmd_Register("scene", WRAP_METHOD(Console, Cmd_Scene)); + DCmd_Register("surfaces", WRAP_METHOD(Console, Cmd_Surfaces)); } Console::~Console() { } -bool Console::Cmd_Room(int argc, const char **argv) { - int currentModule = _vm->_gameModule->getCurrentModuleNum(); - int previousModule = _vm->_gameModule->getPreviousModuleNum(); - int scene = _vm->gameState().sceneNum; - - DebugPrintf("Current module: %d, previous module: %d, scene %d\n", currentModule, previousModule, scene); - +bool Console::Cmd_Scene(int argc, const char **argv) { if (argc != 3) { - DebugPrintf("Use room <module> <scene> to change rooms\n"); + int currentModule = _vm->_gameModule->getCurrentModuleNum(); + int previousModule = _vm->_gameModule->getPreviousModuleNum(); + int scenenNum = _vm->gameState().sceneNum; + SceneType sceneType = ((GameModule *)_vm->_gameModule->_childObject)->getSceneType(); + + const char *sceneTypes[] = { "normal", "smacker", "navigation" }; + + DebugPrintf("Current module: %d, previous module: %d, scene %d (%s scene)\n", currentModule, previousModule, scenenNum, sceneTypes[sceneType]); + + if (sceneType == kSceneTypeNormal) { + Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject; + // Normal scenes have a background and a cursor file hash + DebugPrintf("Background hash: 0x%x, cursor hash: 0x%x\n", scene->getBackgroundFileHash(), scene->getCursorFileHash()); + } else if (sceneType == kSceneTypeSmacker) { + SmackerScene *scene = (SmackerScene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject; + // Smacker scenes have a file hash, or a list of hashes + // TODO: Only the first file hash is shown - any additional hashes, found in + // scenes with a list of hashes (two scenes in module 1100 and the making of + // video) aren't shown yet + DebugPrintf("File hash: 0x%x\n", scene->getSmackerFileHash()); + } else if (sceneType == kSceneTypeNavigation) { + NavigationScene *scene = (NavigationScene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject; + // Navigation scenes have a navigation list and its index + NavigationList *navigationList = _vm->_staticData->getNavigationList(scene->getNavigationListId()); + int navigationIndex = scene->getGlobalVar(V_NAVIGATION_INDEX); + NavigationItem curNavigation = (*navigationList)[navigationIndex]; + DebugPrintf("Navigation list ID: 0x%x, index: %d\n", scene->getNavigationListId(), navigationIndex); + DebugPrintf("File hash: 0x%x, cursor hash: 0x%x, Smacker hashes: [left: 0x%x, middle: 0x%x, right: 0x%x\n", + curNavigation.fileHash, curNavigation.mouseCursorFileHash, + curNavigation.leftSmackerFileHash, curNavigation.middleSmackerFileHash, curNavigation.rightSmackerFileHash); + } + + DebugPrintf("Use %s <module> <scene> to change scenes\n", argv[0]); DebugPrintf("Modules are incremental by 100, from 1000 to 3000\n"); } else { int newModule = atoi(argv[1]); @@ -188,4 +218,51 @@ bool Console::Cmd_PlaySound(int argc, const char **argv) { return true; } +bool Console::Cmd_CheckResource(int argc, const char **argv) { + const char *resourceNames[] = { "unknown", "unknown", "bitmap", "palette", "animation", "data", "text", "sound", "music", "unknown", "video" }; + + if (argc < 2) { + DebugPrintf("Gets information about a resource\n"); + DebugPrintf("Usage: %s <resource hash>\n", argv[0]); + } else { + uint32 resourceHash = strtol(argv[1], NULL, 0); + ResourceHandle handle; + + _vm->_res->queryResource(resourceHash, handle); + if (!handle.isValid()) { + DebugPrintf("Invalid resource hash\n"); + } else { + DebugPrintf("Resource type: %d (%s). Size: %d bytes\n", handle.type(), resourceNames[handle.type()], handle.size()); + } + } + + return true; +} + +bool Console::Cmd_DumpResource(int argc, const char **argv) { + if (argc < 3) { + DebugPrintf("Dumps a resource to disk\n"); + DebugPrintf("Usage: %s <resource hash> <output file>\n", argv[0]); + } else { + uint32 resourceHash = strtol(argv[1], NULL, 0); + const char *outFileName = argv[2]; + ResourceHandle handle; + + _vm->_res->queryResource(resourceHash, handle); + if (!handle.isValid()) { + DebugPrintf("Invalid resource hash\n"); + } else { + _vm->_res->loadResource(handle); + Common::DumpFile outFile; + outFile.open(outFileName); + outFile.write(handle.data(), handle.size()); + outFile.finalize(); + outFile.close(); + _vm->_res->unloadResource(handle); + } + } + + return true; +} + } // End of namespace Neverhood diff --git a/engines/neverhood/console.h b/engines/neverhood/console.h index 62d65bd693..70260a96af 100644 --- a/engines/neverhood/console.h +++ b/engines/neverhood/console.h @@ -37,11 +37,14 @@ public: private: NeverhoodEngine *_vm; - bool Cmd_Room(int argc, const char **argv); + bool Cmd_Scene(int argc, const char **argv); bool Cmd_Surfaces(int argc, const char **argv); bool Cmd_Cheat(int argc, const char **argv); bool Cmd_Dumpvars(int argc, const char **argv); bool Cmd_PlaySound(int argc, const char **argv); + bool Cmd_CheckResource(int argc, const char **argv); + bool Cmd_DumpResource(int argc, const char **argv); + }; } // End of namespace Neverhood diff --git a/engines/neverhood/module.h b/engines/neverhood/module.h index ba1e1fa3db..8ab2159030 100644 --- a/engines/neverhood/module.h +++ b/engines/neverhood/module.h @@ -48,6 +48,7 @@ public: Module(NeverhoodEngine *vm, Module *parentModule); virtual ~Module(); virtual void draw(); + SceneType getSceneType() { return _sceneType; } Entity *_childObject; protected: diff --git a/engines/neverhood/modules/module1000.cpp b/engines/neverhood/modules/module1000.cpp index f65b89899d..08fb88ad72 100644 --- a/engines/neverhood/modules/module1000.cpp +++ b/engines/neverhood/modules/module1000.cpp @@ -1383,29 +1383,6 @@ uint32 Scene1002::handleMessage(int messageNum, const MessageParam ¶m, Entit return messageResult; } -// StaticScene - -StaticScene::StaticScene(NeverhoodEngine *vm, Module *parentModule, uint32 backgroundFileHash, uint32 cursorFileHash) - : Scene(vm, parentModule) { - - SetMessageHandler(&StaticScene::handleMessage); - - setBackground(backgroundFileHash); - setPalette(backgroundFileHash); - insertPuzzleMouse(cursorFileHash, 20, 620); -} - -uint32 StaticScene::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { - Scene::handleMessage(messageNum, param, sender); - switch (messageNum) { - case 0x0001: - if (param.asPoint().x <= 20 || param.asPoint().x >= 620) - leaveScene(0); - break; - } - return 0; -} - // Scene1004 AsScene1004TrashCan::AsScene1004TrashCan(NeverhoodEngine *vm) diff --git a/engines/neverhood/modules/module1000.h b/engines/neverhood/modules/module1000.h index 8461ecfc6f..9e97e822f6 100644 --- a/engines/neverhood/modules/module1000.h +++ b/engines/neverhood/modules/module1000.h @@ -102,15 +102,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; -// TODO: Move this to some common file since it's used several times - -class StaticScene : public Scene { -public: - StaticScene(NeverhoodEngine *vm, Module *parentModule, uint32 backgroundFileHash, uint32 cursorFileHash); -protected: - uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); -}; - // Scene1002 class AsScene1002Ring : public AnimatedSprite { diff --git a/engines/neverhood/navigationscene.cpp b/engines/neverhood/navigationscene.cpp index 51ab96ef37..a15c00de07 100644 --- a/engines/neverhood/navigationscene.cpp +++ b/engines/neverhood/navigationscene.cpp @@ -35,6 +35,7 @@ NavigationScene::NavigationScene(NeverhoodEngine *vm, Module *parentModule, uint _isWalkingForward(false), _isTurning(false), _smackerFileHash(0), _interactive(true), _leaveSceneAfter(false) { _navigationList = _vm->_staticData->getNavigationList(navigationListId); + _navigationListId = navigationListId; if (_navigationIndex < 0) { _navigationIndex = (int)getGlobalVar(V_NAVIGATION_INDEX); diff --git a/engines/neverhood/navigationscene.h b/engines/neverhood/navigationscene.h index ebe9a3597c..c17446811c 100644 --- a/engines/neverhood/navigationscene.h +++ b/engines/neverhood/navigationscene.h @@ -38,10 +38,12 @@ public: bool isWalkingForward() const { return _isWalkingForward; } bool isTurning() const { return _isTurning; } int getFrameNumber() const { return _smackerPlayer->getFrameNumber(); } + uint32 getNavigationListId() const { return _navigationListId; } protected: SmackerPlayer *_smackerPlayer; bool _smackerDone; NavigationList *_navigationList; + uint32 _navigationListId; // used for debugging int _navigationIndex; uint32 _smackerFileHash; bool _interactive; diff --git a/engines/neverhood/scene.cpp b/engines/neverhood/scene.cpp index c8d7490753..0b2e9c6b75 100644 --- a/engines/neverhood/scene.cpp +++ b/engines/neverhood/scene.cpp @@ -51,6 +51,8 @@ Scene::Scene(NeverhoodEngine *vm, Module *parentModule) _isMessageListBusy = false; _messageValue = -1; + _backgroundFileHash = _cursorFileHash = 0; + SetUpdateHandler(&Scene::update); SetMessageHandler(&Scene::handleMessage); @@ -188,6 +190,7 @@ Background *Scene::addBackground(Background *background) { void Scene::setBackground(uint32 fileHash) { _background = addBackground(new Background(_vm, fileHash, 0, 0)); + _backgroundFileHash = fileHash; } void Scene::changeBackground(uint32 fileHash) { @@ -216,14 +219,17 @@ void Scene::insertScreenMouse(uint32 fileHash, const NRect *mouseRect) { if (mouseRect) rect = *mouseRect; insertMouse(new Mouse(_vm, fileHash, rect)); + _cursorFileHash = fileHash; } void Scene::insertPuzzleMouse(uint32 fileHash, int16 x1, int16 x2) { insertMouse(new Mouse(_vm, fileHash, x1, x2)); + _cursorFileHash = fileHash; } void Scene::insertNavigationMouse(uint32 fileHash, int type) { insertMouse(new Mouse(_vm, fileHash, type)); + _cursorFileHash = fileHash; } void Scene::showMouse(bool visible) { @@ -593,4 +599,27 @@ void Scene::insertMouse(Mouse *mouseCursor) { addEntity(_mouseCursor); } +// StaticScene + +StaticScene::StaticScene(NeverhoodEngine *vm, Module *parentModule, uint32 backgroundFileHash, uint32 cursorFileHash) + : Scene(vm, parentModule) { + + SetMessageHandler(&StaticScene::handleMessage); + + setBackground(backgroundFileHash); + setPalette(backgroundFileHash); + insertPuzzleMouse(cursorFileHash, 20, 620); +} + +uint32 StaticScene::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + Scene::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x0001: + if (param.asPoint().x <= 20 || param.asPoint().x >= 620) + leaveScene(0); + break; + } + return 0; +} + } // End of namespace Neverhood diff --git a/engines/neverhood/scene.h b/engines/neverhood/scene.h index 5e42e34418..f60e291395 100644 --- a/engines/neverhood/scene.h +++ b/engines/neverhood/scene.h @@ -162,6 +162,10 @@ public: T* createSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6) { return new T(_vm, arg1, arg2, arg3, arg4, arg5, arg6); } + + uint32 getBackgroundFileHash() const { return _backgroundFileHash; } + uint32 getCursorFileHash() const { return _cursorFileHash; } + protected: Module *_parentModule; Common::Array<Entity*> _entities; @@ -197,6 +201,9 @@ protected: HitRectList *_hitRects; Common::Array<Sprite*> _collisionSprites; + // Used for debugging + uint32 _backgroundFileHash, _cursorFileHash; // for StaticScene and all Scene* classes + void (Entity::*_savedUpdateHandlerCb)(); uint32 (Entity::*_savedMessageHandlerCb)(int messageNum, const MessageParam ¶m, Entity *sender); int _messageValue; @@ -224,6 +231,14 @@ protected: void insertMouse(Mouse *mouseCursor); }; + +class StaticScene : public Scene { +public: + StaticScene(NeverhoodEngine *vm, Module *parentModule, uint32 backgroundFileHash, uint32 cursorFileHash); +protected: + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + } // End of namespace Neverhood #endif /* NEVERHOOD_SCENE_H */ diff --git a/engines/neverhood/smackerscene.h b/engines/neverhood/smackerscene.h index 7ed2e0262b..8e5084512f 100644 --- a/engines/neverhood/smackerscene.h +++ b/engines/neverhood/smackerscene.h @@ -36,6 +36,7 @@ public: void setFileHash(uint32 fileHash); void setFileHashList(const uint32 *fileHashList); void nextVideo(); + uint32 getSmackerFileHash() const { return _fileHash[0]; } protected: bool _doubleSurface; bool _canSkip; diff --git a/engines/parallaction/POTFILES b/engines/parallaction/POTFILES new file mode 100644 index 0000000000..f3b1c45afa --- /dev/null +++ b/engines/parallaction/POTFILES @@ -0,0 +1 @@ +engines/parallaction/saveload.cpp diff --git a/engines/pegasus/POTFILES b/engines/pegasus/POTFILES new file mode 100644 index 0000000000..c06cb07479 --- /dev/null +++ b/engines/pegasus/POTFILES @@ -0,0 +1 @@ +engines/pegasus/pegasus.cpp diff --git a/engines/plugins_table.h b/engines/plugins_table.h index 793f15110c..04971a6764 100644 --- a/engines/plugins_table.h +++ b/engines/plugins_table.h @@ -29,6 +29,9 @@ LINK_PLUGIN(DRASCULA) #if PLUGIN_ENABLED_STATIC(DREAMWEB) LINK_PLUGIN(DREAMWEB) #endif +#if PLUGIN_ENABLED_STATIC(FULLPIPE) +LINK_PLUGIN(FULLPIPE) +#endif #if PLUGIN_ENABLED_STATIC(GOB) LINK_PLUGIN(GOB) #endif diff --git a/engines/queen/POTFILES b/engines/queen/POTFILES new file mode 100644 index 0000000000..1baf9c24de --- /dev/null +++ b/engines/queen/POTFILES @@ -0,0 +1 @@ +engines/queen/queen.cpp diff --git a/engines/sci/POTFILES b/engines/sci/POTFILES new file mode 100644 index 0000000000..f076c292d9 --- /dev/null +++ b/engines/sci/POTFILES @@ -0,0 +1,2 @@ +engines/sci/detection.cpp +engines/sci/engine/kfile.cpp diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 9653d9ccff..7640c5f314 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -440,7 +440,7 @@ void MidiParser_SCI::sendToDriver(uint32 midi) { } void MidiParser_SCI::parseNextEvent(EventInfo &info) { - // Set signal AFTER waiting for delta, otherwise we would set signal too soon resulting in all sorts of bugs + // Set signal AFTER waiting for delta, otherwise we would set signal too soon resulting in all sorts of bugs if (_dataincAdd) { _dataincAdd = false; _pSnd->dataInc += _dataincToAdd; @@ -455,7 +455,9 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { } if (_jumpToHoldTick) { _jumpToHoldTick = false; + _pSnd->inFastForward = true; jumpToTick(_loopTick, false, false); + _pSnd->inFastForward = false; } info.start = _position._playPos; @@ -497,8 +499,10 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { // immediately there. if (_soundVersion <= SCI_VERSION_0_LATE || _position._playTick || info.delta) { - _signalSet = true; - _signalToSet = info.basic.param1; + if (!_pSnd->inFastForward) { + _signalSet = true; + _signalToSet = info.basic.param1; + } } } else { _loopTick = _position._playTick + info.delta; @@ -552,19 +556,21 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { } break; case kUpdateCue: - _dataincAdd = true; - switch (_soundVersion) { - case SCI_VERSION_0_EARLY: - case SCI_VERSION_0_LATE: - _dataincToAdd = info.basic.param2; - break; - case SCI_VERSION_1_EARLY: - case SCI_VERSION_1_LATE: - case SCI_VERSION_2_1: - _dataincToAdd = 1; - break; - default: - error("unsupported _soundVersion"); + if (!_pSnd->inFastForward) { + _dataincAdd = true; + switch (_soundVersion) { + case SCI_VERSION_0_EARLY: + case SCI_VERSION_0_LATE: + _dataincToAdd = info.basic.param2; + break; + case SCI_VERSION_1_EARLY: + case SCI_VERSION_1_LATE: + case SCI_VERSION_2_1: + _dataincToAdd = 1; + break; + default: + error("unsupported _soundVersion"); + } } break; case kResetOnPause: @@ -660,7 +666,9 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { assert(_loopTick + info.delta < _position._playTick); uint32 extraDelta = info.delta; + _pSnd->inFastForward = true; jumpToTick(_loopTick); + _pSnd->inFastForward = false; _nextEvent.delta += extraDelta; } else { _pSnd->status = kSoundStopped; diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 913ba32cba..1628a22386 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -519,9 +519,14 @@ void SciMusic::soundPlay(MusicEntry *pSnd) { if (pSnd->status == kSoundStopped) pSnd->pMidiParser->jumpToTick(0); - else + else { // Fast forward to the last position and perform associated events when loading + pSnd->inFastForward = true; + // we set this flag, so that the midiparser doesn't set any signals for scripts + // if we don't do this, at least accessing the debugger will reset previously set signals pSnd->pMidiParser->jumpToTick(pSnd->ticker, true, true, true); + pSnd->inFastForward = false; + } // Restore looping and hold pSnd->loop = prevLoop; @@ -760,6 +765,7 @@ MusicEntry::MusicEntry() { resourceId = 0; isQueued = false; + inFastForward = false; dataInc = 0; ticker = 0; diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index 1f798c90d7..5924a0fd12 100644 --- a/engines/sci/sound/music.h +++ b/engines/sci/sound/music.h @@ -65,6 +65,7 @@ public: uint16 resourceId; bool isQueued; // for SCI0 only! + bool inFastForward; // if we are currently fast-forwarding (disables any signals to scripts) uint16 dataInc; uint16 ticker; diff --git a/engines/scumm/POTFILES b/engines/scumm/POTFILES new file mode 100644 index 0000000000..6034320259 --- /dev/null +++ b/engines/scumm/POTFILES @@ -0,0 +1,3 @@ +engines/scumm/dialogs.cpp +engines/scumm/help.cpp +engines/scumm/scumm.cpp diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index 28884d7f78..a377ad3dc4 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -35,6 +35,7 @@ MODULE_OBJS := \ midiparser_ro.o \ object.o \ palette.o \ + player_ad.o \ player_apple2.o \ player_mac.o \ player_mod.o \ diff --git a/engines/scumm/player_ad.cpp b/engines/scumm/player_ad.cpp new file mode 100644 index 0000000000..ed368afbf6 --- /dev/null +++ b/engines/scumm/player_ad.cpp @@ -0,0 +1,959 @@ +/* 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 "scumm/player_ad.h" +#include "scumm/imuse/imuse.h" +#include "scumm/scumm.h" +#include "scumm/resource.h" + +#include "audio/fmopl.h" + +#include "common/textconsole.h" +#include "common/config-manager.h" + +namespace Scumm { + +#define AD_CALLBACK_FREQUENCY 472 + +Player_AD::Player_AD(ScummEngine *scumm, Audio::Mixer *mixer) + : _vm(scumm), _mixer(mixer), _rate(mixer->getOutputRate()) { + _opl2 = OPL::Config::create(); + if (!_opl2->init(_rate)) { + error("Could not initialize OPL2 emulator"); + } + + _samplesPerCallback = _rate / AD_CALLBACK_FREQUENCY; + _samplesPerCallbackRemainder = _rate % AD_CALLBACK_FREQUENCY; + _samplesTillCallback = 0; + _samplesTillCallbackRemainder = 0; + + memset(_registerBackUpTable, 0, sizeof(_registerBackUpTable)); + writeReg(0x01, 0x00); + writeReg(0xBD, 0x00); + writeReg(0x08, 0x00); + writeReg(0x01, 0x20); + + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + + _engineMusicTimer = 0; + _soundPlaying = -1; + + _curOffset = 0; + + _sfxTimer = 4; + _rndSeed = 1; + + memset(_channels, 0, sizeof(_channels)); + memset(_sfxResource, 0, sizeof(_sfxResource)); + memset(_sfxPriority, 0, sizeof(_sfxPriority)); +} + +Player_AD::~Player_AD() { + _mixer->stopHandle(_soundHandle); + + stopAllSounds(); + Common::StackLock lock(_mutex); + delete _opl2; + _opl2 = 0; +} + +void Player_AD::setMusicVolume(int vol) { + // HACK: We ignore the parameter and set up the volume specified in the + // config manager. This allows us to differentiate between music and sfx + // volume changes. + setupVolume(); +} + +void Player_AD::startSound(int sound) { + Common::StackLock lock(_mutex); + + // Query the sound resource + const byte *res = _vm->getResourceAddress(rtSound, sound); + + if (res[2] == 0x80) { + // Stop the current sounds + stopAllSounds(); + + // Lock the new music resource + _soundPlaying = sound; + _vm->_res->lock(rtSound, _soundPlaying); + + // Start the new music resource + _resource = res; + startMusic(); + } else { + // Only try to start a sfx when no music is playing. + if (_soundPlaying == -1) { + const byte priority = res[0]; + const byte channel = res[1]; + + // Check for out of bounds access + if (channel >= 3) { + warning("AdLib sfx resource %d uses channel %d", sound, channel); + return; + } + + // Check whether the channel is free or the priority of the new + // sfx resource is above the old one. + if (_channels[channel * 3 + 0].state + || _channels[channel * 3 + 1].state + || _channels[channel * 3 + 2].state) { + if (_sfxPriority[channel] > priority) { + return; + } + } + + // Lock the new resource + _sfxResource[channel] = sound; + _sfxPriority[channel] = priority; + _vm->_res->lock(rtSound, sound); + + // Start the actual sfx resource + _resource = res; + startSfx(); + } + } + + // Setup the sound volume + setupVolume(); +} + +void Player_AD::stopSound(int sound) { + Common::StackLock lock(_mutex); + + if (sound == _soundPlaying) { + stopAllSounds(); + } else { + for (int i = 0; i < 3; ++i) { + if (_sfxResource[i] == sound) { + if (_channels[i * 3 + 0].state + || _channels[i * 3 + 1].state + || _channels[i * 3 + 2].state) { + // Unlock the sound resource + _vm->_res->unlock(rtSound, sound); + + // Stop the actual sfx playback + _channels[i * 3 + 0].state = 0; + _channels[i * 3 + 1].state = 0; + _channels[i * 3 + 2].state = 0; + clearChannel(i * 3 + 0); + clearChannel(i * 3 + 1); + clearChannel(i * 3 + 2); + } + } + } + } +} + +void Player_AD::stopAllSounds() { + Common::StackLock lock(_mutex); + + // Unlock the music resource if present + if (_soundPlaying != -1) { + _vm->_res->unlock(rtSound, _soundPlaying); + _soundPlaying = -1; + } + + // Stop the music playback + _curOffset = 0; + + // Unloack all used sfx resources + for (int i = 0; i < 3; ++i) { + if (_channels[i * 3 + 0].state || _channels[i * 3 + 1].state || _channels[i * 3 + 2].state) { + _vm->_res->unlock(rtSound, _sfxResource[i]); + } + } + + // Reset all the sfx channels + for (int i = 0; i < 9; ++i) { + _channels[i].state = 0; + clearChannel(i); + } + + writeReg(0xBD, 0x00); +} + +int Player_AD::getMusicTimer() { + return _engineMusicTimer; +} + +int Player_AD::getSoundStatus(int sound) const { + return (sound == _soundPlaying); +} + +void Player_AD::saveLoadWithSerializer(Serializer *ser) { + Common::StackLock lock(_mutex); + + if (ser->getVersion() < VER(95)) { + IMuse *dummyImuse = IMuse::create(_vm->_system, NULL, NULL); + dummyImuse->save_or_load(ser, _vm, false); + delete dummyImuse; + return; + } + + // TODO: Be nicer than the original and save the data to continue the + // currently played sound resources on load? +} + +int Player_AD::readBuffer(int16 *buffer, const int numSamples) { + Common::StackLock lock(_mutex); + + int len = numSamples; + + while (len > 0) { + if (!_samplesTillCallback) { + // Run the update callback for music or sfx depending on which is + // active. + if (_curOffset) { + updateMusic(); + } else { + updateSfx(); + } + + _samplesTillCallback = _samplesPerCallback; + _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; + if (_samplesTillCallbackRemainder >= AD_CALLBACK_FREQUENCY) { + ++_samplesTillCallback; + _samplesTillCallbackRemainder -= AD_CALLBACK_FREQUENCY; + } + } + + const int samplesToRead = MIN(len, _samplesTillCallback); + _opl2->readBuffer(buffer, samplesToRead); + + buffer += samplesToRead; + len -= samplesToRead; + _samplesTillCallback -= samplesToRead; + } + + return numSamples; +} + +void Player_AD::setupVolume() { + // Setup the correct volume + int soundVolumeMusic = CLIP<int>(ConfMan.getInt("music_volume"), 0, Audio::Mixer::kMaxChannelVolume); + int soundVolumeSfx = CLIP<int>(ConfMan.getInt("sfx_volume"), 0, Audio::Mixer::kMaxChannelVolume); + if (ConfMan.hasKey("mute")) { + if (ConfMan.getBool("mute")) { + soundVolumeMusic = 0; + soundVolumeSfx = 0; + } + } + + // In case a music is being played set the music volume. Set the sfx + // volume otherwise. This is safe because in the latter case either + // sfx are playing or there is no sound being played at all. + if (_soundPlaying != -1) { + _mixer->setChannelVolume(_soundHandle, soundVolumeMusic); + } else { + _mixer->setChannelVolume(_soundHandle, soundVolumeSfx); + } +} + +void Player_AD::writeReg(int r, int v) { + if (r >= 0 && r < ARRAYSIZE(_registerBackUpTable)) { + _registerBackUpTable[r] = v; + } + _opl2->writeReg(r, v); +} + +uint8 Player_AD::readReg(int r) const { + if (r >= 0 && r < ARRAYSIZE(_registerBackUpTable)) { + return _registerBackUpTable[r]; + } else { + return 0; + } +} + +void Player_AD::setupChannel(const uint channel, const byte *instrOffset) { + instrOffset += 2; + writeReg(0xC0 + channel, *instrOffset++); + setupOperator(_operatorOffsetTable[channel * 2 + 0], instrOffset); + setupOperator(_operatorOffsetTable[channel * 2 + 1], instrOffset); +} + +void Player_AD::setupOperator(const uint opr, const byte *&instrOffset) { + writeReg(0x20 + opr, *instrOffset++); + writeReg(0x40 + opr, *instrOffset++); + writeReg(0x60 + opr, *instrOffset++); + writeReg(0x80 + opr, *instrOffset++); + writeReg(0xE0 + opr, *instrOffset++); +} + +const int Player_AD::_operatorOffsetTable[18] = { + 0, 3, 1, 4, + 2, 5, 8, 11, + 9, 12, 10, 13, + 16, 19, 17, 20, + 18, 21 +}; + +// Music + +void Player_AD::startMusic() { + memset(_instrumentOffset, 0, sizeof(_instrumentOffset)); + memset(_channelLastEvent, 0, sizeof(_channelLastEvent)); + memset(_channelFrequency, 0, sizeof(_channelFrequency)); + memset(_channelB0Reg, 0, sizeof(_channelB0Reg)); + + _voiceChannels = 0; + uint instruments = _resource[10]; + for (uint i = 0; i < instruments; ++i) { + const int instrIndex = _resource[11 + i] - 1; + if (0 <= instrIndex && instrIndex < 16) { + _instrumentOffset[instrIndex] = i * 16 + 16 + 3; + _voiceChannels |= _resource[_instrumentOffset[instrIndex] + 13]; + } + } + + if (_voiceChannels) { + _mdvdrState = 0x20; + _voiceChannels = 6; + } else { + _mdvdrState = 0; + _voiceChannels = 9; + } + + _curOffset = 0x93; + // TODO: is this the same for Loom? + _nextEventTimer = 40; + _engineMusicTimer = 0; + _internalMusicTimer = 0; + _musicTimer = 0; + + writeReg(0xBD, _mdvdrState); + + const bool isLoom = (_vm->_game.id == GID_LOOM); + _timerLimit = isLoom ? 473 : 256; + _musicTicks = _resource[3] * (isLoom ? 2 : 1); + _loopFlag = (_resource[4] == 0); + _musicLoopStart = READ_LE_UINT16(_resource + 5); +} + +void Player_AD::updateMusic() { + _musicTimer += _musicTicks; + if (_musicTimer < _timerLimit) { + return; + } + _musicTimer -= _timerLimit; + + ++_internalMusicTimer; + if (_internalMusicTimer > 120) { + _internalMusicTimer = 0; + ++_engineMusicTimer; + } + + --_nextEventTimer; + if (_nextEventTimer) { + return; + } + + while (true) { + uint command = _resource[_curOffset++]; + if (command == 0xFF) { + // META EVENT + // Get the command number. + command = _resource[_curOffset++]; + if (command == 47) { + // End of track + if (_loopFlag) { + // In case the track is looping jump to the start. + _curOffset = _musicLoopStart; + _nextEventTimer = 0; + } else { + // Otherwise completely stop playback. + stopAllSounds(); + } + return; + } else if (command == 88) { + // This is proposedly a debug information insertion. The CMS + // player code handles this differently, but is still using + // the same resources... + _curOffset += 5; + } else if (command == 81) { + // Change tempo. This is used exclusively in Loom. + const uint timing = _resource[_curOffset + 2] | (_resource[_curOffset + 1] << 8); + _musicTicks = 0x73000 / timing; + command = _resource[_curOffset++]; + _curOffset += command; + } else { + // In case an unknown meta event occurs just skip over the + // data by using the length supplied. + command = _resource[_curOffset++]; + _curOffset += command; + } + } else { + if (command >= 0x90) { + // NOTE ON + // Extract the channel number and save it in command. + command -= 0x90; + + const uint instrOffset = _instrumentOffset[command]; + if (instrOffset) { + if (_resource[instrOffset + 13] != 0) { + setupRhythm(_resource[instrOffset + 13], instrOffset); + } else { + int channel = findFreeChannel(); + if (channel != -1) { + noteOff(channel); + setupChannel(channel, instrOffset); + _channelLastEvent[channel] = command + 0x90; + _channelFrequency[channel] = _resource[_curOffset]; + setupFrequency(channel, _resource[_curOffset]); + } + } + } + } else { + // NOTE OFF + const uint note = _resource[_curOffset]; + command += 0x10; + + // Find the output channel which plays the note. + uint channel = 0xFF; + for (uint i = 0; i < _voiceChannels; ++i) { + if (_channelFrequency[i] == note && _channelLastEvent[i] == command) { + channel = i; + break; + } + } + + if (channel != 0xFF) { + // In case a output channel playing the note was found, + // stop it. + noteOff(channel); + } else { + // In case there is no such note this will disable the + // rhythm instrument played on the channel. + command -= 0x90; + const uint instrOffset = _instrumentOffset[command]; + if (instrOffset && _resource[instrOffset + 13] != 0) { + const uint rhythmInstr = _resource[instrOffset + 13]; + if (rhythmInstr < 6) { + _mdvdrState &= _mdvdrTable[rhythmInstr] ^ 0xFF; + writeReg(0xBD, _mdvdrState); + } + } + } + } + + _curOffset += 2; + } + + // In case there is a delay till the next event stop handling. + if (_resource[_curOffset] != 0) { + break; + } + ++_curOffset; + } + + _nextEventTimer = _resource[_curOffset++]; + if (_nextEventTimer & 0x80) { + _nextEventTimer -= 0x80; + _nextEventTimer <<= 7; + _nextEventTimer |= _resource[_curOffset++]; + } + + _nextEventTimer >>= (_vm->_game.id == GID_LOOM) ? 2 : 1; + if (!_nextEventTimer) { + _nextEventTimer = 1; + } +} + +void Player_AD::noteOff(uint channel) { + _channelLastEvent[channel] = 0; + writeReg(0xB0 + channel, _channelB0Reg[channel] & 0xDF); +} + +int Player_AD::findFreeChannel() { + for (uint i = 0; i < _voiceChannels; ++i) { + if (!_channelLastEvent[i]) { + return i; + } + } + + return -1; +} + +void Player_AD::setupFrequency(uint channel, int8 frequency) { + frequency -= 31; + if (frequency < 0) { + frequency = 0; + } + + uint octave = 0; + while (frequency >= 12) { + frequency -= 12; + ++octave; + } + + const uint noteFrequency = _noteFrequencies[frequency]; + octave <<= 2; + octave |= noteFrequency >> 8; + octave |= 0x20; + writeReg(0xA0 + channel, noteFrequency & 0xFF); + _channelB0Reg[channel] = octave; + writeReg(0xB0 + channel, octave); +} + +void Player_AD::setupRhythm(uint rhythmInstr, uint instrOffset) { + if (rhythmInstr == 1) { + setupChannel(6, instrOffset); + writeReg(0xA6, _resource[instrOffset++]); + writeReg(0xB6, _resource[instrOffset] & 0xDF); + _mdvdrState |= 0x10; + writeReg(0xBD, _mdvdrState); + } else if (rhythmInstr < 6) { + const byte *secondOperatorOffset = _resource + instrOffset + 8; + setupOperator(_rhythmOperatorTable[rhythmInstr], secondOperatorOffset); + writeReg(0xA0 + _rhythmChannelTable[rhythmInstr], _resource[instrOffset++]); + writeReg(0xB0 + _rhythmChannelTable[rhythmInstr], _resource[instrOffset++] & 0xDF); + writeReg(0xC0 + _rhythmChannelTable[rhythmInstr], _resource[instrOffset]); + _mdvdrState |= _mdvdrTable[rhythmInstr]; + writeReg(0xBD, _mdvdrState); + } +} + +const uint Player_AD::_noteFrequencies[12] = { + 0x200, 0x21E, 0x23F, 0x261, + 0x285, 0x2AB, 0x2D4, 0x300, + 0x32E, 0x35E, 0x390, 0x3C7 +}; + +const uint Player_AD::_mdvdrTable[6] = { + 0x00, 0x10, 0x08, 0x04, 0x02, 0x01 +}; + +const uint Player_AD::_rhythmOperatorTable[6] = { + 0x00, 0x00, 0x14, 0x12, 0x15, 0x11 +}; + +const uint Player_AD::_rhythmChannelTable[6] = { + 0x00, 0x00, 0x07, 0x08, 0x08, 0x07 +}; + +// SFX + +void Player_AD::startSfx() { + writeReg(0xBD, 0x00); + + // The second byte of the resource defines the logical channel where + // the sound effect should be played. + const int startChannel = _resource[1] * 3; + + // Clear the channel. + _channels[startChannel + 0].state = 0; + _channels[startChannel + 1].state = 0; + _channels[startChannel + 2].state = 0; + + clearChannel(startChannel + 0); + clearChannel(startChannel + 1); + clearChannel(startChannel + 2); + + // Set up the first channel to pick up playback. + _channels[startChannel].currentOffset = _channels[startChannel].startOffset = _resource + 2; + _channels[startChannel].state = 1; + + // Scan for the start of the other channels and set them up if required. + int curChannel = startChannel + 1; + const byte *bufferPosition = _resource + 2; + uint8 command = 0; + while ((command = *bufferPosition) != 0xFF) { + switch (command) { + case 1: + // INSTRUMENT DEFINITION + bufferPosition += 15; + break; + + case 2: + // NOTE DEFINITION + bufferPosition += 11; + break; + + case 0x80: + // LOOP + bufferPosition += 1; + break; + + default: + // START OF CHANNEL + bufferPosition += 1; + _channels[curChannel].currentOffset = bufferPosition; + _channels[curChannel].startOffset = bufferPosition; + _channels[curChannel].state = 1; + ++curChannel; + break; + } + } +} + +void Player_AD::updateSfx() { + if (--_sfxTimer) { + return; + } + _sfxTimer = 4; + + for (int i = 0; i <= 9; ++i) { + if (!_channels[i].state) { + continue; + } + + updateChannel(i); + } +} + +void Player_AD::clearChannel(int channel) { + writeReg(0xA0 + channel, 0x00); + writeReg(0xB0 + channel, 0x00); +} + +void Player_AD::updateChannel(int channel) { + if (_channels[channel].state == 1) { + parseSlot(channel); + } else { + updateSlot(channel); + } +} + +void Player_AD::parseSlot(int channel) { + while (true) { + const byte *curOffset = _channels[channel].currentOffset; + + switch (*curOffset) { + case 1: + // INSTRUMENT DEFINITION + ++curOffset; + _channels[channel].instrumentData[0] = *(curOffset + 0); + _channels[channel].instrumentData[1] = *(curOffset + 2); + _channels[channel].instrumentData[2] = *(curOffset + 9); + _channels[channel].instrumentData[3] = *(curOffset + 8); + _channels[channel].instrumentData[4] = *(curOffset + 4); + _channels[channel].instrumentData[5] = *(curOffset + 3); + _channels[channel].instrumentData[6] = 0; + + setupChannel(channel, curOffset); + + writeReg(0xA0 + channel, *(curOffset + 0)); + writeReg(0xB0 + channel, *(curOffset + 1) & 0xDF); + + _channels[channel].currentOffset += 15; + break; + + case 2: + // NOTE DEFINITION + ++curOffset; + _channels[channel].state = 2; + noteOffOn(channel); + parseNote(channel, 0, curOffset); + parseNote(channel, 1, curOffset); + return; + + case 0x80: + // LOOP + _channels[channel].currentOffset = _channels[channel].startOffset; + break; + + default: + // START OF CHANNEL + // When we encounter a start of another channel while playback + // it means that the current channel is finished. Thus, we will + // stop it. + clearChannel(channel); + _channels[channel].state = 0; + + // If no channel of the sound effect is playing anymore, unlock + // the resource. + channel /= 3; + if (!_channels[channel + 0].state + && !_channels[channel + 1].state + && !_channels[channel + 2].state) { + _vm->_res->unlock(rtSound, _sfxResource[channel]); + } + return; + } + } +} + +void Player_AD::updateSlot(int channel) { + const byte *curOffset = _channels[channel].currentOffset + 1; + + for (int num = 0; num <= 1; ++num, curOffset += 5) { + if (!(*curOffset & 0x80)) { + continue; + } + + const int note = channel * 2 + num; + bool updateNote = false; + + if (_notes[note].state == 2) { + if (!--_notes[note].sustainTimer) { + updateNote = true; + } + } else { + updateNote = processNoteEnvelope(note, _notes[note].instrumentValue); + + if (_notes[note].bias) { + writeRegisterSpecial(note, _notes[note].bias - _notes[note].instrumentValue, *curOffset & 0x07); + } else { + writeRegisterSpecial(note, _notes[note].instrumentValue, *curOffset & 0x07); + } + } + + if (updateNote) { + if (processNote(note, curOffset)) { + if (!(*curOffset & 0x08)) { + _channels[channel].currentOffset += 11; + _channels[channel].state = 1; + continue; + } else if (*curOffset & 0x10) { + noteOffOn(channel); + } + + _notes[note].state = -1; + processNote(note, curOffset); + } + } + + if ((*curOffset & 0x20) && !--_notes[note].playTime) { + _channels[channel].currentOffset += 11; + _channels[channel].state = 1; + } + } +} + +void Player_AD::parseNote(int channel, int num, const byte *offset) { + if (num) { + offset += 5; + } + + if (*offset & 0x80) { + const int note = channel * 2 + num; + _notes[note].state = -1; + processNote(note, offset); + _notes[note].playTime = 0; + + if (*offset & 0x20) { + _notes[note].playTime = (*(offset + 4) >> 4) * 118; + _notes[note].playTime += (*(offset + 4) & 0x0F) * 8; + } + } +} + +bool Player_AD::processNote(int note, const byte *offset) { + if (++_notes[note].state == 4) { + return true; + } + + const int instrumentDataOffset = *offset & 0x07; + _notes[note].bias = _noteBiasTable[instrumentDataOffset]; + + uint8 instrumentDataValue = 0; + if (_notes[note].state == 0) { + instrumentDataValue = _channels[note / 2].instrumentData[instrumentDataOffset]; + } + + uint8 noteInstrumentValue = readRegisterSpecial(note, instrumentDataValue, instrumentDataOffset); + if (_notes[note].bias) { + noteInstrumentValue = _notes[note].bias - noteInstrumentValue; + } + _notes[note].instrumentValue = noteInstrumentValue; + + if (_notes[note].state == 2) { + _notes[note].sustainTimer = _numStepsTable[*(offset + 3) >> 4]; + + if (*offset & 0x40) { + _notes[note].sustainTimer = (((getRnd() << 8) * _notes[note].sustainTimer) >> 16) + 1; + } + } else { + int timer1, timer2; + if (_notes[note].state == 3) { + timer1 = *(offset + 3) & 0x0F; + timer2 = 0; + } else { + timer1 = *(offset + _notes[note].state + 1) >> 4; + timer2 = *(offset + _notes[note].state + 1) & 0x0F; + } + + int adjustValue = ((_noteAdjustTable[timer2] * _noteAdjustScaleTable[instrumentDataOffset]) >> 16) - noteInstrumentValue; + setupNoteEnvelopeState(note, _numStepsTable[timer1], adjustValue); + } + + return false; +} + +void Player_AD::noteOffOn(int channel) { + const uint8 regValue = readReg(0xB0 | channel); + writeReg(0xB0 | channel, regValue & 0xDF); + writeReg(0xB0 | channel, regValue | 0x20); +} + +void Player_AD::writeRegisterSpecial(int note, uint8 value, int offset) { + if (offset == 6) { + return; + } + + // Division by 2 extracts the channel number out of the note. + note /= 2; + + uint8 regNum; + if (_useOperatorTable[offset]) { + regNum = _operatorOffsetTable[_channelOperatorOffsetTable[offset] + note * 2]; + } else { + regNum = _channelOffsetTable[note]; + } + + regNum += _baseRegisterTable[offset]; + + uint8 regValue = readReg(regNum) & (~_registerMaskTable[offset]); + regValue |= value << _registerShiftTable[offset]; + + writeReg(regNum, regValue); +} + +uint8 Player_AD::readRegisterSpecial(int note, uint8 defaultValue, int offset) { + if (offset == 6) { + return 0; + } + + // Division by 2 extracts the channel number out of the note. + note /= 2; + + uint8 regNum; + if (_useOperatorTable[offset]) { + regNum = _operatorOffsetTable[_channelOperatorOffsetTable[offset] + note * 2]; + } else { + regNum = _channelOffsetTable[note]; + } + + regNum += _baseRegisterTable[offset]; + + uint8 regValue; + if (defaultValue) { + regValue = defaultValue; + } else { + regValue = readReg(regNum); + } + + regValue &= _registerMaskTable[offset]; + regValue >>= _registerShiftTable[offset]; + + return regValue; +} + +void Player_AD::setupNoteEnvelopeState(int note, int steps, int adjust) { + _notes[note].preIncrease = 0; + if (ABS(adjust) > steps) { + _notes[note].preIncrease = 1; + _notes[note].adjust = adjust / steps; + _notes[note].envelope.stepIncrease = ABS(adjust % steps); + } else { + _notes[note].adjust = adjust; + _notes[note].envelope.stepIncrease = ABS(adjust); + } + + _notes[note].envelope.step = steps; + _notes[note].envelope.stepCounter = 0; + _notes[note].envelope.timer = steps; +} + +bool Player_AD::processNoteEnvelope(int note, int &instrumentValue) { + if (_notes[note].preIncrease) { + instrumentValue += _notes[note].adjust; + } + + _notes[note].envelope.stepCounter += _notes[note].envelope.stepIncrease; + if (_notes[note].envelope.stepCounter >= _notes[note].envelope.step) { + _notes[note].envelope.stepCounter -= _notes[note].envelope.step; + + if (_notes[note].adjust < 0) { + --instrumentValue; + } else { + ++instrumentValue; + } + } + + if (--_notes[note].envelope.timer) { + return false; + } else { + return true; + } +} + +uint8 Player_AD::getRnd() { + if (_rndSeed & 1) { + _rndSeed >>= 1; + _rndSeed ^= 0xB8; + } else { + _rndSeed >>= 1; + } + + return _rndSeed; +} + +const uint Player_AD::_noteBiasTable[7] = { + 0x00, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x00 +}; + +const uint Player_AD::_numStepsTable[16] = { + 1, 4, 6, 8, + 10, 14, 18, 24, + 36, 64, 100, 160, + 240, 340, 600, 1200 +}; + +const uint Player_AD::_noteAdjustScaleTable[7] = { + 255, 7, 63, 15, 63, 15, 63 +}; + +const uint Player_AD::_noteAdjustTable[16] = { + 0, 4369, 8738, 13107, + 17476, 21845, 26214, 30583, + 34952, 39321, 43690, 48059, + 52428, 46797, 61166, 65535 +}; + +const bool Player_AD::_useOperatorTable[7] = { + false, false, true, true, true, true, false +}; + +const uint Player_AD::_channelOffsetTable[11] = { + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 8, 7 +}; + +const uint Player_AD::_channelOperatorOffsetTable[7] = { + 0, 0, 1, 1, 0, 0, 0 +}; + +const uint Player_AD::_baseRegisterTable[7] = { + 0xA0, 0xC0, 0x40, 0x20, 0x40, 0x20, 0x00 +}; + +const uint Player_AD::_registerMaskTable[7] = { + 0xFF, 0x0E, 0x3F, 0x0F, 0x3F, 0x0F, 0x00 +}; + +const uint Player_AD::_registerShiftTable[7] = { + 0, 1, 0, 0, 0, 0, 0 +}; + +} // End of namespace Scumm diff --git a/engines/scumm/player_ad.h b/engines/scumm/player_ad.h new file mode 100644 index 0000000000..da6c7177ef --- /dev/null +++ b/engines/scumm/player_ad.h @@ -0,0 +1,190 @@ +/* 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 SCUMM_PLAYER_AD_H +#define SCUMM_PLAYER_AD_H + +#include "scumm/music.h" + +#include "audio/audiostream.h" +#include "audio/mixer.h" + +#include "common/mutex.h" + +namespace OPL { +class OPL; +} + +namespace Scumm { + +class ScummEngine; + +/** + * Sound output for v3/v4 AdLib data. + */ +class Player_AD : public MusicEngine, public Audio::AudioStream { +public: + Player_AD(ScummEngine *scumm, Audio::Mixer *mixer); + virtual ~Player_AD(); + + // MusicEngine API + virtual void setMusicVolume(int vol); + virtual void startSound(int sound); + virtual void stopSound(int sound); + virtual void stopAllSounds(); + virtual int getMusicTimer(); + virtual int getSoundStatus(int sound) const; + + virtual void saveLoadWithSerializer(Serializer *ser); + + // AudioStream API + virtual int readBuffer(int16 *buffer, const int numSamples); + virtual bool isStereo() const { return false; } + virtual bool endOfData() const { return false; } + virtual int getRate() const { return _rate; } + +private: + ScummEngine *const _vm; + Common::Mutex _mutex; + Audio::Mixer *const _mixer; + const int _rate; + Audio::SoundHandle _soundHandle; + void setupVolume(); + + OPL::OPL *_opl2; + + int _samplesPerCallback; + int _samplesPerCallbackRemainder; + int _samplesTillCallback; + int _samplesTillCallbackRemainder; + + int _soundPlaying; + int _engineMusicTimer; + + // AdLib register utilities + uint8 _registerBackUpTable[256]; + void writeReg(int r, int v); + uint8 readReg(int r) const; + + // Instrument setup + void setupChannel(const uint channel, uint instrOffset) { + setupChannel(channel, _resource + instrOffset); + } + void setupChannel(const uint channel, const byte *instrOffset); + void setupOperator(const uint opr, const byte *&instrOffset); + static const int _operatorOffsetTable[18]; + + // Sound data + const byte *_resource; + + // Music handling + void startMusic(); + void updateMusic(); + void noteOff(uint channel); + int findFreeChannel(); + void setupFrequency(uint channel, int8 frequency); + void setupRhythm(uint rhythmInstr, uint instrOffset); + + uint _timerLimit; + uint _musicTicks; + uint _musicTimer; + uint _internalMusicTimer; + bool _loopFlag; + uint _musicLoopStart; + uint _instrumentOffset[16]; + uint _channelLastEvent[9]; + uint _channelFrequency[9]; + uint _channelB0Reg[9]; + + uint _mdvdrState; + uint _voiceChannels; + + uint _curOffset; + uint _nextEventTimer; + + static const uint _noteFrequencies[12]; + static const uint _mdvdrTable[6]; + static const uint _rhythmOperatorTable[6]; + static const uint _rhythmChannelTable[6]; + + // SFX handling + void startSfx(); + void updateSfx(); + void clearChannel(int channel); + void updateChannel(int channel); + void parseSlot(int channel); + void updateSlot(int channel); + void parseNote(int channel, int num, const byte *offset); + bool processNote(int note, const byte *offset); + void noteOffOn(int channel); + void writeRegisterSpecial(int note, uint8 value, int offset); + uint8 readRegisterSpecial(int note, uint8 defaultValue, int offset); + void setupNoteEnvelopeState(int note, int steps, int adjust); + bool processNoteEnvelope(int note, int &instrumentValue); + + int _sfxTimer; + + int _sfxResource[3]; + int _sfxPriority[3]; + + struct Channel { + int state; + const byte *currentOffset; + const byte *startOffset; + uint8 instrumentData[7]; + } _channels[11]; + + uint8 _rndSeed; + uint8 getRnd(); + + struct Note { + int state; + int playTime; + int sustainTimer; + int instrumentValue; + int bias; + int preIncrease; + int adjust; + + struct Envelope { + int stepIncrease; + int step; + int stepCounter; + int timer; + } envelope; + } _notes[22]; + + static const uint _noteBiasTable[7]; + static const uint _numStepsTable[16]; + static const uint _noteAdjustScaleTable[7]; + static const uint _noteAdjustTable[16]; + static const bool _useOperatorTable[7]; + static const uint _channelOffsetTable[11]; + static const uint _channelOperatorOffsetTable[7]; + static const uint _baseRegisterTable[7]; + static const uint _registerMaskTable[7]; + static const uint _registerShiftTable[7]; +}; + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 7b2ff91ad3..c34be5816d 100644 --- a/engines/scumm/saveload.h +++ b/engines/scumm/saveload.h @@ -47,7 +47,7 @@ namespace Scumm { * only saves/loads those which are valid for the version of the savegame * which is being loaded/saved currently. */ -#define CURRENT_VER 94 +#define CURRENT_VER 95 /** * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 2a14673855..d1a3de94b8 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -52,6 +52,7 @@ #include "scumm/he/logic_he.h" #include "scumm/he/sound_he.h" #include "scumm/object.h" +#include "scumm/player_ad.h" #include "scumm/player_nes.h" #include "scumm/player_sid.h" #include "scumm/player_pce.h" @@ -1841,6 +1842,15 @@ void ScummEngine::setupMusic(int midi) { _musicEngine = _townsPlayer = new Player_Towns_v1(this, _mixer); if (!_townsPlayer->init()) error("Failed to initialize FM-Towns audio driver"); + } else if (_game.platform == Common::kPlatformDOS && (_sound->_musicType == MDT_ADLIB) && (_game.id == GID_LOOM || _game.id == GID_INDY3)) { + // For Indy3 DOS and Loom DOS we use an implementation of the original + // AD player when AdLib is selected. This fixes sound effects in those + // games (see for example bug #2027877 "INDY3: Non-Looping Sound + // Effects"). The player itself is also used in Monkey Island DOS + // EGA/VGA. However, we support multi MIDI for that game and we cannot + // support this with the Player_AD code at the moment. The reason here + // is that multi MIDI is supported internally by our iMuse output. + _musicEngine = new Player_AD(this, _mixer); } else if (_game.version >= 3 && _game.heversion <= 62) { MidiDriver *nativeMidiDriver = 0; MidiDriver *adlibMidiDriver = 0; diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 3f6290f8fc..5e5e8045b5 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -1930,7 +1930,6 @@ int ScummEngine::readSoundResourceSmallHeader(ResId idx) { // 8 bytes MTrk header // 7 bytes MIDI tempo sysex // + some default instruments - byte *ptr; if (_game.features & GF_OLD_BUNDLE) { ad_size -= 4; _fileHandle->seek(ad_offs + 4, SEEK_SET); @@ -1938,10 +1937,17 @@ int ScummEngine::readSoundResourceSmallHeader(ResId idx) { ad_size -= 6; _fileHandle->seek(ad_offs, SEEK_SET); } - ptr = (byte *) calloc(ad_size, 1); - _fileHandle->read(ptr, ad_size); - convertADResource(_res, _game, idx, ptr, ad_size); - free(ptr); + // For games using AD except Indy3 and Loom we are using our iMuse + // implementation. See output initialization in + // ScummEngine::setupMusic for more information. + if (_game.id != GID_INDY3 && _game.id != GID_LOOM) { + byte *ptr = (byte *)calloc(ad_size, 1); + _fileHandle->read(ptr, ad_size); + convertADResource(_res, _game, idx, ptr, ad_size); + free(ptr); + } else { + _fileHandle->read(_res->createResource(rtSound, idx, ad_size), ad_size); + } return 1; } else if (ro_offs != 0) { _fileHandle->seek(ro_offs - 2, SEEK_SET); diff --git a/engines/sky/POTFILES b/engines/sky/POTFILES new file mode 100644 index 0000000000..6c39f82e75 --- /dev/null +++ b/engines/sky/POTFILES @@ -0,0 +1,2 @@ +engines/sky/compact.cpp +engines/sky/detection.cpp diff --git a/engines/sword1/POTFILES b/engines/sword1/POTFILES new file mode 100644 index 0000000000..849bef9060 --- /dev/null +++ b/engines/sword1/POTFILES @@ -0,0 +1,4 @@ +engines/sword1/animation.cpp +engines/sword1/control.cpp +engines/sword1/logic.cpp +engines/sword1/sword1.cpp diff --git a/engines/sword2/POTFILES b/engines/sword2/POTFILES new file mode 100644 index 0000000000..94ad720989 --- /dev/null +++ b/engines/sword2/POTFILES @@ -0,0 +1,2 @@ +engines/sword2/animation.cpp +engines/sword2/sword2.cpp diff --git a/engines/sword25/gfx/microtiles.cpp b/engines/sword25/gfx/microtiles.cpp index 8dceed5348..18e4a9a1fb 100644 --- a/engines/sword25/gfx/microtiles.cpp +++ b/engines/sword25/gfx/microtiles.cpp @@ -119,7 +119,6 @@ RectangleList *MicroTileArray::getRectangles() { for (y = 0; y < _tilesH; ++y) { for (x = 0; x < _tilesW; ++x) { - int start; int finish = 0; BoundingBox boundingBox = _tiles[i]; @@ -132,8 +131,6 @@ RectangleList *MicroTileArray::getRectangles() { y0 = (y * TileSize) + TileY0(boundingBox); y1 = (y * TileSize) + TileY1(boundingBox); - start = i; - if (TileX1(boundingBox) == TileSize - 1 && x != _tilesW - 1) { // check if the tile continues while (!finish) { ++x; diff --git a/engines/teenagent/POTFILES b/engines/teenagent/POTFILES new file mode 100644 index 0000000000..b8b832872e --- /dev/null +++ b/engines/teenagent/POTFILES @@ -0,0 +1 @@ +engines/teenagent/resources.cpp diff --git a/engines/tinsel/POTFILES b/engines/tinsel/POTFILES new file mode 100644 index 0000000000..714da378c8 --- /dev/null +++ b/engines/tinsel/POTFILES @@ -0,0 +1 @@ +engines/tinsel/saveload.cpp diff --git a/engines/toltecs/POTFILES b/engines/toltecs/POTFILES new file mode 100644 index 0000000000..81adbb86a1 --- /dev/null +++ b/engines/toltecs/POTFILES @@ -0,0 +1,2 @@ +engines/toltecs/detection.cpp +engines/toltecs/menu.cpp diff --git a/engines/tsage/core.cpp b/engines/tsage/core.cpp index 5ad5b01f8b..fbbf982c28 100644 --- a/engines/tsage/core.cpp +++ b/engines/tsage/core.cpp @@ -1179,7 +1179,7 @@ void PaletteRotation::signal() { int count = _end - _currIndex; g_system->getPaletteManager()->setPalette((const byte *)&_palette[_currIndex * 3], _start, count); - if (count2) { + if (count2 > 0) { g_system->getPaletteManager()->setPalette((const byte *)&_palette[_start * 3], _start + count, count2); } } @@ -1516,6 +1516,10 @@ void ScenePalette::changeBackground(const Rect &bounds, FadeMode fadeMode) { g_globals->_screenSurface.copyFrom(g_globals->_sceneManager._scene->_backSurface, tempRect, Rect(0, 0, tempRect.width(), tempRect.height()), NULL); + if (g_vm->getGameID() == GType_Ringworld2 && !GLOBALS._player._uiEnabled + && T2_GLOBALS._interfaceY == UI_INTERFACE_Y) { + g_globals->_screenSurface.fillRect(Rect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT), 0); + } for (SynchronizedList<PaletteModifier *>::iterator i = tempPalette._listeners.begin(); i != tempPalette._listeners.end(); ++i) delete *i; @@ -2757,13 +2761,29 @@ void BackgroundSceneObject::draw() { g_globals->_sceneManager._scene->_backSurface.copyFrom(frame, destRect, priorityRegion); } -void BackgroundSceneObject::setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY, int priority, int32 arg10) { - warning("TODO: Implement properly BackgroundSceneObject::setup2()"); +SceneObject *BackgroundSceneObject::clone() const { + BackgroundSceneObject *obj = new BackgroundSceneObject(*this); + return obj; +} + +void BackgroundSceneObject::setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY, int priority, int effect) { + // Check if the given object is already in the background object list + if (R2_GLOBALS._sceneManager._scene->_bgSceneObjects.contains(this)) { + _flags |= OBJFLAG_REMOVE; + + // Clone the item + SceneObject *obj = clone(); + obj->_flags |= OBJFLAG_CLONED; + R2_GLOBALS._sceneManager._scene->_bgSceneObjects.push_back(obj); + + _flags |= ~OBJFLAG_REMOVE; + } + postInit(); setVisage(visage); setStrip(stripFrameNum); setFrame(frameNum); - setPosition(Common::Point(posX, posY), 0); + setPosition(Common::Point(posX, posY)); fixPriority(priority); } diff --git a/engines/tsage/core.h b/engines/tsage/core.h index f7a5a43b16..6156d13b34 100644 --- a/engines/tsage/core.h +++ b/engines/tsage/core.h @@ -575,7 +575,6 @@ public: int getRegionIndex(); int checkRegion(const Common::Point &pt); void animate(AnimateMode animMode, ...); - SceneObject *clone() const; void checkAngle(const SceneObject *obj); void checkAngle(const Common::Point &pt); void hide(); @@ -602,6 +601,7 @@ public: virtual void changeAngle(int angle); // New methods introduced by Ringworld 2 virtual void copy(SceneObject *src); + virtual SceneObject *clone() const; void setup(int visage, int stripFrameNum, int frameNum, int posX, int posY, int priority); void setup(int visage, int stripFrameNum, int frameNum); @@ -612,7 +612,9 @@ public: virtual Common::String getClassName() { return "BackgroundSceneObject"; } virtual void postInit(SceneObjectList *OwnerList = NULL); virtual void draw(); - void setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY, int priority, int32 arg10); + virtual SceneObject *clone() const; + + void setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY, int priority, int effect); static void copySceneToBackground(); }; diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp index 22b0d7280a..7068c2fa1a 100644 --- a/engines/tsage/globals.cpp +++ b/engines/tsage/globals.cpp @@ -409,23 +409,23 @@ void Ringworld2Globals::reset() { _v565E9 = -5; _v565EB = 26; _foodCount = 0; - _v565F6 = 0; - _v565FA = 0; + _rimLocation = 0; + _rimTransportLocation = 0; _v565AE = 0; - _v56605[0] = 0; - _v56605[1] = 3; - _v56605[2] = 5; - _v56605[3] = 1; - _v56605[4] = 2; - _v56605[5] = 5; - _v56605[6] = 9; - _v56605[7] = 14; - _v56605[8] = 15; - _v56605[9] = 18; - _v56605[10] = 20; - _v56605[11] = 25; - _v56605[12] = 27; - _v56605[13] = 31; + _spillLocation[0] = 0; + _spillLocation[1] = 3; + _spillLocation[R2_SEEKER] = 5; + _spillLocation[3] = 1; + _spillLocation[4] = 2; + _spillLocation[5] = 5; + _spillLocation[6] = 9; + _spillLocation[7] = 14; + _spillLocation[8] = 15; + _spillLocation[9] = 18; + _spillLocation[10] = 20; + _spillLocation[11] = 25; + _spillLocation[12] = 27; + _spillLocation[13] = 31; for (int i = 0; i < 18; i++) { _v56613[(i * 4) ] = 1; @@ -455,13 +455,13 @@ void Ringworld2Globals::reset() { _landerSuitNumber = 2; _v566A4 = 1; _v566A5 = 0; - _v566A8 = 5; - _v566A9 = 0; - _v566AA = 0; + _desertStepsRemaining = 5; + _desertCorrectDirection = 0; + _desertPreviousDirection = 0; for (int i = 0; i < 1000; i++) - _v566AB[i] = 0; - _v56A93 = -1; - _v56A99 = 5; + _desertMovements[i] = 0; + _desertWrongDirCtr = -1; + _balloonAltitude = 5; _scene1925CurrLevel = 0; //_v56A9C _v56A9E = 0; _v56AA0 = 0; @@ -502,8 +502,8 @@ void Ringworld2Globals::reset() { // Reset fields stored in the player class _player._characterIndex = R2_QUINN; - _player._characterScene[1] = 100; - _player._characterScene[2] = 300; + _player._characterScene[R2_QUINN] = 100; + _player._characterScene[R2_SEEKER] = 300; _player._characterScene[3] = 300; } @@ -524,11 +524,11 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsSint16LE(_v565E9); s.syncAsSint16LE(_v565EB); s.syncAsSint16LE(_foodCount); - s.syncAsSint32LE(_v565F6); - s.syncAsSint16LE(_v565FA); + s.syncAsSint32LE(_rimLocation); + s.syncAsSint16LE(_rimTransportLocation); s.syncAsSint16LE(_landerSuitNumber); s.syncAsSint16LE(_v566A6); - s.syncAsSint16LE(_v56A93); + s.syncAsSint16LE(_desertWrongDirCtr); s.syncAsSint16LE(_scene1925CurrLevel); // _v56A9C s.syncAsSint16LE(_v56A9E); s.syncAsSint16LE(_v56AA2); @@ -555,9 +555,9 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsByte(_v565AE); s.syncAsByte(_v566A4); s.syncAsByte(_v566A5); - s.syncAsByte(_v566A8); - s.syncAsByte(_v566A9); - s.syncAsByte(_v566AA); + s.syncAsByte(_desertStepsRemaining); + s.syncAsByte(_desertCorrectDirection); + s.syncAsByte(_desertPreviousDirection); s.syncAsByte(_v56AA0); s.syncAsByte(_v56AA1); s.syncAsByte(_v56AA6); @@ -565,10 +565,10 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsByte(_v56AA8); for (i = 0; i < 14; ++i) - s.syncAsByte(_v56605[i]); + s.syncAsByte(_spillLocation[i]); for (i = 0; i < 1000; ++i) - s.syncAsByte(_v566AB[i]); - s.syncAsByte(_v56A99); + s.syncAsByte(_desertMovements[i]); + s.syncAsByte(_balloonAltitude); for (i = 0; i < 12; ++i) s.syncAsByte(_stripManager_lookupList[i]); @@ -577,6 +577,9 @@ void Ringworld2Globals::synchronize(Serializer &s) { for (i = 0; i < 508; i += 4) s.syncAsByte(_scene1550JunkLocations[i + 2]); + + s.syncAsSint16LE(_balloonPosition.x); + s.syncAsSint16LE(_balloonPosition.y); } } // end of namespace Ringworld2 diff --git a/engines/tsage/globals.h b/engines/tsage/globals.h index 01e1594502..0684076b1e 100644 --- a/engines/tsage/globals.h +++ b/engines/tsage/globals.h @@ -265,22 +265,22 @@ public: int _v565E9; int _v565EB; int _foodCount; - int _v565F6; - int _v565FA; + int _rimLocation; + int _rimTransportLocation; int _v5657C; byte _v565AE; - byte _v56605[14]; + byte _spillLocation[14]; int _v56613[76]; byte _v566A4; byte _v566A5; int _v566A6; byte _landerSuitNumber; - byte _v566A8; - byte _v566A9; - byte _v566AA; - byte _v566AB[1000]; - int _v56A93; - byte _v56A99; + byte _desertStepsRemaining; + byte _desertCorrectDirection; + byte _desertPreviousDirection; + byte _desertMovements[1000]; + int _desertWrongDirCtr; + byte _balloonAltitude; int _scene1925CurrLevel; //_v56A9C int _v56A9E; byte _v56AA0; @@ -302,6 +302,8 @@ public: byte _scannerFrequencies[4]; byte _stripManager_lookupList[12]; byte _scene1550JunkLocations[508]; + Common::Point _balloonPosition; + ScannerDialog *_scannerDialog; Ringworld2Globals(); diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.cpp b/engines/tsage/ringworld2/ringworld2_dialogs.cpp index e2afa574de..663697d94d 100644 --- a/engines/tsage/ringworld2/ringworld2_dialogs.cpp +++ b/engines/tsage/ringworld2/ringworld2_dialogs.cpp @@ -272,7 +272,7 @@ void CharacterDialog::show() { default: break; } - } else if ((R2_GLOBALS._player._characterScene[1] == 300) && (R2_GLOBALS._scannerFrequencies[1] != 1)) { + } else if ((R2_GLOBALS._player._characterScene[R2_QUINN] == 300) && (R2_GLOBALS._scannerFrequencies[1] != 1)) { switch (R2_GLOBALS._scannerFrequencies[1] - 1) { case 2: R2_GLOBALS._sound4.play(45); @@ -289,7 +289,7 @@ void CharacterDialog::show() { default: break; } - } else if (R2_GLOBALS._player._characterScene[2] != 300) { + } else if (R2_GLOBALS._player._characterScene[R2_SEEKER] != 300) { R2_GLOBALS._sound4.stop(); } else if (R2_GLOBALS._scannerFrequencies[2] == 1) { R2_GLOBALS._sound4.stop(); diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp index 2d55b8c524..013abfa4a4 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.cpp +++ b/engines/tsage/ringworld2/ringworld2_logic.cpp @@ -144,16 +144,22 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Miranda being questioned return new Scene1625(); case 1700: + // Rim return new Scene1700(); case 1750: + // Rim Transport Vechile return new Scene1750(); case 1800: + // Rim Lift Exterior return new Scene1800(); case 1850: + // Rim Lift Interior return new Scene1850(); case 1875: + // Rim Lift Computer return new Scene1875(); case 1900: + // Spill Mountains Elevator Exit return new Scene1900(); case 1925: return new Scene1925(); @@ -164,49 +170,49 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { /* Scene group #2 */ // case 2000: - // Ice Maze + // Spill Mountains return new Scene2000(); case 2350: - // Ice Maze: Balloon Launch Platform + // Spill Mountains: Balloon Launch Platform return new Scene2350(); case 2400: - // Ice Maze: Large empty room + // Spill Mountains: Large empty room return new Scene2400(); case 2425: - // Ice Maze: The Hall of Records + // Spill Mountains: The Hall of Records return new Scene2425(); case 2430: - // Ice Maze: Bedroom + // Spill Mountains: Bedroom return new Scene2430(); case 2435: - // Ice Maze: Throne room + // Spill Mountains: Throne room return new Scene2435(); case 2440: - // Ice Maze: Another bedroom + // Spill Mountains: Another bedroom return new Scene2440(); case 2445: - // Ice Maze: + // Spill Mountains: return new Scene2445(); case 2450: - // Ice Maze: Another bedroom + // Spill Mountains: Another bedroom return new Scene2450(); case 2455: - // Ice Maze: Inside crevasse + // Spill Mountains: Inside crevasse return new Scene2455(); case 2500: - // Ice Maze: Large Cave + // Spill Mountains: Large Cave return new Scene2500(); case 2525: - // Ice Maze: Furnace room + // Spill Mountains: Furnace room return new Scene2525(); case 2530: - // Ice Maze: Well + // Spill Mountains: Well return new Scene2530(); case 2535: - // Ice Maze: Tannery + // Spill Mountains: Tannery return new Scene2535(); case 2600: - // Ice Maze: Exit + // Spill Mountains: Exit return new Scene2600(); case 2700: // Forest Maze @@ -218,7 +224,9 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Exiting Forest return new Scene2800(); case 2900: - error("Missing scene %d from group 2", sceneNumber); + // Balloon Cutscene + return new Scene2900(); + /* Scene group #3 */ // ARM Base Hanager case 3100: @@ -286,6 +294,7 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Cutscene - Teleport outside return new Scene3700(); case 3800: + // Desert return new Scene3800(); case 3900: return new Scene3900(); @@ -517,6 +526,8 @@ void SceneExt::refreshBackground(int xAmount, int yAmount) { Common::copy(dataP, dataP + (s.w * s.h), destP); _backSurface.unlockSurface(); + R2_GLOBALS._screenSurface.addDirtyRect(_backSurface.getBounds()); + // Free the resource data DEALLOCATE(dataP); } @@ -2271,22 +2282,22 @@ void ScannerDialog::Button::reset() { break; case 1700: case 1800: - if (R2_GLOBALS._v565F6 < 1201) + if (R2_GLOBALS._rimLocation < 1201) scanner._obj4.setup(4, 3, 3); - else if (R2_GLOBALS._v565F6 < 1201) + else if (R2_GLOBALS._rimLocation < 1201) scanner._obj4.setup(4, 3, 4); else scanner._obj4.setup(4, 3, 5); break; case 3800: case 3900: - if ((R2_GLOBALS._v56A93 + 1) == 0 && R2_GLOBALS._v566A9 == 0) { + if ((R2_GLOBALS._desertWrongDirCtr + 1) == 0 && R2_GLOBALS._desertCorrectDirection == 0) { do { - R2_GLOBALS._v566A9 = R2_GLOBALS._randomSource.getRandomNumber(3); - } while (R2_GLOBALS._v566A9 == R2_GLOBALS._v566AA); + R2_GLOBALS._desertCorrectDirection = R2_GLOBALS._randomSource.getRandomNumber(3) + 1; + } while (R2_GLOBALS._desertCorrectDirection == R2_GLOBALS._desertPreviousDirection); } - scanner._obj4.setup(4, 7, R2_GLOBALS._v566A9); + scanner._obj4.setup(4, 7, R2_GLOBALS._desertCorrectDirection); if (!R2_GLOBALS.getFlag(46)) R2_GLOBALS.setFlag(46); break; diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.cpp b/engines/tsage/ringworld2/ringworld2_scenes0.cpp index a0846d386a..40e17b6ed9 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes0.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes0.cpp @@ -577,7 +577,7 @@ bool Scene125::DiskSlot::startAction(CursorType action, Event &event) { Scene125 *scene = (Scene125 *)R2_GLOBALS._sceneManager._scene; switch (action) { case CURSOR_USE: - if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == R2_GLOBALS._player._oldCharacterScene[1]) { + if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == R2_GLOBALS._player._oldCharacterScene[R2_QUINN]) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 126; scene->setAction(&scene->_sequenceManager, scene, 126, &scene->_infoDisk, NULL); @@ -619,13 +619,13 @@ void Scene125::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene != 125) // Save the prior scene to return to when the console is turned off - R2_GLOBALS._player._oldCharacterScene[1] = R2_GLOBALS._sceneManager._previousScene; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = R2_GLOBALS._sceneManager._previousScene; R2_GLOBALS._player.postInit(); R2_GLOBALS._player.hide(); R2_GLOBALS._player.disableControl(); - if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == R2_GLOBALS._player._oldCharacterScene[1]) { + if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == R2_GLOBALS._player._oldCharacterScene[R2_QUINN]) { _infoDisk.postInit(); _infoDisk.setup(160, 3, 5); _infoDisk.setPosition(Common::Point(47, 167)); @@ -781,7 +781,7 @@ void Scene125::signal() { } break; case 125: - R2_INVENTORY.setObjectScene(R2_OPTO_DISK, R2_GLOBALS._player._oldCharacterScene[1]); + R2_INVENTORY.setObjectScene(R2_OPTO_DISK, R2_GLOBALS._player._oldCharacterScene[R2_QUINN]); R2_GLOBALS._player.enableControl(); break; case 126: @@ -883,7 +883,7 @@ void Scene125::consoleAction(int id) { _icon2.setIcon(23); break; case 6: - R2_GLOBALS._sceneManager.changeScene(R2_GLOBALS._player._oldCharacterScene[1]); + R2_GLOBALS._sceneManager.changeScene(R2_GLOBALS._player._oldCharacterScene[R2_QUINN]); break; case 7: if (_consoleMode == 11) @@ -946,7 +946,7 @@ void Scene125::consoleAction(int id) { break; case 13: consoleAction(2); - if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) != R2_GLOBALS._player._oldCharacterScene[1]) { + if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) != R2_GLOBALS._player._oldCharacterScene[R2_QUINN]) { SceneItem::display2(126, 17); } else { R2_GLOBALS._player.disableControl(); @@ -3279,7 +3279,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { _miranda.setAction(&_action3); _miranda.setDetails(300, 39, 40, 41, 1, (SceneItem *)NULL); - if ((R2_GLOBALS._player._characterScene[2] == 300) || (R2_GLOBALS._player._characterScene[2] == 325)) { + if ((R2_GLOBALS._player._characterScene[R2_SEEKER] == 300) || (R2_GLOBALS._player._characterScene[R2_SEEKER] == 325)) { _seeker.postInit(); _seeker.setVisage(302); _seeker.setPosition(Common::Point(158, 108)); @@ -3301,7 +3301,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { _miranda.setAction(&_action3); _miranda.setDetails(300, 39, 40, 41, 1, (SceneItem *)NULL); - if ((R2_GLOBALS._player._characterScene[1] == 300) || (R2_GLOBALS._player._characterScene[1] == 325)) { + if ((R2_GLOBALS._player._characterScene[R2_QUINN] == 300) || (R2_GLOBALS._player._characterScene[R2_QUINN] == 325)) { _quinn.postInit(); _quinn.setup(302, 3, 1); _quinn.setPosition(Common::Point(271, 150)); @@ -3317,7 +3317,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { break; case 3: - if ((R2_GLOBALS._player._characterScene[2] == 300) || (R2_GLOBALS._player._characterScene[2] == 325)) { + if ((R2_GLOBALS._player._characterScene[R2_SEEKER] == 300) || (R2_GLOBALS._player._characterScene[R2_SEEKER] == 325)) { _seeker.postInit(); _seeker.setVisage(302); _seeker.setPosition(Common::Point(158, 108)); @@ -3326,7 +3326,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { _seeker.setDetails(300, 42, 43, 44, 1, (SceneItem *)NULL); } - if ((R2_GLOBALS._player._characterScene[1] == 300) || (R2_GLOBALS._player._characterScene[1] == 325)) { + if ((R2_GLOBALS._player._characterScene[R2_QUINN] == 300) || (R2_GLOBALS._player._characterScene[R2_QUINN] == 325)) { _quinn.postInit(); _quinn.setup(302, 3, 1); _quinn.setPosition(Common::Point(271, 150)); @@ -3657,7 +3657,7 @@ void Scene300::signal() { break; case 316: - R2_GLOBALS._player._characterScene[2] = 500; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 500; _seeker.remove(); R2_GLOBALS._player.enableControl(CURSOR_CROSSHAIRS); break; diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp index 2925347d78..0941f09677 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp @@ -5,7 +5,7 @@ * 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 + * modify it under the terms of the GNU GenWeral Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. @@ -779,7 +779,7 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._v5589E.right = 200; } - if (R2_GLOBALS._player._characterScene[1] == 1100) + if (R2_GLOBALS._player._characterScene[R2_QUINN] == 1100) R2_GLOBALS._sceneManager._previousScene = 1100; if (R2_GLOBALS._sceneManager._previousScene == -1) { @@ -817,8 +817,8 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene == 300) { if (R2_GLOBALS._player._characterIndex == R2_MIRANDA) R2_GLOBALS._player._characterIndex = R2_QUINN; - R2_GLOBALS._player._characterScene[1] = 1100; - R2_GLOBALS._player._characterScene[2] = 1100; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1100; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1100; _actor2.setPosition(Common::Point(150, 30)); R2_GLOBALS._sound1.play(93); R2_GLOBALS._player.postInit(); @@ -1217,8 +1217,8 @@ void Scene1100::signal() { R2_GLOBALS._player._canWalk = false; break; case 99: - R2_GLOBALS._player._characterScene[1] = 300; - R2_GLOBALS._player._characterScene[2] = 300; + R2_GLOBALS._player._characterScene[R2_QUINN] = 300; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 300; R2_GLOBALS._player._characterIndex = R2_QUINN; R2_GLOBALS._sceneManager.changeScene(300); break; @@ -7787,9 +7787,9 @@ void Scene1550::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene == -1) R2_GLOBALS.setFlag(16); - if ((R2_GLOBALS._player._characterScene[1] != 1550) && (R2_GLOBALS._player._characterScene[1] != 1580)) { - R2_GLOBALS._player._characterScene[1] = 1550; - R2_GLOBALS._player._characterScene[2] = 1550; + if ((R2_GLOBALS._player._characterScene[R2_QUINN] != 1550) && (R2_GLOBALS._player._characterScene[R2_QUINN] != 1580)) { + R2_GLOBALS._player._characterScene[R2_QUINN] = 1550; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1550; } _stripManager.setColors(60, 255); @@ -9252,7 +9252,7 @@ void Scene1550::enterArea() { R2_GLOBALS._walkRegions.enableRegion(k5A750[_field419 - 1550]); _companion.setPosition(Common::Point(k5A72E[k5A76D[_field419 - 1550]], k5A73F[k5A76D[_field419 - 1550]] + 8)); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - if (R2_GLOBALS._player._characterScene[2] == 1580) { + if (R2_GLOBALS._player._characterScene[R2_SEEKER] == 1580) { _companion.setup(1516, 3, 17); _companion.setPosition(Common::Point(272, 94)); _companion.fixPriority(91); @@ -9263,7 +9263,7 @@ void Scene1550::enterArea() { _companion.setDetails(1550, -1, -1, -1, 2, (SceneItem *) NULL); } } else { - if (R2_GLOBALS._player._characterScene[1] == 1580) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == 1580) { _companion.setup(1516, 2, 14); _companion.setPosition(Common::Point(276, 97)); _companion.fixPriority(91); @@ -10016,17 +10016,8 @@ void Scene1580::signal() { * Scene 1625 - Miranda being questioned * *--------------------------------------------------------------------------*/ -Scene1625::Scene1625() { - _field412 = 0; -} - -void Scene1625::synchronize(Serializer &s) { - SceneExt::synchronize(s); - s.syncAsSint16LE(_field412); -} - -bool Scene1625::Actor7::startAction(CursorType action, Event &event) { +bool Scene1625::Wire::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); @@ -10035,10 +10026,20 @@ bool Scene1625::Actor7::startAction(CursorType action, Event &event) { scene->_sceneMode = 1631; scene->_actor3.postInit(); - scene->setAction(&scene->_sequenceManager, scene, 1631, &scene->_actor3, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1631, &scene->_actor3, &scene->_wire, NULL); return true; } +Scene1625::Scene1625() { + _field412 = 0; +} + +void Scene1625::synchronize(Serializer &s) { + SceneExt::synchronize(s); + + s.syncAsSint16LE(_field412); +} + void Scene1625::postInit(SceneObjectList *OwnerList) { loadScene(1625); R2_GLOBALS._player._characterIndex = R2_MIRANDA; @@ -10049,23 +10050,24 @@ void Scene1625::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_soldierSpeaker); R2_GLOBALS._player.postInit(); + R2_GLOBALS._player.hide(); - _actor7.postInit(); - _actor7.setup(1626, 2, 1); - _actor7.setPosition(Common::Point(206, 133)); - _actor7.setDetails(1625, 0, -1, -1, 1, (SceneItem *) NULL); + _wire.postInit(); + _wire.setup(1626, 2, 1); + _wire.setPosition(Common::Point(206, 133)); + _wire.setDetails(1625, 0, -1, -1, 1, (SceneItem *) NULL); _actor5.postInit(); _actor5.setup(1625, 8, 1); _actor5.setPosition(Common::Point(190, 131)); _actor5.setDetails(1625, 6, -1, 2, 1, (SceneItem *) NULL); - if (R2_GLOBALS._player._oldCharacterScene[3] == 1625) { + if (R2_GLOBALS._player._oldCharacterScene[R2_MIRANDA] == 1625) { if (!R2_GLOBALS.getFlag(83)) { - _actor4.postInit(); - _actor4.setup(1626, 4, 1); - _actor4.setPosition(Common::Point(96, 166)); - _actor4.setDetails(1625, -1, -1, -1, 1, (SceneItem *) NULL); + _glass.postInit(); + _glass.setup(1626, 4, 1); + _glass.setPosition(Common::Point(96, 166)); + _glass.setDetails(1625, -1, -1, -1, 1, (SceneItem *) NULL); } R2_GLOBALS._player.enableControl(); R2_GLOBALS._player._canWalk = false; @@ -10082,8 +10084,8 @@ void Scene1625::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._sound1.play(245); _item1.setDetails(Rect(0, 0, 320, 200), 1625, 12, -1, -1, 1, NULL); - R2_GLOBALS._player._oldCharacterScene[3] = 1625; - R2_GLOBALS._player._characterScene[3] = 1625; + R2_GLOBALS._player._oldCharacterScene[R2_MIRANDA] = 1625; + R2_GLOBALS._player._characterScene[R2_MIRANDA] = 1625; } void Scene1625::remove() { @@ -10095,70 +10097,69 @@ void Scene1625::signal() { switch (_sceneMode) { case 10: R2_GLOBALS._player.disableControl(); - _actor4.postInit(); - _actor4.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); + _glass.postInit(); + _glass.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); _sceneMode = 1626; - setAction(&_sequenceManager, this, 1626, &_actor2, &_actor4, NULL); + setAction(&_sequenceManager, this, 1626, &_tealHead, &_glass, NULL); break; case 12: - // TODO: check if OK_BTN_STRING is required MessageDialog::show(DONE_MSG, OK_BTN_STRING); break; case 14: - _actor2.postInit(); - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); + _tealHead.postInit(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); _sceneMode = 99; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); _stripManager.start(831, this); break; case 99: R2_GLOBALS._player.disableControl(); - switch (_stripManager._field2E8) { - case 0: + switch (_stripManager._exitMode) { + case 1: _sceneMode = 1627; - setAction(&_sequenceManager, this, 1627, &_actor3, &_actor4, NULL); + setAction(&_sequenceManager, this, 1627, &_actor3, &_glass, NULL); break; - case 1: + case 2: _sceneMode = 1629; - setAction(&_sequenceManager, this, 1629, &_actor2, &_actor5, NULL); + setAction(&_sequenceManager, this, 1629, &_tealHead, &_actor5, NULL); break; - case 3: - R2_GLOBALS._player._oldCharacterScene[3] = 3150; - R2_GLOBALS._player._characterScene[3] = 3150; + case 4: + R2_GLOBALS._player._oldCharacterScene[R2_MIRANDA] = 3150; + R2_GLOBALS._player._characterScene[R2_MIRANDA] = 3150; R2_GLOBALS._player._characterIndex = R2_QUINN; - R2_GLOBALS._sceneManager.changeScene(R2_GLOBALS._player._characterScene[1]); + R2_GLOBALS._sceneManager.changeScene(R2_GLOBALS._player._characterScene[R2_QUINN]); break; - case 4: + case 5: _sceneMode = 1628; - _actor2.remove(); - setAction(&_sequenceManager, this, 1628, &_actor3, &_actor4, NULL); + _tealHead.remove(); + setAction(&_sequenceManager, this, 1628, &_actor3, &_glass, NULL); break; - case 5: - _actor4.postInit(); - _actor4.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); + case 6: + _glass.postInit(); + _glass.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); _sceneMode = 1632; - setAction(&_sequenceManager, this, 1632, &_actor4, NULL); + setAction(&_sequenceManager, this, 1632, &_glass, NULL); break; - case 6: + case 7: _sceneMode = 1633; - setAction(&_sequenceManager, this, 1633, &_actor4, NULL); + setAction(&_sequenceManager, this, 1633, &_glass, NULL); break; - case 7: + case 8: _sceneMode = 1635; setAction(&_sequenceManager, this, 1635, &_actor3, &_actor5, NULL); break; - case 8: - _actor4.postInit(); - _actor4.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); + case 9: + _glass.postInit(); + _glass.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); _sceneMode = 1634; setAction(&_sequenceManager, this, 1634, &_actor3, &_actor5, NULL); break; - case 2: + case 3: // No break on purpose default: _sceneMode = 1630; - _actor2.postInit(); + _tealHead.remove(); setAction(&_sequenceManager, this, 1630, &_actor1, &_actor6, NULL); break; } @@ -10166,17 +10167,17 @@ void Scene1625::signal() { _stripManager._field2E8 = 0; break; case 1625: - _actor2.postInit(); - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); + _tealHead.postInit(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); _sceneMode = 10; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); _stripManager.start(800, this); break; case 1626: - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); - _actor2.show(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); + _tealHead.show(); _actor3.postInit(); _actor3.setup(1627, 3, 1); @@ -10197,9 +10198,9 @@ void Scene1625::signal() { break; case 1628: R2_GLOBALS.setFlag(83); - _actor2.postInit(); - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); + _tealHead.postInit(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); _actor3.setup(1627, 3, 1); _actor3.setPosition(Common::Point(196, 65)); @@ -10210,9 +10211,9 @@ void Scene1625::signal() { _stripManager.start(834, this); break; case 1629: - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); - _actor2.show(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); + _tealHead.show(); _sceneMode = 99; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); @@ -10227,13 +10228,12 @@ void Scene1625::signal() { _actor3.setPosition(Common::Point(196, 65)); _actor3.show(); - _actor7.remove(); + _wire.remove(); _actor1.postInit(); _actor1.fixPriority(10); _actor6.postInit(); - warning("_actor6._actorName = \"arm\";"); R2_INVENTORY.setObjectScene(R2_SUPERCONDUCTOR_WIRE, 3); _sceneMode = 14; @@ -10241,16 +10241,16 @@ void Scene1625::signal() { setAction(&_sequenceManager, this, 1625, &_actor1, &_actor6, NULL); break; case 1632: - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); - _actor2.show(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); + _tealHead.show(); _sceneMode = 99; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); _stripManager.start(835, this); break; case 1633: - _actor4.remove(); + _glass.remove(); _sceneMode = 99; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); _stripManager.start(818, this); @@ -10282,7 +10282,7 @@ void Scene1625::process(Event &event) { } /*-------------------------------------------------------------------------- - * Scene 1700 - + * Scene 1700 - Rim * *--------------------------------------------------------------------------*/ @@ -10304,7 +10304,7 @@ bool Scene1700::Item2::startAction(CursorType action, Event &event) { return SceneHotspot::startAction(action, event); } -bool Scene1700::Actor11::startAction(CursorType action, Event &event) { +bool Scene1700::RimTransport::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); @@ -10372,13 +10372,13 @@ void Scene1700::enterArea() { Rect tmpRect; R2_GLOBALS._walkRegions.load(1700); - _actor3.remove(); - _actor4.remove(); - _actor5.remove(); - _actor6.remove(); - _actor7.remove(); - _actor8.remove(); - _actor11.remove(); + _slabWest.remove(); + _slabEast.remove(); + _slabShadowWest.remove(); + _slabShadowEast.remove(); + _westPlatform.remove(); + _rimTransportDoor.remove(); + _rimTransport.remove(); if (_sceneMode != 40) { _ledgeHopper.remove(); @@ -10397,7 +10397,8 @@ void Scene1700::enterArea() { warning("set_pane_p(_paneNumber);"); - if (_sceneMode != 40 && R2_GLOBALS._v565F6 == 0) { + if (_sceneMode != 40 && R2_GLOBALS._rimLocation == 0) { + // Crashed ledge hopper _ledgeHopper.postInit(); _ledgeHopper.setup(1701, 1, 1); _ledgeHopper.setPosition(Common::Point(220, 137)); @@ -10406,35 +10407,37 @@ void Scene1700::enterArea() { R2_GLOBALS._walkRegions.enableRegion(12); } - if ((R2_GLOBALS._v565F6 + 2) % 4 == 0) { - _actor3.postInit(); - _actor3.setup(1700, 1, 1); - _actor3.setPosition(Common::Point(222, 82)); - _actor3.setDetails(100, -1, -1, -1, 2, (SceneItem *) NULL); + if ((R2_GLOBALS._rimLocation + 2) % 4 == 0) { + // The slabs forming the bottom of the regular rings the rim transport travels through + _slabWest.postInit(); + _slabWest.setup(1700, 1, 1); + _slabWest.setPosition(Common::Point(222, 82)); + _slabWest.setDetails(100, -1, -1, -1, 2, (SceneItem *) NULL); - _actor5.postInit(); - _actor5.setup(1700, 2, 1); - _actor5.setPosition(Common::Point(177, 82)); - _actor5.fixPriority(0); + _slabShadowWest.postInit(); + _slabShadowWest.setup(1700, 2, 1); + _slabShadowWest.setPosition(Common::Point(177, 82)); + _slabShadowWest.fixPriority(0); - _actor6.postInit(); - _actor6.setup(1700, 2, 2); - _actor6.setPosition(Common::Point(332, 96)); - _actor6.fixPriority(0); + _slabShadowEast.postInit(); + _slabShadowEast.setup(1700, 2, 2); + _slabShadowEast.setPosition(Common::Point(332, 96)); + _slabShadowEast.fixPriority(0); - _actor4.postInit(); - _actor4.setup(1700, 1, 2); - _actor4.setPosition(Common::Point(424, 84)); + _slabEast.postInit(); + _slabEast.setup(1700, 1, 2); + _slabEast.setPosition(Common::Point(424, 84)); R2_GLOBALS._walkRegions.enableRegion(11); } - if ((R2_GLOBALS._v565F6 + 399) % 800 == 0) { - _actor7.postInit(); - _actor7.setup(1700, 3, 2); - _actor7.setPosition(Common::Point(51, 141)); - _actor7.fixPriority(0); - _actor7.setDetails(100, -1, -1, -1, 2, (SceneItem *) NULL); + if ((R2_GLOBALS._rimLocation + 399) % 800 == 0) { + // Enable west exit to lift + _westPlatform.postInit(); + _westPlatform.setup(1700, 3, 2); + _westPlatform.setPosition(Common::Point(51, 141)); + _westPlatform.fixPriority(0); + _westPlatform.setDetails(100, -1, -1, -1, 2, (SceneItem *) NULL); _westExit._enabled = true; } else { @@ -10442,23 +10445,24 @@ void Scene1700::enterArea() { _westExit._enabled = false; } - if ( ((!R2_GLOBALS.getFlag(15)) && ((R2_GLOBALS._v565F6 == 25) || (R2_GLOBALS._v565F6 == -3))) - || ((R2_GLOBALS.getFlag(15)) && (R2_GLOBALS._v565F6 == R2_GLOBALS._v565FA)) + if ( ((!R2_GLOBALS.getFlag(15)) && ((R2_GLOBALS._rimLocation == 25) || (R2_GLOBALS._rimLocation == -3))) + || ((R2_GLOBALS.getFlag(15)) && (R2_GLOBALS._rimLocation == R2_GLOBALS._rimTransportLocation)) ) { - R2_GLOBALS._v565FA = R2_GLOBALS._v565F6; + // Rim transport vechile located + R2_GLOBALS._rimTransportLocation = R2_GLOBALS._rimLocation; if (!R2_GLOBALS.getFlag(15)) _field77C = 1; - _actor11.postInit(); - _actor11.setup(1700, 3, 1); - _actor11.setPosition(Common::Point(338, 150)); - _actor11.setDetails(1700, 9, -1, -1, 2, (SceneItem *) NULL); - _actor11.fixPriority(15); + _rimTransport.postInit(); + _rimTransport.setup(1700, 3, 1); + _rimTransport.setPosition(Common::Point(338, 150)); + _rimTransport.setDetails(1700, 9, -1, -1, 2, (SceneItem *) NULL); + _rimTransport.fixPriority(15); - _actor8.postInit(); - _actor8.setup(1700, 4, 1); - _actor8.setPosition(Common::Point(312, 106)); - _actor8.fixPriority(130); + _rimTransportDoor.postInit(); + _rimTransportDoor.setup(1700, 4, 1); + _rimTransportDoor.setPosition(Common::Point(312, 106)); + _rimTransportDoor.fixPriority(130); } } @@ -10593,10 +10597,10 @@ void Scene1700::postInit(SceneObjectList *OwnerList) { setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL); break; } - R2_GLOBALS._player._characterScene[1] = 1700; - R2_GLOBALS._player._characterScene[2] = 1700; - R2_GLOBALS._player._oldCharacterScene[1] = 1700; - R2_GLOBALS._player._oldCharacterScene[2] = 1700; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1700; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1700; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1700; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1700; R2_GLOBALS._v558B6.set(20, 0, 320, 200); enterArea(); @@ -10613,8 +10617,8 @@ void Scene1700::signal() { switch (_sceneMode) { case 1: { _sceneMode = 3; - if ((R2_GLOBALS._v565F6 < 2400) && (R2_GLOBALS._v565F6 >= 0)) - ++R2_GLOBALS._v565F6; + if (R2_GLOBALS._rimLocation < 2400) + ++R2_GLOBALS._rimLocation; enterArea(); R2_GLOBALS._player.setPosition(Common::Point(235 - (((((235 - R2_GLOBALS._player._position.x) * 100) / 103) * 167) / 100), 170)); Common::Point pt(R2_GLOBALS._player._position.x, 160); @@ -10638,8 +10642,8 @@ void Scene1700::signal() { break; case 2: { _sceneMode = 3; - if ((R2_GLOBALS._v565F6 > -2400) && (R2_GLOBALS._v565F6 < 0)) - R2_GLOBALS._v565F6--; + if (R2_GLOBALS._rimLocation > -2400) + --R2_GLOBALS._rimLocation; enterArea(); R2_GLOBALS._player.setPosition(Common::Point(235 - (((((235 - R2_GLOBALS._player._position.x) * 100) / 167) * 103) / 100), 0)); Common::Point pt(R2_GLOBALS._player._position.x, 10); @@ -10681,9 +10685,9 @@ void Scene1700::signal() { PlayerMover *mover = new PlayerMover(); _actor12.addMover(mover, &pt, NULL); if (R2_GLOBALS._player._characterIndex == R2_QUINN) - setAction(&_sequenceManager, this, 1700, &R2_GLOBALS._player, &_actor8, NULL); + setAction(&_sequenceManager, this, 1700, &R2_GLOBALS._player, &_rimTransportDoor, NULL); else - setAction(&_sequenceManager, this, 1701, &R2_GLOBALS._player, &_actor8, NULL); + setAction(&_sequenceManager, this, 1701, &R2_GLOBALS._player, &_rimTransportDoor, NULL); } break; case 5: @@ -10747,7 +10751,7 @@ void Scene1700::signal() { } /*-------------------------------------------------------------------------- - * Scene 1750 - Rim Transport + * Scene 1750 - Maintaiance Vechile * *--------------------------------------------------------------------------*/ @@ -10921,17 +10925,17 @@ void Scene1750::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._v5589E.set(0, 0, 320, 200); SceneExt::postInit(); - R2_GLOBALS._player._characterScene[1] = 1750; - R2_GLOBALS._player._characterScene[2] = 1750; - R2_GLOBALS._player._oldCharacterScene[1] = 1750; - R2_GLOBALS._player._oldCharacterScene[2] = 1750; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1750; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1750; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1750; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1750; _rotation = R2_GLOBALS._scenePalette.addRotation(224, 254, 1); _rotation->setDelay(0); _rotation->_idxChange = 0; _rotation->_countdown = 2; - switch ((R2_GLOBALS._v565F6 + 2) % 4) { + switch ((R2_GLOBALS._rimLocation + 2) % 4) { case 0: _rotation->_currIndex = 247; break; @@ -10977,7 +10981,7 @@ void Scene1750::postInit(SceneObjectList *OwnerList) { _actor1.postInit(); _actor1.setup(1750, 2, 1); - _actor1.setPosition(Common::Point(35, ((_rotation->_currIndex - 218) % 4) + ((R2_GLOBALS._v565F6 % 800) * 4) - 1440)); + _actor1.setPosition(Common::Point(35, ((_rotation->_currIndex - 218) % 4) + ((R2_GLOBALS._rimLocation % 800) * 4) - 1440)); _actor1.fixPriority(8); _actor2.postInit(); @@ -11028,13 +11032,13 @@ void Scene1750::postInit(SceneObjectList *OwnerList) { } void Scene1750::remove() { - if (R2_GLOBALS._v565F6 == 2400) - R2_GLOBALS._v565F6 = 2399; + if (R2_GLOBALS._rimLocation == 2400) + R2_GLOBALS._rimLocation = 2399; - if (R2_GLOBALS._v565F6 == -2400) - R2_GLOBALS._v565F6 = -2399; + if (R2_GLOBALS._rimLocation == -2400) + R2_GLOBALS._rimLocation = -2399; - R2_GLOBALS._v565FA = R2_GLOBALS._v565F6; + R2_GLOBALS._rimTransportLocation = R2_GLOBALS._rimLocation; SceneExt::remove(); R2_GLOBALS._sound1.fadeOut2(NULL); @@ -11095,21 +11099,21 @@ void Scene1750::dispatch() { _field419 = ((_rotation->_currIndex - 218) / 4) / 4; if ((_field41B + 1) == _field419 || (_field41B - 3) == _field419) { - if (R2_GLOBALS._v565F6 >= 2400) { - ++R2_GLOBALS._v565F6; + if (R2_GLOBALS._rimLocation < 2400) { + ++R2_GLOBALS._rimLocation; } } if ((_field41B - 1) == _field419 || (_field41B + 3) == _field419) { - if (R2_GLOBALS._v565F6 > -2400) { - --R2_GLOBALS._v565F6; + if (R2_GLOBALS._rimLocation > -2400) { + --R2_GLOBALS._rimLocation; } } if (_rotation->_currIndex != _field41D) { _field41D = _rotation->_currIndex; - _actor1.setPosition(Common::Point(35, ((_rotation->_currIndex - 218) / 4) + - ((R2_GLOBALS._v565F6 % 800) * 4))); + _actor1.setPosition(Common::Point(35, ((_rotation->_currIndex - 218) % 4) + + ((R2_GLOBALS._rimLocation % 800) * 4) - 1440)); } } @@ -11124,20 +11128,21 @@ void Scene1750::dispatch() { } /*-------------------------------------------------------------------------- - * Scene 1800 - + * Scene 1800 - Rim Lift Exterior * *--------------------------------------------------------------------------*/ + Scene1800::Scene1800() { - _field412 = 0; + _locationMode = 0; } void Scene1800::synchronize(Serializer &s) { SceneExt::synchronize(s); - s.syncAsSint16LE(_field412); + s.syncAsSint16LE(_locationMode); } -bool Scene1800::Hotspot5::startAction(CursorType action, Event &event) { +bool Scene1800::Background::startAction(CursorType action, Event &event) { if ((action != R2_COM_SCANNER) && (action != R2_COM_SCANNER_2)) return false; @@ -11146,7 +11151,7 @@ bool Scene1800::Hotspot5::startAction(CursorType action, Event &event) { R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - if (R2_GLOBALS._v565F6 == 1201) { + if (R2_GLOBALS._rimLocation == 1201) { scene->_stripManager.start(548, this); } else if (R2_GLOBALS.getFlag(66)) { return false; @@ -11154,7 +11159,7 @@ bool Scene1800::Hotspot5::startAction(CursorType action, Event &event) { scene->_stripManager.start(546, this); } } else { - if (R2_GLOBALS._v565F6 == 1201) { + if (R2_GLOBALS._rimLocation == 1201) { scene->_stripManager.start(549, this); } else if (R2_GLOBALS.getFlag(66)) { return false; @@ -11167,7 +11172,7 @@ bool Scene1800::Hotspot5::startAction(CursorType action, Event &event) { return true; } -bool Scene1800::Actor6::startAction(CursorType action, Event &event) { +bool Scene1800::Lever::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); @@ -11183,31 +11188,34 @@ bool Scene1800::Actor6::startAction(CursorType action, Event &event) { if (_frame == 1) { R2_GLOBALS.setFlag(64); scene->_sceneMode = 1810; - scene->setAction(&scene->_sequenceManager, scene, 1810, &R2_GLOBALS._player, &scene->_actor6, &scene->_actor4, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1810, &R2_GLOBALS._player, &scene->_lever, &scene->_leftStaircase, &scene->_rightStaircase, NULL); } else { R2_GLOBALS.clearFlag(64); scene->_sceneMode = 1811; - scene->setAction(&scene->_sequenceManager, scene, 1811, &R2_GLOBALS._player, &scene->_actor6, &scene->_actor4, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1811, &R2_GLOBALS._player, &scene->_lever, &scene->_leftStaircase, &scene->_rightStaircase, NULL); } return true; } -bool Scene1800::Actor7::startAction(CursorType action, Event &event) { +bool Scene1800::Doors::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); Scene1800 *scene = (Scene1800 *)R2_GLOBALS._sceneManager._scene; if (R2_GLOBALS._player._characterIndex == R2_SEEKER) { + // Seeker trying to force open the door R2_GLOBALS._player.disableControl(); - if (scene->_field412 >= 2) { + if (scene->_locationMode >= 2) { if (R2_GLOBALS.getFlag(14)) { + // Allow door to close scene->_sceneMode = 1809; - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); } else { + // Force open door scene->_sceneMode = 1808; - scene->setAction(&scene->_sequenceManager, scene, 1808, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1808, &R2_GLOBALS._player, &scene->_doors, NULL); R2_GLOBALS.setFlag(14); } } else { @@ -11217,6 +11225,7 @@ bool Scene1800::Actor7::startAction(CursorType action, Event &event) { } else if (R2_GLOBALS.getFlag(14)) { return SceneActor::startAction(action, event); } else { + // Quinn trying to force open doors R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1812; scene->setAction(&scene->_sequenceManager, scene, 1812, &R2_GLOBALS._player, NULL); @@ -11225,40 +11234,40 @@ bool Scene1800::Actor7::startAction(CursorType action, Event &event) { return true; } -bool Scene1800::Actor8::startAction(CursorType action, Event &event) { +bool Scene1800::PassengerDoor::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); Scene1800 *scene = (Scene1800 *)R2_GLOBALS._sceneManager._scene; if (_position.x < 160) { - if (scene->_actor4._frame == 1) { + if (scene->_leftStaircase._frame == 1) { return SceneActor::startAction(action, event); } else { R2_GLOBALS.setFlag(29); R2_GLOBALS._player.disableControl(); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS.getFlag(14)) { - scene->_sceneMode = 1804; - scene->setAction(&scene->_sequenceManager, scene, 1804, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor8, NULL); - } else { scene->_sceneMode = 1; - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &scene->_companion, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); + } else { + scene->_sceneMode = 1804; + scene->setAction(&scene->_sequenceManager, scene, 1804, &R2_GLOBALS._player, &scene->_companion, &scene->_leftDoor, NULL); } } else { if (R2_GLOBALS.getFlag(14)) { scene->_sceneMode = 1; - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); } else { scene->_sceneMode = 1805; - scene->setAction(&scene->_sequenceManager, scene, 1805, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor8, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1805, &R2_GLOBALS._player, &scene->_companion, &scene->_leftDoor, NULL); } } } } else { - if (scene->_actor4._frame == 1) { + if (scene->_leftStaircase._frame == 1) { return SceneActor::startAction(action, event); } else { R2_GLOBALS.clearFlag(29); @@ -11266,20 +11275,20 @@ bool Scene1800::Actor8::startAction(CursorType action, Event &event) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS.getFlag(14)) { scene->_sceneMode = 2; - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &scene->_companion, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); } else { scene->_sceneMode = 1806; - scene->setAction(&scene->_sequenceManager, scene, 1806, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor9, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1806, &R2_GLOBALS._player, &scene->_companion, &scene->_rightDoor, NULL); } } else { if (R2_GLOBALS.getFlag(14)) { scene->_sceneMode = 2; - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); } else { scene->_sceneMode = 1807; - scene->setAction(&scene->_sequenceManager, scene, 1807, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor9, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1807, &R2_GLOBALS._player, &scene->_companion, &scene->_rightDoor, NULL); } } } @@ -11297,16 +11306,16 @@ void Scene1800::Exit1::changeScene() { if (R2_GLOBALS.getFlag(14)) { scene->_sceneMode = 3; if (R2_GLOBALS._player._characterIndex == R2_QUINN) - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &scene->_companion, &scene->_doors, NULL); else - scene->setAction(&scene->_sequenceManager, scene, 1809, &scene->_actor2, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); } else { scene->_sceneMode = 1802; if (R2_GLOBALS._player._characterIndex == R2_QUINN) - scene->setAction(&scene->_sequenceManager, scene, 1802, &R2_GLOBALS._player, &scene->_actor2, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1802, &R2_GLOBALS._player, &scene->_companion, NULL); else - scene->setAction(&scene->_sequenceManager, scene, 1802, &R2_GLOBALS._player, &scene->_actor2, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1802, &R2_GLOBALS._player, &scene->_companion, NULL); } } @@ -11318,95 +11327,98 @@ void Scene1800::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_seekerSpeaker); if (R2_GLOBALS._sceneManager._previousScene == -1) - R2_GLOBALS._v565F6 = 1201; + R2_GLOBALS._rimLocation = 1201; - if (R2_GLOBALS._v565F6 == 1201) - _field412 = 2; + // Set the mode based on whether this is the "correct" lift or not + if (R2_GLOBALS._rimLocation == 1201) + _locationMode = 2; else - _field412 = 0; + _locationMode = 0; scalePalette(65, 65, 65); _exit1.setDetails(Rect(0, 160, 319, 168), EXITCURSOR_S, 1800); - _item5.setDetails(Rect(0, 0, 320, 200), -1, -1, -1, -1, 1, NULL); - - _actor6.postInit(); - _actor6.setup(1801, 4, 1); - _actor6.setPosition(Common::Point(170, 24)); - _actor6.setDetails(1800, 13, 14, 15, 1, (SceneItem *) NULL); - - _actor7.postInit(); - _actor7.setup(1801, 3, 1); - _actor7.setPosition(Common::Point(160, 139)); - _actor7.setDetails(1800, 6, -1, -1, 1, (SceneItem *) NULL); - - _actor8.postInit(); - _actor8.setup(1800, 1, 1); - _actor8.setPosition(Common::Point(110, 78)); - _actor8.fixPriority(135); - _actor8.setDetails(1800, 20, -1, -1, 1, (SceneItem *) NULL); - - _actor9.postInit(); - _actor9.setup(1800, 2, 1); - _actor9.setPosition(Common::Point(209, 78)); - _actor9.fixPriority(135); - _actor9.setDetails(1800, 20, -1, -1, 1, (SceneItem *) NULL); - - _actor4.postInit(); - if ((_field412 != 1) && (_field412 != 3) && (!R2_GLOBALS.getFlag(64))) - _actor4.setup(1801, 2, 1); + _background.setDetails(Rect(0, 0, 320, 200), -1, -1, -1, -1, 1, NULL); + + _lever.postInit(); + _lever.setup(1801, 4, 1); + _lever.setPosition(Common::Point(170, 124)); + _lever.setDetails(1800, 13, 14, 15, 1, (SceneItem *) NULL); + + _doors.postInit(); + _doors.setup(1801, 3, 1); + _doors.setPosition(Common::Point(160, 139)); + _doors.setDetails(1800, 6, -1, -1, 1, (SceneItem *) NULL); + + _leftDoor.postInit(); + _leftDoor.setup(1800, 1, 1); + _leftDoor.setPosition(Common::Point(110, 78)); + _leftDoor.fixPriority(135); + _leftDoor.setDetails(1800, 20, -1, -1, 1, (SceneItem *) NULL); + + _rightDoor.postInit(); + _rightDoor.setup(1800, 2, 1); + _rightDoor.setPosition(Common::Point(209, 78)); + _rightDoor.fixPriority(135); + _rightDoor.setDetails(1800, 20, -1, -1, 1, (SceneItem *) NULL); + + _leftStaircase.postInit(); + if ((_locationMode != 1) && (_locationMode != 3) && (!R2_GLOBALS.getFlag(64))) + _leftStaircase.setup(1801, 2, 1); else - _actor4.setup(1801, 2, 10); - _actor4.setPosition(Common::Point(76, 142)); - _actor4.setDetails(1800, 3, -1, -1, 1, (SceneItem *) NULL); + _leftStaircase.setup(1801, 2, 10); + _leftStaircase.setPosition(Common::Point(76, 142)); + _leftStaircase.setDetails(1800, 3, -1, -1, 1, (SceneItem *) NULL); - _actor5.postInit(); - if ((_field412 != 1) && (_field412 != 3) && (!R2_GLOBALS.getFlag(64))) - _actor5.setup(1801, 1, 1); + _rightStaircase.postInit(); + if ((_locationMode != 1) && (_locationMode != 3) && (!R2_GLOBALS.getFlag(64))) + _rightStaircase.setup(1801, 1, 1); else - _actor5.setup(1801, 1, 10); - _actor5.setPosition(Common::Point(243, 142)); - _actor5.setDetails(1800, 3, -1, -1, 1, (SceneItem *) NULL); + _rightStaircase.setup(1801, 1, 10); + _rightStaircase.setPosition(Common::Point(243, 142)); + _rightStaircase.setDetails(1800, 3, -1, -1, 1, (SceneItem *) NULL); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + // Standard Quinn setup + R2_GLOBALS._player.setVisage(1503); + R2_GLOBALS._player._moveDiff = Common::Point(2, 2); + } else { + // Seeker setup dependent on whether he's holding the doors or not if (R2_GLOBALS.getFlag(14)) { R2_GLOBALS._player.animate(ANIM_MODE_NONE, NULL); R2_GLOBALS._player.setObjectWrapper(NULL); R2_GLOBALS._player.setup(1801, 5, 12); R2_GLOBALS._player.setPosition(Common::Point(160, 139)); R2_GLOBALS._walkRegions.enableRegion(9); - _actor7.hide(); + _doors.hide(); } else { R2_GLOBALS._player.setVisage(1507); } R2_GLOBALS._player._moveDiff = Common::Point(4, 2); - } else { - R2_GLOBALS._player.setVisage(1503); - R2_GLOBALS._player._moveDiff = Common::Point(2, 2); } - _actor2.postInit(); - _actor2.animate(ANIM_MODE_1, NULL); - _actor2.setObjectWrapper(new SceneObjectWrapper()); + _companion.postInit(); + _companion.animate(ANIM_MODE_1, NULL); + _companion.setObjectWrapper(new SceneObjectWrapper()); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS.getFlag(14)) { - _actor2.animate(ANIM_MODE_NONE, NULL); - _actor2.setObjectWrapper(NULL); - _actor2.setup(1801, 5, 12); + _companion.animate(ANIM_MODE_NONE, NULL); + _companion.setObjectWrapper(NULL); + _companion.setup(1801, 5, 12); R2_GLOBALS._walkRegions.enableRegion(9); - _actor7.hide(); + _doors.hide(); } else { - _actor2.setup(1507, 1, 1); - _actor2.setPosition(Common::Point(180, 160)); + _companion.setup(1507, 1, 1); + _companion.setPosition(Common::Point(180, 160)); } - _actor2.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); - _actor2._moveDiff = Common::Point(4, 2); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); + _companion._moveDiff = Common::Point(4, 2); } else { - _actor2.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); - _actor2.setVisage(1503); - _actor2._moveDiff = Common::Point(2, 2); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); + _companion.setVisage(1503); + _companion._moveDiff = Common::Point(2, 2); } if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 1800) { @@ -11414,11 +11426,11 @@ void Scene1800::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setPosition(Common::Point(114, 150)); R2_GLOBALS._player.setStrip(5); if (R2_GLOBALS.getFlag(14)) { - _actor2.setPosition(Common::Point(160, 139)); + _companion.setPosition(Common::Point(160, 139)); R2_GLOBALS._walkRegions.enableRegion(8); } else { - _actor2.setPosition(Common::Point(209, 150)); - _actor2.setStrip(6); + _companion.setPosition(Common::Point(209, 150)); + _companion.setStrip(6); R2_GLOBALS._walkRegions.enableRegion(8); } } else { @@ -11429,18 +11441,18 @@ void Scene1800::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setPosition(Common::Point(209, 150)); R2_GLOBALS._player.setStrip(6); } - _actor2.setPosition(Common::Point(114, 150)); - _actor2.setStrip(5); + _companion.setPosition(Common::Point(114, 150)); + _companion.setStrip(5); R2_GLOBALS._walkRegions.enableRegion(10); R2_GLOBALS._walkRegions.enableRegion(11); } } else { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._player.setPosition(Common::Point(140, 160)); - _actor2.setPosition(Common::Point(180, 160)); + _companion.setPosition(Common::Point(180, 160)); } else { R2_GLOBALS._player.setPosition(Common::Point(180, 160)); - _actor2.setPosition(Common::Point(140, 160)); + _companion.setPosition(Common::Point(140, 160)); } } @@ -11466,10 +11478,10 @@ void Scene1800::postInit(SceneObjectList *OwnerList) { _actor3._effect = 5; _actor3._field9C = _field312; - _actor2._linkedActor = &_actor3; + _companion._linkedActor = &_actor3; - R2_GLOBALS._player._characterScene[1] = 1800; - R2_GLOBALS._player._characterScene[2] = 1800; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1800; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1800; _item2.setDetails(Rect(128, 95, 190, 135), 1800, 10, -1, -1, 1, NULL); _item1.setDetails(Rect(95, 3, 223, 135), 1800, 0, -1, -1, 1, NULL); @@ -11491,32 +11503,32 @@ void Scene1800::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS.getFlag(29)) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _sceneMode = 1814; - setAction(&_sequenceManager, this, 1814, &R2_GLOBALS._player, &_actor2, &_actor8, NULL); + setAction(&_sequenceManager, this, 1814, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } else { _sceneMode = 1815; - setAction(&_sequenceManager, this, 1815, &R2_GLOBALS._player, &_actor2, &_actor8, NULL); + setAction(&_sequenceManager, this, 1815, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } } else { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _sceneMode = 1816; - setAction(&_sequenceManager, this, 1816, &R2_GLOBALS._player, &_actor2, &_actor9, NULL); + setAction(&_sequenceManager, this, 1816, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } else { _sceneMode = 1817; - setAction(&_sequenceManager, this, 1817, &R2_GLOBALS._player, &_actor2, &_actor9, NULL); + setAction(&_sequenceManager, this, 1817, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } } } else { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _sceneMode = 1800; - setAction(&_sequenceManager, this, 1800, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager, this, 1800, &R2_GLOBALS._player, &_companion, NULL); } else { _sceneMode = 1801; - setAction(&_sequenceManager, this, 1801, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager, this, 1801, &R2_GLOBALS._player, &_companion, NULL); } } - R2_GLOBALS._player._oldCharacterScene[1] = 1800; - R2_GLOBALS._player._oldCharacterScene[2] = 1800; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1800; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1800; } void Scene1800::signal() { @@ -11524,27 +11536,27 @@ void Scene1800::signal() { case 1: if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _sceneMode = 1804; - setAction(&_sequenceManager, this, 1804, &R2_GLOBALS._player, &_actor2, &_actor8, NULL); + setAction(&_sequenceManager, this, 1804, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } else { _sceneMode = 1805; - setAction(&_sequenceManager, this, 1805, &R2_GLOBALS._player, &_actor2, &_actor8, NULL); + setAction(&_sequenceManager, this, 1805, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } break; case 2: if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _sceneMode = 1806; - setAction(&_sequenceManager, this, 1806, &R2_GLOBALS._player, &_actor2, &_actor9, NULL); + setAction(&_sequenceManager, this, 1806, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } else { _sceneMode = 1807; - setAction(&_sequenceManager, this, 1807, &R2_GLOBALS._player, &_actor2, &_actor9, NULL); + setAction(&_sequenceManager, this, 1807, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } break; case 3: _sceneMode = 1802; if (R2_GLOBALS._player._characterIndex == R2_QUINN) - setAction(&_sequenceManager, this, 1802, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager, this, 1802, &R2_GLOBALS._player, &_companion, NULL); else - setAction(&_sequenceManager, this, 1803, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager, this, 1803, &R2_GLOBALS._player, &_companion, NULL); break; case 10: // No break on purpose @@ -11614,7 +11626,7 @@ void Scene1800::signal() { break; case 1808: _sceneMode = 12; - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_WALK); _stripManager.start(553, this); break; case 1812: @@ -11648,18 +11660,11 @@ void Scene1800::saveCharacter(int characterIndex) { } /*-------------------------------------------------------------------------- - * Scene 1850 - + * Scene 1850 - Rim Lift Interior * *--------------------------------------------------------------------------*/ -Scene1850::Scene1850() { - warning("STUBBED: Scene1850()"); -} -void Scene1850::synchronize(Serializer &s) { - warning("STUBBED: Scene1850::synchronize()"); -} - -bool Scene1850::Hotspot2::startAction(CursorType action, Event &event) { +bool Scene1850::Button::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneHotspot::startAction(action, event); @@ -11677,9 +11682,9 @@ bool Scene1850::Hotspot2::startAction(CursorType action, Event &event) { scene->_sceneMode = 1860; if (R2_GLOBALS.getFlag(32)) - scene->setAction(&scene->_sequenceManager1, scene, 1860, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1860, &R2_GLOBALS._player, &scene->_robot, NULL); else - scene->setAction(&scene->_sequenceManager1, scene, 1859, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1859, &R2_GLOBALS._player, &scene->_robot, NULL); R2_GLOBALS.clearFlag(30); } else { @@ -11694,21 +11699,21 @@ bool Scene1850::Hotspot2::startAction(CursorType action, Event &event) { return true; } -bool Scene1850::Actor5::startAction(CursorType action, Event &event) { +bool Scene1850::Robot::startAction(CursorType action, Event &event) { Scene1850 *scene = (Scene1850 *)R2_GLOBALS._sceneManager._scene; switch (action) { case CURSOR_USE: - if ((R2_GLOBALS._player._characterIndex != R2_SEEKER) || (R2_GLOBALS.getFlag(33)) || (R2_GLOBALS.getFlag(30))) + if ((R2_GLOBALS._player._characterIndex != R2_SEEKER) || R2_GLOBALS.getFlag(33) || R2_GLOBALS.getFlag(30)) return SceneActor::startAction(action, event); R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1857; if (R2_GLOBALS.getFlag(32)) - scene->setAction(&scene->_sequenceManager1, scene, 1858, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1858, &R2_GLOBALS._player, &scene->_robot, NULL); else - scene->setAction(&scene->_sequenceManager1, scene, 1857, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1857, &R2_GLOBALS._player, &scene->_robot, NULL); R2_GLOBALS.setFlag(30); return true; @@ -11727,7 +11732,7 @@ bool Scene1850::Actor5::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 30; - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_WALK); scene->_stripManager.start(558, scene); return true; @@ -11747,8 +11752,8 @@ bool Scene1850::Actor5::startAction(CursorType action, Event &event) { return true; } else if (R2_GLOBALS.getFlag(70)) { R2_GLOBALS._player.disableControl(); - scene->_sceneMode = 30; - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + scene->_sceneMode = 20; + R2_GLOBALS._events.setCursor(CURSOR_WALK); scene->_stripManager.start(557, scene); R2_GLOBALS.setFlag(69); @@ -11764,7 +11769,7 @@ bool Scene1850::Actor5::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1878; - scene->setAction(&scene->_sequenceManager1, scene, 1878, &R2_GLOBALS._player, &scene->_actor5, &scene->_actor2, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1878, &R2_GLOBALS._player, &scene->_robot, &scene->_actor2, NULL); } return true; @@ -11804,23 +11809,23 @@ bool Scene1850::Actor6::startAction(CursorType action, Event &event) { scene->_sceneMode = 1860; if (R2_GLOBALS.getFlag(32)) { - scene->setAction(&scene->_sequenceManager1, scene, 1860, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1860, &R2_GLOBALS._player, &scene->_robot, NULL); } else { - scene->setAction(&scene->_sequenceManager1, scene, 1859, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1859, &R2_GLOBALS._player, &scene->_robot, NULL); } } else { scene->_sceneMode = 11; if (_position.x >= 160) { - scene->setAction(&scene->_sequenceManager1, scene, 1866, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1866, &R2_GLOBALS._player, &scene->_rightDoor, NULL); } else { - scene->setAction(&scene->_sequenceManager1, scene, 1865, &R2_GLOBALS._player, &scene->_actor6, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1865, &R2_GLOBALS._player, &scene->_leftDoor, NULL); } } return true; } -bool Scene1850::Actor8::startAction(CursorType action, Event &event) { +bool Scene1850::DisplayScreen::startAction(CursorType action, Event &event) { if ((action != CURSOR_USE) || (_position.y != 120)) return SceneHotspot::startAction(action, event); @@ -11838,6 +11843,28 @@ bool Scene1850::Actor8::startAction(CursorType action, Event &event) { return true; } +/*------------------------------------------------------------------------*/ + +Scene1850::Scene1850() { + _field412 = 0; + _field414 = 0; + _field416 = 0; + _field418 = 0; + _field41E = 0; +} + +void Scene1850::synchronize(Serializer &s) { + SceneExt::synchronize(s); + + s.syncAsSint16LE(_field412); + s.syncAsSint16LE(_field414); + s.syncAsSint16LE(_field416); + s.syncAsSint16LE(_field418); + s.syncAsSint16LE(_field41E); + s.syncAsSint16LE(_field41A.x); + s.syncAsSint16LE(_field41A.y); +} + void Scene1850::postInit(SceneObjectList *OwnerList) { loadScene(1850); @@ -11866,62 +11893,62 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { _field41E = 0; _field41A = Common::Point(0, 0); - R2_GLOBALS._player._characterScene[1] = 1850; - R2_GLOBALS._player._characterScene[2] = 1850; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1850; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1850; - _item2.setDetails(Rect(101, 56, 111, 63), 1850, 19, -1, -1, 1, NULL); + _button.setDetails(Rect(101, 56, 111, 63), 1850, 19, -1, -1, 1, NULL); - _actor6.postInit(); - _actor6.setup(1850, 3, 1); - _actor6.setPosition(Common::Point(66, 102)); - _actor6.setDetails(1850, 22, -1, -1, 1, (SceneItem *) NULL); + _leftDoor.postInit(); + _leftDoor.setup(1850, 3, 1); + _leftDoor.setPosition(Common::Point(66, 102)); + _leftDoor.setDetails(1850, 22, -1, -1, 1, (SceneItem *) NULL); - _actor7.postInit(); - _actor7.setup(1850, 2, 1); - _actor7.setPosition(Common::Point(253, 102)); - _actor7.setDetails(1850, 22, -1, -1, 1, (SceneItem *) NULL); + _rightDoor.postInit(); + _rightDoor.setup(1850, 2, 1); + _rightDoor.setPosition(Common::Point(253, 102)); + _rightDoor.setDetails(1850, 22, -1, -1, 1, (SceneItem *) NULL); R2_GLOBALS._walkRegions.enableRegion(1); - _actor5.postInit(); + _robot.postInit(); if (R2_GLOBALS.getFlag(34)) { R2_GLOBALS._walkRegions.enableRegion(2); - _actor5.setup(1851, 4, 3); + _robot.setup(1851, 4, 3); } else if (R2_GLOBALS.getFlag(30)) { - _actor5.setup(1851, 2, 2); + _robot.setup(1851, 2, 2); } else { R2_GLOBALS._walkRegions.enableRegion(5); if (R2_GLOBALS.getFlag(33)) { R2_GLOBALS._walkRegions.enableRegion(2); - _actor5.setup(1851, 1, 3); + _robot.setup(1851, 1, 3); } else { - _actor5.setup(1851, 2, 1); + _robot.setup(1851, 2, 1); } } - _actor5.setPosition(Common::Point(219, 130)); - _actor5.fixPriority(114); - _actor5.setDetails(1850, -1, -1, -1, 1, (SceneItem *) NULL); + _robot.setPosition(Common::Point(219, 130)); + _robot.fixPriority(114); + _robot.setDetails(1850, -1, -1, -1, 1, (SceneItem *) NULL); R2_GLOBALS._player.postInit(); - _actor1.postInit(); + _companion.postInit(); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); } else { - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); } if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 1850) { R2_GLOBALS._player._effect = 6; - _actor1._effect = 6; + _companion._effect = 6; if (R2_GLOBALS.getFlag(31)) { R2_GLOBALS._player._shade = 0; - _actor1._shade = 0; + _companion._shade = 0; } else { R2_GLOBALS._player._shade = 6; - _actor1._shade = 6; + _companion._shade = 6; } if (R2_INVENTORY.getObjectScene(R2_AIRBAG) == 1850) { @@ -11935,7 +11962,7 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { _actor2.setPosition(Common::Point(179, 113)); - if ((_actor5._strip == 1) && (_actor5._frame == 3)){ + if ((_robot._strip == 1) && (_robot._frame == 3)){ _actor2.hide(); } @@ -11945,7 +11972,7 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS.getFlag(32)) { R2_GLOBALS._player.setVisage(1511); - _actor1.setVisage(1508); + _companion.setVisage(1508); _actor3.postInit(); _actor3.setup(1853, 3, 1); @@ -11984,12 +12011,12 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { } } else { R2_GLOBALS._player.setVisage(1500); - _actor1.setVisage(1505); + _companion.setVisage(1505); } } else { // Not Quinn if (R2_GLOBALS.getFlag(32)) { R2_GLOBALS._player.setVisage(1508); - _actor1.setVisage(1511); + _companion.setVisage(1511); _actor3.postInit(); _actor3.setup(1853, 3, 1); @@ -12028,7 +12055,7 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { } } else { R2_GLOBALS._player.setVisage(1505); - _actor1.setVisage(1500); + _companion.setVisage(1500); } } @@ -12036,25 +12063,25 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setStrip(3); R2_GLOBALS._player.setPosition(Common::Point(80, 114)); - _actor1.animate(ANIM_MODE_1, NULL); - _actor1.setObjectWrapper(new SceneObjectWrapper()); - _actor1.setStrip(3); - _actor1.setPosition(Common::Point(180, 96)); + _companion.animate(ANIM_MODE_1, NULL); + _companion.setObjectWrapper(new SceneObjectWrapper()); + _companion.setStrip(3); + _companion.setPosition(Common::Point(180, 96)); if (R2_GLOBALS.getFlag(30)) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - _actor1.animate(ANIM_MODE_NONE, NULL); - _actor1.setObjectWrapper(NULL); + _companion.animate(ANIM_MODE_NONE, NULL); + _companion.setObjectWrapper(NULL); if (R2_GLOBALS.getFlag(32)) { - _actor1.setup(1854, 1, 3); + _companion.setup(1854, 1, 3); } else { - _actor1.setup(1854, 2, 3); + _companion.setup(1854, 2, 3); } - _actor1.setPosition(Common::Point(164, 106)); + _companion.setPosition(Common::Point(164, 106)); } else { - _actor1.animate(ANIM_MODE_NONE, NULL); - _actor1.setObjectWrapper(NULL); + _companion.animate(ANIM_MODE_NONE, NULL); + _companion.setObjectWrapper(NULL); if (R2_GLOBALS.getFlag(32)) { R2_GLOBALS._player.setup(1854, 1, 3); } else { @@ -12068,57 +12095,57 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.enableControl(); } else { // R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] != 1850 R2_GLOBALS._player._effect = 1; - _actor1._effect = 1; + _companion._effect = 1; R2_GLOBALS._player.disableControl(); _sceneMode = 10; if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS.getFlag(29)) { - setAction(&_sequenceManager1, this, 1863, &R2_GLOBALS._player, &_actor1, &_actor7, NULL); + setAction(&_sequenceManager1, this, 1863, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } else { - setAction(&_sequenceManager1, this, 1861, &R2_GLOBALS._player, &_actor1, &_actor6, NULL); + setAction(&_sequenceManager1, this, 1861, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } } else { if (R2_GLOBALS.getFlag(29)) { - setAction(&_sequenceManager1, this, 1864, &R2_GLOBALS._player, &_actor1, &_actor7, NULL); + setAction(&_sequenceManager1, this, 1864, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } else { - setAction(&_sequenceManager1, this, 1862, &R2_GLOBALS._player, &_actor1, &_actor6, NULL); + setAction(&_sequenceManager1, this, 1862, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } } } if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._player._moveDiff = Common::Point(3, 2); - _actor1._moveDiff = Common::Point(5, 3); + _companion._moveDiff = Common::Point(5, 3); } else { R2_GLOBALS._player._moveDiff = Common::Point(5, 3); - _actor1._moveDiff = Common::Point(3, 2); + _companion._moveDiff = Common::Point(3, 2); } - _actor8.postInit(); - _actor8.setup(1850, 1, 1); + _displayScreen.postInit(); + _displayScreen.setup(1850, 1, 1); if (R2_GLOBALS.getFlag(62)) { - _actor8.setPosition(Common::Point(159, 120)); + _displayScreen.setPosition(Common::Point(159, 120)); } else { - _actor8.setPosition(Common::Point(159, 184)); + _displayScreen.setPosition(Common::Point(159, 184)); } - _actor8.fixPriority(113); + _displayScreen.fixPriority(113); if (R2_GLOBALS.getFlag(34)) { - _actor8.setDetails(1850, 25, -1, -1, 4, &_actor5); + _displayScreen.setDetails(1850, 25, -1, -1, 4, &_robot); } else { - _actor8.setDetails(1850, 25, -1, -1, 2, (SceneItem *) NULL); + _displayScreen.setDetails(1850, 25, -1, -1, 2, (SceneItem *) NULL); } if (!R2_GLOBALS.getFlag(62)) { - _actor8.hide(); + _displayScreen.hide(); } - _item1.setDetails(Rect(0, 0, 320, 200), 1850, 16, -1, -1, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 1850, 16, -1, -1, 1, NULL); - R2_GLOBALS._player._oldCharacterScene[1] = 1850; - R2_GLOBALS._player._oldCharacterScene[2] = 1850; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1850; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1850; } void Scene1850::remove() { @@ -12137,8 +12164,8 @@ void Scene1850::signal() { R2_GLOBALS._player._effect = 6; R2_GLOBALS._player._shade = 6; - _actor1._effect = 6; - _actor1._shade = 6; + _companion._effect = 6; + _companion._shade = 6; R2_GLOBALS._walkRegions.enableRegion(5); @@ -12160,7 +12187,7 @@ void Scene1850::signal() { break; case 16: _sceneMode = 1870; - setAction(&_sequenceManager1, this, 1870, &R2_GLOBALS._player, &_actor1, &_actor3, &_actor4, NULL); + setAction(&_sequenceManager1, this, 1870, &R2_GLOBALS._player, &_companion, &_actor3, &_actor4, NULL); break; case 20: R2_GLOBALS._player.enableControl(CURSOR_TALK); @@ -12168,7 +12195,7 @@ void Scene1850::signal() { case 21: R2_GLOBALS._player.disableControl(); _sceneMode = 1877; - setAction(&_sequenceManager1, this, 1877, &R2_GLOBALS._player, &_actor1, &_actor5, NULL); + setAction(&_sequenceManager1, this, 1877, &R2_GLOBALS._player, &_companion, &_robot, NULL); break; case 30: R2_GLOBALS._player.disableControl(); @@ -12190,14 +12217,14 @@ void Scene1850::signal() { _field418 = 1; if (R2_GLOBALS.getFlag(30)) { - _actor8.setAction(&_sequenceManager2, NULL, 1867, &_actor8, NULL); + _displayScreen.setAction(&_sequenceManager2, NULL, 1867, &_displayScreen, NULL); } else if (R2_GLOBALS.getFlag(34)) { if (R2_GLOBALS.getFlag(62)) { R2_GLOBALS.clearFlag(62); - _actor8.setAction(&_sequenceManager2, this, 1851, &_actor8, NULL); + _displayScreen.setAction(&_sequenceManager2, this, 1851, &_displayScreen, NULL); } else { R2_GLOBALS.setFlag(62); - _actor8.setAction(&_sequenceManager2, this, 1850, &_actor8, NULL); + _displayScreen.setAction(&_sequenceManager2, this, 1850, &_displayScreen, NULL); } } else if (R2_GLOBALS.getFlag(33)) { R2_GLOBALS.setFlag(62); @@ -12205,13 +12232,13 @@ void Scene1850::signal() { R2_GLOBALS._walkRegions.enableRegion(2); _actor2.postInit(); - _actor2.setDetails(1850, 6, -1, -1, 5, &_actor5); + _actor2.setDetails(1850, 6, -1, -1, 5, &_robot); _sceneMode = 1879; - _actor8.setAction(&_sequenceManager2, this, 1879, &_actor5, &_actor8, &_actor2, NULL); + _displayScreen.setAction(&_sequenceManager2, this, 1879, &_robot, &_displayScreen, &_actor2, NULL); } else { - _actor8.setAction(&_sequenceManager2, NULL, 1867, &_actor8, NULL); + _displayScreen.setAction(&_sequenceManager2, NULL, 1867, &_displayScreen, NULL); } if (R2_GLOBALS.getFlag(34)) @@ -12260,7 +12287,7 @@ void Scene1850::signal() { case 1858: R2_GLOBALS._player.disableControl(); _sceneMode = 1859; - setAction(&_sequenceManager1, this, 1859, &R2_GLOBALS._player, &_actor5, NULL); + setAction(&_sequenceManager1, this, 1859, &R2_GLOBALS._player, &_robot, NULL); R2_GLOBALS.clearFlag(30); break; case 1859: @@ -12290,12 +12317,11 @@ void Scene1850::signal() { break; case 2: _sceneMode = 11; - setAction(&_sequenceManager1, this, 1865, &R2_GLOBALS._player, &_actor6, NULL); + setAction(&_sequenceManager1, this, 1865, &R2_GLOBALS._player, &_leftDoor, NULL); break; case 3: - warning("_field41E == 3"); _sceneMode = 11; - setAction(&_sequenceManager1, this, 1866, &R2_GLOBALS._player, &_actor7, NULL); + setAction(&_sequenceManager1, this, 1866, &R2_GLOBALS._player, &_rightDoor, NULL); break; default: break; @@ -12345,7 +12371,7 @@ void Scene1850::signal() { R2_GLOBALS.clearFlag(30); _sceneMode = 15; setAction(&_sequenceManager1, this, 1869, &R2_GLOBALS._player, &_actor3, NULL); - setAction(&_sequenceManager2, this, 1868, &_actor1, &_actor4, NULL); + _companion.setAction(&_sequenceManager2, this, 1868, &_companion, &_actor4, NULL); break; case 1878: R2_INVENTORY.setObjectScene(R2_REBREATHER_TANK, 1850); @@ -12376,9 +12402,9 @@ void Scene1850::process(Event &event) { R2_GLOBALS._player.disableControl(); _sceneMode = 1860; if (R2_GLOBALS.getFlag(32)) { - setAction(&_sequenceManager1, this, 1860, &R2_GLOBALS._player, &_actor5, NULL); + setAction(&_sequenceManager1, this, 1860, &R2_GLOBALS._player, &_robot, NULL); } else { - setAction(&_sequenceManager1, this, 1859, &R2_GLOBALS._player, &_actor5, NULL); + setAction(&_sequenceManager1, this, 1859, &R2_GLOBALS._player, &_robot, NULL); } R2_GLOBALS.clearFlag(32); event.handled = true; @@ -12400,8 +12426,8 @@ void Scene1850::dispatch() { } R2_GLOBALS._player._flags |= OBJFLAG_PANES; - _actor1._shade = R2_GLOBALS._player._shade; - _actor1._flags |= OBJFLAG_PANES; + _companion._shade = R2_GLOBALS._player._shade; + _companion._flags |= OBJFLAG_PANES; _actor3._shade = R2_GLOBALS._player._shade; _actor3._flags |= OBJFLAG_PANES; @@ -12411,46 +12437,47 @@ void Scene1850::dispatch() { } if (R2_GLOBALS.getFlag(32)) { - _actor3.setPosition(Common::Point(_actor8._position.x - 37, _actor8._position.y - 71)); - _actor4.setPosition(Common::Point(_actor8._position.x - 20, _actor8._position.y - 73)); + _actor3.setPosition(Common::Point(_displayScreen._position.x - 37, _displayScreen._position.y - 71)); + _actor4.setPosition(Common::Point(_displayScreen._position.x - 20, _displayScreen._position.y - 73)); } if (R2_INVENTORY.getObjectScene(R2_AIRBAG) == 1850) { - _actor2.setPosition(Common::Point(_actor8._position.x + 20, _actor8._position.y - 71)); + _actor2.setPosition(Common::Point(_displayScreen._position.x + 20, _displayScreen._position.y - 71)); } Scene::dispatch(); } /*-------------------------------------------------------------------------- - * Scene 1875 - + * Scene 1875 - Rim Lift Computer * *--------------------------------------------------------------------------*/ -Scene1875::Actor1875::Actor1875() { - _fieldA4 = 0; - _fieldA6 = 0; + +Scene1875::Button::Button() { + _buttonId = 0; + _buttonDown = false; } -void Scene1875::Actor1875::synchronize(Serializer &s) { +void Scene1875::Button::synchronize(Serializer &s) { SceneActor::synchronize(s); - s.syncAsSint16LE(_fieldA4); - s.syncAsSint16LE(_fieldA6); + s.syncAsSint16LE(_buttonId); + s.syncAsSint16LE(_buttonDown); } -void Scene1875::Actor1875::subB84AB() { +void Scene1875::Button::doButtonPress() { Scene1875 *scene = (Scene1875 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._sound1.play(227); int newFrameNumber; - switch (_fieldA4) { + switch (_buttonId) { case 3: - if ((scene->_actor1._frame == 1) && (scene->_actor4._strip == 2)) { + if ((scene->_actor1._frame == 1) && (scene->_button1._strip == 2)) { R2_GLOBALS._player.disableControl(); R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); scene->_sceneMode = 10; - scene->_stripManager.start(576, this); + scene->_stripManager.start(576, scene); } else { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1890; @@ -12475,32 +12502,32 @@ void Scene1875::Actor1875::subB84AB() { } } -void Scene1875::Actor1875::subB8271(int indx) { +void Scene1875::Button::initButton(int buttonId) { postInit(); - _fieldA4 = indx; - _fieldA6 = 0; + _buttonId = buttonId; + _buttonDown = false; setVisage(1855); - if (_fieldA4 == 1) + if (_buttonId == 1) setStrip(2); else setStrip(1); - setFrame(_fieldA4); - switch (_fieldA4 - 1) { - case 0: + setFrame(_buttonId); + switch (_buttonId) { + case 1: setPosition(Common::Point(20, 144)); break; - case 1: + case 2: setPosition(Common::Point(82, 144)); break; - case 2: + case 3: setPosition(Common::Point(136, 144)); break; - case 3: + case 4: setPosition(Common::Point(237, 144)); break; - case 4: + case 5: setPosition(Common::Point(299, 144)); break; default: @@ -12510,36 +12537,37 @@ void Scene1875::Actor1875::subB8271(int indx) { setDetails(1875, 6, 1, -1, 2, (SceneItem *) NULL); } -void Scene1875::Actor1875::process(Event &event) { - if ((R2_GLOBALS._player._uiEnabled) || (event.handled)) +void Scene1875::Button::process(Event &event) { + if (!R2_GLOBALS._player._uiEnabled || event.handled) return; Scene1875 *scene = (Scene1875 *)R2_GLOBALS._sceneManager._scene; - if ((event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._events.getCursor() == R2_STEPPING_DISKS) && (_bounds.contains(event.mousePos)) && (_fieldA6 == 0)) { + if ((event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._events.getCursor() == CURSOR_USE) + && (_bounds.contains(event.mousePos)) && !_buttonDown) { setStrip(2); - switch (_fieldA4) { + switch (_buttonId) { case 1: R2_GLOBALS._sound2.play(227); - scene->_actor5.setStrip(1); + scene->_button2.setStrip(1); break; case 2: R2_GLOBALS._sound2.play(227); - scene->_actor4.setStrip(1); + scene->_button1.setStrip(1); break; default: break; } - _fieldA6 = 1; + _buttonDown = true; event.handled = true; } - if ((event.eventType == EVENT_BUTTON_UP) && (_fieldA6 != 0)) { - if ((_fieldA4 == 3) || (_fieldA4 == 4) || (_fieldA4 == 5)) { + if ((event.eventType == EVENT_BUTTON_UP) && _buttonDown) { + if ((_buttonId == 3) || (_buttonId == 4) || (_buttonId == 5)) { setStrip(1); - subB84AB(); + doButtonPress(); } - _fieldA6 = 0; + _buttonDown = false; event.handled = true; } } @@ -12548,32 +12576,36 @@ void Scene1875::postInit(SceneObjectList *OwnerList) { loadScene(1875); SceneExt::postInit(); - R2_GLOBALS._player._characterScene[1] = 1875; - R2_GLOBALS._player._characterScene[2] = 1875; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1875; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1875; _stripManager.addSpeaker(&_quinnSpeaker); _stripManager.addSpeaker(&_seekerSpeaker); - _actor4.subB8271(1); - _actor5.subB8271(2); - _actor6.subB8271(3); - _actor7.subB8271(4); - _actor8.subB8271(5); + _button1.initButton(1); + _button2.initButton(2); + _button3.initButton(3); + _button4.initButton(4); + _button5.initButton(5); _actor1.postInit(); _actor1.setup(1855, 4, 1); _actor1.setPosition(Common::Point(160, 116)); R2_GLOBALS._player.postInit(); + R2_GLOBALS._player.hide(); + if (R2_GLOBALS._sceneManager._previousScene == 1625) { R2_GLOBALS._sound1.play(122); R2_GLOBALS._player.disableControl(); _sceneMode = 11; _actor2.postInit(); setAction(&_sequenceManager, this, 1892, &_actor2, NULL); - } else if (R2_GLOBALS._sceneManager._previousScene == 3150) { - R2_GLOBALS._sound1.play(116); } else { + if (R2_GLOBALS._sceneManager._previousScene == 3150) { + R2_GLOBALS._sound1.play(116); + } + R2_GLOBALS._player.enableControl(); R2_GLOBALS._player._canWalk = false; } @@ -12581,10 +12613,10 @@ void Scene1875::postInit(SceneObjectList *OwnerList) { _item2.setDetails(Rect(43, 14, 275, 122), 1875, 9, 1, -1, 1, NULL); _item1.setDetails(Rect(0, 0, 320, 200), 1875, 3, -1, -1, 1, NULL); - R2_GLOBALS._player._characterScene[1] = 1875; - R2_GLOBALS._player._characterScene[2] = 1875; - R2_GLOBALS._player._oldCharacterScene[1] = 1875; - R2_GLOBALS._player._oldCharacterScene[2] = 1875; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1875; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1875; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1875; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1875; } void Scene1875::signal() { @@ -12623,18 +12655,19 @@ void Scene1875::signal() { void Scene1875::process(Event &event) { Scene::process(event); - _actor4.process(event); - _actor5.process(event); - _actor6.process(event); - _actor7.process(event); - _actor8.process(event); + _button1.process(event); + _button2.process(event); + _button3.process(event); + _button4.process(event); + _button5.process(event); } /*-------------------------------------------------------------------------- - * Scene 1900 - + * Scene 1900 - Spill Mountains Elevator Exit * *--------------------------------------------------------------------------*/ -bool Scene1900::Actor2::startAction(CursorType action, Event &event) { + +bool Scene1900::LiftDoor::startAction(CursorType action, Event &event) { Scene1900 *scene = (Scene1900 *)R2_GLOBALS._sceneManager._scene; if (action != CURSOR_USE) @@ -12651,17 +12684,17 @@ bool Scene1900::Actor2::startAction(CursorType action, Event &event) { if (_position.x >= 160) { scene->_sceneMode = 1905; - scene->setAction(&scene->_sequenceManager1, scene, 1905, &R2_GLOBALS._player, &scene->_actor3, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1905, &R2_GLOBALS._player, &scene->_rightDoor, NULL); } else { R2_GLOBALS.setFlag(29); scene->_sceneMode = 1904; - scene->setAction(&scene->_sequenceManager1, scene, 1904, &R2_GLOBALS._player, &scene->_actor2, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1904, &R2_GLOBALS._player, &scene->_leftDoor, NULL); } return true; } -void Scene1900::Exit1::changeScene() { +void Scene1900::WestExit::changeScene() { Scene1900 *scene = (Scene1900 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(CURSOR_ARROW); @@ -12672,7 +12705,7 @@ void Scene1900::Exit1::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene1900::Exit2::changeScene() { +void Scene1900::EastExit::changeScene() { Scene1900 *scene = (Scene1900 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(CURSOR_ARROW); @@ -12692,7 +12725,7 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene == -1) { R2_GLOBALS._sceneManager._previousScene = 1925; R2_GLOBALS._player._characterIndex = R2_SEEKER; - R2_GLOBALS._player._oldCharacterScene[2] = 1925; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1925; } if (R2_GLOBALS._sceneManager._previousScene != 1875) @@ -12702,11 +12735,11 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { _stripManager.setFontNumber(3); _stripManager.addSpeaker(&_seekerSpeaker); - _exit1.setDetails(Rect(0, 105, 14, 145), R2_COM_SCANNER, 2000); - _exit1.setDest(Common::Point(14, 135)); + _westExit.setDetails(Rect(0, 105, 14, 145), EXITCURSOR_W, 2000); + _westExit.setDest(Common::Point(14, 135)); - _exit2.setDetails(Rect(305, 105, 320, 145), R2_SPENT_POWER_CAPSULE, 2000); - _exit2.setDest(Common::Point(315, 135)); + _eastExit.setDetails(Rect(305, 105, 320, 145), EXITCURSOR_E, 2000); + _eastExit.setDest(Common::Point(315, 135)); R2_GLOBALS._player.postInit(); if (R2_GLOBALS._player._characterIndex == R2_QUINN) @@ -12723,24 +12756,24 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene != 1925) R2_GLOBALS.clearFlag(29); - _actor2.postInit(); - _actor2.setup(1901, 1, 1); - _actor2.setPosition(Common::Point(95, 109)); - _actor2.fixPriority(100); + _leftDoor.postInit(); + _leftDoor.setup(1901, 1, 1); + _leftDoor.setPosition(Common::Point(95, 109)); + _leftDoor.fixPriority(100); if (R2_GLOBALS._player._characterIndex == R2_QUINN) - _actor2.setDetails(1900, 0, 1, 2, 1, (SceneItem *) NULL); + _leftDoor.setDetails(1900, 0, 1, 2, 1, (SceneItem *) NULL); else - _actor2.setDetails(1900, 0, 1, -1, 1, (SceneItem *) NULL); + _leftDoor.setDetails(1900, 0, 1, -1, 1, (SceneItem *) NULL); - _actor3.postInit(); - _actor3.setup(1901, 2, 1); - _actor3.setPosition(Common::Point(225, 109)); - _actor3.fixPriority(100); + _rightDoor.postInit(); + _rightDoor.setup(1901, 2, 1); + _rightDoor.setPosition(Common::Point(225, 109)); + _rightDoor.fixPriority(100); if (R2_GLOBALS._player._characterIndex == R2_QUINN) - _actor3.setDetails(1900, 0, 1, 2, 1, (SceneItem *) NULL); + _rightDoor.setDetails(1900, 0, 1, 2, 1, (SceneItem *) NULL); else - _actor3.setDetails(1900, 0, 1, -1, 1, (SceneItem *) NULL); + _rightDoor.setDetails(1900, 0, 1, -1, 1, (SceneItem *) NULL); if (R2_GLOBALS._sceneManager._previousScene != 1875) { _object1.postInit(); @@ -12758,26 +12791,26 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._characterIndex = R2_QUINN; _actor1.postInit(); _sceneMode = 20; - R2_GLOBALS._player.setAction(&_sequenceManager1, NULL, 1901, &R2_GLOBALS._player, &_actor2, NULL); - _actor1.setAction(&_sequenceManager2, this, 1900, &_actor1, &_actor3, NULL); + R2_GLOBALS._player.setAction(&_sequenceManager1, NULL, 1901, &R2_GLOBALS._player, &_leftDoor, NULL); + _actor1.setAction(&_sequenceManager2, this, 1900, &_actor1, &_rightDoor, NULL); } else if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 1925) { if (R2_GLOBALS.getFlag(29)) { R2_GLOBALS.clearFlag(29); - _actor2.hide(); + _leftDoor.hide(); R2_GLOBALS._player.setStrip(6); R2_GLOBALS._player.setPosition(Common::Point(90, 106)); _sceneMode = 1906; - setAction(&_sequenceManager1, this, 1906, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager1, this, 1906, &R2_GLOBALS._player, &_leftDoor, NULL); } else { - _actor3.hide(); + _rightDoor.hide(); R2_GLOBALS._player.setStrip(5); R2_GLOBALS._player.setPosition(Common::Point(230, 106)); _sceneMode = 1907; - setAction(&_sequenceManager1, this, 1907, &R2_GLOBALS._player, &_actor3, NULL); + setAction(&_sequenceManager1, this, 1907, &R2_GLOBALS._player, &_rightDoor, NULL); } - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); _actor1.setPosition(Common::Point(30, 110)); R2_GLOBALS._walkRegions.enableRegion(1); @@ -12785,21 +12818,23 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { _actor1.setDetails(9001, 0, -1, -1, 1, (SceneItem *) NULL); } R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 1900; - } else if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { - _actor1.postInit(); - _actor1.setPosition(Common::Point(30, 110)); - R2_GLOBALS._walkRegions.enableRegion(1); - if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - _actor1.setup(20, 3, 1); - _actor1.setDetails(9002, 1, -1, -1, 1, (SceneItem *) NULL); - } else { - _actor1.setup(2008, 3, 1); - _actor1.setDetails(9001, 0, -1, -1, 1, (SceneItem *) NULL); + } else { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { + _actor1.postInit(); + _actor1.setPosition(Common::Point(30, 110)); + R2_GLOBALS._walkRegions.enableRegion(1); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + _actor1.setup(20, 3, 1); + _actor1.setDetails(9002, 1, -1, -1, 1, (SceneItem *) NULL); + } else { + _actor1.setup(2008, 3, 1); + _actor1.setDetails(9001, 0, -1, -1, 1, (SceneItem *) NULL); + } } if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2000) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - if (R2_GLOBALS._v56605[1] == 5) { + if (R2_GLOBALS._spillLocation[R2_QUINN] == 5) { _sceneMode = 1902; setAction(&_sequenceManager1, this, 1902, &R2_GLOBALS._player, NULL); } else { @@ -12807,7 +12842,7 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { setAction(&_sequenceManager1, this, 1903, &R2_GLOBALS._player, NULL); } } else { - if (R2_GLOBALS._v56605[2] == 5) { + if (R2_GLOBALS._spillLocation[R2_SEEKER] == 5) { _sceneMode = 1908; setAction(&_sequenceManager1, this, 1908, &R2_GLOBALS._player, NULL); } else { @@ -12822,8 +12857,8 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 1900; } - _item2.setDetails(Rect(77, 2, 240, 103), 1900, 6, -1, -1, 1, NULL); - _item1.setDetails(Rect(0, 0, 320, 200), 1900, 3, -1, -1, 1, NULL); + _elevator.setDetails(Rect(77, 2, 240, 103), 1900, 6, -1, -1, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 1900, 3, -1, -1, 1, NULL); } void Scene1900::remove() { @@ -12834,16 +12869,16 @@ void Scene1900::remove() { void Scene1900::signal() { switch (_sceneMode) { case 10: - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 5; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 5; R2_GLOBALS._sceneManager.changeScene(2000); break; case 11: - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 6; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 6; R2_GLOBALS._sceneManager.changeScene(2000); break; case 20: ++_sceneMode; - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_WALK); _stripManager.start(1300, this); break; case 21: @@ -12866,10 +12901,10 @@ void Scene1900::signal() { R2_GLOBALS._sceneManager.changeScene(1925); break; case 1910: - R2_INVENTORY.setObjectScene(R2_GUIDANCE_MODULE, 2535); + R2_INVENTORY.setObjectScene(R2_REBREATHER_TANK, 2535); R2_GLOBALS._player.disableControl(CURSOR_ARROW); - R2_GLOBALS._player._oldCharacterScene[1] = 1900; - R2_GLOBALS._player._oldCharacterScene[2] = 1900; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1900; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1900; R2_GLOBALS._sceneManager.changeScene(2450); break; case 1906: @@ -13096,7 +13131,7 @@ void Scene1925::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._sound1.play(220); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.disableControl(); - R2_GLOBALS._player._characterScene[2] = 1925; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1925; R2_GLOBALS._player._characterIndex = R2_SEEKER; switch (R2_GLOBALS._scene1925CurrLevel) { case -2: @@ -13155,7 +13190,7 @@ void Scene1925::postInit(SceneObjectList *OwnerList) { void Scene1925::remove() { R2_GLOBALS._sound1.fadeOut2(NULL); - R2_GLOBALS._player._oldCharacterScene[2] = 1925; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1925; SceneExt::remove(); } @@ -13363,7 +13398,7 @@ void Scene1945::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.postInit(); R2_GLOBALS._player.enableControl(CURSOR_USE); R2_GLOBALS._player._canWalk = false; - R2_GLOBALS._player._characterScene[2] = 1945; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1945; R2_GLOBALS._player._characterIndex = R2_SEEKER; _exitUp.setDetails(Rect(128, 0, 186, 10), EXITCURSOR_N, 1945); diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.h b/engines/tsage/ringworld2/ringworld2_scenes1.h index 0e929b3ef3..82895c7ab0 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.h +++ b/engines/tsage/ringworld2/ringworld2_scenes1.h @@ -687,7 +687,7 @@ public: }; class Scene1625 : public SceneExt { - class Actor7 : public SceneActor { + class Wire : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -698,12 +698,12 @@ public: SpeakerSoldier1625 _soldierSpeaker; NamedHotspot _item1; SceneActor _actor1; - SceneActor _actor2; + SceneActor _tealHead; SceneActor _actor3; - SceneActor _actor4; + SceneActor _glass; SceneActor _actor5; SceneActor _actor6; - Actor7 _actor7; + Wire _wire; SequenceManager _sequenceManager; Scene1625(); @@ -721,7 +721,7 @@ class Scene1700 : public SceneExt { virtual bool startAction(CursorType action, Event &event); }; - class Actor11 : public SceneActor { + class RimTransport : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -749,15 +749,15 @@ public: Item2 _item2; SceneActor _actor1; SceneActor _actor2; - SceneActor _actor3; - SceneActor _actor4; - SceneActor _actor5; - SceneActor _actor6; - SceneActor _actor7; - SceneActor _actor8; + SceneActor _slabWest; + SceneActor _slabEast; + SceneActor _slabShadowWest; + SceneActor _slabShadowEast; + SceneActor _westPlatform; + SceneActor _rimTransportDoor; SceneActor _ledgeHopper; SceneActor _actor10; - Actor11 _actor11; + RimTransport _rimTransport; Actor12 _actor12; NorthExit _northExit; SouthExit _southExit; @@ -841,20 +841,20 @@ public: }; class Scene1800 : public SceneExt { - class Hotspot5 : public NamedHotspot { + class Background : public NamedHotspot { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor6 : public SceneActor { + class Lever : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor7 : public SceneActor { + class Doors : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor8 : public SceneActor { + class PassengerDoor : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -864,23 +864,23 @@ class Scene1800 : public SceneExt { virtual void changeScene(); }; public: - int _field412; + int _locationMode; SpeakerQuinn _quinnSpeaker; SpeakerSeeker _seekerSpeaker; NamedHotspot _item1; NamedHotspot _item2; NamedHotspot _item3; NamedHotspot _item4; - Hotspot5 _item5; + Background _background; SceneActor _actor1; - SceneActor _actor2; + SceneActor _companion; SceneActor _actor3; - SceneActor _actor4; - SceneActor _actor5; - Actor6 _actor6; - Actor7 _actor7; - Actor8 _actor8; - Actor8 _actor9; + SceneActor _leftStaircase; + SceneActor _rightStaircase; + Lever _lever; + Doors _doors; + PassengerDoor _leftDoor; + PassengerDoor _rightDoor; Exit1 _exit1; SequenceManager _sequenceManager; @@ -893,12 +893,12 @@ public: }; class Scene1850 : public SceneExt { - class Hotspot2 : public NamedHotspot { + class Button : public NamedHotspot { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor5 : public SceneActor { + class Robot : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -906,7 +906,7 @@ class Scene1850 : public SceneExt { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor8 : public SceneActor { + class DisplayScreen : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -921,16 +921,16 @@ public: ScenePalette _palette1; SpeakerQuinn _quinnSpeaker; SpeakerSeeker _seekerSpeaker; - NamedHotspot _item1; - Hotspot2 _item2; - SceneActor _actor1; + NamedHotspot _background; + Button _button; + SceneActor _companion; SceneActor _actor2; SceneActor _actor3; SceneActor _actor4; - Actor5 _actor5; - Actor6 _actor6; - Actor6 _actor7; - Actor8 _actor8; + Robot _robot; + Actor6 _leftDoor; + Actor6 _rightDoor; + DisplayScreen _displayScreen; SequenceManager _sequenceManager1; SequenceManager _sequenceManager2; @@ -945,15 +945,16 @@ public: }; class Scene1875 : public SceneExt { - class Actor1875 : public SceneActor { + class Button : public SceneActor { public: - int _fieldA4; - int _fieldA6; + int _buttonId; + bool _buttonDown; - Actor1875(); - void subB84AB(); - void subB8271(int indx); + Button(); + void doButtonPress(); + void initButton(int buttonId); + virtual Common::String getClassName() { return "Scene1875_Button"; } void synchronize(Serializer &s); virtual void process(Event &event); }; @@ -965,11 +966,11 @@ public: SceneActor _actor1; SceneActor _actor2; SceneActor _actor3; - Actor1875 _actor4; - Actor1875 _actor5; - Actor1875 _actor6; - Actor1875 _actor7; - Actor1875 _actor8; + Button _button1; + Button _button2; + Button _button3; + Button _button4; + Button _button5; SequenceManager _sequenceManager; virtual void postInit(SceneObjectList *OwnerList = NULL); @@ -978,30 +979,29 @@ public: }; class Scene1900 : public SceneExt { - class Actor2 : public SceneActor { + class LiftDoor : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Exit1 : public SceneExit { + class WestExit : public SceneExit { public: virtual void changeScene(); }; - class Exit2 : public SceneExit { + class EastExit : public SceneExit { public: virtual void changeScene(); }; public: SpeakerSeeker1900 _seekerSpeaker; - NamedHotspot _item1; - NamedHotspot _item2; + NamedHotspot _background; + NamedHotspot _elevator; SceneActor _actor1; BackgroundSceneObject _object1; BackgroundSceneObject _object2; - Actor2 _actor2; - Actor2 _actor3; - Exit1 _exit1; - Exit2 _exit2; + LiftDoor _leftDoor, _rightDoor; + WestExit _westExit; + EastExit _eastExit; SequenceManager _sequenceManager1; SequenceManager _sequenceManager2; diff --git a/engines/tsage/ringworld2/ringworld2_scenes2.cpp b/engines/tsage/ringworld2/ringworld2_scenes2.cpp index f802f0b2e5..3eac2bffe1 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes2.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes2.cpp @@ -30,17 +30,19 @@ namespace TsAGE { namespace Ringworld2 { /*-------------------------------------------------------------------------- - * Scene 2000 - Ice Maze + * Scene 2000 - Spill Mountains * *--------------------------------------------------------------------------*/ + void Scene2000::initPlayer() { + R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._player.disableControl(); switch (_mazePlayerMode) { case 0: R2_GLOBALS._player.setStrip(5); - if (_exit1._enabled) { - if (_exit2._enabled) + if (_westExit._enabled) { + if (_eastExit._enabled) R2_GLOBALS._player.setPosition(Common::Point(140, 129)); else R2_GLOBALS._player.setPosition(Common::Point(20, 129)); @@ -129,11 +131,11 @@ void Scene2000::initPlayer() { break; } for (int i = 0; i < 11; i++) { - if (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] == R2_GLOBALS._v56605[3 + i]) + if (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] == R2_GLOBALS._spillLocation[3 + i]) _objList1[i].show(); } - if ((R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) && (R2_GLOBALS._v56605[1] == R2_GLOBALS._v56605[2])) { + if ((R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) && (R2_GLOBALS._spillLocation[R2_QUINN] == R2_GLOBALS._spillLocation[R2_SEEKER])) { _object1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _object1.setup(20, 5, 1); @@ -142,8 +144,8 @@ void Scene2000::initPlayer() { _object1.setup(2008, 5, 1); _object1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); } - if (_exit1._enabled) { - if (_exit2._enabled) + if (_westExit._enabled) { + if (_eastExit._enabled) _object1.setPosition(Common::Point(180, 128)); else _object1.setPosition(Common::Point(75, 128)); @@ -153,53 +155,53 @@ void Scene2000::initPlayer() { } void Scene2000::initExits() { - _exit1._enabled = true; - _exit2._enabled = true; - _exit3._enabled = false; - _exit4._enabled = false; - _exit5._enabled = false; - - _exit1._insideArea = false; - _exit2._insideArea = false; - _exit3._insideArea = false; - _exit4._insideArea = false; - _exit5._insideArea = false; - - _exit1._moving = false; - _exit2._moving = false; - _exit3._moving = false; - _exit4._moving = false; - _exit5._moving = false; + _westExit._enabled = true; + _eastExit._enabled = true; + _southExit._enabled = false; + _northExit._enabled = false; + _doorExit._enabled = false; + + _westExit._insideArea = false; + _eastExit._insideArea = false; + _southExit._insideArea = false; + _northExit._insideArea = false; + _doorExit._insideArea = false; + + _westExit._moving = false; + _eastExit._moving = false; + _southExit._moving = false; + _northExit._moving = false; + _doorExit._moving = false; for (int i = 0; i < 11; i++) _objList1[i].hide(); _object1.remove(); - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) { case 3: case 10: case 16: case 21: - _exit5._enabled = true; - _exit5._bounds.set(61, 68, 90, 125); - _exit5.setDest(Common::Point(92, 129)); - _exit5._cursorNum = EXITCURSOR_W; + _doorExit._enabled = true; + _doorExit._bounds.set(61, 68, 90, 125); + _doorExit.setDest(Common::Point(92, 129)); + _doorExit._cursorNum = EXITCURSOR_W; break; case 4: case 12: case 25: case 34: - _exit5._enabled = true; - _exit5._bounds.set(230, 68, 259, 125); - _exit5.setDest(Common::Point(244, 129)); - _exit5._cursorNum = EXITCURSOR_E; + _doorExit._enabled = true; + _doorExit._bounds.set(230, 68, 259, 125); + _doorExit.setDest(Common::Point(244, 129)); + _doorExit._cursorNum = EXITCURSOR_E; break; default: break; } - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] - 1) { + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] - 1) { case 0: case 6: case 13: @@ -207,7 +209,7 @@ void Scene2000::initExits() { case 22: case 27: case 30: - _exit1._enabled = false; + _westExit._enabled = false; loadScene(2225); R2_GLOBALS._walkRegions.load(2225); if (!_exitingFlag) @@ -216,10 +218,10 @@ void Scene2000::initExits() { break; case 1: case 19: - _exit3._enabled = true; - _exit3._bounds.set(71, 130, 154, 168); - _exit3.setDest(Common::Point(94, 129)); - _exit3._cursorNum = EXITCURSOR_SE; + _southExit._enabled = true; + _southExit._bounds.set(71, 130, 154, 168); + _southExit.setDest(Common::Point(94, 129)); + _southExit._cursorNum = EXITCURSOR_SE; loadScene(2300); if (!_exitingFlag) _mazePlayerMode = 0; @@ -283,8 +285,8 @@ void Scene2000::initExits() { case 21: case 26: loadScene(2200); - R2_GLOBALS._walkRegions.load(2000); - _exit2._enabled = false; + R2_GLOBALS._walkRegions.load(2200); + _eastExit._enabled = false; if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 1900) _mazePlayerMode = 2; else if (!_exitingFlag) @@ -294,10 +296,10 @@ void Scene2000::initExits() { break; case 7: case 29: - _exit4._enabled = true; - _exit4._bounds.set(138, 83, 211, 125); - _exit4.setDest(Common::Point(129, 188)); - _exit4._cursorNum = EXITCURSOR_NW; + _northExit._enabled = true; + _northExit._bounds.set(138, 83, 211, 125); + _northExit.setDest(Common::Point(188, 129)); + _northExit._cursorNum = EXITCURSOR_NW; loadScene(2250); R2_GLOBALS._walkRegions.load(2000); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2500) @@ -309,10 +311,10 @@ void Scene2000::initExits() { break; case 10: case 25: - _exit3._enabled = true; - _exit3._bounds.set(78, 130, 148, 168); - _exit3.setDest(Common::Point(100, 129)); - _exit3._cursorNum = EXITCURSOR_SE; + _southExit._enabled = true; + _southExit._bounds.set(78, 130, 148, 168); + _southExit.setDest(Common::Point(100, 129)); + _southExit._cursorNum = EXITCURSOR_SE; loadScene(2075); R2_GLOBALS._walkRegions.load(2000); if (!_exitingFlag) @@ -320,10 +322,10 @@ void Scene2000::initExits() { R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 2000; break; case 14: - _exit3._enabled = true; - _exit3._bounds.set(160, 130, 248, 168); - _exit3.setDest(Common::Point(225, 129)); - _exit3._cursorNum = EXITCURSOR_SW; + _southExit._enabled = true; + _southExit._bounds.set(160, 130, 248, 168); + _southExit.setDest(Common::Point(225, 129)); + _southExit._cursorNum = EXITCURSOR_SW; loadScene(2325); R2_GLOBALS._walkRegions.load(2000); if (!_exitingFlag) @@ -332,10 +334,10 @@ void Scene2000::initExits() { break; case 16: case 31: - _exit4._enabled = true; - _exit4._bounds.set(122, 83, 207, 125); - _exit4.setDest(Common::Point(210, 129)); - _exit4._cursorNum = EXITCURSOR_NW; + _northExit._enabled = true; + _northExit._bounds.set(122, 83, 207, 125); + _northExit.setDest(Common::Point(210, 129)); + _northExit._cursorNum = EXITCURSOR_NW; loadScene(2125); R2_GLOBALS._walkRegions.load(2000); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2400) @@ -346,10 +348,10 @@ void Scene2000::initExits() { R2_GLOBALS._sceneManager._previousScene = 2000; break; case 23: - _exit4._enabled = true; - _exit4._bounds.set(108, 83, 128, 184); - _exit4.setDest(Common::Point(135, 129)); - _exit4._cursorNum = CURSOR_INVALID; + _northExit._enabled = true; + _northExit._bounds.set(108, 83, 128, 184); + _northExit.setDest(Common::Point(135, 129)); + _northExit._cursorNum = CURSOR_INVALID; loadScene(2275); R2_GLOBALS._walkRegions.load(2000); if (!_exitingFlag) @@ -357,10 +359,10 @@ void Scene2000::initExits() { R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 2000; break; case 28: - _exit3._enabled = true; - _exit3._bounds.set(171, 130, 241, 168); - _exit3.setDest(Common::Point(218, 129)); - _exit3._cursorNum = EXITCURSOR_SW; + _southExit._enabled = true; + _southExit._bounds.set(171, 130, 241, 168); + _southExit.setDest(Common::Point(218, 129)); + _southExit._cursorNum = EXITCURSOR_SW; loadScene(2050); R2_GLOBALS._walkRegions.load(2000); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2350) @@ -396,34 +398,34 @@ void Scene2000::Action1::signal() { } case 1: scene->_objList1[_state].setPosition(Common::Point(340, 127)); - --R2_GLOBALS._v56605[4 + _state]; + --R2_GLOBALS._spillLocation[4 + _state]; _actionIndex = 0; switch (_state - 1) { case 0: - if (R2_GLOBALS._v56605[4] == 1) + if (R2_GLOBALS._spillLocation[4] == 1) _actionIndex = 10; break; case 2: - if (R2_GLOBALS._v56605[6] == 7) + if (R2_GLOBALS._spillLocation[6] == 7) _actionIndex = 10; break; case 4: - if (R2_GLOBALS._v56605[8] == 14) + if (R2_GLOBALS._spillLocation[8] == 14) _actionIndex = 10; break; case 6: - if (R2_GLOBALS._v56605[10] == 19) + if (R2_GLOBALS._spillLocation[10] == 19) _actionIndex = 10; break; case 7: - if (R2_GLOBALS._v56605[11] == 23) + if (R2_GLOBALS._spillLocation[11] == 23) _actionIndex = 10; break; default: break; } - if (R2_GLOBALS._v56605[3 + _state] == R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) + if (R2_GLOBALS._spillLocation[3 + _state] == R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) scene->_objList1[_state].show(); else scene->_objList1[_state].hide(); @@ -439,34 +441,34 @@ void Scene2000::Action1::signal() { } case 6: scene->_objList1[_state].setPosition(Common::Point(-20, 127)); - ++R2_GLOBALS._v56605[3 + _state]; + ++R2_GLOBALS._spillLocation[3 + _state]; _actionIndex = 5; switch (_state - 1) { case 0: - if (R2_GLOBALS._v56605[4] == 5) + if (R2_GLOBALS._spillLocation[4] == 5) _actionIndex = 15; break; case 2: - if (R2_GLOBALS._v56605[6] == 13) + if (R2_GLOBALS._spillLocation[6] == 13) _actionIndex = 15; break; case 4: - if (R2_GLOBALS._v56605[8] == 16) + if (R2_GLOBALS._spillLocation[8] == 16) _actionIndex = 15; break; case 6: - if (R2_GLOBALS._v56605[10] == 22) + if (R2_GLOBALS._spillLocation[10] == 22) _actionIndex = 15; break; case 7: - if (R2_GLOBALS._v56605[11] == 27) + if (R2_GLOBALS._spillLocation[11] == 27) _actionIndex = 15; break; default: break; } - if (R2_GLOBALS._v56605[3 + _state] == R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) + if (R2_GLOBALS._spillLocation[3 + _state] == R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) scene->_objList1[_state].show(); else scene->_objList1[_state].hide(); @@ -498,7 +500,7 @@ void Scene2000::Action1::signal() { signal(); break; case 15: - if ((R2_GLOBALS._v56605[3 + _state] == 13) || (R2_GLOBALS._v56605[3 + _state] == 22) || (R2_GLOBALS._v56605[3 + _state] == 27)) { + if ((R2_GLOBALS._spillLocation[3 + _state] == 13) || (R2_GLOBALS._spillLocation[3 + _state] == 22) || (R2_GLOBALS._spillLocation[3 + _state] == 27)) { Common::Point pt(30, 127); NpcMover *mover = new NpcMover(); scene->_objList1[_state].addMover(mover, &pt, this); @@ -534,26 +536,24 @@ void Scene2000::Action1::signal() { } } -void Scene2000::Exit1::changeScene() { +void Scene2000::WestExit::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; scene->_exitingFlag = true; - scene->_sceneMode = 0; + _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 10; Common::Point pt(-10, 129); NpcMover *mover = new NpcMover(); R2_GLOBALS._player.addMover(mover, &pt, scene); - - scene->setAction(&scene->_sequenceManager, scene, 206, &R2_GLOBALS._player, NULL); } -void Scene2000::Exit2::changeScene() { +void Scene2000::EastExit::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; scene->_exitingFlag = true; - scene->_sceneMode = 0; + _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 11; @@ -562,38 +562,38 @@ void Scene2000::Exit2::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene2000::Exit3::changeScene() { +void Scene2000::SouthExit::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; scene->_exitingFlag = true; - scene->_sceneMode = 0; + _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 12; - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) { case 2: scene->_mazePlayerMode = 4; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 8; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 8; break; case 11: scene->_mazePlayerMode = 6; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 17; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 17; break; case 15: scene->_mazePlayerMode = 8; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 24; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 24; break; case 20: scene->_mazePlayerMode = 4; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 30; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 30; break; case 26: scene->_mazePlayerMode = 6; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 32; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 32; break; case 29: scene->_mazePlayerMode = 11; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 29; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 29; break; default: break; @@ -631,34 +631,34 @@ void Scene2000::Exit3::changeScene() { } } -void Scene2000::Exit4::changeScene() { +void Scene2000::NorthExit::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; scene->_exitingFlag = true; - scene->_sceneMode = 0; + _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 13; - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) { case 8: scene->_mazePlayerMode = 5; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 2; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 2; break; case 17: scene->_mazePlayerMode = 7; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 11; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 11; break; case 24: scene->_mazePlayerMode = 9; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 15; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 15; break; case 30: scene->_mazePlayerMode = 5; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 20; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 20; break; case 32: scene->_mazePlayerMode = 7; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 26; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 26; break; default: break; @@ -688,14 +688,14 @@ void Scene2000::Exit4::changeScene() { } } -void Scene2000::Exit5::changeScene() { +void Scene2000::DoorExit::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; - scene->_sceneMode = 0; + _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 14; - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) { case 3: scene->_mazePlayerMode = 1; if (R2_GLOBALS._player._characterIndex == 1) @@ -758,9 +758,9 @@ void Scene2000::Exit5::changeScene() { } Scene2000::Scene2000(): SceneExt() { - if (R2_GLOBALS._sceneManager._previousScene != -1) { - R2_GLOBALS._v56605[1] = 21; - R2_GLOBALS._v56605[2] = 21; + if (R2_GLOBALS._sceneManager._previousScene == -1) { + R2_GLOBALS._spillLocation[R2_QUINN] = 21; + R2_GLOBALS._spillLocation[R2_SEEKER] = 21; } if ((R2_GLOBALS._player._characterScene[R2_GLOBALS._player._characterIndex] != R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex]) @@ -773,16 +773,16 @@ Scene2000::Scene2000(): SceneExt() { } void Scene2000::postInit(SceneObjectList *OwnerList) { - _exit1.setDetails(Rect(0, 100, 14, 140), EXITCURSOR_W, 2000); - _exit1.setDest(Common::Point(14, 129)); - _exit2.setDetails(Rect(305, 100, 320, 140), EXITCURSOR_E, 2000); - _exit2.setDest(Common::Point(315, 129)); - _exit3.setDetails(Rect(71, 130, 154, 168), EXITCURSOR_S, 2000); - _exit3.setDest(Common::Point(94, 129)); - _exit4.setDetails(Rect(138, 83, 211, 125), EXITCURSOR_N, 2000); - _exit4.setDest(Common::Point(188, 128)); - _exit5.setDetails(Rect(61, 68, 90, 125), EXITCURSOR_W, 2000); - _exit5.setDest(Common::Point(92, 129)); + _westExit.setDetails(Rect(0, 100, 14, 140), EXITCURSOR_W, 2000); + _westExit.setDest(Common::Point(14, 129)); + _eastExit.setDetails(Rect(305, 100, 320, 140), EXITCURSOR_E, 2000); + _eastExit.setDest(Common::Point(315, 129)); + _southExit.setDetails(Rect(71, 130, 154, 168), EXITCURSOR_S, 2000); + _southExit.setDest(Common::Point(94, 129)); + _northExit.setDetails(Rect(138, 83, 211, 125), EXITCURSOR_N, 2000); + _northExit.setDest(Common::Point(188, 129)); + _doorExit.setDetails(Rect(61, 68, 90, 125), EXITCURSOR_W, 2000); + _doorExit.setDest(Common::Point(92, 129)); R2_GLOBALS._sound1.play(200); initExits(); @@ -859,39 +859,39 @@ void Scene2000::postInit(SceneObjectList *OwnerList) { _objList1[i].hide(); switch (i - 1) { case 0: - if (R2_GLOBALS._v56605[3 + i] == 1) - ++R2_GLOBALS._v56605[3 + i]; - else if (R2_GLOBALS._v56605[3 + i] == 5) - --R2_GLOBALS._v56605[3 + i]; + if (R2_GLOBALS._spillLocation[3 + i] == 1) + ++R2_GLOBALS._spillLocation[3 + i]; + else if (R2_GLOBALS._spillLocation[3 + i] == 5) + --R2_GLOBALS._spillLocation[3 + i]; break; case 2: - if (R2_GLOBALS._v56605[3 + i] == 7) - ++R2_GLOBALS._v56605[3 + i]; - else if (R2_GLOBALS._v56605[3 + i] == 13) - --R2_GLOBALS._v56605[3 + i]; + if (R2_GLOBALS._spillLocation[3 + i] == 7) + ++R2_GLOBALS._spillLocation[3 + i]; + else if (R2_GLOBALS._spillLocation[3 + i] == 13) + --R2_GLOBALS._spillLocation[3 + i]; break; case 4: - if (R2_GLOBALS._v56605[3 + i] == 14) - ++R2_GLOBALS._v56605[3 + i]; - else if (R2_GLOBALS._v56605[3 + i] == 16) - --R2_GLOBALS._v56605[3 + i]; + if (R2_GLOBALS._spillLocation[3 + i] == 14) + ++R2_GLOBALS._spillLocation[3 + i]; + else if (R2_GLOBALS._spillLocation[3 + i] == 16) + --R2_GLOBALS._spillLocation[3 + i]; break; case 6: - if (R2_GLOBALS._v56605[3 + i] == 19) - ++R2_GLOBALS._v56605[3 + i]; - else if (R2_GLOBALS._v56605[3 + i] == 22) - --R2_GLOBALS._v56605[3 + i]; + if (R2_GLOBALS._spillLocation[3 + i] == 19) + ++R2_GLOBALS._spillLocation[3 + i]; + else if (R2_GLOBALS._spillLocation[3 + i] == 22) + --R2_GLOBALS._spillLocation[3 + i]; break; case 8: - if (R2_GLOBALS._v56605[3 + i] == 23) - ++R2_GLOBALS._v56605[3 + i]; - else if (R2_GLOBALS._v56605[3 + i] == 27) - --R2_GLOBALS._v56605[3 + i]; + if (R2_GLOBALS._spillLocation[3 + i] == 23) + ++R2_GLOBALS._spillLocation[3 + i]; + else if (R2_GLOBALS._spillLocation[3 + i] == 27) + --R2_GLOBALS._spillLocation[3 + i]; break; default: break; } - switch (R2_GLOBALS._v56605[3 + i] - 1) { + switch (R2_GLOBALS._spillLocation[3 + i] - 1) { case 0: case 6: case 13: @@ -926,6 +926,7 @@ void Scene2000::postInit(SceneObjectList *OwnerList) { } void Scene2000::remove() { + R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._sound1.fadeOut(NULL); SceneExt::remove(); } @@ -933,17 +934,19 @@ void Scene2000::remove() { void Scene2000::signal() { switch (_sceneMode) { case 10: - if (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] == 6) + // Leaving left-hand side of scene + if (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] == 6) g_globals->_sceneManager.changeScene(1900); else { _mazePlayerMode = 1; - --R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]; + --R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]; initExits(); initPlayer(); } break; case 11: - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) { + // Leaving right-hand side of scene + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) { case 5: g_globals->_sceneManager.changeScene(1900); break; @@ -955,7 +958,7 @@ void Scene2000::signal() { break; default: _mazePlayerMode = 2; - ++R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]; + ++R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]; initExits(); initPlayer(); break; @@ -963,6 +966,7 @@ void Scene2000::signal() { break; case 12: case 13: + // Top/bottom scene exits initExits(); initPlayer(); break; @@ -995,7 +999,7 @@ void Scene2000::signal() { default: if (R2_GLOBALS._v56AAB != 0) R2_GLOBALS._v56AAB = 0; - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); break; } break; @@ -1026,6 +1030,12 @@ void Scene2000::process(Event &event) { void Scene2000::synchronize(Serializer &s) { SceneExt::synchronize(s); + // Synchronise active walk regions + int regionsId = R2_GLOBALS._walkRegions._resNum; + s.syncAsUint16LE(regionsId); + if (s.isLoading()) + R2_GLOBALS._walkRegions.load(regionsId); + s.syncAsByte(_exitingFlag); s.syncAsSint16LE(_mazePlayerMode); } @@ -1085,7 +1095,7 @@ void Scene2350::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_quinnSpeaker); if (R2_GLOBALS._sceneManager._previousScene == -1) - R2_GLOBALS._player._characterScene[2] = 2350; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 2350; _exitUp.setDetails(Rect(25, 83, 93, 125), EXITCURSOR_NW, 2350); _exitUp.setDest(Common::Point(80, 129)); @@ -1103,7 +1113,7 @@ void Scene2350::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(5, 3); } - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor2.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor2.setup(20, 5, 1); @@ -1134,7 +1144,7 @@ void Scene2350::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.disableControl(); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2000) { - if (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] == 34) { + if (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] == 34) { if (R2_GLOBALS._player._characterIndex == 1) _sceneMode = 2351; else @@ -1164,11 +1174,11 @@ void Scene2350::remove() { void Scene2350::signal() { switch (_sceneMode) { case 11: - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 34; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 34; g_globals->_sceneManager.changeScene(2000); break; case 12: - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 29; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 29; g_globals->_sceneManager.changeScene(2000); break; case 20: @@ -1208,7 +1218,7 @@ void Scene2350::process(Event &event) { } /*-------------------------------------------------------------------------- - * Scene 2400 - Ice Maze: Large empty room + * Scene 2400 - Spill Mountains: Large empty room * *--------------------------------------------------------------------------*/ void Scene2400::Exit1::changeScene() { @@ -1244,7 +1254,7 @@ void Scene2400::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.postInit(); R2_GLOBALS._player.disableControl(); - if (R2_GLOBALS._v56605[1] == 16) { + if (R2_GLOBALS._spillLocation[R2_QUINN] == 16) { _sceneMode = 2400; setAction(&_sequenceManager, this, 2400, &R2_GLOBALS._player, NULL); } else { @@ -1256,11 +1266,11 @@ void Scene2400::postInit(SceneObjectList *OwnerList) { void Scene2400::signal() { switch (_sceneMode) { case 10: - R2_GLOBALS._v56605[1] = 16; + R2_GLOBALS._spillLocation[R2_QUINN] = 16; g_globals->_sceneManager.changeScene(2000); break; case 11: - R2_GLOBALS._v56605[1] = 17; + R2_GLOBALS._spillLocation[R2_QUINN] = 17; g_globals->_sceneManager.changeScene(2000); break; default: @@ -1270,7 +1280,7 @@ void Scene2400::signal() { } /*-------------------------------------------------------------------------- - * Scene 2425 - Ice Maze: + * Scene 2425 - Spill Mountains: * *--------------------------------------------------------------------------*/ @@ -1365,7 +1375,7 @@ void Scene2425::Exit1::changeScene() { Scene2425 *scene = (Scene2425 *)R2_GLOBALS._sceneManager._scene; _enabled = false; - R2_GLOBALS._events.setCursor(R2_NEGATOR_GUN); + R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._player.disableControl(); scene->_sceneMode = 11; @@ -1396,7 +1406,7 @@ void Scene2425::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(5, 3); } - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor2.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor2.setup(20, 5, 1); @@ -1485,7 +1495,7 @@ void Scene2425::signal() { } /*-------------------------------------------------------------------------- - * Scene 2430 - Ice Maze: Bedroom + * Scene 2430 - Spill Mountains: Bedroom * *--------------------------------------------------------------------------*/ @@ -1521,7 +1531,7 @@ void Scene2430::Exit1::changeScene() { Scene2430 *scene = (Scene2430 *)R2_GLOBALS._sceneManager._scene; scene->_sceneMode = 0; - R2_GLOBALS._events.setCursor(R2_NEGATOR_GUN); + R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._player.disableControl(); scene->_sceneMode = 11; Common::Point pt(108, 200); @@ -1561,7 +1571,7 @@ void Scene2430::postInit(SceneObjectList *OwnerList) { } R2_GLOBALS._player.setPosition(Common::Point(100, 200)); - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(20, 5, 1); @@ -1624,14 +1634,15 @@ void Scene2430::signal() { } /*-------------------------------------------------------------------------- - * Scene 2435 - Ice Maze: Throne room + * Scene 2435 - Spill Mountains: Throne room * *--------------------------------------------------------------------------*/ -bool Scene2435::Actor1::startAction(CursorType action, Event &event) { + +bool Scene2435::Companion::startAction(CursorType action, Event &event) { return SceneActor::startAction(action, event); } -bool Scene2435::Actor2::startAction(CursorType action, Event &event) { +bool Scene2435::Astor::startAction(CursorType action, Event &event) { Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; switch (action) { @@ -1672,7 +1683,7 @@ void Scene2435::Exit1::changeScene() { Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; _enabled = false; - R2_GLOBALS._events.setCursor(R2_NEGATOR_GUN); + R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._player.disableControl(); scene->_sceneMode = 11; Common::Point pt(175, 200); @@ -1690,36 +1701,38 @@ void Scene2435::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_pharishaSpeaker); _exit1.setDetails(Rect(142, 155, 207, 167), EXITCURSOR_S, 2000); _exit1.setDest(Common::Point(175, 160)); - _actor2.postInit(); - _actor2.setup(2005, 3, 1); - _actor2.setPosition(Common::Point(219, 106)); - _actor2.setDetails(2001, 25, 26, -1, 1, (SceneItem *)NULL); + _astor.postInit(); + _astor.setup(2005, 3, 1); + _astor.setPosition(Common::Point(219, 106)); + _astor.setDetails(2001, 25, 26, -1, 1, (SceneItem *)NULL); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); - if (R2_GLOBALS._player._characterIndex == 1) { + + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._player.setVisage(2008); R2_GLOBALS._player._moveDiff = Common::Point(3, 2); } else { R2_GLOBALS._player.setVisage(20); R2_GLOBALS._player._moveDiff = Common::Point(5, 3); } - R2_GLOBALS._player.setPosition(Common::Point(715, 200)); - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { - _actor1.postInit(); - if (R2_GLOBALS._player._characterIndex == 1) { - _actor1.setup(20, 5, 1); - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); + R2_GLOBALS._player.setPosition(Common::Point(175, 200)); + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { + _companion.postInit(); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + _companion.setup(20, 5, 1); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); } else { - _actor1.setup(2008, 5, 1); - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); + _companion.setup(2008, 5, 1); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); } - _actor1.setPosition(Common::Point(107, 145)); + _companion.setPosition(Common::Point(107, 145)); R2_GLOBALS._walkRegions.enableRegion(2); } - _item2.setDetails(Rect(52, 44, 96, 82), 2430, 3, -1, 5, 1, NULL); - _item3.setDetails(Rect(117, 36, 161, 74), 2430, 3, -1, 5, 1, NULL); - _item1.setDetails(Rect(0, 0, 320, 200), 2430, 0, -1, -1, 1, NULL); + _leftWindow.setDetails(Rect(52, 44, 96, 82), 2430, 3, -1, 5, 1, NULL); + _rightWindow.setDetails(Rect(117, 36, 161, 74), 2430, 3, -1, 5, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 2430, 0, -1, -1, 1, NULL); + R2_GLOBALS._player.disableControl(); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2000) { _sceneMode = 10; @@ -1737,7 +1750,7 @@ void Scene2435::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.enableControl(); } R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 2435; - R2_GLOBALS._v56605[1 + R2_GLOBALS._player._characterIndex] = 12; + R2_GLOBALS._spillLocation[1 + R2_GLOBALS._player._characterIndex] = 12; } void Scene2435::remove() { @@ -1754,21 +1767,21 @@ void Scene2435::signal() { R2_GLOBALS._player.enableControl(CURSOR_TALK); break; case 30: - R2_GLOBALS._player._characterScene[1] = 2435; - R2_GLOBALS._player._characterScene[2] = 2435; - R2_GLOBALS._player._oldCharacterScene[1] = 2435; - R2_GLOBALS._player._oldCharacterScene[2] = 2435; - R2_GLOBALS._v56605[1] = 12; - R2_GLOBALS._v56605[2] = 12; + R2_GLOBALS._player._characterScene[R2_QUINN] = 2435; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 2435; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 2435; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 2435; + R2_GLOBALS._spillLocation[R2_QUINN] = 12; + R2_GLOBALS._spillLocation[R2_SEEKER] = 12; R2_GLOBALS.setFlag(81); _sceneMode = 2436; R2_GLOBALS._player.setStrip(7); - _actor1.postInit(); + _companion.postInit(); if (R2_GLOBALS._player._characterIndex == 1) - _actor1.setVisage(20); + _companion.setVisage(20); else - _actor1.setVisage(2008); - setAction(&_sequenceManager, this, 2436, &_actor1, NULL); + _companion.setVisage(2008); + setAction(&_sequenceManager, this, 2436, &_companion, NULL); break; case 2436: R2_GLOBALS._walkRegions.enableRegion(2); @@ -1782,7 +1795,7 @@ void Scene2435::signal() { } /*-------------------------------------------------------------------------- - * Scene 2440 - Ice Maze: Another bedroom + * Scene 2440 - Spill Mountains: Another bedroom * *--------------------------------------------------------------------------*/ @@ -1840,7 +1853,7 @@ void Scene2440::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(5, 3); } R2_GLOBALS._player.setPosition(Common::Point(210, 200)); - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(20, 5, 1); @@ -1895,7 +1908,7 @@ void Scene2440::signal() { } /*-------------------------------------------------------------------------- - * Scene 2445 - Ice Maze: + * Scene 2445 - Spill Mountains: * *--------------------------------------------------------------------------*/ void Scene2445::postInit(SceneObjectList *OwnerList) { @@ -1913,23 +1926,23 @@ void Scene2445::signal() { } /*-------------------------------------------------------------------------- - * Scene 2450 - Ice Maze: Another bedroom + * Scene 2450 - Spill Mountains: Another bedroom * *--------------------------------------------------------------------------*/ -bool Scene2450::Actor2::startAction(CursorType action, Event &event) { +bool Scene2450::Parker::startAction(CursorType action, Event &event) { Scene2450 *scene = (Scene2450 *)R2_GLOBALS._sceneManager._scene; if ((action == CURSOR_USE) && (R2_GLOBALS._player._characterIndex == 1)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 2452; - scene->setAction(&scene->_sequenceManager, scene, 2452, &R2_GLOBALS._player, &scene->_actor2, NULL); + scene->setAction(&scene->_sequenceManager, scene, 2452, &R2_GLOBALS._player, &scene->_parker, NULL); return true; } return SceneActor::startAction(action, event); } -bool Scene2450::Actor3::startAction(CursorType action, Event &event) { +bool Scene2450::CareTaker::startAction(CursorType action, Event &event) { Scene2450 *scene = (Scene2450 *)R2_GLOBALS._sceneManager._scene; if (action == CURSOR_TALK) { @@ -1943,7 +1956,8 @@ bool Scene2450::Actor3::startAction(CursorType action, Event &event) { else scene->_stripManager.start(700 + (R2_GLOBALS._v565AE * 2), scene); } - return true;} else { + return true; + } else { return SceneActor::startAction(action, event); } } @@ -1974,8 +1988,8 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._sound1.play(200); if (R2_GLOBALS._sceneManager._previousScene == -1) { R2_GLOBALS._sceneManager._previousScene = 1900; - R2_GLOBALS._player._oldCharacterScene[1] = 1900; - R2_GLOBALS._player._oldCharacterScene[2] = 1900; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1900; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1900; } _stripManager.addSpeaker(&_quinnSpeaker); _stripManager.addSpeaker(&_seekerSpeaker); @@ -1987,11 +2001,11 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { } if (!R2_GLOBALS.getFlag(61)) { - _actor2.postInit(); - _actor2.setVisage(2009); - _actor2.setPosition(Common::Point(190, 119)); - _actor2.fixPriority(50); - _actor2.setDetails(2450, 0, -1, -1, 1, (SceneItem *)NULL); + _parker.postInit(); + _parker.setVisage(2009); + _parker.setPosition(Common::Point(190, 119)); + _parker.fixPriority(50); + _parker.setDetails(2450, 0, -1, -1, 1, (SceneItem *)NULL); } R2_GLOBALS._player.postInit(); @@ -1999,10 +2013,10 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { switch (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex]) { case 1900: R2_GLOBALS._v565AE = 0; - R2_GLOBALS._player._characterScene[1] = 2450; - R2_GLOBALS._player._characterScene[2] = 2450; - R2_GLOBALS._player._oldCharacterScene[1] = 2450; - R2_GLOBALS._player._oldCharacterScene[2] = 2450; + R2_GLOBALS._player._characterScene[R2_QUINN] = 2450; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 2450; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 2450; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 2450; R2_GLOBALS._player.setup(2450, 1, 1); R2_GLOBALS._player.setPosition(Common::Point(126, 101)); setAction(&_sequenceManager, this, 2450, &R2_GLOBALS._player, NULL); @@ -2010,24 +2024,24 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { case 2000: _sceneMode = 2451; if (R2_GLOBALS._player._characterIndex == 1) { - if (R2_GLOBALS._player._characterScene[2] == 2450) { - _actor1.postInit(); - _actor1.setup(20, 6, 1); - _actor1.setPosition(Common::Point(240, 120)); - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); + if (R2_GLOBALS._player._characterScene[R2_SEEKER] == 2450) { + _companion.postInit(); + _companion.setup(20, 6, 1); + _companion.setPosition(Common::Point(240, 120)); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); } setAction(&_sequenceManager, this, 2451, &R2_GLOBALS._player, NULL); } else { - R2_GLOBALS._player._oldCharacterScene[2] = 2450; - R2_GLOBALS._player._characterScene[2] = 2450; - if (R2_GLOBALS._player._characterScene[1] == 2450) { - _actor1.postInit(); + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 2450; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 2450; + if (R2_GLOBALS._player._characterScene[R2_QUINN] == 2450) { + _companion.postInit(); if (R2_GLOBALS.getFlag(61)) - _actor1.setup(2008, 6, 1); + _companion.setup(2008, 6, 1); else - _actor1.setup(10, 6, 1); - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); - _actor1.setPosition(Common::Point(106, 111)); + _companion.setup(10, 6, 1); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); + _companion.setPosition(Common::Point(106, 111)); } setAction(&_sequenceManager, this, 2456, &R2_GLOBALS._player, NULL); } @@ -2043,22 +2057,22 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setPosition(Common::Point(106, 111)); R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); if (R2_GLOBALS.getFlag(72)) { - if (R2_GLOBALS._player._characterScene[2] == 2450) { - _actor1.postInit(); - _actor1.setup(20, 6, 1); - _actor1.setPosition(Common::Point(240, 120)); - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); + if (R2_GLOBALS._player._characterScene[R2_SEEKER] == 2450) { + _companion.postInit(); + _companion.setup(20, 6, 1); + _companion.setPosition(Common::Point(240, 120)); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); } } else { - _actor1.postInit(); - _actor1.setup(20, 8, 1); - _actor1.setPosition(Common::Point(93, 158)); - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); + _companion.postInit(); + _companion.setup(20, 8, 1); + _companion.setPosition(Common::Point(93, 158)); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); - _actor3.postInit(); - _actor3.setup(2001, 7, 1); - _actor3.setPosition(Common::Point(34, 153)); - _actor3.setDetails(2001, 40, -1, -1, 1, (SceneItem *)NULL); + _careTaker.postInit(); + _careTaker.setup(2001, 7, 1); + _careTaker.setPosition(Common::Point(34, 153)); + _careTaker.setDetails(2001, 40, -1, -1, 1, (SceneItem *)NULL); _exit1._enabled = false; } @@ -2068,30 +2082,30 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); R2_GLOBALS._player.setPosition(Common::Point(93, 158)); if (R2_GLOBALS.getFlag(72)) { - if (R2_GLOBALS._player._characterScene[1] == 2450) { - _actor1.postInit(); + if (R2_GLOBALS._player._characterScene[R2_QUINN] == 2450) { + _companion.postInit(); if (R2_GLOBALS.getFlag(61)) { - _actor1.setup(2008, 6, 1); + _companion.setup(2008, 6, 1); } else { - _actor1.setup(10, 6, 1); + _companion.setup(10, 6, 1); } - _actor1.setPosition(Common::Point(106, 111)); - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); + _companion.setPosition(Common::Point(106, 111)); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); } } else { - _actor1.postInit(); + _companion.postInit(); if (R2_GLOBALS.getFlag(61)) { - _actor1.setup(2008, 6, 1); + _companion.setup(2008, 6, 1); } else { - _actor1.setup(10, 6, 1); + _companion.setup(10, 6, 1); } - _actor1.setPosition(Common::Point(106, 111)); - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); + _companion.setPosition(Common::Point(106, 111)); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); - _actor3.postInit(); - _actor3.setup(2001, 7, 1); - _actor3.setPosition(Common::Point(34, 153)); - _actor3.setDetails(2001, 40, -1, -1, 1, (SceneItem *)NULL); + _careTaker.postInit(); + _careTaker.setup(2001, 7, 1); + _careTaker.setPosition(Common::Point(34, 153)); + _careTaker.setDetails(2001, 40, -1, -1, 1, (SceneItem *)NULL); _exit1._enabled = false; } @@ -2118,9 +2132,9 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.enableControl(); break; } - _item2.setDetails(Rect(174, 4, 199, 123), 2430, 30, 31, 32, 1, NULL); - _item3.setDetails(Rect(67, 73, 207, 121), 2430, 36, -1, 38, 1, NULL); - _item1.setDetails(Rect(0, 0, 320, 200), 2430, 0, -1, -1, 1, NULL); + _post.setDetails(Rect(174, 4, 199, 123), 2430, 30, 31, 32, 1, NULL); + _bedspread.setDetails(Rect(67, 73, 207, 121), 2430, 36, -1, 38, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 2430, 0, -1, -1, 1, NULL); } void Scene2450::remove() { @@ -2138,7 +2152,7 @@ void Scene2450::signal() { R2_GLOBALS._player.disableControl(); R2_GLOBALS._v565AE = 4; _sceneMode = 2454; - setAction(&_sequenceManager, this, 2454, &_actor3, NULL); + setAction(&_sequenceManager, this, 2454, &_careTaker, NULL); } else { R2_GLOBALS._player.enableControl(CURSOR_TALK); if (R2_GLOBALS._v565AE < 4) @@ -2148,7 +2162,7 @@ void Scene2450::signal() { case 30: R2_GLOBALS._player.disableControl(); _sceneMode = 2455; - setAction(&_sequenceManager, this, 2455, &_actor1, NULL); + setAction(&_sequenceManager, this, 2455, &_companion, NULL); break; case 31: R2_GLOBALS.setFlag(61); @@ -2159,7 +2173,7 @@ void Scene2450::signal() { break; case 2452: R2_GLOBALS.setFlag(61); - _actor2.remove(); + _parker.remove(); R2_GLOBALS._player.enableControl(); if (!R2_GLOBALS.getFlag(72)) { R2_GLOBALS._player.setStrip(6); @@ -2174,38 +2188,38 @@ void Scene2450::signal() { case 2454: _exit1._enabled = true; R2_GLOBALS.setFlag(72); - _actor3.remove(); + _careTaker.remove(); if (R2_GLOBALS.getFlag(61)) { g_globals->_sceneManager.changeScene(2435); } else { _sceneMode = 31; - if (R2_GLOBALS._player._characterIndex == 1) { - setAction(&_sequenceManager, this, 2452, &R2_GLOBALS._player, NULL); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + setAction(&_sequenceManager, this, 2452, &R2_GLOBALS._player, &_parker, NULL); } else { - setAction(&_sequenceManager, this, 2452, &_actor1, &_actor2, NULL); + setAction(&_sequenceManager, this, 2452, &_companion, &_parker, NULL); } } break; case 2455: - R2_GLOBALS._player._oldCharacterScene[2] = 2450; - R2_GLOBALS._player._characterScene[2] = 2000; - R2_GLOBALS._v56605[2] = 3; - _actor1.remove(); - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 2450; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 2000; + R2_GLOBALS._spillLocation[R2_SEEKER] = 3; + _companion.remove(); + R2_GLOBALS._player.enableControl(CURSOR_WALK); break; default: - _actor1.postInit(); - _actor1.setDetails(9002, 0, 4, 3, 2, (SceneItem *)NULL); - _actor3.postInit(); - _actor3.setDetails(2001, 40, -1, -1, 2, (SceneItem *)NULL); + _companion.postInit(); + _companion.setDetails(9002, 0, 4, 3, 2, (SceneItem *)NULL); + _careTaker.postInit(); + _careTaker.setDetails(2001, 40, -1, -1, 2, (SceneItem *)NULL); _sceneMode = 2453; - setAction(&_sequenceManager, this, 2453, &_actor3, &_actor1, NULL); + setAction(&_sequenceManager, this, 2453, &_careTaker, &_companion, NULL); break; } } /*-------------------------------------------------------------------------- - * Scene 2455 - Ice Maze: Inside crevasse + * Scene 2455 - Spill Mountains: Inside crevasse * *--------------------------------------------------------------------------*/ @@ -2385,7 +2399,7 @@ void Scene2455::signal() { } /*-------------------------------------------------------------------------- - * Scene 2500 - Ice Maze: Large Cave + * Scene 2500 - Spill Mountains: Large Cave * *--------------------------------------------------------------------------*/ @@ -2430,7 +2444,7 @@ void Scene2500::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(3, 2); } - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(21, 3, 1); @@ -2568,7 +2582,7 @@ void Scene2525::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(5, 3); } - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(20, 5, 1); @@ -2630,7 +2644,7 @@ void Scene2525::signal() { } /*-------------------------------------------------------------------------- - * Scene 2530 - Ice Maze: Well + * Scene 2530 - Spill Mountains: Well * *--------------------------------------------------------------------------*/ bool Scene2530::Actor2::startAction(CursorType action, Event &event) { @@ -2729,7 +2743,7 @@ void Scene2530::postInit(SceneObjectList *OwnerList) { } R2_GLOBALS._player.setPosition(Common::Point(100, 200)); - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(20, 5, 1); @@ -2787,25 +2801,22 @@ void Scene2530::signal() { } /*-------------------------------------------------------------------------- - * Scene 2535 - Ice Maze: Tannery + * Scene 2535 - Spill Mountains: Tannery * *--------------------------------------------------------------------------*/ -bool Scene2535::Actor3::startAction(CursorType action, Event &event) { +bool Scene2535::RebreatherTank::startAction(CursorType action, Event &event) { Scene2535 *scene = (Scene2535 *)R2_GLOBALS._sceneManager._scene; if (action != CURSOR_USE) return SceneActor::startAction(action, event); - if (R2_GLOBALS._player._characterIndex == 1) { + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._player.disableControl(); - if (R2_INVENTORY.getObjectScene(R2_REBREATHER_TANK) == 2535) { - scene->_sceneMode = 2536; - scene->setAction(&scene->_sequenceManager, scene, 2536, &R2_GLOBALS._player, &scene->_actor3, NULL); - } else { - scene->_sceneMode = 2537; - scene->setAction(&scene->_sequenceManager, scene, 2537, &R2_GLOBALS._player, &scene->_actor3, NULL); - } + + scene->_sceneMode = (R2_INVENTORY.getObjectScene(R2_REBREATHER_TANK) == 2535) ? 2536 : 2537; + scene->setAction(&scene->_sequenceManager, scene, scene->_sceneMode, + &R2_GLOBALS._player, &scene->_rebreatherTank, NULL); } else { SceneItem::display(2530, 33, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); } @@ -2813,7 +2824,7 @@ bool Scene2535::Actor3::startAction(CursorType action, Event &event) { return true; } -bool Scene2535::Actor4::startAction(CursorType action, Event &event) { +bool Scene2535::TannerMask::startAction(CursorType action, Event &event) { Scene2535 *scene = (Scene2535 *)R2_GLOBALS._sceneManager._scene; if (action != CURSOR_USE) @@ -2822,7 +2833,7 @@ bool Scene2535::Actor4::startAction(CursorType action, Event &event) { if (R2_GLOBALS._player._characterIndex == 2) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 2535; - scene->setAction(&scene->_sequenceManager, scene, 2535, &R2_GLOBALS._player, &scene->_actor4, NULL); + scene->setAction(&scene->_sequenceManager, scene, 2535, &R2_GLOBALS._player, &scene->_tannerMask, NULL); } else { SceneItem::display(2530, 33, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); } @@ -2853,34 +2864,34 @@ void Scene2535::postInit(SceneObjectList *OwnerList) { _exit1.setDest(Common::Point(210, 160)); if (R2_INVENTORY.getObjectScene(R2_TANNER_MASK) == 2535) { - _actor4.postInit(); - _actor4.setup(2435, 1, 4); - _actor4.setPosition(Common::Point(47, 74)); - _actor4.fixPriority(74); - _actor4.setDetails(2535, 21, -1, -1, 1, (SceneItem *)NULL); + _tannerMask.postInit(); + _tannerMask.setup(2435, 1, 4); + _tannerMask.setPosition(Common::Point(47, 74)); + _tannerMask.fixPriority(74); + _tannerMask.setDetails(2535, 21, -1, -1, 1, (SceneItem *)NULL); } if (R2_INVENTORY.getObjectScene(R2_REBREATHER_TANK) == 2535) { - _actor3.postInit(); - _actor3.setup(2535, 3, 1); - _actor3.setPosition(Common::Point(203, 131)); - _actor3.setDetails(3, 20, -1, -1, 1, (SceneItem *)NULL); + _rebreatherTank.postInit(); + _rebreatherTank.setup(2535, 3, 1); + _rebreatherTank.setPosition(Common::Point(203, 131)); + _rebreatherTank.setDetails(3, 20, -1, -1, 1, (SceneItem *)NULL); R2_GLOBALS._walkRegions.enableRegion(6); } if ((R2_INVENTORY.getObjectScene(R2_REBREATHER_TANK) == 0) && (R2_GLOBALS.getFlag(73))) { - _actor3.postInit(); - _actor3.setup(2536, 1, 2); - _actor3.setPosition(Common::Point(164, 133)); - _actor3.setDetails(3, 20, -1, -1, 1, (SceneItem *)NULL); + _rebreatherTank.postInit(); + _rebreatherTank.setup(2536, 1, 2); + _rebreatherTank.setPosition(Common::Point(164, 133)); + _rebreatherTank.setDetails(3, 20, -1, -1, 1, (SceneItem *)NULL); } if (R2_GLOBALS.getFlag(73)) { - _actor2.postInit(); - _actor2.setup(2536, 1, 1); - _actor2.setPosition(Common::Point(160, 130)); - _actor2.fixPriority(122); - _actor2.setDetails(2535, 37, -1, -1, 1, (SceneItem *)NULL); + _rope.postInit(); + _rope.setup(2536, 1, 1); + _rope.setPosition(Common::Point(160, 130)); + _rope.fixPriority(122); + _rope.setDetails(2535, 37, -1, -1, 1, (SceneItem *)NULL); } R2_GLOBALS._player.postInit(); @@ -2894,26 +2905,26 @@ void Scene2535::postInit(SceneObjectList *OwnerList) { } R2_GLOBALS._player.setPosition(Common::Point(210, 200)); - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { - _actor1.postInit(); + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { + _companion.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { - _actor1.setup(20, 5, 1); - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); + _companion.setup(20, 5, 1); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); } else { - _actor1.setup(2008, 5, 1); - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); + _companion.setup(2008, 5, 1); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); } - _actor1.setPosition(Common::Point(245, 115)); + _companion.setPosition(Common::Point(245, 115)); R2_GLOBALS._walkRegions.enableRegion(2); } - _item2.setDetails(Rect(96, 3, 215, 33), 2535, 3, 6, 5, 1, NULL); - _item3.setDetails(Rect(4, 43, 40, 101), 2535, 6, 7, 8, 1, NULL); - _item4.setDetails(Rect(55, 13, 140, 89), 2535, 6, 7, 8, 1, NULL); - _item5.setDetails(Rect(144, 23, 216, 76), 2535, 6, 7, 8, 1, NULL); - _item6.setDetails(Rect(227, 8, 307, 99), 2535, 6, 7, 8, 1, NULL); - _item7.setDetails(Rect(116, 111, 201, 132), 2535, 18, 19, 20, 1, NULL); - _item1.setDetails(Rect(0, 0, 320, 200), 2535, 0, 1, -1, 1, NULL); + _roof.setDetails(Rect(96, 3, 215, 33), 2535, 3, 6, 5, 1, NULL); + _skin1.setDetails(Rect(4, 43, 40, 101), 2535, 6, 7, 8, 1, NULL); + _skin2.setDetails(Rect(55, 13, 140, 89), 2535, 6, 7, 8, 1, NULL); + _skin3.setDetails(Rect(144, 23, 216, 76), 2535, 6, 7, 8, 1, NULL); + _skin4.setDetails(Rect(227, 8, 307, 99), 2535, 6, 7, 8, 1, NULL); + _depression.setDetails(Rect(116, 111, 201, 132), 2535, 18, 19, 20, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 2535, 0, 1, -1, 1, NULL); R2_GLOBALS._player.disableControl(); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2000) { @@ -2935,30 +2946,29 @@ void Scene2535::signal() { break; case 2535: R2_INVENTORY.setObjectScene(R2_TANNER_MASK, 2); - _actor4.remove(); + _tannerMask.remove(); R2_GLOBALS._player.enableControl(); break; case 2536: R2_INVENTORY.setObjectScene(R2_REBREATHER_TANK, 0); R2_GLOBALS._walkRegions.disableRegion(6); if (!R2_GLOBALS.getFlag(73)) { - _actor3.remove(); + _rebreatherTank.remove(); R2_GLOBALS._player.enableControl(); } else { _sceneMode = 20; - _actor3.show(); - _actor3.setup(2536, 1, 2); - _actor3.setDetails(3, 20, -1, -1, 3, (SceneItem *)NULL); - _actor3.setPosition(Common::Point(164, 150)); - _actor3.fixPriority(130); - _actor3._moveDiff.y = 1; - Common::Point pt(164, 133); - PlayerMover *mover = new PlayerMover(); - _actor3.addMover(mover, &pt, this); + _rebreatherTank.show(); + _rebreatherTank.setup(2536, 1, 2); + _rebreatherTank.setDetails(3, 20, -1, -1, 3, (SceneItem *)NULL); + _rebreatherTank.setPosition(Common::Point(164, 150)); + _rebreatherTank.fixPriority(130); + + _rebreatherTank._moveDiff.y = 1; + ADD_MOVER(_rebreatherTank, 164, 133); } break; case 2537: - _actor3.remove(); + _rebreatherTank.remove(); R2_INVENTORY.setObjectScene(R2_REBREATHER_TANK, 1); R2_GLOBALS._player.enableControl(); break; @@ -2971,7 +2981,7 @@ void Scene2535::signal() { } /*-------------------------------------------------------------------------- - * Scene 2600 - Ice Maze: Exit + * Scene 2600 - Spill Mountains: Exit * *--------------------------------------------------------------------------*/ Scene2600::Scene2600(): SceneExt() { @@ -3482,7 +3492,7 @@ void Scene2700::signal() { break; case 2700: _actor1.remove(); - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); break; case 2703: g_globals->_sceneManager.changeScene(3900); @@ -3515,7 +3525,7 @@ void Scene2700::signal() { setAction(&_sequenceManager, this, 2713, &R2_GLOBALS._player, &_actor1, NULL); break; default: - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); break; } } @@ -4496,7 +4506,7 @@ void Scene2800::signal() { case 11: _actor2.remove(); _object1.setAction(NULL); - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); R2_GLOBALS._player._moveDiff = Common::Point(3, 2); _item2.setDetails(Rect(76, 45, 155, 90), 2800, 3, -1, -1, 2, NULL); break; @@ -4509,7 +4519,7 @@ void Scene2800::signal() { g_globals->_sceneManager.changeScene(2750); break; case 2801: - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); R2_GLOBALS._player._canWalk = false; break; case 2803: @@ -4531,5 +4541,671 @@ void Scene2800::signal() { } } +/*-------------------------------------------------------------------------- + * Scene 2900 - Balloon Cutscene + * + *--------------------------------------------------------------------------*/ + +bool Scene2900::Scenery::startAction(CursorType action, Event &event) { + switch (action) { + case CURSOR_USE: + SceneItem::display2(1, 5 + R2_GLOBALS._randomSource.getRandomNumber(5)); + break; + case CURSOR_LOOK: + SceneItem::display2(2900, 0); + break; + case CURSOR_TALK: + SceneItem::display2(1, 10 + R2_GLOBALS._randomSource.getRandomNumber(5)); + break; + default: + break; + } + + event.handled = true; + return true; +} + +bool Scene2900::ControlPanel::startAction(CursorType action, Event &event) { + switch (action) { + case CURSOR_USE: + SceneItem::display2(2900, 5); + break; + case CURSOR_LOOK: + SceneItem::display2(2900, 3); + break; + case CURSOR_TALK: + SceneItem::display2(2900, 4); + break; + default: + break; + } + + event.handled = true; + return true; +} + +bool Scene2900::Altimeter::startAction(CursorType action, Event &event) { + switch (action) { + case CURSOR_USE: + SceneItem::display2(2900, 8); + break; + case CURSOR_LOOK: + SceneItem::display2(2900, 6); + break; + case CURSOR_TALK: + SceneItem::display2(2900, 4); + break; + default: + break; + } + + event.handled = true; + return true; +} + +bool Scene2900::KnobLeft::startAction(CursorType action, Event &event) { + Scene2900 *scene = (Scene2900 *)R2_GLOBALS._sceneManager._scene; + + switch (action) { + case CURSOR_USE: + if (scene->_field416 || scene->_altitudeChanging || + scene->_field425 != scene->_field426) { + // Let your altitude stablize first + SceneItem::display2(2900, 17); + } else if (R2_GLOBALS._balloonAltitude / 48 == 0) { + // Maximum altitude + SceneItem::display2(2900, 15); + } else { + // Increase altitude + R2_GLOBALS._sound2.fadeSound(282); + scene->_altitudeChanging = true; + scene->_altitudeMajorChange = -1; + scene->_field426 = 100 - ((R2_GLOBALS._balloonAltitude / 48) - 1) * 25; + } + break; + + case CURSOR_LOOK: + SceneItem::display2(2900, 9); + break; + + case CURSOR_TALK: + SceneItem::display2(2900, 4); + break; + + default: + break; + } + + event.handled = true; + return true; +} + +bool Scene2900::KnobRight::startAction(CursorType action, Event &event) { + Scene2900 *scene = (Scene2900 *)R2_GLOBALS._sceneManager._scene; + + switch (action) { + case CURSOR_USE: + if (scene->_field416 || scene->_altitudeChanging || + scene->_field425 != scene->_field426) { + // Let your altitude stablize first + SceneItem::display2(2900, 17); + } else if (R2_GLOBALS._balloonAltitude / 48 >= 3) { + // Altitude is too low - cannot land here + SceneItem::display2(2900, 16); + } else { + // Decrease altitude + R2_GLOBALS._sound2.fadeSound(212); + scene->_altitudeChanging = true; + scene->_altitudeMajorChange = 1; + scene->_field426 = 100 - ((R2_GLOBALS._balloonAltitude / 48) + 1) * 25; + } + break; + + case CURSOR_LOOK: + SceneItem::display2(2900, 12); + break; + + case CURSOR_TALK: + SceneItem::display2(2900, 4); + break; + + default: + break; + } + + event.handled = true; + return true; +} + +bool Scene2900::Skip::startAction(CursorType action, Event &event) { + Scene2900 *scene = (Scene2900 *)R2_GLOBALS._sceneManager._scene; + + if (action == CURSOR_USE) { + R2_GLOBALS._player.disableControl(); + scene->_sceneMode = 12; + scene->signal(); + } + + return true; +} + +/*------------------------------------------------------------------------*/ + +void Scene2900::Action1::signal() { + Scene2900 *scene = (Scene2900 *)R2_GLOBALS._sceneManager._scene; + setDelay(3); + + if (!scene->_field416 && !scene->_altitudeChanging) { + scene->_field427 = 2; + scene->_field412 = 0; + } else if (scene->_field416) { + R2_GLOBALS._sound2.fadeOut2(NULL); + } else if (scene->_field427 == 0) { + R2_GLOBALS._sound2.fadeOut2(NULL); + } else if (scene->_field412 == 0) { + scene->_knobLeftContent.hide(); + scene->_knobRightContent.hide(); + scene->_field412 = 1; + } else { + --scene->_field427; + scene->_knobLeftContent.show(); + scene->_knobRightContent.show(); + scene->_field412 = 0; + } +} + +/*------------------------------------------------------------------------*/ + +Scene2900::Map::Map() { + _mapWidth = _mapHeight = 0; + _field4 = 0; + _field6 = 0; + _field8 = 0; + _fieldA = 0; + _resNum = 0; + _xV = _yV = 0; + _bounds = Rect(40, 0, 280, 150); +} + +void Scene2900::Map::load(int resNum) { + byte *data = g_resourceManager->getResource(RES_BITMAP, resNum, 9999); + + _resNum = resNum; + _xV = _yV = 0; + _mapWidth = READ_LE_UINT16(data); + _mapHeight = READ_LE_UINT16(data + 2); + + DEALLOCATE(data); +} + +Common::Point Scene2900::Map::setPosition(const Common::Point &pos, bool initialFlag) { + Common::Point p = pos; + Rect updateRect; + + if (p.x >= 0) { + int xRight = p.x + _bounds.width(); + if (xRight > _mapWidth) { + p.x = _mapWidth - _bounds.width(); + } + } else { + p.x = 0; + } + + if (p.y >= 0) { + int yBottom = p.y + _bounds.height(); + if (yBottom > _mapHeight) { + p.y = _mapHeight - _bounds.height(); + } + } else { + p.y = 0; + } + + if ((p.x != 0 || p.y != 0) && !initialFlag) { + moveArea(updateRect, _xV - p.x, _yV - p.y); + redraw(&updateRect); + } else { + redraw(); + } + + _xV = p.x; + _yV = p.y; + return Common::Point(_xV, _yV); +} + +void Scene2900::Map::redraw(Rect *updateRect) { + int xHalfCount = _mapWidth / 160; + int yHalfCount = _mapHeight / 100; + int rlbNum = 0; + + Rect blockRect(0, 0, 160, 100); + Rect screenRect = _bounds; + screenRect.translate(_xV - _bounds.left, _yV - _bounds.top); + + Rect modifyRect; + if (updateRect) + modifyRect = *updateRect; + + for (int xCtr = 0; xCtr < xHalfCount; ++xCtr) { + for (int yCtr = 0; yCtr < yHalfCount; ++yCtr, ++rlbNum) { + blockRect.moveTo(160 * xCtr, 100 * yCtr); + if (blockRect.intersects(screenRect)) { + // The block of the map is at least partially on-screen, so needs drawing + blockRect.translate(_bounds.left - _xV, _bounds.top - _yV); + byte *data = g_resourceManager->getResource(RES_BITMAP, _resNum, rlbNum); + + drawBlock(data, blockRect.left, blockRect.top, _bounds, modifyRect); + + DEALLOCATE(data); + } + } + } +} + +void Scene2900::Map::synchronize(Serializer &s) { + s.syncAsUint16LE(_resNum); + if (s.isLoading()) + load(_resNum); + + s.syncAsSint16LE(_xV); + s.syncAsSint16LE(_yV); + _bounds.synchronize(s); +} + +int Scene2900::Map::adjustRect(Common::Rect &r1, const Common::Rect &r2) { + if (r2.contains(r1)) + return 0; + if (!r2.intersects(r1)) + return 1; + + if (r1.top >= r2.top && r1.bottom <= r2.bottom) { + if (r1.left >= r2.left && r1.left < r2.right) { + r1.left = r2.right - 1; + return 1; + } + if (r1.right > r2.left && r1.right <= r2.right) { + r1.right = r2.left + 1; + return 1; + } + } + + if (r1.left < r2.left || r1.right > r2.right) + return -1; + + if (r1.top >= r2.top && r1.top < r2.bottom) { + r1.top = r2.bottom - 1; + return 1; + } + if (r1.bottom > r2.top && r1.bottom <= r2.bottom) { + r1.bottom = r2.top + 1; + return 1; + } + + return -1; +} + +void Scene2900::Map::drawBlock(const byte *data, int xp, int yp, + const Rect &bounds, const Rect &updateRect) { + Rect blockRect(xp, yp, xp + 160, yp + 100); + const byte *src = data; + + if (blockRect.intersects(bounds)) { + blockRect.clip(bounds); + + if (adjustRect(blockRect, updateRect) != 0) { + int width = blockRect.width(); + int height = blockRect.height(); + src += (blockRect.top - yp) * 160 + blockRect.left - xp; + + GfxSurface &surface = R2_GLOBALS._sceneManager._scene->_backSurface; + Graphics::Surface s = surface.lockSurface(); + + for (int yCtr = 0; yCtr < height; ++yCtr, src += 160) { + byte *destP = (byte *)s.getBasePtr(blockRect.left, blockRect.top + yCtr); + Common::copy(src, src + width, destP); + } + + surface.unlockSurface(); + R2_GLOBALS.gfxManager().copyFrom(surface, blockRect, blockRect); + } + } +} + +void Scene2900::Map::moveArea(Rect &r, int xAmt, int yAmt) { + Rect tempRect = r; + tempRect.translate(xAmt, yAmt); + int xpSrc, xpDest, width; + int ypSrc, ypDest, height; + + if (tempRect.intersects(r)) { + if (xAmt >= 0) { + xpSrc = tempRect.left; + width = tempRect.width() - xAmt; + xpDest = tempRect.left + xAmt; + } else { + xpSrc = tempRect.left - xAmt; + width = tempRect.width() + xAmt; + xpDest = tempRect.left; + } + + if (yAmt > 0) { + height = tempRect.height() - yAmt; + ypDest = tempRect.top + yAmt + (height - 1); + ypSrc = tempRect.top + (height - 1); + + for (int yCtr = 0; yCtr < height; ++yCtr, --ypSrc, --ypDest) { + moveLine(xpSrc, ypSrc, xpDest, ypDest, width); + } + } else { + ypSrc = tempRect.top - yAmt; + height = tempRect.height() + yAmt; + ypDest = tempRect.top; + + for (int yCtr = 0; yCtr < height; ++yCtr, ++ypSrc, ++ypDest) { + moveLine(xpSrc, ypSrc, xpDest, ypDest, width); + } + } + } else { + r = Rect(0, 0, 0, 0); + } +} + +void Scene2900::Map::moveLine(int xpSrc, int ypSrc, int xpDest, int ypDest, int width) { + byte buffer[SCREEN_WIDTH]; + assert(width <= SCREEN_WIDTH); + + GfxSurface &surface = R2_GLOBALS.gfxManager().getSurface(); + Graphics::Surface s = surface.lockSurface(); + + byte *srcP = (byte *)s.getBasePtr(xpSrc, ypSrc); + byte *destP = (byte *)s.getBasePtr(xpDest, ypDest); + Common::copy(srcP, srcP + width, &buffer[0]); + Common::copy(&buffer[0], &buffer[width], destP); + + surface.unlockSurface(); +} + +/*------------------------------------------------------------------------*/ + +Scene2900::Scene2900(): SceneExt() { + _field412 = 0; + _altitudeChanging = false; + _field416 = false; + _balloonLocation = Common::Point(550, 550); + _field41C = 0; + _altitudeMajorChange = 0; + _balloonScreenPos = Common::Point(160, 100); + _newAltitude = 0; + _field425 = 100; + _field426 = 100; + _field427 = 0; + _field8F8 = false; +} + +void Scene2900::synchronize(Serializer &s) { + SceneExt::synchronize(s); + + s.syncAsSint16LE(_field412); + s.syncAsSint16LE(_altitudeChanging); + s.syncAsSint16LE(_field416); + s.syncAsSint16LE(_field41C); + s.syncAsSint16LE(_altitudeMajorChange); + s.syncAsSint16LE(_balloonLocation.x); + s.syncAsSint16LE(_balloonLocation.y); + s.syncAsSint16LE(_balloonScreenPos.x); + s.syncAsSint16LE(_balloonScreenPos.y); + s.syncAsSint16LE(_newAltitude); + s.syncAsSint16LE(_field425); + s.syncAsSint16LE(_field426); + s.syncAsSint16LE(_field427); + s.syncAsSint16LE(_field8F8); + + _map.synchronize(s); +} + +void Scene2900::postInit(SceneObjectList *OwnerList) { + R2_GLOBALS._uiElements._active = false; + // TODO: Determine correct colours + R2_GLOBALS._gfxColors.foreground = 228; + R2_GLOBALS._fontColors.background = 12; + R2_GLOBALS._fontColors.foreground = 22; + + _map.load(2950); + + loadScene(2900); + SceneExt::postInit(); + R2_GLOBALS._interfaceY = SCREEN_HEIGHT; + + _leftEdge.setup(2900, 6, 1, 22, 0, 25); + _rightEdge.setup(2900, 6, 1, 280, 0, 25); + _knob.setup(2900, 1, 3, 228, 199, 25); + + _altimeterContent.postInit(); + _altimeterContent.setVisage(2900); + _altimeterContent.setStrip(2); + _altimeterContent.setFrame(1); + _altimeterContent.fixPriority(10); + + _knobLeftContent.postInit(); + _knobLeftContent.setVisage(2900); + _knobLeftContent.setStrip(1); + _knobLeftContent.setFrame(1); + _knobLeftContent.setPosition(Common::Point(209, 199)); + _knobLeftContent.fixPriority(200); + + _knobRightContent.postInit(); + _knobRightContent.setVisage(2900); + _knobRightContent.setStrip(1); + _knobRightContent.setFrame(2); + _knobRightContent.setPosition(Common::Point(247, 199)); + _knobRightContent.fixPriority(200); + + // Set up hotspots + _scenery.setDetails(Rect(0, 0, 320, 150), 2900, -1, -1, -1, 1, (SceneItem *)NULL); + _controlPanel.setDetails(Rect(0, 150, 320, 200), 2900, -1, -1, -1, 1, (SceneItem *)NULL); + _altimeter.setDetails(Rect(42, 164, 129, 190), 2900, -1, -1, -1, 2, (SceneItem *)NULL); + _knobLeft.setDetails(Rect(165, 160, 228, 200), 2900, -1, -1, -1, 2, (SceneItem *)NULL); + _knobRight.setDetails(Rect(228, 160, 285, 200), 2900, -1, -1, -1, 2, (SceneItem *)NULL); + _skip.postInit(); + _skip.setBounds(185, 50, 200, 0); + R2_GLOBALS._sceneItems.push_front(&_skip); + + // For ScummVM, we're introducing a Skip button, since the scene is a pain + _skipText._color1 = R2_GLOBALS._scenePalette._colors.foreground; + _skipText._color2 = R2_GLOBALS._scenePalette._colors.background; + _skipText.setPosition(Common::Point(0, 185)); + _skipText.setup("Skip"); + + setAction(&_action1); + R2_GLOBALS._player.postInit(); + R2_GLOBALS._player.setVisage(2900); + R2_GLOBALS._player.setStrip2(3); + R2_GLOBALS._player.setFrame2(1); + R2_GLOBALS._player.fixPriority(15); + R2_GLOBALS._player._moveDiff = Common::Point(2, 2); + R2_GLOBALS._player.disableControl(); + + if (R2_GLOBALS._sceneManager._previousScene == 2350 && + R2_GLOBALS._balloonPosition.x == 0 && R2_GLOBALS._balloonPosition.y == 0) { + R2_GLOBALS._balloonAltitude = 5; + _map.setPosition(Common::Point(_balloonLocation.x - 120, _balloonLocation.y - 100)); + _sceneMode = 10; + + R2_GLOBALS._player.changeZoom(100); + R2_GLOBALS._player.setPosition(Common::Point(160, 180)); + ADD_PLAYER_MOVER(160, 100); + + _altimeterContent.setPosition(Common::Point(9, 189)); + } else { + _balloonLocation.x = R2_GLOBALS._balloonPosition.x + 120; + _balloonLocation.y = R2_GLOBALS._balloonPosition.y + 100; + + if ((R2_GLOBALS._balloonAltitude % 8) == 0) + _balloonLocation.x -= 70; + else if ((R2_GLOBALS._balloonAltitude % 8) == 7) + _balloonLocation.x += 70; + + if (_balloonLocation.x <= 120) + _balloonScreenPos.x = _balloonLocation.x + 40; + else if (_balloonLocation.x >= 680) + _balloonScreenPos.x = _balloonLocation.x - 520; + + if ((R2_GLOBALS._balloonAltitude / 6) == 5) + _balloonLocation.y -= 50; + if (_balloonLocation.y <= 100) + _balloonScreenPos.y = _balloonLocation.y; + + _field425 = _field426 = 100 - (R2_GLOBALS._balloonAltitude / 48) * 25; + _map.setPosition(Common::Point(_balloonLocation.x - 120, _balloonLocation.y - 100)); + _sceneMode = 11; + + R2_GLOBALS._player.changeZoom(_field425); + R2_GLOBALS._player.setPosition(_balloonScreenPos); + R2_GLOBALS._player.enableControl(); + R2_GLOBALS._player._canWalk = false; + + _altimeterContent.setPosition(Common::Point(109 - _field425, 189)); + } + + R2_GLOBALS._sound1.play(211); +} + +void Scene2900::remove() { + // TODO: Figure out correct colours + R2_GLOBALS._gfxColors.foreground = 59; + R2_GLOBALS._fontColors.background = 4; + R2_GLOBALS._fontColors.foreground = 15; + + R2_GLOBALS._scenePalette.loadPalette(0); + R2_GLOBALS._scenePalette.setEntry(255, 255, 255, 255); + + R2_GLOBALS._sound1.fadeOut2(NULL); + R2_GLOBALS._sound2.stop(); + + R2_GLOBALS._interfaceY = UI_INTERFACE_Y; + SceneExt::remove(); +} + +void Scene2900::signal() { + switch (_sceneMode) { + case 10: + _sceneMode = 11; + R2_GLOBALS._player.enableControl(); + R2_GLOBALS._player._canWalk = false; + break; + case 12: + R2_GLOBALS._sceneManager.changeScene(2600); + break; + default: + break; + } +} + +void Scene2900::dispatch() { + if (_sceneMode == 11) { + _balloonLocation.x += balloonData[R2_GLOBALS._balloonAltitude].x; + _balloonLocation.y += balloonData[R2_GLOBALS._balloonAltitude].y; + _field41C = balloonData[R2_GLOBALS._balloonAltitude].v3; + + if (_field41C == 0) { + _field416 = false; + } else { + _field416 = true; + _altitudeChanging = false; + _field426 = 100 - ((R2_GLOBALS._balloonAltitude / 48) + _field41C) * 25; + } + + // Zooming/altitude balloon change + if (_field425 == _field426) { + _field416 = false; + } else { + if (!_field416) { + _field425 = _field425 - _altitudeMajorChange; + } else { + _field425 = _field425 - _field41C; + } + + if (_field41C == -1 || _altitudeMajorChange == -1) { + if (_altimeterContent._frame == 1) { + _altimeterContent.setFrame2(10); + } else { + _altimeterContent.setFrame2(_altimeterContent._frame - 1); + } + } else if (_field41C == -1 || _altitudeMajorChange == 1) { + if (_altimeterContent._frame == 10) + _altimeterContent.setFrame2(1); + else + _altimeterContent.setFrame2(_altimeterContent._frame + 1); + } + + _altimeterContent.setPosition(Common::Point(109 - _field425, 189)); + R2_GLOBALS._player.changeZoom(_field425); + } + + if (!_field8F8) { + R2_GLOBALS._scenePalette.loadPalette(2950); + R2_GLOBALS._scenePalette.refresh(); + } + + R2_GLOBALS._balloonPosition = _map.setPosition( + Common::Point(_balloonLocation.x - 120, _balloonLocation.y - 100), !_field8F8); + _field8F8 = true; + + if (_balloonLocation.x <= 120) + _balloonScreenPos.x = _balloonLocation.x + 40; + else if (_balloonLocation.x >= 680) + _balloonScreenPos.x = _balloonLocation.x - 520; + + if (_balloonLocation.y <= 100) + _balloonScreenPos.y = _balloonLocation.y; + + R2_GLOBALS._player.setPosition(_balloonScreenPos); + + if ((_balloonLocation.x % 100) == 50 && (_balloonLocation.y % 100) == 50 && !_field416) { + // At an altitude change point, so calculate new altitude + _newAltitude = R2_GLOBALS._balloonAltitude; + if (_altitudeChanging) { + _newAltitude += _altitudeMajorChange * 48; + _altitudeChanging = false; + } + + if (balloonData[R2_GLOBALS._balloonAltitude].x > 0) { + ++_newAltitude; + } else if (balloonData[R2_GLOBALS._balloonAltitude].x < 0) { + --_newAltitude; + } + + if (balloonData[R2_GLOBALS._balloonAltitude].y > 0) { + _newAltitude -= 8; + } else if (balloonData[R2_GLOBALS._balloonAltitude].y < 0) { + _newAltitude += 8; + } + + if (balloonData[R2_GLOBALS._balloonAltitude].v3 > 0) { + _newAltitude += 48; + } else if (balloonData[R2_GLOBALS._balloonAltitude].v3 < 0) { + _newAltitude -= 48; + } + + assert(_newAltitude < 193); + R2_GLOBALS._balloonAltitude = _newAltitude; + if (R2_GLOBALS._balloonAltitude == 189) { + // Finally reached landing point + _sceneMode = 12; + R2_GLOBALS._player.disableControl(); + + ADD_MOVER(R2_GLOBALS._player, 160, -10); + } + } + } + + Scene::dispatch(); +} + +void Scene2900::refreshBackground(int xAmount, int yAmount) { + SceneExt::refreshBackground(xAmount, yAmount); + + _map.redraw(); +} + } // End of namespace Ringworld2 } // End of namespace TsAGE diff --git a/engines/tsage/ringworld2/ringworld2_scenes2.h b/engines/tsage/ringworld2/ringworld2_scenes2.h index feceaa1537..422507883f 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes2.h +++ b/engines/tsage/ringworld2/ringworld2_scenes2.h @@ -45,23 +45,23 @@ class Scene2000 : public SceneExt { virtual void signal(); }; - class Exit1 : public SceneExit { + class WestExit : public SceneExit { public: virtual void changeScene(); }; - class Exit2 : public SceneExit { + class EastExit : public SceneExit { public: virtual void changeScene(); }; - class Exit3 : public SceneExit { + class SouthExit : public SceneExit { public: virtual void changeScene(); }; - class Exit4 : public SceneExit { + class NorthExit : public SceneExit { public: virtual void changeScene(); }; - class Exit5 : public SceneExit { + class DoorExit : public SceneExit { public: virtual void changeScene(); }; @@ -72,11 +72,11 @@ public: NamedHotspot _item1; SceneActor _object1; SceneActor _objList1[11]; - Exit1 _exit1; - Exit2 _exit2; - Exit3 _exit3; - Exit4 _exit4; - Exit5 _exit5; + WestExit _westExit; + EastExit _eastExit; + SouthExit _southExit; + NorthExit _northExit; + DoorExit _doorExit; Action1 _action1, _action2, _action3, _action4, _action5; SequenceManager _sequenceManager; @@ -230,11 +230,11 @@ public: }; class Scene2435 : public SceneExt { - class Actor1 : public SceneActor { + class Companion : public SceneActor { public: bool startAction(CursorType action, Event &event); }; - class Actor2 : public SceneActor { + class Astor : public SceneActor { public: bool startAction(CursorType action, Event &event); }; @@ -247,11 +247,11 @@ public: SpeakerQuinn2435 _quinnSpeaker; SpeakerSeeker2435 _seekerSpeaker; SpeakerPharisha2435 _pharishaSpeaker; - NamedHotspot _item1; - NamedHotspot _item2; - NamedHotspot _item3; - Actor1 _actor1; - Actor2 _actor2; + NamedHotspot _background; + NamedHotspot _leftWindow; + NamedHotspot _rightWindow; + Companion _companion; + Astor _astor; Exit1 _exit1; SequenceManager _sequenceManager; @@ -301,11 +301,11 @@ public: }; class Scene2450 : public SceneExt { - class Actor2 : public SceneActor { + class Parker : public SceneActor { public: bool startAction(CursorType action, Event &event); }; - class Actor3 : public SceneActor { + class CareTaker : public SceneActor { public: bool startAction(CursorType action, Event &event); }; @@ -318,12 +318,12 @@ public: SpeakerQuinn2450 _quinnSpeaker; SpeakerSeeker2450 _seekerSpeaker; SpeakerCaretaker2450 _caretakerSpeaker; - NamedHotspot _item1; - NamedHotspot _item2; - NamedHotspot _item3; - SceneActor _actor1; - Actor2 _actor2; - Actor3 _actor3; + NamedHotspot _background; + NamedHotspot _post; + NamedHotspot _bedspread; + SceneActor _companion; + Parker _parker; + CareTaker _careTaker; Exit1 _exit1; SequenceManager _sequenceManager; @@ -447,11 +447,11 @@ public: }; class Scene2535 : public SceneExt { - class Actor3 : public SceneActor { + class RebreatherTank : public SceneActor { public: bool startAction(CursorType action, Event &event); }; - class Actor4 : public SceneActor { + class TannerMask : public SceneActor { public: bool startAction(CursorType action, Event &event); }; @@ -461,17 +461,17 @@ class Scene2535 : public SceneExt { virtual void changeScene(); }; public: - NamedHotspot _item1; - NamedHotspot _item2; - NamedHotspot _item3; - NamedHotspot _item4; - NamedHotspot _item5; - NamedHotspot _item6; - NamedHotspot _item7; - SceneActor _actor1; - SceneActor _actor2; - Actor3 _actor3; - Actor4 _actor4; + NamedHotspot _background; + NamedHotspot _roof; + NamedHotspot _skin1; + NamedHotspot _skin2; + NamedHotspot _skin3; + NamedHotspot _skin4; + NamedHotspot _depression; + SceneActor _companion; + SceneActor _rope; + RebreatherTank _rebreatherTank; + TannerMask _tannerMask; Exit1 _exit1; SequenceManager _sequenceManager; @@ -667,6 +667,101 @@ public: virtual void signal(); }; +class Scene2900 : public SceneExt { + /* Items */ + class Scenery : public NamedHotspot { + public: + virtual bool startAction(CursorType action, Event &event); + }; + class ControlPanel : public NamedHotspot { + public: + virtual bool startAction(CursorType action, Event &event); + }; + class Altimeter : public NamedHotspot { + public: + virtual bool startAction(CursorType action, Event &event); + }; + class KnobLeft : public NamedHotspot { + public: + virtual bool startAction(CursorType action, Event &event); + }; + class KnobRight : public NamedHotspot { + public: + virtual bool startAction(CursorType action, Event &event); + }; + class Skip : public NamedHotspot { + public: + virtual bool startAction(CursorType action, Event &event); + }; + + /* Actions */ + class Action1: public Action { + public: + void signal(); + }; + + /* Miscellaneous */ + class Map { + private: + void moveArea(Rect &r, int xAmt, int yAmt); + void moveLine(int xpSrc, int ypSrc, int xpDest, int ypDest, int width); + int adjustRect(Common::Rect &r1, const Common::Rect &r2); + void drawBlock(const byte *data, int xp, int yp, const Rect &r1, const Rect &r2); + public: + int _mapWidth, _mapHeight; + int _field4; + int _field6; + int _field8; + int _fieldA; + int _resNum; + int _xV, _yV; + Rect _bounds; + + Map(); + void load(int resNum); + Common::Point setPosition(const Common::Point &pos, bool initialFlag = false); + void synchronize(Serializer &s); + void redraw(Rect *updateRect = NULL); + }; +public: + SceneObject _leftEdge; + SceneObject _rightEdge; + SceneObject _knob; + SceneObject _altimeterContent; + SceneObject _knobRightContent; + SceneObject _knobLeftContent; + Scenery _scenery; + ControlPanel _controlPanel; + Altimeter _altimeter; + KnobLeft _knobLeft; + KnobRight _knobRight; + Skip _skip; + Action1 _action1; + Map _map; + SceneText _skipText; + + int _field412; + bool _altitudeChanging; + bool _field416; + int _field41C; + int _altitudeMajorChange; + Common::Point _balloonLocation; + Common::Point _balloonScreenPos; + int _newAltitude; + int _field425; + int _field426; + int _field427; + bool _field8F8; + + Scene2900(); + virtual void synchronize(Serializer &s); + virtual void postInit(SceneObjectList *OwnerList = NULL); + virtual void remove(); + virtual void signal(); + virtual void dispatch(); + virtual void refreshBackground(int xAmount, int yAmount); +}; + } // End of namespace Ringworld2 } // End of namespace TsAGE diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp index 7703d49188..b40263b2ae 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp @@ -58,7 +58,7 @@ bool Scene3100::Guard::startAction(CursorType action, Event &event) { void Scene3100::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene == 1000) { - if (R2_GLOBALS._player._oldCharacterScene[1] == 3100) { + if (R2_GLOBALS._player._oldCharacterScene[R2_QUINN] == 3100) { loadScene(3101); R2_GLOBALS._uiElements._active = false; } else { @@ -89,7 +89,7 @@ void Scene3100::postInit(SceneObjectList *OwnerList) { _field412 = 0; if (R2_GLOBALS._sceneManager._previousScene == 1000) { - if (R2_GLOBALS._player._oldCharacterScene[1] == 3100) { + if (R2_GLOBALS._player._oldCharacterScene[R2_QUINN] == 3100) { _sceneMode = 3102; _actor3.postInit(); _actor4.postInit(); @@ -153,7 +153,7 @@ void Scene3100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._sound1.play(243); } - R2_GLOBALS._player._oldCharacterScene[1] = 3100; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 3100; } void Scene3100::remove() { @@ -178,7 +178,7 @@ void Scene3100::signal() { R2_GLOBALS._sceneManager.changeScene(1000); break; case 3102: - R2_GLOBALS._player._oldCharacterScene[1] = 1000; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1000; R2_GLOBALS._sceneManager.changeScene(1000); break; default: @@ -536,7 +536,7 @@ void Scene3150::postInit(SceneObjectList *OwnerList) { loadScene(3150); if (R2_GLOBALS._sceneManager._previousScene == -1) { R2_INVENTORY.setObjectScene(R2_ANCIENT_SCROLLS, 2000); - R2_GLOBALS._player._oldCharacterScene[1] = 3100; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 3100; R2_GLOBALS._player._oldCharacterScene[3] = 0; R2_GLOBALS._player._characterIndex = R2_MIRANDA; } @@ -675,7 +675,7 @@ void Scene3150::postInit(SceneObjectList *OwnerList) { break; } default: - if ((R2_GLOBALS._v56AA0 == 1) && (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 2000) && (R2_GLOBALS._player._oldCharacterScene[1] == 3100)) { + if ((R2_GLOBALS._v56AA0 == 1) && (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 2000) && (R2_GLOBALS._player._oldCharacterScene[R2_QUINN] == 3100)) { ++R2_GLOBALS._v56AA0; _sceneMode = 3156; _actor1.postInit(); @@ -1957,8 +1957,8 @@ void Scene3375::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_mirandaSpeaker); _stripManager.addSpeaker(&_webbsterSpeaker); - R2_GLOBALS._player._characterScene[1] = 3375; - R2_GLOBALS._player._characterScene[2] = 3375; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3375; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3375; R2_GLOBALS._player._characterScene[3] = 3375; setZoomPercents(126, 55, 200, 167); @@ -2292,8 +2292,8 @@ void Scene3385::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_mirandaSpeaker); _stripManager.addSpeaker(&_webbsterSpeaker); - R2_GLOBALS._player._characterScene[1] = 3385; - R2_GLOBALS._player._characterScene[2] = 3385; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3385; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3385; R2_GLOBALS._player._characterScene[3] = 3385; if (R2_GLOBALS._sceneManager._previousScene == 3375) @@ -2512,8 +2512,8 @@ void Scene3395::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_mirandaSpeaker); _stripManager.addSpeaker(&_webbsterSpeaker); - R2_GLOBALS._player._characterScene[1] = 3395; - R2_GLOBALS._player._characterScene[2] = 3395; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3395; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3395; R2_GLOBALS._player._characterScene[3] = 3395; if (R2_GLOBALS._sceneManager._previousScene == 3385) @@ -2669,8 +2669,8 @@ void Scene3400::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_tealSpeaker); setZoomPercents(51, 46, 180, 200); - R2_GLOBALS._player._characterScene[1] = 3400; - R2_GLOBALS._player._characterScene[2] = 3400; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3400; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3400; R2_GLOBALS._player._characterScene[3] = 3400; _actor7.postInit(); @@ -3577,8 +3577,8 @@ void Scene3500::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._v5589E.set(0, 0, 320, 200); R2_GLOBALS._sound1.play(305); R2_GLOBALS._player._characterIndex = R2_QUINN; - R2_GLOBALS._player._characterScene[1] = 3500; - R2_GLOBALS._player._characterScene[2] = 3500; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3500; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3500; R2_GLOBALS._player._characterScene[3] = 3500; _field1284 = 0; _field1282 = 0; @@ -4377,8 +4377,8 @@ void Scene3600::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_protectorSpeaker); setZoomPercents(142, 80, 167, 105); - R2_GLOBALS._player._characterScene[1] = 3600; - R2_GLOBALS._player._characterScene[2] = 3600; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3600; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3600; R2_GLOBALS._player._characterScene[3] = 3600; _item2.setDetails(33, 3600, 6, -1, -1); @@ -4950,45 +4950,47 @@ void Scene3700::signal() { } /*-------------------------------------------------------------------------- - * Scene 3800 - + * Scene 3800 - Desert * *--------------------------------------------------------------------------*/ + Scene3800::Scene3800() { - _field412 = 0; + _desertDirection = 0; } + void Scene3800::synchronize(Serializer &s) { SceneExt::synchronize(s); - s.syncAsSint16LE(_field412); + s.syncAsSint16LE(_desertDirection); } -void Scene3800::Exit1::changeScene() { +void Scene3800::NorthExit::changeScene() { Scene3800 *scene = (Scene3800 *)R2_GLOBALS._sceneManager._scene; _enabled = false; - R2_GLOBALS._player.disableControl(CURSOR_ARROW); - scene->_field412 = 1; + R2_GLOBALS._player.disableControl(); + scene->_desertDirection = 1; if (R2_GLOBALS.getFlag(46)) { - if (scene->_field412 == R2_GLOBALS._v566A9) { - R2_GLOBALS._v566AA = 3; - if (R2_GLOBALS._v56A93 + 1 == 0) { - R2_GLOBALS._v566A8--; - R2_GLOBALS._v566A9 = 0; + if (scene->_desertDirection == R2_GLOBALS._desertCorrectDirection) { + R2_GLOBALS._desertPreviousDirection = 3; + if (R2_GLOBALS._desertWrongDirCtr + 1 == 0) { + R2_GLOBALS._desertStepsRemaining--; + R2_GLOBALS._desertCorrectDirection = 0; } else { - R2_GLOBALS._v566A9 = R2_GLOBALS._v566AB[R2_GLOBALS._v56A93]; - R2_GLOBALS._v56A93--; + R2_GLOBALS._desertCorrectDirection = R2_GLOBALS._desertMovements[R2_GLOBALS._desertWrongDirCtr]; + R2_GLOBALS._desertWrongDirCtr--; } } else { - ++R2_GLOBALS._v56A93; - if (R2_GLOBALS._v56A93 > 999) - R2_GLOBALS._v56A93 = 999; - R2_GLOBALS._v566AB[R2_GLOBALS._v56A93] = R2_GLOBALS._v566A9; - R2_GLOBALS._v566A9 = 3; + ++R2_GLOBALS._desertWrongDirCtr; + if (R2_GLOBALS._desertWrongDirCtr > 999) + R2_GLOBALS._desertWrongDirCtr = 999; + R2_GLOBALS._desertMovements[R2_GLOBALS._desertWrongDirCtr] = R2_GLOBALS._desertCorrectDirection; + R2_GLOBALS._desertCorrectDirection = 3; } } - if (R2_GLOBALS._v566A8 == 0) + if (R2_GLOBALS._desertStepsRemaining == 0) scene->_sceneMode = 16; else scene->_sceneMode = 11; @@ -4998,33 +5000,33 @@ void Scene3800::Exit1::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene3800::Exit2::changeScene() { +void Scene3800::EastExit::changeScene() { Scene3800 *scene = (Scene3800 *)R2_GLOBALS._sceneManager._scene; _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); - scene->_field412 = 2; + scene->_desertDirection = 2; if (R2_GLOBALS.getFlag(46)) { - if (scene->_field412 == R2_GLOBALS._v566A9) { - R2_GLOBALS._v566AA = 4; - if (R2_GLOBALS._v56A93 + 1 == 0) { - R2_GLOBALS._v566A8--; - R2_GLOBALS._v566A9 = 0; + if (scene->_desertDirection == R2_GLOBALS._desertCorrectDirection) { + R2_GLOBALS._desertPreviousDirection = 4; + if (R2_GLOBALS._desertWrongDirCtr + 1 == 0) { + R2_GLOBALS._desertStepsRemaining--; + R2_GLOBALS._desertCorrectDirection = 0; } else { - R2_GLOBALS._v566A9 = R2_GLOBALS._v566AB[R2_GLOBALS._v56A93]; - R2_GLOBALS._v56A93--; + R2_GLOBALS._desertCorrectDirection = R2_GLOBALS._desertMovements[R2_GLOBALS._desertWrongDirCtr]; + R2_GLOBALS._desertWrongDirCtr--; } } else { - ++R2_GLOBALS._v56A93; - if (R2_GLOBALS._v56A93 > 999) - R2_GLOBALS._v56A93 = 999; - R2_GLOBALS._v566AB[R2_GLOBALS._v56A93] = R2_GLOBALS._v566A9; - R2_GLOBALS._v566A9 = 4; + ++R2_GLOBALS._desertWrongDirCtr; + if (R2_GLOBALS._desertWrongDirCtr > 999) + R2_GLOBALS._desertWrongDirCtr = 999; + R2_GLOBALS._desertMovements[R2_GLOBALS._desertWrongDirCtr] = R2_GLOBALS._desertCorrectDirection; + R2_GLOBALS._desertCorrectDirection = 4; } } - if (R2_GLOBALS._v566A8 == 0) + if (R2_GLOBALS._desertStepsRemaining == 0) scene->_sceneMode = 16; else scene->_sceneMode = 12; @@ -5034,33 +5036,33 @@ void Scene3800::Exit2::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene3800::Exit3::changeScene() { +void Scene3800::SouthExit::changeScene() { Scene3800 *scene = (Scene3800 *)R2_GLOBALS._sceneManager._scene; _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); - scene->_field412 = 3; + scene->_desertDirection = 3; if (R2_GLOBALS.getFlag(46)) { - if (scene->_field412 == R2_GLOBALS._v566A9) { - R2_GLOBALS._v566AA = 1; - if (R2_GLOBALS._v56A93 + 1 == 0) { - R2_GLOBALS._v566A8--; - R2_GLOBALS._v566A9 = 0; + if (scene->_desertDirection == R2_GLOBALS._desertCorrectDirection) { + R2_GLOBALS._desertPreviousDirection = 1; + if (R2_GLOBALS._desertWrongDirCtr + 1 == 0) { + R2_GLOBALS._desertStepsRemaining--; + R2_GLOBALS._desertCorrectDirection = 0; } else { - R2_GLOBALS._v566A9 = R2_GLOBALS._v566AB[R2_GLOBALS._v56A93]; - R2_GLOBALS._v56A93--; + R2_GLOBALS._desertCorrectDirection = R2_GLOBALS._desertMovements[R2_GLOBALS._desertWrongDirCtr]; + R2_GLOBALS._desertWrongDirCtr--; } } else { - ++R2_GLOBALS._v56A93; - if (R2_GLOBALS._v56A93 > 999) - R2_GLOBALS._v56A93 = 999; - R2_GLOBALS._v566AB[R2_GLOBALS._v56A93] = R2_GLOBALS._v566A9; - R2_GLOBALS._v566A9 = 1; + ++R2_GLOBALS._desertWrongDirCtr; + if (R2_GLOBALS._desertWrongDirCtr > 999) + R2_GLOBALS._desertWrongDirCtr = 999; + R2_GLOBALS._desertMovements[R2_GLOBALS._desertWrongDirCtr] = R2_GLOBALS._desertCorrectDirection; + R2_GLOBALS._desertCorrectDirection = 1; } } - if (R2_GLOBALS._v566A8 == 0) + if (R2_GLOBALS._desertStepsRemaining == 0) scene->_sceneMode = 16; else scene->_sceneMode = 13; @@ -5070,33 +5072,33 @@ void Scene3800::Exit3::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene3800::Exit4::changeScene() { +void Scene3800::WestExit::changeScene() { Scene3800 *scene = (Scene3800 *)R2_GLOBALS._sceneManager._scene; _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); - scene->_field412 = 4; + scene->_desertDirection = 4; if (R2_GLOBALS.getFlag(46)) { - if (scene->_field412 == R2_GLOBALS._v566A9) { - R2_GLOBALS._v566AA = 2; - if (R2_GLOBALS._v56A93 + 1 == 0) { - R2_GLOBALS._v566A8--; - R2_GLOBALS._v566A9 = 0; + if (scene->_desertDirection == R2_GLOBALS._desertCorrectDirection) { + R2_GLOBALS._desertPreviousDirection = 2; + if (R2_GLOBALS._desertWrongDirCtr + 1 == 0) { + R2_GLOBALS._desertStepsRemaining--; + R2_GLOBALS._desertCorrectDirection = 0; } else { - R2_GLOBALS._v566A9 = R2_GLOBALS._v566AB[R2_GLOBALS._v56A93]; - R2_GLOBALS._v56A93--; + R2_GLOBALS._desertCorrectDirection = R2_GLOBALS._desertMovements[R2_GLOBALS._desertWrongDirCtr]; + R2_GLOBALS._desertWrongDirCtr--; } } else { - ++R2_GLOBALS._v56A93; - if (R2_GLOBALS._v56A93 > 999) - R2_GLOBALS._v56A93 = 999; - R2_GLOBALS._v566AB[R2_GLOBALS._v56A93] = R2_GLOBALS._v566A9; - R2_GLOBALS._v566A9 = 2; + ++R2_GLOBALS._desertWrongDirCtr; + if (R2_GLOBALS._desertWrongDirCtr > 999) + R2_GLOBALS._desertWrongDirCtr = 999; + R2_GLOBALS._desertMovements[R2_GLOBALS._desertWrongDirCtr] = R2_GLOBALS._desertCorrectDirection; + R2_GLOBALS._desertCorrectDirection = 2; } } - if (R2_GLOBALS._v566A8 == 0) + if (R2_GLOBALS._desertStepsRemaining == 0) scene->_sceneMode = 16; else scene->_sceneMode = 14; @@ -5106,28 +5108,28 @@ void Scene3800::Exit4::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene3800::initScene3800() { - _exit1._enabled = true; - _exit2._enabled = true; - _exit3._enabled = true; - _exit4._enabled = true; - _exit1._insideArea = false; - _exit2._insideArea = false; - _exit3._insideArea = false; - _exit4._insideArea = false; - _exit1._moving = false; - _exit2._moving = false; - _exit3._moving = false; - _exit4._moving = false; +void Scene3800::initExits() { + _northExit._enabled = true; + _eastExit._enabled = true; + _southExit._enabled = true; + _westExit._enabled = true; + _northExit._insideArea = false; + _eastExit._insideArea = false; + _southExit._insideArea = false; + _westExit._insideArea = false; + _northExit._moving = false; + _eastExit._moving = false; + _southExit._moving = false; + _westExit._moving = false; loadScene(R2_GLOBALS._v566A6); R2_GLOBALS._uiElements.draw(); } -void Scene3800::sub110BBD() { +void Scene3800::enterArea() { R2_GLOBALS._player.disableControl(); - switch (_field412) { + switch (_desertDirection) { case 0: R2_GLOBALS._player.postInit(); R2_GLOBALS._player.setVisage(10); @@ -5153,7 +5155,7 @@ void Scene3800::sub110BBD() { break; case 3900: _sceneMode = 15; - switch (R2_GLOBALS._v566AA - 1) { + switch (R2_GLOBALS._desertPreviousDirection - 1) { case 0: { R2_GLOBALS._player.setPosition(Common::Point(160, 220)); Common::Point pt(160, 160); @@ -5228,9 +5230,9 @@ void Scene3800::sub110BBD() { } void Scene3800::postInit(SceneObjectList *OwnerList) { - _field412 = 0; + _desertDirection = 0; - initScene3800(); + initExits(); SceneExt::postInit(); R2_GLOBALS._sound1.play(231); @@ -5239,19 +5241,19 @@ void Scene3800::postInit(SceneObjectList *OwnerList) { setZoomPercents(87, 40, 144, 100); - _exit1.setDetails(Rect(14, 87, 305, 125), SHADECURSOR_UP, 3800); - _exit1.setDest(Common::Point(160, 126)); - _exit2.setDetails(Rect(305, 87, 320, 128), EXITCURSOR_E, 3800); - _exit2.setDest(Common::Point(312, 145)); - _exit3.setDetails(Rect(14, 160, 305, 168), SHADECURSOR_DOWN, 3800); - _exit3.setDest(Common::Point(160, 165)); - _exit4.setDetails(Rect(0, 87, 14, 168), EXITCURSOR_W, 3800); - _exit4.setDest(Common::Point(7, 145)); + _northExit.setDetails(Rect(14, 87, 305, 125), SHADECURSOR_UP, 3800); + _northExit.setDest(Common::Point(160, 126)); + _eastExit.setDetails(Rect(305, 87, 320, 168), EXITCURSOR_E, 3800); + _eastExit.setDest(Common::Point(312, 145)); + _southExit.setDetails(Rect(14, 160, 305, 168), SHADECURSOR_DOWN, 3800); + _southExit.setDest(Common::Point(160, 165)); + _westExit.setDetails(Rect(0, 87, 14, 168), EXITCURSOR_W, 3800); + _westExit.setDest(Common::Point(7, 145)); _rect1.set(0, 0, 320, 87); - _item1.setDetails(Rect(0, 0, 320, 200), 3800, 0, 1, 2, 1, (SceneItem *) NULL); + _background.setDetails(Rect(0, 0, 320, 200), 3800, 0, 1, 2, 1, (SceneItem *) NULL); - sub110BBD(); + enterArea(); } void Scene3800::signal() { @@ -5260,33 +5262,33 @@ void Scene3800::signal() { R2_GLOBALS._v566A6 += 15; if (R2_GLOBALS._v566A6 > 3815) R2_GLOBALS._v566A6 -= 20; - initScene3800(); - sub110BBD(); + initExits(); + enterArea(); break; case 12: R2_GLOBALS._v566A6 += 5; if (R2_GLOBALS._v566A6 > 3815) R2_GLOBALS._v566A6 = 3800; - initScene3800(); - sub110BBD(); + initExits(); + enterArea(); break; case 13: R2_GLOBALS._v566A6 -= 15; if (R2_GLOBALS._v566A6 < 3800) R2_GLOBALS._v566A6 += 20; - initScene3800(); - sub110BBD(); + initExits(); + enterArea(); break; case 14: R2_GLOBALS._v566A6 -= 5; if (R2_GLOBALS._v566A6 < 3800) R2_GLOBALS._v566A6 = 3815; - initScene3800(); - sub110BBD(); + initExits(); + enterArea(); break; case 15: R2_GLOBALS._v56AAB = 0; - R2_GLOBALS._player.disableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(); break; case 16: g_globals->_sceneManager.changeScene(3900); @@ -5296,22 +5298,22 @@ void Scene3800::signal() { _object1.remove(); _object2.remove(); R2_GLOBALS._v56AAB = 0; - R2_GLOBALS._player.disableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(); break; case 3805: - _exit1._enabled = false; - _exit2._enabled = false; - _exit3._enabled = false; - _exit4._enabled = false; + _northExit._enabled = false; + _eastExit._enabled = false; + _southExit._enabled = false; + _westExit._enabled = false; R2_GLOBALS._player._canWalk = false; R2_GLOBALS._events.setCursor(CURSOR_USE); break; case 3806: - _exit1._enabled = true; - _exit2._enabled = true; - _exit3._enabled = true; - _exit4._enabled = true; - R2_GLOBALS._player.disableControl(CURSOR_ARROW); + _northExit._enabled = true; + _eastExit._enabled = true; + _southExit._enabled = true; + _westExit._enabled = true; + R2_GLOBALS._player.enableControl(); break; default: break; @@ -5345,14 +5347,15 @@ void Scene3800::process(Event &event) { * Scene 3900 - * *--------------------------------------------------------------------------*/ -void Scene3900::Exit1::changeScene() { + +void Scene3900::NorthExit::changeScene() { Scene3900 *scene = (Scene3900 *)R2_GLOBALS._sceneManager._scene; _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); - R2_GLOBALS._v566A9 = 3; - R2_GLOBALS._v566AA = 1; - R2_GLOBALS._v566A8 = 1; + R2_GLOBALS._desertCorrectDirection = 3; + R2_GLOBALS._desertPreviousDirection = 1; + R2_GLOBALS._desertStepsRemaining = 1; scene->_sceneMode = 14; Common::Point pt(160, 115); @@ -5360,14 +5363,14 @@ void Scene3900::Exit1::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene3900::Exit2::changeScene() { +void Scene3900::EastExit::changeScene() { Scene3900 *scene = (Scene3900 *)R2_GLOBALS._sceneManager._scene; _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); - R2_GLOBALS._v566A9 = 4; - R2_GLOBALS._v566AA = 2; - R2_GLOBALS._v566A8 = 1; + R2_GLOBALS._desertCorrectDirection = 4; + R2_GLOBALS._desertPreviousDirection = 2; + R2_GLOBALS._desertStepsRemaining = 1; scene->_sceneMode = 14; Common::Point pt(330, 145); @@ -5375,14 +5378,14 @@ void Scene3900::Exit2::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene3900::Exit3::changeScene() { +void Scene3900::SouthExit::changeScene() { Scene3900 *scene = (Scene3900 *)R2_GLOBALS._sceneManager._scene; _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); - R2_GLOBALS._v566A9 = 1; - R2_GLOBALS._v566AA = 3; - R2_GLOBALS._v566A8 = 1; + R2_GLOBALS._desertCorrectDirection = 1; + R2_GLOBALS._desertPreviousDirection = 3; + R2_GLOBALS._desertStepsRemaining = 1; scene->_sceneMode = 14; Common::Point pt(160, 220); @@ -5390,14 +5393,14 @@ void Scene3900::Exit3::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene3900::Exit4::changeScene() { +void Scene3900::WestExit::changeScene() { Scene3900 *scene = (Scene3900 *)R2_GLOBALS._sceneManager._scene; _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); - R2_GLOBALS._v566A9 = 2; - R2_GLOBALS._v566AA = 4; - R2_GLOBALS._v566A8 = 1; + R2_GLOBALS._desertCorrectDirection = 2; + R2_GLOBALS._desertPreviousDirection = 4; + R2_GLOBALS._desertStepsRemaining = 1; scene->_sceneMode = 14; Common::Point pt(-10, 145); @@ -5412,7 +5415,7 @@ void Scene3900::Exit5::changeScene() { R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 13; - if (R2_GLOBALS._v566A9 == 4) { + if (R2_GLOBALS._desertCorrectDirection == 4) { Common::Point pt(-10, 135); NpcMover *mover = new NpcMover(); R2_GLOBALS._player.addMover(mover, &pt, scene); @@ -5422,17 +5425,20 @@ void Scene3900::Exit5::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } - R2_GLOBALS._v566A9 = 0; + R2_GLOBALS._desertCorrectDirection = 0; } void Scene3900::postInit(SceneObjectList *OwnerList) { - if ((R2_GLOBALS._v566AA == 2) && (R2_GLOBALS._sceneManager._previousScene != 2700)) + if ((R2_GLOBALS._desertPreviousDirection == 2) + && (R2_GLOBALS._sceneManager._previousScene != 2700)) loadScene(3825); else loadScene(3820); SceneExt::postInit(); + R2_GLOBALS._sound1.changeSound(231); setZoomPercents(87, 40, 144, 100); + R2_GLOBALS._player.disableControl(); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.setVisage(10); @@ -5440,6 +5446,7 @@ void Scene3900::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setStrip(3); R2_GLOBALS._player.changeZoom(-1); R2_GLOBALS._player._moveDiff = Common::Point(3, 2); + _actor1.postInit(); _actor1.fixPriority(10); _actor1.changeZoom(-1); @@ -5447,36 +5454,36 @@ void Scene3900::postInit(SceneObjectList *OwnerList) { _actor1._effect = 5; _actor1._field9C = _field312; R2_GLOBALS._player._linkedActor = &_actor1; - if ((R2_GLOBALS._v566AA == 2) && (R2_GLOBALS._sceneManager._previousScene != 2700)) { + + if ((R2_GLOBALS._desertPreviousDirection == 2) && (R2_GLOBALS._sceneManager._previousScene != 2700)) { // loadScene(3825); - R2_GLOBALS._v566AA = 4; - _exit1.setDetails(Rect(29, 87, 305, 125), SHADECURSOR_UP, 3900); - _exit3.setDetails(Rect(29, 160, 305, 168), SHADECURSOR_DOWN, 3900); + R2_GLOBALS._desertCorrectDirection = 4; + _northExit.setDetails(Rect(29, 87, 305, 125), SHADECURSOR_UP, 3900); + _southExit.setDetails(Rect(29, 160, 305, 168), SHADECURSOR_DOWN, 3900); - _exit2.setDetails(Rect(305, 87, 320, 168), EXITCURSOR_E, 3900); - _exit2.setDest(Common::Point(312, 145)); - _exit2._enabled = true; - _exit2._insideArea = false; - _exit2._moving = false; + _eastExit.setDetails(Rect(305, 87, 320, 168), EXITCURSOR_E, 3900); + _eastExit.setDest(Common::Point(312, 145)); + _eastExit._enabled = true; + _eastExit._insideArea = false; + _eastExit._moving = false; - _exit4._enabled = false; + _westExit._enabled = false; _exit5.setDetails(Rect(0, 87, 29, 168), EXITCURSOR_W, 3900); _exit5.setDest(Common::Point(24, 135)); } else { // loadScene(3820); - R2_GLOBALS._v566AA = 2; - _exit1.setDetails(Rect(14, 87, 290, 125), SHADECURSOR_UP, 3900); - _exit3.setDetails(Rect(14, 160, 290, 168), SHADECURSOR_DOWN, 3900); - + R2_GLOBALS._desertCorrectDirection = 2; + _northExit.setDetails(Rect(14, 87, 290, 125), SHADECURSOR_UP, 3900); + _southExit.setDetails(Rect(14, 160, 290, 168), SHADECURSOR_DOWN, 3900); - _exit2._enabled = false; + _eastExit._enabled = false; - _exit4.setDetails(Rect(0, 87, 14, 168), EXITCURSOR_W, 3900); - _exit4.setDest(Common::Point(7, 145)); - _exit4._enabled = true; - _exit4._insideArea = false; - _exit4._moving = false; + _westExit.setDetails(Rect(0, 87, 14, 168), EXITCURSOR_W, 3900); + _westExit.setDest(Common::Point(7, 145)); + _westExit._enabled = true; + _westExit._insideArea = false; + _westExit._moving = false; _exit5.setDetails(Rect(290, 87, 320, 168), EXITCURSOR_E, 3900); _exit5.setDest(Common::Point(295, 135)); @@ -5487,15 +5494,15 @@ void Scene3900::postInit(SceneObjectList *OwnerList) { scalePalette(65, 65, 65); - _exit1.setDest(Common::Point(160, 126)); - _exit1._enabled = true; - _exit1._insideArea = false; - _exit1._moving = false; + _northExit.setDest(Common::Point(160, 126)); + _northExit._enabled = true; + _northExit._insideArea = false; + _northExit._moving = false; - _exit3.setDest(Common::Point(160, 165)); - _exit3._enabled = true; - _exit3._insideArea = false; - _exit3._moving = false; + _southExit.setDest(Common::Point(160, 165)); + _southExit._enabled = true; + _southExit._insideArea = false; + _southExit._moving = false; R2_GLOBALS._uiElements.draw(); @@ -5503,29 +5510,33 @@ void Scene3900::postInit(SceneObjectList *OwnerList) { _item1.setDetails(Rect(0, 0, 320, 200), 3800, 0, 1, 2, 1, (SceneItem *)NULL); if (R2_GLOBALS._sceneManager._previousScene == 3800) { _sceneMode = 11; - switch (R2_GLOBALS._v566AA - 1) { - case 0: { + switch (R2_GLOBALS._desertPreviousDirection) { + case 1: { + // Entering from the north R2_GLOBALS._player.setPosition(Common::Point(160, 115)); Common::Point pt(160, 120); NpcMover *mover = new NpcMover(); R2_GLOBALS._player.addMover(mover, &pt, this); } break; - case 1: { + case 2: { + // Entering from the east R2_GLOBALS._player.setPosition(Common::Point(330, 145)); Common::Point pt(300, 145); NpcMover *mover = new NpcMover(); R2_GLOBALS._player.addMover(mover, &pt, this); } break; - case 2: { + case 3: { + // Entering from the south R2_GLOBALS._player.setPosition(Common::Point(160, 220)); Common::Point pt(160, 160); NpcMover *mover = new NpcMover(); R2_GLOBALS._player.addMover(mover, &pt, this); } break; - case 3: { + case 4: { + // Entering from the west R2_GLOBALS._player.setPosition(Common::Point(-10, 145)); Common::Point pt(19, 145); NpcMover *mover = new NpcMover(); @@ -5553,7 +5564,7 @@ void Scene3900::signal() { // No break on purpose case 12: R2_GLOBALS._v56AAB = 0; - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); break; case 13: R2_GLOBALS._sceneManager.changeScene(2700); @@ -5562,18 +5573,18 @@ void Scene3900::signal() { R2_GLOBALS._sceneManager.changeScene(3800); break; case 3805: - _exit1._enabled = false; - _exit2._enabled = false; - _exit3._enabled = false; - _exit4._enabled = false; + _northExit._enabled = false; + _eastExit._enabled = false; + _southExit._enabled = false; + _westExit._enabled = false; R2_GLOBALS._player._canWalk = false; - R2_GLOBALS._events.setCursor(R2_STEPPING_DISKS); + R2_GLOBALS._events.setCursor(CURSOR_USE); break; case 3806: - _exit1._enabled = true; - _exit2._enabled = true; - _exit3._enabled = true; - _exit4._enabled = true; + _northExit._enabled = true; + _eastExit._enabled = true; + _southExit._enabled = true; + _westExit._enabled = true; R2_GLOBALS._player.enableControl(CURSOR_ARROW); break; default: diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.h b/engines/tsage/ringworld2/ringworld2_scenes3.h index 85e5674433..14600ff6df 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.h +++ b/engines/tsage/ringworld2/ringworld2_scenes3.h @@ -778,22 +778,22 @@ public: }; class Scene3800 : public SceneExt { - class Exit1 : public SceneExit { + class NorthExit : public SceneExit { public: virtual void changeScene(); }; - class Exit2 : public SceneExit { + class EastExit : public SceneExit { public: virtual void changeScene(); }; - class Exit3 : public SceneExit { + class SouthExit : public SceneExit { public: virtual void changeScene(); }; - class Exit4 : public SceneExit { + class WestExit : public SceneExit { public: virtual void changeScene(); }; @@ -802,19 +802,19 @@ public: SceneObject _object1; SceneObject _object2; SceneActor _actor1; - NamedHotspot _item1; - Exit1 _exit1; - Exit2 _exit2; - Exit3 _exit3; - Exit4 _exit4; + NamedHotspot _background; + NorthExit _northExit; + EastExit _eastExit; + SouthExit _southExit; + WestExit _westExit; Rect _rect1; SequenceManager _sequenceManager1; - int _field412; + int _desertDirection; Scene3800(); - void initScene3800(); - void sub110BBD(); + void initExits(); + void enterArea(); virtual void postInit(SceneObjectList *OwnerList = NULL); virtual void signal(); @@ -823,22 +823,22 @@ public: }; class Scene3900 : public SceneExt { - class Exit1 : public SceneExit { + class NorthExit : public SceneExit { public: virtual void changeScene(); }; - class Exit2 : public SceneExit { + class EastExit : public SceneExit { public: virtual void changeScene(); }; - class Exit3 : public SceneExit { + class SouthExit : public SceneExit { public: virtual void changeScene(); }; - class Exit4 : public SceneExit { + class WestExit : public SceneExit { public: virtual void changeScene(); }; @@ -850,10 +850,10 @@ class Scene3900 : public SceneExt { public: SceneActor _actor1; NamedHotspot _item1; - Exit1 _exit1; - Exit2 _exit2; - Exit3 _exit3; - Exit4 _exit4; + NorthExit _northExit; + EastExit _eastExit; + SouthExit _southExit; + WestExit _westExit; Exit5 _exit5; Rect _rect1; diff --git a/engines/tsage/ringworld2/ringworld2_speakers.cpp b/engines/tsage/ringworld2/ringworld2_speakers.cpp index e7109829b0..e908fb4412 100644 --- a/engines/tsage/ringworld2/ringworld2_speakers.cpp +++ b/engines/tsage/ringworld2/ringworld2_speakers.cpp @@ -1041,7 +1041,7 @@ void SpeakerPharisha2435::proc15() { Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { - _object2 = &scene->_actor2; + _object2 = &scene->_astor; _object2->hide(); _object1.postInit(); _object1.setPosition(_object2->_position); @@ -1323,7 +1323,7 @@ void SpeakerQuinn2435::proc15() { } else { assert(R2_GLOBALS._sceneManager._sceneNumber == 2435); Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; - _object2 = &scene->_actor1; + _object2 = &scene->_companion; } _object2->hide(); @@ -1350,7 +1350,7 @@ void SpeakerQuinn2450::proc15() { } else { assert(R2_GLOBALS._sceneManager._sceneNumber == 2435); Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; - _object2 = &scene->_actor1; + _object2 = &scene->_companion; } _object2->hide(); @@ -2165,7 +2165,7 @@ void SpeakerSeeker2435::proc15() { } else { assert(R2_GLOBALS._sceneManager._sceneNumber == 2435); Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; - _object2 = &scene->_actor1; + _object2 = &scene->_companion; } _object2->hide(); @@ -2192,7 +2192,7 @@ void SpeakerSeeker2450::proc15() { } else { assert(R2_GLOBALS._sceneManager._sceneNumber == 2450); Scene2450 *scene = (Scene2450 *)R2_GLOBALS._sceneManager._scene; - _object2 = &scene->_actor1; + _object2 = &scene->_companion; } _object2->hide(); @@ -2666,7 +2666,7 @@ void SpeakerTeal1625::proc15() { if (!_object2) { Scene1625 *scene = (Scene1625 *)R2_GLOBALS._sceneManager._scene; - _object2 = &scene->_actor2; + _object2 = &scene->_tealHead; _object2->hide(); _object1.postInit(); diff --git a/engines/tsage/staticres.cpp b/engines/tsage/staticres.cpp index db38862365..2c5e8e57a0 100644 --- a/engines/tsage/staticres.cpp +++ b/engines/tsage/staticres.cpp @@ -162,7 +162,7 @@ char const *const BIKINI_HUT = "Bikini Hut"; char const *const RADIO_BTN_LIST[8] = { "10-2 ", "10-4 ", "10-13", "10-15", "10-27", "10-35", "10-97", "10-98" }; // Scene 570 computer messageS -char const *const SCENE570_PASSWORD = "PASSWORD -> "; +char const *const SCENE570_PASSWORD = "PASSWORD - }, "; char const *const SCENE570_C_DRIVE = "C:\\"; char const *const SCENE570_RING = "RING"; char const *const SCENE570_PROTO = "PROTO"; @@ -448,6 +448,201 @@ const byte k5A7F6[] = { 15, 10, 11 }; +const BalloonRecord balloonData[] = { + { 0, -2, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 0, 1 }, + { 0, 0, 1 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 0, 2, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 0, 0, -1 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 2, 0, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, 0, -1 }, + { 0, 0, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, 0, 0 }, + { 0, 0, -1 }, + { -2, 0, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { 0, 2, 0 }, + { 2, 0, 0 }, + { 0, 0, -1 }, + { -2, 0, 0 }, + { 0, 0, -1 }, + { -2, 0, 0 }, + { 0, 0, -1 }, + { 2, 0, 0 }, + { 0, 0, -1 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 2, 0, 0 }, + { 0, 2, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 0, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 0, 1 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, 0, 1 }, + { -2, 0, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { -2, 0, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { 0, 2, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 2, 0, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { -2, 0, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { 0, 0, -1 }, + { 0, 2, 0 }, + { -2, 0, 0 }, + { 0, -2, 0 }, + { 0, -2, 0 }, + { 0, 0, -1 }, + { -2, 0, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { -2, 0, 0 }, + { 0, -2, 0 }, + { 2, 0, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { 0, 0, 0 }, + { 2, 0, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { -2, 0, 0 }, + { 0, -2, 0 }, + { 0, 2, 0 }, + { -2, 0, 0 } +}; + } // End of namespace Ringworld2 } // End of namespace TsAGE diff --git a/engines/tsage/staticres.h b/engines/tsage/staticres.h index 8c21147191..b6c5d5e72a 100644 --- a/engines/tsage/staticres.h +++ b/engines/tsage/staticres.h @@ -209,6 +209,14 @@ extern const byte scene1550JunkRegions[]; extern const byte k5A79B[]; extern const byte k5A7F6[]; +// Scene 2900 balloon data +struct BalloonRecord { + int8 x; + int8 y; + int8 v3; +}; +extern const BalloonRecord balloonData[]; + } // End of namespace Ringworld2 } // End of namespace TsAGE diff --git a/engines/wintermute/base/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp index 2e2726f361..e5542d96b7 100644 --- a/engines/wintermute/base/base_persistence_manager.cpp +++ b/engines/wintermute/base/base_persistence_manager.cpp @@ -465,44 +465,53 @@ uint32 BasePersistenceManager::getDWORD() { ////////////////////////////////////////////////////////////////////////// -void BasePersistenceManager::putString(const Common::String &val) { - if (!val.size()) { - putString("(null)"); - } else { - _saveStream->writeUint32LE(val.size()); - _saveStream->writeString(val); +void BasePersistenceManager::putString(const char *val) { + if (!val) { + _saveStream->writeUint32LE(0); + return; } -} - -Common::String BasePersistenceManager::getStringObj() { - uint32 len = _loadStream->readUint32LE(); - char *ret = new char[len + 1]; - _loadStream->read(ret, len); - ret[len] = '\0'; - Common::String retString = ret; - delete[] ret; + uint32 len = strlen(val); - if (retString == "(null)") { - retString = ""; - } + _saveStream->writeUint32LE(len + 1); + _saveStream->write(val, len); +} - return retString; +Common::String BasePersistenceManager::getStringObj() { + return getString(); } ////////////////////////////////////////////////////////////////////////// char *BasePersistenceManager::getString() { uint32 len = _loadStream->readUint32LE(); - char *ret = new char[len + 1]; - _loadStream->read(ret, len); - ret[len] = '\0'; - if (!strcmp(ret, "(null)")) { - delete[] ret; - return nullptr; + if (checkVersion(1,2,2)) { + // Version 1.2.2 and above: len == strlen() + 1, NULL has len == 0 + + if (len == 0) + return nullptr; + + char *ret = new char[len]; + _loadStream->read(ret, len - 1); + ret[len - 1] = '\0'; + + return ret; + } else { + + // Version 1.2.1 and older: NULL strings are represented as "(null)" + char *ret = new char[len + 1]; + _loadStream->read(ret, len); + ret[len] = '\0'; + + if (!strcmp(ret, "(null)")) { + delete[] ret; + return nullptr; + } + return ret; } + } bool BasePersistenceManager::putTimeDate(const TimeDate &t) { @@ -536,8 +545,7 @@ void BasePersistenceManager::putFloat(float val) { int exponent = 0; float significand = frexp(val, &exponent); Common::String str = Common::String::format("FS%f", significand); - _saveStream->writeUint32LE(str.size()); - _saveStream->writeString(str); + putString(str.c_str()); _saveStream->writeSint32LE(exponent); } @@ -559,8 +567,7 @@ void BasePersistenceManager::putDouble(double val) { int exponent = 0; double significand = frexp(val, &exponent); Common::String str = Common::String::format("DS%f", significand); - _saveStream->writeUint32LE(str.size()); - _saveStream->writeString(str); + putString(str.c_str()); _saveStream->writeSint32LE(exponent); } @@ -711,7 +718,7 @@ bool BasePersistenceManager::transfer(const char *name, const char **val) { // Common::String bool BasePersistenceManager::transfer(const char *name, Common::String *val) { if (_saving) { - putString(*val); + putString(val->c_str()); return STATUS_OK; } else { char *str = getString(); diff --git a/engines/wintermute/base/base_persistence_manager.h b/engines/wintermute/base/base_persistence_manager.h index c09b3345b7..3c0587b362 100644 --- a/engines/wintermute/base/base_persistence_manager.h +++ b/engines/wintermute/base/base_persistence_manager.h @@ -52,7 +52,7 @@ public: void putDWORD(uint32 val); char *getString(); Common::String getStringObj(); - void putString(const Common::String &val); + void putString(const char *val); float getFloat(); void putFloat(float val); double getDouble(); diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp index e073f27970..b6f372f377 100644 --- a/engines/wintermute/base/font/base_font_truetype.cpp +++ b/engines/wintermute/base/font/base_font_truetype.cpp @@ -559,7 +559,7 @@ bool BaseFontTT::initFont() { } if (file) { - _deletableFont = Graphics::loadTTFFont(*file, 96, _fontHeight); // Use the same dpi as WME (96 vs 72). + _deletableFont = Graphics::loadTTFFont(*file, _fontHeight, 96); // Use the same dpi as WME (96 vs 72). _font = _deletableFont; BaseFileManager::getEngineInstance()->closeFile(file); file = nullptr; diff --git a/engines/wintermute/base/gfx/base_renderer.h b/engines/wintermute/base/gfx/base_renderer.h index 31dc2a022d..b6615bc8fc 100644 --- a/engines/wintermute/base/gfx/base_renderer.h +++ b/engines/wintermute/base/gfx/base_renderer.h @@ -84,7 +84,7 @@ public: * @param a the alpha component to fade too. * @param rect the portion of the screen to fade (if nullptr, the entire screen will be faded). */ - virtual void fadeToColor(byte r, byte g, byte b, byte a, Common::Rect *rect = nullptr) = 0; + virtual void fadeToColor(byte r, byte g, byte b, byte a) = 0; virtual bool drawLine(int x1, int y1, int x2, int y2, uint32 color); // Unused outside indicator-display virtual bool drawRect(int x1, int y1, int x2, int y2, uint32 color, int width = 1); // Unused outside indicator-display diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp index e6d769c653..e4c19fde8b 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp @@ -243,22 +243,16 @@ void BaseRenderOSystem::fade(uint16 alpha) { } ////////////////////////////////////////////////////////////////////////// -void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a, Common::Rect *rect) { +void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a) { Common::Rect fillRect; - if (rect) { - fillRect.left = rect->left; - fillRect.top = rect->top; - fillRect.setWidth(rect->width()); - fillRect.setHeight(rect->height()); - } else { - Rect32 rc; - _gameRef->getCurrentViewportRect(&rc); - fillRect.left = (int16)rc.left; - fillRect.top = (int16)rc.top; - fillRect.setWidth((int16)(rc.right - rc.left)); - fillRect.setHeight((int16)(rc.bottom - rc.top)); - } + Rect32 rc; + _gameRef->getCurrentViewportRect(&rc); + fillRect.left = (int16)rc.left; + fillRect.top = (int16)rc.top; + fillRect.setWidth((int16)(rc.right - rc.left)); + fillRect.setHeight((int16)(rc.bottom - rc.top)); + modTargetRect(&fillRect); //TODO: This is only here until I'm sure about the final pixelformat diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h index 928a52d4fc..306563af3b 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h @@ -70,7 +70,7 @@ public: bool fill(byte r, byte g, byte b, Common::Rect *rect = nullptr) override; Graphics::PixelFormat getPixelFormat() const override; void fade(uint16 alpha) override; - void fadeToColor(byte r, byte g, byte b, byte a, Common::Rect *rect = nullptr) override; + void fadeToColor(byte r, byte g, byte b, byte a) override; bool drawLine(int x1, int y1, int x2, int y2, uint32 color) override; diff --git a/engines/wintermute/base/scriptables/script_engine.cpp b/engines/wintermute/base/scriptables/script_engine.cpp index dd24457d6c..bb819b23e4 100644 --- a/engines/wintermute/base/scriptables/script_engine.cpp +++ b/engines/wintermute/base/scriptables/script_engine.cpp @@ -362,6 +362,8 @@ bool ScEngine::tick() { ////////////////////////////////////////////////////////////////////////// bool ScEngine::tickUnbreakable() { + ScScript *oldScript = _currentScript; + // execute unbreakable scripts for (uint32 i = 0; i < _scripts.size(); i++) { if (!_scripts[i]->_unbreakable) { @@ -373,9 +375,12 @@ bool ScEngine::tickUnbreakable() { _scripts[i]->executeInstruction(); } _scripts[i]->finish(); - _currentScript = nullptr; + _currentScript = oldScript; } - removeFinishedScripts(); + + // NB: Don't remove finished scripts here since we could be recursively + // executing scripts. Doing so could invalidate the outer iteration in + // ::tick() over _scripts. return STATUS_OK; } diff --git a/engines/wintermute/base/scriptables/script_value.cpp b/engines/wintermute/base/scriptables/script_value.cpp index 3532e127d0..31ec457df1 100644 --- a/engines/wintermute/base/scriptables/script_value.cpp +++ b/engines/wintermute/base/scriptables/script_value.cpp @@ -827,6 +827,17 @@ bool ScValue::persist(BasePersistenceManager *persistMgr) { persistMgr->transferPtr(TMEMBER_PTR(_valRef)); persistMgr->transfer(TMEMBER(_valString)); + if (!persistMgr->getIsSaving() && !persistMgr->checkVersion(1,2,2)) { + // Savegames prior to 1.2.2 stored empty strings as NULL. + // We disambiguate those by turning NULL strings into empty + // strings if _type is VAL_STRING instead of VAL_NULL. + + if (_type == VAL_STRING && !_valString) { + _valString = new char[1]; + _valString[0] = '\0'; + } + } + /* // TODO: Convert to Debug-statements. FILE* f = fopen("c:\\val.log", "a+"); switch(_type) diff --git a/engines/wintermute/dcgf.h b/engines/wintermute/dcgf.h index fe92194443..3db443965e 100644 --- a/engines/wintermute/dcgf.h +++ b/engines/wintermute/dcgf.h @@ -33,7 +33,7 @@ ////////////////////////////////////////////////////////////////////////// #define DCGF_VER_MAJOR 1 #define DCGF_VER_MINOR 2 -#define DCGF_VER_BUILD 1 +#define DCGF_VER_BUILD 2 #define DCGF_VER_SUFFIX "ScummVM" #define DCGF_VER_BETA true |