Пример #1
0
uint SoundChannel::play(uint soundNum, uint repeats, uint notify) {
	stop();
	if (repeats == 0)
		return 1;

	// Find a sound of the given name
	Audio::AudioStream *stream;
	Common::File f;
	Common::String nameSnd = Common::String::format("sound%u.snd", soundNum);
	Common::String nameWav = Common::String::format("sound%u.wav", soundNum);
	Common::String nameAiff = Common::String::format("sound%u.aiff", soundNum);
#ifdef USE_MAD
	Common::String nameMp3 = Common::String::format("sound%u.mp3", soundNum);
#endif

	if (f.exists(nameSnd) && f.open(nameSnd)) {
		if (f.readUint16BE() != (f.size() - 2))
			error("Invalid sound filesize");
		byte headerRepeats = f.readByte();
		if (headerRepeats > 0)
			repeats = headerRepeats;
		f.skip(1);
		uint freq = f.readUint16BE();
		f.skip(2);
		uint size = f.readUint16BE();

		Common::SeekableReadStream *s = f.readStream(size);
		stream = Audio::makeRawStream(s, freq, Audio::FLAG_UNSIGNED);

#ifdef USE_MAD
	} else if (f.exists(nameMp3) && f.open(nameMp3)) {
		Common::SeekableReadStream *s = f.readStream(f.size());
		stream = Audio::makeMP3Stream(s, DisposeAfterUse::YES);
#endif
	} else if (f.exists(nameWav) && f.open(nameWav)) {
		Common::SeekableReadStream *s = f.readStream(f.size());
		stream = Audio::makeWAVStream(s, DisposeAfterUse::YES);

	} else if (f.exists(nameAiff) && f.open(nameAiff)) {
		Common::SeekableReadStream *s = f.readStream(f.size());
		stream = Audio::makeAIFFStream(s, DisposeAfterUse::YES);

	} else {
		warning("Could not find sound %u", soundNum);
		return 1;
	}

	_soundNum = soundNum;
	_notify = notify;

	// Set up a repeat if multiple repeats are specified
	if (repeats > 1) {
		Audio::RewindableAudioStream *rwStream = dynamic_cast<Audio::RewindableAudioStream *>(stream);
		assert(rwStream);
		stream = new Audio::LoopingAudioStream(rwStream, repeats, DisposeAfterUse::YES);
	}

	// Start playing the audio
	g_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, stream);
	return 0;
}
Пример #2
0
void MidiMusicPlayer::playSEQ(uint32 size, bool loop) {
	// MIDI.DAT holds the file names in DW1 PSX
	Common::String baseName((char *)g_midiBuffer.pDat, size);
	Common::String seqName = baseName + ".SEQ";

	// TODO: Load the instrument bank (<baseName>.VB and <baseName>.VH)

	Common::File seqFile;
	if (!seqFile.open(seqName))
		error("Failed to open SEQ file '%s'", seqName.c_str());

	if (seqFile.readUint32LE() != MKTAG('S', 'E', 'Q', 'p'))
		error("Failed to find SEQp tag");

	// Make sure we don't have a SEP file (with multiple SEQ's inside)
	if (seqFile.readUint32BE() != 1)
		error("Can only play SEQ files, not SEP");

	uint16 ppqn = seqFile.readUint16BE();
	uint32 tempo = seqFile.readUint16BE() << 8;
	tempo |= seqFile.readByte();
	/* uint16 beat = */ seqFile.readUint16BE();

	// SEQ is directly based on SMF and we'll use that to our advantage here
	// and convert to SMF and then use the SMF MidiParser.

	// Calculate the SMF size we'll need
	uint32 dataSize = seqFile.size() - 15;
	uint32 actualSize = dataSize + 7 + 22;

	// Resize the buffer if necessary
	if (g_midiBuffer.size < actualSize) {
		g_midiBuffer.pDat = (byte *)realloc(g_midiBuffer.pDat, actualSize);
		assert(g_midiBuffer.pDat);
	}

	// Now construct the header
	WRITE_BE_UINT32(g_midiBuffer.pDat, MKTAG('M', 'T', 'h', 'd'));
	WRITE_BE_UINT32(g_midiBuffer.pDat + 4, 6); // header size
	WRITE_BE_UINT16(g_midiBuffer.pDat + 8, 0); // type 0
	WRITE_BE_UINT16(g_midiBuffer.pDat + 10, 1); // one track
	WRITE_BE_UINT16(g_midiBuffer.pDat + 12, ppqn);
	WRITE_BE_UINT32(g_midiBuffer.pDat + 14, MKTAG('M', 'T', 'r', 'k'));
	WRITE_BE_UINT32(g_midiBuffer.pDat + 18, dataSize + 7); // SEQ data size + tempo change event size

	// Add in a fake tempo change event
	WRITE_BE_UINT32(g_midiBuffer.pDat + 22, 0x00FF5103); // no delta, meta event, tempo change, param size = 3
	WRITE_BE_UINT16(g_midiBuffer.pDat + 26, tempo >> 8);
	g_midiBuffer.pDat[28] = tempo & 0xFF;

	// Now copy in the rest of the events
	seqFile.read(g_midiBuffer.pDat + 29, dataSize);
	seqFile.close();

	MidiParser *parser = MidiParser::createParser_SMF();
	if (parser->loadMusic(g_midiBuffer.pDat, actualSize)) {
		parser->setTrack(0);
		parser->setMidiDriver(this);
		parser->setTimerRate(getBaseTempo());
		parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
		parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);

		_parser = parser;

		_isLooping = loop;
		_isPlaying = true;
	} else {
		delete parser;
	}
}
Пример #3
0
/**
 * Loads and draws the chosen page of the help.
 * @remarks Originally called 'getme'
 */
void Help::switchPage(byte which) {
	// Help icons are 80x20.

	_highlightWas = 177; // Forget where the highlight was.

	Common::File file;

	if (!file.open("help.avd"))
		error("AVALANCHE: Help: File not found: help.avd");

	file.seek(which * 2);
	uint16 offset = file.readUint16LE();
	file.seek(offset);

	Common::String title = getLine(file);

	_vm->_graphics->drawFilledRectangle(Common::Rect(0, 0, 639, 199), kColorBlue);
	_vm->_graphics->drawFilledRectangle(Common::Rect(8, 40, 449, 199), kColorWhite);

	byte index = file.readByte();
	_vm->_graphics->helpDrawButton(-177, index);

	// Plot the title:
	_vm->_graphics->drawNormalText(title, _vm->_font, 8, 629 - 8 * title.size(), 26, kColorBlack);
	_vm->_graphics->drawNormalText(title, _vm->_font, 8, 630 - 8 * title.size(), 25, kColorCyan);

	_vm->_graphics->drawBigText("help!", _vm->_font, 8, 549, 1, kColorBlack);
	_vm->_graphics->drawBigText("help!", _vm->_font, 8, 550, 0, kColorCyan);

	byte y = 0;
	do {
		Common::String line = getLine(file);
		if (!line.empty()) {
			if (line.compareTo(Common::String('!')) == 0)  // End of the help text is signalled with a '!'.
				break;
			if (line[0] == '\\') {
				line.deleteChar(0);
				_vm->_graphics->drawNormalText(line, _vm->_font, 8, 16, 41 + y * 10, kColorRed);
			}
			else
				_vm->_graphics->drawNormalText(line, _vm->_font, 8, 16, 41 + y * 10, kColorBlack);
		}
		y++;
	} while (true);

	// We are now at the end of the text. Next we must read the icons:
	y = 0;
	_buttonNum = 0;
	while (!file.eos()) {
		int trigger = file.readByte();

		if (trigger == 177)
			break;
		switch (trigger) {
		case 254: // Escape
			trigger = 27;
			break;
		case 214: // PageUp
			trigger = 280;
			break;
		case 216: // PageDown
			trigger = 281;
			break;
		default: // A - Z
			// The characters are stored in the file in uppercase, but we need the lowercase versions for KeyCode:
			trigger = tolower(trigger);
			break;
		}

		_buttons[y]._trigger = Common::KeyCode(trigger);
		index = file.readByte();
		if (_buttons[y]._trigger != Common::KEYCODE_INVALID)
			_vm->_graphics->helpDrawButton(13 + (y + 1) * 27, index);
		_buttons[y]._whither = file.readByte(); // This is the position to jump to.

		Common::String text = "";
		switch (_buttons[y]._trigger) {
		case Common::KEYCODE_ESCAPE:
			text = Common::String("Esc");
			break;
		case Common::KEYCODE_PAGEUP:
			text = Common::String(24);
			break;
		case Common::KEYCODE_PAGEDOWN:
			text = Common::String(25);
			break;
		default:
			text = Common::String(toupper(_buttons[y]._trigger));
			break;
		}

		_vm->_graphics->drawBigText(text, _vm->_font, 8, 589 - (text.size() * 8), 18 + (y + 1) * 27, kColorBlack);
		_vm->_graphics->drawBigText(text, _vm->_font, 8, 590 - (text.size() * 8), 17 + (y + 1) * 27, kColorCyan);

		y++;
		_buttonNum++;
	}

	_vm->_graphics->refreshScreen();

	file.close();
}
Пример #4
0
bool DrasculaEngine::loadDrasculaDat() {
	Common::File in;
	int i;

	in.open("drascula.dat");

	if (!in.isOpen()) {
		Common::String errorMessage = "You're missing the 'drascula.dat' file. Get it from the ScummVM website";
		GUIErrorMessage(errorMessage);
		warning("%s", errorMessage.c_str());

		return false;
	}

	char buf[256];
	int ver;

	in.read(buf, 8);
	buf[8] = '\0';

	if (strcmp(buf, "DRASCULA")) {
		Common::String errorMessage = "File 'drascula.dat' is corrupt. Get it from the ScummVM website";
		GUIErrorMessage(errorMessage);
		warning("%s", errorMessage.c_str());

		return false;
	}

	ver = in.readByte();

	if (ver != DRASCULA_DAT_VER) {
		snprintf(buf, 256, "File 'drascula.dat' is wrong version. Expected %d but got %d. Get it from the ScummVM website", DRASCULA_DAT_VER, ver);
		GUIErrorMessage(buf);
		warning("%s", buf);

		return false;
	}

	_charMapSize = in.readUint16BE();
	_charMap = (CharInfo *)malloc(sizeof(CharInfo) * _charMapSize);
	for (i = 0; i < _charMapSize; i++) {
		_charMap[i].inChar = in.readByte();
		_charMap[i].mappedChar = in.readSint16BE();
		_charMap[i].charType = in.readByte();
	}

	_itemLocationsSize = in.readUint16BE();
	_itemLocations = (ItemLocation *)malloc(sizeof(ItemLocation) * _itemLocationsSize);
	for (i = 0; i < _itemLocationsSize; i++) {
		_itemLocations[i].x = in.readSint16BE();
		_itemLocations[i].y = in.readSint16BE();
	}

	_polXSize = in.readUint16BE();
	_polX = (int *)malloc(sizeof(int) * _polXSize);
	_polY = (int *)malloc(sizeof(int) * _polXSize);
	for (i = 0; i < _polXSize; i++) {
		_polX[i] = in.readSint16BE();
		_polY[i] = in.readSint16BE();
	}

	_verbBarXSize = in.readUint16BE();
	_verbBarX = (int *)malloc(sizeof(int) * _verbBarXSize);
	for (i = 0; i < _verbBarXSize; i++) {
		_verbBarX[i] = in.readSint16BE();
	}

	_x1dMenuSize = in.readUint16BE();
	_x1d_menu = (int *)malloc(sizeof(int) * _x1dMenuSize);
	_y1d_menu = (int *)malloc(sizeof(int) * _x1dMenuSize);
	for (i = 0; i < _x1dMenuSize; i++) {
		_x1d_menu[i] = in.readSint16BE();
		_y1d_menu[i] = in.readSint16BE();
	}

	_frameXSize = in.readUint16BE();
	_frameX = (int *)malloc(sizeof(int) * _frameXSize);
	for (i = 0; i < _frameXSize; i++) {
		_frameX[i] = in.readSint16BE();
	}

	_candleXSize = in.readUint16BE();
	_candleX = (int *)malloc(sizeof(int) * _candleXSize);
	_candleY = (int *)malloc(sizeof(int) * _candleXSize);
	for (i = 0; i < _candleXSize; i++) {
		_candleX[i] = in.readSint16BE();
		_candleY[i] = in.readSint16BE();
	}

	_pianistXSize = in.readUint16BE();
	_pianistX = (int *)malloc(sizeof(int) * _pianistXSize);
	for (i = 0; i < _pianistXSize; i++) {
		_pianistX[i] = in.readSint16BE();
	}

	_drunkXSize = in.readUint16BE();
	_drunkX = (int *)malloc(sizeof(int) * _drunkXSize);
	for (i = 0; i < _drunkXSize; i++) {
		_drunkX[i] = in.readSint16BE();
	}

	_roomPreUpdatesSize = in.readUint16BE();
	_roomPreUpdates = (RoomUpdate *)malloc(sizeof(RoomUpdate) * _roomPreUpdatesSize);
	for (i = 0; i < _roomPreUpdatesSize; i++) {
		_roomPreUpdates[i].roomNum = in.readSint16BE();
		_roomPreUpdates[i].flag = in.readSint16BE();
		_roomPreUpdates[i].flagValue = in.readSint16BE();
		_roomPreUpdates[i].sourceX = in.readSint16BE();
		_roomPreUpdates[i].sourceY = in.readSint16BE();
		_roomPreUpdates[i].destX = in.readSint16BE();
		_roomPreUpdates[i].destY = in.readSint16BE();
		_roomPreUpdates[i].width = in.readSint16BE();
		_roomPreUpdates[i].height = in.readSint16BE();
		_roomPreUpdates[i].type = in.readSint16BE();
	}

	_roomUpdatesSize = in.readUint16BE();
	_roomUpdates = (RoomUpdate *)malloc(sizeof(RoomUpdate) * _roomUpdatesSize);
	for (i = 0; i < _roomUpdatesSize; i++) {
		_roomUpdates[i].roomNum = in.readSint16BE();
		_roomUpdates[i].flag = in.readSint16BE();
		_roomUpdates[i].flagValue = in.readSint16BE();
		_roomUpdates[i].sourceX = in.readSint16BE();
		_roomUpdates[i].sourceY = in.readSint16BE();
		_roomUpdates[i].destX = in.readSint16BE();
		_roomUpdates[i].destY = in.readSint16BE();
		_roomUpdates[i].width = in.readSint16BE();
		_roomUpdates[i].height = in.readSint16BE();
		_roomUpdates[i].type = in.readSint16BE();
	}

	_roomActionsSize = in.readUint16BE();
	_roomActions = (RoomTalkAction *)malloc(sizeof(RoomTalkAction) * _roomActionsSize);
	for (i = 0; i < _roomActionsSize; i++) {
		_roomActions[i].room = in.readSint16BE();
		_roomActions[i].chapter = in.readSint16BE();
		_roomActions[i].action = in.readSint16BE();
		_roomActions[i].objectID = in.readSint16BE();
		_roomActions[i].speechID = in.readSint16BE();
	}

	_talkSequencesSize = in.readUint16BE();
	_talkSequences = (TalkSequenceCommand *)malloc(sizeof(TalkSequenceCommand) * _talkSequencesSize);
	for (i = 0; i < _talkSequencesSize; i++) {
		_talkSequences[i].chapter = in.readSint16BE();
		_talkSequences[i].sequence = in.readSint16BE();
		_talkSequences[i].commandType = in.readSint16BE();
		_talkSequences[i].action = in.readSint16BE();
	}

	_numLangs = in.readUint16BE();

	_text = loadTexts(in);
	_textd = loadTexts(in);
	_textb = loadTexts(in);
	_textbj = loadTexts(in);
	_texte = loadTexts(in);
	_texti = loadTexts(in);
	_textl = loadTexts(in);
	_textp = loadTexts(in);
	_textt = loadTexts(in);
	_textvb = loadTexts(in);
	_textsys = loadTexts(in);
	_texthis = loadTexts(in);
	_textverbs = loadTexts(in);
	_textmisc = loadTexts(in);
	_textd1 = loadTexts(in);

	return true;
}
Пример #5
0
bool BaseAnimationState::init(const char *name) {
#ifdef USE_MPEG2
	char tempFile[512];

	_mpegDecoder = NULL;
	_mpegFile = NULL;

#ifdef BACKEND_8BIT

	uint i, p;

	// Load lookup palettes
	sprintf(tempFile, "%s.pal", name);

	Common::File f;

	if (!f.open(tempFile)) {
		warning("Cutscene: %s palette missing", tempFile);
		return false;
	}

	p = 0;
	while (!f.eos()) {
		_palettes[p].end = f.readUint16LE();
		_palettes[p].cnt = f.readUint16LE();

		for (i = 0; i < _palettes[p].cnt; i++) {
			_palettes[p].pal[4 * i] = f.readByte();
			_palettes[p].pal[4 * i + 1] = f.readByte();
			_palettes[p].pal[4 * i + 2] = f.readByte();
			_palettes[p].pal[4 * i + 3] = 0;
		}
		for (; i < 256; i++) {
			_palettes[p].pal[4 * i] = 0;
			_palettes[p].pal[4 * i + 1] = 0;
			_palettes[p].pal[4 * i + 2] = 0;
			_palettes[p].pal[4 * i + 3] = 0;
		}

		p++;
	}

	f.close();

	_palNum = 0;
	_maxPalNum = p;
	setPalette(_palettes[_palNum].pal);
	_lut = _lut2 = _yuvLookup[0];
	_curPal = -1;
	_cr = 0;
	buildLookup(_palNum, 256);
	_lut2 = _yuvLookup[1];
	_lutCalcNum = (BITDEPTH + _palettes[_palNum].end + 2) / (_palettes[_palNum].end + 2);
#else
	buildLookup();
	_overlay = (OverlayColor *)calloc(_movieScale * _movieWidth * _movieScale * _movieHeight, sizeof(OverlayColor));
	_sys->showOverlay();
#endif

	// Open MPEG2 stream
	_mpegFile = new Common::File();
	sprintf(tempFile, "%s.mp2", name);
	if (!_mpegFile->open(tempFile)) {
		warning("Cutscene: Could not open %s", tempFile);
		return false;
	}

	// Load and configure decoder
	_mpegDecoder = mpeg2_init();
	if (_mpegDecoder == NULL) {
		warning("Cutscene: Could not allocate an MPEG2 decoder");
		return false;
	}

	_mpegInfo = mpeg2_info(_mpegDecoder);
	_frameNum = 0;

	return true;
#else /* USE_MPEG2 */
	return false;
#endif
}
Пример #6
0
int main(int argc, char *argv[]) {
	GtkWidget *main_window, *scroll;
	GtkWidget *treeview;
	GtkTreeViewColumn *column;
	GtkCellRenderer *name_renderer, *size_renderer;
	GtkTreeStore *store;
	GtkTreeIter categories[14];
	GValue value = { 0, };
	gint offset;
	uint32 res_counts[14];
	uint32 res_sizes[14];
	int i;

	Common::File in;
	uint32 index_pos;
	uint32 pos, len;

	gtk_init(&argc, &argv);

	if (argc != 2) {
		printf("Usage: %s filename\n", argv[0]);
		return EXIT_FAILURE;
	}

	in.open(argv[1], "rb");
	if (!in.isOpen()) {
		printf("Couldn't open %s for reading\n", argv[1]);
		return EXIT_FAILURE;
	}

	/* Create the main window, scrollable in both directions */

	main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(GTK_WINDOW(main_window), "CLUster Explorer");
	gtk_window_set_default_size(GTK_WINDOW(main_window), 400, 400);

	g_signal_connect(G_OBJECT(main_window), "destroy", G_CALLBACK(main_window_destroy_cb), NULL);

	scroll = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_ETCHED_IN);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

	/* Create the tree view */

	for (i = 0; i < ARRAYSIZE(res_counts); i++) {
		res_counts[i] = 0;
		res_sizes[i] = 0;
	}

	store = gtk_tree_store_new(N_COLUMNS,
		G_TYPE_STRING,
		G_TYPE_STRING,
		G_TYPE_INT,
		G_TYPE_INT,
		G_TYPE_INT);

	gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), compare_items, NULL, NULL);
	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);

	index_pos = in.readUint32LE();
	in.seek(index_pos, SEEK_SET);

	for (;;) {
		GtkTreeIter iter;
		byte type;
		gchar *utf8_name;
		gchar name[34];
		gchar *size;

		try {
			pos = in.readUint32LE();
			len = in.readUint32LE();
		} catch (...) {
			break;
		}

		size = make_size(len);

		index_pos = in.pos();

		in.seek(pos, SEEK_SET);

		type = in.readByte();
		in.readByte();				/* compType	*/
		in.readUint32LE();			/* compSize	*/
		in.readUint32LE();			/* decompSize	*/
		in.read_noThrow(name, sizeof(name));

		/*
		 * We need to convert from Latin-1 to UTF-8. Otherwise the text
		 * "CAFÉ" won't be displayed properly.
		 */

		utf8_name = g_convert(name, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);

		if (!res_counts[type]) {
			gtk_tree_store_append(store, &categories[type], NULL);
			gtk_tree_store_set(store, &categories[type],
				NAME_COLUMN, getType(type),
				SIZE_COLUMN, "",
				TYPE_COLUMN, -1,
				POSITION_COLUMN, -1,
				LENGTH_COLUMN, -1,
				-1);
		}

		res_counts[type]++;
		res_sizes[type] += len;
		gtk_tree_store_append(store, &iter, &categories[type]);
		gtk_tree_store_set(store, &iter,
			NAME_COLUMN, utf8_name,
			SIZE_COLUMN, size,
			TYPE_COLUMN, type,
			POSITION_COLUMN, pos,
			LENGTH_COLUMN, len);

		in.seek(index_pos, SEEK_SET);
	}

	in.close();

	for (i = 0; i < ARRAYSIZE(res_counts); i++) {
		if (res_counts[i]) {
			gchar size[80];

			sprintf(size, "%s [%d]", make_size(res_sizes[i]), res_counts[i]);
			gtk_tree_store_set(store, &categories[i],
				SIZE_COLUMN, size,
				-1);
		}
	}

	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);

	g_signal_connect(G_OBJECT(treeview), "button-press-event", G_CALLBACK(tree_view_button_cb), argv[1]);

	/* The view now holds a reference. We can get rid of our own. */
	g_object_unref(G_OBJECT(store));

	name_renderer = gtk_cell_renderer_text_new();
	size_renderer = gtk_cell_renderer_text_new();

	g_value_init(&value, G_TYPE_FLOAT);
	g_value_set_float(&value, 1.0);
	g_object_set_property(G_OBJECT(size_renderer), "xalign", &value);

	gtk_tree_view_insert_column_with_attributes(
		GTK_TREE_VIEW(treeview), -1, "Name", name_renderer,
		"text", NAME_COLUMN,
		NULL);

	offset = gtk_tree_view_insert_column_with_attributes(
		GTK_TREE_VIEW(treeview), -1, "Size", size_renderer,
		"text", SIZE_COLUMN,
		NULL);
	column = gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), offset - 1);
	gtk_tree_view_column_set_alignment(column, 1.0);

	gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(treeview));
	gtk_container_add(GTK_CONTAINER(main_window), scroll);
	gtk_widget_show_all(GTK_WIDGET(main_window));
	gtk_main();

	return EXIT_SUCCESS;
}
Пример #7
0
void Screen::rollCredits() {
	uint32 loopingMusicId = _vm->_sound->getLoopingMusicId();

	// Prepare for the credits by fading down, stoping the music, etc.

	_vm->_mouse->setMouse(0);

	_vm->_sound->muteFx(true);
	_vm->_sound->muteSpeech(true);

	waitForFade();
	fadeDown();
	waitForFade();

	_vm->_mouse->closeMenuImmediately();

	// There are three files which I believe are involved in showing the
	// credits:
	//
	// credits.bmp  - The "Smacker" logo, stored as follows:
	//
	//     width     2 bytes, little endian
	//     height    2 bytes, little endian
	//     palette   3 * 256 bytes
	//     data      width * height bytes
	//
	//     Note that the maximum colour component in the palette is 0x3F.
	//     This is the same resolution as the _paletteMatch table. I doubt
	//     that this is a coincidence, but let's use the image palette
	//     directly anyway, just to be safe.
	//
	// credits.clu  - The credits text
	//
	//     This is simply a text file with CRLF line endings.
	//     '^' is not shown, but used to mark the center of the line.
	//     '@' is used as a placeholder for the "Smacker" logo. At least
	//     when it appears alone.
	//     Remaining lines are centered.
	//     The German version also contains character code 9 for no
	//     apparent reason. We ignore them.
	//
	// fonts.clu    - The credits font?
	//
	//     FIXME: At this time I don't know how to interpret fonts.clu. For
	//     now, let's just the standard speech font instead.

	SpriteInfo spriteInfo;
	Common::File f;
	int i;

	// Read the "Smacker" logo

	uint16 logoWidth = 0;
	uint16 logoHeight = 0;
	byte *logoData = NULL;
	byte palette[256 * 4];

	if (f.open("credits.bmp")) {
		logoWidth = f.readUint16LE();
		logoHeight = f.readUint16LE();

		for (i = 0; i < 256; i++) {
			palette[i * 4 + 0] = f.readByte() << 2;
			palette[i * 4 + 1] = f.readByte() << 2;
			palette[i * 4 + 2] = f.readByte() << 2;
			palette[i * 4 + 3] = 0;
		}

		logoData = (byte *)malloc(logoWidth * logoHeight);

		f.read(logoData, logoWidth * logoHeight);
		f.close();
	} else {
		warning("Can't find credits.bmp");
		memset(palette, 0, sizeof(palette));
		palette[14 * 4 + 0] = 252;
		palette[14 * 4 + 1] = 252;
		palette[14 * 4 + 2] = 252;
		palette[14 * 4 + 3] = 0;
	}

	setPalette(0, 256, palette, RDPAL_INSTANT);

	// Read the credits text

	Common::Array<CreditsLine *> creditsLines;

	int lineCount = 0;
	int lineTop = 400;
	int paragraphStart = 0;
	bool hasCenterMark = false;

	if (!f.open("credits.clu")) {
		warning("Can't find credits.clu");
		return;
	}

	while (1) {
		char buffer[80];
		char *line = f.readLine(buffer, sizeof(buffer));

		if (!line || *line == 0) {
			if (!hasCenterMark) {
				for (i = paragraphStart; i < lineCount; i++)
					creditsLines[i]->type = LINE_CENTER;
			}
			paragraphStart = lineCount;
			hasCenterMark = false;
			if (paragraphStart == lineCount)
				lineTop += CREDITS_LINE_SPACING;

			if (!line)
				break;

			continue;
		}

		// The German credits contains character code 9. We don't want
		// the credits to show the 'dud' symbol, so we replace them
		// with spaces.

		for (char *ptr = line; *ptr; ptr++) {
			if (*ptr < 32)
				*ptr = 32;
		}

		char *center_mark = strchr(line, '^');

		if (center_mark) {
			// The current paragraph has at least one center mark.
			hasCenterMark = true;

			if (center_mark != line) {
				creditsLines.push_back(new CreditsLine);

				// The center mark is somewhere inside the
				// line. Split it into left and right side.
				*center_mark = 0;

				creditsLines[lineCount]->top = lineTop;
				creditsLines[lineCount]->height = CREDITS_FONT_HEIGHT;
				creditsLines[lineCount]->type = LINE_LEFT;
				creditsLines[lineCount]->str = strdup(line);

				lineCount++;
				*center_mark = '^';
			}

			line = center_mark;
		}

		creditsLines.push_back(new CreditsLine);

		creditsLines[lineCount]->top = lineTop;

		if (*line == '^') {
			creditsLines[lineCount]->type = LINE_RIGHT;
			line++;
		} else
			creditsLines[lineCount]->type = LINE_LEFT;

		if (strcmp(line, "@") == 0) {
			creditsLines[lineCount]->height = logoHeight;
			lineTop += logoHeight;
		} else {
			creditsLines[lineCount]->height = CREDITS_FONT_HEIGHT;
			lineTop += CREDITS_LINE_SPACING;
		}

		creditsLines[lineCount]->str = strdup(line);
		lineCount++;
	}

	f.close();

	// We could easily add some ScummVM stuff to the credits, if we wanted
	// to. On the other hand, anyone with the attention span to actually
	// read all the credits probably already knows. :-)

	// Start the music and roll the credits

	// The credits music (which can also be heard briefly in the "carib"
	// cutscene) is played once.

	_vm->_sound->streamCompMusic(309, false);

	clearScene();
	fadeUp(0);

	spriteInfo.scale = 0;
	spriteInfo.scaledWidth = 0;
	spriteInfo.scaledHeight = 0;
	spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS;
	spriteInfo.blend = 0;

	int startLine = 0;
	int scrollPos = 0;

	bool abortCredits = false;

	int scrollSteps = lineTop + CREDITS_FONT_HEIGHT;
	uint32 musicStart = _vm->getMillis();

	// Ideally the music should last just a tiny bit longer than the
	// credits. Note that musicTimeRemaining() will return 0 if the music
	// is muted, so we need a sensible fallback for that case.

	uint32 musicLength = MAX((int32)(1000 * (_vm->_sound->musicTimeRemaining() - 3)), 25 * (int32)scrollSteps);

	while (scrollPos < scrollSteps && !_vm->_quit) {
		clearScene();

		for (i = startLine; i < lineCount; i++) {
			if (!creditsLines[i])
				continue;

			// Free any sprites that have scrolled off the screen

			if (creditsLines[i]->top + creditsLines[i]->height < scrollPos) {
				debug(2, "Freeing line %d: '%s'", i, creditsLines[i]->str);

				delete creditsLines[i];
				creditsLines[i] = NULL;

				startLine = i + 1;
			} else if (creditsLines[i]->top < scrollPos + 400) {
				if (!creditsLines[i]->sprite) {
					debug(2, "Creating line %d: '%s'", i, creditsLines[i]->str);
					creditsLines[i]->sprite = _vm->_fontRenderer->makeTextSprite((byte *)creditsLines[i]->str, 600, 14, _vm->_speechFontId, 0);
				}

				FrameHeader frame;

				frame.read(creditsLines[i]->sprite);

				spriteInfo.y = creditsLines[i]->top - scrollPos;
				spriteInfo.w = frame.width;
				spriteInfo.h = frame.height;
				spriteInfo.data = creditsLines[i]->sprite + FrameHeader::size();

				switch (creditsLines[i]->type) {
				case LINE_LEFT:
					spriteInfo.x = RENDERWIDE / 2 - 5 - frame.width;
					break;
				case LINE_RIGHT:
					spriteInfo.x = RENDERWIDE / 2 + 5;
					break;
				case LINE_CENTER:
					if (strcmp(creditsLines[i]->str, "@") == 0) {
						spriteInfo.data = logoData;
						spriteInfo.x = (RENDERWIDE - logoWidth) / 2;
						spriteInfo.w = logoWidth;
						spriteInfo.h = logoHeight;
					} else
						spriteInfo.x = (RENDERWIDE - frame.width) / 2;
					break;
				}

				if (spriteInfo.data)
					drawSprite(&spriteInfo);
			} else
				break;
		}

		updateDisplay();

		KeyboardEvent *ke = _vm->keyboardEvent();

		if (ke && ke->keycode == 27) {
			if (!abortCredits) {
				abortCredits = true;
				fadeDown();
			}
		}

		if (abortCredits && getFadeStatus() == RDFADE_BLACK)
			break;

		_vm->sleepUntil(musicStart + (musicLength * scrollPos) / scrollSteps);
		scrollPos++;
	}

	// We're done. Clean up and try to put everything back where it was
	// before the credits.

	for (i = 0; i < lineCount; i++) {
		delete creditsLines[i];
	}

	free(logoData);

	if (!abortCredits) {
		fadeDown();

		// The music should either have stopped or be about to stop, so
		// wait for it to really happen.

		while (_vm->_sound->musicTimeRemaining() && !_vm->_quit) {
			updateDisplay(false);
			_vm->_system->delayMillis(100);
		}
	}

	if (_vm->_quit)
		return;

	waitForFade();

	_vm->_sound->muteFx(false);
	_vm->_sound->muteSpeech(false);

	if (loopingMusicId)
		_vm->_sound->streamCompMusic(loopingMusicId, true);
	else
		_vm->_sound->stopMusic(false);

	if (!_vm->_mouse->getMouseStatus() || _vm->_mouse->isChoosing())
		_vm->_mouse->setMouse(NORMAL_MOUSE_ID);

	if (_vm->_logic->readVar(DEAD))
		_vm->_mouse->buildSystemMenu();
}
Пример #8
0
/**
 * Loads Hugo.dat file, which contains all the hardcoded data in the original executables
 */
bool HugoEngine::loadHugoDat() {
	Common::File in;
	in.open("hugo.dat");

	if (!in.isOpen()) {
		Common::String errorMessage = "You're missing the 'hugo.dat' file. Get it from the ScummVM website";
		GUIErrorMessage(errorMessage);
		warning("%s", errorMessage.c_str());
		return false;
	}

	// Read header
	char buf[4];
	in.read(buf, 4);

	if (memcmp(buf, "HUGO", 4)) {
		Common::String errorMessage = "File 'hugo.dat' is corrupt. Get it from the ScummVM website";
		GUIErrorMessage(errorMessage);
		return false;
	}

	int majVer = in.readByte();
	int minVer = in.readByte();

	if ((majVer != HUGO_DAT_VER_MAJ) || (minVer != HUGO_DAT_VER_MIN)) {
		Common::String errorMessage = Common::String::format("File 'hugo.dat' is wrong version. Expected %d.%d but got %d.%d. Get it from the ScummVM website", HUGO_DAT_VER_MAJ, HUGO_DAT_VER_MIN, majVer, minVer);
		GUIErrorMessage(errorMessage);
		return false;
	}

	_numVariant = in.readUint16BE();

	_screen->loadPalette(in);
	_screen->loadFontArr(in);
	_text->loadAllTexts(in);
	_intro->loadIntroData(in);
	_parser->loadArrayReqs(in);
	_parser->loadCatchallList(in);
	_parser->loadBackgroundObjects(in);
	_parser->loadCmdList(in);
	_mouse->loadHotspots(in);
	_inventory->loadInvent(in);
	_object->loadObjectUses(in);
	_object->loadObjectArr(in);
	_object->loadNumObj(in);
	_scheduler->loadPoints(in);
	_scheduler->loadScreenAct(in);
	_scheduler->loadActListArr(in);
	_scheduler->loadAlNewscrIndex(in);
	_hero = &_object->_objects[kHeroIndex];         // This always points to hero
	_screenPtr = &(_object->_objects[kHeroIndex]._screenIndex); // Current screen is hero's
	_heroImage = kHeroIndex;                        // Current in use hero image

	for (int varnt = 0; varnt < _numVariant; varnt++) {
		if (varnt == _gameVariant) {
			_tunesNbr     = in.readSByte();
			_soundSilence = in.readSByte();
			_soundTest    = in.readSByte();
		} else {
			in.readSByte();
			in.readSByte();
			in.readSByte();
		}
	}

	int numElem;

	//Read _defltTunes
	for (int varnt = 0; varnt < _numVariant; varnt++) {
		numElem = in.readUint16BE();
		if (varnt == _gameVariant) {
			_defltTunes = (int16 *)malloc(sizeof(int16) * numElem);
			for (int i = 0; i < numElem; i++)
				_defltTunes[i] = in.readSint16BE();
		} else {
			for (int i = 0; i < numElem; i++)
				in.readSint16BE();
		}
	}

	//Read _screenStates size
	for (int varnt = 0; varnt < _numVariant; varnt++) {
		numElem = in.readUint16BE();
		if (varnt == _gameVariant) {
			_numStates = numElem;
			_screenStates = (byte *)malloc(sizeof(byte) * numElem);
			memset(_screenStates, 0, sizeof(byte) * numElem);
		}
	}

	//Read look, take and drop special verbs indexes
	for (int varnt = 0; varnt < _numVariant; varnt++) {
		if (varnt == _gameVariant) {
			_look = in.readUint16BE();
			_take = in.readUint16BE();
			_drop = in.readUint16BE();
		} else {
			in.readUint16BE();
			in.readUint16BE();
			in.readUint16BE();
		}
	}

	_sound->loadIntroSong(in);
	_topMenu->loadBmpArr(in);

	return true;
}
Пример #9
0
ADDetectedGame DirectorMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
	// TODO: Handle Mac fallback

	// reset fallback description
	Director::DirectorGameDescription *desc = &s_fallbackDesc;
	desc->desc.gameId = "director";
	desc->desc.extra = "";
	desc->desc.language = Common::UNK_LANG;
	desc->desc.flags = ADGF_NO_FLAGS;
	desc->desc.platform = Common::kPlatformWindows;
	desc->desc.guiOptions = GUIO0();
	desc->desc.filesDescriptions[0].fileName = 0;
	desc->version = 0;
	desc->gameID = Director::GID_GENERIC;

	for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
		if (file->isDirectory())
			continue;

		Common::String fileName = file->getName();
		fileName.toLowercase();
		if (!fileName.hasSuffix(".exe"))
			continue;

		Common::File f;
		if (!f.open(*file))
			continue;

		f.seek(-4, SEEK_END);

		uint32 offset = f.readUint32LE();

		if (f.eos() || offset == 0 || offset >= (uint32)(f.size() - 4))
			continue;

		f.seek(offset);

		uint32 tag = f.readUint32LE();

		switch (tag) {
		case MKTAG('3', '9', 'J', 'P'):
			desc->version = 4;
			break;
		case MKTAG('P', 'J', '9', '5'):
			desc->version = 5;
			break;
		case MKTAG('P', 'J', '0', '0'):
			desc->version = 7;
			break;
		default:
			// Prior to version 4, there was no tag here. So we'll use a bit of a
			// heuristic to detect. The first field is the entry count, of which
			// there should only be one.
			if ((tag & 0xFFFF) != 1)
				continue;

			f.skip(3);

			uint32 mmmSize = f.readUint32LE();

			if (f.eos() || mmmSize == 0)
				continue;

			byte fileNameSize = f.readByte();

			if (f.eos())
				continue;

			f.skip(fileNameSize);
			byte directoryNameSize = f.readByte();

			if (f.eos())
				continue;

			f.skip(directoryNameSize);

			if (f.pos() != f.size() - 4)
				continue;

			// Assume v3 at this point (for now at least)
			desc->version = 3;
		}

		strncpy(s_fallbackFileNameBuffer, fileName.c_str(), 50);
		s_fallbackFileNameBuffer[50] = '\0';
		desc->desc.filesDescriptions[0].fileName = s_fallbackFileNameBuffer;

		warning("Director fallback detection D%d", desc->version);

		return ADDetectedGame(&desc->desc);
	}

	return ADDetectedGame();
}
Пример #10
0
FileSystem::FileSystem(const char *hashFilename) {

	for (int i = 0; i < 10; i++) {
		_hagEntries[i].filename[0] = '\0';
		_hagEntries[i].fileIndex = 0; // Was -1
		_hagEntries[i].hagFile = 0;
	}

	Common::File hashFile;
	uint32 hashSize;

	hashFile.open(hashFilename);

	if (!hashFile.isOpen()) {
		printf("FileSystem::FileSystem: error opening hash %s\n", hashFilename);
	}

	hashSize = hashFile.readUint32LE();

	//printf("FileSystem::FileSystem: hashSize = %d\n", hashSize);

	/* load file records and add them to the hash list */
	for (uint i = 0; i < hashSize; i++) {
		HashFileEntry entry;
		hashFile.read(entry.filename, kM4MaxFilenameSize);
		str_lower(entry.filename);
		entry.hagfile = hashFile.readByte();
		hashFile.readByte();
		entry.offset = hashFile.readUint32LE();
		entry.size = hashFile.readUint32LE();
		hashFile.readUint32LE();

		if (entry.filename[0]) {
			/*
			printf("  filename: %s\n", entry.filename);
			printf("  hagfile: %d\n", entry.hagfile);
			printf("  disks: %d\n", entry.disks);
			printf("  offset: %08X\n", entry.offset);
			printf("  size: %d\n", entry.size);
			printf("  next: %08X\n", entry.next);
			*/
			_fileEntries[entry.filename] = entry;
		}

	}

	/* load hagfile records and update the list */
	while (!hashFile.eos()) {
		HashHagEntry entry;
		hashFile.read(entry.filename, kM4MaxFilenameSize);
		entry.fileIndex = hashFile.readByte();
		if (hashFile.eos())
			break;

		changeExtension(_hagEntries[entry.fileIndex].filename, entry.filename, "HAG");
		_hagEntries[entry.fileIndex].fileIndex = entry.fileIndex;

		_hagEntries[entry.fileIndex].hagFile = new Common::File();
		_hagEntries[entry.fileIndex].hagFile->open(_hagEntries[entry.fileIndex].filename);

		if (!_hagEntries[entry.fileIndex].hagFile->isOpen()) {
			printf("FileSystem::FileSystem: error opening hag %s\n", _hagEntries[entry.fileIndex].filename);
		}

	}

	hashFile.close();

}
Пример #11
0
InstallShieldCabinet::InstallShieldCabinet(const Common::String &filename) : _installShieldFilename(filename) {
	Common::File installShieldFile;

	if (!installShieldFile.open(_installShieldFilename)) {
		warning("InstallShieldCabinet::InstallShieldCabinet(): Could not find the archive file %s", _installShieldFilename.c_str());
		return;
	}

	// Note that we only support a limited subset of cabinet files
	// Only single cabinet files and ones without data shared between
	// cabinets.

	// Check for the magic uint32
	if (installShieldFile.readUint32LE() != 0x28635349) {
		warning("InstallShieldCabinet::InstallShieldCabinet(): Magic ID doesn't match");
		return;
	}

	uint32 version = installShieldFile.readUint32LE();

	if (version != 0x01000004) {
		warning("Unsupported CAB version %08x", version);
		return;
	}

	/* uint32 volumeInfo = */ installShieldFile.readUint32LE();
	uint32 cabDescriptorOffset = installShieldFile.readUint32LE();
	/* uint32 cabDescriptorSize = */ installShieldFile.readUint32LE();

	installShieldFile.seek(cabDescriptorOffset);

	installShieldFile.skip(12);
	uint32 fileTableOffset = installShieldFile.readUint32LE();
	installShieldFile.skip(4);
	uint32 fileTableSize = installShieldFile.readUint32LE();
	uint32 fileTableSize2 = installShieldFile.readUint32LE();
	uint32 directoryCount = installShieldFile.readUint32LE();
	installShieldFile.skip(8);
	uint32 fileCount = installShieldFile.readUint32LE();

	if (fileTableSize != fileTableSize2)
		warning("file table sizes do not match");

	// We're ignoring file groups and components since we
	// should not need them. Moving on to the files...

	installShieldFile.seek(cabDescriptorOffset + fileTableOffset);
	uint32 fileTableCount = directoryCount + fileCount;
	uint32 *fileTableOffsets = new uint32[fileTableCount];
	for (uint32 i = 0; i < fileTableCount; i++)
		fileTableOffsets[i] = installShieldFile.readUint32LE();

	for (uint32 i = directoryCount; i < fileCount + directoryCount; i++) {
		installShieldFile.seek(cabDescriptorOffset + fileTableOffset + fileTableOffsets[i]);
		uint32 nameOffset = installShieldFile.readUint32LE();
		/* uint32 directoryIndex = */ installShieldFile.readUint32LE();

		// First read in data needed by us to get at the file data
		FileEntry entry;
		entry.flags = installShieldFile.readUint16LE();
		entry.uncompressedSize = installShieldFile.readUint32LE();
		entry.compressedSize = installShieldFile.readUint32LE();
		installShieldFile.skip(20);
		entry.offset = installShieldFile.readUint32LE();

		// Then let's get the string
		installShieldFile.seek(cabDescriptorOffset + fileTableOffset + nameOffset);
		Common::String fileName;

		char c = installShieldFile.readByte();
		while (c) {
			fileName += c;
			c = installShieldFile.readByte();
		}
		_map[fileName] = entry;
	}

	delete[] fileTableOffsets;
}