diff options
author | johndoe123 | 2014-03-21 17:21:55 +0100 |
---|---|---|
committer | Eugene Sandulenko | 2018-07-20 06:43:33 +0000 |
commit | 762be35a364fe66359d29b85b650c6e7add80e47 (patch) | |
tree | 61a1d7dd5849f7d79f961f4f46ce77036a88ade9 | |
parent | 43cd806f17377d5244e575b863519f013e5f033c (diff) | |
download | scummvm-rg350-762be35a364fe66359d29b85b650c6e7add80e47.tar.gz scummvm-rg350-762be35a364fe66359d29b85b650c6e7add80e47.tar.bz2 scummvm-rg350-762be35a364fe66359d29b85b650c6e7add80e47.zip |
ILLUSIONS: Add more script opcodes and fix/add stuff along the way
- Unload backgrounds
- Add transparent sprite drawing
- Add AbortableThread
23 files changed, 399 insertions, 57 deletions
diff --git a/engines/illusions/abortablethread.cpp b/engines/illusions/abortablethread.cpp new file mode 100644 index 0000000000..493b81ebd8 --- /dev/null +++ b/engines/illusions/abortablethread.cpp @@ -0,0 +1,70 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "illusions/illusions.h" +#include "illusions/abortablethread.h" +#include "illusions/input.h" +#include "illusions/scriptman.h" +#include "illusions/time.h" + +namespace Illusions { + +// AbortableThread + +AbortableThread::AbortableThread(IllusionsEngine *vm, uint32 threadId, uint32 callingThreadId, uint notifyFlags, + uint32 scriptThreadId, byte *scriptCodeIp) + : Thread(vm, threadId, callingThreadId, notifyFlags), _scriptThreadId(scriptThreadId), + _scriptCodeIp(scriptCodeIp), _status(1) { + _type = kTTAbortableThread; + _tag = _vm->_scriptMan->_activeScenes.getCurrentScene(); + _vm->_input->discardButtons(8); +} + +int AbortableThread::onUpdate() { + if (_status != 1 || _pauseCtr < 0) + return kTSTerminate; + if (_vm->_input->pollButton(8)) { + _vm->_scriptMan->_threads->killThread(_scriptThreadId); + ++_pauseCtr; + _vm->_scriptMan->startTempScriptThread(_scriptCodeIp, _threadId, 0, 0, 0); + _status = 2; + return kTSSuspend; + } + return kTSYield; +} + +void AbortableThread::onSuspend() { +} + +void AbortableThread::onNotify() { +} + +void AbortableThread::onPause() { +} + +void AbortableThread::onResume() { +} + +void AbortableThread::onTerminated() { +} + +} // End of namespace Illusions diff --git a/engines/illusions/abortablethread.h b/engines/illusions/abortablethread.h new file mode 100644 index 0000000000..8fc2a47fce --- /dev/null +++ b/engines/illusions/abortablethread.h @@ -0,0 +1,50 @@ +/* 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_ABORTABLETHREAD_H +#define ILLUSIONS_ABORTABLETHREAD_H + +#include "illusions/thread.h" + +namespace Illusions { + +class IllusionsEngine; + +class AbortableThread : public Thread { +public: + AbortableThread(IllusionsEngine *vm, uint32 threadId, uint32 callingThreadId, uint notifyFlags, + uint32 scriptThreadId, byte *scriptCodeIp); + virtual int onUpdate(); + virtual void onSuspend(); + virtual void onNotify(); + virtual void onPause(); + virtual void onResume(); + virtual void onTerminated(); +public: + int _status; + byte *_scriptCodeIp; + uint32 _scriptThreadId; +}; + +} // End of namespace Illusions + +#endif // ILLUSIONS_ABORTABLETHREAD_H diff --git a/engines/illusions/actor.cpp b/engines/illusions/actor.cpp index 5ba576b546..bcaf72bb54 100644 --- a/engines/illusions/actor.cpp +++ b/engines/illusions/actor.cpp @@ -273,20 +273,24 @@ bool Control::isActorVisible() { void Control::activateObject() { _flags |= 1; - for (uint i = 0; i < kSubObjectsCount; ++i) - if (_actor->_subobjects[i]) { - Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]); - subControl->activateObject(); - } + if (_actor) { + for (uint i = 0; i < kSubObjectsCount; ++i) + if (_actor->_subobjects[i]) { + Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]); + subControl->activateObject(); + } + } } void Control::deactivateObject() { _flags |= ~1; - for (uint i = 0; i < kSubObjectsCount; ++i) - if (_actor->_subobjects[i]) { - Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]); - subControl->deactivateObject(); - } + if (_actor) { + for (uint i = 0; i < kSubObjectsCount; ++i) + if (_actor->_subobjects[i]) { + Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]); + subControl->deactivateObject(); + } + } } void Control::readPointsConfig(byte *pointsConfig) { @@ -543,7 +547,7 @@ void Control::sequenceActor() { while (_actor->_seqCodeValue3 <= 0 && !sequenceFinished) { bool breakInner = false; while (!breakInner) { - debug("SEQ op: %08X", _actor->_seqCodeIp[0]); + debug(1, "SEQ op: %08X", _actor->_seqCodeIp[0]); opCall._op = _actor->_seqCodeIp[0] & 0x7F; opCall._opSize = _actor->_seqCodeIp[1]; opCall._code = _actor->_seqCodeIp + 2; @@ -563,7 +567,7 @@ void Control::sequenceActor() { } if (_actor->_newFrameIndex != 0) { - debug("New frame %d", _actor->_newFrameIndex); + debug(1, "New frame %d", _actor->_newFrameIndex); setActorFrameIndex(_actor->_newFrameIndex); if (!(_actor->_flags & 1) && (_actor->_flags & 0x1000) && (_objectId != 0x40004)) { appearActor(); @@ -572,7 +576,7 @@ void Control::sequenceActor() { } if (sequenceFinished) { - debug("Sequence has finished"); + debug(1, "Sequence has finished"); _actor->_seqCodeIp = 0; } @@ -594,7 +598,7 @@ void Control::startSequenceActorIntern(uint32 sequenceId, int value, int value2, _actor->_path40 = 0; Sequence *sequence = _vm->_dict->findSequence(sequenceId); - debug("Control::startSequenceActorIntern() sequence = %p", (void*)sequence); + debug(1, "Control::startSequenceActorIntern() sequence = %p", (void*)sequence); _actor->_seqCodeIp = sequence->_sequenceCode; _actor->_frames = _vm->_actorItems->findSequenceFrames(sequence); @@ -632,14 +636,25 @@ Controls::~Controls() { delete _sequenceOpcodes; } +void Controls::placeBackgroundObject(BackgroundObject *backgroundObject) { + Control *control = newControl(); + control->_objectId = backgroundObject->_objectId; + control->_flags = backgroundObject->_flags; + control->_priority = backgroundObject->_priority; + control->readPointsConfig(backgroundObject->_pointsConfig); + control->activateObject(); + _controls.push_back(control); + _vm->_dict->setObjectControl(control->_objectId, control); +} + 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; control->_flags = actorType->_flags; control->_priority = actorType->_priority; - control->_objectId = objectId; control->readPointsConfig(actorType->_pointsConfig); control->_actorTypeId = actorTypeId; control->_actor = actor; diff --git a/engines/illusions/actor.h b/engines/illusions/actor.h index 59660532c3..63ae4f84bc 100644 --- a/engines/illusions/actor.h +++ b/engines/illusions/actor.h @@ -193,6 +193,7 @@ class Controls { public: Controls(IllusionsEngine *vm); ~Controls(); + void placeBackgroundObject(BackgroundObject *backgroundObject); void placeActor(uint32 actorTypeId, Common::Point placePt, uint32 sequenceId, uint32 objectId, uint32 notifyThreadId); 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); diff --git a/engines/illusions/backgroundresource.cpp b/engines/illusions/backgroundresource.cpp index 6c7808c33e..fd8ae4f7dc 100644 --- a/engines/illusions/backgroundresource.cpp +++ b/engines/illusions/backgroundresource.cpp @@ -22,6 +22,7 @@ #include "illusions/illusions.h" #include "illusions/backgroundresource.h" +#include "illusions/actor.h" #include "illusions/camera.h" #include "illusions/screen.h" #include "common/str.h" @@ -31,19 +32,22 @@ namespace Illusions { // BackgroundResourceLoader void BackgroundResourceLoader::load(Resource *resource) { - // TODO debug("BackgroundResourceLoader::load() Loading background %08X from %s...", resource->_resId, resource->_filename.c_str()); BackgroundResource *backgroundResource = new BackgroundResource(); backgroundResource->load(resource->_data, resource->_dataSize); + resource->_refId = backgroundResource; + // TODO Move to BackgroundItems BackgroundItem *backgroundItem = _vm->_backgroundItems->allocBackgroundItem(); backgroundItem->_bgRes = backgroundResource; backgroundItem->_tag = resource->_tag; - backgroundItem->initSurface(); - // TODO Insert objects from item44s + // TODO Insert background objects + for (uint i = 0; i < backgroundResource->_backgroundObjectsCount; ++i) + _vm->_controls->placeBackgroundObject(&backgroundResource->_backgroundObjects[i]); + // TODO Insert IDs from item48s // TODO camera_fadeClear(); @@ -54,6 +58,13 @@ void BackgroundResourceLoader::load(Resource *resource) { } void BackgroundResourceLoader::unload(Resource *resource) { + debug("BackgroundResourceLoader::unload() Unloading background %08X...", resource->_resId); + // TODO Move to BackgroundItems + BackgroundItem *backgroundItem = _vm->_backgroundItems->findBackgroundByResource((BackgroundResource*)resource->_refId); + backgroundItem->freeSurface(); + _vm->_backgroundItems->freeBackgroundItem(backgroundItem); + // TODO Remove IDs from item48s + // TODO _vm->setDefPointDimensions1(); } void BackgroundResourceLoader::buildFilename(Resource *resource) { @@ -137,6 +148,19 @@ int ScaleLayer::getScale(Common::Point pos) { return _values[pos.y]; } +// BackgroundObject + +void BackgroundObject::load(byte *dataStart, Common::SeekableReadStream &stream) { + _objectId = stream.readUint32LE(); + _flags = stream.readUint16LE(); + _priority = stream.readUint16LE(); + uint32 pointsConfigOffs = stream.readUint32LE(); + _pointsConfig = dataStart + pointsConfigOffs; + + debug("BackgroundObject::load() _objectId: %08X; _flags: %04X; _priority: %d; pointsConfigOffs: %08X", + _objectId, _flags, _priority, pointsConfigOffs); +} + // BackgroundResource BackgroundResource::BackgroundResource() { @@ -185,6 +209,18 @@ void BackgroundResource::load(byte *data, uint32 dataSize) { _priorityLayers[i].load(data, stream); } + // Load background objects + stream.seek(0x1C); + _backgroundObjectsCount = stream.readUint16LE(); + _backgroundObjects = new BackgroundObject[_backgroundObjectsCount]; + stream.seek(0x44); + uint32 backgroundObjectsOffs = stream.readUint32LE(); + debug("_backgroundObjectsCount: %d", _backgroundObjectsCount); + for (uint i = 0; i < _backgroundObjectsCount; ++i) { + stream.seek(backgroundObjectsOffs + i * 12); + _backgroundObjects[i].load(data, stream); + } + } int BackgroundResource::findMasterBgIndex() { @@ -207,6 +243,9 @@ ScaleLayer *BackgroundResource::getScaleLayer(uint index) { BackgroundItem::BackgroundItem(IllusionsEngine *vm) : _vm(vm), _tag(0), _pauseCtr(0), _bgRes(0) { } +BackgroundItem::~BackgroundItem() { +} + void BackgroundItem::initSurface() { for (uint i = 0; i < kMaxBackgroundItemSurfaces; ++i) _surfaces[i] = 0; @@ -329,6 +368,11 @@ BackgroundItem *BackgroundItems::allocBackgroundItem() { return backgroundItem; } +void BackgroundItems::freeBackgroundItem(BackgroundItem *backgroundItem) { + _items.remove(backgroundItem); + delete backgroundItem; +} + void BackgroundItems::pauseByTag(uint32 tag) { for (ItemsIterator it = _items.begin(); it != _items.end(); ++it) if ((*it)->_tag == tag) @@ -348,6 +392,13 @@ BackgroundItem *BackgroundItems::findActiveBackground() { return 0; } +BackgroundItem *BackgroundItems::findBackgroundByResource(BackgroundResource *backgroundResource) { + for (ItemsIterator it = _items.begin(); it != _items.end(); ++it) + if ((*it)->_bgRes == backgroundResource) + return (*it); + return 0; +} + BackgroundResource *BackgroundItems::getActiveBgResource() { BackgroundItem *background = findActiveBackground(); if (background) diff --git a/engines/illusions/backgroundresource.h b/engines/illusions/backgroundresource.h index d3865d1c75..cfb90673da 100644 --- a/engines/illusions/backgroundresource.h +++ b/engines/illusions/backgroundresource.h @@ -100,6 +100,14 @@ points dd ? BgResource_PathWalkPoints ends #endif +struct BackgroundObject { + uint32 _objectId; + uint16 _flags; + int16 _priority; + byte *_pointsConfig; + void load(byte *dataStart, Common::SeekableReadStream &stream); +}; + class BackgroundResource { public: BackgroundResource(); @@ -118,6 +126,9 @@ public: uint _scaleLayersCount; ScaleLayer *_scaleLayers; + + uint _backgroundObjectsCount; + BackgroundObject *_backgroundObjects; }; @@ -149,14 +160,17 @@ public: BackgroundItems(IllusionsEngine *vm); ~BackgroundItems(); BackgroundItem *allocBackgroundItem(); + void freeBackgroundItem(BackgroundItem *backgroundItem); void pauseByTag(uint32 tag); void unpauseByTag(uint32 tag); BackgroundItem *findActiveBackground(); + BackgroundItem *findBackgroundByResource(BackgroundResource *backgroundResource); BackgroundResource *getActiveBgResource(); WidthHeight getMasterBgDimensions(); void refreshPan(); BackgroundItem *debugFirst(); -protected: +//protected: +public: typedef Common::List<BackgroundItem*> Items; typedef Items::iterator ItemsIterator; IllusionsEngine *_vm; diff --git a/engines/illusions/illusions.cpp b/engines/illusions/illusions.cpp index 89668140cb..265833a58e 100644 --- a/engines/illusions/illusions.cpp +++ b/engines/illusions/illusions.cpp @@ -152,6 +152,8 @@ Common::Error IllusionsEngine::run() { */ _resSys->loadResource(0x000D0001, 0, 0); + +#if 0 _resSys->loadResource(0x0011000B, 0, 0); _resSys->loadResource(0x0010000B, 0, 0); @@ -161,6 +163,7 @@ Common::Error IllusionsEngine::run() { control->setActorFrameIndex(1); control->appearActor(); #endif +#endif _scriptMan->startScriptThread(0x00020004, 0, 0, 0, 0); diff --git a/engines/illusions/module.mk b/engines/illusions/module.mk index edaa94f32a..de705ddc5c 100644 --- a/engines/illusions/module.mk +++ b/engines/illusions/module.mk @@ -1,6 +1,7 @@ MODULE := engines/illusions MODULE_OBJS := \ + abortablethread.o \ actor.o \ actorresource.o \ backgroundresource.o \ diff --git a/engines/illusions/resourcesystem.h b/engines/illusions/resourcesystem.h index 18feb511ac..833a7db112 100644 --- a/engines/illusions/resourcesystem.h +++ b/engines/illusions/resourcesystem.h @@ -45,9 +45,10 @@ struct Resource { byte *_data; uint32 _dataSize; BaseResourceLoader *_resourceLoader; + void *_refId; Common::String _filename; // TODO Check if this is needed Resource() : _loaded(false), _resId(0), _tag(0), _threadId(0), _data(0), _dataSize(0), - _resourceLoader(0) {} + _resourceLoader(0), _refId(0) {} ~Resource() { unloadData(); } diff --git a/engines/illusions/screen.cpp b/engines/illusions/screen.cpp index 1a80a33905..694382d94b 100644 --- a/engines/illusions/screen.cpp +++ b/engines/illusions/screen.cpp @@ -36,6 +36,7 @@ Screen::Screen(IllusionsEngine *vm) _backSurface = allocSurface(640, 480); _decompressQueue = new SpriteDecompressQueue(); _drawQueue = new SpriteDrawQueue(this); + _colorKey1 = 0xF800 | 0x1F; } Screen::~Screen() { @@ -80,33 +81,40 @@ void Screen::updateSprites() { } void Screen::drawSurface10(int16 destX, int16 destY, Graphics::Surface *surface, Common::Rect &srcRect, uint16 colorKey) { - // Unscaled, transparent + // Unscaled // TODO - debug("Screen::drawSurface10"); + //debug("Screen::drawSurface10"); } void Screen::drawSurface11(int16 destX, int16 destY, Graphics::Surface *surface, Common::Rect &srcRect) { - // Unscaled, non-transparent - debug("Screen::drawSurface11() destX: %d; destY: %d; srcRect: (%d, %d, %d, %d)", destX, destY, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom); + // Unscaled + //debug("Screen::drawSurface11() destX: %d; destY: %d; srcRect: (%d, %d, %d, %d)", destX, destY, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom); 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); - memcpy(dst, src, w * 2); + //memcpy(dst, src, w * 2); + for (int16 xc = 0; xc < w; ++xc) { + uint16 pixel = READ_LE_UINT16(src); + if (pixel != _colorKey1) + WRITE_LE_UINT16(dst, pixel); + src += 2; + dst += 2; + } } } void Screen::drawSurface20(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, uint16 colorKey) { - // Scaled, transparent + // Scaled // TODO - debug("Screen::drawSurface20"); + //debug("Screen::drawSurface20"); } void Screen::drawSurface21(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect) { - // Scaled, non-transparent + // Scaled // TODO - debug("Screen::drawSurface21"); + //debug("Screen::drawSurface21"); } } // End of namespace Illusions diff --git a/engines/illusions/screen.h b/engines/illusions/screen.h index ef0f50af63..8fa95ecfa6 100644 --- a/engines/illusions/screen.h +++ b/engines/illusions/screen.h @@ -48,6 +48,7 @@ public: public: IllusionsEngine *_vm; bool _displayOn; + uint16 _colorKey1; uint16 _colorKey2; SpriteDecompressQueue *_decompressQueue; SpriteDrawQueue *_drawQueue; diff --git a/engines/illusions/scriptman.cpp b/engines/illusions/scriptman.cpp index 527c0a5f3e..2ba39c7ae5 100644 --- a/engines/illusions/scriptman.cpp +++ b/engines/illusions/scriptman.cpp @@ -21,6 +21,7 @@ */ #include "illusions/illusions.h" +#include "illusions/abortablethread.h" #include "illusions/actor.h" #include "illusions/scriptman.h" #include "illusions/scriptthread.h" @@ -171,6 +172,15 @@ uint32 ScriptMan::startTimerThread(uint32 duration, uint32 threadId) { return newTimerThread(duration, threadId, false); } +uint32 ScriptMan::startAbortableThread(byte *scriptCodeIp1, byte *scriptCodeIp2, uint32 callingThreadId) { + debug("Starting abortable thread"); + uint32 tempThreadId = newTempThreadId(); + uint32 scriptThreadId = startTempScriptThread(scriptCodeIp1, tempThreadId, 0, 0, 0); + AbortableThread *abortableThread = new AbortableThread(_vm, tempThreadId, callingThreadId, 0, scriptThreadId, scriptCodeIp2); + _threads->startThread(abortableThread); + return tempThreadId; +} + void ScriptMan::setCurrFontId(uint32 fontId) { _fontId = fontId; } @@ -198,7 +208,7 @@ void ScriptMan::exitScene(uint32 threadId) { _threads->terminateThreadsByTag(sceneId, threadId); _vm->_controls->destroyControlsByTag(sceneId); // TODO causeFunc_removeBySceneId(sceneId); - // TODO _vm->_resSys->unloadResourceByTag(sceneId); + _vm->_resSys->unloadResourcesByTag(sceneId); _activeScenes.pop(); } diff --git a/engines/illusions/scriptman.h b/engines/illusions/scriptman.h index 4bbd669928..0ce0ef133c 100644 --- a/engines/illusions/scriptman.h +++ b/engines/illusions/scriptman.h @@ -80,6 +80,7 @@ public: uint32 value8, uint32 valueC, uint32 value10); uint32 startAbortableTimerThread(uint32 duration, uint32 threadId); uint32 startTimerThread(uint32 duration, uint32 threadId); + uint32 startAbortableThread(byte *scriptCodeIp1, byte *scriptCodeIp2, uint32 callingThreadId); void setCurrFontId(uint32 fontId); void reset(); bool enterScene(uint32 sceneId, uint32 threadId); diff --git a/engines/illusions/scriptopcodes.cpp b/engines/illusions/scriptopcodes.cpp index a40429b5b0..6d32800d77 100644 --- a/engines/illusions/scriptopcodes.cpp +++ b/engines/illusions/scriptopcodes.cpp @@ -66,14 +66,16 @@ ScriptOpcodes::~ScriptOpcodes() { } void ScriptOpcodes::execOpcode(ScriptThread *scriptThread, OpCall &opCall) { - debug("\nexecOpcode([%08X] %d)", opCall._callerThreadId, opCall._op); if (!_opcodes[opCall._op]) error("ScriptOpcodes::execOpcode() Unimplemented opcode %d", opCall._op); + debug("\nexecOpcode([%08X] %d) %s", opCall._callerThreadId, opCall._op, _opcodeNames[opCall._op].c_str()); (*_opcodes[opCall._op])(scriptThread, opCall); } typedef Common::Functor2Mem<ScriptThread*, OpCall&, void, ScriptOpcodes> ScriptOpcodeI; -#define OPCODE(op, func) _opcodes[op] = new ScriptOpcodeI(this, &ScriptOpcodes::func); +#define OPCODE(op, func) \ + _opcodes[op] = new ScriptOpcodeI(this, &ScriptOpcodes::func); \ + _opcodeNames[op] = #func; void ScriptOpcodes::initOpcodes() { // First clear everything @@ -88,6 +90,7 @@ void ScriptOpcodes::initOpcodes() { OPCODE(8, opStartTempScriptThread); OPCODE(9, opStartTimerThread); OPCODE(14, opSetThreadSceneId); + OPCODE(15, opEndTalkThreads); OPCODE(16, opLoadResource); OPCODE(20, opEnterScene); OPCODE(25, opChangeScene); @@ -96,8 +99,10 @@ void ScriptOpcodes::initOpcodes() { OPCODE(45, opSetProperty); OPCODE(46, opPlaceActor); OPCODE(49, opStartSequenceActor); + OPCODE(56, opStartTalkThread); OPCODE(57, opAppearActor); OPCODE(58, opDisappearActor); + OPCODE(60, opActivateObject); OPCODE(61, opDeactivateObject); OPCODE(63, opSetSelectSfx); OPCODE(64, opSetMoveSfx); @@ -105,6 +110,8 @@ void ScriptOpcodes::initOpcodes() { OPCODE(66, opSetAdjustUpSfx); OPCODE(67, opSetAdjustDnSfx); OPCODE(75, opStartMusic); + OPCODE(78, opStackPushRandom); + OPCODE(79, opIfLte); OPCODE(80, opAddMenuChoice); OPCODE(81, opDisplayMenu); OPCODE(82, opSwitchMenuChoice); @@ -112,13 +119,17 @@ void ScriptOpcodes::initOpcodes() { OPCODE(87, opDeactivateButton); OPCODE(88, opActivateButton); OPCODE(103, opJumpIf); + OPCODE(107, opBoolNot); OPCODE(110, opGetProperty); OPCODE(111, opCompareBlockCounter); OPCODE(126, opDebug126); OPCODE(144, opPlayVideo); + OPCODE(146, opStackPop); + OPCODE(147, opStackDup); OPCODE(148, opLoadSpecialCodeModule); OPCODE(150, opRunSpecialCode); OPCODE(161, opSetActorUsePan); + OPCODE(168, opStartAbortableThread); OPCODE(175, opSetSceneIdThreadId); OPCODE(176, opStackPush0); OPCODE(177, opSetFontId); @@ -190,6 +201,10 @@ void ScriptOpcodes::opSetThreadSceneId(ScriptThread *scriptThread, OpCall &opCal _vm->_scriptMan->_threads->setThreadSceneId(opCall._callerThreadId, sceneId); } +void ScriptOpcodes::opEndTalkThreads(ScriptThread *scriptThread, OpCall &opCall) { + _vm->_scriptMan->_threads->endTalkThreads(); +} + void ScriptOpcodes::opLoadResource(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(resourceId); @@ -240,7 +255,7 @@ void ScriptOpcodes::opIncBlockCounter(ScriptThread *scriptThread, OpCall &opCall void ScriptOpcodes::opSetProperty(ScriptThread *scriptThread, OpCall &opCall) { ARG_INT16(value); ARG_UINT32(propertyId); - // TODO _vm->_scriptMan->_scriptResource->_properties.set(propertyId, value); + _vm->_scriptMan->_scriptResource->_properties.set(propertyId, value != 0); } void ScriptOpcodes::opPlaceActor(ScriptThread *scriptThread, OpCall &opCall) { @@ -262,15 +277,29 @@ void ScriptOpcodes::opStartSequenceActor(ScriptThread *scriptThread, OpCall &opC control->startSequenceActor(sequenceId, 2, opCall._threadId); } +void ScriptOpcodes::opStartTalkThread(ScriptThread *scriptThread, OpCall &opCall) { + ARG_INT16(value); + ARG_UINT32(objectId); + ARG_UINT32(talkId); + ARG_UINT32(sequenceId1); + ARG_UINT32(sequenceId2); + ARG_UINT32(value2); + // NOTE Skipped checking for stalled sequence, not sure if needed + // TODO _vm->_scriptMan->startTalkThread(value, objectId, talkId, sequenceId1, sequenceId2, value2, opCall._callerThreadId); + + //DEBUG Resume calling thread, later done after talking is finished + _vm->notifyThreadId(opCall._threadId); +} + void ScriptOpcodes::opAppearActor(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(objectId); Control *control = _vm->_dict->getObjectControl(objectId); if (!control) { Common::Point pos = _vm->getNamedPointPosition(0x70023); - _vm->_controls->placeActor(0x50001, pos, 0x60001, objectId, 0); - control = _vm->_dict->getObjectControl(objectId); - control->startSequenceActor(0x60001, 2, 0); + _vm->_controls->placeActor(0x50001, pos, 0x60001, objectId, 0); + control = _vm->_dict->getObjectControl(objectId); + control->startSequenceActor(0x60001, 2, 0); } control->appearActor(); } @@ -282,12 +311,19 @@ void ScriptOpcodes::opDisappearActor(ScriptThread *scriptThread, OpCall &opCall) control->disappearActor(); } -void ScriptOpcodes::opDeactivateObject(ScriptThread *scriptThread, OpCall &opCall) { +void ScriptOpcodes::opActivateObject(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(objectId); Control *control = _vm->_dict->getObjectControl(objectId); if (control) - control->deactivateObject(); + control->activateObject(); +} + +void ScriptOpcodes::opDeactivateObject(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_UINT32(objectId); + Control *control = _vm->_dict->getObjectControl(objectId); + control->deactivateObject(); } void ScriptOpcodes::opSetSelectSfx(ScriptThread *scriptThread, OpCall &opCall) { @@ -328,6 +364,20 @@ void ScriptOpcodes::opStartMusic(ScriptThread *scriptThread, OpCall &opCall) { // TODO _vm->playMusic(musicId, type, volume, pan); } +void ScriptOpcodes::opStackPushRandom(ScriptThread *scriptThread, OpCall &opCall) { + ARG_INT16(maxValue); + _vm->_scriptMan->_stack.push(_vm->getRandom(maxValue) + 1); +} + +void ScriptOpcodes::opIfLte(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_INT16(rvalue); + ARG_INT16(elseJumpOffs); + int16 lvalue = _vm->_scriptMan->_stack.pop(); + if (!(lvalue <= rvalue)) + opCall._deltaOfs += elseJumpOffs; +} + void ScriptOpcodes::opAddMenuChoice(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_INT16(jumpOffs); @@ -383,11 +433,16 @@ void ScriptOpcodes::opJumpIf(ScriptThread *scriptThread, OpCall &opCall) { opCall._deltaOfs += jumpOffs; } +void ScriptOpcodes::opBoolNot(ScriptThread *scriptThread, OpCall &opCall) { + int16 value = _vm->_scriptMan->_stack.pop(); + _vm->_scriptMan->_stack.push(value != 0 ? 0 : 1); +} + void ScriptOpcodes::opGetProperty(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(propertyId) - int16 value = 0;// TODO _vm->_scriptMan->_scriptResource->_properties.get(propertyId); - _vm->_scriptMan->_stack.push(value); + bool value = _vm->_scriptMan->_scriptResource->_properties.get(propertyId); + _vm->_scriptMan->_stack.push(value ? 1 : 0); } void ScriptOpcodes::opCompareBlockCounter(ScriptThread *scriptThread, OpCall &opCall) { @@ -436,6 +491,15 @@ void ScriptOpcodes::opPlayVideo(ScriptThread *scriptThread, OpCall &opCall) { } +void ScriptOpcodes::opStackPop(ScriptThread *scriptThread, OpCall &opCall) { + _vm->_scriptMan->_stack.pop(); +} + +void ScriptOpcodes::opStackDup(ScriptThread *scriptThread, OpCall &opCall) { + int16 value = _vm->_scriptMan->_stack.peek(); + _vm->_scriptMan->_stack.push(value); +} + void ScriptOpcodes::opLoadSpecialCodeModule(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(specialCodeModuleId); @@ -461,6 +525,14 @@ void ScriptOpcodes::opSetActorUsePan(ScriptThread *scriptThread, OpCall &opCall) control->setActorUsePan(usePan); } +void ScriptOpcodes::opStartAbortableThread(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_INT16(codeOffs); + ARG_INT16(skipOffs); + _vm->_scriptMan->startAbortableThread(opCall._code + opCall._opSize + codeOffs, + opCall._code + opCall._opSize + skipOffs, opCall._callerThreadId); +} + void ScriptOpcodes::opSetSceneIdThreadId(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(sceneId); diff --git a/engines/illusions/scriptopcodes.h b/engines/illusions/scriptopcodes.h index 5187c9e057..060171d50a 100644 --- a/engines/illusions/scriptopcodes.h +++ b/engines/illusions/scriptopcodes.h @@ -54,6 +54,7 @@ public: protected: IllusionsEngine *_vm; ScriptOpcode *_opcodes[256]; + Common::String _opcodeNames[256]; void initOpcodes(); void freeOpcodes(); @@ -66,6 +67,7 @@ protected: void opStartTempScriptThread(ScriptThread *scriptThread, OpCall &opCall); void opStartTimerThread(ScriptThread *scriptThread, OpCall &opCall); void opSetThreadSceneId(ScriptThread *scriptThread, OpCall &opCall); + void opEndTalkThreads(ScriptThread *scriptThread, OpCall &opCall); void opLoadResource(ScriptThread *scriptThread, OpCall &opCall); void opEnterScene(ScriptThread *scriptThread, OpCall &opCall); void opChangeScene(ScriptThread *scriptThread, OpCall &opCall); @@ -74,8 +76,10 @@ protected: void opSetProperty(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 opSetSelectSfx(ScriptThread *scriptThread, OpCall &opCall); void opSetMoveSfx(ScriptThread *scriptThread, OpCall &opCall); @@ -83,6 +87,8 @@ protected: void opSetAdjustUpSfx(ScriptThread *scriptThread, OpCall &opCall); void opSetAdjustDnSfx(ScriptThread *scriptThread, OpCall &opCall); void opStartMusic(ScriptThread *scriptThread, OpCall &opCall); + void opStackPushRandom(ScriptThread *scriptThread, OpCall &opCall); + void opIfLte(ScriptThread *scriptThread, OpCall &opCall); void opAddMenuChoice(ScriptThread *scriptThread, OpCall &opCall); void opDisplayMenu(ScriptThread *scriptThread, OpCall &opCall); void opSwitchMenuChoice(ScriptThread *scriptThread, OpCall &opCall); @@ -90,13 +96,17 @@ protected: void opDeactivateButton(ScriptThread *scriptThread, OpCall &opCall); void opActivateButton(ScriptThread *scriptThread, OpCall &opCall); void opJumpIf(ScriptThread *scriptThread, OpCall &opCall); + void opBoolNot(ScriptThread *scriptThread, OpCall &opCall); void opGetProperty(ScriptThread *scriptThread, OpCall &opCall); void opCompareBlockCounter(ScriptThread *scriptThread, OpCall &opCall); void opDebug126(ScriptThread *scriptThread, OpCall &opCall); void opPlayVideo(ScriptThread *scriptThread, OpCall &opCall); + void opStackPop(ScriptThread *scriptThread, OpCall &opCall); + void opStackDup(ScriptThread *scriptThread, OpCall &opCall); void opLoadSpecialCodeModule(ScriptThread *scriptThread, OpCall &opCall); void opRunSpecialCode(ScriptThread *scriptThread, OpCall &opCall); void opSetActorUsePan(ScriptThread *scriptThread, OpCall &opCall); + void opStartAbortableThread(ScriptThread *scriptThread, OpCall &opCall); void opSetSceneIdThreadId(ScriptThread *scriptThread, OpCall &opCall); void opStackPush0(ScriptThread *scriptThread, OpCall &opCall); void opSetFontId(ScriptThread *scriptThread, OpCall &opCall); diff --git a/engines/illusions/scriptresource.cpp b/engines/illusions/scriptresource.cpp index 3a08e50471..29f123e492 100644 --- a/engines/illusions/scriptresource.cpp +++ b/engines/illusions/scriptresource.cpp @@ -59,6 +59,29 @@ void Properties::init(uint count, byte *properties) { _properties = properties; } +bool Properties::get(uint32 propertyId) { + uint index; + byte mask; + getProperyPos(propertyId, index, mask); + return (_properties[index] & mask) != 0; +} + +void Properties::set(uint32 propertyId, bool value) { + uint index; + byte mask; + getProperyPos(propertyId, index, mask); + if (value) + _properties[index] |= mask; + else + _properties[index] &= ~mask; +} + +void Properties::getProperyPos(uint32 propertyId, uint &index, byte &mask) { + propertyId &= 0xFFFF; + index = propertyId >> 3; + mask = 1 << (propertyId & 7); +} + // BlockCounters BlockCounters::BlockCounters() diff --git a/engines/illusions/scriptresource.h b/engines/illusions/scriptresource.h index 8a689a97a9..79c46c82a7 100644 --- a/engines/illusions/scriptresource.h +++ b/engines/illusions/scriptresource.h @@ -45,9 +45,12 @@ class Properties { public: Properties(); void init(uint count, byte *properties); + bool get(uint32 propertyId); + void set(uint32 propertyId, bool value); public: uint _count; byte *_properties; + void getProperyPos(uint32 propertyId, uint &index, byte &mask); }; class BlockCounters { diff --git a/engines/illusions/scriptthread.cpp b/engines/illusions/scriptthread.cpp index b21b003c21..69835d94a6 100644 --- a/engines/illusions/scriptthread.cpp +++ b/engines/illusions/scriptthread.cpp @@ -57,27 +57,27 @@ int ScriptThread::onUpdate() { void ScriptThread::onSuspend() { // TODO - debug("ScriptThread::onSuspend()"); + debug(1, "ScriptThread::onSuspend()"); } void ScriptThread::onNotify() { // TODO - debug("ScriptThread::onNotify()"); + debug(1, "ScriptThread::onNotify()"); } void ScriptThread::onPause() { // TODO - debug("ScriptThread::onPause()"); + debug(1, "ScriptThread::onPause()"); } void ScriptThread::onResume() { // TODO - debug("ScriptThread::onResume()"); + debug(1, "ScriptThread::onResume()"); } void ScriptThread::onTerminated() { // TODO - debug("ScriptThread::onTerminated()"); + debug(1, "ScriptThread::onTerminated()"); } void ScriptThread::execOpcode(OpCall &opCall) { diff --git a/engines/illusions/sequenceopcodes.cpp b/engines/illusions/sequenceopcodes.cpp index 4dc3b29a9c..b550be6097 100644 --- a/engines/illusions/sequenceopcodes.cpp +++ b/engines/illusions/sequenceopcodes.cpp @@ -42,7 +42,7 @@ SequenceOpcodes::~SequenceOpcodes() { void SequenceOpcodes::execOpcode(Control *control, OpCall &opCall) { if (!_opcodes[opCall._op]) error("SequenceOpcodes::execOpcode() Unimplemented opcode %d", opCall._op); - debug("execOpcode(%d)", opCall._op); + debug(1, "execOpcode(%d)", opCall._op); (*_opcodes[opCall._op])(control, opCall); } @@ -86,13 +86,13 @@ void SequenceOpcodes::freeOpcodes() { // Convenience macros #define ARG_SKIP(x) opCall.skip(x); -#define ARG_INT16(name) int16 name = opCall.readSint16(); debug("ARG_INT16(" #name " = %d)", name); -#define ARG_UINT32(name) uint32 name = opCall.readUint32(); debug("ARG_UINT32(" #name " = %08X)", name); +#define ARG_INT16(name) int16 name = opCall.readSint16(); debug(1, "ARG_INT16(" #name " = %d)", name); +#define ARG_UINT32(name) uint32 name = opCall.readUint32(); debug(1, "ARG_UINT32(" #name " = %08X)", name); void SequenceOpcodes::opSetFrameIndex(Control *control, OpCall &opCall) { ARG_INT16(frameIndex); if (control->_actor->_flags & 0x80) { - debug("opSetFrameIndex TODO"); + debug(1, "opSetFrameIndex TODO"); /* TODO v9 = actor->field30; if (*(_WORD *)v9) { diff --git a/engines/illusions/spritedrawqueue.cpp b/engines/illusions/spritedrawqueue.cpp index 1e42d18e3e..f39eb5fb76 100644 --- a/engines/illusions/spritedrawqueue.cpp +++ b/engines/illusions/spritedrawqueue.cpp @@ -143,8 +143,8 @@ bool SpriteDrawQueue::calcItemRect(SpriteDrawQueueItem *item, Common::Rect &srcR srcRect.right = item->_dimensions._width; srcRect.bottom = item->_dimensions._height; - debug("item->_drawPosition.x: %d; item->_drawPosition.y: %d", item->_drawPosition.x, item->_drawPosition.y); - debug("item->_controlPosition.x: %d; item->_controlPosition.y: %d", item->_controlPosition.x, item->_controlPosition.y); + //debug("item->_drawPosition.x: %d; item->_drawPosition.y: %d", item->_drawPosition.x, item->_drawPosition.y); + //debug("item->_controlPosition.x: %d; item->_controlPosition.y: %d", item->_controlPosition.x, item->_controlPosition.y); dstRect.left = item->_drawPosition.x - item->_scale * item->_controlPosition.x / 100; dstRect.top = item->_drawPosition.y - item->_scale * item->_controlPosition.y / 100; diff --git a/engines/illusions/thread.cpp b/engines/illusions/thread.cpp index c16ecd4584..83e0ce5ab4 100644 --- a/engines/illusions/thread.cpp +++ b/engines/illusions/thread.cpp @@ -91,7 +91,6 @@ int Thread::update() { int status = kTSYield; if (!_terminated && _pauseCtr <= 0) { status = onUpdate(); - debug("Thread status: %d", status); if (status == kTSTerminate) terminate(); else if (status == kTSSuspend) @@ -230,6 +229,14 @@ void ThreadList::resumeThreads(uint32 threadId) { } } +void ThreadList::endTalkThreads() { + for (Iterator it = _threads.begin(); it != _threads.end(); ++it) { + Thread *thread = *it; + if (thread->_type == kTTTalkThread) + thread->terminate(); + } +} + void ThreadList::killThread(uint32 threadId) { if (!threadId) diff --git a/engines/illusions/thread.h b/engines/illusions/thread.h index 977262a671..fc1a059e2f 100644 --- a/engines/illusions/thread.h +++ b/engines/illusions/thread.h @@ -30,10 +30,11 @@ namespace Illusions { class IllusionsEngine; enum ThreadType { - kTTScriptThread = 1, - kTTTimerThread = 2, - kTTTalkThread = 3, - kTTSpecialThread = 5 + kTTScriptThread = 1, + kTTTimerThread = 2, + kTTTalkThread = 3, + kTTAbortableThread = 4, + kTTSpecialThread = 5 }; enum ThreadStatus { @@ -88,6 +89,7 @@ public: void notifyThreadsByTag(uint32 tag, uint32 threadId); void pauseThreads(uint32 threadId); void resumeThreads(uint32 threadId); + void endTalkThreads(); void killThread(uint32 threadId); void setThreadSceneId(uint32 threadId, uint32 sceneId); uint32 getThreadSceneId(uint32 threadId); diff --git a/engines/illusions/timerthread.cpp b/engines/illusions/timerthread.cpp index 5263305412..42dde6dc17 100644 --- a/engines/illusions/timerthread.cpp +++ b/engines/illusions/timerthread.cpp @@ -39,7 +39,6 @@ TimerThread::TimerThread(IllusionsEngine *vm, uint32 threadId, uint32 callingThr } int TimerThread::onUpdate() { -debug("startTime: %d; endTime: %d; currTime: %d", _startTime, _endTime, getCurrentTime()); if (isTimerExpired(_startTime, _endTime) || (_isAbortable && _vm->_input->pollButton(8))) return kTSTerminate; |