Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

agi.cpp

/* 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.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-11-1/engines/agi/agi.cpp $
 * $Id: agi.cpp 30944 2008-02-23 22:50:18Z sev $
 *
 */


#include "common/md5.h"
#include "common/events.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/config-manager.h"

#include "base/plugins.h"
#include "base/version.h"

#include "graphics/cursorman.h"

#include "sound/mididrv.h"
#include "sound/mixer.h"

#include "agi/agi.h"
#include "agi/graphics.h"
#include "agi/sprite.h"
#include "agi/opcodes.h"
#include "agi/keyboard.h"
#include "agi/menu.h"
#include "agi/sound.h"

namespace Agi {

static uint32 g_tickTimer;
struct Mouse g_mouse;

void AgiEngine::allowSynthetic(bool allow) {
      _allowSynthetic = allow;
}

void AgiEngine::processEvents() {
      Common::Event event;
      int key = 0;

      while (_eventMan->pollEvent(event)) {
            switch (event.type) {
            case Common::EVENT_QUIT:
                  _gfx->deinitVideo();
                  _gfx->deinitMachine();
                  _system->quit();
                  break;
            case Common::EVENT_PREDICTIVE_DIALOG:
                  if (_predictiveDialogRunning)
                        break;
                  if (_game.playerControl && predictiveDialog()) {
                        if (_game.inputMode == INPUT_NORMAL) {
                              strcpy((char *)_game.inputBuffer, _predictiveResult);
                              handleKeys(KEY_ENTER);
                        } else if (_game.inputMode == INPUT_GETSTRING) {
                              strcpy(_game.strings[_stringdata.str], _predictiveResult);
                              newInputMode(INPUT_NORMAL);
                              _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
                                          _stringdata.y, ' ', _game.colorFg, _game.colorBg);
                        }
                  }
                  break;
            case Common::EVENT_LBUTTONDOWN:
                  key = BUTTON_LEFT;
                  g_mouse.button = 1;
                  keyEnqueue(key);
                  g_mouse.x = event.mouse.x;
                  g_mouse.y = event.mouse.y;
                  break;
            case Common::EVENT_RBUTTONDOWN:
                  key = BUTTON_RIGHT;
                  g_mouse.button = 2;
                  keyEnqueue(key);
                  g_mouse.x = event.mouse.x;
                  g_mouse.y = event.mouse.y;
                  break;
            case Common::EVENT_WHEELUP:
                  key = WHEEL_UP;
                  keyEnqueue(key);
                  break;
            case Common::EVENT_WHEELDOWN:
                  key = WHEEL_DOWN;
                  keyEnqueue(key);
                  break;
            case Common::EVENT_MOUSEMOVE:
                  g_mouse.x = event.mouse.x;
                  g_mouse.y = event.mouse.y;
                  break;
            case Common::EVENT_LBUTTONUP:
            case Common::EVENT_RBUTTONUP:
                  g_mouse.button = 0;
                  g_mouse.x = event.mouse.x;
                  g_mouse.y = event.mouse.y;
                  break;
            case Common::EVENT_KEYDOWN:
                  if (event.kbd.flags == Common::KBD_CTRL && event.kbd.keycode == Common::KEYCODE_d) {
                        _console->attach();
                        break;
                  }

                  switch (key = event.kbd.keycode) {
                  case Common::KEYCODE_LEFT:
                  case Common::KEYCODE_KP4:
                        if (_allowSynthetic || !event.synthetic)
                              key = KEY_LEFT;
                        break;
                  case Common::KEYCODE_RIGHT:
                  case Common::KEYCODE_KP6:
                        if (_allowSynthetic || !event.synthetic)
                              key = KEY_RIGHT;
                        break;
                  case Common::KEYCODE_UP:
                  case Common::KEYCODE_KP8:
                        if (_allowSynthetic || !event.synthetic)
                              key = KEY_UP;
                        break;
                  case Common::KEYCODE_DOWN:
                  case Common::KEYCODE_KP2:
                        if (_allowSynthetic || !event.synthetic)
                              key = KEY_DOWN;
                        break;
                  case Common::KEYCODE_PAGEUP:
                  case Common::KEYCODE_KP9:
                        if (_allowSynthetic || !event.synthetic)
                              key = KEY_UP_RIGHT;
                        break;
                  case Common::KEYCODE_PAGEDOWN:
                  case Common::KEYCODE_KP3:
                        if (_allowSynthetic || !event.synthetic)
                              key = KEY_DOWN_RIGHT;
                        break;
                  case Common::KEYCODE_HOME:
                  case Common::KEYCODE_KP7:
                        if (_allowSynthetic || !event.synthetic)
                              key = KEY_UP_LEFT;
                        break;
                  case Common::KEYCODE_END:
                  case Common::KEYCODE_KP1:
                        if (_allowSynthetic || !event.synthetic)
                              key = KEY_DOWN_LEFT;
                        break;
                  case Common::KEYCODE_KP5:
                        key = KEY_STATIONARY;
                        break;
                  case Common::KEYCODE_PLUS:
                        key = '+';
                        break;
                  case Common::KEYCODE_MINUS:
                        key = '-';
                        break;
                  case Common::KEYCODE_TAB:
                        key = 0x0009;
                        break;
                  case Common::KEYCODE_F1:
                        key = 0x3b00;
                        break;
                  case Common::KEYCODE_F2:
                        key = 0x3c00;
                        break;
                  case Common::KEYCODE_F3:
                        key = 0x3d00;
                        break;
                  case Common::KEYCODE_F4:
                        key = 0x3e00;
                        break;
                  case Common::KEYCODE_F5:
                        key = 0x3f00;
                        break;
                  case Common::KEYCODE_F6:
                        key = 0x4000;
                        break;
                  case Common::KEYCODE_F7:
                        key = 0x4100;
                        break;
                  case Common::KEYCODE_F8:
                        key = 0x4200;
                        break;
                  case Common::KEYCODE_F9:
                        key = 0x4300;
                        break;
                  case Common::KEYCODE_F10:
                        key = 0x4400;
                        break;
                  case Common::KEYCODE_F11:
                        key = KEY_STATUSLN;
                        break;
                  case Common::KEYCODE_F12:
                        key = KEY_PRIORITY;
                        break;
                  case Common::KEYCODE_ESCAPE:
                        key = 0x1b;
                        break;
                  case Common::KEYCODE_RETURN:
                  case Common::KEYCODE_KP_ENTER:
                        key = KEY_ENTER;
                        break;
                  case Common::KEYCODE_BACKSPACE:
                        key = KEY_BACKSPACE;
                        break;
                  default:
                        // FIXME: This fixes assertions with isalpha below, but it essentially filters
                        // out all function keys (control, alt and shift).
                        // Well, actually, it does *not* filter them out (as we still pass the value
                        // in key to keyEnqueue after this switch/case statement); but it means that
                        // we perform no filtering on these input events, which is bad. That is, we 
                        // provide keycode in one format, and the AGI core expects some other format...
                        // So maybe we should set key to 0 if key > 255?
                        if (key > 255)
                              break;

                        // FIXME: We let lots of keys slip through here unchanged, passing our internal
                        // keycode values directly to the AGI core. Do we really want that???
                        if (isalpha(key)) {
                              // FIXME: We probably should be using event.kbd.ascii at some point here,
                              // but it's not completly clear how/where, this needs testing.
                              // In particular, what about 'a' vs. 'A' (resp. the keys A vs. Shift-A) ?

                              // Key is A-Z. 
                              // Map Ctrl-A to 1, Ctrl-B to 2, etc.
                              if (event.kbd.flags & Common::KBD_CTRL) {
                                    key = toupper(key) - 'A' + 1;
                              } else if (event.kbd.flags & Common::KBD_ALT) {
                                    // Map Alt-A, Alt-B etc. to special scancode values according to an internal scancode table.
                                    key = scancodeTable[toupper(key) - 'A'] << 8;
                              }
                        }
                        break;
                  }
                  if (key)
                        keyEnqueue(key);
                  break;
            default:
                  break;
            }
      }
}

void AgiEngine::checkQuickLoad() {
      if (ConfMan.hasKey("save_slot")) {
            char saveNameBuffer[256];

            snprintf (saveNameBuffer, 256, "%s.%03d", _targetName.c_str(), ConfMan.getInt("save_slot"));

            if (loadGame(saveNameBuffer, false) == errOK) {  // Do not check game id
                  _game.exitAllLogics = 1;
                  _menu->enableAll();
            }
      }
}

int AgiEngine::agiIsKeypressLow() {
      processEvents();
      return _keyQueueStart != _keyQueueEnd;
}

void AgiEngine::agiTimerLow() {
      static uint32 m = 0;
      uint32 dm;

      if (g_tickTimer < m)
            m = 0;

      while ((dm = g_tickTimer - m) < 5) {
            processEvents();
            if (_console->isAttached())
                  _console->onFrame();
            _system->delayMillis(10);
            _system->updateScreen();
      }
      m = g_tickTimer;
}

int AgiEngine::agiGetKeypressLow() {
      int k;

      while (_keyQueueStart == _keyQueueEnd)    /* block */
            agiTimerLow();
      keyDequeue(k);

      return k;
}

void AgiEngine::agiTimerFunctionLow(void *refCon) {
      g_tickTimer++;
}

void AgiEngine::clearImageStack(void) {
      _imageStack.clear();
}

void AgiEngine::releaseImageStack(void) {
      _imageStack.clear();
}

void AgiEngine::recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
            int16 p4, int16 p5, int16 p6, int16 p7) {
      ImageStackElement pnew;

      pnew.type = type;
      pnew.pad = 0;
      pnew.parm1 = p1;
      pnew.parm2 = p2;
      pnew.parm3 = p3;
      pnew.parm4 = p4;
      pnew.parm5 = p5;
      pnew.parm6 = p6;
      pnew.parm7 = p7;

      _imageStack.push(pnew);
}

void AgiEngine::replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
            int16 p4, int16 p5, int16 p6, int16 p7) {
      switch (type) {
      case ADD_PIC:
            debugC(8, kDebugLevelMain, "--- decoding picture %d ---", p1);
            agiLoadResource(rPICTURE, p1);
            _picture->decodePicture(p1, p2, p3 != 0);
            break;
      case ADD_VIEW:
            agiLoadResource(rVIEW, p1);
            _sprites->addToPic(p1, p2, p3, p4, p5, p6, p7);
            break;
      }
}

void AgiEngine::initPriTable() {
      int i, p, y = 0;

      for (p = 1; p < 15; p++) {
            for (i = 0; i < 12; i++) {
                  _game.priTable[y++] = p < 4 ? 4 : p;
            }
      }
}

int AgiEngine::agiInit() {
      int ec, i;

      debug(2, "initializing");
      debug(2, "game.ver = 0x%x", _game.ver);

      /* reset all flags to false and all variables to 0 */
      for (i = 0; i < MAX_FLAGS; i++)
            _game.flags[i] = 0;
      for (i = 0; i < MAX_VARS; i++)
            _game.vars[i] = 0;

      /* clear all resources and events */
      for (i = 0; i < MAX_DIRS; i++) {
            memset(&_game.views[i], 0, sizeof(struct AgiView));
            memset(&_game.pictures[i], 0, sizeof(struct AgiPicture));
            memset(&_game.logics[i], 0, sizeof(struct AgiLogic));
            memset(&_game.sounds[i], 0, sizeof(class AgiSound *)); // _game.sounds contains pointers now
            memset(&_game.dirView[i], 0, sizeof(struct AgiDir));
            memset(&_game.dirPic[i], 0, sizeof(struct AgiDir));
            memset(&_game.dirLogic[i], 0, sizeof(struct AgiDir));
            memset(&_game.dirSound[i], 0, sizeof(struct AgiDir));
      }

      /* clear view table */
      for (i = 0; i < MAX_VIEWTABLE; i++)
            memset(&_game.viewTable[i], 0, sizeof(VtEntry));

      initWords();

      if (!_menu)
            _menu = new Menu(this, _gfx, _picture);

      initPriTable();

      /* clear string buffer */
      for (i = 0; i < MAX_STRINGS; i++)
            _game.strings[i][0] = 0;

      /* setup emulation */

      switch (_loader->getIntVersion() >> 12) {
      case 2:
            report("Emulating Sierra AGI v%x.%03x\n",
                        (int)(agiGetRelease() >> 12) & 0xF,
                        (int)(agiGetRelease()) & 0xFFF);
            break;
      case 3:
            report("Emulating Sierra AGI v%x.002.%03x\n",
                        (int)(agiGetRelease() >> 12) & 0xF,
                        (int)(agiGetRelease()) & 0xFFF);
            break;
      }

      if (getPlatform() == Common::kPlatformAmiga)
            _game.gameFlags |= ID_AMIGA;

      if (getFeatures() & GF_AGDS)
            _game.gameFlags |= ID_AGDS;

      // Make the 256 color AGI screen the default AGI screen when AGI256 or AGI256-2 is used
      if (getFeatures() & (GF_AGI256 | GF_AGI256_2))
            _game.sbuf = _game.sbuf256c;

      if (_game.gameFlags & ID_AMIGA)
            report("Amiga padded game detected.\n");

      if (_game.gameFlags & ID_AGDS)
            report("AGDS mode enabled.\n");

      ec = _loader->init();   /* load vol files, etc */

      if (ec == errOK)
            ec = _loader->loadObjects(OBJECTS);

      /* note: demogs has no words.tok */
      if (ec == errOK)
            ec = _loader->loadWords(WORDS);

      /* FIXME: load IIgs instruments and samples */
      /* load_instruments("kq.sys16"); */

      /* Load logic 0 into memory */
      if (ec == errOK)
            ec = _loader->loadResource(rLOGIC, 0);

#ifdef __DS__
      // Normally, the engine loads the predictive text dictionary when the predictive dialog
      // is shown.  On the DS version, the word completion feature needs the dictionary too.
      loadDict();
#endif

      return ec;
}

/*
 * Public functions
 */

void AgiEngine::agiUnloadResources() {
      int i;

      /* Make sure logic 0 is always loaded */
      for (i = 1; i < MAX_DIRS; i++) {
            _loader->unloadResource(rLOGIC, i);
      }
      for (i = 0; i < MAX_DIRS; i++) {
            _loader->unloadResource(rVIEW, i);
            _loader->unloadResource(rPICTURE, i);
            _loader->unloadResource(rSOUND, i);
      }
}

int AgiEngine::agiDeinit() {
      int ec;

      cleanInput();           /* remove all words from memory */
      agiUnloadResources();   /* unload resources in memory */
      _loader->unloadResource(rLOGIC, 0);
      ec = _loader->deinit();
      unloadObjects();
      unloadWords();

      clearImageStack();

      return ec;
}

int AgiEngine::agiDetectGame() {
      int ec = errOK;

      assert(_gameDescription != NULL);

      if (getVersion() <= 0x2999) {
            _loader = new AgiLoader_v2(this);
      } else {
            _loader = new AgiLoader_v3(this);
      }
      ec = _loader->detectGame();

      return ec;
}

int AgiEngine::agiVersion() {
      return _loader->version();
}

int AgiEngine::agiGetRelease() {
      return _loader->getIntVersion();
}

void AgiEngine::agiSetRelease(int n) {
      _loader->setIntVersion(n);
}

int AgiEngine::agiLoadResource(int r, int n) {
      int i;

      i = _loader->loadResource(r, n);

      // WORKAROUND: Patches broken picture 147 in a corrupted Amiga version of Gold Rush! (v2.05 1989-03-09).
      // The picture can be seen in room 147 after dropping through the outhouse's hole in room 146.
      if (i == errOK && getGameID() == GID_GOLDRUSH && r == rPICTURE && n == 147 && _game.dirPic[n].len == 1982) {
            uint8 *pic = _game.pictures[n].rdata;
            Common::MemoryReadStream picStream(pic, _game.dirPic[n].len);
            char md5str[32+1];
            Common::md5_file_string(picStream, md5str, _game.dirPic[n].len);
            if (scumm_stricmp(md5str, "1c685eb048656cedcee4eb6eca2cecea") == 0) {
                  pic[0x042] = 0x4B; // 0x49 -> 0x4B
                  pic[0x043] = 0x66; // 0x26 -> 0x66
                  pic[0x204] = 0x68; // 0x28 -> 0x68
                  pic[0x6C0] = 0x2D; // 0x25 -> 0x2D
                  pic[0x6F0] = 0xF0; // 0x70 -> 0xF0
                  pic[0x734] = 0x6F; // 0x2F -> 0x6F
            }
      }

      return i;
}

int AgiEngine::agiUnloadResource(int r, int n) {
      return _loader->unloadResource(r, n);
}

struct GameSettings {
      const char *gameid;
      const char *description;
      byte id;
      uint32 features;
      const char *detectname;
};

static const GameSettings agiSettings[] = {
      {"agi", "AGI game", GID_AGI, MDT_ADLIB, "OBJECT"},
      {NULL, NULL, 0, 0, NULL}
};

00555 AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, bool positive) const {
      if (_amigaStyle) {
            if (positive) {
                  if (pressed) { // Positive pressed Amiga-style button
                        if (_olderAgi) {
                              return AgiTextColor(amigaBlack, amigaOrange);
                        } else {
                              return AgiTextColor(amigaBlack, amigaPurple);
                        }
                  } else { // Positive unpressed Amiga-style button
                        return AgiTextColor(amigaWhite, amigaGreen);
                  }
            } else { // _amigaStyle && !positive
                  if (pressed) { // Negative pressed Amiga-style button
                        return AgiTextColor(amigaBlack, amigaCyan);
                  } else { // Negative unpressed Amiga-style button
                        return AgiTextColor(amigaWhite, amigaRed);
                  }
            }
      } else { // PC-style button
            if (hasFocus || pressed) { // A pressed or in focus PC-style button
                  return AgiTextColor(pcWhite, pcBlack);
            } else { // An unpressed PC-style button without focus
                  return AgiTextColor(pcBlack, pcWhite);
            }
      }
}

00583 AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const {
      return getColor(hasFocus, pressed, AgiTextColor(baseFgColor, baseBgColor));
}

00587 AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const {
      if (hasFocus || pressed)
            return baseColor.swap();
      else
            return baseColor;
}

00594 int AgiButtonStyle::getTextOffset(bool hasFocus, bool pressed) const {
      return (pressed && !_amigaStyle) ? 1 : 0;
}

00598 bool AgiButtonStyle::getBorder(bool hasFocus, bool pressed) const {
      return _amigaStyle && !_authenticAmiga && (hasFocus || pressed);
}

00602 void AgiButtonStyle::setAmigaStyle(bool amigaStyle, bool olderAgi, bool authenticAmiga) {
      _amigaStyle       = amigaStyle;
      _olderAgi         = olderAgi;
      _authenticAmiga   = authenticAmiga;
}

00608 void AgiButtonStyle::setPcStyle(bool pcStyle) {
      setAmigaStyle(!pcStyle);
}

00612 AgiButtonStyle::AgiButtonStyle(Common::RenderMode renderMode) {
      setAmigaStyle(renderMode == Common::kRenderAmiga);
}

AgiBase::AgiBase(OSystem *syst, const AGIGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {

}

AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBase(syst, gameDesc) {

      // Setup mixer
      if (!_mixer->isReady()) {
            warning("Sound initialization failed.");
      }

      _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
      _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));

      const GameSettings *g;

      const char *gameid = ConfMan.get("gameid").c_str();
      for (g = agiSettings; g->gameid; ++g)
            if (!scumm_stricmp(g->gameid, gameid))
                  _gameId = g->id;

      _rnd = new Common::RandomSource();
      syst->getEventManager()->registerRandomSource(*_rnd, "agi");

      Common::addSpecialDebugLevel(kDebugLevelMain, "Main", "Generic debug level");
      Common::addSpecialDebugLevel(kDebugLevelResources, "Resources", "Resources debugging");
      Common::addSpecialDebugLevel(kDebugLevelSprites, "Sprites", "Sprites debugging");
      Common::addSpecialDebugLevel(kDebugLevelInventory, "Inventory", "Inventory debugging");
      Common::addSpecialDebugLevel(kDebugLevelInput, "Input", "Input events debugging");
      Common::addSpecialDebugLevel(kDebugLevelMenu, "Menu", "Menu debugging");
      Common::addSpecialDebugLevel(kDebugLevelScripts, "Scripts", "Scripts debugging");
      Common::addSpecialDebugLevel(kDebugLevelSound, "Sound", "Sound debugging");
      Common::addSpecialDebugLevel(kDebugLevelText, "Text", "Text output debugging");
      Common::addSpecialDebugLevel(kDebugLevelSavegame, "Savegame", "Saving & restoring game debugging");


      memset(&_game, 0, sizeof(struct AgiGame));
      memset(&_debug, 0, sizeof(struct AgiDebug));
      memset(&g_mouse, 0, sizeof(struct Mouse));

      _game.clockEnabled = false;
      _game.state = STATE_INIT;

      _keyQueueStart = 0;
      _keyQueueEnd = 0;

      _allowSynthetic = false;

      g_tickTimer = 0;

      _intobj = NULL;

      _menu = NULL;

      _lastSentence[0] = 0;
      memset(&_stringdata, 0, sizeof(struct StringData));

      _objects = NULL;

      _oldMode = -1;

      _predictiveDialogRunning = false;
      _predictiveDictText = NULL;
      _predictiveDictLine = NULL;
      _predictiveDictLineCount = 0;
      _firstSlot = 0;
}

void AgiEngine::initialize() {
      // TODO: Some sound emulation modes do not fit our current music
      //       drivers, and I'm not sure what they are. For now, they might
      //       as well be called "PC Speaker" and "Not PC Speaker".

      // If used platform is Apple IIGS then we must use Apple IIGS sound emulation
      // because Apple IIGS AGI games use only Apple IIGS specific sound resources.
      if (ConfMan.hasKey("platform") &&
            Common::parsePlatform(ConfMan.get("platform")) == Common::kPlatformApple2GS) {
            _soundemu = SOUND_EMU_APPLE2GS;
      } else {
            switch (MidiDriver::detectMusicDriver(MDT_PCSPK)) {
            case MD_PCSPK:
                  _soundemu = SOUND_EMU_PC;
                  break;
            default:
                  _soundemu = SOUND_EMU_NONE;
                  break;
            }
      }

      if (ConfMan.hasKey("render_mode")) {
            _renderMode = Common::parseRenderMode(ConfMan.get("render_mode").c_str());
      } else if (ConfMan.hasKey("platform")) {
            switch (Common::parsePlatform(ConfMan.get("platform"))) {
            case Common::kPlatformAmiga:
                  _renderMode = Common::kRenderAmiga;
                  break;
            case Common::kPlatformPC:
                  _renderMode = Common::kRenderEGA;
                  break;
            default:
                  _renderMode = Common::kRenderEGA;
                  break;
            }
      }

      _buttonStyle = AgiButtonStyle(_renderMode);
      _defaultButtonStyle = AgiButtonStyle();
      _console = new Console(this);
      _gfx = new GfxMgr(this);
      _sound = new SoundMgr(this, _mixer);
      _picture = new PictureMgr(this, _gfx);
      _sprites = new SpritesMgr(this, _gfx);

      _gfx->initMachine();

      _game.gameFlags = 0;

      _game.colorFg = 15;
      _game.colorBg = 0;

      _game.name[0] = '\0';

      _game.sbufOrig = (uint8 *)calloc(_WIDTH, _HEIGHT * 2); // Allocate space for two AGI screens vertically
      _game.sbuf16c  = _game.sbufOrig + SBUF16_OFFSET; // Make sbuf16c point to the 16 color (+control line & priority info) AGI screen
      _game.sbuf256c = _game.sbufOrig + SBUF256_OFFSET; // Make sbuf256c point to the 256 color AGI screen
      _game.sbuf     = _game.sbuf16c; // Make sbuf point to the 16 color (+control line & priority info) AGI screen by default

      _gfx->initVideo();
      _sound->initSound();

      _timer->installTimerProc(agiTimerFunctionLow, 10 * 1000, NULL);

      _game.ver = -1;         /* Don't display the conf file warning */

      debugC(2, kDebugLevelMain, "Detect game");


      if (agiDetectGame() == errOK) {
            _game.state = STATE_LOADED;
            debugC(2, kDebugLevelMain, "game loaded");
      } else {
            report("Could not open AGI game");
      }

      debugC(2, kDebugLevelMain, "Init sound");
}

AgiEngine::~AgiEngine() {
      // If the engine hasn't been initialized yet via AgiEngine::initialize(), don't attempt to free any resources,
      // as they haven't been allocated. Fixes bug #1742432 - AGI: Engine crashes if no game is detected
      if (_game.state == STATE_INIT) {
            delete _rnd;      // delete _rnd, as it is allocated in the constructor, not in initialize()
            return;
      }

      agiDeinit();
      _sound->deinitSound();
      delete _sound;
      _gfx->deinitVideo();
      delete _sprites;
      free(_game.sbufOrig);
      _gfx->deinitMachine();
      delete _rnd;
      delete _console;

      free(_predictiveDictLine);
      free(_predictiveDictText);
}

int AgiBase::init() {

      // Initialize backend
      _system->beginGFXTransaction();
      initCommonGFX(false);
      _system->initSize(320, 200);
      _system->endGFXTransaction();

      initialize();

      _gfx->gfxSetPalette();

      return 0;
}

int AgiEngine::go() {
      CursorMan.showMouse(true);

      report(" \nAGI engine %s is ready.\n", gScummVMVersion);
      if (_game.state < STATE_LOADED) {
            do {
                  mainCycle();
            } while (_game.state < STATE_RUNNING);
            if (_game.ver < 0)
                  _game.ver = 0;    /* Enable conf file warning */
      }

      runGame();

      return 0;
}

} // End of namespace Agi

Generated by  Doxygen 1.6.0   Back to index