示例#1
0
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;
}
示例#2
0
reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) {
	List *list = s->_segMan->lookupList(argv[0]);

	Node *curNode = s->_segMan->lookupNode(list->first);
	reg_t curObject;
	Selector slc = argv[1].toUint16();

	ObjVarRef address;

	while (curNode) {
		// We get the next node here as the current node might be gone after the invoke
		reg_t nextNode = curNode->succ;
		curObject = curNode->value;

		// First, check if the target selector is a variable
		if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
			// This can only happen with 3 params (list, target selector, variable)
			if (argc != 3) {
				error("kListEachElementDo: Attempted to modify a variable selector with %d params", argc);
			} else {
				writeSelector(s->_segMan, curObject, slc, argv[2]);
			}
		} else {
			invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2);
		}

		curNode = s->_segMan->lookupNode(nextNode);
	}

	return s->r_acc;
}
示例#3
0
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);
	}
}
示例#4
0
void GuestAdditions::syncGK2UI() const {
	const reg_t sliderId = _segMan->findObjectByName("soundSlider");
	if (!sliderId.isNull() && _segMan->getObject(sliderId)->isInserted()) {
		const reg_t oldAcc = _state->r_acc;
		invokeSelector(sliderId, SELECTOR(initialOff));
		writeSelector(_segMan, sliderId, SELECTOR(x), _state->r_acc);
		_state->r_acc = oldAcc;
	}
}
示例#5
0
void CssPrettyWriter::writeRulesetStart(const TokenList &selector) {
  indent();
  
  writeSelector(selector);
  
  writeStr(" {", 2);
  newline();
  indent_size++;
}
示例#6
0
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;
}
示例#7
0
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;
}
示例#8
0
reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) {
	const reg_t listReg = argv[0];
	List *list = s->_segMan->lookupList(listReg);

	Node *curNode = s->_segMan->lookupNode(list->first);
	Selector slc = argv[1].toUint16();

	ObjVarRef address;

	++list->numRecursions;

	if (list->numRecursions >= ARRAYSIZE(list->nextNodes)) {
		error("Too much recursion in kListEachElementDo");
	}

	while (curNode) {
		// We get the next node here as the current node might be deleted by the
		// invoke. In the case that the next node is also deleted, kDeleteKey
		// needs to be able to adjust the location of the next node, which is
		// why it is stored on the list instead of on the stack
		list->nextNodes[list->numRecursions] = curNode->succ;
		reg_t curObject = curNode->value;

		// First, check if the target selector is a variable
		if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
			// This can only happen with 3 params (list, target selector, variable)
			if (argc != 3) {
				error("kListEachElementDo: Attempted to modify a variable selector with %d params", argc);
			} else {
				writeSelector(s->_segMan, curObject, slc, argv[2]);
			}
		} else {
			invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2);

			// Check if the call above leads to a game restore, in which case
			// the segment manager will be reset, and the original list will
			// be invalidated
			if (s->abortScriptProcessing == kAbortLoadGame)
				return s->r_acc;
		}

		curNode = s->_segMan->lookupNode(list->nextNodes[list->numRecursions]);
	}

	if (s->_segMan->isValidAddr(listReg, SEG_TYPE_LISTS)) {
		--list->numRecursions;
	}

	return s->r_acc;
}
示例#9
0
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);
}
示例#10
0
reg_t GuestAdditions::promptSaveRestoreTorin(EngineState *s, int argc, reg_t *argv) const {
	const bool isSave = (argc > 0 && (bool)argv[0].toSint16());
	int saveNo;

	if (isSave) {
		GUI::SaveLoadChooser dialog(_("Save game:"), _("Save"), true);
		saveNo = dialog.runModalWithCurrentTarget();
		if (saveNo != -1) {
			reg_t descriptionId = s->variables[VAR_LOCAL][1];
			reg_t dataId;
			SciArray &description = *_segMan->allocateArray(kArrayTypeString, 0, &dataId);
			Common::String descriptionString = dialog.getResultString();
			if (descriptionString.empty())
				descriptionString = dialog.createDefaultSaveDescription(saveNo - 1);
			description.fromString(descriptionString);
			writeSelector(_segMan, descriptionId, SELECTOR(data), dataId);
		}
	} else {
		if (s->_delayedRestoreGameId != -1) {
			saveNo = s->_delayedRestoreGameId;
		} else {
			GUI::SaveLoadChooser dialog(_("Restore game:"), _("Restore"), false);
			saveNo = dialog.runModalWithCurrentTarget();
		}
	}

	if (saveNo > 0) {
		// The autosave slot in ScummVM takes up slot 0, but in SCI the first
		// non-autosave save game number needs to be 0, so reduce the save
		// number here to match what would come from the normal SCI save/restore
		// dialog. There is additional special code for handling the autosave
		// game inside of kRestoreGame32.
		--saveNo;
	}

	if (saveNo != -1) {
		assert(s->variablesMax[VAR_LOCAL] > 2);
		s->variables[VAR_LOCAL][2] = make_reg(0, saveNo);
		s->variables[VAR_LOCAL][3] = make_reg(0, isSave ? 1 : 0);
	}

	return make_reg(0, saveNo != -1);
}
示例#11
0
void GfxAnimate::drawCels() {
	reg_t bitsHandle;
	AnimateList::iterator it;
	const AnimateList::iterator end = _list.end();
	_lastCastData.clear();

	for (it = _list.begin(); it != end; ++it) {
		if (!(it->signal & (kSignalNoUpdate | kSignalHidden | kSignalAlwaysUpdate))) {
			// Save background
			bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_ALL);
			writeSelector(_s->_segMan, it->object, SELECTOR(underBits), bitsHandle);

			// draw corresponding cel
			_paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
			it->showBitsFlag = true;

			if (it->signal & kSignalRemoveView)
				it->signal &= ~kSignalRemoveView;

			// Remember that entry in lastCast
			_lastCastData.push_back(*it);
		}
	}
}
示例#12
0
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;
}
示例#13
0
reg_t GfxMenu::kernelSelect(reg_t eventObject, bool pauseSound) {
	int16 eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type));
	int16 keyPress, keyModifier;
	GuiMenuItemList::iterator itemIterator = _itemList.begin();
	GuiMenuItemList::iterator itemEnd = _itemList.end();
	GuiMenuItemEntry *itemEntry = NULL;
	bool forceClaimed = false;

	switch (eventType) {
	case SCI_EVENT_KEYBOARD:
		keyPress = readSelectorValue(_segMan, eventObject, SELECTOR(message));
		keyModifier = readSelectorValue(_segMan, eventObject, SELECTOR(modifiers));
		// If tab got pressed, handle it here as if it was Ctrl-I - at least
		// sci0 also did it that way
		if (keyPress == SCI_KEY_TAB) {
			keyModifier = SCI_KEYMOD_CTRL;
			keyPress = 'i';
		}
		switch (keyPress) {
		case 0:
			break;
		case SCI_KEY_ESC:
			interactiveStart(pauseSound);
			itemEntry = interactiveWithKeyboard();
			interactiveEnd(pauseSound);
			forceClaimed = true;
			break;
		default:
			while (itemIterator != itemEnd) {
				itemEntry = *itemIterator;
				if (itemEntry->keyPress == keyPress &&
					itemEntry->keyModifier == keyModifier &&
					itemEntry->enabled)
					break;
				itemIterator++;
			}
			if (itemIterator == itemEnd)
				itemEntry = NULL;
		}
		break;

	case SCI_EVENT_SAID:
		while (itemIterator != itemEnd) {
			itemEntry = *itemIterator;

			if (!itemEntry->saidVmPtr.isNull()) {
				byte *saidSpec = _segMan->derefBulkPtr(itemEntry->saidVmPtr, 0);

				if (!saidSpec) {
					warning("Could not dereference saidSpec");
					continue;
				}

				if (said(saidSpec, 0) != SAID_NO_MATCH)
					break;
			}
			itemIterator++;
		}
		if (itemIterator == itemEnd)
			itemEntry = NULL;
		break;

	case SCI_EVENT_MOUSE_PRESS: {
		Common::Point mousePosition;
		mousePosition.x = readSelectorValue(_segMan, eventObject, SELECTOR(x));
		mousePosition.y = readSelectorValue(_segMan, eventObject, SELECTOR(y));
		if (mousePosition.y < 10) {
			interactiveStart(pauseSound);
			itemEntry = interactiveWithMouse();
			interactiveEnd(pauseSound);
			forceClaimed = true;
		}
		} break;
	}

	if (!_menuSaveHandle.isNull()) {
		_paint16->bitsRestore(_menuSaveHandle);
		// Display line inbetween menubar and actual menu
		Common::Rect menuLine = _menuRect;
		menuLine.bottom = menuLine.top + 1;
		_paint16->bitsShow(menuLine);
		_paint16->kernelGraphRedrawBox(_menuRect);
		_menuSaveHandle = NULL_REG;
	}
	if (!_barSaveHandle.isNull()) {
		_paint16->bitsRestore(_barSaveHandle);
		_paint16->bitsShow(_ports->_menuRect);
		_barSaveHandle = NULL_REG;
	}
	if (_oldPort) {
		_ports->setPort(_oldPort);
		_oldPort = NULL;
	}

	if ((itemEntry) || (forceClaimed))
		writeSelector(_segMan, eventObject, SELECTOR(claimed), make_reg(0, 1));
	if (itemEntry)
		return make_reg(0, (itemEntry->menuId << 8) | (itemEntry->id));
	return NULL_REG;
}
示例#14
0
void GfxAnimate::update() {
	reg_t bitsHandle;
	Common::Rect rect;
	AnimateList::iterator it;
	const AnimateList::iterator end = _list.end();

	// Remove all no-update cels, if requested
	for (it = _list.legacy_reverse_begin(); it != end; --it) {
		if (it->signal & kSignalNoUpdate) {
			if (!(it->signal & kSignalRemoveView)) {
				bitsHandle = readSelector(_s->_segMan, it->object, SELECTOR(underBits));
				if (_screen->_picNotValid != 1) {
					_paint16->bitsRestore(bitsHandle);
					it->showBitsFlag = true;
				} else	{
					_paint16->bitsFree(bitsHandle);
				}
				writeSelectorValue(_s->_segMan, it->object, SELECTOR(underBits), 0);
			}
			it->signal &= ~kSignalForceUpdate;
			if (it->signal & kSignalViewUpdated)
				it->signal &= ~(kSignalViewUpdated | kSignalNoUpdate);
		} else if (it->signal & kSignalStopUpdate) {
			it->signal &= ~kSignalStopUpdate;
			it->signal |= kSignalNoUpdate;
		}
	}

	// Draw always-update cels
	for (it = _list.begin(); it != end; ++it) {
		if (it->signal & kSignalAlwaysUpdate) {
			// draw corresponding cel
			_paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
			it->showBitsFlag = true;

			it->signal &= ~(kSignalStopUpdate | kSignalViewUpdated | kSignalNoUpdate | kSignalForceUpdate);
			if (!(it->signal & kSignalIgnoreActor)) {
				rect = it->celRect;
				rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, rect.top, rect.bottom - 1);
				_paint16->fillRect(rect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
			}
		}
	}

	// Saving background for all NoUpdate-cels
	for (it = _list.begin(); it != end; ++it) {
		if (it->signal & kSignalNoUpdate) {
			if (it->signal & kSignalHidden) {
				it->signal |= kSignalRemoveView;
			} else {
				it->signal &= ~kSignalRemoveView;
				if (it->signal & kSignalIgnoreActor)
					bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY);
				else
					bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_ALL);
				writeSelector(_s->_segMan, it->object, SELECTOR(underBits), bitsHandle);
			}
		}
	}

	// Draw NoUpdate cels
	for (it = _list.begin(); it != end; ++it) {
		if (it->signal & kSignalNoUpdate && !(it->signal & kSignalHidden)) {
			// draw corresponding cel
			_paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
			it->showBitsFlag = true;

			if (!(it->signal & kSignalIgnoreActor)) {
				rect = it->celRect;
				rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, rect.top, rect.bottom - 1);
				_paint16->fillRect(rect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
			}
		}
	}
}