diff options
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(); |