void Mechanical::o_snakeBoxTrigger(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Trigger Playing Of Snake Movie", op); // Used on Mechanical Card 6043 (Weapons Rack with Snake Box) _snakeBox->playMovie(); }
/** * Main interface point for specifying player atcions */ void PlayerEvent(PLR_EVENT pEvent, const Common::Point &coOrds) { // Logging of player actions const char *actionList[] = { "PLR_PROV_WALKTO", "PLR_WALKTO", "PLR_LOOK", "PLR_ACTION", "PLR_ESCAPE", "PLR_MENU", "PLR_QUIT", "PLR_PGUP", "PLR_PGDN", "PLR_HOME", "PLR_END", "PLR_DRAG1_START", "PLR_DRAG1_END", "PLR_DRAG2_START", "PLR_DRAG2_END", "PLR_JUMP", "PLR_NOEVENT", "PLR_SAVE", "PLR_LOAD", "PLR_WHEEL_UP", "PLR_WHEEL_DOWN"}; debugC(DEBUG_BASIC, kTinselDebugActions, "%s - (%d,%d)", actionList[pEvent], coOrds.x, coOrds.y); static uint32 lastRealAction = 0; // FIXME: Avoid non-const global vars // This stuff to allow F1 key during startup. if (g_bEnableMenu && pEvent == PLR_MENU) Control(CONTROL_ON); else IncUserEvents(); if (pEvent == PLR_ESCAPE) { ++g_escEvents; ++g_leftEvents; // Yes, I do mean this } else if ((pEvent == PLR_PROV_WALKTO) || (pEvent == PLR_WALKTO) || (pEvent == PLR_LOOK) || (pEvent == PLR_ACTION)) { ++g_leftEvents; } // Only allow events if player control is on if (!ControlIsOn() && (pEvent != PLR_DRAG1_END)) return; if (TinselV2 && InventoryActive()) { int x, y; PlayfieldGetPos(FIELD_WORLD, &x, &y); EventToInventory(pEvent, Common::Point(coOrds.x - x, coOrds.y - y)); return; } switch (pEvent) { case PLR_QUIT: OpenMenu(QUIT_MENU); break; case PLR_MENU: OpenMenu(MAIN_MENU); break; case PLR_JUMP: OpenMenu(HOPPER_MENU1); break; case PLR_SAVE: OpenMenu(SAVE_MENU); break; case PLR_LOAD: OpenMenu(LOAD_MENU); break; case PLR_PROV_WALKTO: // Provisional WALKTO ! ProcessUserEvent(PROV_WALKTO, coOrds); break; case PLR_WALKTO: REAL_ACTION_CHECK; if (TinselV2 || !InventoryActive()) ProcessUserEvent(WALKTO, coOrds, PLR_SLEFT); else EventToInventory(PLR_SLEFT, coOrds); break; case PLR_ACTION: REAL_ACTION_CHECK; if (TinselV2 || !InventoryActive()) ProcessUserEvent(ACTION, coOrds, PLR_DLEFT); else EventToInventory(PLR_DLEFT, coOrds); break; case PLR_LOOK: REAL_ACTION_CHECK; if (TinselV2 || !InventoryActive()) ProcessUserEvent(LOOK, coOrds, PLR_SRIGHT); else EventToInventory(PLR_SRIGHT, coOrds); break; default: if (InventoryActive()) EventToInventory(pEvent, coOrds); break; } }
void Inter_v6::o6_playVmdOrMusic() { char fileName[128]; int16 x, y; int16 startFrame; int16 lastFrame; int16 breakKey; int16 flags; int16 palStart; int16 palEnd; uint16 palCmd; bool close; _vm->_game->_script->evalExpr(0); strncpy0(fileName, _vm->_game->_script->getResultStr(), 127); x = _vm->_game->_script->readValExpr(); y = _vm->_game->_script->readValExpr(); startFrame = _vm->_game->_script->readValExpr(); lastFrame = _vm->_game->_script->readValExpr(); breakKey = _vm->_game->_script->readValExpr(); flags = _vm->_game->_script->readValExpr(); palStart = _vm->_game->_script->readValExpr(); palEnd = _vm->_game->_script->readValExpr(); palCmd = 1 << (flags & 0x3F); debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " "paletteCmd %d (%d - %d), flags %X", fileName, x, y, startFrame, lastFrame, palCmd, palStart, palEnd, flags); close = false; if (lastFrame == -1) { close = true; } else if (lastFrame == -5) { _vm->_sound->bgStop(); return; } else if (lastFrame == -9) { if (!strchr(fileName, '.')) strcat(fileName, ".WA8"); probe16bitMusic(fileName); _vm->_sound->bgStop(); _vm->_sound->bgPlay(fileName, SOUND_WAV); return; } else if (lastFrame == -10) { _vm->_vidPlayer->primaryClose(); warning("Urban Stub: Video/Music command -10 (close video?)"); return; } else if (lastFrame < 0) { warning("Unknown Video/Music command: %d, %s", lastFrame, fileName); return; } if (startFrame == -2) { startFrame = 0; lastFrame = -1; close = false; } if ((fileName[0] != 0) && !_vm->_vidPlayer->primaryOpen(fileName, x, y, flags)) { WRITE_VAR(11, (uint32) -1); return; } if (startFrame >= 0) _vm->_vidPlayer->primaryPlay(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0, -1, false, -1, true); if (close) _vm->_vidPlayer->primaryClose(); }
/** * Add up all the object values and all the bonus points */ void HugoEngine::calcMaxScore() { debugC(1, kDebugEngine, "calcMaxScore"); _maxscore = _object->calcMaxScore() + _scheduler->calcMaxPoints(); }
/** * Update all object positions. Process object 'local' events * including boundary events and collisions */ void ObjectHandler_v3d::moveObjects() { debugC(4, kDebugObject, "moveObjects"); // Added to DOS version in order to handle mouse properly // Do special route processing _vm->_route->processRoute(); // Perform any adjustments to velocity based on special path types // and store all (visible) object baselines into the boundary file. // Don't store foreground or background objects for (int i = 0; i < _numObj; i++) { object_t *obj = &_objects[i]; // Get pointer to object seq_t *currImage = obj->currImagePtr; // Get ptr to current image if (obj->screenIndex == *_vm->_screen_p) { switch (obj->pathType) { case kPathChase: case kPathChase2: { int8 radius = obj->radius; // Default to object's radius if (radius < 0) // If radius infinity, use closer value radius = kStepDx; // Allowable motion wrt boundary int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - currImage->x1; int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - currImage->y2 - 1; if (abs(dx) <= radius) obj->vx = 0; else obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath); if (abs(dy) <= radius) obj->vy = 0; else obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath); // Set first image in sequence (if multi-seq object) switch (obj->seqNumb) { case 4: if (!obj->vx) { // Got 4 directions if (obj->vx != obj->oldvx) { // vx just stopped if (dy >= 0) obj->currImagePtr = obj->seqList[DOWN].seqPtr; else obj->currImagePtr = obj->seqList[_UP].seqPtr; } } else if (obj->vx != obj->oldvx) { if (dx > 0) obj->currImagePtr = obj->seqList[RIGHT].seqPtr; else obj->currImagePtr = obj->seqList[LEFT].seqPtr; } break; case 3: case 2: if (obj->vx != obj->oldvx) { // vx just stopped if (dx > 0) // Left & right only obj->currImagePtr = obj->seqList[RIGHT].seqPtr; else obj->currImagePtr = obj->seqList[LEFT].seqPtr; } break; } if (obj->vx || obj->vy) { obj->cycling = kCycleForward; } else { obj->cycling = kCycleNotCycling; boundaryCollision(obj); // Must have got hero! } obj->oldvx = obj->vx; obj->oldvy = obj->vy; currImage = obj->currImagePtr; // Get (new) ptr to current image break; } case kPathWander2: case kPathWander: if (!_vm->_rnd->getRandomNumber(3 * _vm->_normalTPS)) { // Kick on random interval obj->vx = _vm->_rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath; obj->vy = _vm->_rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath; // Set first image in sequence (if multi-seq object) if (obj->seqNumb > 1) { if (!obj->vx && (obj->seqNumb >= 4)) { if (obj->vx != obj->oldvx) { // vx just stopped if (obj->vy > 0) obj->currImagePtr = obj->seqList[DOWN].seqPtr; else obj->currImagePtr = obj->seqList[_UP].seqPtr; } } else if (obj->vx != obj->oldvx) { if (obj->vx > 0) obj->currImagePtr = obj->seqList[RIGHT].seqPtr; else obj->currImagePtr = obj->seqList[LEFT].seqPtr; } } obj->oldvx = obj->vx; obj->oldvy = obj->vy; currImage = obj->currImagePtr; // Get (new) ptr to current image } if (obj->vx || obj->vy) obj->cycling = kCycleForward; break; default: ; // Really, nothing } // Store boundaries if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); } } // Move objects, allowing for boundaries for (int i = 0; i < _numObj; i++) { object_t *obj = &_objects[i]; // Get pointer to object if ((obj->screenIndex == *_vm->_screen_p) && (obj->vx || obj->vy)) { // Only process if it's moving // Do object movement. Delta_x,y return allowed movement in x,y // to move as close to a boundary as possible without crossing it. seq_t *currImage = obj->currImagePtr; // Get ptr to current image // object coordinates int x1 = obj->x + currImage->x1; // Left edge of object int x2 = obj->x + currImage->x2; // Right edge int y1 = obj->y + currImage->y1; // Top edge int y2 = obj->y + currImage->y2; // Bottom edge if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) clearBoundary(x1, x2, y2); // Clear our own boundary // Allowable motion wrt boundary int dx = deltaX(x1, x2, obj->vx, y2); if (dx != obj->vx) { // An object boundary collision! boundaryCollision(obj); obj->vx = 0; } int dy = deltaY(x1, x2, obj->vy, y2); if (dy != obj->vy) { // An object boundary collision! boundaryCollision(obj); obj->vy = 0; } if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) storeBoundary(x1, x2, y2); // Re-store our own boundary obj->x += dx; // Update object position obj->y += dy; // Don't let object go outside screen if (x1 < kEdge) obj->x = kEdge2; if (x2 > (kXPix - kEdge)) obj->x = kXPix - kEdge2 - (x2 - x1); if (y1 < kEdge) obj->y = kEdge2; if (y2 > (kYPix - kEdge)) obj->y = kYPix - kEdge2 - (y2 - y1); if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != kPathWander2) && (obj->pathType != kPathChase2)) obj->cycling = kCycleNotCycling; } } // Clear all object baselines from the boundary file. for (int i = 0; i < _numObj; i++) { object_t *obj = &_objects[i]; // Get pointer to object seq_t *currImage = obj->currImagePtr; // Get ptr to current image if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); } // If maze mode is enabled, do special maze processing if (_vm->_maze.enabledFl) { seq_t *currImage = _vm->_hero->currImagePtr;// Get ptr to current image // hero coordinates int x1 = _vm->_hero->x + currImage->x1; // Left edge of object int x2 = _vm->_hero->x + currImage->x2; // Right edge int y1 = _vm->_hero->y + currImage->y1; // Top edge int y2 = _vm->_hero->y + currImage->y2; // Bottom edge _vm->_scheduler->processMaze(x1, x2, y1, y2); } }
void Inter_v7::o7_playVmdOrMusic() { Common::String file = _vm->_game->_script->evalString(); VideoPlayer::Properties props; props.x = _vm->_game->_script->readValExpr(); props.y = _vm->_game->_script->readValExpr(); props.startFrame = _vm->_game->_script->readValExpr(); props.lastFrame = _vm->_game->_script->readValExpr(); props.breakKey = _vm->_game->_script->readValExpr(); props.flags = _vm->_game->_script->readValExpr(); props.palStart = _vm->_game->_script->readValExpr(); props.palEnd = _vm->_game->_script->readValExpr(); props.palCmd = 1 << (props.flags & 0x3F); props.forceSeek = true; debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " "paletteCmd %d (%d - %d), flags %X", file.c_str(), props.x, props.y, props.startFrame, props.lastFrame, props.palCmd, props.palStart, props.palEnd, props.flags); if (file == "RIEN") { _vm->_vidPlayer->closeAll(); return; } bool close = false; if (props.lastFrame == -1) { close = true; } else if (props.lastFrame == -3) { if (file.empty()) { _vm->_vidPlayer->closeVideo(_vm->_mult->_objects[props.startFrame].videoSlot - 1); _vm->_mult->_objects[props.startFrame].videoSlot = 0; return; } props.flags = VideoPlayer::kFlagOtherSurface; props.sprite = -1; _vm->_mult->_objects[props.startFrame].pAnimData->animation = -props.startFrame - 1; if (_vm->_mult->_objects[props.startFrame].videoSlot > 0) _vm->_vidPlayer->closeVideo(_vm->_mult->_objects[props.startFrame].videoSlot - 1); uint32 x = props.x; uint32 y = props.y; int slot = _vm->_vidPlayer->openVideo(false, file, props); _vm->_mult->_objects[props.startFrame].videoSlot = slot + 1; if (x == 0xFFFFFFFF) { *_vm->_mult->_objects[props.startFrame].pPosX = _vm->_vidPlayer->getDefaultX(slot); *_vm->_mult->_objects[props.startFrame].pPosY = _vm->_vidPlayer->getDefaultY(slot); } else { *_vm->_mult->_objects[props.startFrame].pPosX = x; *_vm->_mult->_objects[props.startFrame].pPosY = y; } return; } else if (props.lastFrame == -4) { warning("Woodruff Stub: Video/Music command -4: Play background video %s", file.c_str()); return; } else if (props.lastFrame == -5) { // warning("Urban/Playtoons Stub: Stop without delay"); _vm->_sound->bgStop(); return; } else if (props.lastFrame == -6) { // warning("Urban/Playtoons Stub: Video/Music command -6 (cache video)"); return; } else if (props.lastFrame == -7) { // warning("Urban/Playtoons Stub: Video/Music command -6 (flush cache)"); return; } else if ((props.lastFrame == -8) || (props.lastFrame == -9)) { if (!file.contains('.')) file += ".WA8"; probe16bitMusic(file); if (props.lastFrame == -9) debugC(0, kDebugVideo, "Urban/Playtoons Stub: Delayed music stop?"); _vm->_sound->bgStop(); _vm->_sound->bgPlay(file.c_str(), SOUND_WAV); return; } else if (props.lastFrame <= -10) { _vm->_vidPlayer->closeVideo(); if (!(props.flags & VideoPlayer::kFlagNoVideo)) props.loop = true; } else if (props.lastFrame < 0) { warning("Urban/Playtoons Stub: Unknown Video/Music command: %d, %s", props.lastFrame, file.c_str()); return; } if (props.startFrame == -2) { props.startFrame = 0; props.lastFrame = -1; props.noBlock = true; } _vm->_vidPlayer->evaluateFlags(props); bool primary = true; if (props.noBlock && (props.flags & VideoPlayer::kFlagNoVideo)) primary = false; int slot = 0; if (!file.empty() && ((slot = _vm->_vidPlayer->openVideo(primary, file, props)) < 0)) { WRITE_VAR(11, (uint32) -1); return; } if (props.hasSound) _vm->_vidPlayer->closeLiveSound(); if (props.startFrame >= 0) _vm->_vidPlayer->play(slot, props); if (close && !props.noBlock) { if (!props.canceled) _vm->_vidPlayer->waitSoundEnd(slot); _vm->_vidPlayer->closeVideo(slot); } }
void Inter_v6::o6_playVmdOrMusic() { Common::String file = _vm->_game->_script->evalString(); VideoPlayer::Properties props; props.x = _vm->_game->_script->readValExpr(); props.y = _vm->_game->_script->readValExpr(); props.startFrame = _vm->_game->_script->readValExpr(); props.lastFrame = _vm->_game->_script->readValExpr(); props.breakKey = _vm->_game->_script->readValExpr(); props.flags = _vm->_game->_script->readValExpr(); props.palStart = _vm->_game->_script->readValExpr(); props.palEnd = _vm->_game->_script->readValExpr(); props.palCmd = 1 << (props.flags & 0x3F); props.forceSeek = true; debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " "paletteCmd %d (%d - %d), flags %X", file.c_str(), props.x, props.y, props.startFrame, props.lastFrame, props.palCmd, props.palStart, props.palEnd, props.flags); // WORKAROUND: When taking the music sheet from Dr. Dramish's car, // the video that lets the sheet vanish is missing. We'll // play the one where the sheet is already gone instead. if (_vm->isCurrentTot("avt005.tot") && file.equalsIgnoreCase("MXRAMPART")) file = "PLCOFDR2"; if (file == "RIEN") { _vm->_vidPlayer->closeAll(); return; } bool close = false; if (props.lastFrame == -1) { close = true; } else if (props.lastFrame == -5) { // warning("Urban/Playtoons Stub: Stop without delay"); _vm->_sound->bgStop(); return; } else if (props.lastFrame == -6) { // warning("Urban/Playtoons Stub: Video/Music command -6 (cache video)"); return; } else if (props.lastFrame == -7) { // warning("Urban/Playtoons Stub: Video/Music command -6 (flush cache)"); return; } else if ((props.lastFrame == -8) || (props.lastFrame == -9)) { if (!file.contains('.')) file += ".WA8"; probe16bitMusic(file); if (props.lastFrame == -9) debugC(0, kDebugVideo, "Urban/Playtoons Stub: Delayed music stop?"); _vm->_sound->bgStop(); _vm->_sound->bgPlay(file.c_str(), SOUND_WAV); return; } else if (props.lastFrame <= -10) { _vm->_vidPlayer->closeVideo(); if (!(props.flags & VideoPlayer::kFlagNoVideo)) props.loop = true; } else if (props.lastFrame < 0) { warning("Urban/Playtoons Stub: Unknown Video/Music command: %d, %s", props.lastFrame, file.c_str()); return; } if (props.startFrame == -2) { props.startFrame = 0; props.lastFrame = -1; props.noBlock = true; } _vm->_vidPlayer->evaluateFlags(props); bool primary = true; if (props.noBlock && (props.flags & VideoPlayer::kFlagNoVideo)) primary = false; int slot = 0; if (!file.empty() && ((slot = _vm->_vidPlayer->openVideo(primary, file, props)) < 0)) { WRITE_VAR(11, (uint32) -1); return; } if (props.hasSound) _vm->_vidPlayer->closeLiveSound(); if (props.startFrame >= 0) _vm->_vidPlayer->play(slot, props); if (close && !props.noBlock) { if (!props.canceled) _vm->_vidPlayer->waitSoundEnd(slot); _vm->_vidPlayer->closeVideo(slot); } }
bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) { assert(seqData); static const SeqEntry floppySeqProcs[] = { // 0x00 SEQOP(3, s1_wsaOpen), SEQOP(2, s1_wsaClose), SEQOP(6, s1_wsaPlayFrame), SEQOP(2, s1_wsaPlayNextFrame), // 0x04 SEQOP(2, s1_wsaPlayPrevFrame), SEQOP(5, s1_drawShape), SEQOP(3, s1_waitTicks), SEQOP(3, s1_copyWaitTicks), // 0x08 SEQOP(1, s1_shuffleScreen), SEQOP(1, s1_copyView), SEQOP(2, s1_loopInit), SEQOP(4, s1_loopInc), // 0x0C SEQOP(2, s1_loadPalette), SEQOP(2, s1_loadBitmap), SEQOP(1, s1_fadeToBlack), SEQOP(2, s1_printText), // 0x10 SEQOP(6, s1_printTalkText), SEQOP(1, s1_restoreTalkText), SEQOP(1, s1_clearCurrentScreen), SEQOP(1, s1_break), // 0x14 SEQOP(1, s1_fadeFromBlack), SEQOP(3, s1_copyRegion), SEQOP(2, s1_copyRegionSpecial), SEQOP(9, s1_fillRect), // 0x18 SEQOP(2, s1_playEffect), SEQOP(2, s1_playTrack), SEQOP(1, s1_allocTempBuffer), SEQOP(1, s1_textDisplayEnable), // 0x1C SEQOP(1, s1_textDisplayDisable), SEQOP(1, s1_endOfScript) }; static const SeqEntry cdromSeqProcs[] = { // 0x00 SEQOP(3, s1_wsaOpen), SEQOP(2, s1_wsaClose), SEQOP(6, s1_wsaPlayFrame), SEQOP(2, s1_wsaPlayNextFrame), // 0x04 SEQOP(2, s1_wsaPlayPrevFrame), SEQOP(5, s1_drawShape), SEQOP(3, s1_waitTicks), SEQOP(3, s1_waitTicks), // 0x08 SEQOP(3, s1_copyWaitTicks), SEQOP(1, s1_shuffleScreen), SEQOP(1, s1_copyView), SEQOP(2, s1_loopInit), // 0x0C SEQOP(4, s1_loopInc), SEQOP(4, s1_loopInc), SEQOP(2, s1_skip), SEQOP(2, s1_loadPalette), // 0x10 SEQOP(2, s1_loadBitmap), SEQOP(1, s1_fadeToBlack), SEQOP(2, s1_printText), SEQOP(6, s1_printTalkText), // 0x14 SEQOP(1, s1_restoreTalkText), SEQOP(1, s1_clearCurrentScreen), SEQOP(1, s1_break), SEQOP(1, s1_fadeFromBlack), // 0x18 SEQOP(3, s1_copyRegion), SEQOP(2, s1_copyRegionSpecial), SEQOP(9, s1_fillRect), SEQOP(2, s1_playEffect), // 0x1C SEQOP(2, s1_playTrack), SEQOP(1, s1_allocTempBuffer), SEQOP(1, s1_textDisplayEnable), SEQOP(1, s1_textDisplayDisable), // 0x20 SEQOP(1, s1_endOfScript), SEQOP(1, s1_loadIntroVRM), SEQOP(2, s1_playVocFile), SEQOP(1, s1_miscUnk3), // 0x24 SEQOP(2, s1_prefetchVocFile) }; const SeqEntry *commands; int numCommands; if (_vm->gameFlags().isTalkie) { commands = cdromSeqProcs; numCommands = ARRAYSIZE(cdromSeqProcs); } else { commands = floppySeqProcs; numCommands = ARRAYSIZE(floppySeqProcs); } bool seqSkippedFlag = false; _seqData = seqData; _seqDisplayedTextTimer = 0xFFFFFFFF; _seqDisplayTextFlag = false; _seqDisplayedTextX = 0; _seqDisplayedText = 0; _seqDisplayedChar = 0; _seqTalkTextRestored = false; _seqTalkTextPrinted = false; _seqQuitFlag = false; _seqWsaCurDecodePage = 0; for (int i = 0; i < 20; ++i) { _seqLoopTable[i].ptr = 0; _seqLoopTable[i].count = 0xFFFF; } memset(_seqMovies, 0, sizeof(_seqMovies)); _screen->_curPage = 0; while (!_seqQuitFlag && !_vm->shouldQuit()) { if (skipSeq && _vm->seq_skipSequence()) { while (1) { uint8 code = *_seqData; if (commands[code].proc == &SeqPlayer::s1_endOfScript || commands[code].proc == &SeqPlayer::s1_break) break; _seqData += commands[code].len; } skipSeq = false; seqSkippedFlag = true; } // used in Kallak writing intro if (_seqDisplayTextFlag && _seqDisplayedTextTimer != 0xFFFFFFFF && _vm->textEnabled()) { if (_seqDisplayedTextTimer < _system->getMillis()) { char charStr[3]; charStr[0] = _vm->seqTextsTable()[_seqDisplayedText][_seqDisplayedChar]; charStr[1] = charStr[2] = '\0'; if (_vm->gameFlags().lang == Common::JA_JPN) charStr[1] = _vm->seqTextsTable()[_seqDisplayedText][++_seqDisplayedChar]; _screen->printText(charStr, _seqDisplayedTextX, 180, 0xF, 0xC); _seqDisplayedTextX += _screen->getCharWidth((uint8)charStr[0]); ++_seqDisplayedChar; if (_vm->seqTextsTable()[_seqDisplayedText][_seqDisplayedChar] == '\0') _seqDisplayedTextTimer = 0xFFFFFFFF; else _seqDisplayedTextTimer = _system->getMillis() + 1000 / ((_vm->gameFlags().lang == Common::FR_FRA) ? 120 : 60); } } uint8 seqCode = *_seqData++; if (seqCode < numCommands) { SeqProc currentProc = commands[seqCode].proc; debugC(5, kDebugLevelSequence, "0x%.4X seqCode = %d (%s)", (uint16)(_seqData - 1 - seqData), seqCode, commands[seqCode].desc); (this->*currentProc)(); } else { error("Invalid sequence opcode %d called from 0x%.04X", seqCode, (uint16)(_seqData - 1 - seqData)); } _screen->updateScreen(); } delete[] _specialBuffer; _specialBuffer = 0; for (uint i = 0; i < ARRAYSIZE(_seqMovies); ++i) { delete _seqMovies[i].movie; _seqMovies[i].movie = 0; } return seqSkippedFlag; }
bool VDXPlayer::playFrameInternal() { byte currRes = 0x80; Common::ReadStream *vdxData = 0; while (currRes == 0x80) { currRes = _file->readByte(); // Skip unknown data: 1 byte, ref Edward byte tmp = _file->readByte(); uint32 compSize = _file->readUint32LE(); uint8 lengthmask = _file->readByte(); uint8 lengthbits = _file->readByte(); if (_file->eos()) break; debugC(5, kDebugVideo | kDebugUnknown, "Groovie::VDX: Edward = 0x%04X", tmp); // Read the chunk data and decompress if needed if (compSize) vdxData = _file->readStream(compSize); if (lengthmask && lengthbits) { Common::ReadStream *decompData = new LzssReadStream(vdxData, lengthmask, lengthbits); delete vdxData; vdxData = decompData; } // Use the current chunk switch (currRes) { case 0x00: debugC(6, kDebugVideo, "Groovie::VDX: Replay frame"); break; case 0x20: debugC(5, kDebugVideo, "Groovie::VDX: Still frame"); getStill(vdxData); break; case 0x25: debugC(5, kDebugVideo, "Groovie::VDX: Animation frame"); getDelta(vdxData); break; case 0x80: debugC(5, kDebugVideo, "Groovie::VDX: Sound resource"); chunkSound(vdxData); break; default: error("Groovie::VDX: Invalid resource type: %d", currRes); } delete vdxData; vdxData = 0; } // Wait until the current frame can be shown if (!DebugMan.isDebugChannelEnabled(kDebugFast)) { waitFrame(); } // TODO: Move it to a better place // Update the screen if (currRes == 0x25) { //if (_flagSeven) { //_vm->_graphicsMan->mergeFgAndBg(); //} _vm->_graphicsMan->updateScreen(_bg); } // Report the end of the video if we reached the end of the file or if we // just wanted to play one frame. if (_file->eos() || _flagFirstFrame) { _origX = _origY = 0; return 1; } else { return 0; } }
void Mechanical::o_throne_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { // Used on Card 6238 (Sirrus' Throne) and Card 6027 (Achenar's Throne) debugC(kDebugScript, "Opcode %d: Brother throne init", op); _invokingResource->setEnabled(getVar(var)); }
void Mechanical::o_snakeBox_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Snake box init", op); _snakeBox = static_cast<MystResourceType6 *>(_invokingResource); }
void Mechanical::o_crystalLeaveRed(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Crystal leave", op); _crystalLit = 0; _vm->redrawArea(22); }
void Mechanical::o_crystalEnterRed(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Crystal enter", op); _crystalLit = 2; _vm->redrawArea(22); }
void Mechanical::o_mystStaircaseMovie(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Myst book staircase video", op); _vm->_video->playMovieBlocking(_vm->wrapMovieFilename("sstairs", kMechanicalStack), 199, 108); }
void FontRenderer::setFont(Animation *font) { debugC(5, kDebugFont, "setFont(font)"); _currentFont = font; }
void VDXPlayer::getStill(Common::ReadStream *in) { uint16 numXTiles = in->readUint16LE(); debugC(5, kDebugVideo, "Groovie::VDX: numXTiles=%d", numXTiles); uint16 numYTiles = in->readUint16LE(); debugC(5, kDebugVideo, "Groovie::VDX: numYTiles=%d", numYTiles); // It's skipped in the original: uint16 colorDepth = in->readUint16LE(); debugC(5, kDebugVideo, "Groovie::VDX: colorDepth=%d", colorDepth); uint16 imageWidth = TILE_SIZE * numXTiles; uint8 mask = 0; byte *buf; if (_flagOne) { // Paint to the foreground buf = (byte *)_fg->getPixels(); if (_flag2Byte) { mask = 0xff; } else { mask = 0; } // TODO: Verify this is the right procedure. Couldn't find it on the // disassembly, but it's required to work properly _flagFirstFrame = true; } else { // Paint to the background buf = (byte *)_bg->getPixels(); } // Read the palette in->read(_palBuf, 3 * 256); if (_flagSeven) { _flagFive = true; } // Skip the frame when flag 5 is set, unless flag 1 is set if (!_flagFive || _flagOne) { byte colors[16]; for (uint16 j = 0; j < numYTiles; j++) { byte *currentTile = buf + j * TILE_SIZE * imageWidth; for (uint16 i = numXTiles; i; i--) { uint8 color1 = in->readByte(); uint8 color0 = in->readByte(); uint16 colorMap = in->readUint16LE(); expandColorMap(colors, colorMap, color1, color0); decodeBlockStill(currentTile, colors, 640, mask); currentTile += TILE_SIZE; } } // Apply the palette if (_flagNine) { // Flag 9 starts a fade in fadeIn(_palBuf); } else { if (!_flagOne && !_flagSeven) { // Actually apply the palette setPalette(_palBuf); } } if (!_flagOne) { _vm->_graphicsMan->updateScreen(_bg); } /* if (_flagSix) { if (_flagOne) { _vm->_graphicsMan->updateScreen(_fg); } else { _vm->_graphicsMan->updateScreen(_bg); } _flagSix = 0; } */ } else { // Skip the remaining data debugC(10, kDebugVideo, "Groovie::VDX: Skipping still frame"); while (!in->eos()) { in->readByte(); } } }
void FontRenderer::renderMultiLineText(int16 x, int16 y, const Common::String &origText, int32 mode) { debugC(5, kDebugFont, "renderMultiLineText(%d, %d, %s, %d)", x, y, origText.c_str(), mode); // divide the text in several lines // based on number of characters or size of lines. byte text[1024]; Common::strlcpy((char *)text, origText.c_str(), 1024); byte *lines[16]; int32 lineSize[16]; int32 numLines = 0; byte *it = text; int16 maxWidth = 0; int16 curWidth = 0; while (true) { byte *lastLine = it; byte *lastSpace = it; int32 lastSpaceX = 0; int32 curLetterNr = 0; curWidth = 0; while (*it && curLetterNr < 50 && curWidth < 580) { byte curChar = *it; if (curChar == 32) { lastSpace = it; lastSpaceX = curWidth; } else curChar = textToFont(curChar); int width = _currentFont->getFrameWidth(curChar); curWidth += MAX(width - 2, 0); it++; curLetterNr++; } if (*lastLine == 0) break; lines[numLines] = lastLine; if (*it == 0) lineSize[numLines] = curWidth; else lineSize[numLines] = lastSpaceX; if (lineSize[numLines] > maxWidth) maxWidth = lineSize[numLines]; lastLine = lastSpace + 1; numLines++; if (*it == 0) break; it = lastLine; *lastSpace = 0; if (numLines >= 16) break; } if (curWidth > maxWidth) { maxWidth = curWidth; } //numLines++; // get font height (assumed to be constant) int16 height = _currentFont->getHeight(); int32 textSize = (height - 2) * numLines; y = y - textSize; if (y < 30) y = 30; if (y + textSize > 370) y = 370 - textSize; x -= _vm->state()->_currentScrollValue; // adapt x if (x - 30 - maxWidth / 2 < 0) x = maxWidth / 2 + 30; if (x + 30 + (maxWidth / 2) > TOON_SCREEN_WIDTH) x = TOON_SCREEN_WIDTH - (maxWidth / 2) - 30; // we have good coordinates now, we can render the multi line int16 curX = x; int16 curY = y; for (int32 i = 0; i < numLines; i++) { const byte *line = lines[i]; curX = x - lineSize[i] / 2; _vm->addDirtyRect(curX + _vm->state()->_currentScrollValue, curY, curX + lineSize[i] + _vm->state()->_currentScrollValue + 2, curY + height); while (*line) { byte curChar = textToFont(*line); if (curChar != 32) _currentFont->drawFontFrame(_vm->getMainSurface(), curChar, curX + _vm->state()->_currentScrollValue, curY, _currentFontColor); curX = curX + MAX<int32>(_currentFont->getFrameWidth(curChar) - 2, 0); //height = MAX(height, _currentFont->getFrameHeight(curChar)); line++; } curY += height; } }
uint16 VDXPlayer::loadInternal() { if (DebugMan.isDebugChannelEnabled(kDebugVideo)) { int8 i; debugN(1, "Groovie::VDX: New VDX: bitflags are "); for (i = 15; i >= 0; i--) { debugN(1, "%d", _flags & (1 << i)? 1 : 0); if (i % 4 == 0) { debugN(1, " "); } } debug(1, " <- 0 "); } // Flags: // - 1 Puzzle piece? Skip palette, don't redraw full screen, draw still to b/ack buffer // - 2 Transparent color is 0xFF // - 5 Skip still chunks // - 7 // - 8 Just show the first frame // - 9 Start a palette fade in _flagZero = ((_flags & (1 << 0)) != 0); _flagOne = ((_flags & (1 << 1)) != 0); _flag2Byte = (_flags & (1 << 2)) ? 0xFF : 0x00; _flagThree = ((_flags & (1 << 3)) != 0); _flagFour = ((_flags & (1 << 4)) != 0); _flagFive = ((_flags & (1 << 5)) != 0); _flagSix = ((_flags & (1 << 6)) != 0); _flagSeven = ((_flags & (1 << 7)) != 0); _flagEight = ((_flags & (1 << 8)) != 0); _flagNine = ((_flags & (1 << 9)) != 0); // Enable highspeed if we're not obeying fps, and not marked as special // This will be disabled in chunk audio if we're actually an audio vdx if (_vm->_modeSpeed == kGroovieSpeedFast && ((_flags & (1 << 15)) == 0)) setOverrideSpeed(true); if (_flagOnePrev && !_flagOne && !_flagEight) { _flagSeven = true; } // Save _flagOne for the next video _flagOnePrev = _flagOne; //_flagTransparent = _flagOne; _flagFirstFrame = _flagEight; //_flagSkipPalette = _flagSeven; _flagSkipPalette = false; //_flagSkipStill = _flagFive || _flagSeven; //_flagUpdateStill = _flagNine || _flagSix; // Begin reading the file debugC(1, kDebugVideo, "Groovie::VDX: Playing video"); if (_file->readUint16LE() != VDX_IDENT) { error("Groovie::VDX: This does not appear to be a 7th guest VDX file"); return 0; } else { debugC(5, kDebugVideo, "Groovie::VDX: VDX file identified correctly"); } uint16 tmp; // Skip unknown data: 6 bytes, ref Martine tmp = _file->readUint16LE(); debugC(2, kDebugVideo | kDebugUnknown, "Groovie::VDX: Martine1 = 0x%04X", tmp); tmp = _file->readUint16LE(); debugC(2, kDebugVideo | kDebugUnknown, "Groovie::VDX: Martine2 = 0x%04X", tmp); tmp = _file->readUint16LE(); debugC(2, kDebugVideo | kDebugUnknown, "Groovie::VDX: Martine3 (FPS?) = %d", tmp); return tmp; }
void LegacySoundArchive::openArchive(const char *path) { // Close previously opened archive (if any) closeArchive(); debugCN(1, kDraciArchiverDebugLevel, "Loading samples %s: ", path); _f = new Common::File(); _f->open(path); if (_f->isOpen()) { debugC(1, kDraciArchiverDebugLevel, "Success"); } else { debugC(1, kDraciArchiverDebugLevel, "Error"); delete _f; _f = NULL; return; } // Save path for reading in files later on _path = path; // Read archive header debugC(1, kDraciArchiverDebugLevel, "Loading header"); uint totalLength = _f->readUint32LE(); const uint kMaxSamples = 4095; // The no-sound file is exactly 16K bytes long, so don't fail on short reads uint sampleStarts[kMaxSamples]; for (uint i = 0; i < kMaxSamples; ++i) { sampleStarts[i] = _f->readUint32LE(); } // Fill the sample table for (_sampleCount = 0; _sampleCount < kMaxSamples - 1; ++_sampleCount) { int length = sampleStarts[_sampleCount + 1] - sampleStarts[_sampleCount]; if (length <= 0 && sampleStarts[_sampleCount] >= totalLength) // heuristics to detect the last sample break; } if (_sampleCount > 0) { debugC(1, kDraciArchiverDebugLevel, "Archive info: %d samples, %d total length", _sampleCount, totalLength); _samples = new SoundSample[_sampleCount]; for (uint i = 0; i < _sampleCount; ++i) { _samples[i]._offset = sampleStarts[i]; _samples[i]._length = sampleStarts[i+1] - sampleStarts[i]; _samples[i]._frequency = 0; // set in getSample() } if (_samples[_sampleCount-1]._offset + _samples[_sampleCount-1]._length != totalLength && _samples[_sampleCount-1]._offset + _samples[_sampleCount-1]._length - _samples[0]._offset != totalLength) { // WORKAROUND: the stored length is stored with the header for sounds and without the hader for dubbing. Crazy. debugC(1, kDraciArchiverDebugLevel, "Broken sound archive: %d != %d", _samples[_sampleCount-1]._offset + _samples[_sampleCount-1]._length, totalLength); closeArchive(); return; } } else { debugC(1, kDraciArchiverDebugLevel, "Archive info: empty"); } // Indicate that the archive has been successfully opened _opened = true; }
int32 CharacterDrew::getRandomIdleAnim() { debugC(3, kDebugCharacter, "getRandomIdleAnim()"); static const int32 idle[] = { 6, 9, 10, 11, 12 }; return idle[_vm->randRange(0, 4)]; }
/** * Set the new screen number into the hero object and any carried objects */ void HugoEngine::setNewScreen(const int screenNum) { debugC(1, kDebugEngine, "setNewScreen(%d)", screenNum); *_screenPtr = screenNum; // HERO object _object->setCarriedScreen(screenNum); // Carried objects }
/** * Process required action for inventory * Returns objId under cursor (or -1) for INV_GET */ int16 InventoryHandler::processInventory(const InvAct action, ...) { debugC(1, kDebugInventory, "processInventory(InvAct action, ...)"); int16 imageNumb; // Total number of inventory items int displayNumb; // Total number displayed/carried // Compute total number and number displayed, i.e. number carried for (imageNumb = 0, displayNumb = 0; imageNumb < _maxInvent && _invent[imageNumb] != -1; imageNumb++) { if (_vm->_object->isCarried(_invent[imageNumb])) displayNumb++; } // Will we need the scroll arrows? bool scrollFl = displayNumb > kMaxDisp; va_list marker; // Args used for D_ADD operation int16 cursorx, cursory; // Current cursor position int16 objId = -1; // Return objid under cursor switch (action) { case kInventoryActionInit: // Initialize inventory display constructInventory(imageNumb, displayNumb, scrollFl, _firstIconId); break; case kInventoryActionLeft: // Scroll left by one icon _firstIconId = MAX(0, _firstIconId - 1); constructInventory(imageNumb, displayNumb, scrollFl, _firstIconId); break; case kInventoryActionRight: // Scroll right by one icon _firstIconId = MIN(displayNumb, _firstIconId + 1); constructInventory(imageNumb, displayNumb, scrollFl, _firstIconId); break; case kInventoryActionGet: // Return object id under cursor // Get cursor position from variable argument list va_start(marker, action); // Initialize variable arguments cursorx = va_arg(marker, int); // Cursor x cursory = va_arg(marker, int); // Cursor y va_end(marker); // Reset variable arguments cursory -= kDibOffY; // Icon bar is at true zero if (cursory > 0 && cursory < kInvDy) { // Within icon bar? int16 i = cursorx / kInvDx; // Compute icon index if (scrollFl) { // Scroll buttons displayed if (i == 0) { // Left scroll button objId = kLeftArrow; } else { if (i == kMaxDisp - 1) // Right scroll button objId = kRightArrow; else // Adjust for scroll i += _firstIconId - 1; // i is icon index } } // If not an arrow, find object id - limit to valid range if (objId == -1 && i < displayNumb) { // Find objid by counting # carried objects == i+1 int16 j; for (j = 0, i++; i > 0 && j < _vm->_object->_numObj; j++) { if (_vm->_object->isCarried(j)) { if (--i == 0) objId = j; } } } } break; } return objId; // For the INV_GET action }
void AgiEngine::initialize() { // TODO: Some sound emulation modes do not fit our current music // drivers, and I'm not sure what they are. For now, they might // as well be called "PC Speaker" and "Not PC Speaker". // If used platform is Apple IIGS then we must use Apple IIGS sound emulation // because Apple IIGS AGI games use only Apple IIGS specific sound resources. if (getPlatform() == Common::kPlatformApple2GS) { _soundemu = SOUND_EMU_APPLE2GS; } else if (getPlatform() == Common::kPlatformCoCo3) { _soundemu = SOUND_EMU_COCO3; } else if (ConfMan.get("music_driver") == "auto") { // Default sound is the proper PCJr emulation _soundemu = SOUND_EMU_PCJR; } else { switch (MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK|MDT_AMIGA|MDT_ADLIB|MDT_PCJR|MDT_MIDI))) { case MT_PCSPK: _soundemu = SOUND_EMU_PC; break; case MT_ADLIB: _soundemu = SOUND_EMU_NONE; break; case MT_PCJR: _soundemu = SOUND_EMU_PCJR; break; case MT_AMIGA: _soundemu = SOUND_EMU_AMIGA; break; default: debug(0, "DEF"); _soundemu = SOUND_EMU_MIDI; break; } } initRenderMode(); _buttonStyle = AgiButtonStyle(_renderMode); _defaultButtonStyle = AgiButtonStyle(); _console = new Console(this); _gfx = new GfxMgr(this); _sound = new SoundMgr(this, _mixer); _picture = new PictureMgr(this, _gfx); _sprites = new SpritesMgr(this, _gfx); _gfx->initMachine(); _game.gameFlags = 0; _game.colorFg = 15; _game.colorBg = 0; _game.name[0] = '\0'; _game.sbufOrig = (uint8 *)calloc(_WIDTH, _HEIGHT * 2); // Allocate space for two AGI screens vertically _game.sbuf16c = _game.sbufOrig + SBUF16_OFFSET; // Make sbuf16c point to the 16 color (+control line & priority info) AGI screen _game.sbuf256c = _game.sbufOrig + SBUF256_OFFSET; // Make sbuf256c point to the 256 color AGI screen _game.sbuf = _game.sbuf16c; // Make sbuf point to the 16 color (+control line & priority info) AGI screen by default _gfx->initVideo(); _lastSaveTime = 0; _lastTick = _system->getMillis(); debugC(2, kDebugLevelMain, "Detect game"); if (agiDetectGame() == errOK) { _game.state = STATE_LOADED; debugC(2, kDebugLevelMain, "game loaded"); } else { warning("Could not open AGI game"); } debugC(2, kDebugLevelMain, "Init sound"); }
/** * Process inventory state machine */ void InventoryHandler::runInventory() { Status &gameStatus = _vm->getGameStatus(); debugC(1, kDebugInventory, "runInventory"); switch (_inventoryState) { case kInventoryOff: // Icon bar off screen break; case kInventoryUp: // Icon bar moving up _inventoryHeight -= kStepDy; // Move the icon bar up if (_inventoryHeight <= 0) // Limit travel _inventoryHeight = 0; // Move visible portion to _frontBuffer, restore uncovered portion, display results _vm->_screen->moveImage(_vm->_screen->getIconBuffer(), 0, 0, kXPix, _inventoryHeight, kXPix, _vm->_screen->getFrontBuffer(), 0, kDibOffY, kXPix); _vm->_screen->moveImage(_vm->_screen->getBackBufferBackup(), 0, _inventoryHeight + kDibOffY, kXPix, kStepDy, kXPix, _vm->_screen->getFrontBuffer(), 0, _inventoryHeight + kDibOffY, kXPix); _vm->_screen->displayRect(0, kDibOffY, kXPix, _inventoryHeight + kStepDy); if (_inventoryHeight == 0) { // Finished moving up? // Yes, restore dibs and exit back to game state machine _vm->_screen->moveImage(_vm->_screen->getBackBufferBackup(), 0, 0, kXPix, kYPix, kXPix, _vm->_screen->getBackBuffer(), 0, 0, kXPix); _vm->_screen->moveImage(_vm->_screen->getBackBuffer(), 0, 0, kXPix, kYPix, kXPix, _vm->_screen->getFrontBuffer(), 0, 0, kXPix); _vm->_object->updateImages(); // Add objects back into display list for restore _inventoryState = kInventoryOff; gameStatus._viewState = kViewPlay; } break; case kInventoryDown: // Icon bar moving down // If this is the first step, initialize dib_i // and get any icon/text out of _frontBuffer if (_inventoryHeight == 0) { processInventory(kInventoryActionInit); // Initialize dib_i _vm->_screen->displayList(kDisplayRestore); // Restore _frontBuffer _vm->_object->updateImages(); // Rebuild _frontBuffer without icons/text _vm->_screen->displayList(kDisplayDisplay); // Blit display list to screen } _inventoryHeight += kStepDy; // Move the icon bar down if (_inventoryHeight > kInvDy) // Limit travel _inventoryHeight = kInvDy; // Move visible portion to _frontBuffer, display results _vm->_screen->moveImage(_vm->_screen->getIconBuffer(), 0, 0, kXPix, _inventoryHeight, kXPix, _vm->_screen->getFrontBuffer(), 0, kDibOffY, kXPix); _vm->_screen->displayRect(0, kDibOffY, kXPix, _inventoryHeight); if (_inventoryHeight == kInvDy) { // Finished moving down? // Yes, prepare view dibs for special inventory display since // we can't refresh objects while icon bar overlayed... // 1. Save backing store _backBuffer in temporary dib_c // 2. Make snapshot of _frontBuffer the new _backBuffer backing store // 3. Reset the display list _vm->_screen->moveImage(_vm->_screen->getBackBuffer(), 0, 0, kXPix, kYPix, kXPix, _vm->_screen->getBackBufferBackup(), 0, 0, kXPix); _vm->_screen->moveImage(_vm->_screen->getFrontBuffer(), 0, 0, kXPix, kYPix, kXPix, _vm->_screen->getBackBuffer(), 0, 0, kXPix); _vm->_screen->displayList(kDisplayInit); _inventoryState = kInventoryActive; } break; case kInventoryActive: // Inventory active _vm->_parser->charHandler(); // Still allow commands _vm->_screen->displayList(kDisplayRestore); // Restore previous background _vm->_screen->displayList(kDisplayDisplay); // Blit the display list to screen break; } }
// Save game void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) { if (getState()->scene <= kSceneIntro) return; // Validate main header SavegameMainHeader header; if (!loadMainHeader(_savegame, &header)) { debugC(2, kLastExpressDebugSavegame, "SaveLoad::saveGame - Cannot load main header: %s", getFilename(getMenu()->getGameId()).c_str()); return; } if (!_savegame) error("SaveLoad::saveGame: savegame stream is invalid"); // Validate the current entry if it exists if (header.count > 0) { _savegame->seek(header.offsetEntry); // Load entry header SavegameEntryHeader entry; Common::Serializer ser(_savegame, NULL); entry.saveLoadWithSerializer(ser); if (!entry.isValid()) { warning("SaveLoad::saveGame: Invalid entry. This savegame might be corrupted!"); _savegame->seek(header.offset); } else if (getState()->time < entry.time || (type == kSavegameTypeTickInterval && getState()->time == entry.time)) { // Not ready to save a game, skipping! return; } else if ((type == kSavegameTypeTime || type == kSavegameTypeEvent) && (entry.type == kSavegameTypeTickInterval && (getState()->time - entry.time) < 450)) { _savegame->seek(header.offsetEntry); --header.count; } else { _savegame->seek(header.offset); } } else { // Seek to the next savegame entry _savegame->seek(header.offset); } if (type != kSavegameTypeEvent2 && type != kSavegameTypeAuto) header.offsetEntry = (uint32)_savegame->pos(); // Write the savegame entry writeEntry(type, entity, value); if (!header.keepIndex) ++header.count; if (type == kSavegameTypeEvent2 || type == kSavegameTypeAuto) { header.keepIndex = 1; } else { header.keepIndex = 0; header.offset = (uint32)_savegame->pos(); // Save ticks _gameTicksLastSavegame = getState()->timeTicks; } // Validate the main header if (!header.isValid()) error("SaveLoad::saveGame: main game header is invalid!"); // Write the main header _savegame->seek(0); Common::Serializer ser(NULL, _savegame); header.saveLoadWithSerializer(ser); flushStream(getMenu()->getGameId()); }
void SmushFont::drawStringWrap(const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, int left, int right, bool center) { debugC(DEBUG_SMUSH, "SmushFont::drawStringWrap(%s, %d, %d, %d, %d, %d)", str, x, y, left, right, center); const int width = right - left; char *s = strdup(str); char *words[MAX_WORDS]; int word_count = 0; char *tmp = s; while (tmp) { assert(word_count < MAX_WORDS); words[word_count++] = tmp; tmp = strpbrk(tmp, " \t\r\n"); if (tmp == 0) break; *tmp++ = 0; } int i = 0, max_width = 0, height = 0, line_count = 0; char *substrings[MAX_WORDS]; int substr_widths[MAX_WORDS]; const int space_width = getCharWidth(' '); i = 0; while (i < word_count) { char *substr = words[i++]; int substr_width = getStringWidth(substr); while (i < word_count) { int word_width = getStringWidth(words[i]); if ((substr_width + space_width + word_width) >= width) break; substr_width += word_width + space_width; *(words[i]-1) = ' '; // Convert 0 byte back to space i++; } substrings[line_count] = substr; substr_widths[line_count++] = substr_width; if (max_width < substr_width) max_width = substr_width; height += getStringHeight(substr); } if (y > dst_height - height) { y = dst_height - height; } if (center) { max_width = (max_width + 1) / 2; x = left + width / 2; if (x < left + max_width) x = left + max_width; if (x > right - max_width) x = right - max_width; for (i = 0; i < line_count; i++) { drawSubstring(substrings[i], buffer, dst_width, x - substr_widths[i] / 2, y); y += getStringHeight(substrings[i]); } } else { if (x > dst_width - max_width) x = dst_width - max_width; for (i = 0; i < line_count; i++) { drawSubstring(substrings[i], buffer, dst_width, x, y); y += getStringHeight(substrings[i]); } } free(s); }
void PreAgiEngine::initialize() { // TODO: Some sound emulation modes do not fit our current music // drivers, and I'm not sure what they are. For now, they might // as well be called "PC Speaker" and "Not PC Speaker". switch (MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK))) { case MT_PCSPK: _soundemu = SOUND_EMU_PC; break; default: _soundemu = SOUND_EMU_NONE; break; } if (ConfMan.hasKey("render_mode")) { _renderMode = Common::parseRenderMode(ConfMan.get("render_mode").c_str()); } else if (ConfMan.hasKey("platform")) { switch (Common::parsePlatform(ConfMan.get("platform"))) { case Common::kPlatformAmiga: _renderMode = Common::kRenderAmiga; break; case Common::kPlatformPC: _renderMode = Common::kRenderEGA; break; default: _renderMode = Common::kRenderEGA; break; } } _gfx = new GfxMgr(this); //_sound = new SoundMgr(this, _mixer); _picture = new PictureMgr(this, _gfx); //_sprites = new SpritesMgr(this, _gfx); _gfx->initMachine(); _game.gameFlags = 0; _game.colorFg = 15; _game.colorBg = 0; _defaultColor = 0xF; _game.name[0] = '\0'; _game.sbufOrig = (uint8 *)calloc(_WIDTH, _HEIGHT * 2); // Allocate space for two AGI screens vertically _game.sbuf16c = _game.sbufOrig + SBUF16_OFFSET; // Make sbuf16c point to the 16 color (+control line & priority info) AGI screen _game.sbuf = _game.sbuf16c; // Make sbuf point to the 16 color (+control line & priority info) AGI screen by default _game.lineMinPrint = 0; // hardcoded _gfx->initVideo(); //_sound->initSound(); _speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate()); _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); debugC(2, kDebugLevelMain, "Detect game"); // clear all resources and events for (int i = 0; i < MAX_DIRS; i++) { memset(&_game.pictures[i], 0, sizeof(struct AgiPicture)); memset(&_game.sounds[i], 0, sizeof(class AgiSound *)); // _game.sounds contains pointers now memset(&_game.dirPic[i], 0, sizeof(struct AgiDir)); memset(&_game.dirSound[i], 0, sizeof(struct AgiDir)); } debugC(2, kDebugLevelMain, "Init sound"); }
void Surface::wordWrap(char *text, uint16 width, char **&lines, uint8 &numLines) { debugC(ERROR_INTERMEDIATE, kLureDebugStrings, "wordWrap(text=%s, width=%d", text, width); numLines = 1; uint16 lineWidth = 0; char *s; bool newLine; s = text; // Scan through the text and insert NULLs to break the line into allowable widths while (*s != '\0') { char *wordStart = s; while (*wordStart == ' ') ++wordStart; char *wordEnd = strchr(wordStart, ' '); char *wordEnd2 = strchr(wordStart, '\n'); if ((!wordEnd) || ((wordEnd2) && (wordEnd2 < wordEnd))) { wordEnd = wordEnd2; newLine = (wordEnd2 != NULL); } else { newLine = false; } debugC(ERROR_DETAILED, kLureDebugStrings, "word scanning: start=%xh, after=%xh, newLine=%d", (uint32)(wordStart - text), (uint32)((wordEnd == NULL) ? -1 : wordEnd - text), newLine ? 1 : 0); if (wordEnd) { if (*wordEnd != '\0') --wordEnd; } else { wordEnd = strchr(wordStart, '\0') - 1; } int wordBytes = (int) (wordEnd - s + 1); uint16 wordSize = (wordBytes == 0) ? 0 : textWidth(s, wordBytes); if (gDebugLevel >= ERROR_DETAILED) { char wordBuffer[MAX_DESC_SIZE]; strncpy(wordBuffer, wordStart, wordBytes); wordBuffer[wordBytes] = '\0'; debugC(ERROR_DETAILED, kLureDebugStrings, "word='%s', size=%d", wordBuffer, wordSize); } if (lineWidth + wordSize > width) { // Break word onto next line *(wordStart - 1) = '\0'; ++numLines; lineWidth = 0; wordEnd = wordStart - 1; } else if (newLine) { // Break on newline ++numLines; *++wordEnd = '\0'; lineWidth = 0; } else { // Add word's length to total for line lineWidth += wordSize; } s = wordEnd+1; } // Set up a list for the start of each line lines = (char **) Memory::alloc(sizeof(char *) * numLines); lines[0] = text; debugC(ERROR_DETAILED, kLureDebugStrings, "wordWrap lines[0]='%s'", lines[0]); for (int ctr = 1; ctr < numLines; ++ctr) { lines[ctr] = strchr(lines[ctr-1], 0) + 1; debugC(ERROR_DETAILED, kLureDebugStrings, "wordWrap lines[%d]='%s'", ctr, lines[ctr]); } debugC(ERROR_INTERMEDIATE, kLureDebugStrings, "wordWrap end - numLines=%d", numLines); }
bool AgiEngine::predictiveDialog(void) { int key = 0, active = -1, lastactive = 0; bool rc = false; uint8 x; int y; int bx[17], by[17]; String prefix; char temp[MAXWORDLEN + 1], repeatcount[MAXWORDLEN]; AgiBlock tmpwindow; bool navigationwithkeys = false; bool processkey; const char *buttonStr[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" }; const char *buttons[] = { "(1)'-.&", "(2)abc", "(3)def", "(4)ghi", "(5)jkl", "(6)mno", "(7)pqrs", "(8)tuv", "(9)wxyz", "(#)next", "add", "<", "Cancel", "OK", "Pre", "(0) ", NULL }; const int colors[] = { 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 12, 15, 12, 15, 0, 15, 0, 15, 0, 14, 0, 15, 0, 0, 0 }; const char *modes[] = { "(*)Pre", "(*)123", "(*)Abc" }; // FIXME: Move this to a more appropriate place. if (!_predictiveDictText) { loadDict(); if (!_predictiveDictText) return false; } _predictiveDictActLine = NULL; uint8 numMatchingWords = 0; _predictiveDialogRunning = true; _system->setFeatureState(OSystem::kFeatureDisableKeyFiltering, true); memset(repeatcount, 0, MAXWORDLEN); // show the predictive dialog. // if another window is already in display, save its state into tmpwindow memset(&tmpwindow, 0, sizeof(tmpwindow)); tmpwindow.active = false; if (_game.window.active) memcpy(&tmpwindow, &(_game.window), sizeof(AgiBlock)); drawWindow(50, 40, 269, 159); _gfx->drawRectangle(62, 54, 249, 66, MSG_BOX_TEXT); _gfx->flushBlock(62, 54, 249, 66); bx[15] = 73; // Zero/space by[15] = 120; bx[9] = 110; // next by[9] = 120; bx[10] = 172; // add by[10] = 120; bx[14] = 200; // Mode by[14] = 120; bx[11] = 252; // Backspace by[11] = 57; bx[12] = 180; // Cancel by[12] = 140; bx[13] = 240; // OK by[13] = 140; x = 73; y = 75; for (int i = 0; i < 9; i++) { bx[i] = x; by[i] = y; x += 60; if (i % 3 == 2) { y += 15; x = 73; } } clearKeyQueue(); prefix.clear(); _currentCode.clear(); _currentWord.clear(); _wordNumber = 0; int mode = kModePre; bool needRefresh = true; for (;;) { if (needRefresh) { for (int i = 0; buttons[i]; i++) { int color1 = colors[i * 2]; int color2 = colors[i * 2 + 1]; if (i == 9 && !((mode != kModeAbc && _predictiveDictActLine && numMatchingWords > 1) || (mode == kModeAbc && _currentWord.size() && _currentWord.lastChar() != ' '))) { // Next color2 = 7; } // needs fixing, or remove it! bool _addIsActive = false; // FIXME: word adding is not implemented if (i == 10 && !_addIsActive) { // Add color2 = 7; } if (i == 14) { _gfx->drawDefaultStyleButton(bx[i], by[i], modes[mode], i == active, 0, color1, color2); } else { _gfx->drawDefaultStyleButton(bx[i], by[i], buttons[i], i == active, 0, color1, color2); } } temp[MAXWORDLEN] = 0; strncpy(temp, prefix.c_str(), MAXWORDLEN); strncat(temp, _currentWord.c_str(), MAXWORDLEN); for (int i = prefix.size() + _currentCode.size(); i < MAXWORDLEN; i++) temp[i] = ' '; printText(temp, 0, 8, 7, MAXWORDLEN, 15, 0); _gfx->flushBlock(62, 54, 249, 66); if (active >= 0 && !navigationwithkeys) { // provide visual feedback only when not navigating with the arrows // so that the user can see the active button. active = -1; needRefresh = true; } else needRefresh = false; _gfx->doUpdate(); } pollTimer(); key = doPollKeyboard(); processkey = false; switch (key) { case KEY_ENTER: if (navigationwithkeys) { // when the user has utilized arrow key navigation, // interpret enter as 'click' on the active button active = lastactive; } else { // else it is a shortcut for 'Ok' active = 13; } processkey = true; break; case KEY_ESCAPE: rc = false; goto getout; case BUTTON_LEFT: navigationwithkeys = false; for (int i = 0; buttons[i]; i++) { if (_gfx->testButton(bx[i], by[i], buttons[i])) { active = i; processkey = true; break; } } break; case KEY_BACKSPACE: active = 11; processkey = true; break; case '#': active = 9; processkey = true; break; case '*': active = 14; processkey = true; break; case 0x09: // Tab navigationwithkeys = true; debugC(3, kDebugLevelText, "Focus change"); lastactive = active = lastactive + 1; active %= ARRAYSIZE(buttons) - 1; needRefresh = true; break; case KEY_LEFT: navigationwithkeys = true; if (lastactive == 0 || lastactive == 3 || lastactive == 6) active = lastactive + 2; else if (lastactive == 9) active = 15; else if (lastactive == 11) active = 11; else if (lastactive == 12) active = 13; else if (lastactive == 14) active = 10; else active = lastactive - 1; lastactive = active; needRefresh = true; break; case KEY_RIGHT: navigationwithkeys = true; if (lastactive == 2 || lastactive == 5 || lastactive == 8) active = lastactive - 2; else if (lastactive == 10) active = 14; else if (lastactive == 11) active = 11; else if (lastactive == 13) active = 12; else if (lastactive == 15) active = 9; else active = lastactive + 1; lastactive = active; needRefresh = true; break; case KEY_UP: navigationwithkeys = true; if (lastactive <= 2) active = 11; else if (lastactive == 9 || lastactive == 10) active = lastactive - 2; else if (lastactive == 11) active = 13; else if (lastactive == 14) active = 8; else if (lastactive == 15) active = 6; else active = lastactive - 3; lastactive = active; needRefresh = true; break; case KEY_DOWN: navigationwithkeys = true; if (lastactive == 6) active = 15; else if (lastactive == 7 || lastactive == 8) active = lastactive + 2; else if (lastactive == 11) active = 0; else if (lastactive == 12 || lastactive == 13) active = 11; else if (lastactive == 14 || lastactive == 15) active = lastactive - 2; else active = lastactive + 3; lastactive = active; needRefresh = true; break; default: // handle numeric buttons if (key >= '1' && key <= '9') { active = key - '1'; processkey = true; } else if (key == '0') { active = 15; processkey = true; } break; } if (processkey) { if (active >= 0) { needRefresh = true; lastactive = active; if (active == 15 && mode != kModeNum) { // Space // bring MRU word at the top of the list when changing words if (mode == kModePre && _predictiveDictActLine && numMatchingWords > 1 && _wordNumber != 0) bringWordtoTop(_predictiveDictActLine, _wordNumber); strncpy(temp, _currentWord.c_str(), _currentCode.size()); temp[_currentCode.size()] = 0; prefix += temp; prefix += " "; _currentCode.clear(); _currentWord.clear(); numMatchingWords = 0; memset(repeatcount, 0, MAXWORDLEN); } else if (active < 9 || active == 11 || active == 15) { // number or backspace if (active == 11) { // backspace if (_currentCode.size()) { repeatcount[_currentCode.size() - 1] = 0; _currentCode.deleteLastChar(); } else { if (prefix.size()) prefix.deleteLastChar(); } } else if (prefix.size() + _currentCode.size() < MAXWORDLEN - 1) { // don't overflow the dialog line if (active == 15) { // zero _currentCode += buttonStr[9]; } else { _currentCode += buttonStr[active]; } } switch (mode) { case kModeNum: _currentWord = _currentCode; break; case kModePre: if (!matchWord() && _currentCode.size()) { _currentCode.deleteLastChar(); matchWord(); } numMatchingWords = countWordsInString(_predictiveDictActLine); break; case kModeAbc: for (x = 0; x < _currentCode.size(); x++) if (_currentCode[x] >= '1') temp[x] = buttons[_currentCode[x] - '1'][3 + repeatcount[x]]; temp[_currentCode.size()] = 0; _currentWord = temp; } } else if (active == 9) { // next if (mode == kModePre) { if (_predictiveDictActLine && numMatchingWords > 1) { _wordNumber = (_wordNumber + 1) % numMatchingWords; char tmp[MAXLINELEN]; strncpy(tmp, _predictiveDictActLine, MAXLINELEN); char *tok = strtok(tmp, " "); for (uint8 i = 0; i <= _wordNumber; i++) tok = strtok(NULL, " "); _currentWord = String(tok, _currentCode.size()); } } else if (mode == kModeAbc){ x = _currentCode.size(); if (x) { if (_currentCode.lastChar() == '1' || _currentCode.lastChar() == '7' || _currentCode.lastChar() == '9') repeatcount[x - 1] = (repeatcount[x - 1] + 1) % 4; else repeatcount[x - 1] = (repeatcount[x - 1] + 1) % 3; if (_currentCode.lastChar() >= '1') _currentWord.setChar(buttons[_currentCode[x - 1] - '1'][3 + repeatcount[x - 1]], x-1); } } } else if (active == 10) { // add debug(0, "add"); } else if (active == 13) { // Ok // bring MRU word at the top of the list when ok'ed out of the dialog if (mode == kModePre && _predictiveDictActLine && numMatchingWords > 1 && _wordNumber != 0) bringWordtoTop(_predictiveDictActLine, _wordNumber); rc = true; goto press; } else if (active == 14) { // Mode mode++; if (mode > kModeAbc) mode = kModePre; // truncate current input at mode change strncpy(temp, _currentWord.c_str(), _currentCode.size()); temp[_currentCode.size()] = 0; prefix += temp; _currentCode.clear(); _currentWord.clear(); memset(repeatcount, 0, MAXWORDLEN); } else { goto press; } } } } press: strncpy(_predictiveResult, prefix.c_str(), 40); strncat(_predictiveResult, _currentWord.c_str(), 40); _predictiveResult[prefix.size() + _currentCode.size() + 1] = 0; getout: // if another window was shown, bring it up again if (!tmpwindow.active) closeWindow(); else { _gfx->restoreBlock(_game.window.x1, _game.window.y1, _game.window.x2, _game.window.y2, _game.window.buffer); free(_game.window.buffer); memcpy(&(_game.window), &tmpwindow, sizeof(AgiBlock)); _gfx->doUpdate(); } _system->setFeatureState(OSystem::kFeatureDisableKeyFiltering, false); _predictiveDialogRunning = false; return rc; }
void Mechanical::o_throneEnablePassage(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Enable throne passage", op); _vm->_resources[argv[0]]->setEnabled(getVar(var)); }