aboutsummaryrefslogtreecommitdiff
path: root/engines/saga/saga.cpp
diff options
context:
space:
mode:
authorMax Horn2006-02-11 22:45:04 +0000
committerMax Horn2006-02-11 22:45:04 +0000
commit26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch)
tree26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/saga/saga.cpp
parent2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff)
downloadscummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/saga/saga.cpp')
-rw-r--r--engines/saga/saga.cpp505
1 files changed, 505 insertions, 0 deletions
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
new file mode 100644
index 0000000000..4adda480c6
--- /dev/null
+++ b/engines/saga/saga.cpp
@@ -0,0 +1,505 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "common/stdafx.h"
+
+#include "base/gameDetector.h"
+#include "base/plugins.h"
+#include "backends/fs/fs.h"
+
+#include "common/file.h"
+#include "common/config-manager.h"
+#include "common/system.h"
+
+#include "sound/mixer.h"
+
+#include "saga/saga.h"
+
+#include "saga/rscfile.h"
+#include "saga/gfx.h"
+#include "saga/render.h"
+#include "saga/actor.h"
+#include "saga/animation.h"
+#include "saga/console.h"
+#include "saga/events.h"
+#include "saga/font.h"
+#include "saga/interface.h"
+#include "saga/isomap.h"
+#include "saga/puzzle.h"
+#include "saga/script.h"
+#include "saga/scene.h"
+#include "saga/sndres.h"
+#include "saga/sprite.h"
+#include "saga/sound.h"
+#include "saga/music.h"
+#include "saga/palanim.h"
+#include "saga/objectmap.h"
+#include "saga/resnames.h"
+
+static const GameSettings saga_games[] = {
+ {"ite", "Inherit the Earth", 0},
+ {"ihnm", "I Have No Mouth and I Must Scream", GF_DEFAULT_TO_1X_SCALER },
+ {0, 0, 0}
+};
+
+GameList Engine_SAGA_gameList() {
+ GameList games;
+ const GameSettings *g = saga_games;
+
+ while (g->gameid) {
+ games.push_back(*g);
+ g++;
+ }
+
+ return games;
+}
+
+DetectedGameList Engine_SAGA_detectGames(const FSList &fslist) {
+ return Saga::GAME_ProbeGame(fslist);
+}
+
+Engine *Engine_SAGA_create(GameDetector *detector, OSystem *syst) {
+ return new Saga::SagaEngine(detector, syst);
+}
+
+REGISTER_PLUGIN(SAGA, "SAGA Engine")
+
+namespace Saga {
+
+#define MAX_TIME_DELTA 100
+
+SagaEngine::SagaEngine(GameDetector *detector, OSystem *syst)
+ : Engine(syst),
+ _targetName(detector->_targetName) {
+
+ _leftMouseButtonPressed = _rightMouseButtonPressed = false;
+
+ _console = NULL;
+ _quit = false;
+
+ _resource = NULL;
+ _sndRes = NULL;
+ _events = NULL;
+ _font = NULL;
+ _sprite = NULL;
+ _anim = NULL;
+ _script = NULL;
+ _interface = NULL;
+ _actor = NULL;
+ _palanim = NULL;
+ _scene = NULL;
+ _isoMap = NULL;
+ _gfx = NULL;
+ _console = NULL;
+ _render = NULL;
+ _music = NULL;
+ _sound = NULL;
+ _puzzle = NULL;
+
+ _frameCount = 0;
+ _globalFlags = 0;
+ memset(_ethicsPoints, 0, sizeof(_ethicsPoints));
+
+ // The Linux version of Inherit the Earth puts all data files in an
+ // 'itedata' sub-directory, except for voices.rsc
+ Common::File::addDefaultDirectory(_gameDataPath + "itedata/");
+
+ // The Windows version of Inherit the Earth puts various data files in
+ // other subdirectories.
+ Common::File::addDefaultDirectory(_gameDataPath + "graphics/");
+ Common::File::addDefaultDirectory(_gameDataPath + "music/");
+ Common::File::addDefaultDirectory(_gameDataPath + "sound/");
+
+ // The Multi-OS version puts the voices file in the root directory of
+ // the CD. The rest of the data files are in game/itedata
+ Common::File::addDefaultDirectory(_gameDataPath + "game/itedata/");
+
+ // Mac CD Wyrmkeep
+ Common::File::addDefaultDirectory(_gameDataPath + "patch/");
+
+ // Setup mixer
+ if (!_mixer->isReady()) {
+ warning("Sound initialization failed.");
+ }
+
+ _displayClip.left = _displayClip.top = 0;
+}
+
+SagaEngine::~SagaEngine() {
+ if (_scene != NULL) {
+ if (_scene->isSceneLoaded()) {
+ _scene->endScene();
+ }
+ }
+
+ delete _puzzle;
+ delete _sndRes;
+ delete _events;
+ delete _font;
+ delete _sprite;
+ delete _anim;
+ delete _script;
+ delete _interface;
+ delete _actor;
+ delete _palanim;
+ delete _scene;
+ delete _isoMap;
+ delete _render;
+ delete _music;
+ delete _sound;
+ delete _gfx;
+ delete _console;
+
+ delete _resource;
+}
+
+void SagaEngine::errorString(const char *buf1, char *buf2) {
+ strcpy(buf2, buf1);
+}
+
+int SagaEngine::init(GameDetector &detector) {
+ _soundVolume = ConfMan.getInt("sfx_volume") / 25;
+ _musicVolume = ConfMan.getInt("music_volume") / 25;
+ _subtitlesEnabled = ConfMan.getBool("subtitles");
+ _readingSpeed = ConfMan.getInt("talkspeed");
+ _copyProtection = ConfMan.getBool("copy_protection");
+
+ if (_readingSpeed > 3)
+ _readingSpeed = 0;
+
+ _resource = new Resource(this);
+
+ // Add some default directories
+ // Win32 demo & full game
+ Common::File::addDefaultDirectory("graphics");
+ Common::File::addDefaultDirectory("music");
+ Common::File::addDefaultDirectory("sound");
+
+ // Linux demo
+ Common::File::addDefaultDirectory("itedata");
+
+ // Mac demos & full game
+ Common::File::addDefaultDirectory("patch");
+
+ // Process command line
+
+ // Detect game and open resource files
+ if (!initGame()) {
+ return FAILURE;
+ }
+
+ // Initialize engine modules
+ _sndRes = new SndRes(this);
+ _events = new Events(this);
+ _font = new Font(this);
+ _sprite = new Sprite(this);
+ _anim = new Anim(this);
+ _script = new Script(this);
+ _interface = new Interface(this); // requires script module
+ _scene = new Scene(this);
+ _actor = new Actor(this);
+ _palanim = new PalAnim(this);
+ _isoMap = new IsoMap(this);
+ _puzzle = new Puzzle(this);
+
+ // System initialization
+
+ _previousTicks = _system->getMillis();
+
+ // Initialize graphics
+ _gfx = new Gfx(this, _system, getDisplayWidth(), getDisplayHeight(), detector);
+
+ // Graphics driver should be initialized before console
+ _console = new Console(this);
+
+ // Graphics should be initialized before music
+ int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
+ bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
+ bool adlib = (midiDriver == MD_ADLIB);
+
+ MidiDriver *driver = MidiDriver::createMidi(midiDriver);
+ if (native_mt32)
+ driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+
+ _music = new Music(this, _mixer, driver, _musicVolume);
+ _music->setNativeMT32(native_mt32);
+ _music->setAdlib(adlib);
+
+ if (!_musicVolume) {
+ debug(1, "Music disabled.");
+ }
+
+ _render = new Render(this, _system);
+ if (!_render->initialized()) {
+ return FAILURE;
+ }
+
+ // Initialize system specific sound
+ _sound = new Sound(this, _mixer, _soundVolume);
+ if (!_soundVolume) {
+ debug(1, "Sound disabled.");
+ }
+
+ _interface->converseInit();
+ _script->setVerb(_script->getVerbType(kVerbWalkTo));
+
+ _music->setVolume(-1, 1);
+
+ _gfx->initPalette();
+
+ // FIXME: This is the ugly way of reducing redraw overhead. It works
+ // well for 320x200 but it's unclear how well it will work for
+ // 640x480.
+
+ if (getGameType() == GType_ITE)
+ _system->setFeatureState(OSystem::kFeatureAutoComputeDirtyRects, true);
+
+ return SUCCESS;
+}
+
+int SagaEngine::go() {
+ int msec = 0;
+
+ _previousTicks = _system->getMillis();
+
+ if (ConfMan.hasKey("start_scene")) {
+ _scene->changeScene(ConfMan.getInt("start_scene"), 0, kTransitionNoFade);
+ } else if (ConfMan.hasKey("boot_param")) {
+ if (getGameType() == GType_ITE)
+ _interface->addToInventory(_actor->objIndexToId(ITE_OBJ_MAGIC_HAT));
+ _scene->changeScene(ConfMan.getInt("boot_param"), 0, kTransitionNoFade);
+ } else if (ConfMan.hasKey("save_slot")) {
+ // First scene sets up palette
+ _scene->changeScene(getStartSceneNumber(), 0, kTransitionNoFade);
+ _events->handleEvents(0); // Process immediate events
+
+ char *fileName;
+ fileName = calcSaveFileName(ConfMan.getInt("save_slot"));
+ load(fileName);
+ _interface->setMode(kPanelMain);
+ } else {
+ _framesEsc = 0;
+ _scene->startScene();
+ }
+
+ uint32 currentTicks;
+
+ while (!_quit) {
+ if (_console->isAttached())
+ _console->onFrame();
+
+ if (_render->getFlags() & RF_RENDERPAUSE) {
+ // Freeze time while paused
+ _previousTicks = _system->getMillis();
+ } else {
+ currentTicks = _system->getMillis();
+ // Timer has rolled over after 49 days
+ if (currentTicks < _previousTicks)
+ msec = 0;
+ else {
+ msec = currentTicks - _previousTicks;
+ _previousTicks = currentTicks;
+ }
+ if (msec > MAX_TIME_DELTA) {
+ msec = MAX_TIME_DELTA;
+ }
+
+ // Since Puzzle is actorless, we do it here
+ if (_puzzle->isActive()) {
+ _actor->handleSpeech(msec);
+ } else if (!_scene->isInIntro()) {
+ if (_interface->getMode() == kPanelMain ||
+ _interface->getMode() == kPanelConverse ||
+ _interface->getMode() == kPanelCutaway ||
+ _interface->getMode() == kPanelNull ||
+ _interface->getMode() == kPanelChapterSelection)
+ _actor->direct(msec);
+ }
+
+ _events->handleEvents(msec);
+ _script->executeThreads(msec);
+ }
+ // Per frame processing
+ _render->drawScene();
+ _system->delayMillis(10);
+ }
+
+ return 0;
+}
+
+void SagaEngine::loadStrings(StringsTable &stringsTable, const byte *stringsPointer, size_t stringsLength) {
+ uint16 stringsCount;
+ size_t offset;
+ int i;
+
+ if (stringsLength == 0) {
+ error("SagaEngine::loadStrings() Error loading strings list resource");
+ }
+
+ stringsTable.stringsPointer = (byte*)malloc(stringsLength);
+ memcpy(stringsTable.stringsPointer, stringsPointer, stringsLength);
+
+
+ MemoryReadStreamEndian scriptS(stringsTable.stringsPointer, stringsLength, isBigEndian()); //TODO: get endianess from context
+
+ offset = scriptS.readUint16();
+ stringsCount = offset / 2;
+ stringsTable.strings = (const char **)malloc(stringsCount * sizeof(*stringsTable.strings));
+ i = 0;
+ scriptS.seek(0);
+ while (i < stringsCount) {
+ offset = scriptS.readUint16();
+ if (offset == stringsLength) {
+ stringsCount = i;
+ stringsTable.strings = (const char **)realloc(stringsTable.strings, stringsCount * sizeof(*stringsTable.strings));
+ break;
+ }
+ if (offset > stringsLength) {
+ error("SagaEngine::loadStrings wrong strings table");
+ }
+ stringsTable.strings[i] = (const char *)stringsTable.stringsPointer + offset;
+ debug(9, "string[%i]=%s", i, stringsTable.strings[i]);
+ i++;
+ }
+ stringsTable.stringsCount = stringsCount;
+}
+
+const char *SagaEngine::getObjectName(uint16 objectId) {
+ ActorData *actor;
+ ObjectData *obj;
+ const HitZone *hitZone;
+ switch (objectTypeId(objectId)) {
+ case kGameObjectObject:
+ obj = _actor->getObj(objectId);
+ if (getGameType() == GType_ITE)
+ return _script->_mainStrings.getString(obj->_nameIndex);
+ return _actor->_objectsStrings.getString(obj->_nameIndex);
+ case kGameObjectActor:
+ actor = _actor->getActor(objectId);
+ return _actor->_actorsStrings.getString(actor->_nameIndex);
+ case kGameObjectHitZone:
+ hitZone = _scene->_objectMap->getHitZone(objectIdToIndex(objectId));
+ return _scene->_sceneStrings.getString(hitZone->getNameIndex());
+ }
+ warning("SagaEngine::getObjectName name not found for 0x%X", objectId);
+ return NULL;
+}
+
+const char *SagaEngine::getTextString(int textStringId) {
+ const char *string;
+ int lang = (getLanguage() == Common::DE_DEU) ? 1 : 0;
+
+ string = ITEinterfaceTextStrings[lang][textStringId];
+ if (!string)
+ string = ITEinterfaceTextStrings[0][textStringId];
+
+ return string;
+}
+
+void SagaEngine::getExcuseInfo(int verb, const char *&textString, int &soundResourceId) {
+ textString = NULL;
+
+ if (verb == _script->getVerbType(kVerbPickUp)) {
+ textString = getTextString(kTextICantPickup);
+ soundResourceId = RID_BOAR_VOICE_007;
+ } else
+ if (verb == _script->getVerbType(kVerbLookAt)) {
+ textString = getTextString(kTextNothingSpecial);
+ soundResourceId = RID_BOAR_VOICE_006;
+ }
+ if (verb == _script->getVerbType(kVerbOpen)) {
+ textString = getTextString(kTextNoPlaceToOpen);
+ soundResourceId = RID_BOAR_VOICE_000;
+ }
+ if (verb == _script->getVerbType(kVerbClose)) {
+ textString = getTextString(kTextNoOpening);
+ soundResourceId = RID_BOAR_VOICE_002;
+ }
+ if (verb == _script->getVerbType(kVerbUse)) {
+ textString = getTextString(kTextDontKnow);
+ soundResourceId = RID_BOAR_VOICE_005;
+ }
+}
+
+ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) {
+ ColorId colorId = kITEColorTransBlack;
+
+ if (getGameType() == GType_ITE) {
+ switch (knownColor) {
+ case(kKnownColorTransparent):
+ colorId = kITEColorTransBlack;
+ break;
+
+ case (kKnownColorBrightWhite):
+ colorId = kITEColorBrightWhite;
+ break;
+ case (kKnownColorBlack):
+ colorId = kITEColorBlack;
+ break;
+
+ case (kKnownColorSubtitleTextColor):
+ colorId = (ColorId)255;
+ break;
+ case (kKnownColorVerbText):
+ colorId = kITEColorBlue;
+ break;
+ case (kKnownColorVerbTextShadow):
+ colorId = kITEColorBlack;
+ break;
+ case (kKnownColorVerbTextActive):
+ colorId = (ColorId)96;
+ break;
+
+ default:
+ error("SagaEngine::KnownColor2ColorId unknown color %i", knownColor);
+ }
+ } else if (getGameType() == GType_IHNM) {
+ switch (knownColor)
+ {
+ case(kKnownColorTransparent):
+ colorId = kITEColorTransBlack;
+ break;
+
+ case (kKnownColorBlack):
+ colorId = kIHNMColorBlack;
+ break;
+
+ case (kKnownColorVerbText):
+ colorId = (ColorId)253;
+ break;
+ case (kKnownColorVerbTextShadow):
+ colorId = (ColorId)15;
+ break;
+ case (kKnownColorVerbTextActive):
+ colorId = (ColorId)252;
+ break;
+
+ default:
+ error("SagaEngine::KnownColor2ColorId unknown color %i", knownColor);
+ }
+ }
+ return colorId;
+}
+
+
+} // End of namespace Saga