void GuestAdditions::syncLSL6HiresUI(const int16 musicVolume) const { const reg_t musicDialId = _segMan->findObjectByName("volumeDial"); if (!musicDialId.isNull()) { writeSelectorValue(_segMan, musicDialId, SELECTOR(curPos), musicVolume); writeSelectorValue(_segMan, musicDialId, SELECTOR(cel), musicVolume); reg_t params[] = { make_reg(0, musicVolume) }; invokeSelector(musicDialId, SELECTOR(update), 1, params); if (_segMan->getObject(musicDialId)->isInserted()) { g_sci->_gfxFrameout->kernelUpdateScreenItem(musicDialId); } } }
void SciEngine::setLauncherLanguage() { if (_gameDescription->flags & ADGF_ADDENGLISH) { // If game is multilingual if (Common::parseLanguage(ConfMan.get("language")) == Common::EN_ANY) { // and English was selected as language if (SELECTOR(printLang) != -1) // set text language to English writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(printLang), K_LANG_ENGLISH); if (SELECTOR(parseLang) != -1) // and set parser language to English as well writeSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(parseLang), K_LANG_ENGLISH); } } }
void SoundCommandParser::processPlaySound(reg_t obj) { MusicEntry *musicSlot = _music->getSlot(obj); if (!musicSlot) { warning("kDoSound(play): Slot not found (%04x:%04x), initializing it manually", PRINT_REG(obj)); // The sound hasn't been initialized for some reason, so initialize it // here. Happens in KQ6, room 460, when giving the creature (child) to // the bookworm. Fixes bugs #3413301 and #3421098. processInitSound(obj); musicSlot = _music->getSlot(obj); if (!musicSlot) error("Failed to initialize uninitialized sound slot"); } int resourceId = getSoundResourceId(obj); if (musicSlot->resourceId != resourceId) { // another sound loaded into struct processDisposeSound(obj); processInitSound(obj); // Find slot again :) musicSlot = _music->getSlot(obj); } writeSelector(_segMan, obj, SELECTOR(handle), obj); if (_soundVersion >= SCI_VERSION_1_EARLY) { writeSelector(_segMan, obj, SELECTOR(nodePtr), obj); writeSelectorValue(_segMan, obj, SELECTOR(min), 0); writeSelectorValue(_segMan, obj, SELECTOR(sec), 0); writeSelectorValue(_segMan, obj, SELECTOR(frame), 0); writeSelectorValue(_segMan, obj, SELECTOR(signal), 0); } else { writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundPlaying); } musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop)); musicSlot->priority = readSelectorValue(_segMan, obj, SELECTOR(priority)); // Reset hold when starting a new song. kDoSoundSetHold is always called after // kDoSoundPlay to set it properly, if needed. Fixes bug #3413589. musicSlot->hold = -1; if (_soundVersion >= SCI_VERSION_1_EARLY) musicSlot->volume = readSelectorValue(_segMan, obj, SELECTOR(vol)); debugC(kDebugLevelSound, "kDoSound(play): %04x:%04x number %d, loop %d, prio %d, vol %d", PRINT_REG(obj), resourceId, musicSlot->loop, musicSlot->priority, musicSlot->volume); _music->soundPlay(musicSlot); // Reset any left-over signals musicSlot->signal = 0; musicSlot->fadeStep = 0; }
void GuestAdditions::syncQFG4UI(const int16 musicVolume) const { const reg_t sliderId = _segMan->findObjectByName("volumeSlider"); if (!sliderId.isNull()) { const int16 yPosition = 84 - musicVolume * 34 / 10; writeSelectorValue(_segMan, sliderId, SELECTOR(y), yPosition); // There does not seem to be any good way to learn whether the // volume slider is visible (and thus eligible for // kUpdateScreenItem) const reg_t planeId = readSelector(_segMan, sliderId, SELECTOR(plane)); if (g_sci->_gfxFrameout->getPlanes().findByObject(planeId) != nullptr) { g_sci->_gfxFrameout->kernelUpdateScreenItem(sliderId); } } }
void GfxAnimate::fill(byte &old_picNotValid) { GfxView *view = NULL; AnimateList::iterator it; const AnimateList::iterator end = _list.end(); for (it = _list.begin(); it != end; ++it) { // Get the corresponding view view = _cache->getView(it->viewId); adjustInvalidCels(view, it); processViewScaling(view, it); setNsRect(view, it); //warning("%s view %d, loop %d, cel %d, signal %x", _s->_segMan->getObjectName(curObject), it->viewId, it->loopNo, it->celNo, it->signal); // Calculate current priority according to y-coordinate if (!(it->signal & kSignalFixedPriority)) { it->priority = _ports->kernelCoordinateToPriority(it->y); writeSelectorValue(_s->_segMan, it->object, SELECTOR(priority), it->priority); } if (it->signal & kSignalNoUpdate) { if ((it->signal & (kSignalForceUpdate | kSignalViewUpdated)) || (it->signal & kSignalHidden && !(it->signal & kSignalRemoveView)) || (!(it->signal & kSignalHidden) && it->signal & kSignalRemoveView) || (it->signal & kSignalAlwaysUpdate)) old_picNotValid++; it->signal &= ~kSignalStopUpdate; } else { if ((it->signal & kSignalStopUpdate) || (it->signal & kSignalAlwaysUpdate)) old_picNotValid++; it->signal &= ~kSignalForceUpdate; } } }
reg_t SoundCommandParser::kDoSoundSetVolume(int argc, reg_t *argv, reg_t acc) { reg_t obj = argv[0]; int16 value = argv[1].toSint16(); MusicEntry *musicSlot = _music->getSlot(obj); if (!musicSlot) { // Do not throw a warning if the sound can't be found, as in some games // this is called before the actual sound is loaded (e.g. SQ4CD, with // the drum sounds of the energizer bunny at the beginning), so this is // normal behavior. //warning("cmdSetSoundVolume: Slot not found (%04x:%04x)", PRINT_REG(obj)); return acc; } debugC(kDebugLevelSound, "kDoSound(setVolume): %d", value); value = CLIP<int>(value, 0, MUSIC_VOLUME_MAX); if (musicSlot->volume != value) { musicSlot->volume = value; _music->soundSetVolume(musicSlot, value); writeSelectorValue(_segMan, obj, SELECTOR(vol), value); } return acc; }
reg_t SoundCommandParser::kDoSoundSetLoop(int argc, reg_t *argv, reg_t acc) { reg_t obj = argv[0]; int16 value = argv[1].toSint16(); debugC(kDebugLevelSound, "kDoSound(setLoop): %04x:%04x, %d", PRINT_REG(obj), value); MusicEntry *musicSlot = _music->getSlot(obj); if (!musicSlot) { // Apparently, it's perfectly normal for a game to call cmdSetSoundLoop // before actually initializing the sound and adding it to the playlist // with cmdInitSound. Usually, it doesn't matter if the game doesn't // request to loop the sound, so in this case, don't throw any warning, // otherwise do, because the sound won't be looped. if (value == -1) { warning("kDoSound(setLoop): Slot not found (%04x:%04x) and the song was requested to be looped", PRINT_REG(obj)); } else { // Doesn't really matter } return acc; } if (value == -1) { musicSlot->loop = 0xFFFF; } else { musicSlot->loop = 1; // actually plays the music once } writeSelectorValue(_segMan, obj, SELECTOR(loop), musicSlot->loop); return acc; }
void SoundCommandParser::processDisposeSound(reg_t obj) { MusicEntry *musicSlot = _music->getSlot(obj); if (!musicSlot) { warning("kDoSound(dispose): Slot not found (%04x:%04x)", PRINT_REG(obj)); return; } processStopSound(obj, false); _music->soundKill(musicSlot); writeSelectorValue(_segMan, obj, SELECTOR(handle), 0); if (_soundVersion >= SCI_VERSION_1_EARLY) writeSelector(_segMan, obj, SELECTOR(nodePtr), NULL_REG); else writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundStopped); }
reg_t kArrayGetData(EngineState *s, int argc, reg_t *argv) { if (s->_segMan->isObject(argv[0])) { return readSelector(s->_segMan, argv[0], SELECTOR(data)); } return argv[0]; }
bool GameFeatures::autoDetectSci21StringFunctionType() { // Look up the script address reg_t addr = getDetectionAddr("Str", SELECTOR(size)); if (!addr.segment) return false; uint16 offset = addr.offset; Script *script = _segMan->getScript(addr.segment); while (true) { int16 opparams[4]; byte extOpcode; byte opcode; offset += readPMachineInstruction(script->getBuf(offset), extOpcode, opparams); opcode = extOpcode >> 1; // Check for end of script if (opcode == op_ret || offset >= script->getBufSize()) break; if (opcode == op_callk) { uint16 kFuncNum = opparams[0]; // SCI2.1 games which use the new kString functions call kString(8). // Earlier ones call the callKernel script function, but not kString // directly if (_kernel->getKernelName(kFuncNum) == "String") return true; } } return false; // not found a call to kString }
SciVersion GameFeatures::detectDoSoundType() { if (_doSoundType == SCI_VERSION_NONE) { if (getSciVersion() == SCI_VERSION_0_EARLY) { // Almost all of the SCI0EARLY games use different sound resources than // SCI0LATE. Although the last SCI0EARLY game (lsl2) uses SCI0LATE resources _doSoundType = g_sci->getResMan()->detectEarlySound() ? SCI_VERSION_0_EARLY : SCI_VERSION_0_LATE; #ifdef ENABLE_SCI32 } else if (getSciVersion() >= SCI_VERSION_2_1_EARLY) { _doSoundType = SCI_VERSION_2_1_EARLY; #endif } else if (SELECTOR(nodePtr) == -1) { // No nodePtr selector, so this game is definitely using newer // SCI0 sound code (i.e. SCI_VERSION_0_LATE) _doSoundType = SCI_VERSION_0_LATE; } else if (getSciVersion() >= SCI_VERSION_1_LATE) { // All SCI1 late games use the newer doSound semantics _doSoundType = SCI_VERSION_1_LATE; } else { if (!autoDetectSoundType()) { warning("DoSound detection failed, taking an educated guess"); if (getSciVersion() >= SCI_VERSION_1_MIDDLE) _doSoundType = SCI_VERSION_1_LATE; else if (getSciVersion() > SCI_VERSION_01) _doSoundType = SCI_VERSION_1_EARLY; } } debugC(1, kDebugLevelSound, "Detected DoSound type: %s", getSciVersionDesc(_doSoundType)); } return _doSoundType; }
reg_t kSaid(EngineState *s, int argc, reg_t *argv) { reg_t heap_said_block = argv[0]; byte *said_block; int new_lastmatch; Vocabulary *voc = g_sci->getVocabulary(); #ifdef DEBUG_PARSER const int debug_parser = 1; #else const int debug_parser = 0; #endif if (!heap_said_block.getSegment()) return NULL_REG; said_block = (byte *)s->_segMan->derefBulkPtr(heap_said_block, 0); if (!said_block) { warning("Said on non-string, pointer %04x:%04x", PRINT_REG(heap_said_block)); return NULL_REG; } #ifdef DEBUG_PARSER debugN("Said block: "); g_sci->getVocabulary()->debugDecipherSaidBlock(said_block); #endif if (voc->parser_event.isNull() || (readSelectorValue(s->_segMan, voc->parser_event, SELECTOR(claimed)))) { return NULL_REG; } new_lastmatch = said(said_block, debug_parser); if (new_lastmatch != SAID_NO_MATCH) { /* Build and possibly display a parse tree */ #ifdef DEBUG_PARSER debugN("kSaid: Match.\n"); #endif s->r_acc = make_reg(0, 1); if (new_lastmatch != SAID_PARTIAL_MATCH) writeSelectorValue(s->_segMan, voc->parser_event, SELECTOR(claimed), 1); } else { return NULL_REG; } return s->r_acc; }
void SciEngine::runGame() { setTotalPlayTime(0); initStackBaseWithSelector(SELECTOR(play)); // Call the play selector // Attach the debug console on game startup, if requested if (DebugMan.isDebugChannelEnabled(kDebugLevelOnStartup)) _console->attach(); _gamestate->_syncedAudioOptions = false; do { _gamestate->_executionStackPosChanged = false; run_vm(_gamestate); exitGame(); _gamestate->_syncedAudioOptions = true; if (_gamestate->abortScriptProcessing == kAbortRestartGame) { _gamestate->_segMan->resetSegMan(); initGame(); initStackBaseWithSelector(SELECTOR(play)); patchGameSaveRestore(); setLauncherLanguage(); _gamestate->gameIsRestarting = GAMEISRESTARTING_RESTART; _gamestate->_throttleLastTime = 0; if (_gfxMenu) _gfxMenu->reset(); _gamestate->abortScriptProcessing = kAbortNone; _gamestate->_syncedAudioOptions = false; } else if (_gamestate->abortScriptProcessing == kAbortLoadGame) { _gamestate->abortScriptProcessing = kAbortNone; _gamestate->_executionStack.clear(); initStackBaseWithSelector(SELECTOR(replay)); patchGameSaveRestore(); setLauncherLanguage(); _gamestate->shrinkStackToBase(); _gamestate->abortScriptProcessing = kAbortNone; syncSoundSettings(); syncIngameAudioOptions(); // Games do not set their audio settings when loading } else { break; // exit loop } } while (true); }
Common::Rect GfxCompare::getNSRect(reg_t object, bool fixRect) { Common::Rect nsRect; nsRect.top = readSelectorValue(_segMan, object, SELECTOR(nsTop)); nsRect.left = readSelectorValue(_segMan, object, SELECTOR(nsLeft)); nsRect.bottom = readSelectorValue(_segMan, object, SELECTOR(nsBottom)); nsRect.right = readSelectorValue(_segMan, object, SELECTOR(nsRight)); if (fixRect) { // nsRect top/left may be negative, adjust accordingly if (nsRect.top < 0) nsRect.top = 0; if (nsRect.left < 0) nsRect.left = 0; } return nsRect; }
reg_t kLocalToGlobal(EngineState *s, int argc, reg_t *argv) { reg_t obj = argv[0]; reg_t planeObject = argc > 1 ? argv[1] : NULL_REG; // SCI32 SegManager *segMan = s->_segMan; if (obj.getSegment()) { int16 x = readSelectorValue(segMan, obj, SELECTOR(x)); int16 y = readSelectorValue(segMan, obj, SELECTOR(y)); g_sci->_gfxCoordAdjuster->kernelLocalToGlobal(x, y, planeObject); writeSelectorValue(segMan, obj, SELECTOR(x), x); writeSelectorValue(segMan, obj, SELECTOR(y), y); } return s->r_acc; }
reg_t SoundCommandParser::kDoSoundPause(int argc, reg_t *argv, reg_t acc) { if (argc == 1) debugC(kDebugLevelSound, "kDoSound(pause): %04x:%04x", PRINT_REG(argv[0])); else debugC(kDebugLevelSound, "kDoSound(pause): %04x:%04x, %04x:%04x", PRINT_REG(argv[0]), PRINT_REG(argv[1])); if (_soundVersion <= SCI_VERSION_0_LATE) { // SCI0 games give us 0/1 for either resuming or pausing the current music // this one doesn't count, so pausing 2 times and resuming once means here that we are supposed to resume uint16 value = argv[0].toUint16(); MusicEntry *musicSlot = _music->getActiveSci0MusicSlot(); switch (value) { case 1: if ((musicSlot) && (musicSlot->status == kSoundPlaying)) { _music->soundPause(musicSlot); writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPaused); } return make_reg(0, 0); case 0: if ((musicSlot) && (musicSlot->status == kSoundPaused)) { _music->soundResume(musicSlot); writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPlaying); return make_reg(0, 1); } return make_reg(0, 0); default: error("kDoSound(pause): parameter 0 is invalid for sound-sci0"); } } reg_t obj = argv[0]; uint16 value = argc > 1 ? argv[1].toUint16() : 0; if (!obj.segment) { // pause the whole playlist _music->pauseAll(value); } else { // pause a playlist slot MusicEntry *musicSlot = _music->getSlot(obj); if (!musicSlot) { // This happens quite frequently debugC(kDebugLevelSound, "kDoSound(pause): Slot not found (%04x:%04x)", PRINT_REG(obj)); return acc; } _music->soundToggle(musicSlot, value); } return acc; }
void GuestAdditions::syncGK2VolumeFromScummVM(const int16 musicVolume) const { _state->variables[VAR_GLOBAL][kGlobalVarGK2MusicVolume] = make_reg(0, musicVolume); // Calling `setVol` on all sounds is necessary to propagate the volume // change to existing sounds, and matches how game scripts propagate // volume changes when the in-game music slider is moved const reg_t soundsId = _state->variables[VAR_GLOBAL][kGlobalVarSounds]; if (!soundsId.isNull()) { List *sounds = _segMan->lookupList(readSelector(_segMan, soundsId, SELECTOR(elements))); reg_t soundId = sounds->first; while (!soundId.isNull()) { Node *sound = _segMan->lookupNode(soundId); reg_t params[] = { make_reg(0, musicVolume) }; invokeSelector(sound->value, SELECTOR(setVol), 1, params); soundId = sound->succ; } } }
bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) { reg_t curAddress = list->first; Node *curNode = _s->_segMan->lookupNode(curAddress); reg_t curObject; uint16 signal; while (curNode) { curObject = curNode->value; if (_fastCastEnabled) { // Check if the game has a fastCast object set // if we don't abort kAnimate processing, at least in kq5 there will be animation cels drawn into speech boxes. if (!_s->variables[VAR_GLOBAL][84].isNull()) { // This normally points to an object called "fastCast", // but for example in Eco Quest 1 it may also point to an object called "EventHandler" (see bug #5170) // Original SCI only checked, if this global was not 0. return false; } } signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal)); if (!(signal & kSignalFrozen)) { // Call .doit method of that object invokeSelector(_s, curObject, SELECTOR(doit), argc, argv, 0); // If a game is being loaded, stop processing if (_s->abortScriptProcessing != kAbortNone) return true; // Stop processing // Lookup node again, since the nodetable it was in may have been reallocated. // The node might have been deallocated at this point (e.g. LSL2, room 42), // in which case the node reference will be null and the loop will stop below. // If the node is deleted from kDeleteKey, it won't have a successor node, thus // list processing will stop here (which is what SSCI does). curNode = _s->_segMan->lookupNode(curAddress, false); } if (curNode) { curAddress = curNode->succ; curNode = _s->_segMan->lookupNode(curAddress); } } return true; }
reg_t kRobot(EngineState *s, int argc, reg_t *argv) { int16 subop = argv[0].toUint16(); switch (subop) { case 0: { // init int id = argv[1].toUint16(); reg_t obj = argv[2]; int16 flag = argv[3].toSint16(); int16 x = argv[4].toUint16(); int16 y = argv[5].toUint16(); warning("kRobot(init), id %d, obj %04x:%04x, flag %d, x=%d, y=%d", id, PRINT_REG(obj), flag, x, y); g_sci->_robotDecoder->load(id); g_sci->_robotDecoder->start(); g_sci->_robotDecoder->setPos(x, y); } break; case 1: // LSL6 hires (startup) // TODO return NULL_REG; // an integer is expected case 4: { // start - we don't really have a use for this one //int id = argv[1].toUint16(); //warning("kRobot(start), id %d", id); } break; case 7: // unknown, called e.g. by Phantasmagoria warning("kRobot(%d)", subop); break; case 8: // sync //if (true) { // debug: automatically skip all robot videos if (g_sci->_robotDecoder->endOfVideo()) { g_sci->_robotDecoder->close(); // Signal the engine scripts that the video is done writeSelector(s->_segMan, argv[1], SELECTOR(signal), SIGNAL_REG); } else { writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG); } break; default: warning("kRobot(%d)", subop); break; } return s->r_acc; }
void GfxText32::drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject) { reg_t hunkId = readSelector(_segMan, textObject, SELECTOR(bitmap)); uint16 backColor = readSelectorValue(_segMan, textObject, SELECTOR(back)); // Sanity check: Check if the hunk is set. If not, either the game scripts // didn't set it, or an old saved game has been loaded, where it wasn't set. if (hunkId.isNull()) return; // Negative coordinates indicate that text shouldn't be displayed if (x < 0 || y < 0) return; byte *memoryPtr = _segMan->getHunkPointer(hunkId); if (!memoryPtr) { // Happens when restoring in some SCI32 games warning("Attempt to draw an invalid text bitmap"); return; } byte *surface = memoryPtr + BITMAP_HEADER_SIZE; int curByte = 0; uint16 skipColor = readSelectorValue(_segMan, textObject, SELECTOR(skip)); uint16 textX = planeRect.left + x; uint16 textY = planeRect.top + y; // Get totalWidth, totalHeight uint16 width = READ_LE_UINT16(memoryPtr); uint16 height = READ_LE_UINT16(memoryPtr + 2); // Upscale the coordinates/width if the fonts are already upscaled if (_screen->fontIsUpscaled()) { textX = textX * _screen->getDisplayWidth() / _screen->getWidth(); textY = textY * _screen->getDisplayHeight() / _screen->getHeight(); } for (int curY = 0; curY < height; curY++) { for (int curX = 0; curX < width; curX++) { byte pixel = surface[curByte++]; if (pixel != skipColor && pixel != backColor) _screen->putFontPixel(textY, curX + textX, curY, pixel); } } }
void GfxFrameout::kernelAddPlane(reg_t object) { PlaneEntry newPlane; if (_planes.empty()) { // There has to be another way for sierra sci to do this or maybe script resolution is compiled into // interpreter (TODO) uint16 scriptWidth = readSelectorValue(_segMan, object, SELECTOR(resX)); uint16 scriptHeight = readSelectorValue(_segMan, object, SELECTOR(resY)); // Phantasmagoria 2 doesn't specify a script width/height if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { scriptWidth = 640; scriptHeight = 480; } assert(scriptWidth > 0 && scriptHeight > 0); _coordAdjuster->setScriptsResolution(scriptWidth, scriptHeight); } // Import of QfG character files dialog is shown in QFG4. // Display additional popup information before letting user use it. // For the SCI0-SCI1.1 version of this, check kDrawControl(). if (g_sci->inQfGImportRoom() && !strcmp(_segMan->getObjectName(object), "DSPlane")) { showScummVMDialog("Characters saved inside ScummVM are shown " "automatically. Character files saved in the original " "interpreter need to be put inside ScummVM's saved games " "directory and a prefix needs to be added depending on which " "game it was saved in: 'qfg1-' for Quest for Glory 1, 'qfg2-' " "for Quest for Glory 2, 'qfg3-' for Quest for Glory 3. " "Example: 'qfg2-thief.sav'."); } newPlane.object = object; newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority)); newPlane.lastPriority = -1; // hidden newPlane.planeOffsetX = 0; newPlane.planeOffsetY = 0; newPlane.pictureId = kPlanePlainColored; newPlane.planePictureMirrored = false; newPlane.planeBack = 0; _planes.push_back(newPlane); kernelUpdatePlane(object); }
void GuestAdditions::syncPQ4UI(const int16 musicVolume) const { const SegmentId segment = _segMan->getScriptSegment(9, SCRIPT_GET_DONT_LOAD); if (segment != 0 && _segMan->getScript(segment)->getLocalsCount() > 2) { const reg_t barId = _segMan->getScript(segment)->getLocalsBegin()[2]; if (!barId.isNull()) { reg_t params[] = { make_reg(0, musicVolume) }; invokeSelector(barId, SELECTOR(setSize), 1, params); } } }
void GuestAdditions::syncShivers1UI(const int16 dacVolume) const { const reg_t sliderId = _segMan->findObjectByName("spVolume"); if (!sliderId.isNull()) { const int16 xPosition = dacVolume * 78 / Audio32::kMaxVolume + 32; writeSelectorValue(_segMan, sliderId, SELECTOR(x), xPosition); if (_segMan->getObject(sliderId)->isInserted()) { g_sci->_gfxFrameout->kernelUpdateScreenItem(sliderId); } } }
void GuestAdditions::syncSQ6UI() const { const reg_t bars[] = { _segMan->findObjectByName("musicBar"), _segMan->findObjectByName("soundBar") }; for (int i = 0; i < ARRAYSIZE(bars); ++i) { const reg_t barId = bars[i]; if (!barId.isNull()) { invokeSelector(barId, SELECTOR(show)); } } }
void GuestAdditions::syncMessageTypeToScummVMUsingLSL6HiresStrategy(const reg_t sendObj, Selector &selector, reg_t *argp) { if (_state->variables[VAR_GLOBAL][kGlobalVarLSL6HiresGameFlags] == sendObj && (selector == SELECTOR(clear) || selector == SELECTOR(set))) { if (argp[1].toUint16() == kLSL6HiresSubtitleFlag) { if (_messageTypeSynced) { ConfMan.setBool("subtitles", selector == SELECTOR(clear)); } else if (ConfMan.getBool("subtitles")) { selector = SELECTOR(clear); argp[-1].setOffset(selector); _messageTypeSynced = true; } else { selector = SELECTOR(set); argp[-1].setOffset(selector); _messageTypeSynced = true; } } } }
reg_t SoundCommandParser::kDoSoundUpdate(EngineState *s, int argc, reg_t *argv) { reg_t obj = argv[0]; debugC(kDebugLevelSound, "kDoSound(update): %04x:%04x", PRINT_REG(argv[0])); MusicEntry *musicSlot = _music->getSlot(obj); if (!musicSlot) { warning("kDoSound(update): Slot not found (%04x:%04x)", PRINT_REG(obj)); return s->r_acc; } musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop)); int16 objVol = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, 255); if (objVol != musicSlot->volume) _music->soundSetVolume(musicSlot, objVol); int16 objPrio = readSelectorValue(_segMan, obj, SELECTOR(priority)); if (objPrio != musicSlot->priority) _music->soundSetPriority(musicSlot, objPrio); return s->r_acc; }
void SoundCommandParser::startNewSound(int number) { Common::StackLock lock(_music->_mutex); // Overwrite the first sound in the playlist MusicEntry *song = *_music->getPlayListStart(); reg_t soundObj = song->soundObj; processDisposeSound(soundObj); writeSelectorValue(_segMan, soundObj, SELECTOR(number), number); processInitSound(soundObj); processPlaySound(soundObj); }
bool GameFeatures::autoDetectSci21KernelType() { // First, check if the Sound object is loaded reg_t soundObjAddr = _segMan->findObjectByName("Sound"); if (soundObjAddr.isNull()) { // Usually, this means that the Sound object isn't loaded yet. // This case doesn't occur in early SCI2.1 games, and we've only // seen it happen in the RAMA demo, thus we can assume that the // game is using a SCI2.1 table warning("autoDetectSci21KernelType(): Sound object not loaded, assuming a SCI2.1 table"); _sci21KernelType = SCI_VERSION_2_1; return true; } // Look up the script address reg_t addr = getDetectionAddr("Sound", SELECTOR(play)); if (!addr.segment) return false; uint16 offset = addr.offset; Script *script = _segMan->getScript(addr.segment); while (true) { int16 opparams[4]; byte extOpcode; byte opcode; offset += readPMachineInstruction(script->getBuf(offset), extOpcode, opparams); opcode = extOpcode >> 1; // Check for end of script if (opcode == op_ret || offset >= script->getBufSize()) break; if (opcode == op_callk) { uint16 kFuncNum = opparams[0]; // Here we check for the kDoSound opcode that's used in SCI2.1. // Finding 0x40 as kDoSound in the Sound::play() function means the // game is using the modified SCI2 kernel table found in some older // SCI2.1 games (GK2 demo, KQ7 v1.4). // Finding 0x75 as kDoSound means the game is using the regular // SCI2.1 kernel table. if (kFuncNum == 0x40) { _sci21KernelType = SCI_VERSION_2; return true; } else if (kFuncNum == 0x75) { _sci21KernelType = SCI_VERSION_2_1; return true; } } } return false; // not found }
reg_t kScrollWindowCreate(EngineState *s, int argc, reg_t *argv) { const reg_t object = argv[0]; const uint16 maxNumEntries = argv[1].toUint16(); SegManager *segMan = s->_segMan; const int16 borderColor = readSelectorValue(segMan, object, SELECTOR(borderColor)); const TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode)); const GuiResourceId fontId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(font)); const int16 backColor = readSelectorValue(segMan, object, SELECTOR(back)); const int16 foreColor = readSelectorValue(segMan, object, SELECTOR(fore)); const reg_t plane = readSelector(segMan, object, SELECTOR(plane)); Common::Rect rect; rect.left = readSelectorValue(segMan, object, SELECTOR(nsLeft)); rect.top = readSelectorValue(segMan, object, SELECTOR(nsTop)); rect.right = readSelectorValue(segMan, object, SELECTOR(nsRight)) + 1; rect.bottom = readSelectorValue(segMan, object, SELECTOR(nsBottom)) + 1; const Common::Point position(rect.left, rect.top); return g_sci->_gfxControls32->makeScrollWindow(rect, position, plane, foreColor, backColor, fontId, alignment, borderColor, maxNumEntries); }
void GuestAdditions::syncGK1UI() const { const reg_t bars[] = { _segMan->findObjectByName("musicBar"), _segMan->findObjectByName("soundBar") }; for (int i = 0; i < ARRAYSIZE(bars); ++i) { const reg_t barId = bars[i]; if (!barId.isNull()) { // Resetting the position to 0 causes the bar to refresh its // position when it next draws writeSelectorValue(_segMan, barId, SELECTOR(position), 0); // The `signal` property indicates bar visibility (for some // reason, the normal `-info-` flag is not used) if (readSelectorValue(_segMan, barId, SELECTOR(signal)) & 0x20) { // `show` pulls a new value from the underlying sound object // and refreshes the bar rendering invokeSelector(barId, SELECTOR(show)); } } } }