ILLUSIONS: More work on Duckman

This commit is contained in:
johndoe123 2014-04-08 19:43:17 +02:00 committed by Eugene Sandulenko
parent 3f15233f78
commit 67366aa04b
37 changed files with 2810 additions and 202 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -54,7 +54,11 @@ void BackgroundResourceLoader::load(Resource *resource) {
int index = backgroundItem->_bgRes->findMasterBgIndex();
_vm->_camera->set(backgroundItem->_bgRes->_bgInfos[index - 1]._panPoint, backgroundItem->_bgRes->_bgInfos[index - 1]._surfInfo._dimensions);
// NOTE Skipped palette loading (not used in BBDOU)
if (backgroundItem->_bgRes->_palettesCount > 0) {
Palette *palette = &backgroundItem->_bgRes->_palettes[backgroundItem->_bgRes->_paletteIndex - 1];
_vm->_screen->setPalette(palette->_palette, 1, palette->_count);
}
}
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

View file

@ -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;
@ -134,6 +143,9 @@ public:
NamedPoints _namedPoints;
uint _palettesCount;
Palette *_palettes;
};
const uint kMaxBackgroundItemSurfaces = 3;
@ -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;

View file

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

View file

@ -37,7 +37,8 @@ public:
void show();
void hide();
void cursorControlRoutine(Control *control, uint32 deltaTime);
protected:
//protected:
public:
IllusionsEngine *_vm;
Control *_control;
uint32 _sequenceId;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -125,4 +125,4 @@ protected:
} // End of namespace Illusions
#endif // ILLUSIONS_SCRIPTOPCODES_H
#endif // ILLUSIONS_SCRIPTOPCODES_BBDOU_H

View file

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

View file

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

View file

@ -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;
_data = data;
_dataSize = dataSize;
Common::MemoryReadStream stream(_data, _dataSize, DisposeAfterUse::NO);
uint32 objectMapOffs, progInfosOffs;
_objectMapCount = 0;
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

View file

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

View file

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

View file

@ -41,6 +41,7 @@ public:
uint32 _value8;
uint32 _valueC;
uint32 _value10;
void loadOpcode(OpCall &opCall);
void execOpcode(OpCall &opCall);
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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