aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/illusions/actor.cpp94
-rw-r--r--engines/illusions/actor.h4
-rw-r--r--engines/illusions/actorresource.cpp19
-rw-r--r--engines/illusions/actorresource.h2
-rw-r--r--engines/illusions/backgroundresource.cpp84
-rw-r--r--engines/illusions/backgroundresource.h17
-rw-r--r--engines/illusions/cursor.cpp11
-rw-r--r--engines/illusions/cursor.h3
-rw-r--r--engines/illusions/detection.cpp25
-rw-r--r--engines/illusions/illusions.cpp2
-rw-r--r--engines/illusions/illusions.h27
-rw-r--r--engines/illusions/illusions_bbdou.cpp53
-rw-r--r--engines/illusions/illusions_bbdou.h13
-rw-r--r--engines/illusions/illusions_duckman.cpp440
-rw-r--r--engines/illusions/illusions_duckman.h111
-rw-r--r--engines/illusions/midiresource.cpp48
-rw-r--r--engines/illusions/midiresource.h47
-rw-r--r--engines/illusions/module.mk4
-rw-r--r--engines/illusions/resourcesystem.cpp16
-rw-r--r--engines/illusions/resourcesystem.h18
-rw-r--r--engines/illusions/screen.cpp399
-rw-r--r--engines/illusions/screen.h34
-rw-r--r--engines/illusions/scriptopcodes_bbdou.cpp2
-rw-r--r--engines/illusions/scriptopcodes_bbdou.h2
-rw-r--r--engines/illusions/scriptopcodes_duckman.cpp811
-rw-r--r--engines/illusions/scriptopcodes_duckman.h137
-rw-r--r--engines/illusions/scriptresource.cpp99
-rw-r--r--engines/illusions/scriptresource.h13
-rw-r--r--engines/illusions/scriptthread.cpp25
-rw-r--r--engines/illusions/scriptthread.h1
-rw-r--r--engines/illusions/sequenceopcodes.cpp16
-rw-r--r--engines/illusions/sequenceopcodes.h2
-rw-r--r--engines/illusions/talkthread.cpp9
-rw-r--r--engines/illusions/talkthread_duckman.cpp311
-rw-r--r--engines/illusions/talkthread_duckman.h86
-rw-r--r--engines/illusions/thread.cpp24
-rw-r--r--engines/illusions/thread.h3
37 files changed, 2810 insertions, 202 deletions
diff --git a/engines/illusions/actor.cpp b/engines/illusions/actor.cpp
index 1d9aae0c46..bfb6fe2da2 100644
--- a/engines/illusions/actor.cpp
+++ b/engines/illusions/actor.cpp
@@ -226,7 +226,7 @@ void Control::pause() {
_vm->_dict->setObjectControl(_objectId, 0);
if (_objectId == 0x40004)
- _vm->_cursor->setControl(0);
+ _vm->setCursorControl(0);
if (_actor && !(_actor->_flags & 0x0200))
_actor->destroySurface();
@@ -238,7 +238,7 @@ void Control::unpause() {
_vm->_dict->setObjectControl(_objectId, this);
if (_objectId == 0x40004)
- _vm->_cursor->setControl(this);
+ _vm->setCursorControl(this);
if (_actor && !(_actor->_flags & 0x0200)) {
SurfInfo surfInfo;
@@ -254,7 +254,7 @@ void Control::unpause() {
void Control::appearActor() {
if (_objectId == 0x40004) {
- _vm->_cursor->show();
+ _vm->showCursor();
} else {
if (_actor->_frameIndex || _actorTypeId == 0x50004)
_actor->_flags |= 1;
@@ -270,7 +270,7 @@ void Control::appearActor() {
void Control::disappearActor() {
if (_objectId == 0x40004) {
- _vm->_cursor->hide();
+ _vm->hideCursor();
} else {
_actor->_flags &= ~1;
_actor->_flags &= ~0x1000;
@@ -540,8 +540,10 @@ void Control::stopActor() {
_actor->_pathPointIndex = 0;
_actor->_walkCallerThreadId1 = 0;
}
- _vm->notifyThreadId(_actor->_notifyId3C);
- _vm->notifyThreadId(_actor->_notifyThreadId1);
+ if (_vm->getGameId() == kGameIdBBDOU) {
+ _vm->notifyThreadId(_actor->_notifyId3C);
+ _vm->notifyThreadId(_actor->_notifyThreadId1);
+ }
}
void Control::startSequenceActor(uint32 sequenceId, int value, uint32 notifyThreadId) {
@@ -623,6 +625,7 @@ void Control::sequenceActor() {
appearActor();
_actor->_flags &= ~0x1000;
}
+ debug(1, "New frame OK");
}
if (sequenceFinished) {
@@ -905,22 +908,43 @@ void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entry
_actor->_notifyThreadId1 = notifyThreadId;
_actor->_notifyId3C = 0;
_actor->_walkCallerThreadId1 = 0;
+ _actor->_entryTblPtr = 0;
Sequence *sequence = _vm->_dict->findSequence(sequenceId);
+ if (!sequence && _vm->getGameId() == kGameIdDuckman) {
+ debug("Load external sequence...");
+ _vm->_resSys->loadResource(0x00060000 | (sequenceId & 0xFFFF), _vm->getCurrentScene(), 0);
+ sequence = _vm->_dict->findSequence(sequenceId);
+ _actor->_flags |= 0x800;
+ }
+
_actor->_seqCodeIp = sequence->_sequenceCode;
_actor->_frames = _vm->_actorItems->findSequenceFrames(sequence);
+
_actor->_seqCodeValue3 = 0;
_actor->_seqCodeValue1 = 0;
- _actor->_seqCodeValue2 = value == 1 ? 350 : 600;
+
+ if (_vm->getGameId() == kGameIdBBDOU) {
+ _actor->_seqCodeValue2 = value == 1 ? 350 : 600;
+ } else if (_vm->getGameId() == kGameIdDuckman) {
+ _actor->_seqCodeValue2 = value == 1 ? 350 : 750;
+ }
+
_actor->initSequenceStack();
- stopSequenceActor();
+
+ if (_vm->getGameId() == kGameIdBBDOU)
+ stopSequenceActor();
+
_actor->_linkIndex2 = 0;
+
if (entryTblPtr) {
_actor->_flags |= 0x80;
_actor->_entryTblPtr = entryTblPtr;
- _actor->_notifyThreadId1 = 0;
- _actor->_notifyThreadId2 = notifyThreadId;
+ if (_vm->getGameId() == kGameIdBBDOU) {
+ _actor->_notifyThreadId1 = 0;
+ _actor->_notifyThreadId2 = notifyThreadId;
+ }
}
sequenceActor();
@@ -958,7 +982,6 @@ void Controls::placeBackgroundObject(BackgroundObject *backgroundObject) {
void Controls::placeActor(uint32 actorTypeId, Common::Point placePt, uint32 sequenceId, uint32 objectId, uint32 notifyThreadId) {
Control *control = newControl();
Actor *actor = newActor();
-
ActorType *actorType = _vm->_dict->findActorType(actorTypeId);
control->_objectId = objectId;
@@ -967,8 +990,9 @@ void Controls::placeActor(uint32 actorTypeId, Common::Point placePt, uint32 sequ
control->readPointsConfig(actorType->_pointsConfig);
control->_actorTypeId = actorTypeId;
control->_actor = actor;
- if (actorTypeId == 0x50001 && objectId == 0x40004)
- actor->setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, Cursor>(_vm->_cursor, &Cursor::cursorControlRoutine));
+
+ if (_vm->isCursorObject(actorTypeId, objectId))
+ _vm->setCursorControlRoutine(control);
if (actorType->_surfInfo._dimensions._width > 0 || actorType->_surfInfo._dimensions._height > 0) {
actor->createSurface(actorType->_surfInfo);
@@ -1015,12 +1039,11 @@ void Controls::placeActor(uint32 actorTypeId, Common::Point placePt, uint32 sequ
_controls.push_back(control);
_vm->_dict->setObjectControl(objectId, control);
- if (actorTypeId == 0x50001 && objectId == 0x40004)
- _vm->_cursor->place(control, sequenceId);
+ if (_vm->isCursorObject(actorTypeId, objectId))
+ _vm->placeCursorControl(control, sequenceId);
control->_flags |= 0x01;
actor->_flags |= 0x1000;
-
control->startSequenceActor(sequenceId, 2, notifyThreadId);
}
@@ -1083,6 +1106,25 @@ void Controls::placeSubActor(uint32 objectId, int linkIndex, uint32 actorTypeId,
subActor->_linkIndex = linkIndex;
}
+void Controls::destroyControls() {
+ ItemsIterator it = _controls.begin();
+ while (it != _controls.end()) {
+ destroyControl(*it);
+ it = _controls.erase(it);
+ }
+}
+
+void Controls::destroyActiveControls() {
+ ItemsIterator it = _controls.begin();
+ while (it != _controls.end()) {
+ if ((*it)->_pauseCtr <= 0) {
+ destroyControl(*it);
+ it = _controls.erase(it);
+ } else
+ ++it;
+ }
+}
+
void Controls::destroyControlsByTag(uint32 tag) {
ItemsIterator it = _controls.begin();
while (it != _controls.end()) {
@@ -1105,6 +1147,24 @@ void Controls::threadIsDead(uint32 threadId) {
}
}
+void Controls::pauseControls() {
+ for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
+ Control *control = *it;
+ ++control->_pauseCtr;
+ if (control->_pauseCtr == 1)
+ control->pause();
+ }
+}
+
+void Controls::unpauseControls() {
+ for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
+ Control *control = *it;
+ --control->_pauseCtr;
+ if (control->_pauseCtr == 0)
+ control->unpause();
+ }
+}
+
void Controls::pauseControlsByTag(uint32 tag) {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
@@ -1225,7 +1285,7 @@ void Controls::destroyControl(Control *control) {
_vm->_dict->setObjectControl(control->_objectId, 0);
if (control->_objectId == 0x40004 && control->_pauseCtr <= 0)
- _vm->_cursor->setControl(0);
+ _vm->setCursorControl(0);
if (control->_actor) {
if (control->_actor->_pathNode && (control->_actor->_flags & 0x400))
diff --git a/engines/illusions/actor.h b/engines/illusions/actor.h
index 4c937efbf9..d1740ebb36 100644
--- a/engines/illusions/actor.h
+++ b/engines/illusions/actor.h
@@ -220,8 +220,12 @@ public:
void placeSequenceLessActor(uint32 objectId, Common::Point placePt, WidthHeight dimensions, int16 priority);
void placeActorLessObject(uint32 objectId, Common::Point feetPt, Common::Point pt, int16 priority, uint flags);
void placeSubActor(uint32 objectId, int linkIndex, uint32 actorTypeId, uint32 sequenceId);
+ void destroyControls();
+ void destroyActiveControls();
void destroyControlsByTag(uint32 tag);
void threadIsDead(uint32 threadId);
+ void pauseControls();
+ void unpauseControls();
void pauseControlsByTag(uint32 tag);
void unpauseControlsByTag(uint32 tag);
bool getOverlappedObject(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority);
diff --git a/engines/illusions/actorresource.cpp b/engines/illusions/actorresource.cpp
index 058b093ac6..d3762f96b6 100644
--- a/engines/illusions/actorresource.cpp
+++ b/engines/illusions/actorresource.cpp
@@ -32,7 +32,7 @@ void ActorResourceLoader::load(Resource *resource) {
debug("ActorResourceLoader::load() Loading actor %08X from %s...", resource->_resId, resource->_filename.c_str());
ActorResource *actorResource = new ActorResource();
- actorResource->load(resource->_data, resource->_dataSize);
+ actorResource->load(resource);
resource->_refId = actorResource;
ActorItem *actorItem = _vm->_actorItems->allocActorItem();
@@ -151,7 +151,10 @@ ActorResource::ActorResource() {
ActorResource::~ActorResource() {
}
-void ActorResource::load(byte *data, uint32 dataSize) {
+void ActorResource::load(Resource *resource) {
+ byte *data = resource->_data;
+ uint32 dataSize = resource->_dataSize;
+
Common::MemoryReadStream stream(data, dataSize, DisposeAfterUse::NO);
_totalSize = stream.readUint32LE();
@@ -196,10 +199,14 @@ void ActorResource::load(byte *data, uint32 dataSize) {
}
// Load named points
- // The count isn't stored explicitly so calculate it
- uint namedPointsCount = (actorTypesOffs - 0x20) / 8;
- stream.seek(0x20);
- _namedPoints.load(namedPointsCount, stream);
+ if (resource->_gameId == kGameIdBBDOU) {
+ // The count isn't stored explicitly so calculate it
+ uint namedPointsCount = (actorTypesOffs - 0x20) / 8;
+ stream.seek(0x20);
+ _namedPoints.load(namedPointsCount, stream);
+ }
+
+ debug("ActorResource(%08X) framesCount: %d", resource->_resId, framesCount);
}
diff --git a/engines/illusions/actorresource.h b/engines/illusions/actorresource.h
index 78cfc199a3..3a4c46213e 100644
--- a/engines/illusions/actorresource.h
+++ b/engines/illusions/actorresource.h
@@ -83,7 +83,7 @@ class ActorResource {
public:
ActorResource();
~ActorResource();
- void load(byte *data, uint32 dataSize);
+ void load(Resource *resource);
bool containsSequence(Sequence *sequence);
bool findNamedPoint(uint32 namedPointId, Common::Point &pt);
public:
diff --git a/engines/illusions/backgroundresource.cpp b/engines/illusions/backgroundresource.cpp
index 754b9d2e80..a4111c7893 100644
--- a/engines/illusions/backgroundresource.cpp
+++ b/engines/illusions/backgroundresource.cpp
@@ -53,8 +53,12 @@ void BackgroundResourceLoader::load(Resource *resource) {
// TODO camera_fadeClear();
int index = backgroundItem->_bgRes->findMasterBgIndex();
_vm->_camera->set(backgroundItem->_bgRes->_bgInfos[index - 1]._panPoint, backgroundItem->_bgRes->_bgInfos[index - 1]._surfInfo._dimensions);
+
+ if (backgroundItem->_bgRes->_palettesCount > 0) {
+ Palette *palette = &backgroundItem->_bgRes->_palettes[backgroundItem->_bgRes->_paletteIndex - 1];
+ _vm->_screen->setPalette(palette->_palette, 1, palette->_count);
+ }
- // NOTE Skipped palette loading (not used in BBDOU)
}
void BackgroundResourceLoader::unload(Resource *resource) {
@@ -150,6 +154,15 @@ int ScaleLayer::getScale(Common::Point pos) {
return _values[pos.y];
}
+// Palette
+
+void Palette::load(byte *dataStart, Common::SeekableReadStream &stream) {
+ _count = stream.readUint16LE();
+ _unk = stream.readUint16LE();
+ uint32 paletteOffs = stream.readUint32LE();
+ _palette = dataStart + paletteOffs;
+}
+
// BackgroundObject
void BackgroundObject::load(byte *dataStart, Common::SeekableReadStream &stream) {
@@ -176,13 +189,15 @@ void BackgroundResource::load(byte *data, uint32 dataSize) {
Common::MemoryReadStream stream(data, dataSize, DisposeAfterUse::NO);
// TODO A lot
+ stream.seek(8);
+ _paletteIndex = stream.readUint16LE();
+
// Load background pixels
stream.seek(0x0A);
_bgInfosCount = stream.readUint16LE();
_bgInfos = new BgInfo[_bgInfosCount];
stream.seek(0x20);
uint32 bgInfosOffs = stream.readUint32LE();
- debug("_bgInfosCount: %d", _bgInfosCount);
for (uint i = 0; i < _bgInfosCount; ++i) {
stream.seek(bgInfosOffs + i * 0x1C);
_bgInfos[i].load(data, stream);
@@ -232,6 +247,18 @@ void BackgroundResource::load(byte *data, uint32 dataSize) {
stream.seek(namedPointsOffs);
_namedPoints.load(namedPointsCount, stream);
+ // Load palettes
+ stream.seek(0x18);
+ _palettesCount = stream.readUint16LE();
+ _palettes = new Palette[_palettesCount];
+ stream.seek(0x3C);
+ uint32 palettesOffs = stream.readUint32LE();
+ debug(0, "_palettesCount: %d", _palettesCount);
+ for (uint i = 0; i < _palettesCount; ++i) {
+ stream.seek(palettesOffs + i * 8);
+ _palettes[i].load(data, stream);
+ }
+
}
int BackgroundResource::findMasterBgIndex() {
@@ -255,7 +282,7 @@ bool BackgroundResource::findNamedPoint(uint32 namedPointId, Common::Point &pt)
// BackgroundItem
-BackgroundItem::BackgroundItem(IllusionsEngine *vm) : _vm(vm), _tag(0), _pauseCtr(0), _bgRes(0) {
+BackgroundItem::BackgroundItem(IllusionsEngine *vm) : _vm(vm), _tag(0), _pauseCtr(0), _bgRes(0), _savedPalette(0) {
}
BackgroundItem::~BackgroundItem() {
@@ -282,6 +309,41 @@ void BackgroundItem::freeSurface() {
}
void BackgroundItem::drawTiles(Graphics::Surface *surface, TileMap &tileMap, byte *tilePixels) {
+ switch (_vm->getGameId()) {
+ case kGameIdDuckman:
+ drawTiles8(surface, tileMap, tilePixels);
+ break;
+ case kGameIdBBDOU:
+ drawTiles16(surface, tileMap, tilePixels);
+ break;
+ }
+}
+
+void BackgroundItem::drawTiles8(Graphics::Surface *surface, TileMap &tileMap, byte *tilePixels) {
+ const int kTileWidth = 32;
+ const int kTileHeight = 8;
+ const int kTileSize = kTileWidth * kTileHeight;
+ uint tileMapIndex = 0;
+ for (int tileY = 0; tileY < tileMap._height; ++tileY) {
+ int tileDestY = tileY * kTileHeight;
+ int tileDestH = MIN(kTileHeight, surface->h - tileDestY);
+ for (int tileX = 0; tileX < tileMap._width; ++tileX) {
+ int tileDestX = tileX * kTileWidth;
+ int tileDestW = MIN(kTileWidth, surface->w - tileDestX);
+ uint16 tileIndex = READ_LE_UINT16(tileMap._map + 2 * tileMapIndex);
+ ++tileMapIndex;
+ byte *src = tilePixels + (tileIndex - 1) * kTileSize;
+ byte *dst = (byte*)surface->getBasePtr(tileDestX, tileDestY);
+ for (int h = 0; h < tileDestH; ++h) {
+ memcpy(dst, src, tileDestW);
+ dst += surface->pitch;
+ src += kTileWidth;
+ }
+ }
+ }
+}
+
+void BackgroundItem::drawTiles16(Graphics::Surface *surface, TileMap &tileMap, byte *tilePixels) {
const int kTileWidth = 32;
const int kTileHeight = 8;
const int kTileSize = kTileWidth * kTileHeight * 2;
@@ -318,10 +380,8 @@ void BackgroundItem::pause() {
*/
// TODO _vm->setDefPointDimensions1();
_vm->_camera->getActiveState(_savedCameraState);
- /* Unused
- _savedPalette = malloc(1024);
- savePalette(_savedPalette);
- */
+ _savedPalette = new byte[1024];
+ _vm->_screen->getPalette(_savedPalette);
freeSurface();
}
}
@@ -335,11 +395,9 @@ void BackgroundItem::unpause() {
krndictAddID(_bgRes->_item48s[i].id, _bgRes->_item48s[i]);
*/
initSurface();
- /* Unused
- restorePalette(_savedPalette, 1, 256);
- free(_savedPalette);
+ _vm->_screen->setPalette(_savedPalette, 1, 256);
+ delete[] _savedPalette;
_savedPalette = 0;
- */
// TODO _vm->_screen->_fadeClear();
_vm->_camera->setActiveState(_savedCameraState);
_vm->_backgroundItems->refreshPan();
@@ -437,8 +495,4 @@ bool BackgroundItems::findActiveBackgroundNamedPoint(uint32 namedPointId, Common
return backgroundResource ? backgroundResource->findNamedPoint(namedPointId, pt) : false;
}
-BackgroundItem *BackgroundItems::debugFirst() {
- return *(_items.begin());
-}
-
} // End of namespace Illusions
diff --git a/engines/illusions/backgroundresource.h b/engines/illusions/backgroundresource.h
index 741047f5b9..75c867acbd 100644
--- a/engines/illusions/backgroundresource.h
+++ b/engines/illusions/backgroundresource.h
@@ -101,6 +101,13 @@ points dd ?
BgResource_PathWalkPoints ends
#endif
+struct Palette {
+ uint16 _count;
+ uint16 _unk;
+ byte *_palette;
+ void load(byte *dataStart, Common::SeekableReadStream &stream);
+};
+
struct BackgroundObject {
uint32 _objectId;
uint16 _flags;
@@ -120,6 +127,8 @@ public:
bool findNamedPoint(uint32 namedPointId, Common::Point &pt);
public:
+ uint _paletteIndex;
+
uint _bgInfosCount;
BgInfo *_bgInfos;
@@ -133,6 +142,9 @@ public:
BackgroundObject *_backgroundObjects;
NamedPoints _namedPoints;
+
+ uint _palettesCount;
+ Palette *_palettes;
};
@@ -156,7 +168,9 @@ public:
Common::Point _panPoints[kMaxBackgroundItemSurfaces];
Graphics::Surface *_surfaces[kMaxBackgroundItemSurfaces];
CameraState _savedCameraState;
- // TODO? byte *savedPalette;
+ byte *_savedPalette;
+ void drawTiles8(Graphics::Surface *surface, TileMap &tileMap, byte *tilePixels);
+ void drawTiles16(Graphics::Surface *surface, TileMap &tileMap, byte *tilePixels);
};
class BackgroundItems {
@@ -173,7 +187,6 @@ public:
WidthHeight getMasterBgDimensions();
void refreshPan();
bool findActiveBackgroundNamedPoint(uint32 namedPointId, Common::Point &pt);
- BackgroundItem *debugFirst();
//protected:
public:
typedef Common::List<BackgroundItem*> Items;
diff --git a/engines/illusions/cursor.cpp b/engines/illusions/cursor.cpp
index ccbff9540b..b591ae617b 100644
--- a/engines/illusions/cursor.cpp
+++ b/engines/illusions/cursor.cpp
@@ -79,15 +79,4 @@ void Cursor::hide() {
}
}
-void Cursor::cursorControlRoutine(Control *control, uint32 deltaTime) {
- _control->_actor->_seqCodeValue1 = 100 * deltaTime;
- if (_control->_actor->_flags & 1) {
- if (_status == 2) {
- // Unused nullsub_1(control);
- } else if (_status == 3) {
- // TODO _vm->_shellMgr->handleMouse(_control);
- }
- }
-}
-
} // End of namespace Illusions
diff --git a/engines/illusions/cursor.h b/engines/illusions/cursor.h
index 3179b71917..e528f09708 100644
--- a/engines/illusions/cursor.h
+++ b/engines/illusions/cursor.h
@@ -37,7 +37,8 @@ public:
void show();
void hide();
void cursorControlRoutine(Control *control, uint32 deltaTime);
-protected:
+//protected:
+public:
IllusionsEngine *_vm;
Control *_control;
uint32 _sequenceId;
diff --git a/engines/illusions/detection.cpp b/engines/illusions/detection.cpp
index c42909c57e..5c1e53a24a 100644
--- a/engines/illusions/detection.cpp
+++ b/engines/illusions/detection.cpp
@@ -22,6 +22,7 @@
#include "illusions/illusions.h"
#include "illusions/illusions_bbdou.h"
+#include "illusions/illusions_duckman.h"
#include "common/config-manager.h"
#include "engines/advancedDetector.h"
@@ -33,16 +34,12 @@
static const PlainGameDescriptor illusionsGames[] = {
{ "illusions", "Illusions engine game" },
{ "bbdou", "Beavis and Butthead Do U" },
+ { "duckman", "Duckman" },
{ 0, 0 }
};
namespace Illusions {
-struct IllusionsGameDescription {
- ADGameDescription desc;
- int gameId;
-};
-
static const IllusionsGameDescription gameDescriptions[] = {
{
{
@@ -57,6 +54,19 @@ static const IllusionsGameDescription gameDescriptions[] = {
kGameIdBBDOU
},
+ {
+ {
+ "duckman",
+ 0,
+ AD_ENTRY1s("duckman.gam", "172c0514f3793041718159cf9cf9935f", 29560832),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO0()
+ },
+ kGameIdDuckman
+ },
+
{AD_TABLE_END_MARKER, 0}
};
@@ -172,7 +182,10 @@ bool IllusionsMetaEngine::createInstance(OSystem *syst, Engine **engine, const A
if (gd) {
switch (gd->gameId) {
case Illusions::kGameIdBBDOU:
- *engine = new Illusions::IllusionsEngine_BBDOU(syst, desc);
+ *engine = new Illusions::IllusionsEngine_BBDOU(syst, gd);
+ break;
+ case Illusions::kGameIdDuckman:
+ *engine = new Illusions::IllusionsEngine_Duckman(syst, gd);
break;
default:
error("Unknown game id");
diff --git a/engines/illusions/illusions.cpp b/engines/illusions/illusions.cpp
index 60d9b5bd6a..4d9f4a0702 100644
--- a/engines/illusions/illusions.cpp
+++ b/engines/illusions/illusions.cpp
@@ -58,7 +58,7 @@
namespace Illusions {
-IllusionsEngine::IllusionsEngine(OSystem *syst, const ADGameDescription *gd) :
+IllusionsEngine::IllusionsEngine(OSystem *syst, const IllusionsGameDescription *gd) :
Engine(syst), _gameDescription(gd) {
_random = new Common::RandomSource("illusions");
diff --git a/engines/illusions/illusions.h b/engines/illusions/illusions.h
index a9b8555c50..ff7d2194af 100644
--- a/engines/illusions/illusions.h
+++ b/engines/illusions/illusions.h
@@ -35,6 +35,7 @@
#include "common/system.h"
#include "common/winexe.h"
#include "common/winexe_pe.h"
+#include "engines/advancedDetector.h"
#include "engines/engine.h"
#include "graphics/surface.h"
@@ -74,15 +75,21 @@ enum {
kGameIdDuckman = 2
};
+struct IllusionsGameDescription {
+ ADGameDescription desc;
+ int gameId;
+};
+
class IllusionsEngine : public Engine {
public:
- IllusionsEngine(OSystem *syst, const ADGameDescription *gd);
+ IllusionsEngine(OSystem *syst, const IllusionsGameDescription *gd);
~IllusionsEngine();
const Common::String getTargetName() { return _targetName; }
private:
- const ADGameDescription *_gameDescription;
+ const IllusionsGameDescription *_gameDescription;
Graphics::PixelFormat _pixelFormat;
-public:
+public:
+
Common::RandomSource *_random;
Dictionary *_dict;
ResourceSystem *_resSys;
@@ -99,7 +106,6 @@ public:
ScriptOpcodes *_scriptOpcodes;
SpecialCode *_specialCode;
ThreadList *_threads;
- Cursor *_cursor;
ScriptResource *_scriptResource;
@@ -114,6 +120,10 @@ public:
int16 _menuChoiceOfs;
+ int getGameId() const {
+ return _gameDescription->gameId;
+ }
+
Common::Point *getObjectActorPositionPtr(uint32 objectId);
uint32 getElapsedUpdateTime();
int updateActors();
@@ -133,7 +143,7 @@ public:
void setCurrFontId(uint32 fontId);
bool checkActiveTalkThreads();
uint32 clipTextDuration(uint32 duration);
-
+
virtual void loadSpecialCode(uint32 resId) = 0;
virtual void unloadSpecialCode(uint32 resId) = 0;
virtual void notifyThreadId(uint32 &threadId) = 0;
@@ -143,6 +153,13 @@ public:
virtual uint32 getPrevScene() = 0;
virtual uint32 getCurrentScene() = 0;
+ virtual bool isCursorObject(uint32 actorTypeId, uint32 objectId) = 0;
+ virtual void setCursorControlRoutine(Control *control) = 0;
+ virtual void placeCursorControl(Control *control, uint32 sequenceId) = 0;
+ virtual void setCursorControl(Control *control) = 0;
+ virtual void showCursor() = 0;
+ virtual void hideCursor() = 0;
+
virtual void startScriptThreadSimple(uint32 threadId, uint32 callingThreadId) = 0;
virtual uint32 startTempScriptThread(byte *scriptCodeIp, uint32 callingThreadId,
uint32 value8, uint32 valueC, uint32 value10) = 0;
diff --git a/engines/illusions/illusions_bbdou.cpp b/engines/illusions/illusions_bbdou.cpp
index 76d476aa50..84b3876e6c 100644
--- a/engines/illusions/illusions_bbdou.cpp
+++ b/engines/illusions/illusions_bbdou.cpp
@@ -172,7 +172,7 @@ bool ActiveScenes::isSceneActive(uint32 sceneId) {
// IllusionsEngine_BBDOU
-IllusionsEngine_BBDOU::IllusionsEngine_BBDOU(OSystem *syst, const ADGameDescription *gd)
+IllusionsEngine_BBDOU::IllusionsEngine_BBDOU(OSystem *syst, const IllusionsGameDescription *gd)
: IllusionsEngine(syst, gd) {
}
@@ -188,12 +188,9 @@ Common::Error IllusionsEngine_BBDOU::run() {
SearchMan.addSubDirectoryMatching(gameDataDir, "video");
SearchMan.addSubDirectoryMatching(gameDataDir, "voice");
- Graphics::PixelFormat pixelFormat16(2, 5, 6, 5, 0, 11, 5, 0, 0);
- initGraphics(640, 480, true, &pixelFormat16);
-
_dict = new Dictionary();
- _resSys = new ResourceSystem();
+ _resSys = new ResourceSystem(this);
_resSys->addResourceLoader(0x00060000, new ActorResourceLoader(this));
_resSys->addResourceLoader(0x00080000, new SoundGroupResourceLoader(this));
_resSys->addResourceLoader(0x000D0000, new ScriptResourceLoader(this));
@@ -203,7 +200,7 @@ Common::Error IllusionsEngine_BBDOU::run() {
_resSys->addResourceLoader(0x00120000, new FontResourceLoader(this));
_resSys->addResourceLoader(0x00170000, new SpecialCodeLoader(this));
- _screen = new Screen(this);
+ _screen = new Screen(this, 640, 480, 16);
_input = new Input();
_scriptMan = new ScriptMan(this);
_actorItems = new ActorItems(this);
@@ -281,12 +278,9 @@ bool IllusionsEngine_BBDOU::hasFeature(EngineFeature f) const {
bool IllusionsEngine_BBDOU::causeIsDeclared(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId) {
uint32 codeOffs;
- bool r =
+ return
_triggerFunctions->find(sceneId, verbId, objectId2, objectId) ||
findTriggerCause(sceneId, verbId, objectId2, objectId, codeOffs);
- debug(3, "causeIsDeclared() sceneId: %08X; verbId: %08X; objectId2: %08X; objectId: %08X -> %d",
- sceneId, verbId, objectId2, objectId, r);
- return r;
}
void IllusionsEngine_BBDOU::causeDeclare(uint32 verbId, uint32 objectId2, uint32 objectId, TriggerFunctionCallback *callback) {
@@ -352,6 +346,45 @@ uint32 IllusionsEngine_BBDOU::getPrevScene() {
return _prevSceneId;
}
+bool IllusionsEngine_BBDOU::isCursorObject(uint32 actorTypeId, uint32 objectId) {
+ return actorTypeId == 0x50001 && objectId == 0x40004;
+}
+
+void IllusionsEngine_BBDOU::setCursorControlRoutine(Control *control) {
+ control->_actor->setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, IllusionsEngine_BBDOU>
+ (this, &IllusionsEngine_BBDOU::cursorControlRoutine));
+}
+
+void IllusionsEngine_BBDOU::placeCursorControl(Control *control, uint32 sequenceId) {
+ _cursor->place(control, sequenceId);
+}
+
+void IllusionsEngine_BBDOU::setCursorControl(Control *control) {
+ _cursor->setControl(control);
+}
+
+void IllusionsEngine_BBDOU::showCursor() {
+ _cursor->show();
+}
+
+void IllusionsEngine_BBDOU::hideCursor() {
+ _cursor->hide();
+}
+
+void IllusionsEngine_BBDOU::cursorControlRoutine(Control *control, uint32 deltaTime) {
+ control->_actor->_seqCodeValue1 = 100 * deltaTime;
+ if (control->_actor->_flags & 1) {
+ switch (_cursor->_status) {
+ case 2:
+ // Unused nullsub_1(control);
+ break;
+ case 3:
+ // TODO _vm->_shellMgr->handleMouse(control);
+ break;
+ }
+ }
+}
+
void IllusionsEngine_BBDOU::startScriptThreadSimple(uint32 threadId, uint32 callingThreadId) {
startScriptThread(threadId, callingThreadId, 0, 0, 0);
}
diff --git a/engines/illusions/illusions_bbdou.h b/engines/illusions/illusions_bbdou.h
index cd6d8d7d31..d50fe4ce1a 100644
--- a/engines/illusions/illusions_bbdou.h
+++ b/engines/illusions/illusions_bbdou.h
@@ -83,13 +83,14 @@ protected:
class IllusionsEngine_BBDOU : public IllusionsEngine {
public:
- IllusionsEngine_BBDOU(OSystem *syst, const ADGameDescription *gd);
+ IllusionsEngine_BBDOU(OSystem *syst, const IllusionsGameDescription *gd);
protected:
virtual Common::Error run();
virtual bool hasFeature(EngineFeature f) const;
public:
ScriptMan *_scriptMan;
TriggerFunctions *_triggerFunctions;
+ Cursor *_cursor;
ActiveScenes _activeScenes;
uint32 _prevSceneId;
@@ -113,8 +114,16 @@ public:
Control *getObjectControl(uint32 objectId);
Common::Point getNamedPointPosition(uint32 namedPointId);
uint32 getPriorityFromBase(int16 priority);
- uint32 getPrevScene();
uint32 getCurrentScene();
+ uint32 getPrevScene();
+
+ bool isCursorObject(uint32 actorTypeId, uint32 objectId);
+ void setCursorControlRoutine(Control *control);
+ void placeCursorControl(Control *control, uint32 sequenceId);
+ void setCursorControl(Control *control);
+ void showCursor();
+ void hideCursor();
+ void cursorControlRoutine(Control *control, uint32 deltaTime);
void startScriptThreadSimple(uint32 threadId, uint32 callingThreadId);
void startScriptThread(uint32 threadId, uint32 callingThreadId,
diff --git a/engines/illusions/illusions_duckman.cpp b/engines/illusions/illusions_duckman.cpp
new file mode 100644
index 0000000000..74c27889e4
--- /dev/null
+++ b/engines/illusions/illusions_duckman.cpp
@@ -0,0 +1,440 @@
+/* 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_duckman.h"
+#include "illusions/actor.h"
+#include "illusions/actorresource.h"
+#include "illusions/backgroundresource.h"
+#include "illusions/camera.h"
+#include "illusions/cursor.h"
+#include "illusions/dictionary.h"
+#include "illusions/fontresource.h"
+#include "illusions/graphics.h"
+#include "illusions/input.h"
+#include "illusions/midiresource.h"
+#include "illusions/resourcesystem.h"
+#include "illusions/screen.h"
+#include "illusions/scriptopcodes_duckman.h"
+#include "illusions/scriptresource.h"
+#include "illusions/scriptman.h"
+#include "illusions/soundresource.h"
+#include "illusions/specialcode.h"
+//TODO#include "illusions/bbdou/bbdou_specialcode.h"
+#include "illusions/talkresource.h"
+#include "illusions/thread.h"
+#include "illusions/time.h"
+#include "illusions/updatefunctions.h"
+
+#include "illusions/abortablethread.h"
+#include "illusions/scriptthread.h"
+#include "illusions/talkthread_duckman.h"
+#include "illusions/timerthread.h"
+
+#include "audio/audiostream.h"
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "common/fs.h"
+#include "common/timer.h"
+#include "engines/util.h"
+#include "graphics/cursorman.h"
+#include "graphics/font.h"
+#include "graphics/fontman.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+
+namespace Illusions {
+
+// IllusionsEngine_Duckman
+
+IllusionsEngine_Duckman::IllusionsEngine_Duckman(OSystem *syst, const IllusionsGameDescription *gd)
+ : IllusionsEngine(syst, gd) {
+}
+
+Common::Error IllusionsEngine_Duckman::run() {
+
+ // Init search paths
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+ SearchMan.addSubDirectoryMatching(gameDataDir, "music");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "sfx");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "video");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "voice");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "x");// DEBUG until gam reader is done
+
+ _dict = new Dictionary();
+
+ _resSys = new ResourceSystem(this);
+ _resSys->addResourceLoader(0x00060000, new ActorResourceLoader(this));
+ _resSys->addResourceLoader(0x00080000, new SoundGroupResourceLoader(this));
+ _resSys->addResourceLoader(0x000A0000, new MidiGroupResourceLoader(this));
+ _resSys->addResourceLoader(0x000D0000, new ScriptResourceLoader(this));
+ _resSys->addResourceLoader(0x000F0000, new TalkResourceLoader(this));
+ _resSys->addResourceLoader(0x00100000, new ActorResourceLoader(this));
+ _resSys->addResourceLoader(0x00110000, new BackgroundResourceLoader(this));
+ _resSys->addResourceLoader(0x00120000, new FontResourceLoader(this));
+
+ _screen = new Screen(this, 320, 200, 8);
+ _input = new Input();
+ _actorItems = new ActorItems(this);
+ _backgroundItems = new BackgroundItems(this);
+ _camera = new Camera(this);
+ _controls = new Controls(this);
+ _talkItems = new TalkItems(this);
+ _threads = new ThreadList(this);
+
+ _scriptOpcodes = new ScriptOpcodes_Duckman(this);
+ _stack = new ScriptStack();
+
+ // TODO Move to own class
+ _resGetCtr = 0;
+ _unpauseControlActorFlag = false;
+ _lastUpdateTime = 0;
+
+ _pauseCtr = 0;
+ _doScriptThreadInit = false;
+ _field8 = 1;
+ _fieldA = 0;
+ _fieldE = 240;
+
+ _globalSceneId = 0x00010003;
+
+ _resSys->loadResource(0x000D0001, 0x00010001, 0);
+
+ initActiveScenes();
+ startScriptThread(0x00020004, 0);
+ _doScriptThreadInit = true;
+
+ while (!shouldQuit()) {
+ _threads->updateThreads();
+ updateActors();
+ updateSequences();
+ updateGraphics();
+ _screen->updateSprites();
+ _screen->updatePalette();
+ _system->updateScreen();
+ updateEvents();
+ _system->delayMillis(10);
+ }
+
+ delete _stack;
+ delete _scriptOpcodes;
+
+ delete _threads;
+ delete _talkItems;
+ delete _controls;
+ delete _camera;
+ delete _backgroundItems;
+ delete _actorItems;
+ delete _input;
+ delete _screen;
+ delete _resSys;
+ delete _dict;
+
+ debug("Ok");
+
+ return Common::kNoError;
+}
+
+bool IllusionsEngine_Duckman::hasFeature(EngineFeature f) const {
+ return
+ false;
+ /*
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+ */
+}
+
+void IllusionsEngine_Duckman::loadSpecialCode(uint32 resId) {
+//TODO _specialCode = new BbdouSpecialCode(this);
+//TODO _specialCode->init();
+}
+
+void IllusionsEngine_Duckman::unloadSpecialCode(uint32 resId) {
+//TODO delete _specialCode;
+//TODO _specialCode = 0;
+}
+
+void IllusionsEngine_Duckman::notifyThreadId(uint32 &threadId) {
+ if (threadId) {
+ uint32 tempThreadId = threadId;
+ threadId = 0;
+ _threads->notifyId(tempThreadId);
+ }
+}
+
+Control *IllusionsEngine_Duckman::getObjectControl(uint32 objectId) {
+ return _dict->getObjectControl(objectId);
+}
+
+Common::Point IllusionsEngine_Duckman::getNamedPointPosition(uint32 namedPointId) {
+ Common::Point pt;
+ Common::Point currPan = _camera->getCurrentPan();
+ if (_backgroundItems->findActiveBackgroundNamedPoint(namedPointId, pt)) {
+ return pt;
+ } else if (namedPointId - 0x00070001 > 209) {
+ if (_controls->findNamedPoint(namedPointId, pt)) {
+ return pt;
+ } else {
+ return currPan;
+ }
+ } else {
+ // TODO
+ //debug("getNamedPointPosition(%08X) UNKNOWN", namedPointId);
+ return Common::Point(0, 0);
+ }
+}
+
+uint32 IllusionsEngine_Duckman::getPriorityFromBase(int16 priority) {
+ return 32000000 * priority;
+}
+
+uint32 IllusionsEngine_Duckman::getCurrentScene() {
+ return _activeScenes[_activeScenesCount];
+}
+
+uint32 IllusionsEngine_Duckman::getPrevScene() {
+ uint index = _activeScenesCount - 1;
+ if (_activeScenesCount == 1)
+ index = 5;
+ return _activeScenes[index];
+}
+
+bool IllusionsEngine_Duckman::isCursorObject(uint32 actorTypeId, uint32 objectId) {
+ return actorTypeId == 0x50001;
+}
+
+void IllusionsEngine_Duckman::setCursorControlRoutine(Control *control) {
+ control->_actor->setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, IllusionsEngine_Duckman>
+ (this, &IllusionsEngine_Duckman::cursorControlRoutine));
+}
+
+void IllusionsEngine_Duckman::placeCursorControl(Control *control, uint32 sequenceId) {
+ // TODO
+ control->_actor->_actorIndex = 2;
+ // TODO _cursor->place(control, sequenceId);
+}
+
+void IllusionsEngine_Duckman::setCursorControl(Control *control) {
+ // TODO
+}
+
+void IllusionsEngine_Duckman::showCursor() {
+ // TODO
+}
+
+void IllusionsEngine_Duckman::hideCursor() {
+ // TODO
+}
+
+void IllusionsEngine_Duckman::cursorControlRoutine(Control *control, uint32 deltaTime) {
+ control->_actor->_seqCodeValue1 = 100 * deltaTime;
+ // TODO
+}
+
+void IllusionsEngine_Duckman::startScriptThreadSimple(uint32 threadId, uint32 callingThreadId) {
+ startScriptThread(threadId, callingThreadId);
+}
+
+void IllusionsEngine_Duckman::startScriptThread(uint32 threadId, uint32 callingThreadId) {
+ debug(2, "Starting script thread %08X", threadId);
+ byte *scriptCodeIp = _scriptResource->getThreadCode(threadId);
+ newScriptThread(threadId, callingThreadId, 0, scriptCodeIp);
+}
+
+uint32 IllusionsEngine_Duckman::startAbortableTimerThread(uint32 duration, uint32 threadId) {
+ return newTimerThread(duration, threadId, true);
+}
+
+uint32 IllusionsEngine_Duckman::startTimerThread(uint32 duration, uint32 threadId) {
+ return newTimerThread(duration, threadId, false);
+}
+
+uint32 IllusionsEngine_Duckman::startAbortableThread(byte *scriptCodeIp1, byte *scriptCodeIp2, uint32 callingThreadId) {
+ uint32 tempThreadId = newTempThreadId();
+ debug(2, "Starting abortable thread %08X", tempThreadId);
+ uint32 scriptThreadId = startTempScriptThread(scriptCodeIp1, tempThreadId, 0, 0, 0);
+ AbortableThread *abortableThread = new AbortableThread(this, tempThreadId, callingThreadId, 0,
+ scriptThreadId, scriptCodeIp2);
+ _threads->startThread(abortableThread);
+ return tempThreadId;
+}
+
+uint32 IllusionsEngine_Duckman::startTalkThread(uint32 objectId, uint32 talkId, uint32 sequenceId1,
+ uint32 sequenceId2, uint32 callingThreadId) {
+ debug(2, "Starting talk thread");
+ uint32 tempThreadId = newTempThreadId();
+ TalkThread_Duckman *talkThread = new TalkThread_Duckman(this, tempThreadId, callingThreadId, 0,
+ objectId, talkId, sequenceId1, sequenceId2);
+ _threads->startThread(talkThread);
+ return tempThreadId;
+}
+
+uint32 IllusionsEngine_Duckman::startTempScriptThread(byte *scriptCodeIp, uint32 callingThreadId,
+ uint32 value8, uint32 valueC, uint32 value10) {
+ uint32 tempThreadId = newTempThreadId();
+ debug(2, "Starting temp script thread %08X", tempThreadId);
+ newScriptThread(tempThreadId, callingThreadId, 0, scriptCodeIp);
+ return tempThreadId;
+}
+
+void IllusionsEngine_Duckman::newScriptThread(uint32 threadId, uint32 callingThreadId, uint notifyFlags,
+ byte *scriptCodeIp) {
+ ScriptThread *scriptThread = new ScriptThread(this, threadId, callingThreadId, notifyFlags,
+ scriptCodeIp, 0, 0, 0);
+ _threads->startThread(scriptThread);
+ if (_pauseCtr > 0)
+ scriptThread->pause();
+ if (_doScriptThreadInit) {
+ int updateResult = kTSRun;
+ while (scriptThread->_pauseCtr <= 0 && updateResult != kTSTerminate && updateResult != kTSYield)
+ updateResult = scriptThread->update();
+ }
+}
+
+uint32 IllusionsEngine_Duckman::newTimerThread(uint32 duration, uint32 callingThreadId, bool isAbortable) {
+ uint32 tempThreadId = newTempThreadId();
+ TimerThread *timerThread = new TimerThread(this, tempThreadId, callingThreadId, 0,
+ duration, isAbortable);
+ _threads->startThread(timerThread);
+ return tempThreadId;
+}
+
+uint32 IllusionsEngine_Duckman::newTempThreadId() {
+ uint32 threadId = _nextTempThreadId + 2 * _scriptResource->_codeCount;
+ if (threadId > 65535) {
+ _nextTempThreadId = 0;
+ threadId = 2 * _scriptResource->_codeCount;
+ }
+ ++_nextTempThreadId;
+ return 0x00020000 | threadId;
+}
+
+void IllusionsEngine_Duckman::initActiveScenes() {
+ _activeScenesCount = 0;
+ _activeScenes[0] = 0xEFEF;
+ pushActiveScene(0x10000);
+}
+
+void IllusionsEngine_Duckman::pushActiveScene(uint32 sceneId) {
+ ++_activeScenesCount;
+ if (_activeScenesCount >= 6)
+ _activeScenesCount = 1;
+ _activeScenes[_activeScenesCount] = sceneId;
+}
+
+void IllusionsEngine_Duckman::popActiveScene() {
+ --_activeScenesCount;
+ if (_activeScenesCount == 0)
+ _activeScenesCount = 5;
+}
+
+bool IllusionsEngine_Duckman::loadScene(uint32 sceneId) {
+ ProgInfo *progInfo = _scriptResource->getProgInfo(sceneId & 0xFFFF);
+ if (!progInfo)
+ return false;
+ pushActiveScene(sceneId);
+ uint resourcesCount;
+ uint32 *resources;
+ progInfo->getResources(resourcesCount, resources);
+ for (uint i = 0; i < resourcesCount; ++i)
+ _resSys->loadResource(resources[i], sceneId, 0);
+ return true;
+}
+
+bool IllusionsEngine_Duckman::enterScene(uint32 sceneId, uint32 threadId) {
+ if (loadScene(sceneId)) {
+ if (threadId)
+ startScriptThread(threadId, 0);
+ return true;
+ }
+ // TODO startScriptThread2(0x10002, 0x20001, 0);
+ return false;
+}
+
+void IllusionsEngine_Duckman::exitScene() {
+ popActiveScene();
+}
+
+bool IllusionsEngine_Duckman::changeScene(uint32 sceneId, uint32 threadId, uint32 callerThreadId) {
+ uint32 currSceneId = getCurrentScene();
+ if (currSceneId != 0x10003)
+ dumpCurrSceneFiles(currSceneId, callerThreadId);
+ _threads->terminateThreads(callerThreadId);
+ _controls->destroyControls();
+ _resSys->unloadSceneResources(0x10003, 0x10001);
+ if (enterScene(sceneId, threadId)) {
+ // TODO GameStates_writeStates(sceneId, threadId);
+ return true;
+ }
+ return false;
+}
+
+void IllusionsEngine_Duckman::enterPause(uint32 sceneId, uint32 threadId) {
+ _threads->suspendThreads(threadId);
+ _controls->pauseControls();
+ _actorItems->pauseByTag(sceneId);
+ _backgroundItems->pauseByTag(sceneId);
+}
+
+void IllusionsEngine_Duckman::leavePause(uint32 sceneId, uint32 threadId) {
+ _backgroundItems->unpauseByTag(sceneId);
+ _actorItems->unpauseByTag(sceneId);
+ _controls->unpauseControls();
+ _threads->notifyThreads(threadId);
+}
+
+void IllusionsEngine_Duckman::dumpActiveScenes(uint32 sceneId, uint32 threadId) {
+ // TODO
+}
+
+void IllusionsEngine_Duckman::dumpCurrSceneFiles(uint32 sceneId, uint32 threadId) {
+ // TODO UpdateFunctions_disableByTag(sceneId);
+ _threads->terminateActiveThreads(threadId);
+ _threads->terminateThreadsByTag(sceneId, threadId);
+ _controls->destroyActiveControls();
+ _resSys->unloadResourcesByTag(sceneId);
+}
+
+void IllusionsEngine_Duckman::setSceneIdThreadId(uint32 theSceneId, uint32 theThreadId) {
+ _theSceneId = theSceneId;
+ _theThreadId = theThreadId;
+}
+
+bool IllusionsEngine_Duckman::findTriggerCause(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, uint32 &codeOffs) {
+ ProgInfo *progInfo = _scriptResource->getProgInfo(sceneId & 0xFFFF);
+ if (progInfo)
+ return progInfo->findTriggerCause(verbId, objectId2, objectId, codeOffs);
+ return false;
+}
+
+void IllusionsEngine_Duckman::reset() {
+ _scriptResource->_blockCounters.clear();
+ _scriptResource->_properties.clear();
+ // TODO script_sub_417FF0(1, 0);
+}
+
+uint32 IllusionsEngine_Duckman::getObjectActorTypeId(uint32 objectId) {
+ return _scriptResource->getObjectActorTypeId(objectId);
+}
+
+} // End of namespace Illusions
diff --git a/engines/illusions/illusions_duckman.h b/engines/illusions/illusions_duckman.h
new file mode 100644
index 0000000000..f70156af88
--- /dev/null
+++ b/engines/illusions/illusions_duckman.h
@@ -0,0 +1,111 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ILLUSIONS_ILLUSIONS_DUCKMAN_H
+#define ILLUSIONS_ILLUSIONS_DUCKMAN_H
+
+#include "illusions/illusions.h"
+#include "common/algorithm.h"
+#include "common/stack.h"
+
+namespace Illusions {
+
+class Dictionary;
+class ScriptStack;
+
+class IllusionsEngine_Duckman : public IllusionsEngine {
+public:
+ IllusionsEngine_Duckman(OSystem *syst, const IllusionsGameDescription *gd);
+protected:
+ virtual Common::Error run();
+ virtual bool hasFeature(EngineFeature f) const;
+public:
+
+ // TODO ActiveScenes _activeScenes;
+ uint32 _prevSceneId;
+ uint32 _theSceneId;
+ uint32 _theThreadId;
+ uint32 _globalSceneId;
+
+ int _pauseCtr;
+ ScriptStack *_stack;
+ bool _doScriptThreadInit;
+
+ uint32 _nextTempThreadId;
+
+ uint _activeScenesCount;
+ uint32 _activeScenes[6];
+
+ void loadSpecialCode(uint32 resId);
+ void unloadSpecialCode(uint32 resId);
+ void notifyThreadId(uint32 &threadId);
+ Control *getObjectControl(uint32 objectId);
+ Common::Point getNamedPointPosition(uint32 namedPointId);
+ uint32 getPriorityFromBase(int16 priority);
+ uint32 getCurrentScene();
+ uint32 getPrevScene();
+
+ bool isCursorObject(uint32 actorTypeId, uint32 objectId);
+ void setCursorControlRoutine(Control *control);
+ void placeCursorControl(Control *control, uint32 sequenceId);
+ void setCursorControl(Control *control);
+ void showCursor();
+ void hideCursor();
+ void cursorControlRoutine(Control *control, uint32 deltaTime);
+
+ void startScriptThreadSimple(uint32 threadId, uint32 callingThreadId);
+ void startScriptThread(uint32 threadId, uint32 callingThreadId);
+ uint32 startAbortableTimerThread(uint32 duration, uint32 threadId);
+ uint32 startTimerThread(uint32 duration, uint32 threadId);
+ uint32 startAbortableThread(byte *scriptCodeIp1, byte *scriptCodeIp2, uint32 callingThreadId);
+ uint32 startTalkThread(uint32 objectId, uint32 talkId, uint32 sequenceId1,
+ uint32 sequenceId2, uint32 callingThreadId);
+ uint32 startTempScriptThread(byte *scriptCodeIp, uint32 callingThreadId,
+ uint32 value8, uint32 valueC, uint32 value10);
+ void newScriptThread(uint32 threadId, uint32 callingThreadId, uint notifyFlags,
+ byte *scriptCodeIp);
+ uint32 newTimerThread(uint32 duration, uint32 callingThreadId, bool isAbortable);
+ uint32 newTempThreadId();
+
+ void initActiveScenes();
+ void pushActiveScene(uint32 sceneId);
+ void popActiveScene();
+ bool loadScene(uint32 sceneId);
+ bool enterScene(uint32 sceneId, uint32 threadId);
+ void exitScene();
+ bool changeScene(uint32 sceneId, uint32 threadId, uint32 callerThreadId);
+ void enterPause(uint32 sceneId, uint32 threadId);
+ void leavePause(uint32 sceneId, uint32 threadId);
+ void dumpActiveScenes(uint32 sceneId, uint32 threadId);
+ void dumpCurrSceneFiles(uint32 sceneId, uint32 threadId);
+
+ void setSceneIdThreadId(uint32 theSceneId, uint32 theThreadId);
+ bool findTriggerCause(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, uint32 &codeOffs);
+ void reset();
+
+ uint32 getObjectActorTypeId(uint32 objectId);
+
+};
+
+} // End of namespace Illusions
+
+#endif // ILLUSIONS_ILLUSIONS_H
diff --git a/engines/illusions/midiresource.cpp b/engines/illusions/midiresource.cpp
new file mode 100644
index 0000000000..b6e181e2c7
--- /dev/null
+++ b/engines/illusions/midiresource.cpp
@@ -0,0 +1,48 @@
+/* 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/midiresource.h"
+
+namespace Illusions {
+
+// MidiGroupResourceLoader
+
+void MidiGroupResourceLoader::load(Resource *resource) {
+ debug("MidiGroupResourceLoader::load() Loading midi group %08X...", resource->_resId);
+
+ // TODO
+
+}
+
+void MidiGroupResourceLoader::unload(Resource *resource) {
+}
+
+void MidiGroupResourceLoader::buildFilename(Resource *resource) {
+ resource->_filename = Common::String::format("%08X.fnt", resource->_resId);
+}
+
+bool MidiGroupResourceLoader::isFlag(int flag) {
+ return false;
+}
+
+} // End of namespace Illusions
diff --git a/engines/illusions/midiresource.h b/engines/illusions/midiresource.h
new file mode 100644
index 0000000000..54ad8765be
--- /dev/null
+++ b/engines/illusions/midiresource.h
@@ -0,0 +1,47 @@
+/* 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_MIDIRESOURCE_H
+#define ILLUSIONS_MIDIRESOURCE_H
+
+#include "illusions/graphics.h"
+#include "illusions/resourcesystem.h"
+
+namespace Illusions {
+
+class IllusionsEngine;
+
+class MidiGroupResourceLoader : public BaseResourceLoader {
+public:
+ MidiGroupResourceLoader(IllusionsEngine *vm) : _vm(vm) {}
+ virtual ~MidiGroupResourceLoader() {}
+ virtual void load(Resource *resource);
+ virtual void unload(Resource *resource);
+ virtual void buildFilename(Resource *resource);
+ virtual bool isFlag(int flag);
+protected:
+ IllusionsEngine *_vm;
+};
+
+} // End of namespace Illusions
+
+#endif // ILLUSIONS_SOUNDRESOURCE_H
diff --git a/engines/illusions/module.mk b/engines/illusions/module.mk
index 63bf8260e8..4341732657 100644
--- a/engines/illusions/module.mk
+++ b/engines/illusions/module.mk
@@ -18,12 +18,15 @@ MODULE_OBJS := \
graphics.o \
illusions.o \
illusions_bbdou.o \
+ illusions_duckman.o \
input.o \
+ midiresource.o \
resourcesystem.o \
screen.o \
scriptman.o \
scriptopcodes.o \
scriptopcodes_bbdou.o \
+ scriptopcodes_duckman.o \
scriptresource.o \
scriptthread.o \
sequenceopcodes.o \
@@ -31,6 +34,7 @@ MODULE_OBJS := \
specialcode.o \
talkresource.o \
talkthread.o \
+ talkthread_duckman.o \
thread.o \
time.o \
timerthread.o \
diff --git a/engines/illusions/resourcesystem.cpp b/engines/illusions/resourcesystem.cpp
index 01a076bac0..3d99541579 100644
--- a/engines/illusions/resourcesystem.cpp
+++ b/engines/illusions/resourcesystem.cpp
@@ -21,6 +21,7 @@
*/
#include "illusions/resourcesystem.h"
+#include "illusions/illusions.h"
#include "common/algorithm.h"
#include "common/debug.h"
@@ -38,6 +39,7 @@ void Resource::loadData() {
_dataSize = fd.size();
_data = (byte*)malloc(_dataSize);
fd.read(_data, _dataSize);
+ debug("Resource::loadData() OK");
}
void Resource::unloadData() {
@@ -50,7 +52,8 @@ void Resource::unloadData() {
// ResourceSystem
-ResourceSystem::ResourceSystem() {
+ResourceSystem::ResourceSystem(IllusionsEngine *vm)
+ : _vm(vm) {
}
ResourceSystem::~ResourceSystem() {
@@ -64,6 +67,7 @@ void ResourceSystem::addResourceLoader(uint32 resTypeId, BaseResourceLoader *res
}
void ResourceSystem::loadResource(uint32 resId, uint32 tag, uint32 threadId) {
+ debug("ResourceSystem::loadResource(%08X, %08X, %08X)", resId, tag, threadId);
BaseResourceLoader *resourceLoader = getResourceLoader(resId);
Resource *resource = new Resource();
@@ -72,6 +76,7 @@ void ResourceSystem::loadResource(uint32 resId, uint32 tag, uint32 threadId) {
resource->_tag = tag;
resource->_threadId = threadId;
resource->_resourceLoader = resourceLoader;
+ resource->_gameId = _vm->getGameId();
resourceLoader->buildFilename(resource);
@@ -108,6 +113,14 @@ void ResourceSystem::unloadResourcesByTag(uint32 tag) {
}
}
+void ResourceSystem::unloadSceneResources(uint32 sceneId1, uint32 sceneId2) {
+ ResourcesArrayIterator it = Common::find_if(_resources.begin(), _resources.end(), ResourceNotEqualByScenes(sceneId1, sceneId2));
+ while (it != _resources.end()) {
+ unloadResource(*it);
+ it = Common::find_if(it, _resources.end(), ResourceNotEqualByScenes(sceneId1, sceneId2));
+ }
+}
+
BaseResourceLoader *ResourceSystem::getResourceLoader(uint32 resId) {
ResourceLoadersMapIterator it = _resourceLoaders.find(ResourceTypeId(resId));
if (it != _resourceLoaders.end())
@@ -121,6 +134,7 @@ Resource *ResourceSystem::getResource(uint32 resId) {
}
void ResourceSystem::unloadResource(Resource *resource) {
+ debug("Unloading %08X... (tag: %08X)", resource->_resId, resource->_tag);
resource->_resourceLoader->unload(resource);
ResourcesArrayIterator it = Common::find_if(_resources.begin(), _resources.end(), ResourceEqualByValue(resource));
if (it != _resources.end())
diff --git a/engines/illusions/resourcesystem.h b/engines/illusions/resourcesystem.h
index 833a7db112..0a214c5a2a 100644
--- a/engines/illusions/resourcesystem.h
+++ b/engines/illusions/resourcesystem.h
@@ -36,6 +36,7 @@ namespace Illusions {
#define ResourceTypeId(x) ((x) & 0xFFFF0000)
class BaseResourceLoader;
+class IllusionsEngine;
struct Resource {
bool _loaded;
@@ -46,7 +47,8 @@ struct Resource {
uint32 _dataSize;
BaseResourceLoader *_resourceLoader;
void *_refId;
- Common::String _filename; // TODO Check if this is needed
+ int _gameId;
+ Common::String _filename;
Resource() : _loaded(false), _resId(0), _tag(0), _threadId(0), _data(0), _dataSize(0),
_resourceLoader(0), _refId(0) {}
~Resource() {
@@ -80,7 +82,7 @@ public:
class ResourceSystem {
public:
- ResourceSystem();
+ ResourceSystem(IllusionsEngine *vm);
~ResourceSystem();
void addResourceLoader(uint32 resTypeId, BaseResourceLoader *resourceLoader);
@@ -89,10 +91,12 @@ public:
void loadResource(uint32 resId, uint32 tag, uint32 threadId);
void unloadResourceById(uint32 resId);
void unloadResourcesByTag(uint32 tag);
-
+ void unloadSceneResources(uint32 sceneId1, uint32 sceneId2);
+
protected:
typedef Common::HashMap<uint32, BaseResourceLoader*> ResourceLoadersMap;
typedef ResourceLoadersMap::iterator ResourceLoadersMapIterator;
+ IllusionsEngine *_vm;
ResourceLoadersMap _resourceLoaders;
BaseResourceLoader *getResourceLoader(uint32 resId);
@@ -124,6 +128,14 @@ protected:
}
};
+ struct ResourceNotEqualByScenes : public Common::UnaryFunction<const Resource*, bool> {
+ uint32 _sceneId1, _sceneId2;
+ ResourceNotEqualByScenes(uint32 sceneId1, uint32 sceneId2) : _sceneId1(sceneId1), _sceneId2(sceneId2) {}
+ bool operator()(const Resource *resource) const {
+ return resource->_tag != _sceneId1 && resource->_tag != _sceneId2;
+ }
+ };
+
Resource *getResource(uint32 resId);
void unloadResource(Resource *resource);
diff --git a/engines/illusions/screen.cpp b/engines/illusions/screen.cpp
index 9e03a40bd9..0eb78321a9 100644
--- a/engines/illusions/screen.cpp
+++ b/engines/illusions/screen.cpp
@@ -22,12 +22,15 @@
#include "illusions/illusions.h"
#include "illusions/screen.h"
+#include "engines/util.h"
+#include "graphics/palette.h"
namespace Illusions {
// SpriteDecompressQueue
-SpriteDecompressQueue::SpriteDecompressQueue() {
+SpriteDecompressQueue::SpriteDecompressQueue(Screen *screen)
+ : _screen(screen) {
}
SpriteDecompressQueue::~SpriteDecompressQueue() {
@@ -56,80 +59,7 @@ void SpriteDecompressQueue::decompressAll() {
}
void SpriteDecompressQueue::decompress(SpriteDecompressQueueItem *item) {
- byte *src = item->_compressedPixels;
- Graphics::Surface *dstSurface = item->_surface;
- int dstSize = item->_dimensions._width * item->_dimensions._height;
- int processedSize = 0;
- int xincr, x, xstart;
- int yincr, y;
-
- // Safeguard
- if (item->_dimensions._width > item->_surface->w ||
- item->_dimensions._height > item->_surface->h) {
- debug("Incorrect frame dimensions (%d, %d <> %d, %d)",
- item->_dimensions._width, item->_dimensions._height,
- item->_surface->w, item->_surface->h);
- return;
- }
-
- if (item->_flags & 1) {
- x = xstart = item->_dimensions._width - 1;
- xincr = -1;
- } else {
- x = xstart = 0;
- xincr = 1;
- }
-
- if (item->_flags & 2) {
- y = item->_dimensions._height - 1;
- yincr = -1;
- } else {
- y = 0;
- yincr = 1;
- }
-
- byte *dst = (byte*)dstSurface->getBasePtr(x, y);
-
- while (processedSize < dstSize) {
- int16 op = READ_LE_UINT16(src);
- src += 2;
- if (op & 0x8000) {
- int runCount = (op & 0x7FFF) + 1;
- processedSize += runCount;
- uint16 runColor = READ_LE_UINT16(src);
- src += 2;
- while (runCount--) {
- WRITE_LE_UINT16(dst, runColor);
- x += xincr;
- if (x >= item->_dimensions._width || x < 0) {
- x = xstart;
- y += yincr;
- dst = (byte*)dstSurface->getBasePtr(x, y);
- } else {
- dst += 2 * xincr;
- }
- }
- } else {
- int copyCount = op + 1;
- processedSize += copyCount;
- while (copyCount--) {
- uint16 color = READ_LE_UINT16(src);
- src += 2;
- WRITE_LE_UINT16(dst, color);
- x += xincr;
- if (x >= item->_dimensions._width || x < 0) {
- x = xstart;
- y += yincr;
- dst = (byte*)dstSurface->getBasePtr(x, y);
- } else {
- dst += 2 * xincr;
- }
- }
- }
- }
-
- *item->_drawFlags &= ~1;
-
+ _screen->decompressSprite(item);
}
// SpriteDrawQueue
@@ -258,7 +188,7 @@ bool SpriteDrawQueue::calcItemRect(SpriteDrawQueueItem *item, Common::Rect &srcR
*/
// Check if the sprite is on-screen
- if (dstRect.left >= 640 || dstRect.right <= 0 || dstRect.top >= 480 || dstRect.bottom <= 0)
+ if (dstRect.left >= _screen->getScreenWidth() || dstRect.right <= 0 || dstRect.top >= _screen->getScreenHeight() || dstRect.bottom <= 0)
return false;
// Clip the sprite rect if neccessary
@@ -273,14 +203,14 @@ bool SpriteDrawQueue::calcItemRect(SpriteDrawQueueItem *item, Common::Rect &srcR
dstRect.top = 0;
}
- if (dstRect.right > 640) {
- srcRect.right += 100 * (640 - dstRect.right) / item->_scale;
- dstRect.right = 640;
+ if (dstRect.right > _screen->getScreenWidth()) {
+ srcRect.right += 100 * (_screen->getScreenWidth() - dstRect.right) / item->_scale;
+ dstRect.right = _screen->getScreenWidth();
}
- if (dstRect.bottom > 480) {
- srcRect.bottom += 100 * (480 - dstRect.bottom) / item->_scale;
- dstRect.bottom = 480;
+ if (dstRect.bottom > _screen->getScreenHeight()) {
+ srcRect.bottom += 100 * (_screen->getScreenHeight() - dstRect.bottom) / item->_scale;
+ dstRect.bottom = _screen->getScreenHeight();
}
return true;
@@ -288,13 +218,24 @@ bool SpriteDrawQueue::calcItemRect(SpriteDrawQueueItem *item, Common::Rect &srcR
// Screen
-Screen::Screen(IllusionsEngine *vm)
+Screen::Screen(IllusionsEngine *vm, int16 width, int16 height, int bpp)
: _vm(vm), _colorKey2(0) {
_displayOn = true;
- _backSurface = allocSurface(640, 480);
- _decompressQueue = new SpriteDecompressQueue();
+ _decompressQueue = new SpriteDecompressQueue(this);
_drawQueue = new SpriteDrawQueue(this);
_colorKey1 = 0xF800 | 0x1F;
+ if (bpp == 8) {
+ initGraphics(width, height, false);
+ } else {
+ Graphics::PixelFormat pixelFormat16(2, 5, 6, 5, 0, 11, 5, 0, 0);
+ initGraphics(width, height, true, &pixelFormat16);
+ }
+
+ _backSurface = allocSurface(width, height);
+
+ _needRefreshPalette = false;
+ memset(_mainPalette, 0, sizeof(_mainPalette));
+
}
Screen::~Screen() {
@@ -336,7 +277,295 @@ void Screen::updateSprites() {
g_system->copyRectToScreen((byte*)_backSurface->getBasePtr(0, 0), _backSurface->pitch, 0, 0, _backSurface->w, _backSurface->h);
}
+void Screen::decompressSprite(SpriteDecompressQueueItem *item) {
+ switch (_backSurface->format.bytesPerPixel) {
+ case 1:
+ decompressSprite8(item);
+ break;
+ case 2:
+ decompressSprite16(item);
+ break;
+ default:
+ break;
+ }
+}
+
void Screen::drawSurface(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, int16 scale, uint32 flags) {
+ switch (_backSurface->format.bytesPerPixel) {
+ case 1:
+ drawSurface8(dstRect, surface, srcRect, scale, flags);
+ break;
+ case 2:
+ drawSurface16(dstRect, surface, srcRect, scale, flags);
+ break;
+ default:
+ break;
+ }
+}
+
+void Screen::setPalette(byte *colors, uint start, uint count) {
+ byte *dstPal = &_mainPalette[3 * (start - 1)];
+ for (uint i = 0; i < count; ++i) {
+ *dstPal++ = *colors++;
+ *dstPal++ = *colors++;
+ *dstPal++ = *colors++;
+ ++colors;
+ }
+ // TODO Build colorTransTbl
+ _needRefreshPalette = true;
+}
+
+void Screen::getPalette(byte *colors) {
+ byte *srcPal = _mainPalette;
+ for (uint i = 0; i < 256; ++i) {
+ *colors++ = *srcPal++;
+ *colors++ = *srcPal++;
+ *colors++ = *srcPal++;
+ ++colors;
+ }
+}
+
+void Screen::updatePalette() {
+ if (_needRefreshPalette) {
+ // TODO Update fader palette
+ setSystemPalette(_mainPalette);
+ _needRefreshPalette = false;
+ }
+}
+
+void Screen::setSystemPalette(byte *palette) {
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+}
+
+void Screen::decompressSprite8(SpriteDecompressQueueItem *item) {
+ byte *src = item->_compressedPixels;
+ Graphics::Surface *dstSurface = item->_surface;
+ int dstSize = item->_dimensions._width * item->_dimensions._height;
+ int processedSize = 0;
+ int xincr, x, xstart;
+ int yincr, y;
+
+ *item->_drawFlags &= ~1;
+
+ // Safeguard
+ if (item->_dimensions._width > item->_surface->w ||
+ item->_dimensions._height > item->_surface->h) {
+ debug("Incorrect frame dimensions (%d, %d <> %d, %d)",
+ item->_dimensions._width, item->_dimensions._height,
+ item->_surface->w, item->_surface->h);
+ return;
+ }
+
+ if (item->_flags & 1) {
+ x = xstart = item->_dimensions._width - 1;
+ xincr = -1;
+ } else {
+ x = xstart = 0;
+ xincr = 1;
+ }
+
+ if (item->_flags & 2) {
+ y = item->_dimensions._height - 1;
+ yincr = -1;
+ } else {
+ y = 0;
+ yincr = 1;
+ }
+
+ byte *dst = (byte*)dstSurface->getBasePtr(x, y);
+
+ while (processedSize < dstSize) {
+ byte op = *src++;
+ if (op & 0x80) {
+ int runCount = (op & 0x7F) + 1;
+ processedSize += runCount;
+ byte runColor = *src++;
+ while (runCount--) {
+ *dst = runColor;
+ x += xincr;
+ if (x >= item->_dimensions._width || x < 0) {
+ x = xstart;
+ y += yincr;
+ dst = (byte*)dstSurface->getBasePtr(x, y);
+ } else {
+ dst += xincr;
+ }
+ }
+ } else {
+ int copyCount = op + 1;
+ processedSize += copyCount;
+ while (copyCount--) {
+ byte color = *src++;
+ *dst = color;
+ x += xincr;
+ if (x >= item->_dimensions._width || x < 0) {
+ x = xstart;
+ y += yincr;
+ dst = (byte*)dstSurface->getBasePtr(x, y);
+ } else {
+ dst += xincr;
+ }
+ }
+ }
+ }
+
+}
+
+void Screen::drawSurface8(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, int16 scale, uint32 flags) {
+ drawSurface81(dstRect.left, dstRect.top, surface, srcRect);
+ /*
+ if (scale == 100) {
+ drawSurface81(dstRect.left, dstRect.top, surface, srcRect);
+ } else {
+ drawSurface82(dstRect, surface, srcRect);
+ }
+ */
+}
+
+void Screen::drawSurface81(int16 destX, int16 destY, Graphics::Surface *surface, Common::Rect &srcRect) {
+ // Unscaled
+ const int16 w = srcRect.width();
+ const int16 h = srcRect.height();
+ for (int16 yc = 0; yc < h; ++yc) {
+ byte *src = (byte*)surface->getBasePtr(srcRect.left, srcRect.top + yc);
+ byte *dst = (byte*)_backSurface->getBasePtr(destX, destY + yc);
+ for (int16 xc = 0; xc < w; ++xc) {
+ byte pixel = *src++;
+ if (pixel != 0)
+ *dst = pixel;
+ ++dst;
+ }
+ }
+}
+
+void Screen::drawSurface82(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect) {
+ // Scaled
+ const int dstWidth = dstRect.width(), dstHeight = dstRect.height();
+ const int srcWidth = srcRect.width(), srcHeight = srcRect.height();
+ const int errYStart = srcHeight / dstHeight;
+ const int errYIncr = srcHeight % dstHeight;
+ const int midY = dstHeight / 2;
+ const int errXStart = srcWidth / dstWidth;
+ const int errXIncr = srcWidth % dstWidth;
+ const int midX = dstWidth / 2;
+ int h = dstHeight, errY = 0, skipY, srcY = srcRect.top;
+ byte *dst = (byte*)_backSurface->getBasePtr(dstRect.left, dstRect.top);
+ skipY = (dstHeight < srcHeight) ? 0 : dstHeight / (2*srcHeight) + 1;
+ h -= skipY;
+ while (h-- > 0) {
+ int w = dstWidth, errX = 0, skipX;
+ skipX = (dstWidth < srcWidth) ? 0 : dstWidth / (2*srcWidth) + 1;
+ w -= skipX;
+ byte *src = (byte*)surface->getBasePtr(srcRect.left, srcY);
+ byte *dstRow = dst;
+ while (w-- > 0) {
+ byte pixel = *src;
+ if (pixel != 0) {
+ *dstRow = pixel;
+ }
+ ++dstRow;
+ src += errXStart;
+ errX += errXIncr;
+ if (errX >= dstWidth) {
+ errX -= dstWidth;
+ ++src;
+ }
+ }
+ while (skipX-- > 0) {
+ byte pixel = *src;
+ if (pixel != 0)
+ *dstRow = pixel;
+ ++src;
+ ++dstRow;
+ }
+ dst += _backSurface->pitch;
+ srcY += errYStart;
+ errY += errYIncr;
+ if (errY >= dstHeight) {
+ errY -= dstHeight;
+ ++srcY;
+ }
+ }
+}
+
+void Screen::decompressSprite16(SpriteDecompressQueueItem *item) {
+ byte *src = item->_compressedPixels;
+ Graphics::Surface *dstSurface = item->_surface;
+ int dstSize = item->_dimensions._width * item->_dimensions._height;
+ int processedSize = 0;
+ int xincr, x, xstart;
+ int yincr, y;
+
+ *item->_drawFlags &= ~1;
+
+ // Safeguard
+ if (item->_dimensions._width > item->_surface->w ||
+ item->_dimensions._height > item->_surface->h) {
+ debug("Incorrect frame dimensions (%d, %d <> %d, %d)",
+ item->_dimensions._width, item->_dimensions._height,
+ item->_surface->w, item->_surface->h);
+ return;
+ }
+
+ if (item->_flags & 1) {
+ x = xstart = item->_dimensions._width - 1;
+ xincr = -1;
+ } else {
+ x = xstart = 0;
+ xincr = 1;
+ }
+
+ if (item->_flags & 2) {
+ y = item->_dimensions._height - 1;
+ yincr = -1;
+ } else {
+ y = 0;
+ yincr = 1;
+ }
+
+ byte *dst = (byte*)dstSurface->getBasePtr(x, y);
+
+ while (processedSize < dstSize) {
+ int16 op = READ_LE_UINT16(src);
+ src += 2;
+ if (op & 0x8000) {
+ int runCount = (op & 0x7FFF) + 1;
+ processedSize += runCount;
+ uint16 runColor = READ_LE_UINT16(src);
+ src += 2;
+ while (runCount--) {
+ WRITE_LE_UINT16(dst, runColor);
+ x += xincr;
+ if (x >= item->_dimensions._width || x < 0) {
+ x = xstart;
+ y += yincr;
+ dst = (byte*)dstSurface->getBasePtr(x, y);
+ } else {
+ dst += 2 * xincr;
+ }
+ }
+ } else {
+ int copyCount = op + 1;
+ processedSize += copyCount;
+ while (copyCount--) {
+ uint16 color = READ_LE_UINT16(src);
+ src += 2;
+ WRITE_LE_UINT16(dst, color);
+ x += xincr;
+ if (x >= item->_dimensions._width || x < 0) {
+ x = xstart;
+ y += yincr;
+ dst = (byte*)dstSurface->getBasePtr(x, y);
+ } else {
+ dst += 2 * xincr;
+ }
+ }
+ }
+ }
+
+}
+
+void Screen::drawSurface16(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, int16 scale, uint32 flags) {
if (scale == 100) {
if (flags & 1)
drawSurface10(dstRect.left, dstRect.top, surface, srcRect, _colorKey2);
diff --git a/engines/illusions/screen.h b/engines/illusions/screen.h
index cfeaba63bc..5bd5eb79ce 100644
--- a/engines/illusions/screen.h
+++ b/engines/illusions/screen.h
@@ -44,7 +44,7 @@ struct SpriteDecompressQueueItem {
class SpriteDecompressQueue {
public:
- SpriteDecompressQueue();
+ SpriteDecompressQueue(Screen *screen);
~SpriteDecompressQueue();
void insert(byte *drawFlags, uint32 flags, uint32 field8, WidthHeight &dimensions,
byte *compressedPixels, Graphics::Surface *surface);
@@ -52,6 +52,7 @@ public:
protected:
typedef Common::List<SpriteDecompressQueueItem*> SpriteDecompressQueueList;
typedef SpriteDecompressQueueList::iterator SpriteDecompressQueueListIterator;
+ Screen *_screen;
SpriteDecompressQueueList _queue;
void decompress(SpriteDecompressQueueItem *item);
};
@@ -96,9 +97,11 @@ protected:
bool calcItemRect(SpriteDrawQueueItem *item, Common::Rect &srcRect, Common::Rect &dstRect);
};
+// TODO Split into two classes (8bit and 16bit)?
+
class Screen {
public:
- Screen(IllusionsEngine *vm);
+ Screen(IllusionsEngine *vm, int16 width, int16 height, int bpp);
~Screen();
Graphics::Surface *allocSurface(int16 width, int16 height);
Graphics::Surface *allocSurface(SurfInfo &surfInfo);
@@ -106,11 +109,13 @@ public:
void setDisplayOn(bool isOn);
uint16 getColorKey2();
void updateSprites();
+ void decompressSprite(SpriteDecompressQueueItem *item);
void drawSurface(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, int16 scale, uint32 flags);
- void drawSurface10(int16 destX, int16 destY, Graphics::Surface *surface, Common::Rect &srcRect, uint16 colorKey);
- void drawSurface11(int16 destX, int16 destY, Graphics::Surface *surface, Common::Rect &srcRect);
- void drawSurface20(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, uint16 colorKey);
- void drawSurface21(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect);
+ void setPalette(byte *colors, uint start, uint count);
+ void getPalette(byte *colors);
+ void updatePalette();
+ int16 getScreenWidth() const { return _backSurface->w; }
+ int16 getScreenHeight() const { return _backSurface->h; }
public:
IllusionsEngine *_vm;
bool _displayOn;
@@ -119,6 +124,23 @@ public:
SpriteDecompressQueue *_decompressQueue;
SpriteDrawQueue *_drawQueue;
Graphics::Surface *_backSurface;
+
+ bool _needRefreshPalette;
+ byte _mainPalette[768];
+
+ void setSystemPalette(byte *palette);
+
+ void decompressSprite8(SpriteDecompressQueueItem *item);
+ void drawSurface8(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, int16 scale, uint32 flags);
+ void drawSurface81(int16 destX, int16 destY, Graphics::Surface *surface, Common::Rect &srcRect);
+ void drawSurface82(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect);
+
+ void decompressSprite16(SpriteDecompressQueueItem *item);
+ void drawSurface16(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, int16 scale, uint32 flags);
+ void drawSurface10(int16 destX, int16 destY, Graphics::Surface *surface, Common::Rect &srcRect, uint16 colorKey);
+ void drawSurface11(int16 destX, int16 destY, Graphics::Surface *surface, Common::Rect &srcRect);
+ void drawSurface20(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, uint16 colorKey);
+ void drawSurface21(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect);
};
} // End of namespace Illusions
diff --git a/engines/illusions/scriptopcodes_bbdou.cpp b/engines/illusions/scriptopcodes_bbdou.cpp
index f63a2216b9..b566f521a3 100644
--- a/engines/illusions/scriptopcodes_bbdou.cpp
+++ b/engines/illusions/scriptopcodes_bbdou.cpp
@@ -20,7 +20,7 @@
*
*/
-#include "illusions/illusions.h"
+#include "illusions/illusions_bbdou.h"
#include "illusions/scriptopcodes_bbdou.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
diff --git a/engines/illusions/scriptopcodes_bbdou.h b/engines/illusions/scriptopcodes_bbdou.h
index 28c798710b..dbbc325a4d 100644
--- a/engines/illusions/scriptopcodes_bbdou.h
+++ b/engines/illusions/scriptopcodes_bbdou.h
@@ -125,4 +125,4 @@ protected:
} // End of namespace Illusions
-#endif // ILLUSIONS_SCRIPTOPCODES_H
+#endif // ILLUSIONS_SCRIPTOPCODES_BBDOU_H
diff --git a/engines/illusions/scriptopcodes_duckman.cpp b/engines/illusions/scriptopcodes_duckman.cpp
new file mode 100644
index 0000000000..ffe4ac0689
--- /dev/null
+++ b/engines/illusions/scriptopcodes_duckman.cpp
@@ -0,0 +1,811 @@
+/* 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_duckman.h"
+#include "illusions/scriptopcodes_duckman.h"
+#include "illusions/actor.h"
+#include "illusions/camera.h"
+#include "illusions/dictionary.h"
+#include "illusions/input.h"
+#include "illusions/screen.h"
+#include "illusions/scriptman.h"
+#include "illusions/scriptresource.h"
+#include "illusions/scriptthread.h"
+#include "illusions/specialcode.h"
+#include "illusions/talkresource.h"
+
+namespace Illusions {
+
+// ScriptOpcodes_Duckman
+
+ScriptOpcodes_Duckman::ScriptOpcodes_Duckman(IllusionsEngine_Duckman *vm)
+ : ScriptOpcodes(vm), _vm(vm) {
+ initOpcodes();
+}
+
+ScriptOpcodes_Duckman::~ScriptOpcodes_Duckman() {
+ freeOpcodes();
+}
+
+typedef Common::Functor2Mem<ScriptThread*, OpCall&, void, ScriptOpcodes_Duckman> ScriptOpcodeI;
+#define OPCODE(op, func) \
+ _opcodes[op] = new ScriptOpcodeI(this, &ScriptOpcodes_Duckman::func); \
+ _opcodeNames[op] = #func;
+
+void ScriptOpcodes_Duckman::initOpcodes() {
+ // First clear everything
+ for (uint i = 0; i < 256; ++i)
+ _opcodes[i] = 0;
+ OPCODE(2, opSuspend);
+ OPCODE(3, opYield);
+ OPCODE(4, opTerminate);
+ OPCODE(5, opJump);
+ OPCODE(6, opStartScriptThread);
+ OPCODE(7, opStartTimerThread);
+ OPCODE(9, opNotifyThread);
+ OPCODE(10, opSuspendThread);
+ OPCODE(18, opEnterScene18);
+ OPCODE(20, opChangeScene);
+ OPCODE(24, opEnterScene24);
+ OPCODE(25, opLeaveScene24);
+ OPCODE(38, opStartFade);
+ OPCODE(39, opSetDisplay);
+ OPCODE(49, opPlaceActor);
+ OPCODE(52, opStartSequenceActor);
+ OPCODE(56, opStartTalkThread);
+ OPCODE(57, opAppearActor);
+ OPCODE(58, opDisappearActor);
+ OPCODE(59, opActivateObject);
+ OPCODE(60, opDeactivateObject);
+ OPCODE(61, opSetDefaultSequence);
+ OPCODE(66, opPlayVideo);
+ OPCODE(69, opRunSpecialCode);
+ OPCODE(72, opStartSound);
+ OPCODE(75, opStopSound);
+ OPCODE(76, opStartMidiMusic);
+ OPCODE(77, opStopMidiMusic);
+ OPCODE(80, opAddMenuChoice);
+ OPCODE(81, opDisplayMenu);
+ OPCODE(82, opSwitchMenuChoice);
+ OPCODE(84, opResetGame);
+ OPCODE(87, opDeactivateButton);
+ OPCODE(88, opActivateButton);
+ OPCODE(96, opIncBlockCounter);
+ OPCODE(104, opJumpIf);
+ OPCODE(106, opNot);
+ OPCODE(107, opAnd);
+ OPCODE(108, opOr);
+ OPCODE(109, opGetProperty);
+ OPCODE(110, opCompareBlockCounter);
+ OPCODE(126, opDebug126);
+#if 0
+ // Register opcodes
+ OPCODE(8, opStartTempScriptThread);
+ OPCODE(14, opSetThreadSceneId);
+ OPCODE(15, opEndTalkThreads);
+ OPCODE(17, opUnloadResource);
+ OPCODE(20, opEnterScene);
+ OPCODE(26, opStartModalScene);
+ OPCODE(27, opExitModalScene);
+ OPCODE(30, opEnterCloseUpScene);
+ OPCODE(31, opExitCloseUpScene);
+ OPCODE(32, opPanCenterObject);
+ OPCODE(34, opPanToObject);
+ OPCODE(35, opPanToNamedPoint);
+ OPCODE(36, opPanToPoint);
+ OPCODE(37, opPanStop);
+ OPCODE(43, opClearBlockCounter);
+ OPCODE(45, opSetProperty);
+ OPCODE(47, opFaceActor);
+ OPCODE(48, opFaceActorToObject);
+ OPCODE(51, opStartMoveActor);
+ OPCODE(53, opSetActorToNamedPoint);
+ OPCODE(63, opSetSelectSfx);
+ OPCODE(64, opSetMoveSfx);
+ OPCODE(65, opSetDenySfx);
+ OPCODE(66, opSetAdjustUpSfx);
+ OPCODE(67, opSetAdjustDnSfx);
+ OPCODE(78, opStackPushRandom);
+ OPCODE(79, opIfLte);
+ OPCODE(104, opIsPrevSceneId);
+ OPCODE(105, opIsCurrentSceneId);
+ OPCODE(106, opIsActiveSceneId);
+ OPCODE(146, opStackPop);
+ OPCODE(147, opStackDup);
+ OPCODE(148, opLoadSpecialCodeModule);
+ OPCODE(160, opStopActor);
+ OPCODE(161, opSetActorUsePan);
+ OPCODE(168, opStartAbortableThread);
+ OPCODE(169, opKillThread);
+ OPCODE(175, opSetSceneIdThreadId);
+ OPCODE(176, opStackPush0);
+ OPCODE(177, opSetFontId);
+ OPCODE(178, opAddMenuKey);
+ OPCODE(179, opChangeSceneAll);
+#endif
+}
+
+#undef OPCODE
+
+void ScriptOpcodes_Duckman::freeOpcodes() {
+ for (uint i = 0; i < 256; ++i)
+ delete _opcodes[i];
+}
+
+// Opcodes
+
+void ScriptOpcodes_Duckman::opSuspend(ScriptThread *scriptThread, OpCall &opCall) {
+ opCall._result = kTSSuspend;
+}
+
+void ScriptOpcodes_Duckman::opYield(ScriptThread *scriptThread, OpCall &opCall) {
+ opCall._result = kTSYield;
+}
+
+void ScriptOpcodes_Duckman::opTerminate(ScriptThread *scriptThread, OpCall &opCall) {
+ opCall._result = kTSTerminate;
+}
+
+void ScriptOpcodes_Duckman::opJump(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(jumpOffs);
+ opCall._deltaOfs += jumpOffs;
+}
+
+void ScriptOpcodes_Duckman::opStartScriptThread(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(threadId);
+ _vm->startScriptThread(threadId, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opStartTimerThread(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(isAbortable);
+ ARG_INT16(duration);
+ ARG_INT16(maxDuration);
+ if (maxDuration)
+ duration += _vm->getRandom(maxDuration);
+
+//duration = 1;//DEBUG Speeds up things
+duration = 5;
+
+ if (isAbortable)
+ _vm->startAbortableTimerThread(duration, opCall._threadId);
+ else
+ _vm->startTimerThread(duration, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opNotifyThread(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(threadId);
+ _vm->_threads->notifyId(threadId);
+ _vm->_threads->notifyTimerThreads(threadId);
+}
+
+void ScriptOpcodes_Duckman::opSuspendThread(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(threadId);
+ _vm->_threads->suspendId(threadId);
+ _vm->_threads->suspendTimerThreads(threadId);
+}
+
+void ScriptOpcodes_Duckman::opEnterScene18(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ _vm->enterScene(sceneId, 0);
+}
+
+static uint dsceneId = 0x00010008, dthreadId = 0x00020029;
+
+void ScriptOpcodes_Duckman::opChangeScene(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ ARG_UINT32(threadId);
+ _vm->_input->discardButtons(0xFFFF);
+
+ //DEBUG
+ if (dsceneId) {
+ sceneId = dsceneId;
+ threadId = dthreadId;
+ dsceneId = 0;
+ }
+
+ if (_vm->_scriptResource->_properties.get(31)) {
+ _vm->changeScene(0x10002, 0x20001, opCall._callerThreadId);
+ } else {
+ _vm->changeScene(sceneId, threadId, opCall._callerThreadId);
+ }
+}
+
+void ScriptOpcodes_Duckman::opEnterScene24(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ _vm->_input->discardButtons(0xFFFF);
+ _vm->enterPause(_vm->getCurrentScene(), opCall._callerThreadId);
+ _vm->enterScene(sceneId, 0);
+}
+
+void ScriptOpcodes_Duckman::opLeaveScene24(ScriptThread *scriptThread, OpCall &opCall) {
+ _vm->_input->discardButtons(0xFFFF);
+ _vm->dumpCurrSceneFiles(_vm->getCurrentScene(), opCall._callerThreadId);
+ _vm->exitScene();
+ _vm->leavePause(_vm->getCurrentScene(), opCall._callerThreadId);
+}
+
+void ScriptOpcodes_Duckman::opStartFade(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(arg1);
+ ARG_INT16(arg2);
+ ARG_INT16(arg3);
+ ARG_INT16(arg4);
+ ARG_INT16(arg5);
+ // TODO
+
+ //DEBUG Resume calling thread, later done when the fading is finished
+ _vm->notifyThreadId(opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opSetDisplay(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(flag);
+ _vm->_screen->setDisplayOn(flag != 0);
+}
+
+void ScriptOpcodes_Duckman::opPlaceActor(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ ARG_UINT32(sequenceId);
+ ARG_UINT32(namedPointId);
+ Common::Point pos = _vm->getNamedPointPosition(namedPointId);
+ uint32 actorTypeId = _vm->getObjectActorTypeId(objectId);
+ _vm->_controls->placeActor(actorTypeId, pos, sequenceId, objectId, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opStartSequenceActor(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ ARG_UINT32(sequenceId);
+ // NOTE Skipped checking for stalled sequence, not sure if needed
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ control->startSequenceActor(sequenceId, 2, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opStartTalkThread(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ ARG_UINT32(talkId);
+ ARG_UINT32(sequenceId1);
+ ARG_UINT32(sequenceId2);
+ _vm->startTalkThread(objectId, talkId, sequenceId1, sequenceId2, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opAppearActor(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ if (!control) {
+ Common::Point pos = _vm->getNamedPointPosition(0x70001);
+ _vm->_controls->placeActor(0x50001, pos, 0x60001, objectId, 0);
+ control = _vm->_dict->getObjectControl(objectId);
+ }
+ control->appearActor();
+}
+
+void ScriptOpcodes_Duckman::opDisappearActor(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ control->disappearActor();
+}
+
+void ScriptOpcodes_Duckman::opActivateObject(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ if (control)
+ control->activateObject();
+}
+
+void ScriptOpcodes_Duckman::opDeactivateObject(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ control->deactivateObject();
+}
+
+void ScriptOpcodes_Duckman::opSetDefaultSequence(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ ARG_UINT32(defaultSequenceId);
+ ARG_UINT32(sequenceId);
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ control->_actor->_defaultSequences.set(sequenceId, defaultSequenceId);
+}
+
+void ScriptOpcodes_Duckman::opPlayVideo(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ // NOTE This has no attached objectId or priority
+ // TODO _vm->playVideo(videoId, objectId, value, opCall._threadId);
+
+ //DEBUG Resume calling thread, later done by the video player
+ _vm->notifyThreadId(opCall._threadId);
+
+}
+
+void ScriptOpcodes_Duckman::opRunSpecialCode(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(specialCodeId);
+//TODO _vm->_specialCode->run(specialCodeId, opCall);
+ //DEBUG Resume calling thread, later done by the special code
+ _vm->notifyThreadId(opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opStartSound(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(volume);
+ ARG_UINT32(soundEffectId);
+ // TODO _vm->startSound(soundEffectId, volume, pan);
+}
+
+void ScriptOpcodes_Duckman::opStopSound(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(soundEffectId);
+ // TODO _vm->stopSound(soundEffectId);
+}
+
+void ScriptOpcodes_Duckman::opStartMidiMusic(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(musicId);
+ // TODO _vm->playMidiMusic(musicId);
+}
+
+void ScriptOpcodes_Duckman::opStopMidiMusic(ScriptThread *scriptThread, OpCall &opCall) {
+ // TODO _vm->stopMidiMusic();
+}
+
+void ScriptOpcodes_Duckman::opAddMenuChoice(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_INT16(jumpOffs);
+ ARG_INT16(endMarker);
+ _vm->_stack->push(endMarker);
+ _vm->_stack->push(jumpOffs);
+}
+
+void ScriptOpcodes_Duckman::opDisplayMenu(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(unk1);
+ 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
+ do {
+ _vm->_stack->pop();
+ } while (_vm->_stack->pop() == 0);
+
+ //DEBUG Resume calling thread, later done by the video player
+ _vm->notifyThreadId(opCall._callerThreadId);
+
+}
+
+void ScriptOpcodes_Duckman::opSwitchMenuChoice(ScriptThread *scriptThread, OpCall &opCall) {
+_vm->_menuChoiceOfs = 156; // DEBUG Chose "Start game"
+
+ opCall._deltaOfs += _vm->_menuChoiceOfs;
+}
+
+void ScriptOpcodes_Duckman::opResetGame(ScriptThread *scriptThread, OpCall &opCall) {
+ _vm->reset();
+ _vm->_input->activateButton(0xFFFF);
+ // TODO _vm->stopMusic();
+ // TODO _vm->_gameStates->clear();
+}
+
+void ScriptOpcodes_Duckman::opDeactivateButton(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(button)
+ _vm->_input->deactivateButton(button);
+}
+
+void ScriptOpcodes_Duckman::opActivateButton(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(button)
+ _vm->_input->activateButton(button);
+}
+
+void ScriptOpcodes_Duckman::opIncBlockCounter(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(index);
+ byte value = _vm->_scriptResource->_blockCounters.get(index) + 1;
+ if (value <= 63)
+ _vm->_scriptResource->_blockCounters.set(index, value);
+}
+
+void ScriptOpcodes_Duckman::opJumpIf(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(jumpOffs);
+ int16 value = _vm->_stack->pop();
+ if (value == 0)
+ opCall._deltaOfs += jumpOffs;
+}
+
+void ScriptOpcodes_Duckman::opNot(ScriptThread *scriptThread, OpCall &opCall) {
+ int16 value = _vm->_stack->pop();
+ _vm->_stack->push(value != 0 ? 0 : 1);
+}
+
+void ScriptOpcodes_Duckman::opAnd(ScriptThread *scriptThread, OpCall &opCall) {
+ int16 value1 = _vm->_stack->pop();
+ int16 value2 = _vm->_stack->pop();
+ _vm->_stack->push(value1 & value2);
+}
+
+void ScriptOpcodes_Duckman::opOr(ScriptThread *scriptThread, OpCall &opCall) {
+ int16 value1 = _vm->_stack->pop();
+ int16 value2 = _vm->_stack->pop();
+ _vm->_stack->push(value1 | value2);
+}
+
+void ScriptOpcodes_Duckman::opGetProperty(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(propertyId)
+ bool value = _vm->_scriptResource->_properties.get(propertyId);
+ _vm->_stack->push(value ? 1 : 0);
+}
+
+void ScriptOpcodes_Duckman::opCompareBlockCounter(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(index);
+ ARG_INT16(compareOp);
+ ARG_INT16(rvalue);
+ int16 lvalue = _vm->_scriptResource->_blockCounters.get(index);
+ bool compareResult = false;
+ switch (compareOp) {
+ case 1:
+ compareResult = lvalue == rvalue;
+ break;
+ case 2:
+ compareResult = lvalue != rvalue;
+ break;
+ case 3:
+ compareResult = lvalue < rvalue;
+ break;
+ case 4:
+ compareResult = lvalue > rvalue;
+ break;
+ case 5:
+ compareResult = lvalue >= rvalue;
+ break;
+ case 6:
+ compareResult = lvalue <= rvalue;
+ break;
+ }
+ _vm->_stack->push(compareResult ? 1 : 0);
+}
+
+void ScriptOpcodes_Duckman::opDebug126(ScriptThread *scriptThread, OpCall &opCall) {
+ // NOTE Prints some debug text
+ debug(1, "[DBG] %s", (char*)opCall._code);
+}
+
+#if 0
+
+void ScriptOpcodes_Duckman::opStartTempScriptThread(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(codeOffs);
+ _vm->startTempScriptThread(opCall._code + codeOffs,
+ opCall._threadId, scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10);
+}
+
+void ScriptOpcodes_Duckman::opSetThreadSceneId(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ _vm->_threads->setThreadSceneId(opCall._callerThreadId, sceneId);
+}
+
+void ScriptOpcodes_Duckman::opEndTalkThreads(ScriptThread *scriptThread, OpCall &opCall) {
+ _vm->_threads->endTalkThreads();
+}
+
+void ScriptOpcodes_Duckman::opLoadResource(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(resourceId);
+ // NOTE Skipped checking for stalled resources
+ uint32 sceneId = _vm->getCurrentScene();
+ _vm->_resSys->loadResource(resourceId, sceneId, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opUnloadResource(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(resourceId);
+ // NOTE Skipped checking for stalled resources
+ _vm->_resSys->unloadResourceById(resourceId);
+}
+
+void ScriptOpcodes_Duckman::opEnterScene(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ uint scenesCount = _vm->_activeScenes.getActiveScenesCount();
+ if (scenesCount > 0) {
+ uint32 currSceneId;
+ _vm->_activeScenes.getActiveSceneInfo(scenesCount, &currSceneId, 0);
+ // TODO krnfileDump(currSceneId);
+ }
+ if (!_vm->enterScene(sceneId, opCall._callerThreadId))
+ opCall._result = kTSTerminate;
+}
+
+void ScriptOpcodes_Duckman::opStartModalScene(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ ARG_UINT32(threadId);
+ // NOTE Skipped checking for stalled resources
+ _vm->_input->discardButtons(0xFFFF);
+ _vm->enterPause(opCall._callerThreadId);
+ _vm->_talkItems->pauseByTag(_vm->getCurrentScene());
+ _vm->enterScene(sceneId, opCall._callerThreadId);
+ _vm->startScriptThread(threadId, 0,
+ scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10);
+ opCall._result = kTSSuspend;
+}
+
+void ScriptOpcodes_Duckman::opExitModalScene(ScriptThread *scriptThread, OpCall &opCall) {
+ // NOTE Skipped checking for stalled resources
+ _vm->_input->discardButtons(0xFFFF);
+ _vm->exitScene(opCall._callerThreadId);
+ _vm->leavePause(opCall._callerThreadId);
+ _vm->_talkItems->unpauseByTag(_vm->getCurrentScene());
+}
+
+void ScriptOpcodes_Duckman::opEnterCloseUpScene(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ // NOTE Skipped checking for stalled resources
+ _vm->_input->discardButtons(0xFFFF);
+ _vm->enterPause(opCall._callerThreadId);
+ _vm->enterScene(sceneId, opCall._callerThreadId);
+}
+
+void ScriptOpcodes_Duckman::opExitCloseUpScene(ScriptThread *scriptThread, OpCall &opCall) {
+ _vm->exitScene(opCall._callerThreadId);
+ _vm->leavePause(opCall._callerThreadId);
+ opCall._result = kTSYield;
+}
+
+void ScriptOpcodes_Duckman::opPanCenterObject(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(speed);
+ ARG_UINT32(objectId);
+ _vm->_camera->panCenterObject(objectId, speed);
+}
+
+void ScriptOpcodes_Duckman::opPanToObject(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(speed);
+ ARG_UINT32(objectId);
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ Common::Point pos = control->getActorPosition();
+ _vm->_camera->panToPoint(pos, speed, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opPanToNamedPoint(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(speed);
+ ARG_UINT32(namedPointId);
+ Common::Point pos = _vm->getNamedPointPosition(namedPointId);
+ _vm->_camera->panToPoint(pos, speed, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opPanToPoint(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(speed);
+ ARG_INT16(x);
+ ARG_INT16(y);
+ _vm->_camera->panToPoint(Common::Point(x, y), speed, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opPanStop(ScriptThread *scriptThread, OpCall &opCall) {
+ _vm->_camera->stopPan();
+}
+
+void ScriptOpcodes_Duckman::opClearBlockCounter(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(index);
+ _vm->_scriptResource->_blockCounters.set(index, 0);
+}
+
+void ScriptOpcodes_Duckman::opSetProperty(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(value);
+ ARG_UINT32(propertyId);
+ _vm->_scriptResource->_properties.set(propertyId, value != 0);
+}
+
+void ScriptOpcodes_Duckman::opFaceActor(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(facing);
+ ARG_UINT32(objectId);
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ control->faceActor(facing);
+}
+
+void ScriptOpcodes_Duckman::opFaceActorToObject(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId1);
+ ARG_UINT32(objectId2);
+ Control *control1 = _vm->_dict->getObjectControl(objectId1);
+ Control *control2 = _vm->_dict->getObjectControl(objectId2);
+ Common::Point pos1 = control1->getActorPosition();
+ Common::Point pos2 = control2->getActorPosition();
+ uint facing;
+ if (_vm->calcPointDirection(pos1, pos2, facing))
+ control1->faceActor(facing);
+}
+
+void ScriptOpcodes_Duckman::opStartMoveActor(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ ARG_UINT32(sequenceId);
+ ARG_UINT32(namedPointId);
+ // NOTE Skipped checking for stalled sequence, not sure if needed
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ Common::Point pos = _vm->getNamedPointPosition(namedPointId);
+ control->startMoveActor(sequenceId, pos, opCall._callerThreadId, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opSetActorToNamedPoint(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ ARG_UINT32(namedPointId);
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ Common::Point pos = _vm->getNamedPointPosition(namedPointId);
+ control->stopActor();
+ control->setActorPosition(pos);
+}
+
+void ScriptOpcodes_Duckman::opSetSelectSfx(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(soundEffectId);
+ // TODO _vm->setSelectSfx(soundEffectId);
+}
+
+void ScriptOpcodes_Duckman::opSetMoveSfx(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(soundEffectId);
+ // TODO _vm->setMoveSfx(soundEffectId);
+}
+
+void ScriptOpcodes_Duckman::opSetDenySfx(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(soundEffectId);
+ // TODO _vm->setDenySfx(soundEffectId);
+}
+
+void ScriptOpcodes_Duckman::opSetAdjustUpSfx(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(soundEffectId);
+ // TODO _vm->setAdjustUpSfx(soundEffectId);
+}
+
+void ScriptOpcodes_Duckman::opSetAdjustDnSfx(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(soundEffectId);
+ // TODO _vm->setAdjustDnSfx(soundEffectId);
+}
+
+void ScriptOpcodes_Duckman::opStackPushRandom(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(maxValue);
+ _vm->_stack->push(_vm->getRandom(maxValue) + 1);
+}
+
+void ScriptOpcodes_Duckman::opIfLte(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_INT16(rvalue);
+ ARG_INT16(elseJumpOffs);
+ int16 lvalue = _vm->_stack->pop();
+ if (!(lvalue <= rvalue))
+ opCall._deltaOfs += elseJumpOffs;
+}
+
+void ScriptOpcodes_Duckman::opIsPrevSceneId(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ _vm->_stack->push(_vm->_prevSceneId == sceneId ? 1 : 0);
+}
+
+void ScriptOpcodes_Duckman::opIsCurrentSceneId(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ _vm->_stack->push(_vm->getCurrentScene() == sceneId ? 1 : 0);
+}
+
+void ScriptOpcodes_Duckman::opIsActiveSceneId(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ _vm->_stack->push(_vm->_activeScenes.isSceneActive(sceneId) ? 1 : 0);
+}
+
+void ScriptOpcodes_Duckman::opStackPop(ScriptThread *scriptThread, OpCall &opCall) {
+ _vm->_stack->pop();
+}
+
+void ScriptOpcodes_Duckman::opStackDup(ScriptThread *scriptThread, OpCall &opCall) {
+ int16 value = _vm->_stack->peek();
+ _vm->_stack->push(value);
+}
+
+void ScriptOpcodes_Duckman::opLoadSpecialCodeModule(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(specialCodeModuleId);
+ _vm->_resSys->loadResource(specialCodeModuleId, 0, 0);
+}
+
+void ScriptOpcodes_Duckman::opStopActor(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(objectId);
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ control->stopActor();
+}
+
+void ScriptOpcodes_Duckman::opSetActorUsePan(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_INT16(usePan)
+ ARG_UINT32(objectId);
+ Control *control = _vm->_dict->getObjectControl(objectId);
+ control->setActorUsePan(usePan);
+}
+
+void ScriptOpcodes_Duckman::opStartAbortableThread(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_INT16(codeOffs);
+ ARG_INT16(skipOffs);
+ _vm->startAbortableThread(opCall._code + codeOffs,
+ opCall._code + skipOffs, opCall._threadId);
+}
+
+void ScriptOpcodes_Duckman::opKillThread(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(threadId);
+ _vm->_threads->killThread(threadId);
+}
+
+void ScriptOpcodes_Duckman::opSetSceneIdThreadId(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ ARG_UINT32(threadId);
+ _vm->setSceneIdThreadId(sceneId, threadId);
+}
+
+void ScriptOpcodes_Duckman::opStackPush0(ScriptThread *scriptThread, OpCall &opCall) {
+ _vm->_stack->push(0);
+}
+
+void ScriptOpcodes_Duckman::opSetFontId(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(fontId);
+ _vm->setCurrFontId(fontId);
+}
+
+void ScriptOpcodes_Duckman::opAddMenuKey(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(key);
+ ARG_UINT32(threadId);
+ // TODO _vm->addMenuKey(key, threadId);
+}
+
+void ScriptOpcodes_Duckman::opChangeSceneAll(ScriptThread *scriptThread, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_UINT32(sceneId);
+ ARG_UINT32(threadId);
+ // NOTE Skipped checking for stalled resources
+ _vm->_input->discardButtons(0xFFFF);
+ _vm->_prevSceneId = _vm->getCurrentScene();
+ _vm->dumpActiveScenes(_vm->_globalSceneId, opCall._callerThreadId);
+ _vm->enterScene(sceneId, opCall._callerThreadId);
+ // TODO _vm->_gameStates->writeStates(_vm->_prevSceneId, sceneId, threadId);
+ _vm->startAnonScriptThread(threadId, 0,
+ scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10);
+}
+
+#endif
+
+} // End of namespace Illusions
diff --git a/engines/illusions/scriptopcodes_duckman.h b/engines/illusions/scriptopcodes_duckman.h
new file mode 100644
index 0000000000..a533d7dfbc
--- /dev/null
+++ b/engines/illusions/scriptopcodes_duckman.h
@@ -0,0 +1,137 @@
+/* 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_SCRIPTOPCODES_DUCKMAN_H
+#define ILLUSIONS_SCRIPTOPCODES_DUCKMAN_H
+
+#include "illusions/scriptopcodes.h"
+#include "common/func.h"
+
+namespace Illusions {
+
+class IllusionsEngine_Duckman;
+class ScriptThread;
+
+class ScriptOpcodes_Duckman : public ScriptOpcodes {
+public:
+ ScriptOpcodes_Duckman(IllusionsEngine_Duckman *vm);
+ ~ScriptOpcodes_Duckman();
+ void initOpcodes();
+ void freeOpcodes();
+protected:
+ IllusionsEngine_Duckman *_vm;
+
+ // Opcodes
+
+ void opSuspend(ScriptThread *scriptThread, OpCall &opCall);
+ void opYield(ScriptThread *scriptThread, OpCall &opCall);
+ void opTerminate(ScriptThread *scriptThread, OpCall &opCall);
+ void opJump(ScriptThread *scriptThread, OpCall &opCall);
+ void opStartScriptThread(ScriptThread *scriptThread, OpCall &opCall);
+ void opNotifyThread(ScriptThread *scriptThread, OpCall &opCall);
+ void opSuspendThread(ScriptThread *scriptThread, OpCall &opCall);
+ void opStartTimerThread(ScriptThread *scriptThread, OpCall &opCall);
+ void opEnterScene18(ScriptThread *scriptThread, OpCall &opCall);
+ void opChangeScene(ScriptThread *scriptThread, OpCall &opCall);
+ void opEnterScene24(ScriptThread *scriptThread, OpCall &opCall);
+ void opLeaveScene24(ScriptThread *scriptThread, OpCall &opCall);
+ void opStartFade(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetDisplay(ScriptThread *scriptThread, OpCall &opCall);
+ void opPlaceActor(ScriptThread *scriptThread, OpCall &opCall);
+ void opStartSequenceActor(ScriptThread *scriptThread, OpCall &opCall);
+ void opStartTalkThread(ScriptThread *scriptThread, OpCall &opCall);
+ void opAppearActor(ScriptThread *scriptThread, OpCall &opCall);
+ void opDisappearActor(ScriptThread *scriptThread, OpCall &opCall);
+ void opActivateObject(ScriptThread *scriptThread, OpCall &opCall);
+ void opDeactivateObject(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetDefaultSequence(ScriptThread *scriptThread, OpCall &opCall);
+ void opPlayVideo(ScriptThread *scriptThread, OpCall &opCall);
+ void opRunSpecialCode(ScriptThread *scriptThread, OpCall &opCall);
+ void opStartSound(ScriptThread *scriptThread, OpCall &opCall);
+ void opStopSound(ScriptThread *scriptThread, OpCall &opCall);
+ void opStartMidiMusic(ScriptThread *scriptThread, OpCall &opCall);
+ void opStopMidiMusic(ScriptThread *scriptThread, OpCall &opCall);
+ void opAddMenuChoice(ScriptThread *scriptThread, OpCall &opCall);
+ void opDisplayMenu(ScriptThread *scriptThread, OpCall &opCall);
+ void opSwitchMenuChoice(ScriptThread *scriptThread, OpCall &opCall);
+ void opResetGame(ScriptThread *scriptThread, OpCall &opCall);
+ void opDeactivateButton(ScriptThread *scriptThread, OpCall &opCall);
+ void opActivateButton(ScriptThread *scriptThread, OpCall &opCall);
+ void opIncBlockCounter(ScriptThread *scriptThread, OpCall &opCall);
+ void opJumpIf(ScriptThread *scriptThread, OpCall &opCall);
+ void opNot(ScriptThread *scriptThread, OpCall &opCall);
+ void opAnd(ScriptThread *scriptThread, OpCall &opCall);
+ void opOr(ScriptThread *scriptThread, OpCall &opCall);
+ void opGetProperty(ScriptThread *scriptThread, OpCall &opCall);
+ void opCompareBlockCounter(ScriptThread *scriptThread, OpCall &opCall);
+ void opDebug126(ScriptThread *scriptThread, OpCall &opCall);
+
+#if 0
+ void opStartTempScriptThread(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetThreadSceneId(ScriptThread *scriptThread, OpCall &opCall);
+ void opEndTalkThreads(ScriptThread *scriptThread, OpCall &opCall);
+ void opLoadResource(ScriptThread *scriptThread, OpCall &opCall);
+ void opUnloadResource(ScriptThread *scriptThread, OpCall &opCall);
+ void opEnterScene(ScriptThread *scriptThread, OpCall &opCall);
+ void opStartModalScene(ScriptThread *scriptThread, OpCall &opCall);
+ void opExitModalScene(ScriptThread *scriptThread, OpCall &opCall);
+ void opEnterCloseUpScene(ScriptThread *scriptThread, OpCall &opCall);
+ void opExitCloseUpScene(ScriptThread *scriptThread, OpCall &opCall);
+ void opPanCenterObject(ScriptThread *scriptThread, OpCall &opCall);
+ void opPanToObject(ScriptThread *scriptThread, OpCall &opCall);
+ void opPanToNamedPoint(ScriptThread *scriptThread, OpCall &opCall);
+ void opPanToPoint(ScriptThread *scriptThread, OpCall &opCall);
+ void opPanStop(ScriptThread *scriptThread, OpCall &opCall);
+ void opClearBlockCounter(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetProperty(ScriptThread *scriptThread, OpCall &opCall);
+ void opFaceActor(ScriptThread *scriptThread, OpCall &opCall);
+ void opFaceActorToObject(ScriptThread *scriptThread, OpCall &opCall);
+ void opStartMoveActor(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetActorToNamedPoint(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetSelectSfx(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetMoveSfx(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetDenySfx(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetAdjustUpSfx(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetAdjustDnSfx(ScriptThread *scriptThread, OpCall &opCall);
+ void opStackPushRandom(ScriptThread *scriptThread, OpCall &opCall);
+ void opIfLte(ScriptThread *scriptThread, OpCall &opCall);
+ void opIsPrevSceneId(ScriptThread *scriptThread, OpCall &opCall);
+ void opIsCurrentSceneId(ScriptThread *scriptThread, OpCall &opCall);
+ void opIsActiveSceneId(ScriptThread *scriptThread, OpCall &opCall);
+ void opStackPop(ScriptThread *scriptThread, OpCall &opCall);
+ void opStackDup(ScriptThread *scriptThread, OpCall &opCall);
+ void opLoadSpecialCodeModule(ScriptThread *scriptThread, OpCall &opCall);
+ void opStopActor(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetActorUsePan(ScriptThread *scriptThread, OpCall &opCall);
+ void opStartAbortableThread(ScriptThread *scriptThread, OpCall &opCall);
+ void opKillThread(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetSceneIdThreadId(ScriptThread *scriptThread, OpCall &opCall);
+ void opStackPush0(ScriptThread *scriptThread, OpCall &opCall);
+ void opSetFontId(ScriptThread *scriptThread, OpCall &opCall);
+ void opAddMenuKey(ScriptThread *scriptThread, OpCall &opCall);
+ void opChangeSceneAll(ScriptThread *scriptThread, OpCall &opCall);
+#endif
+};
+
+} // End of namespace Illusions
+
+#endif // ILLUSIONS_SCRIPTOPCODES_DUCKMAN_H
diff --git a/engines/illusions/scriptresource.cpp b/engines/illusions/scriptresource.cpp
index 715039e7d5..fb8260f4f2 100644
--- a/engines/illusions/scriptresource.cpp
+++ b/engines/illusions/scriptresource.cpp
@@ -32,13 +32,14 @@ void ScriptResourceLoader::load(Resource *resource) {
debug(2, "ScriptResourceLoader::load() Loading script %08X from %s...", resource->_resId, resource->_filename.c_str());
ScriptResource *scriptResource = new ScriptResource();
- scriptResource->load(resource->_data, resource->_dataSize);
+ scriptResource->load(resource);
_vm->_scriptResource = scriptResource;
}
void ScriptResourceLoader::unload(Resource *resource) {
+ delete _vm->_scriptResource;
}
void ScriptResourceLoader::buildFilename(Resource *resource) {
@@ -153,14 +154,21 @@ bool TriggerObject::findTriggerCause(uint32 verbId, uint32 objectId2, uint32 &co
return false;
}
+void TriggerObject::fixupProgInfosDuckman() {
+ for (uint i = 0; i < _causesCount; ++i)
+ _causes[i]._verbId &= 0xFFFF;
+}
+
// ProgInfo
ProgInfo::ProgInfo()
- : _triggerObjectsCount(0), _triggerObjects(0) {
+ : _triggerObjectsCount(0), _triggerObjects(0),
+ _resourcesCount(0), _resources(0) {
}
ProgInfo::~ProgInfo() {
delete[] _triggerObjects;
+ delete[] _resources;
}
char *debugW2I(byte *wstr) {
@@ -180,10 +188,15 @@ void ProgInfo::load(byte *dataStart, Common::SeekableReadStream &stream) {
_name = dataStart + stream.pos();
stream.skip(128);
_triggerObjectsCount = stream.readUint16LE();
- stream.skip(2); // Skip padding
+ _resourcesCount = stream.readUint16LE();
debug(2, "\nProgInfo::load() _id: %d; _unk: %d; _name: [%s]",
_id, _unk, debugW2I(_name));
uint32 triggerObjectsListOffs = stream.readUint32LE();
+ if (_resourcesCount > 0) {
+ _resources = new uint32[_resourcesCount];
+ for (uint i = 0; i < _resourcesCount; ++i)
+ _resources[i] = stream.readUint32LE();
+ }
if (_triggerObjectsCount > 0) {
_triggerObjects = new TriggerObject[_triggerObjectsCount];
for (uint i = 0; i < _triggerObjectsCount; ++i) {
@@ -202,6 +215,11 @@ bool ProgInfo::findTriggerCause(uint32 verbId, uint32 objectId2, uint32 objectId
return false;
}
+void ProgInfo::getResources(uint &resourcesCount, uint32 *&resources) {
+ resourcesCount = _resourcesCount;
+ resources = _resources;
+}
+
TriggerObject *ProgInfo::findTriggerObject(uint32 objectId) {
for (uint i = 0; i < _triggerObjectsCount; ++i)
if (_triggerObjects[i]._objectId == objectId)
@@ -209,36 +227,67 @@ TriggerObject *ProgInfo::findTriggerObject(uint32 objectId) {
return 0;
}
+void ProgInfo::fixupProgInfosDuckman() {
+ for (uint i = 0; i < _triggerObjectsCount; ++i)
+ _triggerObjects[i].fixupProgInfosDuckman();
+}
+
// ScriptResource
ScriptResource::ScriptResource()
- : _codeOffsets(0) {
+ : _codeOffsets(0), _objectMap(0) {
}
ScriptResource::~ScriptResource() {
delete[] _codeOffsets;
+ delete[] _objectMap;
}
-void ScriptResource::load(byte *data, uint32 dataSize) {
- Common::MemoryReadStream stream(data, dataSize, DisposeAfterUse::NO);
+void ScriptResource::load(Resource *resource) {
+ _data = resource->_data;
+ _dataSize = resource->_dataSize;
+
+ Common::MemoryReadStream stream(_data, _dataSize, DisposeAfterUse::NO);
+
+ uint32 objectMapOffs, progInfosOffs;
+ _objectMapCount = 0;
- _data = data;
- _dataSize = dataSize;
+ if (resource->_gameId == kGameIdBBDOU) {
+ progInfosOffs = 0x18;
+ } else if (resource->_gameId == kGameIdDuckman) {
+ for (uint i = 0; i < 27; ++i)
+ _soundIds[i] = stream.readUint32LE();
+ progInfosOffs = 0x8C;
+ }
stream.skip(4); // Skip unused
+
+ // Read item counts
uint propertiesCount = stream.readUint16LE();
uint blockCountersCount = stream.readUint16LE();
+ if (resource->_gameId == kGameIdDuckman)
+ _objectMapCount = stream.readUint16LE();
_codeCount = stream.readUint16LE();
_progInfosCount = stream.readUint16LE();
+ if (resource->_gameId == kGameIdDuckman)
+ stream.readUint16LE();//Unused?
+
+ // Read item offsets
uint32 propertiesOffs = stream.readUint32LE();
uint32 blockCountersOffs = stream.readUint32LE();
+ if (resource->_gameId == kGameIdDuckman)
+ objectMapOffs = stream.readUint32LE();
uint32 codeTblOffs = stream.readUint32LE();
+ debug(2, "ScriptResource::load() propertiesCount: %d; blockCountersCount: %d; _codeCount: %d; _progInfosCount: %d; _objectMapCount: %d",
+ propertiesCount, blockCountersCount, _codeCount, _progInfosCount, _objectMapCount);
+ debug(2, "ScriptResource::load() propertiesOffs: %08X; blockCountersOffs: %08X; codeTblOffs: %08X; objectMapOffs: %08X",
+ propertiesOffs, blockCountersOffs, codeTblOffs, objectMapOffs);
// Init properties
- _properties.init(propertiesCount, data + propertiesOffs);
+ _properties.init(propertiesCount, _data + propertiesOffs);
// Init blockcounters
- _blockCounters.init(blockCountersCount, data + blockCountersOffs);
+ _blockCounters.init(blockCountersCount, _data + blockCountersOffs);
_codeOffsets = new uint32[_codeCount];
stream.seek(codeTblOffs);
@@ -247,16 +296,23 @@ void ScriptResource::load(byte *data, uint32 dataSize) {
_progInfos = new ProgInfo[_progInfosCount];
for (uint i = 0; i < _progInfosCount; ++i) {
- stream.seek(0x18 + i * 4);
+ stream.seek(progInfosOffs + i * 4);
uint32 progInfoOffs = stream.readUint32LE();
stream.seek(progInfoOffs);
- _progInfos[i].load(data, stream);
+ _progInfos[i].load(_data, stream);
}
-
- debug(2, "ScriptResource::load() propertiesCount: %d; blockCountersCount: %d; _codeCount: %d; _progInfosCount: %d",
- propertiesCount, blockCountersCount, _codeCount, _progInfosCount);
- debug(2, "ScriptResource::load() propertiesOffs: %08X; blockCountersOffs: %08X; codeTblOffs: %08X",
- propertiesOffs, blockCountersOffs, codeTblOffs);
+
+ if (_objectMapCount > 0) {
+ _objectMap = new uint32[_objectMapCount];
+ stream.seek(objectMapOffs);
+ for (uint i = 0; i < _objectMapCount; ++i) {
+ _objectMap[i] = stream.readUint32LE();
+ stream.skip(4);
+ }
+ }
+
+ if (resource->_gameId == kGameIdDuckman)
+ fixupProgInfosDuckman();
}
@@ -274,4 +330,13 @@ ProgInfo *ScriptResource::getProgInfo(uint32 index) {
return 0;
}
+uint32 ScriptResource::getObjectActorTypeId(uint32 objectId) {
+ return _objectMap[(objectId & 0xFFFF) - 1];
+}
+
+void ScriptResource::fixupProgInfosDuckman() {
+ for (uint i = 0; i < _progInfosCount; ++i)
+ _progInfos[i].fixupProgInfosDuckman();
+}
+
} // End of namespace Illusions
diff --git a/engines/illusions/scriptresource.h b/engines/illusions/scriptresource.h
index 5e2da4574d..f33ac10a41 100644
--- a/engines/illusions/scriptresource.h
+++ b/engines/illusions/scriptresource.h
@@ -79,6 +79,7 @@ public:
~TriggerObject();
void load(byte *dataStart, Common::SeekableReadStream &stream);
bool findTriggerCause(uint32 verbId, uint32 objectId2, uint32 &codeOffs);
+ void fixupProgInfosDuckman();
public:
uint32 _objectId;
uint _causesCount;
@@ -91,12 +92,16 @@ public:
~ProgInfo();
void load(byte *dataStart, Common::SeekableReadStream &stream);
bool findTriggerCause(uint32 verbId, uint32 objectId2, uint32 objectId, uint32 &codeOffs);
+ void getResources(uint &resourcesCount, uint32 *&resources);
+ void fixupProgInfosDuckman();
protected:
uint16 _id;
uint16 _unk;
byte *_name;
uint _triggerObjectsCount;
TriggerObject *_triggerObjects;
+ uint _resourcesCount;
+ uint32 *_resources;
TriggerObject *findTriggerObject(uint32 objectId);
};
@@ -104,10 +109,11 @@ class ScriptResource {
public:
ScriptResource();
~ScriptResource();
- void load(byte *data, uint32 dataSize);
+ void load(Resource *resource);
byte *getThreadCode(uint32 threadId);
byte *getCode(uint32 codeOffs);
ProgInfo *getProgInfo(uint32 index);
+ uint32 getObjectActorTypeId(uint32 objectId);
public:
byte *_data;
uint32 _dataSize;
@@ -117,6 +123,11 @@ public:
uint32 *_codeOffsets;
uint _progInfosCount;
ProgInfo *_progInfos;
+ // Duckman specific
+ uint32 _soundIds[27];
+ uint _objectMapCount;
+ uint32 *_objectMap;
+ void fixupProgInfosDuckman();
};
} // End of namespace Illusions
diff --git a/engines/illusions/scriptthread.cpp b/engines/illusions/scriptthread.cpp
index 78fb8b86ab..73ef8ecd67 100644
--- a/engines/illusions/scriptthread.cpp
+++ b/engines/illusions/scriptthread.cpp
@@ -42,11 +42,7 @@ int ScriptThread::onUpdate() {
opCall._result = kTSRun;
opCall._callerThreadId = _threadId;
while (!_terminated && opCall._result == kTSRun) {
- opCall._op = _scriptCodeIp[0];
- opCall._opSize = _scriptCodeIp[1] >> 1;
- opCall._threadId = _scriptCodeIp[1] & 1 ? _threadId : 0;
- opCall._code = _scriptCodeIp + 2;
- opCall._deltaOfs = opCall._opSize;
+ loadOpcode(opCall);
execOpcode(opCall);
_scriptCodeIp += opCall._deltaOfs;
}
@@ -55,6 +51,25 @@ int ScriptThread::onUpdate() {
return opCall._result;
}
+void ScriptThread::loadOpcode(OpCall &opCall) {
+#if 0
+ for (uint i = 0; i < 16; ++i)
+ debugN("%02X ", _scriptCodeIp[i]);
+ debug(".");
+#endif
+ if (_vm->getGameId() == kGameIdDuckman) {
+ opCall._op = _scriptCodeIp[0] & 0x7F;
+ opCall._opSize = _scriptCodeIp[1];
+ opCall._threadId = _scriptCodeIp[0] & 0x80 ? _threadId : 0;
+ } else {
+ opCall._op = _scriptCodeIp[0];
+ opCall._opSize = _scriptCodeIp[1] >> 1;
+ opCall._threadId = _scriptCodeIp[1] & 1 ? _threadId : 0;
+ }
+ opCall._code = _scriptCodeIp + 2;
+ opCall._deltaOfs = opCall._opSize;
+}
+
void ScriptThread::execOpcode(OpCall &opCall) {
_vm->_scriptOpcodes->execOpcode(this, opCall);
}
diff --git a/engines/illusions/scriptthread.h b/engines/illusions/scriptthread.h
index cb82b6c614..0306c4f1cd 100644
--- a/engines/illusions/scriptthread.h
+++ b/engines/illusions/scriptthread.h
@@ -41,6 +41,7 @@ public:
uint32 _value8;
uint32 _valueC;
uint32 _value10;
+ void loadOpcode(OpCall &opCall);
void execOpcode(OpCall &opCall);
};
diff --git a/engines/illusions/sequenceopcodes.cpp b/engines/illusions/sequenceopcodes.cpp
index f020423a1a..e00bb23722 100644
--- a/engines/illusions/sequenceopcodes.cpp
+++ b/engines/illusions/sequenceopcodes.cpp
@@ -74,11 +74,13 @@ void SequenceOpcodes::initOpcodes() {
OPCODE(17, opDisappearActor);
OPCODE(18, opAppearForeignActor);
OPCODE(19, opDisappearForeignActor);
+ OPCODE(21, opMoveDelta);
OPCODE(28, opNotifyThreadId1);
OPCODE(29, opSetPathCtrY);
OPCODE(33, opSetPathWalkPoints);
OPCODE(35, opSetScale);
OPCODE(36, opSetScaleLayer);
+ OPCODE(37, opDeactivatePathWalkRects);
OPCODE(38, opSetPathWalkRects);
OPCODE(39, opSetPriority);
OPCODE(40, opSetPriorityLayer);
@@ -243,6 +245,14 @@ void SequenceOpcodes::opDisappearForeignActor(Control *control, OpCall &opCall)
foreignControl->disappearActor();
}
+void SequenceOpcodes::opMoveDelta(Control *control, OpCall &opCall) {
+ ARG_SKIP(2);
+ ARG_INT16(deltaX);
+ ARG_INT16(deltaY);
+ control->_actor->_position.x += deltaX;
+ control->_actor->_position.y += deltaY;
+}
+
void SequenceOpcodes::opNotifyThreadId1(Control *control, OpCall &opCall) {
_vm->notifyThreadId(control->_actor->_notifyThreadId1);
}
@@ -274,10 +284,14 @@ void SequenceOpcodes::opSetScaleLayer(Control *control, OpCall &opCall) {
control->setActorScale(scale);
}
+void SequenceOpcodes::opDeactivatePathWalkRects(Control *control, OpCall &opCall) {
+ control->_actor->_flags &= ~0x0010;
+}
+
void SequenceOpcodes::opSetPathWalkRects(Control *control, OpCall &opCall) {
ARG_INT16(pathWalkRectsIndex);
BackgroundResource *bgRes = _vm->_backgroundItems->getActiveBgResource();
- control->_actor->_flags |= 0x10;
+ control->_actor->_flags |= 0x0010;
// TODO control->_actor->_pathWalkRects = bgRes->getPathWalkRects(pathWalkRectsIndex - 1);
}
diff --git a/engines/illusions/sequenceopcodes.h b/engines/illusions/sequenceopcodes.h
index 02561e3dc2..3aab3a8328 100644
--- a/engines/illusions/sequenceopcodes.h
+++ b/engines/illusions/sequenceopcodes.h
@@ -63,11 +63,13 @@ protected:
void opDisappearActor(Control *control, OpCall &opCall);
void opAppearForeignActor(Control *control, OpCall &opCall);
void opDisappearForeignActor(Control *control, OpCall &opCall);
+ void opMoveDelta(Control *control, OpCall &opCall);
void opNotifyThreadId1(Control *control, OpCall &opCall);
void opSetPathCtrY(Control *control, OpCall &opCall);
void opSetPathWalkPoints(Control *control, OpCall &opCall);
void opSetScale(Control *control, OpCall &opCall);
void opSetScaleLayer(Control *control, OpCall &opCall);
+ void opDeactivatePathWalkRects(Control *control, OpCall &opCall);
void opSetPathWalkRects(Control *control, OpCall &opCall);
void opSetPriority(Control *control, OpCall &opCall);
void opSetPriorityLayer(Control *control, OpCall &opCall);
diff --git a/engines/illusions/talkthread.cpp b/engines/illusions/talkthread.cpp
index d74dddeea2..5ad6f7214a 100644
--- a/engines/illusions/talkthread.cpp
+++ b/engines/illusions/talkthread.cpp
@@ -110,11 +110,12 @@ int TalkThread::onUpdate() {
_entryText = talkEntry->_text;
_entryTblPtr = talkEntry->_tblPtr;
if (_sequenceId1) {
- _pauseCtr = 0;
// TODO _field30 = v6;
+ _pauseCtr = 0;
} else {
- _flags = 3;
// TODO _field30 = 0;
+ _flags |= 2;
+ _flags |= 1;
}
if (_vm->isSoundActive()) {
if (!_vm->cueVoice(talkEntry->_voiceName) && !_durationMult)
@@ -150,7 +151,7 @@ int TalkThread::onUpdate() {
}
_vm->startVoice(255, panX);
}
- _vm->_input->discardButtons(16);
+ _vm->_input->discardButtons(0x10);
_status = 6;
return kTSYield;
@@ -161,7 +162,7 @@ int TalkThread::onUpdate() {
// TODO _vm->removeText();
if (_entryText && *_entryText) {
refreshText();
- _vm->_input->discardButtons(16);
+ _vm->_input->discardButtons(0x10);
} else {
_flags |= 8;
}
diff --git a/engines/illusions/talkthread_duckman.cpp b/engines/illusions/talkthread_duckman.cpp
new file mode 100644
index 0000000000..46c11c88b6
--- /dev/null
+++ b/engines/illusions/talkthread_duckman.cpp
@@ -0,0 +1,311 @@
+/* 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_duckman.h"
+#include "illusions/talkthread_duckman.h"
+#include "illusions/actor.h"
+#include "illusions/dictionary.h"
+#include "illusions/input.h"
+#include "illusions/scriptman.h"
+#include "illusions/talkresource.h"
+#include "illusions/time.h"
+
+namespace Illusions {
+
+// TalkThread_Duckman
+
+TalkThread_Duckman::TalkThread_Duckman(IllusionsEngine_Duckman *vm, uint32 threadId, uint32 callingThreadId, uint notifyFlags,
+ uint32 objectId, uint32 talkId, uint32 sequenceId1, uint32 sequenceId2)
+ : Thread(vm, threadId, callingThreadId, notifyFlags), _vm(vm), _objectId(objectId), _talkId(talkId) {
+ _type = kTTTalkThread;
+
+ if ((sequenceId1 & 0xFFFF0000) == 0x60000) {
+ _sequenceId1 = sequenceId1;
+ _sequenceId2 = sequenceId2;
+ _namedPointId1 = 0;
+ _namedPointId2 = 0;
+ } else {
+ _sequenceId1 = 0;
+ _sequenceId2 = 0;
+ _namedPointId1 = sequenceId1;
+ _namedPointId2 = sequenceId2;
+ }
+
+ if (_vm->checkActiveTalkThreads())
+ _status = 1;
+ else
+ _status = 2;
+
+ _durationMult = _vm->clipTextDuration(_vm->_fieldE);
+ _textDuration = _durationMult;
+ _defDurationMult = _vm->clipTextDuration(240);
+
+ _tag = _vm->getCurrentScene();
+
+}
+
+int TalkThread_Duckman::onUpdate() {
+
+ TalkEntry *talkEntry;
+
+ switch (_status) {
+
+ case 1:
+ if (_vm->checkActiveTalkThreads())
+ return kTSYield;
+ _status = 3;
+ // Fallthrough to status 2
+
+ case 2:
+ talkEntry = getTalkResourceEntry(_talkId);
+ _flags = 0;
+ _entryText = talkEntry->_text;
+ _currEntryText = 0;
+ _entryTblPtr = talkEntry->_tblPtr;
+ _flags = 0;
+ if (_sequenceId1) {
+ _pauseCtr = 0;
+ _pauseCtrPtr = &_pauseCtr;
+ } else {
+ _pauseCtrPtr = 0;
+ _flags |= 2;
+ _flags |= 1;
+ }
+ if (_vm->isSoundActive()) {
+ if (!_vm->cueVoice(talkEntry->_voiceName) && !_durationMult)
+ _durationMult = _defDurationMult;
+ } else {
+ _flags |= 4;
+ if (!_durationMult)
+ _durationMult = _defDurationMult;
+ }
+ if (_objectId == 0 || _durationMult == 0)
+ _flags |= 8;
+ _status = 3;
+ // Fallthrough to status 3
+
+ case 3:
+ if (!(_flags & 4) && !_vm->isVoiceCued())
+ return kTSYield;
+ _status = 4;
+ // Fallthrough to status 4
+
+ case 4:
+ if (!(_flags & 8) ) {
+ uint32 actorTypeId = _vm->getObjectActorTypeId(_objectId);
+ // TODO getActorTypeColor(actorTypeId, &_colorR, &_colorG, &_colorB);
+ refreshText();
+ }
+ if (!(_flags & 2)) {
+ Control *control = _vm->_dict->getObjectControl(_objectId);
+ control->startTalkActor(_sequenceId1, _entryTblPtr, _threadId);
+ }
+ if (!(_flags & 4)) {
+ int16 panX = 0;
+ if (_flags & 1) {
+ if (_namedPointId2) {
+ panX = _vm->getNamedPointPosition(_namedPointId2).x;
+ panX = _vm->convertPanXCoord(panX);
+ }
+ } else {
+ Control *control = _vm->_dict->getObjectControl(_objectId);
+ panX = control->getActorPosition().x;
+ panX = _vm->convertPanXCoord(panX);
+ }
+ _vm->startVoice(255, panX);
+ }
+ _vm->_input->discardButtons(0x20);
+ _status = 5;
+ return kTSYield;
+
+ case 5:
+ if (!(_flags & 4) && !_vm->isVoicePlaying())
+ _flags |= 4;
+ if (!(_flags & 8) && isTimerExpired(_textStartTime, _textEndTime)) {
+ // TODO _vm->removeText();
+ if (_entryText && *_entryText) {
+ refreshText();
+ _vm->_input->discardButtons(0x20);
+ } else {
+ _flags |= 8;
+ }
+ }
+ if (!(_flags & 2)) {
+ if (*_pauseCtrPtr < 0) {
+ ++(*_pauseCtrPtr);
+ Control *control = _vm->_dict->getObjectControl(_objectId);
+ control->startSequenceActor(_sequenceId2, 2, 0);
+ _flags |= 2;
+ }
+ }
+ if (_objectId && _vm->_input->pollButton(0x20)) {
+ if (!(_flags & 8)) {
+ // TODO largeObj_removeText();
+ if (_entryText && *_entryText)
+ refreshText();
+ else
+ _flags |= 8;
+ }
+ if (_flags & 8) {
+ if (!(_flags & 4)) {
+ _vm->stopVoice();
+ _flags |= 4;
+ }
+ if (!(_flags & 2)) {
+ Control *control = _vm->_dict->getObjectControl(_objectId);
+ control->clearNotifyThreadId1();
+ control->startSequenceActor(_sequenceId2, 2, 0);
+ _flags |= 2;
+ }
+ }
+ }
+ /*
+ debug("8: %d", (_flags & 8) != 0);
+ debug("4: %d", (_flags & 4) != 0);
+ debug("2: %d", (_flags & 2) != 0);
+ */
+ if ((_flags & 8) && (_flags & 2) && (_flags & 4)) {
+debug("TALK DONE");
+ _vm->_input->discardButtons(0x20);
+ return kTSTerminate;
+ }
+ return kTSYield;
+
+ case 6:
+ if (!(_flags & 2)) {
+ Control *control = _vm->_dict->getObjectControl(_objectId);
+ if (*_pauseCtrPtr >= 0) {
+ control->clearNotifyThreadId1();
+ } else {
+ ++(*_pauseCtrPtr);
+ }
+ control->startSequenceActor(_sequenceId2, 2, 0);
+ _flags |= 2;
+ }
+ return kTSTerminate;
+
+ }
+
+ return kTSTerminate;
+
+}
+
+void TalkThread_Duckman::onSuspend() {
+}
+
+void TalkThread_Duckman::onNotify() {
+}
+
+void TalkThread_Duckman::onPause() {
+}
+
+void TalkThread_Duckman::onResume() {
+}
+
+void TalkThread_Duckman::onTerminated() {
+ if (_status == 5) {
+ if (!(_flags & 4))
+ _vm->stopVoice();
+ if (!(_flags & 8)) {
+ // TODO largeObj_removeText();
+ }
+ if (!(_flags & 2)) {
+ Control *control = _vm->_dict->getObjectControl(_objectId);
+ if (control) {
+ control->clearNotifyThreadId1();
+ control->startSequenceActor(_sequenceId2, 2, 0);
+ }
+ }
+ }
+}
+
+void TalkThread_Duckman::onKill() {
+ _callingThreadId = 0;
+ sendMessage(kMsgClearSequenceId1, 0);
+ sendMessage(kMsgClearSequenceId2, 0);
+}
+
+uint32 TalkThread_Duckman::sendMessage(int msgNum, uint32 msgValue) {
+ // TODO
+ switch (msgNum) {
+ case kMsgQueryTalkThreadActive:
+ if (_status != 1 && _status != 2)
+ return 1;
+ break;
+ case kMsgClearSequenceId1:
+ _sequenceId1 = 0;
+ _flags |= 3;
+ // TODO _pauseCtrPtr = 0;
+ break;
+ case kMsgClearSequenceId2:
+ _sequenceId2 = 0;
+ break;
+ }
+ return 0;
+}
+
+void TalkThread_Duckman::refreshText() {
+ _currEntryText = _entryText;
+ int charCount = insertText();
+ uint32 duration = _durationMult;
+ if (charCount < 80) {
+ duration = _durationMult * charCount / 80;
+ if (duration < 25 * _durationMult / 100)
+ duration = 25 * _durationMult / 100;
+ if (duration < 60)
+ duration = 60;
+ }
+ _textDuration = duration;
+ _textStartTime = getCurrentTime();
+ _textEndTime = _textStartTime + _textDuration;
+}
+
+static char *debugW2I(byte *wstr) {
+ static char buf[65];
+ char *p = buf;
+ while (*wstr != 0) {
+ *p++ = *wstr;
+ wstr += 2;
+ }
+ *p = 0;
+ return buf;
+}
+
+int TalkThread_Duckman::insertText() {
+ int charCount = 100;
+ debug("%08X %08X [%s]", _threadId, _talkId, debugW2I(_currEntryText));
+ _entryText = 0;
+ // TODO _vm->getDimensions1(&dimensions);
+ // TODO _vm->insertText(_currEntryText, 0x00120001, dimensions, 0, 2, 0, 0, _colorR, _colorG, _colorB, 0, &outTextPtr);
+ // TODO _vm->charCount = (char *)outTextPtr - (char *)text;
+ // TODO _entryText = outTextPtr;
+ // TODO _vm->getPoint1(&pt);
+ // TODO _vm->updateTextInfoPosition(pt);
+ return charCount >> 1;
+}
+
+TalkEntry *TalkThread_Duckman::getTalkResourceEntry(uint32 talkId) {
+ TalkEntry *talkEntry = _vm->_dict->findTalkEntry(talkId);
+ return talkEntry;
+}
+
+} // End of namespace Illusions
diff --git a/engines/illusions/talkthread_duckman.h b/engines/illusions/talkthread_duckman.h
new file mode 100644
index 0000000000..656dab72f0
--- /dev/null
+++ b/engines/illusions/talkthread_duckman.h
@@ -0,0 +1,86 @@
+/* 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_TALKTHREAD_DUCKMAN_H
+#define ILLUSIONS_TALKTHREAD_DUCKMAN_H
+
+#include "illusions/thread.h"
+
+namespace Illusions {
+
+class IllusionsEngine_Duckman;
+struct TalkEntry;
+
+enum {
+ kMsgQueryTalkThreadActive = 0,
+ kMsgClearSequenceId1 = 1,
+ kMsgClearSequenceId2 = 2
+};
+
+class TalkThread_Duckman : public Thread {
+public:
+ TalkThread_Duckman(IllusionsEngine_Duckman *vm, uint32 threadId, uint32 callingThreadId, uint notifyFlags,
+ uint32 objectId, uint32 talkId, uint32 sequenceId1, uint32 sequenceId2);
+ virtual int onUpdate();
+ virtual void onSuspend();
+ virtual void onNotify();
+ virtual void onPause();
+ virtual void onResume();
+ virtual void onTerminated();
+ virtual void onKill();
+ virtual uint32 sendMessage(int msgNum, uint32 msgValue);
+public:
+ IllusionsEngine_Duckman *_vm;
+ //field0 dw
+ int _status;
+ uint _flags;
+ uint32 _textStartTime;
+ uint32 _textEndTime;
+ uint32 _textDuration;
+ uint32 _defDurationMult;
+ uint32 _textDurationElapsed;
+ uint32 _durationMult;
+ //field12 dw
+ uint32 _objectId;
+ uint32 _talkId;
+ uint32 _sequenceId1;
+ uint32 _sequenceId2;
+ uint32 _namedPointId1;
+ uint32 _namedPointId2;
+ byte *_entryTblPtr;
+ byte *_entryText;
+ byte *_currEntryText;
+ //field30 dd
+ uint32 _voiceStartTime;
+ uint32 _voiceEndTime;
+ uint32 _voiceDuration;
+ uint32 _voiceDurationElapsed;
+ int *_pauseCtrPtr;
+ byte _colorR, _colorG, _colorB;
+ void refreshText();
+ int insertText();
+ TalkEntry *getTalkResourceEntry(uint32 talkId);
+};
+
+} // End of namespace Illusions
+
+#endif // ILLUSIONS_TALKTHREAD_H
diff --git a/engines/illusions/thread.cpp b/engines/illusions/thread.cpp
index d597d4810b..7ecc3d8606 100644
--- a/engines/illusions/thread.cpp
+++ b/engines/illusions/thread.cpp
@@ -197,6 +197,14 @@ void ThreadList::terminateThreads(uint32 threadId) {
}
}
+void ThreadList::terminateActiveThreads(uint32 threadId) {
+ for (Iterator it = _threads.begin(); it != _threads.end(); ++it) {
+ Thread *thread = *it;
+ if (thread->_pauseCtr <= 0 && thread->_threadId != threadId)
+ thread->terminate();
+ }
+}
+
void ThreadList::terminateThreadsByTag(uint32 tag, uint32 threadId) {
for (Iterator it = _threads.begin(); it != _threads.end(); ++it) {
Thread *thread = *it;
@@ -213,6 +221,14 @@ void ThreadList::suspendThreadsByTag(uint32 tag, uint32 threadId) {
}
}
+void ThreadList::notifyThreads(uint32 threadId) {
+ for (Iterator it = _threads.begin(); it != _threads.end(); ++it) {
+ Thread *thread = *it;
+ if (thread->_threadId != threadId)
+ thread->notify();
+ }
+}
+
void ThreadList::notifyThreadsByTag(uint32 tag, uint32 threadId) {
for (Iterator it = _threads.begin(); it != _threads.end(); ++it) {
Thread *thread = *it;
@@ -229,6 +245,14 @@ void ThreadList::pauseThreads(uint32 threadId) {
}
}
+void ThreadList::suspendThreads(uint32 threadId) {
+ for (Iterator it = _threads.begin(); it != _threads.end(); ++it) {
+ Thread *thread = *it;
+ if (thread->_threadId != threadId)
+ thread->suspend();
+ }
+}
+
void ThreadList::resumeThreads(uint32 threadId) {
for (Iterator it = _threads.begin(); it != _threads.end(); ++it) {
Thread *thread = *it;
diff --git a/engines/illusions/thread.h b/engines/illusions/thread.h
index ea4868d936..e9a9ec3f3f 100644
--- a/engines/illusions/thread.h
+++ b/engines/illusions/thread.h
@@ -86,10 +86,13 @@ public:
void notifyTimerThreads(uint32 callingThreadId);
void suspendTimerThreads(uint32 callingThreadId);
void terminateThreads(uint32 threadId);
+ void terminateActiveThreads(uint32 threadId);
void terminateThreadsByTag(uint32 tag, uint32 threadId);
void suspendThreadsByTag(uint32 tag, uint32 threadId);
+ void notifyThreads(uint32 threadId);
void notifyThreadsByTag(uint32 tag, uint32 threadId);
void pauseThreads(uint32 threadId);
+ void suspendThreads(uint32 threadId);
void resumeThreads(uint32 threadId);
void endTalkThreads();
void endTalkThreadsNoNotify();