예제 #1
0
void MessageState::outputString(reg_t buf, const Common::String &str) {
#ifdef ENABLE_SCI32
	if (getSciVersion() >= SCI_VERSION_2) {
		if (_segMan->getSegmentType(buf.getSegment()) == SEG_TYPE_STRING) {
			SciString *sciString = _segMan->lookupString(buf);
			sciString->setSize(str.size() + 1);
			for (uint32 i = 0; i < str.size(); i++)
				sciString->setValue(i, str.c_str()[i]);
			sciString->setValue(str.size(), 0);
		} else if (_segMan->getSegmentType(buf.getSegment()) == SEG_TYPE_ARRAY) {
			// Happens in the intro of LSL6, we are asked to write the string
			// into an array
			SciArray<reg_t> *sciString = _segMan->lookupArray(buf);
			sciString->setSize(str.size() + 1);
			for (uint32 i = 0; i < str.size(); i++)
				sciString->setValue(i, make_reg(0, str.c_str()[i]));
			sciString->setValue(str.size(), NULL_REG);
		}
	} else {
#endif
		SegmentRef buffer_r = _segMan->dereference(buf);

		if ((unsigned)buffer_r.maxSize >= str.size() + 1) {
			_segMan->strcpy(buf, str.c_str());
		} else {
			// LSL6 sets an exit text here, but the buffer size allocated
			// is too small. Don't display a warning in this case, as we
			// don't use the exit text anyway - bug report #3035533
			if (g_sci->getGameId() == GID_LSL6 && str.hasPrefix("\r\n(c) 1993 Sierra On-Line, Inc")) {
				// LSL6 buggy exit text, don't show warning
			} else {
				warning("Message: buffer %04x:%04x invalid or too small to hold the following text of %i bytes: '%s'", PRINT_REG(buf), str.size() + 1, str.c_str());
			}

			// Set buffer to empty string if possible
			if (buffer_r.maxSize > 0)
				_segMan->strcpy(buf, "");
		}
#ifdef ENABLE_SCI32
	}
#endif
}
예제 #2
0
reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv) {
	// Creates a savegame name from a slot number. Used when deleting saved games.
	// Param 0: the output buffer (same as in kMakeSaveCatName)
	// Param 1: a string with game parameters, ignored
	// Param 2: the selected slot

	SciString *resultString = s->_segMan->lookupString(argv[0]);
	uint16 virtualId = argv[2].toUint16();
	if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END))
		error("kMakeSaveFileName: invalid savegame ID specified");
	uint saveSlot = virtualId - SAVEGAMEID_OFFICIALRANGE_START;
	
	Common::Array<SavegameDesc> saves;
	listSavegames(saves);

	Common::String filename = g_sci->getSavegameName(saveSlot);
	resultString->fromString(filename);

	return argv[0];
}
예제 #3
0
reg_t kArray(EngineState *s, int argc, reg_t *argv) {
	uint16 op = argv[0].toUint16();

	// Use kString when accessing strings
	// This is possible, as strings inherit from arrays
	// and in this case (type 3) arrays are of type char *.
	// kString is almost exactly the same as kArray, so
	// this call is possible
	// TODO: we need to either merge SCI2 strings and
	// arrays together, and in the future merge them with
	// the SCI1 strings and arrays in the segment manager
	if (op == 0) {
		// New, check if the target type is 3 (string)
		if (argv[2].toUint16() == 3)
			return kString(s, argc, argv);
	} else {
		if (s->_segMan->getSegmentType(argv[1].segment) == SEG_TYPE_STRING ||
			s->_segMan->getSegmentType(argv[1].segment) == SEG_TYPE_SCRIPT) {
			return kString(s, argc, argv);
		}

#if 0
		if (op == 6) {
			if (s->_segMan->getSegmentType(argv[3].segment) == SEG_TYPE_STRING ||
				s->_segMan->getSegmentType(argv[3].segment) == SEG_TYPE_SCRIPT) {
				return kString(s, argc, argv);
			}
		}
#endif
	}

	switch (op) {
	case 0: { // New
		reg_t arrayHandle;
		SciArray<reg_t> *array = s->_segMan->allocateArray(&arrayHandle);
		array->setType(argv[2].toUint16());
		array->setSize(argv[1].toUint16());
		return arrayHandle;
	}
	case 1: { // Size
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		return make_reg(0, array->getSize());
	}
	case 2: { // At (return value at an index)
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		return array->getValue(argv[2].toUint16());
	}
	case 3: { // Atput (put value at an index)
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);

		uint32 index = argv[2].toUint16();
		uint32 count = argc - 3;

		if (index + count > 65535)
			break;

		if (array->getSize() < index + count)
			array->setSize(index + count);

		for (uint16 i = 0; i < count; i++)
			array->setValue(i + index, argv[i + 3]);

		return argv[1]; // We also have to return the handle
	}
	case 4: // Free
		// Freeing of arrays is handled by the garbage collector
		return s->r_acc;
	case 5: { // Fill
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		uint16 index = argv[2].toUint16();

		// A count of -1 means fill the rest of the array
		uint16 count = argv[3].toSint16() == -1 ? array->getSize() - index : argv[3].toUint16();
		uint16 arraySize = array->getSize();

		if (arraySize < index + count)
			array->setSize(index + count);

		for (uint16 i = 0; i < count; i++)
			array->setValue(i + index, argv[4]);

		return argv[1];
	}
	case 6: { // Cpy
		if (argv[1].isNull() || argv[3].isNull()) {
			if (getSciVersion() == SCI_VERSION_3) {
				// FIXME: Happens in SCI3, probably because of a missing kernel function.
				warning("kArray(Cpy): Request to copy from or to a null pointer");
				return NULL_REG;
			} else {
				// SCI2-2.1: error out
				error("kArray(Cpy): Request to copy from or to a null pointer");
			}
		}

		reg_t arrayHandle = argv[1];
		SciArray<reg_t> *array1 = s->_segMan->lookupArray(argv[1]);
		//SciArray<reg_t> *array1 = !argv[1].isNull() ? s->_segMan->lookupArray(argv[1]) : s->_segMan->allocateArray(&arrayHandle);
		SciArray<reg_t> *array2 = s->_segMan->lookupArray(argv[3]);
		uint32 index1 = argv[2].toUint16();
		uint32 index2 = argv[4].toUint16();

		// The original engine ignores bad copies too
		if (index2 > array2->getSize())
			break;

		// A count of -1 means fill the rest of the array
		uint32 count = argv[5].toSint16() == -1 ? array2->getSize() - index2 : argv[5].toUint16();

		if (array1->getSize() < index1 + count)
			array1->setSize(index1 + count);

		for (uint16 i = 0; i < count; i++)
			array1->setValue(i + index1, array2->getValue(i + index2));

		return arrayHandle;
	}
	case 7: // Cmp
		// Not implemented in SSCI
		warning("kArray(Cmp) called");
		return s->r_acc;
	case 8: { // Dup
		if (argv[1].isNull()) {
			warning("kArray(Dup): Request to duplicate a null pointer");
#if 0
			// Allocate an array anyway
			reg_t arrayHandle;
			SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
			dupArray->setType(3);
			dupArray->setSize(0);
			return arrayHandle;
#endif
			return NULL_REG;
		}
		SegmentType sourceType = s->_segMan->getSegmentObj(argv[1].segment)->getType();
		if (sourceType == SEG_TYPE_SCRIPT) {
			// A technique used in later SCI2.1 and SCI3 games: the contents of a script
			// are loaded in an array (well, actually a string).
			Script *scr = s->_segMan->getScript(argv[1].segment);
			reg_t stringHandle;

			SciString *dupString = s->_segMan->allocateString(&stringHandle);
			dupString->setSize(scr->getBufSize());
			dupString->fromString(Common::String((const char *)scr->getBuf()));

			return stringHandle;
		} else if (sourceType != SEG_TYPE_ARRAY && sourceType != SEG_TYPE_SCRIPT) {
			error("kArray(Dup): Request to duplicate a segment which isn't an array or a script");
		}

		reg_t arrayHandle;
		SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
		// This must occur after allocateArray, as inserting a new object
		// in the heap object list might invalidate this pointer. Also refer
		// to the same issue in kClone()
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);

		dupArray->setType(array->getType());
		dupArray->setSize(array->getSize());

		for (uint32 i = 0; i < array->getSize(); i++)
			dupArray->setValue(i, array->getValue(i));

		return arrayHandle;
	}
	case 9: // Getdata
		if (!s->_segMan->isHeapObject(argv[1]))
			return argv[1];

		return readSelector(s->_segMan, argv[1], SELECTOR(data));
	default:
		error("Unknown kArray subop %d", op);
	}

	return NULL_REG;
}