/* 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 "base/plugins.h" #include "base/version.h" #include "common/archive.h" #include "common/config-manager.h" #include "common/debug-channels.h" #include "common/error.h" #include "common/events.h" #include "common/file.h" #include "common/macresman.h" #include "graphics/pixelformat.h" #include "graphics/surface.h" #include "engines/util.h" #include "video/qt_decoder.h" #include "startrek/console.h" #include "startrek/iwfile.h" #include "startrek/lzss.h" #include "startrek/resource.h" #include "startrek/room.h" #include "startrek/startrek.h" namespace StarTrek { StarTrekEngine::StarTrekEngine(OSystem *syst, const StarTrekGameDescription *gamedesc) : Engine(syst), _gameDescription(gamedesc), _randomSource("Star Trek"), _kirkActor(&_actorList[0]), _spockActor(&_actorList[1]), _mccoyActor(&_actorList[2]), _redshirtActor(&_actorList[3]), _sineTable(1024), _cosineTable(1024) { if (getPlatform() != Common::kPlatformDOS) error("Only DOS versions of Star Trek: 25th Anniversary are currently supported"); else if (getGameType() == GType_STJR) error("Star Trek: Judgment Rites is not yet supported"); DebugMan.addDebugChannel(kDebugSound, "sound", "Sound"); DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics"); DebugMan.addDebugChannel(kDebugSavegame, "savegame", "Savegames"); DebugMan.addDebugChannel(kDebugSpace, "space", "Space and Pseudo-3D"); DebugMan.addDebugChannel(kDebugGeneral, "general", "General"); _gfx = nullptr; _activeMenu = nullptr; _sound = nullptr; _room = nullptr; _resource = nullptr; memset(_actionOnWalkCompletionInUse, 0, sizeof(_actionOnWalkCompletionInUse)); _clockTicks = 0; _musicEnabled = true; _sfxEnabled = true; _word_467a6 = true; _musicWorking = true; _sfxWorking = true; _finishedPlayingSpeech = false; _lookActionBitmapIndex = 0; _mouseControllingShip = false; _keyboardControlsMouse = true; _inQuitGameMenu = false; _textDisplayMode = TEXTDISPLAY_SUBTITLES; _textboxVar2 = 0; _textboxVar6 = 0; _textboxHasMultipleChoices = false; _missionToLoad = "DEMON"; _roomIndexToLoad = 0; _mapFile = nullptr; _iwFile = nullptr; _showSubtitles = true; Common::fill(_r3List, _r3List + NUM_SPACE_OBJECTS, (R3 *)nullptr); Common::fill(_orderedR3List, _orderedR3List + NUM_SPACE_OBJECTS, (R3 *)nullptr); for (int i = 0; i < NUM_OBJECTS; i++) _itemList[i] = g_itemList[i]; for (int i = 0; i < MAX_BAN_FILES; i++) _banFiles[i] = nullptr; const Common::FSNode gameDataDir(ConfMan.get("path")); SearchMan.addSubDirectoryMatching(gameDataDir, "patches"); } StarTrekEngine::~StarTrekEngine() { delete _activeMenu->nextMenu; delete _activeMenu; delete _gfx; delete _sound; delete _resource; } Common::Error StarTrekEngine::run() { _resource = new Resource(getPlatform(), getFeatures() & GF_DEMO); _gfx = new Graphics(this); _sound = new Sound(this); setDebugger(new Console(this)); initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT); initializeEventsAndMouse(); _gfx->setMouseBitmap("pushbtn"); _gfx->toggleMouse(true); bool loadedSave = false; if (ConfMan.hasKey("save_slot")) { if (!loadGame(ConfMan.getInt("save_slot"))) error("Failed to load savegame %d", ConfMan.getInt("save_slot")); loadedSave = true; } if (!loadedSave) { playIntro(); runGameMode(GAMEMODE_BEAMDOWN, false); } else { _roomIndexToLoad = -1; runGameMode(_gameMode, true); } return Common::kNoError; } Common::Error StarTrekEngine::runGameMode(int mode, bool resume) { if (!resume) { // Only run this if not just resuming from a savefile _frameIndex = 0; _lastGameMode = -1; _gameMode = mode; _sound->stopAllVocSounds(); _resetGameMode = true; if (_gameMode == GAMEMODE_START) _gameMode = GAMEMODE_BRIDGE; } while (true) { if (_resetGameMode) { if (!_sound->_loopingAudioName.empty()) _sound->playVoc(_sound->_loopingAudioName); _resetGameMode = false; } TrekEvent event; if (_gameMode != _lastGameMode) { // Cleanup previous game mode switch (_lastGameMode) { case GAMEMODE_BRIDGE: cleanupBridge(); break; case GAMEMODE_AWAYMISSION: cleanupAwayMission(); break; case GAMEMODE_BEAMDOWN: case GAMEMODE_BEAMUP: default: break; } _lastGameMode = _gameMode; // Load next game mode switch (_gameMode) { case GAMEMODE_BRIDGE: _sound->loadMusicFile("bridge"); initBridge(false); // TODO: param break; case GAMEMODE_AWAYMISSION: initAwayMission(); break; case GAMEMODE_BEAMDOWN: _awayMission.redshirtDead = false; _sound->loadMusicFile("ground"); runTransportSequence("teled"); _gameMode = GAMEMODE_AWAYMISSION; continue; // Back to start of loop case GAMEMODE_BEAMUP: runTransportSequence("teleb"); _gameMode = GAMEMODE_BRIDGE; //sub_15c61(); _sound->stopAllVocSounds(); _sound->playVoc("bridloop"); continue; // Back to start of loop default: break; } } // Run current game mode switch (_gameMode) { case GAMEMODE_BRIDGE: popNextEvent(&event); runBridge(); break; case GAMEMODE_AWAYMISSION: runAwayMission(); break; case GAMEMODE_BEAMDOWN: case GAMEMODE_BEAMUP: error("Can't be here."); break; default: break; } } return Common::kNoError; } void StarTrekEngine::runTransportSequence(const Common::String &name) { const uint16 crewmanTransportPositions[][2] = { { 0x8e, 0x7c }, { 0xbe, 0x7c }, { 0x7e, 0x72 }, { 0xaa, 0x72 } }; _sound->stopAllVocSounds(); _gfx->fadeoutScreen(); actorFunc1(); initActors(); _gfx->setBackgroundImage("transprt"); _gfx->clearPri(); _gfx->loadPalette("palette"); _gfx->copyBackgroundScreen(); _system->updateScreen(); _system->delayMillis(10); for (int i = 0; i < (_awayMission.redshirtDead ? 3 : 4); i++) { Common::String filename = getCrewmanAnimFilename(i, name); int x = crewmanTransportPositions[i][0]; int y = crewmanTransportPositions[i][1]; loadActorAnim(i, filename, x, y, 1.0); _actorList[i].animationString.clear(); } if (_missionToLoad.equalsIgnoreCase("feather") && name[4] == 'b') { loadActorAnim(9, "qteleb", 0x61, 0x79, 1.0); } else if (_missionToLoad.equalsIgnoreCase("trial")) { if (name[4] == 'd') { loadActorAnim(9, "qteled", 0x61, 0x79, 1.0); } /* TODO else if (word_51156 >= 3) { loadActorAnim(9, "qteleb", 0x61, 0x79, 1.0); } */ } loadActorAnim(8, "transc", 0, 0, 1.0); // TODO: redraw mouse and sprite_52c4e? _gfx->drawAllSprites(); _gfx->fadeinScreen(); _sound->playSoundEffectIndex(0x0a); if (name.equalsIgnoreCase("teled")) _sound->playSoundEffectIndex(0x08); else _sound->playSoundEffectIndex(0x09); while (_actorList[0].field62 == 0) { TrekEvent event; if (popNextEvent(&event)) { if (event.type == TREKEVENT_TICK) { // TODO: redraw sprite_52c4e? _frameIndex++; updateActorAnimations(); _gfx->drawAllSprites(); } } } // TODO: redraw sprite_52c4e? _gfx->drawAllSprites(); _gfx->fadeoutScreen(); actorFunc1(); initActors(); } void StarTrekEngine::playMovie(Common::String filename) { if (getPlatform() == Common::kPlatformMacintosh) playMovieMac(filename); else error("Interplay MVE not yet supported"); } void StarTrekEngine::playMovieMac(Common::String filename) { // Swap to 16bpp mode initGraphics(512, 384, NULL); Video::QuickTimeDecoder *qtDecoder = new Video::QuickTimeDecoder(); if (!qtDecoder->loadFile(filename)) error("Could not open '%s'", filename.c_str()); bool continuePlaying = true; qtDecoder->start(); while (!qtDecoder->endOfVideo() && !shouldQuit() && continuePlaying) { if (qtDecoder->needsUpdate()) { const ::Graphics::Surface *frame = qtDecoder->decodeNextFrame(); if (frame) { ::Graphics::Surface *convertedFrame = frame->convertTo(_system->getScreenFormat()); _system->copyRectToScreen(convertedFrame->getPixels(), convertedFrame->pitch, 0, 0, convertedFrame->w, convertedFrame->h); _system->updateScreen(); convertedFrame->free(); delete convertedFrame; } } Common::Event event; while (g_system->getEventManager()->pollEvent(event)) if (event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) continuePlaying = false; _system->delayMillis(10); } delete qtDecoder; // Swap back to 8bpp mode initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT); } uint16 StarTrekEngine::getRandomWord() { return _randomSource.getRandomNumber(0xffff); } } // End of namespace StarTrek