scummvm/engines/pegasus/pegasus.cpp

389 lines
12 KiB
C++
Raw Normal View History

/* 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 "common/config-manager.h"
#include "common/error.h"
#include "common/events.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/textconsole.h"
#include "common/translation.h"
#include "base/plugins.h"
#include "base/version.h"
#include "gui/saveload.h"
2011-05-12 20:17:12 +00:00
#include "pegasus/console.h"
#include "pegasus/pegasus.h"
//#define RUN_SUB_MOVIE // :D :D :D :D :D :D
//#define RUN_INTERFACE_TEST
namespace Pegasus {
PegasusEngine::PegasusEngine(OSystem *syst, const PegasusGameDescription *gamedesc) : Engine(syst), _gameDescription(gamedesc) {
}
PegasusEngine::~PegasusEngine() {
delete _video;
delete _sound;
delete _gfx;
delete _resFork;
delete _inventoryLid;
delete _biochipLid;
2011-05-12 20:17:12 +00:00
delete _console;
}
Common::Error PegasusEngine::run() {
2011-05-12 20:17:12 +00:00
_console = new PegasusConsole(this);
_gfx = new GraphicsManager(this);
_video = new VideoManager(this);
_sound = new SoundManager(this);
_resFork = new Common::MacResManager();
_inventoryLid = new Common::MacResManager();
_biochipLid = new Common::MacResManager();
_gameMode = kIntroMode;
_adventureMode = true;
if (!_resFork->open("JMP PP Resources") || !_resFork->hasResFork())
error("Could not load JMP PP Resources");
if (!_inventoryLid->open("Images/Lids/Inventory Lid Sequence") || !_inventoryLid->hasResFork())
error("Could not open Inventory Lid Sequence");
if (!_biochipLid->open("Images/Lids/Biochip Lid Sequence") || !_biochipLid->hasResFork())
error("Could not open Biochip Lid Sequence");
loadItemLocationData();
if (!detectOpeningClosingDirectory()) {
Common::String message = "Missing intro directory. ";
// Give Mac OS X a more specific message because we can
#ifdef MACOSX
message += "Make sure \"Opening/Closing\" is present.";
#else
message += "Be sure to rename \"Opening/Closing\" to \"Opening_Closing\".";
#endif
GUIErrorMessage(message);
warning("%s", message.c_str());
return Common::kNoGameDataFoundError;
}
#if 0
Common::MacResIDArray pictIds = _biochipLid->getResIDArray(MKID_BE('PICT'));
for (uint32 i = 0; i < pictIds.size(); i++) {
Common::String filename = Common::String::printf("PICT_%d.pict", pictIds[i]);
Common::DumpFile file;
assert(file.open(filename));
Common::SeekableReadStream *res = _biochipLid->getResource(MKID_BE('PICT'), pictIds[i]);
byte *data = new byte[res->size()];
res->read(data, res->size());
for (int j = 0; j < 512; j++)
file.writeByte(0);
file.write(data, res->size());
file.close();
delete res;
delete[] data;
}
#endif
#if defined(RUN_SUB_MOVIE)
_video->playMovie("Images/Norad Alpha/Sub Chase Movie");
#elif defined(RUN_INTERFACE_TEST)
drawInterface();
_gfx->setCursor(kMainCursor);
_sound->playSound("Sounds/Caldoria/Apartment Music.aiff", true);
while (!shouldQuit()) {
Common::Event event;
// Ignore events for now
while (_eventMan->pollEvent(event)) {
if (event.type == Common::EVENT_MOUSEMOVE)
_system->updateScreen();
}
_system->delayMillis(10);
}
#else
while (!shouldQuit()) {
switch (_gameMode) {
case kIntroMode:
if (!isDemo())
runIntro();
_gameMode = kMainMenuMode;
break;
case kMainMenuMode:
runMainMenu();
break;
case kMainGameMode:
if (isDemo())
changeLocation(kLocPrehistoric);
else
changeLocation(kLocCaldoria);
mainGameLoop();
break;
case kQuitMode:
return Common::kNoError;
default:
_gameMode = kMainMenuMode;
break;
}
}
#endif
return Common::kNoError;
}
bool PegasusEngine::detectOpeningClosingDirectory() {
// We need to detect what our Opening/Closing directory is listed as
// On the original disc, it was 'Opening/Closing' but only HFS(+) supports the slash
// Mac OS X will display this as 'Opening:Closing' and we can use that directly
// On other systems, users will need to rename to "Opening_Closing"
Common::FSNode gameDataDir(ConfMan.get("path"));
gameDataDir = gameDataDir.getChild("Images");
if (!gameDataDir.exists())
return false;
Common::FSList fsList;
if (!gameDataDir.getChildren(fsList, Common::FSNode::kListDirectoriesOnly, true))
return false;
for (uint i = 0; i < fsList.size() && _introDirectory.empty(); i++) {
Common::String name = fsList[i].getName();
if (name.equalsIgnoreCase("Opening:Closing"))
_introDirectory = name;
else if (name.equalsIgnoreCase("Opening_Closing"))
_introDirectory = name;
}
if (_introDirectory.empty())
return false;
debug(0, "Detected intro location as '%s'", _introDirectory.c_str());
_introDirectory = Common::String("Images/") + _introDirectory;
return true;
}
void PegasusEngine::loadItemLocationData() {
Common::SeekableReadStream *res = _resFork->getResource(MKTAG('N', 'I', 't', 'm'), 0x80);
uint16 entryCount = res->readUint16BE();
for (uint16 i = 0; i < entryCount; i++) {
ItemLocationData loc;
loc.id = res->readUint16BE(); // Which is always == i, anyway
loc.location = (ItemLocation)res->readUint16BE();
loc.u0 = res->readUint16BE();
loc.u1 = res->readByte();
debug(1, "Item[%d]: ID = %d, location = %x, u0 = %d, u1 = %d", i, loc.id, loc.location, loc.u0, loc.u1);
res->readByte();
_itemLocationData.push_back(loc);
}
delete res;
}
void PegasusEngine::runIntro() {
_video->playMovieCentered(_introDirectory + "/BandaiLogo.movie");
VideoHandle handle = _video->playBackgroundMovie(_introDirectory + "/Big Movie.movie");
_video->seekToTime(handle, 10 * 600);
_video->waitUntilMovieEnds(handle);
}
void PegasusEngine::drawInterface() {
_gfx->drawPict("Images/Interface/3DInterface Top", 0, 0, false);
_gfx->drawPict("Images/Interface/3DInterface Left", 0, kViewScreenOffset, false);
_gfx->drawPict("Images/Interface/3DInterface Right", 640 - kViewScreenOffset, kViewScreenOffset, false);
_gfx->drawPict("Images/Interface/3DInterface Bottom", 0, kViewScreenOffset + 256, false);
//drawCompass();
_system->updateScreen();
}
void PegasusEngine::mainGameLoop() {
// TODO: Yeah...
_system->fillScreen(0);
_video->playMovieCentered("Images/Caldoria/Pullback.movie");
drawInterface();
Common::String navMovie = Common::String::format("Images/%s/%s.movie", getTimeZoneFolder(_timeZone).c_str(), getTimeZoneDesc(_timeZone).c_str());
_video->playMovie(navMovie, kViewScreenOffset, kViewScreenOffset);
_gameMode = kQuitMode;
}
void PegasusEngine::changeLocation(TimeZone timeZone) {
_timeZone = timeZone;
loadViews(_timeZone);
//loadExits(_timeZone);
loadDoors(_timeZone);
//loadHSLs(_timeZone);
//loadHSIn(_timeZone);
loadSoundSpots(_timeZone);
//loadTurns(_timeZone);
loadZooms(_timeZone);
loadExtras(_timeZone);
}
void PegasusEngine::loadViews(TimeZone timeZone) {
_currentViews.clear();
Common::SeekableReadStream *res = _resFork->getResource(MKTAG('V', 'i', 'e', 'w'), getTimeZoneDesc(timeZone));
uint32 entryCount = res->readUint32BE();
for (uint32 i = 0; i < entryCount; i++) {
View view;
view.u0 = res->readUint16BE(); // Compass reading?
view.u1 = res->readByte(); // Always 0-3, direction?
view.u2 = res->readByte(); // Usually 0, rarely 3
view.frameTime = res->readUint32BE();
debug(1, "View[%d]: u0 = %d, u1 = %d, u2 = %d, time = %d", i, view.u0, view.u1, view.u2, view.frameTime);
_currentViews.push_back(view);
}
delete res;
}
void PegasusEngine::loadDoors(TimeZone timeZone) {
_currentDoors.clear();
Common::SeekableReadStream *res = _resFork->getResource(MKTAG('D', 'o', 'o', 'r'), getTimeZoneDesc(timeZone));
uint32 entryCount = res->readUint32BE();
for (uint32 i = 0; i < entryCount; i++) {
Door door;
door.u0 = res->readUint16BE();
door.u1 = res->readUint16BE(); // Always divisible by 256?
door.startTime = res->readUint32BE();
door.endTime = res->readUint32BE();
door.u2 = res->readUint16BE();
debug(1, "Door[%d]: u0 = %d, u1 = %d, startTime = %d, endTime = %d, u2 = %d", i, door.u0, door.u1, door.startTime, door.endTime, door.u2);
_currentDoors.push_back(door);
}
delete res;
}
void PegasusEngine::loadSoundSpots(TimeZone timeZone) {
_currentSoundSpots.clear();
Common::SeekableReadStream *res = _resFork->getResource(MKTAG('S', 'p', 'o', 't'), getTimeZoneDesc(timeZone));
uint32 entryCount = res->readUint32BE();
for (uint32 i = 0; i < entryCount; i++) {
SoundSpot spot;
spot.u0 = res->readUint16BE();
spot.u1 = res->readUint16BE();
spot.u2 = res->readUint16BE(); // 0/1 or 768/769
spot.startTime = res->readUint32BE();
spot.endTime = res->readUint32BE();
spot.u3 = res->readUint16BE();
debug(1, "Sound Spot[%d]: u0 = %d, u1 = %d, u2 = %d, startTime = %d, endTime = %d, u3 = %d", i, spot.u0, spot.u1, spot.u2, spot.startTime, spot.endTime, spot.u3);
_currentSoundSpots.push_back(spot);
}
delete res;
}
void PegasusEngine::loadZooms(TimeZone timeZone) {
_currentZooms.clear();
Common::SeekableReadStream *res = _resFork->getResource(MKTAG('Z', 'o', 'o', 'm'), getTimeZoneDesc(timeZone));
uint32 entryCount = res->readUint32BE();
for (uint32 i = 0; i < entryCount; i++) {
Zoom zoom;
zoom.u0 = res->readUint16BE();
zoom.u1 = res->readUint16BE();
zoom.startTime = res->readUint32BE();
zoom.endTime = res->readUint32BE();
zoom.u2 = res->readUint16BE();
debug(1, "Zoom[%d]: u0 = %d, u1 = %d, startTime = %d, endTime = %d, u2 = %d", i, zoom.u0, zoom.u1, zoom.startTime, zoom.endTime, zoom.u2);
_currentZooms.push_back(zoom);
}
delete res;
}
void PegasusEngine::loadExtras(TimeZone timeZone) {
_currentExtras.clear();
Common::SeekableReadStream *res = _resFork->getResource(MKTAG('X', 't', 'r', 'a'), getTimeZoneDesc(timeZone));
uint32 entryCount = res->readUint32BE();
for (uint32 i = 0; i < entryCount; i++) {
Extra extra;
extra.u0 = res->readUint32BE();
extra.startTime = res->readUint32BE();
extra.endTime = res->readUint32BE();
debug(1, "Extra[%d]: u0 = %d, startTime = %d, endTime = %d", i, extra.u0, extra.startTime, extra.endTime);
_currentExtras.push_back(extra);
}
delete res;
}
void PegasusEngine::showLoadDialog() {
GUI::SaveLoadChooser slc(_("Load game:"), _("Load"));
slc.setSaveMode(false);
Common::String gameId = ConfMan.get("gameid");
const EnginePlugin *plugin = 0;
EngineMan.findGame(gameId, &plugin);
int slot = slc.runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName());
if (slot >= 0) {
warning("TODO: Load game");
_gameMode = kMainGameMode;
}
slc.close();
}
Common::String PegasusEngine::getTimeZoneDesc(TimeZone timeZone) {
static const char *names[] = { "Prehistoric", "Mars", "WSC", "Tiny TSA", "Full TSA", "Norad Alpha", "Caldoria", "Norad Delta" };
return names[timeZone];
}
Common::String PegasusEngine::getTimeZoneFolder(TimeZone timeZone) {
if (timeZone == kLocFullTSA || timeZone == kLocTinyTSA)
return "TSA";
return getTimeZoneDesc(timeZone);
}
2011-05-12 20:17:12 +00:00
GUI::Debugger *PegasusEngine::getDebugger() {
return _console;
}
} // End of namespace Pegasus