aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorjohndoe1232015-11-24 00:10:10 +0100
committerEugene Sandulenko2018-07-20 06:43:33 +0000
commitfa17f684da1da7fded805746b75c454502ffe683 (patch)
tree1e668515abccf6455299a5b9fbadc2c5b6affd98 /engines
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')
-rw-r--r--engines/illusions/actor.cpp17
-rw-r--r--engines/illusions/actor.h4
-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
-rw-r--r--engines/illusions/gamarchive.cpp4
-rw-r--r--engines/illusions/input.cpp10
-rw-r--r--engines/illusions/input.h1
-rw-r--r--engines/illusions/menusystem.cpp591
-rw-r--r--engines/illusions/menusystem.h235
-rw-r--r--engines/illusions/module.mk2
-rw-r--r--engines/illusions/resources/fontresource.h2
-rw-r--r--engines/illusions/screentext.cpp6
-rw-r--r--engines/illusions/screentext.h1
-rw-r--r--engines/illusions/scriptopcodes.cpp2
-rw-r--r--engines/illusions/sound.cpp8
-rw-r--r--engines/illusions/textdrawer.cpp2
20 files changed, 1186 insertions, 30 deletions
diff --git a/engines/illusions/actor.cpp b/engines/illusions/actor.cpp
index bae77c71fc..91929466be 100644
--- a/engines/illusions/actor.cpp
+++ b/engines/illusions/actor.cpp
@@ -929,6 +929,23 @@ void Control::refreshSequenceCode() {
_actor->_seqCodeIp = sequence->_sequenceCode;
}
+void Control::getActorFrameDimensions(WidthHeight &dimensions) {
+ dimensions._width = _actor->_surface->w;
+ dimensions._height = _actor->_surface->h;
+}
+
+void Control::drawActorRect(const Common::Rect r, byte color) {
+ _actor->_surface->fillRect(r, color);
+ _actor->_flags |= 0x4000;
+}
+
+void Control::fillActor(byte color) {
+ debug("FILL %d, %d", _actor->_surface->w, _actor->_surface->h);
+ Common::Rect r = Common::Rect(_actor->_surface->w, _actor->_surface->h);
+ _actor->_surface->fillRect(r, color);
+ _actor->_flags |= 0x4000;
+}
+
void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entryTblPtr, uint32 notifyThreadId) {
stopActor();
diff --git a/engines/illusions/actor.h b/engines/illusions/actor.h
index 295a0b5c9a..add7519156 100644
--- a/engines/illusions/actor.h
+++ b/engines/illusions/actor.h
@@ -34,6 +34,7 @@
namespace Illusions {
+class Control;
class IllusionsEngine;
class SequenceOpcodes;
struct OpCall;
@@ -200,6 +201,9 @@ public:
PointArray *createPath(Common::Point destPt);
void updateActorMovement(uint32 deltaTime);
void refreshSequenceCode();
+ void getActorFrameDimensions(WidthHeight &dimensions);
+ void drawActorRect(const Common::Rect r, byte color);
+ void fillActor(byte color);
public:
IllusionsEngine *_vm;
uint _flags;
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);
diff --git a/engines/illusions/gamarchive.cpp b/engines/illusions/gamarchive.cpp
index 517882c501..098ad35154 100644
--- a/engines/illusions/gamarchive.cpp
+++ b/engines/illusions/gamarchive.cpp
@@ -61,13 +61,13 @@ void GamArchive::loadDictionary() {
_groups[i]._fileCount = fileCount;
_groups[i]._files = new GamFileEntry[fileCount];
- debug("Group %08X, fileCount: %d", _groups[i]._id, _groups[i]._fileCount);
+ debug(8, "Group %08X, fileCount: %d", _groups[i]._id, _groups[i]._fileCount);
for (uint j = 0; j < fileCount; ++j) {
_groups[i]._files[j]._id = _fd->readUint32LE();
_groups[i]._files[j]._fileOffset = _fd->readUint32LE();
_groups[i]._files[j]._fileSize = _fd->readUint32LE();
- debug(" %08X, %08X, %d", _groups[i]._files[j]._id, _groups[i]._files[j]._fileOffset, _groups[i]._files[j]._fileSize);
+ debug(8, " %08X, %08X, %d", _groups[i]._files[j]._id, _groups[i]._files[j]._fileOffset, _groups[i]._files[j]._fileSize);
}
}
diff --git a/engines/illusions/input.cpp b/engines/illusions/input.cpp
index 3956691ef6..37da087543 100644
--- a/engines/illusions/input.cpp
+++ b/engines/illusions/input.cpp
@@ -77,12 +77,14 @@ uint InputEvent::handle(Common::KeyCode key, int mouseButton, bool down) {
// Input
+const uint kAllButtons = 0xFFFF;
+
Input::Input() {
_buttonStates = 0;
_newButtons = 0;
_buttonsDown = 0;
_newKeys = 0;
- _enabledButtons = 0xFFFF;
+ _enabledButtons = kAllButtons;
_cursorPos.x = 0;
_cursorPos.y = 0;
_prevCursorPos.x = 0;
@@ -123,12 +125,16 @@ bool Input::pollEvent(uint evt) {
return pollButton(_inputEvents[evt].getBitMask());
}
+bool Input::hasNewEvents() {
+ return lookNewButtons(kAllButtons);
+}
+
void Input::discardEvent(uint evt) {
discardButtons(_inputEvents[evt].getBitMask());
}
void Input::discardAllEvents() {
- discardButtons(0xFFFF);
+ discardButtons(kAllButtons);
}
void Input::activateButton(uint bitMask) {
diff --git a/engines/illusions/input.h b/engines/illusions/input.h
index 093adad222..7d01ea6eec 100644
--- a/engines/illusions/input.h
+++ b/engines/illusions/input.h
@@ -79,6 +79,7 @@ public:
Input();
void processEvent(Common::Event event);
bool pollEvent(uint evt);
+ bool hasNewEvents();
void discardEvent(uint evt);
void discardAllEvents();
void activateButton(uint bitMask);
diff --git a/engines/illusions/menusystem.cpp b/engines/illusions/menusystem.cpp
new file mode 100644
index 0000000000..f26a461223
--- /dev/null
+++ b/engines/illusions/menusystem.cpp
@@ -0,0 +1,591 @@
+/* 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/menusystem.h"
+#include "illusions/illusions.h"
+#include "illusions/dictionary.h"
+#include "illusions/input.h"
+#include "illusions/screen.h"
+#include "illusions/screentext.h"
+#include "illusions/thread.h"
+#include "illusions/time.h"
+
+namespace Illusions {
+
+// MenuItem
+
+MenuItem::MenuItem(const Common::String text, BaseMenuAction *action)
+ : _text(text), _action(action) {
+}
+
+MenuItem::~MenuItem() {
+ delete _action;
+}
+
+void MenuItem::executeAction() {
+ _action->execute();
+}
+
+// BaseMenu
+
+BaseMenu::BaseMenu(BaseMenuSystem *menuSystem, uint32 fontId, byte field8, byte fieldA, byte fieldC, byte fieldE,
+ uint defaultMenuItemIndex)
+ : _menuSystem(menuSystem), _fontId(fontId), _field8(field8), _fieldA(fieldA), _fieldC(fieldC), _fieldE(fieldE),
+ _defaultMenuItemIndex(defaultMenuItemIndex)
+{
+}
+
+BaseMenu::~BaseMenu() {
+ for (MenuItems::iterator it = _menuItems.begin(); it != _menuItems.end(); ++it)
+ delete *it;
+}
+
+void BaseMenu::addText(const Common::String text) {
+ _text.push_back(text);
+}
+
+void BaseMenu::addMenuItem(MenuItem *menuItem) {
+ _menuItems.push_back(menuItem);
+}
+
+uint BaseMenu::getHeaderLinesCount() {
+ return _text.size();
+}
+
+const Common::String& BaseMenu::getHeaderLine(uint index) {
+ return _text[index];
+}
+
+uint BaseMenu::getMenuItemsCount() {
+ return _menuItems.size();
+}
+
+MenuItem *BaseMenu::getMenuItem(uint index) {
+ return _menuItems[index];
+}
+
+void BaseMenu::enterMenu() {
+ // Empty, implemented if neccessary by the inherited class when the menu is entered
+}
+
+// BaseMenuSystem
+
+BaseMenuSystem::BaseMenuSystem(IllusionsEngine *vm)
+ : _vm(vm), _isTimeOutEnabled(false), _menuChoiceOffset(0) {
+}
+
+BaseMenuSystem::~BaseMenuSystem() {
+}
+
+void BaseMenuSystem::playSoundEffect13() {
+ // TODO
+}
+
+void BaseMenuSystem::playSoundEffect14() {
+ // TODO
+}
+
+void BaseMenuSystem::selectMenuChoiceIndex(uint choiceIndex) {
+ if (choiceIndex > 0 && _menuChoiceOffset) {
+ *_menuChoiceOffset = _menuChoiceOffsets[choiceIndex - 1];
+ debug(0, "*_menuChoiceOffset: %04X", *_menuChoiceOffset);
+ }
+ _vm->_threads->notifyId(_menuCallerThreadId);
+ _menuCallerThreadId = 0;
+ closeMenu();
+}
+
+void BaseMenuSystem::leaveMenu() {
+ playSoundEffect13();
+ if (!_menuStack.empty())
+ leaveSubMenu();
+ else
+ closeMenu();
+}
+
+void BaseMenuSystem::enterSubMenu(BaseMenu *menu) {
+ _menuStack.push(_activeMenu);
+ activateMenu(menu);
+ _hoveredMenuItemIndex = _hoveredMenuItemIndex3;
+ _hoveredMenuItemIndex2 = _hoveredMenuItemIndex3;
+ setMouseCursorToMenuItem(_hoveredMenuItemIndex);
+ placeActor318();
+ placeActor323();
+}
+
+void BaseMenuSystem::leaveSubMenu() {
+ _activeMenu = _menuStack.pop();
+ _field54 = _activeMenu->_field2C18;
+ _menuLinesCount = _activeMenu->getHeaderLinesCount();
+ _hoveredMenuItemIndex = 1;
+ _vm->_screenText->removeText();
+ _vm->_screenText->removeText();
+ activateMenu(_activeMenu);
+ _hoveredMenuItemIndex = _hoveredMenuItemIndex3;
+ _hoveredMenuItemIndex2 = _hoveredMenuItemIndex3;
+ setMouseCursorToMenuItem(_hoveredMenuItemIndex);
+ initActor318();
+ placeActor323();
+}
+
+void BaseMenuSystem::enterSubMenuById(int menuId) {
+ BaseMenu *menu = getMenuById(menuId);
+ enterSubMenu(menu);
+}
+
+uint BaseMenuSystem::getQueryConfirmationChoiceIndex() const {
+ return _queryConfirmationChoiceIndex;
+}
+
+void BaseMenuSystem::setQueryConfirmationChoiceIndex(uint queryConfirmationChoiceIndex) {
+ _queryConfirmationChoiceIndex = queryConfirmationChoiceIndex;
+}
+
+void BaseMenuSystem::setMouseCursorToMenuItem(int menuItemIndex) {
+ Common::Point mousePos;
+ if (calcMenuItemMousePos(menuItemIndex, mousePos))
+ setMousePos(mousePos);
+}
+
+void BaseMenuSystem::calcMenuItemRect(uint menuItemIndex, WRect &rect) {
+ FontResource *font = _vm->_dict->findFont(_activeMenu->_fontId);
+ int charHeight = font->getCharHeight() + font->getLineIncr();
+
+ _vm->_screenText->getTextInfoPosition(rect._topLeft);
+ /* TODO
+ if (_activeMenu->_field8) {
+ rect._topLeft.y += 4;
+ rect._topLeft.x += 4;
+ }
+ */
+ rect._topLeft.y += charHeight * (menuItemIndex + _menuLinesCount - 1);
+
+ WidthHeight textInfoDimensions;
+ _vm->_screenText->getTextInfoDimensions(textInfoDimensions);
+ rect._bottomRight.x = rect._topLeft.x + textInfoDimensions._width;
+ rect._bottomRight.y = rect._topLeft.y + charHeight;
+}
+
+bool BaseMenuSystem::calcMenuItemMousePos(uint menuItemIndex, Common::Point &pt) {
+ if (menuItemIndex < _hoveredMenuItemIndex3 || menuItemIndex >= _hoveredMenuItemIndex3 + _menuItemCount)
+ return false;
+
+ WRect rect;
+ calcMenuItemRect(menuItemIndex - _hoveredMenuItemIndex3 + 1, rect);
+ pt.x = rect._topLeft.x;
+ pt.y = rect._topLeft.y + (rect._bottomRight.y - rect._topLeft.y) / 2;
+ return true;
+}
+
+bool BaseMenuSystem::calcMenuItemIndexAtPoint(Common::Point pt, uint &menuItemIndex) {
+ WRect rect;
+ calcMenuItemRect(1, rect);
+
+ uint index = _hoveredMenuItemIndex3 + (pt.y - rect._topLeft.y) / (rect._bottomRight.y - rect._topLeft.y);
+
+ if (pt.y < rect._topLeft.y || pt.x < rect._topLeft.x || pt.x > rect._bottomRight.x ||
+ index > _field54 || index > _hoveredMenuItemIndex3 + _menuItemCount - 1)
+ return false;
+
+ menuItemIndex = index;
+ return true;
+}
+
+void BaseMenuSystem::setMousePos(Common::Point &mousePos) {
+ _vm->_input->setCursorPosition(mousePos);
+ Control *mouseCursor = _vm->getObjectControl(0x40004);
+ mouseCursor->_actor->_position = mousePos;
+}
+
+void BaseMenuSystem::activateMenu(BaseMenu *menu) {
+ _activeMenu = menu;
+ // TODO Run menu enter callback if neccessary
+ _menuLinesCount = menu->getHeaderLinesCount();
+ menu->_field2C18 = menu->getMenuItemsCount();
+ _hoveredMenuItemIndex3 = 1;
+ _field54 = menu->_field2C18;
+
+ uint v2 = drawMenuText(menu);
+ if (menu->_field2C18 <= v2)
+ _menuItemCount = menu->_field2C18;
+ else
+ _menuItemCount = v2;
+
+}
+
+void BaseMenuSystem::initActor318() {
+ Control *v0 = _vm->getObjectControl(0x4013E);
+ if (!v0) {
+ WidthHeight dimensions;
+ dimensions._width = 300;
+ dimensions._height = 15;
+ _vm->_controls->placeSequenceLessActor(0x4013E, Common::Point(0, 0), dimensions, 18);
+ v0 = _vm->getObjectControl(0x4013E);
+ v0->_flags |= 8;
+ }
+ placeActor318();
+ v0->appearActor();
+}
+
+void BaseMenuSystem::placeActor318() {
+ Control *v0 = _vm->getObjectControl(0x4013E);
+ v0->fillActor(0);
+
+ WidthHeight textInfoDimensions;
+ _vm->_screenText->getTextInfoDimensions(textInfoDimensions);
+
+ /* TODO
+ if ( _activeMenu->_field8 && _activeMenu->_fieldA != _activeMenu->_field8)
+ textInfoDimensions._width -= 6;
+ */
+
+ WidthHeight frameDimensions;
+ v0->getActorFrameDimensions(frameDimensions);
+
+ FontResource *font = _vm->_dict->findFont(_activeMenu->_fontId);
+ int charHeight = font->getCharHeight() + font->getLineIncr();
+ if (frameDimensions._height < charHeight)
+ charHeight = frameDimensions._height;
+
+ v0->drawActorRect(Common::Rect(textInfoDimensions._width - 1, charHeight - 1), _activeMenu->_fieldE);
+
+ updateActor318();
+}
+
+void BaseMenuSystem::updateActor318() {
+ Control *v0 = _vm->getObjectControl(0x4013E);
+ WRect rect;
+ calcMenuItemRect(_hoveredMenuItemIndex2 - _hoveredMenuItemIndex3 + 1, rect);
+ v0->setActorPosition(rect._topLeft);
+}
+
+void BaseMenuSystem::hideActor318() {
+ Control *v0 = _vm->getObjectControl(0x4013E);
+ if (v0)
+ v0->disappearActor();
+}
+
+void BaseMenuSystem::initActor323() {
+ Control *v0 = _vm->getObjectControl(0x40143);
+ if (!v0) {
+ WidthHeight dimensions;
+ dimensions._width = 300;
+ dimensions._height = 180;
+ _vm->_controls->placeSequenceLessActor(0x40143, Common::Point(0, 0), dimensions, 17);
+ v0 = _vm->getObjectControl(0x40143);
+ v0->_flags |= 8;
+ }
+ placeActor323();
+ v0->appearActor();
+}
+
+void BaseMenuSystem::placeActor323() {
+ Control *v0 = _vm->getObjectControl(0x40143);
+ v0->fillActor(0);
+
+ Common::Point textInfoPosition;
+ WidthHeight textInfoDimensions;
+ _vm->_screenText->getTextInfoPosition(textInfoPosition);
+ _vm->_screenText->getTextInfoDimensions(textInfoDimensions);
+
+ /* TODO
+ if (_activeMenu->_field8 && _activeMenu->_fieldA != _activeMenu->_field8) {
+ textInfoDimensions._width -= 2;
+ textInfoDimensions._height -= 6;
+ }
+ */
+
+ v0->setActorPosition(textInfoPosition);
+ v0->drawActorRect(Common::Rect(textInfoDimensions._width - 1, textInfoDimensions._height - 1), _activeMenu->_fieldC);
+
+}
+
+void BaseMenuSystem::hideActor323() {
+ Control *v0 = _vm->getObjectControl(0x40143);
+ if (v0)
+ v0->disappearActor();
+}
+
+void BaseMenuSystem::openMenu(BaseMenu *menu) {
+
+ _isActive = true;
+ _menuStack.clear();
+
+ _cursorInitialVisibleFlag = initMenuCursor();
+ _savedCursorPos = _vm->_input->getCursorPosition();
+ _savedGameState = getGameState();
+ Control *cursorControl = _vm->getObjectControl(0x40004);
+ _savedCursorActorIndex = cursorControl->_actor->_actorIndex;
+ _savedCursorSequenceId = cursorControl->_actor->_sequenceId;
+
+ setMenuCursorNum(1);
+
+ setGameState(4);
+
+ activateMenu(menu);
+
+ _hoveredMenuItemIndex = _hoveredMenuItemIndex3;
+ _hoveredMenuItemIndex2 = _hoveredMenuItemIndex3;
+ setMouseCursorToMenuItem(_hoveredMenuItemIndex);
+ initActor318();
+ initActor323();
+ _vm->_input->discardAllEvents();
+}
+
+void BaseMenuSystem::closeMenu() {
+ while (!_menuStack.empty()) {
+ _vm->_screenText->removeText();
+ _menuStack.pop();
+ }
+ _vm->_screenText->removeText();
+ hideActor318();
+ hideActor323();
+ Control *mouseCursor = _vm->getObjectControl(0x40004);
+ setGameState(_savedGameState);
+ mouseCursor->_actor->_actorIndex = _savedCursorActorIndex;
+ mouseCursor->_actor->_position = _savedCursorPos;
+ setMousePos(_savedCursorPos);
+ mouseCursor->startSequenceActor(_savedCursorSequenceId, 2, 0);
+ if (_cursorInitialVisibleFlag)
+ mouseCursor->disappearActor();
+ _vm->_input->discardAllEvents();
+ _isActive = false;
+}
+
+void BaseMenuSystem::handleClick(uint menuItemIndex, const Common::Point &mousePos) {
+
+ if (menuItemIndex == 0) {
+ playSoundEffect14();
+ return;
+ }
+
+ MenuItem *menuItem = _activeMenu->getMenuItem(menuItemIndex - 1);
+ menuItem->executeAction();
+
+}
+
+uint BaseMenuSystem::drawMenuText(BaseMenu *menu) {
+ MenuTextBuilder *menuTextBuilder = new MenuTextBuilder();
+ uint lineCount = 0;
+
+ for (uint i = 0; i < menu->getHeaderLinesCount(); ++i) {
+ menuTextBuilder->appendString(menu->getHeaderLine(i));
+ menuTextBuilder->appendNewLine();
+ }
+
+ for (uint i = _hoveredMenuItemIndex3; i <= _field54; ++i) {
+ menuTextBuilder->appendString(menu->getMenuItem(i - 1)->getText());
+ if (i + 1 <= menu->getMenuItemsCount())
+ menuTextBuilder->appendNewLine();
+ ++lineCount;
+ }
+
+ menuTextBuilder->finalize();
+
+ uint16 *text = menuTextBuilder->getText();
+
+ Common::Point textPt;
+ int16 v9 = 0;
+ if (menu->_field8)
+ v9 = 4;
+ textPt.x = v9;
+ textPt.y = v9;
+
+ uint flags = 1;
+ if (menu->_field8 != menu->_fieldA)
+ flags = 25;
+
+ WidthHeight dimensions;
+ dimensions._width = 300;
+ dimensions._height = 180;
+
+ uint16 *outTextPtr;
+ if (!_vm->_screenText->insertText(text, menu->_fontId, dimensions, textPt, flags, menu->_field8, menu->_fieldA, 0xFF, 0xFF, 0xFF, outTextPtr)) {
+ --lineCount;
+ for ( ; *outTextPtr; ++outTextPtr) {
+ if (*outTextPtr == 13)
+ --lineCount;
+ }
+ }
+
+ delete menuTextBuilder;
+
+ return lineCount;
+}
+
+void BaseMenuSystem::update(Control *cursorControl) {
+ Common::Point mousePos = _vm->_input->getCursorPosition();
+ setMousePos(mousePos);
+
+ uint newHoveredMenuItemIndex;
+ bool resetTimeOut = false;
+
+ if (calcMenuItemIndexAtPoint(mousePos, newHoveredMenuItemIndex) && newHoveredMenuItemIndex != _hoveredMenuItemIndex) {
+ if (_hoveredMenuItemIndex == 0)
+ initActor318();
+ _hoveredMenuItemIndex = newHoveredMenuItemIndex;
+ _hoveredMenuItemIndex2 = newHoveredMenuItemIndex;
+ setMenuCursorNum(2);
+ updateActor318();
+ resetTimeOut = true;
+ } else if (_hoveredMenuItemIndex == 0) {
+ setMenuCursorNum(1);
+ hideActor318();
+ _hoveredMenuItemIndex = 0;
+ resetTimeOut = true;
+ }
+
+ if (_vm->_input->hasNewEvents())
+ resetTimeOut = true;
+
+ if (_vm->_input->pollEvent(kEventLeftClick)) {
+ handleClick(_hoveredMenuItemIndex, mousePos);
+ } else if (_vm->_input->pollEvent(kEventAbort) && _activeMenu->_defaultMenuItemIndex) {
+ handleClick(_activeMenu->_defaultMenuItemIndex, mousePos);
+ } else if (_vm->_input->pollEvent(kEventUp)) {
+ // TODO handleUpKey();
+ } else if (_vm->_input->pollEvent(kEventDown)) {
+ // TODO handleDownKey();
+ }
+
+ updateTimeOut(resetTimeOut);
+}
+
+void BaseMenuSystem::setTimeOutDuration(uint32 duration, uint timeOutMenuChoiceIndex) {
+ if (duration > 0) {
+ _isTimeOutEnabled = true;
+ _isTimeOutReached = false;
+ _timeOutDuration = duration;
+ _timeOutMenuChoiceIndex = timeOutMenuChoiceIndex;
+ _timeOutStartTime = getCurrentTime();
+ _timeOutEndTime = duration + _timeOutStartTime;
+ } else {
+ _isTimeOutEnabled = false;
+ }
+}
+
+void BaseMenuSystem::setMenuCallerThreadId(uint32 menuCallerThreadId) {
+ _menuCallerThreadId = menuCallerThreadId;
+}
+
+void BaseMenuSystem::setMenuChoiceOffsets(MenuChoiceOffsets menuChoiceOffsets, int16 *menuChoiceOffset) {
+ _menuChoiceOffsets = menuChoiceOffsets;
+ _menuChoiceOffset = menuChoiceOffset;
+}
+
+void BaseMenuSystem::updateTimeOut(bool resetTimeOut) {
+
+ if (!_isTimeOutEnabled)
+ return;
+
+ if (_menuStack.empty()) {
+ if (_isTimeOutReached) {
+ resetTimeOut = true;
+ _isTimeOutReached = false;
+ }
+ } else if (!_isTimeOutReached) {
+ _isTimeOutReached = true;
+ }
+
+ if (!_isTimeOutReached) {
+ if (resetTimeOut) {
+ _timeOutStartTime = getCurrentTime();
+ _timeOutEndTime = _timeOutDuration + _timeOutStartTime;
+ } else if (isTimerExpired(_timeOutStartTime, _timeOutEndTime)) {
+ _isTimeOutEnabled = false;
+ selectMenuChoiceIndex(_timeOutMenuChoiceIndex);
+ // TODO *_menuChoiceOffset = *((_WORD *)&_menuCallerThreadId + _timeOutMenuChoiceIndex + 1);
+ //_vm->_threads->notifyId(_menuCallerThreadId);
+ //_menuCallerThreadId = 0;
+ //closeMenu();
+ }
+ }
+
+}
+
+// MenuTextBuilder
+
+MenuTextBuilder::MenuTextBuilder() : _pos(0) {
+}
+
+void MenuTextBuilder::appendString(const Common::String &value) {
+ for (uint i = 0; i < value.size(); ++i)
+ _text[_pos++] = value[i];
+}
+
+void MenuTextBuilder::appendNewLine() {
+ _text[_pos++] = '\r';
+}
+
+void MenuTextBuilder::finalize() {
+ _text[_pos] = '\0';
+}
+
+// BaseMenuAction
+
+BaseMenuAction::BaseMenuAction(BaseMenuSystem *menuSystem)
+ : _menuSystem(menuSystem) {
+}
+
+// MenuActionEnterMenu
+
+MenuActionEnterMenu::MenuActionEnterMenu(BaseMenuSystem *menuSystem, int menuId)
+ : BaseMenuAction(menuSystem), _menuId(menuId) {
+}
+
+void MenuActionEnterMenu::execute() {
+ _menuSystem->enterSubMenuById(_menuId);
+}
+
+// MenuActionLeaveMenu
+
+MenuActionLeaveMenu::MenuActionLeaveMenu(BaseMenuSystem *menuSystem)
+ : BaseMenuAction(menuSystem) {
+}
+
+void MenuActionLeaveMenu::execute() {
+ _menuSystem->leaveMenu();
+}
+
+// MenuActionReturnChoice
+
+MenuActionReturnChoice::MenuActionReturnChoice(BaseMenuSystem *menuSystem, uint choiceIndex)
+ : BaseMenuAction(menuSystem), _choiceIndex(choiceIndex) {
+}
+
+void MenuActionReturnChoice::execute() {
+ _menuSystem->playSoundEffect13();
+ _menuSystem->selectMenuChoiceIndex(_choiceIndex);
+}
+
+// MenuActionEnterQueryMenu
+
+MenuActionEnterQueryMenu::MenuActionEnterQueryMenu(BaseMenuSystem *menuSystem, int menuId, uint confirmationChoiceIndex)
+ : BaseMenuAction(menuSystem), _menuId(menuId), _confirmationChoiceIndex(confirmationChoiceIndex) {
+}
+
+void MenuActionEnterQueryMenu::execute() {
+ _menuSystem->setQueryConfirmationChoiceIndex(_confirmationChoiceIndex);
+ _menuSystem->enterSubMenuById(_menuId);
+}
+
+} // End of namespace Illusions
diff --git a/engines/illusions/menusystem.h b/engines/illusions/menusystem.h
new file mode 100644
index 0000000000..98ef924300
--- /dev/null
+++ b/engines/illusions/menusystem.h
@@ -0,0 +1,235 @@
+/* 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_MENUSYSTEM_H
+#define ILLUSIONS_MENUSYSTEM_H
+
+#include "illusions/actor.h"
+#include "illusions/graphics.h"
+#include "illusions/resources/fontresource.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/stack.h"
+#include "common/str.h"
+#include "graphics/surface.h"
+
+namespace Illusions {
+
+class IllusionsEngine;
+
+class BaseMenuSystem;
+class BaseMenuAction;
+
+const uint kMenuTextSize = 4096;
+
+class MenuItem {
+public:
+ MenuItem(const Common::String text, BaseMenuAction *action);
+ ~MenuItem();
+ void executeAction();
+ const Common::String& getText() const { return _text; }
+protected:
+ Common::String _text;
+ BaseMenuAction *_action;
+};
+
+class BaseMenu {
+public:
+ BaseMenu(BaseMenuSystem *menuSystem, uint32 fontId, byte field8, byte fieldA, byte fieldC, byte fieldE,
+ uint defaultMenuItemIndex);
+ virtual ~BaseMenu();
+ void addText(const Common::String text);
+ void addMenuItem(MenuItem *menuItem);
+ uint getHeaderLinesCount();
+ const Common::String& getHeaderLine(uint index);
+ uint getMenuItemsCount();
+ MenuItem *getMenuItem(uint index);
+ virtual void enterMenu();
+public://protected://TODO
+ typedef Common::Array<MenuItem*> MenuItems;
+ BaseMenuSystem *_menuSystem;
+ uint32 _fontId;
+ byte _field8, _fieldA, _fieldC, _fieldE;
+ uint _field2C18;
+ uint _defaultMenuItemIndex;
+ Common::Array<Common::String> _text;
+ MenuItems _menuItems;
+};
+
+class MenuStack : public Common::Stack<BaseMenu*> {
+};
+
+typedef Common::Array<int16> MenuChoiceOffsets;
+
+class BaseMenuSystem {
+public:
+ BaseMenuSystem(IllusionsEngine *vm);
+ virtual ~BaseMenuSystem();
+ void playSoundEffect13();
+ void playSoundEffect14();
+ void selectMenuChoiceIndex(uint choiceIndex);
+ void leaveMenu();
+ void enterSubMenu(BaseMenu *menu);
+ void leaveSubMenu();
+ void enterSubMenuById(int menuId);
+ uint getQueryConfirmationChoiceIndex() const;
+ void setQueryConfirmationChoiceIndex(uint queryConfirmationChoiceIndex);
+ bool isActive() const { return _isActive; }
+ void openMenu(BaseMenu *menu);
+ void closeMenu();
+ void handleClick(uint menuItemIndex, const Common::Point &mousePos);
+ uint drawMenuText(BaseMenu *menu);
+ void update(Control *cursorControl);
+ void setTimeOutDuration(uint32 duration, uint timeOutMenuChoiceIndex);
+ void setMenuCallerThreadId(uint32 menuCallerThreadId);
+ void setMenuChoiceOffsets(MenuChoiceOffsets menuChoiceOffsets, int16 *menuChoiceOffset);
+ virtual bool initMenuCursor() = 0;
+ virtual int getGameState() = 0;
+ virtual void setGameState(int gameState) = 0;
+ virtual void setMenuCursorNum(int cursorNum) = 0;
+protected:
+ IllusionsEngine *_vm;
+ MenuStack _menuStack;
+
+ uint32 _menuCallerThreadId;
+ bool _isTimeOutEnabled;
+ bool _isTimeOutReached;
+ uint32 _timeOutDuration;
+ uint _timeOutMenuChoiceIndex;
+ uint32 _timeOutStartTime;
+ uint32 _timeOutEndTime;
+
+ Common::Point _savedCursorPos;
+ bool _cursorInitialVisibleFlag;
+ int _savedGameState;
+ int _savedCursorActorIndex;
+ int _savedCursorSequenceId;
+
+ bool _isActive;
+
+ MenuChoiceOffsets _menuChoiceOffsets;
+ int16 *_menuChoiceOffset;
+
+ uint _queryConfirmationChoiceIndex;
+
+ uint _field54;
+ uint _menuLinesCount;
+ uint _menuItemCount;
+
+ uint _hoveredMenuItemIndex;
+ uint _hoveredMenuItemIndex2;
+ uint _hoveredMenuItemIndex3;
+
+ BaseMenu *_activeMenu;
+ void setMouseCursorToMenuItem(int menuItemIndex);
+
+ void calcMenuItemRect(uint menuItemIndex, WRect &rect);
+ bool calcMenuItemMousePos(uint menuItemIndex, Common::Point &pt);
+ bool calcMenuItemIndexAtPoint(Common::Point pt, uint &menuItemIndex);
+ void setMousePos(Common::Point &mousePos);
+
+ void activateMenu(BaseMenu *menu);
+
+ void updateTimeOut(bool resetTimeOut);
+
+ void initActor318();
+ void placeActor318();
+ void updateActor318();
+ void hideActor318();
+
+ void initActor323();
+ void placeActor323();
+ void hideActor323();
+
+ virtual BaseMenu *getMenuById(int menuId) = 0;
+};
+
+/*
+
+
+*/
+
+class MenuTextBuilder {
+public:
+ MenuTextBuilder();
+ void appendString(const Common::String &value);
+ void appendNewLine();
+ void finalize();
+ uint16 *getText() { return _text; }
+protected:
+ uint16 _text[kMenuTextSize];
+ uint _pos;
+};
+
+// Menu actions
+
+class BaseMenuAction {
+public:
+ BaseMenuAction(BaseMenuSystem *menuSystem);
+ virtual ~BaseMenuAction() {}
+ virtual void execute() = 0;
+protected:
+ BaseMenuSystem *_menuSystem;
+};
+
+// Type 1: Enter a submenu
+
+class MenuActionEnterMenu : public BaseMenuAction {
+public:
+ MenuActionEnterMenu(BaseMenuSystem *menuSystem, int menuId);
+ virtual void execute();
+protected:
+ int _menuId;
+};
+
+// Type 4: Leave a submenu or the whole menu if on the main menu level
+
+class MenuActionLeaveMenu : public BaseMenuAction {
+public:
+ MenuActionLeaveMenu(BaseMenuSystem *menuSystem);
+ virtual void execute();
+};
+
+// Type 5: Return a menu choice index and exit the menu
+
+class MenuActionReturnChoice : public BaseMenuAction {
+public:
+ MenuActionReturnChoice(BaseMenuSystem *menuSystem, uint choiceIndex);
+ virtual void execute();
+protected:
+ int _choiceIndex;
+};
+
+// Type 8: Return a menu choice index and exit the menu after displaying a query message
+
+class MenuActionEnterQueryMenu : public BaseMenuAction {
+public:
+ MenuActionEnterQueryMenu(BaseMenuSystem *menuSystem, int menuId, uint confirmationChoiceIndex);
+ virtual void execute();
+protected:
+ int _menuId;
+ uint _confirmationChoiceIndex;
+};
+
+} // End of namespace Illusions
+
+#endif // ILLUSIONS_MENUSYSTEM_H
diff --git a/engines/illusions/module.mk b/engines/illusions/module.mk
index ee40fb37bc..d4bc3930d8 100644
--- a/engines/illusions/module.mk
+++ b/engines/illusions/module.mk
@@ -18,6 +18,7 @@ MODULE_OBJS := \
duckman/duckman_screenshakereffects.o \
duckman/duckman_specialcode.o \
duckman/illusions_duckman.o \
+ duckman/menusystem_duckman.o \
duckman/propertytimers.o \
duckman/scriptopcodes_duckman.o \
fileresourcereader.o \
@@ -27,6 +28,7 @@ MODULE_OBJS := \
graphics.o \
illusions.o \
input.o \
+ menusystem.o \
pathfinder.o \
resources/actorresource.o \
resources/backgroundresource.o \
diff --git a/engines/illusions/resources/fontresource.h b/engines/illusions/resources/fontresource.h
index e0291452df..fa758bc4f1 100644
--- a/engines/illusions/resources/fontresource.h
+++ b/engines/illusions/resources/fontresource.h
@@ -65,6 +65,8 @@ public:
void load(Resource *resource);
CharInfo *getCharInfo(uint16 c);
int16 getColorIndex() const { return _colorIndex; }
+ int16 getCharHeight() const { return _charHeight; }
+ int16 getLineIncr() const { return _lineIncr; }
public:
uint32 _totalSize;
int16 _charHeight;
diff --git a/engines/illusions/screentext.cpp b/engines/illusions/screentext.cpp
index 8c31705300..7c39823dc5 100644
--- a/engines/illusions/screentext.cpp
+++ b/engines/illusions/screentext.cpp
@@ -42,6 +42,10 @@ void ScreenText::getTextInfoDimensions(WidthHeight &textInfoDimensions) {
textInfoDimensions = _dimensions;
}
+void ScreenText::getTextInfoPosition(Common::Point &position) {
+ position = _position;
+}
+
void ScreenText::setTextInfoPosition(Common::Point position) {
_position = position;
clipTextInfoPosition(_position);
@@ -86,6 +90,7 @@ bool ScreenText::refreshScreenText(FontResource *font, WidthHeight dimensions, C
bool done = textDrawer.wrapText(font, text, &dimensions, offsPt, textFlags, outTextPtr);
_surface = _vm->_screen->allocSurface(dimensions._width, dimensions._height);
_surface->fillRect(Common::Rect(0, 0, _surface->w, _surface->h), _vm->_screen->getColorKey1());
+ debug("ScreenText dimensions (%d, %d)", dimensions._width, dimensions._height);
_dimensions = dimensions;
textDrawer.drawText(_vm->_screen, _surface, color2, color1);
return done;
@@ -121,6 +126,7 @@ bool ScreenText::insertText(uint16 *text, uint32 fontId, WidthHeight dimensions,
_screenTexts.push_back(screenText);
FontResource *font = _vm->_dict->findFont(screenText->_info._fontId);
+ debug("font: %p", font);
bool done = refreshScreenText(font, screenText->_info._dimensions, screenText->_info._offsPt,
text, screenText->_info._flags, screenText->_info._color2, screenText->_info._color1,
outTextPtr);
diff --git a/engines/illusions/screentext.h b/engines/illusions/screentext.h
index 4340224bdb..6b365e5f6e 100644
--- a/engines/illusions/screentext.h
+++ b/engines/illusions/screentext.h
@@ -54,6 +54,7 @@ public:
ScreenText(IllusionsEngine *vm);
~ScreenText();
void getTextInfoDimensions(WidthHeight &textInfoDimensions);
+ void getTextInfoPosition(Common::Point &position);
void setTextInfoPosition(Common::Point position);
void updateTextInfoPosition(Common::Point position);
void clipTextInfoPosition(Common::Point &position);
diff --git a/engines/illusions/scriptopcodes.cpp b/engines/illusions/scriptopcodes.cpp
index 7d515a8109..38fdbec3ce 100644
--- a/engines/illusions/scriptopcodes.cpp
+++ b/engines/illusions/scriptopcodes.cpp
@@ -62,7 +62,7 @@ ScriptOpcodes::~ScriptOpcodes() {
void ScriptOpcodes::execOpcode(ScriptThread *scriptThread, OpCall &opCall) {
if (!_opcodes[opCall._op])
error("ScriptOpcodes::execOpcode() Unimplemented opcode %d", opCall._op);
- debug(0, "\nexecOpcode([%08X] %d) %s", opCall._callerThreadId, opCall._op, _opcodeNames[opCall._op].c_str());
+ debug("\nexecOpcode([%08X] %d) %s", opCall._callerThreadId, opCall._op, _opcodeNames[opCall._op].c_str());
(*_opcodes[opCall._op])(scriptThread, opCall);
}
diff --git a/engines/illusions/sound.cpp b/engines/illusions/sound.cpp
index 5eebf00d21..5b1eea85f8 100644
--- a/engines/illusions/sound.cpp
+++ b/engines/illusions/sound.cpp
@@ -37,7 +37,7 @@ MusicPlayer::~MusicPlayer() {
}
void MusicPlayer::play(uint32 musicId, bool looping, int16 volume, int16 pan) {
- debug("MusicPlayer::play(%08X)", musicId);
+ debug(1, "MusicPlayer::play(%08X)", musicId);
if (_flags & 1) {
stop();
_musicId = musicId;
@@ -57,7 +57,7 @@ void MusicPlayer::play(uint32 musicId, bool looping, int16 volume, int16 pan) {
}
void MusicPlayer::stop() {
- debug("MusicPlayer::stop()");
+ debug(1, "MusicPlayer::stop()");
if ((_flags & 1) && (_flags & 2)) {
if (g_system->getMixer()->isSoundHandleActive(_soundHandle))
g_system->getMixer()->stopHandle(_soundHandle);
@@ -82,7 +82,7 @@ VoicePlayer::~VoicePlayer() {
}
bool VoicePlayer::cue(const char *voiceName) {
- debug("VoicePlayer::cue(%s)", voiceName);
+ debug(1, "VoicePlayer::cue(%s)", voiceName);
_voiceName = voiceName;
_voiceStatus = 2;
if (!isEnabled()) {
@@ -147,7 +147,7 @@ void Sound::load() {
}
void Sound::unload() {
- debug("Sound::unload() %08X", _soundEffectId);
+ debug(1, "Sound::unload() %08X", _soundEffectId);
stop();
delete _stream;
_stream = 0;
diff --git a/engines/illusions/textdrawer.cpp b/engines/illusions/textdrawer.cpp
index 61c4455150..f1c93c7c80 100644
--- a/engines/illusions/textdrawer.cpp
+++ b/engines/illusions/textdrawer.cpp
@@ -161,7 +161,7 @@ bool TextDrawer::wrapTextIntern(int16 x, int16 y, int16 maxWidth, int16 maxHeigh
}
}
-
+
_dimensions->_width = maxLineWidth;
_dimensions->_height = textPosY - _font->_lineIncr;