2015-02-06 15:31:43 +01:00
|
|
|
|
2014-05-16 21:58:49 +02:00
|
|
|
/* 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"
|
|
|
|
|
2015-02-06 15:31:43 +01:00
|
|
|
#include "bladerunner/ambient_sounds.h"
|
|
|
|
#include "bladerunner/audio_player.h"
|
2014-05-16 21:58:49 +02:00
|
|
|
#include "bladerunner/chapters.h"
|
|
|
|
#include "bladerunner/gameinfo.h"
|
2015-02-06 15:31:43 +01:00
|
|
|
#include "bladerunner/gameflags.h"
|
2014-05-16 21:58:49 +02:00
|
|
|
#include "bladerunner/image.h"
|
2014-05-17 17:13:49 +02:00
|
|
|
#include "bladerunner/outtake.h"
|
2014-05-25 15:01:06 +02:00
|
|
|
#include "bladerunner/scene.h"
|
2015-02-07 11:41:52 +01:00
|
|
|
#include "bladerunner/script/init.h"
|
2014-05-25 15:01:06 +02:00
|
|
|
#include "bladerunner/script/script.h"
|
2014-05-16 21:58:49 +02:00
|
|
|
#include "bladerunner/settings.h"
|
2014-06-05 23:49:57 +02:00
|
|
|
#include "bladerunner/slice_animations.h"
|
|
|
|
#include "bladerunner/slice_renderer.h"
|
2014-05-16 21:58:49 +02:00
|
|
|
#include "bladerunner/vqa_decoder.h"
|
|
|
|
|
|
|
|
#include "common/error.h"
|
|
|
|
#include "common/events.h"
|
|
|
|
#include "common/system.h"
|
|
|
|
|
|
|
|
#include "engines/util.h"
|
|
|
|
|
|
|
|
#include "graphics/pixelformat.h"
|
|
|
|
|
|
|
|
namespace BladeRunner {
|
|
|
|
|
2015-02-06 15:31:43 +01:00
|
|
|
BladeRunnerEngine::BladeRunnerEngine(OSystem *syst)
|
|
|
|
: Engine(syst),
|
|
|
|
_rnd("bladerunner")
|
|
|
|
{
|
2014-05-16 21:58:49 +02:00
|
|
|
_windowIsActive = true;
|
|
|
|
_gameIsRunning = true;
|
|
|
|
|
2015-02-06 15:31:43 +01:00
|
|
|
_ambientSounds = new AmbientSounds(this);
|
|
|
|
_audioPlayer = new AudioPlayer(this);
|
2014-05-16 21:58:49 +02:00
|
|
|
_chapters = nullptr;
|
2014-05-30 13:52:59 -07:00
|
|
|
_gameInfo = nullptr;
|
2015-02-06 15:31:43 +01:00
|
|
|
_gameFlags = new GameFlags();
|
|
|
|
_gameVars = nullptr;
|
2014-05-25 15:01:06 +02:00
|
|
|
_scene = new Scene(this);
|
|
|
|
_script = new Script(this);
|
2014-05-16 21:58:49 +02:00
|
|
|
_settings = new Settings(this);
|
2014-06-05 23:49:57 +02:00
|
|
|
_sliceAnimations = new SliceAnimations(this);
|
|
|
|
_sliceRenderer = new SliceRenderer(this);
|
2014-05-16 21:58:49 +02:00
|
|
|
}
|
|
|
|
|
2014-05-30 13:52:59 -07:00
|
|
|
BladeRunnerEngine::~BladeRunnerEngine() {
|
2014-06-05 23:49:57 +02:00
|
|
|
delete _sliceRenderer;
|
|
|
|
delete _sliceAnimations;
|
2014-05-30 13:52:59 -07:00
|
|
|
delete _settings;
|
|
|
|
delete _script;
|
|
|
|
delete _scene;
|
2015-02-06 15:31:43 +01:00
|
|
|
delete _gameVars;
|
|
|
|
delete _gameFlags;
|
2014-05-30 13:52:59 -07:00
|
|
|
delete _gameInfo;
|
|
|
|
delete _chapters;
|
2015-02-06 15:31:43 +01:00
|
|
|
delete _audioPlayer;
|
|
|
|
delete _ambientSounds;
|
2014-05-30 13:52:59 -07:00
|
|
|
|
|
|
|
_surface1.free();
|
2014-06-05 23:49:57 +02:00
|
|
|
_surface2.free();
|
2014-05-30 13:52:59 -07:00
|
|
|
}
|
|
|
|
|
2014-05-16 21:58:49 +02:00
|
|
|
bool BladeRunnerEngine::hasFeature(EngineFeature f) const {
|
|
|
|
return f == kSupportsRTL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::Error BladeRunnerEngine::run() {
|
2014-05-30 12:45:01 -07:00
|
|
|
Graphics::PixelFormat format = createRGB555();
|
|
|
|
initGraphics(640, 480, true, &format);
|
2014-05-16 21:58:49 +02:00
|
|
|
|
2015-02-06 15:31:43 +01:00
|
|
|
_system->showMouse(true);
|
|
|
|
|
2014-05-30 10:24:24 -07:00
|
|
|
if (!startup())
|
|
|
|
return Common::Error(Common::kUnknownError, "Failed to initialize resources");
|
2014-05-16 21:58:49 +02:00
|
|
|
|
2014-05-20 11:30:16 +02:00
|
|
|
if (warnUserAboutUnsupportedGame()) {
|
|
|
|
init2();
|
2014-05-16 21:58:49 +02:00
|
|
|
|
2014-05-20 11:30:16 +02:00
|
|
|
/* TODO: Check for save games and enter KIA */
|
|
|
|
gameLoop();
|
|
|
|
}
|
2014-05-16 21:58:49 +02:00
|
|
|
|
|
|
|
shutdown();
|
|
|
|
|
|
|
|
return Common::kNoError;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BladeRunnerEngine::startup() {
|
|
|
|
bool r;
|
|
|
|
|
2014-05-30 12:45:01 -07:00
|
|
|
_surface1.create(640, 480, createRGB555());
|
2014-05-16 21:58:49 +02:00
|
|
|
|
|
|
|
r = openArchive("STARTUP.MIX");
|
|
|
|
if (!r)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
loadSplash();
|
|
|
|
|
|
|
|
_gameInfo = new GameInfo(this);
|
|
|
|
if (!_gameInfo)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
r = _gameInfo->open("GAMEINFO.DAT");
|
|
|
|
if (!r)
|
|
|
|
return false;
|
|
|
|
|
2015-02-06 15:31:43 +01:00
|
|
|
_gameFlags->setFlagCount(_gameInfo->getFlagCount());
|
|
|
|
|
|
|
|
_gameVars = new int[_gameInfo->getGlobalVarCount()];
|
|
|
|
|
2014-05-16 21:58:49 +02:00
|
|
|
_chapters = new Chapters(this);
|
|
|
|
if (!_chapters)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
r = openArchive("MUSIC.MIX");
|
|
|
|
if (!r)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
r = openArchive("SFX.MIX");
|
|
|
|
if (!r)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
r = openArchive("SPCHSFX.TLK");
|
|
|
|
if (!r)
|
|
|
|
return false;
|
|
|
|
|
2014-06-05 23:49:57 +02:00
|
|
|
r = _sliceAnimations->open("INDEX.DAT");
|
|
|
|
if (!r)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
r = _sliceAnimations->openCoreAnim();
|
|
|
|
if (!r)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
r = _sliceAnimations->openHDFrames();
|
|
|
|
if (!r)
|
|
|
|
return false;
|
|
|
|
|
2015-02-06 15:31:43 +01:00
|
|
|
_zBuffer1 = new uint16[640 * 480];
|
|
|
|
_zBuffer2 = new uint16[640 * 480];
|
|
|
|
|
2015-02-07 11:41:52 +01:00
|
|
|
ScriptInit initScript(this);
|
|
|
|
initScript.SCRIPT_Initialize_Game();
|
|
|
|
|
2014-05-25 15:01:06 +02:00
|
|
|
initChapterAndScene();
|
2014-05-16 21:58:49 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-05-25 15:01:06 +02:00
|
|
|
void BladeRunnerEngine::initChapterAndScene() {
|
2014-05-16 21:58:49 +02:00
|
|
|
// TODO: Init actors...
|
|
|
|
|
|
|
|
_settings->setChapter(1);
|
|
|
|
_settings->setNewSetAndScene(_gameInfo->getInitialSetId(), _gameInfo->getInitialSceneId());
|
|
|
|
}
|
|
|
|
|
|
|
|
void BladeRunnerEngine::shutdown() {
|
2015-02-06 15:31:43 +01:00
|
|
|
_mixer->stopAll();
|
|
|
|
|
2014-05-16 21:58:49 +02:00
|
|
|
if (_chapters) {
|
|
|
|
if (_chapters->hasOpenResources())
|
|
|
|
_chapters->closeResources();
|
|
|
|
delete _chapters;
|
|
|
|
_chapters = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isArchiveOpen("MUSIC.MIX"))
|
|
|
|
closeArchive("MUSIC.MIX");
|
|
|
|
|
|
|
|
if (isArchiveOpen("SFX.MIX"))
|
|
|
|
closeArchive("SFX.MIX");
|
|
|
|
|
|
|
|
if (isArchiveOpen("SPCHSFX.TLK"))
|
|
|
|
closeArchive("SPCHSFX.TLK");
|
|
|
|
|
|
|
|
if (isArchiveOpen("STARTUP.MIX"))
|
|
|
|
closeArchive("STARTUP.MIX");
|
|
|
|
}
|
|
|
|
|
|
|
|
void BladeRunnerEngine::loadSplash() {
|
|
|
|
Image img(this);
|
|
|
|
if (!img.open("SPLASH.IMG"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
img.copyToSurface(&_surface1);
|
|
|
|
|
|
|
|
_system->copyRectToScreen(_surface1.getPixels(), _surface1.pitch, 0, 0, _surface1.w, _surface1.h);
|
|
|
|
_system->updateScreen();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BladeRunnerEngine::init2() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BladeRunnerEngine::gameLoop() {
|
|
|
|
_gameIsRunning = true;
|
|
|
|
do {
|
|
|
|
/* TODO: check player death */
|
|
|
|
gameTick();
|
|
|
|
} while (_gameIsRunning && !shouldQuit());
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
// TODO: Call Script_Player_Walked_In if applicable
|
|
|
|
// TODO: Gun range announcements
|
|
|
|
// TODO: ZBUF repair dirty rects
|
2015-02-06 15:31:43 +01:00
|
|
|
|
|
|
|
_ambientSounds->tick();
|
2014-05-16 21:58:49 +02:00
|
|
|
|
2014-05-25 15:01:06 +02:00
|
|
|
bool backgroundChanged = false;
|
2015-02-06 15:31:43 +01:00
|
|
|
int frame = _scene->advanceFrame(_surface1, _zBuffer1);
|
2014-05-25 15:01:06 +02:00
|
|
|
if (frame >= 0) {
|
|
|
|
_script->SceneFrameAdvanced(frame);
|
|
|
|
backgroundChanged = true;
|
|
|
|
}
|
2015-02-06 15:31:43 +01:00
|
|
|
(void)backgroundChanged;
|
2014-06-05 23:49:57 +02:00
|
|
|
_surface2.copyFrom(_surface1);
|
2015-02-06 15:31:43 +01:00
|
|
|
memcpy(_zBuffer2, _zBuffer1, 640*480*2);
|
2014-05-25 15:01:06 +02:00
|
|
|
|
2014-05-16 21:58:49 +02:00
|
|
|
// TODO: Render overlays (mostly in Replicant)
|
|
|
|
// TODO: Tick Actor AI and Timers (timers in Replicant)
|
|
|
|
|
2014-05-25 15:01:06 +02:00
|
|
|
if (_settings->getNewScene() == -1 || _script->_inScriptCounter /* || in_ai */) {
|
2014-05-16 21:58:49 +02:00
|
|
|
|
|
|
|
// TODO: Tick and draw all actors in current set (drawing works in Replicant)
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
// Hardcode McCoy in place to test the slice renderer
|
2015-02-06 15:31:43 +01:00
|
|
|
Vector3 pos = _scene->_actorStartPosition;
|
2014-06-05 23:49:57 +02:00
|
|
|
Vector3 draw_pos(pos.x, -pos.z, pos.y + 2);
|
|
|
|
float facing = -1.570796f;
|
|
|
|
|
|
|
|
_sliceRenderer->setView(_scene->_view);
|
|
|
|
_sliceRenderer->setupFrame(19, 1, draw_pos, facing);
|
2015-02-06 15:31:43 +01:00
|
|
|
_sliceRenderer->drawFrame(_surface2, _zBuffer2);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2014-05-16 21:58:49 +02:00
|
|
|
// TODO: Draw items (drawing works in Replicant)
|
|
|
|
// TODO: Draw item pickup (understood, drawing works in Replicant)
|
|
|
|
// TODO: Draw dialogue menu
|
|
|
|
// TODO: Draw mouse (understood)
|
|
|
|
// TODO: Process AUD (audio in Replicant)
|
|
|
|
// TODO: Footstep sound
|
|
|
|
|
2014-06-05 23:49:57 +02:00
|
|
|
_system->copyRectToScreen((const byte *)_surface2.getBasePtr(0, 0), _surface2.pitch, 0, 0, 640, 480);
|
2014-05-16 21:58:49 +02:00
|
|
|
_system->updateScreen();
|
2014-05-25 15:01:06 +02:00
|
|
|
_system->delayMillis(10);
|
2014-05-16 21:58:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BladeRunnerEngine::handleEvents() {
|
|
|
|
Common::Event event;
|
|
|
|
Common::EventManager *eventMan = _system->getEventManager();
|
|
|
|
while (eventMan->pollEvent(event)) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-17 17:13:49 +02:00
|
|
|
void BladeRunnerEngine::outtakePlay(int id, bool noLocalization, int container) {
|
2014-05-16 21:58:49 +02:00
|
|
|
Common::String name = _gameInfo->getOuttake(id);
|
|
|
|
|
2014-05-17 17:13:49 +02:00
|
|
|
OuttakePlayer player(this);
|
2014-05-16 21:58:49 +02:00
|
|
|
|
2015-02-06 15:31:43 +01:00
|
|
|
player.play(name, noLocalization, container);
|
2014-05-16 21:58:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-05-25 19:56:03 +02:00
|
|
|
void BladeRunnerEngine::ISez(const char *str) {
|
|
|
|
debug("\t%s", str);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-16 21:58:49 +02:00
|
|
|
} // End of namespace BladeRunner
|