aboutsummaryrefslogtreecommitdiff
path: root/engines/illusions/duckman
diff options
context:
space:
mode:
authorjohndoe1232015-11-24 00:10:10 +0100
committerEugene Sandulenko2018-07-20 06:43:33 +0000
commitfa17f684da1da7fded805746b75c454502ffe683 (patch)
tree1e668515abccf6455299a5b9fbadc2c5b6affd98 /engines/illusions/duckman
parent09bbb482a8ccdfb8e36128d40364900b99aa2a13 (diff)
downloadscummvm-rg350-fa17f684da1da7fded805746b75c454502ffe683.tar.gz
scummvm-rg350-fa17f684da1da7fded805746b75c454502ffe683.tar.bz2
scummvm-rg350-fa17f684da1da7fded805746b75c454502ffe683.zip
ILLUSIONS: DUCKMAN: Start implementing the menu system
Still work-in-progress, missing functionality and buggy Maybe needs some work for BBDOU where this isn't implemented yet.
Diffstat (limited to 'engines/illusions/duckman')
-rw-r--r--engines/illusions/duckman/illusions_duckman.cpp14
-rw-r--r--engines/illusions/duckman/illusions_duckman.h2
-rw-r--r--engines/illusions/duckman/menusystem_duckman.cpp179
-rw-r--r--engines/illusions/duckman/menusystem_duckman.h70
-rw-r--r--engines/illusions/duckman/scriptopcodes_duckman.cpp60
-rw-r--r--engines/illusions/duckman/scriptopcodes_duckman.h6
6 files changed, 311 insertions, 20 deletions
diff --git a/engines/illusions/duckman/illusions_duckman.cpp b/engines/illusions/duckman/illusions_duckman.cpp
index 7255327eaa..db8f83c295 100644
--- a/engines/illusions/duckman/illusions_duckman.cpp
+++ b/engines/illusions/duckman/illusions_duckman.cpp
@@ -23,6 +23,7 @@
#include "illusions/duckman/illusions_duckman.h"
#include "illusions/duckman/duckman_dialog.h"
#include "illusions/duckman/duckman_specialcode.h"
+#include "illusions/duckman/menusystem_duckman.h"
#include "illusions/duckman/scriptopcodes_duckman.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
@@ -110,6 +111,7 @@ Common::Error IllusionsEngine_Duckman::run() {
_threads = new ThreadList(this);
_updateFunctions = new UpdateFunctions();
_soundMan = new SoundMan(this);
+ _menuSystem = new DuckmanMenuSystem(this);
_fader = new Fader();
@@ -180,6 +182,7 @@ Common::Error IllusionsEngine_Duckman::run() {
delete _fader;
+ delete _menuSystem;
delete _soundMan;
delete _updateFunctions;
delete _threads;
@@ -231,8 +234,10 @@ void IllusionsEngine_Duckman::initInput() {
_input->setInputEvent(kEventDown, 0x80)
.addMouseButton(MOUSE_RIGHT_BUTTON)
.addKey(Common::KEYCODE_DOWN);
+ /* Not implemented, used for original debugging purposes
_input->setInputEvent(kEventF1, 0x100)
.addKey(Common::KEYCODE_F1);
+ */
}
#define UPDATEFUNCTION(priority, sceneId, callback) \
@@ -256,8 +261,13 @@ int IllusionsEngine_Duckman::updateScript(uint flags) {
if (_screen->isDisplayOn() && !_screen->isFaderActive() && _pauseCtr == 0) {
if (_input->pollEvent(kEventAbort)) {
startScriptThread(0x00020342, 0);
+ //testMenu(this);//TODO DEBUG
+
+ //BaseMenu *me = _menuSystem->getMenuById(kDuckmanPauseMenu);
+ //_menuSystem->openMenu(me);
+ //_menuSystem->runMenu(0x180002);
+
} else if (_input->pollEvent(kEventF1)) {
- debug("F1");
startScriptThread(0x0002033F, 0);
}
}
@@ -632,7 +642,7 @@ void IllusionsEngine_Duckman::cursorControlRoutine(Control *control, uint32 delt
_dialogSys->updateDialogState();
break;
case 4:
- // TODO ShellMgr_update(_cursor._control);
+ _menuSystem->update(_cursor._control);
break;
}
}
diff --git a/engines/illusions/duckman/illusions_duckman.h b/engines/illusions/duckman/illusions_duckman.h
index 39c421dae9..e2b3223efc 100644
--- a/engines/illusions/duckman/illusions_duckman.h
+++ b/engines/illusions/duckman/illusions_duckman.h
@@ -32,6 +32,7 @@ namespace Illusions {
class Dictionary;
class ScriptStack;
class DuckmanDialogSystem;
+class DuckmanMenuSystem;
struct Cursor_Duckman {
int _gameState;
@@ -99,6 +100,7 @@ public:
int _savedInventoryActorIndex;
ScreenShaker *_screenShaker;
+ DuckmanMenuSystem *_menuSystem;
void initInput();
diff --git a/engines/illusions/duckman/menusystem_duckman.cpp b/engines/illusions/duckman/menusystem_duckman.cpp
new file mode 100644
index 0000000000..96d350ab4b
--- /dev/null
+++ b/engines/illusions/duckman/menusystem_duckman.cpp
@@ -0,0 +1,179 @@
+/* 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 "illusions/illusions.h"
+#include "illusions/actor.h"
+#include "illusions/duckman/illusions_duckman.h"
+#include "illusions/duckman/menusystem_duckman.h"
+
+namespace Illusions {
+
+// DuckmanMenuSystem
+
+DuckmanMenuSystem::DuckmanMenuSystem(IllusionsEngine_Duckman *vm)
+ : BaseMenuSystem(vm), _vm(vm) {
+ clearMenus();
+}
+
+DuckmanMenuSystem::~DuckmanMenuSystem() {
+ freeMenus();
+}
+
+void DuckmanMenuSystem::runMenu(MenuChoiceOffsets menuChoiceOffsets, int16 *menuChoiceOffset,
+ uint32 menuId, uint32 duration, uint timeOutMenuChoiceIndex, uint32 menuCallerThreadId) {
+
+ setTimeOutDuration(duration, timeOutMenuChoiceIndex);
+ setMenuCallerThreadId(menuCallerThreadId);
+ setMenuChoiceOffsets(menuChoiceOffsets, menuChoiceOffset);
+
+ int rootMenuId = convertRootMenuId(menuId | 0x180000);
+ BaseMenu *rootMenu = getMenuById(rootMenuId);
+ openMenu(rootMenu);
+
+}
+
+void DuckmanMenuSystem::clearMenus() {
+ for (int i = 0; i < kDuckmanLastMenuIndex; ++i)
+ _menus[i] = 0;
+}
+
+void DuckmanMenuSystem::freeMenus() {
+ for (int i = 0; i < kDuckmanLastMenuIndex; ++i)
+ delete _menus[i];
+}
+
+BaseMenu *DuckmanMenuSystem::getMenuById(int menuId) {
+ if (!_menus[menuId])
+ _menus[menuId] = createMenuById(menuId);
+ return _menus[menuId];
+}
+
+BaseMenu *DuckmanMenuSystem::createMenuById(int menuId) {
+ switch (menuId) {
+ case kDuckmanMainMenu:
+ return createMainMenu();
+ case kDuckmanPauseMenu:
+ return createPauseMenu();
+ case kDuckmanQueryRestartMenu:
+ return createQueryRestartMenu();
+ case kDuckmanQueryQuitMenu:
+ return createQueryQuitMenu();
+ default:
+ error("DuckmanMenuSystem::createMenuById() Invalid menu id %d", menuId);
+ }
+}
+
+BaseMenu *DuckmanMenuSystem::createMainMenu() {
+ BaseMenu *menu = new BaseMenu(this, 0x00120003, 12, 17, 11, 27, 0);
+ menu->addMenuItem(new MenuItem("Start New Game", new MenuActionReturnChoice(this, 11)));
+
+ menu->addMenuItem(new MenuItem("Load Saved Game", new MenuActionReturnChoice(this, 0)));
+ menu->addMenuItem(new MenuItem("Options", new MenuActionReturnChoice(this, 0)));
+
+ // TODO menu->addMenuItem(new MenuItem("Load Saved Game", new MenuActionEnterMenu(this, kDuckmanLoadGameMenu)));
+ // TODO menu->addMenuItem(new MenuItem("Options", new MenuActionEnterMenu(this, kDuckmanOptionsMenu)));
+ menu->addMenuItem(new MenuItem("Quit Game", new MenuActionEnterQueryMenu(this, kDuckmanQueryQuitMenu, 12)));
+ return menu;
+}
+
+BaseMenu *DuckmanMenuSystem::createLoadGameMenu() {
+ return 0; // TODO
+}
+
+BaseMenu *DuckmanMenuSystem::createOptionsMenu() {
+ return 0; // TODO
+}
+
+BaseMenu *DuckmanMenuSystem::createPauseMenu() {
+ BaseMenu *menu = new BaseMenu(this, 0x00120003, 12, 17, 11, 27, 1);
+ menu->addText(" Game Paused");
+ menu->addText("-------------------");
+ menu->addMenuItem(new MenuItem("Resume", new MenuActionReturnChoice(this, 1)));
+ //menu->addMenuItem(new MenuItem("Restart Game", new MenuActionEnterQueryMenu(this, kDuckmanQueryRestartMenu, 2)));
+ // TODO menu->addMenuItem(new MenuItem("Options", new MenuActionEnterMenu(this, kDuckmanOptionsMenu)));
+ menu->addMenuItem(new MenuItem("Quit Game", new MenuActionEnterQueryMenu(this, kDuckmanQueryQuitMenu, 3)));
+ return menu;
+}
+
+BaseMenu *DuckmanMenuSystem::createQueryRestartMenu() {
+ return 0; // TODO
+}
+
+BaseMenu *DuckmanMenuSystem::createQueryQuitMenu() {
+ BaseMenu *menu = new BaseMenu(this, 0x00120003, 12, 17, 11, 27, 2);
+ menu->addText("Do you really want to quit?");
+ menu->addText("-------------------------------");
+ menu->addMenuItem(new MenuItem("Yes, I'm outta here", new MenuActionReturnChoice(this, getQueryConfirmationChoiceIndex())));
+ menu->addMenuItem(new MenuItem("No, just kidding", new MenuActionLeaveMenu(this)));
+ return menu;
+}
+
+int DuckmanMenuSystem::convertRootMenuId(uint32 menuId) {
+ switch (menuId) {
+ case 0x180001:
+ return kDuckmanMainMenu;
+ case 0x180002:
+ return kDuckmanPauseMenu;
+ /* Debug menus, not implemented
+ case 0x180005:
+ case 0x180006:
+ case 0x180007:
+ */
+ /* TODO CHECKME Another pause menu?
+ case 0x180008:
+ menuData = &g_menuDataPause;
+ */
+ default:
+ error("DuckmanMenuSystem() Menu ID %08X not found", menuId);
+ }
+}
+
+bool DuckmanMenuSystem::initMenuCursor() {
+ bool cursorInitialVisibleFlag = false;
+ Control *cursorControl = _vm->getObjectControl(0x40004);
+ if (cursorControl) {
+ if (cursorControl->_flags & 1)
+ cursorInitialVisibleFlag = false;
+ cursorControl->appearActor();
+ } else {
+ Common::Point pos = _vm->getNamedPointPosition(0x70001);
+ _vm->_controls->placeActor(0x50001, pos, 0x60001, 0x40004, 0);
+ cursorControl = _vm->getObjectControl(0x40004);
+ }
+ return cursorInitialVisibleFlag;
+}
+
+int DuckmanMenuSystem::getGameState() {
+ return _vm->_cursor._gameState;
+}
+
+void DuckmanMenuSystem::setMenuCursorNum(int cursorNum) {
+ Control *mouseCursor = _vm->getObjectControl(0x40004);
+ _vm->setCursorActorIndex(5, cursorNum, 0);
+ mouseCursor->startSequenceActor(0x60001, 2, 0);
+}
+
+void DuckmanMenuSystem::setGameState(int gameState) {
+ _vm->_cursor._gameState = gameState;
+}
+
+} // End of namespace Illusions
diff --git a/engines/illusions/duckman/menusystem_duckman.h b/engines/illusions/duckman/menusystem_duckman.h
new file mode 100644
index 0000000000..bb43619acd
--- /dev/null
+++ b/engines/illusions/duckman/menusystem_duckman.h
@@ -0,0 +1,70 @@
+/* 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 ILLUSIONS_DUCKMAN_MENUSYSTEM_DUCKMAN_H
+#define ILLUSIONS_DUCKMAN_MENUSYSTEM_DUCKMAN_H
+
+#include "illusions/menusystem.h"
+
+namespace Illusions {
+
+enum {
+ kDuckmanMainMenu,
+ kDuckmanLoadGameMenu,
+ kDuckmanOptionsMenu,
+ kDuckmanPauseMenu,
+ kDuckmanQueryQuitMenu,
+ kDuckmanQueryRestartMenu,
+ kDuckmanLastMenuIndex
+};
+
+class IllusionsEngine_Duckman;
+
+class DuckmanMenuSystem : public BaseMenuSystem {
+public:
+ DuckmanMenuSystem(IllusionsEngine_Duckman *vm);
+ ~DuckmanMenuSystem();
+ void runMenu(MenuChoiceOffsets menuChoiceOffsets, int16 *menuChoiceOffset,
+ uint32 menuId, uint32 duration, uint timeOutMenuChoiceIndex, uint32 menuCallerThreadId);
+public://protected:
+ IllusionsEngine_Duckman *_vm;
+ BaseMenu *_menus[kDuckmanLastMenuIndex];
+ void clearMenus();
+ void freeMenus();
+ BaseMenu *getMenuById(int menuId);
+ BaseMenu *createMenuById(int menuId);
+ BaseMenu *createMainMenu();
+ BaseMenu *createLoadGameMenu();
+ BaseMenu *createOptionsMenu();
+ BaseMenu *createPauseMenu();
+ BaseMenu *createQueryRestartMenu();
+ BaseMenu *createQueryQuitMenu();
+ int convertRootMenuId(uint32 menuId);
+ virtual bool initMenuCursor();
+ virtual int getGameState();
+ virtual void setGameState(int gameState);
+ virtual void setMenuCursorNum(int cursorNum);
+};
+
+} // End of namespace Illusions
+
+#endif // ILLUSIONS_DUCKMAN_MENUSYSTEM_DUCKMAN_H
diff --git a/engines/illusions/duckman/scriptopcodes_duckman.cpp b/engines/illusions/duckman/scriptopcodes_duckman.cpp
index 401f2e3eed..0fa7361574 100644
--- a/engines/illusions/duckman/scriptopcodes_duckman.cpp
+++ b/engines/illusions/duckman/scriptopcodes_duckman.cpp
@@ -23,10 +23,12 @@
#include "illusions/duckman/illusions_duckman.h"
#include "illusions/duckman/scriptopcodes_duckman.h"
#include "illusions/duckman/duckman_dialog.h"
+#include "illusions/duckman/menusystem_duckman.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
#include "illusions/dictionary.h"
#include "illusions/input.h"
+#include "illusions/menusystem.h"
#include "illusions/resources/scriptresource.h"
#include "illusions/resources/talkresource.h"
#include "illusions/screen.h"
@@ -57,6 +59,7 @@ void ScriptOpcodes_Duckman::initOpcodes() {
// First clear everything
for (uint i = 0; i < 256; ++i)
_opcodes[i] = 0;
+ // Register opcodes
OPCODE(1, opNop);
OPCODE(2, opSuspend);
OPCODE(3, opYield);
@@ -69,13 +72,15 @@ void ScriptOpcodes_Duckman::initOpcodes() {
OPCODE(16, opLoadResource);
OPCODE(17, opUnloadResource);
OPCODE(18, opEnterScene18);
+ OPCODE(19, opUnloadResourcesBySceneId);
OPCODE(20, opChangeScene);
OPCODE(22, opStartModalScene);
OPCODE(23, opExitModalScene);
OPCODE(24, opEnterScene24);
OPCODE(25, opLeaveScene24);
- OPCODE(26, opEnterScene26);
- OPCODE(27, opLeaveScene26);
+ OPCODE(26, opEnterDebugger);
+ OPCODE(27, opLeaveDebugger);
+ OPCODE(28, opDumpCurrentSceneFiles);
OPCODE(32, opPanCenterObject);
OPCODE(33, opPanTrackObject);
OPCODE(34, opPanToObject);
@@ -135,7 +140,6 @@ void ScriptOpcodes_Duckman::initOpcodes() {
OPCODE(126, opDebug126);
OPCODE(127, opDebug127);
#if 0
- // Register opcodes
OPCODE(8, opStartTempScriptThread);
OPCODE(14, opSetThreadSceneId);
OPCODE(15, opEndTalkThreads);
@@ -252,6 +256,12 @@ void ScriptOpcodes_Duckman::opEnterScene18(ScriptThread *scriptThread, OpCall &o
_vm->enterScene(sceneId, 0);
}
+void ScriptOpcodes_Duckman::opUnloadResourcesBySceneId(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ _vm->_resSys->unloadResourcesBySceneId(sceneId);
+}
+
//static uint dsceneId = 0, dthreadId = 0;
//static uint dsceneId = 0x00010008, dthreadId = 0x00020029;//Beginning in Jac
static uint dsceneId = 0x0001000A, dthreadId = 0x00020043;//Home front
@@ -279,11 +289,13 @@ void ScriptOpcodes_Duckman::opChangeScene(ScriptThread *scriptThread, OpCall &op
debug(1, "changeScene(%08X, %08X)", sceneId, threadId);
//DEBUG
+ /*
if (dsceneId) {
sceneId = dsceneId;
threadId = dthreadId;
dsceneId = 0;
}
+ */
if (_vm->_scriptResource->_properties.get(31)) {
_vm->changeScene(0x10002, 0x20001, opCall._callerThreadId);
@@ -331,12 +343,19 @@ void ScriptOpcodes_Duckman::opLeaveScene24(ScriptThread *scriptThread, OpCall &o
_vm->leavePause(_vm->getCurrentScene(), opCall._callerThreadId);
}
-void ScriptOpcodes_Duckman::opEnterScene26(ScriptThread *scriptThread, OpCall &opCall) {
- // TODO
+void ScriptOpcodes_Duckman::opEnterDebugger(ScriptThread *scriptThread, OpCall &opCall) {
+ // Used for debugging purposes in the original engine
+ // This is not supported and only reachable by code not implemented here!
+ error("ScriptOpcodes_Duckman::opEnterDebugger() Debugger function called");
+}
+
+void ScriptOpcodes_Duckman::opLeaveDebugger(ScriptThread *scriptThread, OpCall &opCall) {
+ // See opEnterDebugger
+ error("ScriptOpcodes_Duckman::opLeaveDebugger() Debugger function called");
}
-void ScriptOpcodes_Duckman::opLeaveScene26(ScriptThread *scriptThread, OpCall &opCall) {
- // TODO
+void ScriptOpcodes_Duckman::opDumpCurrentSceneFiles(ScriptThread *scriptThread, OpCall &opCall) {
+ _vm->dumpCurrSceneFiles(_vm->getCurrentScene(), opCall._callerThreadId);
}
void ScriptOpcodes_Duckman::opPanCenterObject(ScriptThread *scriptThread, OpCall &opCall) {
@@ -615,23 +634,32 @@ void ScriptOpcodes_Duckman::opAddMenuChoice(ScriptThread *scriptThread, OpCall &
}
void ScriptOpcodes_Duckman::opDisplayMenu(ScriptThread *scriptThread, OpCall &opCall) {
- ARG_INT16(unk1);
+ ARG_INT16(timeOutDuration);
ARG_UINT32(menuId);
- ARG_UINT32(unk2);
- // TODO _vm->_shellMgr->displayMenu(_vm->_stack->topPtr(), &_vm->_menuChoiceOfs, menuId, unk1, unk2, opCall._callerThreadId);
- // Remove menu choices from the stack
+ ARG_UINT32(timeOutMenuChoiceIndex);
+
+ debug("timeOutMenuChoiceIndex: %d", timeOutMenuChoiceIndex);
+
+ MenuChoiceOffsets menuChoiceOffsets;
+
+ // Load menu choices from the stack
do {
- _vm->_stack->pop();
+ int16 choiceOffs = _vm->_stack->pop();
+ debug("choiceOffs: %04X", choiceOffs);
+ menuChoiceOffsets.push_back(choiceOffs);
} while (_vm->_stack->pop() == 0);
-
+
+ _vm->_menuSystem->runMenu(menuChoiceOffsets, &_vm->_menuChoiceOfs,
+ menuId, timeOutDuration, timeOutMenuChoiceIndex,
+ opCall._threadId);
+
//DEBUG Resume calling thread, later done by the video player
- _vm->notifyThreadId(opCall._callerThreadId);
+ //_vm->notifyThreadId(opCall._callerThreadId);
}
void ScriptOpcodes_Duckman::opSwitchMenuChoice(ScriptThread *scriptThread, OpCall &opCall) {
-_vm->_menuChoiceOfs = 156; // DEBUG Chose "Start game"
-
+ //_vm->_menuChoiceOfs = 156; // DEBUG Chose "Start game"
opCall._deltaOfs += _vm->_menuChoiceOfs;
}
diff --git a/engines/illusions/duckman/scriptopcodes_duckman.h b/engines/illusions/duckman/scriptopcodes_duckman.h
index 5b2f089460..d50f967a43 100644
--- a/engines/illusions/duckman/scriptopcodes_duckman.h
+++ b/engines/illusions/duckman/scriptopcodes_duckman.h
@@ -54,13 +54,15 @@ protected:
void opUnloadResource(ScriptThread *scriptThread, OpCall &opCall);
void opStartTimerThread(ScriptThread *scriptThread, OpCall &opCall);
void opEnterScene18(ScriptThread *scriptThread, OpCall &opCall);
+ void opUnloadResourcesBySceneId(ScriptThread *scriptThread, OpCall &opCall);
void opChangeScene(ScriptThread *scriptThread, OpCall &opCall);
void opStartModalScene(ScriptThread *scriptThread, OpCall &opCall);
void opExitModalScene(ScriptThread *scriptThread, OpCall &opCall);
void opEnterScene24(ScriptThread *scriptThread, OpCall &opCall);
void opLeaveScene24(ScriptThread *scriptThread, OpCall &opCall);
- void opEnterScene26(ScriptThread *scriptThread, OpCall &opCall);
- void opLeaveScene26(ScriptThread *scriptThread, OpCall &opCall);
+ void opEnterDebugger(ScriptThread *scriptThread, OpCall &opCall);
+ void opLeaveDebugger(ScriptThread *scriptThread, OpCall &opCall);
+ void opDumpCurrentSceneFiles(ScriptThread *scriptThread, OpCall &opCall);
void opPanCenterObject(ScriptThread *scriptThread, OpCall &opCall);
void opPanTrackObject(ScriptThread *scriptThread, OpCall &opCall);
void opPanToObject(ScriptThread *scriptThread, OpCall &opCall);