Ejemplo n.º 1
0
/**
 * Given the scene background film, extracts the palette handle for
 * everything else's use, then starts a display process for each reel
 * in the film.
 * @param hFilm			Scene background film
 */
void StartupBackground(CORO_PARAM, SCNHANDLE hFilm) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	const FILM *pfilm;
	IMAGE *pim;

	hBackground = hFilm;		// Save handle in case of Save_Scene()

	pim = GetImageFromFilm(hFilm, 0, NULL, NULL, &pfilm);

	SetBackPal(FROM_LE_32(pim->hImgPal));

	// Extract the film speed
	BGspeed = ONE_SECOND / FROM_LE_32(pfilm->frate);

	// Start display process for each reel in the film
	g_scheduler->createProcess(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL));

	if (TinselV0) {
		for (uint i = 1; i < FROM_LE_32(pfilm->numreels); ++i)
			g_scheduler->createProcess(PID_REEL, BGotherProcess, &pfilm->reels[i], sizeof(FREEL));
	}

	if (pBG[0] == NULL)
		ControlStartOff();

	if (TinselV2 && (coroParam != nullContext))
		CORO_GIVE_WAY;

	CORO_END_CODE;
}
Ejemplo n.º 2
0
Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary *fi, Win32ImageResourceDirectory *pe_res, int level, int *count) {
	WinResource *wr;
	int c, rescnt;
	Win32ImageResourceDirectoryEntry *dirent
	  = (Win32ImageResourceDirectoryEntry *)(pe_res + 1);

	/* count number of `type' resources */
	RETURN_IF_BAD_POINTER(NULL, *dirent);
	rescnt = FROM_LE_16(pe_res->number_of_named_entries) + FROM_LE_16(pe_res->number_of_id_entries);
	*count = rescnt;

	/* allocate WinResource's */
	wr = (WinResource *)malloc(sizeof(WinResource) * rescnt);

	/* fill in the WinResource's */
	for (c = 0 ; c < rescnt ; c++) {
		RETURN_IF_BAD_POINTER(NULL, dirent[c]);
		wr[c].this_ = pe_res;
		wr[c].level = level;
		wr[c].is_directory = ((FROM_LE_32(dirent[c].offset_to_data) & IMAGE_RESOURCE_DATA_IS_DIRECTORY) != 0);
		wr[c].children = fi->first_resource + (FROM_LE_32(dirent[c].offset_to_data) & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY);

		/* fill in wr->id, wr->numeric_id */
		if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name))) {
			free(wr);
			return NULL;
		}
	}

	return wr;
}
Ejemplo n.º 3
0
/**
 * Called at the start of each scene for each actor with a code block.
 * @param as			Actor structure
 * @param bRunScript	Flag for whether to run actor's script for the scene
 */
void StartActor(const T1_ACTOR_STRUC *as, bool bRunScript) {
	SCNHANDLE hActorId = FROM_LE_32(as->hActorId);

	// Zero-out many things
	actorInfo[hActorId - 1].bHidden = false;
	actorInfo[hActorId - 1].completed = false;
	actorInfo[hActorId - 1].x = 0;
	actorInfo[hActorId - 1].y = 0;
	actorInfo[hActorId - 1].presReel = NULL;
	actorInfo[hActorId - 1].presFilm = 0;
	actorInfo[hActorId - 1].presObj = NULL;

	// Store current scene's parameters for this actor
	actorInfo[hActorId - 1].mtype = FROM_LE_32(as->masking);
	actorInfo[hActorId - 1].actorCode = FROM_LE_32(as->hActorCode);

	// Run actor's script for this scene
	if (bRunScript) {
		if (bActorsOn)
			actorInfo[hActorId - 1].bAlive = true;

		if (actorInfo[hActorId - 1].bAlive && FROM_LE_32(as->hActorCode))
			ActorEvent(hActorId, STARTUP, PLR_NOEVENT);
	}
}
Ejemplo n.º 4
0
/**
 * Return the position of an object.
 * Returns X, Y and direction in angles
 */
void ScummEngine::getObjectXYPos(int object, int &x, int &y, int &dir) {
	int idx = getObjectIndex(object);
	assert(idx >= 0);
	ObjectData &od = _objs[idx];
	int state;
	const byte *ptr;
	const ImageHeader *imhd;

	if (_game.version >= 6) {
		state = getState(object) - 1;
		if (state < 0)
			state = 0;

		ptr = getOBIMFromObjectData(od);
		if (!ptr) {
			// FIXME: We used to assert here, but it seems that in the nexus
			// in The Dig, this can happen, at least with old savegames, and
			// it's safe to continue...
			debug(0, "getObjectXYPos: Can't find object %d", object);
			return;
		}
		imhd = (const ImageHeader *)findResourceData(MKTAG('I','M','H','D'), ptr);
		assert(imhd);
		if (_game.version == 8) {
			switch (FROM_LE_32(imhd->v8.version)) {
			case 800:
				x = od.x_pos + (int32)READ_LE_UINT32((const byte *)imhd + 8 * state + 0x44);
				y = od.y_pos + (int32)READ_LE_UINT32((const byte *)imhd + 8 * state + 0x48);
				break;
			case 801:
				x = od.x_pos + (int32)READ_LE_UINT32(&imhd->v8.hotspot[state].x);
				y = od.y_pos + (int32)READ_LE_UINT32(&imhd->v8.hotspot[state].y);
				break;
			default:
				error("Unsupported image header version %d", FROM_LE_32(imhd->v8.version));
			}
		} else if (_game.version == 7) {
			x = od.x_pos + (int16)READ_LE_UINT16(&imhd->v7.hotspot[state].x);
			y = od.y_pos + (int16)READ_LE_UINT16(&imhd->v7.hotspot[state].y);
		} else {
			x = od.x_pos + (int16)READ_LE_UINT16(&imhd->old.hotspot[state].x);
			y = od.y_pos + (int16)READ_LE_UINT16(&imhd->old.hotspot[state].y);
		}
	} else if (_game.version <= 2) {
		x = od.walk_x;
		y = od.walk_y;

		// Adjust x, y when no actor direction is set, but only perform this
		// adjustment for V0 games (e.g. MM C64), otherwise certain scenes in
		// newer games are affected as well (e.g. the interior of the Shuttle
		// Bus scene in Zak V2, where no actor is present). Refer to bug #3526089.
		if (!od.actordir && _game.version == 0) {
			x = od.x_pos + od.width / 2;
			y = od.y_pos + od.height / 2;
		}
		x = x >> V12_X_SHIFT;
		y = y >> V12_Y_SHIFT;
	} else {
Ejemplo n.º 5
0
/**
 * LoadBasicChunks
 */
void LoadBasicChunks(void) {
	byte *cptr;
	int numObjects;

	// Allocate RAM for savescene data
	InitialiseSaveScenes();

	// CHUNK_TOTAL_ACTORS seems to be missing in the released version, hard coding a value
	// TODO: Would be nice to just change 511 to MAX_SAVED_ALIVES
	cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_TOTAL_ACTORS);
	RegisterActors((cptr != NULL) ? READ_LE_UINT32(cptr) : 511);

	// CHUNK_TOTAL_GLOBALS seems to be missing in some versions.
	// So if it is missing, set a reasonably high value for the number of globals.
	cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_TOTAL_GLOBALS);
	RegisterGlobals((cptr != NULL) ? READ_LE_UINT32(cptr) : 512);

	cptr = FindChunk(INV_OBJ_SCNHANDLE, CHUNK_TOTAL_OBJECTS);
	numObjects = (cptr != NULL) ? READ_LE_UINT32(cptr) : 0;

	cptr = FindChunk(INV_OBJ_SCNHANDLE, CHUNK_OBJECTS);

#ifdef SCUMM_BIG_ENDIAN
	//convert to native endianness
	INV_OBJECT *io = (INV_OBJECT *)cptr;
	for (int i = 0; i < numObjects; i++, io++) {
		io->id        = FROM_LE_32(io->id);
		io->hIconFilm = FROM_LE_32(io->hIconFilm);
		io->hScript   = FROM_LE_32(io->hScript);
		io->attribute = FROM_LE_32(io->attribute);
	}
#endif

	RegisterIcons(cptr, numObjects);

	cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_TOTAL_POLY);
	if (cptr != NULL)
		MaxPolygons(*cptr);

	if (TinselV2) {
		// Global processes
		cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_NUM_PROCESSES);
		assert(cptr && (*cptr < 100));
		int num = *cptr;
		cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_PROCESSES);
		assert(!num || cptr);
		GlobalProcesses(num, cptr);

		// CdPlay() stuff
		cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_CDPLAY_HANDLE);
		assert(cptr);
		uint32 playHandle = READ_LE_UINT32(cptr);
		assert(playHandle < 512);
		SetCdPlayHandle(playHandle);
	}
}
Ejemplo n.º 6
0
static void MoverProcessHelper(int X, int Y, int id, PMOVER pMover) {
	const FILM *pfilm;
	const MULTI_INIT *pmi;
	const FRAME *pFrame;
	IMAGE *pim;


	assert(BgPal()); // Can't start actor without a background palette
	assert(pMover->walkReels[0][FORWARD]); // Starting actor process without walk reels

	InitMover(pMover);
	InitialPathChecks(pMover, X, Y);

	pfilm = (const FILM *)LockMem(pMover->walkReels[0][FORWARD]);
	pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pfilm->reels[0].mobj));

//---
	pFrame = (const FRAME *)LockMem(FROM_LE_32(pmi->hMulFrame));

	// get pointer to image
	pim = (IMAGE *)LockMem(READ_LE_UINT32(pFrame));	// handle to image
	pim->hImgPal = TO_LE_32(BgPal());
//---
	pMover->actorObj = MultiInitObject(pmi);

/**/	assert(pMover->actorID == id);
	pMover->actorID = id;

	// add it to display list
	MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pMover->actorObj);
	storeActorReel(id, NULL, 0, pMover->actorObj, 0, 0, 0);

	InitStepAnimScript(&pMover->actorAnim, pMover->actorObj, FROM_LE_32(pfilm->reels[0].script), ONE_SECOND / FROM_LE_32(pfilm->frate));
	pMover->stepCount = 0;

	MultiSetAniXY(pMover->actorObj, pMover->objX, pMover->objY);

	// If no path, just use first path in the scene
	if (pMover->hCpath != NOPOLY)
		SetMoverZ(pMover, pMover->objY, GetPolyZfactor(pMover->hCpath));
	else
		SetMoverZ(pMover, pMover->objY, GetPolyZfactor(FirstPathPoly()));

	// Make him the right size
	SetMoverStanding(pMover);

//**** if added 18/11/94, am
	if (X != MAGICX && Y != MAGICY) {
		HideMover(pMover, 0);		// Allows a play to come in before this appears
		pMover->bHidden = false;	// ...but don't stay hidden
	}

	pMover->bActive = true;
}
Ejemplo n.º 7
0
byte *Win32ResExtractor::get_resource_entry(WinLibrary *fi, WinResource *wr, int *size) {
	byte *result;

	Win32ImageResourceDataEntry *dataent;

	dataent = (Win32ImageResourceDataEntry *) wr->children;
	RETURN_IF_BAD_POINTER(NULL, *dataent);
	*size = FROM_LE_32(dataent->size);

	result = fi->memory + FROM_LE_32(dataent->offset_to_data);

	RETURN_IF_BAD_OFFSET(NULL, result, *size);

	return result;
}
Ejemplo n.º 8
0
void ResourceManager::readCluIndex(uint16 fileNum, Common::File *file) {
    // we didn't read from this file before, get its index table
    assert(_resFiles[fileNum].entryTab == NULL);
    assert(file);

    // 1st DWORD of a cluster is an offset to the look-up table
    uint32 table_offset = file->readUint32LE();
    debug(6, "table offset = %d", table_offset);
    uint32 tableSize = file->size() - table_offset; // the table is stored at the end of the file
    file->seek(table_offset);

    assert((tableSize % 8) == 0);
    _resFiles[fileNum].entryTab = (uint32 *)malloc(tableSize);
    _resFiles[fileNum].numEntries = tableSize / 8;

    assert(_resFiles[fileNum].entryTab);

    file->read(_resFiles[fileNum].entryTab, tableSize);
    if (file->eos() || file->err())
        error("unable to read index table from file %s", _resFiles[fileNum].fileName);

#ifdef SCUMM_BIG_ENDIAN
    for (int tabCnt = 0; tabCnt < _resFiles[fileNum].numEntries * 2; tabCnt++)
        _resFiles[fileNum].entryTab[tabCnt] = FROM_LE_32(_resFiles[fileNum].entryTab[tabCnt]);
#endif
}
Ejemplo n.º 9
0
/**
 * Return the position of an object.
 * Returns X, Y and direction in angles
 */
void ScummEngine::getObjectXYPos(int object, int &x, int &y, int &dir) {
	int idx = (_v0ObjectIndex) ? object : getObjectIndex(object);
	assert(idx >= 0);
	ObjectData &od = _objs[idx];
	int state;
	const byte *ptr;
	const ImageHeader *imhd;

	if (_game.version >= 6) {
		state = getState(object) - 1;
		if (state < 0)
			state = 0;

		ptr = getOBIMFromObjectData(od);
		if (!ptr) {
			// FIXME: We used to assert here, but it seems that in the nexus
			// in The Dig, this can happen, at least with old savegames, and
			// it's safe to continue...
			debug(0, "getObjectXYPos: Can't find object %d", object);
			return;
		}
		imhd = (const ImageHeader *)findResourceData(MKTAG('I','M','H','D'), ptr);
		assert(imhd);
		if (_game.version == 8) {
			switch (FROM_LE_32(imhd->v8.version)) {
			case 800:
				x = od.x_pos + (int32)READ_LE_UINT32((const byte *)imhd + 8 * state + 0x44);
				y = od.y_pos + (int32)READ_LE_UINT32((const byte *)imhd + 8 * state + 0x48);
				break;
			case 801:
				x = od.x_pos + (int32)READ_LE_UINT32(&imhd->v8.hotspot[state].x);
				y = od.y_pos + (int32)READ_LE_UINT32(&imhd->v8.hotspot[state].y);
				break;
			default:
				error("Unsupported image header version %d", FROM_LE_32(imhd->v8.version));
			}
		} else if (_game.version == 7) {
			x = od.x_pos + (int16)READ_LE_UINT16(&imhd->v7.hotspot[state].x);
			y = od.y_pos + (int16)READ_LE_UINT16(&imhd->v7.hotspot[state].y);
		} else {
			x = od.x_pos + (int16)READ_LE_UINT16(&imhd->old.hotspot[state].x);
			y = od.y_pos + (int16)READ_LE_UINT16(&imhd->old.hotspot[state].y);
		}
	} else if (_game.version <= 2) {
		x = od.walk_x >> V12_X_SHIFT;
		y = od.walk_y >> V12_Y_SHIFT;
	} else {
Ejemplo n.º 10
0
/**
 * Run a scene process with the given event.
 */
void SceneProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait, int myEscape,
						bool *result) {
	uint32 i;		// Loop counter
	if (result) *result = false;

	CORO_BEGIN_CONTEXT;
		PROCESS_STRUC *pStruc;
		PPROCESS pProc;
		PINT_CONTEXT pic;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	_ctx->pStruc = (PROCESS_STRUC *)LockMem(hSceneProcess);
	for (i = 0; i < numSceneProcess; i++) {
		if (FROM_LE_32(_ctx->pStruc[i].processId) == procID) {
			assert(_ctx->pStruc[i].hProcessCode);		// Must have some code to run

			_ctx->pic = InitInterpretContext(GS_PROCESS,
				FROM_LE_32(_ctx->pStruc[i].hProcessCode),
				event,
				NOPOLY,			// No polygon
				0,			// No actor
				NULL,			// No object
				myEscape);
			if (_ctx->pic == NULL)
				return;

			_ctx->pProc = g_scheduler->createProcess(PID_PROCESS + i, ProcessTinselProcess,
				&_ctx->pic, sizeof(_ctx->pic));
			AttachInterpret(_ctx->pic, _ctx->pProc);
			break;
		}
	}

	if (i == numSceneProcess)
		return;

	if (bWait) {
		CORO_INVOKE_2(WaitInterpret, _ctx->pProc, result);
	}

	CORO_END_CODE;
}
Ejemplo n.º 11
0
/**
 * Change which reel is playing for a moving actor.
 */
void AlterMover(PMOVER pMover, SCNHANDLE film, AR_FUNCTION fn) {
	const FILM *pfilm;

	assert(pMover->actorObj); // Altering null moving actor's animation script

	if (fn == AR_POPREEL) {
		// Use the saved film
		film = pMover->hPushedFilm;
	}
	if (fn == AR_PUSHREEL) {
		// Save the one we're replacing
		pMover->hPushedFilm = (pMover->bSpecReel) ? pMover->hLastFilm : 0;
	}

	if (film == 0) {
		if (pMover->bSpecReel) {
			// Revert to 'normal' actor
			SetMoverWalkReel(pMover, pMover->direction, pMover->scale, true);
			pMover->bSpecReel = false;
		}
	} else {
		// Remember this one in case the actor talks
		pMover->hLastFilm = film;

		pfilm = (const FILM *)LockMem(film);
		assert(pfilm != NULL);

		InitStepAnimScript(&pMover->actorAnim, pMover->actorObj, FROM_LE_32(pfilm->reels[0].script), ONE_SECOND / FROM_LE_32(pfilm->frate));
		if (!TinselV2)
			pMover->stepCount = 0;

		// If no path, just use first path in the scene
		if (pMover->hCpath != NOPOLY)
			SetMoverZ(pMover, pMover->objY, GetPolyZfactor(pMover->hCpath));
		else
			SetMoverZ(pMover, pMover->objY, GetPolyZfactor(FirstPathPoly()));

		if (fn == AR_WALKREEL) {
			pMover->bSpecReel = false;
			pMover->bWalkReel = true;
		} else {
			pMover->bSpecReel = true;
			pMover->bWalkReel = false;

#ifdef DEBUG
			assert(StepAnimScript(&pMover->actorAnim) != ScriptFinished); // Actor reel has finished!
#else
			StepAnimScript(&pMover->actorAnim);	// 04/01/95
#endif
		}

		// Hang on, we may not want him yet! 04/01/95
		if (pMover->bHidden)
			MultiSetZPosition(pMover->actorObj, -1);
	}
}
Ejemplo n.º 12
0
/**
 * Called at the start of each scene. Start each actor with a code block.
 * @param ah			Scene handle
 * @param numActors		Number of actors
 * @param bRunScript	Flag for whether to run actor scene scripts
 */
void StartTaggedActors(SCNHANDLE ah, int numActors, bool bRunScript) {
	int	i;

	if (TinselV2) {
		// Clear it all out for a fresh start
		memset(taggedActors, 0, sizeof(taggedActors));
		numTaggedActors = numActors;
	} else {
		// Only actors with code blocks got (x, y) re-initialized, so...
		for (i = 0; i < NumActors; i++) {
			actorInfo[i].x = actorInfo[i].y = 0;
			actorInfo[i].mtype = 0;
		}
	}

	if (!TinselV2) {
		// Tinsel 1 load variation
		const T1_ACTOR_STRUC *as = (const T1_ACTOR_STRUC *)LockMem(ah);
		for (i = 0; i < numActors; i++, as++) {
			StartActor(as, bRunScript);
		}
	} else if (numActors > 0) {
		// Tinsel 2 load variation
		const T2_ACTOR_STRUC *as = (T2_ACTOR_STRUC *)LockMem(ah);
		for (i = 0; i < numActors; i++, as++) {
			assert(as->hActorCode);

			// Store current scene's parameters for this tagged actor
			taggedActors[i].id			= FROM_LE_32(as->hActorId);
			taggedActors[i].hTagText	= FROM_LE_32(as->hTagText);
			taggedActors[i].tagPortionV	= FROM_LE_32(as->tagPortionV);
			taggedActors[i].tagPortionH	= FROM_LE_32(as->tagPortionH);
			taggedActors[i].hActorCode	= FROM_LE_32(as->hActorCode);

			// Run actor's script for this scene
			if (bRunScript) {
				// Send in reverse order - they get swapped round in the scheduler
				ActorEvent(nullContext, taggedActors[i].id, SHOWEVENT, false, 0);
				ActorEvent(nullContext, taggedActors[i].id, STARTUP, false, 0);
			}
		}
	}
}
Ejemplo n.º 13
0
/**
 * Kill all instances of a scene process.
 */
void KillSceneProcess(uint32 procID) {
	uint32 i;		// Loop counter
	PROCESS_STRUC	*pStruc;

	pStruc = (PROCESS_STRUC *) LockMem(hSceneProcess);
	for (i = 0; i < numSceneProcess; i++) {
		if (FROM_LE_32(pStruc[i].processId) == procID) {
			g_scheduler->killMatchingProcess(PID_PROCESS + i, -1);
			break;
		}
	}
}
Ejemplo n.º 14
0
/**
 * Runs secondary reels for a scene background
 */
static void BGotherProcess(CORO_PARAM, const void *param) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
		OBJECT *pObj;
		ANIM anim;
	CORO_END_CONTEXT(_ctx);

	const FREEL *pReel = (const FREEL *)param;
	const MULTI_INIT *pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pReel->mobj));

	CORO_BEGIN_CODE(_ctx);

	// Initialise and insert the object, and initialise its script.
	_ctx->pObj = MultiInitObject(pmi);
	MultiInsertObject(GetPlayfieldList(FIELD_WORLD), _ctx->pObj);

	InitStepAnimScript(&_ctx->anim, pBG[0], FROM_LE_32(pReel->script), BGspeed);

	while (StepAnimScript(&_ctx->anim) != ScriptFinished)
		CORO_SLEEP(1);

	CORO_END_CODE;
}
Ejemplo n.º 15
0
/**
 * Called to restore a scene process.
 */
void RestoreSceneProcess(INT_CONTEXT *pic) {
	uint32 i;
	PROCESS_STRUC	*pStruc;

	pStruc = (PROCESS_STRUC *)LockMem(hSceneProcess);
	for (i = 0; i < numSceneProcess; i++) {
		if (FROM_LE_32(pStruc[i].hProcessCode) == pic->hCode) {
			g_scheduler->createProcess(PID_PROCESS + i, RestoredProcessProcess,
					 &pic, sizeof(pic));
			break;
		}
	}

	assert(i < numSceneProcess);
}
Ejemplo n.º 16
0
/**
 * Give a object a new image and new orientation flags.
 * @param pAniObj			Object to be updated
 * @param newflags			Objects new flags
 * @param hNewImg			Objects new image
 */
void AnimateObjectFlags(OBJECT *pAniObj, int newflags, SCNHANDLE hNewImg) {
	// validate object pointer
	assert(isValidObject(pAniObj));

	if (pAniObj->hImg != hNewImg
		|| (pAniObj->flags & DMA_HARDFLAGS) != (newflags & DMA_HARDFLAGS)) {
		// something has changed

		int oldAniX, oldAniY;	// objects old animation offsets
		int newAniX, newAniY;	// objects new animation offsets

		// get objects old animation offsets
		GetAniOffset(pAniObj->hImg, pAniObj->flags, &oldAniX, &oldAniY);

		// get objects new animation offsets
		GetAniOffset(hNewImg, newflags, &newAniX, &newAniY);

		if (hNewImg) {
			// get pointer to image
			const IMAGE *pNewImg = (IMAGE *)LockMem(hNewImg);

			// setup new shape
			pAniObj->width  = FROM_LE_16(pNewImg->imgWidth);
			pAniObj->height = FROM_LE_16(pNewImg->imgHeight) & ~C16_FLAG_MASK;
			newflags &= ~C16_FLAG_MASK;
			newflags |= FROM_LE_16(pNewImg->imgHeight) & C16_FLAG_MASK;

			// set objects bitmap definition
			pAniObj->hBits  = FROM_LE_32(pNewImg->hImgBits);
		} else {	// null image
			pAniObj->width  = 0;
			pAniObj->height = 0;
			pAniObj->hBits  = 0;
		}

		// set objects flags and signal a change
		pAniObj->flags = newflags | DMA_CHANGED;

		// set objects image
		pAniObj->hImg = hNewImg;

		// adjust objects position - subtract new from old for difference
		pAniObj->xPos += intToFrac(oldAniX - newAniX);
		pAniObj->yPos += intToFrac(oldAniY - newAniY);
	}
}
Ejemplo n.º 17
0
/**
 * Initialise a multi-part object using a list of images to init
 * each object piece. One object is created for each image in the list.
 * All objects are given the same palette as the first image. A pointer
 * to the first (master) object created is returned.
 * @param pInitTbl			Pointer to multi-object initialisation table
 */
OBJECT *MultiInitObject(const MULTI_INIT *pInitTbl) {
	OBJ_INIT obj_init;	// object init table
	OBJECT *pFirst, *pObj;	// object pointers
	FRAME *pFrame;		// list of images for the multi-part object

	if (FROM_LE_32(pInitTbl->hMulFrame)) {
		// we have a frame handle
		pFrame = (FRAME *)LockMem(FROM_LE_32(pInitTbl->hMulFrame));

		obj_init.hObjImg  = READ_LE_UINT32(pFrame);	// first objects shape
	} else {	// this must be a animation list for a NULL object
		pFrame = NULL;
		obj_init.hObjImg = 0;	// first objects shape
	}

	// init the object init table
	obj_init.objFlags = (int)FROM_LE_32(pInitTbl->mulFlags);	// all objects have same flags
	obj_init.objID    = (int)FROM_LE_32(pInitTbl->mulID);	// all objects have same ID
	obj_init.objX     = (int)FROM_LE_32(pInitTbl->mulX);	// all objects have same X ani pos
	obj_init.objY     = (int)FROM_LE_32(pInitTbl->mulY);	// all objects have same Y ani pos
	obj_init.objZ     = (int)FROM_LE_32(pInitTbl->mulZ);	// all objects have same Z pos

	// create and init the first object
	pObj = pFirst = InitObject(&obj_init);

	if (pFrame) {
		// if we have any animation frames

		pFrame++;

		while (READ_LE_UINT32(pFrame) != 0) {
			// set next objects shape
			obj_init.hObjImg = READ_LE_UINT32(pFrame);

			// create next object and link to previous
			pObj = pObj->pSlave = InitObject(&obj_init);

			pFrame++;
		}
	}

	// null end of list for final object
	pObj->pSlave = NULL;

	// return master object
	return pFirst;
}
Ejemplo n.º 18
0
void ScummEngine_v70he::readGlobalObjects() {
	int num = _fileHandle->readUint16LE();
	assert(num == _numGlobalObjects);
	assert(_objectStateTable);
	assert(_objectOwnerTable);

	_fileHandle->read(_objectStateTable, num);
	_fileHandle->read(_objectOwnerTable, num);
	_fileHandle->read(_objectRoomTable, num);

	_fileHandle->read(_classData, num * sizeof(uint32));

#if defined(SCUMM_BIG_ENDIAN)
	// Correct the endianess if necessary
	for (int i = 0; i != num; i++)
		_classData[i] = FROM_LE_32(_classData[i]);
#endif
}
Ejemplo n.º 19
0
/**
 * Get actor to adopt its appropriate walking reel.
 */
void SetMoverWalkReel(PMOVER pMover, DIRECTION reel, int scale, bool force) {
	SCNHANDLE	whichReel;
	const FILM *pfilm;

	// Kill off any play that may be going on for this actor
	// and restore the real actor
	storeActorReel(pMover->actorID, NULL, 0, NULL, 0, 0, 0);
	UnHideMover(pMover);

	// Don't do it if using a special walk reel
	if (pMover->bWalkReel)
		return;

	if (force || pMover->scale != scale || pMover->direction != reel) {
		assert(reel >= 0 && reel <= 3 && scale > 0 && scale <= TOTAL_SCALES); // out of range scale or reel

		// If scale change and both are regular scales
		// and there's a scaling reel in the right direction
		if (pMover->scale != scale
				&& scale <= NUM_MAINSCALES && pMover->scale <= NUM_MAINSCALES
				&& (whichReel = ScalingReel(pMover->actorID, pMover->scale, scale, reel)) != 0) {
//			error("Cripes");
			;	// Use what is now in 'whichReel'
		} else {
			whichReel = pMover->walkReels[scale-1][reel];
			assert(whichReel); // no reel
		}

		pfilm = (const FILM *)LockMem(whichReel);
		assert(pfilm != NULL); // no film

		InitStepAnimScript(&pMover->actorAnim, pMover->actorObj, FROM_LE_32(pfilm->reels[0].script), 1);

		// Synchronised walking reels
		assert(pMover->stepCount >= 0);
		SkipFrames(&pMover->actorAnim, pMover->stepCount);

		pMover->scale = scale;
		pMover->direction = reel;
	}
}
Ejemplo n.º 20
0
BaseSound::BaseSound(Audio::Mixer *mixer, File *file, uint32 base, bool bigendian) {
	_mixer = mixer;
	_file = file;

	uint res = 0;
	uint32 size;

	_file->seek(base + sizeof(uint32), SEEK_SET);
	if (bigendian)
		size = _file->readUint32BE();
	else
		size = _file->readUint32LE();

	// The Feeble Files uses set amount of voice offsets
	if (size == 0)
		size = 40000;

	res = size / sizeof(uint32);

	_offsets = (uint32 *)malloc(size + sizeof(uint32));
	_freeOffsets = true;

	_file->seek(base, SEEK_SET);

	if (_file->read(_offsets, size) != size)
		error("Can't read offsets");

	for (uint i = 0; i < res; i++) {
#if defined(SCUMM_BIG_ENDIAN)
	if (!(bigendian))
		_offsets[i] = FROM_LE_32(_offsets[i]);
#endif
	if (bigendian)
			_offsets[i] = TO_BE_32(_offsets[i]);
		_offsets[i] += base;
	}

	// only needed for mp3
	_offsets[res] = _file->size();
}
Ejemplo n.º 21
0
/**
 * About to jump or end
 * @param pAnim			Animation data structure
 */
bool AboutToJumpOrEnd(PANIM pAnim) {
	if (pAnim->aniDelta == 1) {
		// get a pointer to the script
		ANI_SCRIPT *pAni = (ANI_SCRIPT *)LockMem(pAnim->hScript);
		int	zzz = pAnim->scriptIndex;

		for (;;) {
			// repeat until a real image
			switch (FROM_LE_32(pAni[zzz].op)) {
			case ANI_END:		// end of animation script
			case ANI_JUMP:		// do animation jump
				return true;

			case ANI_HFLIP:		// flip animated object horizontally
			case ANI_VFLIP:		// flip animated object vertically
			case ANI_HVFLIP:	// flip animated object in both directions
				zzz++;
				break;

			case ANI_ADJUSTX:	// adjust animated object x animation point
			case ANI_ADJUSTY:	// adjust animated object y animation point
				zzz += 2;
				break;

			case ANI_ADJUSTXY:	// adjust animated object x & y animation points
				zzz += 3;
				break;

			case ANI_HIDE:		// hide animated object
			default:		// must be an actual animation frame handle
				return false;
			}
		}
	}

	return false;
}
Ejemplo n.º 22
0
/**
 * Run main animation that comprises the scene background.
 */
static void BGmainProcess(CORO_PARAM, const void *param) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	const FILM *pFilm;
	const FREEL *pReel;
	const MULTI_INIT *pmi;

	// get the stuff copied to process when it was created
	if (pBG[0] == NULL) {
		/*** At start of scene ***/

		if (!TinselV2) {
			pReel = (const FREEL *)param;

			// Get the MULTI_INIT structure
			pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pReel->mobj));

			// Initialise and insert the object, and initialise its script.
			pBG[0] = MultiInitObject(pmi);
			MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG[0]);
			InitStepAnimScript(&thisAnim[0], pBG[0], FROM_LE_32(pReel->script), BGspeed);
			bgReels = 1;
		} else {
			/*** At start of scene ***/
			pFilm = (const FILM *)LockMem(hBackground);
			bgReels = FROM_LE_32(pFilm->numreels);

			int i;
			for (i = 0; i < bgReels; i++) {
				// Get the MULTI_INIT structure
				pmi = (PMULTI_INIT) LockMem(FROM_LE_32(pFilm->reels[i].mobj));

				// Initialise and insert the object, and initialise its script.
				pBG[i] = MultiInitObject(pmi);
				MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG[i]);
				MultiSetZPosition(pBG[i], 0);
				InitStepAnimScript(&thisAnim[i], pBG[i], FROM_LE_32(pFilm->reels[i].script), BGspeed);

				if (i > 0)
					pBG[i-1]->pSlave = pBG[i];
			}
		}

		if (bDoFadeIn) {
			FadeInFast(NULL);
			bDoFadeIn = false;
		} else if (TinselV2)
			PokeInTagColor();

		for (;;) {
			for (int i = 0; i < bgReels; i++) {
				if (StepAnimScript(&thisAnim[i]) == ScriptFinished)
					error("Background animation has finished");
			}

			CORO_SLEEP(1);
		}
	} else {
		// New background during scene
		if (!TinselV2) {
			pReel = (const FREEL *)param;
			InitStepAnimScript(&thisAnim[0], pBG[0], FROM_LE_32(pReel->script), BGspeed);
			StepAnimScript(&thisAnim[0]);
		} else {
			pFilm = (const FILM *)LockMem(hBackground);
			assert(bgReels == (int32)FROM_LE_32(pFilm->numreels));

			// Just re-initialise the scripts.
			for (int i = 0; i < bgReels; i++) {
				InitStepAnimScript(&thisAnim[i], pBG[i], pFilm->reels[i].script, BGspeed);
				StepAnimScript(&thisAnim[i]);
			}
		}
	}

	CORO_END_CODE;
}
Ejemplo n.º 23
0
/**
 * Advance to next frame routine.
 * @param pAnim			Animation data structure
 */
SCRIPTSTATE DoNextFrame(ANIM *pAnim) {
	// get a pointer to the script
	const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript);

	while (1) {	// repeat until a real image
		debugC(DEBUG_DETAILED, kTinselDebugAnimations,
		"DoNextFrame %ph index=%d, op=%xh", (byte *)pAnim, pAnim->scriptIndex,
		FROM_LE_32(pAni[pAnim->scriptIndex].op));

		switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) {
		case ANI_END:	// end of animation script

			// move to next opcode
			pAnim->scriptIndex++;

			// indicate script has finished
			return ScriptFinished;

		case ANI_JUMP:	// do animation jump

			// move to jump address
			pAnim->scriptIndex++;

			// jump to new frame position
			pAnim->scriptIndex += (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op);

			// go fetch a real image
			break;

		case ANI_HFLIP:	// flip animated object horizontally

			// next opcode
			pAnim->scriptIndex++;

			MultiHorizontalFlip(pAnim->pObject);

			// go fetch a real image
			break;

		case ANI_VFLIP:	// flip animated object vertically

			// next opcode
			pAnim->scriptIndex++;

			MultiVerticalFlip(pAnim->pObject);

			// go fetch a real image
			break;
		case ANI_HVFLIP:	// flip animated object in both directions

			// next opcode
			pAnim->scriptIndex++;

			MultiHorizontalFlip(pAnim->pObject);
			MultiVerticalFlip(pAnim->pObject);

			// go fetch a real image
			break;

		case ANI_ADJUSTX:	// adjust animated object x animation point

			// move to x adjustment operand
			pAnim->scriptIndex++;

			MultiAdjustXY(pAnim->pObject, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op), 0);

			// next opcode
			pAnim->scriptIndex++;

			// go fetch a real image
			break;

		case ANI_ADJUSTY:	// adjust animated object y animation point

			// move to y adjustment operand
			pAnim->scriptIndex++;

			MultiAdjustXY(pAnim->pObject, 0, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op));

			// next opcode
			pAnim->scriptIndex++;

			// go fetch a real image
			break;

		case ANI_ADJUSTXY:	// adjust animated object x & y animation points
		{
			int x, y;

			// move to x adjustment operand
			pAnim->scriptIndex++;
			x = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op);

			// move to y adjustment operand
			pAnim->scriptIndex++;
			y = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op);

			MultiAdjustXY(pAnim->pObject, x, y);

			// next opcode
			pAnim->scriptIndex++;

			// go fetch a real image
			break;
		}

		case ANI_NOSLEEP:	// do not sleep for this frame

			// next opcode
			pAnim->scriptIndex++;

			// indicate not to sleep
			return ScriptNoSleep;

		case ANI_CALL:		// call routine

			// move to function address
			pAnim->scriptIndex++;

			// make function call

			// REMOVED BUGGY CODE
			// pFunc is a function pointer that's part of a union and is assumed to be 32-bits.
			// There is no known place where a function pointer is stored inside the animation
			// scripts, something which wouldn't have worked anyway. Having played through the
			// entire game, there hasn't been any occurence of this case, so just error out here
			// in case we missed something (highly unlikely though)
			error("ANI_CALL opcode encountered! Please report this error to the ScummVM team");
			//(*pAni[pAnim->scriptIndex].pFunc)(pAnim);
			return ScriptSleep;	// for compilers that don't support NORETURN

#if 0
			// next opcode
			pAnim->scriptIndex++;

			// go fetch a real image
			break;
#endif

		case ANI_HIDE:		// hide animated object

			MultiHideObject(pAnim->pObject);

			// next opcode
			pAnim->scriptIndex++;

			// dont skip a sleep
			return ScriptSleep;

		default:	// must be an actual animation frame handle

			// set objects new animation frame
			pAnim->pObject->hShape = FROM_LE_32(pAni[pAnim->scriptIndex].hFrame);

			// re-shape the object
			MultiReshape(pAnim->pObject);

			// next opcode
			pAnim->scriptIndex++;

			// dont skip a sleep
			return ScriptSleep;
		}
	}
}
Ejemplo n.º 24
0
static void LoadScene(SCNHANDLE scene, int entry) {
	uint	i;
	TP_INIT init;
	const SCENE_STRUC	*ss;
	const ENTRANCE_STRUC	*es;

	// Scene handle
	SceneHandle = scene;		// Save scene handle in case of Save_Scene()
	LockMem(SceneHandle);		// Make sure scene is loaded
	LockScene(SceneHandle);		// Prevent current scene from being discarded

	if (TinselV2) {
		// CdPlay() stuff
		byte *cptr = FindChunk(scene, CHUNK_CDPLAY_FILENUM);
		assert(cptr);
		i = READ_LE_UINT32(cptr);
		assert(i < 512);
		cptr = FindChunk(scene, CHUNK_CDPLAY_FILENAME);
		assert(cptr);
		SetCdPlaySceneDetails(i, (const char *)cptr);
	}

	// Find scene structure
	ss = GetSceneStruc(FindChunk(scene, CHUNK_SCENE));
	assert(ss != NULL);

	if (TinselV2) {
		// Handle to scene description
		newestScene = FROM_LE_32(ss->hSceneDesc);

		// Music stuff
		char *cptr = (char *)FindChunk(scene, CHUNK_MUSIC_FILENAME);
		assert(cptr);
		_vm->_pcmMusic->setMusicSceneDetails(FROM_LE_32(ss->hMusicScript),
			FROM_LE_32(ss->hMusicSegment), cptr);
	}

	if (entry == NO_ENTRY_NUM) {
		// Restoring scene

		// Initialise all the polygons for this scene
		InitPolygons(FROM_LE_32(ss->hPoly), FROM_LE_32(ss->numPoly), true);

		// Initialise the actors for this scene
		StartTaggedActors(FROM_LE_32(ss->hTaggedActor), FROM_LE_32(ss->numTaggedActor), false);

		if (TinselV2)
			// Returning from cutscene
			SendSceneTinselProcess(RESTORE);

	} else {
		// Genuine new scene

		// Initialise all the polygons for this scene
		InitPolygons(FROM_LE_32(ss->hPoly), FROM_LE_32(ss->numPoly), false);

		// Initialise the actors for this scene
		StartTaggedActors(FROM_LE_32(ss->hTaggedActor), FROM_LE_32(ss->numTaggedActor), true);

		// Run the appropriate entrance code (if any)
		es = (const ENTRANCE_STRUC *)LockMem(FROM_LE_32(ss->hEntrance));
		for (i = 0; i < FROM_LE_32(ss->numEntrance); i++) {
			if (FROM_LE_32(es->eNumber) == (uint)entry) {
				if (es->hScript) {
					init.event = STARTUP;
					init.hTinselCode = es->hScript;

					g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
				}
				break;
			}

			// Move to next entrance
			if (TinselV2)
				++es;
			else
				es = (const ENTRANCE_STRUC *)((const byte *)es + 8);

		}

		if (i == FROM_LE_32(ss->numEntrance))
			error("Non-existant scene entry number");

		if (ss->hSceneScript) {
			init.event = STARTUP;
			init.hTinselCode = ss->hSceneScript;

			g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
		}
	}

	// Default refer type
	SetDefaultRefer(FROM_LE_32(ss->defRefer));

	// Scene's processes
	SceneProcesses(FROM_LE_32(ss->numProcess), FROM_LE_32(ss->hProcess));
}
Ejemplo n.º 25
0
/**
 * Initialise a object using a OBJ_INIT structure to supply parameters.
 * @param pInitTbl			Pointer to object initialisation table
 */
OBJECT *InitObject(const OBJ_INIT *pInitTbl) {
	// allocate a new object
	OBJECT *pObj = AllocObject();

	// make sure object created
	assert(pObj != NULL);

	// set objects shape
	pObj->hImg = pInitTbl->hObjImg;

	// set objects ID
	pObj->oid = pInitTbl->objID;

	// set objects flags
	pObj->flags = DMA_CHANGED | pInitTbl->objFlags;

	// set objects Z position
	pObj->zPos = pInitTbl->objZ;

	// get pointer to image
	if (pInitTbl->hObjImg) {
		int aniX, aniY;		// objects animation offsets
		PALQ *pPalQ = NULL;	// palette queue pointer
		const IMAGE *pImg = (const IMAGE *)LockMem(pInitTbl->hObjImg);	// handle to image

		if (pImg->hImgPal) {
			// allocate a palette for this object
			pPalQ = AllocPalette(FROM_LE_32(pImg->hImgPal));

			// make sure palette allocated
			assert(pPalQ != NULL);
		}

		// assign palette to object
		pObj->pPal = pPalQ;

		// set objects size
		pObj->width  = FROM_LE_16(pImg->imgWidth);
		pObj->height = FROM_LE_16(pImg->imgHeight) & ~C16_FLAG_MASK;
		pObj->flags &= ~C16_FLAG_MASK;
		pObj->flags |= FROM_LE_16(pImg->imgHeight) & C16_FLAG_MASK;

		// set objects bitmap definition
		pObj->hBits = FROM_LE_32(pImg->hImgBits);

		// get animation offset of object
		GetAniOffset(pObj->hImg, pInitTbl->objFlags, &aniX, &aniY);

		// set objects X position - subtract ani offset
		pObj->xPos = intToFrac(pInitTbl->objX - aniX);

		// set objects Y position - subtract ani offset
		pObj->yPos = intToFrac(pInitTbl->objY - aniY);
	} else {	// no image handle - null image

		// set objects X position
		pObj->xPos = intToFrac(pInitTbl->objX);

		// set objects Y position
		pObj->yPos = intToFrac(pInitTbl->objY);
	}

	// return new object
	return pObj;
}
Ejemplo n.º 26
0
byte *ScEngine::getCompiledScript(const char *filename, uint32 *outSize, bool ignoreCache) {
	// is script in cache?
	if (!ignoreCache) {
		for (int i = 0; i < MAX_CACHED_SCRIPTS; i++) {
			if (_cachedScripts[i] && scumm_stricmp(_cachedScripts[i]->_filename.c_str(), filename) == 0) {
				_cachedScripts[i]->_timestamp = g_system->getMillis();
				*outSize = _cachedScripts[i]->_size;
				return _cachedScripts[i]->_buffer;
			}
		}
	}

	// nope, load it
	byte *compBuffer;
	uint32 compSize;

	uint32 size;

	byte *buffer = BaseEngine::instance().getFileManager()->readWholeFile(filename, &size);
	if (!buffer) {
		_gameRef->LOG(0, "ScEngine::GetCompiledScript - error opening script '%s'", filename);
		return nullptr;
	}

	// needs to be compiled?
	if (FROM_LE_32(*(uint32 *)buffer) == SCRIPT_MAGIC) {
		compBuffer = buffer;
		compSize = size;
	} else {
		if (!_compilerAvailable) {
			_gameRef->LOG(0, "ScEngine::GetCompiledScript - script '%s' needs to be compiled but compiler is not available", filename);
			delete[] buffer;
			return nullptr;
		}
		// This code will never be called, since _compilerAvailable is const false.
		// It's only here in the event someone would want to reinclude the compiler.
		error("Script needs compilation, ScummVM does not contain a WME compiler");
	}

	byte *ret = nullptr;

	// add script to cache
	CScCachedScript *cachedScript = new CScCachedScript(filename, compBuffer, compSize);
	if (cachedScript) {
		int index = 0;
		uint32 minTime = g_system->getMillis();
		for (int i = 0; i < MAX_CACHED_SCRIPTS; i++) {
			if (_cachedScripts[i] == nullptr) {
				index = i;
				break;
			} else if (_cachedScripts[i]->_timestamp <= minTime) {
				minTime = _cachedScripts[i]->_timestamp;
				index = i;
			}
		}

		if (_cachedScripts[index] != nullptr) {
			delete _cachedScripts[index];
		}
		_cachedScripts[index] = cachedScript;

		ret = cachedScript->_buffer;
		*outSize = cachedScript->_size;
	}


	// cleanup
	delete[] buffer;

	return ret;
}
Ejemplo n.º 27
0
int Logic::runScript2(byte *scriptData, byte *objectData, byte *offsetPtr) {
	// Interestingly, unlike our BASS engine the stack is a local variable.
	// I don't know whether or not this is relevant to the working of the
	// BS2 engine.

	int32 stack[STACK_SIZE];
	int32 stackPtr = 0;

	uint32 offset = READ_LE_UINT32(offsetPtr);

	ResHeader header;

	header.read(scriptData);

	scriptData += ResHeader::size() + ObjectHub::size();

	// The script data format:
	//	int32_TYPE	1		Size of variable space in bytes
	//	...				The variable space
	//	int32_TYPE	1		numberOfScripts
	//	int32_TYPE	numberOfScripts	The offsets for each script

	// Initialise some stuff

	uint32 ip = 0;			 // Code pointer
	int scriptNumber;

	// Get the start of variables and start of code

	byte *localVars = scriptData + 4;
	byte *code = scriptData + READ_LE_UINT32(scriptData) + 4;
	uint32 noScripts = READ_LE_UINT32(code);

	code += 4;

	byte *offsetTable = code;

	if (offset < noScripts) {
		ip = READ_LE_UINT32(offsetTable + offset * 4);
		scriptNumber = offset;
		debug(8, "Starting script %d from %d", scriptNumber, ip);
	} else {
		uint i;

		ip = offset;

		for (i = 1; i < noScripts; i++) {
			if (READ_LE_UINT32(offsetTable + 4 * i) >= ip)
				break;
		}

		scriptNumber = i - 1;
		debug(8, "Resuming script %d from %d", scriptNumber, ip);
	}

	// There are a couple of known script bugs related to interacting with
	// certain objects. We try to work around a few of them.

	bool checkMopBug = false;
	bool checkPyramidBug = false;
	bool checkElevatorBug = false;

	if (scriptNumber == 2) {
		if (strcmp((char *)header.name, "mop_73") == 0)
			checkMopBug = true;
		else if (strcmp((char *)header.name, "titipoco_81") == 0)
			checkPyramidBug = true;
		else if (strcmp((char *)header.name, "lift_82") == 0)
			checkElevatorBug = true;
	}

	code += noScripts * 4;

	// Code should now be pointing at an identifier and a checksum
	byte *checksumBlock = code;

	code += 4 * 3;

	if (READ_LE_UINT32(checksumBlock) != 12345678) {
		error("Invalid script in object %s", header.name);
		return 0;
	}

	int32 codeLen = READ_LE_UINT32(checksumBlock + 4);
	int32 checksum = 0;

	for (int i = 0; i < codeLen; i++)
		checksum += (unsigned char) code[i];

	if (checksum != (int32)READ_LE_UINT32(checksumBlock + 8)) {
		debug(1, "Checksum error in object %s", header.name);
		// This could be bad, but there has been a report about someone
		// who had problems running the German version because of
		// checksum errors. Could there be a version where checksums
		// weren't properly calculated?
	}

	bool runningScript = true;

	int parameterReturnedFromMcodeFunction = 0;	// Allow scripts to return things
	int savedStartOfMcode = 0;	// For saving start of mcode commands

	while (runningScript) {
		int i;
		int32 a, b;
		int curCommand, parameter, value; // Command and parameter variables
		int retVal;
		int caseCount;
		bool foundCase;
		byte *ptr;

		curCommand = code[ip++];

		switch (curCommand) {

		// Script-related opcodes

		case CP_END_SCRIPT:
			// End the script
			runningScript = false;

			// WORKAROUND: The dreaded pyramid bug makes the torch
			// untakeable when you speak to Titipoco. This is
			// because one of the conditions for the torch to be
			// takeable is that Titipoco isn't doing anything out
			// of the ordinary. Global variable 913 has to be 0 to
			// signify that he is in his "idle" state.
			//
			// Unfortunately, simply the act of speaking to him
			// sets variable 913 to 1 (probably to stop him from
			// turning around every now and then). The script may
			// then go on to set the variable to different values
			// to trigger various behaviours in him, but if you
			// have run out of these cases the script won't ever
			// set it back to 0 again.
			//
			// So if his click hander finishes, and variable 913 is
			// 1, we set it back to 0 manually.

			if (checkPyramidBug && readVar(913) == 1) {
				warning("Working around pyramid bug: Resetting Titipoco's state");
				writeVar(913, 0);
			}

			// WORKAROUND: The not-so-known-but-should-be-dreaded
			// elevator bug.
			//
			// The click handler for the top of the elevator only
			// handles using the elevator, not examining it. When
			// examining it, the mouse cursor is removed but never
			// restored.

			if (checkElevatorBug && readVar(RIGHT_BUTTON)) {
				warning("Working around elevator bug: Restoring mouse pointer");
				fnAddHuman(NULL);
			}

			debug(9, "CP_END_SCRIPT");
			break;
		case CP_QUIT:
			// Quit out for a cycle
			WRITE_LE_UINT32(offsetPtr, ip);
			debug(9, "CP_QUIT");
			return 0;
		case CP_TERMINATE:
			// Quit out immediately without affecting the offset
			// pointer
			debug(9, "CP_TERMINATE");
			return 3;
		case CP_RESTART_SCRIPT:
			// Start the script again
			ip = FROM_LE_32(offsetTable[scriptNumber]);
			debug(9, "CP_RESTART_SCRIPT");
			break;

		// Stack-related opcodes

		case CP_PUSH_INT32:
			// Push a long word value on to the stack
			Read32ip(parameter);
			push(parameter);
			debug(9, "CP_PUSH_INT32: %d", parameter);
			break;
		case CP_PUSH_LOCAL_VAR32:
			// Push the contents of a local variable
			Read16ip(parameter);
			push(READ_LE_UINT32(localVars + parameter));
			debug(9, "CP_PUSH_LOCAL_VAR32: localVars[%d] => %d", parameter / 4, READ_LE_UINT32(localVars + parameter));
			break;
		case CP_PUSH_GLOBAL_VAR32:
			// Push a global variable
			Read16ip(parameter);
			push(readVar(parameter));
			debug(9, "CP_PUSH_GLOBAL_VAR32: scriptVars[%d] => %d", parameter, readVar(parameter));
			break;
		case CP_PUSH_LOCAL_ADDR:
			// Push the address of a local variable

			// From what I understand, some scripts store data
			// (e.g. mouse pointers) in their local variable space
			// from the very beginning, and use this mechanism to
			// pass that data to the opcode function. I don't yet
			// know the conceptual difference between this and the
			// CP_PUSH_DEREFERENCED_STRUCTURE opcode.

			Read16ip(parameter);
			push_ptr(localVars + parameter);
			debug(9, "CP_PUSH_LOCAL_ADDR: &localVars[%d] => %p", parameter / 4, localVars + parameter);
			break;
		case CP_PUSH_STRING:
			// Push the address of a string on to the stack
			// Get the string size
			Read8ip(parameter);

			// ip now points to the string
			ptr = code + ip;
			push_ptr(ptr);
			debug(9, "CP_PUSH_STRING: \"%s\"", ptr);
			ip += (parameter + 1);
			break;
		case CP_PUSH_DEREFERENCED_STRUCTURE:
			// Push the address of a dereferenced structure
			Read32ip(parameter);
			ptr = objectData + 4 + ResHeader::size() + ObjectHub::size() + parameter;
			push_ptr(ptr);
			debug(9, "CP_PUSH_DEREFERENCED_STRUCTURE: %d => %p", parameter, ptr);
			break;
		case CP_POP_LOCAL_VAR32:
			// Pop a value into a local word variable
			Read16ip(parameter);
			value = pop();
			WRITE_LE_UINT32(localVars + parameter, value);
			debug(9, "CP_POP_LOCAL_VAR32: localVars[%d] = %d", parameter / 4, value);
			break;
		case CP_POP_GLOBAL_VAR32:
			// Pop a global variable
			Read16ip(parameter);
			value = pop();

			// WORKAROUND for bug #1214168: The not-at-all dreaded
			// mop bug.
			//
			// At the London Docks, global variable 1003 keeps
			// track of Nico:
			//
			// 0: Hiding behind the first crate.
			// 1: Hiding behind the second crate.
			// 2: Standing in plain view on the deck.
			// 3: Hiding on the roof.
			//
			// The bug happens when trying to pick up the mop while
			// hiding on the roof. Nico climbs down, the mop is
			// picked up, but the variable remains set to 3.
			// Visually, everything looks ok. But as far as the
			// scripts are concerned, she's still hiding up on the
			// roof. This is not fatal, but leads to a number of
			// glitches until the state is corrected. E.g. trying
			// to climb back up the ladder will cause Nico to climb
			// down again.
			//
			// Global variable 1017 keeps track of the mop. Setting
			// it to 2 means that the mop has been picked up. We
			// use that as the signal that Nico's state needs to be
			// updated as well.

			if (checkMopBug && parameter == 1017 && readVar(1003) != 2) {
				warning("Working around mop bug: Setting Nico's state");
				writeVar(1003, 2);
			}

			writeVar(parameter, value);
			debug(9, "CP_POP_GLOBAL_VAR32: scriptsVars[%d] = %d", parameter, value);
			break;
		case CP_ADDNPOP_LOCAL_VAR32:
			Read16ip(parameter);
			value = READ_LE_UINT32(localVars + parameter) + pop();
			WRITE_LE_UINT32(localVars + parameter, value);
			debug(9, "CP_ADDNPOP_LOCAL_VAR32: localVars[%d] => %d", parameter / 4, value);
			break;
		case CP_SUBNPOP_LOCAL_VAR32:
			Read16ip(parameter);
			value = READ_LE_UINT32(localVars + parameter) - pop();
			WRITE_LE_UINT32(localVars + parameter, value);
			debug(9, "CP_SUBNPOP_LOCAL_VAR32: localVars[%d] => %d", parameter / 4, value);
			break;
		case CP_ADDNPOP_GLOBAL_VAR32:
			// Add and pop a global variable
			Read16ip(parameter);
			value = readVar(parameter) + pop();
			writeVar(parameter, value);
			debug(9, "CP_ADDNPOP_GLOBAL_VAR32: scriptVars[%d] => %d", parameter, value);
			break;
		case CP_SUBNPOP_GLOBAL_VAR32:
			// Sub and pop a global variable
			Read16ip(parameter);
			value = readVar(parameter) - pop();
			writeVar(parameter, value);
			debug(9, "CP_SUBNPOP_GLOBAL_VAR32: scriptVars[%d] => %d", parameter, value);
			break;

		// Jump opcodes

		case CP_SKIPONTRUE:
			// Skip if the value on the stack is true
			Read32ipLeaveip(parameter);
			value = pop();
			if (!value) {
				ip += 4;
				debug(9, "CP_SKIPONTRUE: %d (IS FALSE (NOT SKIPPED))", parameter);
			} else {
				ip += parameter;
				debug(9, "CP_SKIPONTRUE: %d (IS TRUE (SKIPPED))", parameter);
			}
			break;
		case CP_SKIPONFALSE:
			// Skip if the value on the stack is false
			Read32ipLeaveip(parameter);
			value = pop();
			if (value) {
				ip += 4;
				debug(9, "CP_SKIPONFALSE: %d (IS TRUE (NOT SKIPPED))", parameter);
			} else {
				ip += parameter;
				debug(9, "CP_SKIPONFALSE: %d (IS FALSE (SKIPPED))", parameter);
			}
			break;
		case CP_SKIPALWAYS:
			// skip a block
			Read32ipLeaveip(parameter);
			ip += parameter;
			debug(9, "CP_SKIPALWAYS: %d", parameter);
			break;
		case CP_SWITCH:
			// switch
			value = pop();
			Read32ip(caseCount);

			// Search the cases
			foundCase = false;
			for (i = 0; i < caseCount && !foundCase; i++) {
				if (value == (int32)READ_LE_UINT32(code + ip)) {
					// We have found the case, so lets
					// jump to it
					foundCase = true;
					ip += READ_LE_UINT32(code + ip + 4);
				} else
					ip += 4 * 2;
			}

			// If we found no matching case then use the default

			if (!foundCase)
				ip += READ_LE_UINT32(code + ip);

			debug(9, "CP_SWITCH: [SORRY, NO DEBUG INFO]");
			break;
		case CP_SAVE_MCODE_START:
			// Save the start position on an mcode instruction in
			// case we need to restart it again
			savedStartOfMcode = ip - 1;
			debug(9, "CP_SAVE_MCODE_START");
			break;
		case CP_CALL_MCODE:
			// Call an mcode routine
			Read16ip(parameter);
			assert(parameter < ARRAYSIZE(opcodes));
			// amount to adjust stack by (no of parameters)
			Read8ip(value);
			debug(9, "CP_CALL_MCODE: '%s', %d", opcodes[parameter].desc, value);
			stackPtr -= value;
			assert(stackPtr >= 0);
			retVal = (this->*opcodes[parameter].proc)(&stack[stackPtr]);

			switch (retVal & 7) {
			case IR_STOP:
				// Quit out for a cycle
				WRITE_LE_UINT32(offsetPtr, ip);
				return 0;
			case IR_CONT:
				// Continue as normal
				break;
			case IR_TERMINATE:
				// Return without updating the offset
				return 2;
			case IR_REPEAT:
				// Return setting offset to start of this
				// function call
				WRITE_LE_UINT32(offsetPtr, savedStartOfMcode);
				return 0;
			case IR_GOSUB:
				// that's really neat
				WRITE_LE_UINT32(offsetPtr, ip);
				return 2;
			default:
				error("Bad return code (%d) from '%s'", retVal & 7, opcodes[parameter].desc);
			}
			parameterReturnedFromMcodeFunction = retVal >> 3;
			break;
		case CP_JUMP_ON_RETURNED:
			// Jump to a part of the script depending on
			// the return value from an mcode routine

			// Get the maximum value
			Read8ip(parameter);
			debug(9, "CP_JUMP_ON_RETURNED: %d => %d",
				parameterReturnedFromMcodeFunction,
				READ_LE_UINT32(code + ip + parameterReturnedFromMcodeFunction * 4));
			ip += READ_LE_UINT32(code + ip + parameterReturnedFromMcodeFunction * 4);
			break;

		// Operators

		case OP_ISEQUAL:
			b = pop();
			a = pop();
			push(a == b);
			debug(9, "OP_ISEQUAL: RESULT = %d", a == b);
			break;
		case OP_NOTEQUAL:
			b = pop();
			a = pop();
			push(a != b);
			debug(9, "OP_NOTEQUAL: RESULT = %d", a != b);
			break;
		case OP_GTTHAN:
			b = pop();
			a = pop();
			push(a > b);
			debug(9, "OP_GTTHAN: RESULT = %d", a > b);
			break;
		case OP_LSTHAN:
			b = pop();
			a = pop();
			push(a < b);
			debug(9, "OP_LSTHAN: RESULT = %d", a < b);
			break;
		case OP_GTTHANE:
			b = pop();
			a = pop();
			push(a >= b);
			debug(9, "OP_GTTHANE: RESULT = %d", a >= b);
			break;
		case OP_LSTHANE:
			b = pop();
			a = pop();
			push(a <= b);
			debug(9, "OP_LSTHANE: RESULT = %d", a <= b);
			break;
		case OP_PLUS:
			b = pop();
			a = pop();
			push(a + b);
			debug(9, "OP_PLUS: RESULT = %d", a + b);
			break;
		case OP_MINUS:
			b = pop();
			a = pop();
			push(a - b);
			debug(9, "OP_MINUS: RESULT = %d", a - b);
			break;
		case OP_TIMES:
			b = pop();
			a = pop();
			push(a * b);
			debug(9, "OP_TIMES: RESULT = %d", a * b);
			break;
		case OP_DIVIDE:
			b = pop();
			a = pop();
			push(a / b);
			debug(9, "OP_DIVIDE: RESULT = %d", a / b);
			break;
		case OP_ANDAND:
			b = pop();
			a = pop();
			push(a && b);
			debug(9, "OP_ANDAND: RESULT = %d", a && b);
			break;
		case OP_OROR:
			b = pop();
			a = pop();
			push(a || b);
			debug(9, "OP_OROR: RESULT = %d", a || b);
			break;

		// Debugging opcodes, I think

		case CP_DEBUGON:
			debug(9, "CP_DEBUGON");
			break;
		case CP_DEBUGOFF:
			debug(9, "CP_DEBUGOFF");
			break;
		case CP_TEMP_TEXT_PROCESS:
			Read32ip(parameter);
			debug(9, "CP_TEMP_TEXT_PROCESS: %d", parameter);
			break;
		default:
			error("Invalid script command %d", curCommand);
			return 3;
		}
	}

	return 1;
}
Ejemplo n.º 28
0
uint32 File::readLong() {
	uint32 v;
	read(&v, sizeof(uint32));
	return FROM_LE_32(v);
}
Ejemplo n.º 29
0
/**
 * Skip the specified number of frames.
 * @param pAnim			Animation data structure
 * @param numFrames		Number of frames to skip
 */
void SkipFrames(ANIM *pAnim, int numFrames) {
	// get a pointer to the script
	const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript);

	if (!TinselV2 && (numFrames <= 0))
		// do nothing
		return;

	while (1) {	// repeat until a real image

		switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) {
		case ANI_END:	// end of animation script
			// going off the end is probably a error, but only in Tinsel 1
			if (!TinselV2)
				error("SkipFrames(): formally 'assert(0)!'");
			return;

		case ANI_JUMP:	// do animation jump

			// move to jump address
			pAnim->scriptIndex++;

			// jump to new frame position
			pAnim->scriptIndex += (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op);

			if (TinselV2)
				// Done if skip to jump
				return;
			break;

		case ANI_HFLIP:	// flip animated object horizontally

			// next opcode
			pAnim->scriptIndex++;

			MultiHorizontalFlip(pAnim->pObject);
			break;

		case ANI_VFLIP:	// flip animated object vertically

			// next opcode
			pAnim->scriptIndex++;

			MultiVerticalFlip(pAnim->pObject);
			break;

		case ANI_HVFLIP:	// flip animated object in both directions

			// next opcode
			pAnim->scriptIndex++;

			MultiHorizontalFlip(pAnim->pObject);
			MultiVerticalFlip(pAnim->pObject);
			break;

		case ANI_ADJUSTX:	// adjust animated object x animation point

			// move to x adjustment operand
			pAnim->scriptIndex++;

			MultiAdjustXY(pAnim->pObject, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op), 0);

			// next opcode
			pAnim->scriptIndex++;
			break;

		case ANI_ADJUSTY:	// adjust animated object y animation point

			// move to y adjustment operand
			pAnim->scriptIndex++;

			MultiAdjustXY(pAnim->pObject, 0, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op));

			// next opcode
			pAnim->scriptIndex++;
			break;

		case ANI_ADJUSTXY:	// adjust animated object x & y animation points
		{
			int x, y;

			// move to x adjustment operand
			pAnim->scriptIndex++;
			x = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op);

			// move to y adjustment operand
			pAnim->scriptIndex++;
			y = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op);

			MultiAdjustXY(pAnim->pObject, x, y);

			// next opcode
			pAnim->scriptIndex++;

			break;
		}

		case ANI_NOSLEEP:	// do not sleep for this frame

			// next opcode
			pAnim->scriptIndex++;
			break;

		case ANI_CALL:		// call routine

			// skip function address
			pAnim->scriptIndex += 2;
			break;

		case ANI_HIDE:		// hide animated object

			// next opcode
			pAnim->scriptIndex++;
			break;

		default:	// must be an actual animation frame handle

			// one less frame
			if (numFrames == 0)
				return;

			if (numFrames == -1 || numFrames-- > 0) {
				// next opcode
				pAnim->scriptIndex++;
			} else {
				// set objects new animation frame
				pAnim->pObject->hShape = FROM_LE_32(pAni[pAnim->scriptIndex].hFrame);

				// re-shape the object
				MultiReshape(pAnim->pObject);

				// we have skipped to the correct place
				return;
			}
			break;
		}
	}
}
Ejemplo n.º 30
0
/**
 * Tinsel 2 Moving actor process
 * - 1 per moving actor in current scene.
 */
void T2MoverProcess(CORO_PARAM, const void *param) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	// Get the co-ordinates - copied to process when it was created
	const MAINIT *rpos = (const MAINIT *)param;
	PMOVER pMover = rpos->pMover;
	int i;
	FILM *pFilm;
	PMULTI_INIT pmi;

	CORO_BEGIN_CODE(_ctx);

	for (i = 0; i < TOTAL_SCALES; i++) {
		if (pMover->walkReels[i][FORWARD])
			break;
	}
	assert(i < TOTAL_SCALES);

	InitMover(pMover);
	InitialPathChecks(pMover, rpos->X, rpos->Y);

	pFilm = (FILM *)LockMem(pMover->walkReels[i][FORWARD]);	// Any old reel
	pmi = (PMULTI_INIT)LockMem(FROM_LE_32(pFilm->reels[0].mobj));

	// Poke in the background palette
	PokeInPalette(pmi);

	pMover->actorObj = MultiInitObject(pmi);
	pMover->actorID = pMover->actorID;
	pMover->bActive = true;

	// add it to display list
	MultiInsertObject( GetPlayfieldList(FIELD_WORLD), pMover->actorObj );

	InitStepAnimScript(&pMover->actorAnim, pMover->actorObj, pFilm->reels[0].script, ONE_SECOND/pFilm->frate);
	pMover->stepCount = 0;

	MultiSetAniXY(pMover->actorObj, pMover->objX, pMover->objY);

	// If no path, just use first path in the scene
	if (pMover->hCpath != NOPOLY)
		SetMoverZ(pMover, pMover->objY, GetPolyZfactor(pMover->hCpath));
	else
		SetMoverZ(pMover, pMover->objY, GetPolyZfactor(FirstPathPoly()));

	// Make him the right size
	SetMoverStanding(pMover);

	HideMover(pMover);		// Allows a play to come in before this appears
	pMover->bHidden = false;	// ...but don't stay hidden

	for (;;) {
		if (pMover->bSpecReel) {
			if (!pMover->bHidden)
				StepAnimScript(&pMover->actorAnim);
		} else
			DoMoveActor(pMover);

		CheckBrightness(pMover);

		CORO_SLEEP(1);
	}

	CORO_END_CODE;
}