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

kyra_v1.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/kyra/kyra_v1.cpp $
 * $Id: kyra_v1.cpp 30944 2008-02-23 22:50:18Z sev $
 *
 */

#include "kyra/kyra_v1.h"

#include "common/file.h"
#include "common/events.h"
#include "common/system.h"
#include "common/savefile.h"

#include "gui/message.h"

#include "kyra/resource.h"
#include "kyra/screen.h"
#include "kyra/script.h"
#include "kyra/seqplayer.h"
#include "kyra/sound.h"
#include "kyra/sprites.h"
#include "kyra/wsamovie.h"
#include "kyra/animator_v1.h"
#include "kyra/text.h"
#include "kyra/debugger.h"
#include "kyra/timer.h"

namespace Kyra {

KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags)
      : KyraEngine(system, flags) {
      _flags = flags;

      _seq_Forest = _seq_KallakWriting = _seq_KyrandiaLogo = _seq_KallakMalcolm =
      _seq_MalcolmTree = _seq_WestwoodLogo = _seq_Demo1 = _seq_Demo2 = _seq_Demo3 =
      _seq_Demo4 = 0;
      
      _seq_WSATable = _seq_CPSTable = _seq_COLTable = _seq_textsTable = 0;
      _seq_WSATable_Size = _seq_CPSTable_Size = _seq_COLTable_Size = _seq_textsTable_Size = 0;
      
      _roomFilenameTable = _characterImageTable = 0;
      _roomFilenameTableSize = _characterImageTableSize = 0;
      _itemList = _takenList = _placedList = _droppedList = _noDropList = 0;
      _itemList_Size = _takenList_Size = _placedList_Size = _droppedList_Size = _noDropList_Size = 0;
      _putDownFirst = _waitForAmulet = _blackJewel = _poisonGone = _healingTip = 0;
      _putDownFirst_Size = _waitForAmulet_Size = _blackJewel_Size = _poisonGone_Size = _healingTip_Size = 0;
      _thePoison = _fluteString = _wispJewelStrings = _magicJewelString = _flaskFull = _fullFlask = 0;
      _thePoison_Size = _fluteString_Size = _wispJewelStrings_Size = 0;
      _magicJewelString_Size = _flaskFull_Size = _fullFlask_Size = 0;
      
      _defaultShapeTable = 0;
      _healingShapeTable = _healingShape2Table = 0;
      _defaultShapeTableSize = _healingShapeTableSize = _healingShape2TableSize = 0;
      _posionDeathShapeTable = _fluteAnimShapeTable = 0;
      _posionDeathShapeTableSize = _fluteAnimShapeTableSize = 0;
      _winterScrollTable = _winterScroll1Table = _winterScroll2Table = 0;
      _winterScrollTableSize = _winterScroll1TableSize = _winterScroll2TableSize = 0;
      _drinkAnimationTable = _brandonToWispTable = _magicAnimationTable = _brandonStoneTable = 0;
      _drinkAnimationTableSize = _brandonToWispTableSize = _magicAnimationTableSize = _brandonStoneTableSize = 0;
      memset(&_specialPalettes, 0, sizeof(_specialPalettes));
      _debugger = 0;
      _sprites = 0;
      _animator = 0;
      _seq = 0;
      _npcScriptData = 0;
      _scriptMain = 0;
      _scriptClickData = 0;
      _scriptClick = 0;
      _characterList = 0;
      _movFacingTable = 0;
      memset(_shapes, 0, sizeof(_shapes));
      memset(_movieObjects, 0, sizeof(_movieObjects));
      _finalA = _finalB = _finalC = 0;
      _endSequenceBackUpRect = 0;
      memset(_panPagesTable, 0, sizeof(_panPagesTable));
      _npcScriptData = _scriptClickData = 0;
      _scrollUpButton.process0PtrShape = _scrollUpButton.process1PtrShape = _scrollUpButton.process2PtrShape = 0;
      _scrollDownButton.process0PtrShape = _scrollDownButton.process1PtrShape = _scrollDownButton.process2PtrShape = 0;
      memset(_sceneAnimTable, 0, sizeof(_sceneAnimTable));
      _currHeadShape = 0;

      memset(&_itemBkgBackUp, 0, sizeof(_itemBkgBackUp));
}

KyraEngine_v1::~KyraEngine_v1() {
      for (int i = 0; i < ARRAYSIZE(_movieObjects); ++i) {
            if (_movieObjects[i])
                  _movieObjects[i]->close();
            delete _movieObjects[i];
            _movieObjects[i] = 0;
      }

      closeFinalWsa();
      if (_scriptInterpreter) {
            _scriptInterpreter->unloadScript(_npcScriptData);
            _scriptInterpreter->unloadScript(_scriptClickData);
      }

      Common::clearAllSpecialDebugLevels();

      delete _screen;
      delete _debugger;
      delete _sprites;
      delete _animator;
      delete _seq;
            
      delete _npcScriptData;
      delete _scriptMain;
      
      delete _scriptClickData;
      delete _scriptClick;
      
      delete [] _characterList;
      
      delete [] _movFacingTable;

      delete [] _scrollUpButton.process0PtrShape;
      delete [] _scrollUpButton.process1PtrShape;
      delete [] _scrollUpButton.process2PtrShape;
      delete [] _scrollDownButton.process0PtrShape;
      delete [] _scrollDownButton.process1PtrShape;
      delete [] _scrollDownButton.process2PtrShape;

      delete [] _itemBkgBackUp[0];
      delete [] _itemBkgBackUp[1];  

      for (int i = 0; i < ARRAYSIZE(_shapes); ++i) {
            if (_shapes[i] != 0) {
                  delete [] _shapes[i];
                  for (int i2 = 0; i2 < ARRAYSIZE(_shapes); i2++) {
                        if (_shapes[i2] == _shapes[i] && i2 != i) {
                              _shapes[i2] = 0;
                        }
                  }
                  _shapes[i] = 0;
            }
      }

      for (int i = 0; i < ARRAYSIZE(_sceneAnimTable); ++i)
            delete [] _sceneAnimTable[i];
}

int KyraEngine_v1::init() {
      _screen = new Screen_v1(this, _system);
      assert(_screen);
      if (!_screen->init())
            error("_screen->init() failed");

      KyraEngine::init();

      _sprites = new Sprites(this, _system);
      assert(_sprites);
      _seq = new SeqPlayer(this, _system);
      assert(_seq);
      _animator = new ScreenAnimator(this, _system);
      assert(_animator);
      _animator->init(5, 11, 12);
      assert(*_animator);
      _text = new TextDisplayer(this, screen());
      assert(_text);

      initStaticResource();
      
      if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
            _sound->setSoundFileList(_soundFilesTowns, _soundFilesTownsCount);
      else
            _sound->setSoundFileList(_soundFiles, _soundFilesCount);

      _trackMap = _dosTrackMap;
      _trackMapSize = _dosTrackMapSize;
      
      if (!_sound->init())
            error("Couldn't init sound");

      _sound->setVolume(255);
      _sound->loadSoundFile((_flags.platform == Common::kPlatformFMTowns
            || _flags.platform == Common::kPlatformPC98) ? 0 : 9);

      setupTimers();
      setupButtonData();
      setupMenu();

      _paletteChanged = 1;
      _currentCharacter = 0;
      _characterList = new Character[11];
      assert(_characterList);
      memset(_characterList, 0, sizeof(Character)*11);

      for (int i = 0; i < 11; ++i)
            memset(_characterList[i].inventoryItems, 0xFF, sizeof(_characterList[i].inventoryItems));

      _characterList[0].sceneId = 5;
      _characterList[0].height = 48;
      _characterList[0].facing = 3;
      _characterList[0].currentAnimFrame = 7;
      
      _npcScriptData = new ScriptData;
      memset(_npcScriptData, 0, sizeof(ScriptData));
      assert(_npcScriptData);
      _npcScript = new ScriptState;
      assert(_npcScript);
      memset(_npcScript, 0, sizeof(ScriptState));
      
      _scriptMain = new ScriptState;
      assert(_scriptMain);
      memset(_scriptMain, 0, sizeof(ScriptState));
      
      _scriptClickData = new ScriptData;
      assert(_scriptClickData);
      memset(_scriptClickData, 0, sizeof(ScriptData));
      _scriptClick = new ScriptState;
      assert(_scriptClick);
      memset(_scriptClick, 0, sizeof(ScriptState));
      
      _debugger = new Debugger_v1(this);
      assert(_debugger);      
      memset(_shapes, 0, sizeof(_shapes));

      for (int i = 0; i < ARRAYSIZE(_movieObjects); ++i)
            _movieObjects[i] = createWSAMovie();

      memset(_flagsTable, 0, sizeof(_flagsTable));

      _abortWalkFlag = false;
      _abortWalkFlag2 = false;
      _talkingCharNum = -1;
      _charSayUnk3 = -1;
      memset(_currSentenceColor, 0, 3);
      _startSentencePalIndex = -1;
      _fadeText = false;

      _cauldronState = 0;
      _crystalState[0] = _crystalState[1] = -1;

      _brandonStatusBit = 0;
      _brandonStatusBit0x02Flag = _brandonStatusBit0x20Flag = 10;
      _brandonPosX = _brandonPosY = -1;
      _deathHandler = 0xFF;
      _poisonDeathCounter = 0;
      
      memset(_itemTable, 0, sizeof(_itemTable));
      memset(_exitList, 0xFFFF, sizeof(_exitList));
      _exitListPtr = 0;
      _pathfinderFlag = _pathfinderFlag2 = 0;
      _lastFindWayRet = 0;
      _sceneChangeState = _loopFlag2 = 0;

      _movFacingTable = new int[150];
      assert(_movFacingTable);
      _movFacingTable[0] = 8;

      registerDefaultSettings();
      readSettings();

      _skipFlag = false;

      _marbleVaseItem = -1;
      memset(_foyerItemTable, -1, sizeof(_foyerItemTable));
      _mouseState = _itemInHand = -1;
      _handleInput = false;
      
      _currentRoom = 0xFFFF;
      _scenePhasingFlag = 0;
      _lastProcessedItem = 0;
      _lastProcessedItemHeight = 16;
      
      _unkScreenVar1 = 1;
      _unkScreenVar2 = 0;
      _unkScreenVar3 = 0;
      _unkAmuletVar = 0;
      
      _endSequenceNeedLoading = 1;
      _malcolmFlag = 0;
      _beadStateVar = 0;
      _endSequenceSkipFlag = 0;
      _unkEndSeqVar2 = 0;
      _endSequenceBackUpRect = 0;
      _unkEndSeqVar4 = 0;
      _unkEndSeqVar5 = 0;
      _lastDisplayedPanPage = 0;
      memset(_panPagesTable, 0, sizeof(_panPagesTable));
      _finalA = _finalB = _finalC = 0;
      memset(&_kyragemFadingState, 0, sizeof(_kyragemFadingState));     
      _kyragemFadingState.gOffset = 0x13;
      _kyragemFadingState.bOffset = 0x13;

      _mousePressFlag = false;
      
      _menuDirectlyToLoad = false;

      _lastMusicCommand = 0;
      
      return 0;
}

int KyraEngine_v1::go() {
      if (_res->getFileSize("6.FNT"))
            _screen->loadFont(Screen::FID_6_FNT, "6.FNT");
      _screen->loadFont(Screen::FID_8_FNT, "8FAT.FNT");
      _screen->setScreenDim(0);

      _abortIntroFlag = false;

      if (_flags.isDemo) {
            seq_demo();
      } else {
            setGameFlag(0xF3);
            setGameFlag(0xFD);
            setGameFlag(0xEF);
            seq_intro();
            if (_quitFlag)
                  return 0;
            if (_skipIntroFlag && _abortIntroFlag)
                  resetGameFlag(0xEF);
            startup();
            resetGameFlag(0xEF);
            mainLoop();
      }
      return 0;
}


void KyraEngine_v1::startup() {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::startup()");
      static const uint8 colorMap[] = { 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0 };
      _screen->setTextColorMap(colorMap);
//    _screen->setFont(Screen::FID_6_FNT);
      _screen->setAnimBlockPtr(3750);
      memset(_sceneAnimTable, 0, sizeof(_sceneAnimTable));
      loadMouseShapes();
      _currentCharacter = &_characterList[0];
      for (int i = 1; i < 5; ++i)
            _animator->setCharacterDefaultFrame(i);
      for (int i = 5; i <= 10; ++i)
            setCharactersPositions(i);
      _animator->setCharactersHeight();
      resetBrandonPoisonFlags();
      _screen->_curPage = 0;
      // XXX
      for (int i = 0; i < 12; ++i) {
            int size = _screen->getRectSize(3, 24);
            _shapes[361+i] = new byte[size];
      }

      _itemBkgBackUp[0] = new uint8[_screen->getRectSize(3, 24)];
      memset(_itemBkgBackUp[0], 0, _screen->getRectSize(3, 24));
      _itemBkgBackUp[1] = new uint8[_screen->getRectSize(4, 32)];
      memset(_itemBkgBackUp[1], 0, _screen->getRectSize(4, 32));

      for (int i = 0; i < _roomTableSize; ++i) {
            for (int item = 0; item < 12; ++item) {
                  _roomTable[i].itemsTable[item] = 0xFF;
                  _roomTable[i].itemsXPos[item] = 0xFFFF;
                  _roomTable[i].itemsYPos[item] = 0xFF;
                  _roomTable[i].needInit[item] = 0;
            }
      }

      loadCharacterShapes();
      loadSpecialEffectShapes();
      loadItems();
      loadButtonShapes();
      initMainButtonList();
      loadMainScreen();
      _screen->loadPalette("PALETTE.COL", _screen->_currentPalette);

      // XXX
      _animator->initAnimStateList();
      setCharactersInDefaultScene();

      if (!_scriptInterpreter->loadScript("_STARTUP.EMC", _npcScriptData, &_opcodes))
            error("Could not load \"_STARTUP.EMC\" script");
      _scriptInterpreter->initScript(_scriptMain, _npcScriptData);

      if (!_scriptInterpreter->startScript(_scriptMain, 0))
            error("Could not start script function 0 of script \"_STARTUP.EMC\"");

      while (_scriptInterpreter->validScript(_scriptMain))
            _scriptInterpreter->runScript(_scriptMain);
      
      _scriptInterpreter->unloadScript(_npcScriptData);

      if (!_scriptInterpreter->loadScript("_NPC.EMC", _npcScriptData, &_opcodes))
            error("Could not load \"_NPC.EMC\" script");
      
      snd_playTheme(1);
      enterNewScene(_currentCharacter->sceneId, _currentCharacter->facing, 0, 0, 1);
      
      if (_abortIntroFlag && _skipIntroFlag) {
            _menuDirectlyToLoad = true;
            _screen->setMouseCursor(1, 1, _shapes[0]);
            _screen->showMouse();
            buttonMenuCallback(0);
            _menuDirectlyToLoad = false;
      } else
            saveGame(getSavegameFilename(0), "New game");
}

void KyraEngine_v1::mainLoop() {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::mainLoop()");

      while (!_quitFlag) {
            int32 frameTime = (int32)_system->getMillis();
            _skipFlag = false;

            if (_currentCharacter->sceneId == 210) {
                  updateKyragemFading();
                  if (seq_playEnd() && _deathHandler != 8)
                        break;
            }
            
            if (_deathHandler != 0xFF) {
                  snd_playWanderScoreViaMap(0, 1);
                  snd_playSoundEffect(49);
                  _screen->hideMouse();
                  _screen->setMouseCursor(1, 1, _shapes[0]);
                  destroyMouseItem();
                  _screen->showMouse();
                  buttonMenuCallback(0);
                  _deathHandler = 0xFF;
            }
            
            if ((_brandonStatusBit & 2) && _brandonStatusBit0x02Flag)
                  _animator->animRefreshNPC(0);

            if ((_brandonStatusBit & 0x20) && _brandonStatusBit0x20Flag) {
                  _animator->animRefreshNPC(0);
                  _brandonStatusBit0x20Flag = 0;
            }
            
            _screen->showMouse();

            processButtonList(_buttonList);
            updateMousePointer();
            _timer->update();
            updateTextFade();

            _handleInput = true;
            delay((frameTime + _gameSpeed) - _system->getMillis(), true, true);
            _handleInput = false;

            _sound->process();
      }
}

void KyraEngine_v1::delayUntil(uint32 timestamp, bool updateTimers, bool update, bool isMainLoop) {
      while (_system->getMillis() < timestamp && !_quitFlag) {
            if (updateTimers)
                  _timer->update();

            if (timestamp - _system->getMillis() >= 10)
                  delay(10, update, isMainLoop);
      }
}

void KyraEngine_v1::delay(uint32 amount, bool update, bool isMainLoop) {
      Common::Event event;

      uint32 start = _system->getMillis();
      do {
            while (_eventMan->pollEvent(event)) {
                  switch (event.type) {
                  case Common::EVENT_KEYDOWN:
                        if (event.kbd.keycode >= '1' && event.kbd.keycode <= '9' && 
                                    (event.kbd.flags == Common::KBD_CTRL || event.kbd.flags == Common::KBD_ALT) && isMainLoop) {
                              const char *saveLoadSlot = getSavegameFilename(event.kbd.keycode - '0');

                              if (event.kbd.flags == Common::KBD_CTRL)
                                    loadGame(saveLoadSlot);
                              else {
                                    char savegameName[14];
                                    sprintf(savegameName, "Quicksave %d",  event.kbd.keycode - '0');
                                    saveGame(saveLoadSlot, savegameName);
                              }
                        } else if (event.kbd.flags == Common::KBD_CTRL) {
                              if (event.kbd.keycode == 'd')
                                    _debugger->attach();
                              else if (event.kbd.keycode == 'q')
                                    _quitFlag = true;
                        } else if (event.kbd.keycode == '.')
                                    _skipFlag = true;
                        else if (event.kbd.keycode == Common::KEYCODE_RETURN || event.kbd.keycode == Common::KEYCODE_SPACE || event.kbd.keycode == Common::KEYCODE_ESCAPE) {
                              _abortIntroFlag = true;
                              _skipFlag = true;
                        }

                        break;
                  case Common::EVENT_MOUSEMOVE:
                        _animator->_updateScreen = true;
                        break;
                  case Common::EVENT_QUIT:
                        quitGame();
                        break;
                  case Common::EVENT_LBUTTONDOWN:
                        _mousePressFlag = true;
                        break;
                  case Common::EVENT_LBUTTONUP:
                        _mousePressFlag = false;

                        if (_abortWalkFlag2) 
                              _abortWalkFlag = true;

                        if (_handleInput) {
                              _handleInput = false;
                              processInput();
                              _handleInput = true;
                        } else
                              _skipFlag = true;

                        break;
                  default:
                        break;
                  }
            }

            if (_debugger->isAttached())
                  _debugger->onFrame();

            if (update) {
                  _sprites->updateSceneAnims();
                  _animator->updateAllObjectShapes();
                  updateTextFade();
                  updateMousePointer();
            }

            if (_currentCharacter && _currentCharacter->sceneId == 210 && update)
                  updateKyragemFading();

            if (_skipFlag && !_abortIntroFlag && !queryGameFlag(0xFE))
                  _skipFlag = false;
                  
            if (amount > 0 && !_skipFlag && !_quitFlag)
                  _system->delayMillis(10);

            if (_skipFlag)
                  _sound->voiceStop();
      } while (!_skipFlag && _system->getMillis() < start + amount && !_quitFlag);
}

void KyraEngine_v1::waitForEvent() {
      bool finished = false;
      Common::Event event;

      while (!finished && !_quitFlag) {
            while (_eventMan->pollEvent(event)) {
                  switch (event.type) {
                  case Common::EVENT_KEYDOWN:
                        finished = true;
                        break;
                  case Common::EVENT_QUIT:
                        quitGame();
                        break;
                  case Common::EVENT_LBUTTONDOWN:
                        finished = true;
                        _skipFlag = true;
                        break;
                  default:
                        break;
                  }
            }

            if (_debugger->isAttached())
                  _debugger->onFrame();

            _system->delayMillis(10);
      }
}

void KyraEngine_v1::delayWithTicks(int ticks) {
      uint32 nextTime = _system->getMillis() + ticks * _tickLength;

      while (_system->getMillis() < nextTime) {
            _sprites->updateSceneAnims();
            _animator->updateAllObjectShapes();

            if (_currentCharacter->sceneId == 210) {
                  updateKyragemFading();
                  seq_playEnd();
            }

            if (_skipFlag)
                  break;

            if (nextTime - _system->getMillis() >= 10)
                  delay(10);
      }
}

#pragma mark -
#pragma mark - Animation/shape specific code
#pragma mark -

void KyraEngine_v1::setupShapes123(const Shape *shapeTable, int endShape, int flags) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::setupShapes123(%p, %d, %d)", (const void *)shapeTable, endShape, flags);

      for (int i = 123; i <= 172; ++i)
            _shapes[i] = 0;

      uint8 curImage = 0xFF;
      int curPageBackUp = _screen->_curPage;
      _screen->_curPage = 8;  // we are using page 8 here in the original page 2 was backuped and then used for this stuff
      int shapeFlags = 2;
      if (flags)
            shapeFlags = 3;
      for (int i = 123; i < 123+endShape; ++i) {
            uint8 newImage = shapeTable[i-123].imageIndex;
            if (newImage != curImage && newImage != 0xFF) {
                  assert(_characterImageTable);
                  _screen->loadBitmap(_characterImageTable[newImage], 8, 8, 0);
                  curImage = newImage;
            }
            _shapes[i] = _screen->encodeShape(shapeTable[i-123].x<<3, shapeTable[i-123].y, shapeTable[i-123].w<<3, shapeTable[i-123].h, shapeFlags);
            assert(i-7 < _defaultShapeTableSize);
            _defaultShapeTable[i-7].xOffset = shapeTable[i-123].xOffset;
            _defaultShapeTable[i-7].yOffset = shapeTable[i-123].yOffset;
            _defaultShapeTable[i-7].w = shapeTable[i-123].w;
            _defaultShapeTable[i-7].h = shapeTable[i-123].h;
      }
      _screen->_curPage = curPageBackUp;
}

void KyraEngine_v1::freeShapes123() {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::freeShapes123()");

      for (int i = 123; i <= 172; ++i) {
            delete [] _shapes[i];
            _shapes[i] = 0;
      }
}

#pragma mark -
#pragma mark - Misc stuff
#pragma mark -

Movie *KyraEngine_v1::createWSAMovie() {
      if (_flags.platform == Common::kPlatformAmiga)
            return new WSAMovieAmiga(this);

      return new WSAMovieV1(this);
}

void KyraEngine_v1::setBrandonPoisonFlags(int reset) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::setBrandonPoisonFlags(%d)", reset);
      _brandonStatusBit |= 1;

      if (reset)
            _poisonDeathCounter = 0;

      for (int i = 0; i < 0x100; ++i)
            _brandonPoisonFlagsGFX[i] = i;

      _brandonPoisonFlagsGFX[0x99] = 0x34;
      _brandonPoisonFlagsGFX[0x9A] = 0x35;
      _brandonPoisonFlagsGFX[0x9B] = 0x37;
      _brandonPoisonFlagsGFX[0x9C] = 0x38;
      _brandonPoisonFlagsGFX[0x9D] = 0x2B;
}

void KyraEngine_v1::resetBrandonPoisonFlags() {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::resetBrandonPoisonFlags()");
      _brandonStatusBit = 0;

      for (int i = 0; i < 0x100; ++i)
            _brandonPoisonFlagsGFX[i] = i;
}

#pragma mark -
#pragma mark - Input
#pragma mark -

void KyraEngine_v1::processInput() {
      Common::Point mouse = getMousePos();
      int xpos = mouse.x;
      int ypos = mouse.y;

      debugC(9, kDebugLevelMain, "KyraEngine_v1::processInput(%d, %d)", xpos, ypos);
      _abortWalkFlag2 = false;

      if (processInputHelper(xpos, ypos))
            return;

      uint8 item = findItemAtPos(xpos, ypos);
      if (item == 0xFF) {
            _changedScene = false;
            int handled = clickEventHandler(xpos, ypos);
            if (_changedScene || handled)
                  return;
      } 
      
      // XXX _deathHandler specific
      if (ypos <= 158) {
            uint16 exit = 0xFFFF;
            if (xpos < 12) {
                  exit = _walkBlockWest;
            } else if (xpos >= 308) {
                  exit = _walkBlockEast;
            } else if (ypos >= 136) {
                  exit = _walkBlockSouth;
            } else if (ypos < 12) {
                  exit = _walkBlockNorth;
            }
            
            if (exit != 0xFFFF) {
                  _abortWalkFlag2 = true;
                  handleSceneChange(xpos, ypos, 1, 1);
                  _abortWalkFlag2 = false;
                  return;
            } else {
                  int script = checkForNPCScriptRun(xpos, ypos);
                  if (script >= 0) {
                        runNpcScript(script);
                        return;
                  }
                  if (_itemInHand != -1) {
                        if (ypos < 155) {
                              if (hasClickedOnExit(xpos, ypos)) {
                                    _abortWalkFlag2 = true;
                                    handleSceneChange(xpos, ypos, 1, 1);
                                    _abortWalkFlag2 = false;
                                    return;
                              }
                              dropItem(0, _itemInHand, xpos, ypos, 1);
                        }
                  } else {
                        if (ypos <= 155) {
                              _abortWalkFlag2 = true;
                              handleSceneChange(xpos, ypos, 1, 1);
                              _abortWalkFlag2 = false;
                        }
                  }
            }
      }     
}

int KyraEngine_v1::processInputHelper(int xpos, int ypos) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::processInputHelper(%d, %d)", xpos, ypos);
      uint8 item = findItemAtPos(xpos, ypos);
      if (item != 0xFF) {
            if (_itemInHand == -1) {
                  _screen->hideMouse();
                  _animator->animRemoveGameItem(item);
                  snd_playSoundEffect(53);
                  assert(_currentCharacter->sceneId < _roomTableSize);
                  Room *currentRoom = &_roomTable[_currentCharacter->sceneId];
                  int item2 = currentRoom->itemsTable[item];
                  currentRoom->itemsTable[item] = 0xFF;
                  setMouseItem(item2);
                  assert(_itemList && _takenList);
                  updateSentenceCommand(_itemList[item2], _takenList[0], 179);
                  _itemInHand = item2;
                  _screen->showMouse();
                  clickEventHandler2();
                  return 1;
            } else {
                  exchangeItemWithMouseItem(_currentCharacter->sceneId, item);
                  return 1;
            }
      }
      return 0;
}

int KyraEngine_v1::clickEventHandler(int xpos, int ypos) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::clickEventHandler(%d, %d)", xpos, ypos);
      _scriptInterpreter->initScript(_scriptClick, _scriptClickData);
      _scriptClick->regs[1] = xpos;
      _scriptClick->regs[2] = ypos;
      _scriptClick->regs[3] = 0;
      _scriptClick->regs[4] = _itemInHand;
      _scriptInterpreter->startScript(_scriptClick, 1);

      while (_scriptInterpreter->validScript(_scriptClick))
            _scriptInterpreter->runScript(_scriptClick);

      return _scriptClick->regs[3];
}

void KyraEngine_v1::updateMousePointer(bool forceUpdate) {
      int shape = 0;
      
      int newMouseState = 0;
      int newX = 0;
      int newY = 0;
      Common::Point mouse = getMousePos();
      if (mouse.y <= 158) {
            if (mouse.x >= 12) {
                  if (mouse.x >= 308) {
                        if (_walkBlockEast == 0xFFFF) {
                              newMouseState = -2;
                        } else {
                              newMouseState = -5;
                              shape = 3;
                              newX = 7;
                              newY = 5;
                        }
                  } else if (mouse.y >= 136) {
                        if (_walkBlockSouth == 0xFFFF) {
                              newMouseState = -2;
                        } else {
                              newMouseState = -4;
                              shape = 4;
                              newX = 5;
                              newY = 7;
                        }
                  } else if (mouse.y < 12) {
                        if (_walkBlockNorth == 0xFFFF) {
                              newMouseState = -2;
                        } else {
                              newMouseState = -6;
                              shape = 2;
                              newX = 5;
                              newY = 1;
                        }
                  }
            } else {
                  if (_walkBlockWest == 0xFFFF) {
                        newMouseState = -2;
                  } else {
                        newMouseState = -3;
                        newX = 1;
                        newY = shape = 5;
                  }
            }
      }
      
      if (mouse.x >= _entranceMouseCursorTracks[0] && mouse.y >= _entranceMouseCursorTracks[1]
            && mouse.x <= _entranceMouseCursorTracks[2] && mouse.y <= _entranceMouseCursorTracks[3]) {
            switch (_entranceMouseCursorTracks[4]) {
            case 0:
                  newMouseState = -6;
                  shape = 2;
                  newX = 5;
                  newY = 1;
                  break;

            case 2:
                  newMouseState = -5;
                  shape = 3;
                  newX = 7;
                  newY = 5;
                  break;

            case 4:
                  newMouseState = -4;
                  shape = 4;
                  newX = 5;
                  newY = 7;
                  break;

            case 6:
                  newMouseState = -3;
                  shape = 5;
                  newX = 1;
                  newY = 5;
                  break;

            default:
                  break;
            }
      }
      
      if (newMouseState == -2) {
            shape = 6;
            newX = 4;
            newY = 4;
      }
      
      if ((newMouseState && _mouseState != newMouseState) || (newMouseState && forceUpdate)) {
            _mouseState = newMouseState;
            _screen->hideMouse();
            _screen->setMouseCursor(newX, newY, _shapes[shape]);
            _screen->showMouse();
      }
      
      if (!newMouseState) {
            if (_mouseState != _itemInHand || forceUpdate) {
                  if (mouse.y > 158 || (mouse.x >= 12 && mouse.x < 308 && mouse.y < 136 && mouse.y >= 12) || forceUpdate) {
                        _mouseState = _itemInHand;
                        _screen->hideMouse();
                        if (_itemInHand == -1)
                              _screen->setMouseCursor(1, 1, _shapes[0]);
                        else
                              _screen->setMouseCursor(8, 15, _shapes[216+_itemInHand]);
                        _screen->showMouse();
                  }
            }
      }
}

bool KyraEngine_v1::hasClickedOnExit(int xpos, int ypos) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::hasClickedOnExit(%d, %d)", xpos, ypos);
      if (xpos < 16 || xpos >= 304)
            return true;

      if (ypos < 8)
            return true;

      if (ypos < 136 || ypos > 155)
            return false;

      return true;
}

void KyraEngine_v1::clickEventHandler2() {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::clickEventHandler2()");

      Common::Point mouse = getMousePos();

      _scriptInterpreter->initScript(_scriptClick, _scriptClickData);
      _scriptClick->regs[0] = _currentCharacter->sceneId;
      _scriptClick->regs[1] = mouse.x;
      _scriptClick->regs[2] = mouse.y;
      _scriptClick->regs[4] = _itemInHand;
      _scriptInterpreter->startScript(_scriptClick, 6);
      
      while (_scriptInterpreter->validScript(_scriptClick))
            _scriptInterpreter->runScript(_scriptClick);
}

int KyraEngine_v1::checkForNPCScriptRun(int xpos, int ypos) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::checkForNPCScriptRun(%d, %d)", xpos, ypos);
      int returnValue = -1;
      const Character *currentChar = _currentCharacter;
      int charLeft = 0, charRight = 0, charTop = 0, charBottom = 0;
      
      int scaleFactor = _scaleTable[currentChar->y1];
      int addX = (((scaleFactor*8)*3)>>8)>>1;
      int addY = ((scaleFactor*3)<<4)>>8;
      
      charLeft = currentChar->x1 - addX;
      charRight = currentChar->x1 + addX;
      charTop = currentChar->y1 - addY;
      charBottom = currentChar->y1;
      
      if (xpos >= charLeft && charRight >= xpos && charTop <= ypos && charBottom >= ypos)
            return 0;
      
      if (xpos > 304 || xpos < 16)
            return -1;
      
      for (int i = 1; i < 5; ++i) {
            currentChar = &_characterList[i];
            
            if (currentChar->sceneId != _currentCharacter->sceneId)
                  continue;
                  
            charLeft = currentChar->x1 - 12;
            charRight = currentChar->x1 + 11;
            charTop = currentChar->y1 - 48;
            // if (!i)
            //    charBottom = currentChar->y2 - 16;
            // else
            charBottom = currentChar->y1;
            
            if (xpos < charLeft || xpos > charRight || ypos < charTop || charBottom < ypos)
                  continue;
            
            if (returnValue != -1) {
                  if (currentChar->y1 >= _characterList[returnValue].y1)
                        returnValue = i;
            } else {
                  returnValue = i;
            }
      }
      
      return returnValue;
}

void KyraEngine_v1::runNpcScript(int func) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::runNpcScript(%d)", func);
      _scriptInterpreter->initScript(_npcScript, _npcScriptData);
      _scriptInterpreter->startScript(_npcScript, func);
      _npcScript->regs[0] = _currentCharacter->sceneId;
      _npcScript->regs[4] = _itemInHand;
      _npcScript->regs[5] = func;
      
      while (_scriptInterpreter->validScript(_npcScript))
            _scriptInterpreter->runScript(_npcScript);
}

void KyraEngine_v1::checkAmuletAnimFlags() {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::checkSpecialAnimFlags()");

      if (_brandonStatusBit & 2) {
            seq_makeBrandonNormal2();
            _timer->setCountdown(19, 300);
      }

      if (_brandonStatusBit & 0x20) {
            seq_makeBrandonNormal();
            _timer->setCountdown(19, 300);
      }
}

typedef Functor1Mem<ScriptState*, int, KyraEngine_v1> OpcodeV1;
#define Opcode(x) OpcodeV1(this, &KyraEngine_v1::x)
void KyraEngine_v1::setupOpcodeTable() {
      static const OpcodeV1 opcodeTable[] = {
            // 0x00
            Opcode(o1_magicInMouseItem),
            Opcode(o1_characterSays),
            Opcode(o1_pauseTicks),
            Opcode(o1_drawSceneAnimShape),
            // 0x04
            Opcode(o1_queryGameFlag),
            Opcode(o1_setGameFlag),
            Opcode(o1_resetGameFlag),
            Opcode(o1_runNPCScript),
            // 0x08
            Opcode(o1_setSpecialExitList),
            Opcode(o1_blockInWalkableRegion),
            Opcode(o1_blockOutWalkableRegion),
            Opcode(o1_walkPlayerToPoint),
            // 0x0c
            Opcode(o1_dropItemInScene),
            Opcode(o1_drawAnimShapeIntoScene),
            Opcode(o1_createMouseItem),
            Opcode(o1_savePageToDisk),
            // 0x10
            Opcode(o1_sceneAnimOn),
            Opcode(o1_sceneAnimOff),
            Opcode(o1_getElapsedSeconds),
            Opcode(o1_mouseIsPointer),
            // 0x14
            Opcode(o1_destroyMouseItem),
            Opcode(o1_runSceneAnimUntilDone),
            Opcode(o1_fadeSpecialPalette),
            Opcode(o1_playAdlibSound),
            // 0x18
            Opcode(o1_playAdlibScore),
            Opcode(o1_phaseInSameScene),
            Opcode(o1_setScenePhasingFlag),
            Opcode(o1_resetScenePhasingFlag),
            // 0x1c
            Opcode(o1_queryScenePhasingFlag),
            Opcode(o1_sceneToDirection),
            Opcode(o1_setBirthstoneGem),
            Opcode(o1_placeItemInGenericMapScene),
            // 0x20
            Opcode(o1_setBrandonStatusBit),
            Opcode(o1_pauseSeconds),
            Opcode(o1_getCharactersLocation),
            Opcode(o1_runNPCSubscript),
            // 0x24
            Opcode(o1_magicOutMouseItem),
            Opcode(o1_internalAnimOn),
            Opcode(o1_forceBrandonToNormal),
            Opcode(o1_poisonDeathNow),
            // 0x28
            Opcode(o1_setScaleMode),
            Opcode(o1_openWSAFile),
            Opcode(o1_closeWSAFile),
            Opcode(o1_runWSAFromBeginningToEnd),
            // 0x2c
            Opcode(o1_displayWSAFrame),
            Opcode(o1_enterNewScene),
            Opcode(o1_setSpecialEnterXAndY),
            Opcode(o1_runWSAFrames),
            // 0x30
            Opcode(o1_popBrandonIntoScene),
            Opcode(o1_restoreAllObjectBackgrounds),
            Opcode(o1_setCustomPaletteRange),
            Opcode(o1_loadPageFromDisk),
            // 0x34
            Opcode(o1_customPrintTalkString),
            Opcode(o1_restoreCustomPrintBackground),
            Opcode(o1_hideMouse),
            Opcode(o1_showMouse),
            // 0x38
            Opcode(o1_getCharacterX),
            Opcode(o1_getCharacterY),
            Opcode(o1_changeCharactersFacing),
            Opcode(o1_copyWSARegion),
            // 0x3c
            Opcode(o1_printText),
            Opcode(o1_random),
            Opcode(o1_loadSoundFile),
            Opcode(o1_displayWSAFrameOnHidPage),
            // 0x40
            Opcode(o1_displayWSASequentialFrames),
            Opcode(o1_drawCharacterStanding),
            Opcode(o1_internalAnimOff),
            Opcode(o1_changeCharactersXAndY),
            // 0x44
            Opcode(o1_clearSceneAnimatorBeacon),
            Opcode(o1_querySceneAnimatorBeacon),
            Opcode(o1_refreshSceneAnimator),
            Opcode(o1_placeItemInOffScene),
            // 0x48
            Opcode(o1_wipeDownMouseItem),
            Opcode(o1_placeCharacterInOtherScene),
            Opcode(o1_getKey),
            Opcode(o1_specificItemInInventory),
            // 0x4c
            Opcode(o1_popMobileNPCIntoScene),
            Opcode(o1_mobileCharacterInScene),
            Opcode(o1_hideMobileCharacter),
            Opcode(o1_unhideMobileCharacter),
            // 0x50
            Opcode(o1_setCharactersLocation),
            Opcode(o1_walkCharacterToPoint),
            Opcode(o1_specialEventDisplayBrynnsNote),
            Opcode(o1_specialEventRemoveBrynnsNote),
            // 0x54
            Opcode(o1_setLogicPage),
            Opcode(o1_fatPrint),
            Opcode(o1_preserveAllObjectBackgrounds),
            Opcode(o1_updateSceneAnimations),
            // 0x58
            Opcode(o1_sceneAnimationActive),
            Opcode(o1_setCharactersMovementDelay),
            Opcode(o1_getCharactersFacing),
            Opcode(o1_bkgdScrollSceneAndMasksRight),
            // 0x5c
            Opcode(o1_dispelMagicAnimation),
            Opcode(o1_findBrightestFireberry),
            Opcode(o1_setFireberryGlowPalette),
            Opcode(o1_setDeathHandlerFlag),
            // 0x60
            Opcode(o1_drinkPotionAnimation),
            Opcode(o1_makeAmuletAppear),
            Opcode(o1_drawItemShapeIntoScene),
            Opcode(o1_setCharactersCurrentFrame),
            // 0x64
            Opcode(o1_waitForConfirmationMouseClick),
            Opcode(o1_pageFlip),
            Opcode(o1_setSceneFile),
            Opcode(o1_getItemInMarbleVase),
            // 0x68
            Opcode(o1_setItemInMarbleVase),
            Opcode(o1_addItemToInventory),
            Opcode(o1_intPrint),
            Opcode(o1_shakeScreen),
            // 0x6c
            Opcode(o1_createAmuletJewel),
            Opcode(o1_setSceneAnimCurrXY),
            Opcode(o1_poisonBrandonAndRemaps),
            Opcode(o1_fillFlaskWithWater),
            // 0x70
            Opcode(o1_getCharactersMovementDelay),
            Opcode(o1_getBirthstoneGem),
            Opcode(o1_queryBrandonStatusBit),
            Opcode(o1_playFluteAnimation),
            // 0x74
            Opcode(o1_playWinterScrollSequence),
            Opcode(o1_getIdolGem),
            Opcode(o1_setIdolGem),
            Opcode(o1_totalItemsInScene),
            // 0x78
            Opcode(o1_restoreBrandonsMovementDelay),
            Opcode(o1_setMousePos),
            Opcode(o1_getMouseState),
            Opcode(o1_setEntranceMouseCursorTrack),
            // 0x7c
            Opcode(o1_itemAppearsOnGround),
            Opcode(o1_setNoDrawShapesFlag),
            Opcode(o1_fadeEntirePalette),
            Opcode(o1_itemOnGroundHere),
            // 0x80
            Opcode(o1_queryCauldronState),
            Opcode(o1_setCauldronState),
            Opcode(o1_queryCrystalState),
            Opcode(o1_setCrystalState),
            // 0x84
            Opcode(o1_setPaletteRange),
            Opcode(o1_shrinkBrandonDown),
            Opcode(o1_growBrandonUp),
            Opcode(o1_setBrandonScaleXAndY),
            // 0x88
            Opcode(o1_resetScaleMode),
            Opcode(o1_getScaleDepthTableValue),
            Opcode(o1_setScaleDepthTableValue),
            Opcode(o1_message),
            // 0x8c
            Opcode(o1_checkClickOnNPC),
            Opcode(o1_getFoyerItem),
            Opcode(o1_setFoyerItem),
            Opcode(o1_setNoItemDropRegion),
            // 0x90
            Opcode(o1_walkMalcolmOn),
            Opcode(o1_passiveProtection),
            Opcode(o1_setPlayingLoop),
            Opcode(o1_brandonToStoneSequence),
            // 0x94
            Opcode(o1_brandonHealingSequence),
            Opcode(o1_protectCommandLine),
            Opcode(o1_pauseMusicSeconds),
            Opcode(o1_resetMaskRegion),
            // 0x98
            Opcode(o1_setPaletteChangeFlag),
            Opcode(o1_fillRect),
            Opcode(o1_vocUnload),
            Opcode(o1_vocLoad),
            // 0x9c
            Opcode(o1_dummy)
      };
      
      for (int i = 0; i < ARRAYSIZE(opcodeTable); ++i)
            _opcodes.push_back(&opcodeTable[i]);
}
#undef Opcode

} // end of namespace Kyra



Generated by  Doxygen 1.6.0   Back to index