/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "common/file.h" #include "backends/keymapper/action.h" #include "backends/keymapper/keymap.h" #include "backends/keymapper/standard-actions.h" #include "common/translation.h" #include "freescape/freescape.h" #include "freescape/games/eclipse/eclipse.h" #include "freescape/language/8bitDetokeniser.h" namespace Freescape { EclipseEngine::EclipseEngine(OSystem *syst, const ADGameDescription *gd) : FreescapeEngine(syst, gd) { // These sounds can be overriden by the class of each platform _soundIndexStartFalling = -1; _soundIndexEndFalling = -1; _soundIndexNoShield = -1; _soundIndexNoEnergy = -1; _soundIndexFallen = -1; _soundIndexTimeout = -1; _soundIndexForceEndGame = -1; _soundIndexCrushed = -1; _soundIndexMissionComplete = -1; _maxEnergy = 27; _maxShield = 50; _initialEnergy = 16; _initialShield = 50; if (isDOS()) initDOS(); else if (isCPC()) initCPC(); else if (isC64()) initC64(); else if (isSpectrum()) initZX(); else if (isAmiga() || isAtariST()) initAmigaAtari(); _playerHeightNumber = 1; _playerHeightMaxNumber = 1; _playerWidth = 8; _playerDepth = 8; _stepUpDistance = 32; _playerStepIndex = 2; _playerSteps.clear(); _playerSteps.push_back(2); _playerSteps.push_back(30); _playerSteps.push_back(60); _angleRotationIndex = 1; _angleRotations.push_back(5); _angleRotations.push_back(10); _angleRotations.push_back(15); _endArea = 1; _endEntrance = 33; _lastThirtySeconds = 0; _lastFiveSeconds = 0; _lastSecond = -1; _resting = false; } void EclipseEngine::initGameState() { FreescapeEngine::initGameState(); _playerHeightNumber = 1; _gameStateVars[k8bitVariableEnergy] = _initialEnergy; _gameStateVars[k8bitVariableShield] = _initialShield; int seconds, minutes, hours; getTimeFromCountdown(seconds, minutes, hours); _lastThirtySeconds = seconds / 30; _lastFiveSeconds = seconds / 5; _resting = false; // Start playing music, if any, in any supported format playMusic("Total Eclipse Theme"); } void EclipseEngine::loadAssets() { FreescapeEngine::loadAssets(); Common::List globalIds = _areaMap[255]->getEntranceIds(); for (auto &it : _areaMap) { if (it._value->getAreaID() == 255) continue; it._value->addStructure(_areaMap[255]); if (isDemo()) { it._value->_name = " NOW TRAINING "; } for (auto &id : globalIds) { if (it._value->entranceWithID(id)) continue; Object *obj = _areaMap[255]->entranceWithID(id); assert(obj); assert(obj->getType() == ObjectType::kEntranceType); // The entrance is not in the current area, so we need to add it it._value->addObjectFromArea(id, _areaMap[255]); } } _timeoutMessage = _messagesList[1]; _noShieldMessage = _messagesList[0]; //_noEnergyMessage = _messagesList[16]; _fallenMessage = _messagesList[3]; _crushedMessage = _messagesList[2]; _areaMap[1]->addFloor(); if (isSpectrum()) _areaMap[1]->_paperColor = 1; if (!isDemo() && !isEclipse2()) { _areaMap[51]->addFloor(); _areaMap[51]->_paperColor = 1; // Workaround for fixing some planar objects from area 9 that have null size Object *obj = nullptr; obj = _areaMap[9]->objectWithID(7); assert(obj); obj->_size = 32 * Math::Vector3d(3, 0, 2); obj = _areaMap[9]->objectWithID(8); assert(obj); obj->_size = 32 * Math::Vector3d(3, 0, 2); obj = _areaMap[9]->objectWithID(9); assert(obj); obj->_size = 32 * Math::Vector3d(3, 0, 2); } } bool EclipseEngine::checkIfGameEnded() { if (_gameStateControl == kFreescapeGameStatePlaying) { if (_hasFallen && _avoidRenderingFrames == 0) { _hasFallen = false; if (isDOS()) playSoundFx(4, false); else playSound(_soundIndexStartFalling, false, _soundFxHandle); stopMovement(); // If shield is less than 11 after a fall, the game ends if (_gameStateVars[k8bitVariableShield] > 15 + 11) { _gameStateVars[k8bitVariableShield] -= 15; return false; // Game can continue } if (!_fallenMessage.empty()) insertTemporaryMessage(_fallenMessage, _countdown - 4); _gameStateControl = kFreescapeGameStateEnd; } else if (getGameBit(16)) { _gameStateControl = kFreescapeGameStateEnd; insertTemporaryMessage(_messagesList[4], INT_MIN); } FreescapeEngine::checkIfGameEnded(); } return false; } void EclipseEngine::endGame() { FreescapeEngine::endGame(); if (!_endGamePlayerEndArea) return; if (_gameStateControl == kFreescapeGameStateEnd) { removeTimers(); if (getGameBit(16)) { if (_countdown > - 3600) _countdown -= 10; else _countdown = -3600; } else { if (_countdown > 0) _countdown -= 10; else _countdown = 0; } } if (_endGameKeyPressed && (_countdown == 0 || _countdown == -3600)) { if (isSpectrum()) playSound(5, true, _soundFxHandle); _gameStateControl = kFreescapeGameStateRestart; } _endGameKeyPressed = false; } void EclipseEngine::initKeymaps(Common::Keymap *engineKeyMap, Common::Keymap *infoScreenKeyMap, const char *target) { FreescapeEngine::initKeymaps(engineKeyMap, infoScreenKeyMap, target); Common::Action *act; act = new Common::Action("SAVE", _("Save game")); act->setCustomEngineActionEvent(kActionSave); act->addDefaultInputMapping("s"); infoScreenKeyMap->addAction(act); act = new Common::Action("LOAD", _("Load game")); act->setCustomEngineActionEvent(kActionLoad); act->addDefaultInputMapping("l"); infoScreenKeyMap->addAction(act); act = new Common::Action("QUIT", _("Quit game")); act->setCustomEngineActionEvent(kActionEscape); if (isSpectrum()) act->addDefaultInputMapping("1"); else act->addDefaultInputMapping("ESCAPE"); infoScreenKeyMap->addAction(act); act = new Common::Action("TOGGLESOUND", _("Toggle Sound")); act->setCustomEngineActionEvent(kActionToggleSound); act->addDefaultInputMapping("t"); infoScreenKeyMap->addAction(act); act = new Common::Action("ROTL", _("Rotate Left")); act->setCustomEngineActionEvent(kActionRotateLeft); act->addDefaultInputMapping("q"); engineKeyMap->addAction(act); act = new Common::Action("ROTR", _("Rotate Right")); act->setCustomEngineActionEvent(kActionRotateRight); act->addDefaultInputMapping("w"); engineKeyMap->addAction(act); // I18N: Illustrates the angle at which you turn left or right. act = new Common::Action("CHNGANGLE", _("Change Angle")); act->setCustomEngineActionEvent(kActionIncreaseAngle); act->addDefaultInputMapping("a"); engineKeyMap->addAction(act); // I18N: STEP SIZE: Measures the size of one movement in the direction you are facing (1-250 standard distance units (SDUs)) act = new Common::Action("CHNGSTEPSIZE", _("Change Step Size")); act->setCustomEngineActionEvent(kActionChangeStepSize); act->addDefaultInputMapping("s"); engineKeyMap->addAction(act); act = new Common::Action("TGGLHEIGHT", _("Toggle Height")); act->setCustomEngineActionEvent(kActionToggleRiseLower); act->addDefaultInputMapping("JOY_B"); act->addDefaultInputMapping("h"); engineKeyMap->addAction(act); act = new Common::Action("REST", _("Rest")); act->setCustomEngineActionEvent(kActionRest); act->addDefaultInputMapping("JOY_Y"); act->addDefaultInputMapping("r"); engineKeyMap->addAction(act); act = new Common::Action("FACEFRWARD", _("Face Forward")); act->setCustomEngineActionEvent(kActionFaceForward); act->addDefaultInputMapping("f"); engineKeyMap->addAction(act); } void EclipseEngine::gotoArea(uint16 areaID, int entranceID) { debugC(1, kFreescapeDebugMove, "Jumping to area: %d, entrance: %d", areaID, entranceID); assert(_areaMap.contains(areaID)); _currentArea = _areaMap[areaID]; _currentArea->show(); _currentAreaMessages.clear(); _currentAreaMessages.push_back(_currentArea->_name); if (entranceID > 0) traverseEntrance(entranceID); else if (entranceID == -1) debugC(1, kFreescapeDebugMove, "Loading game, no change in position"); else error("Invalid area change!"); _lastPosition = _position; if (areaID == _startArea && entranceID == _startEntrance) { if (_pitch >= 180) _pitch = 360 - _pitch; playSound(_soundIndexStart, false, _soundFxHandle); if (isEclipse2()) { _gameStateControl = kFreescapeGameStateStart; _pitch = -10; } } if (areaID == _endArea && entranceID == _endEntrance) { _flyMode = true; if (isDemo()) _pitch = 20; else _pitch = 10; } else { playSound(_soundIndexAreaChange, false, _soundFxHandle); } _gfx->_keyColor = 0; swapPalette(areaID); _currentArea->_usualBackgroundColor = isCPC() ? 1 : 0; if (isAmiga() || isAtariST()) _currentArea->_skyColor = 15; resetInput(); } void EclipseEngine::drawBackground() { clearBackground(); _gfx->drawBackground(_currentArea->_skyColor); if (_currentArea && _currentArea->getAreaID() == 1) { if (ABS(_countdown) <= 15 * 60) // Last 15 minutes _gfx->drawBackground(5); if (ABS(_countdown) <= 10) // Last 10 seconds _gfx->drawBackground(1); float progress = 0; if (_countdown >= 0 || getGameBit(16)) progress = float(_countdown) / _initialCountdown; uint8 color1 = 15; uint8 color2 = 10; if (isSpectrum() || isCPC() || isC64()) { color1 = 2; color2 = 10; } else if (isAmiga() || isAtariST()) { color1 = 8; color2 = 14; } _gfx->drawEclipse(color1, color2, progress); } } void EclipseEngine::titleScreen() { if (isDOS()) playSoundFx(2, true); FreescapeEngine::titleScreen(); } void EclipseEngine::borderScreen() { if (_border) { drawBorder(); if (isDemo() && isCPC()) { drawFullscreenMessageAndWait(_messagesList[23]); drawFullscreenMessageAndWait(_messagesList[24]); drawFullscreenMessageAndWait(_messagesList[25]); } else if (isDemo() && isSpectrum()) { if (_variant & GF_ZX_DEMO_MICROHOBBY) { drawFullscreenMessageAndWait(_messagesList[23]); } else if (_variant & GF_ZX_DEMO_CRASH) { drawFullscreenMessageAndWait(_messagesList[9]); drawFullscreenMessageAndWait(_messagesList[10]); drawFullscreenMessageAndWait(_messagesList[11]); } } else { FreescapeEngine::borderScreen(); } } } void EclipseEngine::drawInfoMenu() { PauseToken pauseToken = pauseEngine(); if (_savedScreen) { _savedScreen->free(); delete _savedScreen; } _savedScreen = _gfx->getScreenshot(); uint32 color = 0; switch (_renderMode) { case Common::kRenderCGA: color = 1; break; case Common::kRenderZX: color = 6; break; default: color = 14; } uint8 r, g, b; _gfx->readFromPalette(color, r, g, b); uint32 front = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b); uint32 black = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0x00, 0x00, 0x00); Graphics::Surface *surface = new Graphics::Surface(); surface->create(_screenW, _screenH, _gfx->_texturePixelFormat); surface->fillRect(Common::Rect(88, 48, 231, 103), black); surface->frameRect(Common::Rect(88, 48, 231, 103), front); surface->frameRect(Common::Rect(90, 50, 229, 101), front); drawStringInSurface("L-LOAD S-SAVE", 105, 56, front, black, surface); if (isSpectrum()) drawStringInSurface("1-TERMINATE", 105, 64, front, black, surface); else drawStringInSurface("ESC-TERMINATE", 105, 64, front, black, surface); drawStringInSurface("T-TOGGLE", 128, 81, front, black, surface); drawStringInSurface("SOUND ON/OFF", 113, 88, front, black, surface); Texture *menuTexture = _gfx->createTexture(surface); Common::Event event; bool cont = true; while (!shouldQuit() && cont) { while (_eventManager->pollEvent(event)) { // Events switch (event.type) { case Common::EVENT_CUSTOM_ENGINE_ACTION_START: if (event.customType == kActionLoad) { _gfx->setViewport(_fullscreenViewArea); _eventManager->purgeKeyboardEvents(); loadGameDialog(); _gfx->setViewport(_viewArea); } else if (event.customType == kActionSave) { _gfx->setViewport(_fullscreenViewArea); _eventManager->purgeKeyboardEvents(); saveGameDialog(); _gfx->setViewport(_viewArea); } else if (isDOS() && event.customType == kActionToggleSound) { playSound(_soundIndexMenu, false, _soundFxHandle); } else if ((isDOS() || isCPC() || isSpectrum()) && event.customType == kActionEscape) { _forceEndGame = true; cont = false; } else cont = false; break; case Common::EVENT_KEYDOWN: cont = false; break; case Common::EVENT_SCREEN_CHANGED: _gfx->computeScreenViewport(); break; default: break; } } drawFrame(); _gfx->drawTexturedRect2D(_fullscreenViewArea, _fullscreenViewArea, menuTexture); _gfx->flipBuffer(); g_system->updateScreen(); g_system->delayMillis(15); // try to target ~60 FPS } _savedScreen->free(); delete _savedScreen; _savedScreen = nullptr; surface->free(); delete surface; delete menuTexture; pauseToken.clear(); } void EclipseEngine::pressedKey(const int keycode) { if (keycode == kActionIncreaseAngle) { changeAngle(1, true); } else if (keycode == kActionChangeStepSize) { changeStepSize(); } else if (keycode == kActionToggleRiseLower) { if (_playerHeightNumber == 0) rise(); else if (_playerHeightNumber == 1) lower(); else error("Invalid player height index: %d", _playerHeightNumber); } else if (keycode == kActionRest) { if (_currentArea->getAreaID() == 1) { playSoundFx(3, false); if (_temporaryMessages.empty()) insertTemporaryMessage(_messagesList[6], _countdown - 2); } else { _resting = true; if (_temporaryMessages.empty()) insertTemporaryMessage(_messagesList[7], _countdown - 2); _countdown = _countdown - 5; } } else if (keycode == kActionFaceForward) { _pitch = 0; updateCamera(); } } void EclipseEngine::releasedKey(const int keycode) { if (keycode == kActionRiseOrFlyUp) _resting = false; } void EclipseEngine::drawAnalogClock(Graphics::Surface *surface, int x, int y, uint32 colorHand1, uint32 colorHand2, uint32 colorBack) { // These calls will cover the pixels of the hardcoded clock image drawAnalogClockHand(surface, x, y, 6 * 6 - 90, 12, colorBack); drawAnalogClockHand(surface, x, y, 7 * 6 - 90, 12, colorBack); drawAnalogClockHand(surface, x, y, 41 * 6 - 90, 11, colorBack); drawAnalogClockHand(surface, x, y, 42 * 6 - 90, 11, colorBack); drawAnalogClockHand(surface, x, y, 0 * 6 - 90, 11, colorBack); int seconds, minutes, hours; getTimeFromCountdown(seconds, minutes, hours); hours = 7 + 2 - hours; // It's 7 o-clock when the game starts minutes = 59 - minutes; seconds = 59 - seconds; drawAnalogClockHand(surface, x, y, hours * 30 - 90, 11, colorHand1); drawAnalogClockHand(surface, x, y, minutes * 6 - 90, 11, colorHand1); drawAnalogClockHand(surface, x, y, seconds * 6 - 90, 11, colorHand2); } void EclipseEngine::drawAnalogClockHand(Graphics::Surface *surface, int x, int y, double degrees, double magnitude, uint32 color) { const double degtorad = (M_PI * 2) / 360; double w = magnitude * cos(degrees * degtorad); double h = magnitude * sin(degrees * degtorad); surface->drawLine(x, y, x+(int)w, y+(int)h, color); if (isC64()) { surface->drawLine(x+1, y, x+1+(int)w, y+(int)h, color); } } void EclipseEngine::drawCompass(Graphics::Surface *surface, int x, int y, double degrees, double magnitude, uint32 color) { const double degtorad = (M_PI * 2) / 360; double w = magnitude * cos(-degrees * degtorad); double h = magnitude * sin(-degrees * degtorad); int dx = 0; int dy = 0; // Adjust dx and dy to make the compass look like a compass if (degrees == 0 || degrees == 360) { dx = 1; dy = 2; } else if (degrees > 0 && degrees < 90) { dx = 2; dy = 1; } else if (degrees == 90) { dx = 2; dy = 1; } else if (degrees > 90 && degrees < 180) { dx = 2; dy = -1; } else if (degrees == 180) { dx = 1; dy = 2; } else if (degrees > 180 && degrees < 270) { dx = -2; dy = -1; } else if (degrees == 270) { dx = 2; dy = 1; } else if (degrees > 270 && degrees < 360) { dx = -2; dy = 1; } surface->drawLine(x, y, x+(int)w, y+(int)h, color); surface->drawLine(x - dx, y - dy, x+(int)w, y+(int)h, color); surface->drawLine(x + dx, y + dy, x+(int)w, y+(int)h, color); surface->drawLine(x - dx, y - dy, x+(int)-w, y+(int)-h, color); surface->drawLine(x + dx, y + dy, x+(int)-w, y+(int)-h, color); } // Copied from BITMAP::circlefill in engines/ags/lib/allegro/surface.cpp void fillCircle(Graphics::Surface *surface, int x, int y, int radius, int color) { int cx = 0; int cy = radius; int df = 1 - radius; int d_e = 3; int d_se = -2 * radius + 5; do { surface->hLine(x - cy, y - cx, x + cy, color); if (cx) surface->hLine(x - cy, y + cx, x + cy, color); if (df < 0) { df += d_e; d_e += 2; d_se += 2; } else { if (cx != cy) { surface->hLine(x - cx, y - cy, x + cx, color); if (cy) surface->hLine(x - cx, y + cy, x + cx, color); } df += d_se; d_e += 2; d_se += 4; cy--; } cx++; } while (cx <= cy); } void EclipseEngine::drawEclipseIndicator(Graphics::Surface *surface, int x, int y, uint32 color1, uint32 color2) { uint32 black = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0x00, 0x00, 0x00); // These calls will cover the pixels of the hardcoded eclipse image surface->fillRect(Common::Rect(x, y, x + 50, y + 20), black); float progress = 0; if (_countdown >= 0) progress = float(_countdown) / _initialCountdown; int difference = 14 * progress; fillCircle(surface, x + 7, y + 10, 7, color1); // Sun fillCircle(surface, x + 7 + difference, y + 10, 7, color2); // Moon } void EclipseEngine::drawIndicator(Graphics::Surface *surface, int xPosition, int yPosition, int separation) { if (_indicators.size() == 0) return; for (int i = 0; i < 5; i++) { if (isSpectrum() || isC64()) { if (_gameStateVars[kVariableEclipseAnkhs] <= i) continue; } else if (_gameStateVars[kVariableEclipseAnkhs] > i) continue; surface->copyRectToSurface(*_indicators[0], xPosition + separation * i, yPosition, Common::Rect(_indicators[0]->w, _indicators[0]->h)); } } void EclipseEngine::drawSensorShoot(Sensor *sensor) { Math::Vector3d target; float distance = 5; int axisToSkip = -1; if (sensor->_axis == 0x1 || sensor->_axis == 0x2) axisToSkip = 0; if (sensor->_axis == 0x10 || sensor->_axis == 0x20) axisToSkip = 2; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (i == j) { target = sensor->getOrigin(); if (i != axisToSkip) target.setValue(i, target.getValue(i) + distance); _gfx->renderSensorShoot(1, sensor->getOrigin(), target, _viewArea); target = sensor->getOrigin(); if (i != axisToSkip) target.setValue(i, target.getValue(i) - distance); _gfx->renderSensorShoot(1, sensor->getOrigin(), target, _viewArea); } else { target = sensor->getOrigin(); if (i != axisToSkip) target.setValue(i, target.getValue(i) + distance); if (j != axisToSkip) target.setValue(j, target.getValue(j) + distance); _gfx->renderSensorShoot(1, sensor->getOrigin(), target, _viewArea); target = sensor->getOrigin(); if (i != axisToSkip) target.setValue(i, target.getValue(i) + distance); if (j != axisToSkip) target.setValue(j, target.getValue(j) - distance); _gfx->renderSensorShoot(1, sensor->getOrigin(), target, _viewArea); target = sensor->getOrigin(); if (i != axisToSkip) target.setValue(i, target.getValue(i) - distance); if (j != axisToSkip) target.setValue(j, target.getValue(j) - distance); _gfx->renderSensorShoot(1, sensor->getOrigin(), target, _viewArea); target = sensor->getOrigin(); if (i != axisToSkip) target.setValue(i, target.getValue(i) - distance); if (j != axisToSkip) target.setValue(j, target.getValue(j) + distance); _gfx->renderSensorShoot(1, sensor->getOrigin(), target, _viewArea); } } } } void EclipseEngine::drawScoreString(int score, int x, int y, uint32 front, uint32 back, Graphics::Surface *surface) { Common::String scoreStr = Common::String::format("%07d", score); if (isDOS() || isCPC() || isSpectrum()) { scoreStr = shiftStr(scoreStr, 'Z' - '0' + 1); if (_renderMode == Common::RenderMode::kRenderEGA || isSpectrum()) { drawStringInSurface(scoreStr, x, y, front, back, surface); return; } } // Start in x,y and draw each digit, from left to right, adding a gap every 3 digits int gapSize = isC64() ? 8 : 4; for (int i = 0; i < int(scoreStr.size()); i++) { drawStringInSurface(Common::String(scoreStr[i]), x, y, front, back, surface); x += 8; if ((i - scoreStr.size() + 1) % 3 == 1) x += gapSize; } } void EclipseEngine::updateTimeVariables() { if (isEclipse2() && _gameStateControl == kFreescapeGameStateStart) { executeLocalGlobalConditions(false, true, false); _gameStateControl = kFreescapeGameStatePlaying; } if (_gameStateControl != kFreescapeGameStatePlaying) return; // This function only executes "on collision" room/global conditions int seconds, minutes, hours; getTimeFromCountdown(seconds, minutes, hours); if (_lastFiveSeconds != seconds / 5) { _lastFiveSeconds = seconds / 5; executeLocalGlobalConditions(false, false, true); } if (_lastThirtySeconds != seconds / 30) { _lastThirtySeconds = seconds / 30; if (!_resting && _gameStateVars[k8bitVariableEnergy] > 0) { _gameStateVars[k8bitVariableEnergy] -= 1; } if (_gameStateVars[k8bitVariableShield] < _maxShield) { _gameStateVars[k8bitVariableShield] += 1; } } if (isEclipse() && isSpectrum() && _currentArea->getAreaID() == 42) { if (_lastSecond != seconds) { // Swap ink and paper colors every second _lastSecond = seconds; int tmp = _gfx->_inkColor; _gfx->_inkColor = _gfx->_paperColor; _gfx->_paperColor = tmp; } } } void EclipseEngine::executePrint(FCLInstruction &instruction) { uint16 index = instruction._source - 1; debugC(1, kFreescapeDebugCode, "Printing message %d", index); if (index > 127) { index = _messagesList.size() - (index - 254) - 2; drawFullscreenMessageAndWait(_messagesList[index]); return; } insertTemporaryMessage(_messagesList[index], _countdown - 2); } Common::Error EclipseEngine::saveGameStreamExtended(Common::WriteStream *stream, bool isAutosave) { return Common::kNoError; } Common::Error EclipseEngine::loadGameStreamExtended(Common::SeekableReadStream *stream) { return Common::kNoError; } } // End of namespace Freescape