ILLUSIONS: Add more script opcodes and fix/add stuff along the way

- Unload backgrounds
- Add transparent sprite drawing
- Add AbortableThread
This commit is contained in:
johndoe123 2014-03-21 17:21:55 +01:00 committed by Eugene Sandulenko
parent 43cd806f17
commit 762be35a36
23 changed files with 399 additions and 57 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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);
@ -160,6 +162,7 @@ Common::Error IllusionsEngine::run() {
Control *control = *_controls->_controls.begin();
control->setActorFrameIndex(1);
control->appearActor();
#endif
#endif
_scriptMan->startScriptThread(0x00020004, 0, 0, 0, 0);

View File

@ -1,6 +1,7 @@
MODULE := engines/illusions
MODULE_OBJS := \
abortablethread.o \
actor.o \
actorresource.o \
backgroundresource.o \

View File

@ -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();
}

View File

@ -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

View File

@ -48,6 +48,7 @@ public:
public:
IllusionsEngine *_vm;
bool _displayOn;
uint16 _colorKey1;
uint16 _colorKey2;
SpriteDecompressQueue *_decompressQueue;
SpriteDrawQueue *_drawQueue;

View File

@ -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();
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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()

View File

@ -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 {

View File

@ -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) {

View File

@ -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) {

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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;