Ejemplo n.º 1
0
void Screen::addHistLine()
{
  // add line to history buffer
  // we have to take care about scrolling, too...

  if (hasScroll())
  {
    int oldHistLines = hist->getLines();

    hist->addCellsVector(screenLines[0]);
    hist->addLine( lineProperties[0] & LINE_WRAPPED );

    int newHistLines = hist->getLines();

    bool beginIsTL = (sel_begin == sel_TL);

    // If the history is full, increment the count
    // of dropped lines
    if ( newHistLines == oldHistLines )
        _droppedLines++;

    // Adjust selection for the new point of reference
    if (newHistLines > oldHistLines)
    {
       if (sel_begin != -1)
       {
          sel_TL += columns;
          sel_BR += columns;
       }
    }

    if (sel_begin != -1)
    {
       // Scroll selection in history up
       int top_BR = loc(0, 1+newHistLines);

       if (sel_TL < top_BR)
          sel_TL -= columns;

       if (sel_BR < top_BR)
          sel_BR -= columns;

       if (sel_BR < 0)
       {
          clearSelection();
       }
       else
       {
          if (sel_TL < 0)
             sel_TL = 0;
       }

       if (beginIsTL)
          sel_begin = sel_TL;
       else
          sel_begin = sel_BR;
    }
  }

}
Ejemplo n.º 2
0
int HistoryScroll::startOfLine(int lineno)
{
    if (lineno <= 0) return 0;
    if (!hasScroll()) return 0;
    if (lineno <= getLines())
    {   int res;
        index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int));
        return res;
    }
    return cells.len();
}
Ejemplo n.º 3
0
void HistoryBuffer::add(const unsigned char* bytes, int len)
{   int rc;
    assert(hasScroll());
    rc = lseek(ion,length,SEEK_SET);
    if (rc < 0) {
        perror("HistoryBuffer::add.seek");
        setScroll(FALSE);
        return;
    }
    rc = write(ion,bytes,len);
    if (rc < 0) {
        perror("HistoryBuffer::add.write");
        setScroll(FALSE);
        return;
    }
    length += rc;
}
Ejemplo n.º 4
0
void HistoryBuffer::get(unsigned char* bytes, int len, int loc)
{   int rc;
    assert(hasScroll());
    if (loc < 0 || len < 0 || loc + len > length)
        fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc);
    rc = lseek(ion,loc,SEEK_SET);
    if (rc < 0) {
        perror("HistoryBuffer::get.seek");
        setScroll(FALSE);
        return;
    }
    rc = read(ion,bytes,len);
    if (rc < 0) {
        perror("HistoryBuffer::get.read");
        setScroll(FALSE);
        return;
    }
}
Ejemplo n.º 5
0
void HistoryBuffer::setScroll(bool on)
{
    if (on == hasScroll()) return;

    if (on)
    {
        assert( ion < 0 );
        assert( length == 0);
        char* tmpDir = getenv("TMPDIR");
        char* tmpFilePath = 0;
        if (tmpDir && *tmpDir != '\0') {
            tmpFilePath = new char[strlen(tmpDir) + strlen("/opie-console-HistoryBuffer-XXXXXX") + 1];
            strcpy(tmpFilePath, tmpDir);
            free(tmpDir);
        } else {
            tmpFilePath = new char[strlen("/tmp/opie-console-HistoryBuffer-XXXXXX") + 1];
            strcpy(tmpFilePath, "/tmp");
        }
        strcat(tmpFilePath, "/opie-console-HistoryBuffer-XXXXXX");
        mode_t currUmask = umask(S_IRWXO | S_IRWXG);
        int tmpfd = mkstemp(tmpFilePath);
        delete [] tmpFilePath;
        umask(currUmask);
        if (tmpfd == -1) {
            perror("konsole: cannot open temp file.\n");
            return;
        }
        ion = dup(tmpfd);
        if (ion<0)
            perror("konsole: cannot dup temp file.\n");
        close(tmpfd);
    }
    else
    {
        assert( ion >= 0 );
        close(ion);
        ion    = -1;
        length = 0;
    }
}
Ejemplo n.º 6
0
void HistoryScroll::addLine()
{
    if (!hasScroll()) return;
    int locn = cells.len();
    index.add((unsigned char*)&locn,sizeof(int));
}
Ejemplo n.º 7
0
void HistoryScroll::addCells(ca text[], int count)
{
    if (!hasScroll()) return;
    cells.add((unsigned char*)text,count*sizeof(ca));
}
Ejemplo n.º 8
0
void HistoryScroll::getCells(int lineno, int colno, int count, ca res[])
{
    assert(hasScroll());
    cells.get((unsigned char*)res,count*sizeof(ca),startOfLine(lineno)+colno*sizeof(ca));
}
Ejemplo n.º 9
0
int HistoryScroll::getLineLen(int lineno)
{
    if (!hasScroll()) return 0;
    return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(ca);
}
Ejemplo n.º 10
0
int HistoryScroll::getLines()
{
    if (!hasScroll()) return 0;
    return index.len() / sizeof(int);
}
Ejemplo n.º 11
0
void Animation::update() {
	Scene &scene = _vm->_game->_scene;
	Palette &palette = *_vm->_palette;

	if (_header._manualFlag) {
		int spriteListIndex = _spriteListIndexes[_header._spritesIndex];
		int newIndex = -1;

		for (uint idx = _oldFrameEntry; idx < _frameEntries.size(); ++idx) {
			if (_frameEntries[idx]._frameNumber > _currentFrame)
				break;
			if (_frameEntries[idx]._spriteSlot._spritesIndex == spriteListIndex)
				newIndex = _frameEntries[idx]._spriteSlot._frameNumber;
		}

		if (newIndex >= 0)
			loadFrame(newIndex);
	}

	// If it's not time for the next frame, then exit
	if (_vm->_game->_scene._frameStartTime < _nextFrameTimer)
		return;

	for (uint idx = 0; idx < scene._spriteSlots.size(); ++idx) {
		if (scene._spriteSlots[idx]._seqIndex >= 0x80)
			scene._spriteSlots[idx]._flags = IMG_ERASE;
	}

	// Validate the current frame
	if (_currentFrame >= (int)_miscEntries.size()) {
		// Is the animation allowed to be repeated?
		if (_resetFlag) {
			_currentFrame = 0;
			_oldFrameEntry = 0;
		} else {
			_freeFlag = true;
			return;
		}
	}

	// Handle executing any sound command for this frame
	AnimMiscEntry &misc = _miscEntries[_currentFrame];
	if (misc._soundId)
		_vm->_sound->command(misc._soundId);

	// Handle any screen scrolling
	if (hasScroll()) {
		scene._backgroundSurface.scrollX(_header._scrollPosition.x);
		scene._backgroundSurface.scrollY(_header._scrollPosition.y);
		scene._spriteSlots.fullRefresh();
	}

	// Handle any offset adjustment for sprites as of this frame
	bool paChanged = false;
	if (scene._posAdjust.x != misc._posAdjust.x) {
		scene._posAdjust.x = misc._posAdjust.x;
		paChanged = true;
	}
	if (scene._posAdjust.y != misc._posAdjust.y) {
		scene._posAdjust.y = misc._posAdjust.y;
		paChanged = true;
	}

	if (paChanged) {
		int newIndex = scene._spriteSlots.add();
		scene._spriteSlots[newIndex]._seqIndex = -1;
		scene._spriteSlots[newIndex]._flags = IMG_REFRESH;
	}

	// Main frame animation loop - frames get animated by being placed, as necessary, into the
	// main sprite slot array
	while ((uint)_oldFrameEntry < _frameEntries.size()) {
		if (_frameEntries[_oldFrameEntry]._frameNumber > _currentFrame)
			break;
		else if (_frameEntries[_oldFrameEntry]._frameNumber == _currentFrame) {
			// Found the correct frame
			int spriteSlotIndex = 0;
			int index = 0;

			for (;;) {
				if ((spriteSlotIndex == 0) && (index < (int)scene._spriteSlots.size())) {
					int seqIndex = _frameEntries[_oldFrameEntry]._seqIndex - scene._spriteSlots[index]._seqIndex;
					if (seqIndex == 0x80) {
						if (scene._spriteSlots[index] == _frameEntries[_oldFrameEntry]._spriteSlot) {
							scene._spriteSlots[index]._flags = IMG_STATIC;
							spriteSlotIndex = -1;
						}
					}
					++index;
					continue;
				}

				if (spriteSlotIndex == 0) {
					int slotIndex = scene._spriteSlots.add();
					SpriteSlot &slot = scene._spriteSlots[slotIndex];
					slot.copy(_frameEntries[_oldFrameEntry]._spriteSlot);
					slot._seqIndex = _frameEntries[_oldFrameEntry]._seqIndex + 0x80;

					SpriteAsset &spriteSet = *scene._sprites[
						scene._spriteSlots[slotIndex]._spritesIndex];
					slot._flags = spriteSet.isBackground() ? IMG_DELTA : IMG_UPDATE;
				}
				break;
			}
		}

		++_oldFrameEntry;
	}

	// Handle the display of any messages
	for (uint idx = 0; idx < _messages.size(); ++idx) {
		if (_messages[idx]._kernelMsgIndex >= 0) {
			// Handle currently active message
			if ((_currentFrame < _messages[idx]._startFrame) || (_currentFrame > _messages[idx]._endFrame)) {
				scene._kernelMessages.remove(_messages[idx]._kernelMsgIndex);
				_messages[idx]._kernelMsgIndex = -1;
				--_messageCtr;
			}
		} else if ((_currentFrame >= _messages[idx]._startFrame) && (_currentFrame <= _messages[idx]._endFrame)) {
			// Start displaying the message
			AnimMessage &me = _messages[idx];

			if (_flags & ANIMFLAG_ANIMVIEW) {
				_rgbResult = palette._paletteUsage.checkRGB(me._rgb1, -1, true, &_palIndex1);
				_rgbResult = palette._paletteUsage.checkRGB(me._rgb2, _rgbResult, true, &_palIndex2);

				// Update the palette with the two needed colors
				int palStart = MIN(_palIndex1, _palIndex2);
				int palCount = ABS(_palIndex2 - _palIndex1) + 1;
				palette.setPalette(&palette._mainPalette[palStart * 3], palStart, palCount);
			} else {
				// The color index to use is dependant on how many messages are currently on-screen
				switch (_messageCtr) {
				case 1:
					_palIndex1 = 252;
					break;
				case 2:
					_palIndex1 = 16;
					break;
				default:
					_palIndex1 = 250;
					break;
				}
				_palIndex2 = _palIndex1 + 1;

				_vm->_palette->setEntry(_palIndex1, me._rgb1[0], me._rgb1[1], me._rgb1[2]);
				_vm->_palette->setEntry(_palIndex2, me._rgb2[0], me._rgb2[1], me._rgb2[2]);
			}

			// Add a kernel message to display the given text
			me._kernelMsgIndex = scene._kernelMessages.add(me._pos,
				_palIndex1 | (_palIndex2 << 8),
				0, 0, INDEFINITE_TIMEOUT, me._msg);
			assert(me._kernelMsgIndex >= 0);
			++_messageCtr;

			// If there's an accompanying sound, also play it
			if (me._soundId > 0)
				_vm->_audio->playSound(me._soundId - 1);
		}
	}

	// Move to the next frame
	_currentFrame++;
	if (_currentFrame >= (int)_miscEntries.size()) {
		// Animation is complete
		if (_trigger != 0) {
			_vm->_game->_trigger = _trigger;
			_vm->_game->_triggerMode = _triggerMode;

			if (_triggerMode != SEQUENCE_TRIGGER_DAEMON) {
				// Copy the noun list
				scene._action._activeAction = _actionDetails;
			}
		}
	}

	int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1);
	_nextFrameTimer = _vm->_game->_scene._frameStartTime + _miscEntries[frameNum]._numTicks;
}
Ejemplo n.º 12
0
/**
 * Initialises and loads the data of an animation
 */
void MadsAnimation::initialise(const Common::String &filename, uint16 flags, M4Surface *surface, M4Surface *depthSurface) {
	MadsPack anim(filename.c_str(), _vm);
	bool madsRes = filename[0] == '*';
	char buffer[20];
	int streamIndex = 1;

	// Chunk 1: header
	// header

	Common::SeekableReadStream *animStream = anim.getItemStream(0);

	int spriteListCount = animStream->readUint16LE();
	int miscEntriesCount = animStream->readUint16LE();
	int frameEntryCount = animStream->readUint16LE();
	int messagesCount = animStream->readUint16LE();
	animStream->skip(1);
	_flags = animStream->readByte();

	animStream->skip(2);
	_animMode = animStream->readUint16LE();
	_roomNumber = animStream->readUint16LE();
	animStream->skip(2);
	_field12 = animStream->readUint16LE() != 0;
	_spriteListIndex = animStream->readUint16LE();
	_scrollX = animStream->readSint16LE();
	_scrollY = animStream->readSint16LE();
	_scrollTicks = animStream->readUint16LE();
	animStream->skip(8);
	
	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	_interfaceFile = Common::String(buffer);

	for (int i = 0; i < 10; ++i) {
		animStream->read(buffer, FILENAME_SIZE);
		buffer[FILENAME_SIZE] = '\0';
		_spriteSetNames[i] = Common::String(buffer);
	}

	animStream->skip(81);
	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	_lbmFilename = Common::String(buffer);

	animStream->skip(365);
	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	_spritesFilename = Common::String(buffer);

	animStream->skip(48);
	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	_soundName = Common::String(buffer);

	animStream->skip(13);
	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	_dsrName = Common::String(buffer);

	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	Common::String fontResource(buffer);

	if (_animMode == 4)
		flags |= 0x4000;
	if (flags & 0x100)
		loadInterface(surface, depthSurface);

	// Initialise the reference list
	for (int i = 0; i < spriteListCount; ++i)
		_spriteListIndexes.push_back(-1);

	delete animStream;

	if (messagesCount > 0) {
		// Chunk 2
		// Following is a list of any messages for the animation

		animStream = anim.getItemStream(streamIndex++);

		for (int i = 0; i < messagesCount; ++i) {
			AnimMessage rec;
			rec.soundId = animStream->readSint16LE();
			animStream->read(rec.msg, 64);
			animStream->skip(4);
			rec.pos.x = animStream->readSint16LE();
			rec.pos.y = animStream->readSint16LE();
			rec.flags = animStream->readUint16LE();
			rec.rgb1.r = animStream->readByte() << 2;
			rec.rgb1.g = animStream->readByte() << 2;
			rec.rgb1.b = animStream->readByte() << 2;
			rec.rgb2.r = animStream->readByte() << 2;
			rec.rgb2.g = animStream->readByte() << 2;
			rec.rgb2.b = animStream->readByte() << 2;
			animStream->skip(2);	// Space for kernelMsgIndex
			rec.kernelMsgIndex = -1;
			animStream->skip(6);
			rec.startFrame = animStream->readUint16LE();
			rec.endFrame = animStream->readUint16LE();
			animStream->skip(2);

			_messages.push_back(rec);
		}

		delete animStream;
	}

	if (frameEntryCount > 0) {
		// Chunk 3: animation frame info
		animStream = anim.getItemStream(streamIndex++);

		for (int i = 0; i < frameEntryCount; i++) {
			AnimFrameEntry rec;
			rec.frameNumber = animStream->readUint16LE();
			rec.seqIndex = animStream->readByte();
			rec.spriteSlot.spriteListIndex = animStream->readByte();
			rec.spriteSlot.frameNumber = animStream->readUint16LE();
			rec.spriteSlot.xp = animStream->readSint16LE();
			rec.spriteSlot.yp = animStream->readSint16LE();
			rec.spriteSlot.depth = animStream->readSByte();
			rec.spriteSlot.scale = (int8)animStream->readByte();

			_frameEntries.push_back(rec);
		}

		delete animStream;
	}

	if (miscEntriesCount > 0) {
		// Chunk 4: Misc Data
		animStream = anim.getItemStream(streamIndex);

		for (int i = 0; i < miscEntriesCount; ++i) {
			AnimMiscEntry rec;
			rec.soundNum = animStream->readByte();
			rec.msgIndex = animStream->readSByte();
			rec.numTicks = animStream->readUint16LE();
			rec.posAdjust.x = animStream->readUint16LE();
			rec.posAdjust.y = animStream->readUint16LE();
			animStream->readUint16LE();

			_miscEntries.push_back(rec);
		}

		delete animStream;
	}

	// If the animation specifies a font, then load it for access
	if (_flags & ANIM_CUSTOM_FONT) {
		Common::String fontName;
		if (madsRes)
			fontName += "*";
		fontName += fontResource;

		if (fontName != "")
			_font = _vm->_font->getFont(fontName.c_str());
		else
			warning("Attempted to set a font with an empty name");
	}

	// If a speech file is specified, then load it
	if (!_dsrName.empty())
		_vm->_sound->loadDSRFile(_dsrName.c_str());

	// Load all the sprite sets for the animation
	for (int i = 0; i < spriteListCount; ++i) {
		if (_field12 && (i == _spriteListIndex))
			// Skip over field, since it's manually loaded		
			continue;

		_spriteListIndexes[i] = _view->_spriteSlots.addSprites(_spriteSetNames[i].c_str());
	}


	if (_field12) {
		Common::String resName;
		if (madsRes)
			resName += "*";
		resName += _spriteSetNames[_spriteListIndex];
		
		_spriteListIndexes[_spriteListIndex] = _view->_spriteSlots.addSprites(resName.c_str());
	}

	// TODO: Unknown section about handling sprite set list combined with messages size

	// TODO: The original has two separate loops for the loop below based on _animMode == 4. Is it
	// perhaps that in that mode the sprite frames has a different format..?

	// Remap the sprite list index fields from the initial value to the indexes of the loaded
	// sprite sets for the animation
	for (uint i = 0; i < _frameEntries.size(); ++i)  {
		int idx = _frameEntries[i].spriteSlot.spriteListIndex;
		_frameEntries[i].spriteSlot.spriteListIndex = _spriteListIndexes[idx];
	}

	if (hasScroll())
		_nextScrollTimer = _madsVm->_currentTimer + _scrollTicks;
}
Ejemplo n.º 13
0
void MadsAnimation::update() {
	if (_field12) {
		int spriteListIndex = _spriteListIndexes[_spriteListIndex];
		int newIndex = -1;
		
		for (uint idx = _oldFrameEntry; idx < _frameEntries.size(); ++idx) {
			if (_frameEntries[idx].frameNumber > _currentFrame)
				break;
			if (_frameEntries[idx].spriteSlot.spriteListIndex == spriteListIndex)
				newIndex = _frameEntries[idx].spriteSlot.frameNumber;
		}

		if (newIndex >= 0)
			load1(newIndex);
	}

	// Check for scroll change
	bool screenChanged = false;

	// Handle any scrolling of the screen surface
	if (hasScroll() && (_madsVm->_currentTimer >= _nextScrollTimer)) {
		_view->_bgSurface->scrollX(_scrollX);
		_view->_bgSurface->scrollY(_scrollY);

		_nextScrollTimer = _madsVm->_currentTimer + _scrollTicks;
		screenChanged = true;
	}

	// If it's not time for the next frame, then exit
	if (_madsVm->_currentTimer < _nextFrameTimer) {
		if (screenChanged)
			_view->_spriteSlots.fullRefresh();
		return;
	}

	// Loop checks for any prior animation sprite slots to be expired
	for (int slotIndex = 0; slotIndex < _view->_spriteSlots.startIndex; ++slotIndex) {
		if (_view->_spriteSlots[slotIndex].seqIndex >= 0x80) {
			// Flag the frame as animation sprite slot
			_view->_spriteSlots[slotIndex].spriteType = EXPIRED_SPRITE;
		}
	}

	// Validate the current frame
	if (_currentFrame >= (int)_miscEntries.size()) {
		// Is the animation allowed to be repeated?
		if (_resetFlag) {
			_currentFrame = 0;
			_oldFrameEntry = 0;
		} else {
			_freeFlag = true;
			return;
		}
	}

	// Handle starting any sound for this frame
	AnimMiscEntry &misc = _miscEntries[_currentFrame];
	if (misc.soundNum)
		_vm->_sound->playSound(misc.soundNum);

	// Handle any offset adjustment for sprites as of this frame
	if (_view->_posAdjust.x != misc.posAdjust.x) {
		_view->_posAdjust.x = misc.posAdjust.x;
		screenChanged = true;
	}
	if (_view->_posAdjust.y != misc.posAdjust.y) {
		_view->_posAdjust.y = misc.posAdjust.y;
		screenChanged = true;
	}


	if (screenChanged) {
		// Signal the entire screen needs refreshing
		_view->_spriteSlots.fullRefresh();
	}

	int spriteSlotsMax = _view->_spriteSlots.startIndex;

	// Main frame animation loop - frames get animated by being placed, as necessary, into the
	// main sprite slot array
	while ((uint)_oldFrameEntry < _frameEntries.size()) {
		if (_frameEntries[_oldFrameEntry].frameNumber > _currentFrame)
			break;
		else if (_frameEntries[_oldFrameEntry].frameNumber == _currentFrame) {
			// Found the correct frame 
			int spriteSlotIndex = 0;
			int index = 0;

			for (;;) {
				if ((spriteSlotIndex == 0) && (index < spriteSlotsMax)) {
					int seqIndex = _frameEntries[_oldFrameEntry].seqIndex - _view->_spriteSlots[index].seqIndex;
					if (seqIndex == 0x80) {
						if (_view->_spriteSlots[index] == _frameEntries[_oldFrameEntry].spriteSlot) {
							_view->_spriteSlots[index].spriteType = SPRITE_ZERO;
							spriteSlotIndex = -1;
						}
					}
					++index;
					continue;
				} 
				
				if (spriteSlotIndex == 0) {
					int slotIndex = _view->_spriteSlots.getIndex();
					MadsSpriteSlot &slot = _view->_spriteSlots[slotIndex];
					slot.copy(_frameEntries[_oldFrameEntry].spriteSlot);
					slot.seqIndex = _frameEntries[_oldFrameEntry].seqIndex + 0x80;
					
					SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(
						_view->_spriteSlots[slotIndex].spriteListIndex);
					slot.spriteType = spriteSet.isBackground() ? BACKGROUND_SPRITE : FOREGROUND_SPRITE;
				}
				break;
			}
		}
		
		++_oldFrameEntry;
	}

	// Handle the display of any messages
	for (uint idx = 0; idx < _messages.size(); ++idx) {
		if (_messages[idx].kernelMsgIndex >= 0) {
			// Handle currently active message
			if ((_currentFrame < _messages[idx].startFrame) || (_currentFrame > _messages[idx].endFrame)) {
				_view->_kernelMessages.remove(_messages[idx].kernelMsgIndex);
				_messages[idx].kernelMsgIndex = -1;
				--_messageCtr;
			}
		} else if ((_currentFrame >= _messages[idx].startFrame) && (_currentFrame <= _messages[idx].endFrame)) {
			// Start displaying the message
			AnimMessage &me = _messages[idx];

			// The color index to use is dependant on how many messages are currently on-screen
			uint8 colIndex;
			switch (_messageCtr) {
			case 1:
				colIndex = 252;
				break;
			case 2:
				colIndex = 16;
				break;
			default:
				colIndex = 250;
				break;
			}

			_vm->_palette->setEntry(colIndex, me.rgb1.r, me.rgb1.g, me.rgb1.b);
			_vm->_palette->setEntry(colIndex + 1, me.rgb2.r, me.rgb2.g, me.rgb2.b);

			// Add a kernel message to display the given text
			me.kernelMsgIndex = _view->_kernelMessages.add(me.pos, colIndex * 0x101 + 0x100, 0, 0, INDEFINITE_TIMEOUT, me.msg);
			assert(me.kernelMsgIndex >= 0);

			// Play the associated sound, if it exists
			if (me.soundId > 0)
				_vm->_sound->playDSRSound(me.soundId - 1, 255, false);
			++_messageCtr;
		}
	}

	// Move to the next frame
	_currentFrame++;
	if (_currentFrame >= (int)_miscEntries.size()) {
		// Animation is complete
		if (_abortTimers != 0) {
			_view->_abortTimers = _abortTimers;
			_view->_abortTimersMode = _abortMode;

			if (_abortMode != ABORTMODE_1) {
				// Copy the noun list
				if (_madsVm->_scene)
					_madsVm->scene()->_action._action = _actionNouns;
			}
		}
	}

	int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1);
	_nextFrameTimer = _madsVm->_currentTimer + _miscEntries[frameNum].numTicks;
}