diff options
Diffstat (limited to 'engines/draci/game.cpp')
-rw-r--r-- | engines/draci/game.cpp | 821 |
1 files changed, 380 insertions, 441 deletions
diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index f9eb55fb0e..1f3245a31b 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -135,6 +135,8 @@ Game::Game(DraciEngine *vm) : _vm(vm), _walkingState(vm) { // Set object location _objects[i]._location = (~(1 << 7) & tmp) - 1; + + _objects[i]._playingAnim = -1; } assert(numDialogues == _info._numDialogues); @@ -154,6 +156,7 @@ void Game::start() { loop(kOuterLoop, false); } } + } void Game::init() { @@ -168,61 +171,63 @@ void Game::init() { setLoopStatus(kStatusGate); setLoopSubstatus(kOuterLoop); - _animUnderCursor = kOverlayImage; + _animUnderCursor = NULL; - _currentItem = kNoItem; - _itemUnderCursor = kNoItem; + _currentItem = _itemUnderCursor = NULL; _vm->_mouse->setCursorType(kHighlightedCursor); // anything different from kNormalCursor - _objUnderCursor = kOverlayImage; + _objUnderCursor = NULL; // Set the inventory to empty initially - memset(_inventory, kNoItem, kInventorySlots * sizeof(int)); + memset(_inventory, 0, kInventorySlots * sizeof(GameItem *)); // Initialize animation for object / room titles - Animation *titleAnim = _vm->_anims->addText(kTitleText, true); - Text *title = new Text("", _vm->_smallFont, kTitleColour, 0, 0, 0); - titleAnim->addFrame(title, NULL); + _titleAnim = new Animation(_vm, kTitleText, 257, true); + _titleAnim->addFrame(new Text("", _vm->_smallFont, kTitleColour, 0, 0, 0), NULL); + _vm->_anims->insert(_titleAnim, false); // Initialize animation for speech text - Animation *speechAnim = _vm->_anims->addText(kSpeechText, true); - Text *speech = new Text("", _vm->_bigFont, kFontColour1, 0, 0, 0); - speechAnim->addFrame(speech, NULL); + Animation *speechAnim = new Animation(_vm, kSpeechText, 257, true); + speechAnim->addFrame(new Text("", _vm->_bigFont, kFontColour1, 0, 0, 0), NULL); + _vm->_anims->insert(speechAnim, false); // Initialize inventory animation. _iconsArchive is never flushed. const BAFile *f = _vm->_iconsArchive->getFile(13); - Animation *inventoryAnim = _vm->_anims->addAnimation(kInventorySprite, 255, false); + _inventoryAnim = new Animation(_vm, kInventorySprite, 255, false); Sprite *inventorySprite = new Sprite(f->_data, f->_length, 0, 0, true); - inventoryAnim->addFrame(inventorySprite, NULL); - inventoryAnim->setRelative((kScreenWidth - inventorySprite->getWidth()) / 2, + _inventoryAnim->addFrame(inventorySprite, NULL); + _inventoryAnim->setRelative((kScreenWidth - inventorySprite->getWidth()) / 2, (kScreenHeight - inventorySprite->getHeight()) / 2); + _vm->_anims->insert(_inventoryAnim, true); for (uint i = 0; i < kDialogueLines; ++i) { - _dialogueAnims[i] = _vm->_anims->addText(kDialogueLinesID - i, true); - Text *dialogueLine = new Text("", _vm->_smallFont, kLineInactiveColour, 0, 0, 0); - _dialogueAnims[i]->addFrame(dialogueLine, NULL); + _dialogueAnims[i] = new Animation(_vm, kDialogueLinesID - i, 254, true); + _dialogueAnims[i]->addFrame(new Text("", _vm->_smallFont, kLineInactiveColour, 0, 0, 0), NULL); - _dialogueAnims[i]->setZ(254); _dialogueAnims[i]->setRelative(1, kScreenHeight - (i + 1) * _vm->_smallFont->getFontHeight()); + _vm->_anims->insert(_dialogueAnims[i], false); Text *text = reinterpret_cast<Text *>(_dialogueAnims[i]->getCurrentFrame()); text->setText(""); } for (uint i = 0; i < _info._numItems; ++i) { - loadItem(i); + _items[i].load(i, _vm->_itemsArchive); } - loadObject(kDragonObject); + _objects[kDragonObject].load(kDragonObject, _vm->_objectsArchive); const GameObject *dragon = getObject(kDragonObject); debugC(4, kDraciLogicDebugLevel, "Running init program for the dragon object..."); _vm->_script->run(dragon->_program, dragon->_init); + // Add overlays for the walking map and shortest/obliqued paths. + initWalkingOverlays(); + // Make sure we enter the right room in start(). - setRoomNum(kNoEscRoom); + setRoomNum(-1); rememberRoomNumAsPrevious(); scheduleEnteringRoomUsingGate(_info._startRoom, 0); _pushedNewRoom = _pushedNewGate = -1; @@ -238,23 +243,21 @@ void Game::handleOrdinaryLoop(int x, int y) { if (_vm->_mouse->lButtonPressed()) { _vm->_mouse->lButtonSet(false); - if (_currentItem != kNoItem) { + if (_currentItem) { putItem(_currentItem, 0); - _currentItem = kNoItem; + _currentItem = NULL; updateOrdinaryCursor(); } else { - if (_objUnderCursor != kObjectNotFound) { - const GameObject *obj = &_objects[_objUnderCursor]; + if (_objUnderCursor) { + _walkingState.setCallback(&_objUnderCursor->_program, _objUnderCursor->_look); - _walkingState.setCallback(&obj->_program, obj->_look); - - if (obj->_imLook || !_currentRoom._heroOn) { + if (_objUnderCursor->_imLook || !_currentRoom._heroOn) { _walkingState.callback(); } else { - if (obj->_lookDir == kDirectionLast) { - walkHero(x, y, obj->_lookDir); + if (_objUnderCursor->_lookDir == kDirectionLast) { + walkHero(x, y, _objUnderCursor->_lookDir); } else { - walkHero(obj->_lookX, obj->_lookY, obj->_lookDir); + walkHero(_objUnderCursor->_lookX, _objUnderCursor->_lookY, _objUnderCursor->_lookDir); } } } else { @@ -267,19 +270,17 @@ void Game::handleOrdinaryLoop(int x, int y) { if (_vm->_mouse->rButtonPressed()) { _vm->_mouse->rButtonSet(false); - if (_objUnderCursor != kObjectNotFound) { - const GameObject *obj = &_objects[_objUnderCursor]; - - if (_vm->_script->testExpression(obj->_program, obj->_canUse)) { - _walkingState.setCallback(&obj->_program, obj->_use); + if (_objUnderCursor) { + if (_vm->_script->testExpression(_objUnderCursor->_program, _objUnderCursor->_canUse)) { + _walkingState.setCallback(&_objUnderCursor->_program, _objUnderCursor->_use); - if (obj->_imUse || !_currentRoom._heroOn) { + if (_objUnderCursor->_imUse || !_currentRoom._heroOn) { _walkingState.callback(); } else { - if (obj->_useDir == kDirectionLast) { - walkHero(x, y, obj->_useDir); + if (_objUnderCursor->_useDir == kDirectionLast) { + walkHero(x, y, _objUnderCursor->_useDir); } else { - walkHero(obj->_useX, obj->_useY, obj->_useDir); + walkHero(_objUnderCursor->_useX, _objUnderCursor->_useY, _objUnderCursor->_useDir); } } } else { @@ -309,14 +310,15 @@ void Game::handleInventoryLoop() { // If we are in inventory mode, all the animations except game items' // images will necessarily be paused so we can safely assume that any // animation under the cursor (a value returned by - // AnimationManager::getTopAnimationID()) will be an item animation or + // AnimationManager::getTopAnimation()) will be an item animation or // an overlay, for which we check. Item animations have their IDs // calculated by offseting their itemID from the ID of the last "special" // animation ID. In this way, we obtain its itemID. - if (_animUnderCursor != kOverlayImage && _animUnderCursor != kInventorySprite) { - _itemUnderCursor = kInventoryItemsID - _animUnderCursor; + if (_animUnderCursor != NULL && _animUnderCursor != _inventoryAnim && _animUnderCursor->getID() != kOverlayImage) { + _itemUnderCursor = getItem(kInventoryItemsID - _animUnderCursor->getID()); + assert(_itemUnderCursor->_anim == _animUnderCursor); } else { - _itemUnderCursor = kNoItem; + _itemUnderCursor = NULL; } // If the user pressed the left mouse button @@ -325,13 +327,11 @@ void Game::handleInventoryLoop() { // If there is an inventory item under the cursor and we aren't // holding any item, run its look GPL program - if (_itemUnderCursor != kNoItem && _currentItem == kNoItem) { - const GameItem *item = &_items[_itemUnderCursor]; - - _vm->_script->run(item->_program, item->_look); + if (_itemUnderCursor && !_currentItem) { + _vm->_script->run(_itemUnderCursor->_program, _itemUnderCursor->_look); // Otherwise, if we are holding an item, try to place it inside the // inventory - } else if (_currentItem != kNoItem) { + } else if (_currentItem) { const int column = scummvm_lround( (_vm->_mouse->getPosX() - kInventoryX + kInventoryItemWidth / 2.) / kInventoryItemWidth) - 1; @@ -342,22 +342,22 @@ void Game::handleInventoryLoop() { putItem(_currentItem, index); // Remove it from our hands - _currentItem = kNoItem; + _currentItem = NULL; } } else if (_vm->_mouse->rButtonPressed()) { _vm->_mouse->rButtonSet(false); // If we right-clicked outside the inventory, close it - if (_animUnderCursor != kInventorySprite && _itemUnderCursor == kNoItem) { + if (_animUnderCursor != _inventoryAnim && !_itemUnderCursor) { inventoryDone(); // If there is an inventory item under our cursor - } else if (_itemUnderCursor != kNoItem) { + } else if (_itemUnderCursor) { // Again, we have two possibilities: // The first is that there is no item in our hands. // In that case, just take the inventory item from the inventory. - if (_currentItem == kNoItem) { + if (!_currentItem) { _currentItem = _itemUnderCursor; removeItem(_itemUnderCursor); @@ -366,10 +366,8 @@ void Game::handleInventoryLoop() { // which will check if the two items are combinable and, finally, // run the use script for the item. } else { - const GameItem *item = &_items[_itemUnderCursor]; - - if (_vm->_script->testExpression(item->_program, item->_canUse)) { - _vm->_script->run(item->_program, item->_use); + if (_vm->_script->testExpression(_itemUnderCursor->_program, _itemUnderCursor->_canUse)) { + _vm->_script->run(_itemUnderCursor->_program, _itemUnderCursor->_use); } } updateInventoryCursor(); @@ -386,7 +384,7 @@ void Game::handleDialogueLoop() { for (int i = 0; i < kDialogueLines; ++i) { text = reinterpret_cast<Text *>(_dialogueAnims[i]->getCurrentFrame()); - if (_animUnderCursor == _dialogueAnims[i]->getID()) { + if (_animUnderCursor == _dialogueAnims[i]) { text->setColour(kLineActiveColour); } else { text->setColour(kLineInactiveColour); @@ -509,9 +507,9 @@ void Game::loop(LoopSubstatus substatus, bool shouldExit) { // corresponding to it int x = _vm->_mouse->getPosX(); int y = _vm->_mouse->getPosY(); - _animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + _animUnderCursor = _vm->_anims->getTopAnimation(x, y); _objUnderCursor = getObjectWithAnimation(_animUnderCursor); - debugC(5, kDraciLogicDebugLevel, "Anim under cursor: %d", _animUnderCursor); + debugC(5, kDraciLogicDebugLevel, "Anim under cursor: %d", _animUnderCursor ? _animUnderCursor->getID() : -1); switch (_loopStatus) { case kStatusOrdinary: @@ -547,9 +545,9 @@ void Game::updateOrdinaryCursor() { bool mouseChanged = false; // If there is no game object under the cursor, try using the room itself - if (_objUnderCursor == kObjectNotFound) { + if (!_objUnderCursor) { if (_vm->_script->testExpression(_currentRoom._program, _currentRoom._canUse)) { - if (_currentItem == kNoItem) { + if (!_currentItem) { _vm->_mouse->setCursorType(kHighlightedCursor); } else { _vm->_mouse->loadItemCursor(_currentItem, true); @@ -558,14 +556,12 @@ void Game::updateOrdinaryCursor() { } // If there *is* a game object under the cursor, update the cursor image } else { - const GameObject *obj = &_objects[_objUnderCursor]; - // If there is no walking direction set on the object (i.e. the object // is not a gate / exit), test whether it can be used and, if so, // update the cursor image (highlight it). - if (obj->_walkDir == 0) { - if (_vm->_script->testExpression(obj->_program, obj->_canUse)) { - if (_currentItem == kNoItem) { + if (_objUnderCursor->_walkDir == 0) { + if (_vm->_script->testExpression(_objUnderCursor->_program, _objUnderCursor->_canUse)) { + if (!_currentItem) { _vm->_mouse->setCursorType(kHighlightedCursor); } else { _vm->_mouse->loadItemCursor(_currentItem, true); @@ -575,14 +571,14 @@ void Game::updateOrdinaryCursor() { // If the walking direction *is* set, the game object is a gate, so update // the cursor image to the appropriate arrow. } else { - _vm->_mouse->setCursorType((CursorType)obj->_walkDir); + _vm->_mouse->setCursorType((CursorType)_objUnderCursor->_walkDir); mouseChanged = true; } } // Load the appropriate cursor (item image if an item is held or ordinary cursor // if not) if (!mouseChanged) { - if (_currentItem == kNoItem) { + if (!_currentItem) { _vm->_mouse->setCursorType(kNormalCursor); } else { _vm->_mouse->loadItemCursor(_currentItem, false); @@ -594,11 +590,9 @@ void Game::updateInventoryCursor() { // Fetch mouse coordinates bool mouseChanged = false; - if (_itemUnderCursor != kNoItem) { - const GameItem *item = &_items[_itemUnderCursor]; - - if (_vm->_script->testExpression(item->_program, item->_canUse)) { - if (_currentItem == kNoItem) { + if (_itemUnderCursor) { + if (_vm->_script->testExpression(_itemUnderCursor->_program, _itemUnderCursor->_canUse)) { + if (!_currentItem) { _vm->_mouse->setCursorType(kHighlightedCursor); } else { _vm->_mouse->loadItemCursor(_currentItem, true); @@ -607,7 +601,7 @@ void Game::updateInventoryCursor() { } } if (!mouseChanged) { - if (_currentItem == kNoItem) { + if (!_currentItem) { _vm->_mouse->setCursorType(kNormalCursor); } else { _vm->_mouse->loadItemCursor(_currentItem, false); @@ -621,101 +615,85 @@ void Game::updateTitle(int x, int y) { const int smallFontHeight = _vm->_smallFont->getFontHeight(); // Fetch the dedicated objects' title animation / current frame - Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); - Text *title = reinterpret_cast<Text *>(titleAnim->getCurrentFrame()); + Text *title = reinterpret_cast<Text *>(_titleAnim->getCurrentFrame()); // Mark dirty rectangle to delete the previous text - titleAnim->markDirtyRect(surface); + _titleAnim->markDirtyRect(surface); if (_loopStatus == kStatusInventory) { // If there is no item under the cursor, delete the title. // Otherwise, show the item's title. - if (_itemUnderCursor == kNoItem) { - title->setText(""); - } else { - const GameItem *item = &_items[_itemUnderCursor]; - title->setText(item->_title); - } + title->setText(_itemUnderCursor ? _itemUnderCursor->_title : ""); } else { // If there is no object under the cursor, delete the title. // Otherwise, show the object's title. - if (_objUnderCursor == kObjectNotFound) { - title->setText(""); - } else { - const GameObject *obj = &_objects[_objUnderCursor]; - title->setText(obj->_title); - } + title->setText(_objUnderCursor ? _objUnderCursor->_title : ""); } // Move the title to the correct place (just above the cursor) int newX = surface->centerOnX(x, title->getWidth()); int newY = surface->putAboveY(y - smallFontHeight / 2, title->getHeight()); - titleAnim->setRelative(newX, newY); + _titleAnim->setRelative(newX, newY); // If we are currently playing the title, mark it dirty so it gets updated. // Otherwise, start playing the title animation. - if (titleAnim->isPlaying()) { - titleAnim->markDirtyRect(surface); + if (_titleAnim->isPlaying()) { + _titleAnim->markDirtyRect(surface); } else { - _vm->_anims->play(titleAnim->getID()); + _titleAnim->play(); } } -int Game::getObjectWithAnimation(int animID) const { +const GameObject *Game::getObjectWithAnimation(const Animation *anim) const { for (uint i = 0; i < _info._numObjects; ++i) { GameObject *obj = &_objects[i]; - - for (uint j = 0; j < obj->_anim.size(); ++j) { - if (obj->_anim[j] == animID) { - return i; - } + if (obj->_playingAnim >= 0 && obj->_anim[obj->_playingAnim] == anim) { + return obj; } } - return kObjectNotFound; + return NULL; } -void Game::removeItem(int itemID) { +void Game::removeItem(GameItem *item) { for (uint i = 0; i < kInventorySlots; ++i) { - if (_inventory[i] == itemID) { - _inventory[i] = kNoItem; - _vm->_anims->stop(kInventoryItemsID - itemID); + if (_inventory[i] == item) { + _inventory[i] = NULL; + item->_anim->stop(); break; } } } -void Game::putItem(int itemID, int position) { - if (itemID == kNoItem) +void Game::loadItemAnimation(GameItem *item) { + if (item->_anim) return; + item->_anim = new Animation(_vm, kInventoryItemsID - item->_absNum, 256, false); + _vm->_anims->insert(item->_anim, false); + // _itemImagesArchive is never flushed. + const BAFile *img = _vm->_itemImagesArchive->getFile(2 * item->_absNum); + item->_anim->addFrame(new Sprite(img->_data, img->_length, 0, 0, true), NULL); +} - if (position >= 0 && - position < kInventorySlots && - (_inventory[position] == kNoItem || _inventory[position] == itemID)) { - _inventory[position] = itemID; - } else { - for (int i = 0; i < kInventorySlots; ++i) { - int pos = (position + i) % kInventorySlots; - if (_inventory[pos] == kNoItem) { - _inventory[pos] = itemID; - position = pos; - break; - } +void Game::putItem(GameItem *item, int position) { + if (!item) + return; + assert(position >= 0); + + for (int i = 0; i < kInventorySlots; ++i) { + int pos = (position + i) % kInventorySlots; + if (!_inventory[pos] || _inventory[pos] == item) { + _inventory[pos] = item; + position = pos; + break; } } const int line = position / kInventoryColumns + 1; const int column = position % kInventoryColumns + 1; - const int anim_id = kInventoryItemsID - itemID; - Animation *anim = _vm->_anims->getAnimation(anim_id); - if (!anim) { - anim = _vm->_anims->addItem(anim_id, false); - // _itemImagesArchive is never flushed. - const BAFile *img = _vm->_itemImagesArchive->getFile(2 * itemID); - Sprite *sp = new Sprite(img->_data, img->_length, 0, 0, true); - anim->addFrame(sp, NULL); - } + loadItemAnimation(item); + Animation *anim = item->_anim; Drawable *frame = anim->getCurrentFrame(); const int x = kInventoryX + @@ -728,7 +706,7 @@ void Game::putItem(int itemID, int position) { (kInventoryItemHeight / 2) - (frame->getHeight() / 2); - debug(2, "itemID: %d position: %d line: %d column: %d x: %d y: %d", itemID, position, line, column, x, y); + debug(2, "itemID: %d position: %d line: %d column: %d x: %d y: %d", item->_absNum, position, line, column, x, y); anim->setRelative(x, y); @@ -736,7 +714,7 @@ void Game::putItem(int itemID, int position) { // upon returning it to its slot but *not* in other modes because it should be // invisible then (along with the inventory) if (_loopStatus == kStatusInventory && _loopSubstatus == kOuterLoop) { - _vm->_anims->play(anim_id); + anim->play(); } } @@ -764,24 +742,24 @@ void Game::inventoryDone() { _vm->_anims->unpauseAnimations(); - _vm->_anims->stop(kInventorySprite); + _inventoryAnim->stop(); for (uint i = 0; i < kInventorySlots; ++i) { - if (_inventory[i] != kNoItem) { - _vm->_anims->stop(kInventoryItemsID - _inventory[i]); + if (_inventory[i]) { + _inventory[i]->_anim->stop(); } } // Reset item under cursor - _itemUnderCursor = kNoItem; + _itemUnderCursor = NULL; } void Game::inventoryDraw() { - _vm->_anims->play(kInventorySprite); + _inventoryAnim->play(); for (uint i = 0; i < kInventorySlots; ++i) { - if (_inventory[i] != kNoItem) { - _vm->_anims->play(kInventoryItemsID - _inventory[i]); + if (_inventory[i]) { + _inventory[i]->_anim->play(); } } } @@ -834,7 +812,7 @@ void Game::dialogueMenu(int dialogueID) { } while (!_dialogueExit); dialogueDone(); - _currentDialogue = kNoDialogue; + _currentDialogue = -1; } int Game::dialogueDraw() { @@ -878,7 +856,7 @@ int Game::dialogueDraw() { bool notDialogueAnim = true; for (uint j = 0; j < kDialogueLines; ++j) { - if (_dialogueAnims[j]->getID() == _animUnderCursor) { + if (_dialogueAnims[j] == _animUnderCursor) { notDialogueAnim = false; break; } @@ -887,7 +865,7 @@ int Game::dialogueDraw() { if (notDialogueAnim) { ret = -1; } else { - ret = _dialogueAnims[0]->getID() - _animUnderCursor; + ret = kDialogueLinesID - _animUnderCursor->getID(); } } else { ret = _dialogueLinesNum - 1; @@ -932,7 +910,7 @@ void Game::dialogueInit(int dialogID) { } for (uint i = 0; i < kDialogueLines; ++i) { - _vm->_anims->play(_dialogueAnims[i]->getID()); + _dialogueAnims[i]->play(); } setLoopStatus(kStatusDialogue); @@ -942,7 +920,7 @@ void Game::dialogueInit(int dialogID) { void Game::dialogueDone() { for (uint i = 0; i < kDialogueLines; ++i) { - _vm->_anims->stop(_dialogueAnims[i]->getID()); + _dialogueAnims[i]->stop(); } delete _dialogueArchive; @@ -963,28 +941,26 @@ void Game::runDialogueProg(GPL2Program prog, int offset) { } int Game::playHeroAnimation(int anim_index) { - const GameObject *dragon = getObject(kDragonObject); - const int current_anim_index = playingObjectAnimation(dragon); - const int animID = dragon->_anim[anim_index]; - Animation *anim = _vm->_anims->getAnimation(animID); + GameObject *dragon = getObject(kDragonObject); + const int current_anim_index = dragon->_playingAnim; + Animation *anim = dragon->_anim[anim_index]; if (anim_index == current_anim_index) { anim->markDirtyRect(_vm->_screen->getSurface()); } else { - stopObjectAnimations(dragon); + dragon->stopAnim(); } positionAnimAsHero(anim); if (anim_index == current_anim_index) { anim->markDirtyRect(_vm->_screen->getSurface()); } else { - _vm->_anims->play(animID); + dragon->playAnim(anim_index); } return anim->currentFrameNum(); } -void Game::redrawWalkingPath(int id, byte colour, const WalkingPath &path) { - Animation *anim = _vm->_anims->getAnimation(id); +void Game::redrawWalkingPath(Animation *anim, byte colour, const WalkingPath &path) { Sprite *ov = _walkingMap.newOverlayFromPath(path, colour); delete anim->getFrame(0); anim->replaceFrame(0, ov, NULL); @@ -1016,8 +992,8 @@ void Game::walkHero(int x, int y, SightDirection dir) { _walkingMap.obliquePath(shortestPath, &obliquePath); debugC(2, kDraciWalkingDebugLevel, "Walking path lengths: shortest=%d oblique=%d", shortestPath.size(), obliquePath.size()); if (_vm->_showWalkingMap) { - redrawWalkingPath(kWalkingShortestPathOverlay, kWalkingShortestPathOverlayColour, shortestPath); - redrawWalkingPath(kWalkingObliquePathOverlay, kWalkingObliquePathOverlayColour, obliquePath); + redrawWalkingPath(_walkingShortestPathOverlay, kWalkingShortestPathOverlayColour, shortestPath); + redrawWalkingPath(_walkingObliquePathOverlay, kWalkingObliquePathOverlayColour, obliquePath); } // Start walking. Walking will be gradually advanced by @@ -1030,123 +1006,30 @@ void Game::walkHero(int x, int y, SightDirection dir) { _walkingMap.getDelta(), obliquePath); } -void Game::loadItem(int itemID) { - const BAFile *f = _vm->_itemsArchive->getFile(itemID * 3); - Common::MemoryReadStream itemReader(f->_data, f->_length); - - GameItem *item = _items + itemID; - - item->_init = itemReader.readSint16LE(); - item->_look = itemReader.readSint16LE(); - item->_use = itemReader.readSint16LE(); - item->_canUse = itemReader.readSint16LE(); - item->_imInit = itemReader.readByte(); - item->_imLook = itemReader.readByte(); - item->_imUse = itemReader.readByte(); - - f = _vm->_itemsArchive->getFile(itemID * 3 + 1); - - // The first byte is the length of the string - item->_title = Common::String((const char *)f->_data + 1, f->_length - 1); - assert(f->_data[0] == item->_title.size()); - - f = _vm->_itemsArchive->getFile(itemID * 3 + 2); - - item->_program._bytecode = f->_data; - item->_program._length = f->_length; -} - -void Game::loadRoom(int roomNum) { - const BAFile *f; - f = _vm->_roomsArchive->getFile(roomNum * 4); - Common::MemoryReadStream roomReader(f->_data, f->_length); - - roomReader.readUint32LE(); // Pointer to room program, not used - roomReader.readUint16LE(); // Program length, not used - roomReader.readUint32LE(); // Pointer to room title, not used - - // Music will be played by the GPL2 command startMusic when needed. - setMusicTrack(roomReader.readByte()); - - _currentRoom._mapID = roomReader.readByte() - 1; - _currentRoom._palette = roomReader.readByte() - 1; - _currentRoom._numOverlays = roomReader.readSint16LE(); - _currentRoom._init = roomReader.readSint16LE(); - _currentRoom._look = roomReader.readSint16LE(); - _currentRoom._use = roomReader.readSint16LE(); - _currentRoom._canUse = roomReader.readSint16LE(); - _currentRoom._imInit = roomReader.readByte(); - _currentRoom._imLook = roomReader.readByte(); - _currentRoom._imUse = roomReader.readByte(); - _currentRoom._mouseOn = roomReader.readByte(); - _currentRoom._heroOn = roomReader.readByte(); - - // Read in pers0 and persStep (stored as 6-byte Pascal reals) - byte real[6]; - - for (int i = 5; i >= 0; --i) { - real[i] = roomReader.readByte(); - } +void Game::initWalkingOverlays() { + _walkingMapOverlay = new Animation(_vm, kWalkingMapOverlay, 256, _vm->_showWalkingMap); + _walkingMapOverlay->addFrame(NULL, NULL); // rewritten below by loadWalkingMap() + _vm->_anims->insert(_walkingMapOverlay, true); - _currentRoom._pers0 = real_to_double(real); - - for (int i = 5; i >= 0; --i) { - real[i] = roomReader.readByte(); - } - - _currentRoom._persStep = real_to_double(real); - - _currentRoom._escRoom = roomReader.readByte() - 1; - _currentRoom._numGates = roomReader.readByte(); - - debugC(4, kDraciLogicDebugLevel, "Music: %d", getMusicTrack()); - debugC(4, kDraciLogicDebugLevel, "Map: %d", getMapID()); - debugC(4, kDraciLogicDebugLevel, "Palette: %d", _currentRoom._palette); - debugC(4, kDraciLogicDebugLevel, "Overlays: %d", _currentRoom._numOverlays); - debugC(4, kDraciLogicDebugLevel, "Init: %d", _currentRoom._init); - debugC(4, kDraciLogicDebugLevel, "Look: %d", _currentRoom._look); - debugC(4, kDraciLogicDebugLevel, "Use: %d", _currentRoom._use); - debugC(4, kDraciLogicDebugLevel, "CanUse: %d", _currentRoom._canUse); - debugC(4, kDraciLogicDebugLevel, "ImInit: %d", _currentRoom._imInit); - debugC(4, kDraciLogicDebugLevel, "ImLook: %d", _currentRoom._imLook); - debugC(4, kDraciLogicDebugLevel, "ImUse: %d", _currentRoom._imUse); - debugC(4, kDraciLogicDebugLevel, "MouseOn: %d", _currentRoom._mouseOn); - debugC(4, kDraciLogicDebugLevel, "HeroOn: %d", _currentRoom._heroOn); - debugC(4, kDraciLogicDebugLevel, "Pers0: %f", _currentRoom._pers0); - debugC(4, kDraciLogicDebugLevel, "PersStep: %f", _currentRoom._persStep); - debugC(4, kDraciLogicDebugLevel, "EscRoom: %d", _currentRoom._escRoom); - debugC(4, kDraciLogicDebugLevel, "Gates: %d", _currentRoom._numGates); - - // Read in the gates' numbers - _currentRoom._gates.clear(); - for (uint i = 0; i < _currentRoom._numGates; ++i) { - _currentRoom._gates.push_back(roomReader.readSint16LE()); - } - - // Add overlays for the walking map and shortest/obliqued paths. - Animation *map = _vm->_anims->addAnimation(kWalkingMapOverlay, 256, _vm->_showWalkingMap); - map->addFrame(NULL, NULL); // rewritten below by loadWalkingMap() - - Animation *sPath = _vm->_anims->addAnimation(kWalkingShortestPathOverlay, 257, _vm->_showWalkingMap); - Animation *oPath = _vm->_anims->addAnimation(kWalkingObliquePathOverlay, 258, _vm->_showWalkingMap); + _walkingShortestPathOverlay = new Animation(_vm, kWalkingShortestPathOverlay, 257, _vm->_showWalkingMap); + _walkingObliquePathOverlay = new Animation(_vm, kWalkingObliquePathOverlay, 258, _vm->_showWalkingMap); WalkingPath emptyPath; - Sprite *ov = _walkingMap.newOverlayFromPath(emptyPath, 0); - sPath->addFrame(ov, NULL); - ov = _walkingMap.newOverlayFromPath(emptyPath, 0); - oPath->addFrame(ov, NULL); - - // Load the walking map - loadWalkingMap(getMapID()); + _walkingShortestPathOverlay->addFrame(_walkingMap.newOverlayFromPath(emptyPath, 0), NULL); + _walkingObliquePathOverlay->addFrame(_walkingMap.newOverlayFromPath(emptyPath, 0), NULL); + _vm->_anims->insert(_walkingShortestPathOverlay, true); + _vm->_anims->insert(_walkingObliquePathOverlay, true); +} +void Game::loadRoomObjects() { // Load the room's objects for (uint i = 0; i < _info._numObjects; ++i) { debugC(7, kDraciLogicDebugLevel, "Checking if object %d (%d) is at the current location (%d)", i, - _objects[i]._location, roomNum); + _objects[i]._location, getRoomNum()); - if (_objects[i]._location == roomNum) { - debugC(6, kDraciLogicDebugLevel, "Loading object %d from room %d", i, roomNum); - loadObject(i); + if (_objects[i]._location == getRoomNum()) { + debugC(6, kDraciLogicDebugLevel, "Loading object %d from room %d", i, getRoomNum()); + _objects[i].load(i, _vm->_objectsArchive); } } @@ -1154,7 +1037,7 @@ void Game::loadRoom(int roomNum) { // We can't do this in the above loop because some objects' scripts reference // other objects that may not yet be loaded for (uint i = 0; i < _info._numObjects; ++i) { - if (_objects[i]._location == roomNum) { + if (_objects[i]._location == getRoomNum()) { const GameObject *obj = getObject(i); debugC(6, kDraciLogicDebugLevel, "Running init program for object %d (offset %d)", i, obj->_init); @@ -1162,138 +1045,9 @@ void Game::loadRoom(int roomNum) { } } - // Load the room's GPL program and run the init part - f = _vm->_roomsArchive->getFile(roomNum * 4 + 3); - _currentRoom._program._bytecode = f->_data; - _currentRoom._program._length = f->_length; - + // Run the init part of the GPL program debugC(4, kDraciLogicDebugLevel, "Running room init program..."); _vm->_script->run(_currentRoom._program, _currentRoom._init); - - // Set room palette - f = _vm->_paletteArchive->getFile(_currentRoom._palette); - _vm->_screen->setPalette(f->_data, 0, kNumColours); -} - -int Game::loadAnimation(uint animNum, uint z) { - // Make double-sure that an animation isn't loaded more than twice, - // otherwise horrible things happen in the AnimationManager, because - // they use a simple link-list without duplicate checking. This should - // never happen unless there is a bug in the game, because all GPL2 - // commands are guarded. - assert(!_vm->_anims->getAnimation(animNum)); - - const BAFile *animFile = _vm->_animationsArchive->getFile(animNum); - Common::MemoryReadStream animationReader(animFile->_data, animFile->_length); - - uint numFrames = animationReader.readByte(); - - // The following two flags are ignored by the played. Memory logic was - // a hint to the old player whether it should cache the sprites or load - // them on demand. We have 1 memory manager and ignore these hints. - animationReader.readByte(); - // The disable erasing field is just a (poor) optimization flag that - // turns of drawing the background underneath the sprite. By reading - // the source code of the old player, I'm not sure if that would ever - // have worked. There are only 6 animations in the game with this flag - // true. All of them have just 1 animation phase and they are used to - // patch a part of the original background by a new sprite. This - // should work with the default logic as well---just play this - // animation on top of the background. Since the only meaning of the - // flag was optimization, ignoring should be OK even without dipping - // into details. - animationReader.readByte(); - const bool cyclic = animationReader.readByte(); - const bool relative = animationReader.readByte(); - - Animation *anim = _vm->_anims->addAnimation(animNum, z, false); - - anim->setLooping(cyclic); - - for (uint i = 0; i < numFrames; ++i) { - uint spriteNum = animationReader.readUint16LE() - 1; - int x = animationReader.readSint16LE(); - int y = animationReader.readSint16LE(); - uint scaledWidth = animationReader.readUint16LE(); - uint scaledHeight = animationReader.readUint16LE(); - byte mirror = animationReader.readByte(); - int sample = animationReader.readUint16LE() - 1; - uint freq = animationReader.readUint16LE(); - uint delay = animationReader.readUint16LE(); - - // _spritesArchive is flushed when entering a room. All - // scripts in a room are responsible for loading their animations. - const BAFile *spriteFile = _vm->_spritesArchive->getFile(spriteNum); - Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length, - relative ? 0 : x, relative ? 0 : y, true); - - // Some frames set the scaled dimensions to 0 even though other frames - // from the same animations have them set to normal values - // We work around this by assuming it means no scaling is necessary - if (scaledWidth == 0) { - scaledWidth = sp->getWidth(); - } - - if (scaledHeight == 0) { - scaledHeight = sp->getHeight(); - } - - sp->setScaled(scaledWidth, scaledHeight); - - if (mirror) - sp->setMirrorOn(); - - sp->setDelay(delay * 10); - - const SoundSample *sam = _vm->_soundsArchive->getSample(sample, freq); - - anim->addFrame(sp, sam); - if (relative) { - anim->makeLastFrameRelative(x, y); - } - } - - return animNum; -} - -void Game::loadObject(uint objNum) { - const BAFile *file; - - file = _vm->_objectsArchive->getFile(objNum * 3); - Common::MemoryReadStream objReader(file->_data, file->_length); - - GameObject *obj = _objects + objNum; - - obj->_init = objReader.readUint16LE(); - obj->_look = objReader.readUint16LE(); - obj->_use = objReader.readUint16LE(); - obj->_canUse = objReader.readUint16LE(); - obj->_imInit = objReader.readByte(); - obj->_imLook = objReader.readByte(); - obj->_imUse = objReader.readByte(); - obj->_walkDir = objReader.readByte() - 1; - obj->_z = objReader.readByte(); - objReader.readUint16LE(); // idxSeq field, not used - objReader.readUint16LE(); // numSeq field, not used - obj->_lookX = objReader.readUint16LE(); - obj->_lookY = objReader.readUint16LE(); - obj->_useX = objReader.readUint16LE(); - obj->_useY = objReader.readUint16LE(); - obj->_lookDir = static_cast<SightDirection> (objReader.readByte()); - obj->_useDir = static_cast<SightDirection> (objReader.readByte()); - - obj->_absNum = objNum; - - file = _vm->_objectsArchive->getFile(objNum * 3 + 1); - - // The first byte of the file is the length of the string (without the length) - assert(file->_length - 1 == file->_data[0]); - - obj->_title = Common::String((char *)(file->_data+1), file->_length-1); - - file = _vm->_objectsArchive->getFile(objNum * 3 + 2); - obj->_program._bytecode = file->_data; - obj->_program._length = file->_length; } void Game::loadWalkingMap(int mapID) { @@ -1301,11 +1055,22 @@ void Game::loadWalkingMap(int mapID) { f = _vm->_walkingMapsArchive->getFile(mapID); _walkingMap.load(f->_data, f->_length); - Animation *anim = _vm->_anims->getAnimation(kWalkingMapOverlay); Sprite *ov = _walkingMap.newOverlayFromMap(kWalkingMapOverlayColour); - delete anim->getFrame(0); - anim->replaceFrame(0, ov, NULL); - anim->markDirtyRect(_vm->_screen->getSurface()); + delete _walkingMapOverlay->getFrame(0); + _walkingMapOverlay->replaceFrame(0, ov, NULL); + _walkingMapOverlay->markDirtyRect(_vm->_screen->getSurface()); +} + +void Game::switchWalkingAnimations(bool enabled) { + if (enabled) { + _walkingMapOverlay->play(); + _walkingShortestPathOverlay->play(); + _walkingObliquePathOverlay->play(); + } else { + _walkingMapOverlay->stop(); + _walkingShortestPathOverlay->stop(); + _walkingObliquePathOverlay->stop(); + } } void Game::loadOverlays() { @@ -1328,7 +1093,11 @@ void Game::loadOverlays() { overlayFile = _vm->_overlaysArchive->getFile(num); Sprite *sp = new Sprite(overlayFile->_data, overlayFile->_length, x, y, true); - _vm->_anims->addOverlay(sp, z); + Animation *anim = new Animation(_vm, kOverlayImage, z, true); + anim->addFrame(sp, NULL); + // Since this is an overlay, we don't need it to be deleted + // when the GPL Release command is invoked + _vm->_anims->insert(anim, false); } _vm->_screen->getSurface()->markDirty(); @@ -1337,27 +1106,12 @@ void Game::loadOverlays() { void Game::deleteObjectAnimations() { for (uint i = 0; i < _info._numObjects; ++i) { GameObject *obj = &_objects[i]; - if (i != 0 && (obj->_location == getPreviousRoomNum())) { - for (uint j = 0; j < obj->_anim.size(); ++j) { - _vm->_anims->deleteAnimation(obj->_anim[j]); - } - obj->_anim.clear(); + obj->deleteAnims(); } } } -int Game::playingObjectAnimation(const GameObject *obj) const { - for (uint i = 0; i < obj->_anim.size(); ++i) { - const int animID = obj->_anim[i]; - const Animation *anim = _vm->_anims->getAnimation(animID); - if (anim && anim->isPlaying()) { - return i; - } - } - return -1; -} - bool Game::enterNewRoom() { if (_newRoom == getRoomNum() && !isReloaded()) { // If the game has been reloaded, force reloading all animations. @@ -1386,22 +1140,13 @@ bool Game::enterNewRoom() { _vm->_anims->deleteOverlays(); - // Delete walking map testing overlay - _vm->_anims->deleteAnimation(kWalkingMapOverlay); - _vm->_anims->deleteAnimation(kWalkingShortestPathOverlay); - _vm->_anims->deleteAnimation(kWalkingObliquePathOverlay); - - // TODO: Make objects capable of stopping their own animations - const GameObject *dragon = getObject(kDragonObject); - stopObjectAnimations(dragon); + GameObject *dragon = getObject(kDragonObject); + dragon->stopAnim(); // Remember the previous room for returning back from the map. rememberRoomNumAsPrevious(); deleteObjectAnimations(); - // Set the current room to the new value - _currentRoom._roomNum = _newRoom; - // Before setting these variables we have to convert the values to 1-based indexing // because this is how everything is stored in the data files _variables[0] = _newGate + 1; @@ -1425,16 +1170,22 @@ bool Game::enterNewRoom() { // on by pressing Escape in the intro or in the map room. _vm->_script->endCurrentProgram(false); - loadRoom(_newRoom); + _currentRoom.load(_newRoom, _vm->_roomsArchive); + loadWalkingMap(getMapID()); + loadRoomObjects(); loadOverlays(); + // Set room palette + const BAFile *f; + f = _vm->_paletteArchive->getFile(_currentRoom._palette); + _vm->_screen->setPalette(f->_data, 0, kNumColours); + // Clean the mouse and animation title. It gets first updated in // loop(), hence if the hero walks during the initialization scripts, // the old values would remain otherwise. _vm->_mouse->setCursorType(kNormalCursor); - Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); - titleAnim->markDirtyRect(_vm->_screen->getSurface()); - Text *title = reinterpret_cast<Text *>(titleAnim->getCurrentFrame()); + _titleAnim->markDirtyRect(_vm->_screen->getSurface()); + Text *title = reinterpret_cast<Text *>(_titleAnim->getCurrentFrame()); title->setText(""); // Run the program for the gate the dragon came through @@ -1557,24 +1308,20 @@ void Game::deleteAnimationsAfterIndex(int lastAnimIndex) { for (uint i = 0; i < getNumObjects(); ++i) { GameObject *obj = &_objects[i]; - for (uint j = 0; j < obj->_anim.size(); ++j) { - Animation *anim; - - anim = _vm->_anims->getAnimation(obj->_anim[j]); - if (anim != NULL && anim->getIndex() > lastAnimIndex) - obj->_anim.remove_at(j--); + for (int j = obj->_anim.size() - 1; j >= 0; --j) { + Animation *anim = obj->_anim[j]; + if (anim->getIndex() > lastAnimIndex) { + obj->_anim.remove_at(j); + if (j == obj->_playingAnim) { + obj->_playingAnim = -1; + } + } } } _vm->_anims->deleteAfterIndex(lastAnimIndex); } -void Game::stopObjectAnimations(const GameObject *obj) { - for (uint i = 0; i < obj->_anim.size(); ++i) { - _vm->_anims->stop(obj->_anim[i]); - } -} - Game::~Game() { delete[] _persons; delete[] _variables; @@ -1599,7 +1346,14 @@ void Game::DoSync(Common::Serializer &s) { } for (int i = 0; i < kInventorySlots; ++i) { - s.syncAsSint16LE(_inventory[i]); + if (s.isSaving()) { + int itemID = _inventory[i] ? _inventory[i]->_absNum : -1; + s.syncAsSint16LE(itemID); + } else { + int itemID; + s.syncAsSint16LE(itemID); + _inventory[i] = getItem(itemID); + } } for (int i = 0; i < _info._numVariables; ++i) { @@ -1648,4 +1402,189 @@ static double real_to_double(byte real[6]) { return ldexp(mantissa, exp); } +int GameObject::getAnim(int animID) const { + for (uint i = 0; i < _anim.size(); ++i) { + if (_anim[i]->getID() == animID) { + return i; + } + } + return -1; +} + +int GameObject::addAnim(Animation *anim) { + anim->setZ(_z); + _anim.push_back(anim); + int index = _anim.size() - 1; + if (_absNum == kDragonObject && index <= kLastTurning) { + // Index to _anim is the Movement type. All walking and + // turning movements can be accelerated. + anim->supportsQuickAnimation(true); + } + return index; +} + +void GameObject::playAnim(int i) { + _anim[i]->play(); + _playingAnim = i; +} + +void GameObject::stopAnim() { + if (_playingAnim >= 0) { + _anim[_playingAnim]->stop(); + _playingAnim = -1; + } +} + +void GameObject::deleteAnims() { + for (uint j = 0; j < _anim.size(); ++j) { + _anim[j]->del(); + } + _anim.clear(); + _playingAnim = -1; +} + +void GameObject::load(uint objNum, BArchive *archive) { + const BAFile *file; + + file = archive->getFile(objNum * 3); + Common::MemoryReadStream objReader(file->_data, file->_length); + + _init = objReader.readUint16LE(); + _look = objReader.readUint16LE(); + _use = objReader.readUint16LE(); + _canUse = objReader.readUint16LE(); + _imInit = objReader.readByte(); + _imLook = objReader.readByte(); + _imUse = objReader.readByte(); + _walkDir = objReader.readByte() - 1; + _z = objReader.readByte(); + objReader.readUint16LE(); // idxSeq field, not used + objReader.readUint16LE(); // numSeq field, not used + _lookX = objReader.readUint16LE(); + _lookY = objReader.readUint16LE(); + _useX = objReader.readUint16LE(); + _useY = objReader.readUint16LE(); + _lookDir = static_cast<SightDirection> (objReader.readByte()); + _useDir = static_cast<SightDirection> (objReader.readByte()); + + _absNum = objNum; + + file = archive->getFile(objNum * 3 + 1); + + // The first byte of the file is the length of the string (without the length) + assert(file->_length - 1 == file->_data[0]); + + _title = Common::String((char *)(file->_data+1), file->_length-1); + + file = archive->getFile(objNum * 3 + 2); + _program._bytecode = file->_data; + _program._length = file->_length; + + _playingAnim = -1; + _anim.clear(); +} + +void GameItem::load(int itemID, BArchive *archive) { + const BAFile *f = archive->getFile(itemID * 3); + Common::MemoryReadStream itemReader(f->_data, f->_length); + + _init = itemReader.readSint16LE(); + _look = itemReader.readSint16LE(); + _use = itemReader.readSint16LE(); + _canUse = itemReader.readSint16LE(); + _imInit = itemReader.readByte(); + _imLook = itemReader.readByte(); + _imUse = itemReader.readByte(); + + _absNum = itemID; + + f = archive->getFile(itemID * 3 + 1); + + // The first byte is the length of the string + _title = Common::String((const char *)f->_data + 1, f->_length - 1); + assert(f->_data[0] == _title.size()); + + f = archive->getFile(itemID * 3 + 2); + + _program._bytecode = f->_data; + _program._length = f->_length; + + _anim = NULL; +} + +void Room::load(int roomNum, BArchive *archive) { + const BAFile *f; + f = archive->getFile(roomNum * 4); + Common::MemoryReadStream roomReader(f->_data, f->_length); + + roomReader.readUint32LE(); // Pointer to room program, not used + roomReader.readUint16LE(); // Program length, not used + roomReader.readUint32LE(); // Pointer to room title, not used + + // Set the current room to the new value + _roomNum = roomNum; + + // Music will be played by the GPL2 command startMusic when needed. + _music = roomReader.readByte(); + _mapID = roomReader.readByte() - 1; + _palette = roomReader.readByte() - 1; + _numOverlays = roomReader.readSint16LE(); + _init = roomReader.readSint16LE(); + _look = roomReader.readSint16LE(); + _use = roomReader.readSint16LE(); + _canUse = roomReader.readSint16LE(); + _imInit = roomReader.readByte(); + _imLook = roomReader.readByte(); + _imUse = roomReader.readByte(); + _mouseOn = roomReader.readByte(); + _heroOn = roomReader.readByte(); + + // Read in pers0 and persStep (stored as 6-byte Pascal reals) + byte real[6]; + + for (int i = 5; i >= 0; --i) { + real[i] = roomReader.readByte(); + } + + _pers0 = real_to_double(real); + + for (int i = 5; i >= 0; --i) { + real[i] = roomReader.readByte(); + } + + _persStep = real_to_double(real); + + _escRoom = roomReader.readByte() - 1; + _numGates = roomReader.readByte(); + + debugC(4, kDraciLogicDebugLevel, "Music: %d", _music); + debugC(4, kDraciLogicDebugLevel, "Map: %d", _mapID); + debugC(4, kDraciLogicDebugLevel, "Palette: %d", _palette); + debugC(4, kDraciLogicDebugLevel, "Overlays: %d", _numOverlays); + debugC(4, kDraciLogicDebugLevel, "Init: %d", _init); + debugC(4, kDraciLogicDebugLevel, "Look: %d", _look); + debugC(4, kDraciLogicDebugLevel, "Use: %d", _use); + debugC(4, kDraciLogicDebugLevel, "CanUse: %d", _canUse); + debugC(4, kDraciLogicDebugLevel, "ImInit: %d", _imInit); + debugC(4, kDraciLogicDebugLevel, "ImLook: %d", _imLook); + debugC(4, kDraciLogicDebugLevel, "ImUse: %d", _imUse); + debugC(4, kDraciLogicDebugLevel, "MouseOn: %d", _mouseOn); + debugC(4, kDraciLogicDebugLevel, "HeroOn: %d", _heroOn); + debugC(4, kDraciLogicDebugLevel, "Pers0: %f", _pers0); + debugC(4, kDraciLogicDebugLevel, "PersStep: %f", _persStep); + debugC(4, kDraciLogicDebugLevel, "EscRoom: %d", _escRoom); + debugC(4, kDraciLogicDebugLevel, "Gates: %d", _numGates); + + // Read in the gates' numbers + _gates.clear(); + for (uint i = 0; i < _numGates; ++i) { + _gates.push_back(roomReader.readSint16LE()); + } + + // Load the room's GPL program + f = archive->getFile(roomNum * 4 + 3); + _program._bytecode = f->_data; + _program._length = f->_length; +} + } |