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; } } }
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(); }
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; }
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; } }
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; } }
void HistoryScroll::addLine() { if (!hasScroll()) return; int locn = cells.len(); index.add((unsigned char*)&locn,sizeof(int)); }
void HistoryScroll::addCells(ca text[], int count) { if (!hasScroll()) return; cells.add((unsigned char*)text,count*sizeof(ca)); }
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)); }
int HistoryScroll::getLineLen(int lineno) { if (!hasScroll()) return 0; return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(ca); }
int HistoryScroll::getLines() { if (!hasScroll()) return 0; return index.len() / sizeof(int); }
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; }
/** * 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; }
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; }