Files
scummvm/engines/startrek/startrek.cpp
T
Filippos Karapetis 108f3174f4 STARTREK: Implement basic functionality for the Enterprise's bridge
It's now possible to use the menu system and talk to some crewmates.
The game now starts in bridge mode, and it's possible to beam down
by using Kirk's transporter icon.
2020-11-23 01:24:51 +02:00

389 lines
9.4 KiB
C++

/* 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 = "";
_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() {
bool isDemo = getFeatures() & GF_DEMO;
_resource = new Resource(getPlatform(), isDemo);
_gfx = new Graphics(this);
_sound = new Sound(this);
setDebugger(new Console(this));
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
initializeEventsAndMouse();
loadBridgeComputerTopics();
_gfx->setMouseBitmap(!isDemo ? "pushbtn" : "cursor");
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) {
if (!isDemo) {
playIntro();
_missionToLoad = "DEMON";
runGameMode(GAMEMODE_BRIDGE, false);
} else {
_missionToLoad = "DEMO";
runGameMode(GAMEMODE_AWAYMISSION, false);
}
} else {
_roomIndexToLoad = -1;
runGameMode(_gameMode, true);
}
return Common::kNoError;
}
Common::Error StarTrekEngine::runGameMode(int mode, bool resume) {
_gfx->toggleMouse(true);
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