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 tmpRunningWidth = readSelectorValue(_segMan, object, SELECTOR(resX)); uint16 tmpRunningHeight = readSelectorValue(_segMan, object, SELECTOR(resY)); // The above can be 0 in SCI3 (e.g. Phantasmagoria 2) if (tmpRunningWidth > 0 && tmpRunningHeight > 0) { scriptsRunningWidth = tmpRunningWidth; scriptsRunningHeight = tmpRunningHeight; } _coordAdjuster->setScriptsResolution(scriptsRunningWidth, scriptsRunningHeight); } newPlane.object = object; newPlane.pictureId = 0xFFFF; newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority)); newPlane.lastPriority = 0xFFFF; // hidden newPlane.planeOffsetX = 0; _planes.push_back(newPlane); kernelUpdatePlane(object); }
reg_t GfxCompare::canBeHereCheckRectList(const reg_t checkObject, const Common::Rect &checkRect, const List *list, const uint16 signalFlags) const { reg_t curAddress = list->first; Node *curNode = _segMan->lookupNode(curAddress); reg_t curObject; uint16 signal; Common::Rect curRect; while (curNode) { curObject = curNode->value; if (curObject != checkObject) { signal = readSelectorValue(_segMan, curObject, SELECTOR(signal)); if (!(signal & signalFlags)) { curRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft)); curRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop)); curRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight)); curRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom)); // Check if curRect is within checkRect // This behavior is slightly odd, but it's how the original SCI // engine did it: a rect cannot be contained within itself // (there is no equality). Do NOT change this to contains(), as // it breaks KQ4 early (bug #3315639). if (curRect.right > checkRect.left && curRect.left < checkRect.right && curRect.bottom > checkRect.top && curRect.top < checkRect.bottom) return curObject; } } curAddress = curNode->succ; curNode = _segMan->lookupNode(curAddress); } return NULL_REG; }
reg_t SoundCommandParser::kDoSoundSetPriority(int argc, reg_t *argv, reg_t acc) { reg_t obj = argv[0]; int16 value = argv[1].toSint16(); debugC(kDebugLevelSound, "kDoSound(setPriority): %04x:%04x, %d", PRINT_REG(obj), value); MusicEntry *musicSlot = _music->getSlot(obj); if (!musicSlot) { debugC(kDebugLevelSound, "kDoSound(setPriority): Slot not found (%04x:%04x)", PRINT_REG(obj)); return acc; } if (value == -1) { uint16 resourceId = musicSlot->resourceId; // Set priority from the song data Resource *song = _resMan->findResource(ResourceId(kResourceTypeSound, resourceId), 0); if (song->data[0] == 0xf0) _music->soundSetPriority(musicSlot, song->data[1]); else warning("kDoSound(setPriority): Attempt to unset song priority when there is no built-in value"); //pSnd->prio=0;field_15B=0 writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) & 0xFD); } else { // Scripted priority //pSnd->field_15B=1; writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) | 2); //DoSOund(0xF,hobj,w) } return acc; }
void SoundCommandParser::processInitSound(reg_t obj) { int resourceId = getSoundResourceId(obj); // Check if a track with the same sound object is already playing MusicEntry *oldSound = _music->getSlot(obj); if (oldSound) processDisposeSound(obj); MusicEntry *newSound = new MusicEntry(); newSound->resourceId = resourceId; newSound->soundObj = obj; newSound->loop = readSelectorValue(_segMan, obj, SELECTOR(loop)); newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(pri)) & 0xFF; if (_soundVersion >= SCI_VERSION_1_EARLY) newSound->volume = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX); newSound->reverb = -1; // initialize to SCI invalid, it'll be set correctly in soundInitSnd() below debugC(kDebugLevelSound, "kDoSound(init): %04x:%04x number %d, loop %d, prio %d, vol %d", PRINT_REG(obj), resourceId, newSound->loop, newSound->priority, newSound->volume); initSoundResource(newSound); _music->pushBackSlot(newSound); if (newSound->soundRes || newSound->pStreamAud) { // Notify the engine if (_soundVersion <= SCI_VERSION_0_LATE) writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized); else writeSelector(_segMan, obj, SELECTOR(nodePtr), obj); } }
// Adapted from GfxAnimate::applyGlobalScaling() void GfxFrameout::applyGlobalScaling(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 celHeight) { // Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY int16 maxScale = readSelectorValue(_segMan, itemEntry->object, SELECTOR(maxScale)); int16 maxCelHeight = (maxScale * celHeight) >> 7; reg_t globalVar2 = g_sci->getEngineState()->variables[VAR_GLOBAL][2]; // current room object int16 vanishingY = readSelectorValue(_segMan, globalVar2, SELECTOR(vanishingY)); int16 fixedPortY = planeRect.bottom - vanishingY; int16 fixedEntryY = itemEntry->y - vanishingY; if (!fixedEntryY) fixedEntryY = 1; if ((celHeight == 0) || (fixedPortY == 0)) error("global scaling panic"); itemEntry->scaleY = (maxCelHeight * fixedEntryY) / fixedPortY; itemEntry->scaleY = (itemEntry->scaleY * maxScale) / celHeight; // Make sure that the calculated value is sane if (itemEntry->scaleY < 1 /*|| itemEntry->scaleY > 128*/) itemEntry->scaleY = 128; itemEntry->scaleX = itemEntry->scaleY; // and set objects scale selectors //writeSelectorValue(_segMan, itemEntry->object, SELECTOR(scaleX), itemEntry->scaleX); //writeSelectorValue(_segMan, itemEntry->object, SELECTOR(scaleY), itemEntry->scaleY); }
void GfxAnimate::applyGlobalScaling(AnimateList::iterator entry, GfxView *view) { // Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY int16 maxScale = readSelectorValue(_s->_segMan, entry->object, SELECTOR(maxScale)); int16 celHeight = view->getHeight(entry->loopNo, entry->celNo); int16 maxCelHeight = (maxScale * celHeight) >> 7; reg_t globalVar2 = _s->variables[VAR_GLOBAL][2]; // current room object int16 vanishingY = readSelectorValue(_s->_segMan, globalVar2, SELECTOR(vanishingY)); int16 fixedPortY = _ports->getPort()->rect.bottom - vanishingY; int16 fixedEntryY = entry->y - vanishingY; if (!fixedEntryY) fixedEntryY = 1; if ((celHeight == 0) || (fixedPortY == 0)) error("global scaling panic"); entry->scaleY = ( maxCelHeight * fixedEntryY ) / fixedPortY; entry->scaleY = (entry->scaleY * 128) / celHeight; entry->scaleX = entry->scaleY; // and set objects scale selectors writeSelectorValue(_s->_segMan, entry->object, SELECTOR(scaleX), entry->scaleX); writeSelectorValue(_s->_segMan, entry->object, SELECTOR(scaleY), entry->scaleY); }
reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) { reg_t obj = argv[0]; SegManager *segMan = s->_segMan; if (readSelectorValue(segMan, obj, SELECTOR(type)) == SCI_EVENT_KEYBOARD) { // Keyboard uint16 message = readSelectorValue(segMan, obj, SELECTOR(message)); uint16 eventType = SCI_EVENT_DIRECTION; // Check if the game is using cursor views. These games allowed control // of the mouse cursor via the keyboard controls (the so called // "PseudoMouse" functionality in script 933). if (g_sci->_features->detectSetCursorType() == SCI_VERSION_1_1) eventType |= SCI_EVENT_KEYBOARD; for (int i = 0; i < 9; i++) { if (keyToDirMap[i].key == message) { writeSelectorValue(segMan, obj, SELECTOR(type), eventType); writeSelectorValue(segMan, obj, SELECTOR(message), keyToDirMap[i].direction); return TRUE_REG; // direction mapped } } return NULL_REG; // unknown direction } return s->r_acc; // no keyboard event to map, leave accumulator unchanged }
reg_t GfxCompare::kernelCantBeHere32(const reg_t curObject, const reg_t listReference) const { // Most of SCI32 graphics code converts rects from the VM to exclusive // rects before operating on them, but this call leverages SCI16 engine // code that operates on inclusive rects, so the rect's bottom-right // point is not modified like in other SCI32 kernel calls Common::Rect checkRect; // At least LSL6 hires passes invalid rectangles which trigger the // isValidRect assertion in the Rect constructor; this is avoided by // assigning the properties after construction and then testing the // rect for validity ourselves here. SSCI does not care about whether // or not the rects are valid checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft)); checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop)); checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight)); checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom)); if (!checkRect.isValidRect()) { return make_reg(0, 0); } uint16 result = 0; uint16 signal = readSelectorValue(_segMan, curObject, SELECTOR(signal)); const uint16 signalFlags = kSignalIgnoreActor | kSignalHidden; if ((signal & signalFlags) == 0) { List *list = _segMan->lookupList(listReference); if (!list) { error("kCantBeHere called with non-list as parameter"); } result = !canBeHereCheckRectList(curObject, checkRect, list, signalFlags).isNull(); } return make_reg(0, result); }
void GfxCoordAdjuster32::kernelGlobalToLocal(int16 &x, int16 &y, reg_t planeObject) { uint16 planeTop = readSelectorValue(_segMan, planeObject, SELECTOR(top)); uint16 planeLeft = readSelectorValue(_segMan, planeObject, SELECTOR(left)); y -= planeTop; x -= planeLeft; }
Common::Rect GfxCompare::getNSRect(reg_t object) { 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)); return nsRect; }
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 GfxCompare::kernelBaseSetter(reg_t object) { if (lookupSelector(_segMan, object, SELECTOR(brLeft), NULL, NULL) == kSelectorVariable) { int16 x = readSelectorValue(_segMan, object, SELECTOR(x)); int16 y = readSelectorValue(_segMan, object, SELECTOR(y)); int16 z = (SELECTOR(z) > -1) ? readSelectorValue(_segMan, object, SELECTOR(z)) : 0; int16 yStep = readSelectorValue(_segMan, object, SELECTOR(yStep)); GuiResourceId viewId = readSelectorValue(_segMan, object, SELECTOR(view)); int16 loopNo = readSelectorValue(_segMan, object, SELECTOR(loop)); int16 celNo = readSelectorValue(_segMan, object, SELECTOR(cel)); uint16 scaleSignal = 0; if (getSciVersion() >= SCI_VERSION_1_1) scaleSignal = readSelectorValue(_segMan, object, SELECTOR(scaleSignal)); Common::Rect celRect; GfxView *tmpView = _cache->getView(viewId); if (!tmpView->isScaleable()) scaleSignal = 0; if (scaleSignal & kScaleSignalDoScaling) { celRect = getNSRect(object); } else { tmpView->getCelRect(loopNo, celNo, x, y, z, celRect); } celRect.bottom = y + 1; celRect.top = celRect.bottom - yStep; writeSelectorValue(_segMan, object, SELECTOR(brLeft), celRect.left); writeSelectorValue(_segMan, object, SELECTOR(brRight), celRect.right); writeSelectorValue(_segMan, object, SELECTOR(brTop), celRect.top); writeSelectorValue(_segMan, object, SELECTOR(brBottom), celRect.bottom); } }
void GuestAdditions::syncGK1StartupVolumeFromScummVM(const int index, const reg_t value) const { if (index == kGlobalVarGK1Music1 || index == kGlobalVarGK1Music2 || index == kGlobalVarGK1DAC1 || index == kGlobalVarGK1DAC2 || index == kGlobalVarGK1DAC3) { int16 volume; Selector selector; switch (readSelectorValue(_segMan, value, SELECTOR(type))) { case kSoundsMusicType: { volume = (ConfMan.getInt("music_volume") + 1) * MUSIC_VOLUME_MAX / Audio::Mixer::kMaxMixerVolume; selector = SELECTOR(musicVolume); break; } case kSoundsSoundType: { volume = (ConfMan.getInt("sound_volume") + 1) * MUSIC_VOLUME_MAX / Audio::Mixer::kMaxMixerVolume; selector = SELECTOR(soundVolume); break; } default: error("Unknown sound type"); } writeSelectorValue(_segMan, value, selector, volume); writeSelectorValue(_segMan, value, selector, volume); } }
void GuestAdditions::syncGK1VolumeFromScummVM(const int16 musicVolume, const int16 dacVolume) const { 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); const int16 type = readSelectorValue(_segMan, sound->value, SELECTOR(type)); int16 volume; if (type == kSoundsMusicType) { volume = ConfMan.getBool("mute") ? 0 : musicVolume; writeSelectorValue(_segMan, sound->value, SELECTOR(musicVolume), musicVolume); } else if (type == kSoundsSoundType) { volume = dacVolume; writeSelectorValue(_segMan, sound->value, SELECTOR(soundVolume), dacVolume); } else { error("Unknown sound type %d", type); } // `setVolume` will set the `vol` property on the sound object; // if it did not do this, an invocation of the `setVol` selector // would need to be here (though doing so would result in // recursion, so don't) g_sci->_soundCmd->setVolume(sound->value, volume); soundId = sound->succ; } } }
void GfxMacIconBar::drawIcons() { // Draw the icons to the bottom of the screen byte *pal = new byte[256 * 4]; Graphics::PictDecoder *pict = new Graphics::PictDecoder(Graphics::PixelFormat::createFormatCLUT8()); uint32 lastX = 0; for (uint32 i = 0; i < _iconBarObjects.size(); i++) { uint32 iconIndex = readSelectorValue(g_sci->getEngineState()->_segMan, _iconBarObjects[i], SELECTOR(iconIndex)); Resource *res = g_sci->getResMan()->findResource(ResourceId(kResourceTypeMacIconBarPictN, iconIndex + 1), false); if (!res) continue; Common::SeekableReadStream *stream = new Common::MemoryReadStream(res->data, res->size); Graphics::Surface *surf = pict->decodeImage(stream, pal); remapColors(surf, pal); g_system->copyRectToScreen((byte *)surf->pixels, surf->pitch, lastX, 200, MIN<uint32>(surf->w, 320 - lastX), surf->h); lastX += surf->w; surf->free(); delete surf; delete stream; } delete pict; delete[] pal; }
void GfxAnimate::restoreAndDelete(int argc, reg_t *argv) { AnimateList::iterator it; const AnimateList::iterator end = _list.end(); // This has to be done in a separate loop. At least in sq1 some .dispose // modifies FIXEDLOOP flag in signal for another object. In that case we // would overwrite the new signal with our version of the old signal. for (it = _list.begin(); it != end; ++it) { // Finally update signal writeSelectorValue(_s->_segMan, it->object, SELECTOR(signal), it->signal); } for (it = _list.legacy_reverse_begin(); it != end; --it) { // We read out signal here again, this is not by accident but to ensure // that we got an up-to-date signal it->signal = readSelectorValue(_s->_segMan, it->object, SELECTOR(signal)); if ((it->signal & (kSignalNoUpdate | kSignalRemoveView)) == 0) { _paint16->bitsRestore(readSelector(_s->_segMan, it->object, SELECTOR(underBits))); writeSelectorValue(_s->_segMan, it->object, SELECTOR(underBits), 0); } if (it->signal & kSignalDisposeMe) { // Call .delete_ method of that object invokeSelector(_s, it->object, SELECTOR(delete_), argc, argv, 0); } } }
reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) { SegManager *segMan = s->_segMan; reg_t object = argv[0]; List *list; Node *node; int script; int numSynonyms = 0; Vocabulary *voc = g_sci->getVocabulary(); // Only SCI0-SCI1 EGA games had a parser. In newer versions, this is a stub if (getSciVersion() > SCI_VERSION_1_EGA_ONLY) return s->r_acc; voc->clearSynonyms(); list = s->_segMan->lookupList(readSelector(segMan, object, SELECTOR(elements))); node = s->_segMan->lookupNode(list->first); while (node) { reg_t objpos = node->value; int seg; script = readSelectorValue(segMan, objpos, SELECTOR(number)); seg = s->_segMan->getScriptSegment(script); if (seg > 0) numSynonyms = s->_segMan->getScript(seg)->getSynonymsNr(); if (numSynonyms) { const byte *synonyms = s->_segMan->getScript(seg)->getSynonyms(); if (synonyms) { debugC(kDebugLevelParser, "Setting %d synonyms for script.%d", numSynonyms, script); if (numSynonyms > 16384) { error("Segtable corruption: script.%03d has %d synonyms", script, numSynonyms); /* We used to reset the corrupted value here. I really don't think it's appropriate. * Lars */ } else for (int i = 0; i < numSynonyms; i++) { synonym_t tmp; tmp.replaceant = READ_LE_UINT16(synonyms + i * 4); tmp.replacement = READ_LE_UINT16(synonyms + i * 4 + 2); voc->addSynonym(tmp); } } else warning("Synonyms of script.%03d were requested, but script is not available", script); } node = s->_segMan->lookupNode(node->succ); } debugC(kDebugLevelParser, "A total of %d synonyms are active now.", numSynonyms); return s->r_acc; }
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; }
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); }
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; }
reg_t GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) { Common::Rect checkRect; uint16 result; checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft)); checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop)); checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight)); checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom)); uint16 signal = readSelectorValue(_segMan, curObject, SELECTOR(signal)); if (!checkRect.isValidRect()) { // can occur in Iceman and Mother Goose - HACK? TODO: is this really occuring in sierra sci? check this warning("kCan(t)BeHere - invalid rect %d, %d -> %d, %d", checkRect.left, checkRect.top, checkRect.right, checkRect.bottom); return NULL_REG; // this means "can be here" } Common::Rect adjustedRect = _coordAdjuster->onControl(checkRect); uint16 controlMask = readSelectorValue(_segMan, curObject, SELECTOR(illegalBits)); result = isOnControl(GFX_SCREEN_MASK_CONTROL, adjustedRect) & controlMask; if ((!result) && (signal & (kSignalIgnoreActor | kSignalRemoveView)) == 0) { List *list = _segMan->lookupList(listReference); if (!list) error("kCanBeHere called with non-list as parameter"); return canBeHereCheckRectList(curObject, checkRect, list, kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate); } return make_reg(0, result); }
int SoundCommandParser::getSoundResourceId(reg_t obj) { int resourceId = obj.getSegment() ? (int)readSelectorValue(_segMan, obj, SELECTOR(number)) : -1; // Modify the resourceId for the Windows versions that have an alternate MIDI soundtrack, like SSCI did. if (g_sci && g_sci->_features->useAltWinGMSound()) { // Check if the alternate MIDI song actually exists... // There are cases where it just doesn't exist (e.g. SQ4, room 530 - // bug #3392767). In these cases, use the DOS tracks instead. if (resourceId && _resMan->testResource(ResourceId(kResourceTypeSound, resourceId + 1000))) resourceId += 1000; } return resourceId; }
void GfxAnimate::updateScreen(byte oldPicNotValid) { AnimateList::iterator it; const AnimateList::iterator end = _list.end(); Common::Rect lsRect; Common::Rect workerRect; for (it = _list.begin(); it != end; ++it) { if (it->showBitsFlag || !(it->signal & (kSignalRemoveView | kSignalNoUpdate) || (!(it->signal & kSignalRemoveView) && (it->signal & kSignalNoUpdate) && oldPicNotValid))) { lsRect.left = readSelectorValue(_s->_segMan, it->object, SELECTOR(lsLeft)); lsRect.top = readSelectorValue(_s->_segMan, it->object, SELECTOR(lsTop)); lsRect.right = readSelectorValue(_s->_segMan, it->object, SELECTOR(lsRight)); lsRect.bottom = readSelectorValue(_s->_segMan, it->object, SELECTOR(lsBottom)); workerRect = lsRect; workerRect.clip(it->celRect); if (!workerRect.isEmpty()) { workerRect = lsRect; workerRect.extend(it->celRect); } else { _paint16->bitsShow(lsRect); workerRect = it->celRect; } writeSelectorValue(_s->_segMan, it->object, SELECTOR(lsLeft), it->celRect.left); writeSelectorValue(_s->_segMan, it->object, SELECTOR(lsTop), it->celRect.top); writeSelectorValue(_s->_segMan, it->object, SELECTOR(lsRight), it->celRect.right); writeSelectorValue(_s->_segMan, it->object, SELECTOR(lsBottom), it->celRect.bottom); // may get used for debugging //_paint16->frameRect(workerRect); _paint16->bitsShow(workerRect); if (it->signal & kSignalHidden) it->signal |= kSignalRemoveView; } } // use this for debug purposes // _screen->copyToScreen(); }
void GfxFrameout::kernelDeletePlane(reg_t object) { deletePlaneItems(object); deletePlanePictures(object); for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { if (it->object == object) { _planes.erase(it); Common::Rect planeRect; planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top)); planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left)); planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)); planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)); _coordAdjuster->fromScriptToDisplay(planeRect.top, planeRect.left); _coordAdjuster->fromScriptToDisplay(planeRect.bottom, planeRect.right); // Blackout removed plane rect _paint32->fillRect(planeRect, 0); return; } } }
reg_t kSort(EngineState *s, int argc, reg_t *argv) { SegManager *segMan = s->_segMan; reg_t source = argv[0]; reg_t dest = argv[1]; reg_t order_func = argv[2]; int input_size = (int16)readSelectorValue(segMan, source, SELECTOR(size)); reg_t input_data = readSelector(segMan, source, SELECTOR(elements)); reg_t output_data = readSelector(segMan, dest, SELECTOR(elements)); List *list; Node *node; if (!input_size) return s->r_acc; if (output_data.isNull()) { list = s->_segMan->allocateList(&output_data); list->first = list->last = NULL_REG; writeSelector(segMan, dest, SELECTOR(elements), output_data); } writeSelectorValue(segMan, dest, SELECTOR(size), input_size); list = s->_segMan->lookupList(input_data); node = s->_segMan->lookupNode(list->first); sort_temp_t *temp_array = (sort_temp_t *)malloc(sizeof(sort_temp_t) * input_size); int i = 0; while (node) { reg_t params[1] = { node->value }; invokeSelector(s, order_func, SELECTOR(doit), argc, argv, 1, params); temp_array[i].key = node->key; temp_array[i].value = node->value; temp_array[i].order = s->r_acc; i++; node = s->_segMan->lookupNode(node->succ); } qsort(temp_array, input_size, sizeof(sort_temp_t), sort_temp_cmp); for (i = 0;i < input_size;i++) { reg_t lNode = s->_segMan->newNode(temp_array[i].value, temp_array[i].key); addToEnd(s, output_data, lNode); } free(temp_array); return s->r_acc; }
void GfxCompare::kernelBaseSetter(reg_t object) { if (lookupSelector(_segMan, object, SELECTOR(brLeft), NULL, NULL) == kSelectorVariable) { int16 x = readSelectorValue(_segMan, object, SELECTOR(x)); int16 y = readSelectorValue(_segMan, object, SELECTOR(y)); int16 z = (SELECTOR(z) > -1) ? readSelectorValue(_segMan, object, SELECTOR(z)) : 0; int16 yStep = readSelectorValue(_segMan, object, SELECTOR(yStep)); GuiResourceId viewId = readSelectorValue(_segMan, object, SELECTOR(view)); int16 loopNo = readSelectorValue(_segMan, object, SELECTOR(loop)); int16 celNo = readSelectorValue(_segMan, object, SELECTOR(cel)); // HACK: Ignore invalid views for now (perhaps unimplemented text views?) if (viewId == 0xFFFF) // invalid view return; uint16 scaleSignal = 0; if (getSciVersion() >= SCI_VERSION_1_1) { scaleSignal = readSelectorValue(_segMan, object, SELECTOR(scaleSignal)); } Common::Rect celRect; GfxView *tmpView = _cache->getView(viewId); if (!tmpView->isScaleable()) scaleSignal = 0; if (scaleSignal & kScaleSignalDoScaling) { celRect = getNSRect(object); } else { if (tmpView->isSci2Hires()) tmpView->adjustToUpscaledCoordinates(y, x); tmpView->getCelRect(loopNo, celNo, x, y, z, celRect); if (tmpView->isSci2Hires()) { tmpView->adjustBackUpscaledCoordinates(celRect.top, celRect.left); tmpView->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right); } } celRect.bottom = y + 1; celRect.top = celRect.bottom - yStep; writeSelectorValue(_segMan, object, SELECTOR(brLeft), celRect.left); writeSelectorValue(_segMan, object, SELECTOR(brRight), celRect.right); writeSelectorValue(_segMan, object, SELECTOR(brTop), celRect.top); writeSelectorValue(_segMan, object, SELECTOR(brBottom), celRect.bottom); } }
void ScreenItem::update(const reg_t object) { SegManager *segMan = g_sci->getEngineState()->_segMan; const GuiResourceId view = readSelectorValue(segMan, object, SELECTOR(view)); const int16 loopNo = readSelectorValue(segMan, object, SELECTOR(loop)); const int16 celNo = readSelectorValue(segMan, object, SELECTOR(cel)); const bool updateCel = ( _celInfo.resourceId != view || _celInfo.loopNo != loopNo || _celInfo.celNo != celNo ); const bool updateBitmap = !readSelector(segMan, object, SELECTOR(bitmap)).isNull(); setFromObject(segMan, object, updateCel, updateBitmap); if (!_created) { _updated = g_sci->_gfxFrameout->getScreenCount(); } _deleted = 0; }
void GfxFrameout::kernelDeletePlane(reg_t object) { deletePlanePictures(object); for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) { if (it->object == object) { _planes.erase(it); Common::Rect planeRect; planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top)); planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left)); planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)) + 1; planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)) + 1; Common::Rect screenRect(_screen->getWidth(), _screen->getHeight()); planeRect.top = (planeRect.top * screenRect.height()) / scriptsRunningHeight; planeRect.left = (planeRect.left * screenRect.width()) / scriptsRunningWidth; planeRect.bottom = (planeRect.bottom * screenRect.height()) / scriptsRunningHeight; planeRect.right = (planeRect.right * screenRect.width()) / scriptsRunningWidth; planeRect.clip(screenRect); // we need to do this, at least in gk1 on cemetary we get bottom right -> 201, 321 // Blackout removed plane rect _paint32->fillRect(planeRect, 0); return; } } }