diff options
| author | Filippos Karapetis | 2009-10-09 16:15:56 +0000 | 
|---|---|---|
| committer | Filippos Karapetis | 2009-10-09 16:15:56 +0000 | 
| commit | 4011e948e71b8bf03493caeede8c2018e6d756a0 (patch) | |
| tree | a713ac73a90b101798819fc1c097c2b62e884c0b | |
| parent | c26e283d1bdec6cec36050cd37a147fc5a2e4e6e (diff) | |
| download | scummvm-rg350-4011e948e71b8bf03493caeede8c2018e6d756a0.tar.gz scummvm-rg350-4011e948e71b8bf03493caeede8c2018e6d756a0.tar.bz2 scummvm-rg350-4011e948e71b8bf03493caeede8c2018e6d756a0.zip | |
Finished the automatic detection of the graphics functions used in SCI0 games. Also, introduced a new helper function to detect the offset of a ret call inside a script, with possible uses in other script detection routines
svn-id: r44828
| -rw-r--r-- | engines/sci/engine/state.cpp | 157 | ||||
| -rw-r--r-- | engines/sci/engine/state.h | 1 | 
2 files changed, 148 insertions, 10 deletions
| diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index b5d199b718..f187ea34e3 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -264,6 +264,58 @@ int EngineState::methodChecksum(reg_t objAddress, Selector sel, int offset, uint  	return sum;  } +uint16 EngineState::firstRetOffset(reg_t objectAddress) const { +	Script *script = _segMan->getScript(objectAddress.segment); + +	if ((script == NULL) || (script->_buf == NULL)) +		return 0; + +	uint16 offset = objectAddress.offset; + +	while (offset < script->_bufSize) { +		byte opcode = script->_buf[offset++]; +		byte opnumber = opcode >> 1; + +		if (opnumber == 0x24)	// ret +			return offset - 1; + +		// Skip operands for non-ret opcodes +		for (int i = 0; g_opcode_formats[opnumber][i]; i++) { +			switch (g_opcode_formats[opnumber][i]) { +			case Script_Byte: +			case Script_SByte: +				offset++; +				break; +			case Script_Word: +			case Script_SWord: +				offset += 2; +				break; +			case Script_Variable: +			case Script_Property: +			case Script_Local: +			case Script_Temp: +			case Script_Global: +			case Script_Param: +			case Script_SVariable: +			case Script_SRelative: +			case Script_Offset: +				offset++; +				if (!(opcode & 1)) +					offset++; +				break; +			case Script_End: +				return offset; +				break; +			case Script_Invalid: +			default: +				warning("opcode %02x: Invalid", opcode); +			} +		}	// end for +	}	// end while + +	return 0; +} +  SciVersion EngineState::detectDoSoundType() {  	if (_doSoundType == SCI_VERSION_AUTODETECT) {  		reg_t soundClass = _segMan->findObjectByName("Sound"); @@ -472,16 +524,101 @@ SciVersion EngineState::detectGfxFunctionsType() {  					_gfxFunctionsType = SCI_VERSION_0_EARLY;  				} else {  					// An in-between case: The game does not have a shiftParser -					// selector, but it does have an overlay selector. Therefore, -					// check it to see how it calls kDisplay to determine the -					// graphics functions type used - -					// TODO: Finish this! -					// For now, we're using the old hack of detecting for the motionCue selector -					if (_kernel->findSelector("motionCue") != -1) -						_gfxFunctionsType = SCI_VERSION_0_LATE; -					else -						_gfxFunctionsType = SCI_VERSION_0_EARLY; +					// selector, but it does have an overlay selector, so it uses an +					// overlay. Therefore, check it to see how it calls kDrawPic to +					// determine the graphics functions type used + +					reg_t roomObjAddr = _segMan->findObjectByName("Rm"); + +					bool found = false; + +					if (!roomObjAddr.isNull()) { +						reg_t addr; + +						if (lookup_selector(_segMan, roomObjAddr, _kernel->_selectorCache.overlay, NULL, &addr) == kSelectorMethod) { +							uint16 offset = addr.offset; +							byte *scr = _segMan->getScript(addr.segment)->_buf; +							do { +								uint16 kFuncNum; +								int opsize = scr[offset++]; +								uint opcode = opsize >> 1; +								int i = 0; + +								while (g_opcode_formats[opcode][i]) { +									switch (g_opcode_formats[opcode][i++]) { +									case Script_Invalid: +										break; +									case Script_SByte: +									case Script_Byte: +										offset++; +										break; +									case Script_Word: +									case Script_SWord: +										offset += 2; +										break; +									case Script_SVariable: +									case Script_Variable: +									case Script_Property: +									case Script_Global: +									case Script_Local: +									case Script_Temp: +									case Script_Param: +										if (opsize & 1) +											kFuncNum = scr[offset++]; +										else { +											kFuncNum = 0xffff & (scr[offset] | (scr[offset + 1] << 8)); +											offset += 2; +										} + +										if (opcode == op_callk) { +											if (kFuncNum == 8) {	// kDrawPic +												// Now get the number of parameters +												byte argc = scr[offset++]; +												// If kDrawPic is called with 6 parameters from the +												// overlay selector, the game is using old graphics functions. +												// Otherwise, if it's called with 8 parameters, it's using new +												// graphics functions +												if (argc == 6) { +													_gfxFunctionsType = SCI_VERSION_0_EARLY; +													found = true; +												} else if (argc == 8) { +													_gfxFunctionsType = SCI_VERSION_0_LATE; +													found = true; +												} else { +													warning("overlay selector calling kDrawPic with %d parameters", argc); +												} +											} +										} +										break; + +									case Script_Offset: +									case Script_SRelative: +										offset++; +										if (!opsize & 1) +											offset++; +										break; +									case Script_End: +										offset = 0;	// exit loop +										break; +									default: +										warning("opcode %02x: Invalid", opcode); + +									} +								} +							} while (offset > 0 && !found); +						} +					} + +					if (!found) { +						warning("Graphics functions detection failed, taking an educated guess"); + +						// Try detecting the graphics function types from the existence of the motionCue +						// selector (which is a bit of a hack) +						if (_kernel->findSelector("motionCue") != -1) +							_gfxFunctionsType = SCI_VERSION_0_LATE; +						else +							_gfxFunctionsType = SCI_VERSION_0_EARLY; +					}  				}  			}  		} else {	// (getSciVersion() == SCI_VERSION_0_EARLY) diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index 3a6bc7e510..fdce259ca8 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -318,6 +318,7 @@ private:  	SciVersion _doSoundType, _setCursorType, _lofsType, _gfxFunctionsType;  	kLanguage charToLanguage(const char c) const;  	int methodChecksum(reg_t objAddress, Selector sel, int offset, uint size) const; +	uint16 firstRetOffset(reg_t objectAddress) const;  };  /** | 
