// Will try to set amiga palette by using "spal" file. If not found, we return false bool GfxPalette::setAmiga() { Common::File file; if (file.open("spal")) { for (int curColor = 0; curColor < 32; curColor++) { byte byte1 = file.readByte(); byte byte2 = file.readByte(); if (file.eos()) error("Amiga palette file ends prematurely"); _sysPalette.colors[curColor].used = 1; _sysPalette.colors[curColor].r = (byte1 & 0x0F) * 0x11; _sysPalette.colors[curColor].g = ((byte2 & 0xF0) >> 4) * 0x11; _sysPalette.colors[curColor].b = (byte2 & 0x0F) * 0x11; if (_totalScreenColors == 64) { // Set the associated color from the Amiga halfbrite colors _sysPalette.colors[curColor + 32].used = 1; _sysPalette.colors[curColor + 32].r = _sysPalette.colors[curColor].r >> 1; _sysPalette.colors[curColor + 32].g = _sysPalette.colors[curColor].g >> 1; _sysPalette.colors[curColor + 32].b = _sysPalette.colors[curColor].b >> 1; } } // Directly set the palette, because setOnScreen() wont do a thing for amiga copySysPaletteToScreen(); return true; }
void ScriptManager::parseScrFile(const Common::String &fileName, bool isGlobal) { Common::File file; if (!file.open(fileName)) { warning("Script file not found: %s", fileName.c_str()); return; } while(!file.eos()) { Common::String line = file.readLine(); if (file.err()) { warning("Error parsing scr file: %s", fileName.c_str()); return; } trimCommentsAndWhiteSpace(&line); if (line.empty()) continue; if (line.matchString("puzzle:*", true)) { Puzzle *puzzle = new Puzzle(); sscanf(line.c_str(),"puzzle:%u",&(puzzle->key)); parsePuzzle(puzzle, file); if (isGlobal) { _globalPuzzles.push_back(puzzle); } else { _activePuzzles.push_back(puzzle); } } else if (line.matchString("control:*", true)) { parseControl(line, file); } } }
bool readBit8u(MT32Emu::Bit8u *in) { byte b = _in.readByte(); if (_in.eos()) return false; *in = b; return true; }
//Gets AGIPAL Data void GfxMgr::setAGIPal(int p0) { //If 0 from savefile, do not use if (p0 == 0) return; char filename[15]; sprintf(filename, "pal.%d", p0); Common::File agipal; if (!agipal.open(filename)) { warning("Couldn't open AGIPAL palette file '%s'. Not changing palette", filename); return; // Needed at least by Naturette 3 which uses AGIPAL but provides no palette files } //Chunk0 holds colors 0-7 agipal.read(&_agipalPalette[0], 24); //Chunk1 is the same as the chunk0 //Chunk2 chunk holds colors 8-15 agipal.seek(24, SEEK_CUR); agipal.read(&_agipalPalette[24], 24); //Chunk3 is the same as the chunk2 //Chunks4-7 are duplicates of chunks0-3 if (agipal.eos() || agipal.err()) { warning("Couldn't read AGIPAL palette from '%s'. Not changing palette", filename); return; } // Use only the lowest 6 bits of each color component (Red, Green and Blue) // because VGA used only 6 bits per color component (i.e. VGA had 18-bit colors). // This should now be identical to the original AGIPAL-hack's behavior. bool validVgaPalette = true; for (int i = 0; i < 16 * 3; i++) { if (_agipalPalette[i] >= (1 << 6)) { _agipalPalette[i] &= 0x3F; // Leave only the lowest 6 bits of each color component validVgaPalette = false; } } if (!validVgaPalette) warning("Invalid AGIPAL palette (Over 6 bits per color component) in '%s'. Using only the lowest 6 bits per color component", filename); _agipalFileNum = p0; initPalette(_agipalPalette); gfxSetPalette(); debug(1, "Using AGIPAL palette from '%s'", filename); }
int AgiEngine::loadWords(const char *fname) { Common::File fp; if (!fp.open(fname)) { warning("loadWords: can't open %s", fname); return errOK; // err_BadFileOpen } debug(0, "Loading dictionary: %s", fname); // Loop through alphabet, as words in the dictionary file are sorted by // first character for (int i = 0; i < 26; i++) { fp.seek(i * 2, SEEK_SET); int offset = fp.readUint16BE(); if (offset == 0) continue; fp.seek(offset, SEEK_SET); int k = fp.readByte(); while (!fp.eos() && !fp.err()) { // Read next word char c, str[64]; do { c = fp.readByte(); str[k++] = (c ^ 0x7F) & 0x7F; } while (!(c & 0x80) && k < (int)sizeof(str) - 1); str[k] = 0; // WORKAROUND: // The SQ0 fan game stores words starting with numbers (like '7up') // in its dictionary under the 'a' entry. We skip these. // See bug #3615061 if (str[0] == 'a' + i) { // And store it in our internal dictionary AgiWord *w = new AgiWord; w->word = myStrndup(str, k); w->id = fp.readUint16BE(); _game.words[i].push_back(w); } k = fp.readByte(); // Are there more words with an already known prefix? // WORKAROUND: We only break after already seeing words with the // right prefix, for the SQ0 words starting with digits filed under // 'a'. See above comment and bug #3615061. if (k == 0 && str[0] >= 'a' + i) break; } } return errOK; }
void ResMan::resOpen(uint32 id) { // load resource ID into memory MemHandle *memHandle = resHandle(id); if (!memHandle) return; if (memHandle->cond == MEM_FREED) { // memory has been freed uint32 size = resLength(id); _memMan->alloc(memHandle, size); Common::File *clusFile = resFile(id); assert(clusFile); clusFile->seek(resOffset(id)); clusFile->read(memHandle->data, size); if (clusFile->err() || clusFile->eos()) { error("Can't read %d bytes from offset %d from cluster file %s\nResource ID: %d (%08X)", size, resOffset(id), _prj.clu[(id >> 24) - 1].label, id, id); }
void StringManager::loadStrFile(const Common::String &fileName) { Common::File file; if (!_engine->getSearchManager()->openFile(file, fileName)) { error("%s does not exist. String parsing failed", fileName.c_str()); } uint lineNumber = 0; while (!file.eos()) { _lines[lineNumber] = readWideLine(file); lineNumber++; assert(lineNumber <= NUM_TEXT_LINES); } }
/** * Allocates enough RAM to hold the global Glitter variables. */ void RegisterGlobals(int num) { if (pGlobals == NULL) { numGlobals = num; hMasterScript = !TinselV2 ? 0 : READ_LE_UINT32(FindChunk(MASTER_SCNHANDLE, CHUNK_MASTER_SCRIPT)); // Allocate RAM for pGlobals and make sure it's allocated pGlobals = (int32 *)calloc(numGlobals, sizeof(int32)); if (pGlobals == NULL) { error("Cannot allocate memory for global data"); } // Allocate RAM for interpret contexts and make sure it's allocated icList = (INT_CONTEXT *)calloc(NUM_INTERPRET, sizeof(INT_CONTEXT)); if (icList == NULL) { error("Cannot allocate memory for interpret contexts"); } g_scheduler->setResourceCallback(FreeInterpretContextPr); } else { // Check size is still the same assert(numGlobals == num); memset(pGlobals, 0, numGlobals * sizeof(int32)); memset(icList, 0, NUM_INTERPRET * sizeof(INT_CONTEXT)); } if (TinselV2) { // read initial values CdCD(nullContext); Common::File f; if (!f.open(GLOBALS_FILENAME)) error(CANNOT_FIND_FILE, GLOBALS_FILENAME); int32 length = f.readSint32LE(); if (length != num) error(FILE_IS_CORRUPT, GLOBALS_FILENAME); for (int i = 0; i < length; ++i) pGlobals[i] = f.readSint32LE(); if (f.eos() || f.err()) error(FILE_IS_CORRUPT, GLOBALS_FILENAME); f.close(); } }
void TitlerControl::readStringsFile(const Common::String &fileName) { Common::File file; if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("String_resource_file %s could could be opened", fileName.c_str()); return; } _strings.clear(); while (!file.eos()) { Common::String line = readWideLine(file); _strings.push_back(line); } file.close(); }
// AUDIOnnn.MAP contains 10-byte entries: // Early format: // w 5 bits resource type and 11 bits resource number // dw 7 bits volume number and 25 bits offset // dw size // Later format: // w nEntry // dw offset+volume (as in resource.map) // dw size // ending with 10 0xFFs int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) { Common::File file; if (!file.open(map->getLocationName())) return SCI_ERROR_RESMAP_NOT_FOUND; bool oldFormat = (file.readUint16LE() >> 11) == kResourceTypeAudio; file.seek(0); for (;;) { uint16 n = file.readUint16LE(); uint32 offset = file.readUint32LE(); uint32 size = file.readUint32LE(); if (file.eos() || file.err()) { warning("Error while reading %s", map->getLocationName().c_str()); return SCI_ERROR_RESMAP_NOT_FOUND; } if (n == 0xffff) break; byte volume_nr; if (oldFormat) { n &= 0x07ff; // Mask out resource type volume_nr = offset >> 25; // most significant 7 bits offset &= 0x01ffffff; // least significant 25 bits } else { volume_nr = offset >> 28; // most significant 4 bits offset &= 0x0fffffff; // least significant 28 bits } ResourceSource *src = findVolume(map, volume_nr); if (src) { const ResourceId resId(kResourceTypeAudio, n); if (unload) removeAudioResource(resId); else addResource(resId, src, offset, size, map->getLocationName()); } else { warning("Failed to find audio volume %i", volume_nr); return SCI_ERROR_NO_RESOURCE_FILES_FOUND; } }
TLib::TLib(MemoryManager &memManager, const Common::String &filename) : _memoryManager(memManager) { // If the resource strings list isn't yet loaded, load them if (_resStrings.size() == 0) { Common::File f; if (f.open("tsage.cfg")) { while (!f.eos()) { _resStrings.push_back(f.readLine()); } f.close(); } } if (!_file.open(filename)) error("Missing file %s", filename.c_str()); loadIndex(); }
// Will try to set amiga palette by using "spal" file. If not found, we return false bool GfxPalette::setAmiga() { Common::File file; if (file.open("spal")) { for (int curColor = 0; curColor < 32; curColor++) { byte byte1 = file.readByte(); byte byte2 = file.readByte(); if (file.eos()) error("Amiga palette file ends prematurely"); _sysPalette.colors[curColor].used = 1; _sysPalette.colors[curColor].r = (byte1 & 0x0F) * 0x11; _sysPalette.colors[curColor].g = ((byte2 & 0xF0) >> 4) * 0x11; _sysPalette.colors[curColor].b = (byte2 & 0x0F) * 0x11; } // Directly set the palette, because setOnScreen() wont do a thing for amiga copySysPaletteToScreen(); return true; } return false; }
bool PCMMusicPlayer::getNextChunk() { MusicSegment *musicSegments; int32 *script, *scriptBuffer; int id; int snum; uint32 sampleOffset, sampleLength, sampleCLength; Common::File file; byte *buffer; Common::SeekableReadStream *sampleStream; switch (_state) { case S_NEW: case S_NEXT: _forcePlay = false; script = scriptBuffer = (int32 *)LockMem(_hScript); // Set parameters for this chunk of music id = _scriptNum; while (id--) script = scriptBuffer + READ_32(script); snum = FROM_32(script[_scriptIndex++]); if (snum == MUSIC_JUMP || snum == MUSIC_END) { // Let usual code sort it out! _scriptIndex--; // Undo increment _forcePlay = true; // Force a Play _state = S_END1; // 'Goto' S_END1 break; } musicSegments = (MusicSegment *) LockMem(_hSegment); assert(FROM_32(musicSegments[snum].numChannels) == 1); assert(FROM_32(musicSegments[snum].bitsPerSample) == 16); sampleOffset = FROM_32(musicSegments[snum].sampleOffset); sampleLength = FROM_32(musicSegments[snum].sampleLength); sampleCLength = (((sampleLength + 63) & ~63)*33)/64; if (!file.open(_filename)) error(CANNOT_FIND_FILE, _filename.c_str()); file.seek(sampleOffset); if (file.eos() || file.err() || (uint32)file.pos() != sampleOffset) error(FILE_IS_CORRUPT, _filename.c_str()); buffer = (byte *) malloc(sampleCLength); assert(buffer); // read all of the sample if (file.read(buffer, sampleCLength) != sampleCLength) error(FILE_IS_CORRUPT, _filename.c_str()); debugC(DEBUG_DETAILED, kTinselDebugMusic, "Creating ADPCM music chunk with size %d, " "offset %d (script %d.%d)", sampleCLength, sampleOffset, _scriptNum, _scriptIndex - 1); sampleStream = new Common::MemoryReadStream(buffer, sampleCLength, DisposeAfterUse::YES); delete _curChunk; _curChunk = new Tinsel8_ADPCMStream(sampleStream, DisposeAfterUse::YES, sampleCLength, 22050, 1, 32); _state = S_MID; return true; case S_END1: debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END1 (script %d.%d)", _scriptNum, _scriptIndex); script = scriptBuffer = (int32 *) LockMem(_hScript); id = _scriptNum; while (id--) script = scriptBuffer + READ_32(script); snum = FROM_32(script[_scriptIndex]); if (snum == MUSIC_END) { _state = S_END2; } else { if (snum == MUSIC_JUMP) _scriptIndex = FROM_32(script[_scriptIndex+1]); _state = _forcePlay ? S_NEW : S_NEXT; _forcePlay = false; } return true; case S_END2: debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END2 (script %d.%d)", _scriptNum, _scriptIndex); _silenceSamples = 11025; // Half a second of silence return true; case S_END3: debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END3 (script %d.%d)", _scriptNum, _scriptIndex); stop(); _state = S_IDLE; return false; case S_IDLE: return false; default: break; } return true; }
bool isEOF() { return _in.isOpen() && _in.eos(); }
bool fileToStack(const Common::String &filename, StackHandler *sH) { Variable stringVar; stringVar.varType = SVT_NULL; Common::String checker = saveEncoding ? "[Custom data (encoded)]\r\n" : "[Custom data (ASCII)]\n"; Common::File fd; if (!fd.open(filename)) { #if 0 char currentDir[1000]; if (!getcwd(currentDir, 998)) { debugOut("Can't get current directory.\n"); } if (chdir(gamePath)) { debugOut("Error: Failed changing to directory %s\n", gamePath); } if (chdir(currentDir)) { debugOut("Error: Failed changing to directory %s\n", currentDir); } if (!fd.open(filename)) { return fatal("No such file", filename); } #endif return fatal("No such file", filename); //TODO: false value } encode1 = (byte)saveEncoding & 255; encode2 = (byte)(saveEncoding >> 8); for (uint i = 0; i < checker.size(); ++i) { if (fd.readByte() != checker[i]) { fd.close(); return fatal(LOAD_ERROR "This isn't a SLUDGE custom data file:", filename); } } if (saveEncoding) { checker = readStringEncoded(&fd); if (checker == UTF8_CHECKER) { fd.close(); return fatal( LOAD_ERROR "The current file encoding setting does not match the encoding setting used when this file was created:", filename); } } for (;;) { if (saveEncoding) { char i = fd.readByte() ^ encode1; if (fd.eos()) break; switch (i) { case 0: { Common::String g = readStringEncoded(&fd); makeTextVar(stringVar, g); } break; case 1: setVariable(stringVar, SVT_INT, fd.readUint32LE()); break; case 2: setVariable(stringVar, SVT_INT, fd.readByte()); break; default: fatal(LOAD_ERROR "Corrupt custom data file:", filename); fd.close(); return false; } } else { char *line = readTextPlain(&fd); if (!line) break; makeTextVar(stringVar, line); } if (sH->first == NULL) { // Adds to the TOP of the array... oops! if (!addVarToStackQuick(stringVar, sH->first)) return false; sH->last = sH->first; } else { // Adds to the END of the array... much better if (!addVarToStackQuick(stringVar, sH->last->next)) return false; sH->last = sH->last->next; } } fd.close(); return true; }
bool Sound::startSpeech(uint16 roomNo, uint16 localNo) { if (_cowHeader == NULL) { warning("Sound::startSpeech: COW file isn't open"); return false; } uint32 locIndex = 0xFFFFFFFF; uint32 sampleSize = 0; uint32 index = 0; if (_cowMode == CowPSX) { Common::File file; uint16 i; if (!file.open("speech.lis")) { warning ("Could not open speech.lis"); return false; } for (i = 0; !file.eos() && !file.err(); i++) if (file.readUint16LE() == roomNo) { locIndex = i; break; } file.close(); if (locIndex == 0xFFFFFFFF) { warning ("Could not find room %d in speech.lis", roomNo); return false; } if (!file.open("speech.inf")) { warning ("Could not open speech.inf"); return false; } uint16 numRooms = file.readUint16LE(); // Read number of rooms referenced in this file file.seek(locIndex * 4 + 2); // 4 bytes per room, skip first 2 bytes uint16 numLines = file.readUint16LE(); uint16 roomOffset = file.readUint16LE(); file.seek(2 + numRooms * 4 + roomOffset * 2); // The offset is in terms of uint16's, so multiply by 2. Skip the room indexes too. locIndex = 0xFFFFFFFF; for (i = 0; i < numLines; i++) if (file.readUint16LE() == localNo) { locIndex = i; break; } if (locIndex == 0xFFFFFFFF) { warning ("Could not find local number %d in room %d in speech.inf", roomNo, localNo); return false; } file.close(); index = _cowHeader[(roomOffset + locIndex) * 2]; sampleSize = _cowHeader[(roomOffset + locIndex) * 2 + 1]; } else { locIndex = _cowHeader[roomNo] >> 2; sampleSize = _cowHeader[locIndex + (localNo * 2)]; index = _cowHeader[locIndex + (localNo * 2) - 1]; } debug(6, "startSpeech(%d, %d): locIndex %d, sampleSize %d, index %d", roomNo, localNo, locIndex, sampleSize, index); Audio::AudioStream *stream = 0; if (sampleSize) { uint8 speechVol = (_speechVolR + _speechVolL) / 2; int8 speechPan = (_speechVolR - _speechVolL) / 2; if ((_cowMode == CowWave) || (_cowMode == CowDemo)) { uint32 size; int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size); if (data) { stream = Audio::makeRawStream((byte *)data, size, 11025, SPEECH_FLAGS); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); } } else if (_cowMode == CowPSX && sampleSize != 0xffffffff) { _cowFile.seek(index * 2048); Common::SeekableReadStream *tmp = _cowFile.readStream(sampleSize); assert(tmp); stream = Audio::makeVagStream(tmp); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } #ifdef USE_FLAC else if (_cowMode == CowFLAC) { _cowFile.seek(index); Common::SeekableReadStream *tmp = _cowFile.readStream(sampleSize); assert(tmp); stream = Audio::makeFLACStream(tmp, DisposeAfterUse::YES); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } #endif #ifdef USE_VORBIS else if (_cowMode == CowVorbis) { _cowFile.seek(index); Common::SeekableReadStream *tmp = _cowFile.readStream(sampleSize); assert(tmp); stream = Audio::makeVorbisStream(tmp, DisposeAfterUse::YES); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } #endif #ifdef USE_MAD else if (_cowMode == CowMP3) { _cowFile.seek(index); Common::SeekableReadStream *tmp = _cowFile.readStream(sampleSize); assert(tmp); stream = Audio::makeMP3Stream(tmp, DisposeAfterUse::YES); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } #endif return true; } else return false; }
void LeverControl::parseLevFile(const Common::String &fileName) { Common::File file; if (!file.open(fileName)) { warning("LEV file %s could could be opened", fileName.c_str()); return; } Common::String line = file.readLine(); while (!file.eos()) { if (line.matchString("*animation_id*", true)) { // Not used } else if (line.matchString("*filename*", true)) { char fileNameBuffer[25]; sscanf(line.c_str(), "%*[^:]:%25[^~]~", fileNameBuffer); Common::String animationFileName(fileNameBuffer); if (animationFileName.hasSuffix(".avi")) { _animation.avi = new ZorkAVIDecoder(); _animation.avi->loadFile(animationFileName); _fileType = AVI; } else if (animationFileName.hasSuffix(".rlf")) { _animation.rlf = new RlfAnimation(animationFileName, false); _fileType = RLF; } } else if (line.matchString("*skipcolor*", true)) { // Not used } else if (line.matchString("*anim_coords*", true)) { int left, top, right, bottom; sscanf(line.c_str(), "%*[^:]:%d %d %d %d~", &left, &top, &right, &bottom); _animationCoords.left = left; _animationCoords.top = top; _animationCoords.right = right; _animationCoords.bottom = bottom; } else if (line.matchString("*mirrored*", true)) { uint mirrored; sscanf(line.c_str(), "%*[^:]:%u~", &mirrored); _mirrored = mirrored == 0 ? false : true; } else if (line.matchString("*frames*", true)) { sscanf(line.c_str(), "%*[^:]:%u~", &_frameCount); _frameInfo = new FrameInfo[_frameCount]; } else if (line.matchString("*elsewhere*", true)) { // Not used } else if (line.matchString("*out_of_control*", true)) { // Not used } else if (line.matchString("*start_pos*", true)) { sscanf(line.c_str(), "%*[^:]:%u~", &_startFrame); _currentFrame = _startFrame; } else if (line.matchString("*hotspot_deltas*", true)) { uint x; uint y; sscanf(line.c_str(), "%*[^:]:%u %u~", &x, &y); _hotspotDelta.x = x; _hotspotDelta.y = y; } else { uint frameNumber; uint x, y; if (sscanf(line.c_str(), "%u:%u %u", &frameNumber, &x, &y) == 3) { _frameInfo[frameNumber].hotspot.left = x; _frameInfo[frameNumber].hotspot.top = y; _frameInfo[frameNumber].hotspot.right = x + _hotspotDelta.x; _frameInfo[frameNumber].hotspot.bottom = y + _hotspotDelta.y; } Common::StringTokenizer tokenizer(line, " ^=()"); tokenizer.nextToken(); tokenizer.nextToken(); Common::String token = tokenizer.nextToken(); while (!tokenizer.empty()) { if (token == "D") { token = tokenizer.nextToken(); uint angle; uint toFrame; sscanf(token.c_str(), "%u,%u", &toFrame, &angle); _frameInfo[frameNumber].directions.push_back(Direction(angle, toFrame)); } else if (token.hasPrefix("P")) { // Format: P(<from> to <to>) tokenizer.nextToken(); tokenizer.nextToken(); token = tokenizer.nextToken(); uint to = atoi(token.c_str()); _frameInfo[frameNumber].returnRoute.push_back(to); } token = tokenizer.nextToken(); } } line = file.readLine(); } }
void LeverControl::parseLevFile(const Common::String &fileName) { Common::File file; if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("LEV file %s could could be opened", fileName.c_str()); return; } Common::String line; Common::String param; Common::String values; while (!file.eos()) { line = file.readLine(); getLevParams(line, param, values); if (param.matchString("animation_id", true)) { // Not used } else if (param.matchString("filename", true)) { _animation = _engine->loadAnimation(values); } else if (param.matchString("skipcolor", true)) { // Not used } else if (param.matchString("anim_coords", true)) { int left, top, right, bottom; sscanf(values.c_str(), "%d %d %d %d", &left, &top, &right, &bottom); _animationCoords.left = left; _animationCoords.top = top; _animationCoords.right = right; _animationCoords.bottom = bottom; } else if (param.matchString("mirrored", true)) { uint mirrored; sscanf(values.c_str(), "%u", &mirrored); _mirrored = mirrored == 0 ? false : true; } else if (param.matchString("frames", true)) { sscanf(values.c_str(), "%u", &_frameCount); _frameInfo = new FrameInfo[_frameCount]; } else if (param.matchString("elsewhere", true)) { // Not used } else if (param.matchString("out_of_control", true)) { // Not used } else if (param.matchString("start_pos", true)) { sscanf(values.c_str(), "%u", &_startFrame); _currentFrame = _startFrame; } else if (param.matchString("hotspot_deltas", true)) { uint x; uint y; sscanf(values.c_str(), "%u %u", &x, &y); _hotspotDelta.x = x; _hotspotDelta.y = y; } else if (param.matchString("venus_id", true)) { _venusId = atoi(values.c_str()); } else { uint frameNumber; uint x, y; line.toLowercase(); if (sscanf(line.c_str(), "%u:%u %u", &frameNumber, &x, &y) == 3) { _frameInfo[frameNumber].hotspot.left = x; _frameInfo[frameNumber].hotspot.top = y; _frameInfo[frameNumber].hotspot.right = x + _hotspotDelta.x; _frameInfo[frameNumber].hotspot.bottom = y + _hotspotDelta.y; } Common::StringTokenizer tokenizer(line, " ^=()~"); tokenizer.nextToken(); tokenizer.nextToken(); Common::String token = tokenizer.nextToken(); while (!tokenizer.empty()) { if (token == "d") { token = tokenizer.nextToken(); uint angle; uint toFrame; sscanf(token.c_str(), "%u,%u", &toFrame, &angle); _frameInfo[frameNumber].directions.push_back(Direction(angle, toFrame)); } else if (token.hasPrefix("p")) { // Format: P(<from> to <to>) tokenizer.nextToken(); tokenizer.nextToken(); token = tokenizer.nextToken(); uint to = atoi(token.c_str()); _frameInfo[frameNumber].returnRoute.push_back(to); } token = tokenizer.nextToken(); } } // Don't read lines in this place because last will not be parsed. } }
Common::Error GagEngine::StateScript() { Common::Error status(Common::kNoError); Common::File file; if(file.open(_script, *_archive)) { // simple script parsing: skim through, find section and execute commands ParserState parse_state(PS_SECTION_SEARCH); Common::String buffer; Common::String command_name; bool done(false); while(!file.eos()) { // add space for multiline command support Common::String line = file.readLine() + ' '; if(file.err()) { status = Common::Error(Common::kReadingFailed, _script + ", readLine()"); break; } bool skip_line(false); for(Common::String::const_iterator it = line.begin(); it != line.end(); ++it) { switch(parse_state) { case PS_SECTION_SEARCH: // section if(*it == '[') { buffer.clear(); parse_state = PS_SECTION_NAME; } break; case PS_SECTION_NAME: // section end if(*it == ']') { #ifdef DEBUG_SKIM_SCRIPT parse_state = PS_SECTION_BODY; #else if(buffer == _section) parse_state = PS_SECTION_BODY; else if(buffer == _END_SECTION) { status = Common::Error(Common::kUnknownError, "[" + _section + "] script section not found"); skip_line = true; done = true; } else parse_state = PS_SECTION_SEARCH; #endif } else buffer += *it; break; case PS_SECTION_BODY: // section if(*it == '[') { #ifdef DEBUG_SKIM_SCRIPT buffer.clear(); parse_state = PS_SECTION_NAME; #else skip_line = true; done = true; #endif } // comment else if(*it == '*') { skip_line = true; } //NOTE: invalid syntax else if(*it == '-' || *it == '/' || (*it >= 'A' && *it <= 'Z')) { #ifndef DEBUG_SKIM_SCRIPT warning("invalid script syntax [file: %s, section: %s, line: \"%s\"], skipped", _script.c_str(), _section.c_str(), line.c_str()); #endif skip_line = true; } // command name else if((*it >= 'a' && *it <= 'z')) { buffer.clear(); buffer += *it; parse_state = PS_COMMAND_NAME; } break; case PS_COMMAND_NAME: // command value if(*it == '=') { command_name = buffer; buffer.clear(); parse_state = PS_COMMAND_VALUE; } else buffer += *it; break; case PS_COMMAND_VALUE: // command value end if(*it == ';') { command_name.trim(); buffer.trim(); #ifndef DEBUG_SKIM_SCRIPT debug("%s=%s;", command_name.c_str(), buffer.c_str()); #endif Common::HashMap<Common::String, Common::Error (GagEngine::*)(const Common::String &)>::const_iterator f = _commandCallbacks.find(command_name); if(f != _commandCallbacks.end()) { status = (this->*f->_value)(buffer); if(status.getCode() != Common::kNoError) { skip_line = true; done = true; } } parse_state = PS_SECTION_BODY; } else buffer += *it; break; } if(skip_line) break; } if(done) break; } } else { status = Common::Error(Common::kReadingFailed, _script + ", open()"); } return status; }
/** * Plays an animated cutscene. * @param id the id of the file */ bool MoviePlayer::load(uint32 id) { Common::File f; Common::String filename; if (_decoderType == kVideoDecoderDXA) _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(sequenceList[id]); else _bgSoundStream = NULL; if (SwordEngine::_systemVars.showText) { filename = Common::String::format("%s.txt", sequenceList[id]); if (f.open(filename)) { Common::String line; int lineNo = 0; int lastEnd = -1; _movieTexts.clear(); while (!f.eos() && !f.err()) { line = f.readLine(); lineNo++; if (line.empty() || line[0] == '#') { continue; } const char *ptr = line.c_str(); // TODO: Better error handling int startFrame = strtoul(ptr, const_cast<char **>(&ptr), 10); int endFrame = strtoul(ptr, const_cast<char **>(&ptr), 10); while (*ptr && Common::isSpace(*ptr)) ptr++; if (startFrame > endFrame) { warning("%s:%d: startFrame (%d) > endFrame (%d)", filename.c_str(), lineNo, startFrame, endFrame); continue; } if (startFrame <= lastEnd) { warning("%s:%d startFrame (%d) <= lastEnd (%d)", filename.c_str(), lineNo, startFrame, lastEnd); continue; } int color = 0; if (*ptr == '@') { ++ptr; color = strtoul(ptr, const_cast<char **>(&ptr), 10); while (*ptr && Common::isSpace(*ptr)) ptr++; } _movieTexts.push_back(MovieText(startFrame, endFrame, ptr, color)); lastEnd = endFrame; } f.close(); } } switch (_decoderType) { case kVideoDecoderDXA: filename = Common::String::format("%s.dxa", sequenceList[id]); break; case kVideoDecoderSMK: filename = Common::String::format("%s.smk", sequenceList[id]); break; case kVideoDecoderPSX: filename = Common::String::format("%s.str", (_vm->_systemVars.isDemo) ? sequenceList[id] : sequenceListPSX[id]); // Need to switch to true color initGraphics(g_system->getWidth(), g_system->getHeight(), true, 0); // Need to load here in case it fails in which case we'd need // to go back to paletted mode if (_decoder->loadFile(filename)) { return true; } else { initGraphics(g_system->getWidth(), g_system->getHeight(), true); return false; } break; } return _decoder->loadFile(filename.c_str()); }
/** * Opens and inits all MIDI sequence files. */ void OpenMidiFiles() { Common::File midiStream; // Demo version has no midi file // Also, Discworld PSX uses still unsupported psx SEQ format for music... if ((_vm->getFeatures() & GF_DEMO) || (TinselVersion == TINSEL_V2) || TinselV1PSX) return; if (midiBuffer.pDat) // already allocated return; // open MIDI sequence file in binary mode if (!midiStream.open(MIDI_FILE)) error(CANNOT_FIND_FILE, MIDI_FILE); // gen length of the largest sequence midiBuffer.size = midiStream.readUint32LE(); if (midiStream.eos() || midiStream.err()) error(FILE_IS_CORRUPT, MIDI_FILE); if (midiBuffer.size) { // allocate a buffer big enough for the largest MIDI sequence if ((midiBuffer.pDat = (uint8 *)malloc(midiBuffer.size)) != NULL) { // clear out the buffer memset(midiBuffer.pDat, 0, midiBuffer.size); // VMM_lock(midiBuffer.pDat, midiBuffer.size); } else { //mSeqHandle = NULL; } } // Now scan through the contents of the MIDI file to find the offset // of each individual track, in order to create a mapping from MIDI // offset to track number, for the enhanced MIDI soundtrack. // The first song is always at position 4. The subsequent ones are // calculated dynamically. uint32 curOffset = 4; uint32 curTrack = 0; uint32 songLength = 0; // Init for (int i = 0; i < ARRAYSIZE(midiOffsets); i++) midiOffsets[i] = 0; while (!midiStream.eos() && !midiStream.err()) { if (curOffset + (4 * curTrack) >= (uint32)midiStream.size()) break; assert(curTrack < ARRAYSIZE(midiOffsets)); midiOffsets[curTrack] = curOffset + (4 * curTrack); //debug("%d: %d", curTrack, midiOffsets[curTrack]); songLength = midiStream.readUint32LE(); curOffset += songLength; midiStream.skip(songLength); curTrack++; } midiStream.close(); }
void loadKoreanStrings() { Common::File fp; char fname[128]; strcpy(fname, "sub/"); strcat(fname, _gameID); strcat(fname, ".dat"); if(!fp.open(fname)) { warning("WARNING: Cannot load Korean V2 subtitle!, %s\n", fname); return; // strcpy(fname, ""); // strcat(fname, _gameID); // strcat(fname, ".dat"); // // if(!fp.open(fname)) { // warning("WARNING: Cannot load Korean V2 subtitle!, %s\n", fname); // return; // } } int k; char *buf = new char[1024]; int len = 0; for(k = 0; !fp.eos(); k++) { FGETS(buf, 1023, fp); //printf("%d: <%s>\n", k+1, buf); } // 파일의 라인 수를 계산 _numKLines = k; // memory size = file size k = fp.size(); fp.seek(0, SEEK_SET); _KBuffer = new char *[_numKLines]; //printf("_KBuffer size = %d\n", (int)k); _KBuffer[0] = new char[k]; //printf("_KBuffer[0] = 0x%x\n", (int)_KBuffer[0]); for(int i = 0; i < _numKLines; i++) { FGETS(buf, 1023, fp); buf[1023] = 0; len = strlen(buf); //_KBuffer[i] = new char[strlen(buf) + 1]; //\0 if (i > 0) _KBuffer[i] = _KBuffer[i-1] + strlen(_KBuffer[i-1])+1; if (len > 1000) warning("_KBuffer[%d]:%lx, len=%d\n", i, (long)_KBuffer[i], len); if(strlen(buf)) { strcpy(_KBuffer[i], buf); char *b = _KBuffer[i]; if(b[strlen(b) - 1] == '\n' || b[strlen(b) - 1] == 0x0a || b[strlen(b) - 1] == 0x0d) b[strlen(b) - 1] = 0; if(b[strlen(b) - 1] == '\n' || b[strlen(b) - 1] == 0x0a || b[strlen(b) - 1] == 0x0d) b[strlen(b) - 1] = 0; } else _KBuffer[i][0] = 0; } fp.close(); warning("Korean subtitle file loaded -- total %d lines, %ld bytes\n", _numKLines, _KBuffer[_numKLines-1]-_KBuffer[0]+len); delete[] buf; return; }
/** * Plays an animated cutscene. * @param id the id of the file */ bool MoviePlayer::load(uint32 id) { Common::String filename; if (SwordEngine::_systemVars.showText) { Common::File f; filename = Common::String::format("%s.txt", sequenceList[id]); if (f.open(filename)) { Common::String line; int lineNo = 0; int lastEnd = -1; _movieTexts.clear(); while (!f.eos() && !f.err()) { line = f.readLine(); lineNo++; if (line.empty() || line[0] == '#') { continue; } const char *ptr = line.c_str(); // TODO: Better error handling int startFrame = strtoul(ptr, const_cast<char **>(&ptr), 10); int endFrame = strtoul(ptr, const_cast<char **>(&ptr), 10); while (*ptr && Common::isSpace(*ptr)) ptr++; if (startFrame > endFrame) { warning("%s:%d: startFrame (%d) > endFrame (%d)", filename.c_str(), lineNo, startFrame, endFrame); continue; } if (startFrame <= lastEnd) { warning("%s:%d startFrame (%d) <= lastEnd (%d)", filename.c_str(), lineNo, startFrame, lastEnd); continue; } int color = 0; if (*ptr == '@') { ++ptr; color = strtoul(ptr, const_cast<char **>(&ptr), 10); while (*ptr && Common::isSpace(*ptr)) ptr++; } _movieTexts.push_back(MovieText(startFrame, endFrame, ptr, color)); lastEnd = endFrame; } } } switch (_decoderType) { case kVideoDecoderDXA: filename = Common::String::format("%s.dxa", sequenceList[id]); break; case kVideoDecoderSMK: filename = Common::String::format("%s.smk", sequenceList[id]); break; case kVideoDecoderPSX: filename = Common::String::format("%s.str", (_vm->_systemVars.isDemo) ? sequenceList[id] : sequenceListPSX[id]); break; case kVideoDecoderMP2: filename = Common::String::format("%s.mp2", sequenceList[id]); break; } // Need to switch to true color for PSX/MP2 videos if (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) initGraphics(g_system->getWidth(), g_system->getHeight(), true, 0); if (!_decoder->loadFile(filename)) { // Go back to 8bpp color if (_decoderType == kVideoDecoderPSX || _decoderType == kVideoDecoderMP2) initGraphics(g_system->getWidth(), g_system->getHeight(), true); return false; } // For DXA/MP2, also add the external sound file if (_decoderType == kVideoDecoderDXA || _decoderType == kVideoDecoderMP2) _decoder->addStreamFileTrack(sequenceList[id]); _decoder->start(); 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 }
/** * 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, 640, 200), kColorBlue); _vm->_graphics->drawFilledRectangle(Common::Rect(8, 40, 450, 200), 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->helpDrawBigText("help!", 549, 1, kColorBlack); _vm->_graphics->helpDrawBigText("help!", 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->helpDrawBigText(text, 589 - (text.size() * 8), 18 + (y + 1) * 27, kColorBlack); _vm->_graphics->helpDrawBigText(text, 590 - (text.size() * 8), 17 + (y + 1) * 27, kColorCyan); y++; _buttonNum++; } _vm->_graphics->refreshScreen(); file.close(); }
bool ResourceManager::init() { uint32 i, j; // Until proven differently, assume we're on CD 1. This is so the start // dialog will be able to play any music at all. setCD(1); // We read in the resource info which tells us the names of the // resource cluster files ultimately, although there might be groups // within the clusters at this point it makes no difference. We only // wish to know what resource files there are and what is in each Common::File file; if (!file.open("resource.inf")) { GUIErrorMessage("Broken Sword II: Cannot open resource.inf"); return false; } // The resource.inf file is a simple text file containing the names of // all the resource files. while (1) { char *buf = _resFiles[_totalClusters].fileName; uint len = sizeof(_resFiles[_totalClusters].fileName); if (!file.readLine(buf, len)) break; int pos = strlen(buf); if (buf[pos - 1] == 0x0A) buf[pos - 1] = 0; _resFiles[_totalClusters].numEntries = -1; _resFiles[_totalClusters].entryTab = NULL; if (++_totalClusters >= MAX_res_files) { GUIErrorMessage("Broken Sword II: Too many entries in resource.inf"); return false; } } file.close(); // Now load in the binary id to res conversion table if (!file.open("resource.tab")) { GUIErrorMessage("Broken Sword II: Cannot open resource.tab"); return false; } // Find how many resources uint32 size = file.size(); _totalResFiles = size / 4; // Table seems ok so malloc some space _resConvTable = (uint16 *)malloc(size); for (i = 0; i < size / 2; i++) _resConvTable[i] = file.readUint16LE(); if (file.eos() || file.err()) { file.close(); GUIErrorMessage("Broken Sword II: Cannot read resource.tab"); return false; } file.close(); // Check that we have cd.inf file, unless we are running PSX // version, which has all files on one disc. if (!file.open("cd.inf") && !Sword2Engine::isPsx()) { GUIErrorMessage("Broken Sword II: Cannot open cd.inf"); return false; } CdInf *cdInf = new CdInf[_totalClusters]; for (i = 0; i < _totalClusters; i++) { if (Sword2Engine::isPsx()) { // We are running PSX version, artificially fill CdInf structure cdInf[i].cd = CD1; } else { // We are running PC version, read cd.inf file file.read(cdInf[i].clusterName, sizeof(cdInf[i].clusterName)); cdInf[i].cd = file.readByte(); if (file.eos() || file.err()) { delete[] cdInf; file.close(); GUIErrorMessage("Broken Sword II: Cannot read cd.inf"); return false; } } // It has been reported that there are two different versions // of the cd.inf file: One where all clusters on CD also have // the LOCAL_CACHE bit set. This bit is no longer used. To // avoid future problems, let's normalize the flag once and for // all here. if (cdInf[i].cd & LOCAL_PERM) cdInf[i].cd = 0; else if (cdInf[i].cd & CD1) cdInf[i].cd = 1; else if (cdInf[i].cd & CD2) cdInf[i].cd = 2; else cdInf[i].cd = 0; // Any file on "CD 0" may be needed at all times. Verify that // it exists. Any other missing cluster will be requested with // an "insert CD" message. Of course, the file may still vanish // during game-play (oh, that wascally wabbit!) in which case // the resource manager will print a fatal error. if (cdInf[i].cd == 0 && !Common::File::exists((char *)cdInf[i].clusterName)) { GUIErrorMessage("Broken Sword II: Cannot find " + Common::String((char *)cdInf[i].clusterName)); delete[] cdInf; return false; } } file.close(); // We check the presence of resource files in cd.inf // This is ok in PC version, but in PSX version we don't // have cd.inf so we'll have to skip this. if (!Sword2Engine::isPsx()) { for (i = 0; i < _totalClusters; i++) { for (j = 0; j < _totalClusters; j++) { if (scumm_stricmp((char *)cdInf[j].clusterName, _resFiles[i].fileName) == 0) break; } if (j == _totalClusters) { delete[] cdInf; GUIErrorMessage(Common::String(_resFiles[i].fileName) + " is not in cd.inf"); return false; } _resFiles[i].cd = cdInf[j].cd; } } delete[] cdInf; debug(1, "%d resources in %d cluster files", _totalResFiles, _totalClusters); for (i = 0; i < _totalClusters; i++) debug(2, "filename of cluster %d: -%s (%d)", i, _resFiles[i].fileName, _resFiles[i].cd); _resList = (Resource *)malloc(_totalResFiles * sizeof(Resource)); for (i = 0; i < _totalResFiles; i++) { _resList[i].ptr = NULL; _resList[i].size = 0; _resList[i].refCount = 0; _resList[i].prev = _resList[i].next = NULL; } return true; }
Common::Error GroovieEngine::run() { _script = new Script(this, _gameDescription->version); // Initialize the graphics switch (_gameDescription->version) { case kGroovieV2: // Request the mode with the highest precision available initGraphics(640, 480, true, NULL); // Save the enabled mode as it can be both an RGB mode or CLUT8 _pixelFormat = _system->getScreenFormat(); _mode8bit = (_pixelFormat == Graphics::PixelFormat::createFormatCLUT8()); break; case kGroovieT7G: initGraphics(640, 480, true); _pixelFormat = Graphics::PixelFormat::createFormatCLUT8(); break; } // Create debugger. It requires GFX to be initialized _debugger = new Debugger(this); _script->setDebugger(_debugger); // Create the graphics manager _graphicsMan = new GraphicsMan(this); // Create the resource and cursor managers and the video player // Prepare the font too switch (_gameDescription->version) { case kGroovieT7G: if (getPlatform() == Common::kPlatformMacintosh) { _macResFork = new Common::MacResManager(); if (!_macResFork->open(_gameDescription->desc.filesDescriptions[0].fileName)) error("Could not open %s as a resource fork", _gameDescription->desc.filesDescriptions[0].fileName); // The Macintosh release used system fonts. We use GUI fonts. _font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); } else { Common::File fontfile; if (!fontfile.open("sphinx.fnt")) { error("Couldn't open sphinx.fnt"); return Common::kNoGameDataFoundError; } else if (!_sphinxFont.load(fontfile)) { error("Error loading sphinx.fnt"); return Common::kUnknownError; } fontfile.close(); _font = &_sphinxFont; } _resMan = new ResMan_t7g(_macResFork); _grvCursorMan = new GrvCursorMan_t7g(_system, _macResFork); _videoPlayer = new VDXPlayer(this); break; case kGroovieV2: _resMan = new ResMan_v2(); _grvCursorMan = new GrvCursorMan_v2(_system); _videoPlayer = new ROQPlayer(this); break; } // Create the music player if (getPlatform() == Common::kPlatformMacintosh) _musicPlayer = new MusicPlayerMac(this); else _musicPlayer = new MusicPlayerXMI(this, _gameDescription->version == kGroovieT7G ? "fat" : "sample"); // Load volume levels syncSoundSettings(); // Get the name of the main script Common::String filename = _gameDescription->desc.filesDescriptions[0].fileName; if (_gameDescription->version == kGroovieT7G) { // Run The 7th Guest's demo if requested if (ConfMan.hasKey("demo_mode") && ConfMan.getBool("demo_mode")) filename = "demo.grv"; else if (getPlatform() == Common::kPlatformMacintosh) filename = "script.grv"; // Stored inside the executable's resource fork } else if (_gameDescription->version == kGroovieV2) { // Open the disk index Common::File disk; if (!disk.open(filename)) { error("Couldn't open %s", filename.c_str()); return Common::kNoGameDataFoundError; } // Search the entry bool found = false; int index = 0; while (!found && !disk.eos()) { Common::String line = disk.readLine(); if (line.hasPrefix("title: ")) { // A new entry index++; } else if (line.hasPrefix("boot: ") && index == _gameDescription->indexEntry) { // It's the boot of the entry we're looking for, // get the script filename filename = line.c_str() + 6; found = true; } } // Couldn't find the entry if (!found) { error("Couldn't find entry %d in %s", _gameDescription->indexEntry, filename.c_str()); return Common::kUnknownError; } } // Check the script file extension if (!filename.hasSuffix(".grv")) { error("%s isn't a valid script filename", filename.c_str()); return Common::kUnknownError; } // Load the script if (!_script->loadScript(filename)) { error("Couldn't load the script file %s", filename.c_str()); return Common::kUnknownError; } // Should I load a saved game? if (ConfMan.hasKey("save_slot")) { // Get the requested slot int slot = ConfMan.getInt("save_slot"); _script->directGameLoad(slot); } // Check that the game files and the audio tracks aren't together run from // the same cd checkCD(); // Game timer counter uint16 tmr = 0; // Initialize the CD int cd_num = ConfMan.getInt("cdrom"); if (cd_num >= 0) _system->getAudioCDManager()->openCD(cd_num); while (!shouldQuit()) { // Give the debugger a chance to act _debugger->onFrame(); // Handle input Common::Event ev; while (_eventMan->pollEvent(ev)) { switch (ev.type) { case Common::EVENT_KEYDOWN: // CTRL-D: Attach the debugger if ((ev.kbd.flags & Common::KBD_CTRL) && ev.kbd.keycode == Common::KEYCODE_d) _debugger->attach(); // Send the event to the scripts _script->setKbdChar(ev.kbd.ascii); // Continue the script execution to handle the key _waitingForInput = false; break; case Common::EVENT_MAINMENU: // Closing the GMM case Common::EVENT_MOUSEMOVE: // Continue the script execution, the mouse pointer // may fall inside a different hotspot now _waitingForInput = false; break; case Common::EVENT_LBUTTONDOWN: // Send the event to the scripts _script->setMouseClick(1); // Continue the script execution to handle // the click _waitingForInput = false; break; case Common::EVENT_RBUTTONDOWN: // Send the event to the scripts (to skip the video) _script->setMouseClick(2); break; case Common::EVENT_QUIT: quitGame(); break; default: break; } } // The event loop may have triggered the quit status. In this case, // stop the execution. if (shouldQuit()) { continue; } if (_waitingForInput) { // Still waiting for input, just update the mouse, game timer and then wait a bit more _grvCursorMan->animate(); _system->updateScreen(); tmr++; // Wait a little bit between increments. While mouse is moving, this triggers // only negligably slower. if (tmr > 4) { _script->timerTick(); tmr = 0; } _system->delayMillis(50); } else if (_graphicsMan->isFading()) { // We're waiting for a fading to end, let the CPU rest // for a while and continue _system->delayMillis(30); } else { // Everything's fine, execute another script step _script->step(); } // Update the screen if required _graphicsMan->update(); } return Common::kNoError; }
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()) { debugCN(kDebugCore, "FileSystem::FileSystem: error opening hash %s\n", hashFilename); } hashSize = hashFile.readUint32LE(); //debugCN(kDebugCore, "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]) { /* debugCN(kDebugCore, " filename: %s\n", entry.filename); debugCN(kDebugCore, " hagfile: %d\n", entry.hagfile); debugCN(kDebugCore, " disks: %d\n", entry.disks); debugCN(kDebugCore, " offset: %08X\n", entry.offset); debugCN(kDebugCore, " size: %d\n", entry.size); debugCN(kDebugCore, " 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()) { debugCN(kDebugCore, "FileSystem::FileSystem: error opening hag %s\n", _hagEntries[entry.fileIndex].filename); } } hashFile.close(); }
bool Sword2Engine::initStartMenu() { // Print out a list of all the start points available. // There should be a linc produced file called startup.txt. // This file should contain ascii numbers of all the resource game // objects that are screen managers. // We query each in turn and setup an array of start structures. // If the file doesn't exist then we say so and return a 0. Common::File fp; // ok, load in the master screen manager file _totalStartups = 0; _totalScreenManagers = 0; if (!fp.open("startup.inf")) { warning("Cannot open startup.inf - the debugger won't have a start menu"); return false; } // The startup.inf file which contains a list of all the files. Now // extract the filenames int start_ids[MAX_starts]; int lineno = 0; while (!fp.eos() && !fp.err()) { Common::String line = fp.readLine(); // Skip empty lines or, more likely, the end of the stream. if (line.size() == 0) continue; char *errptr; int id; lineno++; id = strtol(line.c_str(), &errptr, 10); if (*errptr) { warning("startup.inf:%d: Invalid string '%s'", lineno, line.c_str()); continue; } if (!_resman->checkValid(id)) { warning("startup.inf:%d: Invalid resource %d", lineno, id); continue; } if (_resman->fetchType(id) != SCREEN_MANAGER) { warning("startup.inf:%d: '%s' (%d) is not a screen manager", lineno, _resman->fetchName(id), id); continue; } start_ids[_totalScreenManagers] = id; if (++_totalScreenManagers >= MAX_starts) { warning("Too many entries in startup.inf"); break; } } // An I/O error before EOS? That's bad, but this is not a vital file. if (fp.err() && !fp.eos()) warning("I/O error while reading startup.inf"); fp.close(); // Using this method the Gode generated resource.inf must have #0d0a // on the last entry debug(1, "%d screen manager objects", _totalScreenManagers); // Open each object and make a query call. The object must fill in a // startup structure. It may fill in several if it wishes - for // instance a startup could be set for later in the game where // specific vars are set for (uint i = 0; i < _totalScreenManagers; i++) { _startRes = start_ids[i]; debug(2, "Querying screen manager %d", _startRes); // Open each one and run through the interpreter. Script 0 is // the query request script. We have already made reasonably // sure the resource is ok. _logic->runResScript(_startRes, 0); } return 1; }
/** * Opens and inits all MIDI sequence files. */ void OpenMidiFiles() { Common::File midiStream; if (TinselV0) { // The early demo version of DW1 doesn't have MIDI } else if (TinselV2) { // DW2 uses a different music mechanism } else if (TinselV1Mac) { // open MIDI sequence file in binary mode if (!midiStream.open(MIDI_FILE)) error(CANNOT_FIND_FILE, MIDI_FILE); uint32 curTrack = 1; uint32 songLength = 0; int32 fileSize = midiStream.size(); // Init for (int i = 0; i < ARRAYSIZE(g_midiOffsets); i++) g_midiOffsets[i] = 0; midiStream.skip(4); // skip file header while (!midiStream.eos() && !midiStream.err() && midiStream.pos() != fileSize) { assert(curTrack < ARRAYSIZE(g_midiOffsets)); g_midiOffsets[curTrack] = midiStream.pos(); //debug("%d: %d", curTrack, g_midiOffsets[curTrack]); songLength = midiStream.readUint32BE(); midiStream.skip(songLength); curTrack++; } midiStream.close(); } else { if (g_midiBuffer.pDat) // already allocated return; // open MIDI sequence file in binary mode if (!midiStream.open(MIDI_FILE)) error(CANNOT_FIND_FILE, MIDI_FILE); // get length of the largest sequence g_midiBuffer.size = midiStream.readUint32LE(); if (midiStream.eos() || midiStream.err()) error(FILE_IS_CORRUPT, MIDI_FILE); if (g_midiBuffer.size) { // allocate a buffer big enough for the largest MIDI sequence if ((g_midiBuffer.pDat = (uint8 *)malloc(g_midiBuffer.size)) != NULL) { // clear out the buffer memset(g_midiBuffer.pDat, 0, g_midiBuffer.size); } } // Now scan through the contents of the MIDI file to find the offset // of each individual track, in order to create a mapping from MIDI // offset to track number, for the enhanced MIDI soundtrack. // The first song is always at position 4. The subsequent ones are // calculated dynamically. uint32 curOffset = 4; uint32 curTrack = 0; uint32 songLength = 0; // Init for (int i = 0; i < ARRAYSIZE(g_midiOffsets); i++) g_midiOffsets[i] = 0; while (!midiStream.eos() && !midiStream.err()) { if (curOffset + (4 * curTrack) >= (uint32)midiStream.size()) break; assert(curTrack < ARRAYSIZE(g_midiOffsets)); g_midiOffsets[curTrack] = curOffset + (4 * curTrack); //debug("%d: %d", curTrack, midiOffsets[curTrack]); songLength = midiStream.readUint32LE(); curOffset += songLength; midiStream.skip(songLength); curTrack++; } midiStream.close(); } }