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