aboutsummaryrefslogtreecommitdiff
path: root/engines/draci/game.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/draci/game.cpp')
-rw-r--r--engines/draci/game.cpp821
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;
+}
+
}