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

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

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

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

namespace Kyra {

void KyraEngine_v1::enterNewScene(int sceneId, int facing, int unk1, int unk2, int brandonAlive) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::enterNewScene(%d, %d, %d, %d, %d)", sceneId, facing, unk1, unk2, brandonAlive);
      int unkVar1 = 1;
      _screen->hideMouse();
      _handleInput = false;
      _abortWalkFlag = false;
      _abortWalkFlag2 = false;

      if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) {
            int newSfxFile = -1;
            if (_currentCharacter->sceneId == 7 && sceneId == 24)
                  newSfxFile = 2;
            else if (_currentCharacter->sceneId == 25 && sceneId == 109)
                  newSfxFile = 3;
            else if (_currentCharacter->sceneId == 120 && sceneId == 37)
                  newSfxFile = 4;
            else if (_currentCharacter->sceneId == 52 && sceneId == 199)
                  newSfxFile = 5;
            else if (_currentCharacter->sceneId == 37 && sceneId == 120)
                  newSfxFile = 3;
            else if (_currentCharacter->sceneId == 109 && sceneId == 25)
                  newSfxFile = 2;
            else if (_currentCharacter->sceneId == 24 && sceneId == 7)
                  newSfxFile = 1;
            
            if (newSfxFile != -1) {
                  _curSfxFile = newSfxFile;
                  _sound->loadSoundFile(_curSfxFile);
            }
      }
      
      switch (_currentCharacter->sceneId) {
      case 1:
            if (sceneId == 0) {
                  moveCharacterToPos(0, 0, _currentCharacter->x1, 84);
                  unkVar1 = 0;
            }
            break;

      case 3:
            if (sceneId == 2) {
                  moveCharacterToPos(0, 6, 155, _currentCharacter->y1);
                  unkVar1 = 0;
            }
            break;

      case 26:
            if (sceneId == 27) {
                  moveCharacterToPos(0, 6, 155, _currentCharacter->y1);
                  unkVar1 = 0;
            }
            break;

      case 44:
            if (sceneId == 45) {
                  moveCharacterToPos(0, 2, 192, _currentCharacter->y1);
                  unkVar1 = 0;
            }
            break;

      default:
            break;
      }
      
      if (unkVar1 && unk1) {
            int xpos = _currentCharacter->x1;
            int ypos = _currentCharacter->y1;
            switch (facing) {
            case 0:
                  ypos = _currentCharacter->y1 - 6;
                  break;

            case 2:
                  xpos = 336;
                  break;

            case 4:
                  ypos = 143;
                  break;

            case 6:
                  xpos = -16;
                  break;

            default:
                  break;
            }
            
            moveCharacterToPos(0, facing, xpos, ypos);
      }
      
      for (int i = 0; i < ARRAYSIZE(_movieObjects); ++i)
            _movieObjects[i]->close();
      
      if (!brandonAlive) {
            _scriptInterpreter->initScript(_scriptClick, _scriptClickData);
            _scriptInterpreter->startScript(_scriptClick, 5);
            while (_scriptInterpreter->validScript(_scriptClick))
                  _scriptInterpreter->runScript(_scriptClick);
      }
      
      memset(_entranceMouseCursorTracks, 0xFFFF, sizeof(uint16)*4);
      _currentCharacter->sceneId = sceneId;
      
      assert(sceneId < _roomTableSize);
      assert(_roomTable[sceneId].nameIndex < _roomFilenameTableSize);

      Room *currentRoom = &_roomTable[sceneId];
      
      setupSceneResource(sceneId);
      
      _currentRoom = sceneId;
      
      int tableId = _roomTable[sceneId].nameIndex;
      char fileNameBuffer[32];
      strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
      strcat(fileNameBuffer, ".DAT");
      _sprites->loadDat(fileNameBuffer, _sceneExits);
      _sprites->setupSceneAnims();
      _scriptInterpreter->unloadScript(_scriptClickData);
      loadSceneMsc();
      
      _walkBlockNorth = currentRoom->northExit;
      _walkBlockEast = currentRoom->eastExit;
      _walkBlockSouth = currentRoom->southExit;
      _walkBlockWest = currentRoom->westExit;
      
      if (_walkBlockNorth == 0xFFFF)
            _screen->blockOutRegion(0, 0, 320, (_northExitHeight & 0xFF)+3);
      if (_walkBlockEast == 0xFFFF)
            _screen->blockOutRegion(312, 0, 8, 139);
      if (_walkBlockSouth == 0xFFFF)
            _screen->blockOutRegion(0, 135, 320, 8);
      if (_walkBlockWest == 0xFFFF)
            _screen->blockOutRegion(0, 0, 8, 139);
      
      if (!brandonAlive)
            updatePlayerItemsForScene();

      startSceneScript(brandonAlive);
      setupSceneItems();
      
      initSceneData(facing, unk2, brandonAlive);
      
      _loopFlag2 = 0;
      _screen->showMouse();
      if (!brandonAlive)
            seq_poisonDeathNow(0);
      updateMousePointer(true);
      _changedScene = true;
}

void KyraEngine_v1::transcendScenes(int roomIndex, int roomName) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::transcendScenes(%d, %d)", roomIndex, roomName);
      assert(roomIndex < _roomTableSize);

      if (_flags.isTalkie) {
            char file[32];
            assert(roomIndex < _roomTableSize);
            int tableId = _roomTable[roomIndex].nameIndex;
            assert(tableId < _roomFilenameTableSize);
            strcpy(file, _roomFilenameTable[tableId]);
            strcat(file, ".VRM");
            _res->unloadPakFile(file);
      }

      _roomTable[roomIndex].nameIndex = roomName;
      _unkScreenVar2 = 1;
      _unkScreenVar3 = 1;
      _unkScreenVar1 = 0;
      _brandonPosX = _currentCharacter->x1;
      _brandonPosY = _currentCharacter->y1;
      enterNewScene(roomIndex, _currentCharacter->facing, 0, 0, 0);
      _unkScreenVar1 = 1;
      _unkScreenVar2 = 0;
      _unkScreenVar3 = 0;
}

void KyraEngine_v1::setSceneFile(int roomIndex, int roomName) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::setSceneFile(%d, %d)", roomIndex, roomName);
      assert(roomIndex < _roomTableSize);
      _roomTable[roomIndex].nameIndex = roomName;
}

void KyraEngine_v1::moveCharacterToPos(int character, int facing, int xpos, int ypos) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::moveCharacterToPos(%d, %d, %d, %d)", character, facing, xpos, ypos);
      Character *ch = &_characterList[character];
      ch->facing = facing;
      _screen->hideMouse();
      xpos = (int16)(xpos & 0xFFFC);
      ypos = (int16)(ypos & 0xFFFE);
      _timer->disable(19);
      _timer->disable(14);
      _timer->disable(18);
      uint32 nextFrame = 0;

      switch (facing) {
      case 0:
            while (ypos < ch->y1) {
                  nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
                  setCharacterPositionWithUpdate(character);
                  delayUntil(nextFrame, true);
            }
            break;
            
      case 2:     
            while (ch->x1 < xpos) {
                  nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
                  setCharacterPositionWithUpdate(character);
                  delayUntil(nextFrame, true);
            }
            break;
            
      case 4:
            while (ypos > ch->y1) {
                  nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
                  setCharacterPositionWithUpdate(character);
                  delayUntil(nextFrame, true);
            }
            break;
            
      case 6:
            while (ch->x1 > xpos) {
                  nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
                  setCharacterPositionWithUpdate(character);
                  delayUntil(nextFrame, true);
            }
            break;
            
      default:
            break;
      }

      _timer->enable(19);
      _timer->enable(14);
      _timer->enable(18);
      _screen->showMouse();
}

void KyraEngine_v1::setCharacterPositionWithUpdate(int character) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::setCharacterPositionWithUpdate(%d)", character);
      setCharacterPosition(character, 0);
      _sprites->updateSceneAnims();
      _timer->update();
      _animator->updateAllObjectShapes();
      updateTextFade();

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

int KyraEngine_v1::setCharacterPosition(int character, int *facingTable) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::setCharacterPosition(%d, %p)", character, (const void *)facingTable);

      if (character == 0) {
            _currentCharacter->x1 += _charXPosTable[_currentCharacter->facing];
            _currentCharacter->y1 += _charYPosTable[_currentCharacter->facing];
            setCharacterPositionHelper(0, facingTable);
            return 1;
      } else {
            _characterList[character].x1 += _charXPosTable[_characterList[character].facing];
            _characterList[character].y1 += _charYPosTable[_characterList[character].facing];
            if (_characterList[character].sceneId == _currentCharacter->sceneId)
                  setCharacterPositionHelper(character, 0);
      }
      return 0;
}

void KyraEngine_v1::setCharacterPositionHelper(int character, int *facingTable) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::setCharacterPositionHelper(%d, %p)", character, (const void *)facingTable);
      Character *ch = &_characterList[character];
      ++ch->currentAnimFrame;
      int facing = ch->facing;
      if (facingTable) {
            if (*facingTable != *(facingTable - 1)) {
                  if (*(facingTable - 1) == *(facingTable + 1)) {
                        facing = getOppositeFacingDirection(*(facingTable - 1));
                        *facingTable = *(facingTable - 1);
                  }
            }
      }
      
      static uint8 facingIsZero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
      static uint8 facingIsFour[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
      
      if (facing == 0) {
            ++facingIsZero[character];
      } else {
            bool resetTables = false;
            if (facing != 7) {
                  if (facing - 1 != 0) {
                        if (facing != 4) {
                              if (facing == 3 || facing == 5) {
                                    if (facingIsFour[character] > 2)
                                          facing = 4;
                                    resetTables = true;
                              }
                        } else {
                              ++facingIsFour[character];
                        }
                  } else {
                        if (facingIsZero[character] > 2)
                              facing = 0;
                        resetTables = true;
                  }
            } else {
                  if (facingIsZero[character] > 2)
                        facing = 0;
                  resetTables = true;
            }
            
            if (resetTables) {
                  facingIsZero[character] = 0;
                  facingIsFour[character] = 0;
            }
      }
      
      static const uint16 maxAnimationFrame[] = {
            0x000F, 0x0031, 0x0055, 0x0000, 0x0000, 0x0000,
            0x0008, 0x002A, 0x004E, 0x0000, 0x0000, 0x0000,
            0x0022, 0x0046, 0x006A, 0x0000, 0x0000, 0x0000,
            0x001D, 0x0041, 0x0065, 0x0000, 0x0000, 0x0000,
            0x001F, 0x0043, 0x0067, 0x0000, 0x0000, 0x0000,
            0x0028, 0x004C, 0x0070, 0x0000, 0x0000, 0x0000,
            0x0023, 0x0047, 0x006B, 0x0000, 0x0000, 0x0000
      };
      
      if (facing == 0) {
            if (maxAnimationFrame[36+character] > ch->currentAnimFrame)
                  ch->currentAnimFrame = maxAnimationFrame[36+character];
            if (maxAnimationFrame[30+character] < ch->currentAnimFrame)
                  ch->currentAnimFrame = maxAnimationFrame[36+character];
      } else if (facing == 4) {
            if (maxAnimationFrame[18+character] > ch->currentAnimFrame)
                  ch->currentAnimFrame = maxAnimationFrame[18+character];
            if (maxAnimationFrame[12+character] < ch->currentAnimFrame)
                  ch->currentAnimFrame = maxAnimationFrame[18+character];
      } else {
            if (maxAnimationFrame[18+character] < ch->currentAnimFrame)
                  ch->currentAnimFrame = maxAnimationFrame[30+character];
            if (maxAnimationFrame[character] == ch->currentAnimFrame)
                  ch->currentAnimFrame = maxAnimationFrame[6+character];
            if (maxAnimationFrame[character] < ch->currentAnimFrame)
                  ch->currentAnimFrame = maxAnimationFrame[6+character]+2;
      }
      
      if (character == 0 && (_brandonStatusBit & 0x10))
            ch->currentAnimFrame = 88;
      
      _animator->animRefreshNPC(character);
}

void KyraEngine_v1::loadSceneMsc() {
      assert(_currentCharacter->sceneId < _roomTableSize);
      int tableId = _roomTable[_currentCharacter->sceneId].nameIndex;
      assert(tableId < _roomFilenameTableSize);
      char fileNameBuffer[32];
      strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
      strcat(fileNameBuffer, ".MSC");
      _screen->fillRect(0, 0, 319, 199, 0, 5);
      _screen->loadBitmap(fileNameBuffer, 3, 5, 0);
}

void KyraEngine_v1::startSceneScript(int brandonAlive) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::startSceneScript(%d)", brandonAlive);
      assert(_currentCharacter->sceneId < _roomTableSize);
      int tableId = _roomTable[_currentCharacter->sceneId].nameIndex;
      assert(tableId < _roomFilenameTableSize);
      char fileNameBuffer[32];
      strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
      strcat(fileNameBuffer, ".CPS");
      _screen->clearPage(3);
      // FIXME: check this hack for amiga version
      _screen->loadBitmap(fileNameBuffer, 3, 3, (_flags.platform == Common::kPlatformAmiga ? _screen->getPalette(0) : 0));
      _sprites->loadSceneShapes();
      _exitListPtr = 0;
      
      _scaleMode = 1;   
      for (int i = 0; i < 145; ++i)
            _scaleTable[i] = 256;
      
      clearNoDropRects();
      _scriptInterpreter->initScript(_scriptClick, _scriptClickData);
      strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
      strcat(fileNameBuffer, ".EMC");
      _scriptInterpreter->unloadScript(_scriptClickData);
      _scriptInterpreter->loadScript(fileNameBuffer, _scriptClickData, &_opcodes);
      _scriptInterpreter->startScript(_scriptClick, 0);
      _scriptClick->regs[0] = _currentCharacter->sceneId;
      _scriptClick->regs[7] = brandonAlive;
      
      while (_scriptInterpreter->validScript(_scriptClick))
            _scriptInterpreter->runScript(_scriptClick);
}

void KyraEngine_v1::initSceneData(int facing, int unk1, int brandonAlive) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::initSceneData(%d, %d, %d)", facing, unk1, brandonAlive);
      
      int16 xpos2 = 0;
      int setFacing = 1;
      
      int16 xpos = 0, ypos = 0;
      
      if (_brandonPosX == -1 && _brandonPosY == -1) {
            switch (facing + 1) {
            case 0:
                  xpos = ypos = -1;
                  break;

            case 1: case 2: case 8:
                  xpos = _sceneExits.southXPos;
                  ypos = _sceneExits.southYPos;
                  break;

            case 3:
                  xpos = _sceneExits.westXPos;
                  ypos = _sceneExits.westYPos;
                  break;

            case 4: case 5: case 6:
                  xpos = _sceneExits.northXPos;
                  ypos = _sceneExits.northYPos;
                  break;

            case 7:
                  xpos = _sceneExits.eastXPos;
                  ypos = _sceneExits.eastYPos;
                  break;

            default:
                  break;
            }
            
            if ((uint8)(_northExitHeight & 0xFF) + 2 >= ypos)
                  ypos = (_northExitHeight & 0xFF) + 4;
            if (xpos >= 308)
                  xpos = 304;
            if ((uint8)(_northExitHeight >> 8) - 2 <= ypos)
                  ypos = (_northExitHeight >> 8) - 4;
            if (xpos <= 12)
                  xpos = 16;
      }
      
      if (_brandonPosX > -1)
            xpos = _brandonPosX;
      if (_brandonPosY > -1)
            ypos = _brandonPosY;
      
      int16 ypos2 = 0;
      if (_brandonPosX > -1 && _brandonPosY > -1) {
            switch (_currentCharacter->sceneId) {
            case 1:
                  _currentCharacter->x1 = xpos;
                  _currentCharacter->x2 = xpos;
                  _currentCharacter->y1 = ypos;
                  _currentCharacter->y2 = ypos;
                  facing = 4;
                  xpos2 = 192;
                  ypos2 = 104;
                  setFacing = 0;
                  unk1 = 1;
                  break;

            case 3:
                  _currentCharacter->x1 = xpos;
                  _currentCharacter->x2 = xpos;
                  _currentCharacter->y1 = ypos;
                  _currentCharacter->y2 = ypos;
                  facing = 2;
                  xpos2 = 204;
                  ypos2 = 94;
                  setFacing = 0;
                  unk1 = 1;
                  break;

            case 26:
                  _currentCharacter->x1 = xpos;
                  _currentCharacter->x2 = xpos;
                  _currentCharacter->y1 = ypos;
                  _currentCharacter->y2 = ypos;
                  facing = 2;
                  xpos2 = 192;
                  ypos2 = 128;
                  setFacing = 0;
                  unk1 = 1;
                  break;

            case 44:
                  _currentCharacter->x1 = xpos;
                  _currentCharacter->x2 = xpos;
                  _currentCharacter->y1 = ypos;
                  _currentCharacter->y2 = ypos;
                  facing = 6;
                  xpos2 = 156;
                  ypos2 = 96;
                  setFacing = 0;
                  unk1 = 1;
                  break;

            case 37:
                  _currentCharacter->x1 = xpos;
                  _currentCharacter->x2 = xpos;
                  _currentCharacter->y1 = ypos;
                  _currentCharacter->y2 = ypos;
                  facing = 2;
                  xpos2 = 148;
                  ypos2 = 114;
                  setFacing = 0;
                  unk1 = 1;
                  break;

            default:
                  break;
            }
      }
      
      _brandonPosX = _brandonPosY = -1;
      
      if (unk1 && setFacing) {
            ypos2 = ypos;
            xpos2 = xpos;
            switch (facing) {
            case 0:
                  ypos = 142;
                  break;

            case 2:
                  xpos = -16;
                  break;

            case 4:
                  ypos = (uint8)(_northExitHeight & 0xFF) - 4;
                  break;

            case 6:
                  xpos = 336;
                  break;

            default:
                  break;
            }
      }
      
      xpos2 = (int16)(xpos2 & 0xFFFC);
      ypos2 = (int16)(ypos2 & 0xFFFE);
      xpos = (int16)(xpos & 0xFFFC);
      ypos = (int16)(ypos & 0xFFFE);
      _currentCharacter->facing = facing;
      _currentCharacter->x1 = xpos;
      _currentCharacter->x2 = xpos;
      _currentCharacter->y1 = ypos;
      _currentCharacter->y2 = ypos;
      
      initSceneObjectList(brandonAlive);
      
      if (unk1 && brandonAlive == 0)
            moveCharacterToPos(0, facing, xpos2, ypos2);
      
      _scriptClick->regs[4] = _itemInHand;
      _scriptClick->regs[7] = brandonAlive;
      _scriptInterpreter->startScript(_scriptClick, 3);
      while (_scriptInterpreter->validScript(_scriptClick))
            _scriptInterpreter->runScript(_scriptClick);
}

void KyraEngine_v1::initSceneObjectList(int brandonAlive) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::initSceneObjectList(%d)", brandonAlive);
      for (int i = 0; i < 28; ++i)
            _animator->actors()[i].active = 0;
      
      int startAnimFrame = 0;
      
      AnimObject *curAnimState = _animator->actors();
      curAnimState->active = 1;
      curAnimState->drawY = _currentCharacter->y1;
      curAnimState->sceneAnimPtr = _shapes[_currentCharacter->currentAnimFrame];
      curAnimState->animFrameNumber = _currentCharacter->currentAnimFrame;
      startAnimFrame = _currentCharacter->currentAnimFrame-7;
      int xOffset = _defaultShapeTable[startAnimFrame].xOffset;
      int yOffset = _defaultShapeTable[startAnimFrame].yOffset;

      if (_scaleMode) {
            curAnimState->x1 = _currentCharacter->x1;
            curAnimState->y1 = _currentCharacter->y1;
            
            _animator->_brandonScaleX = _scaleTable[_currentCharacter->y1];
            _animator->_brandonScaleY = _scaleTable[_currentCharacter->y1];
            
            curAnimState->x1 += (_animator->_brandonScaleX * xOffset) >> 8;
            curAnimState->y1 += (_animator->_brandonScaleY * yOffset) >> 8;
      } else {
            curAnimState->x1 = _currentCharacter->x1 + xOffset;
            curAnimState->y1 = _currentCharacter->y1 + yOffset;
      }

      curAnimState->x2 = curAnimState->x1;
      curAnimState->y2 = curAnimState->y1;
      curAnimState->refreshFlag = 1;
      curAnimState->bkgdChangeFlag = 1;
      _animator->clearQueue();
      _animator->addObjectToQueue(curAnimState);
      
      int listAdded = 0;
      int addedObjects = 1;
      
      for (int i = 1; i < 5; ++i) {
            Character *ch = &_characterList[i];
            curAnimState = &_animator->actors()[addedObjects];
            if (ch->sceneId != _currentCharacter->sceneId) {
                  curAnimState->active = 0;
                  curAnimState->refreshFlag = 0;
                  curAnimState->bkgdChangeFlag = 0;
                  ++addedObjects;
                  continue;
            }
            
            curAnimState->drawY = ch->y1;
            curAnimState->sceneAnimPtr = _shapes[ch->currentAnimFrame];
            curAnimState->animFrameNumber = ch->currentAnimFrame;
            startAnimFrame = ch->currentAnimFrame-7;
            xOffset = _defaultShapeTable[startAnimFrame].xOffset;
            yOffset = _defaultShapeTable[startAnimFrame].yOffset;
            if (_scaleMode) {
                  curAnimState->x1 = ch->x1;
                  curAnimState->y1 = ch->y1;
            
                  _animator->_brandonScaleX = _scaleTable[ch->y1];
                  _animator->_brandonScaleY = _scaleTable[ch->y1];
            
                  curAnimState->x1 += (_animator->_brandonScaleX * xOffset) >> 8;
                  curAnimState->y1 += (_animator->_brandonScaleY * yOffset) >> 8;
            } else {
                  curAnimState->x1 = ch->x1 + xOffset;
                  curAnimState->y1 = ch->y1 + yOffset;
            }
            curAnimState->x2 = curAnimState->x1;
            curAnimState->y2 = curAnimState->y1;
            curAnimState->active = 1;
            curAnimState->refreshFlag = 1;
            curAnimState->bkgdChangeFlag = 1;
            
            if (ch->facing >= 1 && ch->facing <= 3)
                  curAnimState->flags |= 1;
            else if (ch->facing >= 5 && ch->facing <= 7)
                  curAnimState->flags &= 0xFFFFFFFE;
            
            _animator->addObjectToQueue(curAnimState);
            
            ++addedObjects;
            ++listAdded;
            if (listAdded < 2)
                  i = 5;
      }
      
      for (int i = 0; i < 11; ++i) {
            curAnimState = &_animator->sprites()[i];

            if (_sprites->_anims[i].play) {
                  curAnimState->active = 1;
                  curAnimState->refreshFlag = 1;
                  curAnimState->bkgdChangeFlag = 1;
            } else {
                  curAnimState->active = 0;
                  curAnimState->refreshFlag = 0;
                  curAnimState->bkgdChangeFlag = 0;
            }
            curAnimState->height = _sprites->_anims[i].height;
            curAnimState->height2 = _sprites->_anims[i].height2;
            curAnimState->width = _sprites->_anims[i].width + 1;
            curAnimState->width2 = _sprites->_anims[i].width2;
            curAnimState->drawY = _sprites->_anims[i].drawY;
            curAnimState->x1 = curAnimState->x2 = _sprites->_anims[i].x;
            curAnimState->y1 = curAnimState->y2 = _sprites->_anims[i].y;
            curAnimState->background = _sprites->_anims[i].background;
            curAnimState->sceneAnimPtr = _sprites->_sceneShapes[_sprites->_anims[i].sprite];
            
            curAnimState->disable = _sprites->_anims[i].disable;
            
            if (_sprites->_anims[i].unk2)
                  curAnimState->flags = 0x800;
            else
                  curAnimState->flags = 0;

            if (_sprites->_anims[i].flipX)
                  curAnimState->flags |= 0x1;
            
            _animator->addObjectToQueue(curAnimState);
      }
      
      for (int i = 0; i < 12; ++i) {
            curAnimState = &_animator->items()[i];
            Room *curRoom = &_roomTable[_currentCharacter->sceneId];
            byte curItem = curRoom->itemsTable[i];
            if (curItem != 0xFF) {
                  curAnimState->drawY = curRoom->itemsYPos[i];
                  curAnimState->sceneAnimPtr = _shapes[216+curItem];
                  curAnimState->animFrameNumber = (int16)0xFFFF;
                  curAnimState->y1 = curRoom->itemsYPos[i];
                  curAnimState->x1 = curRoom->itemsXPos[i];
                  
                  curAnimState->x1 -= (_animator->fetchAnimWidth(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY])) >> 1;
                  curAnimState->y1 -= _animator->fetchAnimHeight(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY]);
                  
                  curAnimState->x2 = curAnimState->x1;
                  curAnimState->y2 = curAnimState->y1;
                  
                  curAnimState->active = 1;
                  curAnimState->refreshFlag = 1;
                  curAnimState->bkgdChangeFlag = 1;
                  
                  _animator->addObjectToQueue(curAnimState);
            } else {
                  curAnimState->active = 0;
                  curAnimState->refreshFlag = 0;
                  curAnimState->bkgdChangeFlag = 0;
            }
      }
      
      _animator->preserveAnyChangedBackgrounds();
      curAnimState = _animator->actors();
      curAnimState->bkgdChangeFlag = 1;
      curAnimState->refreshFlag = 1;
      for (int i = 1; i < 28; ++i) {
            curAnimState = &_animator->objects()[i];
            if (curAnimState->active) {
                  curAnimState->bkgdChangeFlag = 1;
                  curAnimState->refreshFlag = 1;
            }
      }
      _animator->restoreAllObjectBackgrounds();
      _animator->preserveAnyChangedBackgrounds();
      _animator->prepDrawAllObjects();
      initSceneScreen(brandonAlive);
      _animator->copyChangedObjectsForward(0);
}

void KyraEngine_v1::initSceneScreen(int brandonAlive) {
      if (_flags.platform == Common::kPlatformAmiga) {
            if (_unkScreenVar1 && !queryGameFlag(0xF0)) {
                  memset(_screen->getPalette(2), 0, 32*3);
                  if (_currentCharacter->sceneId != 117 || !queryGameFlag(0xB3))
                        _screen->setScreenPalette(_screen->getPalette(2));
            }

            if (_unkScreenVar2 == 1)
                  _screen->shuffleScreen(8, 8, 304, 128, 2, 0, _unkScreenVar3, false);
            else
                  _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0);

            if (_unkScreenVar1 && !queryGameFlag(0xA0)) {
                  if (_currentCharacter->sceneId == 45 && _paletteChanged)
                        memcpy(_screen->getPalette(0) + 12*3, _screen->getPalette(4) + 12*3, 2);

                  if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245 && (_brandonStatusBit & 1))
                        memcpy(_screen->getPalette(0), _screen->getPalette(0) + 320*3, 64);

                  _screen->setScreenPalette(_screen->getPalette(0));
            }
      } else {
            if (_unkScreenVar1 && !queryGameFlag(0xA0)) {
                  for (int i = 0; i < 60; ++i) {
                        uint16 col = _screen->getPalette(0)[684+i];
                        col += _screen->getPalette(1)[684+i] << 1;
                        col >>= 2;
                        _screen->getPalette(0)[684+i] = col;
                  }
                  _screen->setScreenPalette(_screen->getPalette(0));
            }

            if (_unkScreenVar2 == 1)
                  _screen->shuffleScreen(8, 8, 304, 128, 2, 0, _unkScreenVar3, false);
            else
                  _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0);

            if (_unkScreenVar1 && _paletteChanged) {
                  if (!queryGameFlag(0xA0)) {
                        memcpy(_screen->getPalette(0) + 684, _screen->getPalette(1) + 684, 60);
                        _screen->setScreenPalette(_screen->getPalette(0));
                  } else {
                        memset(_screen->getPalette(0), 0, 768);
                  }
            }
      }

      // really call this here?
      _screen->updateScreen();

      if (!_scriptInterpreter->startScript(_scriptClick, 2))
            error("Could not start script function 2 of scene script");

      _scriptClick->regs[7] = brandonAlive;

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

      setTextFadeTimerCountdown(-1);
      if (_currentCharacter->sceneId == 210) {
            if (_itemInHand != -1)
                  magicOutMouseItem(2, -1);
            
            _screen->hideMouse();
            for (int i = 0; i < 10; ++i) {
                  if (_currentCharacter->inventoryItems[i] != 0xFF)
                        magicOutMouseItem(2, i);
            }
            _screen->showMouse();
      }
}

int KyraEngine_v1::handleSceneChange(int xpos, int ypos, int unk1, int frameReset) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::handleSceneChange(%d, %d, %d, %d)", xpos, ypos, unk1, frameReset);
      if (queryGameFlag(0xEF))
            unk1 = 0;

      int sceneId = _currentCharacter->sceneId;
      _pathfinderFlag = 0;

      if (xpos < 12) {
            if (_roomTable[sceneId].westExit != 0xFFFF) {
                  xpos = 12;
                  ypos = _sceneExits.westYPos;
                  _pathfinderFlag = 7;
            }
      } else if (xpos >= 308) {
            if (_roomTable[sceneId].eastExit != 0xFFFF) {
                  xpos = 307;
                  ypos = _sceneExits.eastYPos;
                  _pathfinderFlag = 13;
            }
      }
      
      if (ypos <= (_northExitHeight&0xFF)+2) {
            if (_roomTable[sceneId].northExit != 0xFFFF) {
                  xpos = _sceneExits.northXPos;
                  ypos = _northExitHeight & 0xFF;
                  _pathfinderFlag = 14;
            }
      } else if (ypos >= 136) {
            if (_roomTable[sceneId].southExit != 0xFFFF) {
                  xpos = _sceneExits.southXPos;
                  ypos = 136;
                  _pathfinderFlag = 11;
            }
      }
      
      int temp = xpos - _currentCharacter->x1;
      if (ABS(temp) < 4) {
            temp = ypos - _currentCharacter->y1;
            if (ABS(temp) < 2)
                  return 0;
      }
      
      int x = (int16)(_currentCharacter->x1 & 0xFFFC);
      int y = (int16)(_currentCharacter->y1 & 0xFFFE);
      xpos = (int16)(xpos & 0xFFFC);
      ypos = (int16)(ypos & 0xFFFE);
      
      int ret = findWay(x, y, xpos, ypos, _movFacingTable, 150);
      _pathfinderFlag = 0;

      if (ret >= _lastFindWayRet)
            _lastFindWayRet = ret;

      if (ret == 0x7D00 || ret == 0)
            return 0;

      return processSceneChange(_movFacingTable, unk1, frameReset);
}

int KyraEngine_v1::processSceneChange(int *table, int unk1, int frameReset) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::processSceneChange(%p, %d, %d)", (const void *)table, unk1, frameReset);
      if (queryGameFlag(0xEF))
            unk1 = 0;

      int *tableStart = table;
      _sceneChangeState = 0;
      _loopFlag2 = 0;
      bool running = true;
      int returnValue = 0;
      uint32 nextFrame = 0;
      _abortWalkFlag = false;
      _mousePressFlag = false;

      while (running) {
            if (_abortWalkFlag) {
                  *table = 8;
                  _currentCharacter->currentAnimFrame = 7;
                  _animator->animRefreshNPC(0);
                  _animator->updateAllObjectShapes();
                  processInput();
                  return 0;
            }
            bool forceContinue = false;
            switch (*table) {
            case 0: case 1: case 2:
            case 3: case 4: case 5:
            case 6: case 7:
                  _currentCharacter->facing = getOppositeFacingDirection(*table);
                  break;

            case 8:
                  forceContinue = true;
                  running = false;
                  break;

            default:
                  ++table;
                  forceContinue = true;
                  break;
            }
            
            returnValue = changeScene(_currentCharacter->facing);
            if (returnValue) {
                  running = false;
                  _abortWalkFlag = false;
            }
            
            if (unk1) {
                  if (_mousePressFlag) {
                        running = false;
                        _sceneChangeState = 1;
                  }
            }
            
            if (forceContinue || !running)
                  continue;
            
            int temp = 0;
            if (table == tableStart || table[1] == 8)
                  temp = setCharacterPosition(0, 0);
            else
                  temp = setCharacterPosition(0, table);

            if (temp)
                  ++table;
            
            nextFrame = _timer->getDelay(5) * _tickLength + _system->getMillis();
            while (_system->getMillis() < nextFrame) {
                  _timer->update();

                  if (_currentCharacter->sceneId == 210) {
                        updateKyragemFading();
                        if (seq_playEnd() || _beadStateVar == 4 || _beadStateVar == 5) {
                              *table = 8;
                              running = false;
                              break;
                        }
                  }

                  if ((nextFrame - _system->getMillis()) >= 10)
                        delay(10, true);
            }
      }
      
      if (frameReset && !(_brandonStatusBit & 2))
            _currentCharacter->currentAnimFrame = 7;

      _animator->animRefreshNPC(0);
      _animator->updateAllObjectShapes();
      return returnValue;
}

int KyraEngine_v1::changeScene(int facing) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::changeScene(%d)", facing);
      if (queryGameFlag(0xEF)) {
            if (_currentCharacter->sceneId == 5)
                  return 0;
      }
      
      int xpos = _charXPosTable[facing] + _currentCharacter->x1;
      int ypos = _charYPosTable[facing] + _currentCharacter->y1;
      
      if (xpos >= 12 && xpos <= 308) {
            if (!lineIsPassable(xpos, ypos))
                  return false;
      }
      
      if (_exitListPtr) {
            int16 *ptr = _exitListPtr;
            // this loop should be only entered one time, seems to be some hack in the original
            while (true) {
                  if (*ptr == -1)
                        break;
                  
                  if (*ptr > _currentCharacter->x1 || _currentCharacter->y1 < ptr[1] || _currentCharacter->x1 > ptr[2] || _currentCharacter->y1 > ptr[3]) {
                        ptr += 10;
                        break;
                  }

                  _brandonPosX = ptr[6];
                  _brandonPosY = ptr[7];
                  uint16 sceneId = ptr[5];
                  facing = ptr[4];
                  int unk1 = ptr[8];
                  int unk2 = ptr[9];

                  if (sceneId == 0xFFFF) {
                        switch (facing) {
                        case 0:
                              sceneId = _roomTable[_currentCharacter->sceneId].northExit;
                              break;

                        case 2:
                              sceneId = _roomTable[_currentCharacter->sceneId].eastExit;
                              break;

                        case 4:
                              sceneId = _roomTable[_currentCharacter->sceneId].southExit;
                              break;

                        case 6:
                              sceneId = _roomTable[_currentCharacter->sceneId].westExit;
                              break;

                        default:
                              break;
                        }
                  }
                  
                  _currentCharacter->facing = facing;
                  _animator->animRefreshNPC(0);
                  _animator->updateAllObjectShapes();
                  enterNewScene(sceneId, facing, unk1, unk2, 0);
                  resetGameFlag(0xEE);
                  return 1;
            }
      }
      
      int returnValue = 0;
      facing = 0;
      
      if ((_northExitHeight & 0xFF) + 2 >= ypos || (_northExitHeight & 0xFF) + 2 >= _currentCharacter->y1) {
            facing = 0;
            returnValue = 1;
      }
      
      if (xpos >= 308 || (_currentCharacter->x1 + 4) >= 308) {
            facing = 2;
            returnValue = 1;
      }
      
      if (((_northExitHeight >> 8) & 0xFF) - 2 < ypos || ((_northExitHeight >> 8) & 0xFF) - 2 < _currentCharacter->y1) {
            facing = 4;
            returnValue = 1;
      }
      
      if (xpos <= 12 || _currentCharacter->y1 <= 12) {
            facing = 6;
            returnValue = 1;
      }
      
      if (!returnValue)
            return 0;
      
      uint16 sceneId = 0xFFFF;
      switch (facing) {
      case 0:
            sceneId = _roomTable[_currentCharacter->sceneId].northExit;
            break;

      case 2:
            sceneId = _roomTable[_currentCharacter->sceneId].eastExit;
            break;

      case 4:
            sceneId = _roomTable[_currentCharacter->sceneId].southExit;
            break;

      default:
            sceneId = _roomTable[_currentCharacter->sceneId].westExit;
            break;
      }
      
      if (sceneId == 0xFFFF)
            return 0;

      enterNewScene(sceneId, facing, 1, 1, 0);
      return returnValue;
}

void KyraEngine_v1::setCharactersInDefaultScene() {
      static const uint32 defaultSceneTable[][4] = {
            { 0xFFFF, 0x0004, 0x0003, 0xFFFF },
            { 0xFFFF, 0x0022, 0xFFFF, 0x0000 },
            { 0xFFFF, 0x001D, 0x0021, 0xFFFF },
            { 0xFFFF, 0x0000, 0x0000, 0xFFFF }
      };
      
      for (int i = 1; i < 5; ++i) {
            Character *cur = &_characterList[i];
            //cur->field_20 = 0;

            const uint32 *curTable = defaultSceneTable[i-1];
            cur->sceneId = curTable[0];

            if (cur->sceneId == _currentCharacter->sceneId)
                  //++cur->field_20;
                  cur->sceneId = curTable[1/*cur->field_20*/];

            //cur->field_23 = curTable[cur->field_20+1];
      }
}

void KyraEngine_v1::setCharactersPositions(int character) {
      static uint16 initXPosTable[] = {
            0x3200, 0x0024, 0x2230, 0x2F00, 0x0020, 0x002B,
            0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042
      };
      static uint8 initYPosTable[] = {
            0x00, 0xA2, 0x00, 0x42, 0x00,
            0x67, 0x67, 0x60, 0x5A, 0x71,
            0x76
      };

      assert(character < ARRAYSIZE(initXPosTable));
      Character *edit = &_characterList[character];
      edit->x1 = edit->x2 = initXPosTable[character];
      edit->y1 = edit->y2 = initYPosTable[character];
}

#pragma mark -
#pragma mark - Pathfinder
#pragma mark -

int KyraEngine_v1::findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::findWay(%d, %d, %d, %d, %p, %d)", x, y, toX, toY, (const void *)moveTable, moveTableSize);
      int ret = KyraEngine::findWay(x, y, toX, toY, moveTable, moveTableSize);
      if (ret == 0x7D00)
            return 0;
      return getMoveTableSize(moveTable);
}

bool KyraEngine_v1::lineIsPassable(int x, int y) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::lineIsPassable(%d, %d)", x, y);
      if (queryGameFlag(0xEF)) {
            if (_currentCharacter->sceneId == 5)
                  return true;
      }
      
      if (_pathfinderFlag & 2) {
            if (x >= 312)
                  return false;
      }
      
      if (_pathfinderFlag & 4) {
            if (y >= 136)
                  return false;
      }
      
      if (_pathfinderFlag & 8) {
            if (x < 8)
                  return false;
      }
      
      if (_pathfinderFlag2) {
            if (x <= 8 || x >= 312)
                  return true;
            if (y < (_northExitHeight & 0xFF) || y > 135)
                  return true;
      }
      
      if (y > 137)
            return false;

      if (y < 0)
            y = 0;
      
      int ypos = 8;
      if (_scaleMode) {
            ypos = (_scaleTable[y] >> 5) + 1;
            if (8 < ypos)
                  ypos = 8;
      }
      
      x -= (ypos >> 1);
      
      int xpos = x;
      int xtemp = xpos + ypos - 1;
      if (x < 0)
            xpos = 0;
            
      if (xtemp > 319)
            xtemp = 319;

      for (; xpos < xtemp; ++xpos) {
            if (!_screen->getShapeFlag1(xpos, y))
                  return false;
      }
      return true;
}

#pragma mark -

void KyraEngine_v1::setupSceneResource(int sceneId) {
      debugC(9, kDebugLevelMain, "KyraEngine_v1::setupSceneResource(%d)", sceneId);
      if (!_flags.isTalkie)
            return;

      if (_currentRoom != 0xFFFF) {
            assert(_currentRoom < _roomTableSize);
            int tableId = _roomTable[_currentRoom].nameIndex;
            assert(tableId < _roomFilenameTableSize);

            // unload our old room
            char file[64];
            strcpy(file, _roomFilenameTable[tableId]);
            strcat(file, ".VRM");
            _res->unloadPakFile(file);

            strcpy(file, _roomFilenameTable[tableId]);
            strcat(file, ".PAK");
            _res->unloadPakFile(file);

            strcpy(file, _roomFilenameTable[tableId]);
            strcat(file, ".APK");
            _res->unloadPakFile(file);
      }

      assert(sceneId < _roomTableSize);
      int tableId = _roomTable[sceneId].nameIndex;
      assert(tableId < _roomFilenameTableSize);

      // load our new room
      char file[64];
      strcpy(file, _roomFilenameTable[tableId]);
      strcat(file, ".VRM");
      if (Common::File::exists(file))
            _res->loadPakFile(file);

      strcpy(file, _roomFilenameTable[tableId]);
      strcat(file, ".PAK");
      if (Common::File::exists(file))
            _res->loadPakFile(file);

      strcpy(file, _roomFilenameTable[tableId]);
      strcat(file, ".APK");
      if (Common::File::exists(file))
            _res->loadPakFile(file);
}

} // end of namespace Kyra


Generated by  Doxygen 1.6.0   Back to index