diff options
Diffstat (limited to 'engines/bladerunner/bladerunner.cpp')
-rw-r--r-- | engines/bladerunner/bladerunner.cpp | 942 |
1 files changed, 942 insertions, 0 deletions
diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp new file mode 100644 index 0000000000..9cd0e0ddc2 --- /dev/null +++ b/engines/bladerunner/bladerunner.cpp @@ -0,0 +1,942 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "bladerunner/bladerunner.h" + +#include "bladerunner/actor.h" +#include "bladerunner/adq.h" +#include "bladerunner/ambient_sounds.h" +#include "bladerunner/audio_player.h" +#include "bladerunner/audio_speech.h" +#include "bladerunner/chapters.h" +#include "bladerunner/combat.h" +#include "bladerunner/crimes_database.h" +#include "bladerunner/font.h" +#include "bladerunner/gameflags.h" +#include "bladerunner/gameinfo.h" +#include "bladerunner/image.h" +#include "bladerunner/item_pickup.h" +#include "bladerunner/items.h" +#include "bladerunner/lights.h" +#include "bladerunner/mouse.h" +#include "bladerunner/outtake.h" +#include "bladerunner/obstacles.h" +#include "bladerunner/scene.h" +#include "bladerunner/scene_objects.h" +#include "bladerunner/script/init.h" +#include "bladerunner/script/script.h" +#include "bladerunner/settings.h" +#include "bladerunner/shape.h" +#include "bladerunner/slice_animations.h" +#include "bladerunner/slice_renderer.h" +#include "bladerunner/text_resource.h" +#include "bladerunner/vqa_decoder.h" +#include "bladerunner/waypoints.h" + +#include "common/array.h" +#include "common/error.h" +#include "common/events.h" +#include "common/system.h" + +#include "engines/util.h" + +#include "graphics/pixelformat.h" +#include "suspects_database.h" + +namespace BladeRunner { + +BladeRunnerEngine::BladeRunnerEngine(OSystem *syst) + : Engine(syst), + _rnd("bladerunner") { + _windowIsActive = true; + _gameIsRunning = true; + _playerLosesControlCounter = 0; + + _crimesDatabase = nullptr; + _script = new Script(this); + _settings = new Settings(this); + _lights = new Lights(this); + _combat = new Combat(this); + _adq = new ADQ(this); + _obstacles = new Obstacles(this); + _itemPickup = new ItemPickup(this); + + _walkSoundId = -1; + _walkSoundVolume = 0; + _walkSoundBalance = 0; +} + +BladeRunnerEngine::~BladeRunnerEngine() { + // delete _sliceRenderer; + // delete _sliceAnimations; + // delete _settings; + // delete _script; + // delete _scene; + // delete[] _gameVars; + // delete _gameFlags; + // delete _gameInfo; + // delete _clues; + // delete _chapters; + // delete _audioSpeech; + // delete _audioPlayer; + // delete _ambientSounds; + + // _surface1.free(); + // _surface2.free(); + + // delete[] _zBuffer1; + // delete[] _zBuffer2; + + delete _itemPickup; + delete _obstacles; + delete _adq; + delete _combat; + delete _lights; + delete _settings; + delete _script; +} + +bool BladeRunnerEngine::hasFeature(EngineFeature f) const { + return f == kSupportsRTL; +} + +Common::Error BladeRunnerEngine::run() { + Graphics::PixelFormat format = createRGB555(); + initGraphics(640, 480, true, &format); + + _system->showMouse(true); + + if (!startup()) { + shutdown(); + return Common::Error(Common::kUnknownError, "Failed to initialize resources"); + } + + if (warnUserAboutUnsupportedGame()) { + init2(); + + /* TODO: Check for save games and enter KIA */ + gameLoop(); + } + + shutdown(); + + return Common::kNoError; +} + +bool BladeRunnerEngine::startup(bool hasSavegames) { + bool r; + + _surface1.create(640, 480, createRGB555()); + + r = openArchive("STARTUP.MIX"); + if (!r) + return false; + + // TODO: Timer + + _gameInfo = new GameInfo(this); + if (!_gameInfo) + return false; + + r = _gameInfo->open("GAMEINFO.DAT"); + if (!r) + return false; + + // TODO: Create datetime - not used + + // TODO: Create graphics surfaces 1-4 + + // TODO: Allocate audio cache + + if (hasSavegames) { + if (!loadSplash()) { + return false; + } + } + + _waypoints = new Waypoints(this, _gameInfo->getWaypointCount()); + + // TODO: Cover waypoints + + // TODO: Flee waypoints + + _gameVars = new int[_gameInfo->getGlobalVarCount()]; + + // TODO: Actor AI DLL init + + // Seed rand + + // TODO: Sine and cosine lookup tables for intervals of 1.0, 4.0, and 12.0 + + _view = new View(); + + _sceneObjects = new SceneObjects(this, _view); + + _gameFlags = new GameFlags(); + _gameFlags->setFlagCount(_gameInfo->getFlagCount()); + + _items = new Items(this); + + // Setup sound output + + _audioPlayer = new AudioPlayer(this); + + // TODO: Audio: Music + + _audioSpeech = new AudioSpeech(this); + + _ambientSounds = new AmbientSounds(this); + + // TODO: Read BLADE.INI + + _chapters = new Chapters(this); + if (!_chapters) + return false; + + if (!openArchive("MUSIC.MIX")) + return false; + + if (!openArchive("SFX.MIX")) + return false; + + if (!openArchive("SPCHSFX.TLK")) + return false; + + // TODO: Video overlays + + // TODO: Proper ZBuf class + _zBuffer1 = new uint16[640 * 480]; + _zBuffer2 = new uint16[640 * 480]; + + int actorCount = (int)_gameInfo->getActorCount(); + assert(actorCount < 99); + for (int i = 0; i != actorCount; ++i) { + _actors[i] = new Actor(this, i); + _actors[i]->setup(i); + } + _voiceoverActor = new Actor(this, 99); + _playerActor = _actors[_gameInfo->getPlayerId()]; + + _playerActor->setFPS(15); + + // TODO: set _playerActor countdown timer 6 + + // TODO: Set actor ids (redundant?) + + // TODO: Police Maze + + _textActorNames = new TextResource(this); + if (!_textActorNames->open("ACTORS")) + return false; + + _textCrimes = new TextResource(this); + if (!_textCrimes->open("CRIMES")) + return false; + + _textCluetype = new TextResource(this); + if (!_textCluetype->open("CLUETYPE")) + return false; + + _textKIA = new TextResource(this); + if (!_textKIA->open("KIA")) + return false; + + _textSpindest = new TextResource(this); + if (!_textSpindest->open("SPINDEST")) + return false; + + _textVK = new TextResource(this); + if (!_textVK->open("VK")) + return false; + + _textOptions = new TextResource(this); + if (!_textOptions->open("OPTIONS")) + return false; + + // TODO: Dialogue Menu (DLGMENU.TRE) + + _suspectsDatabase = new SuspectsDatabase(this, _gameInfo->getSuspectsDatabaseSize()); + + // TODO: KIA + + // TODO: Spinner Interface + + // TODO: Elevators + + // TODO: Scores + + _mainFont = new Font(this); + _mainFont->open("KIA6PT.FON", 640, 480, -1, 0, 0x252D); + _mainFont->setSpacing(1, 0); + + for (int i = 0; i != 43; ++i) { + Shape *shape = new Shape(this); + shape->readFromContainer("SHAPES.SHP", i); + _shapes.push_back(shape); + } + + // TODO: Esper + + // TODO: VK + + _mouse = new Mouse(this); + // _mouse->setCursorPosition(320, 240); + _mouse->setCursor(0); + + _sliceAnimations = new SliceAnimations(this); + r = _sliceAnimations->open("INDEX.DAT"); + if (!r) + return false; + + // TODO: Support cdframes + + r = _sliceAnimations->openHDFrames(); + if (!r) + return false; + + r = _sliceAnimations->openCoreAnim(); + if (!r) + return false; + + _sliceRenderer = new SliceRenderer(this); + + _crimesDatabase = new CrimesDatabase(this, "CLUES", _gameInfo->getClueCount()); + + // TODO: Scene + _scene = new Scene(this); + + // Load INIT.DLL + ScriptInit initScript(this); + initScript.SCRIPT_Initialize_Game(); + + // TODO: Load AI-ACT1.DLL + _aiScripts = new AIScripts(this); + + initChapterAndScene(); + + return true; +} + +void BladeRunnerEngine::initChapterAndScene() { + // TODO: Init actors... + for (int i = 0, end = _gameInfo->getActorCount(); i != end; ++i) + _aiScripts->Initialize(i); + + for (int i = 0, end = _gameInfo->getActorCount(); i != end; ++i) + _actors[i]->changeAnimationMode(i); + + _settings->setChapter(1); + _settings->setNewSetAndScene(_gameInfo->getInitialSetId(), _gameInfo->getInitialSceneId()); +} + +void BladeRunnerEngine::shutdown() { + _mixer->stopAll(); + + // TODO: Write BLADE.INI + + // TODO: Shutdown VK + + // TODO: Shutdown Esper + + delete _mouse; + _mouse = nullptr; + + for (uint i = 0; i != _shapes.size(); ++i) { + delete _shapes[i]; + } + _shapes.clear(); + + // TODO: Shutdown Scene + delete _scene; + + if (_chapters) { + if (_chapters->hasOpenResources()) + _chapters->closeResources(); + delete _chapters; + _chapters = nullptr; + } + + delete _crimesDatabase; + _crimesDatabase = nullptr; + + delete _sliceRenderer; + _sliceRenderer = nullptr; + + delete _sliceAnimations; + _sliceAnimations = nullptr; + + delete _textActorNames; + _textActorNames = nullptr; + + delete _textCrimes; + _textCrimes = nullptr; + + delete _textCluetype; + _textCluetype = nullptr; + + delete _textKIA; + _textKIA = nullptr; + + delete _textSpindest; + _textSpindest = nullptr; + + delete _textVK; + _textVK = nullptr; + + delete _textOptions; + _textOptions = nullptr; + + // TODO: Delete dialogue menu + + delete _ambientSounds; + + // TODO: Delete overlays + + delete _audioSpeech; + + // TODO: Delete Audio: Music + + delete _audioPlayer; + + // Shutdown sound output + + if (isArchiveOpen("MUSIC.MIX")) + closeArchive("MUSIC.MIX"); + + if (isArchiveOpen("SFX.MIX")) + closeArchive("SFX.MIX"); + + if (isArchiveOpen("SPCHSFX.TLK")) + closeArchive("SPCHSFX.TLK"); + + if (_mainFont) { + _mainFont->close(); + delete _mainFont; + _mainFont = nullptr; + } + + delete _items; + _items = nullptr; + + delete _gameFlags; + _gameFlags = nullptr; + + delete _view; + _view = nullptr; + + delete _sceneObjects; + _sceneObjects = nullptr; + + // TODO: Delete sine and cosine lookup tables + + // TODO: Unload AI dll + + delete[] _gameVars; + _gameVars = nullptr; + + delete _waypoints; + _waypoints = nullptr; + + // TODO: Delete Cover waypoints + + // TODO: Delete Flee waypoints + + // TODO: Delete Scores + + // TODO: Delete Elevators + + // TODO: Delete Spinner Interface + + // TODO: Delete KIA + + delete _suspectsDatabase; + _suspectsDatabase = nullptr; + + // TODO: Delete datetime - not used + + // TODO: Delete actors + + // TODO: Delete proper ZBuf class + delete[] _zBuffer1; + _zBuffer1 = nullptr; + + delete[] _zBuffer2; + _zBuffer2 = nullptr; + + delete _gameInfo; + _gameInfo = nullptr; + + // TODO: Delete graphics surfaces here + _surface1.free(); + _surface2.free(); + + if (isArchiveOpen("STARTUP.MIX")) + closeArchive("STARTUP.MIX"); + + // TODO: Delete MIXArchives here + + // TODO: Delete Timer +} + +bool BladeRunnerEngine::loadSplash() { + Image img(this); + if (!img.open("SPLASH.IMG")) + return false; + + img.copyToSurface(&_surface1); + + _system->copyRectToScreen(_surface1.getPixels(), _surface1.pitch, 0, 0, _surface1.w, _surface1.h); + _system->updateScreen(); + + return false; +} + +bool BladeRunnerEngine::init2() { + return true; +} + +void BladeRunnerEngine::gameLoop() { + _gameIsRunning = true; + do { + /* TODO: check player death */ + gameTick(); + } while (_gameIsRunning); +} + +#if _DEBUG + +void drawBBox(Vector3 start, Vector3 end, View *view, Graphics::Surface *surface, int color) { + Vector3 bfl = view->calculateScreenPosition(Vector3(start.x, start.y, start.z)); + Vector3 bfr = view->calculateScreenPosition(Vector3(start.x, end.y, start.z)); + Vector3 bbr = view->calculateScreenPosition(Vector3(end.x, end.y, start.z)); + Vector3 bbl = view->calculateScreenPosition(Vector3(end.x, start.y, start.z)); + + Vector3 tfl = view->calculateScreenPosition(Vector3(start.x, start.y, end.z)); + Vector3 tfr = view->calculateScreenPosition(Vector3(start.x, end.y, end.z)); + Vector3 tbr = view->calculateScreenPosition(Vector3(end.x, end.y, end.z)); + Vector3 tbl = view->calculateScreenPosition(Vector3(end.x, start.y, end.z)); + + surface->drawLine(bfl.x, bfl.y, bfr.x, bfr.y, color); + surface->drawLine(bfr.x, bfr.y, bbr.x, bbr.y, color); + surface->drawLine(bbr.x, bbr.y, bbl.x, bbl.y, color); + surface->drawLine(bbl.x, bbl.y, bfl.x, bfl.y, color); + + surface->drawLine(tfl.x, tfl.y, tfr.x, tfr.y, color); + surface->drawLine(tfr.x, tfr.y, tbr.x, tbr.y, color); + surface->drawLine(tbr.x, tbr.y, tbl.x, tbl.y, color); + surface->drawLine(tbl.x, tbl.y, tfl.x, tfl.y, color); + + surface->drawLine(bfl.x, bfl.y, tfl.x, tfl.y, color); + surface->drawLine(bfr.x, bfr.y, tfr.x, tfr.y, color); + surface->drawLine(bbr.x, bbr.y, tbr.x, tbr.y, color); + surface->drawLine(bbl.x, bbl.y, tbl.x, tbl.y, color); +} +#endif + +void BladeRunnerEngine::gameTick() { + handleEvents(); + + if (_gameIsRunning && _windowIsActive) { + // TODO: Only run if not in Kia, script, nor AI + _settings->openNewScene(); + + // TODO: Autosave + // TODO: Kia + // TODO: Spinner + // TODO: Esper + // TODO: VK + // TODO: Elevators + // TODO: Scores + + _adq->tick(); + if (_scene->didPlayerWalkIn()) { + _script->PlayerWalkedIn(); + } + // TODO: Gun range announcements + // TODO: ZBUF repair dirty rects + + _ambientSounds->tick(); + + bool backgroundChanged = false; + int frame = _scene->advanceFrame(_surface1, _zBuffer1); + if (frame >= 0) { + _script->SceneFrameAdvanced(frame); + backgroundChanged = true; + } + (void)backgroundChanged; + _surface2.copyFrom(_surface1); + memcpy(_zBuffer2, _zBuffer1, 640 * 480 * 2); + +#if 0 + { + for (int y = 0; y != 480; ++y) { + for (int x = 0; x != 640; ++x) { + if (_scene->_regions->getRegionAtXY(x, y) >= 0) { + uint16 *p = (uint16*)_surface2.getBasePtr(x, y); + *p = 0x7C00; + } + if (_scene->_exits->getRegionAtXY(x, y) >= 0) { + uint16 *p = (uint16*)_surface2.getBasePtr(x, y); + *p = 0x7C08; + } + } + } + } +#endif + + // TODO: Render overlays + // TODO: Tick Actor AI and Timers + + if (_settings->getNewScene() == -1 || _script->_inScriptCounter /* || in_ai */) { + _sliceRenderer->setView(*_view); + + // Tick and draw all actors in current set + //int setId = _scene->_setId; + for (int i = 0, end = _gameInfo->getActorCount(); i != end; ++i) { + //if (_actors[i]->getSetId() == setId) { + if (i == 0 || i == 23) { // Currently limited to McCoy and Officer Leroy + _actors[i]->tick(backgroundChanged); + } + } + + _items->tick(); + + _itemPickup->tick(); + _itemPickup->draw(); + + // TODO: Draw dialogue menu + + Common::Point p = _eventMan->getMousePos(); + _mouse->tick(p.x, p.y); + _mouse->draw(_surface2, p.x, p.y); + + // TODO: Process AUD + // TODO: Footstep sound + + if (_walkSoundId >= 0) { + const char *name = _gameInfo->getSfxTrack(_walkSoundId); + _audioPlayer->playAud(name, _walkSoundVolume, _walkSoundBalance, _walkSoundBalance, 50, 0); + _walkSoundId = -1; + } + +#if 0 + //draw scene objects + int count = _sceneObjects->_count; + if (count > 0) { + for (int i = 0; i < count; i++) { + SceneObject *sceneObject = &_sceneObjects->_sceneObjects[_sceneObjects->_sceneObjectsSortedByDistance[i]]; + + BoundingBox *bbox = &sceneObject->_boundingBox; + Vector3 a, b; + bbox->getXYZ(&a.x, &a.y, &a.z, &b.x, &b.y, &b.z); + + int color = 0b111111111111111; + if (sceneObject->_sceneObjectType == SceneObjectTypeActor) { + color = 0b111110000000000; + } + if (sceneObject->_sceneObjectType == SceneObjectTypeObject) { + color = 0b011110111101111; + //if (sceneObject->_isObstacle) + // color += 0b100000000000000; + if (sceneObject->_isClickable) + color = 0b000001111100000; + //if (sceneObject->_isTarget) + // color += 0b000000000010000; + } + + drawBBox(a, b, _view, &_surface2, color); + + //_surface2.frameRect(sceneObject->_screenRectangle, color); + + Vector3 pos = _view->calculateScreenPosition(0.5 * (a + b)); + switch (sceneObject->_sceneObjectType) { + case SceneObjectTypeActor: + _mainFont->drawColor(_textActorNames->getText(sceneObject->_sceneObjectId - SCENE_OBJECTS_ACTORS_OFFSET), _surface2, pos.x, pos.y, color); + break; + case SceneObjectTypeItem: + _mainFont->drawColor("item", _surface2, pos.x, pos.y, color); + break; + case SceneObjectTypeObject: + _mainFont->drawColor(_scene->objectGetName(sceneObject->_sceneObjectId - SCENE_OBJECTS_OBJECTS_OFFSET), _surface2, pos.x, pos.y, color); + break; + } + } + } + + //draw regions + for (int i = 0; i < 10; i++) { + Region *region = &_scene->_regions->_regions[i]; + if (!region->_present) continue; + _surface2.frameRect(region->_rectangle, 0b000000000011111); + } + + for (int i = 0; i < 10; i++) { + Region *region = &_scene->_exits->_regions[i]; + if (!region->_present) continue; + _surface2.frameRect(region->_rectangle, 0b111111111111111); + } + + for (int i = 0; i < _scene->_set->_walkboxCount; i++) { + Walkbox *walkbox = &_scene->_set->_walkboxes[i]; + + for (int j = 0; j < walkbox->_vertexCount; j++) { + Vector3 start = _view->calculateScreenPosition(walkbox->_vertices[j]); + Vector3 end = _view->calculateScreenPosition(walkbox->_vertices[(j + 1) % walkbox->_vertexCount]); + //debug("walkbox[%i][%i] = x=%f y=%f x=%f y=%f", i, j, start.x, start.y, end.x, end.y); + _surface2.drawLine(start.x, start.y, end.x, end.y, 0b111111111100000); + Vector3 pos = _view->calculateScreenPosition(0.5 * (start + end)); + _mainFont->drawColor(walkbox->_name, _surface2, pos.x, pos.y, 0b111111111100000); + } + + } + + for (int i = 0; i < (int)_lights->_lights.size(); i++) { + Light *light = _lights->_lights[i]; + Matrix4x3 m = light->_matrix; + Vector3 pos = Vector3(m(0, 3), m(1, 3), m(2, 3)); + Vector3 size = Vector3(5.0f, 5.0f, 5.0f); + int colorR = (light->_color.r * 31.0f); + int colorG = (light->_color.g * 31.0f); + int colorB = (light->_color.b * 31.0f); + int color = (colorR << 10) + (colorG << 5) + colorB; + drawBBox(pos - size, pos + size, _view, &_surface2, color); + + } +#endif + + _system->copyRectToScreen((const byte *)_surface2.getBasePtr(0, 0), _surface2.pitch, 0, 0, 640, 480); + _system->updateScreen(); + _system->delayMillis(10); + } + } +} + +void BladeRunnerEngine::handleEvents() { + if (shouldQuit()) { + _gameIsRunning = false; + return; + } + + Common::Event event; + Common::EventManager *eventMan = _system->getEventManager(); + while (eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_RBUTTONDOWN: + handleMouseClick(event.mouse.x, event.mouse.y); + default: + ; + } + } +} + +void BladeRunnerEngine::handleMouseClick(int x, int y) { + if (!playerHasControl() || _mouse->isDisabled()) + return; + + Vector3 mousePosition = _mouse->getXYZ(x, y); + + int isClickable; + int isObstacle; + int isTarget; + + int sceneObjectId = _sceneObjects->findByXYZ(&isClickable, &isObstacle, &isTarget, mousePosition.x, mousePosition.y, mousePosition.z, 1, 0, 1); + int exitIndex = _scene->_exits->getRegionAtXY(x, y); + + debug("%d %d", sceneObjectId, exitIndex); + + if ((sceneObjectId < 0 || sceneObjectId > 73) && exitIndex >= 0) { + handleMouseClickExit(x, y, exitIndex); + return; + } + + int regionIndex = _scene->_regions->getRegionAtXY(x, y); + if (regionIndex >= 0) { + handleMouseClickRegion(x, y, regionIndex); + return; + } + + if (sceneObjectId == -1) { + bool isRunning; + _playerActor->loopWalkToXYZ(mousePosition, 0, false, false, false, &isRunning); + debug("Clicked on nothing %f, %f, %f", mousePosition.x, mousePosition.y, mousePosition.z); + return; + } else if (sceneObjectId >= 0 && sceneObjectId <= 73) { + handleMouseClickActor(x, y, sceneObjectId); + return; + } else if (sceneObjectId >= 74 && sceneObjectId <= 197) { + handleMouseClickItem(x, y, sceneObjectId - 74); + return; + } else if (sceneObjectId >= 198 && sceneObjectId <= 293) { + handleMouseClick3DObject(x, y, sceneObjectId - 198, isClickable, isTarget); + return; + } +} + +void BladeRunnerEngine::handleMouseClickExit(int x, int y, int exitIndex) { + // clickedOnExit(exitType, x, y); + debug("clicked on exit %d %d %d", exitIndex, x, y); + _script->ClickedOnExit(exitIndex); +} + +void BladeRunnerEngine::handleMouseClickRegion(int x, int y, int regionIndex) { + debug("clicked on region %d %d %d", regionIndex, x, y); + _script->ClickedOn2DRegion(regionIndex); +} + +void BladeRunnerEngine::handleMouseClick3DObject(int x, int y, int objectId, bool isClickable, bool isTarget) { + const char *objectName = _scene->objectGetName(objectId); + debug("Clicked on object %s", objectName); + _script->ClickedOn3DObject(objectName, false); +} + +void BladeRunnerEngine::handleMouseClickItem(int x, int y, int itemId) { + debug("Clicked on item %d", itemId); + _script->ClickedOnItem(itemId, false); +} + +void BladeRunnerEngine::handleMouseClickActor(int x, int y, int actorId) { + debug("Clicked on actor %d", actorId); + _script->ClickedOnActor(actorId); +} + +void BladeRunnerEngine::gameWaitForActive() { + while (!_windowIsActive) { + handleEvents(); + } +} + +void BladeRunnerEngine::loopActorSpeaking() { + if (!_audioSpeech->isPlaying()) + return; + + playerLosesControl(); + + do { + gameTick(); + } while (_gameIsRunning && _audioSpeech->isPlaying()); + + playerGainsControl(); +} + +void BladeRunnerEngine::outtakePlay(int id, bool noLocalization, int container) { + Common::String name = _gameInfo->getOuttake(id); + + OuttakePlayer player(this); + + player.play(name, noLocalization, container); +} + +bool BladeRunnerEngine::openArchive(const Common::String &name) { + uint i; + + // If archive is already open, return true + for (i = 0; i != kArchiveCount; ++i) { + if (_archives[i].isOpen() && _archives[i].getName() == name) + return true; + } + + // Find first available slot + for (i = 0; i != kArchiveCount; ++i) { + if (!_archives[i].isOpen()) + break; + } + if (i == kArchiveCount) { + /* TODO: BLADE.EXE retires the least recently used + * archive when it runs out of slots. */ + + error("openArchive: No more archive slots"); + return false; + } + + _archives[i].open(name); + return _archives[i].isOpen(); +} + +bool BladeRunnerEngine::closeArchive(const Common::String &name) { + for (uint i = 0; i != 10; ++i) { + if (_archives[i].isOpen() && _archives[i].getName() == name) { + _archives[i].close(); + return true; + } + } + + debug("closeArchive: Archive %s not open.", name.c_str()); + return false; +} + +bool BladeRunnerEngine::isArchiveOpen(const Common::String &name) { + for (uint i = 0; i != 10; ++i) { + if (_archives[i].isOpen() && _archives[i].getName() == name) + return true; + } + + return false; +} + +Common::SeekableReadStream *BladeRunnerEngine::getResourceStream(const Common::String &name) { + for (uint i = 0; i != 10; ++i) { + if (!_archives[i].isOpen()) + continue; + + if (false) + debug("getResource: Searching archive %s for %s.", _archives[i].getName().c_str(), name.c_str()); + Common::SeekableReadStream *stream = _archives[i].createReadStreamForMember(name); + if (stream) + return stream; + } + + debug("getResource: Resource %s not found.", name.c_str()); + return 0; +} + +bool BladeRunnerEngine::playerHasControl() { + return _playerLosesControlCounter == 0; +} + +void BladeRunnerEngine::playerLosesControl() { + if (++_playerLosesControlCounter == 1) { + _mouse->disable(); + } + // debug("Player Lost Control (%d)", _playerLosesControlCounter); +} + +void BladeRunnerEngine::playerGainsControl() { + if (_playerLosesControlCounter == 0) { + warning("Unbalanced call to BladeRunnerEngine::playerGainsControl"); + } + + if (_playerLosesControlCounter > 0) + --_playerLosesControlCounter; + + // debug("Player Gained Control (%d)", _playerLosesControlCounter); + + if (_playerLosesControlCounter == 0) { + _mouse->enable(); + } +} + +void BladeRunnerEngine::ISez(const char *str) { + debug("\t%s", str); +} + +} // End of namespace BladeRunner |