diff options
Diffstat (limited to 'engines')
143 files changed, 5475 insertions, 3118 deletions
diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h index 500f98546b..d95035a073 100644 --- a/engines/agi/preagi.h +++ b/engines/agi/preagi.h @@ -73,7 +73,7 @@ public:  	// Keyboard  	int getSelection(SelectionTypes type); -	int rnd(int hi) { return (_rnd->getRandomNumber(hi) + 1); } +	int rnd(int hi) { return (_rnd->getRandomNumber(hi - 1) + 1); }  	// Text  	void drawStr(int row, int col, int attr, const char *buffer); diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp index df7f32b432..f643ab9cfc 100644 --- a/engines/agi/preagi_mickey.cpp +++ b/engines/agi/preagi_mickey.cpp @@ -932,10 +932,17 @@ bool Mickey::loadGame() {  			if (_vm->getSelection(kSelAnyKey) == 0)  				return false;  		} else { -			if (infile->readUint32BE() != MKID_BE('MICK')) -				error("Mickey::loadGame wrong save game format"); +			if (infile->readUint32BE() != MKID_BE('MICK')) { +				warning("Mickey::loadGame wrong save game format"); +				return false; +			}  			saveVersion = infile->readByte(); +			if (saveVersion < 2) { +				warning("The planet data in this save game is corrupted. Load aborted"); +				return false; +			} +  			if (saveVersion != MSA_SAVEGAME_VERSION)  				warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, MSA_SAVEGAME_VERSION); @@ -953,7 +960,7 @@ bool Mickey::loadGame() {  				_game.iPlanetXtal[i] = infile->readByte();  			for(i = 0; i < IDI_MSA_MAX_PLANET; i++) -				_game.iClue[i] = infile->readByte(); +				_game.iClue[i] = infile->readUint16LE();  			infile->read(_game.szAddr, IDI_MSA_MAX_BUTTON + 1); @@ -1058,7 +1065,7 @@ void Mickey::saveGame() {  				outfile->writeByte(_game.iPlanetXtal[i]);  			for(i = 0; i < IDI_MSA_MAX_PLANET; i++) -				outfile->writeByte(_game.iClue[i]); +				outfile->writeUint16LE(_game.iClue[i]);  			outfile->write(_game.szAddr, IDI_MSA_MAX_BUTTON + 1); diff --git a/engines/agi/preagi_mickey.h b/engines/agi/preagi_mickey.h index 8d982dc401..f29d2fbccd 100644 --- a/engines/agi/preagi_mickey.h +++ b/engines/agi/preagi_mickey.h @@ -30,7 +30,7 @@  namespace Agi { -#define MSA_SAVEGAME_VERSION			1 +#define MSA_SAVEGAME_VERSION			2  // strings  #define IDS_MSA_PATH_DAT	"dat/%s" @@ -637,7 +637,7 @@ const int IDO_MSA_NEXT_PIECE[IDI_MSA_MAX_PLANET][5] = {  	{0x5B78,	0x5BB6,	0x5C29,	0x5C76,	0x5CE1},	// pluto  	{0x526B,	0x52DA,	0x5340,	0x53A1,	0x540C},	// jupiter  	{0x50F6,	0x512C,	0x5170,	0x51D5,	0x5228},	// mars -	{0x56AA,	0x571C,	0x579E,	0x5807,	0x5875}	// uranus +	{0x56AA,	0x571C,	0x579E,	0x5807,	0x5875}		// uranus  };  // message offsets @@ -697,7 +697,7 @@ struct MSA_GAME {  	uint8 nXtals;  	uint8 iPlanetXtal[IDI_MSA_MAX_DAT]; -	uint8 iClue[IDI_MSA_MAX_PLANET]; +	uint16 iClue[IDI_MSA_MAX_PLANET];  	char szAddr[IDI_MSA_MAX_BUTTON + 1];  	// Flags diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index c2c815596e..f5cde579e6 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -53,7 +53,6 @@ Common::Array<AnimData> animDataTable;  static const AnimDataEntry transparencyData[] = {  	{"ALPHA", 0xF}, -	{"TITRE", 0xF},  	{"TITRE2", 0xF},  	{"ET", 0xC},  	{"L311", 0x3}, @@ -586,6 +585,14 @@ int loadAni(const char *resourceName, int16 idx) {  	transparentColor = getAnimTransparentColor(resourceName); +	// TODO: Merge this special case hack into getAnimTransparentColor somehow.	 +	// HACK: Versions of TITRE.ANI with height 37 use color 0xF for transparency. +	//       Versions of TITRE.ANI with height 57 use color 0x0 for transparency. +	//       Fixes bug #2057619: FW: Glitches in title display of demo (regression). +	if (scumm_stricmp(resourceName, "TITRE.ANI") == 0 && animHeader.frameHeight == 37) { +		transparentColor = 0xF; +	} +  	entry = idx < 0 ? emptyAnimSpace() : idx;  	assert(entry >= 0); diff --git a/engines/cine/bg.cpp b/engines/cine/bg.cpp index 45bfae7925..cc7e843c2b 100644 --- a/engines/cine/bg.cpp +++ b/engines/cine/bg.cpp @@ -41,10 +41,18 @@ byte loadCtFW(const char *ctName) {  	uint16 header[32];  	byte *ptr, *dataPtr; +	int16 foundFileIdx = findFileInBundle(ctName); +	if (foundFileIdx == -1) { +		warning("loadCtFW: Unable to find collision data file '%s'", ctName); +		// FIXME: Rework this function's return value policy and return an appropriate value here. +		// The return value isn't yet used for anything so currently it doesn't really matter. +		return 0; +	} +  	if (currentCtName != ctName)  		strcpy(currentCtName, ctName); -	ptr = dataPtr = readBundleFile(findFileInBundle(ctName)); +	ptr = dataPtr = readBundleFile(foundFileIdx);  	loadRelatedPalette(ctName); diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index cb900e8850..e24b23f7f0 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -200,9 +200,15 @@ void FWRenderer::incrustSprite(const objectStruct &obj) {  	width = animDataTable[obj.frame]._realWidth;  	height = animDataTable[obj.frame]._height; -	assert(mask); - -	drawSpriteRaw(data, mask, width, height, _background, x, y); +	// There was an assert(mask) here before but it made savegame loading +	// in Future Wars sometimes fail the assertion (e.g. see bug #2055912). +	// Not drawing sprites that have no mask seems to work, but not sure +	// if this is really a correct way to fix this. +	if (mask) { +		drawSpriteRaw(data, mask, width, height, _background, x, y); +	} else { // mask == NULL +		warning("FWRenderer::incrustSprite: Skipping maskless sprite (frame=%d)", obj.frame); +	}  }  /*! \brief Draw command box on screen @@ -368,7 +374,7 @@ int FWRenderer::drawChar(char character, int x, int y) {  		x += 5;  	} else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) {  		idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx; -		drawSpriteRaw(g_cine->_textHandler.textTable[idx][0], g_cine->_textHandler.textTable[idx][1], 16, 8, _backBuffer, x, y); +		drawSpriteRaw(g_cine->_textHandler.textTable[idx][FONT_DATA], g_cine->_textHandler.textTable[idx][FONT_MASK], FONT_WIDTH, FONT_HEIGHT, _backBuffer, x, y);  		x += width + 1;  	} @@ -436,6 +442,9 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {  	switch (it->type) {  	// color sprite  	case 0: +		if (objectTable[it->objIdx].frame < 0) { +			return; +		}  		sprite = &animDataTable[objectTable[it->objIdx].frame];  		len = sprite->_realWidth * sprite->_height;  		mask = new byte[len]; @@ -1037,7 +1046,7 @@ int OSRenderer::drawChar(char character, int x, int y) {  		x += 5;  	} else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) {  		idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx; -		drawSpriteRaw2(g_cine->_textHandler.textTable[idx][0], 0, 16, 8, _backBuffer, x, y); +		drawSpriteRaw2(g_cine->_textHandler.textTable[idx][FONT_DATA], 0, FONT_WIDTH, FONT_HEIGHT, _backBuffer, x, y);  		x += width + 1;  	} @@ -1664,6 +1673,16 @@ void gfxResetRawPage(byte *pageRaw) {  }  void gfxConvertSpriteToRaw(byte *dst, const byte *src, uint16 w, uint16 h) { +	// Output is 4 bits per pixel. +	// Pixels are in 16 pixel chunks (8 bytes of source per 16 pixels of output). +	// The source data is interleaved so that +	// 1st big-endian 16-bit value contains all bit position 0 values for 16 pixels, +	// 2nd big-endian 16-bit value contains all bit position 1 values for 16 pixels, +	// 3rd big-endian 16-bit value contains all bit position 2 values for 16 pixels, +	// 4th big-endian 16-bit value contains all bit position 3 values for 16 pixels. +	// 1st pixel's bits are in the 16th bits, +	// 2nd pixel's bits are in the 15th bits, +	// 3rd pixel's bits are in the 14th bits etc.  	for (int y = 0; y < h; ++y) {  		for (int x = 0; x < w / 8; ++x) {  			for (int bit = 0; bit < 16; ++bit) { diff --git a/engines/cine/part.cpp b/engines/cine/part.cpp index 657471be4e..7679d9d380 100644 --- a/engines/cine/part.cpp +++ b/engines/cine/part.cpp @@ -123,13 +123,13 @@ void CineEngine::readVolCnf() {  		unpackedSize = packedSize = f.size();  	}  	uint8 *buf = new uint8[unpackedSize]; -	f.read(buf, packedSize); -	if (packedSize != unpackedSize) { -		CineUnpacker cineUnpacker; -		if (!cineUnpacker.unpack(buf, packedSize, buf, unpackedSize)) { -			error("Error while unpacking 'vol.cnf' data"); -		} +	uint8 *packedBuf = new uint8[packedSize]; +	f.read(packedBuf, packedSize); +	CineUnpacker cineUnpacker; +	if (!cineUnpacker.unpack(packedBuf, packedSize, buf, unpackedSize)) { +		error("Error while unpacking 'vol.cnf' data");  	} +	delete[] packedBuf;  	uint8 *p = buf;  	int resourceFilesCount = READ_BE_UINT16(p); p += 2;  	int entrySize = READ_BE_UINT16(p); p += 2; @@ -211,26 +211,23 @@ int16 findFileInBundle(const char *fileName) {  }  void readFromPart(int16 idx, byte *dataPtr, uint32 maxSize) { +	assert(maxSize >= partBuffer[idx].packedSize);  	setMouseCursor(MOUSE_CURSOR_DISK);  	g_cine->_partFileHandle.seek(partBuffer[idx].offset, SEEK_SET); -	g_cine->_partFileHandle.read(dataPtr, MIN(partBuffer[idx].packedSize, maxSize)); +	g_cine->_partFileHandle.read(dataPtr, partBuffer[idx].packedSize);  }  byte *readBundleFile(int16 foundFileIdx, uint32 *size) {  	assert(foundFileIdx >= 0 && foundFileIdx < (int32)partBuffer.size());  	bool error = false;  	byte *dataPtr = (byte *)calloc(partBuffer[foundFileIdx].unpackedSize, 1); -	readFromPart(foundFileIdx, dataPtr, partBuffer[foundFileIdx].unpackedSize); -	if (partBuffer[foundFileIdx].unpackedSize > partBuffer[foundFileIdx].packedSize) { -		CineUnpacker cineUnpacker; -		error = !cineUnpacker.unpack(dataPtr, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize); -	} else if (partBuffer[foundFileIdx].unpackedSize < partBuffer[foundFileIdx].packedSize) { -		// Unpacked size of a file should never be less than its packed size -		error = true; -	} else { // partBuffer[foundFileIdx].unpackedSize == partBuffer[foundFileIdx].packedSize -		debugC(5, kCineDebugPart, "Loaded non-compressed file '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName); -	} +	byte *packedData = (byte *)calloc(partBuffer[foundFileIdx].packedSize, 1); +	assert(dataPtr && packedData); +	readFromPart(foundFileIdx, packedData, partBuffer[foundFileIdx].packedSize); +	CineUnpacker cineUnpacker; +	error = !cineUnpacker.unpack(packedData, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize); +	free(packedData);  	if (error) {  		warning("Error unpacking '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName); diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 97f45488f2..6c13647ff3 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1501,7 +1501,18 @@ int FWScript::o1_compareGlobalVar() {  		debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and %d", _line, varIdx, value); -		_compare = compareVars(_globalVars[varIdx], value); +		// WORKAROUND for bug #2054882. Without this, the monks will always +		// kill you as an impostor, even if you enter the monastery in disguise. +		// +		// TODO: Check whether this might be worked around in some other way +		// like setting global variable 255 to 143 in Future Wars (This is +		// supposedly what Future Wars checks for from time to time during +		// gameplay to verify that copy protection was successfully passed). +		if (varIdx == 255 && (g_cine->getGameType() == Cine::GType_FW)) { +			_compare = kCmpEQ; +		} else { +			_compare = compareVars(_globalVars[varIdx], value); +		}  	}  	return 0; diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp index 3618350476..164c5a9ca5 100644 --- a/engines/cine/sound.cpp +++ b/engines/cine/sound.cpp @@ -79,13 +79,13 @@ const int PCSoundDriver::_noteTable[] = {  const int PCSoundDriver::_noteTableCount = ARRAYSIZE(_noteTable);  struct AdlibRegisterSoundInstrument { -	uint16 vibrato; -	uint16 attackDecay; -	uint16 sustainRelease; -	uint16 feedbackStrength; -	uint16 keyScaling; -	uint16 outputLevel; -	uint16 freqMod; +	uint8 vibrato; +	uint8 attackDecay; +	uint8 sustainRelease; +	uint8 feedbackStrength; +	uint8 keyScaling; +	uint8 outputLevel; +	uint8 freqMod;  };  struct AdlibSoundInstrument { diff --git a/engines/cine/texte.cpp b/engines/cine/texte.cpp index 33c16159ec..c8d48d3a06 100644 --- a/engines/cine/texte.cpp +++ b/engines/cine/texte.cpp @@ -39,6 +39,13 @@ const char **commandPrepositionTable;  void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency); +/*! \brief Loads font data from the given file. + * The number of characters used in the font varies between game versions: + * 78 (Most PC, Amiga and Atari ST versions of Future Wars, but also Operation Stealth's Amiga demo), + * 85 (All observed versions of German Future Wars (Amiga and PC), possibly Spanish Future Wars too), + * 90 (Most PC, Amiga and Atari ST versions of Operation Stealth), + * 93 (All observed versions of German Operation Stealth (Amiga and PC)). + */  void loadTextData(const char *filename) {  	Common::File fileHandle;  	assert(filename); @@ -46,30 +53,29 @@ void loadTextData(const char *filename) {  	if (!fileHandle.open(filename))  		error("loadTextData(): Cannot open file %s", filename); -	uint entrySize = fileHandle.readUint16BE(); -	uint numEntry = fileHandle.readUint16BE(); +	static const uint headerSize = 2 + 2;              // The entry size (16-bit) and entry count (16-bit). +	const uint entrySize = fileHandle.readUint16BE();  // Observed values: 8. +	const uint entryCount = fileHandle.readUint16BE(); // Observed values: 624, 680, 720, 744. +	const uint fontDataSize = entryCount * entrySize;  // Observed values: 4992, 5440, 5760, 5952. +	const uint numChars = entryCount / entrySize;      // Observed values: 78, 85, 90, 93. +	const uint bytesPerChar = fontDataSize / numChars; // Observed values: 64. +	static const uint bytesPerRow = FONT_WIDTH / 2;    // The input font data is 4-bit so it takes only half the space + +	if (headerSize + fontDataSize != fileHandle.size()) { +		warning("loadTextData: file '%s' (entrySize = %d, entryCount = %d) is of incorrect size %d", filename, entrySize, entryCount, fileHandle.size()); +	} -	uint sourceSize = numEntry * entrySize;  	Common::Array<byte> source; -	source.resize(sourceSize); -	fileHandle.read(source.begin(), sourceSize); +	source.resize(fontDataSize); +	fileHandle.read(source.begin(), fontDataSize); -	const int fontHeight = 8; -	const int fontWidth = (g_cine->getGameType() == Cine::GType_FW) ? 16 : 8; -	uint numCharacters; -	uint bytesPerCharacter;  	if (g_cine->getGameType() == Cine::GType_FW) { -		numCharacters = (g_cine->getFeatures() & GF_ALT_FONT) ? 85 : 78;		 -		bytesPerCharacter = sourceSize / numCharacters; // TODO: Check if this could be replaced with fontWidth * fontHeight  		loadRelatedPalette(filename); -	} else { -		numCharacters = 90; -		bytesPerCharacter = fontWidth * fontHeight;  	} -	for (uint i = 0; i < numCharacters; i++) { -		gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], &source[i * bytesPerCharacter], fontWidth, fontHeight); -		generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], fontWidth * fontHeight, 0); +	for (uint i = 0; i < numChars; i++) { +		gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][FONT_DATA], &source[i * bytesPerChar], bytesPerRow, FONT_HEIGHT); +		generateMask(g_cine->_textHandler.textTable[i][FONT_DATA], g_cine->_textHandler.textTable[i][FONT_MASK], FONT_WIDTH * FONT_HEIGHT, 0);  	}  	fileHandle.close(); diff --git a/engines/cine/texte.h b/engines/cine/texte.h index bc4beac492..0b1fc88e86 100644 --- a/engines/cine/texte.h +++ b/engines/cine/texte.h @@ -36,13 +36,20 @@ typedef char CommandeType[20];  // Number of characters in a font  #define NUM_FONT_CHARS 256 +#define FONT_WIDTH 16 +#define FONT_HEIGHT 8 + +// Used for choosing between font's data and font's mask +#define FONT_DATA 0 +#define FONT_MASK 1 +  struct CharacterEntry {  	byte characterIdx;  	byte characterWidth;  };  struct TextHandler { -	byte textTable[NUM_FONT_CHARS][2][16 * 8]; +	byte textTable[NUM_FONT_CHARS][2][FONT_WIDTH * FONT_HEIGHT];  	CharacterEntry fontParamTable[NUM_FONT_CHARS];  }; diff --git a/engines/cine/unpack.cpp b/engines/cine/unpack.cpp index 5d85ff6cab..7915fd1cf8 100644 --- a/engines/cine/unpack.cpp +++ b/engines/cine/unpack.cpp @@ -100,6 +100,14 @@ bool CineUnpacker::unpack(const byte *src, uint srcLen, byte *dst, uint dstLen)  	_dstBegin = dst;  	_dstEnd   = dst + dstLen; +	// Handle already unpacked data here +	if (srcLen == dstLen) { +		// Source length is same as destination length so the source +		// data is already unpacked. Let's just copy it then. +		memcpy(dst, src, srcLen); +		return true; +	} +  	// Initialize other variables  	_src = _srcBegin + srcLen - 4;  	uint32 unpackedLength = readSource(); // Unpacked length in bytes diff --git a/engines/cine/unpack.h b/engines/cine/unpack.h index e16cb594a9..2355df5ee1 100644 --- a/engines/cine/unpack.h +++ b/engines/cine/unpack.h @@ -35,14 +35,14 @@ namespace Cine {   * A LZ77 style decompressor for Delphine's data files   * used in at least Future Wars and Operation Stealth.   * @note Works backwards in the source and destination buffers. - * @note Can work with source and destination in the same buffer if there's space. + * @warning Having the source and destination in the same buffer when unpacking can cause errors!   */  class CineUnpacker {  public:  	/**  	 * Unpacks packed data from the source buffer to the destination buffer. -	 * @warning Do NOT call this on data that is not packed. -	 * @note Source and destination buffer pointers can be the same as long as there's space for the unpacked data. +	 * @note You may call this on already unpacked data but then source length must be equal to destination length. +	 * @warning The source and destination should not point to the same buffer. If they do, errors may occur!  	 * @param src Pointer to the source buffer.  	 * @param srcLen Length of the source buffer.  	 * @param dst Pointer to the destination buffer. diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 5e4c0eee30..2621278c59 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -1092,7 +1092,7 @@ bool CineEngine::makeLoad(char *saveName) {  		// that's not implemented here because it was never used in a stable  		// release of ScummVM but only during development (From revision 31453,  		// which introduced the problem, until revision 32073, which fixed it). -		// Therefore be bail out if we detect this particular savegame format. +		// Therefore we bail out if we detect this particular savegame format.  		warning("Detected a known broken savegame format, not loading savegame");  		load = false; // Don't load the savegame  	} else if (saveGameFormat == ANIMSIZE_UNKNOWN) { diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp index 06868494b5..954181d327 100644 --- a/engines/drascula/animation.cpp +++ b/engines/drascula/animation.cpp @@ -134,7 +134,7 @@ void DrasculaEngine::animation_1_1() {  		for (l2 = 0; l2 < 3; l2++)  			for (l = 0; l < 7; l++) { -				copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +				copyBackground();  				copyBackground(interf_x[l], interf_y[l], 156, 45, 63, 31, drawSurface2, screenSurface);  				updateScreen();  				if (getScan() == Common::KEYCODE_ESCAPE) { @@ -177,7 +177,7 @@ void DrasculaEngine::animation_1_1() {  			break;  		copyBackground(0, 0, 0, 0, 320, 200, screenSurface, bgSurface); -		talk_dr_grande(1); +		talk_drascula_big(1);  		if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))  			break; @@ -193,14 +193,14 @@ void DrasculaEngine::animation_1_1() {  		igorX = 66;  		igorY = 97; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		placeIgor();  		placeDrascula();  		updateScreen();  		talk_igor(8, kIgorDch);  		if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))  			break; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		placeIgor();  		placeDrascula();  		updateScreen(); @@ -297,13 +297,13 @@ void DrasculaEngine::animation_1_1() {  		if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))  			break;  		trackDrascula = 3; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		placeIgor();  		placeDrascula();  		updateScreen();  		pause(1);  		trackDrascula = 0; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		placeIgor();  		placeDrascula();  		updateScreen(); @@ -311,13 +311,13 @@ void DrasculaEngine::animation_1_1() {  		if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))  			break;  		trackDrascula = 3; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		placeIgor();  		placeDrascula();  		updateScreen();  		pause(1);  		trackDrascula = 1; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		placeIgor();  		placeDrascula();  		updateScreen(); @@ -329,13 +329,13 @@ void DrasculaEngine::animation_1_1() {  		if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))  			break;  		trackDrascula = 3; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		placeIgor();  		placeDrascula();  		updateScreen();  		pause(1);  		trackDrascula = 0; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		placeIgor();  		placeDrascula();  		updateScreen(); @@ -596,6 +596,7 @@ void DrasculaEngine::animation_2_1() {  	}  } +// John Hacker talks with the bartender to book a room  void DrasculaEngine::animation_3_1() {  	if (_lang == kSpanish)  		textSurface = frontSurface; @@ -631,6 +632,7 @@ void DrasculaEngine::animation_3_1() {  	loadPic(97, extraSurface);  } +// John Hacker talks with the pianist  void DrasculaEngine::animation_4_1() {  	if (_lang == kSpanish)  		textSurface = frontSurface; @@ -680,14 +682,14 @@ void DrasculaEngine::animation_1_2() {  void DrasculaEngine::animation_2_2() {  	trackProtagonist = 0; -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	moveCharacters();  	updateRefresh();  	updateScreen();  	loadPic("an2_1.alg", frontSurface);  	loadPic("an2_2.alg", extraSurface); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	copyBackground(1, 1, 201, 87, 50, 52, frontSurface, screenSurface);  	updateScreen(); @@ -701,7 +703,7 @@ void DrasculaEngine::animation_2_2() {  	updateAnim(55, 201, 87, 50, 52, 6, extraSurface);  	updateAnim(109, 201, 87, 50, 52, 2, extraSurface); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  	finishSound(); @@ -724,7 +726,7 @@ void DrasculaEngine::animation_4_2() {  	flags[9] = 1;  	pause(12); -	talk(56); +	talk(60);  	pause(8);  	clearRoom(); @@ -737,7 +739,7 @@ void DrasculaEngine::animation_4_2() {  	if (_lang == kSpanish)  		textSurface = frontSurface; -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  	pause(10); @@ -761,13 +763,13 @@ void DrasculaEngine::animation_4_2() {  	talk_blind(7);  	talk_hacker(63);  	talk_blind(8); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  	_system->delayMillis(1000);  	talk_hacker(64);  	talk_blind(9); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  	pause(14); @@ -822,7 +824,7 @@ void DrasculaEngine::animation_14_2() {  	loadPic("an14_2.alg", backSurface);  	for (int n = -160; n <= 0; n = n + 5 + l) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		moveCharacters();  		moveVonBraun(); @@ -876,7 +878,7 @@ void DrasculaEngine::animation_16_2() {  	if (_lang == kSpanish)  		black(); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	if (_lang != kSpanish)  		centerText(_texthis[_lang][1], 180, 180); @@ -906,7 +908,7 @@ void DrasculaEngine::animation_16_2() {  	clearRoom();  	loadPic("his2.alg", bgSurface, HALF_PAL); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	if (_lang != kSpanish)  		centerText(_texthis[_lang][2], 180, 180); @@ -932,7 +934,7 @@ void DrasculaEngine::animation_16_2() {  	clearRoom();  	loadPic("his3.alg", bgSurface, HALF_PAL); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	if (_lang != kSpanish)  		centerText(_texthis[_lang][3], 180, 180); @@ -1009,24 +1011,24 @@ void DrasculaEngine::animation_17_2() {  }  void DrasculaEngine::animation_19_2() { -	talk_vonBraunpuerta(5); +	talk_vonBraun(5, kVonBraunDoor);  }  void DrasculaEngine::animation_20_2() { -	talk_vonBraunpuerta(7); -	talk_vonBraunpuerta(8); +	talk_vonBraun(7, kVonBraunDoor); +	talk_vonBraun(8, kVonBraunDoor);  	talk(383); -	talk_vonBraunpuerta(9); +	talk_vonBraun(9, kVonBraunDoor);  	talk(384); -	talk_vonBraunpuerta(10); +	talk_vonBraun(10, kVonBraunDoor);  	talk(385); -	talk_vonBraunpuerta(11); +	talk_vonBraun(11, kVonBraunDoor);  	if (flags[23] == 0) {  		talk(350); -		talk_vonBraunpuerta(57); +	talk_vonBraun(57, kVonBraunDoor);  	} else {  		talk(386); -		talk_vonBraunpuerta(12); +		talk_vonBraun(12, kVonBraunDoor);  		flags[18] = 0;  		flags[14] = 1;  		openDoor(15, 1); @@ -1043,7 +1045,7 @@ void DrasculaEngine::animation_20_2() {  }  void DrasculaEngine::animation_21_2() { -	talk_vonBraunpuerta(6); +	talk_vonBraun(6, kVonBraunDoor);  }  void DrasculaEngine::animation_23_2() { @@ -1052,26 +1054,26 @@ void DrasculaEngine::animation_23_2() {  	flags[21] = 1;  	if (flags[25] == 0) { -		talk_vonBraun(13); -		talk_vonBraun(14); +		talk_vonBraun(13, kVonBraunDoor); +		talk_vonBraun(14, kVonBraunDoor);  		pause(10);  		talk(387);  	} -	talk_vonBraun(15); +	talk_vonBraun(15, kVonBraunNormal);  	placeVonBraun(42);  	trackVonBraun = 1; -	talk_vonBraun(16); +	talk_vonBraun(16, kVonBraunNormal);  	trackVonBraun = 2;  	gotoObject(157, 147);  	gotoObject(131, 149);  	trackProtagonist = 0;  	animation_14_2();  	if (flags[25] == 0) -		talk_vonBraun(17); +		talk_vonBraun(17, kVonBraunNormal);  	pause(8);  	trackVonBraun = 1; -	talk_vonBraun(18); +	talk_vonBraun(18, kVonBraunNormal);  	if (flags[29] == 0)  		animation_23_joined(); @@ -1083,9 +1085,9 @@ void DrasculaEngine::animation_23_2() {  	placeVonBraun(99);  	if (flags[29] == 0) { -		talk_vonBraun(19); +		talk_vonBraun(19, kVonBraunNormal);  		if (flags[25] == 0) { -			talk_vonBraun(20); +			talk_vonBraun(20, kVonBraunNormal);  			if (removeObject(kItemMoney) == 0)  				flags[30] = 1;  			if (removeObject(kItemTwoCoins) == 0) @@ -1093,7 +1095,7 @@ void DrasculaEngine::animation_23_2() {  			if (removeObject(kItemOneCoin) == 0)  				flags[32] = 1;  		} -		talk_vonBraun(21); +		talk_vonBraun(21, kVonBraunNormal);  	} else  		animation_27_2(); @@ -1152,7 +1154,7 @@ void DrasculaEngine::animation_25_2() {  	playSound(6);  	for (int n = 0; n >= -160; n = n - 8) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		moveCharacters(); @@ -1178,46 +1180,46 @@ void DrasculaEngine::animation_27_2() {  	removeObject(kItemEarWithEarPlug);  	addObject(kItemEarplugs); -	talk_vonBraun(23); -	talk_vonBraun(24); +	talk_vonBraun(23, kVonBraunNormal); +	talk_vonBraun(24, kVonBraunNormal);  	if (flags[30] == 1)  		addObject(kItemMoney);  	if (flags[31] == 1)  		addObject(kItemTwoCoins);  	if (flags[32] == 1)  		addObject(kItemOneCoin); -	talk_vonBraun(25); -	talk_vonBraun(26); +	talk_vonBraun(25, kVonBraunNormal); +	talk_vonBraun(26, kVonBraunNormal);  }  void DrasculaEngine::animation_28_2() {  	for(int i = 27; i <= 30; i++) -		talk_vonBraun(i); +		talk_vonBraun(i, kVonBraunNormal);  }  void DrasculaEngine::animation_29_2() {  	if (flags[33] == 0) { -		talk_vonBraun(32); +		talk_vonBraun(32, kVonBraunNormal);  		talk(398); -		talk_vonBraun(33); +		talk_vonBraun(33, kVonBraunNormal);  		talk(399); -		talk_vonBraun(34); -		talk_vonBraun(35); +		talk_vonBraun(34, kVonBraunNormal); +		talk_vonBraun(35, kVonBraunNormal);  		talk(400); -		talk_vonBraun(36); -		talk_vonBraun(37); +		talk_vonBraun(36, kVonBraunNormal); +		talk_vonBraun(37, kVonBraunNormal);  		talk(386); -		talk_vonBraun(38); -		talk_vonBraun(39); +		talk_vonBraun(38, kVonBraunNormal); +		talk_vonBraun(39, kVonBraunNormal);  		talk(401); -		talk_vonBraun(40); -		talk_vonBraun(41); +		talk_vonBraun(40, kVonBraunNormal); +		talk_vonBraun(41, kVonBraunNormal);  		flags[33] = 1;  	} else -		talk_vonBraun(43); +		talk_vonBraun(43, kVonBraunNormal);  	talk(402); -	talk_vonBraun(42); +	talk_vonBraun(42, kVonBraunNormal);  	if (flags[38] == 0) {  		talk(403); @@ -1227,12 +1229,12 @@ void DrasculaEngine::animation_29_2() {  }  void DrasculaEngine::animation_30_2() { -	talk_vonBraun(31); +	talk_vonBraun(31, kVonBraunNormal);  	talk(396);  }  void DrasculaEngine::animation_31_2() { -	talk_vonBraun(44); +	talk_vonBraun(44, kVonBraunNormal);  	placeVonBraun(-50);  	pause(15);  	gotoObject(159, 140); @@ -1247,23 +1249,23 @@ void DrasculaEngine::animation_31_2() {  	pause(22);  	talk(406);  	placeVonBraun(98); -	talk_vonBraun(45); -	talk_vonBraun(46); -	talk_vonBraun(47); +	talk_vonBraun(45, kVonBraunNormal); +	talk_vonBraun(46, kVonBraunNormal); +	talk_vonBraun(47, kVonBraunNormal);  	talk(407); -	talk_vonBraun(48); -	talk_vonBraun(49); +	talk_vonBraun(48, kVonBraunNormal); +	talk_vonBraun(49, kVonBraunNormal);  	talk(408); -	talk_vonBraun(50); -	talk_vonBraun(51); +	talk_vonBraun(50, kVonBraunNormal); +	talk_vonBraun(51, kVonBraunNormal);  	talk(409); -	talk_vonBraun(52); -	talk_vonBraun(53); +	talk_vonBraun(52, kVonBraunNormal); +	talk_vonBraun(53, kVonBraunNormal);  	pause(12); -	talk_vonBraun(54); -	talk_vonBraun(55); +	talk_vonBraun(54, kVonBraunNormal); +	talk_vonBraun(55, kVonBraunNormal);  	talk(410); -	talk_vonBraun(56); +	talk_vonBraun(56, kVonBraunNormal);  	breakOut = 1; @@ -1293,7 +1295,7 @@ void DrasculaEngine::animation_35_2() {  	updateAnim(1, 70, 90, 46, 80, 6, frontSurface);  	updateAnim(82, 70, 90, 46, 80, 2, frontSurface); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen(); @@ -1396,7 +1398,7 @@ void DrasculaEngine::animation_6_3() {  	for (frame = 0; frame < 6; frame++) {  		pause(3); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		copyRect(yoda_x[frame], yoda_y[frame], px, py,	78, 90,	frontSurface, screenSurface);  		updateScreen(px, py, px, py, 78, 90, screenSurface);  	} @@ -1564,7 +1566,7 @@ void DrasculaEngine::animation_5_5(){  	for (frame = 0; frame < 9; frame++) {  		pause(3); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		copyRect(boneX[frame], boneY[frame], pixelX, pixelY, 97, 64, backSurface, screenSurface);  		updateScreen(pixelX, pixelY, pixelX,pixelY, 97,64, screenSurface);  	} @@ -1574,7 +1576,7 @@ void DrasculaEngine::animation_5_5(){  	for (frame = 0; frame < 9; frame++) {  		pause(3); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		copyRect(boneX[frame], boneY[frame], pixelX, pixelY, 97, 64, frontSurface, screenSurface);  		updateScreen(pixelX, pixelY, pixelX,pixelY, 97, 64, screenSurface);  	} @@ -1935,7 +1937,7 @@ void DrasculaEngine::animation_5_6() {  	animate("man.bin", 14);  	for (int n = -125; n <= 0; n = n + 2) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		pos_pen[3] = n;  		copyRectClip(pos_pen, drawSurface3, screenSurface); @@ -2056,7 +2058,7 @@ void DrasculaEngine::animation_9_6() {  void DrasculaEngine::animation_10_6() {  	playSound(14); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateRefresh_pre();  	copyBackground(164, 85, 155, 48, 113, 114, drawSurface3, screenSurface);  	updateScreen(); @@ -2101,7 +2103,7 @@ void DrasculaEngine::animation_18_6() {  }  void DrasculaEngine::animation_19_6() { -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	copyBackground(140, 23, 161, 69, 35, 80, drawSurface3, screenSurface);  	updateRefresh_pre(); @@ -2258,7 +2260,7 @@ void DrasculaEngine::animation_13_2() {  void DrasculaEngine::animation_18_2() {  	talk(378); -	talk_vonBraunpuerta(4); +	talk_vonBraun(4, kVonBraunDoor);  	converse(3);  } @@ -2272,11 +2274,11 @@ void DrasculaEngine::animation_22_2() {  	finishSound();  	trackProtagonist = 1; -	talk_vonBraunpuerta(1); +	talk_vonBraun(1, kVonBraunDoor);  	talk(375); -	talk_vonBraunpuerta(2); +	talk_vonBraun(2, kVonBraunDoor);  	talk(376); -	talk_vonBraunpuerta(3); +	talk_vonBraun(3, kVonBraunDoor);  	flags[18] = 1;  } @@ -2297,7 +2299,7 @@ void DrasculaEngine::animation_24_2() {  	flags[21] = 1; -	talk_vonBraun(22); +	talk_vonBraun(22, kVonBraunNormal);  	if (flags[22] == 0)  		converse(4); @@ -2387,7 +2389,7 @@ void DrasculaEngine::animation_7_2() {  	if (flags[3] == 1)  		copyBackground(258, 110, 85, 44, 23, 53, drawSurface3, bgSurface); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen(); @@ -2485,7 +2487,7 @@ void DrasculaEngine::animation_6_2() {  	loadPic("ciego4.alg", backSurface);  	loadPic("ciego5.alg", frontSurface); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  	pause(1); @@ -2497,7 +2499,7 @@ void DrasculaEngine::animation_6_2() {  	pause(4);  	talk_hacker(67); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  	pause(10); @@ -2536,7 +2538,7 @@ void DrasculaEngine::animation_33_2() {  	if (_lang == kSpanish)  		textSurface = frontSurface; -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  	pause(10); @@ -2549,7 +2551,7 @@ void DrasculaEngine::animation_33_2() {  	talk_blind(10);  	talk_hacker(65); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  	pause(14); @@ -2663,7 +2665,7 @@ void DrasculaEngine::animation_6_4() {  	loadPic(26, bgSurface, HALF_PAL);  	loadPic("aux26.alg", drawSurface3);  	loadPic("auxigor.alg", frontSurface); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	update_26_pre();  	igorX = 104;  	igorY = 71; diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp index 9832d58294..81c8d9a62a 100644 --- a/engines/drascula/detection.cpp +++ b/engines/drascula/detection.cpp @@ -218,7 +218,7 @@ static const DrasculaGameDescription gameDescriptions[] = {  			0,  			{  				{"packet.001", 0, "c6a8697396e213a18472542d5f547cb4", 32847563}, -				{"packet.005", 0, "f80e10e37000a2201eabf8dad82c7f64", 16184223}, +				{"packet.005", 0, "58caac54b891f5d7f335e710e45e5d29", 16209623},  				{NULL, 0, NULL, 0}  			},  			Common::IT_ITA, diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index 2d24978f21..ac402c82ba 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -181,6 +181,8 @@ int DrasculaEngine::go() {  	currentChapter = 1; // values from 1 to 6 will start each part of game  	hay_que_load = 0; +	checkCD(); +  	for (;;) {  		int i; @@ -224,41 +226,35 @@ int DrasculaEngine::go() {  		if (currentChapter != 6)  			loadPic(95, tableSurface); -		if (currentChapter == 1) { +		if (currentChapter != 3)  			loadPic(96, frontSurface, COMPLETE_PAL); -			loadPic(99, backSurface); -			loadPic(97, extraSurface); + +		if (currentChapter == 1) {  		} else if (currentChapter == 2) { -			loadPic(96, frontSurface, COMPLETE_PAL);  			loadPic("pts.alg", drawSurface2);  		} else if (currentChapter == 3) {  			loadPic("aux13.alg", bgSurface, COMPLETE_PAL);  			loadPic(96, frontSurface); -			loadPic(97, extraSurface); -			loadPic(99, backSurface);  		} else if (currentChapter == 4) { -			loadPic(96, frontSurface, COMPLETE_PAL);  			if (hay_que_load == 0)  				animation_ray();  			loadPic(96, frontSurface);  			clearRoom(); -			loadPic(99, backSurface); -			loadPic(97, extraSurface);  		} else if (currentChapter == 5) { -			loadPic(96, frontSurface, COMPLETE_PAL); -			loadPic(97, extraSurface); -			loadPic(99, backSurface);  		} else if (currentChapter == 6) {  			igorX = 105, igorY = 85, trackIgor = 1;  			drasculaX = 62, drasculaY = 99, trackDrascula = 1;  			actorFrames[kFramePendulum] = 0;  			flag_tv = 0; -			loadPic(96, frontSurface, COMPLETE_PAL); +			loadPic(95, tableSurface); +		} + +		if (currentChapter != 2) {  			loadPic(99, backSurface);  			loadPic(97, extraSurface); -			loadPic(95, tableSurface);  		} +  		memset(iconName, 0, sizeof(iconName));  		for (i = 0; i < 6; i++) @@ -485,6 +481,7 @@ bool DrasculaEngine::runCurrentChapter() {  #else  		if (rightMouseButton == 1 && menuScreen == 1) {  #endif +			delay(100);  			if (currentChapter == 2)  				loadPic(menuBackground, backSurface);  			else @@ -502,8 +499,14 @@ bool DrasculaEngine::runCurrentChapter() {  			} else {  #else  		} -		if (rightMouseButton == 1 && menuScreen == 0) { + +		// Do not show the inventory screen in chapter 5, if the right mouse button is clicked +		// while the plug (object 16) is held +		// Fixes bug #2059621 - "DRASCULA: Plug bug" +		if (rightMouseButton == 1 && menuScreen == 0 &&  +			!(currentChapter == 5 && pickedObject == 16)) {  #endif +			delay(100);  			characterMoved = 0;  			if (trackProtagonist == 2)  				trackProtagonist = 1; @@ -523,8 +526,10 @@ bool DrasculaEngine::runCurrentChapter() {  		}  		if (leftMouseButton == 1 && menuBar == 1) { +			delay(100);  			selectVerbFromBar();  		} else if (leftMouseButton == 1 && takeObject == 0) { +			delay(100);  			if (verify1())  				return true;  		} else if (leftMouseButton == 1 && takeObject == 1) { @@ -796,7 +801,7 @@ void DrasculaEngine::hipo_sin_nadie(int counter){  	do {  		counter--; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		if (currentChapter == 3)  			updateScreen(0, 0, 0, y, 320, 200, screenSurface);  		else @@ -820,7 +825,7 @@ void DrasculaEngine::hipo_sin_nadie(int counter){  		}  	} while (counter > 0); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  } diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index 8bb73d8dd1..2eb7a19559 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -135,6 +135,11 @@ enum IgorTalkerTypes {  	kIgorWig = 4  }; +enum VonBraunTalkerTypes { +	kVonBraunNormal = 0, +	kVonBraunDoor = 1 +}; +  enum AnimFrameTypes {  	kFrameBlind = 0,  	kFrameSnore = 1, @@ -252,6 +257,11 @@ public:  	void setPalette(byte *PalBuf);  	void copyBackground(int xorg, int yorg, int xdes, int ydes, int width,  				int height, byte *src, byte *dest); + +	void copyBackground() { +		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	} +  	void copyRect(int xorg, int yorg, int xdes, int ydes, int width,  				int height, byte *src, byte *dest);  	void copyRectClip(int *Array, byte *src, byte *dest); @@ -417,7 +427,7 @@ public:  	void talk_bj_bed(int);  	void talk_htel(int);  	void talk_bj(int); -	void talk_baul(int); +	void talk_trunk(int);  	void talk(int);  	void talk(const char *, const char *);  	void talk_sync(const char *, const char *, const char *); @@ -425,9 +435,8 @@ public:  	void talk_pianist(int);  	void talk_werewolf(int);  	void talk_mus(int); -	void talk_dr_grande(int); -	void talk_vonBraun(int); -	void talk_vonBraunpuerta(int); +	void talk_drascula_big(int); +	void talk_vonBraun(int, int);  	void talk_blind(int);  	void talk_hacker(int);  	void talk_generic(const char* said, const char* filename, int* faces, int faceCount, int* coords, byte* surface); diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp index 67993bfb6c..cde9dcca4d 100644 --- a/engines/drascula/graphics.cpp +++ b/engines/drascula/graphics.cpp @@ -61,7 +61,7 @@ void DrasculaEngine::freeMemory() {  }  void DrasculaEngine::moveCursor() { -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateRefresh_pre();  	moveCharacters(); @@ -621,12 +621,11 @@ void DrasculaEngine::decodeRLE(byte* srcPtr, byte* dstPtr) {  			pixel = *srcPtr++;  		}  		for (uint j = 0; j < repeat; j++) { -			curByte++; -			if (curByte > 64000) { +			*dstPtr++ = pixel; +			if (++curByte >= 64000) {  				stopProcessing = true;  				break;  			} -			*dstPtr++ = pixel;  		}  	}  } diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp index 37dddf4b7e..0693b342da 100644 --- a/engines/drascula/rooms.cpp +++ b/engines/drascula/rooms.cpp @@ -252,7 +252,7 @@ bool DrasculaEngine::room_6(int fl) {  	else if (pickedObject == kVerbClose && fl == 138)  		closeDoor(0, 1);  	else if (pickedObject == kVerbOpen && fl == 143 && flags[2] == 0) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		copyRect(228, 102, curX + 5, curY - 1, 47, 73, drawSurface3, screenSurface);  		updateScreen(); @@ -263,7 +263,7 @@ bool DrasculaEngine::room_6(int fl) {  		updateScreen();  		finishSound();  	} else if (pickedObject == kVerbClose && fl == 143 && flags[2] == 1) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		flags[2] = 0;  		updateRefresh_pre();  		copyRect(228, 102, curX + 5, curY - 1, 47, 73, drawSurface3, screenSurface); @@ -274,7 +274,7 @@ bool DrasculaEngine::room_6(int fl) {  		updateScreen();  		finishSound();  	} else if (pickedObject == kVerbOpen && fl == 139 && flags[1] == 0) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		copyRect(267, 1, curX - 14, curY - 2, 52, 73, drawSurface3, screenSurface);  		updateScreen(); @@ -287,7 +287,7 @@ bool DrasculaEngine::room_6(int fl) {  		updateScreen();  		finishSound();  	} else if (pickedObject == kVerbPick && fl == 140) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		copyRect(267, 1, curX - 14, curY - 2, 52, 73, drawSurface3, screenSurface);  		updateScreen(); @@ -407,7 +407,7 @@ bool DrasculaEngine::room_15(int fl) {  		talk_sync(_text[_lang][46], "46.als", "4442444244244");  		trackProtagonist = 1;  	} else if (pickedObject == 18 && fl == 188 && flags[26] == 0) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		copyRect(133, 135, curX + 6, curY, 39, 63, drawSurface3, screenSurface);  		updateScreen();  		playSound(8); @@ -440,7 +440,7 @@ bool DrasculaEngine::room_16(int fl) {  		pause(10);  		talk_sync(_text[_lang][50], "50.als", "11111111111144432554433");  		pause(3); -		talk_baul(83); +		talk_trunk(83);  	} else if (pickedObject == kVerbOpen && fl == 183) {  		openDoor(19, NO_DOOR);  		if (flags[20] == 0) { @@ -497,7 +497,7 @@ bool DrasculaEngine::room_18(int fl) {  	else if (pickedObject == kVerbTalk && fl == 55 && flags[36] == 1)  		talk(109);  	else if (pickedObject == kVerbPick && fl == 182) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		copyRect(44, 1, curX, curY, 41, 70, drawSurface2, screenSurface);  		updateRefresh(); @@ -519,7 +519,7 @@ bool DrasculaEngine::room_18(int fl) {  		trackProtagonist = 3;  		updateRoom();  		updateScreen(); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		copyRect(1, 1, curX - 1, curY + 3, 42, 67, drawSurface2, screenSurface);  		updateRefresh(); @@ -815,10 +815,11 @@ bool DrasculaEngine::room_53(int fl) {  		flags[2] = 1;  		withoutVerb();  		updateVisible(); +		pickedObject = kVerbMove;  	} else if (pickedObject == 16) { -		talk(439); -		withoutVerb(); +		// Wall plug in chapter 5  		visible[3] = 1; +		hasAnswer = 0;  	} else  		hasAnswer = 0; @@ -1976,7 +1977,7 @@ bool DrasculaEngine::exitRoom(int l) {  }  void DrasculaEngine::updateRoom() { -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateRefresh_pre();  	if (currentChapter == 3) {  		if (flags[0] == 0) diff --git a/engines/drascula/saveload.cpp b/engines/drascula/saveload.cpp index 6f88a58fbb..d3e4d0dd31 100644 --- a/engines/drascula/saveload.cpp +++ b/engines/drascula/saveload.cpp @@ -63,7 +63,7 @@ bool DrasculaEngine::saveLoadScreen() {  	for (;;) {  		y = 27; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		for (n = 0; n < NUM_SAVES; n++) {  			print_abc(names[n], 116, y);  			y = y + 9; diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp index a89c5ff734..5ee7f13a25 100644 --- a/engines/drascula/talk.cpp +++ b/engines/drascula/talk.cpp @@ -70,11 +70,11 @@ void DrasculaEngine::talk_igor(int index, int talkerType) {  	do {  		if (talkerType == kIgorDch || talkerType == kIgorFront) {  			face = _rnd->getRandomNumber(7); -			copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +			copyBackground();  			updateRefresh_pre();  		} else if (talkerType == kIgorSeated || talkerType == kIgorWig) {  			face = _rnd->getRandomNumber(3); -			copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +			copyBackground();  			updateRefresh_pre();  		} @@ -127,7 +127,7 @@ void DrasculaEngine::talk_igor(int index, int talkerType) {  	}  	if (talkerType == kIgorDch || (talkerType == kIgorFront && currentChapter == 1)) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		placeIgor();  		placeDrascula();  	} @@ -152,7 +152,7 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) {  	do {  		face = _rnd->getRandomNumber(7); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre(); @@ -179,7 +179,7 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) {  	} while (!isTalkFinished(&length));  	if (talkerType == 0) -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  	if (talkerType == 1 && currentChapter == 6)  		updateRoom(); @@ -193,6 +193,41 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) {  	updateScreen();  } +void DrasculaEngine::talk_drascula_big(int index) { +	char filename[20]; +	sprintf(filename, "d%i.als", index); +	const char *said = _textd[_lang][index]; +	int x_talk[4] = {47, 93, 139, 185}; +	int face; +	int l = 0; +	int length = strlen(said); + +	color_abc(kColorRed); + +	talkInit(filename); + +	do { +		face = _rnd->getRandomNumber(3); +		copyBackground(); +		copyBackground(interf_x[l] + 24, interf_y[l], 0, 45, 39, 31, drawSurface2, screenSurface); +		copyBackground(x_talk[face], 1, 171, 68, 45, 48, drawSurface2, screenSurface); +		l++; +		if (l == 7) +			l = 0; + +		if (withVoices == 0) +			centerText(said, 191, 69); + +		updateScreen(); + +		pause(3); + +		byte key = getScan(); +		if (key == Common::KEYCODE_ESCAPE) +			term_int = 1; +	} while (!isTalkFinished(&length)); +} +  void DrasculaEngine::talk_solo(const char *said, const char *filename) {  	int length = strlen(said); @@ -204,7 +239,7 @@ void DrasculaEngine::talk_solo(const char *said, const char *filename) {  	talkInit(filename);  	if (currentChapter == 6) -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  	do {  		if (withVoices == 0) { @@ -219,7 +254,7 @@ void DrasculaEngine::talk_solo(const char *said, const char *filename) {  	} while (!isTalkFinished(&length));  	if (currentChapter == 6) { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateScreen();  	}  } @@ -260,7 +295,7 @@ void DrasculaEngine::talk_bartender(int index, int talkerType) {  			face = _rnd->getRandomNumber(5);  		} -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre(); @@ -299,7 +334,7 @@ void DrasculaEngine::talk_bj(int index) {  		if (currentChapter != 5) {  			face = _rnd->getRandomNumber(4); -			copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +			copyBackground();  			updateRefresh_pre(); @@ -375,7 +410,7 @@ void DrasculaEngine::talk(const char *said, const char *filename) {  	do {  		face = _rnd->getRandomNumber(5); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		if (currentChapter == 2) @@ -498,7 +533,10 @@ void DrasculaEngine::talk_drunk(int index) {  	}  } -void DrasculaEngine::talk_vonBraun(int index) { +// talker types: +// 0: kVonBraunNormal +// 1: KVonBraunDoor +void DrasculaEngine::talk_vonBraun(int index, int talkerType) {  	char filename[20];  	sprintf(filename, "VB%i.als", index);  	const char *said = _textvb[_lang][index]; @@ -513,49 +551,32 @@ void DrasculaEngine::talk_vonBraun(int index) {  	copyBackground(vonBraunX + 5, 64, OBJWIDTH + 1, 0, 25, 27, bgSurface, drawSurface3);  	do { -		if (trackVonBraun == 1) { -			face = _rnd->getRandomNumber(5); -			copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); - -			moveCharacters(); -			moveVonBraun(); - -			copyBackground(OBJWIDTH + 1, 0, vonBraunX + 5, 64, 25, 27, drawSurface3, screenSurface); -			copyRect(x_talk[face], 34, vonBraunX + 5, 64, 25, 27, frontSurface, screenSurface); -			updateRefresh(); -		} - -		if (withVoices == 0) -			centerText(said, vonBraunX, 66); - -		updateScreen(); - -		pause(3); -	} while (!isTalkFinished(&length)); - -	updateRoom(); -	updateScreen(); -	if (musicStatus() == 0 && flags[11] == 0 && roomMusic != 0) -		playMusic(roomMusic); -} +		if (talkerType == kVonBraunNormal) { +			if (trackVonBraun == 1) { +				face = _rnd->getRandomNumber(5); +				copyBackground(); -void DrasculaEngine::talk_vonBraunpuerta(int index) { -	char filename[20]; -	sprintf(filename, "VB%i.als", index); -	const char *said = _textvb[_lang][index]; -	int length = strlen(said); +				moveCharacters(); +				moveVonBraun(); -	color_abc(kColorBrown); +				copyBackground(OBJWIDTH + 1, 0, vonBraunX + 5, 64, 25, 27, drawSurface3, screenSurface); +				copyRect(x_talk[face], 34, vonBraunX + 5, 64, 25, 27, frontSurface, screenSurface); +				updateRefresh(); +			} -	talkInit(filename); +			if (withVoices == 0) +				centerText(said, vonBraunX, 66); -	do { -		updateRoom(); +			updateScreen(); +			pause(3); +		} else { +			updateRoom(); -		if (withVoices == 0) -			centerText(said, 150, 80); +			if (withVoices == 0) +				centerText(said, 150, 80); -		updateScreen(); +			updateScreen(); +		}  	} while (!isTalkFinished(&length));  	updateRoom(); @@ -580,13 +601,13 @@ void DrasculaEngine::talk_blind(int index) {  	color_abc(kColorBrown); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  	talkInit(filename);  	do { -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		pos_blind[5] = 149;  		char c = toupper(syncChar[p]); @@ -623,7 +644,7 @@ void DrasculaEngine::talk_hacker(int index) {  	const char *said = _textd[_lang][index];  	int length = strlen(said); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  	color_abc(kColorYellow); @@ -683,7 +704,7 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker  		else  			face = _rnd->getRandomNumber(4); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		if (talkerType == 0) @@ -706,7 +727,7 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker  	} while (!isTalkFinished(&length));  	flags[1] = 0; -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateRefresh_pre();  	updateScreen();  } @@ -726,7 +747,7 @@ void DrasculaEngine::talk_bj_bed(int index) {  	do {  		face = _rnd->getRandomNumber(4); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre(); @@ -771,7 +792,7 @@ void DrasculaEngine::talk_htel(int index) {  		else  			faceBuffer = (char *)backSurface; -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		copyBackground(x_talk[face], 1, 45, 24, 92, 108, (byte *)faceBuffer, screenSurface); @@ -782,7 +803,7 @@ void DrasculaEngine::talk_htel(int index) {  		pause(3);  	} while (!isTalkFinished(&length)); -	copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +	copyBackground();  	updateScreen();  } @@ -808,7 +829,7 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha  		strncpy(buf, &syncChar[p], 1);  		face = atoi(buf); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		if (currentChapter == 2) @@ -871,7 +892,7 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha  		playMusic(roomMusic);  } -void DrasculaEngine::talk_baul(int index) { +void DrasculaEngine::talk_trunk(int index) {  	char filename[20];  	sprintf(filename, "d%i.als", index);  	const char *said = _text[_lang][index]; @@ -903,41 +924,6 @@ void DrasculaEngine::talk_baul(int index) {  	updateScreen();  } -void DrasculaEngine::talk_dr_grande(int index) { -	char filename[20]; -	sprintf(filename, "D%i.als", index); -	const char *said = _textd[_lang][index]; -	int x_talk[4] = {47, 93, 139, 185}; -	int face; -	int l = 0; -	int length = strlen(said); - -	color_abc(kColorRed); - -	talkInit(filename); - -	do { -		face = _rnd->getRandomNumber(3); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); -		copyBackground(interf_x[l] + 24, interf_y[l], 0, 45, 39, 31, drawSurface2, screenSurface); -		copyBackground(x_talk[face], 1, 171, 68, 45, 48, drawSurface2, screenSurface); -		l++; -		if (l == 7) -			l = 0; - -		if (withVoices == 0) -			centerText(said, 191, 69); - -		updateScreen(); - -		pause(3); - -		byte key = getScan(); -		if (key == Common::KEYCODE_ESCAPE) -			term_int = 1; -	} while (!isTalkFinished(&length)); -} -  void DrasculaEngine::talk_generic(const char* said, const char* filename, int* faces, int faceCount, int* coords, byte* surface) {  	int face;  	int length = strlen(said); @@ -946,7 +932,7 @@ void DrasculaEngine::talk_generic(const char* said, const char* filename, int* f  	do {  		face = _rnd->getRandomNumber(faceCount - 1); -		copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); +		copyBackground();  		updateRefresh_pre();  		copyBackground(faces[face], coords[0], coords[1], coords[2],   						coords[3], coords[4], surface, screenSurface); diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 15e343c8cc..2de645ad76 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -57,6 +57,7 @@ static const PlainGameDescriptor gobGames[] = {  	{"inca2", "Inca II: Wiracocha"},  	{"woodruff", "The Bizarre Adventures of Woodruff and the Schnibble"},  	{"dynasty", "The Last Dynasty"}, +	{"urban", "Urban Runner"},  	{0, 0}  }; @@ -1771,7 +1772,7 @@ static const GOBGameDescription gameDescriptions[] = {  			kPlatformPC,  			Common::ADGF_NO_FLAGS  		}, -		kGameTypeWoodruff, +		kGameTypeDynasty,  		kFeatures640,  		"intro"  	}, @@ -1784,7 +1785,20 @@ static const GOBGameDescription gameDescriptions[] = {  			kPlatformPC,  			Common::ADGF_NO_FLAGS  		}, -		kGameTypeWoodruff, +		kGameTypeDynasty, +		kFeatures640, +		"intro" +	}, +	{ +		{ +			"urban", +			"", +			AD_ENTRY1s("intro.stk", "3ab2c542bd9216ae5d02cc6f45701ae1", 1252436), +			EN_USA, +			kPlatformPC, +			Common::ADGF_NO_FLAGS +		}, +		kGameTypeDynasty,  		kFeatures640,  		"intro"  	}, diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp index 8a7de9bdaa..7136646018 100644 --- a/engines/gob/draw.cpp +++ b/engines/gob/draw.cpp @@ -323,7 +323,38 @@ void Draw::adjustCoords(char adjust, int16 *coord1, int16 *coord2) {  	}  } -void Draw::drawString(char *str, int16 x, int16 y, int16 color1, int16 color2, +int Draw::stringLength(const char *str, int16 fontIndex) { +	static const int8 dword_8F74C[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +	if ((fontIndex < 0) || (fontIndex > 7) || !_fonts[fontIndex]) +		return 0; + +	int len = 0; + +	if (_vm->_global->_language == 10) { + +		for (int i = 0; str[i] != 0; i++) { +			if (((unsigned char) str[i+1]) < 128) { +				len += dword_8F74C[4]; +				i++; +			} else +				len += _fonts[fontIndex]->itemWidth; +		} + +	} else { + +		if (_fonts[fontIndex]->extraData) +			while (*str != 0) +				len += *(_fonts[fontIndex]->extraData + (*str++ - _fonts[fontIndex]->startItem)); +		else +			len = (strlen(str) * _fonts[fontIndex]->itemWidth); + +	} + +	return len; +} + +void Draw::drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2,  		int16 transp, SurfaceDesc *dest, Video::FontDesc *font) {  	while (*str != '\0') { @@ -337,7 +368,7 @@ void Draw::drawString(char *str, int16 x, int16 y, int16 color1, int16 color2,  }  void Draw::printTextCentered(int16 id, int16 left, int16 top, int16 right, -		int16 bottom, char *str, int16 fontIndex, int16 color) { +		int16 bottom, const char *str, int16 fontIndex, int16 color) {  	adjustCoords(1, &left, &top);  	adjustCoords(1, &right, &bottom); diff --git a/engines/gob/draw.h b/engines/gob/draw.h index 9ba589aa53..897208a42d 100644 --- a/engines/gob/draw.h +++ b/engines/gob/draw.h @@ -69,7 +69,7 @@ public:  	int16 _destSurface;  	char _letterToPrint; -	char *_textToPrint; +	const char *_textToPrint;  	int16 _backDeltaX;  	int16 _backDeltaY; @@ -146,10 +146,11 @@ public:  	void adjustCoords(char adjust, uint16 *coord1, uint16 *coord2) {  		adjustCoords(adjust, (int16 *) coord1, (int16 *) coord2);  	} -	void drawString(char *str, int16 x, int16 y, int16 color1, int16 color2, +	int stringLength(const char *str, int16 fontIndex); +	void drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2,  			int16 transp, SurfaceDesc *dest, Video::FontDesc *font);  	void printTextCentered(int16 id, int16 left, int16 top, int16 right, -			int16 bottom, char *str, int16 fontIndex, int16 color); +			int16 bottom, const char *str, int16 fontIndex, int16 color);  	int32 getSpriteRectSize(int16 index);  	void forceBlit(bool backwards = false); diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index d64ce3c9cc..8057402985 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -61,7 +61,9 @@ const Common::Language GobEngine::_gobToScummVMLang[] = {  	Common::EN_USA,  	Common::NL_NLD,  	Common::KO_KOR, -	Common::HB_ISR +	Common::HB_ISR, +	Common::PT_BRA, +	Common::JA_JPN  };  GobEngine::GobEngine(OSystem *syst) : Engine(syst) { @@ -114,7 +116,7 @@ int GobEngine::go() {  }  const char *GobEngine::getLangDesc(int16 language) const { -	if ((language < 0) || (language > 8)) +	if ((language < 0) || (language > 10))  		language = 2;  	return Common::getLanguageDescription(_gobToScummVMLang[language]);  } @@ -238,6 +240,12 @@ int GobEngine::init() {  	case Common::HB_ISR:  		_global->_language = 8;  		break; +	case Common::PT_BRA: +		_global->_language = 9; +		break; +	case Common::JA_JPN: +		_global->_language = 10; +		break;  	default:  		// Default to English  		_global->_language = 2; @@ -381,6 +389,20 @@ bool GobEngine::initGameParts() {  			_saveLoad = new SaveLoad_v4(this, _targetName.c_str());  			break; +		case kGameTypeDynasty: +			_init = new Init_v3(this); +			_video = new Video_v2(this); +			_inter = new Inter_v5(this); +			_parse = new Parse_v2(this); +			_mult = new Mult_v2(this); +			_draw = new Draw_v2(this); +			_game = new Game_v2(this); +			_map = new Map_v4(this); +			_goblin = new Goblin_v4(this); +			_scenery = new Scenery_v2(this); +			_saveLoad = new SaveLoad_v4(this, _targetName.c_str()); +			break; +  		default:  			deinitGameParts();  			return false; diff --git a/engines/gob/gob.h b/engines/gob/gob.h index 485389f990..a48a99ec42 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -93,7 +93,8 @@ enum GameType {  	kGameTypeBargon,  	kGameTypeWeen,  	kGameTypeLostInTime, -	kGameTypeInca2 +	kGameTypeInca2, +	kGameTypeDynasty  };  enum Features { diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp index 5add0b9cea..55758cdfdc 100644 --- a/engines/gob/goblin.cpp +++ b/engines/gob/goblin.cpp @@ -652,7 +652,7 @@ void Goblin::adjustDest(int16 posX, int16 posY) {  	if ((_vm->_map->getPass(_pressedMapX, _pressedMapY) == 0) &&  	    ((_gobAction == 0) || -			(_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0))) { +			(_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0))) {  		resDelta = -1;  		resDeltaDir = 0; @@ -727,17 +727,17 @@ void Goblin::adjustDest(int16 posX, int16 posY) {  void Goblin::adjustTarget(void) {  	if ((_gobAction == 4) && -	    (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0)) { +	    (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0)) {  		if ((_pressedMapY > 0) && -		    (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] != 0)) { +		    (_vm->_map->getItem(_pressedMapX, _pressedMapY - 1) != 0)) {  			_pressedMapY--;  		} else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && -				(_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] != 0)) { +				(_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) != 0)) {  			_pressedMapX++;  		} else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&  				(_pressedMapY > 0) && -				(_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX + 1] != 0)) { +				(_vm->_map->getItem(_pressedMapX + 1, _pressedMapY - 1) != 0)) {  			_pressedMapY--;  			_pressedMapX++;  		} @@ -747,7 +747,7 @@ void Goblin::adjustTarget(void) {  }  void Goblin::targetDummyItem(Gob_Object *gobDesc) { -	if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0 && +	if (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0 &&  	    _vm->_map->getPass(_pressedMapX, _pressedMapY) == 1) {  		if (gobDesc->curLookDir == 0) {  			_vm->_map->_itemPoses[0].x = _pressedMapX; @@ -771,7 +771,7 @@ void Goblin::targetItem(void) {  	Gob_Object *itemDesc;  	if ((_gobAction == 3) || (_gobAction == 4)) { -		items = _vm->_map->_itemsMap[_pressedMapY][_pressedMapX]; +		items = _vm->_map->getItem(_pressedMapX, _pressedMapY);  		if ((_gobAction == 4) && ((items & 0xFF00) != 0) &&  		    (_objects[_itemToObject[(items & 0xFF00) >> 8]]->pickable == 1)) {  			_destItemId = (items & 0xFF00) >> 8; @@ -802,40 +802,40 @@ void Goblin::targetItem(void) {  			_gobDestX = _vm->_map->_itemPoses[_destItemId].x;  		} else if ((items & 0xFF00) != 0) {  			if (_vm->_map->_itemPoses[_destItemId].orient == 4) { -				if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1] & 0xFF00) == -						(_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) { +				if ((_vm->_map->getItem(_pressedMapX - 1, _pressedMapY) & 0xFF00) == +						(_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) {  					_pressedMapX--;  					_vm->_map->_destX = _pressedMapX;  					_gobDestX = _pressedMapX;  				}  			} else if (_vm->_map->_itemPoses[_destItemId].orient == 0) { -				if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] & 0xFF00) == -						(_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) { +				if ((_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) & 0xFF00) == +						(_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) {  					_pressedMapX++;  					_vm->_map->_destX = _pressedMapX;  					_gobDestX = _pressedMapX;  				}  			} -			if ((_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX] & 0xFF00) == -			    (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) { +			if ((_vm->_map->getItem(_pressedMapX, _pressedMapY + 1) & 0xFF00) == +			    (_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) {  				_pressedMapY++;  				_vm->_map->_destY = _pressedMapY;  				_gobDestY = _pressedMapY;  			}  		} else {  			if (_vm->_map->_itemPoses[_destItemId].orient == 4) { -				if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1]) == -				    (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) { +				if ((_vm->_map->getItem(_pressedMapX - 1, _pressedMapY)) == +				    (_vm->_map->getItem(_pressedMapX, _pressedMapY))) {  					_pressedMapX--;  					_vm->_map->_destX = _pressedMapX;  					_gobDestX = _pressedMapX;  				}  			} else if (_vm->_map->_itemPoses[_destItemId].orient == 0) { -				if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1]) == -				    (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) { +				if ((_vm->_map->getItem(_pressedMapX + 1, _pressedMapY)) == +				    (_vm->_map->getItem(_pressedMapX, _pressedMapY))) {  					_pressedMapX++;  					_vm->_map->_destX = _pressedMapX;  					_gobDestX = _pressedMapX; @@ -843,8 +843,8 @@ void Goblin::targetItem(void) {  			}  			if (_pressedMapY < (_vm->_map->_mapHeight-1)) { -				if ((_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX]) == -						(_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) { +				if ((_vm->_map->getItem(_pressedMapX, _pressedMapY + 1)) == +						(_vm->_map->getItem(_pressedMapX, _pressedMapY))) {  					_pressedMapY++;  					_vm->_map->_destY = _pressedMapY;  					_gobDestY = _pressedMapY; @@ -931,37 +931,37 @@ void Goblin::moveFindItem(int16 posX, int16 posY) {  		_pressedMapX = CLIP(posX / 12, 0, _vm->_map->_mapWidth - 1);  		_pressedMapY = CLIP(posY / 6, 0, _vm->_map->_mapHeight - 1); -		if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0) && (i < 20)) { +		if ((_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0) && (i < 20)) {  			if ((_pressedMapY < (_vm->_map->_mapHeight - 1)) && -					(_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX] != 0)) { +					(_vm->_map->getItem(_pressedMapX, _pressedMapY + 1) != 0)) {  				_pressedMapY++;  			} else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&  					(_pressedMapY < (_vm->_map->_mapHeight - 1)) && -					(_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX + 1] != 0)) { +					(_vm->_map->getItem(_pressedMapX + 1, _pressedMapY + 1) != 0)) {  				_pressedMapX++;  				_pressedMapY++;  			} else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && -					(_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] != 0)) { +					(_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) != 0)) {  				_pressedMapX++;  			} else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&  					(_pressedMapY > 0) && -					(_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX + 1] != 0)) { +					(_vm->_map->getItem(_pressedMapX + 1, _pressedMapY - 1) != 0)) {  				_pressedMapX++;  				_pressedMapY--;  			} else if ((_pressedMapY > 0) && -					(_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] != 0)) { +					(_vm->_map->getItem(_pressedMapX, _pressedMapY - 1) != 0)) {  				_pressedMapY--;  			} else if ((_pressedMapY > 0) && (_pressedMapX > 0) && -					(_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX - 1] != 0)) { +					(_vm->_map->getItem(_pressedMapX - 1, _pressedMapY - 1) != 0)) {  				_pressedMapY--;  				_pressedMapX--;  			} else if ((_pressedMapX > 0) && -					(_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1] != 0)) { +					(_vm->_map->getItem(_pressedMapX - 1, _pressedMapY) != 0)) {  				_pressedMapX--;  			} else if ((_pressedMapX > 0) &&  					(_pressedMapY < (_vm->_map->_mapHeight - 1)) && -					(_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX - 1] != 0)) { +					(_vm->_map->getItem(_pressedMapX - 1, _pressedMapY + 1) != 0)) {  				_pressedMapX--;  				_pressedMapY++;  			} @@ -1384,11 +1384,11 @@ void Goblin::pickItem(int16 indexToPocket, int16 idToPocket) {  	for (int y = 0; y < _vm->_map->_mapHeight; y++) {  		for (int x = 0; x < _vm->_map->_mapWidth; x++) {  			if (_itemByteFlag == 1) { -				if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == idToPocket) -					_vm->_map->_itemsMap[y][x] &= 0xFF; +				if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == idToPocket) +					_vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF);  			} else { -				if ((_vm->_map->_itemsMap[y][x] & 0xFF) == idToPocket) -					_vm->_map->_itemsMap[y][x] &= 0xFF00; +				if ((_vm->_map->getItem(x, y) & 0xFF) == idToPocket) +					_vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF00);  			}  		}  	} @@ -1494,18 +1494,16 @@ void Goblin::swapItems(int16 indexToPick, int16 idToPick) {  	if (_itemByteFlag == 0) {  		for (y = 0; y < _vm->_map->_mapHeight; y++) {  			for (x = 0; x < _vm->_map->_mapWidth; x++) { -				if ((_vm->_map->_itemsMap[y][x] & 0xFF) == idToPick) -					_vm->_map->_itemsMap[y][x] = -					    (_vm->_map->_itemsMap[y][x] & 0xFF00) + idToPlace; +				if ((_vm->_map->getItem(x, y) & 0xFF) == idToPick) +					_vm->_map->setItem(x, y, (_vm->_map->getItem(x, y) & 0xFF00) + idToPlace);  			}  		}  	} else {  		for (y = 0; y < _vm->_map->_mapHeight; y++) {  			for (x = 0; x < _vm->_map->_mapWidth; x++) { -				if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == idToPick) -					_vm->_map->_itemsMap[y][x] = -					    (_vm->_map->_itemsMap[y][x] & 0xFF) + (idToPlace << 8); +				if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == idToPick) +					_vm->_map->setItem(x, y, (_vm->_map->getItem(x, y) & 0xFF) + (idToPlace << 8));  			}  		}  	} diff --git a/engines/gob/inter.h b/engines/gob/inter.h index b684be6c07..ad59d0d15a 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -529,6 +529,64 @@ protected:  	void o4_playVmdOrMusic();  }; +class Inter_v5 : public Inter_v4 { +public: +	Inter_v5(GobEngine *vm); +	virtual ~Inter_v5() {} + +protected: +	typedef void (Inter_v5::*OpcodeDrawProcV5)(); +	typedef bool (Inter_v5::*OpcodeFuncProcV5)(OpFuncParams &); +	typedef void (Inter_v5::*OpcodeGoblinProcV5)(OpGobParams &); +	struct OpcodeDrawEntryV5 { +		OpcodeDrawProcV5 proc; +		const char *desc; +	}; +	struct OpcodeFuncEntryV5 { +		OpcodeFuncProcV5 proc; +		const char *desc; +	}; +	struct OpcodeGoblinEntryV5 { +		OpcodeGoblinProcV5 proc; +		const char *desc; +	}; +	const OpcodeDrawEntryV5 *_opcodesDrawV5; +	const OpcodeFuncEntryV5 *_opcodesFuncV5; +	const OpcodeGoblinEntryV5 *_opcodesGoblinV5; +	static const int _goblinFuncLookUp[][2]; + +	virtual void setupOpcodes(); +	virtual void executeDrawOpcode(byte i); +	virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); +	virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); +	virtual const char *getOpcodeDrawDesc(byte i); +	virtual const char *getOpcodeFuncDesc(byte i, byte j); +	virtual const char *getOpcodeGoblinDesc(int i); + +	byte _byte_8AA14; + +	void o5_deleteFile(); + +	bool o5_istrlen(OpFuncParams ¶ms); + +	void o5_spaceShooter(OpGobParams ¶ms); +	void o5_getSystemCDSpeed(OpGobParams ¶ms); +	void o5_getSystemRAM(OpGobParams ¶ms); +	void o5_getSystemCPUSpeed(OpGobParams ¶ms); +	void o5_getSystemDrawSpeed(OpGobParams ¶ms); +	void o5_totalSystemSpecs(OpGobParams ¶ms); +	void o5_saveSystemSpecs(OpGobParams ¶ms); +	void o5_loadSystemSpecs(OpGobParams ¶ms); + +	void o5_gob92(OpGobParams ¶ms); +	void o5_gob95(OpGobParams ¶ms); +	void o5_gob96(OpGobParams ¶ms); +	void o5_gob97(OpGobParams ¶ms); +	void o5_gob98(OpGobParams ¶ms); +	void o5_gob100(OpGobParams ¶ms); +	void o5_gob200(OpGobParams ¶ms); +}; +  } // End of namespace Gob  #endif // GOB_INTER_H diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index cc114f0afc..1e01cd9048 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -2443,10 +2443,10 @@ void Inter_v1::o1_getItem(OpGobParams ¶ms) {  	int16 xPos = load16();  	int16 yPos = load16(); -	if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) -		params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8); +	if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) +		params.retVarPtr = (uint32) ((_vm->_map->getItem(xPos, yPos) & 0xFF00) >> 8);  	else -		params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos]; +		params.retVarPtr = (uint32) _vm->_map->getItem(xPos, yPos);  }  void Inter_v1::o1_manipulateMapIndirect(OpGobParams ¶ms) { @@ -2468,10 +2468,10 @@ void Inter_v1::o1_getItemIndirect(OpGobParams ¶ms) {  	xPos = VAR(xPos);  	yPos = VAR(yPos); -	if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) -		params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8); +	if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) +		params.retVarPtr = (uint32) ((_vm->_map->getItem(xPos, yPos) & 0xFF00) >> 8);  	else -		params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos]; +		params.retVarPtr = (uint32) _vm->_map->getItem(xPos, yPos);  }  void Inter_v1::o1_setPassMap(OpGobParams ¶ms) { @@ -3025,88 +3025,88 @@ void Inter_v1::animPalette() {  void Inter_v1::manipulateMap(int16 xPos, int16 yPos, int16 item) {  	for (int y = 0; y < _vm->_map->_mapHeight; y++) {  		for (int x = 0; x < _vm->_map->_mapWidth; x++) { -			if ((_vm->_map->_itemsMap[y][x] & 0xFF) == item) -				_vm->_map->_itemsMap[y][x] &= 0xFF00; -			else if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == item) -				_vm->_map->_itemsMap[y][x] &= 0xFF; +			if ((_vm->_map->getItem(x, y) & 0xFF) == item) +				_vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF00); +			else if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == item) +				_vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF);  		}  	}  	if (xPos < _vm->_map->_mapWidth - 1) {  		if (yPos > 0) { -			if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) || -					((_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) != 0) || -					((_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) != 0) || -					((_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF00) != 0)) { +			if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) || +					((_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) != 0) || +					((_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) != 0) || +					((_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF00) != 0)) { -				_vm->_map->_itemsMap[yPos][xPos] = -						(_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; +				_vm->_map->setItem(xPos, yPos, +						(_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); -				_vm->_map->_itemsMap[yPos - 1][xPos] = -						(_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) + item; +				_vm->_map->setItem(xPos, yPos - 1, +						(_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) + item); -				_vm->_map->_itemsMap[yPos][xPos + 1] = -						(_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) + item; +				_vm->_map->setItem(xPos + 1, yPos, +						(_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) + item); -				_vm->_map->_itemsMap[yPos - 1][xPos + 1] = -						(_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF00) + item; +				_vm->_map->setItem(xPos + 1, yPos - 1, +						(_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF00) + item);  			} else { -				_vm->_map->_itemsMap[yPos][xPos] = -						(_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); +				_vm->_map->setItem(xPos, yPos, +						(_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); -				_vm->_map->_itemsMap[yPos - 1][xPos] = -						(_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF) + (item << 8); +				_vm->_map->setItem(xPos, yPos - 1, +						(_vm->_map->getItem(xPos, yPos - 1) & 0xFF) + (item << 8)); -				_vm->_map->_itemsMap[yPos][xPos + 1] = -						(_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF) + (item << 8); +				_vm->_map->setItem(xPos + 1, yPos, +						(_vm->_map->getItem(xPos + 1, yPos) & 0xFF) + (item << 8)); -				_vm->_map->_itemsMap[yPos - 1][xPos + 1] = -						(_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF) + (item << 8); +				_vm->_map->setItem(xPos + 1, yPos - 1, +						(_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF) + (item << 8));  			}  		} else { -			if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) || -					((_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) != 0)) { +			if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) || +					((_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) != 0)) { -				_vm->_map->_itemsMap[yPos][xPos] = -						(_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; +				_vm->_map->setItem(xPos, yPos, +						(_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); -				_vm->_map->_itemsMap[yPos][xPos + 1] = -						(_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) + item; +				_vm->_map->setItem(xPos + 1, yPos, +						(_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) + item);  			} else { -				_vm->_map->_itemsMap[yPos][xPos] = -						(_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); +				_vm->_map->setItem(xPos, yPos, +						(_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); -				_vm->_map->_itemsMap[yPos][xPos + 1] = -						(_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF) + (item << 8); +				_vm->_map->setItem(xPos + 1, yPos, +						(_vm->_map->getItem(xPos + 1, yPos) & 0xFF) + (item << 8));  			}  		}  	} else {  		if (yPos > 0) { -			if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) || -					((_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) != 0)) { +			if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) || +					((_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) != 0)) { -				_vm->_map->_itemsMap[yPos][xPos] = -						(_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; +				_vm->_map->setItem(xPos, yPos, +						(_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); -				_vm->_map->_itemsMap[yPos - 1][xPos] = -						(_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) + item; +				_vm->_map->setItem(xPos, yPos - 1, +						(_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) + item);  			} else { -				_vm->_map->_itemsMap[yPos][xPos] = -						(_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); +				_vm->_map->setItem(xPos, yPos, +						(_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); -				_vm->_map->_itemsMap[yPos - 1][xPos] = -						(_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF) + (item << 8); +				_vm->_map->setItem(xPos, yPos - 1, +						(_vm->_map->getItem(xPos, yPos - 1) & 0xFF) + (item << 8));  			}  		} else { -			if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) { -				_vm->_map->_itemsMap[yPos][xPos] = -						(_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; +			if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) { +				_vm->_map->setItem(xPos, yPos, +						(_vm->_map->getItem(xPos, yPos) & 0xFF00) + item);  			} else { -				_vm->_map->_itemsMap[yPos][xPos] = -						(_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); +				_vm->_map->setItem(xPos, yPos, +						(_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8));  			}  		}  	} diff --git a/engines/gob/inter_v5.cpp b/engines/gob/inter_v5.cpp new file mode 100644 index 0000000000..6df76bda4a --- /dev/null +++ b/engines/gob/inter_v5.cpp @@ -0,0 +1,1040 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/file.h" + +#include "gob/gob.h" +#include "gob/inter.h" +#include "gob/global.h" +#include "gob/game.h" +#include "gob/parse.h" +#include "gob/draw.h" + +namespace Gob { + +#define OPCODE(x) _OPCODE(Inter_v5, x) + +const int Inter_v5::_goblinFuncLookUp[][2] = { +	{0, 0}, +	{1, 0}, +	{80, 1}, +	{81, 2}, +	{82, 3}, +	{83, 4}, +	{84, 5}, +	{85, 6}, +	{86, 7}, +	{87, 0}, +	{88, 0}, +	{89, 0}, +	{90, 0}, +	{91, 0}, +	{92, 8}, +	{93, 0}, +	{94, 0}, +	{95, 9}, +	{96, 10}, +	{97, 11}, +	{98, 12}, +	{99, 0}, +	{100, 13}, +	{200, 14}, +	{30, 24}, +	{32, 25}, +	{33, 26}, +	{34, 27}, +	{35, 28}, +	{36, 29}, +	{37, 30}, +	{40, 31}, +	{41, 32}, +	{42, 33}, +	{43, 34}, +	{44, 35}, +	{50, 36}, +	{52, 37}, +	{53, 38}, +	{100, 39}, +	{152, 40}, +	{200, 41}, +	{201, 42}, +	{202, 43}, +	{203, 44}, +	{204, 45}, +	{250, 46}, +	{251, 47}, +	{252, 48}, +	{500, 49}, +	{502, 50}, +	{503, 51}, +	{600, 52}, +	{601, 53}, +	{602, 54}, +	{603, 55}, +	{604, 56}, +	{605, 57}, +	{1000, 58}, +	{1001, 59}, +	{1002, 60}, +	{1003, 61}, +	{1004, 62}, +	{1005, 63}, +	{1006, 64}, +	{1008, 65}, +	{1009, 66}, +	{1010, 67}, +	{1011, 68}, +	{1015, 69}, +	{2005, 70} +}; + +Inter_v5::Inter_v5(GobEngine *vm) : Inter_v4(vm) { +	setupOpcodes(); +} + +void Inter_v5::setupOpcodes() { +	static const OpcodeDrawEntryV5 opcodesDraw[256] = { +		/* 00 */ +		OPCODE(o1_loadMult), +		OPCODE(o2_playMult), +		OPCODE(o2_freeMultKeys), +		{NULL, ""}, +		/* 04 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		OPCODE(o1_initCursor), +		/* 08 */ +		OPCODE(o1_initCursorAnim), +		OPCODE(o1_clearCursorAnim), +		OPCODE(o2_setRenderFlags), +		{NULL, ""}, +		/* 0C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 10 */ +		OPCODE(o1_loadAnim), +		OPCODE(o1_freeAnim), +		OPCODE(o1_updateAnim), +		OPCODE(o2_multSub), +		/* 14 */ +		OPCODE(o2_initMult), +		OPCODE(o1_freeMult), +		OPCODE(o1_animate), +		OPCODE(o2_loadMultObject), +		/* 18 */ +		OPCODE(o1_getAnimLayerInfo), +		OPCODE(o1_getObjAnimSize), +		OPCODE(o1_loadStatic), +		OPCODE(o1_freeStatic), +		/* 1C */ +		OPCODE(o2_renderStatic), +		OPCODE(o2_loadCurLayer), +		{NULL, ""}, +		{NULL, ""}, +		/* 20 */ +		OPCODE(o2_playCDTrack), +		OPCODE(o2_waitCDTrackEnd), +		OPCODE(o2_stopCD), +		OPCODE(o2_readLIC), +		/* 24 */ +		OPCODE(o2_freeLIC), +		OPCODE(o2_getCDTrackPos), +		{NULL, ""}, +		{NULL, ""}, +		/* 28 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 2C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 30 */ +		OPCODE(o2_loadFontToSprite), +		OPCODE(o1_freeFontToSprite), +		{NULL, ""}, +		{NULL, ""}, +		/* 34 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 38 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 3C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 40 */ +		OPCODE(o2_totSub), +		OPCODE(o2_switchTotSub), +		OPCODE(o2_copyVars), +		OPCODE(o2_pasteVars), +		/* 44 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 48 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 4C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 50 */ +		OPCODE(o2_loadMapObjects), +		OPCODE(o2_freeGoblins), +		OPCODE(o2_moveGoblin), +		OPCODE(o2_writeGoblinPos), +		/* 54 */ +		OPCODE(o2_stopGoblin), +		OPCODE(o2_setGoblinState), +		OPCODE(o2_placeGoblin), +		{NULL, ""}, +		/* 58 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 5C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 60 */ +		{NULL, ""}, +		OPCODE(o5_deleteFile), +		{NULL, ""}, +		{NULL, ""}, +		/* 64 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 68 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 6C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 70 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 74 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 78 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 7C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 80 */ +		OPCODE(o4_initScreen), +		OPCODE(o2_scroll), +		OPCODE(o2_setScrollOffset), +		OPCODE(o4_playVmdOrMusic), +		/* 84 */ +		OPCODE(o2_getImdInfo), +		OPCODE(o2_openItk), +		OPCODE(o2_closeItk), +		OPCODE(o2_setImdFrontSurf), +		/* 88 */ +		OPCODE(o2_resetImdFrontSurf), +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 8C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 90 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 94 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 98 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 9C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* A0 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* A4 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* A8 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* AC */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* B0 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* B4 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* B8 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* BC */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* C0 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* C4 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* C8 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* CC */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* D0 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* D4 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* D8 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* DC */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* E0 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* E4 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* E8 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* EC */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* F0 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* F4 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* F8 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* FC */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""} +	}; + +	static const OpcodeFuncEntryV5 opcodesFunc[80] = { +		/* 00 */ +		OPCODE(o1_callSub), +		OPCODE(o1_callSub), +		OPCODE(o1_printTotText), +		OPCODE(o1_loadCursor), +		/* 04 */ +		{NULL, ""}, +		OPCODE(o1_switch), +		OPCODE(o1_repeatUntil), +		OPCODE(o1_whileDo), +		/* 08 */ +		OPCODE(o1_if), +		OPCODE(o2_evaluateStore), +		OPCODE(o1_loadSpriteToPos), +		{NULL, ""}, +		/* 0C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 10 */ +		{NULL, ""}, +		OPCODE(o2_printText), +		OPCODE(o1_loadTot), +		OPCODE(o1_palLoad), +		/* 14 */ +		OPCODE(o1_keyFunc), +		OPCODE(o1_capturePush), +		OPCODE(o1_capturePop), +		OPCODE(o2_animPalInit), +		/* 18 */ +		OPCODE(o2_addCollision), +		OPCODE(o2_freeCollision), +		OPCODE(o3_getTotTextItemPart), +		{NULL, ""}, +		/* 1C */ +		{NULL, ""}, +		{NULL, ""}, +		OPCODE(o1_drawOperations), +		OPCODE(o1_setcmdCount), +		/* 20 */ +		OPCODE(o1_return), +		OPCODE(o1_renewTimeInVars), +		OPCODE(o1_speakerOn), +		OPCODE(o1_speakerOff), +		/* 24 */ +		OPCODE(o1_putPixel), +		OPCODE(o2_goblinFunc), +		OPCODE(o2_createSprite), +		OPCODE(o1_freeSprite), +		/* 28 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 2C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 30 */ +		OPCODE(o1_returnTo), +		OPCODE(o1_loadSpriteContent), +		OPCODE(o1_copySprite), +		OPCODE(o1_fillRect), +		/* 34 */ +		OPCODE(o1_drawLine), +		OPCODE(o1_strToLong), +		OPCODE(o1_invalidate), +		OPCODE(o1_setBackDelta), +		/* 38 */ +		OPCODE(o1_playSound), +		OPCODE(o2_stopSound), +		OPCODE(o2_loadSound), +		OPCODE(o1_freeSoundSlot), +		/* 3C */ +		OPCODE(o1_waitEndPlay), +		OPCODE(o1_playComposition), +		OPCODE(o2_getFreeMem), +		OPCODE(o2_checkData), +		/* 40 */ +		{NULL, ""}, +		OPCODE(o1_prepareStr), +		OPCODE(o1_insertStr), +		OPCODE(o1_cutStr), +		/* 44 */ +		OPCODE(o1_strstr), +		OPCODE(o5_istrlen), +		OPCODE(o1_setMousePos), +		OPCODE(o1_setFrameRate), +		/* 48 */ +		OPCODE(o1_animatePalette), +		OPCODE(o1_animateCursor), +		OPCODE(o1_blitCursor), +		OPCODE(o1_loadFont), +		/* 4C */ +		OPCODE(o1_freeFont), +		OPCODE(o2_readData), +		OPCODE(o2_writeData), +		OPCODE(o1_manageDataFile), +	}; + +	static const OpcodeGoblinEntryV5 opcodesGoblin[71] = { +		/* 00 */ +		OPCODE(o5_spaceShooter), +		OPCODE(o5_getSystemCDSpeed), +		OPCODE(o5_getSystemRAM), +		OPCODE(o5_getSystemCPUSpeed), +		/* 04 */ +		OPCODE(o5_getSystemDrawSpeed), +		OPCODE(o5_totalSystemSpecs), +		OPCODE(o5_saveSystemSpecs), +		OPCODE(o5_loadSystemSpecs), +		/* 08 */ +		OPCODE(o5_gob92), +		OPCODE(o5_gob95), +		OPCODE(o5_gob96), +		OPCODE(o5_gob97), +		/* 0C */ +		OPCODE(o5_gob98), +		OPCODE(o5_gob100), +		OPCODE(o5_gob200), +		{NULL, ""}, +		/* 10 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 14 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 18 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 1C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 20 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 24 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 28 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 2C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 30 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 34 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 38 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 3C */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 40 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +		/* 44 */ +		{NULL, ""}, +		{NULL, ""}, +		{NULL, ""}, +	}; + +	_opcodesDrawV5 = opcodesDraw; +	_opcodesFuncV5 = opcodesFunc; +	_opcodesGoblinV5 = opcodesGoblin; +} + +void Inter_v5::executeDrawOpcode(byte i) { +	debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", +			i, i, getOpcodeDrawDesc(i)); + +	OpcodeDrawProcV5 op = _opcodesDrawV5[i].proc; + +	if (op == NULL) +		warning("unimplemented opcodeDraw: %d", i); +	else +		(this->*op) (); +} + +bool Inter_v5::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { +	debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s) - %s, %d, %d", +			i, j, i, j, getOpcodeFuncDesc(i, j), _vm->_game->_curTotFile, +			(uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData), +			(uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData - params.counter - 4)); + +	if ((i > 4) || (j > 15)) { +		warning("unimplemented opcodeFunc: %d.%d", i, j); +		return false; +	} + +	OpcodeFuncProcV5 op = _opcodesFuncV5[i*16 + j].proc; + +	if (op == NULL) +		warning("unimplemented opcodeFunc: %d.%d", i, j); +	else +		return (this->*op) (params); + +	return false; +} + +void Inter_v5::executeGoblinOpcode(int i, OpGobParams ¶ms) { +	debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", +			i, i, getOpcodeGoblinDesc(i)); + +	OpcodeGoblinProcV5 op = NULL; + +	for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) +		if (_goblinFuncLookUp[j][0] == i) { +			op = _opcodesGoblinV5[_goblinFuncLookUp[j][1]].proc; +			break; +		} + +	_vm->_global->_inter_execPtr -= 2; + +	if (op == NULL) { +		warning("unimplemented opcodeGoblin: %d", i); + +		int16 paramCount = load16(); +		_vm->_global->_inter_execPtr += paramCount * 2; +	} else { +		params.extraData = i; + +		(this->*op) (params); +	} +} + +const char *Inter_v5::getOpcodeDrawDesc(byte i) { +	return _opcodesDrawV5[i].desc; +} + +const char *Inter_v5::getOpcodeFuncDesc(byte i, byte j) { +	if ((i > 4) || (j > 15)) +		return ""; + +	return _opcodesFuncV5[i*16 + j].desc; +} + +const char *Inter_v5::getOpcodeGoblinDesc(int i) { +	for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) +		if (_goblinFuncLookUp[j][0] == i) +			return _opcodesGoblinV5[_goblinFuncLookUp[j][1]].desc; +	return ""; +} + +void Inter_v5::o5_deleteFile() { +	evalExpr(0); + +	warning("Dynasty Stub: deleteFile \"%s\"", _vm->_global->_inter_resStr); +} + +bool Inter_v5::o5_istrlen(OpFuncParams ¶ms) { +	int16 strVar1, strVar2; +	int16 len; + +	if (*_vm->_global->_inter_execPtr == 0x80) { +		_vm->_global->_inter_execPtr++; + +		strVar1 = _vm->_parse->parseVarIndex(); +		strVar2 = _vm->_parse->parseVarIndex(); + +		len = _vm->_draw->stringLength(GET_VARO_STR(strVar1), READ_VARO_UINT16(strVar2)); + +	} else { + +		strVar1 = _vm->_parse->parseVarIndex(); +		strVar2 = _vm->_parse->parseVarIndex(); + +		if (_vm->_global->_language == 10) { +			// Extra handling for Japanese strings + +			for (len = 0; READ_VARO_UINT8(strVar1) != 0; strVar1++, len++) +				if (READ_VARO_UINT8(strVar1) >= 128) +					strVar1++; + +		} else +			len = strlen(GET_VARO_STR(strVar1)); +	} + +	WRITE_VAR_OFFSET(strVar2, len); +	return false; +} + +void Inter_v5::o5_spaceShooter(OpGobParams ¶ms) { +	int16 paramCount = load16(); + +	warning("Dynasty Stub: Space shooter: %d, %d, %s", +			params.extraData, paramCount, _vm->_game->_curTotFile); + +	if (paramCount < 4) { +		warning("Space shooter variable counter < 4"); +		_vm->_global->_inter_execPtr += paramCount * 2; +		return; +	} + +	uint32 var1 = load16() * 4; +	uint32 var2 = load16() * 4; +#if 1 +	load16(); +	load16(); +#else +	uint32 var3 = load16() * 4; +	uint16 var4 = load16(); +#endif + +	if (params.extraData != 0) { +		WRITE_VARO_UINT32(var1, 0); +		WRITE_VARO_UINT32(var2, 0); +	} else { +		if (paramCount < 5) { +			warning("Space shooter variable counter < 5"); +			return; +		} + +		_vm->_global->_inter_execPtr += (paramCount - 4) * 2; +	} +} + +void Inter_v5::o5_getSystemCDSpeed(OpGobParams ¶ms) { +	_vm->_global->_inter_execPtr += 2; + +	WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + +	Video::FontDesc *font; +	if ((font = _vm->_util->loadFont("SPEED.LET"))) { +		_vm->_draw->drawString("100 %", 402, 89, 112, 144, 0, _vm->_draw->_backSurface, font); +		_vm->_draw->forceBlit(); + +		_vm->_util->freeFont(font); +	} +} + +void Inter_v5::o5_getSystemRAM(OpGobParams ¶ms) { +	_vm->_global->_inter_execPtr += 2; + +	WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + +	Video::FontDesc *font; +	if ((font = _vm->_util->loadFont("SPEED.LET"))) { +		_vm->_draw->drawString("100 %", 402, 168, 112, 144, 0, _vm->_draw->_backSurface, font); +		_vm->_draw->forceBlit(); + +		_vm->_util->freeFont(font); +	} +} + +void Inter_v5::o5_getSystemCPUSpeed(OpGobParams ¶ms) { +	_vm->_global->_inter_execPtr += 2; + +	WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + +	Video::FontDesc *font; +	if ((font = _vm->_util->loadFont("SPEED.LET"))) { +		_vm->_draw->drawString("100 %", 402, 248, 112, 144, 0, _vm->_draw->_backSurface, font); +		_vm->_draw->forceBlit(); + +		_vm->_util->freeFont(font); +	} +} + +void Inter_v5::o5_getSystemDrawSpeed(OpGobParams ¶ms) { +	_vm->_global->_inter_execPtr += 2; + +	WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + +	Video::FontDesc *font; +	if ((font = _vm->_util->loadFont("SPEED.LET"))) { +		_vm->_draw->drawString("100 %", 402, 326, 112, 144, 0, _vm->_draw->_backSurface, font); +		_vm->_draw->forceBlit(); + +		_vm->_util->freeFont(font); +	} +} + +void Inter_v5::o5_totalSystemSpecs(OpGobParams ¶ms) { +	_vm->_global->_inter_execPtr += 2; + +	WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + +	Video::FontDesc *font; +	if ((font = _vm->_util->loadFont("SPEED.LET"))) { +		_vm->_draw->drawString("100 %", 402, 405, 112, 144, 0, _vm->_draw->_backSurface, font); +		_vm->_draw->forceBlit(); + +		_vm->_util->freeFont(font); +	} +} + +void Inter_v5::o5_saveSystemSpecs(OpGobParams ¶ms) { +	warning("Dynasty Stub: Saving system specifications"); + +	_vm->_global->_inter_execPtr += 2; + +/* +	FILE *f = fopen("SAVE\\SPEED.INF", w); +	fwrite(&_cdSpeed,   sizeof(_cdSpeed),   1, f); +	fwrite(&_ram,       sizeof(_ram),       1, f); +	fwrite(&_cpuSpeed,  sizeof(_cpuSpeed),  1, f); +	fwrite(&_drawSpeed, sizeof(_drawSpeed), 1, f); +	fwrite(&_total,     sizeof(_total),     1, f); +	fclose(f); +*/ +} + +void Inter_v5::o5_loadSystemSpecs(OpGobParams ¶ms) { +	warning("Dynasty Stub: Loading system specifications"); + +	_vm->_global->_inter_execPtr += 2; + +/* +	FILE *f = fopen("SAVE\\SPEED.INF", r); +	fread(&_cdSpeed,   sizeof(_cdSpeed),   1, f); +	fread(&_ram,       sizeof(_ram),       1, f); +	fread(&_cpuSpeed,  sizeof(_cpuSpeed),  1, f); +	fread(&_drawSpeed, sizeof(_drawSpeed), 1, f); +	fread(&_total,     sizeof(_total),     1, f); +	fclose(f); +*/ + +/* +	// Calculating whether speed throttling is necessary? + +	var_E = MAX(_cdSpeed, 150); +	var_E += (_ram << 3); +	var_E += (_cpuSpeed << 3); +	var_E /= 17; + +	byte_8A61E = (var_E > 81) ? 1 : 0; +	byte_8A5E0 = (_total >= 95) ? 1 : 0; + +	if (byte_8A5E0 == 1) { +		word_8AEE2 = 100; +		byte_8AEE4 = 1; +		byte_8AEE5 = 1; +		word_8AEE6 = 0; +	} else { +		word_8AEE2 = 0; +		byte_8AEE4 = 0; +		byte_8AEE5 = 0; +		word_8AEE6 = 40; +	} +*/ +} + +void Inter_v5::o5_gob92(OpGobParams ¶ms) { +	warning("Dynasty Stub: GobFunc 92"); + +	_vm->_global->_inter_execPtr += 2; + +	WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) byte_86B9E)) */); +} + +void Inter_v5::o5_gob95(OpGobParams ¶ms) { +	warning("Dynasty Stub: GobFunc 95"); + +	_vm->_global->_inter_execPtr += 2; + +	WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int16) word_8AEE6)) */); +	WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8)  byte_8AEE5)) */); +	WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8)  byte_8AEE4)) */); +	WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int16) word_8AEE2)) */); +} + +void Inter_v5::o5_gob96(OpGobParams ¶ms) { +	int16 word_8AEE6, word_85B50, word_8AEE2; +	byte byte_8AEE5, byte_8AEE4; + +	_vm->_global->_inter_execPtr += 2; + +	word_8AEE6 = word_85B50 = READ_VAR_UINT16(load16()); +	byte_8AEE5 = READ_VAR_UINT8(load16()); +	byte_8AEE4 = READ_VAR_UINT8(load16()); +	word_8AEE2 = READ_VAR_UINT16(load16()); + +	warning("Dynasty Stub: GobFunc 96: %d, %d, %d, %d", +			word_8AEE6, byte_8AEE5, byte_8AEE4, word_8AEE2); + +	// .--- sub_194B0 --- + +	int16 word_8A8F0, word_8A8F2, word_8A8F4, word_8A8F6, word_8A8F8, word_8A8FA; + +	int16 word_8A62C = 1; +	int16 word_8A63C, word_8A640, word_8B464, word_8B466; + +	byte byte_8A62E; + +	int16 var_2, var_4; + +	var_2 = word_85B50 + 31; +	word_8A8F0 = word_8A8F2 = var_2; +	word_8A8F4 = word_85B50; + +	var_4 = 315 - word_85B50; +	word_8A8F6 = word_8A8F8 = var_4; + +	word_8A8FA = 479 - word_85B50; + +	if (word_8A62C == 0) { +		word_8A63C = word_8A8F0; +		word_8A640 = word_8A8F6; +		word_8B464 = word_8A8F0; +		word_8B466 = word_8A8F6; +	} else if (word_8A62C == 1) { +		word_8A63C = word_85B50; +		word_8A640 = word_8A8FA; +		word_8B464 = word_85B50; +		word_8B466 = word_8A8FA; +	} else if (word_8A62C == 2) { +		word_8A63C = word_8A8F4; +		word_8A640 = word_8A8FA; +		word_8B464 = word_8A8F4; +		word_8B466 = word_8A8FA; +	} else if (word_8A62C == 3) { +		word_8A63C = word_8A8F4; +		word_8A640 = word_8A8FA; +		word_8B464 = word_8A8F4; +		word_8B466 = word_8A8FA; +	} else if (word_8A62C == 4) { +		word_8A63C = word_8A8F4; +		word_8A640 = word_8A8FA; +		word_8B464 = word_8A8F4; +		word_8B466 = word_8A8FA; +	} + +	byte_8A62E = 1; + +// '--- --- + +} + +void Inter_v5::o5_gob97(OpGobParams ¶ms) { +	_byte_8AA14 = 1; + +	_vm->_global->_inter_execPtr += 2; +} + +void Inter_v5::o5_gob98(OpGobParams ¶ms) { +	_byte_8AA14 = 0; + +	_vm->_global->_inter_execPtr += 2; +} + +void Inter_v5::o5_gob100(OpGobParams ¶ms) { +	_vm->_global->_inter_execPtr += 2; + +	uint16 var1 = READ_VAR_UINT16(load16()); +	uint16 var2 = READ_VAR_UINT16(load16()); +	uint16 var3 = READ_VAR_UINT16(load16()); +	uint16 var4 = READ_VAR_UINT16(load16()); + +	warning("Dynasty Stub: GobFunc 100: %d, %d, %d, %d", var1, var2, var3, var4); + +	var3 = (var3 + var1) - 1; +	var4 = (var4 + var2) - 1; +} + +void Inter_v5::o5_gob200(OpGobParams ¶ms) { +	_vm->_global->_inter_execPtr += 2; + +	uint16 var1 = load16(); // index into the spritesArray +	uint16 var2 = load16(); +	uint16 var3 = load16(); + +	warning("Dynasty Stub: GobFunc 200: %d, %d, %d", var1, var2, var3); +} + +} // End of namespace Gob diff --git a/engines/gob/map.cpp b/engines/gob/map.cpp index 75867aaa6c..bb259800c0 100644 --- a/engines/gob/map.cpp +++ b/engines/gob/map.cpp @@ -77,10 +77,10 @@ Map::~Map() {  }  void Map::placeItem(int16 x, int16 y, int16 id) { -	if ((_itemsMap[y][x] & 0xFF00) != 0) -		_itemsMap[y][x] = (_itemsMap[y][x] & 0xFF00) | id; +	if ((getItem(x, y) & 0xFF00) != 0) +		setItem(x, y, (getItem(x, y) & 0xFF00) | id);  	else -		_itemsMap[y][x] = (_itemsMap[y][x] & 0x00FF) | (id << 8); +		setItem(x, y, (getItem(x, y) & 0x00FF) | (id << 8));  }  enum { diff --git a/engines/gob/map.h b/engines/gob/map.h index 8a94de8da9..4a211f205d 100644 --- a/engines/gob/map.h +++ b/engines/gob/map.h @@ -101,6 +101,9 @@ public:  	void loadMapsInitGobs(void); +	virtual int16 getItem(int x, int y) = 0; +	virtual void setItem(int x, int y, int16 item) = 0; +  	virtual int8 getPass(int x, int y, int heightOff = -1) = 0;  	virtual void setPass(int x, int y, int8 pass, int heightOff = -1) = 0; @@ -127,6 +130,23 @@ public:  	virtual void findNearestToDest(Mult::Mult_Object *obj);  	virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y); +	virtual int16 getItem(int x, int y) { +		assert(_itemsMap); + +		x = CLIP<int>(x, 0, _mapWidth - 1); +		y = CLIP<int>(y, 0, _mapHeight - 1); + +		return _itemsMap[y][x]; +	} +	virtual void setItem(int x, int y, int16 item) { +		assert(_itemsMap); + +		x = CLIP<int>(x, 0, _mapWidth - 1); +		y = CLIP<int>(y, 0, _mapHeight - 1); + +		_itemsMap[y][x] = item; +	} +  	virtual int8 getPass(int x, int y, int heightOff = -1) {  		if (!_passMap)  			return 0; diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 45048a0899..c69f76b2c3 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -30,6 +30,7 @@ MODULE_OBJS := \  	inter_bargon.o \  	inter_v3.o \  	inter_v4.o \ +	inter_v5.o \  	map.o \  	map_v1.o \  	map_v2.o \ diff --git a/engines/gob/parse_v2.cpp b/engines/gob/parse_v2.cpp index a2e6b8fb37..f26d051ab5 100644 --- a/engines/gob/parse_v2.cpp +++ b/engines/gob/parse_v2.cpp @@ -116,6 +116,7 @@ int16 Parse_v2::parseValExpr(byte stopToken) {  	int16 brackPos;  	static int16 flag = 0;  	int16 oldflag; +	uint32 varPos = 0;  	memset(values, 0, 20 * sizeof(int16)); @@ -130,11 +131,61 @@ int16 Parse_v2::parseValExpr(byte stopToken) {  	valPtr = values - 1;  	while (1) { +		operation = *_vm->_global->_inter_execPtr++; + +		while ((operation == 14) || (operation == 15)) { +			if (operation == 14) { +				uint16 n = _vm->_inter->load16(); +				varPos += n * 4; + +				_vm->_global->_inter_execPtr += 2; +				if (*_vm->_global->_inter_execPtr == 97) +					_vm->_global->_inter_execPtr++; +			} else if (operation == 15) { +				uint16 n = _vm->_inter->load16(); +				varPos += n * 4; + +				uint16 var_0C = _vm->_inter->load16(); +				uint8 var_A = *_vm->_global->_inter_execPtr++; + +				byte *var_12 = _vm->_global->_inter_execPtr; +				_vm->_global->_inter_execPtr += var_A; + +				uint16 var_6 = 0; + +				for (int i = 0; i < var_A; i++) { +					temp2 = parseValExpr(12); + +					//uint16 ax = sub_12063(temp2, var_12[i], varPos, 0); + +					uint16 ax; + +					if (temp2 < 0) { +						ax = 0; +					} else if (var_12[i] > temp2) { +						ax = temp2; +					} else { +						ax = var_12[i] - 1; +					} + +					var_6 = var_6 * var_12[i] + ax; +				} + +				varPos += var_6 * var_0C * 4; + +				if (*_vm->_global->_inter_execPtr == 97) +					_vm->_global->_inter_execPtr++; +			} + +			warning("v5+ Stub: parseValExpr operation %d, offset %d", operation, varPos); + +			operation = *_vm->_global->_inter_execPtr++; +		} +  		stkPos++;  		operPtr++;  		valPtr++; -		operation = *_vm->_global->_inter_execPtr++;  		if ((operation >= 16) && (operation <= 29)) {  			*operPtr = 20;  			switch (operation) { @@ -373,6 +424,7 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) {  	bool var_1A;  	int16 stkPos;  	int16 brackStart; +	uint32 varPos = 0;  	memset(operStack, 0, 20); @@ -381,10 +433,61 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) {  	valPtr = values - 1;  	while (1) { +		operation = *_vm->_global->_inter_execPtr++; + +		while ((operation == 14) || (operation == 15)) { +			if (operation == 14) { +				uint16 n = _vm->_inter->load16(); +				varPos += n * 4; + +				_vm->_global->_inter_execPtr += 2; +				if (*_vm->_global->_inter_execPtr == 97) +					_vm->_global->_inter_execPtr++; +			} else if (operation == 15) { +				uint16 n = _vm->_inter->load16(); +				varPos += n * 4; + +				uint16 var_0C = _vm->_inter->load16(); +				uint8 var_A = *_vm->_global->_inter_execPtr++; + +				byte *var_12 = _vm->_global->_inter_execPtr; +				_vm->_global->_inter_execPtr += var_A; + +				uint16 var_6 = 0; + +				for (int i = 0; i < var_A; i++) { +					temp2 = parseValExpr(12); + +					//uint16 ax = sub_12063(temp2, var_12[i], varPos, 0); + +					uint16 ax; + +					if (temp2 < 0) { +						ax = 0; +					} else if (var_12[i] > temp2) { +						ax = temp2; +					} else { +						ax = var_12[i] - 1; +					} + +					var_6 = var_6 * var_12[i] + ax; +				} + +				varPos += var_6 * var_0C * 4; + +				if (*_vm->_global->_inter_execPtr == 97) +					_vm->_global->_inter_execPtr++; +			} + +			warning("v5+ Stub: parseExpr operation %d, offset %d", operation, varPos); + +			operation = *_vm->_global->_inter_execPtr++; +		} +  		stkPos++;  		operPtr++;  		valPtr++; -		operation = *_vm->_global->_inter_execPtr++; +  		if ((operation >= 16) && (operation <= 29)) {  			switch (operation) {  			case 16: diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index f5b3f582f4..c19db16d36 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -397,6 +397,18 @@ const KYRAGameDescription adGameDescs[] = {  		KYRA2_FLOPPY_FLAGS  	}, +	{ // Floppy version extracted +		{ +			"kyra2", +			"Extracted", +			AD_ENTRY1("FATE.PAK", "e0a70c31b022cb4bb3061890020fc27c"), +			Common::IT_ITA, +			Common::kPlatformPC, +			Common::ADGF_NO_FLAGS +		}, +		KYRA2_FLOPPY_FLAGS +	}, +  	{ // CD version  		{  			"kyra2", @@ -1052,9 +1064,9 @@ public:  		return "The Legend of Kyrandia (C) Westwood Studios";  	} -	virtual bool hasFeature(MetaEngineFeature f) const; -	virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; -	virtual SaveStateList listSaves(const char *target) const; +	bool hasFeature(MetaEngineFeature f) const; +	bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; +	SaveStateList listSaves(const char *target) const;  };  bool KyraMetaEngine::hasFeature(MetaEngineFeature f) const { @@ -1125,7 +1137,7 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const {  		if (slotNum >= 0 && slotNum <= 999) {  			Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());  			if (in) { -				if (Kyra::KyraEngine_v1::readSaveHeader(in, header) == Kyra::KyraEngine_v1::kRSHENoError) +				if (Kyra::KyraEngine_v1::readSaveHeader(in, false, header) == Kyra::KyraEngine_v1::kRSHENoError)  					saveList.push_back(SaveStateDescriptor(slotNum, header.description, *file));  				delete in;  			} @@ -1140,3 +1152,4 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const {  #else  	REGISTER_PLUGIN_STATIC(KYRA, PLUGIN_TYPE_ENGINE, KyraMetaEngine);  #endif + diff --git a/engines/kyra/gui.h b/engines/kyra/gui.h index 1361bdb399..7db8f52f16 100644 --- a/engines/kyra/gui.h +++ b/engines/kyra/gui.h @@ -32,6 +32,8 @@  #include "common/array.h"  #include "common/func.h" +#include "graphics/surface.h" +  namespace Kyra {  #define BUTTON_FUNCTOR(type, x, y) Button::Callback(new Common::Functor1Mem<Button*, int, type>(x, y)) @@ -153,6 +155,8 @@ public:  	void processHighlights(Menu &menu, int mouseX, int mouseY); +	// utilities for thumbnail creation +	virtual void createScreenThumbnail(Graphics::Surface &dst) = 0;  protected:  	KyraEngine_v1 *_vm;  	Screen *_screen; diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index cb3cef2fb3..0d7b4d973d 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -33,6 +33,8 @@  #include "common/savefile.h" +#include "graphics/scaler.h" +  namespace Kyra {  void KyraEngine_HoF::loadButtonShapes() { @@ -793,6 +795,10 @@ int GUI_HoF::optionsButton(Button *button) {  #pragma mark - +void GUI_HoF::createScreenThumbnail(Graphics::Surface &dst) { +	::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(1)); +} +  void GUI_HoF::setupPalette() {  	memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); @@ -996,7 +1002,7 @@ int GUI_HoF::gameOptionsTalkie(Button *caller) {  	if (_vm->_lang != lang) {  		_reloadTemporarySave = true; -		_vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 2 Savegame"); +		_vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 2 Savegame", 0);  		_vm->loadCCodeBuffer("C_CODE.XXX");  		if (_vm->_flags.isTalkie)  			_vm->loadOptionsBuffer("OPTIONS.XXX"); diff --git a/engines/kyra/gui_hof.h b/engines/kyra/gui_hof.h index f64336a8f6..a9c0426a2b 100644 --- a/engines/kyra/gui_hof.h +++ b/engines/kyra/gui_hof.h @@ -41,6 +41,8 @@ public:  	void initStaticData();  	int optionsButton(Button *button); + +	void createScreenThumbnail(Graphics::Surface &dst);  private:  	const char *getMenuTitle(const Menu &menu);  	const char *getMenuItemTitle(const MenuItem &menuItem); diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index 818d2f9b4e..4d13512751 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -36,6 +36,8 @@  #include "common/savefile.h"  #include "common/system.h" +#include "graphics/scaler.h" +  namespace Kyra {  void KyraEngine_LoK::initMainButtonList() { @@ -198,6 +200,15 @@ GUI_LoK::~GUI_LoK() {  	delete[] _menu;  } +void GUI_LoK::createScreenThumbnail(Graphics::Surface &dst) { +	uint8 *screen = new uint8[Screen::SCREEN_W*Screen::SCREEN_H]; +	if (screen) { +		_screen->queryPageFromDisk("SEENPAGE.TMP", 0, screen); +		::createThumbnail(&dst, screen, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(2)); +	} +	delete[] screen; +} +  int GUI_LoK::processButtonList(Button *list, uint16 inputFlag, int8 mouseWheel) {  	while (list) {  		if (list->flags & 8) { @@ -732,8 +743,12 @@ int GUI_LoK::saveGame(Button *button) {  	} else {  		if (_savegameOffset == 0 && _vm->_gameToLoad == 0)  			_vm->_gameToLoad = getNextSavegameSlot(); -		if (_vm->_gameToLoad > 0) -			_vm->saveGame(_vm->getSavegameFilename(_vm->_gameToLoad), _savegameName); +		if (_vm->_gameToLoad > 0) { +			Graphics::Surface thumb; +			createScreenThumbnail(thumb); +			_vm->saveGame(_vm->getSavegameFilename(_vm->_gameToLoad), _savegameName, &thumb); +			thumb.free(); +		}  	}  	return 0; diff --git a/engines/kyra/gui_lok.h b/engines/kyra/gui_lok.h index 16b7ef9183..0ce718d7a7 100644 --- a/engines/kyra/gui_lok.h +++ b/engines/kyra/gui_lok.h @@ -103,6 +103,8 @@ public:  	int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel);  	int buttonMenuCallback(Button *caller); + +	void createScreenThumbnail(Graphics::Surface &dst);  private:  	void initStaticResource(); diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp index 40fe78c439..11e6f6f1f4 100644 --- a/engines/kyra/gui_mr.cpp +++ b/engines/kyra/gui_mr.cpp @@ -33,6 +33,8 @@  #include "common/savefile.h" +#include "graphics/scaler.h" +  namespace Kyra {  void KyraEngine_MR::loadButtonShapes() { @@ -1138,6 +1140,10 @@ int KyraEngine_MR::albumClose(Button *caller) {  GUI_MR::GUI_MR(KyraEngine_MR *vm) : GUI_v2(vm), _vm(vm), _screen(vm->_screen) {  } +void GUI_MR::createScreenThumbnail(Graphics::Surface &dst) { +	::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(0)); +} +  void GUI_MR::flagButtonEnable(Button *button) {  	if (!button)  		return; @@ -1450,7 +1456,7 @@ int GUI_MR::gameOptions(Button *caller) {  	if (_vm->_lang != lang) {  		_reloadTemporarySave = true; -		_vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 3 Savegame"); +		_vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 3 Savegame", 0);  		if (!_vm->loadLanguageFile("ITEMS.", _vm->_itemFile))  			error("Couldn't load ITEMS");  		if (!_vm->loadLanguageFile("SCORE.", _vm->_scoreFile)) diff --git a/engines/kyra/gui_mr.h b/engines/kyra/gui_mr.h index 5bd3569031..a78d0559a6 100644 --- a/engines/kyra/gui_mr.h +++ b/engines/kyra/gui_mr.h @@ -47,6 +47,8 @@ public:  	int redrawButtonCallback(Button *button);  	int optionsButton(Button *button); + +	void createScreenThumbnail(Graphics::Surface &dst);  private:  	void getInput(); diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index a7ae2a6c44..077e49ebcf 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -35,6 +35,7 @@ namespace Kyra {  GUI_v2::GUI_v2(KyraEngine_v2 *vm) : GUI(vm), _vm(vm), _screen(vm->screen_v2()) {  	_backUpButtonList = _unknownButtonList = 0;  	_buttonListChanged = false; +	_lastScreenUpdate = 0;  	_currentMenu = 0;  	_isDeathMenu = false; @@ -618,7 +619,12 @@ int GUI_v2::saveMenu(Button *caller) {  	restorePage1(_vm->_screenBuffer);  	restorePalette(); -	_vm->saveGame(_vm->getSavegameFilename(_saveSlot), _saveDescription); + +	Graphics::Surface thumb; +	createScreenThumbnail(thumb); +	_vm->saveGame(_vm->getSavegameFilename(_saveSlot), _saveDescription, &thumb); +	thumb.free(); +  	_displayMenu = false;  	_madeSave = true; @@ -762,6 +768,7 @@ const char *GUI_v2::nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8  			x2 -= getCharWidth(buffer[curPos]);  			drawTextfieldBlock(x2, y2, c3);  			_screen->updateScreen(); +			_lastScreenUpdate = _vm->_system->getMillis();  		} else if (_keyPressed.ascii > 31 && _keyPressed.ascii < 127 && curPos < bufferSize) {  			if (x2 + getCharWidth(_keyPressed.ascii) + 7 < 0x11F) {  				buffer[curPos] = _keyPressed.ascii; @@ -771,6 +778,7 @@ const char *GUI_v2::nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8  				drawTextfieldBlock(x2, y2, c3);  				++curPos;  				_screen->updateScreen(); +				_lastScreenUpdate = _vm->_system->getMillis();  			}  		} @@ -818,6 +826,8 @@ int GUI_v2::getCharWidth(uint8 c) {  void GUI_v2::checkTextfieldInput() {  	Common::Event event; +	uint32 now = _vm->_system->getMillis(); +  	bool running = true;  	int keys = 0;  	while (_vm->_eventMan->pollEvent(event) && running) { @@ -844,6 +854,7 @@ void GUI_v2::checkTextfieldInput() {  			_vm->_mouseX = pos.x;  			_vm->_mouseY = pos.y;  			_screen->updateScreen(); +			_lastScreenUpdate = now;  			} break;  		default: @@ -851,7 +862,13 @@ void GUI_v2::checkTextfieldInput() {  		}  	} +	if (now - _lastScreenUpdate > 50) { +		_vm->_system->updateScreen(); +		_lastScreenUpdate = now; +	} +  	processButtonList(_menuButtonList, keys | 0x8000, 0); +	_vm->_system->delayMillis(3);  }  void GUI_v2::drawTextfieldBlock(int x, int y, uint8 c) { diff --git a/engines/kyra/gui_v2.h b/engines/kyra/gui_v2.h index 60b7f0ab86..88861ff905 100644 --- a/engines/kyra/gui_v2.h +++ b/engines/kyra/gui_v2.h @@ -213,6 +213,7 @@ protected:  	// savename menu  	bool _finishNameInput, _cancelNameInput;  	Common::KeyState _keyPressed; +	uint32 _lastScreenUpdate;  	const char *nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8 c2, uint8 c3, int bufferSize);  	int finishSavename(Button *caller); diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 0722fb262b..086d8d6913 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -306,8 +306,10 @@ int KyraEngine_HoF::go() {  			_res->loadFileList(_ingamePakList, _ingamePakListSize);  		} -		if (_flags.platform == Common::kPlatformPC98) +		if (_flags.platform == Common::kPlatformPC98) {  			_res->loadPakFile("AUDIO.PAK"); +			_sound->loadSoundFile("sound.dat"); +		}  	}  	_menuDirectlyToLoad = (_menuChoice == 3) ? true : false; @@ -434,7 +436,7 @@ void KyraEngine_HoF::startup() {  	if (_gameToLoad == -1) {  		snd_playWanderScoreViaMap(52, 1);  		enterNewScene(_mainCharacter.sceneId, _mainCharacter.facing, 0, 0, 1); -		saveGame(getSavegameFilename(0), "New Game"); +		saveGame(getSavegameFilename(0), "New Game", 0);  	} else {  		loadGame(getSavegameFilename(_gameToLoad));  	} @@ -1577,10 +1579,14 @@ void KyraEngine_HoF::snd_playSoundEffect(int track, int volume) {  	int16 vocIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2]);  	if (vocIndex != -1)  		_sound->voicePlay(_ingameSoundList[vocIndex], true); -	else if (_flags.platform != Common::kPlatformFMTowns) +	else if (_flags.platform == Common::kPlatformPC) +		KyraEngine_v1::snd_playSoundEffect(track); +  		// TODO ?? Maybe there is a way to let users select whether they want  		// voc, midi or adl sfx (even though it makes no sense to choose anything but voc). -		KyraEngine_v1::snd_playSoundEffect(track); +		// The PC-98 version has support for non-pcm sound effects, but only for tracks  +		// which also have voc files. The syntax would be: +		// KyraEngine_v1::snd_playSoundEffect(vocIndex);  }  #pragma mark - diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h index f6e887c648..dc4161f0c1 100644 --- a/engines/kyra/kyra_hof.h +++ b/engines/kyra/kyra_hof.h @@ -907,7 +907,7 @@ protected:  	int _dbgPass;  	// save/load specific -	void saveGame(const char *fileName, const char *saveName); +	void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail);  	void loadGame(const char *fileName);  }; diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp index 2ce8af4a81..b6c874339c 100644 --- a/engines/kyra/kyra_lok.cpp +++ b/engines/kyra/kyra_lok.cpp @@ -391,7 +391,7 @@ void KyraEngine_LoK::startup() {  			_gui->buttonMenuCallback(0);  			_menuDirectlyToLoad = false;  		} else -			saveGame(getSavegameFilename(0), "New game"); +			saveGame(getSavegameFilename(0), "New game", 0);  	} else {  		_screen->setFont(Screen::FID_8_FNT);  		loadGame(getSavegameFilename(_gameToLoad)); @@ -473,7 +473,7 @@ void KyraEngine_LoK::delay(uint32 amount, bool update, bool isMainLoop) {  					else {  						char savegameName[14];  						sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0'); -						saveGame(saveLoadSlot, savegameName); +						saveGame(saveLoadSlot, savegameName, 0);  					}  				} else if (event.kbd.flags == Common::KBD_CTRL) {  					if (event.kbd.keycode == 'd') diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h index 1def95ddbf..e6fc0dc774 100644 --- a/engines/kyra/kyra_lok.h +++ b/engines/kyra/kyra_lok.h @@ -214,7 +214,7 @@ public:  protected:  	int32 _speechPlayTime; -	void saveGame(const char *fileName, const char *saveName); +	void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail);  	void loadGame(const char *fileName);  protected: diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index 45a277c400..5bc843d8a8 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -684,7 +684,7 @@ void KyraEngine_MR::startup() {  	assert(_invWsa);  	_invWsa->open("MOODOMTR.WSA", 1, 0);  	_invWsaFrame = 6; -	saveGame(getSavegameFilename(0), (const char*)getTableEntry(_optionsFile, 33)); +	saveGame(getSavegameFilename(0), (const char*)getTableEntry(_optionsFile, 33), 0);  	_soundDigital->beginFadeOut(_musicSoundChannel, 60);  	delayWithTicks(60);  	if (_gameToLoad == -1) diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index 5f9f6f91a3..a6fb9af20c 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -583,7 +583,7 @@ private:  	int albumClose(Button *caller);  	// save/load -	void saveGame(const char *fileName, const char *saveName); +	void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail);  	void loadGame(const char *fileName);  	// opcodes diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index f4f845c5f7..761724fa2f 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -285,6 +285,8 @@ protected:  		bool originalSave;	// savegame from original interpreter  		bool oldHeader;		// old scummvm save header + +		Graphics::Surface *thumbnail;  	};  	enum kReadSaveHeaderError { @@ -294,10 +296,10 @@ protected:  		kRSHEIoError = 3  	}; -	static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, SaveHeader &header); +	static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, bool loadThumbnail, SaveHeader &header);  	Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header); -	Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName) const; +	Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const;  };  } // End of namespace Kyra diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index 08a4e9f4c5..e9ed91b539 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -186,7 +186,7 @@ int KyraEngine_v2::checkInput(Button *buttonList, bool mainLoop) {  				} else {  					char savegameName[14];  					sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0'); -					saveGame(saveLoadSlot, savegameName); +					saveGame(saveLoadSlot, savegameName, 0);  				}  			} else if (event.kbd.flags == Common::KBD_CTRL) {  				if (event.kbd.keycode == 'd') diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h index 6fdf30fff8..e7f9634fc6 100644 --- a/engines/kyra/kyra_v2.h +++ b/engines/kyra/kyra_v2.h @@ -419,7 +419,7 @@ protected:  	int o2_getVocHigh(EMCState *script);  	// save/load specific -	virtual void saveGame(const char *fileName, const char *saveName) = 0; +	virtual void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail) = 0;  	virtual void loadGame(const char *fileName) = 0;  }; diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp index 5da6bb3873..946169ddd4 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -150,7 +150,7 @@ bool Resource::reset() {  }  bool Resource::loadPakFile(const Common::String &filename) { -	if (!isAccessable(filename)) +	if (!isAccessible(filename))  		return false;  	ResFileMap::iterator iter = _map.find(filename); @@ -201,18 +201,18 @@ bool Resource::loadPakFile(const Common::String &filename) {  						// If the old parent is not protected we mark it as not preload anymore,  						// since now no longer all of its embedded files are in the filemap.  						oldParent->_value.preload = false; -						_map[i->filename] = i->entry; +						iter->_value = i->entry;  					}  				} else {  					// Old parent not found? That's strange... But we just overwrite the old  					// entry. -					_map[i->filename] = i->entry; +					iter->_value = i->entry;  				}  			} else {  				// The old parent has the same filenames as the new archive, we are sure and overwrite the  				// old file entry, could be afterall that the preload flag of the new archive was  				// just unflagged. -				_map[i->filename] = i->entry; +				iter->_value = i->entry;  			}  		}  		// 'else' case would mean here overwriting an existing file entry in the map without parent. @@ -244,7 +244,7 @@ bool Resource::loadFileList(const Common::String &filedata) {  		filename.toUppercase();  		if (filename.hasSuffix(".PAK")) { -			if (!isAccessable(filename) && _vm->gameFlags().isDemo) { +			if (!isAccessible(filename) && _vm->gameFlags().isDemo) {  				// the demo version supplied with Kyra3 does not   				// contain all pak files listed in filedata.fdt  				// so we don't do anything here if they are non @@ -289,7 +289,7 @@ void Resource::clearCompFileList() {  }  bool Resource::isInPakList(const Common::String &filename) { -	if (!isAccessable(filename)) +	if (!isAccessible(filename))  		return false;  	ResFileMap::iterator iter = _map.find(filename);  	if (iter == _map.end()) @@ -320,7 +320,7 @@ uint8 *Resource::fileData(const char *file, uint32 *size) {  bool Resource::exists(const char *file, bool errorOutOnFail) {  	if (Common::File::exists(file))  		return true; -	else if (isAccessable(file)) +	else if (isAccessible(file))  		return true;  	else if (errorOutOnFail)  		error("File '%s' can't be found", file); @@ -335,7 +335,7 @@ uint32 Resource::getFileSize(const char *file) {  		if (f.open(file))  			return f.size();  	} else { -		if (!isAccessable(file)) +		if (!isAccessible(file))  			return 0;  		ResFileMap::const_iterator iter = _map.find(file); @@ -362,7 +362,7 @@ Common::SeekableReadStream *Resource::getFileStream(const Common::String &file)  	if ((compEntry = _compFiles.find(file)) != _compFiles.end())  		return new Common::MemoryReadStream(compEntry->_value.data, compEntry->_value.size, false);		 -	if (!isAccessable(file)) +	if (!isAccessible(file))  		return 0;  	ResFileMap::const_iterator iter = _map.find(file); @@ -381,8 +381,8 @@ Common::SeekableReadStream *Resource::getFileStream(const Common::String &file)  		Common::SeekableReadStream *parent = getFileStream(iter->_value.parent);  		assert(parent); -		ResFileMap::const_iterator parentIter = _map.find(iter->_value.parent); -		const ResArchiveLoader *loader = getLoader(parentIter->_value.type); +		ResFileEntry* parentEntry = getParentEntry(&iter->_value); +		const ResArchiveLoader *loader = getLoader(parentEntry->type);  		assert(loader);  		return loader->loadFileFromArchive(file, parent, iter->_value); @@ -391,26 +391,65 @@ Common::SeekableReadStream *Resource::getFileStream(const Common::String &file)  	return 0;  } -bool Resource::isAccessable(const Common::String &file) { +bool Resource::isAccessible(const Common::String &file) {  	checkFile(file);  	ResFileMap::const_iterator iter = _map.find(file); -	while (iter != _map.end()) { -		if (!iter->_value.parent.empty()) { -			iter = _map.find(iter->_value.parent); -			if (iter != _map.end()) { -				// parent can never be a non archive file -				if (iter->_value.type == ResFileEntry::kRaw) -					return false; -				// not mounted parent means not accessable -				else if (!iter->_value.mounted) -					return false; -			} +	if (iter == _map.end()) +		return false; +	 +	return isAccessible(&iter->_value); +} + +bool Resource::isAccessible(const ResFileEntry *fileEntry) { +	assert(fileEntry); +	 +	const ResFileEntry* currentEntry = fileEntry; +	while (!currentEntry->parent.empty()) { +		if (currentEntry->parentEntry) { +			currentEntry = currentEntry->parentEntry;  		} else { -			return true; +			ResFileMap::iterator it = _map.find(currentEntry->parent); +			if (it == _map.end()) +				return false; +			else +				currentEntry->parentEntry = &it->_value;  		} +		// parent can never be a non archive file +		if (currentEntry->type == ResFileEntry::kRaw) +			return false; +		// not mounted parent means not accessable +		else if (!currentEntry->mounted) +			return false;  	} -	return false; +	 +	return true; +} + +ResFileEntry *Resource::getParentEntry(const ResFileEntry *entry) const { +	assert(entry); +	if (entry->parent.empty()) { +		return 0; +	} else if (entry->parentEntry) { +		assert(_map.find(entry->parent) != _map.end());	// If some day the hash map implementations changes and moves nodes around, +														// this assumption would fail and the whole system would need a refactoring +		assert(entry->parentEntry == &_map.find(entry->parent)->_value); +		return entry->parentEntry; +	} else { +		ResFileMap::iterator it = _map.find(entry->parent); +		if (it == _map.end()) +			return 0; // If it happens often, the structure maybe deserves a flag to avoid rechecking the map +		else { +			entry->parentEntry = &it->_value; +			return entry->parentEntry; +		} +	} +} + +ResFileEntry *Resource::getParentEntry(const Common::String &filename) const { +	ResFileMap::iterator it = _map.find(filename); +	assert(it != _map.end()); +	return getParentEntry(&it->_value);  }  void Resource::checkFile(const Common::String &file) { @@ -418,67 +457,72 @@ void Resource::checkFile(const Common::String &file) {  		CompFileMap::const_iterator iter;  		if ((iter = _compFiles.find(file)) != _compFiles.end()) { -			ResFileEntry entry; +			ResFileEntry& entry = _map[file];  			entry.parent = ""; +			entry.parentEntry = 0;  			entry.size = iter->_value.size;  			entry.mounted = false;  			entry.preload = false;  			entry.prot = false;  			entry.type = ResFileEntry::kAutoDetect;  			entry.offset = 0; -			_map[file] = entry; - -			detectFileTypes(); +			 +			detectFileType(file, &entry);  		} else if (Common::File::exists(file)) {  			Common::File temp;  			if (temp.open(file)) { -				ResFileEntry entry; +				ResFileEntry& entry = _map[file];  				entry.parent = ""; +				entry.parentEntry = 0;  				entry.size = temp.size();  				entry.mounted = file.compareToIgnoreCase(StaticResource::staticDataFilename()) != 0;  				entry.preload = false;  				entry.prot = false;  				entry.type = ResFileEntry::kAutoDetect;  				entry.offset = 0; -				_map[file] = entry;  				temp.close(); -				detectFileTypes(); +				detectFileType(file, &entry);  			}  		}  	}  } -void Resource::detectFileTypes() { -	for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i) { -		if (!isAccessable(i->_key)) -			continue; +void Resource::detectFileType(const Common::String &filename, ResFileEntry *fileEntry) { +	assert(fileEntry); +	 +	if (!isAccessible(fileEntry)) +		return; -		if (i->_value.type == ResFileEntry::kAutoDetect) { -			Common::SeekableReadStream *stream = 0; -			for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) { -				if (!(*l)->checkFilename(i->_key)) -					continue; -				 -				if (!stream) -					stream = getFileStream(i->_key); - -				if ((*l)->isLoadable(i->_key, *stream)) { -					i->_value.type = (*l)->getType(); -					i->_value.mounted = false; -					i->_value.preload = false; -					break; -				} -			} -			delete stream; -			stream = 0; +	if (fileEntry->type == ResFileEntry::kAutoDetect) { +		Common::SeekableReadStream *stream = 0; +		for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) { +			if (!(*l)->checkFilename(filename)) +				continue; +			 +			if (!stream) +				stream = getFileStream(filename); -			if (i->_value.type == ResFileEntry::kAutoDetect) -				i->_value.type = ResFileEntry::kRaw; +			if ((*l)->isLoadable(filename, *stream)) { +				fileEntry->type = (*l)->getType(); +				fileEntry->mounted = false; +				fileEntry->preload = false; +				break; +			}  		} +		delete stream; +		stream = 0; + +		if (fileEntry->type == ResFileEntry::kAutoDetect) +			fileEntry->type = ResFileEntry::kRaw;  	}  } +void Resource::detectFileTypes() { +	for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i) +		detectFileType(i->_key, &i->_value); +} +  void Resource::tryLoadCompFiles() {  	for (CCompLoaderIterator i = _compLoaders.begin(); i != _compLoaders.end(); ++i) {  		if ((*i)->checkForFiles()) @@ -620,6 +664,7 @@ bool ResLoaderPak::loadFile(const Common::String &filename, Common::SeekableRead  			entry.size = endoffset - startoffset;  			entry.offset = startoffset;  			entry.parent = filename; +			entry.parentEntry = 0;  			entry.type = ResFileEntry::kAutoDetect;  			entry.mounted = false;  			entry.prot = false; @@ -738,6 +783,7 @@ bool ResLoaderInsMalcolm::loadFile(const Common::String &filename, Common::Seeka  	for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) {  		ResFileEntry entry;  		entry.parent = filename; +		entry.parentEntry = 0;  		entry.type = ResFileEntry::kAutoDetect;  		entry.mounted = false;  		entry.preload = false; @@ -807,6 +853,7 @@ bool ResLoaderTlk::loadFile(const Common::String &filename, Common::SeekableRead  	for (uint i = 0; i < entries; ++i) {  		ResFileEntry entry;  		entry.parent = filename; +		entry.parentEntry = 0;  		entry.type = ResFileEntry::kAutoDetect;  		entry.mounted = false;  		entry.preload = false; diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index d43f730e6b..5ecbd145fe 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -43,6 +43,9 @@ namespace Kyra {  struct ResFileEntry {  	Common::String parent; +	mutable ResFileEntry *parentEntry;	// Cache to avoid lookup by string in the map +										// No smart invalidation is needed because the map is cleared globally +										// or expanded but no element is ever removed  	uint32 size;  	bool preload; @@ -128,9 +131,11 @@ public:  	bool loadFileToBuf(const char *file, void *buf, uint32 maxSize);  protected:  	void checkFile(const Common::String &file); -	bool isAccessable(const Common::String &file); +	bool isAccessible(const Common::String &file); +	bool isAccessible(const ResFileEntry *fileEntry);  	void detectFileTypes(); +	void detectFileType(const Common::String &filename, ResFileEntry *fileEntry);  	void initializeLoaders();  	const ResArchiveLoader *getLoader(ResFileEntry::kType type) const; @@ -140,6 +145,9 @@ protected:  	LoaderList _loaders;  	ResFileMap _map; +	ResFileEntry *getParentEntry(const ResFileEntry *entry) const; +	ResFileEntry *getParentEntry(const Common::String &filename) const; +  	typedef Common::List<Common::SharedPtr<CompArchiveLoader> > CompLoaderList;  	typedef CompLoaderList::iterator CompLoaderIterator;  	typedef CompLoaderList::const_iterator CCompLoaderIterator; diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index cffd0c7800..da0fd731da 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -26,10 +26,11 @@  #include "common/endian.h"  #include "common/savefile.h"  #include "common/system.h" +#include "graphics/thumbnail.h"  #include "kyra/kyra_v1.h" -#define CURRENT_SAVE_VERSION 13 +#define CURRENT_SAVE_VERSION 14  #define GF_FLOPPY  (1 <<  0)  #define GF_TALKIE  (1 <<  1) @@ -37,7 +38,7 @@  namespace Kyra { -KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header) { +KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {  	uint32 type = in->readUint32BE();  	header.originalSave = false;  	header.oldHeader = false; @@ -108,6 +109,19 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab  	if (header.version >= 2)  		header.flags = in->readUint32BE(); +	if (header.version >= 14) { +		if (loadThumbnail) { +			header.thumbnail = new Graphics::Surface(); +			assert(header.thumbnail); +			if (!Graphics::loadThumbnail(*in, *header.thumbnail)) { +				delete header.thumbnail; +				header.thumbnail = 0; +			} +		} else { +			Graphics::skipThumbnailHeader(*in); +		} +	} +  	return (in->ioFailed() ? kRSHEIoError : kRSHENoError);  } @@ -118,7 +132,7 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena  	if (!(in = _saveFileMan->openForLoading(filename)))  		return 0; -	kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, header); +	kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, false, header);  	if (errorCode != kRSHENoError) {  		if (errorCode == kRSHEInvalidType)  			warning("No ScummVM Kyra engine savefile header."); @@ -162,8 +176,8 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena  	return in;  } -Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName) const { -	debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s')", filename, saveName); +Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const { +	debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s', %p)", filename, saveName, (const void *)thumbnail);  	if (quit())  		return 0; @@ -191,6 +205,11 @@ Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, con  		return 0;  	} +	if (thumbnail) +		Graphics::saveThumbnail(*out, *thumbnail); +	else +		Graphics::saveThumbnail(*out); +  	return out;  } diff --git a/engines/kyra/saveload_hof.cpp b/engines/kyra/saveload_hof.cpp index 954cbccfa9..2b245f6167 100644 --- a/engines/kyra/saveload_hof.cpp +++ b/engines/kyra/saveload_hof.cpp @@ -35,10 +35,10 @@  namespace Kyra { -void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName) { -	debugC(9, kDebugLevelMain, "KyraEngine_HoF::saveGame('%s', '%s')", fileName, saveName); +void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) { +	debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb); -	Common::OutSaveFile *out = openSaveForWriting(fileName, saveName); +	Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);  	if (!out) {  		warning("Can't open file '%s', game not loadable", fileName);  		return; diff --git a/engines/kyra/saveload_lok.cpp b/engines/kyra/saveload_lok.cpp index 74cf26646c..257d762ce8 100644 --- a/engines/kyra/saveload_lok.cpp +++ b/engines/kyra/saveload_lok.cpp @@ -218,13 +218,13 @@ void KyraEngine_LoK::loadGame(const char *fileName) {  	delete in;  } -void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName) { -	debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s')", fileName, saveName); +void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) { +	debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb);  	if (quit())  		return; -	Common::OutSaveFile *out = openSaveForWriting(fileName, saveName); +	Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);  	if (!out)  		return; diff --git a/engines/kyra/saveload_mr.cpp b/engines/kyra/saveload_mr.cpp index 51efc33723..8849f99523 100644 --- a/engines/kyra/saveload_mr.cpp +++ b/engines/kyra/saveload_mr.cpp @@ -32,10 +32,10 @@  namespace Kyra { -void KyraEngine_MR::saveGame(const char *fileName, const char *saveName) { -	debugC(9, kDebugLevelMain, "KyraEngine_MR::saveGame('%s', '%s')", fileName, saveName); +void KyraEngine_MR::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) { +	debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb); -	Common::OutSaveFile *out = openSaveForWriting(fileName, saveName); +	Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);  	if (!out) {  		warning("Can't open file '%s', game not loadable", fileName);  		return; diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 0cde066cc0..68faaf6177 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -554,19 +554,16 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag  	copyOverlayRegion(x1, y1, x2, y2, w, h, srcPage, dstPage); -	if (flags & CR_X_FLIPPED) { +	if (flags & CR_NO_P_CHECK) {  		while (h--) { -			for (int i = 0; i < w; ++i) { -				if (src[i] || (flags & CR_NO_P_CHECK)) -					dst[w-i] = src[i]; -			} +			memcpy(dst, src, w);  			src += SCREEN_W;  			dst += SCREEN_W;  		}  	} else {  		while (h--) {  			for (int i = 0; i < w; ++i) { -				if (src[i] || (flags & CR_NO_P_CHECK)) +				if (src[i])  					dst[i] = src[i];  			}  			src += SCREEN_W; diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index 99ba2d7c5f..8623856878 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -74,8 +74,7 @@ public:  	};  	enum CopyRegionFlags { -		CR_X_FLIPPED  = 0x01, -		CR_NO_P_CHECK = 0x02 +		CR_NO_P_CHECK = 0x01  	};  	enum DrawShapeFlags { diff --git a/engines/kyra/screen_lok.cpp b/engines/kyra/screen_lok.cpp index 011c90dde9..da88abc61f 100644 --- a/engines/kyra/screen_lok.cpp +++ b/engines/kyra/screen_lok.cpp @@ -147,8 +147,14 @@ void Screen_LoK::savePageToDisk(const char *file, int page) {  void Screen_LoK::loadPageFromDisk(const char *file, int page) {  	debugC(9, kDebugLevelScreen, "Screen_LoK::loadPageFromDisk('%s', %d)", file, page); +	if (!_saveLoadPage[page/2]) { +		warning("trying to restore page %d, but no backup found", page); +		return; +	} +  	copyBlockToPage(page, 0, 0, SCREEN_W, SCREEN_H, _saveLoadPage[page/2]);  	delete[] _saveLoadPage[page/2]; +	_saveLoadPage[page/2] = 0;  	if (_saveLoadPageOvl[page/2]) {  		uint8 *dstPage = getOverlayPtr(page); @@ -160,7 +166,17 @@ void Screen_LoK::loadPageFromDisk(const char *file, int page) {  		memcpy(dstPage, _saveLoadPageOvl[page/2], SCREEN_OVL_SJIS_SIZE);  		delete[] _saveLoadPageOvl[page/2];  		_saveLoadPageOvl[page/2] = 0; -	}	_saveLoadPage[page/2] = 0; +	} +} + +void Screen_LoK::queryPageFromDisk(const char *file, int page, uint8 *buffer) { +	debugC(9, kDebugLevelScreen, "Screen_LoK::queryPageFromDisk('%s', %d, %p)", file, page, (const void *)buffer); +	if (!_saveLoadPage[page/2]) { +		warning("trying to query page %d, but no backup found", page); +		return; +	} + +	memcpy(buffer, _saveLoadPage[page/2], SCREEN_W*SCREEN_H);  }  void Screen_LoK::deletePageFromDisk(int page) { diff --git a/engines/kyra/screen_lok.h b/engines/kyra/screen_lok.h index 74df23a543..5b4b8a9266 100644 --- a/engines/kyra/screen_lok.h +++ b/engines/kyra/screen_lok.h @@ -50,6 +50,7 @@ public:  	void savePageToDisk(const char *file, int page);  	void loadPageFromDisk(const char *file, int page); +	void queryPageFromDisk(const char *file, int page, uint8 *buffer);  	void deletePageFromDisk(int page);  	void copyBackgroundBlock(int x, int page, int flag); diff --git a/engines/kyra/script_mr.cpp b/engines/kyra/script_mr.cpp index 6dda6c8bd7..dad870a5f4 100644 --- a/engines/kyra/script_mr.cpp +++ b/engines/kyra/script_mr.cpp @@ -293,7 +293,7 @@ int KyraEngine_MR::o3_updateScore(EMCState *script) {  int KyraEngine_MR::o3_makeSecondChanceSave(EMCState *script) {  	debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_makeSecondChanceSave(%p) ()", (const void *)script); -	saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME"); +	saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME", 0);  	return 0;  } diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp index b42374f44f..7915a33996 100644 --- a/engines/kyra/sequences_hof.cpp +++ b/engines/kyra/sequences_hof.cpp @@ -2830,6 +2830,9 @@ void KyraEngine_HoF::seq_init() {  	_res->unloadAllPakFiles();  	_res->loadPakFile(StaticResource::staticDataFilename());  	_res->loadFileList(_sequencePakList, _sequencePakListSize); +	 +	if (_flags.platform == Common::kPlatformPC98) +		_sound->loadSoundFile("sound.dat");  	int numShp = -1; diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index e5294eb15d..2f7ac27ac5 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -429,7 +429,7 @@ public:  	MidiChannel *allocateChannel()		{ return 0; }  	MidiChannel *getPercussionChannel()	{ return 0; } -	static float semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiToneRootkey, +	static float calculatePhaseStep(int8 semiTone, int8 semiToneRootkey,  		uint32 sampleRate, uint32 outputRate, int32 pitchWheel);  private: @@ -492,7 +492,7 @@ public:  	void process();  	void loadSoundFile(uint file) {} -	void loadSoundFile(Common::String) {} +	void loadSoundFile(Common::String file);  	void playTrack(uint8 track);  	void haltTrack(); @@ -507,6 +507,7 @@ protected:  	bool _useFmSfx;  	uint8 *_musicTrackData; +	uint8 *_sfxTrackData;  	TownsPC98_OpnDriver *_driver;	  }; diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index ec1962a58f..abda839ab4 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -23,7 +23,6 @@   *   */ -  #include "common/system.h"  #include "kyra/resource.h"  #include "kyra/sound.h" @@ -64,13 +63,13 @@ public:  	MidiDriver *device() { return 0; }  	byte getNumber() { return 0; }  	void release() { } -	void send(uint32 b) { } +	void send(uint32) { }  	void noteOff(byte note);  	void noteOn(byte note, byte onVelo); -	void programChange(byte program) {} +	void programChange(byte) {}  	void pitchBend(int16 value);  	void controlChange(byte control, byte value); -	void pitchBendFactor(byte value) { } +	void pitchBendFactor(byte) { }  	void sysEx_customInstrument(uint32 unused, const byte *instr);  protected: @@ -427,7 +426,7 @@ void Towns_EuphonyPcmChannel::nextTick(int32 *outbuf, int buflen) {  		return;  	} -	float phaseStep = SoundTowns::semitoneAndSampleRate_to_sampleStep(_note, _voice->_snd[_current]->keyNote - +	float phaseStep = SoundTowns::calculatePhaseStep(_note, _voice->_snd[_current]->keyNote -  		_voice->_env[_current]->rootKeyOffset, _voice->_snd[_current]->samplingRate, _rate, _frequencyOffs);  	int32 looplength = _voice->_snd[_current]->loopLength; @@ -819,7 +818,8 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) {  		}  	} -	while (true) { +	bool loop = true; +	while (loop) {  		byte cmd = *pos;  		byte evt = (cmd & 0xF0); @@ -853,7 +853,7 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) {  				info.basic.param2 = onVelo;  				pos += 12; -				break; +				loop = false;  			} else {  				pos += 6;  			} @@ -870,7 +870,7 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) {  				info.basic.param1 = pos[4];  				info.basic.param2 = pos[5];  				pos += 6; -				break; +				loop = false;  			} else {  				pos += 6;  			} @@ -889,7 +889,7 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) {  			_tempo[2] = tempo & 0xff;  			info.ext.data = (byte*) _tempo;  			pos += 6; -			break; +			loop = false;  		} else if (cmd == 0xFD || cmd == 0xFE) {  			// End of track.  			if (_autoLoop) { @@ -906,12 +906,12 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) {  			info.event = 0xFF;  			info.ext.type = 0x2F;  			info.ext.data = pos; -			break; +			loop = false;  		} else {  			error("Unknown Euphony music event 0x%02X", (int)cmd);  			memset(&info, 0, sizeof(info));  			pos = 0; -			break; +			loop = false;  		}  	}  	_position._play_pos = pos; @@ -1085,7 +1085,7 @@ void Towns_EuphonyTrackQueue::initDriver() {  class TownsPC98_OpnOperator {  public: -	TownsPC98_OpnOperator(double rate, const uint8 *rateTable, +	TownsPC98_OpnOperator(const uint32 timerbase, const uint8 *rateTable,  		const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable,  		const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable);  	~TownsPC98_OpnOperator() {} @@ -1095,7 +1095,7 @@ public:  	void frequency(int freq);  	void updatePhaseIncrement();  	void recalculateRates(); -	void generateOutput(int phasebuf, int *_feedbuf, int &out); +	void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out);  	void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; }  	void detune(int value) { _detn = &_detnTbl[value << 5]; } @@ -1111,6 +1111,7 @@ public:  protected:  	EnvelopeState _state; +	bool _playing;  	uint32 _feedbackLevel;  	uint32 _multiple;  	uint32 _totalLevel; @@ -1137,8 +1138,8 @@ protected:  	const int32 *_tLvlTbl;  	const int32 *_detnTbl; -	const double _tickLength; -	double _tick; +	const uint32 _tickLength; +	uint32 _timer;  	int32 _currentLevel;  	struct EvpState { @@ -1147,23 +1148,31 @@ protected:  	} fs_a, fs_d, fs_s, fs_r;  }; -TownsPC98_OpnOperator::TownsPC98_OpnOperator(double rate, const uint8 *rateTable,  +TownsPC98_OpnOperator::TownsPC98_OpnOperator(const uint32 timerbase, const uint8 *rateTable,  	const uint8 *shiftTable, const uint8 *attackDecayTable,	const uint32 *frqTable,  	const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) :  	_rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable), -	_sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(rate * 65536.0), +	_sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2),  	_specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0),  	_phase(0), _state(s_ready) { -	 +  	reset();  }  void TownsPC98_OpnOperator::keyOn() { +	if (_playing) +		return; + +	_playing = true;  	_state = s_attacking;  	_phase = 0;  }  void TownsPC98_OpnOperator::keyOff() { +	if (!_playing) +		return; +	 +	_playing = false;  	if (_state != s_ready)  		_state = s_releasing;  } @@ -1172,6 +1181,7 @@ void TownsPC98_OpnOperator::frequency(int freq) {  	uint8 block = (freq >> 11);  	uint16 pos = (freq & 0x7ff);  	uint8 c = pos >> 7; +  	_kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 ));  	_frequency = _fTbl[pos << 1] >> (7 - block);  } @@ -1204,44 +1214,44 @@ void TownsPC98_OpnOperator::recalculateRates() {  	fs_r.shift = _rshiftTbl[r + k];  } -void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out) { +void TownsPC98_OpnOperator::generateOutput(int32 phasebuf, int32 *feed, int32 &out) {  	if (_state == s_ready)  		return; -	_tick += _tickLength; -	while (_tick > 0x30000) { -		_tick -= 0x30000; +	_timer += _tickLength; +	while (_timer > 0x5B8D80) { +		_timer -= 0x5B8D80;  		++_tickCount;  		int32 levelIncrement = 0;  		uint32 targetTime = 0;  		int32 targetLevel = 0; -		EnvelopeState next_state = s_ready; +		EnvelopeState nextState = s_ready;  		switch (_state) {  			case s_ready:  				return;  			case s_attacking: -				next_state = s_decaying; +				nextState = s_decaying;  				targetTime = (1 << fs_a.shift) - 1;  				targetLevel = 0;  				levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4;  				break;  			case s_decaying:  				targetTime = (1 << fs_d.shift) - 1; -				next_state = s_sustaining; +				nextState = s_sustaining;  				targetLevel = _sustainLevel;  				levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)];  				break;  			case s_sustaining:  				targetTime = (1 << fs_s.shift) - 1; -				next_state = s_ready; +				nextState = s_sustaining;  				targetLevel = 1023;  				levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)];  				break;  			case s_releasing:  				targetTime = (1 << fs_r.shift) - 1; -				next_state = s_ready; +				nextState = s_ready;  				targetLevel = 1023;  				levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)];  				break; @@ -1249,31 +1259,31 @@ void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out  		if (!(_tickCount & targetTime)) {  			_currentLevel += levelIncrement; -			if ((!targetLevel && _currentLevel <= targetLevel) || (targetLevel && _currentLevel >= targetLevel)) { +			if ((_state == s_attacking && _currentLevel <= targetLevel) || (_state != s_attacking && _currentLevel >= targetLevel)) {  				if (_state != s_decaying)  					_currentLevel = targetLevel; -				if (_state != s_sustaining) -					_state = next_state; +				_state = nextState;  			}  		}  	}  	uint32 lvlout = _totalLevel + (uint32) _currentLevel; -	int outp = 0; -	int *i = &outp, *o = &outp; + +	int32 outp = 0; +	int32 *i = &outp, *o = &outp;  	int phaseShift = 0; -	if (_feedbuf) { -		o = &_feedbuf[0]; -		i = &_feedbuf[1]; -		phaseShift = _feedbackLevel ? ((_feedbuf[0] + _feedbuf[1]) << _feedbackLevel) : 0; +	if (feed) { +		o = &feed[0]; +		i = &feed[1]; +		phaseShift = _feedbackLevel ? ((*o + *i) << _feedbackLevel) : 0;  		if (phasebuf == -1)  			*i = 0;  		*o = *i;  	} else {  		phaseShift = phasebuf << 15; -	}		 +	}  	if (lvlout < 832) {  		uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000) @@ -1285,15 +1295,11 @@ void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out  	_phase += _phaseIncrement;  	out += *o; -	if (out > 32767) -		out = 32767; -	if (out < -32767) -		out = -32767;  }  void TownsPC98_OpnOperator::reset(){  	keyOff(); -	_tick = 0; +	_timer = 0;  	_keyScale2 = 0;  	_currentLevel = 1023; @@ -1306,7 +1312,7 @@ void TownsPC98_OpnOperator::reset(){  	decayRate(0);  	releaseRate(0);  	sustainRate(0); -	feedbackLevel(0);	 +	feedbackLevel(0);  	totalLevel(127);  } @@ -1332,40 +1338,42 @@ public:  	virtual ~TownsPC98_OpnChannel();  	virtual void init(); -	typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para); -  	typedef enum channelState {  		CHS_RECALCFREQ		=	0x01,  		CHS_KEYOFF			=	0x02, -		CHS_SSG				=	0x04, +		CHS_SSGOFF			=	0x04,  		CHS_PITCHWHEELOFF	=	0x08,  		CHS_ALL_BUT_EOT		=	0x0f, +		CHS_PROTECT			=	0x40,  		CHS_EOT				=	0x80  	} ChannelState;  	virtual void loadData(uint8 *data);  	virtual void processEvents();  	virtual void processFrequency(); -	bool processControlEvent(uint8 cmd); -	void writeReg(uint8 regAdress, uint8 value); +	virtual bool processControlEvent(uint8 cmd); +	void writeReg(uint8 regAddress, uint8 value);  	virtual void keyOn(); -	virtual void keyOff();	 -	 +	void keyOff(); +  	void setOutputLevel(); -	void fadeStep(); -	void reset(); +	virtual void fadeStep(); +	virtual void reset();  	void updateEnv(); -	void generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed); +	void generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed);  	bool _enableLeft;  	bool _enableRight; -	bool _updateEnvelopes; +	bool _updateEnvelopeParameters;  	const uint8 _idFlag; -	int _feedbuf[3]; +	int32 _feedbuf[3];  protected: +	void setupPitchWheel(); +	bool processPitchWheel(); +  	bool control_dummy(uint8 para);  	bool control_f0_setPatch(uint8 para);  	bool control_f1_presetOutputLevel(uint8 para); @@ -1377,40 +1385,36 @@ protected:  	bool control_f7_setupPitchWheel(uint8 para);  	bool control_f8_togglePitchWheel(uint8 para);  	bool control_fa_writeReg(uint8 para); -	bool control_fb_incOutLevel(uint8 para); -	bool control_fc_decOutLevel(uint8 para); +	virtual bool control_fb_incOutLevel(uint8 para); +	virtual bool control_fc_decOutLevel(uint8 para);  	bool control_fd_jump(uint8 para); -	bool control_ff_endOfTrack(uint8 para); - -	bool control_f0_setPatchSSG(uint8 para); -	bool control_f1_setTotalLevel(uint8 para); -	bool control_f4_setAlgorithm(uint8 para); -	bool control_f9_unkSSG(uint8 para); -	bool control_fb_incOutLevelSSG(uint8 para); -	bool control_fc_decOutLevelSSG(uint8 para); -	bool control_ff_endOfTrackSSG(uint8 para); +	virtual bool control_ff_endOfTrack(uint8 para);  	uint8 _ticksLeft;  	uint8 _algorithm; -	uint8 _instrID; +	uint8 _instr;  	uint8 _totalLevel;  	uint8 _frqBlockMSB;  	int8 _frqLSB;  	uint8 _keyOffTime; -	bool _protect; +	bool _hold;  	uint8 *_dataPtr; -	uint8 _ptchWhlInitDelayLo;  	uint8 _ptchWhlInitDelayHi; +	uint8 _ptchWhlInitDelayLo;  	int16 _ptchWhlModInitVal;  	uint8 _ptchWhlDuration;  	uint8 _ptchWhlCurDelay;  	int16 _ptchWhlModCurVal;  	uint8 _ptchWhlDurLeft; -	uint16 frequency; +	uint16 _frequency; +	uint8 _block;  	uint8 _regOffset;  	uint8 _flags; -	uint8 _ssg1; -	uint8 _ssg2; +	uint8 _ssgTl; +	uint8 _ssgStep; +	uint8 _ssgTicksLeft; +	uint8 _ssgTargetLvl; +	uint8 _ssgStartLvl;  	const uint8 _chanNum;  	const uint8 _keyNum; @@ -1420,6 +1424,7 @@ protected:  	TownsPC98_OpnOperator **_opr;  	uint16 _frqTemp; +	typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para);  	const ControlEventFunc *controlEvents;  }; @@ -1427,24 +1432,161 @@ class TownsPC98_OpnChannelSSG : public TownsPC98_OpnChannel {  public:  	TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs,  		uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); -	~TownsPC98_OpnChannelSSG() {} +	virtual ~TownsPC98_OpnChannelSSG() {}  	void init(); +	virtual void loadData(uint8 *data);  	void processEvents();  	void processFrequency(); +	bool processControlEvent(uint8 cmd);  	void keyOn(); -	void keyOff(); +	void nextShape(); + +	void protect(); +	void restore(); + +	void fadeStep(); + +protected: +	void setOutputLevel(uint8 lvl); + +	bool control_f0_setInstr(uint8 para); +	bool control_f1_setTotalLevel(uint8 para); +	bool control_f4_setAlgorithm(uint8 para); +	bool control_f9_loadCustomPatch(uint8 para); +	bool control_fb_incOutLevel(uint8 para); +	bool control_fc_decOutLevel(uint8 para); +	bool control_ff_endOfTrack(uint8 para); + +	typedef bool (TownsPC98_OpnChannelSSG::*ControlEventFunc)(uint8 para); +	const ControlEventFunc *controlEvents; +}; + +class TownsPC98_OpnSfxChannel : public TownsPC98_OpnChannelSSG { +public: +	TownsPC98_OpnSfxChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, +		uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : +		TownsPC98_OpnChannelSSG(driver, regOffs, flgs, num, key, prt, id) {} +	~TownsPC98_OpnSfxChannel() {} + +	void loadData(uint8 *data); +}; + +class TownsPC98_OpnChannelPCM : public TownsPC98_OpnChannel { +public: +	TownsPC98_OpnChannelPCM(TownsPC98_OpnDriver *driver, uint8 regOffs, +		uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); +	~TownsPC98_OpnChannelPCM() {} +	void init(); +  	void loadData(uint8 *data); +	void processEvents(); +	bool processControlEvent(uint8 cmd); + +	void reset(); + +private: +	bool control_f1_pcmStart(uint8 para); +	bool control_ff_endOfTrack(uint8 para); + +	typedef bool (TownsPC98_OpnChannelPCM::*ControlEventFunc)(uint8 para); +	const ControlEventFunc *controlEvents; +}; + +class TownsPC98_OpnSquareSineSource { +public: +	TownsPC98_OpnSquareSineSource(const uint32 timerbase); +	~TownsPC98_OpnSquareSineSource(); + +	void init(const int *rsTable, const int *rseTable); +	void reset(); +	uint8 readReg(uint8 address); +	void writeReg(uint8 address, uint8 value, bool force = false); + +	void nextTick(int32 *buffer, uint32 bufferSize);  private: -	void opn_SSG_UNK(uint8 a); +	void updatesRegs(); + +	uint8 _reg[16]; +	uint8 _updateRequestBuf[32]; +	int _updateRequest; +	uint8 *_regIndex; +	int _rand; + +	int8 _evpTimer; +	uint32 _pReslt; +	uint8 _attack; + +	bool _evpUpdate, _cont; + +	int _evpUpdateCnt; +	uint8 _outN; +	int _nTick; + +	int32 *_tlTable; +	int32 *_tleTable; + +	const uint32 _tickLength; +	uint32 _timer; + +	struct Channel { +		int tick; +		uint8 smp; +		uint8 out; +	} _channels[3]; + +	bool _ready;  }; +class TownsPC98_OpnPercussionSource { +public: +	TownsPC98_OpnPercussionSource(const uint32 timerbase); +	~TownsPC98_OpnPercussionSource() {} + +	void init(const uint8 *pcmData = 0); +	void reset(); +	void writeReg(uint8 address, uint8 value); + +	void nextTick(int32 *buffer, uint32 bufferSize); + +private: +	struct PcmInstrument { +		const uint8 *data; + +		const uint8 *start; +		const uint8 *end; +		const uint8 *pos; +		uint32 size; +		bool active; +		uint8 level; + +		int8 decState; +		uint8 decStep; + +		int16 samples[2]; +		int out; +	}; + +	void recalcOuput(PcmInstrument *ins); +	void advanceInput(PcmInstrument *ins); + +	PcmInstrument _pcmInstr[6]; +	uint8 _regs[48]; + +	uint8 _totalLevel; + +	const uint32 _tickLength; +	uint32 _timer; +	bool _ready; +};  class TownsPC98_OpnDriver : public Audio::AudioStream {  friend class TownsPC98_OpnChannel;  friend class TownsPC98_OpnChannelSSG; +friend class TownsPC98_OpnSfxChannel; +friend class TownsPC98_OpnChannelPCM;  public:  	enum OpnType {  		OD_TOWNS, @@ -1456,17 +1598,21 @@ public:  	~TownsPC98_OpnDriver();  	bool init(); -	void loadData(uint8 *data, bool loadPaused = false); + +	void loadMusicData(uint8 *data, bool loadPaused = false); +	void loadSoundEffectData(uint8 *data, uint8 trackNum);  	void reset(); -	void fadeOut(); -	 -	void pause() { _playing = false; } -	void cont() { _playing = true; } +	void fadeStep(); + +	void pause() { _musicPlaying = false; } +	void cont() { _musicPlaying = true; } -	void callback(); -	void nextTick(int16 *buffer, uint32 bufferSize); +	void musicCallback(); +	void sfxCallback(); +	void nextTick(int32 *buffer, uint32 bufferSize);  	bool looping() { return _looping == _updateChannelsFlag ? true : false; } +	bool musicPlaying() { return _musicPlaying; }  	// AudioStream interface  	int inline readBuffer(int16 *buffer, const int numSamples); @@ -1479,9 +1625,16 @@ protected:  	TownsPC98_OpnChannel **_channels;  	TownsPC98_OpnChannelSSG **_ssgChannels; -	//TownsPC98_OpnChannel *_adpcmChannel; +	TownsPC98_OpnSfxChannel **_sfxChannels; +	TownsPC98_OpnChannelPCM *_pcmChannel; -	void setTempo(uint8 tempo); +	TownsPC98_OpnSquareSineSource *_ssg; +	TownsPC98_OpnPercussionSource *_pcm; + +	void startSoundEffect(); +	 +	void setMusicTempo(uint8 tempo); +	void setSfxTempo(uint16 tempo);  	void lock() { _mutex.lock(); }  	void unlock() { _mutex.unlock(); } @@ -1492,6 +1645,7 @@ protected:  	const uint8 *_opnCarrier;  	const uint8 *_opnFreqTable; +	const uint8 *_opnFreqTableSSG;  	const uint8 *_opnFxCmdLen;  	const uint8 *_opnLvlPresets; @@ -1503,34 +1657,54 @@ protected:  	int32 *_oprLevelOut;  	int32 *_oprDetune; -	uint8 *_trackData; +	uint8 *_musicBuffer; +	uint8 *_sfxBuffer; +	uint8 *_trackPtr;  	uint8 *_patches; +	uint8 *_ssgPatches; -	uint8 _cbCounter;  	uint8 _updateChannelsFlag; +	uint8 _updateSSGFlag; +	uint8 _updatePCMFlag; +	uint8 _updateSfxFlag;  	uint8 _finishedChannelsFlag; -	uint16 _tempo; -	bool _playing; -	bool _fading; +	uint8 _finishedSSGFlag; +	uint8 _finishedPCMFlag; +	uint8 _finishedSfxFlag; + +	bool _musicPlaying; +	bool _sfxPlaying; +	uint8 _fading;  	uint8 _looping; -	uint32 _tickCounter; +	uint32 _musicTickCounter; -	bool _updateEnvelopes; -	int _ssgFlag; +	bool _updateEnvelopeParameters; -	int32 _samplesTillCallback; -	int32 _samplesTillCallbackRemainder; -	int32 _samplesPerCallback; -	int32 _samplesPerCallbackRemainder; +	bool _regProtectionFlag; +	int _sfxOffs; +	uint8 *_sfxData; +	uint16 _sfxOffsets[2]; + +	int32 _samplesTillMusicCallback; +	uint32 _samplesTillMusicCallbackRemainder; +	int32 _samplesPerMusicCallback; +	uint32 _samplesPerMusicCallbackRemainder; +	int32 _samplesTillSfxCallback; +	uint32 _samplesTillSfxCallbackRemainder; +	int32 _samplesPerSfxCallback; +	uint32 _samplesPerSfxCallbackRemainder;  	const int _numChan;  	const int _numSSG; -	const bool _hasADPCM; -	const bool _hasStereo; +	const bool _hasPCM; -	double _baserate;  	static const uint8 _drvTables[];  	static const uint32 _adtStat[]; +	static const int _ssgTables[]; + +	const float _baserate; +	uint32 _timerbase; +  	bool _ready;  }; @@ -1538,14 +1712,15 @@ TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 re  	uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key),  	_part(prt), _idFlag(id) { -	_ticksLeft = _algorithm = _instrID = _totalLevel = _frqBlockMSB = _keyOffTime = _ssg1 = _ssg2 = 0; -	_ptchWhlInitDelayLo = _ptchWhlInitDelayHi = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = 0; +	_ticksLeft = _algorithm = _instr = _totalLevel = _frqBlockMSB = _keyOffTime = 0; +	_ssgStartLvl = _ssgTl = _ssgStep = _ssgTicksLeft = _ssgTargetLvl = _block = 0; +	_ptchWhlInitDelayHi = _ptchWhlInitDelayLo = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = 0;  	_frqLSB = 0; -	_protect = _updateEnvelopes = false; +	_hold = _updateEnvelopeParameters = false;  	_enableLeft = _enableRight = true; -	_dataPtr = 0;		 +	_dataPtr = 0;  	_ptchWhlModInitVal = _ptchWhlModCurVal = 0; -	frequency = _frqTemp = 0; +	_frequency = _frqTemp = 0;  	memset(&_feedbuf, 0, sizeof(int) * 3);  	_opr = 0;  } @@ -1559,10 +1734,9 @@ TownsPC98_OpnChannel::~TownsPC98_OpnChannel() {  }  void TownsPC98_OpnChannel::init() { -	  	_opr = new TownsPC98_OpnOperator*[4];  	for (int i = 0; i < 4; i++) -		_opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift, +		_opr[i] = new TownsPC98_OpnOperator(_drv->_timerbase, _drv->_oprRates, _drv->_oprRateshift,  			_drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune);  	#define Control(x)	&TownsPC98_OpnChannel::control_##x @@ -1592,16 +1766,16 @@ void TownsPC98_OpnChannel::init() {  void TownsPC98_OpnChannel::keyOff() {  	// all operators off  	uint8 value = _keyNum & 0x0f; -	uint8 regAdress = 0x28; -	writeReg(regAdress, value); +	uint8 regAddress = 0x28; +	writeReg(regAddress, value);  	_flags |= CHS_KEYOFF;  }  void TownsPC98_OpnChannel::keyOn() {  	// all operators on  	uint8 value = _keyNum | 0xf0; -	uint8 regAdress = 0x28; -	writeReg(regAdress, value); +	uint8 regAddress = 0x28; +	writeReg(regAddress, value);  }  void TownsPC98_OpnChannel::loadData(uint8 *data) { @@ -1645,13 +1819,13 @@ void TownsPC98_OpnChannel::processEvents() {  	if (_flags & CHS_EOT)  		return; -	if (_protect == false && _ticksLeft == _keyOffTime) +	if (!_hold && _ticksLeft == _keyOffTime)  		keyOff();  	if (--_ticksLeft)  		return; -	if (_protect == false) +	if (!_hold)  		keyOff();  	uint8 cmd = 0; @@ -1669,14 +1843,14 @@ void TownsPC98_OpnChannel::processEvents() {  	if (cmd == 0x80) {  		keyOff(); -		_protect = false; +		_hold = false;  	} else {  		keyOn(); -		if (_protect == false || cmd != _frqBlockMSB) +		if (_hold == false || cmd != _frqBlockMSB)  			_flags |= CHS_RECALCFREQ; -	 -		_protect = (para & 0x80) ? true : false; + +		_hold = (para & 0x80) ? true : false;  		_frqBlockMSB = cmd;  	} @@ -1687,35 +1861,46 @@ void TownsPC98_OpnChannel::processFrequency() {  	if (_flags & CHS_RECALCFREQ) {  		uint8 block = (_frqBlockMSB & 0x70) >> 1;  		uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f]; -		frequency = (bfreq + _frqLSB) | (block << 8); -		writeReg(_regOffset + 0xa4, (frequency >> 8)); -		writeReg(_regOffset + 0xa0, (frequency & 0xff)); +		_frequency = (bfreq + _frqLSB) | (block << 8); +		writeReg(_regOffset + 0xa4, (_frequency >> 8)); +		writeReg(_regOffset + 0xa0, (_frequency & 0xff)); -		_ptchWhlCurDelay = _ptchWhlInitDelayHi; -		if (_flags & CHS_KEYOFF) { -			_ptchWhlModCurVal = _ptchWhlModInitVal; -			_ptchWhlCurDelay += _ptchWhlInitDelayLo; -		} - -		_ptchWhlDurLeft = (_ptchWhlDuration >> 1); -		_flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); +		setupPitchWheel();  	}  	if (!(_flags & CHS_PITCHWHEELOFF)) { -		if (--_ptchWhlCurDelay) +		if (!processPitchWheel())  			return; -		_ptchWhlCurDelay = _ptchWhlInitDelayHi; -		frequency += _ptchWhlModCurVal; -		writeReg(_regOffset + 0xa4, (frequency >> 8)); -		writeReg(_regOffset + 0xa0, (frequency & 0xff)); +		writeReg(_regOffset + 0xa4, (_frequency >> 8)); +		writeReg(_regOffset + 0xa0, (_frequency & 0xff)); +	} +} -		if(!--_ptchWhlDurLeft) { -			_ptchWhlDurLeft = _ptchWhlDuration; -			_ptchWhlModCurVal = -_ptchWhlModCurVal; -		} +void TownsPC98_OpnChannel::setupPitchWheel() { +	_ptchWhlCurDelay = _ptchWhlInitDelayHi; +	if (_flags & CHS_KEYOFF) { +		_ptchWhlModCurVal = _ptchWhlModInitVal; +		_ptchWhlCurDelay += _ptchWhlInitDelayLo;  	} +	_ptchWhlDurLeft = (_ptchWhlDuration >> 1); +	_flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); +} + +bool TownsPC98_OpnChannel::processPitchWheel() { +	if (--_ptchWhlCurDelay) +		return false; + +	_ptchWhlCurDelay = _ptchWhlInitDelayHi; +	_frequency += _ptchWhlModCurVal; + +	if(!--_ptchWhlDurLeft) { +		_ptchWhlDurLeft = _ptchWhlDuration; +		_ptchWhlModCurVal = -_ptchWhlModCurVal; +	} + +	return true;  }  bool TownsPC98_OpnChannel::processControlEvent(uint8 cmd) { @@ -1743,10 +1928,24 @@ void TownsPC98_OpnChannel::fadeStep() {  }  void TownsPC98_OpnChannel::reset() { -	for (int i = 0; i < 4; i++) -		_opr[i]->reset(); +	if (_opr) { +		for (int i = 0; i < 4; i++) +			_opr[i]->reset(); +	} -	_updateEnvelopes = false; +	_block = 0; +	_frequency = 0; +	_hold = false; +	_frqTemp = 0; +	_ssgTl = 0; +	_ssgStartLvl = 0; +	_ssgTargetLvl = 0; +	_ssgStep = 0; +	_ssgTicksLeft = 0; +	_totalLevel = 0; +	_flags |= CHS_EOT; + +	_updateEnvelopeParameters = false;  	_enableLeft = _enableRight = true;  	memset(&_feedbuf, 0, sizeof(int) * 3);  } @@ -1756,10 +1955,10 @@ void TownsPC98_OpnChannel::updateEnv() {  		_opr[i]->updatePhaseIncrement();  } -void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed) { -	int phbuf1, phbuf2, output; +void TownsPC98_OpnChannel::generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed) { +	int32 phbuf1, phbuf2, output;  	phbuf1 = phbuf2 = output = 0; -	 +  	switch (_algorithm) {  		case 0:  			_opr[0]->generateOutput(0, feed, phbuf1); @@ -1771,7 +1970,7 @@ void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample,  		case 1:  			_opr[0]->generateOutput(0, feed, phbuf1);  			_opr[2]->generateOutput(*del, 0, phbuf2); -			_opr[1]->generateOutput(0, 0, phbuf1);					 +			_opr[1]->generateOutput(0, 0, phbuf1);  			_opr[3]->generateOutput(phbuf2, 0, output);  			*del = phbuf1;  			break; @@ -1792,7 +1991,7 @@ void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample,  		case 4:  			_opr[0]->generateOutput(0, feed, phbuf1);  			_opr[2]->generateOutput(0, 0, phbuf2); -			_opr[1]->generateOutput(phbuf1, 0, output);					 +			_opr[1]->generateOutput(phbuf1, 0, output);  			_opr[3]->generateOutput(phbuf2, 0, output);  			*del = 0;  			break; @@ -1819,39 +2018,34 @@ void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample,  			break;  		}; -	if (_enableLeft) { -		int l = output + leftSample; -		if (l > 32767) -			l = 32767; -		if (l < -32767) -			l = -32767; -		leftSample = (int16) l; -	} +	int32 finOut = ((output * 7) / 2); -	if (_enableRight) { -		int r = output + rightSample; -		if (r > 32767) -			r = 32767; -		if (r < -32767) -			r = -32767; -		rightSample = (int16) r; -	} +	if (_enableLeft) +		leftSample += finOut; + +	if (_enableRight) +		rightSample += finOut;  } -void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { -	uint8 h = regAdress & 0xf0; -	uint8 l = (regAdress & 0x0f); +void TownsPC98_OpnChannel::writeReg(uint8 regAddress, uint8 value) { +	if (_drv->_regProtectionFlag) +		return; + +	uint8 h = regAddress & 0xf0; +	uint8 l = (regAddress & 0x0f);  	static const uint8 oprOrdr[] = { 0, 2, 1, 3 };  	uint8 o = oprOrdr[(l - _regOffset) >> 2]; -	 +  	switch (h) {  		case 0x00:  			// ssg -			warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); +			if (_drv->_ssg) +				_drv->_ssg->writeReg(regAddress, value);  			break;  		case 0x10: -			// adpcm -			warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); +			// pcm rhythm channel +			if (_drv->_pcm) +				_drv->_pcm->writeReg(regAddress - 0x10, value);  			break;  		case 0x20:  			if (l == 8) { @@ -1884,7 +2078,7 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) {  			// detune, multiple  			_opr[o]->detune((value >> 4) & 7);  			_opr[o]->multiple(value & 0x0f); -			_updateEnvelopes = true; +			_updateEnvelopeParameters = true;  			break;  		case 0x40: @@ -1896,7 +2090,7 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) {  			// rate scaling, attack rate  			_opr[o]->attackRate(value & 0x1f);  			if (_opr[o]->scaleRate(value >> 6)) -				_updateEnvelopes = true; +				_updateEnvelopeParameters = true;  			break;  		case 0x60: @@ -1904,7 +2098,6 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) {  			_opr[o]->decayRate(value & 0x1f);  			if (value & 0x80)  				warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)"); -  			break;  		case 0x70: @@ -1919,8 +2112,7 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) {  			break;  		case 0x90: -			// ssg -			warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); +			warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAddress);  			break;  		case 0xa0: @@ -1928,7 +2120,7 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) {  			l -= _regOffset;  			if (l == 0) {  				_frqTemp = (_frqTemp & 0xff00) | value; -				_updateEnvelopes = true; +				_updateEnvelopeParameters = true;  				for (int i = 0; i < 4; i++)  					_opr[i]->frequency(_frqTemp);  			} else if (l == 4) { @@ -1964,13 +2156,13 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) {  			break;  		default: -			warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); +			warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAddress);  			break;  	}  }  bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) { -	_instrID = para; +	_instr = para;  	uint8 reg = _regOffset + 0x80;  	for (int i = 0; i < 4; i++) { @@ -1979,7 +2171,7 @@ bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) {  		reg += 4;  	} -	const uint8 *tptr = _drv->_patches + ((uint32)_instrID << 5); +	const uint8 *tptr = _drv->_patches + ((uint32)_instr << 5);  	reg = _regOffset + 0x30;  	// write registers 0x30 to 0x8f @@ -2033,7 +2225,7 @@ bool TownsPC98_OpnChannel::control_f4_setOutputLevel(uint8 para) {  }  bool TownsPC98_OpnChannel::control_f5_setTempo(uint8 para) { -	_drv->setTempo(para); +	_drv->setMusicTempo(para);  	return true;  } @@ -2043,7 +2235,7 @@ bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) {  	if (*_dataPtr) {  		// repeat section until counter has reached zero -		_dataPtr = _drv->_trackData + READ_LE_UINT16(_dataPtr + 2); +		_dataPtr = _drv->_trackPtr + READ_LE_UINT16(_dataPtr + 2);  	} else {  		// reset counter, advance to next section  		_dataPtr[0] = _dataPtr[1]; @@ -2053,8 +2245,8 @@ bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) {  }  bool TownsPC98_OpnChannel::control_f7_setupPitchWheel(uint8 para) { -	_ptchWhlInitDelayLo = _dataPtr[0]; -	_ptchWhlInitDelayHi = para; +	_ptchWhlInitDelayHi = _dataPtr[0]; +	_ptchWhlInitDelayLo = para;  	_ptchWhlModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1);  	_ptchWhlDuration = _dataPtr[3];  	_dataPtr += 4; @@ -2070,11 +2262,12 @@ bool TownsPC98_OpnChannel::control_f8_togglePitchWheel(uint8 para) {  			_flags |= CHS_PITCHWHEELOFF;  		}  	} else { -		//uint8 skipChannels = para / 36; -		//uint8 entry = para % 36; -		//TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels]; -		////// NOT IMPLEMENTED -		//t->unnamedEntries[entry] = *_dataPtr++; +		/* NOT IMPLEMENTED +		uint8 skipChannels = para / 36; +		uint8 entry = para % 36; +		TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels]; +		 +		t->unnamedEntries[entry] = *_dataPtr++;*/  	}  	return true;  } @@ -2113,7 +2306,7 @@ bool TownsPC98_OpnChannel::control_fc_decOutLevel(uint8 para) {  }  bool TownsPC98_OpnChannel::control_fd_jump(uint8 para) { -	uint8 *tmp = _drv->_trackData + READ_LE_UINT16(_dataPtr - 1); +	uint8 *tmp = _drv->_trackPtr + READ_LE_UINT16(_dataPtr - 1);  	_dataPtr = (tmp[1] == 1) ? tmp : ++_dataPtr;  	return true;  } @@ -2127,7 +2320,7 @@ bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) {  	uint16 val = READ_LE_UINT16(--_dataPtr);  	if (val) {  		// loop -		_dataPtr = _drv->_trackData + val; +		_dataPtr = _drv->_trackPtr + val;  		return true;  	} else {  		// quit parsing for active channel @@ -2139,31 +2332,248 @@ bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) {  	}  } -bool TownsPC98_OpnChannel::control_f0_setPatchSSG(uint8 para) { -	_instrID = para << 4; +TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, +		uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : +		TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id) { +} + +void TownsPC98_OpnChannelSSG::init() { +	_algorithm = 0x80; + +	#define Control(x)	&TownsPC98_OpnChannelSSG::control_##x +	static const ControlEventFunc ctrlEventsSSG[] = { +		Control(f0_setInstr), +		Control(f1_setTotalLevel), +		Control(f2_setKeyOffTime), +		Control(f3_setFreqLSB), +		Control(f4_setAlgorithm), +		Control(f5_setTempo), +		Control(f6_repeatSection), +		Control(f7_setupPitchWheel), +		Control(f8_togglePitchWheel), +		Control(f9_loadCustomPatch), +		Control(fa_writeReg), +		Control(fb_incOutLevel), +		Control(fc_decOutLevel), +		Control(fd_jump), +		Control(dummy), +		Control(ff_endOfTrack) +	}; +	#undef Control + +	controlEvents = ctrlEventsSSG; +} + +void TownsPC98_OpnChannelSSG::processEvents() { +	if (_flags & CHS_EOT) +		return; + +	_drv->_regProtectionFlag = (_flags & CHS_PROTECT) ? true : false; + +	if (!_hold && _ticksLeft == _keyOffTime) +		nextShape(); + +	if (!--_ticksLeft) { + +		uint8 cmd = 0; +		bool loop = true; + +		while (loop) { +			cmd = *_dataPtr++; +			if (cmd < 0xf0) +				loop = false; +			else if (!processControlEvent(cmd)) +				return; +		} + +		uint8 para = *_dataPtr++; + +		if (cmd == 0x80) { +			nextShape(); +			_hold = false; +		} else { +			if (!_hold) { +				_instr &= 0xf0; +				_ssgStep = _drv->_ssgPatches[_instr]; +				_ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; +				_ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; +				_ssgStartLvl = _drv->_ssgPatches[_instr + 3]; +				_flags = (_flags & ~CHS_SSGOFF) | CHS_KEYOFF; +			} + +			keyOn(); + +			if (_hold == false || cmd != _frqBlockMSB) +				_flags |= CHS_RECALCFREQ; + +			_hold = (para & 0x80) ? true : false; +			_frqBlockMSB = cmd; +		} + +		_ticksLeft = para & 0x7f; +	} + +	if (!(_flags & CHS_SSGOFF)) { +		if (--_ssgTicksLeft) { +			if (!_drv->_fading) +				setOutputLevel(_ssgStartLvl); +			return; +		} + +		_ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + +		if (_drv->_ssgPatches[_instr + 1] & 0x80) { +			uint8 t = _ssgStartLvl - _ssgStep; + +			if (_ssgStep <= _ssgStartLvl && _ssgTargetLvl < t) { +				if (!_drv->_fading) +					setOutputLevel(t); +				return; +			} +		} else { +			int t = _ssgStartLvl + _ssgStep; +			uint8 p = (uint8) (t & 0xff); + +			if (t < 256 && _ssgTargetLvl > p) { +				if (!_drv->_fading) +					setOutputLevel(p); +				return; +			} +		} + +		setOutputLevel(_ssgTargetLvl); +		if (_ssgStartLvl && !(_instr & 8)){ +			_instr += 4; +			_ssgStep = _drv->_ssgPatches[_instr]; +			_ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; +			_ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; +		} else { +			_flags |= CHS_SSGOFF; +			setOutputLevel(0); +		} +	} +} + +void TownsPC98_OpnChannelSSG::processFrequency() { +	if (_algorithm & 0x40) +		return; + +	if (_flags & CHS_RECALCFREQ) { +		_block = _frqBlockMSB >> 4; +		_frequency = ((const uint16*)_drv->_opnFreqTableSSG)[_frqBlockMSB & 0x0f] + _frqLSB; + +		uint16 f = _frequency >> _block; +		writeReg(_regOffset << 1, f & 0xff); +		writeReg((_regOffset << 1) + 1, f >> 8); + +		setupPitchWheel(); +	} + +	if (!(_flags & (CHS_EOT | CHS_PITCHWHEELOFF | CHS_SSGOFF))) { +		if (!processPitchWheel()) +			return; + +		uint16 f = _frequency >> _block; +		writeReg(_regOffset << 1, f & 0xff); +		writeReg((_regOffset << 1) + 1, f >> 8); +	} +} + +bool TownsPC98_OpnChannelSSG::processControlEvent(uint8 cmd) { +	uint8 para = *_dataPtr++; +	return (this->*controlEvents[cmd & 0x0f])(para); +} + +void TownsPC98_OpnChannelSSG::nextShape() { +	_instr = (_instr & 0xf0) + 0x0c; +	_ssgStep = _drv->_ssgPatches[_instr]; +	_ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; +	_ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; +} + +void TownsPC98_OpnChannelSSG::keyOn() { +	uint8 c = 0x7b; +	uint8 t = (_algorithm & 0xC0) << 1; +	if (_algorithm & 0x80) +		t |= 4; + +	c = (c << (_regOffset + 1)) | (c >> (7 - _regOffset)); +	t = (t << (_regOffset + 1)) | (t >> (7 - _regOffset)); + +	if (!(_algorithm & 0x80)) +		writeReg(6, _algorithm & 0x7f); + +	uint8 e = (_drv->_ssg->readReg(7) & c) | t; +	writeReg(7, e); +} + +void TownsPC98_OpnChannelSSG::protect() { +	_flags |= CHS_PROTECT; +} + +void TownsPC98_OpnChannelSSG::restore() { +	_flags &= ~CHS_PROTECT; +	keyOn(); +	writeReg(8 + _regOffset, _ssgTl); +	uint16 f = _frequency >> _block; +	writeReg(_regOffset << 1, f & 0xff); +	writeReg((_regOffset << 1) + 1, f >> 8); +} + +void TownsPC98_OpnChannelSSG::loadData(uint8 *data) { +	_drv->_regProtectionFlag = (_flags & CHS_PROTECT) ? true : false; +	TownsPC98_OpnChannel::loadData(data); +	setOutputLevel(0); +	_algorithm = 0x80; +} + +void TownsPC98_OpnChannelSSG::setOutputLevel(uint8 lvl) { +	_ssgStartLvl = lvl; +	uint16 newTl = (((uint16)_totalLevel + 1) * (uint16)lvl) >> 8; +	if (newTl == _ssgTl) +		return; +	_ssgTl = newTl; +	writeReg(8 + _regOffset, _ssgTl); +} + +void TownsPC98_OpnChannelSSG::fadeStep() { +	_totalLevel--; +	if ((int8)_totalLevel < 0) +		_totalLevel = 0; +	setOutputLevel(_ssgStartLvl); +} + +bool TownsPC98_OpnChannelSSG::control_f0_setInstr(uint8 para) { +	_instr = para << 4;  	para = (para >> 3) & 0x1e;  	if (para)  		return control_f4_setAlgorithm(para | 0x40);  	return true;  } -bool TownsPC98_OpnChannel::control_f1_setTotalLevel(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_f1_setTotalLevel(uint8 para) {  	if (!_drv->_fading)  		_totalLevel = para;  	return true;  } -bool TownsPC98_OpnChannel::control_f4_setAlgorithm(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_f4_setAlgorithm(uint8 para) {  	_algorithm = para;  	return true;  } -bool TownsPC98_OpnChannel::control_f9_unkSSG(uint8 para) { -	_dataPtr += 5; +bool TownsPC98_OpnChannelSSG::control_f9_loadCustomPatch(uint8 para) { +	_instr = (_drv->_sfxOffs + 10 + _regOffset) << 4; +	_drv->_ssgPatches[_instr] = *_dataPtr++; +	_drv->_ssgPatches[_instr + 3] = para; +	_drv->_ssgPatches[_instr + 4] = *_dataPtr++; +	_drv->_ssgPatches[_instr + 6] = *_dataPtr++; +	_drv->_ssgPatches[_instr + 8] = *_dataPtr++; +	_drv->_ssgPatches[_instr + 12] = *_dataPtr++;  	return true;  } -bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_fb_incOutLevel(uint8 para) {  	_dataPtr--;  	if (_drv->_fading)  		return true; @@ -2175,7 +2585,7 @@ bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) {  	return true;  } -bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_fc_decOutLevel(uint8 para) {  	_dataPtr--;  	if (_drv->_fading)  		return true; @@ -2186,184 +2596,481 @@ bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) {  	return true;  } -bool TownsPC98_OpnChannel::control_ff_endOfTrackSSG(uint8 para) { -	uint16 val = READ_LE_UINT16(--_dataPtr); -	if (val) { -		// loop -		_dataPtr = _drv->_trackData + val; -		return true; +bool TownsPC98_OpnChannelSSG::control_ff_endOfTrack(uint8 para) { +	if (!_drv->_sfxOffs) { +		uint16 val = READ_LE_UINT16(--_dataPtr); +		if (val) { +			// loop +			_dataPtr = _drv->_trackPtr + val; +			return true; +		} else { +			// stop parsing +			if (!_drv->_fading) +				setOutputLevel(0); +			--_dataPtr; +			_flags |= CHS_EOT; +			_drv->_finishedSSGFlag |= _idFlag; +		}  	} else { -		// quit parsing for active channel -		--_dataPtr; +		// end of sfx track - restore ssg music channel  		_flags |= CHS_EOT; -		//_finishedChannelsFlag |= _idFlag; -		keyOff(); -		return false; +		_drv->_finishedSfxFlag |= _idFlag; +		_drv->_ssgChannels[_chanNum]->restore();  	} + +	return false;  } -TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs,  +void TownsPC98_OpnSfxChannel::loadData(uint8 *data) { +	_flags = CHS_ALL_BUT_EOT; +	_ticksLeft = 1; +	_dataPtr = data; +	_ssgTl = 0xff; +	_algorithm = 0x80; +} + +TownsPC98_OpnChannelPCM::TownsPC98_OpnChannelPCM(TownsPC98_OpnDriver *driver, uint8 regOffs,  		uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :  		TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id) {  } -void TownsPC98_OpnChannelSSG::init() { +void TownsPC98_OpnChannelPCM::init() {  	_algorithm = 0x80; -	 -	_opr = new TownsPC98_OpnOperator*[4]; -	for (int i = 0; i < 4; i++) -		_opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift, -			_drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune); -	#define Control(x)	&TownsPC98_OpnChannelSSG::control_##x -	static const ControlEventFunc ctrlEventsSSG[] = { -		Control(f0_setPatchSSG), -		Control(f1_setTotalLevel), -		Control(f2_setKeyOffTime), -		Control(f3_setFreqLSB), -		Control(f4_setOutputLevel), -		Control(f5_setTempo), +	#define Control(x)	&TownsPC98_OpnChannelPCM::control_##x +	static const ControlEventFunc ctrlEventsPCM[] = { +		Control(dummy), +		Control(f1_pcmStart), +		Control(dummy), +		Control(dummy), +		Control(dummy), +		Control(dummy),  		Control(f6_repeatSection), -		Control(f7_setupPitchWheel), -		Control(f8_togglePitchWheel), -		Control(f9_unkSSG), +		Control(dummy), +		Control(dummy), +		Control(dummy),  		Control(fa_writeReg), -		Control(fb_incOutLevelSSG), -		Control(fc_decOutLevelSSG), -		Control(fd_jump),  		Control(dummy), -		Control(ff_endOfTrackSSG) +		Control(dummy), +		Control(dummy), +		Control(dummy), +		Control(ff_endOfTrack)  	};  	#undef Control -	controlEvents = ctrlEventsSSG; +	controlEvents = ctrlEventsPCM;  } -void TownsPC98_OpnChannelSSG::processEvents() { +void TownsPC98_OpnChannelPCM::loadData(uint8 *data) { +	_flags = (_flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; +	_ticksLeft = 1; +	_dataPtr = data; +	_totalLevel = 0x7F; +} + +void TownsPC98_OpnChannelPCM::processEvents()  {  	if (_flags & CHS_EOT)  		return; -	_drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0; - -	if (_protect == false && _ticksLeft == _keyOffTime) -		keyOff(); -  	if (--_ticksLeft)  		return; -	if (_protect == false) -		keyOff(); -  	uint8 cmd = 0;  	bool loop = true;  	while (loop) {  		cmd = *_dataPtr++; -		if (cmd < 0xf0) +		if (cmd == 0x80) {  			loop = false; -		else if (!processControlEvent(cmd)) +		} else if (cmd < 0xf0) { +			writeReg(0x10, cmd); +		} else if (!processControlEvent(cmd)) {  			return; +		}  	} +	_ticksLeft = *_dataPtr++; +} + +bool TownsPC98_OpnChannelPCM::processControlEvent(uint8 cmd) {  	uint8 para = *_dataPtr++; +	return (this->*controlEvents[cmd & 0x0f])(para); +} -	if (cmd == 0x80) { -		keyOff(); -		_protect = false; +void TownsPC98_OpnChannelPCM::reset() { +	TownsPC98_OpnChannel::reset(); + +	if (_drv->_pcm) +		_drv->_pcm->reset(); +} + +bool TownsPC98_OpnChannelPCM::control_f1_pcmStart(uint8 para) { +	_totalLevel = para; +	writeReg(0x11, para); +	return true; +} + +bool TownsPC98_OpnChannelPCM::control_ff_endOfTrack(uint8 para) { +	uint16 val = READ_LE_UINT16(--_dataPtr); +	if (val) { +		// loop +		_dataPtr = _drv->_trackPtr + val; +		return true;  	} else { -		keyOn(); +		// quit parsing for active channel +		--_dataPtr; +		_flags |= CHS_EOT; +		_drv->_finishedPCMFlag |= _idFlag; +		return false; +	} +} -		if (_protect == false || cmd != _frqBlockMSB) -			_flags |= CHS_RECALCFREQ; -	 -		_protect = (para & 0x80) ? true : false; -		_frqBlockMSB = cmd; +TownsPC98_OpnSquareSineSource::TownsPC98_OpnSquareSineSource(const uint32 timerbase) : 	_tlTable(0), +	_tleTable(0), _regIndex(_reg), _updateRequest(-1), _tickLength(timerbase * 27), _ready(0) { +	memset(_reg, 0, 16); +	memset(_channels, 0, sizeof(Channel) * 3); +	reset(); +} + +TownsPC98_OpnSquareSineSource::~TownsPC98_OpnSquareSineSource() { +	delete [] _tlTable; +	delete [] _tleTable; +} + +void TownsPC98_OpnSquareSineSource::init(const int *rsTable, const int *rseTable) { +	if (_ready) { +		reset(); +		return;  	} -	_ticksLeft = para & 0x7f; +	delete [] _tlTable; +	delete [] _tleTable; +	_tlTable = new int32[16]; +	_tleTable = new int32[32]; +	float a, b, d; +	d = 801.0f; + +	for (int i = 0; i < 16; i++) { +		b = 1.0f / rsTable[i]; +		a = 1.0f / d + b + 1.0f / 1000.0f; +		float v = (b / a) * 32767.0f; +		_tlTable[i] = (int32) v; + +		b = 1.0f / rseTable[i]; +		a = 1.0f / d + b + 1.0f / 1000.0f; +		v = (b / a) * 32767.0f; +		_tleTable[i] = (int32) v; +	} -	if (!(_flags & CHS_SSG)) { +	for (int i = 16; i < 32; i++) { +		b = 1.0f / rseTable[i]; +		a = 1.0f / d + b + 1.0f / 1000.0f; +		float v = (b / a) * 32767.0f; +		_tleTable[i] = (int32) v; +	} +	_ready = true; +} + +void TownsPC98_OpnSquareSineSource::reset() { +	_rand = 1; +	_outN = 1; +	_updateRequest = -1; +	_nTick = _evpUpdateCnt = 0; +	_regIndex = _reg; +	_evpTimer = 0x1f; +	_pReslt = 0x1f; +	_attack = 0; +	_cont = false; +	_evpUpdate = true; +	_timer = 0; + +	for (int i = 0; i < 3; i++) { +		_channels[i].tick = 0; +		_channels[i].smp = _channels[i].out = 0;  	} + +	for (int i = 0; i < 14; i++) +		writeReg(i, 0, true); + +	writeReg(7, 0xbf, true);  } -void TownsPC98_OpnChannelSSG::processFrequency() { -	if (_flags & CHS_RECALCFREQ) { -		uint8 block = (_frqBlockMSB & 0x70) >> 1; -		uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f]; -		frequency = (bfreq + _frqLSB) | (block << 8); +uint8 TownsPC98_OpnSquareSineSource::readReg(uint8 address) { +	return _reg[address]; +} -		writeReg(_regOffset + 0xa4, (frequency >> 8)); -		writeReg(_regOffset + 0xa0, (frequency & 0xff)); +void TownsPC98_OpnSquareSineSource::writeReg(uint8 address, uint8 value, bool force) { +	_regIndex = &_reg[address]; +	int o = _regIndex - _reg; +	if (!force && (o == 13 || *_regIndex != value)) { +		if (_updateRequest == 31) { +			warning("TownsPC98_OpnSquareSineSource: event buffer overflow"); +			_updateRequest = -1; +		} +		_updateRequestBuf[++_updateRequest] = value; +		_updateRequestBuf[++_updateRequest] = o; +		return; +	} + +	*_regIndex = value; +} + +void TownsPC98_OpnSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) { +	if (!_ready) +		return; + +	for (uint32 i = 0; i < bufferSize; i++) { +		_timer += _tickLength; +		while (_timer > 0x5B8D80) { +			_timer -= 0x5B8D80; + +			if (++_nTick >= (_reg[6] & 0x1f)) { +				if ((_rand + 1) & 2) +					_outN ^= 1; + +				_rand = (((_rand & 1) ^ ((_rand >> 3) & 1)) << 16) | (_rand >> 1); +				_nTick = 0; +			} + +			for (int ii = 0; ii < 3; ii++) { +				if (++_channels[ii].tick >= (((_reg[ii * 2 + 1] & 0x0f) << 8) | _reg[ii * 2])) { +					_channels[ii].tick = 0; +					_channels[ii].smp ^= 1; +				} +				_channels[ii].out = (_channels[ii].smp | ((_reg[7] >> ii) & 1)) & (_outN | ((_reg[7] >> (ii + 3)) & 1)); +			} -		_ptchWhlCurDelay = _ptchWhlInitDelayHi; -		if (_flags & CHS_KEYOFF) { -			_ptchWhlModCurVal = _ptchWhlModInitVal; -			_ptchWhlCurDelay += _ptchWhlInitDelayLo; +			if (_evpUpdate) { +				if (++_evpUpdateCnt >= ((_reg[12] << 8) | _reg[11])) { +					_evpUpdateCnt = 0; + +					if (--_evpTimer < 0) { +						if (_cont) { +							_evpTimer &= 0x1f; +						} else { +							_evpUpdate = false; +							_evpTimer = 0; +						} +					} +				} +			} +			_pReslt = _evpTimer ^ _attack; +			updatesRegs();  		} -		_ptchWhlDurLeft = (_ptchWhlDuration >> 1); -		_flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); +		int32 finOut = 0; +		for (int ii = 0; ii < 3; ii++) { +			if ((_reg[ii + 8] >> 4) & 1) +				finOut += _tleTable[_channels[ii].out ? _pReslt : 0]; +			else +				finOut += _tlTable[_channels[ii].out ? (_reg[ii + 8] & 0x0f) : 0]; +		} + +		finOut /= 2; +		buffer[i << 1] += finOut; +		buffer[(i << 1) + 1] += finOut;  	} +} -	if (!(_flags & CHS_PITCHWHEELOFF)) { -		if (--_ptchWhlCurDelay) -			return; -		_ptchWhlCurDelay = _ptchWhlInitDelayHi; -		frequency += _ptchWhlModCurVal; +void TownsPC98_OpnSquareSineSource::updatesRegs() { +	for (int i = 0; i < _updateRequest;) { +		uint8 b = _updateRequestBuf[i++]; +		uint8 a = _updateRequestBuf[i++]; +		writeReg(a, b, true); +	} +	_updateRequest = -1; +} -		writeReg(_regOffset + 0xa4, (frequency >> 8)); -		writeReg(_regOffset + 0xa0, (frequency & 0xff)); +TownsPC98_OpnPercussionSource::TownsPC98_OpnPercussionSource(const uint32 timerbase) : +	_tickLength(timerbase * 2), _timer(0), _ready(false) { +		memset(_pcmInstr, 0, sizeof(PcmInstrument) * 6); +} -		if(!--_ptchWhlDurLeft) { -			_ptchWhlDurLeft = _ptchWhlDuration; -			_ptchWhlModCurVal = -_ptchWhlModCurVal; +void TownsPC98_OpnPercussionSource::init(const uint8 *pcmData) { +	if (_ready) { +		reset(); +		return; +	} + +	const uint8 *start = pcmData; +	const uint8 *pos = start; + +	if (pcmData) { +		for (int i = 0; i < 6; i++) { +			_pcmInstr[i].data = start + READ_BE_UINT16(pos); +			pos += 2; +			_pcmInstr[i].size = READ_BE_UINT16(pos); +			pos += 2;  		} +		reset(); +		_ready = true; +	} else { +		memset(_pcmInstr, 0, sizeof(PcmInstrument) * 6); +		_ready = false;  	}  } -void TownsPC98_OpnChannelSSG::keyOff() { -	// all operators off -	uint8 value = _keyNum & 0x0f; -	uint8 regAdress = 0x28; -	writeReg(regAdress, value); -	_flags |= CHS_KEYOFF; -} +void TownsPC98_OpnPercussionSource::reset() { +	_timer = 0; +	_totalLevel = 63; -void TownsPC98_OpnChannelSSG::keyOn() { -	// all operators on -	uint8 value = _keyNum | 0xf0; -	uint8 regAdress = 0x28; -	writeReg(regAdress, value); +	memset(_regs, 0, 48); + +	for (int i = 0; i < 6; i++) { +		PcmInstrument *s = &_pcmInstr[i]; +		s->pos = s->start = s->data; +		s->end = s->data + s->size; +		s->active = false; +		s->level = 0; +		s->out = 0; +		s->decStep = 1; +		s->decState = 0; +		s->samples[0] = s->samples[1] = 0; +	}  } -void TownsPC98_OpnChannelSSG::loadData(uint8 *data) { -	_drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0; -	opn_SSG_UNK(0); -	TownsPC98_OpnChannel::loadData(data); -	_algorithm = 0x80; +void TownsPC98_OpnPercussionSource::writeReg(uint8 address, uint8 value) { +	if (!_ready) +		return; + +	 uint8 h = address >> 4; +	 uint8 l = address & 15; + +	_regs[address] = value; + +	if (address == 0) { +		if (value & 0x80) { +			//key off +			for (int i = 0; i < 6; i++) { +				if ((value >> i) & 1) +					_pcmInstr[i].active = false; +			} +		} else { +			//key on +			for (int i = 0; i < 6; i++) { +				if ((value >> i) & 1) { +					PcmInstrument *s = &_pcmInstr[i]; +					s->pos = s->start; +					s->active = true; +					s->out = 0; +					s->samples[0] = s->samples[1] = 0; +					s->decStep = 1; +					s->decState = 0; +				} +			} +		} +	} else if (address == 1) { +		// total level +		_totalLevel = (value & 63) ^ 63; +		for (int i = 0; i < 6; i++) +			recalcOuput(&_pcmInstr[i]); +	} else if (!h && l & 8) { +		// instrument level +		l &= 7; +		_pcmInstr[l].level = (value & 0x1f) ^ 0x1f; +		recalcOuput(&_pcmInstr[l]); +	} else if (h & 3) { +		l &= 7; +		if (h == 1) { +			// set start offset +			_pcmInstr[l].start  = _pcmInstr[l].data + ((_regs[24 + l] * 256 + _regs[16 + l]) << 8); +		} else if (h == 2) { +			// set end offset +			_pcmInstr[l].end = _pcmInstr[l].data + ((_regs[40 + l] * 256 + _regs[32 + l]) << 8) + 255; +		} +	}  } -void TownsPC98_OpnChannelSSG::opn_SSG_UNK(uint8 a) { -	_ssg1 = a; -	uint16 h = (_totalLevel + 1) * a; -	if ((h >> 8) == _ssg2) +void TownsPC98_OpnPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) { +	if (!_ready)  		return; -	_ssg2 = (h >> 8); -	writeReg(8 + _regOffset, _ssg2); + +	for (uint32 i = 0; i < bufferSize; i++) { +		_timer += _tickLength; +		while (_timer > 0x5B8D80) { +			_timer -= 0x5B8D80; + +			for (int ii = 0; ii < 6; ii++) { +				PcmInstrument *s = &_pcmInstr[ii]; +				if (s->active) { +					recalcOuput(s); +					if (s->decStep) { +						advanceInput(s); +						if (s->pos == s->end) +							s->active = false; +					} +					s->decStep ^= 1; +				} +			} +		} + +		int32 finOut = 0; + +		for (int ii = 0; ii < 6; ii++) { +			if (_pcmInstr[ii].active) +				finOut += _pcmInstr[ii].out; +		} + +		finOut = (finOut * 7); + +		buffer[i << 1] += finOut; +		buffer[(i << 1) + 1] += finOut; +	} +} + +void TownsPC98_OpnPercussionSource::recalcOuput(PcmInstrument *ins) { +	uint32 s = _totalLevel + ins->level; +	uint32 x = s > 62 ? 0 : (1 + (s >> 3)); +	int32 y = s > 62 ? 0 : (15 - (s & 7)); +	ins->out = ((ins->samples[ins->decStep] * y) >> x) & ~3; +} + +void TownsPC98_OpnPercussionSource::advanceInput(PcmInstrument *ins) { +	static const int8 adjustIndex[] = {-1, -1, -1, -1, 2, 5, 7, 9 }; + +	static const int16 stepTable[] = { 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, +		60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, +		371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 +	}; +	 +	uint8 cur = (int8) *ins->pos++; + +	for (int i = 0; i < 2; i++) { +		int b = (2 * (cur & 7) + 1) * stepTable[ins->decState] / 8; +		ins->samples[i] = CLIP<int16>(ins->samples[i ^ 1] + (cur & 8 ? b : -b), -2048, 2047); +		ins->decState = CLIP<int8>(ins->decState + adjustIndex[cur & 7], 0, 48); +		cur >>= 4; +	}  }  TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : -	_mixer(mixer), _trackData(0), _playing(false), _fading(false), _channels(0), _ssgChannels(0), -	_looping(0), _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84), -	_opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) , -	_oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0),	_oprSinTbl(0), _oprLevelOut(0), -	_oprDetune(0), _cbCounter(4), _tickCounter(0), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), -	_finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0), _ready(false), -	_numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), -	_numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) {	 -	setTempo(84); -	_baserate = (486202500.0 / (double)getRate()) / 10368.0; +	_mixer(mixer), + +	_channels(0), _ssgChannels(0), _sfxChannels(0), _pcmChannel(0), _ssg(0), _pcm(0), +	 +	_trackPtr(0), _sfxData(0), _sfxOffs(0), _ssgPatches(0),	 + +	_opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84), _opnFreqTableSSG(_drvTables + 252), +	_opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 228)), +	_oprRates(0), _oprRateshift(0), _oprAttackDecay(0),	_oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0),	 +	 +	_numChan(type == OD_TYPE26 ? 3 : 6), _numSSG(type == OD_TOWNS ? 0 : 3), _hasPCM(type == OD_TYPE86 ? true : false), +	_updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), _finishedChannelsFlag(0), +	_updateSSGFlag(type == OD_TOWNS ? 0x00 : 0x07), _finishedSSGFlag(0), +	_updatePCMFlag(type == OD_TYPE86 ? 0x01 : 0x00), _finishedPCMFlag(0), +	_updateSfxFlag(type == OD_TOWNS ? 0x00 : 0x06), _finishedSfxFlag(0), +	 +	_baserate(55125.0f / (float)getRate()), +	_samplesTillMusicCallback(0), _samplesTillSfxCallback(0), +	_samplesTillMusicCallbackRemainder(0), _samplesTillSfxCallbackRemainder(0), +	_musicTickCounter(0), +	 +	_musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) { + +	_timerbase = (uint32)(_baserate * 1000000.0f); +	setMusicTempo(84); +	setSfxTempo(654);  }  TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { @@ -2381,13 +3088,26 @@ TownsPC98_OpnDriver::~TownsPC98_OpnDriver() {  		delete [] _ssgChannels;  	} +	if (_sfxChannels) { +		for (int i = 0; i < 2; i++) +			delete _sfxChannels[i]; +		delete [] _sfxChannels; +	} + +	if (_pcmChannel) +		delete _pcmChannel; + +	delete _ssg; +	delete _pcm; +  	delete [] _oprRates;  	delete [] _oprRateshift;  	delete [] _oprFrq;  	delete [] _oprAttackDecay;  	delete [] _oprSinTbl;  	delete [] _oprLevelOut; -	delete [] _oprDetune;	 +	delete [] _oprDetune; +	delete [] _ssgPatches;  }  bool TownsPC98_OpnDriver::init() { @@ -2420,7 +3140,21 @@ bool TownsPC98_OpnDriver::init() {  		}  		delete [] _ssgChannels;  	} + +	if (_sfxChannels) { +		for (int i = 0; i < 2; i++) { +			if (_sfxChannels[i]) +				delete _sfxChannels[i]; +		} +		delete [] _sfxChannels; +	} +  	if (_numSSG) { +		_ssg = new TownsPC98_OpnSquareSineSource(_timerbase); +		_ssg->init(&_ssgTables[0], &_ssgTables[16]); +		_ssgPatches = new uint8[256]; +		memcpy(_ssgPatches, _drvTables + 244, 256); +  		_ssgChannels = new TownsPC98_OpnChannelSSG*[_numSSG];  		for (int i = 0; i < _numSSG; i++) {  			int ii = i * 6; @@ -2428,6 +3162,23 @@ bool TownsPC98_OpnDriver::init() {  				_drvTables[ii + 2],	_drvTables[ii + 3],	_drvTables[ii + 4], _drvTables[ii + 5]);  			_ssgChannels[i]->init();  		} + +		_sfxChannels = new TownsPC98_OpnSfxChannel*[2]; +		for (int i = 0; i < 2; i++) { +			int ii = (i + 1) * 6; +			_sfxChannels[i] = new TownsPC98_OpnSfxChannel(this, _drvTables[ii], _drvTables[ii + 1], +				_drvTables[ii + 2],	_drvTables[ii + 3],	_drvTables[ii + 4], _drvTables[ii + 5]); +			_sfxChannels[i]->init(); +		} +	} + +	if (_hasPCM) { +		_pcm = new TownsPC98_OpnPercussionSource(_timerbase); +		_pcm->init(); + +		delete _pcmChannel; +		_pcmChannel = new TownsPC98_OpnChannelPCM(this, 0, 0, 0, 0, 0, 1); +		_pcmChannel->init();  	}  	_mixer->playInputStream(Audio::Mixer::kMusicSoundType, @@ -2439,36 +3190,63 @@ bool TownsPC98_OpnDriver::init() {  int inline TownsPC98_OpnDriver::readBuffer(int16 *buffer, const int numSamples) {  	memset(buffer, 0, sizeof(int16) * numSamples); +	int32 *tmp = new int32[numSamples]; +	int32 *tmpStart = tmp; +	memset(tmp, 0, sizeof(int32) * numSamples);  	int32 samplesLeft = numSamples >> 1; +  	while (samplesLeft) { -		if (!_samplesTillCallback) { -			callback(); -			_samplesTillCallback = _samplesPerCallback; -			_samplesTillCallbackRemainder += _samplesPerCallbackRemainder; -			if (_samplesTillCallbackRemainder >= _tempo) { -				_samplesTillCallback++; -				_samplesTillCallbackRemainder -= _tempo; +		if (!_samplesTillMusicCallback) { +			musicCallback(); +			_samplesTillMusicCallback = _samplesPerMusicCallback; + +			_samplesTillMusicCallbackRemainder += _samplesPerMusicCallbackRemainder; +			if (_samplesTillMusicCallbackRemainder >= _timerbase) { +				_samplesTillMusicCallback++; +				_samplesTillMusicCallbackRemainder -= _timerbase;  			}  		} -		int32 render = MIN(samplesLeft, _samplesTillCallback); +		if (!_samplesTillSfxCallback) { +			sfxCallback(); +			_samplesTillSfxCallback = _samplesPerSfxCallback; + +			_samplesTillSfxCallbackRemainder += _samplesPerSfxCallbackRemainder; +			if (_samplesTillSfxCallbackRemainder >= _timerbase) { +				_samplesTillSfxCallback++; +				_samplesTillSfxCallbackRemainder -= _timerbase; +			} +		} + +		int32 render = MIN(samplesLeft, MIN(_samplesTillSfxCallback, _samplesTillMusicCallback));  		samplesLeft -= render; -		_samplesTillCallback -= render; -		nextTick(buffer, render); +		_samplesTillMusicCallback -= render;		 +		_samplesTillSfxCallback -= render; + +		nextTick(tmp, render); + +		if (_ssg) +			_ssg->nextTick(tmp, render); +		if (_pcm) +			_pcm->nextTick(tmp, render);  		for (int i = 0; i < render; ++i) { -			buffer[i << 1] <<= 2; -			buffer[(i << 1) + 1] <<= 2; +			int32 l = CLIP<int32>(tmp[i << 1], -32767, 32767); +			buffer[i << 1] = (int16) l; +			int32 r = CLIP<int32>(tmp[(i << 1) + 1], -32767, 32767); +			buffer[(i << 1) + 1] = (int16) r;  		}  		buffer += (render << 1); +		tmp += (render << 1);  	} +	delete [] tmpStart;  	return numSamples;  } -void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) { +void TownsPC98_OpnDriver::loadMusicData(uint8 *data, bool loadPaused) {  	if (!_ready) {  		warning("TownsPC98_OpnDriver: Driver must be initialized before loading data");  		return; @@ -2479,12 +3257,11 @@ void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) {  		return;  	} +	reset(); +  	lock(); -	_trackData = data; -	reset(); -	 -	uint8 *src_a = data; +	uint8 *src_a = _trackPtr = _musicBuffer = data;  	for (uint8 i = 0; i < 3; i++) {  		_channels[i]->loadData(data + READ_LE_UINT16(src_a)); @@ -2501,117 +3278,179 @@ void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) {  		src_a += 2;  	} -	if (_hasADPCM) { -		//_adpcmChannel->loadData(data + READ_LE_UINT16(src_a)); +	if (_hasPCM) { +		_pcmChannel->loadData(data + READ_LE_UINT16(src_a));  		src_a += 2;  	} -	_ssgFlag = 0; +	_regProtectionFlag = false;  	_patches = src_a + 4; -	_cbCounter = 4; -	_finishedChannelsFlag = 0; +	_finishedChannelsFlag = _finishedSSGFlag = _finishedPCMFlag = 0; + +	_musicPlaying = (loadPaused ? false : true); -	// AH 0x17  	unlock(); -	_playing = (loadPaused ? false : true); +} + +void TownsPC98_OpnDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) { +	if (!_ready) { +		warning("TownsPC98_OpnDriver: Driver must be initialized before loading data"); +		return; +	} + +	if (!_sfxChannels) { +		warning("TownsPC98_OpnDriver: Sound effects not supported by this configuration"); +		return; +	} + +	if (!data) { +		warning("TownsPC98_OpnDriver: Invalid sound effects file data"); +		return; +	} + +	lock(); +	_sfxData = _sfxBuffer = data; +	_sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]); +	_sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]); +	_sfxPlaying = true; +	_finishedSfxFlag = 0; +	unlock();  }  void TownsPC98_OpnDriver::reset() { -	for (int i = 0; i < (_numChan); i++) +	lock(); + +	for (int i = 0; i < _numChan; i++)  		_channels[i]->reset(); -	for (int i = 0; i < (_numSSG); i++) +	for (int i = 0; i < _numSSG; i++)  		_ssgChannels[i]->reset(); -	_playing = _fading = false; +	if (_ssg) { +		for (int i = 0; i < 2; i++) +			_sfxChannels[i]->reset(); + +		memcpy(_ssgPatches, _drvTables + 276, 256); +		_ssg->reset(); +	} + +	if (_pcmChannel) +		_pcmChannel->reset(); + +	_musicPlaying = false; +	_sfxPlaying = false; +	_fading = false;  	_looping = 0; -	_tickCounter = 0; +	_musicTickCounter = 0; +	_sfxData = 0; + +	unlock();  } -void TownsPC98_OpnDriver::fadeOut() { -	if (!_playing) +void TownsPC98_OpnDriver::fadeStep() { +	if (!_musicPlaying)  		return; -	_fading = true; +	lock(); -	for (int i = 0; i < 20; i++) {		 -		lock(); -		uint32 dTime = _tickCounter + 2; -		for (int j = 0; j < _numChan; j++) { -			if (_updateChannelsFlag & _channels[j]->_idFlag) -				_channels[j]->fadeStep(); -		} -		for (int j = 0; j < _numSSG; j++) +	for (int j = 0; j < _numChan; j++) { +		if (_updateChannelsFlag & _channels[j]->_idFlag) +			_channels[j]->fadeStep(); +	} +		 +	for (int j = 0; j < _numSSG; j++) { +		if (_updateSSGFlag & _ssgChannels[j]->_idFlag)  			_ssgChannels[j]->fadeStep(); +	} -		unlock(); - -		while (_playing) { -			if (_tickCounter >= dTime) -				break; +	if (!_fading) { +		_fading = 19; +		if (_hasPCM) { +			if (_updatePCMFlag & _pcmChannel->_idFlag) +				_pcmChannel->reset();  		} +	} else { +		if (!--_fading) +			reset();  	} -	_fading = false; - -	reset(); +	unlock();  } -void TownsPC98_OpnDriver::callback() { -	if (!_playing || --_cbCounter) -		return; +void TownsPC98_OpnDriver::musicCallback() { +	lock(); -	_cbCounter = 4; -	_tickCounter++; +	_sfxOffs = 0; -	lock(); +	if (_musicPlaying) { +		_musicTickCounter++; -	for (int i = 0; i < _numChan; i++) { -		if (_updateChannelsFlag & _channels[i]->_idFlag) { -			_channels[i]->processEvents(); -			_channels[i]->processFrequency(); +		for (int i = 0; i < _numChan; i++) { +			if (_updateChannelsFlag & _channels[i]->_idFlag) { +				_channels[i]->processEvents(); +				_channels[i]->processFrequency(); +			}  		} -	} -	if (_numSSG) {  		for (int i = 0; i < _numSSG; i++) { -			_ssgChannels[i]->processEvents(); -			_ssgChannels[i]->processFrequency(); +			if (_updateSSGFlag & _ssgChannels[i]->_idFlag) { +				_ssgChannels[i]->processEvents(); +				_ssgChannels[i]->processFrequency(); +			}  		} +		 +		if (_hasPCM) +			if (_updatePCMFlag & _pcmChannel->_idFlag) +				_pcmChannel->processEvents();  	} -	 -	_ssgFlag = 0; -	unlock(); +	_regProtectionFlag = false; -	if (_finishedChannelsFlag == _updateChannelsFlag) -		reset(); +	if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedPCMFlag == _updatePCMFlag) +		_musicPlaying = false; + +	unlock();  } -void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) { -	if (!_playing) -		return;	 +void TownsPC98_OpnDriver::sfxCallback() { +	lock(); -	for (int i = 0; i < _numChan ; i++) { -		if (_channels[i]->_updateEnvelopes) { -			_channels[i]->_updateEnvelopes = false; -			_channels[i]->updateEnv(); +	if (_sfxChannels && _sfxPlaying) { +		if (_sfxData) +			startSoundEffect(); + +		_sfxOffs = 3; +		_trackPtr = _sfxBuffer; + +		for (int i = 0; i < 2; i++) { +			if (_updateSfxFlag & _sfxChannels[i]->_idFlag) { +				_sfxChannels[i]->processEvents(); +				_sfxChannels[i]->processFrequency(); +			}  		} -		 -		for (uint32 ii = 0; ii < bufferSize ; ii++) -			_channels[i]->generateOutput(buffer[ii * 2], -			buffer[ii * 2 + 1],	&_channels[i]->_feedbuf[2], _channels[i]->_feedbuf); + +		_trackPtr = _musicBuffer;  	} -	for (int i = 0; i < _numSSG ; i++) { -		if (_ssgChannels[i]->_updateEnvelopes) { -			_ssgChannels[i]->_updateEnvelopes = false; -			_ssgChannels[i]->updateEnv(); +	if (_finishedSfxFlag == _updateSfxFlag) +		_sfxPlaying = false; + +	unlock(); +} + +void TownsPC98_OpnDriver::nextTick(int32 *buffer, uint32 bufferSize) { +	if (!_ready) +		return; + +	for (int i = 0; i < _numChan; i++) { +		if (_channels[i]->_updateEnvelopeParameters) { +			_channels[i]->_updateEnvelopeParameters = false; +			_channels[i]->updateEnv();  		} -		 +  		for (uint32 ii = 0; ii < bufferSize ; ii++) -			_ssgChannels[i]->generateOutput(buffer[ii * 2], -			buffer[ii * 2 + 1],	&_ssgChannels[i]->_feedbuf[2], _ssgChannels[i]->_feedbuf); +			_channels[i]->generateOutput(buffer[ii * 2], +				buffer[ii * 2 + 1],	&_channels[i]->_feedbuf[2], _channels[i]->_feedbuf);  	}  } @@ -2641,7 +3480,7 @@ void TownsPC98_OpnDriver::generateTables() {  	delete [] _oprFrq;  	_oprFrq = new uint32[0x1000];  	for (uint32 i = 0; i < 0x1000; i++) -		_oprFrq[i] = (uint32)(_baserate * (double)(i << 11)); +		_oprFrq[i] = (uint32)(_baserate * (float)(i << 11));  	delete [] _oprAttackDecay;  	_oprAttackDecay = new uint8[152]; @@ -2680,82 +3519,36 @@ void TownsPC98_OpnDriver::generateTables() {  	delete [] _oprDetune;  	_oprDetune = new int32[256];  	for (int i = 0; i < 128; i++) { -		_oprDetune[i] = (int32)	((double)dtt[i] * _baserate * 64.0); +		_oprDetune[i] = (int32)	((float)dtt[i] * _baserate * 64.0);  		_oprDetune[i + 128] = -_oprDetune[i];  	}  	delete [] dtt;  } -void TownsPC98_OpnDriver::setTempo(uint8 tempo) { -	_tempo = tempo; -	_samplesPerCallback = getRate() / _tempo; -	_samplesPerCallbackRemainder = getRate() % _tempo; -} - -const uint8 TownsPC98_OpnDriver::_drvTables[] = { -	//	channel presets -	0x00, 0x80, 0x00, 0x00, 0x00, 0x01, -	0x01, 0x80, 0x01, 0x01, 0x00, 0x02, -	0x02, 0x80, 0x02, 0x02, 0x00, 0x04, -	0x00, 0x80, 0x03, 0x04, 0x01, 0x08, -	0x01, 0x80, 0x04, 0x05, 0x01, 0x10, -	0x02, 0x80, 0x05, 0x06, 0x01, 0x20, - -	//	control event size -	0x01, 0x01, 0x01, 0x01,	0x01, 0x01, 0x04, 0x05, -	0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, - -	//	fmt level presets  -	0x54, 0x50,	0x4C, 0x48,	0x44, 0x40, 0x3C, 0x38, -	0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18, -	0x14, 0x10, 0x0C, 0x08,	0x04, 0x90, 0x90, 0x90, -	 -	//	carriers -	0x08, 0x08, 0x08, 0x08,	0x0C, 0x0E, 0x0E, 0x0F, - -	//	frequencies -	0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02,	0xDF, 0x02, -	0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03, -	0xD5, 0x03,	0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04, -	0x00, 0x00, 0x00, 0x00, - -	//	unused -	0x01, 0x00,	0x00, 0x00, 0x03, 0x00, 0x00, 0x00, -	0x02, 0x00,	0x00, 0x00,	0x05, 0x00, 0x00, 0x00, -	0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, -	0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, +void TownsPC98_OpnDriver::startSoundEffect() { +	for (int i = 0; i < 2; i++) { +		if (_sfxOffsets[i]) { +			_ssgChannels[i + 1]->protect(); +			_sfxChannels[i]->reset(); +			_sfxChannels[i]->loadData(_sfxData + _sfxOffsets[i]); +		} +	} -	//	detune -	0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, -	0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, -	0x08, 0x08, 0x08, 0x08, 0x01, 0x01,	0x01, 0x01, -	0x02, 0x02, 0x02, 0x02, 0x02, 0x03,	0x03, 0x03, -	0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, -	0x08, 0x08, 0x09, 0x0a,	0x0b, 0x0c, 0x0d, 0x0e, -	0x10, 0x10, 0x10, 0x10,	0x02, 0x02, 0x02, 0x02, -	0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, -	0x05, 0x06,	0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, -	0x0b, 0x0c,	0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, -	0x16, 0x16, 0x16, 0x16, +	_sfxData = 0; +} -	//	pc98 level presets  -	0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25, -	0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10, -	0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90 -}; +void TownsPC98_OpnDriver::setMusicTempo(uint8 tempo) { +	float spc = (float)(0x100 - tempo) * 16.0f / _baserate; +	_samplesPerMusicCallback = (int32) spc; +	_samplesPerMusicCallbackRemainder = (uint32) ((spc - (float)_samplesPerMusicCallback) * 1000000.0f); +} -const uint32 TownsPC98_OpnDriver::_adtStat[] = { -	0x00010001, 0x00010001,	0x00010001, 0x01010001, -	0x00010101, 0x00010101, 0x00010101, 0x01010101, -	0x01010101, 0x01010101, 0x01010102, 0x01010102, -	0x01020102, 0x01020102, 0x01020202, 0x01020202, -	0x02020202, 0x02020202, 0x02020204, 0x02020204, -	0x02040204, 0x02040204, 0x02040404, 0x02040404, -	0x04040404, 0x04040404, 0x04040408, 0x04040408, -	0x04080408, 0x04080408, 0x04080808, 0x04080808, -	0x08080808, 0x08080808, 0x10101010, 0x10101010 -}; +void TownsPC98_OpnDriver::setSfxTempo(uint16 tempo) { +	float spc = (float)(0x400 - tempo) / _baserate; +	_samplesPerSfxCallback = (int32) spc; +	_samplesPerSfxCallbackRemainder = (uint32) ((spc - (float)_samplesPerSfxCallback) * 1000000.0f); +}  SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer)  	: Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _sfxFileData(0), @@ -2916,7 +3709,8 @@ void SoundTowns::playSoundEffect(uint8 track) {  	}  	playbackBufferSize -= 0x20; -	uint32 outputRate = uint32(11025 * semitoneAndSampleRate_to_sampleStep(note, sfxRootNoteOffs, sfxRate, 11025, 0x2000)); + +	uint32 outputRate = uint32(11025 * calculatePhaseStep(note, sfxRootNoteOffs, sfxRate, 11025, 0x2000));  	_currentSFX = Audio::makeLinearInputStream(sfxPlaybackBuffer, playbackBufferSize,  		outputRate, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LITTLE_ENDIAN | Audio::Mixer::FLAG_AUTOFREE, 0, 0); @@ -2995,7 +3789,7 @@ void SoundTowns::onTimer(void *data) {  		music->_parser->onTimer();  } -float SoundTowns::semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiToneRootkey, +float SoundTowns::calculatePhaseStep(int8 semiTone, int8 semiToneRootkey,  	uint32 sampleRate, uint32 outputRate, int32 pitchWheel) {  	if (semiTone < 0)  		semiTone = 0; @@ -3050,18 +3844,18 @@ bool SoundPC98::init() {  void SoundPC98::playTrack(uint8 track) {  	if (--track >= 56)  		track -= 55; -  +  	if (track == _lastTrack && _musicEnabled)  		return; -	haltTrack(); +	beginFadeOut();  	char musicfile[13];  	sprintf(musicfile, fileListEntry(0), track);  	delete[] _musicTrackData;  	_musicTrackData = _vm->resource()->fileData(musicfile, 0);  	if (_musicEnabled) -		_driver->loadData(_musicTrackData); +		_driver->loadMusicData(_musicTrackData);  	_lastTrack = track;  } @@ -3074,29 +3868,42 @@ void SoundPC98::haltTrack() {  }  void SoundPC98::beginFadeOut() { -	_driver->fadeOut(); +	if (!_driver->musicPlaying()) +		return; + +	for (int i = 0; i < 20; i++) { +		_driver->fadeStep(); +		_vm->delay(32); +	}  	haltTrack();  } -void SoundPC98::playSoundEffect(uint8) { -	/// TODO /// +void SoundPC98::playSoundEffect(uint8 track) { +	if (!_sfxTrackData) +		return; + +	//	This has been disabled for now since I don't know +	//	how to make up the correct track number. It probably +	//	needs a map. +	//_driver->loadSoundEffectData(_sfxTrackData, track);  }  //	KYRA 2  SoundTownsPC98_v2::SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) : -	Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) { +	Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) {  }  SoundTownsPC98_v2::~SoundTownsPC98_v2() {  	delete[] _musicTrackData; +	delete[] _sfxTrackData;  	delete _driver;  }  bool SoundTownsPC98_v2::init() { -	_driver = new TownsPC98_OpnDriver(_mixer, /*_vm->gameFlags().platform == Common::kPlatformPC98 ? -		TownsPC98_OpnDriver::OD_TYPE86 :*/ TownsPC98_OpnDriver::OD_TOWNS); +	_driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? +		TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS);  	_useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false;  	_vm->checkCD();  	// FIXME: While checking for 'track1.XXX(X)' looks like @@ -3110,9 +3917,15 @@ bool SoundTownsPC98_v2::init() {  		(Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") ||  		 Common::File::exists("track1.flac") || Common::File::exists("track1.fla")))  			_musicEnabled = 2; +	  	return _driver->init();  } +void SoundTownsPC98_v2::loadSoundFile(Common::String file) { +	delete [] _sfxTrackData; +	_sfxTrackData = _vm->resource()->fileData(file.c_str(), 0); +} +  void SoundTownsPC98_v2::process() {  	AudioCD.updateCD();  } @@ -3138,9 +3951,9 @@ void SoundTownsPC98_v2::playTrack(uint8 track) {  	char musicfile[13];  	sprintf(musicfile, fileListEntry(0), track);  	delete[] _musicTrackData; -	 +  	_musicTrackData = _vm->resource()->fileData(musicfile, 0); -	_driver->loadData(_musicTrackData, true); +	_driver->loadMusicData(_musicTrackData, true);  	if (_musicEnabled == 2 && trackNum != -1) {  		AudioCD.play(trackNum+1, _driver->looping() ? -1 : 1, 0, 0); @@ -3160,7 +3973,14 @@ void SoundTownsPC98_v2::haltTrack() {  }  void SoundTownsPC98_v2::beginFadeOut() { -	_driver->fadeOut(); +	if (!_driver->musicPlaying()) +		return; + +	for (int i = 0; i < 20; i++) { +		_driver->fadeStep(); +		_vm->delay(32); +	} +  	haltTrack();  } @@ -3221,7 +4041,7 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) {  		sfx[i] = cmd;  	} -	uint32 outputRate = uint32(11025 * SoundTowns::semitoneAndSampleRate_to_sampleStep(0x3c, 0x3c, sfxRate, 11025, 0x2000)); +	uint32 outputRate = uint32(11025 * SoundTowns::calculatePhaseStep(0x3c, 0x3c, sfxRate, 11025, 0x2000));  	_currentSFX = Audio::makeLinearInputStream(sfx, outsize, outputRate,  		Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LITTLE_ENDIAN | Audio::Mixer::FLAG_AUTOFREE, 0, 0); @@ -3233,16 +4053,126 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) {  }  void SoundTownsPC98_v2::playSoundEffect(uint8 track) { -	if (!_useFmSfx) +	if (!_useFmSfx || !_sfxTrackData)  		return; -	uint8 *sd = _vm->resource()->fileData("sound.dat", 0); +	_driver->loadSoundEffectData(_sfxTrackData, track); +} + +// static resources + +const uint8 TownsPC98_OpnDriver::_drvTables[] = { +	//	channel presets +	0x00, 0x80, 0x00, 0x00, 0x00, 0x01, +	0x01, 0x80, 0x01, 0x01, 0x00, 0x02, +	0x02, 0x80, 0x02, 0x02, 0x00, 0x04, +	0x00, 0x80, 0x03, 0x04, 0x01, 0x08, +	0x01, 0x80, 0x04, 0x05, 0x01, 0x10, +	0x02, 0x80, 0x05, 0x06, 0x01, 0x20, +	//	control event size +	0x01, 0x01, 0x01, 0x01,	0x01, 0x01, 0x04, 0x05, +	0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, -	//TODO +	//	fmt level presets +	0x54, 0x50,	0x4C, 0x48,	0x44, 0x40, 0x3C, 0x38, +	0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18, +	0x14, 0x10, 0x0C, 0x08,	0x04, 0x90, 0x90, 0x90, -	delete [] sd; -} +	//	carriers +	0x08, 0x08, 0x08, 0x08,	0x0C, 0x0E, 0x0E, 0x0F, + +	//	frequencies +	0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02,	0xDF, 0x02, +	0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03, +	0xD5, 0x03,	0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04, +	0x00, 0x00, 0x00, 0x00, + +	//	unused +	0x01, 0x00,	0x00, 0x00, 0x03, 0x00, 0x00, 0x00, +	0x02, 0x00,	0x00, 0x00,	0x05, 0x00, 0x00, 0x00, +	0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, +	0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + +	//	detune +	0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, +	0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, +	0x08, 0x08, 0x08, 0x08, 0x01, 0x01,	0x01, 0x01, +	0x02, 0x02, 0x02, 0x02, 0x02, 0x03,	0x03, 0x03, +	0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, +	0x08, 0x08, 0x09, 0x0a,	0x0b, 0x0c, 0x0d, 0x0e, +	0x10, 0x10, 0x10, 0x10,	0x02, 0x02, 0x02, 0x02, +	0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, +	0x05, 0x06,	0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, +	0x0b, 0x0c,	0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, +	0x16, 0x16, 0x16, 0x16, + +	//	pc98 level presets +	0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25, +	0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10, +	0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90, + +	//	ssg frequencies +	0xE8, 0x0E, 0x12, 0x0E, 0x48, 0x0D, 0x89, 0x0C, +	0xD5, 0x0B, 0x2B, 0x0B, 0x8A, 0x0A, 0xF3, 0x09, +	0x64, 0x09, 0xDD, 0x08, 0x5E, 0x08, 0xE6, 0x07, + +	// ssg patch data +	0x00, 0x00, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, +	0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00, +	0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00, +	0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, +	0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, +	0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, +	0x04, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, +	0x0A, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0x01, 0x00, +	0xFF, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, +	0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x00, +	0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, +	0x64, 0x01, 0xFF, 0x64, 0xFF, 0x81, 0xFF, 0x00, +	0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + +	0x02, 0x01, 0xFF, 0x28, 0xFF, 0x81, 0xF0, 0x00, +	0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xC8, 0x00, +	0x01, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0x78, 0x5F, 0x81, 0xA0, 0x00, +	0x05, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, +	0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, +	0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, +	0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, +	0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00 +}; + +const uint32 TownsPC98_OpnDriver::_adtStat[] = { +	0x00010001, 0x00010001,	0x00010001, 0x01010001, +	0x00010101, 0x00010101, 0x00010101, 0x01010101, +	0x01010101, 0x01010101, 0x01010102, 0x01010102, +	0x01020102, 0x01020102, 0x01020202, 0x01020202, +	0x02020202, 0x02020202, 0x02020204, 0x02020204, +	0x02040204, 0x02040204, 0x02040404, 0x02040404, +	0x04040404, 0x04040404, 0x04040408, 0x04040408, +	0x04080408, 0x04080408, 0x04080808, 0x04080808, +	0x08080808, 0x08080808, 0x10101010, 0x10101010 +}; + +const int TownsPC98_OpnDriver::_ssgTables[] = { +	0x01202A, 0x0092D2, 0x006B42, 0x0053CB, 0x003DF8, 0x003053, 0x0022DA, 0x001A8C, +	0x00129B, 0x000DC1, 0x000963, 0x0006C9, 0x000463, 0x0002FA, 0x0001B6, 0x0000FB, +	0x0193B6, 0x01202A, 0x00CDB1, 0x0092D2, 0x007D7D, 0x006B42, 0x005ECD, 0x0053CB, +	0x00480F, 0x003DF8, 0x0036B9, 0x003053, 0x00290A, 0x0022DA, 0x001E6B, 0x001A8C, +	0x001639, 0x00129B, 0x000FFF, 0x000DC1, 0x000B5D, 0x000963, 0x0007FB, 0x0006C9, +	0x000575, 0x000463, 0x00039D, 0x0002FA, 0x000242, 0x0001B6, 0x00014C, 0x0000FB +};  } // end of namespace Kyra diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 5c0e05f23d..9156fa7e9c 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -43,7 +43,7 @@  namespace Kyra { -#define RESFILE_VERSION 31 +#define RESFILE_VERSION 32  bool StaticResource::checkKyraDat() {  	Common::File kyraDat; diff --git a/engines/kyra/timer_mr.cpp b/engines/kyra/timer_mr.cpp index 37a910ccf2..ea7f64fed1 100644 --- a/engines/kyra/timer_mr.cpp +++ b/engines/kyra/timer_mr.cpp @@ -65,7 +65,7 @@ void KyraEngine_MR::timerRunSceneScript7(int arg) {  void KyraEngine_MR::timerFleaDeath(int arg) {  	debugC(9, kDebugLevelMain | kDebugLevelTimer, "KyraEngine_MR::timerFleaDeath(%d)", arg);  	_timer->setCountdown(4, 5400); -	saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME"); +	saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME", 0);  	_screen->hideMouse();  	_timer->disable(4);  	runAnimationScript("FLEADTH1.EMC", 0, 0, 1, 1); diff --git a/engines/lure/animseq.cpp b/engines/lure/animseq.cpp index 3d5265c90f..f9f53b2806 100644 --- a/engines/lure/animseq.cpp +++ b/engines/lure/animseq.cpp @@ -44,13 +44,18 @@ AnimAbortType AnimationSequence::delay(uint32 milliseconds) {  	while (g_system->getMillis() < delayCtr) {  		while (events.pollEvent()) {  			if ((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0)) { -				if (events.event().kbd.keycode == Common::KEYCODE_ESCAPE) return ABORT_END_INTRO; -				else if (events.event().kbd.keycode == Common::KEYCODE_MAINMENU) return ABORT_NONE; -				else return ABORT_NEXT_SCENE; -			} else if (events.type() == Common::EVENT_LBUTTONDOWN) +				if (events.event().kbd.keycode == Common::KEYCODE_ESCAPE) +					return ABORT_END_INTRO; +				else +					return ABORT_NEXT_SCENE; +			} else if (events.type() == Common::EVENT_LBUTTONDOWN) {  				return ABORT_NEXT_SCENE; -			else if ((events.type() == Common::EVENT_QUIT) || (events.type() == Common::EVENT_RTL)) +			} else if ((events.type() == Common::EVENT_QUIT) || (events.type() == Common::EVENT_RTL)) {  				return ABORT_END_INTRO; +			} else if (events.type() == Common::EVENT_MAINMENU) { +				return ABORT_NONE; +			} +  		}  		uint32 delayAmount = delayCtr - g_system->getMillis(); diff --git a/engines/lure/events.cpp b/engines/lure/events.cpp index 97da8bdb03..e244f69097 100644 --- a/engines/lure/events.cpp +++ b/engines/lure/events.cpp @@ -214,8 +214,7 @@ bool Events::interruptableDelay(uint32 milliseconds) {  		if (engine.quit()) return true;  		if (events.pollEvent()) { -			if (((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0) &&  -			      	events.event().kbd.keycode != KEYCODE_MAINMENU) || +			if (((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0)) ||  				(events.type() == Common::EVENT_LBUTTONDOWN))  				return true;  		} diff --git a/engines/made/music.cpp b/engines/made/music.cpp index c3b36d3b8c..0b58a11774 100644 --- a/engines/made/music.cpp +++ b/engines/made/music.cpp @@ -63,6 +63,8 @@ void MusicPlayer::setVolume(int volume) {  	_masterVolume = volume; +	Common::StackLock lock(_mutex); +  	for (int i = 0; i < 16; ++i) {  		if (_channel[i]) {  			_channel[i]->volume(_channelVolume[i] * _masterVolume / 255); diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp index 222954ec3a..290aa5e625 100644 --- a/engines/parallaction/balloons.cpp +++ b/engines/parallaction/balloons.cpp @@ -246,6 +246,8 @@ class BalloonManager_ns : public BalloonManager {  	static int16 _dialogueBalloonX[5]; +	byte _textColors[2]; +  	struct Balloon {  		Common::Rect outerBox;  		Common::Rect innerBox; @@ -266,16 +268,18 @@ public:  	void freeBalloons();  	int setLocationBalloon(char *text, bool endGame); -	int setDialogueBalloon(char *text, uint16 winding, byte textColor); -	int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); -	void setBalloonText(uint id, char *text, byte textColor); +	int setDialogueBalloon(char *text, uint16 winding, TextColor textColor); +	int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor); +	void setBalloonText(uint id, char *text, TextColor textColor);  	int hitTestDialogueBalloon(int x, int y);  };  int16 BalloonManager_ns::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 };  BalloonManager_ns::BalloonManager_ns(Gfx *gfx) : _numBalloons(0), _gfx(gfx) { - +	_textColors[kSelectedColor] = 0; +	_textColors[kUnselectedColor] = 3; +	_textColors[kNormalColor] = 0;  }  BalloonManager_ns::~BalloonManager_ns() { @@ -314,7 +318,7 @@ int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 bor  		winding = (winding == 0 ? 1 : 0);  		Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT);  		s.moveTo(r.width()/2 - 5, r.bottom - 1); -		_gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR_NS); +		_gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, 100, BALLOON_TRANSPARENT_COLOR_NS);  	}  	_numBalloons++; @@ -323,7 +327,7 @@ int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 bor  } -int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { +int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) {  	int16 w, h; @@ -336,7 +340,7 @@ int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w  	Balloon *balloon = &_intBalloons[id];  	StringWriter_NS sw(_vm->_dialogueFont); -	sw.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); +	sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface);  	// TODO: extract some text to make a name for obj  	balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -347,7 +351,7 @@ int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w  	return id;  } -int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textColor) { +int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, TextColor textColor) {  	int16 w, h; @@ -361,7 +365,7 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC  	Balloon *balloon = &_intBalloons[id];  	StringWriter_NS sw(_vm->_dialogueFont); -	sw.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); +	sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface);  	// TODO: extract some text to make a name for obj  	balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -377,12 +381,12 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC  	return id;  } -void BalloonManager_ns::setBalloonText(uint id, char *text, byte textColor) { +void BalloonManager_ns::setBalloonText(uint id, char *text, TextColor textColor) {  	Balloon *balloon = getBalloon(id);  	balloon->surface->fillRect(balloon->innerBox, 1);  	StringWriter_NS sw(_vm->_dialogueFont); -	sw.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); +	sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface);  } @@ -398,7 +402,7 @@ int BalloonManager_ns::setLocationBalloon(char *text, bool endGame) {  	int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR_NS);  	Balloon *balloon = &_intBalloons[id];  	StringWriter_NS sw(_vm->_dialogueFont); -	sw.write(text, MAX_BALLOON_WIDTH, 0, balloon->surface); +	sw.write(text, MAX_BALLOON_WIDTH, _textColors[kNormalColor], balloon->surface);  	// TODO: extract some text to make a name for obj  	balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -513,8 +517,6 @@ public:  	StringWriter_BR(Font *font) : WrappedLineFormatter(font) { }  	void write(const char *text, uint maxWidth, byte color, Graphics::Surface *surf) { -		maxWidth = 216; -  		StringExtent_BR	se(_font);  		se.calc(text, maxWidth);  		_width = se.width() + 10; @@ -534,6 +536,8 @@ public:  class BalloonManager_br : public BalloonManager { +	byte _textColors[2]; +  	struct Balloon {  		Common::Rect box;  		Graphics::Surface *surface; @@ -550,7 +554,7 @@ class BalloonManager_br : public BalloonManager {  	void cacheAnims();  	void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); -	int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); +	int createBalloon(int16 w, int16 h, uint16 borderThickness);  	Balloon *getBalloon(uint id);  	Graphics::Surface *expandBalloon(Frames *data, int frameNum); @@ -562,9 +566,9 @@ public:  	void freeBalloons();  	int setLocationBalloon(char *text, bool endGame); -	int setDialogueBalloon(char *text, uint16 winding, byte textColor); -	int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); -	void setBalloonText(uint id, char *text, byte textColor); +	int setDialogueBalloon(char *text, uint16 winding, TextColor textColor); +	int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor); +	void setBalloonText(uint id, char *text, TextColor textColor);  	int hitTestDialogueBalloon(int x, int y);  }; @@ -585,12 +589,12 @@ Graphics::Surface *BalloonManager_br::expandBalloon(Frames *data, int frameNum)  	Graphics::Surface *surf = new Graphics::Surface;  	surf->create(rect.width(), rect.height(), 1); -	_gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, 0, BALLOON_TRANSPARENT_COLOR_BR); +	_gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, LAYER_FOREGROUND, 100, BALLOON_TRANSPARENT_COLOR_BR);  	return surf;  } -int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { +int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) {  	cacheAnims();  	int id = _numBalloons; @@ -613,7 +617,7 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w  	balloon->surface = expandBalloon(src, srcFrame);  	src->getRect(srcFrame, balloon->box); -	_writer.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); +	_writer.write(text, 216, _textColors[textColor], balloon->surface);  	// TODO: extract some text to make a name for obj  	balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -626,7 +630,7 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w  	return id;  } -int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textColor) { +int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, TextColor textColor) {  	cacheAnims();  	int id = _numBalloons; @@ -637,11 +641,11 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC  	if (winding == 0) {  		src = _rightBalloon; -		srcFrame = id; +		srcFrame = 0;  	} else  	if (winding == 1) {  		src = _leftBalloon; -		srcFrame = 0; +		srcFrame = id;  	}  	assert(src); @@ -649,7 +653,7 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC  	balloon->surface = expandBalloon(src, srcFrame);  	src->getRect(srcFrame, balloon->box); -	_writer.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); +	_writer.write(text, 216, _textColors[textColor], balloon->surface);  	// TODO: extract some text to make a name for obj  	balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -657,32 +661,51 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC  	balloon->obj->y = balloon->box.top;  	balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR; -	if (id > 0) { -		balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].box.height(); -	} -  	_numBalloons++;  	return id;  } -void BalloonManager_br::setBalloonText(uint id, char *text, byte textColor) { } +void BalloonManager_br::setBalloonText(uint id, char *text, TextColor textColor) { +	Balloon *balloon = getBalloon(id); + +	StringWriter_BR sw(_vm->_dialogueFont); +	sw.write(text, 216, _textColors[textColor], balloon->surface); +} + +int BalloonManager_br::createBalloon(int16 w, int16 h, uint16 borderThickness) { +	assert(_numBalloons < 5); + +	int id = _numBalloons; +	Balloon *balloon = &_intBalloons[id]; + +	balloon->surface = new Graphics::Surface; +	balloon->surface->create(w, h, 1); + +	Common::Rect rect(w, h); +	balloon->surface->fillRect(rect, 1); +	rect.grow(-borderThickness); +	balloon->surface->fillRect(rect, 15); + +	_numBalloons++; + +	return id; +}  int BalloonManager_br::setLocationBalloon(char *text, bool endGame) { -/* -	int16 w, h; +	StringExtent_BR se(_vm->_dialogueFont); -	getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); +	se.calc(text, 240); -	int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR); +	int id = createBalloon(se.width() + 20, se.height() + 30, 2);  	Balloon *balloon = &_intBalloons[id]; -	drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); -	// TODO: extract some text to make a name for obj +	_writer.write(text, 240, kNormalColor, balloon->surface); +  	balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);  	balloon->obj->x = 5;  	balloon->obj->y = 5; -*/ +  	return 0;  } @@ -691,11 +714,9 @@ int BalloonManager_br::hitTestDialogueBalloon(int x, int y) {  	Common::Point p;  	for (uint i = 0; i < _numBalloons; i++) { -		p.x = x - _intBalloons[i].obj->x; -		p.y = y - _intBalloons[i].obj->y; - -		if (_intBalloons[i].box.contains(p)) +		if (_intBalloons[i].box.contains(x, y)) {  			return i; +		}  	}  	return -1; @@ -723,6 +744,10 @@ void BalloonManager_br::cacheAnims() {  BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx),  	_leftBalloon(0), _rightBalloon(0), _writer(_vm->_dialogueFont) { + +	_textColors[kSelectedColor] = 12; +	_textColors[kUnselectedColor] = 0; +	_textColors[kNormalColor] = 0;  }  BalloonManager_br::~BalloonManager_br() { diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 0f89ca22d1..7915daa0b8 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -32,6 +32,7 @@  #include "parallaction/input.h"  #include "parallaction/parallaction.h" +#include "parallaction/saveload.h"  #include "parallaction/sound.h" @@ -170,7 +171,7 @@ void Parallaction_ns::_c_fade(void *parm) {  		_gfx->setPalette(pal);  		_gfx->updateScreen(); -		g_system->delayMillis(20); +		_vm->_system->delayMillis(20);  	}  	return; @@ -305,7 +306,7 @@ void Parallaction_ns::_c_endComment(void *param) {  		_gfx->setPalette(_gfx->_palette);  		_gfx->updateScreen(); -		g_system->delayMillis(20); +		_vm->_system->delayMillis(20);  	}  	_input->waitForButtonEvent(kMouseLeftUp); @@ -324,10 +325,10 @@ void Parallaction_ns::_c_frankenstein(void *parm) {  	}  	for (uint16 _di = 0; _di < 30; _di++) { -		g_system->delayMillis(20); +		_vm->_system->delayMillis(20);  		_gfx->setPalette(pal0);  		_gfx->updateScreen(); -		g_system->delayMillis(20); +		_vm->_system->delayMillis(20);  		_gfx->setPalette(pal1);  		_gfx->updateScreen();  	} @@ -341,7 +342,7 @@ void Parallaction_ns::_c_frankenstein(void *parm) {  void Parallaction_ns::_c_finito(void *parm) { -	setPartComplete(_char); +	_saveLoad->setPartComplete(_char.getBaseName());  	cleanInventory();  	cleanupGame(); diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp index 472fe1fd75..0476b01454 100644 --- a/engines/parallaction/detection.cpp +++ b/engines/parallaction/detection.cpp @@ -243,19 +243,9 @@ public:  		return "Nippon Safes Inc. (C) Dynabyte";  	} -	virtual bool hasFeature(MetaEngineFeature f) const;  	virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; -	virtual SaveStateList listSaves(const char *target) const;  }; -bool ParallactionMetaEngine::hasFeature(MetaEngineFeature f) const { -	return -		(f == kSupportsRTL) || -		(f == kSupportsListSaves) || -		(f == kSupportsDirectLoad) || -		(f == kSupportsDeleteSave); -} -  bool ParallactionMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {  	const Parallaction::PARALLACTIONGameDescription *gd = (const Parallaction::PARALLACTIONGameDescription *)desc;  	bool res = true; @@ -275,34 +265,6 @@ bool ParallactionMetaEngine::createInstance(OSystem *syst, Engine **engine, cons  	return res;  } -SaveStateList ParallactionMetaEngine::listSaves(const char *target) const { -	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); -	Common::StringList filenames; -	char saveDesc[200]; -	Common::String pattern = target; -	pattern += ".0??"; - -	filenames = saveFileMan->listSavefiles(pattern.c_str()); -	sort(filenames.begin(), filenames.end());	// Sort (hopefully ensuring we are sorted numerically..) - -	SaveStateList saveList; -	for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { -		// Obtain the last 2 digits of the filename, since they correspond to the save slot -		int slotNum = atoi(file->c_str() + file->size() - 2); -		 -		if (slotNum >= 0 && slotNum <= 99) { -			Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); -			if (in) { -				in->readLine(saveDesc, 199); -				saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file)); -				delete in; -			} -		} -	} - -	return saveList; -} -  #if PLUGIN_ENABLED_DYNAMIC(PARALLACTION)  	REGISTER_PLUGIN_DYNAMIC(PARALLACTION, PLUGIN_TYPE_ENGINE, ParallactionMetaEngine);  #else diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index c94db751e7..a2de3cbbf3 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -173,7 +173,7 @@ bool DialogueManager::displayAnswer(uint16 i) {  	// display suitable answers  	if (((a->_yesFlags & flags) == a->_yesFlags) && ((a->_noFlags & ~flags) == a->_noFlags)) { -		int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, 3); +		int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, BalloonManager::kUnselectedColor);  		assert(id >= 0);  		_visAnswers[id] = i; @@ -203,7 +203,7 @@ bool DialogueManager::displayAnswers() {  	if (_numVisAnswers == 1) {  		int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y);  		_vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); -		_vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, 0); +		_vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, BalloonManager::kNormalColor);  	} else  	if (_numVisAnswers > 1) {  		int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y); @@ -218,7 +218,7 @@ bool DialogueManager::displayAnswers() {  bool DialogueManager::displayQuestion() {  	if (!scumm_stricmp(_q->_text, "NULL")) return false; -	_vm->_balloonMan->setSingleBalloon(_q->_text, _ballonPos._questionBalloon.x, _ballonPos._questionBalloon.y, _q->_mood & 0x10, 0); +	_vm->_balloonMan->setSingleBalloon(_q->_text, _ballonPos._questionBalloon.x, _ballonPos._questionBalloon.y, _q->_mood & 0x10, BalloonManager::kNormalColor);  	int id = _vm->_gfx->setItem(_questioner, _ballonPos._questionChar.x, _ballonPos._questionChar.y);  	_vm->_gfx->setItemFrame(id, _q->_mood & 0xF); @@ -256,7 +256,7 @@ int16 DialogueManager::askPassword() {  	}  	if (_passwordChanged) { -		_vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3); +		_vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, BalloonManager::kNormalColor);  		_passwordChanged = false;  	} @@ -286,14 +286,11 @@ int16 DialogueManager::selectAnswerN() {  	if (_selection != _oldSelection) {  		if (_oldSelection != -1) { -			_vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, 3); +			_vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, BalloonManager::kUnselectedColor);  		} -		if (_vm->quit()) -			return -1; -  		if (_selection != -1) { -			_vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, 0); +			_vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, BalloonManager::kSelectedColor);  			_vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[_selection]]->_mood & 0xF);  		}  	} @@ -365,6 +362,7 @@ void DialogueManager::nextQuestion() {  	}  } +  void DialogueManager::run() {  	// cache event data diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 2923f239d4..45a2b9d2ef 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -29,10 +29,12 @@  #define PATH_LEN 200  #include "common/fs.h" -  #include "common/file.h" +  #include "graphics/surface.h" +#include "parallaction/graphics.h" +  namespace Parallaction {  class Table; diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index fe7b1b2903..bcc4a5b532 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -546,27 +546,4 @@ ProgramExec_br::ProgramExec_br(Parallaction_br *vm) : ProgramExec_ns(vm), _vm(vm  ProgramExec_br::~ProgramExec_br() {  } -#if 0 -void Parallaction_br::jobWaitRemoveLabelJob(void *parm, Job *job) { - -} - -void Parallaction_br::jobPauseSfx(void *parm, Job *job) { - -} - - -void Parallaction_br::jobStopFollower(void *parm, Job *job) { - -} - - -void Parallaction_br::jobScroll(void *parm, Job *job) { - -} -#endif - - - -  } // namespace Parallaction diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 30790a346f..7262fc0085 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -247,32 +247,6 @@ DECLARE_COMMAND_OPCODE(close) {  	_vm->updateDoor(_ctxt.cmd->u._zone, true);  } -void Parallaction::showZone(ZonePtr z, bool visible) { -	if (!z) { -		return; -	} - -	if (visible) { -		z->_flags &= ~kFlagsRemove; -		z->_flags |= kFlagsActive; -	} else { -		z->_flags |= kFlagsRemove; -	} - -	if ((z->_type & 0xFFFF) == kZoneGet) { -		_gfx->showGfxObj(z->u.get->gfxobj, visible); - -		GetData *data = z->u.get; -		if (data->hasMask && _gfx->_backgroundInfo->hasMask) { -			if (visible) { -				_gfx->_backgroundInfo->mask.bltOr(data->gfxobj->x, data->gfxobj->y, data->_mask[0], 0, 0, data->_mask->w, data->_mask->h); -			} else { -				_gfx->_backgroundInfo->mask.bltCopy(data->gfxobj->x, data->gfxobj->y, data->_mask[1], 0, 0, data->_mask->w, data->_mask->h); -			} -		} -	} -} -  DECLARE_COMMAND_OPCODE(on) {  	_vm->showZone(_ctxt.cmd->u._zone, true);  } @@ -304,8 +278,7 @@ DECLARE_COMMAND_OPCODE(drop){  DECLARE_COMMAND_OPCODE(quit) { -	_vm->_quit = true; -	_vm->quitGame(); +	_engineFlags |= kEngineQuit;  } @@ -319,66 +292,6 @@ DECLARE_COMMAND_OPCODE(stop) {  } -void Parallaction_ns::drawAnimations() { -	debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n"); - -	uint16 layer = 0; - -	for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) { - -		AnimationPtr anim = *it; -		GfxObj *obj = anim->gfxobj; - -		// Validation is performed here, so that every animation is affected, instead that only the ones -		// who *own* a script. In fact, some scripts can change values in other animations. -		// The right way to do this would be to enforce validation when any variable is modified from -		// a script. -		anim->validateScriptVars(); - -		if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0))   { - -			if (anim->_flags & kFlagsNoMasked) -				layer = LAYER_FOREGROUND; -			else { -				if (getGameType() == GType_Nippon) { -					// Layer in NS depends on where the animation is on the screen, for each animation. -					layer = _gfx->_backgroundInfo->getLayer(anim->getFrameY() + anim->height()); -				} else { -					// Layer in BRA is calculated from Z value. For characters it is the same as NS, -					// but other animations can have Z set from scripts independently from their -					// position on the screen. -					layer = _gfx->_backgroundInfo->getLayer(anim->getZ()); -				} -			} - -			if (obj) { -				_gfx->showGfxObj(obj, true); -				obj->frame = anim->getF(); -				obj->x = anim->getX(); -				obj->y = anim->getY(); -				obj->z = anim->getZ(); -				obj->layer = layer; -			} -		} - -		if (((anim->_flags & kFlagsActive) == 0) && (anim->_flags & kFlagsRemove))   { -			anim->_flags &= ~kFlagsRemove; -		} - -		if ((anim->_flags & kFlagsActive) && (anim->_flags & kFlagsRemove))	{ -			anim->_flags &= ~kFlagsActive; -			anim->_flags |= kFlagsRemove; -			if (obj) { -				_gfx->showGfxObj(obj, false); -			} -		} -	} - -	debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n"); - -	return; -} -  void ProgramExec::runScript(ProgramPtr script, AnimationPtr a) {  	debugC(9, kDebugExec, "runScript(Animation = %s)", a->_name); @@ -443,15 +356,11 @@ void CommandExec::runList(CommandList::iterator first, CommandList::iterator las  	_ctxt.suspend = false;  	for ( ; first != last; first++) { - -		if (_vm->quit()) +		if (_engineFlags & kEngineQuit)  			break;  		CommandPtr cmd = *first; -		if (_vm->quit()) -			break; -		  		if (cmd->_flagsOn & kFlagsGlobal) {  			useFlags = _globalFlags | kFlagsGlobal;  			useLocalFlags = false; @@ -537,239 +446,6 @@ CommandExec_ns::~CommandExec_ns() {  } -// -//	ZONE TYPE: EXAMINE -// - -void Parallaction::enterCommentMode(ZonePtr z) { -	if (!z) { -		return; -	} - -	_commentZone = z; - -	ExamineData *data = _commentZone->u.examine; - -	if (!data->_description) { -		return; -	} - -	// TODO: move this balloons stuff into DialogueManager and BalloonManager -	if (getGameType() == GType_Nippon) { -		int id; -		if (data->_filename) { -			if (data->_cnv == 0) { -				data->_cnv = _disk->loadStatic(data->_filename); -			} - -			_gfx->setHalfbriteMode(true); -			_balloonMan->setSingleBalloon(data->_description, 0, 90, 0, 0); -			Common::Rect r; -			data->_cnv->getRect(0, r); -			id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2); -			_gfx->setItemFrame(id, 0); -			id = _gfx->setItem(_char._head, 100, 152); -			_gfx->setItemFrame(id, 0); -		} else { -			_balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0); -			id = _gfx->setItem(_char._talk, 190, 80); -			_gfx->setItemFrame(id, 0); -		} -	} else -	if (getGameType() == GType_BRA) { -		_balloonMan->setSingleBalloon(data->_description, 0, 0, 1, 0); -		int id = _gfx->setItem(_char._talk, 10, 80); -		_gfx->setItemFrame(id, 0); -	} - -	_input->_inputMode = Input::kInputModeComment; -} - -void Parallaction::exitCommentMode() { -	_input->_inputMode = Input::kInputModeGame; - -	hideDialogueStuff(); -	_gfx->setHalfbriteMode(false); - -	_cmdExec->run(_commentZone->_commands, _commentZone); -	_commentZone = nullZonePtr; -} - -void Parallaction::runCommentFrame() { -	if (_input->_inputMode != Input::kInputModeComment) { -		return; -	} - -	if (_input->getLastButtonEvent() == kMouseLeftUp) { -		exitCommentMode(); -	} -} - - -void Parallaction::runZone(ZonePtr z) { -	debugC(3, kDebugExec, "runZone (%s)", z->_name); - -	uint16 subtype = z->_type & 0xFFFF; - -	debugC(3, kDebugExec, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16); -	switch(subtype) { - -	case kZoneExamine: -		enterCommentMode(z); -		return; - -	case kZoneGet: -		pickupItem(z); -		break; - -	case kZoneDoor: -		if (z->_flags & kFlagsLocked) break; -		updateDoor(z, !(z->_flags & kFlagsClosed)); -		break; - -	case kZoneHear: -		_soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping); -		break; - -	case kZoneSpeak: -		enterDialogueMode(z); -		return; -	} - -	debugC(3, kDebugExec, "runZone completed"); - -	_cmdExec->run(z->_commands, z); - -	return; -} - -// -//	ZONE TYPE: DOOR -// -void Parallaction::updateDoor(ZonePtr z, bool close) { -	z->_flags = close ? (z->_flags |= kFlagsClosed) : (z->_flags &= ~kFlagsClosed); - -	if (z->u.door->gfxobj) { -		uint frame = (close ? 0 : 1); -//		z->u.door->gfxobj->setFrame(frame); -		z->u.door->gfxobj->frame = frame; -	} - -	return; -} - - - -// -//	ZONE TYPE: GET -// - -bool Parallaction::pickupItem(ZonePtr z) { -	if (z->_flags & kFlagsFixed) { -		return false; -	} - -	int slot = addInventoryItem(z->u.get->_icon); -	if (slot != -1) { -		showZone(z, false); -	} - -	return (slot != -1); -} - - - -ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) { -//	printf("hitZone(%i, %i, %i)", type, x, y); - -	uint16 _di = y; -	uint16 _si = x; - -	for (ZoneList::iterator it = _location._zones.begin(); it != _location._zones.end(); it++) { -//		printf("Zone name: %s", z->_name); - -		ZonePtr z = *it; - -		if (z->_flags & kFlagsRemove) continue; - -		Common::Rect r; -		z->getBox(r); -		r.right++;		// adjust border because Common::Rect doesn't include bottom-right edge -		r.bottom++; - -		r.grow(-1);		// allows some tolerance for mouse click - -		if (!r.contains(_si, _di)) { - -			// out of Zone, so look for special values -			if ((z->getX() == -2) || (z->getX() == -3)) { - -				// WORKAROUND: this huge condition is needed because we made TypeData a collection of structs -				// instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, -				// but we need to check it separately here. The same workaround is applied in freeZones. -				if ((((z->_type & 0xFFFF) == kZoneMerge) && (((_si == z->u.merge->_obj1) && (_di == z->u.merge->_obj2)) || ((_si == z->u.merge->_obj2) && (_di == z->u.merge->_obj1)))) || -					(((z->_type & 0xFFFF) == kZoneGet) && ((_si == z->u.get->_icon) || (_di == z->u.get->_icon)))) { - -					// special Zone -					if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) -						return z; -					if (z->_type == type) -						return z; -					if ((z->_type & 0xFFFF0000) == type) -						return z; - -				} -			} - -			if (z->getX() != -1) -				continue; -			if (_si < _char._ani->getFrameX()) -				continue; -			if (_si > (_char._ani->getFrameX() + _char._ani->width())) -				continue; -			if (_di < _char._ani->getFrameY()) -				continue; -			if (_di > (_char._ani->getFrameY() + _char._ani->height())) -				continue; - -		} - -		// normal Zone -		if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) -			return z; -		if (z->_type == type) -			return z; -		if ((z->_type & 0xFFFF0000) == type) -			return z; - -	} - - -	int16 _a, _b, _c, _d, _e, _f; -	for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ait++) { - -		AnimationPtr a = *ait; - -		_a = (a->_flags & kFlagsActive) ? 1 : 0;															   // _a: active Animation -		_e = ((_si >= a->getFrameX() + a->width()) || (_si <= a->getFrameX())) ? 0 : 1;		// _e: horizontal range -		_f = ((_di >= a->getFrameY() + a->height()) || (_di <= a->getFrameY())) ? 0 : 1;		// _f: vertical range - -		_b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1;										 // _b: (no type specified) AND (Animation is not the character) -		_c = (a->_type & 0xFFFF0000) ? 0 : 1;															// _c: Animation is not an object -		_d = ((a->_type & 0xFFFF0000) != type) ? 0 : 1;													// _d: Animation is an object of the same type - -		if ((_a != 0 && _e != 0 && _f != 0) && ((_b != 0 && _c != 0) || (a->_type == type) || (_d != 0))) { - -			return a; - -		} - -	} - -	return nullZonePtr; -} - -  void CommandExec_ns::init() {  	Common::Array<const Opcode*> *table = 0; diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 1c373dda44..8eb9753edd 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -32,7 +32,7 @@  namespace Parallaction { -GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : _frames(frames), _keep(true), x(0), y(0), z(0), _flags(kGfxObjNormal), type(objType), frame(0), layer(3)  { +GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : _frames(frames), _keep(true), x(0), y(0), z(0), _flags(kGfxObjNormal), type(objType), frame(0), layer(3), scale(100)  {  	if (name) {  		_name = strdup(name);  	} else { @@ -180,9 +180,9 @@ void Gfx::drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene) {  	data = obj->getData(obj->frame);  	if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { -		blt(rect, data, &surf, obj->layer, obj->transparentKey); +		blt(rect, data, &surf, obj->layer, obj->scale, obj->transparentKey);  	} else { -		unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->transparentKey); +		unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->scale, obj->transparentKey);  	}  } @@ -233,7 +233,7 @@ void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surf  	blt(r, _unpackedBitmap, surf, z, transparentColor);  }  #endif -void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { +void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) {  	byte *d = _unpackedBitmap;  	uint pixelsLeftInLine = r.width(); @@ -259,11 +259,154 @@ void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surf  		d += repeat;  	} -	blt(r, _unpackedBitmap, surf, z, transparentColor); +	blt(r, _unpackedBitmap, surf, z, scale, transparentColor);  } -void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) { +void Gfx::bltMaskScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) { +	if (scale == 100) { +		// use optimized path +		bltMaskNoScale(r, data, surf, z, transparentColor); +		return; +	} + +	Common::Rect q(r); +	Common::Rect clipper(surf->w, surf->h); +	q.clip(clipper); +	if (!q.isValidRect()) return; + +	uint inc = r.width() * (100 - scale); +	uint thr = r.width() * 100; +	uint xAccum = 0, yAccum = 0; + +	Common::Point dp; +	dp.x = q.left + (r.width() * (100 - scale)) / 200; +	dp.y = q.top + (r.height() * (100 - scale)) / 100; +	q.translate(-r.left, -r.top); +	byte *s = data + q.left + q.top * r.width(); +	byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + +	uint line = 0, col = 0; + +	for (uint16 i = 0; i < q.height(); i++) { +		yAccum += inc; + +		if (yAccum >= thr) { +			yAccum -= thr; +			s += r.width(); +			continue; +		} + +		xAccum = 0; +		byte *d2 = d; +		col = 0; + +		for (uint16 j = 0; j < q.width(); j++) { +			xAccum += inc; + +			if (xAccum >= thr) { +				xAccum -= thr; +				s++; +				continue; +			} + +			if (*s != transparentColor) { +				byte v = _backgroundInfo->mask.getValue(dp.x + col, dp.y + line); +				if (z >= v) *d2 = *s; +			} + +			s++; +			d2++; +			col++; +		} + +		s += r.width() - q.width(); +		d += surf->w; +		line++; +	} + +} + +void Gfx::bltMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) { +	if (!_backgroundInfo->mask.data || (z == LAYER_FOREGROUND)) { +		// use optimized path +		bltNoMaskNoScale(r, data, surf, transparentColor); +		return; +	} + +	Common::Point dp; +	Common::Rect q(r); + +	Common::Rect clipper(surf->w, surf->h); + +	q.clip(clipper); +	if (!q.isValidRect()) return; + +	dp.x = q.left; +	dp.y = q.top; + +	q.translate(-r.left, -r.top); + +	byte *s = data + q.left + q.top * r.width(); +	byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + +	uint sPitch = r.width() - q.width(); +	uint dPitch = surf->w - q.width(); + +	for (uint16 i = 0; i < q.height(); i++) { + +		for (uint16 j = 0; j < q.width(); j++) { +			if (*s != transparentColor) { +				byte v = _backgroundInfo->mask.getValue(dp.x + j, dp.y + i); +				if (z >= v) *d = *s; +			} + +			s++; +			d++; +		} + +		s += sPitch; +		d += dPitch; +	} + +} + +void Gfx::bltNoMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, byte transparentColor) { +	Common::Point dp; +	Common::Rect q(r); + +	Common::Rect clipper(surf->w, surf->h); + +	q.clip(clipper); +	if (!q.isValidRect()) return; + +	dp.x = q.left; +	dp.y = q.top; + +	q.translate(-r.left, -r.top); + +	byte *s = data + q.left + q.top * r.width(); +	byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + +	uint sPitch = r.width() - q.width(); +	uint dPitch = surf->w - q.width(); + +	for (uint16 i = q.top; i < q.bottom; i++) { +		for (uint16 j = q.left; j < q.right; j++) { +			if (*s != transparentColor) +				*d = *s; + +			s++; +			d++; +		} + +		s += sPitch; +		d += dPitch; +	} +} + + +void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) {  	Common::Point dp;  	Common::Rect q(r); @@ -308,40 +451,7 @@ void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16  		}      } else { -		if (_backgroundInfo->mask.data && (z < LAYER_FOREGROUND)) { - -			for (uint16 i = 0; i < q.height(); i++) { - -				for (uint16 j = 0; j < q.width(); j++) { -					if (*s != transparentColor) { -						byte v = _backgroundInfo->mask.getValue(dp.x + j, dp.y + i); -						if (z >= v) *d = *s; -					} - -					s++; -					d++; -				} - -				s += sPitch; -				d += dPitch; -			} - -		} else { - -			for (uint16 i = q.top; i < q.bottom; i++) { -				for (uint16 j = q.left; j < q.right; j++) { -					if (*s != transparentColor) -						*d = *s; - -					s++; -					d++; -				} - -				s += sPitch; -				d += dPitch; -			} - -		} +    	bltMaskScale(r, data, surf, z, scale, transparentColor);  	}  } diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 1c2cb58b5b..2bd3935f01 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -34,8 +34,9 @@  namespace Parallaction {  // this is the size of the receiving buffer for unpacked frames, -// since BRA uses some insanely big animations. -#define MAXIMUM_UNPACKED_BITMAP_SIZE	640*401 +// since BRA uses some insanely big animations (the largest is +// part0/ani/dino.ani). +#define MAXIMUM_UNPACKED_BITMAP_SIZE	641*401  void Gfx::registerVar(const Common::String &name, int32 initialValue) { @@ -251,7 +252,7 @@ void Gfx::setPalette(Palette pal) {  	byte sysPal[256*4];  	uint n = pal.fillRGBA(sysPal); -	g_system->setPalette(sysPal, 0, n); +	_vm->_system->setPalette(sysPal, 0, n);  }  void Gfx::setBlackPalette() { @@ -327,7 +328,7 @@ void Gfx::drawInventory() {  	_vm->_inventoryRenderer->getRect(r);  	byte *data = _vm->_inventoryRenderer->getData(); -	g_system->copyRectToScreen(data, r.width(), r.left, r.top, r.width(), r.height()); +	_vm->_system->copyRectToScreen(data, r.width(), r.left, r.top, r.width(), r.height());  }  void Gfx::drawItems() { @@ -335,11 +336,11 @@ void Gfx::drawItems() {  		return;  	} -	Graphics::Surface *surf = g_system->lockScreen(); +	Graphics::Surface *surf = _vm->_system->lockScreen();  	for (uint i = 0; i < _numItems; i++) {  		drawGfxObject(_items[i].data, *surf, false);  	} -	g_system->unlockScreen(); +	_vm->_system->unlockScreen();  }  void Gfx::drawBalloons() { @@ -347,15 +348,15 @@ void Gfx::drawBalloons() {  		return;  	} -	Graphics::Surface *surf = g_system->lockScreen(); +	Graphics::Surface *surf = _vm->_system->lockScreen();  	for (uint i = 0; i < _balloons.size(); i++) {  		drawGfxObject(_balloons[i], *surf, false);  	} -	g_system->unlockScreen(); +	_vm->_system->unlockScreen();  }  void Gfx::clearScreen() { -	g_system->clearScreen(); +	_vm->_system->clearScreen();  }  void Gfx::beginFrame() { @@ -377,7 +378,7 @@ void Gfx::beginFrame() {  						*data++ = _backgroundInfo->mask.getValue(x, y);  					}  				} -#if 1 +#if 0  				Common::DumpFile dump;  				dump.open("maskdump.bin");  				dump.write(_bitmapMask.pixels, _bitmapMask.w * _bitmapMask.h); @@ -437,11 +438,11 @@ void Gfx::updateScreen() {  			backgroundPitch = _bitmapMask.pitch;  			break;  		} -		g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->x, _backgroundInfo->y, w, h); +		_vm->_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->x, _backgroundInfo->y, w, h);  	}  	if (_varDrawPathZones == 1) { -		Graphics::Surface *surf = g_system->lockScreen(); +		Graphics::Surface *surf = _vm->_system->lockScreen();  		ZoneList::iterator b = _vm->_location._zones.begin();  		ZoneList::iterator e = _vm->_location._zones.end();  		for (; b != e; b++) { @@ -450,13 +451,13 @@ void Gfx::updateScreen() {  				surf->frameRect(Common::Rect(z->getX(), z->getY(), z->getX() + z->width(), z->getY() + z->height()), 2);  			}  		} -		g_system->unlockScreen(); +		_vm->_system->unlockScreen();  	}  	_varRenderMode = _varAnimRenderMode;  	// TODO: transform objects coordinates to be drawn with scrolling -	Graphics::Surface *surf = g_system->lockScreen(); +	Graphics::Surface *surf = _vm->_system->lockScreen();  	drawGfxObjects(*surf);  	if (_halfbrite) { @@ -480,7 +481,7 @@ void Gfx::updateScreen() {  		}  	} -	g_system->unlockScreen(); +	_vm->_system->unlockScreen();  	_varRenderMode = _varMiscRenderMode; @@ -489,7 +490,7 @@ void Gfx::updateScreen() {  	drawBalloons();  	drawLabels(); -	g_system->updateScreen(); +	_vm->_system->updateScreen();  	return;  } @@ -506,7 +507,7 @@ void Gfx::patchBackground(Graphics::Surface &surf, int16 x, int16 y, bool mask)  	r.moveTo(x, y);  	uint16 z = (mask) ? _backgroundInfo->getLayer(y) : LAYER_FOREGROUND; -	blt(r, (byte*)surf.pixels, &_backgroundInfo->bg, z, 0); +	blt(r, (byte*)surf.pixels, &_backgroundInfo->bg, z, 100, 0);  }  void Gfx::fillBackground(const Common::Rect& r, byte color) { @@ -600,30 +601,41 @@ void Gfx::updateFloatingLabel() {  		return;  	} -	int16 _si, _di; - -	Common::Point	cursor; -	_vm->_input->getCursorPos(cursor); +	struct FloatingLabelTraits { +		Common::Point _offsetWithItem; +		Common::Point _offsetWithoutItem; +		int	_minX; +		int _minY; +		int	_maxX; +		int _maxY; +	} *traits;  	Common::Rect r;  	_labels[_floatingLabel]->getRect(0, r); -	if (_vm->_input->_activeItem._id != 0) { -		_si = cursor.x + 16 - r.width()/2; -		_di = cursor.y + 34; +	if (_vm->getGameType() == GType_Nippon) { +		FloatingLabelTraits traits_NS = { +			Common::Point(16 - r.width()/2, 34), +			Common::Point(8 - r.width()/2, 21), +			0, 0, _vm->_screenWidth - r.width(), 190 +		}; +		traits = &traits_NS;  	} else { -		_si = cursor.x + 8 - r.width()/2; -		_di = cursor.y + 21; +		// FIXME: _maxY for BRA is not constant (390), but depends on _vm->_subtitleY +		FloatingLabelTraits traits_BR = { +			Common::Point(34 - r.width()/2, 70), +			Common::Point(16 - r.width()/2, 37), +			0, 0, _vm->_screenWidth - r.width(), 390 +		}; +		traits = &traits_BR;  	} -	if (_si < 0) _si = 0; -	if (_di > 190) _di = 190; - -	if (r.width() + _si > _vm->_screenWidth) -		_si = _vm->_screenWidth - r.width(); +	Common::Point	cursor; +	_vm->_input->getCursorPos(cursor); +	Common::Point offset = (_vm->_input->_activeItem._id) ? traits->_offsetWithItem : traits->_offsetWithoutItem; -	_labels[_floatingLabel]->x = _si; -	_labels[_floatingLabel]->y = _di; +	_labels[_floatingLabel]->x = CLIP(cursor.x + offset.x, traits->_minX, traits->_maxX); +	_labels[_floatingLabel]->y = CLIP(cursor.y + offset.y, traits->_minY, traits->_maxY);  } @@ -703,13 +715,13 @@ void Gfx::drawLabels() {  	updateFloatingLabel(); -	Graphics::Surface* surf = g_system->lockScreen(); +	Graphics::Surface* surf = _vm->_system->lockScreen();  	for (uint i = 0; i < _labels.size(); i++) {  		drawGfxObject(_labels[i], *surf, false);  	} -	g_system->unlockScreen(); +	_vm->_system->unlockScreen();  } @@ -737,10 +749,10 @@ void Gfx::grabBackground(const Common::Rect& r, Graphics::Surface &dst) {  Gfx::Gfx(Parallaction* vm) :  	_vm(vm), _disk(vm->_disk) { -	g_system->beginGFXTransaction(); -	g_system->initSize(_vm->_screenWidth, _vm->_screenHeight); +	_vm->_system->beginGFXTransaction(); +	_vm->_system->initSize(_vm->_screenWidth, _vm->_screenHeight);  	_vm->initCommonGFX(_vm->getGameType() == GType_BRA); -	g_system->endGFXTransaction(); +	_vm->_system->endGFXTransaction();  	setPalette(_palette); diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 471f71dfa8..ac9f096d7e 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -313,6 +313,7 @@ struct Cnv : public Frames {  	uint16	_height;	//  	byte**	field_8;	// unused  	byte*	_data; +	bool 	_freeData;  public:  	Cnv() { @@ -320,12 +321,14 @@ public:  		_data = NULL;  	} -	Cnv(uint16 numFrames, uint16 width, uint16 height, byte* data) : _count(numFrames), _width(width), _height(height), _data(data) { +	Cnv(uint16 numFrames, uint16 width, uint16 height, byte* data, bool freeData = false) +		: _count(numFrames), _width(width), _height(height), _data(data), _freeData(freeData) {  	}  	~Cnv() { -		free(_data); +		if (_freeData) +			free(_data);  	}  	byte* getFramePtr(uint16 index) { @@ -410,6 +413,7 @@ public:  	uint frame;  	uint layer;  	uint transparentKey; +	uint scale;  	GfxObj(uint type, Frames *frames, const char *name = NULL);  	virtual ~GfxObj(); @@ -495,13 +499,19 @@ enum {  class BalloonManager {  public: +	enum TextColor { +		kSelectedColor = 0, +		kUnselectedColor = 1, +		kNormalColor = 2 +	}; +  	virtual ~BalloonManager() { }  	virtual void freeBalloons() = 0;  	virtual int setLocationBalloon(char *text, bool endGame) = 0; -	virtual int setDialogueBalloon(char *text, uint16 winding, byte textColor) = 0; -	virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) = 0; -	virtual void setBalloonText(uint id, char *text, byte textColor) = 0; +	virtual int setDialogueBalloon(char *text, uint16 winding, TextColor textColor) = 0; +	virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) = 0; +	virtual void setBalloonText(uint id, char *text, TextColor textColor) = 0;  	virtual int hitTestDialogueBalloon(int x, int y) = 0;  }; @@ -640,8 +650,12 @@ public:  	void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color);  	void drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene); -    void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor); -	void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor); +    void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor); +	void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor); + +	void bltMaskScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor); +	void bltMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor); +	void bltNoMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, byte transparentColor);  }; diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index 4343a982bf..4c98cc4634 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -28,6 +28,7 @@  #include "parallaction/gui.h"  #include "parallaction/input.h"  #include "parallaction/parallaction.h" +#include "parallaction/saveload.h"  namespace Parallaction { @@ -40,11 +41,11 @@ protected:  	Palette blackPal;  	Palette pal; -	Parallaction_br *_vm; +	Parallaction *_vm;  	int _fadeSteps;  public: -	SplashInputState_BR(Parallaction_br *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm)  { +	SplashInputState_BR(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm)  {  	}  	virtual MenuInputState* run() { @@ -52,8 +53,6 @@ public:  			pal.fadeTo(blackPal, 1);  			_vm->_gfx->setPalette(pal);  			_fadeSteps--; -			// TODO: properly implement timers to avoid delay calls -			_vm->_system->delayMillis(20);  			return this;  		} @@ -75,7 +74,7 @@ public:  		_vm->showSlide(_slideName.c_str(), CENTER_LABEL_HORIZONTAL, CENTER_LABEL_VERTICAL);  		_vm->_input->setMouseState(MOUSE_DISABLED); -		_startTime = g_system->getMillis(); +		_startTime = _vm->_system->getMillis();  		_fadeSteps = -1;  	}  }; @@ -152,6 +151,8 @@ class MainMenuInputState_BR : public MenuInputState {  	static const char *_menuStrings[NUM_MENULINES];  	static const MenuOptions _options[NUM_MENULINES]; +	static const char *_firstLocation[]; +  	int _availItems;  	int _selection; @@ -166,9 +167,8 @@ class MainMenuInputState_BR : public MenuInputState {  	void performChoice(int selectedItem) {  		switch (selectedItem) { -		case kMenuQuit: { -			_vm->quitGame(); -		} +		case kMenuQuit: +			_engineFlags |= kEngineQuit;  			break;  		case kMenuLoadGame: @@ -176,7 +176,7 @@ class MainMenuInputState_BR : public MenuInputState {  			break;  		default: -			_vm->startPart(selectedItem); +			_vm->scheduleLocationSwitch(_firstLocation[selectedItem]);  		}  	} @@ -221,9 +221,11 @@ public:  		}  		_vm->showSlide("tbra", x, y); -		// TODO: load progress from savefile -		int progress = 3; -		_availItems = 4 + progress; +		_availItems = 4; + +		bool complete[3]; +		_vm->_saveLoad->getGamePartProgress(complete, 3); +		for (int i = 0; i < 3 && complete[i]; i++, _availItems++) ;  		// TODO: keep track of and destroy menu item frames/surfaces  		int i; @@ -233,12 +235,20 @@ public:  			_vm->_gfx->setItemFrame(id, 0);  		}  		_selection = -1; -		_vm->setArrowCursor(); +		_vm->_input->setArrowCursor();  		_vm->_input->setMouseState(MOUSE_ENABLED_SHOW);  	}  }; +const char *MainMenuInputState_BR::_firstLocation[] = { +	"intro.0", +	"museo.1", +	"start.2", +	"bolscoi.3", +	"treno.4" +}; +  const char *MainMenuInputState_BR::_menuStrings[NUM_MENULINES] = {  	"SEE INTRO",  	"NEW GAME", @@ -265,29 +275,24 @@ const MainMenuInputState_BR::MenuOptions MainMenuInputState_BR::_options[NUM_MEN -void Parallaction_br::startGui() { +void Parallaction_br::startGui(bool showSplash) {  	_menuHelper = new MenuInputHelper; -	new SplashInputState0_BR(this, _menuHelper); -	new SplashInputState1_BR(this, _menuHelper); -	new MainMenuInputState_BR(this, _menuHelper); -	_menuHelper->setState("intro0"); -	_input->_inputMode = Input::kInputModeMenu; - -	do { -		_input->readInput(); -		if (!_menuHelper->run()) break; -		_gfx->beginFrame(); -		_gfx->updateScreen(); -	} while (true); +	new MainMenuInputState_BR(this, _menuHelper); -	delete _menuHelper; -	_menuHelper = 0; +	if (showSplash) { +		new SplashInputState0_BR(this, _menuHelper); +		new SplashInputState1_BR(this, _menuHelper); +		_menuHelper->setState("intro0"); +	} else { +		_menuHelper->setState("mainmenu"); +	} -	_input->_inputMode = Input::kInputModeGame; +	_input->_inputMode = Input::kInputModeMenu;  } +  } // namespace Parallaction diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp index e6f86a1a0a..d172c30103 100644 --- a/engines/parallaction/gui_ns.cpp +++ b/engines/parallaction/gui_ns.cpp @@ -23,13 +23,13 @@   *   */ -#include "common/config-manager.h"  #include "common/system.h"  #include "common/hashmap.h"  #include "parallaction/gui.h"  #include "parallaction/input.h"  #include "parallaction/parallaction.h" +#include "parallaction/saveload.h"  #include "parallaction/sound.h" @@ -42,14 +42,14 @@ protected:  	Common::String _nextState;  	uint32	_startTime; -	Parallaction_ns *_vm; +	Parallaction *_vm;  public: -	SplashInputState_NS(Parallaction_ns *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm)  { +	SplashInputState_NS(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm)  {  	}  	virtual MenuInputState* run() { -		uint32 curTime = g_system->getMillis(); +		uint32 curTime = _vm->_system->getMillis();  		if (curTime - _startTime > _timeOut) {  			_vm->freeBackground();  			return _helper->getState(_nextState); @@ -60,14 +60,14 @@ public:  	virtual void enter() {  		_vm->_input->setMouseState(MOUSE_DISABLED);  		_vm->showSlide(_slideName.c_str()); -		_startTime = g_system->getMillis(); +		_startTime = _vm->_system->getMillis();  	}  };  class SplashInputState0_NS : public SplashInputState_NS {  public: -	SplashInputState0_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro0", helper)  { +	SplashInputState0_NS(Parallaction *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro0", helper)  {  		_slideName = "intro";  		_timeOut = 2000;  		_nextState = "intro1"; @@ -77,7 +77,7 @@ public:  class SplashInputState1_NS : public SplashInputState_NS {  public: -	SplashInputState1_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro1", helper) { +	SplashInputState1_NS(Parallaction *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro1", helper) {  		_slideName = "minintro";  		_timeOut = 2000;  		_nextState = "chooselanguage"; @@ -112,14 +112,12 @@ class ChooseLanguageInputState_NS : public MenuInputState {  	static const Common::Rect _amigaLanguageSelectBlocks[4];  	const Common::Rect *_blocks; -	Parallaction_ns *_vm; +	Parallaction *_vm;  public: -	ChooseLanguageInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) { +	ChooseLanguageInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) {  		_allowChoice = false; -	 -		if (ConfMan.getInt("save_slot") < 0 || ConfMan.getInt("save_slot") > 99) -			_nextState = "selectgame"; +		_nextState = "selectgame";  		if (_vm->getPlatform() == Common::kPlatformAmiga) {  			if (!(_vm->getFeatures() & GF_LANG_MULT)) { @@ -181,7 +179,7 @@ public:  		uint id = _vm->_gfx->createLabel(_vm->_introFont, "SELECT LANGUAGE", 1);  		_vm->_gfx->showLabel(id, 60, 30); -		_vm->setArrowCursor(); +		_vm->_input->setArrowCursor();  	}  }; @@ -206,13 +204,13 @@ class SelectGameInputState_NS : public MenuInputState {  	uint	_labels[2]; -	Parallaction_ns *_vm; +	Parallaction *_vm;  	static const char *newGameMsg[4];  	static const char *loadGameMsg[4];  public: -	SelectGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) { +	SelectGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) {  		_choice = 0;  		_oldChoice = -1; @@ -274,10 +272,10 @@ const char *SelectGameInputState_NS::loadGameMsg[4] = {  class LoadGameInputState_NS : public MenuInputState {  	bool _result; -	Parallaction_ns *_vm; +	Parallaction *_vm;  public: -	LoadGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { } +	LoadGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { }  	virtual MenuInputState* run() {  		if (!_result) { @@ -287,19 +285,19 @@ public:  	}  	virtual void enter() { -		_result = _vm->loadGame(); +		_result = _vm->_saveLoad->loadGame();  	}  };  class NewGameInputState_NS : public MenuInputState { -	Parallaction_ns *_vm; +	Parallaction *_vm;  	static const char *introMsg3[4];  public: -	NewGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) { +	NewGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) {  	}  	virtual MenuInputState* run() { @@ -347,14 +345,15 @@ const char *NewGameInputState_NS::introMsg3[4] = {  class StartDemoInputState_NS : public MenuInputState { -	Parallaction_ns *_vm; +	Parallaction *_vm;  public: -	StartDemoInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) { +	StartDemoInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) {  	}  	virtual MenuInputState* run() {  		_vm->scheduleLocationSwitch("fognedemo.dough"); +		_vm->_input->setMouseState(MOUSE_ENABLED_SHOW);  		return 0;  	} @@ -374,7 +373,7 @@ class SelectCharacterInputState_NS : public MenuInputState {  	static const Common::Rect codeSelectBlocks[9];  	static const Common::Rect codeTrueBlocks[9]; -	Parallaction_ns *_vm; +	Parallaction *_vm;  	int guiGetSelectedBlock(const Common::Point &p) { @@ -391,7 +390,7 @@ class SelectCharacterInputState_NS : public MenuInputState {  			_vm->_gfx->invertBackground(codeTrueBlocks[selection]);  			_vm->_gfx->updateScreen();  			_vm->beep(); -			g_system->delayMillis(100); +			_vm->_system->delayMillis(100);  			_vm->_gfx->invertBackground(codeTrueBlocks[selection]);  			_vm->_gfx->updateScreen();  		} @@ -427,7 +426,7 @@ class SelectCharacterInputState_NS : public MenuInputState {  public: -	SelectCharacterInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) { +	SelectCharacterInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) {  		_keys = (_vm->getPlatform() == Common::kPlatformAmiga && (_vm->getFeatures() & GF_LANG_MULT)) ? _amigaKeys : _pcKeys;  		_block.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1);  	} @@ -446,7 +445,7 @@ public:  	}  	void delay() { -		if (g_system->getMillis() - _startTime < 2000) { +		if (_vm->_system->getMillis() - _startTime < 2000) {  			return;  		}  		cleanup(); @@ -488,7 +487,7 @@ public:  		_vm->_gfx->patchBackground(_emptySlots, SLOT_X, SLOT_Y, false);  		_vm->_gfx->hideLabel(_labels[0]);  		_vm->_gfx->showLabel(_labels[1], 60, 30); -		_startTime = g_system->getMillis(); +		_startTime = _vm->_system->getMillis();  		_state = DELAY;  	} @@ -511,7 +510,6 @@ public:  			error("If you read this, either your CPU or transivity is broken (we believe the former).");  		} -		_vm->_inTestResult = false;  		_vm->cleanupGame();  		_vm->scheduleLocationSwitch(_charStartLocation[character]);  	} @@ -558,7 +556,7 @@ public:  		cleanup(); -		_vm->setArrowCursor(); +		_vm->_input->setArrowCursor();  		_vm->_input->setMouseState(MOUSE_ENABLED_SHOW);  		_state = CHOICE;  	} @@ -623,7 +621,7 @@ const Common::Rect SelectCharacterInputState_NS::codeTrueBlocks[9] = {  class ShowCreditsInputState_NS : public MenuInputState { -	Parallaction_ns *_vm; +	Parallaction *_vm;  	int	_current;  	uint32 _startTime; @@ -635,7 +633,7 @@ class ShowCreditsInputState_NS : public MenuInputState {  	static const Credit _credits[6];  public: -	ShowCreditsInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) { +	ShowCreditsInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) {  	}  	void drawCurrentLabel() { @@ -649,14 +647,14 @@ public:  	virtual MenuInputState* run() {  		if (_current == -1) { -			_startTime = g_system->getMillis(); +			_startTime = _vm->_system->getMillis();  			_current = 0;  			drawCurrentLabel();  			return this;  		}  		int event = _vm->_input->getLastButtonEvent(); -		uint32 curTime = g_system->getMillis(); +		uint32 curTime = _vm->_system->getMillis();  		if ((event == kMouseLeftUp) || (curTime - _startTime > 5500)) {  			_current++;  			_startTime = curTime; @@ -688,11 +686,11 @@ const ShowCreditsInputState_NS::Credit ShowCreditsInputState_NS::_credits[6] = {  };  class EndIntroInputState_NS : public MenuInputState { -	Parallaction_ns *_vm; +	Parallaction *_vm;  	bool _isDemo;  public: -	EndIntroInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) { +	EndIntroInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) {  		_isDemo = (_vm->getFeatures() & GF_DEMO) != 0;  	} @@ -704,7 +702,7 @@ public:  		}  		if (_isDemo) { -			_vm->quitGame(); +			_engineFlags |= kEngineQuit;  			return 0;  		} @@ -725,7 +723,7 @@ public:  class EndPartInputState_NS : public MenuInputState { -	Parallaction_ns *_vm; +	Parallaction *_vm;  	bool _allPartsComplete;  	// part completion messages @@ -741,7 +739,7 @@ class EndPartInputState_NS : public MenuInputState {  public: -	EndPartInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) { +	EndPartInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) {  	}  	virtual MenuInputState* run() { @@ -761,20 +759,23 @@ public:  	}  	virtual void enter() { -		_allPartsComplete = _vm->allPartsComplete(); +		bool completed[3]; +		_vm->_saveLoad->getGamePartProgress(completed, 3); +		_allPartsComplete = (completed[0] && completed[1] && completed[2]);  		_vm->_input->setMouseState(MOUSE_DISABLED); +		uint16 language = _vm->getInternLanguage();  		uint id[4];  		if (_allPartsComplete) { -			id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg4[_language], 1); -			id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg5[_language], 1); -			id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg6[_language], 1); -			id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg7[_language], 1); +			id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg4[language], 1); +			id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg5[language], 1); +			id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg6[language], 1); +			id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg7[language], 1);  		} else { -			id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg0[_language], 1); -			id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg1[_language], 1); -			id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg2[_language], 1); -			id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg3[_language], 1); +			id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg0[language], 1); +			id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg1[language], 1); +			id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg2[language], 1); +			id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg3[language], 1);  		}  		_vm->_gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 70); diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 19747c007e..98198b88f7 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -31,6 +31,58 @@  namespace Parallaction { +#define MOUSEARROW_WIDTH_NS		16 +#define MOUSEARROW_HEIGHT_NS		16 + +#define MOUSECOMBO_WIDTH_NS		32	// sizes for cursor + selected inventory item +#define MOUSECOMBO_HEIGHT_NS		32 + +struct MouseComboProperties { +	int	_xOffset; +	int	_yOffset; +	int	_width; +	int	_height; +}; +/* +// TODO: improve NS's handling of normal cursor before merging cursor code. +MouseComboProperties	_mouseComboProps_NS = { +	7,	// combo x offset (the icon from the inventory will be rendered from here) +	7,	// combo y offset (ditto) +	32,	// combo (arrow + icon) width +	32	// combo (arrow + icon) height +}; +*/ +MouseComboProperties	_mouseComboProps_BR = { +	8,	// combo x offset (the icon from the inventory will be rendered from here) +	8,	// combo y offset (ditto) +	68,	// combo (arrow + icon) width +	68	// combo (arrow + icon) height +}; + +Input::Input(Parallaction *vm) : _vm(vm) { +	_gameType = _vm->getGameType(); +	_transCurrentHoverItem = 0; +	_hasDelayedAction = false;  // actived when the character needs to move before taking an action +	_mouseState = MOUSE_DISABLED; +	_activeItem._index = 0; +	_activeItem._id = 0; +	_mouseButtons = 0; +	_delayedActionZone = nullZonePtr; + +	initCursors(); +} + +Input::~Input() { +	if (_gameType == GType_Nippon) { +		delete _mouseArrow; +	} + +	delete _comboArrow; +	delete _dinoCursor; +	delete _dougCursor; +	delete _donnaCursor; +} +  // FIXME: the engine has 3 event loops. The following routine hosts the main one,  // and it's called from 8 different places in the code. There exist 2 more specialised  // loops which could possibly be merged into this one with some effort in changing @@ -78,9 +130,9 @@ void Input::readInput() {  		case Common::EVENT_MOUSEMOVE:  			_mousePos = e.mouse;  			break; -		case Common::EVENT_RTL: +  		case Common::EVENT_QUIT: -			_vm->_quit = true; +			_engineFlags |= kEngineQuit;  			return;  		default: @@ -127,9 +179,9 @@ void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) {  } -void Input::updateGameInput() { +int Input::updateGameInput() { -	readInput(); +	int event = kEvNone;  	if (!isMouseEnabled() ||  		(_engineFlags & kEngineWalking) || @@ -141,44 +193,38 @@ void Input::updateGameInput() {  			(_engineFlags & kEngineChangeLocation) == 0  		); -		return; +		return event;  	}  	if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) { -		if (_keyPressed.keycode == Common::KEYCODE_l) _inputData._event = kEvLoadGame; -		if (_keyPressed.keycode == Common::KEYCODE_s) _inputData._event = kEvSaveGame; +		if (_keyPressed.keycode == Common::KEYCODE_l) event = kEvLoadGame; +		if (_keyPressed.keycode == Common::KEYCODE_s) event = kEvSaveGame;  	} -	if (_inputData._event == kEvNone) { -		_inputData._mousePos = _mousePos; +	if (event == kEvNone) {  		translateGameInput();  	} +	return event;  } -InputData* Input::updateInput() { +int Input::updateInput() { -	_inputData._event = kEvNone; +	int event = kEvNone; +	readInput();  	switch (_inputMode) { -	case kInputModeComment: -	case kInputModeDialogue: -	case kInputModeMenu: -		readInput(); -		break; -  	case kInputModeGame: -		updateGameInput(); +		event = updateGameInput();  		break;  	case kInputModeInventory: -		readInput();  		updateInventoryInput();  		break;  	} -	return &_inputData; +	return event;  }  void Input::trackMouse(ZonePtr z) { @@ -212,7 +258,7 @@ void Input::takeAction(ZonePtr z) {  void Input::walkTo(const Common::Point &dest) {  	stopHovering(); -	_vm->setArrowCursor(); +	setArrowCursor();  	_vm->_char.scheduleWalk(dest.x, dest.y);  } @@ -252,7 +298,6 @@ bool Input::translateGameInput() {  	if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) { -		_inputData._zone = z;  		if (z->_flags & kFlagsNoWalk) {  			// character doesn't need to walk to take specified action  			takeAction(z); @@ -269,7 +314,7 @@ bool Input::translateGameInput() {  		}  		_vm->beep(); -		_vm->setArrowCursor(); +		setArrowCursor();  		return true;  	} @@ -285,7 +330,7 @@ void Input::enterInventoryMode() {  			_activeItem._index = (_activeItem._id >> 16) & 0xFFFF;  			_engineFlags |= kEngineDragging;  		} else { -			_vm->setArrowCursor(); +			setArrowCursor();  		}  	} @@ -320,12 +365,12 @@ void Input::exitInventoryMode() {  	_vm->closeInventory();  	if (pos == -1) { -		_vm->setArrowCursor(); +		setArrowCursor();  	} else {  		const InventoryItem *item = _vm->getInventoryItem(pos);  		if (item->_index != 0) {  			_activeItem._id = item->_id; -			_vm->setInventoryCursor(item->_index); +			setInventoryCursor(item->_index);  		}  	}  	_vm->resumeJobs(); @@ -373,4 +418,96 @@ bool Input::isMouseEnabled() {  	return (_mouseState == MOUSE_ENABLED_SHOW) || (_mouseState == MOUSE_ENABLED_HIDE);  } + +void Input::initCursors() { + +	_dinoCursor = _donnaCursor = _dougCursor = 0; + +	switch (_gameType) { +	case GType_Nippon: +		_comboArrow = _vm->_disk->loadPointer("pointer"); +		_mouseArrow = new Cnv(1, MOUSEARROW_WIDTH_NS, MOUSEARROW_HEIGHT_NS, _resMouseArrow_NS, false); +		break; + +	case GType_BRA: +		if (_vm->getPlatform() == Common::kPlatformPC) { +			_dinoCursor = _vm->_disk->loadPointer("pointer1"); +			_dougCursor = _vm->_disk->loadPointer("pointer2"); +			_donnaCursor = _vm->_disk->loadPointer("pointer3"); + +			Graphics::Surface *surf = new Graphics::Surface; +			surf->create(_mouseComboProps_BR._width, _mouseComboProps_BR._height, 1); +			_comboArrow = new SurfaceToFrames(surf); + +			// TODO: choose the pointer depending on the active character +			// For now, we pick Donna's +			_mouseArrow = _donnaCursor; +		} else { +			// TODO: Where are the Amiga cursors? +			_mouseArrow = 0; +		} +		break; + +	default: +		warning("Input::initCursors: unknown gametype"); +	} + +} + +void Input::setArrowCursor() { + +	switch (_gameType) { +	case GType_Nippon: +		debugC(1, kDebugInput, "setting mouse cursor to arrow"); +		// this stuff is needed to avoid artifacts with labels and selected items when switching cursors +		stopHovering(); +		_activeItem._id = 0; +		_vm->_system->setMouseCursor(_mouseArrow->getData(0), MOUSEARROW_WIDTH_NS, MOUSEARROW_HEIGHT_NS, 0, 0, 0); +		break; + +	case GType_BRA: { +		if (_vm->getPlatform() == Common::kPlatformAmiga) +			return; + +		Common::Rect r; +		_mouseArrow->getRect(0, r); +		_vm->_system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0); +		_vm->_system->showMouse(true); +		_activeItem._id = 0; +		break; +	} + +	default: +		warning("Input::setArrowCursor: unknown gametype"); +	} + +} + +void Input::setInventoryCursor(ItemName name) { +	assert(name > 0); + +	switch (_gameType) { +	case GType_Nippon: { +		byte *v8 = _comboArrow->getData(0); +		// FIXME: destination offseting is not clear +		_vm->_inventoryRenderer->drawItem(name, v8 + 7 * MOUSECOMBO_WIDTH_NS + 7, MOUSECOMBO_WIDTH_NS); +		_vm->_system->setMouseCursor(v8, MOUSECOMBO_WIDTH_NS, MOUSECOMBO_HEIGHT_NS, 0, 0, 0); +		break; +	} + +	case GType_BRA: { +		byte *src = _mouseArrow->getData(0); +		byte *dst = _comboArrow->getData(0); +		memcpy(dst, src, _comboArrow->getSize(0)); +		// FIXME: destination offseting is not clear +		_vm->_inventoryRenderer->drawItem(name, dst + _mouseComboProps_BR._yOffset * _mouseComboProps_BR._width + _mouseComboProps_BR._xOffset, _mouseComboProps_BR._width); +		_vm->_system->setMouseCursor(dst, _mouseComboProps_BR._width, _mouseComboProps_BR._height, 0, 0, 0); +	} + +	default: +		warning("Input::setInventoryCursor: unknown gametype"); +	} + +} +  } // namespace Parallaction diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index c1e912db74..e7d20c0d2e 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -41,14 +41,6 @@ enum {  	kMouseRightDown		= 8  }; -struct InputData { -	uint16			_event; -	Common::Point	_mousePos; -	int16		_inventoryIndex; -	ZonePtr		_zone; -	uint		_label; -}; -  enum MouseTriState {  	MOUSE_ENABLED_SHOW,  	MOUSE_ENABLED_HIDE, @@ -56,10 +48,7 @@ enum MouseTriState {  };  class Input { -	void updateGameInput(); - -	// input-only -	InputData	_inputData; +	int 		updateGameInput();  	bool		_hasKeyPressEvent;  	Common::KeyState _keyPressed; @@ -69,7 +58,7 @@ class Input {  	int16		_transCurrentHoverItem; -	InputData	*translateInput(); +	void		translateInput();  	bool		translateGameInput();  	bool		updateInventoryInput();  	void 		takeAction(ZonePtr z); @@ -85,6 +74,17 @@ class Input {  	void	enterInventoryMode();  	void 	exitInventoryMode(); +	int		_gameType; + +	static byte _resMouseArrow_NS[256]; +	Frames	*_mouseArrow; +	Frames	*_comboArrow; +	Frames	*_dinoCursor; +	Frames	*_dougCursor; +	Frames	*_donnaCursor; + +	void initCursors(); +  public:  	enum {  		kInputModeGame = 0, @@ -95,18 +95,8 @@ public:  	}; -	Input(Parallaction *vm) : _vm(vm) { -		_transCurrentHoverItem = 0; -		_hasDelayedAction = false;  // actived when the character needs to move before taking an action -		_mouseState = MOUSE_DISABLED; -		_activeItem._index = 0; -		_activeItem._id = 0; -		_mouseButtons = 0; -		_delayedActionZone = nullZonePtr; -	} - -	virtual ~Input() { } - +	Input(Parallaction *vm); +	virtual ~Input();  	void			getCursorPos(Common::Point& p) {  		p = _mousePos; @@ -116,7 +106,7 @@ public:  	InventoryItem	_activeItem;  	void	readInput(); -	InputData* 	updateInput(); +	int 	updateInput();  	void	trackMouse(ZonePtr z);  	void	waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1);  	uint32	getLastButtonEvent() { return _mouseButtons; } @@ -129,6 +119,9 @@ public:  	void setMouseState(MouseTriState state);  	MouseTriState getMouseState();  	bool isMouseEnabled(); + +	void setArrowCursor(); +	void setInventoryCursor(ItemName name);  };  } // namespace Parallaction diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp index d2332643ed..b4776250c6 100644 --- a/engines/parallaction/objects.cpp +++ b/engines/parallaction/objects.cpp @@ -180,7 +180,6 @@ Zone::~Zone() {  	case kZoneDoor:  		free(u.door->_location); -		free(u.door->_background);  		u.door->gfxobj->release();  		delete u.door;  		break; @@ -191,7 +190,6 @@ Zone::~Zone() {  		break;  	case kZoneGet: -		free(u.get->_backup);  		u.get->gfxobj->release();  		delete u.get;  		break; diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index f66e602f68..eee69383b6 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -192,23 +192,19 @@ struct Dialogue {  	~Dialogue();  }; -struct GetData {	// size = 24 +struct GetData {  	uint32			_icon;  	GfxObj			*gfxobj; -	byte		   *_backup; -	uint16			field_14;		// unused -	uint16			field_16;		// unused  	MaskBuffer		_mask[2];  	bool			hasMask;  	GetData() {  		_icon = 0; -		_backup = NULL;  		gfxobj = NULL;  		hasMask = false;  	}  }; -struct SpeakData {	// size = 36 +struct SpeakData {  	char		_name[32];  	Dialogue	*_dialogue; @@ -217,30 +213,25 @@ struct SpeakData {	// size = 36  		_dialogue = NULL;  	}  }; -struct ExamineData {	// size = 28 +struct ExamineData {  	GfxObj	*_cnv; -	uint16		_opBase;		   // unused -	uint16		field_12;			// unused  	char*		_description;  	char*		_filename;  	ExamineData() { -		_opBase = 0;  		_description = NULL;  		_filename = NULL;  		_cnv = NULL;  	}  }; -struct DoorData {	// size = 28 +struct DoorData {  	char*	_location;  	GfxObj	*gfxobj; -	byte*	_background;  	Common::Point	_startPos;  	uint16	_startFrame;  	DoorData() {  		_location = NULL; -		_background = NULL;  		_startFrame = 0;  		gfxobj = NULL;  	} diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index afa246a9f8..f69e39519c 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -35,6 +35,7 @@  #include "parallaction/input.h"  #include "parallaction/parallaction.h"  #include "parallaction/debug.h" +#include "parallaction/saveload.h"  #include "parallaction/sound.h" @@ -47,7 +48,6 @@ Parallaction *_vm = NULL;  // public stuff  char		_saveData1[30] = { '\0' }; -uint16		_language = 0;  uint32		_engineFlags = 0;  uint16		_score = 1; @@ -100,8 +100,6 @@ Parallaction::~Parallaction() {  	cleanupGui(); -	delete _comboArrow; -  	delete _localFlagNames;  	delete _gfx;  	delete _soundMan; @@ -116,17 +114,13 @@ int Parallaction::init() {  	_objectsNames = NULL;  	_globalFlagsNames = NULL;  	_location._hasSound = false; -	_baseTime = 0;  	_numLocations = 0; -	_gameToLoad = -1;  	_location._startPosition.x = -1000;  	_location._startPosition.y = -1000;  	_location._startFrame = 0;  	_location._comment = NULL;  	_location._endComment = NULL; -	_quit = false; -	  	_pathBuffer = 0;  	_screenSize = _screenWidth * _screenHeight; @@ -137,6 +131,7 @@ int Parallaction::init() {  	initInventory();	// needs to be pushed into subclass +	// this needs _disk to be already setup  	_input = new Input(this);  	_gfx = new Gfx(this); @@ -146,19 +141,10 @@ int Parallaction::init() {  	_menuHelper = 0;  	setupBalloonManager(); -	syncSoundSettings();  	return 0;  } - -void Parallaction::clearSet(OpcodeSet &opcodes) { -	for (Common::Array<const Opcode*>::iterator i = opcodes.begin(); i != opcodes.end(); ++i) -		delete *i; -	opcodes.clear(); -} - -  void Parallaction::updateView() {  	if ((_engineFlags & kEnginePauseJobs) && (_input->_inputMode != Input::kInputModeInventory)) { @@ -167,7 +153,7 @@ void Parallaction::updateView() {  	_gfx->animatePalette();  	_gfx->updateScreen(); -	g_system->delayMillis(30); +	_vm->_system->delayMillis(30);  } @@ -282,7 +268,15 @@ void Parallaction::freeLocation() {  	return;  } +void Parallaction::showSlide(const char *name, int x, int y) { +	BackgroundInfo *info = new BackgroundInfo; +	_disk->loadSlide(*info, name); +	info->x = (x == CENTER_LABEL_HORIZONTAL) ? ((_vm->_screenWidth - info->width) >> 1) : x; +	info->y = (y == CENTER_LABEL_VERTICAL) ? ((_vm->_screenHeight - info->height) >> 1) : y; + +	_gfx->setBackground(kBackgroundSlide, info); +}  void Parallaction::freeBackground() { @@ -307,23 +301,19 @@ void Parallaction::showLocationComment(const char *text, bool end) {  } -void Parallaction::processInput(InputData *data) { -	if (!data) { -		return; -	} - -	switch (data->_event) { +void Parallaction::processInput(int event) { +	switch (event) {  	case kEvSaveGame:  		_input->stopHovering(); -		saveGame(); -		setArrowCursor(); +		_saveLoad->saveGame(); +		_input->setArrowCursor();  		break;  	case kEvLoadGame:  		_input->stopHovering(); -		loadGame(); -		setArrowCursor(); +		_saveLoad->loadGame(); +		_input->setArrowCursor();  		break;  	} @@ -333,22 +323,19 @@ void Parallaction::processInput(InputData *data) {  void Parallaction::runGame() { -	InputData *data = _input->updateInput(); -	if (_vm->quit()) +	int event = _input->updateInput(); +	if (_engineFlags & kEngineQuit)  		return;  	runGuiFrame();  	runDialogueFrame();  	runCommentFrame(); -	if (_vm->quit()) -		return; -  	if (_input->_inputMode == Input::kInputModeGame) { -		processInput(data); +		processInput(event);  		runPendingZones(); -		if (_vm->quit()) +		if (_engineFlags & kEngineQuit)  			return;  		if (_engineFlags & kEngineChangeLocation) { @@ -411,7 +398,7 @@ void Parallaction::doLocationEnterTransition() {  		pal.fadeTo(_gfx->_palette, 4);  		_gfx->setPalette(pal);  		_gfx->updateScreen(); -		g_system->delayMillis(20); +		_vm->_system->delayMillis(20);  	}  	_gfx->setPalette(_gfx->_palette); @@ -439,6 +426,387 @@ uint32 Parallaction::getLocationFlags() { +void Parallaction::drawAnimations() { +	debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n"); + +	uint16 layer = 0, scale = 100; + +	for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) { + +		AnimationPtr anim = *it; +		GfxObj *obj = anim->gfxobj; + +		// Validation is performed here, so that every animation is affected, instead that only the ones +		// who *own* a script. In fact, some scripts can change values in other animations. +		// The right way to do this would be to enforce validation when any variable is modified from +		// a script. +		anim->validateScriptVars(); + +		if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0))   { + +			if (anim->_flags & kFlagsNoMasked) +				layer = LAYER_FOREGROUND; +			else { +				if (getGameType() == GType_Nippon) { +					// Layer in NS depends on where the animation is on the screen, for each animation. +					layer = _gfx->_backgroundInfo->getLayer(anim->getFrameY() + anim->height()); +				} else { +					// Layer in BRA is calculated from Z value. For characters it is the same as NS, +					// but other animations can have Z set from scripts independently from their +					// position on the screen. +					layer = _gfx->_backgroundInfo->getLayer(anim->getZ()); +				} +			} + +			if (getGameType() == GType_BRA) { +				if (anim->_flags & (kFlagsScaled | kFlagsCharacter)) { +					if (anim->getZ() <= _location._zeta0) { +						if (anim->getZ() >= _location._zeta1) { +							scale = ((anim->getZ() - _location._zeta1) * (100 - _location._zeta2)) / (_location._zeta0 - _location._zeta1) + _location._zeta2; +						} else { +							scale = _location._zeta2; +						} +					} +				} +			} + +			if (obj) { +				_gfx->showGfxObj(obj, true); +				obj->frame = anim->getF(); +				obj->x = anim->getX(); +				obj->y = anim->getY(); +				obj->z = anim->getZ(); +				obj->layer = layer; +				obj->scale = scale; +			} +		} + +		if (((anim->_flags & kFlagsActive) == 0) && (anim->_flags & kFlagsRemove))   { +			anim->_flags &= ~kFlagsRemove; +		} + +		if ((anim->_flags & kFlagsActive) && (anim->_flags & kFlagsRemove))	{ +			anim->_flags &= ~kFlagsActive; +			anim->_flags |= kFlagsRemove; +			if (obj) { +				_gfx->showGfxObj(obj, false); +			} +		} +	} + +	debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n"); + +	return; +} + + +void Parallaction::showZone(ZonePtr z, bool visible) { +	if (!z) { +		return; +	} + +	if (visible) { +		z->_flags &= ~kFlagsRemove; +		z->_flags |= kFlagsActive; +	} else { +		z->_flags |= kFlagsRemove; +	} + +	if ((z->_type & 0xFFFF) == kZoneGet) { +		_gfx->showGfxObj(z->u.get->gfxobj, visible); + +		GetData *data = z->u.get; +		if (data->hasMask && _gfx->_backgroundInfo->hasMask) { +			if (visible) { +				_gfx->_backgroundInfo->mask.bltOr(data->gfxobj->x, data->gfxobj->y, data->_mask[0], 0, 0, data->_mask->w, data->_mask->h); +			} else { +				_gfx->_backgroundInfo->mask.bltCopy(data->gfxobj->x, data->gfxobj->y, data->_mask[1], 0, 0, data->_mask->w, data->_mask->h); +			} +		} +	} +} + + +// +//	ZONE TYPE: EXAMINE +// + +void Parallaction::enterCommentMode(ZonePtr z) { +	if (!z) { +		return; +	} + +	_commentZone = z; + +	ExamineData *data = _commentZone->u.examine; + +	if (!data->_description) { +		return; +	} + +	// TODO: move this balloons stuff into DialogueManager and BalloonManager +	if (getGameType() == GType_Nippon) { +		int id; +		if (data->_filename) { +			if (data->_cnv == 0) { +				data->_cnv = _disk->loadStatic(data->_filename); +			} + +			_gfx->setHalfbriteMode(true); +			_balloonMan->setSingleBalloon(data->_description, 0, 90, 0, BalloonManager::kNormalColor); +			Common::Rect r; +			data->_cnv->getRect(0, r); +			id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2); +			_gfx->setItemFrame(id, 0); +			id = _gfx->setItem(_char._head, 100, 152); +			_gfx->setItemFrame(id, 0); +		} else { +			_balloonMan->setSingleBalloon(data->_description, 140, 10, 0, BalloonManager::kNormalColor); +			id = _gfx->setItem(_char._talk, 190, 80); +			_gfx->setItemFrame(id, 0); +		} +	} else +	if (getGameType() == GType_BRA) { +		_balloonMan->setSingleBalloon(data->_description, 0, 0, 1, BalloonManager::kNormalColor); +		int id = _gfx->setItem(_char._talk, 10, 80); +		_gfx->setItemFrame(id, 0); +	} + +	_input->_inputMode = Input::kInputModeComment; +} + +void Parallaction::exitCommentMode() { +	_input->_inputMode = Input::kInputModeGame; + +	hideDialogueStuff(); +	_gfx->setHalfbriteMode(false); + +	_cmdExec->run(_commentZone->_commands, _commentZone); +	_commentZone = nullZonePtr; +} + +void Parallaction::runCommentFrame() { +	if (_input->_inputMode != Input::kInputModeComment) { +		return; +	} + +	if (_input->getLastButtonEvent() == kMouseLeftUp) { +		exitCommentMode(); +	} +} + + +void Parallaction::runZone(ZonePtr z) { +	debugC(3, kDebugExec, "runZone (%s)", z->_name); + +	uint16 subtype = z->_type & 0xFFFF; + +	debugC(3, kDebugExec, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16); +	switch(subtype) { + +	case kZoneExamine: +		enterCommentMode(z); +		return; + +	case kZoneGet: +		pickupItem(z); +		break; + +	case kZoneDoor: +		if (z->_flags & kFlagsLocked) break; +		updateDoor(z, !(z->_flags & kFlagsClosed)); +		break; + +	case kZoneHear: +		_soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60); +		break; + +	case kZoneSpeak: +		enterDialogueMode(z); +		return; +	} + +	debugC(3, kDebugExec, "runZone completed"); + +	_cmdExec->run(z->_commands, z); + +	return; +} + +// +//	ZONE TYPE: DOOR +// +void Parallaction::updateDoor(ZonePtr z, bool close) { +	z->_flags = close ? (z->_flags |= kFlagsClosed) : (z->_flags &= ~kFlagsClosed); + +	if (z->u.door->gfxobj) { +		uint frame = (close ? 0 : 1); +//		z->u.door->gfxobj->setFrame(frame); +		z->u.door->gfxobj->frame = frame; +	} + +	return; +} + + + +// +//	ZONE TYPE: GET +// + +bool Parallaction::pickupItem(ZonePtr z) { +	if (z->_flags & kFlagsFixed) { +		return false; +	} + +	int slot = addInventoryItem(z->u.get->_icon); +	if (slot != -1) { +		showZone(z, false); +	} + +	return (slot != -1); +} + +// FIXME: input coordinates must be offseted to handle scrolling! +bool Parallaction::checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y) { +	// not a special zone +	if ((z->getX() != -2) && (z->getX() != -3)) { +		return false; +	} + +	// WORKAROUND: this huge condition is needed because we made TypeData a collection of structs +	// instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, +	// but we need to check it separately here. The same workaround is applied in freeZones. +	if ((((z->_type & 0xFFFF) == kZoneMerge) && (((x == z->u.merge->_obj1) && (y == z->u.merge->_obj2)) || ((x == z->u.merge->_obj2) && (y == z->u.merge->_obj1)))) || +		(((z->_type & 0xFFFF) == kZoneGet) && ((x == z->u.get->_icon) || (y == z->u.get->_icon)))) { + +		// WORKAROUND for bug 2070751: special zones are only used in NS, to allow the +		// the EXAMINE/USE action to be applied on some particular item in the inventory. +		// The usage a verb requires at least an item match, so type can't be 0, as it +		// was in the original code. This bug has been here since the beginning, and was +		// hidden by label code, which filtered the bogus matches produced here. + +		// look for action + item match +		if (z->_type == type) +			return true; +		// look for item match, but don't accept 0 types +		if (((z->_type & 0xFFFF0000) == type) && (type)) +			return true; +	} + +	return false; +} + +// FIXME: input coordinates must be offseted to handle scrolling! +bool Parallaction::checkZoneBox(ZonePtr z, uint32 type, uint x, uint y) { +	if (z->_flags & kFlagsRemove) +		return false; + +	debugC(5, kDebugExec, "checkZoneBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y); + +	Common::Rect r; +	z->getBox(r); +	r.right++;		// adjust border because Common::Rect doesn't include bottom-right edge +	r.bottom++; + +	r.grow(-1);		// allows some tolerance for mouse click + +	if (!r.contains(x, y)) { + +		// check for special zones (items defined in common.loc) +		if (checkSpecialZoneBox(z, type, x, y)) +			return true; + +		if (z->getX() != -1) +			return false; +		if ((int)x < _char._ani->getFrameX()) +			return false; +		if ((int)x > (_char._ani->getFrameX() + _char._ani->width())) +			return false; +		if ((int)y < _char._ani->getFrameY()) +			return false; +		if ((int)y > (_char._ani->getFrameY() + _char._ani->height())) +			return false; +	} + +	// normal Zone +	if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) +		return true; +	if (z->_type == type) +		return true; +	if ((z->_type & 0xFFFF0000) == type) +		return true; + +	return false; +} + +// FIXME: input coordinates must be offseted to handle scrolling! +bool Parallaction::checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y) { +	if (z->_flags & kFlagsRemove) +		return false; + +	if ((z->_flags & kFlagsAnimLinked) == 0) +		return false; + +	debugC(5, kDebugExec, "checkLinkedAnimBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y); + +	AnimationPtr anim = z->_linkedAnim; +	Common::Rect r(anim->getFrameX(), anim->getFrameY(), anim->getFrameX() + anim->width() + 1, anim->getFrameY() + anim->height() + 1); + +	if (!r.contains(x, y)) { +		return false; +	} + +	// NOTE: the implementation of the following lines is a different in the +	// original... it is working so far, though +	if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) +		return true; +	if (z->_type == type) +		return true; +	if ((z->_type & 0xFFFF0000) == type) +		return true; + +	return false; +} + +ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) { +	uint16 _di = y; +	uint16 _si = x; + +	for (ZoneList::iterator it = _location._zones.begin(); it != _location._zones.end(); it++) { +		if (checkLinkedAnimBox(*it, type, x, y)) { +			return *it; +		} +		if (checkZoneBox(*it, type, x, y)) { +			return *it; +		} +	} + + +	int16 _a, _b, _c, _d, _e, _f; +	for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ait++) { + +		AnimationPtr a = *ait; + +		_a = (a->_flags & kFlagsActive) ? 1 : 0;															   // _a: active Animation +		_e = ((_si >= a->getFrameX() + a->width()) || (_si <= a->getFrameX())) ? 0 : 1;		// _e: horizontal range +		_f = ((_di >= a->getFrameY() + a->height()) || (_di <= a->getFrameY())) ? 0 : 1;		// _f: vertical range + +		_b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1;										 // _b: (no type specified) AND (Animation is not the character) +		_c = (a->_type & 0xFFFF0000) ? 0 : 1;															// _c: Animation is not an object +		_d = ((a->_type & 0xFFFF0000) != type) ? 0 : 1;													// _d: Animation is an object of the same type + +		if ((_a != 0 && _e != 0 && _f != 0) && ((_b != 0 && _c != 0) || (a->_type == type) || (_d != 0))) { + +			return a; + +		} + +	} + +	return nullZonePtr; +} +  ZonePtr Parallaction::findZone(const char *name) { @@ -451,7 +819,7 @@ ZonePtr Parallaction::findZone(const char *name) {  void Parallaction::freeZones() { -	debugC(2, kDebugExec, "freeZones: _vm->_quit = %i", _vm->_quit); +	debugC(2, kDebugExec, "freeZones: kEngineQuit = %i", _engineFlags & kEngineQuit);  	ZoneList::iterator it = _location._zones.begin(); @@ -460,8 +828,7 @@ void Parallaction::freeZones() {  		// NOTE : this condition has been relaxed compared to the original, to allow the engine  		// to retain special - needed - zones that were lost across location switches.  		ZonePtr z = *it; - -		if (((z->getY() == -1) || (z->getX() == -2)) && ((_vm->quit()) == 0)) { +		if (((z->getY() == -1) || (z->getX() == -2)) && ((_engineFlags & kEngineQuit) == 0)) {  			debugC(2, kDebugExec, "freeZones preserving zone '%s'", z->_name);  			it++;  		} else { @@ -475,11 +842,6 @@ void Parallaction::freeZones() {  	return;  } -void Parallaction::syncSoundSettings() { -	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); -	_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume") / 6); -	_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); -}  enum {  	WALK_LEFT = 0, @@ -528,7 +890,7 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation) {  	_ani->setY(100);  	_ani->setZ(10);  	_ani->setF(0); -	_ani->_flags = kFlagsActive | kFlagsNoName; +	_ani->_flags = kFlagsActive | kFlagsNoName | kFlagsCharacter;  	_ani->_type = kZoneYou;  	strncpy(_ani->_name, "yourself", ZONENAME_LENGTH); diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index eb7ab2e54b..b8464e7c7a 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -29,6 +29,7 @@  #include "common/str.h"  #include "common/stack.h"  #include "common/array.h" +#include "common/func.h"  #include "common/savefile.h"  #include "engines/engine.h" @@ -44,8 +45,6 @@  #define PATH_LEN	200 -extern OSystem *g_system; -  namespace Parallaction {  enum { @@ -71,34 +70,8 @@ enum {  }; -// high values mean high priority - -enum { -	kPriority0 = 0, -	kPriority1 = 1, -	kPriority2 = 2, -	kPriority3 = 3, -	kPriority4 = 4, -	kPriority5 = 5, -	kPriority6 = 6, -	kPriority7 = 7, -	kPriority8 = 8, -	kPriority9 = 9, -	kPriority10 = 10, -	kPriority11 = 11, -	kPriority12 = 12, -	kPriority13 = 13, -	kPriority14 = 14, -	kPriority15 = 15, -	kPriority16 = 16, -	kPriority17 = 17, -	kPriority18 = 18, -	kPriority19 = 19, -	kPriority20 = 20, -	kPriority21 = 21 -}; -  enum EngineFlags { +	kEngineQuit			= (1 << 0),  	kEnginePauseJobs	= (1 << 1),  	kEngineWalking		= (1 << 3),  	kEngineChangeLocation	= (1 << 4), @@ -115,10 +88,6 @@ enum {  	kEvLoadGame		= 4000  }; -enum { -	kCursorArrow = -1 -}; -  enum ParallactionGameType {  	GType_Nippon = 1,  	GType_BRA @@ -129,10 +98,8 @@ struct PARALLACTIONGameDescription; -extern uint16		_mouseButtons;  extern char			_password[8];  extern uint16		_score; -extern uint16		_language;  extern uint32		_engineFlags;  extern char			_saveData1[];  extern uint32		_globalFlags; @@ -237,6 +204,7 @@ public:  }; +class SaveLoad;  #define NUM_LOCATIONS 120 @@ -244,239 +212,143 @@ class Parallaction : public Engine {  	friend class Debugger;  public: - -	Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gameDesc); -	~Parallaction(); - -	int init(); - -	virtual bool loadGame() = 0; -	virtual bool saveGame() = 0; - -	bool _quit;   /* The only reason this flag exists is for freeZones() to properly  -		       * delete all zones when necessary. THIS FLAG IS NOT THE ENGINE QUIT FLAG,  -		       * use _eventMan->shouldQuit() for that. -		       */ - -	Input	*_input; - -	void		processInput(InputData* data); - -	void		pauseJobs(); -	void		resumeJobs(); - -	virtual void 	syncSoundSettings(); - -	ZonePtr		findZone(const char *name); -	ZonePtr		hitZone(uint32 type, uint16 x, uint16 y); -	void		runZone(ZonePtr z); -	void		freeZones(); - -	AnimationPtr findAnimation(const char *name); -	void		freeAnimations(); - -	void		setBackground(const char *background, const char *mask, const char *path); -	void		freeBackground(); - -	Table		*_globalFlagsNames; -	Table		*_objectsNames; -	Table		*_callableNames; -	Table		*_localFlagNames; - -public:  	int getGameType() const;  	uint32 getFeatures() const;  	Common::Language getLanguage() const;  	Common::Platform getPlatform() const; +protected:		// members +	bool detectGame(void); +  private:  	const PARALLACTIONGameDescription *_gameDescription; +	uint16	_language;  public: +	Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gameDesc); +	~Parallaction(); + +	int init(); +  	// info  	int32			_screenWidth;  	int32			_screenHeight;  	int32			_screenSize; -	PathBuffer		*_pathBuffer; - +	// subsystems +	Gfx				*_gfx; +	Disk			*_disk; +	Input			*_input;  	SoundMan		*_soundMan; +	Debugger		*_debugger; +	SaveLoad		*_saveLoad; +	MenuInputHelper *_menuHelper; +	Common::RandomSource _rnd; -	Gfx*			_gfx; -	Disk*			_disk; +	// fonts +	Font		*_labelFont; +	Font		*_menuFont; +	Font		*_introFont; +	Font		*_dialogueFont; -	CommandExec*	_cmdExec; -	ProgramExec*	_programExec; +	// game utilities +	Table				*_globalFlagsNames; +	Table				*_objectsNames; +	Table				*_callableNames; +	Table				*_localFlagNames; +	CommandExec			*_cmdExec; +	ProgramExec			*_programExec; +	PathBuffer			*_pathBuffer; +	Inventory 			*_inventory; +	BalloonManager 		*_balloonMan; +	DialogueManager		*_dialogueMan; +	InventoryRenderer 	*_inventoryRenderer; + +	// game data  	Character		_char; - -	void			setLocationFlags(uint32 flags); -	void			clearLocationFlags(uint32 flags); -	void			toggleLocationFlags(uint32 flags); -	uint32			getLocationFlags(); -  	uint32			_localFlags[NUM_LOCATIONS];  	char			_locationNames[NUM_LOCATIONS][32];  	int16			_currentLocationIndex;  	uint16			_numLocations;  	Location		_location; -  	ZonePtr			_activeZone; +	char			_characterName1[50];	// only used in changeCharacter +	ZonePtr			_zoneTrap; +	ZonePtr			_commentZone; - -	Font		*_labelFont; -	Font		*_menuFont; -	Font		*_introFont; -	Font		*_dialogueFont; - -	Common::RandomSource _rnd; - -	Debugger	*_debugger; -	Frames	*_comboArrow; - - -protected:		// data -	uint32		_baseTime; -	char		_characterName1[50];	// only used in changeCharacter - -	int		_gameToLoad; -	Common::String	_saveFileName; - - -protected:		// members -	bool detectGame(void); - -	void		initGlobals(); -	void		runGame(); -	void		updateView(); - -	void		doLocationEnterTransition(); -	virtual void changeLocation(char *location) = 0; -	virtual void runPendingZones() = 0; -	void		allocateLocationSlot(const char *name); -	void		finalizeLocationParsing(); -	void		freeLocation(); -	void		showLocationComment(const char *text, bool end); - -	void		displayComment(ExamineData *data); - -	void		freeCharacter(); - -	bool		pickupItem(ZonePtr z); - -	void 		clearSet(OpcodeSet &opcodes); - +protected: +	void	runGame(); +	void 	runGuiFrame(); +	void 	cleanupGui(); +	void 	runDialogueFrame(); +	void 	exitDialogueMode(); +	void 	runCommentFrame(); +	void 	enterCommentMode(ZonePtr z); +	void 	exitCommentMode(); +	void	processInput(int event); +	void	updateView(); +	void 	drawAnimations(); +	void	freeCharacter(); +	void	freeLocation(); +	void	doLocationEnterTransition(); +	void	allocateLocationSlot(const char *name); +	void	finalizeLocationParsing(); +	void	showLocationComment(const char *text, bool end); +	void 	setupBalloonManager();  public: -	void		scheduleLocationSwitch(const char *location); -	virtual void changeCharacter(const char *name) = 0; - -	virtual	void callFunction(uint index, void* parm) { } - -	virtual void setArrowCursor() = 0; -	virtual void setInventoryCursor(ItemName name) = 0; - -	virtual void parseLocation(const char* name) = 0; - -	void updateDoor(ZonePtr z, bool close); - -	virtual void drawAnimations() = 0; - -	void		beep(); - -	ZonePtr		_zoneTrap; -	PathBuilder* getPathBuilder(Character *ch); +	void	beep(); +	void	pauseJobs(); +	void	resumeJobs(); +	void 	hideDialogueStuff(); +	uint 	getInternLanguage(); +	void 	setInternLanguage(uint id); +	void 	enterDialogueMode(ZonePtr z); +	void	scheduleLocationSwitch(const char *location); +	void	showSlide(const char *name, int x = 0, int y = 0);  public: -//	const char **_zoneFlagNamesRes; -//	const char **_zoneTypeNamesRes; -//	const char **_commandsNamesRes; -	const char **_callableNamesRes; -	const char **_instructionNamesRes; - -	void highlightInventoryItem(ItemPosition pos); -	int16 getHoverInventoryItem(int16 x, int16 y); -	int addInventoryItem(ItemName item); -	int addInventoryItem(ItemName item, uint32 value); -	void dropItem(uint16 v); -	bool isItemInInventory(int32 v); -	const InventoryItem* getInventoryItem(int16 pos); -	int16 getInventoryItemIndex(int16 pos); -	void initInventory(); -	void destroyInventory(); -	void cleanInventory(bool keepVerbs = true); -	void openInventory(); -	void closeInventory(); - -	Inventory *_inventory; -	InventoryRenderer *_inventoryRenderer; - -	BalloonManager *_balloonMan; - -	void setupBalloonManager(); - -	void hideDialogueStuff(); -	DialogueManager	*_dialogueMan; -	void enterDialogueMode(ZonePtr z); -	void exitDialogueMode(); -	void runDialogueFrame(); - -	MenuInputHelper *_menuHelper; -	void runGuiFrame(); -	void cleanupGui(); - -	ZonePtr	_commentZone; -	void enterCommentMode(ZonePtr z); -	void exitCommentMode(); -	void runCommentFrame(); - -	void setInternLanguage(uint id); -	uint getInternLanguage(); +	void		setLocationFlags(uint32 flags); +	void		clearLocationFlags(uint32 flags); +	void		toggleLocationFlags(uint32 flags); +	uint32		getLocationFlags(); +	bool 		checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y); +	bool 		checkZoneBox(ZonePtr z, uint32 type, uint x, uint y); +	bool 		checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y); +	ZonePtr		findZone(const char *name); +	ZonePtr		hitZone(uint32 type, uint16 x, uint16 y); +	void		runZone(ZonePtr z); +	void		freeZones(); +	bool		pickupItem(ZonePtr z); +	void 		updateDoor(ZonePtr z, bool close); +	void 		showZone(ZonePtr z, bool visible); +	AnimationPtr findAnimation(const char *name); +	void		freeAnimations(); +	void		setBackground(const char *background, const char *mask, const char *path); +	void		freeBackground(); +	void 		highlightInventoryItem(ItemPosition pos); +	int16 		getHoverInventoryItem(int16 x, int16 y); +	int 		addInventoryItem(ItemName item); +	int 		addInventoryItem(ItemName item, uint32 value); +	void 		dropItem(uint16 v); +	bool 		isItemInInventory(int32 v); +	const 		InventoryItem* getInventoryItem(int16 pos); +	int16 		getInventoryItemIndex(int16 pos); +	void 		initInventory(); +	void 		destroyInventory(); +	void 		cleanInventory(bool keepVerbs = true); +	void 		openInventory(); +	void 		closeInventory(); -	void showZone(ZonePtr z, bool visible); +	virtual void parseLocation(const char* name) = 0; +	virtual void changeLocation(char *location) = 0; +	virtual void changeCharacter(const char *name) = 0; +	virtual	void callFunction(uint index, void* parm) = 0; +	virtual void runPendingZones() = 0; +	virtual void cleanupGame() = 0;  }; -class LocationName { - -	Common::String _slide; -	Common::String _character; -	Common::String _location; - -	bool _hasCharacter; -	bool _hasSlide; -	char *_buf; - -public: -	LocationName(); -	~LocationName(); - -	void bind(const char*); - -	const char *location() const { -		return _location.c_str(); -	} - -	bool hasCharacter() const { -		return _hasCharacter; -	} - -	const char *character() const { -		return _character.c_str(); -	} - -	bool hasSlide() const { -		return _hasSlide; -	} - -	const char *slide() const { -		return _slide.c_str(); -	} - -	const char *c_str() const { -		return _buf; -	} -}; -  class Parallaction_ns : public Parallaction { @@ -488,70 +360,45 @@ public:  	int go();  public: -	typedef void (Parallaction_ns::*Callable)(void*); - -	virtual	void callFunction(uint index, void* parm); +	virtual void 	parseLocation(const char *filename); +	virtual void 	changeLocation(char *location); +	virtual void 	changeCharacter(const char *name); +	virtual void 	callFunction(uint index, void* parm); +	virtual void 	runPendingZones(); +	virtual void 	cleanupGame(); -	bool loadGame(); -	bool saveGame(); -	void		switchBackground(const char* background, const char* mask); -	void		showSlide(const char *name, int x = 0, int y = 0); -	void 		setArrowCursor(); - -	// TODO: this should be private!!!!!!! -	bool	_inTestResult; -	void cleanupGame(); -	bool allPartsComplete(); +	void 	switchBackground(const char* background, const char* mask);  private: -	LocationParser_ns		*_locationParser; -	ProgramParser_ns		*_programParser; - -	void initFonts(); -	void freeFonts(); -	void renameOldSavefiles(); -	Common::String genSaveFileName(uint slot, bool oldStyle = false); -	Common::InSaveFile *getInSaveFile(uint slot); -	Common::OutSaveFile *getOutSaveFile(uint slot); -	void setPartComplete(const Character& character); +	bool				_inTestResult; +	LocationParser_ns	*_locationParser; +	ProgramParser_ns	*_programParser;  private: -	void changeLocation(char *location); -	void changeCharacter(const char *name); -	void runPendingZones(); - -	void setInventoryCursor(ItemName name); - - -	void doLoadGame(uint16 slot); -	void doSaveGame(uint16 slot, const char* name); -	int  buildSaveFileList(Common::StringList& l); -	int  selectSaveFile(uint16 arg_0, const char* caption, const char* button); - -	void initResources(); -	void initCursors(); - -	static byte _resMouseArrow[256]; -	byte	*_mouseArrow; - -	static const Callable _dosCallables[25]; -	static const Callable _amigaCallables[25]; +	void 	initFonts(); +	void 	freeFonts(); +	void 	initResources(); +	void	startGui(); +	void	startCreditSequence(); +	void	startEndPartSequence(); +	void	loadProgram(AnimationPtr a, const char *filename); -	/* -		game callables data members -	*/ +	//  callables data +	typedef void (Parallaction_ns::*Callable)(void*); +	const Callable *_callables;  	ZonePtr _moveSarcZone0;  	ZonePtr _moveSarcZone1;  	uint16 num_foglie;  	int16 _introSarcData1;  	uint16	_introSarcData2;		 // sarcophagus stuff to be saved  	uint16	_introSarcData3;		 // sarcophagus stuff to be saved -  	ZonePtr _moveSarcZones[5];  	ZonePtr _moveSarcExaZones[5];  	AnimationPtr _rightHandAnim; +	static const Callable _dosCallables[25]; +	static const Callable _amigaCallables[25];  	// common callables  	void _c_play_boogie(void*); @@ -585,20 +432,6 @@ private:  	void _c_startMusic(void*);  	void _c_closeMusic(void*);  	void _c_HBOn(void*); - -	const Callable *_callables; - -protected: -	void drawAnimations(); - -	void		parseLocation(const char *filename); -	void		loadProgram(AnimationPtr a, const char *filename); - -	void		selectStartLocation(); - -	void		startGui(); -	void		startCreditSequence(); -	void		startEndPartSequence();  }; @@ -607,8 +440,6 @@ protected:  class Parallaction_br : public Parallaction_ns { -	typedef Parallaction_ns Super; -  public:  	Parallaction_br(OSystem* syst, const PARALLACTIONGameDescription *gameDesc) : Parallaction_ns(syst, gameDesc) { }  	~Parallaction_br(); @@ -617,83 +448,55 @@ public:  	int go();  public: -	typedef void (Parallaction_br::*Callable)(void*); +	virtual void parseLocation(const char* name); +	virtual void changeLocation(char *location); +	virtual void changeCharacter(const char *name);  	virtual	void callFunction(uint index, void* parm); -	void		changeCharacter(const char *name); +	virtual void runPendingZones(); +	virtual void cleanupGame(); + +  	void setupSubtitles(char *s, char *s2, int y);  	void clearSubtitles(); -  public:  	Table		*_countersNames; -  	const char **_audioCommandsNamesRes; - +	static const char *_partNames[];  	int			_part; -	int			_progress; -  #if 0	// disabled since I couldn't find any references to lip sync in the scripts  	int16		_lipSyncVal;  	uint		_subtitleLipSync;  #endif  	int			_subtitleY;  	int			_subtitle[2]; -  	ZonePtr		_activeZone2; -  	int32		_counters[32]; -  	uint32		_zoneFlags[NUM_LOCATIONS][NUM_ZONES]; -	void		startPart(uint part); -	void 		setArrowCursor(); +  private:  	LocationParser_br		*_locationParser;  	ProgramParser_br		*_programParser; -	void		initResources(); -	void		initFonts(); -	void		freeFonts(); - -	void setInventoryCursor(ItemName name); - -	void		changeLocation(char *location); -	void 		runPendingZones(); - -	void		initPart(); -	void		freePart(); - -	void initCursors(); - -	Frames	*_dinoCursor; -	Frames	*_dougCursor; -	Frames	*_donnaCursor; -	Frames	*_mouseArrow; - - -	static const char *_partNames[]; - -	void startGui(); +private: +	void	initResources(); +	void	initFonts(); +	void	freeFonts(); +	void	freeLocation(); +	void 	loadProgram(AnimationPtr a, const char *filename); +	void 	startGui(bool showSplash); +	typedef void (Parallaction_br::*Callable)(void*); +	const Callable *_callables;  	static const Callable _dosCallables[6]; +	// dos callables  	void _c_blufade(void*);  	void _c_resetpalette(void*);  	void _c_ferrcycle(void*);  	void _c_lipsinc(void*);  	void _c_albcycle(void*);  	void _c_password(void*); - -	const Callable *_callables; - -	void parseLocation(const char* name); -	void loadProgram(AnimationPtr a, const char *filename); - -#if 0 -	void jobWaitRemoveLabelJob(void *parm, Job *job); -	void jobPauseSfx(void *parm, Job *job); -	void jobStopFollower(void *parm, Job *job); -	void jobScroll(void *parm, Job *job); -#endif  };  // FIXME: remove global diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index e65faaeda2..7c0fa23e15 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -28,31 +28,11 @@  #include "parallaction/parallaction.h"  #include "parallaction/input.h" +#include "parallaction/saveload.h"  #include "parallaction/sound.h"  namespace Parallaction { -struct MouseComboProperties { -	int	_xOffset; -	int	_yOffset; -	int	_width; -	int	_height; -}; -/* -// TODO: improve NS's handling of normal cursor before merging cursor code. -MouseComboProperties	_mouseComboProps_NS = { -	7,	// combo x offset (the icon from the inventory will be rendered from here) -	7,	// combo y offset (ditto) -	32,	// combo (arrow + icon) width -	32	// combo (arrow + icon) height -}; -*/ -MouseComboProperties	_mouseComboProps_BR = { -	8,	// combo x offset (the icon from the inventory will be rendered from here) -	8,	// combo y offset (ditto) -	68,	// combo (arrow + icon) width -	68	// combo (arrow + icon) height -};  const char *Parallaction_br::_partNames[] = {  	"PART0", @@ -62,14 +42,6 @@ const char *Parallaction_br::_partNames[] = {  	"PART4"  }; -const char *partFirstLocation[] = { -	"intro", -	"museo", -	"start", -	"bolscoi", -	"treno" -}; -  int Parallaction_br::init() {  	_screenWidth = 640; @@ -96,7 +68,6 @@ int Parallaction_br::init() {  	initResources();  	initFonts(); -	initCursors();  	_locationParser = new LocationParser_br(this);  	_locationParser->init();  	_programParser = new ProgramParser_br(this); @@ -112,6 +83,8 @@ int Parallaction_br::init() {  	_subtitle[0] = -1;  	_subtitle[1] = -1; +	_saveLoad = new SaveLoad_br(this, _saveFileMan); +  	Parallaction::init();  	return 0; @@ -119,12 +92,6 @@ int Parallaction_br::init() {  Parallaction_br::~Parallaction_br() {  	freeFonts(); - -	delete _dinoCursor; -	delete _dougCursor; -	delete _donnaCursor; - -	delete _mouseArrow;  }  void Parallaction_br::callFunction(uint index, void* parm) { @@ -135,28 +102,30 @@ void Parallaction_br::callFunction(uint index, void* parm) {  int Parallaction_br::go() { -	if (getFeatures() & GF_DEMO) { -		startPart(1); -	} else { -		startGui(); -	} +	bool splash = true; -	while (quit() == 0) { +	while ((_engineFlags & kEngineQuit) == 0) { + +		if (getFeatures() & GF_DEMO) { +			scheduleLocationSwitch("camalb.1"); +			_input->_inputMode = Input::kInputModeGame; +		} else { +			startGui(splash); +			 // don't show splash after first time +			splash = false; +		}  //		initCharacter(); -		_input->_inputMode = Input::kInputModeGame; -		while (((_engineFlags & kEngineReturn) == 0) && (!quit())) { +		while ((_engineFlags & (kEngineReturn | kEngineQuit)) == 0) {  			runGame();  		}  		_engineFlags &= ~kEngineReturn; -		freePart(); -//		freeCharacter(); - +		cleanupGame();  	} -	return _eventMan->shouldRTL(); +	return 0;  } @@ -169,70 +138,6 @@ void Parallaction_br::freeFonts() {  	return;  } -void Parallaction_br::initCursors() { - -	if (getPlatform() == Common::kPlatformPC) { -		_dinoCursor = _disk->loadPointer("pointer1"); -		_dougCursor = _disk->loadPointer("pointer2"); -		_donnaCursor = _disk->loadPointer("pointer3"); - -		Graphics::Surface *surf = new Graphics::Surface; -		surf->create(_mouseComboProps_BR._width, _mouseComboProps_BR._height, 1); -		_comboArrow = new SurfaceToFrames(surf); - -		// TODO: choose the pointer depending on the active character -		// For now, we pick Donna's -		_mouseArrow = _donnaCursor; -	} else { -		// TODO: Where are the Amiga cursors? -	} - -} - -void Parallaction_br::initPart() { - -	memset(_counters, 0, ARRAYSIZE(_counters)); - -	_globalFlagsNames = _disk->loadTable("global"); -	_objectsNames = _disk->loadTable("objects"); -	_countersNames = _disk->loadTable("counters"); - -	// TODO: maybe handle this into Disk -	if (getPlatform() == Common::kPlatformPC) { -		_char._objs = _disk->loadObjects("icone.ico"); -	} else { -		_char._objs = _disk->loadObjects("icons.ico"); -	} - -} - -void Parallaction_br::freePart() { - -	delete _globalFlagsNames; -	delete _objectsNames; -	delete _countersNames; - -	_globalFlagsNames = 0; -	_objectsNames = 0; -	_countersNames = 0; -} - -void Parallaction_br::startPart(uint part) { -	_part = part; -	_disk->selectArchive(_partNames[_part]); - -	initPart(); - -	if (getFeatures() & GF_DEMO) { -		strcpy(_location._name, "camalb"); -	} else { -		strcpy(_location._name, partFirstLocation[_part]); -	} - -	parseLocation("common"); -	changeLocation(_location._name); - -}  void Parallaction_br::runPendingZones() {  	ZonePtr z; @@ -260,8 +165,7 @@ void Parallaction_br::runPendingZones() {  	}  } - -void Parallaction_br::changeLocation(char *location) { +void Parallaction_br::freeLocation() {  	// free open location stuff  	clearSubtitles(); @@ -279,27 +183,75 @@ void Parallaction_br::changeLocation(char *location) {  	_location._animations.push_front(_char._ani); -//	free(_location._comment); -//	_location._comment = 0; +	free(_location._comment); +	_location._comment = 0;  	_location._commands.clear();  	_location._aCommands.clear(); +} + +void Parallaction_br::cleanupGame() { +	freeLocation(); + +//		freeCharacter(); + +	delete _globalFlagsNames; +	delete _objectsNames; +	delete _countersNames; + +	_globalFlagsNames = 0; +	_objectsNames = 0; +	_countersNames = 0; +} + + +void Parallaction_br::changeLocation(char *location) { +	char *partStr = strrchr(location, '.'); +	if (partStr) { +		int n = partStr - location; +		strncpy(_location._name, location, n); +		_location._name[n] = '\0'; + +		_part = atoi(++partStr); +		if (getFeatures() & GF_DEMO) { +			assert(_part == 1); +		} else { +			assert(_part >= 0 && _part <= 4); +		} + +		_disk->selectArchive(_partNames[_part]); + +		memset(_counters, 0, ARRAYSIZE(_counters)); + +		_globalFlagsNames = _disk->loadTable("global"); +		_objectsNames = _disk->loadTable("objects"); +		_countersNames = _disk->loadTable("counters"); + +		// TODO: maybe handle this into Disk +		if (getPlatform() == Common::kPlatformPC) { +			_char._objs = _disk->loadObjects("icone.ico"); +		} else { +			_char._objs = _disk->loadObjects("icons.ico"); +		} + +		parseLocation("common"); +	} + +	freeLocation();  	// load new location  	parseLocation(location); - -	// kFlagsRemove is cleared because the character defaults to visible on new locations -	// script command can hide the character, anyway, so that's why the flag is cleared -	// before _location._commands are executed +	// kFlagsRemove is cleared because the character is visible by default. +	// Commands can hide the character, anyway.  	_char._ani->_flags &= ~kFlagsRemove; -  	_cmdExec->run(_location._commands); -//	doLocationEnterTransition(); + +	doLocationEnterTransition(); +  	_cmdExec->run(_location._aCommands);  	_engineFlags &= ~kEngineChangeLocation;  } -  // FIXME: Parallaction_br::parseLocation() is now a verbatim copy of the same routine from Parallaction_ns.  void Parallaction_br::parseLocation(const char *filename) {  	debugC(1, kDebugParser, "parseLocation('%s')", filename); @@ -359,30 +311,5 @@ void Parallaction_br::changeCharacter(const char *name) {  } -void Parallaction_br::setArrowCursor() { -	// FIXME: Where are the Amiga cursors? -	if (getPlatform() == Common::kPlatformAmiga) -		return; - -	Common::Rect r; -	_mouseArrow->getRect(0, r); - -	_system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0); -	_system->showMouse(true); - -	_input->_activeItem._id = 0; -} - -void Parallaction_br::setInventoryCursor(ItemName name) { -	assert(name > 0); - -	byte *src = _mouseArrow->getData(0); -	byte *dst = _comboArrow->getData(0); -	memcpy(dst, src, _comboArrow->getSize(0)); - -	// FIXME: destination offseting is not clear -	_inventoryRenderer->drawItem(name, dst + _mouseComboProps_BR._yOffset * _mouseComboProps_BR._width + _mouseComboProps_BR._xOffset, _mouseComboProps_BR._width); -	_system->setMouseCursor(dst, _mouseComboProps_BR._width, _mouseComboProps_BR._height, 0, 0, 0); -}  } // namespace Parallaction diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index eab08142d4..85a4689301 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -28,30 +28,62 @@  #include "common/config-manager.h"  #include "parallaction/parallaction.h" -#include "parallaction/gui.h" -#include "parallaction/gui_ns.cpp"  #include "parallaction/input.h" +#include "parallaction/saveload.h"  #include "parallaction/sound.h"  namespace Parallaction { -#define MOUSEARROW_WIDTH		16 -#define MOUSEARROW_HEIGHT		16 +class LocationName { -#define MOUSECOMBO_WIDTH		32	// sizes for cursor + selected inventory item -#define MOUSECOMBO_HEIGHT		32 +	Common::String _slide; +	Common::String _character; +	Common::String _location; -LocationName::LocationName() { -	_buf = 0; -	_hasSlide = false; -	_hasCharacter = false; -} +	bool _hasCharacter; +	bool _hasSlide; +	char *_buf; + +public: +	LocationName() { +		_buf = 0; +		_hasSlide = false; +		_hasCharacter = false; +	} + +	~LocationName() { +		free(_buf); +	} + +	void bind(const char*); + +	const char *location() const { +		return _location.c_str(); +	} + +	bool hasCharacter() const { +		return _hasCharacter; +	} + +	const char *character() const { +		return _character.c_str(); +	} + +	bool hasSlide() const { +		return _hasSlide; +	} + +	const char *slide() const { +		return _slide.c_str(); +	} + +	const char *c_str() const { +		return _buf; +	} +}; -LocationName::~LocationName() { -	free(_buf); -}  /* @@ -137,7 +169,6 @@ int Parallaction_ns::init() {  	initResources();  	initFonts(); -	initCursors();  	_locationParser = new LocationParser_ns(this);  	_locationParser->init();  	_programParser = new ProgramParser_ns(this); @@ -158,6 +189,8 @@ int Parallaction_ns::init() {  	_location._animations.push_front(_char._ani); +	_saveLoad = new SaveLoad_ns(this, _saveFileMan); +  	Parallaction::init();  	return 0; @@ -183,32 +216,6 @@ void Parallaction_ns::freeFonts() {  } -void Parallaction_ns::initCursors() { -	_comboArrow = _disk->loadPointer("pointer"); -	_mouseArrow = _resMouseArrow; -} - -void Parallaction_ns::setArrowCursor() { - -	debugC(1, kDebugInput, "setting mouse cursor to arrow"); - -	// this stuff is needed to avoid artifacts with labels and selected items when switching cursors -	_input->stopHovering(); -	_input->_activeItem._id = 0; - -	_system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); -} - -void Parallaction_ns::setInventoryCursor(ItemName name) { -	assert(name > 0); - -	byte *v8 = _comboArrow->getData(0); - -	// FIXME: destination offseting is not clear -	_inventoryRenderer->drawItem(name, v8 + 7 * MOUSECOMBO_WIDTH + 7, MOUSECOMBO_WIDTH); -	_system->setMouseCursor(v8, MOUSECOMBO_WIDTH, MOUSECOMBO_HEIGHT, 0, 0, 0); -} -  void Parallaction_ns::callFunction(uint index, void* parm) {  	assert(index < 25);	// magic value 25 is maximum # of callables for Nippon Safes @@ -218,35 +225,17 @@ void Parallaction_ns::callFunction(uint index, void* parm) {  int Parallaction_ns::go() { -	renameOldSavefiles(); +	_saveLoad->renameOldSavefiles();  	_globalFlagsNames = _disk->loadTable("global"); -	// If requested, load a savegame instead of showing the intro -	if (ConfMan.hasKey("save_slot")) { -		_gameToLoad = ConfMan.getInt("save_slot"); -		if (_gameToLoad < 0 || _gameToLoad > 99) -			_gameToLoad = -1; -	} -	if (_gameToLoad == -1) { -		startGui(); -	} else { -		_disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); -		 -		_menuHelper = new MenuInputHelper; -		assert(_menuHelper); -		new ChooseLanguageInputState_NS(this, _menuHelper); -		_menuHelper->setState("chooselanguage"); - -		_input->_inputMode = Input::kInputModeMenu; -		doLoadGame(_gameToLoad); -	} -	 -	while (!quit()) { +	startGui(); + +	while ((_engineFlags & kEngineQuit) == 0) {  		runGame();  	} -	return _eventMan->shouldRTL(); +	return 0;  }  void Parallaction_ns::switchBackground(const char* background, const char* mask) { @@ -262,7 +251,7 @@ void Parallaction_ns::switchBackground(const char* background, const char* mask)  			v2 += 4;  		} -		g_system->delayMillis(20); +		_vm->_system->delayMillis(20);  		_gfx->setPalette(pal);  		_gfx->updateScreen();  	} @@ -273,16 +262,6 @@ void Parallaction_ns::switchBackground(const char* background, const char* mask)  } -void Parallaction_ns::showSlide(const char *name, int x, int y) { -	BackgroundInfo *info = new BackgroundInfo; -	_disk->loadSlide(*info, name); - -	info->x = (x == CENTER_LABEL_HORIZONTAL) ? ((_vm->_screenWidth - info->width) >> 1) : x; -	info->y = (y == CENTER_LABEL_VERTICAL) ? ((_vm->_screenHeight - info->height) >> 1) : y; - -	_gfx->setBackground(kBackgroundSlide, info); -} -  void Parallaction_ns::runPendingZones() {  	if (_activeZone) {  		ZonePtr z = _activeZone;	// speak Zone or sound @@ -307,7 +286,7 @@ void Parallaction_ns::changeLocation(char *location) {  	_zoneTrap = nullZonePtr; -	setArrowCursor(); +	_input->setArrowCursor();  	_gfx->showGfxObj(_char._ani->gfxobj, false);  	_location._animations.remove(_char._ani); @@ -448,6 +427,7 @@ void Parallaction_ns::changeCharacter(const char *name) {  }  void Parallaction_ns::cleanupGame() { +	_inTestResult = false;  	_engineFlags &= ~kEngineTransformedDonna; @@ -460,18 +440,22 @@ void Parallaction_ns::cleanupGame() {  	memset(_locationNames, 0, sizeof(_locationNames));  	// this flag tells freeZones to unconditionally remove *all* Zones -	_vm->_quit = true; +	_engineFlags |= kEngineQuit;  	freeZones();  	freeAnimations();  	// this dangerous flag can now be cleared -	_vm->_quit = false; +	_engineFlags &= ~kEngineQuit;  	// main character animation is restored  	_location._animations.push_front(_char._ani);  	_score = 0; +	_soundMan->stopMusic(); +	_introSarcData3 = 200; +	_introSarcData2 = 1; +  	return;  } diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp index 8e30a631e4..a475f5701a 100644 --- a/engines/parallaction/parser.cpp +++ b/engines/parallaction/parser.cpp @@ -183,13 +183,12 @@ uint16 Script::readLineToken(bool errorOnEOF) {  	clearTokens(); -	bool inBlockComment = false, inLineComment; +	bool inBlockComment = false;  	char buf[200];  	char *line = NULL; +	char *start;  	do { -		inLineComment = false; -  		line = readLine(buf, 200);  		if (line == NULL) { @@ -198,21 +197,27 @@ uint16 Script::readLineToken(bool errorOnEOF) {  			else  				return 0;  		} -		line = Common::ltrim(line); +		start = Common::ltrim(line); -		if (isCommentLine(line)) { -			inLineComment = true; +		if (isCommentLine(start)) { +			// ignore this line +			start[0] = '\0';  		} else -		if (isStartOfCommentBlock(line)) { +		if (isStartOfCommentBlock(start)) { +			// mark this and the following lines as comment  			inBlockComment = true;  		} else -		if (isEndOfCommentBlock(line)) { +		if (isEndOfCommentBlock(start)) { +			// comment is finished, so stop ignoring  			inBlockComment = false; +			// the current line must be skipped, though, +			// as it contains the end-of-comment marker +			start[0] = '\0';  		} -	} while (inLineComment || inBlockComment || strlen(line) == 0); +	} while (inBlockComment || strlen(start) == 0); -	return fillTokens(line); +	return fillTokens(start);  } @@ -403,7 +408,9 @@ void PreProcessor::preprocessScript(Script &script, StatementList &list) {  			break;  		StatementDef *def = findDef(_tokens[0]); -		assert(def); +		if (!def) { +			error("PreProcessor::preprocessScript: unknown statement '%s' found\n", _tokens[0]); +		}  		text = def->makeLine(script);  		int score = getDefScore(def); diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index e622bfd81f..7bf41b2bea 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -27,6 +27,7 @@  #define PARALLACTION_PARSER_H  #include "common/stream.h" +#include "common/stack.h"  #include "parallaction/objects.h"  #include "parallaction/walk.h" diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index 20800abc33..4b11c5caa4 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -497,7 +497,7 @@ DECLARE_LOCATION_PARSER(zeta)  {  	_vm->_location._zeta1 = atoi(_tokens[2]);  	if (_tokens[3][0] != '\0') { -		_vm->_location._zeta2 = atoi(_tokens[1]); +		_vm->_location._zeta2 = atoi(_tokens[3]);  	} else {  		_vm->_location._zeta2 = 50;  	} diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp index ed3812e5be..5620001d7d 100644 --- a/engines/parallaction/saveload.cpp +++ b/engines/parallaction/saveload.cpp @@ -31,6 +31,7 @@  #include "gui/message.h"  #include "parallaction/parallaction.h" +#include "parallaction/saveload.h"  #include "parallaction/sound.h" @@ -57,12 +58,11 @@ protected:  	GUI::StaticTextWidget	*_time;  	GUI::StaticTextWidget	*_playtime;  	GUI::ContainerWidget	*_container; -	Parallaction_ns			*_vm;  	uint8 _fillR, _fillG, _fillB;  public: -	SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction_ns *engine); +	SaveLoadChooser(const String &title, const String &buttonLabel);  	~SaveLoadChooser();  	virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); @@ -73,34 +73,39 @@ public:  	virtual void reflowLayout();  }; -Common::String Parallaction_ns::genSaveFileName(uint slot, bool oldStyle) { +Common::String SaveLoad_ns::genOldSaveFileName(uint slot) {  	assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT);  	char s[20]; -	sprintf(s, (oldStyle ? "game.%i" : "nippon.%.3d"), slot ); +	sprintf(s, "game.%i", slot);  	return Common::String(s);  } -Common::InSaveFile *Parallaction_ns::getInSaveFile(uint slot) { + +Common::String SaveLoad::genSaveFileName(uint slot) { +	assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT); + +	char s[20]; +	sprintf(s, "%s.%.3d", _saveFilePrefix.c_str(), slot); + +	return Common::String(s); +} + +Common::InSaveFile *SaveLoad::getInSaveFile(uint slot) {  	Common::String name = genSaveFileName(slot);  	return _saveFileMan->openForLoading(name.c_str());  } -Common::OutSaveFile *Parallaction_ns::getOutSaveFile(uint slot) { +Common::OutSaveFile *SaveLoad::getOutSaveFile(uint slot) {  	Common::String name = genSaveFileName(slot);  	return _saveFileMan->openForSaving(name.c_str());  } -void Parallaction_ns::doLoadGame(uint16 slot) { - -	_soundMan->stopMusic(); +void SaveLoad_ns::doLoadGame(uint16 slot) { -	cleanupGame(); - -	_introSarcData3 = 200; -	_introSarcData2 = 1; +	_vm->cleanupGame();  	Common::InSaveFile *f = getInSaveFile(slot);  	if (!f) return; @@ -116,10 +121,10 @@ void Parallaction_ns::doLoadGame(uint16 slot) {  	f->readLine(l, 15);  	f->readLine(s, 15); -	_location._startPosition.x = atoi(s); +	_vm->_location._startPosition.x = atoi(s);  	f->readLine(s, 15); -	_location._startPosition.y = atoi(s); +	_vm->_location._startPosition.y = atoi(s);  	f->readLine(s, 15);  	_score = atoi(s); @@ -132,28 +137,26 @@ void Parallaction_ns::doLoadGame(uint16 slot) {  	// TODO (LIST): unify (and parametrize) calls to freeZones.  	// We aren't calling freeAnimations because it is not needed, since  	// kChangeLocation will trigger a complete deletion. Anyway, we still -	// need to invoke freeZones here with _quit set, because the +	// need to invoke freeZones here with kEngineQuit set, because the  	// call in changeLocation preserve certain zones. -	_quit = true; - -	freeZones(); - -	_quit = false; +	_engineFlags |= kEngineQuit; +	_vm->freeZones(); +	_engineFlags &= ~kEngineQuit; -	_numLocations = atoi(s); +	_vm->_numLocations = atoi(s);  	uint16 _si; -	for (_si = 0; _si < _numLocations; _si++) { +	for (_si = 0; _si < _vm->_numLocations; _si++) {  		f->readLine(s, 20);  		s[strlen(s)] = '\0'; -		strcpy(_locationNames[_si], s); +		strcpy(_vm->_locationNames[_si], s);  		f->readLine(s, 15); -		_localFlags[_si] = atoi(s); +		_vm->_localFlags[_si] = atoi(s);  	} -	cleanInventory(false); +	_vm->cleanInventory(false);  	ItemName name;  	uint32 value; @@ -164,24 +167,24 @@ void Parallaction_ns::doLoadGame(uint16 slot) {  		f->readLine(s, 15);  		name = atoi(s); -		addInventoryItem(name, value); +		_vm->addInventoryItem(name, value);  	}  	delete f;  	// force reload of character to solve inventory  	// bugs, but it's a good maneuver anyway -	strcpy(_characterName1, "null"); +	strcpy(_vm->_characterName1, "null");  	char tmp[PATH_LEN];  	sprintf(tmp, "%s.%s" , l, n); -	scheduleLocationSwitch(tmp); +	_vm->scheduleLocationSwitch(tmp);  	return;  } -void Parallaction_ns::doSaveGame(uint16 slot, const char* name) { +void SaveLoad_ns::doSaveGame(uint16 slot, const char* name) {  	Common::OutSaveFile *f = getOutSaveFile(slot);  	if (f == 0) { @@ -204,30 +207,30 @@ void Parallaction_ns::doSaveGame(uint16 slot, const char* name) {  	f->writeString(s);  	f->writeString("\n"); -	sprintf(s, "%s\n", _char.getFullName()); +	sprintf(s, "%s\n", _vm->_char.getFullName());  	f->writeString(s);  	sprintf(s, "%s\n", _saveData1);  	f->writeString(s); -	sprintf(s, "%d\n", _char._ani->getX()); +	sprintf(s, "%d\n", _vm->_char._ani->getX());  	f->writeString(s); -	sprintf(s, "%d\n", _char._ani->getY()); +	sprintf(s, "%d\n", _vm->_char._ani->getY());  	f->writeString(s);  	sprintf(s, "%d\n", _score);  	f->writeString(s);  	sprintf(s, "%u\n", _globalFlags);  	f->writeString(s); -	sprintf(s, "%d\n", _numLocations); +	sprintf(s, "%d\n", _vm->_numLocations);  	f->writeString(s); -	for (uint16 _si = 0; _si < _numLocations; _si++) { -		sprintf(s, "%s\n%u\n", _locationNames[_si], _localFlags[_si]); +	for (uint16 _si = 0; _si < _vm->_numLocations; _si++) { +		sprintf(s, "%s\n%u\n", _vm->_locationNames[_si], _vm->_localFlags[_si]);  		f->writeString(s);  	}  	const InventoryItem *item;  	for (uint16 _si = 0; _si < 30; _si++) { -		item = getInventoryItem(_si); +		item = _vm->getInventoryItem(_si);  		sprintf(s, "%u\n%d\n", item->_id, item->_index);  		f->writeString(s);  	} @@ -249,8 +252,8 @@ enum {  }; -SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction_ns *engine) -	: Dialog("scummsaveload"), _list(0), _chooseButton(0), _gfxWidget(0), _vm(engine) { +SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel) +	: Dialog("scummsaveload"), _list(0), _chooseButton(0), _gfxWidget(0) {  //	_drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR; @@ -337,7 +340,7 @@ void SaveLoadChooser::reflowLayout() {  	Dialog::reflowLayout();  } -int Parallaction_ns::buildSaveFileList(Common::StringList& l) { +int SaveLoad_ns::buildSaveFileList(Common::StringList& l) {  	char buf[200]; @@ -361,9 +364,9 @@ int Parallaction_ns::buildSaveFileList(Common::StringList& l) {  } -int Parallaction_ns::selectSaveFile(uint16 arg_0, const char* caption, const char* button) { +int SaveLoad_ns::selectSaveFile(uint16 arg_0, const char* caption, const char* button) { -	SaveLoadChooser* slc = new SaveLoadChooser(caption, button, this); +	SaveLoadChooser* slc = new SaveLoadChooser(caption, button);  	Common::StringList l; @@ -382,7 +385,7 @@ int Parallaction_ns::selectSaveFile(uint16 arg_0, const char* caption, const cha -bool Parallaction_ns::loadGame() { +bool SaveLoad_ns::loadGame() {  	int _di = selectSaveFile( 0, "Load file", "Load" );  	if (_di == -1) { @@ -394,15 +397,15 @@ bool Parallaction_ns::loadGame() {  	GUI::TimedMessageDialog dialog("Loading game...", 1500);  	dialog.runModal(); -	setArrowCursor(); +	_vm->_input->setArrowCursor();  	return true;  } -bool Parallaction_ns::saveGame() { +bool SaveLoad_ns::saveGame() { -	if (!scumm_stricmp(_location._name, "caveau")) { +	if (!scumm_stricmp(_vm->_location._name, "caveau")) {  		return false;  	} @@ -420,7 +423,7 @@ bool Parallaction_ns::saveGame() {  } -void Parallaction_ns::setPartComplete(const Character& character) { +void SaveLoad_ns::setPartComplete(const char *part) {  	char buf[30];  	bool alreadyPresent = false; @@ -431,7 +434,7 @@ void Parallaction_ns::setPartComplete(const Character& character) {  		inFile->readLine(buf, 29);  		delete inFile; -		if (strstr(buf, character.getBaseName())) { +		if (strstr(buf, part)) {  			alreadyPresent = true;  		}  	} @@ -439,7 +442,7 @@ void Parallaction_ns::setPartComplete(const Character& character) {  	if (!alreadyPresent) {  		Common::OutSaveFile *outFile = getOutSaveFile(SPECIAL_SAVESLOT);  		outFile->writeString(buf); -		outFile->writeString(character.getBaseName()); +		outFile->writeString(part);  		outFile->finalize();  		delete outFile;  	} @@ -447,17 +450,20 @@ void Parallaction_ns::setPartComplete(const Character& character) {  	return;  } -bool Parallaction_ns::allPartsComplete() { -	char buf[30]; +void SaveLoad_ns::getGamePartProgress(bool *complete, int size) { +	assert(complete && size >= 3); +	char buf[30];  	Common::InSaveFile *inFile = getInSaveFile(SPECIAL_SAVESLOT);  	inFile->readLine(buf, 29);  	delete inFile; -	return strstr(buf, "dino") && strstr(buf, "donna") && strstr(buf, "dough"); +	complete[0] = strstr(buf, "dino"); +	complete[1] = strstr(buf, "donna"); +	complete[2] = strstr(buf, "dough");  } -void Parallaction_ns::renameOldSavefiles() { +void SaveLoad_ns::renameOldSavefiles() {  	bool exists[NUM_SAVESLOTS];  	uint num = 0; @@ -465,7 +471,7 @@ void Parallaction_ns::renameOldSavefiles() {  	for (i = 0; i < NUM_SAVESLOTS; i++) {  		exists[i] = false; -		Common::String name = genSaveFileName(i, true); +		Common::String name = genOldSaveFileName(i);  		Common::InSaveFile *f = _saveFileMan->openForLoading(name.c_str());  		if (f) {  			exists[i] = true; @@ -493,8 +499,8 @@ void Parallaction_ns::renameOldSavefiles() {  	uint success = 0;  	for (i = 0; i < NUM_SAVESLOTS; i++) {  		if (exists[i]) { -			Common::String oldName = genSaveFileName(i, true); -			Common::String newName = genSaveFileName(i, false); +			Common::String oldName = genOldSaveFileName(i); +			Common::String newName = genSaveFileName(i);  			if (_saveFileMan->renameSavefile(oldName.c_str(), newName.c_str())) {  				success++;  			} else { @@ -520,4 +526,28 @@ void Parallaction_ns::renameOldSavefiles() {  } +bool SaveLoad_br::loadGame() { +	// TODO: implement loadgame +	return false; +} + +bool SaveLoad_br::saveGame() { +	// TODO: implement savegame +	return false; +} + +void SaveLoad_br::getGamePartProgress(bool *complete, int size) { +	assert(complete && size >= 3); + +	// TODO: implement progress loading + +	complete[0] = true; +	complete[1] = true; +	complete[2] = true; +} + +void SaveLoad_br::setPartComplete(const char *part) { +	// TODO: implement progress saving +} +  } // namespace Parallaction diff --git a/engines/parallaction/saveload.h b/engines/parallaction/saveload.h new file mode 100644 index 0000000000..10bb8aafc2 --- /dev/null +++ b/engines/parallaction/saveload.h @@ -0,0 +1,96 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + + +#ifndef PARALLACTION_SAVELOAD_H +#define PARALLACTION_SAVELOAD_H + +namespace Parallaction { + +struct Character; + + +class SaveLoad { + +protected: +	Common::SaveFileManager	*_saveFileMan; +	Common::String _saveFilePrefix; + +	Common::String genSaveFileName(uint slot); +	Common::InSaveFile *getInSaveFile(uint slot); +	Common::OutSaveFile *getOutSaveFile(uint slot); + +public: +	SaveLoad(Common::SaveFileManager* saveFileMan, const char *prefix) : _saveFileMan(saveFileMan), _saveFilePrefix(prefix) { } +	virtual ~SaveLoad() { } + +	virtual bool loadGame() = 0; +	virtual bool saveGame() = 0; +	virtual void getGamePartProgress(bool *complete, int size) = 0; +	virtual void setPartComplete(const char *part) = 0; + +	virtual void renameOldSavefiles() { } +}; + +class SaveLoad_ns : public SaveLoad { + +	Parallaction_ns *_vm; + +	Common::String	_saveFileName; +	Common::String genOldSaveFileName(uint slot); + +protected: +	void renameOldSavefiles(); +	void doLoadGame(uint16 slot); +	void doSaveGame(uint16 slot, const char* name); +	int  buildSaveFileList(Common::StringList& l); +	int  selectSaveFile(uint16 arg_0, const char* caption, const char* button); + +public: +	SaveLoad_ns(Parallaction_ns *vm, Common::SaveFileManager *saveFileMan) : SaveLoad(saveFileMan, "nippon"), _vm(vm) { } + +	virtual bool loadGame(); +	virtual bool saveGame(); +	virtual void getGamePartProgress(bool *complete, int size); +	virtual void setPartComplete(const char *part); +}; + +class SaveLoad_br : public SaveLoad { + +	Parallaction_br *_vm; + +public: +	SaveLoad_br(Parallaction_br *vm, Common::SaveFileManager *saveFileMan) : SaveLoad(saveFileMan, "bra"), _vm(vm) { } + +	virtual bool loadGame(); +	virtual bool saveGame(); +	virtual void getGamePartProgress(bool *complete, int size); +	virtual void setPartComplete(const char *part); +}; + + +} // namespace Parallaction + +#endif diff --git a/engines/parallaction/sound.cpp b/engines/parallaction/sound.cpp index 4ac1399c3a..df6867a90c 100644 --- a/engines/parallaction/sound.cpp +++ b/engines/parallaction/sound.cpp @@ -387,8 +387,7 @@ void AmigaSoundMan::playSfx(const char *filename, uint channel, bool looping, in  		rate = ch->header.samplesPerSec;  	} -	_mixer->playRaw(Audio::Mixer::kSFXSoundType, &ch->handle, ch->data, ch->dataSize, rate, flags, -1,  -			Audio::Mixer::kMaxChannelVolume, 0, loopStart, loopEnd); +	_mixer->playRaw(Audio::Mixer::kSFXSoundType, &ch->handle, ch->data, ch->dataSize, rate, flags, -1, volume, 0, loopStart, loopEnd);  }  void AmigaSoundMan::stopSfx(uint channel) { diff --git a/engines/parallaction/staticres.cpp b/engines/parallaction/staticres.cpp index 2c5cf281dd..071495e8f1 100644 --- a/engines/parallaction/staticres.cpp +++ b/engines/parallaction/staticres.cpp @@ -29,7 +29,7 @@  namespace Parallaction { -byte Parallaction_ns::_resMouseArrow[256] = { +byte Input::_resMouseArrow_NS[256] = {  	0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00,  	0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x00, 0x00, 0x00,  	0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x00, 0x00, 0x00, 0x00, @@ -335,12 +335,6 @@ const Parallaction_br::Callable Parallaction_br::_dosCallables[] = {  void Parallaction_ns::initResources() { -//	_zoneFlagNamesRes = _zoneFlagNamesRes_ns; -//	_zoneTypeNamesRes = _zoneTypeNamesRes_ns; -//	_commandsNamesRes = _commandsNamesRes_ns; -	_callableNamesRes = _callableNamesRes_ns; -//	_instructionNamesRes = _instructionNamesRes_ns; -  	_callableNames = new Table(ARRAYSIZE(_callableNamesRes_ns), _callableNamesRes_ns);  	_localFlagNames = new FixedTable(NUM_LOCATIONS, 1); @@ -356,13 +350,6 @@ void Parallaction_ns::initResources() {  void Parallaction_br::initResources() { -//	_zoneFlagNamesRes = _zoneFlagNamesRes_br; -//	_zoneTypeNamesRes = _zoneTypeNamesRes_br; -//	_commandsNamesRes = _commandsNamesRes_br; -	_callableNamesRes = _callableNamesRes_br; -//	_instructionNamesRes = _instructionNamesRes_br; -//	_audioCommandsNamesRes = _audioCommandsNamesRes_br; -  	_callableNames = new Table(ARRAYSIZE(_callableNamesRes_br), _callableNamesRes_br);  	_localFlagNames = new FixedTable(NUM_LOCATIONS, 2); diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp index 6513a92018..ccaac8227d 100644 --- a/engines/queen/sound.cpp +++ b/engines/queen/sound.cpp @@ -54,10 +54,27 @@ namespace Queen {  class AudioStreamWrapper : public Audio::AudioStream {  protected:  	Audio::AudioStream *_stream; +	int _rate;  public:  	AudioStreamWrapper(Audio::AudioStream *stream) {  		_stream = stream; + +		int rate = _stream->getRate(); + +		// A file where the sample rate claims to be 11025 Hz is +		// probably compressed with the old tool. We force the real +		// sample rate, which is 11840 Hz. +		// +		// However, a file compressed with the newer tool is not +		// guaranteed to have a sample rate of 11840 Hz. LAME will +		// automatically resample it to 12000 Hz. So in all other +		// cases, we use the rate from the file. + +		if (rate == 11025) +			_rate = 11840; +		else +			_rate = rate;  	}  	~AudioStreamWrapper() {  		delete _stream; @@ -75,7 +92,7 @@ public:  		return _stream->endOfStream();  	}  	int getRate() const { -		return 11840; +		return _rate;  	}  	int32 getTotalPlayTime() {  		return _stream->getTotalPlayTime(); @@ -314,10 +331,8 @@ void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *so  	if (sound) {  		f->read(sound, size);  		byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE; -		if (soundHandle == &_speechHandle) -			_mixer->playRaw(Audio::Mixer::kSpeechSoundType, soundHandle, sound, size, 11025, flags); -		else 	 -			_mixer->playRaw(Audio::Mixer::kSFXSoundType, soundHandle, sound, size, 11025, flags); +		Audio::Mixer::SoundType type = (soundHandle == &_speechHandle) ? Audio::Mixer::kSpeechSoundType : Audio::Mixer::kSFXSoundType; +		_mixer->playRaw(type, soundHandle, sound, size, 11840, flags);  	}  } diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index 1005b0ab5f..9b0efad0d5 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -249,6 +249,8 @@ void MusicPlayer::setVolume(int volume) {  	_masterVolume = volume; +	Common::StackLock lock(_mutex); +  	for (int i = 0; i < 16; ++i) {  		if (_channel[i]) {  			_channel[i]->volume(_channelVolume[i] * _masterVolume / 255); diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index a2dbeebda2..aa3624acea 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -247,13 +247,20 @@ int SagaEngine::go() {  			_interface->addToInventory(_actor->objIndexToId(0));	// Magic hat  		_scene->changeScene(ConfMan.getInt("boot_param"), 0, kTransitionNoFade);  	} else if (ConfMan.hasKey("save_slot")) { +		// Init the current chapter to 8 (character selection) for IHNM +		if (getGameType() == GType_IHNM) +			_scene->changeScene(-2, 0, kTransitionFade, 8); +  		// First scene sets up palette  		_scene->changeScene(getStartSceneNumber(), 0, kTransitionNoFade);  		_events->handleEvents(0); // Process immediate events -		_interface->setMode(kPanelMain); -		char *fileName; -		fileName = calcSaveFileName(ConfMan.getInt("save_slot")); +		if (getGameType() != GType_IHNM) +			_interface->setMode(kPanelMain); +		else +			_interface->setMode(kPanelChapterSelection); + +		char *fileName = calcSaveFileName(ConfMan.getInt("save_slot"));  		load(fileName);  		syncSoundSettings();  	} else { diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp index 9a304de8e1..e1e1074e1d 100644 --- a/engines/saga/sfuncs.cpp +++ b/engines/saga/sfuncs.cpp @@ -276,31 +276,14 @@ void Script::sfTakeObject(SCRIPTFUNC_PARAMS) {  	if (obj->_sceneNumber != ITE_SCENE_INV) {  		obj->_sceneNumber = ITE_SCENE_INV; -		// WORKAROUND for a problematic object in IHNM -		// There are 3 different scenes in front of the zeppelin, in Gorrister's chapter. A scene where the -		// zeppelin is in the air (scene 17), a scene where it approaches Gorrister's (scene 16) and another one -		// where it has landed (scene 18). -		// In two of these scenes (the "on air" and "approaching" ones), when the player uses the knife with the -		// rope, the associated script picks up object id 16392. In the "zeppelin landed" scene (scene 18), the -		// associated script picks up object id 16390. This seems to be a script bug, as it should be id 16392, -		// like in the other two scenes, as it is the same object (the rope). Picking up object 16390 leads to an -		// assertion anyway, therefore we change the problematic object (16390) to the correct one (16392) here. -		// Fixes bug #1861126 - "IHNM: Crash when Gorrister cuts sheet in the mooring ring" -		if (_vm->getGameType() == GType_IHNM) { -			if (_vm->_scene->currentChapterNumber() == 1 && _vm->_scene->currentSceneNumber() == 18) { -				if (objectId == 16390) -					objectId = 16392; -			} -		} - -		// WORKAROUND for two incorrect object sprites in the IHNM demo -		// (the mirror and the icon in Ted's part). Set them correctly here -		if (_vm->getGameId() == GID_IHNM_DEMO) { -			if (objectId == 16408) -				obj->_spriteListResourceId = 24; -			if (objectId == 16409) -				obj->_spriteListResourceId = 25; -		} +		// Normally, when objects are picked up, they should always have the same +		// _spriteListResourceId as their _index value. Some don't in IHNM, so +		// we fix their sprite here +		// Fixes bugs #2057200 - "IHNM: Invisible inventory objects",  +		// #1861126 - "IHNM: Crash when Gorrister cuts sheet in the mooring ring" +		// and some incorrect objects in the IHNM demo +		if (_vm->getGameType() == GType_IHNM) +			obj->_spriteListResourceId = obj->_index;  		_vm->_interface->addToInventory(objectId);  	} diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index 324cc91e78..d281364a77 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -472,12 +472,14 @@ static const GameFilenamePattern gameFilenamesTable[] = {  	{ "fbear", "fbdemo", kGenHEPC, UNK_LANG, UNK, 0 },  	{ "fbear", "Fatty Bear Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 },  	{ "fbear", "Fatty Bear", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, +	{ "fbear", "jfbear", kGenHEPC, Common::JA_JPN, Common::kPlatform3DO, 0 },  	{ "puttmoon", "puttmoon", kGenHEPC, UNK_LANG, UNK, 0 },  	{ "puttmoon", "moondemo", kGenHEPC, UNK_LANG, UNK, 0 },  	{ "puttmoon", "Putt-Putt Moon Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 },  	{ "puttmoon", "Putt-Putt Moon", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, +	{ "puttputt", "jputtputt", kGenHEPC, Common::JA_JPN, Common::kPlatform3DO, 0 },  	{ "puttputt", "puttputt", kGenHEPC, UNK_LANG, UNK, 0 },  	{ "puttputt", "puttdemo", kGenHEPC, UNK_LANG, UNK, 0 },  	{ "puttputt", "Putt-Putt's Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index b590bba65e..41fe43835f 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -395,8 +395,7 @@ void SaveLoadChooser::updateInfos(bool redraw) {  		int hours = minutes / 60;  		minutes %= 60; -		snprintf(buffer, 32, "Playtime: %.2d:%.2d", -			hours & 0xFF, minutes & 0xFF); +		snprintf(buffer, 32, "Playtime: %.2d:%.2d", hours, minutes);  		_playtime->setLabel(buffer);  	} else {  		_date->setLabel("No date saved"); diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index d09accafb0..45b078b6f9 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -46,7 +46,7 @@ namespace Scumm {  static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h);  static void fill(byte *dst, int dstPitch, byte color, int w, int h); -#ifndef ARM_USE_GFX_ASM +#ifndef USE_ARM_GFX_ASM  static void copy8Col(byte *dst, int dstPitch, const byte *src, int height);  #endif  static void clear8Col(byte *dst, int dstPitch, int height); @@ -612,32 +612,37 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i  		assert(0 == (width & 3));  		// Compose the text over the game graphics - -		// TODO: Optimize this code. There are several things that come immediately to mind: -		// (1) Loop unrolling: We could read 4 or even 8 pixels at once, since everything is -		//     a multiple of 8 here. -		// (2) More ASM versions (in particular, the ARM code for the NDS could be used on -		//     all ARM systems, couldn't it?) -		// (3) Better encoding of the text surface data. This is the one with the biggest -		//     potential. -		//     (a) Keep an "isEmpty" marker for each pixel row in the _textSurface. The idea -		//         is that most rows won't contain any text data, so we can just use memcpy. -		//     (b) RLE encode the _textSurface row-wise. This is an improved variant of (a), -		//         but also more complicated to implement, and incurs a bigger overhead when -		//         writing to the text surface. -#ifdef ARM_USE_GFX_ASM +#ifdef USE_ARM_GFX_ASM  		asmDrawStripToScreen(height, width, text, src, dst, vs->pitch, width, _textSurface.pitch);  #else -		for (int h = 0; h < height * m; ++h) { -			for (int w = 0; w < width * m; ++w) { -				byte tmp = *text++; -				if (tmp == CHARSET_MASK_TRANSPARENCY) -					tmp = *src; -				*dst++ = tmp; -				src++; +		// We blit four pixels at a time, for improved performance. +		const uint32 *src32 = (const uint32 *)src; +		const uint32 *text32 = (const uint32 *)text; +		uint32 *dst32 = (uint32 *)dst; +		 +		vsPitch >>= 2; +		const int textPitch = (_textSurface.pitch - width * m) >> 2; +		for (int h = height * m; h > 0; --h) { +			for (int w = width*m; w > 0; w-=4) { +				uint32 temp = *text32++; +				 +				// Generate a byte mask for those text pixels (bytes) with +				// value CHARSET_MASK_TRANSPARENCY. In the end, each byte +				// in mask will be either equal to 0x00 or 0xFF. +				// Doing it this way avoids branches and bytewise operations, +				// at the cost of readability ;). +				uint32 mask = temp ^ CHARSET_MASK_TRANSPARENCY_32; +				mask = (((mask & 0x7f7f7f7f) + 0x7f7f7f7f) | mask) & 0x80808080; +				mask = ((mask >> 7) + 0x7f7f7f7f) ^ 0x80808080; +				 +				// The following line is equivalent to this code: +				//   *dst32++ = (*src32++ & mask) | (temp & ~mask); +				// However, some compilers can generate somewhat better +				// machine code for this equivalent statement: +				*dst32++ = ((temp ^ *src32++) & mask) ^ temp;  			} -			src += vsPitch; -			text += _textSurface.pitch - width * m; +			src32 += vsPitch; +			text32 += textPitch;  		}  #endif  		src = _compositeBuf; @@ -1078,7 +1083,7 @@ static void fill(byte *dst, int dstPitch, byte color, int w, int h) {  	}  } -#ifdef ARM_USE_GFX_ASM +#ifdef USE_ARM_GFX_ASM  #define copy8Col(A,B,C,D) asmCopy8Col(A,B,C,D) @@ -1098,7 +1103,7 @@ static void copy8Col(byte *dst, int dstPitch, const byte *src, int height) {  	} while (--height);  } -#endif /* ARM_USE_GFX_ASM */ +#endif /* USE_ARM_GFX_ASM */  static void clear8Col(byte *dst, int dstPitch, int height) {  	do { diff --git a/engines/scumm/gfx.h b/engines/scumm/gfx.h index e03fdd1c53..e4c1054450 100644 --- a/engines/scumm/gfx.h +++ b/engines/scumm/gfx.h @@ -174,7 +174,8 @@ struct ColorCycle {  struct StripTable; -#define CHARSET_MASK_TRANSPARENCY	253 +#define CHARSET_MASK_TRANSPARENCY	 0xFD +#define CHARSET_MASK_TRANSPARENCY_32 0xFDFDFDFD  class Gdi {  protected: diff --git a/engines/scumm/gfxARM.s b/engines/scumm/gfxARM.s index 83aaa78927..f3a1f20303 100644 --- a/engines/scumm/gfxARM.s +++ b/engines/scumm/gfxARM.s @@ -24,7 +24,7 @@  	.global	asmDrawStripToScreen  	.global	asmCopy8Col -	 +  	@ ARM implementation of asmDrawStripToScreen.  	@  	@ C prototype would be: @@ -47,7 +47,7 @@ asmDrawStripToScreen:  	@ r2 = text  	@ r3 = src  	MOV	r12,r13 -	STMFD	r13!,{r4-r7,r9-r11,R14} +	STMFD	r13!,{r4-r11,R14}  	LDMIA	r12,{r4,r5,r6,r7}  	@ r4 = dst  	@ r5 = vsPitch @@ -69,57 +69,46 @@ asmDrawStripToScreen:  	MOV	r10,#253  	ORR	r10,r10,r10,LSL #8  	ORR	r10,r10,r10,LSL #16	@ r10 = mask -yLoop: -	MOV	r14,r1			@ r14 = width +	MOV	r8,#0x7F +	ORR	r8, r8, r8, LSL #8 +	ORR	r8, r8, r8, LSL #16	@ r8  = 7f7f7f7f +	STR	r1,[r13,#-4]!		@ Stack width +	B	xLoop + +notEntirelyTransparent: +	AND	r14,r9, r8		@ r14  =  mask & 7f7f7f7f +	ADD	r14,r14,r8		@ r14  = (mask & 7f7f7f7f)+7f7f7f7f +	ORR	r14,r14,r9		@ r14 |= mask +	BIC	r14,r14,r8		@ r14 &= 80808080 +	ADD	r14,r8, r14,LSR #7	@ r14  = (rx>>7) + 7f7f7f7f +	EOR	r14,r14,r8		@ r14 ^= 7f7f7f7f +	@ So bytes of r14 are 00 where source was matching value,FF otherwise +	BIC	r11,r11,r14 +	AND	r12,r12,r14 +	ORR	r12,r11,r12 +	STR	r12,[r4],#4 +	SUBS	r1,r1,#4 +	BLE	endXLoop  xLoop: -	LDR	r12,[r2],#4		@ r12 = [text] -	LDR	r11,[r3],#4		@ r11 = [src] -	CMP	r12,r10 -	BNE	singleByteCompare -	SUBS	r14,r14,#4 +	LDR	r12,[r2],#4		@ r12 = temp = [text] +	LDR	r11,[r3],#4		@ r11 =        [src] +	@ Stall +	EORS	r9, r12,r10		@ r9  = mask = temp ^ TRANSPARENCY +	BNE	notEntirelyTransparent +	SUBS	r1, r1, #4  	STR	r11,[r4], #4		@ r4 = [dst]  	BGT	xLoop - +endXLoop:  	ADD	r2,r2,r7		@ text += textSurfacePitch  	ADD	r3,r3,r5		@ src  += vsPitch  	ADD	r4,r4,r6		@ dst  += vmScreenWidth  	SUBS	r0,r0,#1 -	BGT	yLoop -	LDMFD	r13!,{r4-r7,r9-r11,PC} - -singleByteCompare: -	MOV	r9,r12,LSR #24		@ r9 = 1st byte of [text] -	CMP	r9,r10,LSR #24		@ if (r9 == mask) -	MOVEQ	r9,r11,LSR #24		@     r9 = 1st byte of [src] -	ORR	r12,r9,r12,LSL #8	@ r12 = combine r9 and r12 - -	MOV	r9,r12,LSR #24		@ r9 = 1st byte of [text] -	CMP	r9,r10,LSR #24		@ if (r9 == mask) -	MOVEQ	r9,r11,LSR #24		@     r9 = 1st byte of [src] -	ORR	r12,r9,r12,LSL #8	@ r12 = combine r9 and r12 - -	MOV	r9,r12,LSR #24		@ r9 = 1st byte of [text] -	CMP	r9,r10,LSR #24		@ if (r9 == mask) -	MOVEQ	r9,r11,LSR #24		@     r9 = 1st byte of [src] -	ORR	r12,r9,r12,LSL #8	@ r12 = combine r9 and r12 - -	MOV	r9,r12,LSR #24		@ r9 = 1st byte of [text] -	CMP	r9,r10,LSR #24		@ if (r9 == mask) -	MOVEQ	r9,r11,LSR #24		@     r9 = 1st byte of [src] -	ORR	r12,r9,r12,LSL #8	@ r12 = combine r9 and r12 - -	STR	r12,[r4],#4 -	SUBS	r14,r14,#4 +	LDRGT	r1,[r13]		@ r14 = width  	BGT	xLoop - -	ADD	r2,r2,r7		@ text += textSurfacePitch -	ADD	r3,r3,r5		@ src  += vsPitch -	ADD	r4,r4,r6		@ dst  += vmScreenWidth -	SUBS	r0,r0,#1 -	BGT	yLoop +	ADD	r13,r13,#4  end: -	LDMFD	r13!,{r4-r7,r9-r11,PC} -	 +	LDMFD	r13!,{r4-r11,PC} +  	@ ARM implementation of asmCopy8Col  	@  	@ C prototype would be: @@ -156,4 +145,4 @@ roll2:  	STR	r14,[r0],r1  	BNE	yLoop2 -	LDMFD	r13!,{PC}	 +	LDMFD	r13!,{PC} diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index 7d52a02116..b86ad8159b 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -53,7 +53,6 @@ MODULE_OBJS := \  	scumm.o \  	sound.o \  	string.o \ -	thumbnail.o \  	usage_bits.o \  	util.o \  	vars.o \ diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index 9823a9483f..36621440eb 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -809,7 +809,7 @@ byte *ResourceManager::createResource(int type, int idx, uint32 size) {  	ptr = (byte *)calloc(size + sizeof(MemBlkHeader) + SAFETY_AREA, 1);  	if (ptr == NULL) { -		error("Out of memory while allocating %d", size); +		error("createResource(%s,%d): Out of memory while allocating %d", resTypeFromId(type), idx, size);  	}  	_allocatedSize += size; diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 426c7ee48b..eb7cf1ba56 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -46,6 +46,8 @@  #include "sound/audiocd.h"  #include "sound/mixer.h" +#include "graphics/thumbnail.h" +  namespace Scumm {  struct SaveGameHeader { @@ -71,6 +73,22 @@ struct SaveInfoSection {  #define INFOSECTION_VERSION 2 +Graphics::Surface *ScummEngine::loadThumbnail(Common::SeekableReadStream *file) { +	if (!Graphics::checkThumbnailHeader(*file)) +		return 0; + +	Graphics::Surface *thumb = new Graphics::Surface(); +	assert(thumb); +	if (!Graphics::loadThumbnail(*file, *thumb)) { +		delete thumb; +		return 0; +	} + +	return thumb; +} + +#pragma mark - +  void ScummEngine::requestSave(int slot, const char *name, bool temporary) {  	_saveLoadSlot = slot;  	_saveTemporaryState = temporary; @@ -114,7 +132,9 @@ bool ScummEngine::saveState(int slot, bool compat) {  	memcpy(hdr.name, _saveLoadName, sizeof(hdr.name));  	saveSaveGameHeader(out, hdr); -	saveThumbnail(out); +#if !defined(__DS__) +	Graphics::saveThumbnail(*out); +#endif  	saveInfos(out);  	Serializer ser(0, out, CURRENT_VER); @@ -185,16 +205,16 @@ bool ScummEngine::loadState(int slot, bool compat) {  	// Since version 52 a thumbnail is saved directly after the header.  	if (hdr.ver >= VER(52)) { -		uint32 type = in->readUint32BE(); -		// Check for the THMB header. Also, work around a bug which caused -		// the chunk type (incorrectly) to be written in LE on LE machines. -		if (! (type == MKID_BE('THMB') || (hdr.ver < VER(55) && type == MKID_BE('BMHT')))){ -			warning("Can not load thumbnail"); -			delete in; -			return false; +		// Prior to version 75 we always required an thumbnail to be present +		if (hdr.ver <= VER(74)) { +			if (!Graphics::checkThumbnailHeader(*in)) { +				warning("Can not load thumbnail"); +				delete in; +				return false; +			}  		} -		uint32 size = in->readUint32BE(); -		in->skip(size - 8); + +		Graphics::skipThumbnailHeader(*in);  	}  	// Since version 56 we save additional information about the creation of diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 2d7ee64680..4f9899f961 100644 --- a/engines/scumm/saveload.h +++ b/engines/scumm/saveload.h @@ -50,7 +50,7 @@ namespace Scumm {   * only saves/loads those which are valid for the version of the savegame   * which is being loaded/saved currently.   */ -#define CURRENT_VER 74 +#define CURRENT_VER 75  /**   * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp index 245dca883a..c8534396db 100644 --- a/engines/scumm/script_v6.cpp +++ b/engines/scumm/script_v6.cpp @@ -2374,7 +2374,7 @@ void ScummEngine_v6::o6_printEgo() {  void ScummEngine_v6::o6_talkActor() {  	int offset = _scriptPointer - _scriptOrgPointer; -	// WORKAROUNDfor bug #896489: see below for detailed description +	// WORKAROUND for bug #896489: see below for detailed description  	if (_forcedWaitForMessage) {  		if (VAR(VAR_HAVE_MSG)) {  			_scriptPointer--; diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index ce8f0a4d9a..eec9d33903 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@  /* -  This file was generated by the md5table tool on Mon Jul 28 00:13:01 2008 +  This file was generated by the md5table tool on Tue Aug 26 11:12:54 2008    DO NOT EDIT MANUALLY!   */ @@ -54,6 +54,7 @@ static const MD5Table md5table[] = {  	{ "0f5935bd5e88ba6f09e558d64459746d", "thinker1", "", "Demo", 30919, Common::EN_USA, Common::kPlatformWindows },  	{ "0f6f2e716ba896a44e5059bba1de7ca9", "samnmax", "", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown },  	{ "0f9c7a76657f0840b8f7ccb5bffeb9f4", "indy3", "No Adlib", "EGA", -1, Common::FR_FRA, Common::kPlatformAtariST }, +	{ "0f9d3317910ac7a9f449243118884ada", "puttzoo", "", "", 42070, Common::DE_DEU, Common::kPlatformWindows },  	{ "0fb73eddfcf584c02ba097984df131ba", "samnmax", "", "CD", 9080, Common::DE_DEU, Common::kPlatformUnknown },  	{ "1005456bfe351c1b679e1ff2dc2849e9", "puttzoo", "", "", -1, Common::UNK_LANG, Common::kPlatformWindows },  	{ "100b4c8403ad6a83d4bf7dbf83e44dc4", "spyfox", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, @@ -63,6 +64,7 @@ static const MD5Table md5table[] = {  	{ "11e6e244078ff09b0f3832e35420e0a7", "catalog", "", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },  	{ "132bff65e6367c09cc69318ce1b59333", "monkey2", "", "", 11155, Common::EN_ANY, Common::kPlatformAmiga },  	{ "1387d16aa620dc1c2d1fd87f8a9e7a09", "puttcircus", "", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, +	{ "13d2a86a7290813a1c386490447d72db", "fbear", "HE 61", "", -1, Common::EN_ANY, Common::kPlatform3DO },  	{ "145bd3373574feb668cc2eea2ec6cf86", "balloon", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows },  	{ "14d48c95b43ddeb983254cf6c43851f1", "freddi4", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown },  	{ "151071053a1d0021198216713939521d", "freddi2", "HE 80", "", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -98,6 +100,7 @@ static const MD5Table md5table[] = {  	{ "1ff5997c78fbd0a841a75ef15a05d9d5", "BluesBirthday", "", "", -1, Common::EN_ANY, Common::kPlatformWindows },  	{ "2012f854d83d9cc6f73b2b544cd8bbf8", "water", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows },  	{ "20176076d708bf14407bcc9bdcd7a418", "pajama3", "", "", -1, Common::RU_RUS, Common::kPlatformWindows }, +	{ "204453e33456c4faa26e276229fe5b76", "spyfox2", "", "Demo", 14689, Common::DE_DEU, Common::kPlatformWindows },  	{ "20da6fce37805423966aaa8f3c2426aa", "atlantis", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformAmiga },  	{ "2108d83dcf09f8adb4bc524669c8cf51", "PuttTime", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },  	{ "21a6592322f92550f144f68a8a4e685e", "dig", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, @@ -106,6 +109,7 @@ static const MD5Table md5table[] = {  	{ "225e18566e810c634bf7de63e7568e3e", "mustard", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },  	{ "22c9eb04455440131ffc157aeb8d40a8", "fbear", "HE 70", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },  	{ "22d07d6c386c9c25aca5dac2a0c0d94b", "maniac", "NES", "", 262144, Common::SE_SWE, Common::kPlatformNES }, +	{ "22de86b2f7ec6e5db745ed1123310b44", "spyfox2", "", "Demo", 15832, Common::FR_FRA, Common::kPlatformWindows },  	{ "22f4ea88a09da12df9308ba30bcb7d0f", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC },  	{ "23394c8d29cc63c61313959431a12476", "spyfox", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows },  	{ "257f8c14d8c584f7ddd601bcb00920c7", "maniac", "NES", "", 262144, Common::DE_DEU, Common::kPlatformNES }, @@ -144,6 +148,7 @@ static const MD5Table md5table[] = {  	{ "362c1d281fb9899254cda66ad246c66a", "dig", "Demo", "Demo", 3472, Common::EN_ANY, Common::kPlatformUnknown },  	{ "3686cf8f89e102ececf4366e1d2c8126", "monkey2", "", "", 11135, Common::EN_ANY, Common::kPlatformPC },  	{ "36a6750e03fb505fc19fc2bf3e4dbe91", "pajama2", "", "Demo", 58749, Common::EN_ANY, Common::kPlatformUnknown }, +	{ "3769b56c9a22f5521d74525ee459f88d", "puttrace", "HE 99", "Demo", 13108, Common::DE_DEU, Common::kPlatformWindows },  	{ "37aed3f91c1ef959e0bd265f9b13781f", "pajama", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },  	{ "37f56ceb13e401a7ac7d9e6b37fecaf7", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformPC },  	{ "37ff1b308999c4cca7319edfcc1280a0", "puttputt", "HE 70", "Demo", 8269, Common::EN_ANY, Common::kPlatformWindows }, @@ -201,6 +206,7 @@ static const MD5Table md5table[] = {  	{ "4edbf9d03550f7ba01e7f34d69b678dd", "spyfox", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows },  	{ "4f04b321a95d4315ce6d65f8e1dd0368", "maze", "HE 80", "", -1, Common::EN_USA, Common::kPlatformUnknown },  	{ "4f138ac6f9b2ac5a41bc68b2c3296064", "freddi4", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, +	{ "4f1d6f8b38343dba405472538b5037ed", "fbear", "HE 61", "", 7717, Common::EN_ANY, Common::kPlatformPC },  	{ "4f267a901719623de7dde83e47d5b474", "atlantis", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga },  	{ "4f580a021eee026f3b4589e17d130d78", "freddi4", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown },  	{ "4fa6870d9bc8c313b65d54b1da5a1891", "pajama", "", "", -1, Common::NL_NLD, Common::kPlatformWindows }, @@ -272,6 +278,7 @@ static const MD5Table md5table[] = {  	{ "6b27dbcd8d5697d5c918eeca0f68ef6a", "puttrace", "HE CUP", "Preview", 3901484, Common::UNK_LANG, Common::kPlatformUnknown },  	{ "6b3ec67da214f558dc5ceaa2acd47453", "indy3", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC },  	{ "6b5a3fef241e90d4b2e77f1e222773ee", "maniac", "NES", "extracted", -1, Common::SE_SWE, Common::kPlatformNES }, +	{ "6bca7a1a96d16e52b8f3c42b50dbdca3", "fbear", "HE 61", "", -1, Common::JA_JPN, Common::kPlatform3DO },  	{ "6bf70eee5de3d24d2403e0dd3d267e8a", "spyfox", "", "", 49221, Common::UNK_LANG, Common::kPlatformWindows },  	{ "6c2bff0e327f2962e809c2e1a82d7309", "monkey", "VGA", "VGA", -1, Common::EN_ANY, Common::kPlatformAmiga },  	{ "6d1baa1065ac5f7b210be8ebe4235e49", "freddi", "HE 73", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, @@ -296,14 +303,17 @@ static const MD5Table md5table[] = {  	{ "73e5ab7dbb9a8061cc6d25df02dbd1e7", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC },  	{ "7410a8ba9795020cd42f171c4320659e", "pajama3", "", "", -1, Common::FR_FRA, Common::kPlatformWindows },  	{ "746e88c172a5b7a1ae89ac0ee3ee681a", "freddi", "HE 90", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows }, +	{ "74da3494fbe1a7d20213b0afe0954755", "catalog", "HE CUP", "Preview", 10841544, Common::FR_FRA, Common::kPlatformUnknown },  	{ "754feb59d3bf86b8a00840df74fd7b26", "freddi3", "", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows },  	{ "75ba23fff4fd63fa446c02864f2a5a4b", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformPC },  	{ "75bff95816b84672b877d22a911ab811", "freddi3", "HE 99", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows },  	{ "76b66b43e593ad4d2f1dfb5cc8f19700", "spyfox", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformWindows },  	{ "771bc18ec6f93837b839c992b211904b", "monkey", "Demo", "EGA Demo", -1, Common::DE_DEU, Common::kPlatformPC }, +	{ "7766c9487f9d53a8cb0edabda5119c3d", "puttputt", "HE 60", "", 8022, Common::EN_ANY, Common::kPlatformPC },  	{ "77f5c9cc0986eb729c1a6b4c8823bbae", "zak", "FM-TOWNS", "Demo", 7520, Common::EN_ANY, Common::kPlatformFMTowns },  	{ "780e4a0ae2ff17dc296f4a79543b44f8", "puttmoon", "", "", -1, Common::UNK_LANG, Common::kPlatformPC },  	{ "782393c5934ecd0b536eaf5fd541bd26", "pajama", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, +	{ "784b499c98d07260a30952685758636b", "pajama3", "", "Demo", 13911, Common::DE_DEU, Common::kPlatformWindows },  	{ "78bd5f036ea35a878b74e4f47941f784", "freddi4", "HE 99", "", -1, Common::RU_RUS, Common::kPlatformWindows },  	{ "78c07ca088526d8d4446a4c2cb501203", "freddi3", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformUnknown },  	{ "7974365d3dc0f43a2748c975f91ff042", "monkey2", "", "", -1, Common::ES_ESP, Common::kPlatformPC }, @@ -322,6 +332,7 @@ static const MD5Table md5table[] = {  	{ "81bbfa181184cb494e7a81dcfa94fbd9", "maniac", "NES", "", 262144, Common::FR_FRA, Common::kPlatformNES },  	{ "8299d9b8a1b0e7b881bae7a9971dc5e2", "zak", "V2", "Demo", 1916, Common::EN_ANY, Common::kPlatformAtariST },  	{ "8368f552b1e3eba559f8d559bcc4cadb", "freddi3", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown }, +	{ "839a658f7d22de00787ebc945348cdb6", "dog", "", "", 19681, Common::DE_DEU, Common::kPlatformWindows },  	{ "83cedbe26aa8b58988e984e3d34cac8e", "freddi3", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown },  	{ "84e3c23a49ded8a6f9197735c8eb3de7", "PuttTime", "HE 85", "", -1, Common::DE_DEU, Common::kPlatformWindows },  	{ "8539c0ff89868e55a08e652ac44daaae", "water", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, @@ -429,7 +440,9 @@ static const MD5Table md5table[] = {  	{ "b886b0a5d909c7158a914e1d7c1c6c65", "loom", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformPC },  	{ "b8955d7d23b4972229060d1592489fef", "freddicove", "HE 100", "", -1, Common::NL_NLD, Common::kPlatformUnknown },  	{ "b9ba19ce376efc69be78ef3baef8d2b9", "monkey", "CD", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, +	{ "b9bb68c5d2c9b6e2d9c513a29a754a57", "puttmoon", "", "", 7828, Common::EN_ANY, Common::kPlatformPC },  	{ "ba888e6831517597859e91aa173f945c", "spyfox", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, +	{ "bab0fb81dcb12b8930c5d850b8f2a7de", "balloon", "HE 80", "", 12800, Common::DE_DEU, Common::kPlatformWindows },  	{ "bbadf7309c4a2c2763e4bbba3c3be634", "freddi3", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown },  	{ "bc4700bc0e12879f6d25d14d6be6cfdd", "spyfox2", "", "", -1, Common::DE_DEU, Common::kPlatformUnknown },  	{ "bd126753de619a495f9f22adc951c8d5", "monkey2", "", "", -1, Common::IT_ITA, Common::kPlatformPC }, @@ -546,6 +559,7 @@ static const MD5Table md5table[] = {  	{ "ed361270102e355afe5236954216aba2", "lost", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },  	{ "ede149fda3edfc1dbd7347e0737cb583", "tentacle", "", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh },  	{ "edfdb24a499d92c59f824c52987c0eec", "atlantis", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, +	{ "ee41f6afbc5b26fa475754b56fe92048", "puttputt", "HE 61", "", 8032, Common::JA_JPN, Common::kPlatform3DO },  	{ "ee785fe2569bc9965526e774f7ab86f1", "spyfox", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh },  	{ "ef347474f3c7be3b29584eaa133cca05", "samnmax", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC },  	{ "ef74d9071d4e564b037cb44bd6774de7", "fbear", "HE 61", "", -1, Common::HB_ISR, Common::kPlatformPC }, diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 054a1f59b9..3667e5770d 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -632,9 +632,9 @@ public:  protected:  	Graphics::Surface *loadThumbnail(Common::SeekableReadStream *file); -	bool loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff); -	void saveThumbnail(Common::WriteStream *file); +  	void saveInfos(Common::WriteStream* file); +	bool loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff);  	int32 _engineStartTime;  	int32 _pauseStartTime; diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp index 850b547021..e4d8393dbe 100644 --- a/engines/scumm/smush/smush_player.cpp +++ b/engines/scumm/smush/smush_player.cpp @@ -55,10 +55,6 @@  #include "sound/vorbis.h"  #include "sound/mp3.h" -#ifdef DUMP_SMUSH_FRAMES -#include <png.h> -#endif -  #include "common/zlib.h"  namespace Scumm { @@ -212,10 +208,6 @@ static StringResource *getStrings(ScummEngine *vm, const char *file, bool is_enc  void SmushPlayer::timerCallback() {  	parseNextFrame(); -#ifdef _WIN32_WCE -	_inTimer = true; -	_inTimerCount++; -#endif  }  SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) { @@ -252,11 +244,6 @@ SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) {  	_paused = false;  	_pauseStartTime = 0;  	_pauseTime = 0; -#ifdef _WIN32_WCE -	_inTimer = false; -	_inTimerCount = 0; -	_inTimerCountRedraw = ConfMan.getInt("Smush_force_redraw"); -#endif  }  SmushPlayer::~SmushPlayer() { @@ -926,14 +913,7 @@ void SmushPlayer::handleFrame(Chunk &b) {  	}  	if (_width != 0 && _height != 0) { -#ifdef _WIN32_WCE -		if (!_inTimer || _inTimerCount == _inTimerCountRedraw) { -			updateScreen(); -			_inTimerCount = 0; -		} -#else  		updateScreen(); -#endif  	}  	_smixer->handleFrame(); @@ -1098,57 +1078,6 @@ void SmushPlayer::warpMouse(int x, int y, int buttons) {  }  void SmushPlayer::updateScreen() { -#ifdef DUMP_SMUSH_FRAMES -	char fileName[100]; -	// change path below for dump png files -	sprintf(fileName, "/path/to/somethere/%s%04d.png", _vm->getBaseName(), _frame); -	FILE *file = fopen(fileName, "wb"); -	if (file == NULL) -		error("can't open file for writing png"); - -	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); -	if (png_ptr == NULL) { -		fclose(file); -		error("can't write png header"); -	} -	png_infop info_ptr = png_create_info_struct(png_ptr); -	if (info_ptr == NULL) { -		fclose(file); -		error("can't create png info struct"); -	} -	if (setjmp(png_ptr->jmpbuf)) { -		fclose(file); -		error("png jmpbuf error"); -	} - -	png_init_io(png_ptr, file); - -	png_set_IHDR(png_ptr, info_ptr, _width, _height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, -							PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - -	png_colorp palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color)); -	for (int i = 0; i != 256; ++i) { -		(palette + i)->red = _pal[i * 3 + 0]; -		(palette + i)->green = _pal[i * 3 + 1]; -		(palette + i)->blue = _pal[i * 3 + 2]; -	} - -	png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); - -	png_write_info(png_ptr, info_ptr); -	png_set_flush(png_ptr, 10); - -	png_bytep row_pointers[480]; -	for (int y = 0 ; y < _height ; y++) -		row_pointers[y] = (png_byte *) (_dst + y * _width); -	png_write_image(png_ptr, row_pointers); -	png_write_end(png_ptr, info_ptr); -	png_free(png_ptr, palette); - -	fclose(file); -	png_destroy_write_struct(&png_ptr, &info_ptr); -#endif -  	uint32 end_time, start_time = _vm->_system->getMillis();  	_updateNeeded = true;  	end_time = _vm->_system->getMillis(); @@ -1326,10 +1255,6 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st  				_vm->_system->updateScreen();  				_updateNeeded = false;  			} -#ifdef _WIN32_WCE -			_inTimer = false; -			_inTimerCount = 0; -#endif  		}  		if (_endOfFile)  			break; diff --git a/engines/scumm/smush/smush_player.h b/engines/scumm/smush/smush_player.h index 413a5895d3..64ae167349 100644 --- a/engines/scumm/smush/smush_player.h +++ b/engines/scumm/smush/smush_player.h @@ -84,11 +84,6 @@ private:  	bool _insanity;  	bool _middleAudio;  	bool _skipPalette; -#ifdef _WIN32_WCE -	bool _inTimer; -	int16 _inTimerCount; -	int16 _inTimerCountRedraw; -#endif  public:  	SmushPlayer(ScummEngine_v7 *scumm); diff --git a/engines/scumm/thumbnail.cpp b/engines/scumm/thumbnail.cpp deleted file mode 100644 index 40f1ee48e5..0000000000 --- a/engines/scumm/thumbnail.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* 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 file 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. - * - * $URL$ - * $Id$ - * - */ - - -#include "common/system.h" -#include "common/savefile.h" -#include "graphics/scaler.h" -#include "scumm/scumm.h" - -namespace Scumm { - -#define THMB_VERSION 1 - -struct ThumbnailHeader { -	uint32 type; -	uint32 size; -	byte version; -	uint16 width, height; -	byte bpp; -}; - -#define ThumbnailHeaderSize (4+4+1+2+2+1) - -inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) { -	r = (((color >> 11) & 0x1F) << 3); -	g = (((color >> 5) & 0x3F) << 2); -	b = ((color&0x1F) << 3); -} - -Graphics::Surface *ScummEngine::loadThumbnail(Common::SeekableReadStream *file) { -	ThumbnailHeader header; - -	header.type = file->readUint32BE(); -	// We also accept the bad 'BMHT' header here, for the sake of compatibility -	// with some older savegames which were written incorrectly due to a bug in -	// ScummVM which wrote the thumb header type incorrectly on LE systems. -	if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT')) -		return 0; - -	header.size = file->readUint32BE(); -	header.version = file->readByte(); - -	if (header.version > THMB_VERSION) { -		file->skip(header.size - 9); -		warning("Loading a newer thumbnail version"); -		return 0; -	} - -	header.width = file->readUint16BE(); -	header.height = file->readUint16BE(); -	header.bpp = file->readByte(); - -	// TODO: support other bpp values than 2 -	if (header.bpp != 2) { -		file->skip(header.size - 14); -		return 0; -	} - -	Graphics::Surface *thumb = new Graphics::Surface(); -	thumb->create(header.width, header.height, sizeof(OverlayColor)); - -	OverlayColor* pixels = (OverlayColor *)thumb->pixels; - -	for (int y = 0; y < thumb->h; ++y) { -		for (int x = 0; x < thumb->w; ++x) { -			uint8 r, g, b; -			colorToRGB(file->readUint16BE(), r, g, b); - -			// converting to current OSystem Color -			*pixels++ = _system->RGBToColor(r, g, b); -		} -	} - -	return thumb; -} - -void ScummEngine::saveThumbnail(Common::OutSaveFile *file) { -	Graphics::Surface thumb; - -#if !defined(__DS__) -	if (!createThumbnailFromScreen(&thumb)) -#endif -		thumb.create(kThumbnailWidth, kThumbnailHeight2, sizeof(uint16)); - -	ThumbnailHeader header; -	header.type = MKID_BE('THMB'); -	header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel; -	header.version = THMB_VERSION; -	header.width = thumb.w; -	header.height = thumb.h; -	header.bpp = thumb.bytesPerPixel; - -	file->writeUint32BE(header.type); -	file->writeUint32BE(header.size); -	file->writeByte(header.version); -	file->writeUint16BE(header.width); -	file->writeUint16BE(header.height); -	file->writeByte(header.bpp); - -	// TODO: for later this shouldn't be casted to uint16... -	uint16* pixels = (uint16 *)thumb.pixels; -	for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels) -		file->writeUint16BE(*pixels); - -	thumb.free(); -} - -} // end of namespace Scumm diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index 76f14851e7..48196a2f7d 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -357,8 +357,8 @@ bool MoviePlayer::userInterrupt() {  		case Common::EVENT_SCREEN_CHANGED:  			handleScreenChanged();  			break; -		case Common::EVENT_RTL:  		case Common::EVENT_QUIT: +			_vm->closeGame();  			terminate = true;  			break;  		case Common::EVENT_KEYDOWN: @@ -379,7 +379,7 @@ void MoviePlayer::play(SequenceTextInfo *textList, uint32 numLines, int32 leadIn  	bool startNextText = false;  	// This happens if the user quits during the "eye" cutscene. -	if (_vm->quit()) +	if (_vm->_quit)  		return;  	_numSpeechLines = numLines; diff --git a/engines/sword2/controls.cpp b/engines/sword2/controls.cpp index dcacbc78d4..6b466d6be0 100644 --- a/engines/sword2/controls.cpp +++ b/engines/sword2/controls.cpp @@ -396,7 +396,7 @@ int Dialog::runModal() {  		_vm->_system->delayMillis(20); -		if (_vm->quit()) +		if (_vm->_quit)  			setResult(0);  	} @@ -842,7 +842,7 @@ int StartDialog::runModal() {  		if (startDialog.runModal())  			return 1; -		if (_vm->quit()) +		if (_vm->_quit)  			return 0;  		RestoreDialog restoreDialog(_vm); @@ -850,7 +850,7 @@ int StartDialog::runModal() {  		if (restoreDialog.runModal())  			return 0; -		if (_vm->quit()) +		if (_vm->_quit)  			return 0;  	} @@ -882,7 +882,7 @@ int QuitDialog::runModal() {  	int result = MiniDialog::runModal();  	if (result) -		_vm->quitGame(); +		_vm->closeGame();  	return result;  } diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp index 31b799386f..84a5b5af76 100644 --- a/engines/sword2/function.cpp +++ b/engines/sword2/function.cpp @@ -2388,7 +2388,7 @@ int32 Logic::fnPlayCredits(int32 *params) {  	// params:	none  	if (readVar(DEMO)) { -		_vm->quitGame(); +		_vm->closeGame();  		return IR_STOP;  	} diff --git a/engines/sword2/palette.cpp b/engines/sword2/palette.cpp index b66a3c9a81..81f93c77ae 100644 --- a/engines/sword2/palette.cpp +++ b/engines/sword2/palette.cpp @@ -212,7 +212,7 @@ uint8 Screen::getFadeStatus() {  }  void Screen::waitForFade() { -	while (getFadeStatus() != RDFADE_NONE && getFadeStatus() != RDFADE_BLACK && !_vm->quit()) { +	while (getFadeStatus() != RDFADE_NONE && getFadeStatus() != RDFADE_BLACK && !_vm->_quit) {  		updateDisplay();  		_vm->_system->delayMillis(20);  	} diff --git a/engines/sword2/resman.cpp b/engines/sword2/resman.cpp index 880234aab0..8cddddff78 100644 --- a/engines/sword2/resman.cpp +++ b/engines/sword2/resman.cpp @@ -412,7 +412,7 @@ Common::File *ResourceManager::openCluFile(uint16 fileNum) {  		// quit while the game is asking for the user to insert a CD.  		// But recovering from this situation gracefully is just too  		// much trouble, so quit now. -		if (_vm->quit()) +		if (_vm->_quit)  			g_system->quit();  		// If the file is supposed to be on hard disk, or we're diff --git a/engines/sword2/screen.cpp b/engines/sword2/screen.cpp index b2fcc45c9c..fdabb3ee6f 100644 --- a/engines/sword2/screen.cpp +++ b/engines/sword2/screen.cpp @@ -389,7 +389,7 @@ void Screen::displayMsg(byte *text, int time) {  		uint32 targetTime = _vm->getMillis() + (time * 1000);  		_vm->sleepUntil(targetTime);  	} else { -		while (!_vm->quit()) { +		while (!_vm->_quit) {  			MouseEvent *me = _vm->mouseEvent();  			if (me && (me->buttons & (RD_LEFTBUTTONDOWN | RD_RIGHTBUTTONDOWN)))  				break; @@ -1035,7 +1035,7 @@ void Screen::rollCredits() {  	uint32 musicLength = MAX((int32)(1000 * (_vm->_sound->musicTimeRemaining() - 3)), 25 * (int32)scrollSteps); -	while (scrollPos < scrollSteps && !_vm->quit()) { +	while (scrollPos < scrollSteps && !_vm->_quit) {  		clearScene();  		for (i = startLine; i < lineCount; i++) { @@ -1123,13 +1123,13 @@ void Screen::rollCredits() {  		// The music should either have stopped or be about to stop, so  		// wait for it to really happen. -		while (_vm->_sound->musicTimeRemaining() && !_vm->quit()) { +		while (_vm->_sound->musicTimeRemaining() && !_vm->_quit) {  			updateDisplay(false);  			_vm->_system->delayMillis(100);  		}  	} -	if (_vm->quit()) +	if (_vm->_quit)  		return;  	waitForFade(); diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp index 4f942c0d25..7331d1f761 100644 --- a/engines/sword2/sword2.cpp +++ b/engines/sword2/sword2.cpp @@ -33,7 +33,6 @@  #include "common/file.h"  #include "common/fs.h"  #include "common/events.h" -#include "common/savefile.h"  #include "common/system.h"  #include "engines/metaengine.h" @@ -80,23 +79,13 @@ public:  		return "Broken Sword Games (C) Revolution";  	} -	virtual bool hasFeature(MetaEngineFeature f) const;  	virtual GameList getSupportedGames() const;  	virtual GameDescriptor findGame(const char *gameid) const;  	virtual GameList detectGames(const FSList &fslist) const; -	virtual SaveStateList listSaves(const char *target) const;  	virtual PluginError createInstance(OSystem *syst, Engine **engine) const;  }; -bool Sword2MetaEngine::hasFeature(MetaEngineFeature f) const { -	return -		(f == kSupportsRTL) || -		(f == kSupportsListSaves) || -		(f == kSupportsDirectLoad) || -		(f == kSupportsDeleteSave); -} -  GameList Sword2MetaEngine::getSupportedGames() const {  	const Sword2::GameSettings *g = Sword2::sword2_settings;  	GameList games; @@ -167,35 +156,6 @@ GameList Sword2MetaEngine::detectGames(const FSList &fslist) const {  	return detectedGames;  } -SaveStateList Sword2MetaEngine::listSaves(const char *target) const { -	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); -	Common::StringList filenames; -	char saveDesc[SAVE_DESCRIPTION_LEN]; -	Common::String pattern = target; -	pattern += ".???"; - -	filenames = saveFileMan->listSavefiles(pattern.c_str()); -	sort(filenames.begin(), filenames.end());	// Sort (hopefully ensuring we are sorted numerically..) - -	SaveStateList saveList; -	for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { -		// Obtain the last 3 digits of the filename, since they correspond to the save slot -		int slotNum = atoi(file->c_str() + file->size() - 3); -		 -		if (slotNum >= 0 && slotNum <= 999) { -			Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); -			if (in) { -				in->readUint32LE(); -				in->read(saveDesc, SAVE_DESCRIPTION_LEN); -				saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file)); -				delete in; -			} -		} -	} - -	return saveList; -} -  PluginError Sword2MetaEngine::createInstance(OSystem *syst, Engine **engine) const {  	assert(syst);  	assert(engine); @@ -269,6 +229,7 @@ Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst) {  	_gameCycle = 0;  	_gameSpeed = 1; +	_quit = false;  	syst->getEventManager()->registerRandomSource(_rnd, "sword2");  } @@ -410,7 +371,7 @@ int Sword2Engine::init() {  		// player will kill the music for us. Otherwise, the restore  		// will either have killed the music, or done a crossfade. -		if (quit()) +		if (_quit)  			return 0;  		if (result) @@ -482,7 +443,7 @@ int Sword2Engine::go() {  		// because we want the break to happen before updating the  		// screen again. -		if (quit()) +		if (_quit)  			break;  		// creates the debug text blocks @@ -499,7 +460,11 @@ int Sword2Engine::go() {  #endif  	} -	return _eventMan->shouldRTL(); +	return 0; +} + +void Sword2Engine::closeGame() { +	_quit = true;  }  void Sword2Engine::restartGame() { @@ -645,6 +610,9 @@ void Sword2Engine::parseInputEvents() {  				_mouseEvent.buttons = RD_WHEELDOWN;  			}  			break; +		case Common::EVENT_QUIT: +			closeGame(); +			break;  		default:  			break;  		} diff --git a/engines/sword2/sword2.h b/engines/sword2/sword2.h index 9b589c347e..05c5d7fa47 100644 --- a/engines/sword2/sword2.h +++ b/engines/sword2/sword2.h @@ -141,6 +141,8 @@ public:  	bool getSubtitles() { return _useSubtitles; }  	void setSubtitles(bool b) { _useSubtitles = b; } +	bool _quit; +  	uint32 _features;  	MemoryManager *_memory; @@ -208,6 +210,7 @@ public:  	void startGame();  	void gameCycle(); +	void closeGame();  	void restartGame();  	void sleepUntil(uint32 time); diff --git a/engines/tinsel/config.cpp b/engines/tinsel/config.cpp index 4c143f1b8d..cb2099c130 100644 --- a/engines/tinsel/config.cpp +++ b/engines/tinsel/config.cpp @@ -24,8 +24,6 @@   * This file contains configuration functionality   */ -//#define USE_3FLAGS 1 -  #include "tinsel/config.h"  #include "tinsel/dw.h"  #include "tinsel/sound.h" @@ -47,7 +45,7 @@ int volVoice = MAXSAMPVOL;  int speedText = DEFTEXTSPEED;  int bSubtitles = false;  int bSwapButtons = 0; -LANGUAGE language = TXT_ENGLISH; +LANGUAGE g_language = TXT_ENGLISH;  int bAmerica = 0; @@ -55,9 +53,8 @@ int bAmerica = 0;  bool bNoBlocking;  /** - * WriteConfig() + * Write settings to config manager and flush the config file to disk.   */ -  void WriteConfig(void) {  	ConfMan.setInt("dclick_speed", dclickSpeed);  	ConfMan.setInt("music_volume", (volMidi * Audio::Mixer::kMaxChannelVolume) / MAXMIDIVOL); @@ -66,8 +63,33 @@ void WriteConfig(void) {  	ConfMan.setInt("talkspeed", (speedText * 255) / 100);  	ConfMan.setBool("subtitles", bSubtitles);  	//ConfMan.setBool("swap_buttons", bSwapButtons ? 1 : 0); -	//ConfigData.language = language;	// not necessary, as language has been set in the launcher  	//ConfigData.bAmerica = bAmerica;		// EN_USA / EN_GRB + +	// Store language for multilingual versions +	if ((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)) { +		Common::Language lang; +		switch (g_language) { +		case TXT_FRENCH: +			lang = Common::FR_FRA; +			break; +		case TXT_GERMAN: +			lang = Common::DE_DEU; +			break; +		case TXT_SPANISH: +			lang = Common::ES_ESP; +			break; +		case TXT_ITALIAN: +			lang = Common::IT_ITA; +			break; +		default: +			lang = Common::EN_ANY; +		} +		 +		ConfMan.set("language", Common::getLanguageCode(lang)); +	} +	 +	// Write to disk +	ConfMan.flushToDisk();  }  /*---------------------------------------------------------------------*\ @@ -94,24 +116,53 @@ void ReadConfig(void) {  	//ConfigData.language = language;	// not necessary, as language has been set in the launcher  	//ConfigData.bAmerica = bAmerica;		// EN_USA / EN_GRB -// The flags here control how many country flags are displayed in one of the option dialogs. -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) -	language = ConfigData.language; - #ifdef USE_3FLAGS -	if (language == TXT_ENGLISH || language == TXT_ITALIAN) { -		language = TXT_GERMAN; -		bSubtitles = true; +	// Set language - we'll be clever here and use the ScummVM language setting +	g_language = TXT_ENGLISH; +	Common::Language lang = _vm->getLanguage(); +	if (lang == Common::UNK_LANG && ConfMan.hasKey("language")) +		lang = Common::parseLanguage(ConfMan.get("language"));	// For multi-lingual versions, fall back to user settings +	switch (lang) { +	case Common::FR_FRA: +		g_language = TXT_FRENCH; +		break; +	case Common::DE_DEU: +		g_language = TXT_GERMAN; +		break; +	case Common::ES_ESP: +		g_language = TXT_SPANISH; +		break; +	case Common::IT_ITA: +		g_language = TXT_ITALIAN; +		break; +	default: +		g_language = TXT_ENGLISH;  	} - #endif - #ifdef USE_4FLAGS -	if (language == TXT_ENGLISH) { -		language = TXT_GERMAN; + +	if (lang == Common::JA_JPN) { +		// TODO: Add support for JAPAN version +	} else if (lang == Common::HB_ISR) { +		// TODO: Add support for HEBREW version + +		// The Hebrew version appears to the software as being English +		// but it needs to have subtitles on... +		g_language = TXT_ENGLISH;  		bSubtitles = true; +	} else if (_vm->getFeatures() & GF_USE_3FLAGS) { +		// 3 FLAGS version supports French, German, Spanish +		// Fall back to German if necessary +		if (g_language != TXT_FRENCH && g_language != TXT_GERMAN && g_language != TXT_SPANISH) { +			g_language = TXT_GERMAN; +			bSubtitles = true; +		} +	} else if (_vm->getFeatures() & GF_USE_4FLAGS) { +		// 4 FLAGS version supports French, German, Spanish, Italian +		// Fall back to German if necessary +		if (g_language != TXT_FRENCH && g_language != TXT_GERMAN && +				g_language != TXT_SPANISH && g_language != TXT_ITALIAN) { +			g_language = TXT_GERMAN; +			bSubtitles = true; +		}  	} - #endif -#else -	language = TXT_ENGLISH; -#endif  }  bool isJapanMode() { diff --git a/engines/tinsel/config.h b/engines/tinsel/config.h index 73cc411cb6..fc85f0abe0 100644 --- a/engines/tinsel/config.h +++ b/engines/tinsel/config.h @@ -30,23 +30,11 @@  namespace Tinsel { -// None of these defined -> 1 language, in ENGLISH.TXT -//#define USE_5FLAGS	1	// All 5 flags -//#define USE_4FLAGS	1	// French, German, Italian, Spanish -//#define USE_3FLAGS	1	// French, German, Spanish - -// The Hebrew version appears to the software as being English -// but it needs to have subtitles on... -//#define HEBREW	1 - -//#define JAPAN	1 - -  // double click timer initial value -#define	DOUBLE_CLICK_TIME	6	// 6 @ 18Hz = .33 sec - -#define DEFTEXTSPEED	0 - +enum { +	DOUBLE_CLICK_TIME	= 6,	// 6 @ 18Hz = .33 sec +	DEFTEXTSPEED		= 0 +};  extern int dclickSpeed;  extern int volMidi; @@ -55,7 +43,7 @@ extern int volVoice;  extern int speedText;  extern int bSubtitles;  extern int bSwapButtons; -extern LANGUAGE language; +extern LANGUAGE g_language;  extern int bAmerica;  void WriteConfig(void); diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp index b95662cbfe..f933b2dd79 100644 --- a/engines/tinsel/cursor.cpp +++ b/engines/tinsel/cursor.cpp @@ -49,7 +49,7 @@ namespace Tinsel {  //----------------- LOCAL DEFINES --------------------  #define ITERATION_BASE		FRAC_ONE -#define ITER_ACCELLERATION	(10L << (FRAC_BITS - 4)) +#define ITER_ACCELERATION	(10L << (FRAC_BITS - 4))  //----------------- LOCAL GLOBAL DATA -------------------- @@ -404,7 +404,8 @@ static void MoveCursor(void) {  	newY = intToFrac(ptMouse.y);  	// modify mouse driver position depending on cursor keys -	if ((dir = _vm->getKeyDirection()) != 0) { +	dir = _vm->getKeyDirection(); +	if (dir != 0) {  		if (dir & MSK_LEFT)  			newX -= IterationSize; @@ -417,7 +418,7 @@ static void MoveCursor(void) {  		if (dir & MSK_DOWN)  			newY += IterationSize; -		IterationSize += ITER_ACCELLERATION; +		IterationSize += ITER_ACCELERATION;  		// set new mouse driver position  		_vm->setMousePosition(Common::Point(fracToInt(newX), fracToInt(newY))); diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index 7da4192456..f4fe876290 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -130,6 +130,96 @@ static const TinselGameDescription gameDescriptions[] = {  		TINSEL_V1,  	}, +	{	// Multilingual CD with english speech and *.gra files. +		// Note: It contains no english subtitles. +		{ +			"dw", +			"CD", +			{ +				{"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, +				{"english.smp", 0, NULL, -1}, +				{"french.txt", 0, NULL, -1}, +				{"german.txt", 0, NULL, -1}, +				{"italian.txt", 0, NULL, -1}, +				{"spanish.txt", 0, NULL, -1}, +				{NULL, 0, NULL, 0} +			}, +			Common::FR_FRA, +			Common::kPlatformPC, +			Common::ADGF_DROPLANGUAGE +		}, +		GID_DW1, +		0, +		GF_CD | GF_USE_4FLAGS, +		TINSEL_V1, +	}, +	{ +		{ +			"dw", +			"CD", +			{ +				{"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, +				{"english.smp", 0, NULL, -1}, +				{"french.txt", 0, NULL, -1}, +				{"german.txt", 0, NULL, -1}, +				{"italian.txt", 0, NULL, -1}, +				{"spanish.txt", 0, NULL, -1}, +				{NULL, 0, NULL, 0} +			}, +			Common::DE_DEU, +			Common::kPlatformPC, +			Common::ADGF_DROPLANGUAGE +		}, +		GID_DW1, +		0, +		GF_CD | GF_USE_4FLAGS, +		TINSEL_V1, +	}, +	{ +		{ +			"dw", +			"CD", +			{ +				{"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, +				{"english.smp", 0, NULL, -1}, +				{"french.txt", 0, NULL, -1}, +				{"german.txt", 0, NULL, -1}, +				{"italian.txt", 0, NULL, -1}, +				{"spanish.txt", 0, NULL, -1}, +				{NULL, 0, NULL, 0} +			}, +			Common::IT_ITA, +			Common::kPlatformPC, +			Common::ADGF_DROPLANGUAGE +		}, +		GID_DW1, +		0, +		GF_CD | GF_USE_4FLAGS, +		TINSEL_V1, +	}, +	{ +		{ +			"dw", +			"CD", +			{ +				{"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, +				{"english.smp", 0, NULL, -1}, +				{"french.txt", 0, NULL, -1}, +				{"german.txt", 0, NULL, -1}, +				{"italian.txt", 0, NULL, -1}, +				{"spanish.txt", 0, NULL, -1}, +				{NULL, 0, NULL, 0} +			}, +			Common::ES_ESP, +			Common::kPlatformPC, +			Common::ADGF_DROPLANGUAGE +		}, +		GID_DW1, +		0, +		GF_CD | GF_USE_4FLAGS, +		TINSEL_V1, +	}, +  	{	// English CD with SCN files  		{  			"dw", @@ -189,25 +279,6 @@ static const TinselGameDescription gameDescriptions[] = {  	{ AD_TABLE_END_MARKER, 0, 0, 0, 0 }  }; -/** - * The fallback game descriptor used by the Tinsel engine's fallbackDetector. - * Contents of this struct are to be overwritten by the fallbackDetector. - */ -static TinselGameDescription g_fallbackDesc = { -	{ -		"", -		"", -		AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor -		Common::UNK_LANG, -		Common::kPlatformPC, -		Common::ADGF_NO_FLAGS -	}, -	0, -	0, -	0, -	0, -}; -  } // End of namespace Tinsel  static const Common::ADParams detectionParams = { @@ -243,8 +314,6 @@ public:  	virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; -	const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const; -  };  bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { @@ -255,21 +324,6 @@ bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Comm  	return gd != 0;  } -const Common::ADGameDescription *TinselMetaEngine::fallbackDetect(const FSList *fslist) const { -	// Set the default values for the fallback descriptor's ADGameDescription part. -	Tinsel::g_fallbackDesc.desc.language = Common::UNK_LANG; -	Tinsel::g_fallbackDesc.desc.platform = Common::kPlatformPC; -	Tinsel::g_fallbackDesc.desc.flags = Common::ADGF_NO_FLAGS; - -	// Set default values for the fallback descriptor's TinselGameDescription part. -	Tinsel::g_fallbackDesc.gameID = 0; -	Tinsel::g_fallbackDesc.features = 0; -	Tinsel::g_fallbackDesc.version = 0; - -	//return (const Common::ADGameDescription *)&Tinsel::g_fallbackDesc; -	return NULL; -} -  #if PLUGIN_ENABLED_DYNAMIC(TINSEL)  	REGISTER_PLUGIN_DYNAMIC(TINSEL, PLUGIN_TYPE_ENGINE, TinselMetaEngine);  #else diff --git a/engines/tinsel/dw.h b/engines/tinsel/dw.h index d14dd43fa2..9ceef37858 100644 --- a/engines/tinsel/dw.h +++ b/engines/tinsel/dw.h @@ -110,8 +110,11 @@ typedef int HPOLYGON;  // Language for the resource strings  enum LANGUAGE { -	TXT_ENGLISH, TXT_FRENCH, TXT_GERMAN, -		TXT_ITALIAN, TXT_SPANISH +	TXT_ENGLISH, +	TXT_FRENCH, +	TXT_GERMAN, +	TXT_ITALIAN, +	TXT_SPANISH  };  } // end of namespace Tinsel diff --git a/engines/tinsel/inventory.cpp b/engines/tinsel/inventory.cpp index e3333bae90..836e1194fe 100644 --- a/engines/tinsel/inventory.cpp +++ b/engines/tinsel/inventory.cpp @@ -29,8 +29,6 @@   * And there's still a bit of tidying and commenting to do yet.   */ -//#define USE_3FLAGS 1 -  #include "tinsel/actors.h"  #include "tinsel/anim.h"  #include "tinsel/background.h" @@ -370,9 +368,7 @@ enum BFUNC {  	NOFUNC, SAVEGAME, LOADGAME, IQUITGAME, CLOSEWIN,  	OPENLOAD, OPENSAVE, OPENREST,  	OPENSOUND, OPENCONT, -#ifndef JAPAN  	OPENSUBT, -#endif  	OPENQUIT,  	INITGAME, MIDIVOL,  	CLANG, RLANG @@ -402,9 +398,7 @@ struct CONFBOX {  #define SIX_RESTART_OPTION	2  #define SIX_SOUND_OPTION	3  #define SIX_CONTROL_OPTION	4 -#ifndef JAPAN  #define SIX_SUBTITLES_OPTION	5 -#endif  #define SIX_QUIT_OPTION		6  #define SIX_RESUME_OPTION	7  #define SIX_LOAD_HEADING	8 @@ -568,41 +562,60 @@ CONFBOX controlBox[] = {  /*-------------------------------------------------------------*\ -| This is the subtitles 'menu'.					| +| This is the subtitles 'menu'.                                 |  \*-------------------------------------------------------------*/ -#ifndef JAPAN  CONFBOX subtitlesBox[] = { -#ifdef USE_5FLAGS + { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER,	142, 20,	100, 2, &speedText, 0 }, + { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE,	142, 20+40,	23, 19, &bSubtitles, 0 }, + +}; + +CONFBOX subtitlesBox3Flags[] = { + + { FRGROUP, NOFUNC, NULL, USE_POINTER,	15, 118,	56, 32, NULL, FIX_FR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER,	85, 118,	56, 32, NULL, FIX_GR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER,	155, 118,	56, 32, NULL, FIX_SP }, + + { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER,	142, 20,	100, 2, &speedText, 0 }, + { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE,	142, 20+40,	23, 19, &bSubtitles, 0 }, + + { ARSGBUT, CLANG, NULL, USE_POINTER,	230, 110,	23, 19, NULL, IX_TICK1 }, + { AAGBUT, RLANG, NULL, USE_POINTER,	230, 140,	23, 19, NULL, IX_CROSS1 } + +}; + +CONFBOX subtitlesBox4Flags[] = { + + { FRGROUP, NOFUNC, NULL, USE_POINTER,	20, 100,	56, 32, NULL, FIX_FR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER,	108, 100,	56, 32, NULL, FIX_GR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER,	64, 137,	56, 32, NULL, FIX_IT }, + { FRGROUP, NOFUNC, NULL, USE_POINTER,	152, 137,	56, 32, NULL, FIX_SP }, + + { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER,	142, 20,	100, 2, &speedText, 0 }, + { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE,	142, 20+40,	23, 19, &bSubtitles, 0 }, + + { ARSGBUT, CLANG, NULL, USE_POINTER,	230, 110,	23, 19, NULL, IX_TICK1 }, + { AAGBUT, RLANG, NULL, USE_POINTER,	230, 140,	23, 19, NULL, IX_CROSS1 } + +}; + +CONFBOX subtitlesBox5Flags[] = { +   { FRGROUP, NOFUNC, NULL, USE_POINTER,	15, 100,	56, 32, NULL, FIX_UK },   { FRGROUP, NOFUNC, NULL, USE_POINTER,	85, 100,	56, 32, NULL, FIX_FR },   { FRGROUP, NOFUNC, NULL, USE_POINTER,	155, 100,	56, 32, NULL, FIX_GR },   { FRGROUP, NOFUNC, NULL, USE_POINTER,	50, 137,	56, 32, NULL, FIX_IT },   { FRGROUP, NOFUNC, NULL, USE_POINTER,	120, 137,	56, 32, NULL, FIX_SP }, -#endif -#ifdef USE_4FLAGS - { FRGROUP, NOFUNC, NULL, USE_POINTER,	20, 100,	56, 32, NULL, FIX_FR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER,	108, 100,	56, 32, NULL, FIX_GR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER,	64, 137,	56, 32, NULL, FIX_IT }, - { FRGROUP, NOFUNC, NULL, USE_POINTER,	152, 137,	56, 32, NULL, FIX_SP }, -#endif -#ifdef USE_3FLAGS - { FRGROUP, NOFUNC, NULL, USE_POINTER,	15, 118,	56, 32, NULL, FIX_FR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER,	85, 118,	56, 32, NULL, FIX_GR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER,	155, 118,	56, 32, NULL, FIX_SP }, -#endif   { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER,	142, 20,	100, 2, &speedText, 0 },   { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE,	142, 20+40,	23, 19, &bSubtitles, 0 }, -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)   { ARSGBUT, CLANG, NULL, USE_POINTER,	230, 110,	23, 19, NULL, IX_TICK1 },   { AAGBUT, RLANG, NULL, USE_POINTER,	230, 140,	23, 19, NULL, IX_CROSS1 } -#endif  }; -#endif  /*-------------------------------------------------------------*\ @@ -610,7 +623,7 @@ CONFBOX subtitlesBox[] = {  \*-------------------------------------------------------------*/  CONFBOX quitBox[] = { -#ifdef JAPAN +#ifdef g   { AAGBUT, IQUITGAME, NULL, USE_POINTER,70, 44,	23, 19, NULL, IX_TICK1 },   { AAGBUT, CLOSEWIN, NULL, USE_POINTER,	30, 44,	23, 19, NULL, IX_CROSS1 }  #else @@ -652,13 +665,9 @@ CONFINIT ciSound	= { 10, 5, 20, 16, false, soundBox,	ARRAYSIZE(soundBox),	NO_HEA  #else  	CONFINIT ciControl	= { 10, 5, 20, 16, false, controlBox,	ARRAYSIZE(controlBox),	NO_HEADING };  #endif -#ifndef JAPAN -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) -CONFINIT ciSubtitles	= { 10, 6, 20, 16, false, subtitlesBox,	ARRAYSIZE(subtitlesBox),	NO_HEADING }; -#else +  CONFINIT ciSubtitles	= { 10, 3, 20, 16, false, subtitlesBox,	ARRAYSIZE(subtitlesBox),	NO_HEADING }; -#endif -#endif +  CONFINIT ciQuit		= { 4, 2, 98, 53, false, quitBox,	ARRAYSIZE(quitBox),	SIX_QUIT_HEADING };  CONFINIT ciTopWin	= { 6, 5, 72, 23, false, topwinBox,	0,					NO_HEADING }; @@ -762,45 +771,39 @@ static void ConfActionSpecial(int i); -#ifndef JAPAN  bool LanguageChange(void) { -	LANGUAGE nLang; - -#ifdef USE_3FLAGS -	// VERY quick dodgy bodge -	if (cd.selBox == 0) -		nLang = TXT_FRENCH; -	else if (cd.selBox == 1) -		nLang = TXT_GERMAN; -	else -		nLang = TXT_SPANISH; -	if (nLang != language) { -#elif defined(USE_4FLAGS) -	nLang = (LANGUAGE)(cd.selBox + 1); -	if (nLang != language) { -#else -	if (cd.selBox != language) { +	LANGUAGE nLang = TXT_ENGLISH; + +	if (_vm->getFeatures() & GF_USE_3FLAGS) { +		// VERY quick dodgy bodge +		if (cd.selBox == 0) +			nLang = TXT_FRENCH;		// = 1 +		else if (cd.selBox == 1) +			nLang = TXT_GERMAN;		// = 2 +		else +			nLang = TXT_SPANISH;	// = 4 +	} else if (_vm->getFeatures() & GF_USE_4FLAGS) { +		nLang = (LANGUAGE)(cd.selBox + 1); +	} else if (_vm->getFeatures() & GF_USE_5FLAGS) {  		nLang = (LANGUAGE)cd.selBox; -#endif +	} + +	if (nLang != g_language) {  		KillInventory();  		ChangeLanguage(nLang); -		language = nLang; +		g_language = nLang;  		return true; -	} -	else +	} else  		return false;  } -#endif  /**************************************************************************/  /******************** Some miscellaneous functions ************************/  /**************************************************************************/ -/*---------------------------------------------------------------------*\ -|	DumpIconArray()/DumpDobjArray()/DumpObjArray()			| -|-----------------------------------------------------------------------| -| Delete all the objects in iconArray[]/DobjArray[]/objArray[]		| -\*---------------------------------------------------------------------*/ +/** + * Delete all the objects in iconArray[] + */  static void DumpIconArray(void){  	for (int i = 0; i < MAX_ICONS; i++) {  		if (iconArray[i] != NULL) { @@ -813,7 +816,6 @@ static void DumpIconArray(void){  /**   * Delete all the objects in DobjArray[]   */ -  static void DumpDobjArray(void) {  	for (int i = 0; i < MAX_WCOMP; i++) {  		if (DobjArray[i] != NULL) { @@ -826,7 +828,6 @@ static void DumpDobjArray(void) {  /**   * Delete all the objects in objArray[]   */ -  static void DumpObjArray(void) {  	for (int i = 0; i < MAX_WCOMP; i++) {  		if (objArray[i] != NULL) { @@ -886,7 +887,6 @@ bool IsInInventory(int object, int invnum) {  /**   * Returns which item is held (INV_NOICON (-1) if none)   */ -  int WhichItemHeld(void) {  	return HeldItem;  } @@ -895,7 +895,6 @@ int WhichItemHeld(void) {   * Called from the cursor module when it re-initialises (at the start of   * a new scene). For if we are holding something at scene-change time.   */ -  void InventoryIconCursor(void) {  	INV_OBJECT *invObj; @@ -908,7 +907,6 @@ void InventoryIconCursor(void) {  /**   * Returns TRUE if the inventory is active.   */ -  bool InventoryActive(void) {  	return (InventoryState == ACTIVE_INV);  } @@ -1214,8 +1212,8 @@ void Select(int i, bool force) {  		break; -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)  	case FRGROUP: +		assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS));  		iconArray[HL2] = RectangleObject(BackPal(), COL_HILIGHT, cd.Box[i].w+6, cd.Box[i].h+6);  		MultiInsertObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL2]);  		MultiSetAniXY(iconArray[HL2], @@ -1224,7 +1222,7 @@ void Select(int i, bool force) {  		MultiSetZPosition(iconArray[HL2], Z_INV_BRECT+1);  		break; -#endif +  	default:  		break;  	} @@ -1276,7 +1274,6 @@ void DropItem(int item) {   * Stick the item into an inventory list (ItemOrder[]), and hold the   * item if requested.   */ -  void AddToInventory(int invno, int icon, bool hold) {  	int	i;  	bool	bOpen; @@ -1407,12 +1404,12 @@ int InvArea(int x, int y) {  	int RightX = MultiRightmost(RectObject) + 1;  	int BottomY = MultiLowest(RectObject) + 1; -// Outside the whole rectangle? +	// Outside the whole rectangle?  	if (x <= LeftX - EXTRA || x > RightX + EXTRA  	|| y <= TopY - EXTRA || y > BottomY + EXTRA)  		return I_NOTIN; -// The bottom line +	// The bottom line  	if (y > BottomY - 2 - EXTRA) {		// Below top of bottom line?  		if (x <= LeftX + 2 + EXTRA)  			return I_BLEFT;		// Bottom left corner @@ -1422,7 +1419,7 @@ int InvArea(int x, int y) {  			return I_BOTTOM;	// Just plain bottom  	} -// The top line +	// The top line  	if (y <= TopY + 2 + EXTRA) {		// Above bottom of top line?  		if (x <= LeftX + 2 + EXTRA)  			return I_TLEFT;		// Top left corner @@ -1432,24 +1429,24 @@ int InvArea(int x, int y) {  			return I_TOP;		// Just plain top  	} -// Sides +	// Sides  	if (x <= LeftX + 2 + EXTRA)		// Left of right of left side?  		return I_LEFT;  	else if (x > RightX - 2 - EXTRA)		// Right of left of right side?  		return I_RIGHT; -// From here down still needs fixing up properly -/* -* In the move area? -*/ +	// From here down still needs fixing up properly +	/* +	 * In the move area? +	 */  	if (ino != INV_CONF  	&& x >= LeftX + M_SW - 2 && x <= RightX - M_SW + 3 &&  	   y >= TopY + M_TH - 2  && y < TopY + M_TBB + 2)  		return I_MOVE; -/* -* Scroll bits -*/ +	/* +	 * Scroll bits +	 */  	if (ino == INV_CONF && cd.bExtraWin) {  	} else {  		if (x > RightX - M_IAL + 3 && x <= RightX - M_IAR + 1) { @@ -1476,7 +1473,6 @@ int InvArea(int x, int y) {   * Returns the id of the icon displayed under the given position.   * Also return co-ordinates of items tag display position, if requested.   */ -  int InvItem(int *x, int *y, bool update) {  	int itop, ileft;  	int row, col; @@ -1510,7 +1506,6 @@ int InvItem(int *x, int *y, bool update) {  /**   * Returns the id of the icon displayed under the given position.   */ -  int InvItemId(int x, int y) {  	int itop, ileft;  	int row, col; @@ -1539,21 +1534,21 @@ int InvItemId(int x, int y) {  	return INV_NOICON;  } -/*---------------------------------------------------------------------*\ -|	WhichInvBox()							| -|-----------------------------------------------------------------------| -| Finds which box the cursor is in.					| -\*---------------------------------------------------------------------*/ -#define MD_YSLIDTOP	7 -#define MD_YSLIDBOT	18 -#define MD_YBUTTOP	9 -#define MD_YBUTBOT	16 -#define MD_XLBUTL	1 -#define MD_XLBUTR	10 -#define MD_XRBUTL	105 -#define MD_XRBUTR	114 - +/** + * Finds which box the cursor is in. + */  static int WhichInvBox(int curX, int curY, bool bSlides) { +	enum { +		MD_YSLIDTOP	= 7, +		MD_YSLIDBOT	= 18, +		MD_YBUTTOP	= 9, +		MD_YBUTBOT	= 16, +		MD_XLBUTL	= 1, +		MD_XLBUTR	= 10, +		MD_XRBUTL	= 105, +		MD_XRBUTR	= 114 +	}; +  	if (bSlides) {  		for (int i = 0; i < numMdSlides; i++) {  			if (curY > MultiHighest(mdSlides[i].obj) && curY < MultiLowest(mdSlides[i].obj) @@ -1841,7 +1836,6 @@ void InvLabels(bool InBody, int aniX, int aniY) {   * It seems to set up slideStuff[], an array of possible first-displayed   * icons set against the matching y-positions of the slider.   */ -  void AdjustTop(void) {  	int tMissing, bMissing, nMissing;  	int nslideY; @@ -1904,7 +1898,6 @@ void AdjustTop(void) {  /**   * Insert an inventory icon object onto the display list.   */ -  OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) {  	INV_OBJECT *invObj;		// Icon data  	const MULTI_INIT *pmi;		// Its INIT structure - from the reel @@ -1929,7 +1922,6 @@ OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) {  /**   * Create display objects for the displayed icons in an inventory window.   */ -  void FillInInventory(void) {  	int	Index;		// Index into ItemOrder[]  	int	n = 0;		// index into iconArray[] @@ -2010,7 +2002,6 @@ void AddBackground(OBJECT **rect, OBJECT **title, int extraH, int extraV, int te  /**   * Insert a part of the inventory window frame onto the display list.   */ -  static OBJECT *AddObject(const FREEL *pfreel, int num) {  	const MULTI_INIT *pmi;	// Get the MULTI_INIT structure  	IMAGE *pim; @@ -2043,7 +2034,6 @@ static OBJECT *AddObject(const FREEL *pfreel, int num) {  /**   * Display the scroll bar slider.   */ -  void AddSlider(OBJECT **slide, const FILM *pfilm) {  	SlideObject = *slide = AddObject(&pfilm->reels[IX_SLIDE], -1);  	MultiSetAniXY(*slide, MultiRightmost(RectObject)-M_SXOFF+2, InvD[ino].inventoryY + slideY); @@ -2062,7 +2052,6 @@ enum {  /**   * Display a box with some text in it.   */ -  void AddBox(int *pi, int i) {  	int x	= InvD[ino].inventoryX + cd.Box[i].xpos;  	int y	= InvD[ino].inventoryY + cd.Box[i].ypos; @@ -2126,8 +2115,8 @@ void AddBox(int *pi, int i) {  		break; -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)  	case FRGROUP: +		assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS));  		assert(flagFilm != 0); // Language flags not declared!  		pfilm = (const FILM *)LockMem(flagFilm); @@ -2141,7 +2130,7 @@ void AddBox(int *pi, int i) {  		*pi += 1;  		break; -#endif +  	case FLIP:  		pfilm = (const FILM *)LockMem(winPartsf); @@ -2234,7 +2223,6 @@ static void AddBoxes(bool posnSlide) {  /**   * Display the scroll bar slider.   */ -  void AddEWSlider(OBJECT **slide, const FILM *pfilm) {  	SlideObject = *slide = AddObject(&pfilm->reels[IX_SLIDE], -1);  	MultiSetAniXY(*slide, InvD[ino].inventoryX + 24 + 127, slideY); @@ -2244,7 +2232,6 @@ void AddEWSlider(OBJECT **slide, const FILM *pfilm) {  /**   * AddExtraWindow   */ -  int AddExtraWindow(int x, int y, OBJECT **retObj) {  	int	n = 0;  	const FILM *pfilm; @@ -2479,7 +2466,7 @@ void ConstructInventory(InventoryType filling) {  	OBJECT **rect, **title; -// Draw background, slider and icons +	// Draw background, slider and icons  	if (filling == FULL) {  		rect = &retObj[n++];  		title = &retObj[n++]; @@ -2495,8 +2482,7 @@ void ConstructInventory(InventoryType filling) {  		}  		FillInInventory(); -	} -	else if (filling == CONF) { +	} else if (filling == CONF) {  		rect = &retObj[n++];  		title = &retObj[n++]; @@ -2800,7 +2786,6 @@ bool convHid(void) {  /**   * Start up an inventory window.   */ -  void PopUpInventory(int invno) {  	assert((invno == INV_1 || invno == INV_2 || invno == INV_CONV || invno == INV_CONF)); // Trying to open illegal inventory @@ -2849,7 +2834,6 @@ void SetConfGlobals(CONFINIT *ci) {  /**   * PopupConf   */ -  void PopUpConf(CONFTYPE type) {  	int curX, curY; @@ -2903,11 +2887,27 @@ void PopUpConf(CONFTYPE type) {  		SetConfGlobals(&ciSound);  		break; -#ifndef JAPAN  	case SUBT: +		if (_vm->getFeatures() & GF_USE_3FLAGS) { +			ciSubtitles.v = 6; +			ciSubtitles.Box = subtitlesBox3Flags; +			ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox3Flags); +		} else if (_vm->getFeatures() & GF_USE_4FLAGS) { +			ciSubtitles.v = 6; +			ciSubtitles.Box = subtitlesBox4Flags; +			ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox4Flags); +		} else if (_vm->getFeatures() & GF_USE_5FLAGS) { +			ciSubtitles.v = 6; +			ciSubtitles.Box = subtitlesBox4Flags; +			ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox4Flags); +		} else { +			ciSubtitles.v = 3; +			ciSubtitles.Box = subtitlesBox; +			ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox); +		} +  		SetConfGlobals(&ciSubtitles);  		break; -#endif  	case TOPWIN:  		SetConfGlobals(&ciTopWin); @@ -2927,25 +2927,21 @@ void PopUpConf(CONFTYPE type) {  	if (type == SAVE || type == LOAD)  		Select(0, false); -#ifndef JAPAN -#if !defined(USE_3FLAGS) || !defined(USE_4FLAGS) || !defined(USE_5FLAGS)  	else if (type == SUBT) { -#ifdef USE_3FLAGS -		// VERY quick dirty bodges -		if (language == TXT_FRENCH) -			Select(0, false); -		else if (language == TXT_GERMAN) -			Select(1, false); -		else -			Select(2, false); -#elif defined(USE_4FLAGS) -		Select(language-1, false); -#else -		Select(language, false); -#endif +		if (_vm->getFeatures() & GF_USE_3FLAGS) { +			// VERY quick dirty bodges +			if (g_language == TXT_FRENCH) +				Select(0, false); +			else if (g_language == TXT_GERMAN) +				Select(1, false); +			else +				Select(2, false); +		} else if (_vm->getFeatures() & GF_USE_4FLAGS) { +			Select(g_language-1, false); +		} else if (_vm->getFeatures() & GF_USE_5FLAGS) { +			Select(g_language, false); +		}  	} -#endif -#endif // JAPAN  	GetCursorXY(&curX, &curY, false);  	InvCursor(IC_AREA, curX, curY); @@ -2954,7 +2950,6 @@ void PopUpConf(CONFTYPE type) {  /**   * Close down an inventory window.   */ -  void KillInventory(void) {  	if (objArray[0] != NULL) {  		DumpObjArray(); @@ -2976,6 +2971,9 @@ void KillInventory(void) {  	if (bOpenConf) {  		bOpenConf = false;  		PopUpConf(OPTION); +		 +		// Write config changes +		WriteConfig();  	} else if (ino == INV_CONF)  		InventoryIconCursor();  } @@ -3073,7 +3071,7 @@ void InventoryProcess(CORO_PARAM, const void *) {  					InvLoadGame();  					break;  				case IQUITGAME: -					_vm->quitGame(); +					_vm->quitFlag = true;  					break;  				case CLOSEWIN:  					KillInventory(); @@ -3098,12 +3096,10 @@ void InventoryProcess(CORO_PARAM, const void *) {  					KillInventory();  					PopUpConf(CONTROLS);  					break; -	#ifndef JAPAN  				case OPENSUBT:  					KillInventory();  					PopUpConf(SUBT);  					break; -	#endif  				case OPENQUIT:  					KillInventory();  					PopUpConf(QUIT); @@ -3112,7 +3108,6 @@ void InventoryProcess(CORO_PARAM, const void *) {  					KillInventory();  					bRestart = true;  					break; -	#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)  				case CLANG:  					if (!LanguageChange())  						KillInventory(); @@ -3120,7 +3115,6 @@ void InventoryProcess(CORO_PARAM, const void *) {  				case RLANG:  					KillInventory();  					break; -	#endif  				default:  					break;  				} @@ -3344,10 +3338,8 @@ static void SlideMSlider(int x, SSFN fn) {  	case S_END:			// End of a drag on the slider  		AddBoxes(false);	// Might change position slightly -#ifndef JAPAN  		if (ino == INV_CONF && cd.Box == subtitlesBox) -			Select(language, false); -#endif +			Select(g_language, false);  		break;  	}  } @@ -3780,8 +3772,8 @@ void ConfAction(int i, bool dbl) {  			}  			break; -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)  		case FRGROUP: +			assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS));  			if (dbl) {  				Select(i, false);  				LanguageChange(); @@ -3789,7 +3781,6 @@ void ConfAction(int i, bool dbl) {  				Select(i, false);  			}  			break; -#endif  		case AAGBUT:  		case ARSGBUT: diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index 7d4efd8079..4d77ee4ace 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -343,8 +343,6 @@ MusicPlayer::~MusicPlayer() {  }  void MusicPlayer::setVolume(int volume) { -	Common::StackLock lock(_mutex); -  	// FIXME: Could we simply change MAXMIDIVOL to match ScummVM's range?  	volume = CLIP((255 * volume) / MAXMIDIVOL, 0, 255);  	_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); @@ -354,6 +352,8 @@ void MusicPlayer::setVolume(int volume) {  	_masterVolume = volume; +	Common::StackLock lock(_mutex); +  	for (int i = 0; i < 16; ++i) {  		if (_channel[i]) {  			_channel[i]->volume(_channelVolume[i] * _masterVolume / 255); diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp index bf980f0983..d518baa7e8 100644 --- a/engines/tinsel/tinlib.cpp +++ b/engines/tinsel/tinlib.cpp @@ -1271,7 +1271,7 @@ void printtag(HPOLYGON hp, SCNHANDLE text) {  void quitgame(void) {  	stopmidi();  	stopsample(); -	_vm->quitGame(); +	_vm->quitFlag = true;  }  /** @@ -1991,7 +1991,6 @@ void topplay(CORO_PARAM, SCNHANDLE film, int x, int y, int complete, int actorid  /**   * Open or close the 'top window'   */ -  void topwindow(int bpos) {  	assert(bpos == TW_START || bpos == TW_END); @@ -2010,7 +2009,6 @@ void topwindow(int bpos) {  /**   * unhookscene   */ -  void unhookscene(void) {  	UnHookScene();  } @@ -2018,7 +2016,6 @@ void unhookscene(void) {  /**   * Un-define an actor as tagged.   */ -  void untagactor(int actor) {  	UnTagActor(actor);  } @@ -2026,14 +2023,12 @@ void untagactor(int actor) {  /**   * vibrate   */ -  void vibrate(void) {  }  /**   * waitframe(int actor, int frameNumber)   */ -  void waitframe(CORO_PARAM, int actor, int frameNumber, bool escOn, int myescEvent) {  	CORO_BEGIN_CONTEXT;  	CORO_END_CONTEXT(_ctx); @@ -2056,7 +2051,6 @@ void waitframe(CORO_PARAM, int actor, int frameNumber, bool escOn, int myescEven  /**   * Return when a key pressed or button pushed.   */ -  void waitkey(CORO_PARAM, bool escOn, int myescEvent) {  	CORO_BEGIN_CONTEXT;  		int	startEvent; @@ -2104,7 +2098,6 @@ void waitkey(CORO_PARAM, bool escOn, int myescEvent) {  /**   * Pause for requested time.   */ -  void waittime(CORO_PARAM, int time, bool frame, bool escOn, int myescEvent) {  	CORO_BEGIN_CONTEXT;  		int time; @@ -2261,7 +2254,6 @@ void walkingactor(uint32 id, SCNHANDLE *rp) {   * Walk a moving actor towards the polygon's tag, but return when the   * actor enters the polygon.   */ -  void walkpoly(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int myescEvent) {  	// COROUTINE  	CORO_BEGIN_CONTEXT; @@ -2309,7 +2301,6 @@ void walkpoly(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, in  /**   * walktag(actor, reel, hold)   */ -  void walktag(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int myescEvent) {  	// COROUTINE  	CORO_BEGIN_CONTEXT; @@ -2385,7 +2376,6 @@ void walktag(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int  /**   * whichinventory   */ -  int whichinventory(void) {  	return WhichInventoryOpen();  } diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index c91fecf84e..1d145a3cc7 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -206,13 +206,16 @@ void KeyboardProcess(CORO_PARAM, const void *) {  			{  				int sceneOffset = (_vm->getFeatures() & GF_SCNFILES) ? 1 : 0;  				int sceneNumber = (GetSceneHandle() >> SCNHANDLE_SHIFT) - sceneOffset; -				if ((language == TXT_GERMAN) &&  +#if 0	// FIXME: Disabled this code for now, as it doesn't work as it should (see bug #2078922). +				if ((g_language == TXT_GERMAN) &&   					((sceneNumber >= 25 && sceneNumber <= 27) || (sceneNumber == 17))) {  					// Skip to title screen  					// It seems the German CD version uses scenes 25,26,27,17 for the intro,  					// instead of 13,14,15,11;  also, the title screen is 11 instead of 10  					SetNewScene((11 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT); -				} else if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) { +				} else +#endif +				if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) {  					// Skip to title screen  					SetNewScene((10 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT);  				} else { @@ -622,11 +625,11 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)  	bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));  	//bool adlib = (midiDriver == MD_ADLIB); -	_driver = MidiDriver::createMidi(midiDriver); +	MidiDriver *driver = MidiDriver::createMidi(midiDriver);  	if (native_mt32) -		_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); +		driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); -	_music = new MusicPlayer(_driver); +	_music = new MusicPlayer(driver);  	//_music->setNativeMT32(native_mt32);  	//_music->setAdlib(adlib); @@ -638,14 +641,13 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)  	_mousePos.y = 0;  	_keyHandler = NULL;  	_dosPlayerDir = 0; +	quitFlag = false;  }  TinselEngine::~TinselEngine() {  	delete _sound;  	delete _music;  	delete _console; -	delete _driver; -	_screenSurface.free();  	FreeSs();  	FreeTextBuffer();  	FreeHandleTable(); @@ -679,8 +681,6 @@ int TinselEngine::init() {  #if 1  	// FIXME: The following is taken from RestartGame().  	// It may have to be adjusted a bit -	CountOut = 1; -  	RebootCursor();  	RebootDeadTags();  	RebootMovers(); @@ -695,25 +695,8 @@ int TinselEngine::init() {  	// TODO: More stuff from dos_main.c may have to be added here -	// Set language - we'll be clever here and use the ScummVM language setting -	language = TXT_ENGLISH; -	switch (getLanguage()) { -	case Common::FR_FRA: -		language = TXT_FRENCH; -		break; -	case Common::DE_DEU: -		language = TXT_GERMAN; -		break; -	case Common::IT_ITA: -		language = TXT_ITALIAN; -		break; -	case Common::ES_ESP: -		language = TXT_SPANISH; -		break; -	default: -		language = TXT_ENGLISH; -	} -	ChangeLanguage(language); +	// load in text strings +	ChangeLanguage(g_language);  	// load in graphics info  	SetupHandleTable(); @@ -758,7 +741,7 @@ int TinselEngine::go() {  	// Foreground loop -	while (!quit()) { +	while (!quitFlag) {  		assert(_console);  		if (_console->isAttached())  			_console->onFrame(); @@ -792,7 +775,7 @@ int TinselEngine::go() {  	// Write configuration  	WriteConfig(); -	return _eventMan->shouldRTL(); +	return 0;  } @@ -822,6 +805,10 @@ bool TinselEngine::pollEvent() {  	// Handle the various kind of events  	switch (event.type) { +	case Common::EVENT_QUIT: +		quitFlag = true; +		break; +  	case Common::EVENT_LBUTTONDOWN:  	case Common::EVENT_LBUTTONUP:  	case Common::EVENT_RBUTTONDOWN: diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h index 347a344519..de308864a6 100644 --- a/engines/tinsel/tinsel.h +++ b/engines/tinsel/tinsel.h @@ -55,12 +55,19 @@ enum TinselGameFeatures {  	GF_DEMO = 1 << 0,  	GF_CD = 1 << 1,  	GF_FLOPPY = 1 << 2, -	GF_SCNFILES = 1 << 3 +	GF_SCNFILES = 1 << 3, + +	// The GF_USE_?FLAGS values specify how many country flags are displayed +	// in the subtitles options dialog. +	// None of these defined -> 1 language, in ENGLISH.TXT +	GF_USE_3FLAGS = 1 << 4,	// French, German, Spanish +	GF_USE_4FLAGS = 1 << 5,	// French, German, Spanish, Italian +	GF_USE_5FLAGS = 1 << 6	// All 5 flags  };  enum TinselEngineVersion { -	TINSEL_V0 = 1 << 0,	// Used in the DW1 demo only -	TINSEL_V1 = 1 << 1 +	TINSEL_V0 = 0,	// Used in the DW1 demo only +	TINSEL_V1 = 1  };  struct TinselGameDescription; @@ -72,7 +79,7 @@ enum TinselKeyDirection {  typedef bool (*KEYFPTR)(const Common::KeyState &); -class TinselEngine : public ::Engine { +class TinselEngine : public Engine {  	int _gameId;  	Common::KeyState _keyPressed;  	Common::RandomSource _random; @@ -100,8 +107,8 @@ public:  	Common::Language getLanguage() const;  	uint16 getVersion() const;  	Common::Platform getPlatform() const; +	bool quitFlag; -	MidiDriver *_driver;  	SoundManager *_sound;  	MusicPlayer *_music; diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp index 89655ac9ab..d2798d7060 100644 --- a/engines/touche/detection.cpp +++ b/engines/touche/detection.cpp @@ -25,7 +25,6 @@  #include "common/config-manager.h"  #include "common/advancedDetector.h" -#include "common/savefile.h"  #include "base/plugins.h" @@ -136,19 +135,9 @@ public:  		return "Touche: The Adventures of the 5th Musketeer (C) Clipper Software";  	} -	virtual bool hasFeature(MetaEngineFeature f) const;  	virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; -	virtual SaveStateList listSaves(const char *target) const;  }; -bool ToucheMetaEngine::hasFeature(MetaEngineFeature f) const { -	return -		(f == kSupportsRTL) || -		(f == kSupportsListSaves) || -		(f == kSupportsDirectLoad) || -		(f == kSupportsDeleteSave); -} -  bool ToucheMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {  	const Common::ADGameDescription *gd = desc;  	if (gd) { @@ -157,57 +146,6 @@ bool ToucheMetaEngine::createInstance(OSystem *syst, Engine **engine, const Comm  	return gd != 0;  } -SaveStateList ToucheMetaEngine::listSaves(const char *target) const { -	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); -	Common::StringList filenames; -	char saveDesc[Touche::kGameStateDescriptionLen]; -	Common::String pattern = target; -	pattern += ".?"; - -	filenames = saveFileMan->listSavefiles(pattern.c_str()); -	sort(filenames.begin(), filenames.end());	// Sort (hopefully ensuring we are sorted numerically..) - -	SaveStateList saveList; -	for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { -		// Obtain the last digit of the filename, since they correspond to the save slot -		int slotNum = atoi(file->c_str() + file->size() - 1); -	 -		if (slotNum >= 0 && slotNum <= 9) { -			Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); -			if (in) { -				in->readUint16LE(); -				in->readUint16LE(); -				in->read(saveDesc, Touche::kGameStateDescriptionLen); -				saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file)); -				delete in; -			} -		} -	} -	 -	pattern += "?"; - -	filenames = saveFileMan->listSavefiles(pattern.c_str()); -	sort(filenames.begin(), filenames.end());	// Sort (hopefully ensuring we are sorted numerically..) - -	for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { -		// Obtain the last 2 digits of the filename, since they correspond to the save slot -		int slotNum = atoi(file->c_str() + file->size() - 2); -	 -		if (slotNum >= 10 && slotNum <= 99) { -			Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); -			if (in) { -				in->readUint16LE(); -				in->readUint16LE(); -				in->read(saveDesc, Touche::kGameStateDescriptionLen); -				saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file)); -				delete in; -			} -		} -	} - -	return saveList; -} -  #if PLUGIN_ENABLED_DYNAMIC(TOUCHE)  	REGISTER_PLUGIN_DYNAMIC(TOUCHE, PLUGIN_TYPE_ENGINE, ToucheMetaEngine);  #else diff --git a/engines/touche/menu.cpp b/engines/touche/menu.cpp index 82490fca38..6d2d90a572 100644 --- a/engines/touche/menu.cpp +++ b/engines/touche/menu.cpp @@ -297,7 +297,7 @@ void ToucheEngine::handleMenuAction(void *menu, int actionId) {  		menuData->quit = true;  		break;  	case kActionQuitGame: -		quitGame(); +		_flagsTable[611] = 1;  		menuData->quit = true;  		break;  	case kActionTextOnly: @@ -395,10 +395,10 @@ void ToucheEngine::handleOptions(int forceDisplay) {  			while (_eventMan->pollEvent(event)) {  				const Button *button = 0;  				switch (event.type) { -				case Common::EVENT_RTL:  				case Common::EVENT_QUIT:  					menuData.quit = true;  					menuData.exit = true; +					_flagsTable[611] = 1;  					break;  				case Common::EVENT_LBUTTONDOWN:  					button = menuData.findButtonUnderCursor(event.mouse.x, event.mouse.y); @@ -433,9 +433,8 @@ void ToucheEngine::handleOptions(int forceDisplay) {  			_system->delayMillis(10);  		}  		_fullRedrawCounter = 2; -		if (!menuData.exit && quit()) { -			if (displayQuitDialog()) -				quitGame(); +		if (!menuData.exit && _flagsTable[611] != 0) { +			_flagsTable[611] = displayQuitDialog();  		}  	}  } @@ -557,7 +556,6 @@ int ToucheEngine::displayQuitDialog() {  		Common::Event event;  		while (_eventMan->pollEvent(event)) {  			switch (event.type) { -			case Common::EVENT_RTL:  			case Common::EVENT_QUIT:  				quitLoop = true;  				ret = 1; diff --git a/engines/touche/opcodes.cpp b/engines/touche/opcodes.cpp index b2b16eb29d..4405c614ac 100644 --- a/engines/touche/opcodes.cpp +++ b/engines/touche/opcodes.cpp @@ -408,10 +408,6 @@ void ToucheEngine::op_setFlag() {  	case 104:  		_currentKeyCharNum = val;  		break; -	case 611: -		if (val != 0) -			quitGame(); -		break;  	case 612:  		_flagsTable[613] = getRandomNumber(val);  		break; diff --git a/engines/touche/saveload.cpp b/engines/touche/saveload.cpp index fedd40eb76..4fcf6e114d 100644 --- a/engines/touche/saveload.cpp +++ b/engines/touche/saveload.cpp @@ -31,6 +31,11 @@  namespace Touche { +enum { +	kCurrentGameStateVersion = 6, +	kGameStateDescriptionLen = 32 +}; +  static void saveOrLoad(Common::WriteStream &stream, uint16 &i) {  	stream.writeUint16LE(i);  } @@ -287,7 +292,7 @@ void ToucheEngine::loadGameStateData(Common::ReadStream *stream) {  	if (stream->readUint32LE() != saveLoadEndMarker) {  		warning("Corrupted gamestate data");  		// if that ever happens, exit the game -		quitGame(); +		_flagsTable[611] = 1;  	}  	_flagsTable[614] = roomOffsX;  	_flagsTable[615] = roomOffsY; diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp index d1d7528517..a39517fe32 100644 --- a/engines/touche/touche.cpp +++ b/engines/touche/touche.cpp @@ -95,7 +95,7 @@ int ToucheEngine::init() {  	_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));  	_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); -	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); +	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume);  	return 0;  } @@ -111,7 +111,7 @@ int ToucheEngine::go() {  	res_deallocateTables();  	res_closeDataFile(); -	return _eventMan->shouldRTL(); +	return 0;  }  void ToucheEngine::restart() { @@ -234,13 +234,6 @@ Common::Point ToucheEngine::getMousePos() const {  	return _eventMan->getMousePos();  } -void ToucheEngine::syncSoundSettings() { -	readConfigurationSettings(); -	_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); -	_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); -	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); -} -	  void ToucheEngine::mainLoop() {  	restart(); @@ -252,13 +245,10 @@ void ToucheEngine::mainLoop() {  	_inp_rightMouseButtonPressed = false;  	if (ConfMan.hasKey("save_slot")) { -		int saveSlot = ConfMan.getInt("save_slot"); -		if (saveSlot >= 0 && saveSlot <= 99) { -			loadGameState(saveSlot); -			_newEpisodeNum = 0; -			resetSortedKeyCharsTable(); -			showCursor(true); -		} +		loadGameState(ConfMan.getInt("save_slot")); +		_newEpisodeNum = 0; +		resetSortedKeyCharsTable(); +		showCursor(true);  	} else {  		_newEpisodeNum = ConfMan.getInt("boot_param");  		if (_newEpisodeNum == 0) { @@ -268,7 +258,7 @@ void ToucheEngine::mainLoop() {  	}  	uint32 frameTimeStamp = _system->getMillis(); -	for (uint32 cycleCounter = 0; !quit(); ++cycleCounter) { +	for (uint32 cycleCounter = 0; _flagsTable[611] == 0; ++cycleCounter) {  		if ((cycleCounter % 3) == 0) {  			runCycle();  		} @@ -297,6 +287,9 @@ void ToucheEngine::processEvents(bool handleKeyEvents) {  	Common::Event event;  	while (_eventMan->pollEvent(event)) {  		switch (event.type) { +		case Common::EVENT_QUIT: +			_flagsTable[611] = 1; +			break;  		case Common::EVENT_KEYDOWN:  			if (!handleKeyEvents) {  				break; @@ -304,8 +297,7 @@ void ToucheEngine::processEvents(bool handleKeyEvents) {  			_flagsTable[600] = event.kbd.keycode;  			if (event.kbd.keycode == Common::KEYCODE_ESCAPE) {  				if (_displayQuitDialog) { -					if (displayQuitDialog()) -						quitGame(); +					_flagsTable[611] = displayQuitDialog();  				}  			} else if (event.kbd.keycode == Common::KEYCODE_F5) {  				if (_flagsTable[618] == 0 && !_hideInventoryTexts) { @@ -1837,7 +1829,7 @@ int ToucheEngine::handleActionMenuUnderCursor(const int16 *actions, int offs, in  	_menuRedrawCounter = 2;  	Common::Rect rect(0, y, kScreenWidth, y + h);  	i = -1; -	while (_inp_rightMouseButtonPressed && !quit()) { +	while (_inp_rightMouseButtonPressed && _flagsTable[611] == 0) {  		Common::Point mousePos = getMousePos();  		if (rect.contains(mousePos)) {  			int c = (mousePos.y - y) / kTextHeight; @@ -2700,10 +2692,10 @@ bool ToucheEngine::sortPointsData(int num1, int num2) {  		const int md2 = _programWalkTable[num1].point2;  		_programPointsTable[md2].order = 0;  	} -	bool quitLoop = false; +	bool quit = false;  	int order = 1; -	while (!quitLoop) { -		quitLoop = true; +	while (!quit) { +		quit = true;  		for (uint i = 0; i < _programWalkTable.size(); ++i) {  			const int md1 = _programWalkTable[i].point1;  			const int md2 = _programWalkTable[i].point2; @@ -2711,11 +2703,11 @@ bool ToucheEngine::sortPointsData(int num1, int num2) {  				assert((md2 & 0x4000) == 0);  				if (_programPointsTable[md1].order == order - 1 && _programPointsTable[md2].order > order) {  					_programPointsTable[md2].order = order; -					quitLoop = false; +					quit = false;  				}  				if (_programPointsTable[md2].order == order - 1 && _programPointsTable[md1].order > order) {  					_programPointsTable[md1].order = order; -					quitLoop = false; +					quit = false;  				}  			}  		} @@ -2947,9 +2939,9 @@ void ToucheEngine::markWalkPoints(int keyChar) {  	resetPointsData(0);  	if (pointsDataNum != -1) {  		_programPointsTable[pointsDataNum].order = 1; -		bool quitLoop = false; -		while (!quitLoop) { -			quitLoop = true; +		bool quit = false; +		while (!quit) { +			quit = true;  			for (uint i = 0; i < _programWalkTable.size(); ++i) {  				int16 md1 = _programWalkTable[i].point1;  				int16 md2 = _programWalkTable[i].point2; @@ -2957,11 +2949,11 @@ void ToucheEngine::markWalkPoints(int keyChar) {  					assert((md2 & 0x4000) == 0);  					if (_programPointsTable[md1].order != 0 && _programPointsTable[md2].order == 0) {  						_programPointsTable[md2].order = 1; -						quitLoop = false; +						quit = false;  					}  					if (_programPointsTable[md2].order != 0 && _programPointsTable[md1].order == 0) {  						_programPointsTable[md1].order = 1; -						quitLoop = false; +						quit = false;  					}  				}  			} diff --git a/engines/touche/touche.h b/engines/touche/touche.h index f341769422..41f5c832c5 100644 --- a/engines/touche/touche.h +++ b/engines/touche/touche.h @@ -328,9 +328,7 @@ enum {  	kCursorHeight = 42,  	kTextHeight = 16,  	kMaxProgramDataSize = 61440, -	kMaxSaveStates = 100, -	kGameStateDescriptionLen = 32,	// Need these two values defined here -	kCurrentGameStateVersion = 6	// for --list-saves support +	kMaxSaveStates = 100  };  enum StringType { @@ -363,7 +361,6 @@ public:  	virtual int init();  	virtual int go(); -	virtual void syncSoundSettings();  protected:  | 
