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; }
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; } }
/** * 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(); }
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; }
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 }
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; }
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(); }
/** * 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; }
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(); }
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(); }
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; }