SyncSoundNode::SyncSoundNode(ZVision *engine, uint32 key, Common::String &filename, int32 syncto) : ScriptingEffect(engine, key, SCRIPTING_EFFECT_AUDIO) { _syncto = syncto; _sub = NULL; Audio::RewindableAudioStream *audioStream = NULL; if (filename.contains(".wav")) { Common::File *file = new Common::File(); if (_engine->getSearchManager()->openFile(*file, filename)) { audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES); } } else { audioStream = makeRawZorkStream(filename, _engine); } _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream); Common::String subname = filename; subname.setChar('s', subname.size() - 3); subname.setChar('u', subname.size() - 2); subname.setChar('b', subname.size() - 1); if (_engine->getSearchManager()->hasFile(subname)) _sub = new Subtitle(_engine, subname); }
bool ActionStreamVideo::execute() { Video::VideoDecoder *decoder; Common::Rect destRect = Common::Rect(_x1, _y1, _x2 + 1, _y2 + 1); Common::String subname = _fileName; subname.setChar('s', subname.size() - 3); subname.setChar('u', subname.size() - 2); subname.setChar('b', subname.size() - 1); bool subtitleExists = _engine->getSearchManager()->hasFile(subname); bool switchToHires = false; // NOTE: We only show the hires MPEG2 videos when libmpeg2 is compiled in, // otherwise we fall back to the lowres ones #ifdef USE_MPEG2 Common::String hiresFileName = _fileName; hiresFileName.setChar('d', hiresFileName.size() - 8); hiresFileName.setChar('v', hiresFileName.size() - 3); hiresFileName.setChar('o', hiresFileName.size() - 2); hiresFileName.setChar('b', hiresFileName.size() - 1); if (_engine->getScriptManager()->getStateValue(StateKey_MPEGMovies) == 1 &&_engine->getSearchManager()->hasFile(hiresFileName)) { // TODO: Enable once AC3 support is implemented if (!_engine->getSearchManager()->hasFile(_fileName)) // Check for the regular video return true; warning("The hires videos of the DVD version of ZGI aren't supported yet, using lowres"); //_fileName = hiresFileName; //switchToHires = true; } else if (!_engine->getSearchManager()->hasFile(_fileName)) return true; #else if (!_engine->getSearchManager()->hasFile(_fileName)) return true; #endif decoder = _engine->loadAnimation(_fileName); Subtitle *sub = (subtitleExists) ? new Subtitle(_engine, subname, switchToHires) : NULL; _engine->getCursorManager()->showMouse(false); if (switchToHires) { _engine->initHiresScreen(); destRect = Common::Rect(40, -40, 760, 440); Common::Rect workingWindow = _engine->_workingWindow; workingWindow.translate(0, -40); _engine->getRenderManager()->initSubArea(HIRES_WINDOW_WIDTH, HIRES_WINDOW_HEIGHT, workingWindow); } _engine->playVideo(*decoder, destRect, _skippable, sub); if (switchToHires) { _engine->initScreen(); _engine->getRenderManager()->initSubArea(WINDOW_WIDTH, WINDOW_HEIGHT, _engine->_workingWindow); } _engine->getCursorManager()->showMouse(true); delete decoder; delete sub; return true; }
Audio::RewindableAudioStream *makeRawZorkStream(const Common::String &filePath, ZVision *engine) { Common::File *file = new Common::File(); Common::String actualName = filePath; bool found = engine->getSearchManager()->openFile(*file, actualName); bool isRaw = actualName.hasSuffix(".raw"); if ((!found && isRaw) || (found && isRaw && file->size() < 10)) { if (found) file->close(); // Check for an audio patch (.src) actualName.setChar('s', actualName.size() - 3); actualName.setChar('r', actualName.size() - 2); actualName.setChar('c', actualName.size() - 1); if (!engine->getSearchManager()->openFile(*file, actualName)) return NULL; } else if (!found && !isRaw) { return NULL; } // Get the file name Common::StringTokenizer tokenizer(actualName, "/\\"); Common::String fileName; while (!tokenizer.empty()) { fileName = tokenizer.nextToken(); } fileName.toLowercase(); const SoundParams *soundParams = NULL; if (engine->getGameId() == GID_NEMESIS) { for (int i = 0; i < 32; ++i) { if (RawZorkStream::_zNemSoundParamLookupTable[i].identifier == (fileName[6])) soundParams = &RawZorkStream::_zNemSoundParamLookupTable[i]; } } else if (engine->getGameId() == GID_GRANDINQUISITOR) { for (int i = 0; i < 24; ++i) { if (RawZorkStream::_zgiSoundParamLookupTable[i].identifier == (fileName[7])) soundParams = &RawZorkStream::_zgiSoundParamLookupTable[i]; } } if (soundParams == NULL) return NULL; if (soundParams->packed) { return makeRawZorkStream(wrapBufferedSeekableReadStream(file, 2048, DisposeAfterUse::YES), soundParams->rate, soundParams->stereo, DisposeAfterUse::YES); } else { byte flags = 0; if (soundParams->bits16) flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN; if (soundParams->stereo) flags |= Audio::FLAG_STEREO; return Audio::makePCMStream(file, soundParams->rate, flags, DisposeAfterUse::YES); } }
Common::String HiRes4Engine_Atari::formatNounError(const Common::String &verb, const Common::String &noun) const { Common::String err = _strings.nounError; for (uint i = 0; i < verb.size(); ++i) err.setChar(verb[i], i + 8); for (uint i = 0; i < noun.size(); ++i) err.setChar(noun[i], i + 19); return err; }
bool Console::cmdDumpImage(int argc, const char **argv) { if (argc != 2) { debugPrintf("Use %s <TGA/TGZ name> to dump a Z-Vision TGA/TGZ image into a regular BMP image\n", argv[0]); return true; } Common::String fileName = argv[1]; if (!fileName.hasSuffix(".tga")) { debugPrintf("%s is not an image file", argv[1]); } Common::File f; if (!_engine->getSearchManager()->openFile(f, argv[1])) { warning("File not found: %s", argv[1]); return true; } Graphics::Surface surface; _engine->getRenderManager()->readImageToSurface(argv[1], surface, false); // Open file Common::DumpFile out; fileName.setChar('b', fileName.size() - 3); fileName.setChar('m', fileName.size() - 2); fileName.setChar('p', fileName.size() - 1); out.open(fileName); // Write BMP header out.writeByte('B'); out.writeByte('M'); out.writeUint32LE(surface.h * surface.pitch + 54); out.writeUint32LE(0); out.writeUint32LE(54); out.writeUint32LE(40); out.writeUint32LE(surface.w); out.writeUint32LE(surface.h); out.writeUint16LE(1); out.writeUint16LE(16); out.writeUint32LE(0); out.writeUint32LE(0); out.writeUint32LE(0); out.writeUint32LE(0); out.writeUint32LE(0); out.writeUint32LE(0); // Write pixel data to BMP out.write(surface.getPixels(), surface.pitch * surface.h); out.flush(); out.close(); surface.free(); return true; }
void Inter_v6::probe16bitMusic(Common::String &fileName) { if (fileName[fileName.size() - 1] != '8') return; fileName.setChar('V', fileName.size() - 1); if (_vm->_dataIO->hasFile(fileName)) return; fileName.setChar('8', fileName.size() - 1); }
MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool loop, int8 volume) : MusicNodeBASE(engine, key, SCRIPTING_EFFECT_AUDIO) { _loop = loop; _volume = volume; _crossfade = false; _crossfadeTarget = 0; _crossfadeTime = 0; _attenuate = 0; _pantrack = false; _pantrackPosition = 0; _sub = NULL; _stereo = false; _loaded = false; Audio::RewindableAudioStream *audioStream = NULL; if (filename.contains(".wav")) { Common::File *file = new Common::File(); if (_engine->getSearchManager()->openFile(*file, filename)) { audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES); } } else { audioStream = makeRawZorkStream(filename, _engine); } if (audioStream) { _stereo = audioStream->isStereo(); if (_loop) { Audio::LoopingAudioStream *loopingAudioStream = new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::YES); _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopingAudioStream, -1, _volume); } else { _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream, -1, _volume); } if (_key != StateKey_NotSet) _engine->getScriptManager()->setStateValue(_key, 1); // Change filename.raw into filename.sub Common::String subname = filename; subname.setChar('s', subname.size() - 3); subname.setChar('u', subname.size() - 2); subname.setChar('b', subname.size() - 1); if (_engine->getSearchManager()->hasFile(subname)) _sub = new Subtitle(_engine, subname); _loaded = true; } }
int AdlEngine_v2::o2_tellTime(ScriptEnv &e) { OP_DEBUG_0("\tTELL_TIME()"); Common::String time = _strings_v2.time; time.setChar(APPLECHAR('0') + _state.time.hours / 10, 12); time.setChar(APPLECHAR('0') + _state.time.hours % 10, 13); time.setChar(APPLECHAR('0') + _state.time.minutes / 10, 15); time.setChar(APPLECHAR('0') + _state.time.minutes % 10, 16); printString(time); return 0; }
bool Debugger::Cmd_DumpVocab(int argc, const char **argv) { Common::DumpFile outFile; outFile.open("vocab.txt"); for (uint32 i = 0; i < _vm->_game->_scene.getVocabStringsCount(); i++) { Common::String curId = Common::String::format("%x", i + 1); Common::String curVocab = _vm->_game->_scene.getVocab(i + 1); curVocab.toUppercase(); for (uint j = 0; j < curVocab.size(); j++) { if (curVocab[j] == ' ' || curVocab[j] == '-') curVocab.setChar('_', j); } Common::String cur = "\tNOUN_" + curVocab + " = 0x" + curId + ",\n"; outFile.writeString(cur.c_str()); } outFile.flush(); outFile.close(); debugPrintf("Game vocab dumped\n"); return true; }
bool Debugger::Cmd_DumpItems(int argc, const char **argv) { InventoryObjects &objects = _vm->_game->_objects; Common::DumpFile outFile; outFile.open("items.txt"); for (uint32 i = 0; i < objects.size(); i++) { Common::String curId = Common::String::format("%d", i); Common::String desc = _vm->_game->_scene.getVocab(objects[i]._descId); desc.toUppercase(); for (uint j = 0; j < desc.size(); j++) { if (desc[j] == ' ' || desc[j] == '-') desc.setChar('_', j); } Common::String cur = "\tOBJ_" + desc + " = " + curId + ",\n"; outFile.writeString(cur.c_str()); } outFile.flush(); outFile.close(); debugPrintf("Game items dumped\n"); return true; }
void Inter_Geisha::oGeisha_checkData(OpFuncParams ¶ms) { Common::String file = _vm->_game->_script->evalString(); int16 varOff = _vm->_game->_script->readVarIndex(); file.toLowercase(); if (file.hasSuffix(".0ot")) file.setChar('t', file.size() - 3); bool exists = false; SaveLoad::SaveMode mode = _vm->_saveLoad->getSaveMode(file.c_str()); if (mode == SaveLoad::kSaveModeNone) { exists = _vm->_dataIO->hasFile(file); if (!exists) { // NOTE: Geisha looks if fin.tot exists to check if it needs to open disk3.stk. // This is completely normal, so don't print a warning. if (file != "fin.tot") warning("File \"%s\" not found", file.c_str()); } } else if (mode == SaveLoad::kSaveModeSave) exists = _vm->_saveLoad->getSize(file.c_str()) >= 0; else if (mode == SaveLoad::kSaveModeExists) exists = true; WRITE_VAR_OFFSET(varOff, exists ? 50 : (uint32)-1); }
void MADSAction::appendVocab(int vocabId, bool capitalize) { Common::String vocabStr = _vm->_game->_scene.getVocab(vocabId); if (capitalize) vocabStr.setChar(toupper(vocabStr[0]), 0); _statusText += vocabStr; _statusText += " "; }
int PrinceEngine::checkMob(Graphics::Surface *screen, Common::Array<Mob> &mobList, bool usePriorityList) { if (_mouseFlag == 0 || _mouseFlag == 3) { return -1; } Common::Point mousePos = _system->getEventManager()->getMousePos(); int mobNumber = getMob(mobList, usePriorityList, mousePos.x + _picWindowX, mousePos.y); if (mobNumber != -1) { Common::String mobName = mobList[mobNumber]._name; if (getLanguage() == Common::DE_DEU) { for (uint i = 0; i < mobName.size(); i++) { switch (mobName[i]) { case '\xc4': mobName.setChar('\x83', i); break; case '\xd6': mobName.setChar('\x84', i); break; case '\xdc': mobName.setChar('\x85', i); break; case '\xdf': mobName.setChar('\x7f', i); break; case '\xe4': mobName.setChar('\x80', i); break; case '\xf6': mobName.setChar('\x81', i); break; case '\xfc': mobName.setChar('\x82', i); break; } } } uint16 textW = getTextWidth(mobName.c_str()); uint16 x = mousePos.x - textW / 2; if (x > screen->w) { x = 0; } if (x + textW > screen->w) { x = screen->w - textW; } uint16 y = mousePos.y - _font->getFontHeight(); if (y > screen->h) { y = _font->getFontHeight() - 2; } _font->drawString(screen, mobName, x, y, screen->w, 216); } return mobNumber; }
void HiRes1Engine::wordWrap(Common::String &str) const { uint end = 39; while (1) { if (str.size() <= end) return; while (str[end] != APPLECHAR(' ')) --end; str.setChar(APPLECHAR('\r'), end); end += 40; } }
Common::String DefinitionRegistry::stringToCamelCase(const Common::String &input) { Common::String clean = input; // First replace all non alphanumerical characters with spaces for (uint i = 0; i < clean.size(); i++) { if (!Common::isAlnum(clean[i])) { clean.setChar(' ', i); } } // Then turn the string into camel case Common::String output; Common::StringTokenizer tokens = Common::StringTokenizer(clean); while (!tokens.empty()) { Common::String token = tokens.nextToken(); char upperFirstLetter = toupper(token[0]); token.setChar(upperFirstLetter, 0); output += token; } return output; }
/** * Handles the sciAudio calls in fanmade games. * sciAudio is an external .NET library for playing MP3 files in fanmade games. * It runs in the background, and obtains sound commands from the * currently running game via text files (called "conductor files"). * For further info, check: http://sciprogramming.com/community/index.php?topic=634.0 */ void AudioPlayer::handleFanmadeSciAudio(reg_t sciAudioObject, SegManager *segMan) { // TODO: This is a bare bones implementation. Only the play/playx and stop commands // are handled for now - the other commands haven't been observed in any fanmade game // yet. All the volume related and fading functionality is currently missing. Kernel *kernel = g_sci->getKernel(); reg_t commandReg = readSelector(segMan, sciAudioObject, kernel->findSelector("command")); Common::String command = segMan->getString(commandReg); if (command == "play" || command == "playx") { #ifdef USE_MAD reg_t fileNameReg = readSelector(segMan, sciAudioObject, kernel->findSelector("fileName")); Common::String fileName = segMan->getString(fileNameReg); int16 loopCount = (int16)readSelectorValue(segMan, sciAudioObject, kernel->findSelector("loopCount")); // When loopCount is -1, we treat it as infinite looping, else no looping is done. // This is observed by game scripts, which can set loopCount to all sorts of random values. // Adjust loopCount for ScummVM's LoopingAudioStream semantics loopCount = (loopCount == -1) ? 0 : 1; // Determine sound type Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType; if (fileName.hasPrefix("music")) soundType = Audio::Mixer::kMusicSoundType; else if (fileName.hasPrefix("speech")) soundType = Audio::Mixer::kSpeechSoundType; Common::File *sciAudio = new Common::File(); // Replace backwards slashes for (uint i = 0; i < fileName.size(); i++) { if (fileName[i] == '\\') fileName.setChar('/', i); } sciAudio->open("sciAudio/" + fileName); Audio::SeekableAudioStream *audioStream = Audio::makeMP3Stream(sciAudio, DisposeAfterUse::YES); // We only support one audio handle _mixer->playStream(soundType, &_audioHandle, Audio::makeLoopingAudioStream((Audio::RewindableAudioStream *)audioStream, loopCount)); #endif } else if (command == "stop") { _mixer->stopHandle(_audioHandle); } else { warning("Unhandled sciAudio command: %s", command.c_str()); } }
Common::SeekableReadStream *BaseFileManager::openPkgFile(const Common::String &filename) { Common::String upcName = filename; upcName.toUppercase(); Common::SeekableReadStream *file = nullptr; // correct slashes for (uint32 i = 0; i < upcName.size(); i++) { if (upcName[(int32)i] == '/') { upcName.setChar('\\', (uint32)i); } } Common::ArchiveMemberPtr entry = _packages.getMember(upcName); if (!entry) { return nullptr; } file = entry->createReadStream(); return file; }
Common::SeekableReadStream *BaseFileManager::openPkgFile(const Common::String &filename) { Common::String upcName = filename; upcName.toUppercase(); Common::SeekableReadStream *file = NULL; char fileName[MAX_PATH_LENGTH]; strcpy(fileName, upcName.c_str()); // correct slashes for (uint32 i = 0; i < upcName.size(); i++) { if (upcName[(int32)i] == '/') { upcName.setChar('\\', (uint32)i); } } Common::ArchiveMemberPtr entry = _packages.getMember(upcName); if (!entry) { return NULL; } file = entry->createReadStream(); return file; }
DECFile::DECFile(GobEngine *vm, const Common::String &fileName, uint16 width, uint16 height, uint8 bpp) : _vm(vm), _width(width), _height(height), _bpp(bpp), _hasPadding(false), _backdrop(0) { bool bigEndian = false; Common::String endianFileName = fileName; if ((_vm->getEndiannessMethod() == kEndiannessMethodAltFile) && !_vm->_dataIO->hasFile(fileName)) { // If the game has alternate big-endian files, look if one exist Common::String alternateFileName = fileName; alternateFileName.setChar('_', 0); if (_vm->_dataIO->hasFile(alternateFileName)) { bigEndian = true; endianFileName = alternateFileName; } } else if ((_vm->getEndiannessMethod() == kEndiannessMethodBE) || ((_vm->getEndiannessMethod() == kEndiannessMethodSystem) && (_vm->getEndianness() == kEndiannessBE))) // Game always little endian or it follows the system and it is big endian bigEndian = true; Common::SeekableReadStream *ani = _vm->_dataIO->getFile(endianFileName); if (ani) { Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), bigEndian, DisposeAfterUse::YES); // The big endian version pads a few fields to even size _hasPadding = bigEndian; load(sub, fileName); return; } warning("DECFile::DECFile(): No such file \"%s\" (\"%s\")", endianFileName.c_str(), fileName.c_str()); }
void Inter_Geisha::oGeisha_checkData(OpFuncParams ¶ms) { Common::String file = _vm->_game->_script->evalString(); int16 varOff = _vm->_game->_script->readVarIndex(); file.toLowercase(); if (file.hasSuffix(".0ot")) file.setChar('t', file.size() - 3); bool exists = false; SaveLoad::SaveMode mode = _vm->_saveLoad->getSaveMode(file.c_str()); if (mode == SaveLoad::kSaveModeNone) { exists = _vm->_dataIO->hasFile(file); if (!exists) warning("File \"%s\" not found", file.c_str()); } else if (mode == SaveLoad::kSaveModeSave) exists = _vm->_saveLoad->getSize(file.c_str()) >= 0; else if (mode == SaveLoad::kSaveModeExists) exists = true; WRITE_VAR_OFFSET(varOff, exists ? 50 : (uint32)-1); }
void SceneTeleporter::teleporterHandleKey() { switch (_game._trigger) { case 0: { _game._player._stepEnabled = false; Common::Point msgPos = teleporterComputeLocation(); _handSequenceId = _scene->_sequences.startPingPongCycle(_handSpriteId, false, 4, 2, 0, 0); _scene->_sequences.setPosition(_handSequenceId, msgPos); _scene->_sequences.setDepth(_handSequenceId, 2); _scene->_sequences.addSubEntry(_handSequenceId, SEQUENCE_TRIGGER_LOOP, 0, 1); _scene->_sequences.addSubEntry(_handSequenceId, SEQUENCE_TRIGGER_EXPIRE, 0, 2); if (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL) _vm->_events->hideCursor(); } break; case 1: _scene->_sequences.addSubEntry(_handSequenceId, SEQUENCE_TRIGGER_SPRITE, 3, 3); if (_buttonTyped <= 9) { if (_digitCount < 4) { _curCode *= 10; _curCode += _buttonTyped; _digitCount++; Common::String format = "%01d"; format.setChar('0' + _digitCount, 2); _msgText = Common::String::format(format.c_str(), _curCode); if (_digitCount < 4) _msgText += "_"; if (_scene->_currentSceneId != 711) _vm->_sound->command(32); } } else if (_buttonTyped == 11) { _digitCount = 0; _curCode = 0; _msgText = "_"; if (_scene->_currentSceneId != 711) _vm->_sound->command(33); } else if (_digitCount == 4) { if (_scene->_currentSceneId != 711) _finishedCodeCounter = 1; if (teleporterAddress(_curCode, true) > 0) { _vm->_palette->setEntry(252, 0, 63, 0); if (_scene->_currentSceneId != 711) _vm->_sound->command(34); } else { _vm->_palette->setEntry(252, 63, 0, 0); if (_scene->_currentSceneId != 711) _vm->_sound->command(35); } } if (_scene->_currentSceneId != 711) { if (_curMessageId >= 0) _scene->_kernelMessages.remove(_curMessageId); _curMessageId = _scene->_kernelMessages.add(Common::Point(143, 61), 0xFDFC, 16, 0, INDEFINITE_TIMEOUT, _msgText); } break; case 2: if (_finishedCodeCounter == 1) { _finishedCodeCounter++; if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL) _scene->_nextSceneId = 202; else { _vm->_events->showCursor(); int destination = teleporterAddress(_curCode, true); if (destination > 0) { _globals[kTeleporterCommand] = 2; _scene->_nextSceneId = _teleporterSceneId; _globals[kTeleporterDestination] = destination; } else { _globals[kTeleporterCommand] = 4; _scene->_nextSceneId = _teleporterSceneId; } } } else if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL) _scene->_sequences.addTimer(30, 230 + _meteorologistCurPlace); break; case 3: if (!_finishedCodeCounter) { if (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL) { _game._player._stepEnabled = true; _vm->_events->showCursor(); } } break; default: break; } }
Common::String HiRes4Engine_Atari::formatVerbError(const Common::String &verb) const { Common::String err = _strings.verbError; for (uint i = 0; i < verb.size(); ++i) err.setChar(verb[i], i + 8); return err; }
void Room::feather1ReachedVineToClimbDown() { const char *crew = "ksmr"; Common::String anim = "s5r1_d"; anim.setChar(crew[_roomVar.feather.crewmanClimbingVine], 4); loadActorAnimC(_roomVar.feather.crewmanClimbingVine, anim, VINE_BOT_X, VINE_BOT_Y, &Room::feather1ClimbedDownVine); }
reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text)); // The object in the text selector of the item can be either a raw string // or a Str object. In the latter case, we need to access the object's data // selector to get the raw string. if (_segMan->isHeapObject(stringObject)) stringObject = readSelector(_segMan, stringObject, SELECTOR(data)); Common::String text = _segMan->getString(stringObject); // HACK: The character offsets of the up and down arrow buttons are off by one // in GK1, for some unknown reason. Fix them here. if (text.size() == 1 && (text[0] == 29 || text[0] == 30)) { text.setChar(text[0] + 1, 0); } GuiResourceId fontId = readSelectorValue(_segMan, textObject, SELECTOR(font)); GfxFont *font = _cache->getFont(fontId); bool dimmed = readSelectorValue(_segMan, textObject, SELECTOR(dimmed)); int16 alignment = readSelectorValue(_segMan, textObject, SELECTOR(mode)); uint16 foreColor = readSelectorValue(_segMan, textObject, SELECTOR(fore)); uint16 backColor = readSelectorValue(_segMan, textObject, SELECTOR(back)); Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(textObject); uint16 width = nsRect.width() + 1; uint16 height = nsRect.height() + 1; // Limit rectangle dimensions, if requested if (maxWidth > 0) width = maxWidth; if (maxHeight > 0) height = maxHeight; // Upscale the coordinates/width if the fonts are already upscaled if (_screen->fontIsUpscaled()) { width = width * _screen->getDisplayWidth() / _screen->getWidth(); height = height * _screen->getDisplayHeight() / _screen->getHeight(); } int entrySize = width * height + BITMAP_HEADER_SIZE; reg_t memoryId = NULL_REG; if (prevHunk.isNull()) { memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize); writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId); } else { memoryId = prevHunk; } byte *memoryPtr = _segMan->getHunkPointer(memoryId); if (prevHunk.isNull()) memset(memoryPtr, 0, BITMAP_HEADER_SIZE); byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; memset(bitmap, backColor, width * height); // Save totalWidth, totalHeight WRITE_LE_UINT16(memoryPtr, width); WRITE_LE_UINT16(memoryPtr + 2, height); int16 charCount = 0; uint16 curX = 0, curY = 0; const char *txt = text.c_str(); int16 textWidth, textHeight, totalHeight = 0, offsetX = 0, offsetY = 0; uint16 start = 0; // Calculate total text height while (*txt) { charCount = GetLongest(txt, width, font); if (charCount == 0) break; Width(txt, 0, (int16)strlen(txt), fontId, textWidth, textHeight, true); totalHeight += textHeight; txt += charCount; while (*txt == ' ') txt++; // skip over breaking spaces } txt = text.c_str(); // Draw text in buffer while (*txt) { charCount = GetLongest(txt, width, font); if (charCount == 0) break; Width(txt, start, charCount, fontId, textWidth, textHeight, true); switch (alignment) { case SCI_TEXT32_ALIGNMENT_RIGHT: offsetX = width - textWidth; break; case SCI_TEXT32_ALIGNMENT_CENTER: // Center text both horizontally and vertically offsetX = (width - textWidth) / 2; offsetY = (height - totalHeight) / 2; break; case SCI_TEXT32_ALIGNMENT_LEFT: offsetX = 0; break; default: warning("Invalid alignment %d used in TextBox()", alignment); } for (int i = 0; i < charCount; i++) { unsigned char curChar = txt[i]; font->drawToBuffer(curChar, curY + offsetY, curX + offsetX, foreColor, dimmed, bitmap, width, height); curX += font->getCharWidth(curChar); } curX = 0; curY += font->getHeight(); txt += charCount; while (*txt == ' ') txt++; // skip over breaking spaces } return memoryId; }
/** * Handles the sciAudio calls in fanmade games. * sciAudio is an external .NET library for playing MP3 files in fanmade games. * It runs in the background, and obtains sound commands from the * currently running game via text files (called "conductor files"). * For further info, check: http://sciprogramming.com/community/index.php?topic=634.0 */ void AudioPlayer::handleFanmadeSciAudio(reg_t sciAudioObject, SegManager *segMan) { // TODO: This is a bare bones implementation. Only the play/playx and stop commands // are handled for now - the other commands haven't been observed in any fanmade game // yet. All the volume related and fading functionality is currently missing. Kernel *kernel = g_sci->getKernel(); reg_t commandReg = readSelector(segMan, sciAudioObject, kernel->findSelector("command")); Common::String command = segMan->getString(commandReg); if (command == "play" || command == "playx") { reg_t fileNameReg = readSelector(segMan, sciAudioObject, kernel->findSelector("fileName")); Common::String fileName = segMan->getString(fileNameReg); reg_t loopCountReg = readSelector(segMan, sciAudioObject, kernel->findSelector("loopCount")); Common::String loopCountStr = segMan->getString(loopCountReg); int16 loopCount = atoi(loopCountStr.c_str()); // Adjust loopCount for ScummVM's LoopingAudioStream semantics if (loopCount == -1) { loopCount = 0; // loop endlessly } else if (loopCount >= 0) { // sciAudio loopCount == 0 -> play 1 time -> ScummVM's loopCount should be 1 // sciAudio loopCount == 1 -> play 2 times -> ScummVM's loopCount should be 2 loopCount++; } else { loopCount = 1; // play once in case the value makes no sense } // Determine sound type Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType; if (fileName.hasPrefix("music")) soundType = Audio::Mixer::kMusicSoundType; else if (fileName.hasPrefix("speech")) soundType = Audio::Mixer::kSpeechSoundType; // Determine compression uint32 audioCompressionType = 0; if ((fileName.hasSuffix(".mp3")) || (fileName.hasSuffix(".sciAudio")) || (fileName.hasSuffix(".sciaudio"))) { audioCompressionType = MKTAG('M','P','3',' '); } else if (fileName.hasSuffix(".wav")) { audioCompressionType = MKTAG('W','A','V',' '); } else if (fileName.hasSuffix(".aiff")) { audioCompressionType = MKTAG('A','I','F','F'); } else { error("sciAudio: unsupported file type"); } Common::File *sciAudioFile = new Common::File(); // Replace backwards slashes for (uint i = 0; i < fileName.size(); i++) { if (fileName[i] == '\\') fileName.setChar('/', i); } sciAudioFile->open("sciAudio/" + fileName); Audio::RewindableAudioStream *audioStream = nullptr; switch (audioCompressionType) { case MKTAG('M','P','3',' '): #ifdef USE_MAD audioStream = Audio::makeMP3Stream(sciAudioFile, DisposeAfterUse::YES); #endif break; case MKTAG('W','A','V',' '): audioStream = Audio::makeWAVStream(sciAudioFile, DisposeAfterUse::YES); break; case MKTAG('A','I','F','F'): audioStream = Audio::makeAIFFStream(sciAudioFile, DisposeAfterUse::YES); break; default: break; } if (!audioStream) { error("sciAudio: requested compression not compiled into ScummVM"); } // We only support one audio handle _mixer->playStream(soundType, &_audioHandle, Audio::makeLoopingAudioStream((Audio::RewindableAudioStream *)audioStream, loopCount)); } else if (command == "stop") { _mixer->stopHandle(_audioHandle); } else { warning("Unhandled sciAudio command: %s", command.c_str()); } }
void UserInterface::writeVocab(ScrCategory category, int id) { Common::Rect bounds; if (!getBounds(category, id, bounds)) return; Scene &scene = _vm->_game->_scene; Font *font = nullptr; int vocabId; Common::String vocabStr; switch (category) { case CAT_COMMAND: font = _vm->_font->getFont(FONT_INTERFACE); vocabId = scene._verbList[id]._id; if (id == _highlightedCommandIndex) { _vm->_font->setColorMode(SELMODE_HIGHLIGHTED); } else { _vm->_font->setColorMode(id == _selectedActionIndex ? SELMODE_SELECTED : SELMODE_UNSELECTED); } vocabStr = scene.getVocab(vocabId); vocabStr.setChar(toupper(vocabStr[0]), 0); font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top)); break; case CAT_INV_LIST: font = _vm->_font->getFont(FONT_INTERFACE); vocabId = _vm->_game->_objects.getItem(id)._descId; if (id == _highlightedInvIndex) { _vm->_font->setColorMode(SELMODE_HIGHLIGHTED); } else { _vm->_font->setColorMode(id == _selectedInvIndex ? SELMODE_SELECTED : SELMODE_UNSELECTED); } vocabStr = scene.getVocab(vocabId); vocabStr.setChar(toupper(vocabStr[0]), 0); font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top)); break; case CAT_TALK_ENTRY: font = _vm->_font->getFont(FONT_INTERFACE); font->setColorMode(id == _highlightedCommandIndex ? SELMODE_HIGHLIGHTED : SELMODE_UNSELECTED); font->writeString(this, _talkStrings[id], Common::Point(bounds.left, bounds.top)); break; case CAT_INV_SCROLLER: font = _vm->_font->getFont(FONT_MISC); switch (id) { case 1: vocabStr = "a"; break; case 2: vocabStr = "b"; break; case 3: vocabStr = "d"; break; case 4: vocabStr = "c"; break; default: break; } font->setColorMode((id == 4) || (_scrollbarActive == SCROLLBAR_ELEVATOR) ? SELMODE_HIGHLIGHTED : SELMODE_UNSELECTED); font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top)); break; default: // Item specific verbs font = _vm->_font->getFont(FONT_INTERFACE); vocabId = _vm->_game->_objects.getItem(_selectedInvIndex)._vocabList[id]._vocabId; if (id == _highlightedItemVocabIndex) { _vm->_font->setColorMode(SELMODE_HIGHLIGHTED); } else { _vm->_font->setColorMode(id == _selectedInvIndex ? SELMODE_SELECTED : SELMODE_UNSELECTED); vocabStr = scene.getVocab(vocabId); vocabStr.setChar(toupper(vocabStr[0]), 0); font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top)); break; } break; } }
bool WidgetFiles::getFilename() { Events &events = *_vm->_events; TattooScene &scene = *(TattooScene *)_vm->_scene; Screen &screen = *_vm->_screen; Talk &talk = *_vm->_talk; int index = 0; int done = 0; bool blinkFlag = false; int blinkCountdown = 0; int cursorColor = 192; byte color, textColor; bool insert = true; assert(_selector != -1); Common::Point pt(_surface.stringWidth("00.") + _surface.widestChar() + 5, _surface.fontHeight() + 14 + (_selector - _savegameIndex) * (_surface.fontHeight() + 1)); Common::String numStr = Common::String::format("%d.", _selector + 1); _surface.writeString(numStr, Common::Point(_surface.widestChar(), pt.y), COMMAND_HIGHLIGHTED); Common::String filename = _savegames[_selector]; if (isSlotEmpty(_selector)) { index = 0; _surface.fillRect(Common::Rect(pt.x, pt.y, _bounds.right - BUTTON_SIZE - 9, pt.y + _surface.fontHeight() - 1), TRANSPARENCY); filename = ""; } else { index = filename.size(); _surface.writeString(filename, pt, COMMAND_HIGHLIGHTED); pt.x = _surface.stringWidth("00.") + _surface.stringWidth(filename) + _surface.widestChar() + 5; } do { scene.doBgAnim(); if (talk._talkToAbort) return false; char currentChar = (index == (int)filename.size()) ? ' ' : filename[index]; Common::String charString = Common::String::format("%c", currentChar); int width = screen.charWidth(currentChar); // Wait for keypress while (!events.kbHit()) { events.pollEventsAndWait(); events.setButtonState(); scene.doBgAnim(); if (talk._talkToAbort) return false; if (--blinkCountdown <= 0) { blinkCountdown = 3; blinkFlag = !blinkFlag; if (blinkFlag) { textColor = 236; color = cursorColor; } else { textColor = COMMAND_HIGHLIGHTED; color = TRANSPARENCY; } _surface.fillRect(Common::Rect(pt.x, pt.y, pt.x + width, pt.y + _surface.fontHeight()), color); if (currentChar != ' ') _surface.writeString(charString, pt, textColor); } if (_vm->shouldQuit()) return false; } Common::KeyState keyState = events.getKey(); if (keyState.keycode == Common::KEYCODE_BACKSPACE && index > 0) { pt.x -= _surface.charWidth(filename[index - 1]); --index; if (insert) { filename.deleteChar(index); } else { filename.setChar(' ', index); } _surface.fillRect(Common::Rect(pt.x, pt.y, _surface.width() - BUTTON_SIZE - 9, pt.y + _surface.fontHeight() - 1), TRANSPARENCY); _surface.writeString(filename.c_str() + index, pt, COMMAND_HIGHLIGHTED); } else if ((keyState.keycode == Common::KEYCODE_LEFT && index > 0) || (keyState.keycode == Common::KEYCODE_RIGHT && index < 49 && pt.x < (_bounds.right - BUTTON_SIZE - 20)) || (keyState.keycode == Common::KEYCODE_HOME && index > 0) || (keyState.keycode == Common::KEYCODE_END)) { _surface.fillRect(Common::Rect(pt.x, pt.y, pt.x + width, pt.y + _surface.fontHeight()), TRANSPARENCY); if (currentChar) _surface.writeString(charString, pt, COMMAND_HIGHLIGHTED); switch (keyState.keycode) { case Common::KEYCODE_LEFT: pt.x -= _surface.charWidth(filename[index - 1]); --index; break; case Common::KEYCODE_RIGHT: pt.x += _surface.charWidth(filename[index]); ++index; break; case Common::KEYCODE_HOME: pt.x = _surface.stringWidth("00.") + _surface.widestChar() + 5; index = 0; break; case Common::KEYCODE_END: pt.x = _surface.stringWidth("00.") + _surface.stringWidth(filename) + _surface.widestChar() + 5; index = filename.size(); while (filename[index - 1] == ' ' && index > 0) { pt.x -= _surface.charWidth(filename[index - 1]); --index; } break; default: break; } } else if (keyState.keycode == Common::KEYCODE_INSERT) { insert = !insert; if (insert) cursorColor = 192; else cursorColor = 200; } else if (keyState.keycode == Common::KEYCODE_DELETE) { filename.deleteChar(index); _surface.fillRect(Common::Rect(pt.x, pt.y, _bounds.right - BUTTON_SIZE - 9, pt.y + _surface.fontHeight() - 1), TRANSPARENCY); _surface.writeString(filename + index, pt, COMMAND_HIGHLIGHTED); } else if (keyState.keycode == Common::KEYCODE_RETURN) { done = 1; } else if (keyState.keycode == Common::KEYCODE_ESCAPE) { _selector = -1; render(RENDER_NAMES_AND_SCROLLBAR); done = -1; } if ((keyState.ascii >= ' ') && (keyState.ascii <= 'z') && (index < 50)) { if (pt.x + _surface.charWidth(keyState.ascii) < _surface.w - BUTTON_SIZE - 20) { if (insert) filename.insertChar(keyState.ascii, index); else filename.setChar(keyState.ascii, index); _surface.fillRect(Common::Rect(pt.x, pt.y, _bounds.width() - BUTTON_SIZE - 9, pt.y + _surface.fontHeight() - 1), TRANSPARENCY); _surface.writeString(filename.c_str() + index, pt, COMMAND_HIGHLIGHTED); pt.x += _surface.charWidth(keyState.ascii); ++index; } } } while (!done && !_vm->shouldQuit()); scene.doBgAnim(); if (talk._talkToAbort) return false; if (done == 1) _savegames[_selector] = filename; return done == 1; }
void GfxMenu::kernelAddEntry(Common::String title, Common::String content, reg_t contentVmPtr) { GuiMenuEntry *menuEntry; uint16 itemCount = 0; GuiMenuItemEntry *itemEntry; int contentSize = content.size(); int separatorCount; int curPos, beginPos, endPos, tempPos; int tagPos, rightAlignedPos, functionPos, altPos, controlPos; const char *tempPtr; // Sierra SCI starts with id 1, so we do so as well menuEntry = new GuiMenuEntry(_list.size() + 1); menuEntry->text = title; _list.push_back(menuEntry); curPos = 0; uint16 listSize = _list.size(); do { itemCount++; itemEntry = new GuiMenuItemEntry(listSize, itemCount); beginPos = curPos; // Now go through the content till we find end-marker and collect data about it. // ':' is an end-marker for each item. tagPos = 0; rightAlignedPos = 0; controlPos = 0; altPos = 0; functionPos = 0; while ((curPos < contentSize) && (content[curPos] != ':')) { switch (content[curPos]) { case '=': // Set tag // Special case for normal animation speed - they use right // aligned "=" for that one, so we ignore it as being recognized // as tag marker. if (rightAlignedPos == curPos - 1) break; if (tagPos) error("multiple tag markers within one menu-item"); tagPos = curPos; break; case '`': // Right-aligned if (rightAlignedPos) error("multiple right-aligned markers within one menu-item"); rightAlignedPos = curPos; break; case '^': // Ctrl-prefix if (controlPos) error("multiple control markers within one menu-item"); controlPos = curPos; break; case '@': // Alt-prefix if (altPos) error("multiple alt markers within one menu-item"); altPos = curPos; break; case '#': // Function-prefix if (functionPos) error("multiple function markers within one menu-item"); functionPos = curPos; break; } curPos++; } endPos = curPos; // Control/Alt/Function key mapping... if (controlPos) { content.setChar(SCI_MENU_REPLACE_ONCONTROL, controlPos); itemEntry->keyModifier = SCI_KEYMOD_CTRL; tempPos = controlPos + 1; if (tempPos >= contentSize) error("control marker at end of item"); itemEntry->keyPress = tolower(content[tempPos]); content.setChar(toupper(content[tempPos]), tempPos); } if (altPos) { content.setChar(SCI_MENU_REPLACE_ONALT, altPos); itemEntry->keyModifier = SCI_KEYMOD_ALT; tempPos = altPos + 1; if (tempPos >= contentSize) error("alt marker at end of item"); itemEntry->keyPress = tolower(content[tempPos]); content.setChar(toupper(content[tempPos]), tempPos); } if (functionPos) { content.setChar(SCI_MENU_REPLACE_ONFUNCTION, functionPos); tempPos = functionPos + 1; if (tempPos >= contentSize) error("function marker at end of item"); itemEntry->keyPress = content[tempPos]; switch (content[functionPos + 1]) { case '1': itemEntry->keyPress = SCI_KEY_F1; break; case '2': itemEntry->keyPress = SCI_KEY_F2; break; case '3': itemEntry->keyPress = SCI_KEY_F3; break; case '4': itemEntry->keyPress = SCI_KEY_F4; break; case '5': itemEntry->keyPress = SCI_KEY_F5; break; case '6': itemEntry->keyPress = SCI_KEY_F6; break; case '7': itemEntry->keyPress = SCI_KEY_F7; break; case '8': itemEntry->keyPress = SCI_KEY_F8; break; case '9': itemEntry->keyPress = SCI_KEY_F9; break; case '0': itemEntry->keyPress = SCI_KEY_F10; break; default: error("illegal function key specified"); } } // Now get all strings tempPos = endPos; if (rightAlignedPos) { tempPos = rightAlignedPos; } else if (tagPos) { tempPos = tagPos; } curPos = beginPos; separatorCount = 0; while (curPos < tempPos) { switch (content[curPos]) { case '!': case '-': case ' ': separatorCount++; break; case '%': // Some multilingual sci01 games use e.g. '--!%G--!' (which doesn't really make sense) separatorCount += 2; curPos++; } curPos++; } if (separatorCount == tempPos - beginPos) { itemEntry->separatorLine = true; } else { // We don't strSplit here, because multilingual SCI01 support // language switching on the fly, so we have to do this everytime // the menu is called. itemEntry->text = Common::String(content.c_str() + beginPos, tempPos - beginPos); // LSL6 uses "Ctrl-" prefix string instead of ^ like all the other games do tempPtr = itemEntry->text.c_str(); tempPtr = strstr(tempPtr, "Ctrl-"); if (tempPtr) { itemEntry->keyModifier = SCI_KEYMOD_CTRL; itemEntry->keyPress = tolower(tempPtr[5]); } } itemEntry->textVmPtr = contentVmPtr; itemEntry->textVmPtr.incOffset(beginPos); if (rightAlignedPos) { rightAlignedPos++; tempPos = endPos; // some games have tagPos in front of right rightAlignedPos // some have it the other way... (qfg1ega) if (tagPos && tagPos >= rightAlignedPos) tempPos = tagPos; itemEntry->textRightAligned = Common::String(content.c_str() + rightAlignedPos, tempPos - rightAlignedPos); // Remove ending space, if there is one. Strangely sometimes there // are lone spaces at the end in some games if (itemEntry->textRightAligned.hasSuffix(" ")) itemEntry->textRightAligned.deleteLastChar(); // - and + are used sometimes for volume control/animation speed, // = sometimes for animation speed if (itemEntry->textRightAligned == "-") { itemEntry->keyPress = '-'; } else if (itemEntry->textRightAligned == "+") { itemEntry->keyPress = '+'; } else if (itemEntry->textRightAligned == "=") { itemEntry->keyPress = '='; } } if (tagPos) { tempPos = functionPos + 1; if (tempPos >= contentSize) error("tag marker at end of item"); itemEntry->tag = atoi(content.c_str() + tempPos); } curPos = endPos + 1; _itemList.push_back(itemEntry); } while (curPos < contentSize); }
MsCabinet::MsCabinet(Common::SeekableReadStream* data) : _data(data), _decompressor(0) { if (!_data) return; //CFHEADER PARSING // Verify Head-signature uint32 tag = _data->readUint32BE(); if (tag != MKTAG('M','S','C','F')) return; /* uint32 reserved1 = */ _data->readUint32LE(); uint32 length = _data->readUint32LE(); if (length > uint32(_data->size())) return; /* uint32 reserved2 = */ _data->readUint32LE(); uint32 filesOffset = _data->readUint32LE(); /* uint32 reserved3 = */ _data->readUint32LE(); byte versionMinor = _data->readByte(); byte versionMajor = _data->readByte(); if (versionMajor != 1 || versionMinor != 3) return; uint16 numFolders = _data->readUint16LE(); uint16 numFiles = _data->readUint16LE(); if (numFolders == 0 || numFiles == 0) return; //This implementation doesn't support multicabinet and reserved fields uint16 flags = _data->readUint16LE(); if (flags != 0) return; /* uint16 setId = */ _data->readUint16LE(); /* uint16 iCab = */ _data->readUint16LE(); if (_data->err()) return; //CFFOLDERs PARSING for (uint16 i = 0; i < numFolders; ++i) { FolderEntry fEntry; fEntry.offset = _data->readUint32LE(); fEntry.num_blocks = _data->readUint16LE(); fEntry.comp_type = _data->readUint16LE(); if (_data->err()) return; _folderMap[i] = fEntry; } //CFFILEs PARSING _data->seek(filesOffset); if (_data->err()) return; for (uint16 i = 0; i < numFiles; ++i) { FileEntry fEntry; fEntry.length = _data->readUint32LE(); fEntry.folderOffset = _data->readUint32LE(); uint16 iFolder = _data->readUint16LE(); /* uint16 date = */ _data->readUint16LE(); /* uint16 time = */ _data->readUint16LE(); /* uint16 attribs = */ _data->readUint16LE(); Common::String name = readString(_data); for (uint l = 0; l < name.size(); ++l) if (name[l] == '\\') name.setChar('/', l); if (_data->err()) { _fileMap.clear(); return; } if (_folderMap.contains(iFolder)) fEntry.folder = &_folderMap[iFolder]; else { _fileMap.clear(); return; } _fileMap[name] = fEntry; } }
void Room::feather1ReachedVineToClimbUp() { const char *crew = "ksmr"; Common::String anim = "s5r1_c"; anim.setChar(crew[_roomVar.feather.crewmanClimbingVine], 4); loadActorAnimC(_roomVar.feather.crewmanClimbingVine, anim, -1, -1, &Room::feather1ClimbedUpVine); }