diff options
| -rw-r--r-- | engines/sci/detection.cpp | 23 | ||||
| -rw-r--r-- | engines/sci/engine/game.cpp | 151 | ||||
| -rw-r--r-- | engines/sci/engine/savegame.cpp | 2 | ||||
| -rw-r--r-- | engines/sci/engine/seg_manager.cpp | 150 | ||||
| -rw-r--r-- | engines/sci/engine/seg_manager.h | 5 | ||||
| -rw-r--r-- | engines/sci/engine/vm.cpp | 10 | ||||
| -rw-r--r-- | engines/sci/engine/vm.h | 2 | 
7 files changed, 177 insertions, 166 deletions
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index d46dd2cbd8..c025523ca0 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -27,6 +27,7 @@  #include "base/plugins.h"  #include "sci/sci.h" +#include "sci/engine/kernel.h"  #include "sci/exereader.h"  #include "sci/engine/seg_manager.h" @@ -3047,8 +3048,12 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl  		Common::String filename = file->getName();  		filename.toLowercase(); -		if (filename.contains("resource.map") || filename.contains("resmap.000")) +		if (filename.contains("resource.map") || filename.contains("resmap.000")) { +			// resource.map is located in the same directory as the other resource files, +			// therefore add the directory here, so that the game files can be opened later on +			Common::File::addDefaultDirectory(file->getParent().getPath());  			foundResMap = true; +		}  		if (filename.contains("resource.000") || filename.contains("resource.001")  			|| filename.contains("ressci.000") || filename.contains("ressci.001")) @@ -3081,24 +3086,30 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl  		return 0;  	// Set some defaults -	s_fallbackDesc.desc.gameid = "sci";  	s_fallbackDesc.desc.extra = "";  	s_fallbackDesc.desc.language = Common::UNK_LANG;  	s_fallbackDesc.desc.platform = exePlatform;  	s_fallbackDesc.desc.flags = ADGF_NO_FLAGS; -#if 0  	// Determine the game id -	// TODO  	ResourceManager *resMgr = new ResourceManager();  	SciVersion version = resMgr->sciVersion(); -	SegManager *segManager = new SegManager(resMgr, version); +	Kernel *kernel = new Kernel(resMgr); +	SegManager *segManager = new SegManager(resMgr, version, kernel->hasOldScriptHeader()); +	if (!script_instantiate(resMgr, segManager, version, kernel->hasOldScriptHeader(), 0)) { +		warning("fallbackDetect(): Could not instantiate script 0"); +		return 0; +	}  	reg_t game_obj = script_lookup_export(segManager, 0, 0);  	Common::String gameName = obj_get_name(segManager,version, game_obj);  	debug(2, " \"%s\" at %04x:%04x", gameName.c_str(), PRINT_REG(game_obj)); +	gameName.toLowercase(); +	// TODO: Sierra's game IDs are not always the same as our own ones, we need to map them +	// accordingly here +	s_fallbackDesc.desc.gameid = strdup(gameName.c_str()); +	delete kernel;  	delete segManager;  	delete resMgr; -#endif  	printf("If this is *NOT* a fan-modified version (in particular, not a fan-made\n");  	printf("translation), please, report the data above, including the following\n"); diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 6872039c89..c34ac1cf00 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -188,157 +188,10 @@ int game_init_sound(EngineState *s, int sound_flags) {  	return 0;  } -int create_class_table_sci11(EngineState *s) { -	int scriptnr; -	unsigned int seeker_offset; -	char *seeker_ptr; -	int classnr; - -	Resource *vocab996 = s->resmgr->findResource(ResourceId(kResourceTypeVocab, 996), 1); - -	if (!vocab996) -		s->seg_manager->_classtable.resize(20); -	else -		s->seg_manager->_classtable.resize(vocab996->size >> 2); - -	for (scriptnr = 0; scriptnr < 1000; scriptnr++) { -		Resource *heap = s->resmgr->findResource(ResourceId(kResourceTypeHeap, scriptnr), 0); - -		if (heap) { -			int global_vars = READ_LE_UINT16(heap->data + 2); - -			seeker_ptr = (char*)heap->data + 4 + global_vars * 2; -			seeker_offset = 4 + global_vars * 2; - -			while (READ_LE_UINT16((byte*)seeker_ptr) == SCRIPT_OBJECT_MAGIC_NUMBER) { -				if (READ_LE_UINT16((byte*)seeker_ptr + 14) & SCRIPT_INFO_CLASS) { -					classnr = READ_LE_UINT16((byte*)seeker_ptr + 10); -					if (classnr >= (int)s->seg_manager->_classtable.size()) { -						if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) { -							warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x", -							        classnr, scriptnr, scriptnr, seeker_offset); -							return 1; -						} - -						s->seg_manager->_classtable.resize(classnr + 1); // Adjust maximum number of entries -					} - -					s->seg_manager->_classtable[classnr].reg.offset = seeker_offset; -					s->seg_manager->_classtable[classnr].reg.segment = 0; -					s->seg_manager->_classtable[classnr].script = scriptnr; -				} - -				seeker_ptr += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2; -				seeker_offset += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2; -			} -		} -	} - -	s->resmgr->unlockResource(vocab996); -	vocab996 = NULL; -	return 0; -} - -static int create_class_table_sci0(EngineState *s) { -	int scriptnr; -	unsigned int seeker; -	int classnr; -	int magic_offset; // For strange scripts in older SCI versions - -	Resource *vocab996 = s->resmgr->findResource(ResourceId(kResourceTypeVocab, 996), 1); -	SciVersion version = s->_version;	// for the offset defines - -	if (!vocab996) -		s->seg_manager->_classtable.resize(20); -	else -		s->seg_manager->_classtable.resize(vocab996->size >> 2); - -	for (scriptnr = 0; scriptnr < 1000; scriptnr++) { -		int objtype = 0; -		Resource *script = s->resmgr->findResource(ResourceId(kResourceTypeScript, scriptnr), 0); - -		if (script) { -			if (((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader()) -				magic_offset = seeker = 2; -			else -				magic_offset = seeker = 0; - -			do { -				while (seeker < script->size)	{ -					unsigned int lastseeker = seeker; -					objtype = (int16)READ_LE_UINT16(script->data + seeker); -					if (objtype == SCI_OBJ_CLASS || objtype == SCI_OBJ_TERMINATOR) -						break; -					seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); -					if (seeker <= lastseeker) { -						s->seg_manager->_classtable.clear(); -						error("Script version is invalid"); -					} -				} - -				if (objtype == SCI_OBJ_CLASS) { -					int sugg_script; - -					seeker -= SCRIPT_OBJECT_MAGIC_OFFSET; // Adjust position; script home is base +8 bytes - -					classnr = (int16)READ_LE_UINT16(script->data + seeker + 4 + SCRIPT_SPECIES_OFFSET); -					if (classnr >= (int)s->seg_manager->_classtable.size()) { - -						if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) { -							warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x", -							        classnr, scriptnr, scriptnr, seeker); -							return 1; -						} - -						s->seg_manager->_classtable.resize(classnr + 1); // Adjust maximum number of entries -					} - -					// Map the class ID to the script the corresponding class is contained in -					// The script number is found in vocab.996, if it exists -					if (!vocab996 || (uint32)classnr >= vocab996->size >> 2) -						sugg_script = -1; -					else -						sugg_script = (int16)READ_LE_UINT16(vocab996->data + 2 + (classnr << 2)); - -					// First, test whether the script hasn't been claimed, or if it's been claimed by the wrong script - -					if (sugg_script == -1 || scriptnr == sugg_script /*|| !s->_classtable[classnr].reg.segment*/)  { -						// Now set the home script of the class -						s->seg_manager->_classtable[classnr].reg.offset = seeker + 4 - magic_offset; -						s->seg_manager->_classtable[classnr].reg.segment = 0; -						s->seg_manager->_classtable[classnr].script = scriptnr; -					} - -					seeker += SCRIPT_OBJECT_MAGIC_OFFSET; // Re-adjust position -					seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); // Move to next -				} - -			} while (objtype != SCI_OBJ_TERMINATOR && seeker <= script->size); - -		} -	} -	s->resmgr->unlockResource(vocab996); -	vocab996 = NULL; -	return 0; -} -  // Architectural stuff: Init/Unintialize engine  int script_init_engine(EngineState *s) { -	int result; -  	s->kernel_opt_flags = 0; -	s->seg_manager = new SegManager(s->resmgr, s->_version); - -	if (s->_version >= SCI_VERSION_1_1) -		result = create_class_table_sci11(s); -	else -		result = create_class_table_sci0(s); - -	if (result) { -		debug(2, "Failed to initialize class table"); -		return 1; -	} - +	s->seg_manager = new SegManager(s->resmgr, s->_version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader());  	s->gc_countdown = GC_INTERVAL - 1;  	SegmentId script_000_segment = s->seg_manager->getSegment(0, SCRIPT_GET_LOCK); @@ -441,7 +294,7 @@ int game_init(EngineState *s) {  	s->stack_base = stack->entries;  	s->stack_top = s->stack_base + VM_STACK_SIZE; -	if (!script_instantiate(s->resmgr, s->seg_manager, s->_version, 0)) { +	if (!script_instantiate(s->resmgr, s->seg_manager, s->_version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader(), 0)) {  		warning("game_init(): Could not instantiate script 0");  		return 1;  	} diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index b53e9d522c..0ddb5187ac 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -219,7 +219,7 @@ static void sync_SegManagerPtr(Common::Serializer &s, SegManager *&obj) {  	if (s.isLoading()) {  		// FIXME: Do in-place loading at some point, instead of creating a new EngineState instance from scratch.  		delete obj; -		obj = new SegManager(resMgr, version); +		obj = new SegManager(resMgr, version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader());  	}  	obj->saveLoadWithSerializer(s); diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index f47a874528..a6f54c5bf7 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -52,7 +52,7 @@ namespace Sci {  #define INVALID_SCRIPT_ID -1 -SegManager::SegManager(ResourceManager *resMgr, SciVersion version) { +SegManager::SegManager(ResourceManager *resMgr, SciVersion version, bool oldScriptHeader) {  	id_seg_map = new IntMapper();  	reserved_id = INVALID_SCRIPT_ID;  	id_seg_map->checkKey(reserved_id, true);	// reserve entry 0 for INVALID_SCRIPT_ID @@ -68,6 +68,17 @@ SegManager::SegManager(ResourceManager *resMgr, SciVersion version) {  	exports_wide = 0;  	_version = version;  	_resMgr = resMgr; +	_oldScriptHeader = oldScriptHeader; + +	int result = 0; + +	if (version >= SCI_VERSION_1_1) +		result = createSci11ClassTable(); +	else +		result = createSci0ClassTable(); + +	if (result) +		error("SegManager: Failed to initialize class table");  }  // Destroy the object, free the memorys if allocated before @@ -139,7 +150,7 @@ void SegManager::setScriptSize(Script &scr, int script_nr) {  	if (!script || (_version >= SCI_VERSION_1_1 && !heap)) {  		error("SegManager::setScriptSize: failed to load %s", !script ? "script" : "heap");  	} -	if (((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader()) { +	if (_oldScriptHeader) {  		scr.buf_size = script->size + READ_LE_UINT16(script->data) * 2;  		//locals_size = READ_LE_UINT16(script->data) * 2;  	} else if (_version < SCI_VERSION_1_1) { @@ -434,7 +445,7 @@ SegmentId SegManager::getSegment(int script_nr, SCRIPT_GET load) {  	SegmentId segment;  	if ((load & SCRIPT_GET_LOAD) == SCRIPT_GET_LOAD) -		script_instantiate(_resMgr, this, _version, script_nr); +		script_instantiate(_resMgr, this, _version, _oldScriptHeader, script_nr);  	segment = segGet(script_nr); @@ -906,5 +917,138 @@ int SegManager::freeDynmem(reg_t addr) {  	return 0; // OK  } +int SegManager::createSci11ClassTable() { +	int scriptnr; +	unsigned int seeker_offset; +	char *seeker_ptr; +	int classnr; + +	Resource *vocab996 = _resMgr->findResource(ResourceId(kResourceTypeVocab, 996), 1); + +	if (!vocab996) +		_classtable.resize(20); +	else +		_classtable.resize(vocab996->size >> 2); + +	for (scriptnr = 0; scriptnr < 1000; scriptnr++) { +		Resource *heap = _resMgr->findResource(ResourceId(kResourceTypeHeap, scriptnr), 0); + +		if (heap) { +			int global_vars = READ_LE_UINT16(heap->data + 2); + +			seeker_ptr = (char*)heap->data + 4 + global_vars * 2; +			seeker_offset = 4 + global_vars * 2; + +			while (READ_LE_UINT16((byte*)seeker_ptr) == SCRIPT_OBJECT_MAGIC_NUMBER) { +				if (READ_LE_UINT16((byte*)seeker_ptr + 14) & SCRIPT_INFO_CLASS) { +					classnr = READ_LE_UINT16((byte*)seeker_ptr + 10); +					if (classnr >= (int)_classtable.size()) { +						if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) { +							warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x", +							        classnr, scriptnr, scriptnr, seeker_offset); +							return 1; +						} + +						_classtable.resize(classnr + 1); // Adjust maximum number of entries +					} + +					_classtable[classnr].reg.offset = seeker_offset; +					_classtable[classnr].reg.segment = 0; +					_classtable[classnr].script = scriptnr; +				} + +				seeker_ptr += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2; +				seeker_offset += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2; +			} +		} +	} + +	_resMgr->unlockResource(vocab996); +	vocab996 = NULL; +	return 0; +} + +int SegManager::createSci0ClassTable() { +	int scriptnr; +	unsigned int seeker; +	int classnr; +	int magic_offset; // For strange scripts in older SCI versions + +	Resource *vocab996 = _resMgr->findResource(ResourceId(kResourceTypeVocab, 996), 1); +	SciVersion version = _version;	// for the offset defines + +	if (!vocab996) +		_classtable.resize(20); +	else +		_classtable.resize(vocab996->size >> 2); + +	for (scriptnr = 0; scriptnr < 1000; scriptnr++) { +		int objtype = 0; +		Resource *script = _resMgr->findResource(ResourceId(kResourceTypeScript, scriptnr), 0); + +		if (script) { +			if (_oldScriptHeader) +				magic_offset = seeker = 2; +			else +				magic_offset = seeker = 0; + +			do { +				while (seeker < script->size)	{ +					unsigned int lastseeker = seeker; +					objtype = (int16)READ_LE_UINT16(script->data + seeker); +					if (objtype == SCI_OBJ_CLASS || objtype == SCI_OBJ_TERMINATOR) +						break; +					seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); +					if (seeker <= lastseeker) { +						_classtable.clear(); +						error("Script version is invalid"); +					} +				} + +				if (objtype == SCI_OBJ_CLASS) { +					int sugg_script; + +					seeker -= SCRIPT_OBJECT_MAGIC_OFFSET; // Adjust position; script home is base +8 bytes + +					classnr = (int16)READ_LE_UINT16(script->data + seeker + 4 + SCRIPT_SPECIES_OFFSET); +					if (classnr >= (int)_classtable.size()) { + +						if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) { +							warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x", +							        classnr, scriptnr, scriptnr, seeker); +							return 1; +						} + +						_classtable.resize(classnr + 1); // Adjust maximum number of entries +					} + +					// Map the class ID to the script the corresponding class is contained in +					// The script number is found in vocab.996, if it exists +					if (!vocab996 || (uint32)classnr >= vocab996->size >> 2) +						sugg_script = -1; +					else +						sugg_script = (int16)READ_LE_UINT16(vocab996->data + 2 + (classnr << 2)); + +					// First, test whether the script hasn't been claimed, or if it's been claimed by the wrong script + +					if (sugg_script == -1 || scriptnr == sugg_script /*|| !s->_classtable[classnr].reg.segment*/)  { +						// Now set the home script of the class +						_classtable[classnr].reg.offset = seeker + 4 - magic_offset; +						_classtable[classnr].reg.segment = 0; +						_classtable[classnr].script = scriptnr; +					} + +					seeker += SCRIPT_OBJECT_MAGIC_OFFSET; // Re-adjust position +					seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); // Move to next +				} + +			} while (objtype != SCI_OBJ_TERMINATOR && seeker <= script->size); + +		} +	} +	_resMgr->unlockResource(vocab996); +	vocab996 = NULL; +	return 0; +}  } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index f73c788b37..fcf2659df3 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -58,7 +58,7 @@ public:  	/**  	 * Initialize the segment manager  	 */ -	SegManager(ResourceManager *resMgr, SciVersion version); +	SegManager(ResourceManager *resMgr, SciVersion version, bool oldScriptHeader);  	/**  	 * Deallocate all memory associated with the segment manager @@ -342,6 +342,7 @@ public:  private:  	IntMapper *id_seg_map; ///< id - script id; seg - index of heap +	bool _oldScriptHeader;  public: // TODO: make private  	Common::Array<MemObject *> _heap;  	int reserved_id; @@ -360,6 +361,8 @@ private:  	LocalVariables *allocLocalsSegment(Script *scr, int count);  	MemObject *memObjAllocate(SegmentId segid, int hash_id, MemObjectType type);  	int deallocate(SegmentId seg, bool recursive); +	int createSci0ClassTable(); +	int createSci11ClassTable();  	Hunk *alloc_Hunk(reg_t *); diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index fbd3bc3baf..64ee7243fb 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -208,7 +208,7 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP  	Script *scr = s->seg_manager->getScriptIfLoaded(seg);  	if (!scr)  // Script not present yet? -		seg = script_instantiate(s->resmgr, s->seg_manager, s->_version, script); +		seg = script_instantiate(s->resmgr, s->seg_manager, s->_version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader(), script);  	else  		scr->unmarkDeleted(); @@ -1573,7 +1573,7 @@ int script_instantiate_common(ResourceManager *resMgr, SegManager *segManager, S  	return seg_id;  } -int script_instantiate_sci0(ResourceManager *resMgr, SegManager *segManager, SciVersion version, int script_nr) { +int script_instantiate_sci0(ResourceManager *resMgr, SegManager *segManager, SciVersion version, bool oldScriptHeader, int script_nr) {  	int objtype;  	unsigned int objlength;  	reg_t reg; @@ -1593,7 +1593,7 @@ int script_instantiate_sci0(ResourceManager *resMgr, SegManager *segManager, Sci  	Script *scr = segManager->getScript(seg_id); -	if (((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader()) { +	if (oldScriptHeader) {  		//  		int locals_nr = READ_LE_UINT16(script->data); @@ -1761,11 +1761,11 @@ int script_instantiate_sci11(ResourceManager *resMgr, SegManager *segManager, Sc  	return seg_id;  } -int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersion version, int script_nr) { +int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersion version, bool oldScriptHeader, int script_nr) {  	if (version >= SCI_VERSION_1_1)  		return script_instantiate_sci11(resMgr, segManager, version, script_nr);  	else -		return script_instantiate_sci0(resMgr, segManager, version, script_nr); +		return script_instantiate_sci0(resMgr, segManager, version, oldScriptHeader, script_nr);  }  void script_uninstantiate_sci0(SegManager *segManager, SciVersion version, int script_nr, SegmentId seg) { diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index c8f94d5446..867f732e2a 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -489,7 +489,7 @@ reg_t script_lookup_export(SegManager *segManager, int script_nr, int export_ind   * @param[in] script_nr		The script number to load   * @return					The script's segment ID or 0 if out of heap   */ -int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersion version, int script_nr); +int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersion version, bool oldScriptHeader, int script_nr);  /**   * Decreases the numer of lockers of a script and unloads it if that number  | 
