diff options
Diffstat (limited to 'engines/mads/scene.cpp')
-rw-r--r-- | engines/mads/scene.cpp | 224 |
1 files changed, 187 insertions, 37 deletions
diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp index ee5f1a5440..66f56f9407 100644 --- a/engines/mads/scene.cpp +++ b/engines/mads/scene.cpp @@ -24,6 +24,7 @@ #include "mads/scene.h" #include "mads/compression.h" #include "mads/mads.h" +#include "mads/audio.h" #include "mads/dragonsphere/dragonsphere_scenes.h" #include "mads/nebular/nebular_scenes.h" #include "mads/phantom/phantom_scenes.h" @@ -49,7 +50,8 @@ Scene::Scene(MADSEngine *vm) _reloadSceneFlag = false; _freeAnimationFlag = false; _animationData = nullptr; - _activeAnimation = nullptr; + for (int i = 0; i < 10; i++) + _animation[i] = nullptr; _textSpacing = -1; _frameStartTime = 0; _mode = SCREENMODE_VGA; @@ -60,6 +62,8 @@ Scene::Scene(MADSEngine *vm) _spritesCount = 0; _variant = 0; + _speechReady = -1; + _paletteUsageF.push_back(PaletteUsage::UsageEntry(0xF)); // Set up a scene surface that maps to our physical screen drawing surface @@ -85,8 +89,7 @@ Scene::~Scene() { } void Scene::restrictScene() { - _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH, - _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8()); + _sceneSurface.create(*_vm->_screen, Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT)); } void Scene::clearVocab() { @@ -150,6 +153,8 @@ void Scene::loadScene(int sceneId, const Common::String &prefix, bool palFlag) { _sequences.clear(); _kernelMessages.clear(); _vm->_palette->_paletteUsage.load(&_scenePaletteUsage); + if (_vm->getGameID() != GType_RexNebular) + setCamera(Common::Point(0, 0)); int flags = SCENEFLAG_LOAD_SHADOW; if (_vm->_dithering) @@ -385,6 +390,7 @@ void Scene::doFrame() { !_vm->_game->_fx); } + _vm->_game->camUpdate(); if (_action._selectedAction && player._stepEnabled && !player._needToWalk && !_vm->_game->_trigger && !player._trigger) { _action.startAction(); @@ -412,14 +418,24 @@ void Scene::doFrame() { } if (_currentSceneId != _nextSceneId) { + _vm->_gameConv->stop(); _freeAnimationFlag = true; + // TODO: Handle Phantom/Dragonsphere animation list free } else { doSceneStep(); checkKeyboard(); if (_currentSceneId != _nextSceneId) { + _vm->_gameConv->stop(); _freeAnimationFlag = true; + // TODO: Handle Phantom/Dragonsphere animation list free } else { + // Handle conversation updates if one is active + if (!_vm->_game->_trigger && _vm->_gameConv->active() && + !_vm->_game->_camX._activeFl && !_vm->_game->_camY._activeFl) + _vm->_gameConv->update(false); + + // Update the player player.nextFrame(); // Cursor update code @@ -430,8 +446,7 @@ void Scene::doFrame() { _sequences.tick(); // Handle any active animation - if (_activeAnimation) - _activeAnimation->update(); + animations_tick(); } // If the debugget flag is set, show the mouse position @@ -480,8 +495,10 @@ void Scene::doFrame() { _vm->_game->_fx = kTransitionNone; // Handle freeing animation if necessary - if (_activeAnimation && _activeAnimation->freeFlag()) - _freeAnimationFlag = true; + for (int i = 0; i < 10; i++) { + if (_animation[i] && _animation[i]->freeFlag()) + _freeAnimationFlag = true; + } if (_freeAnimationFlag) freeAnimation(); } @@ -496,8 +513,10 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) { // Merge any identified dirty areas _dirtyAreas.merge(1, DIRTY_AREAS_SIZE); + if (_posAdjust != Common::Point(0, 0)) + warning("Adjust used %d %d", _posAdjust.x, _posAdjust.y); // Copy background for the dirty areas to the screen - _dirtyAreas.copy(&_backgroundSurface, &_vm->_screen, _posAdjust); + _dirtyAreas.copy(&_backgroundSurface, _vm->_screen, _posAdjust); // Handle dirty areas for foreground objects _spriteSlots.setDirtyAreas(); @@ -508,11 +527,11 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) { _spriteSlots.drawSprites(&_sceneSurface); // Draw text elements onto the view - _textDisplay.draw(&_vm->_screen); + _textDisplay.draw(_vm->_screen); if (transitionType) { // Fading in the screen - _vm->_screen.transition(transitionType, surfaceFlag); + _vm->_screen->transition(transitionType, surfaceFlag); _vm->_sound->startQueuedCommands(); } else { // Copy dirty areas to the screen @@ -538,13 +557,20 @@ void Scene::doPreactions() { void Scene::doAction() { bool flag = false; + // Don't allow the player to move if a conversation is active + if (_vm->_gameConv->active()) { + _vm->_game->_scene._action._savedFields._lookFlag = false; + if (_vm->_gameConv->currentMode() == CONVMODE_2 || _vm->_gameConv->currentMode() == CONVMODE_3) + _vm->_game->_player._stepEnabled = false; + } + _vm->_game->_triggerSetupMode = SEQUENCE_TRIGGER_PARSER; if ((_action._inProgress || _vm->_game->_trigger) && !_action._savedFields._commandError) { _sceneLogic->actions(); flag = !_action._inProgress; } - if (_vm->_game->_screenObjects._inputMode == kInputConversation) { + if (_vm->_gameConv->active() || _vm->_game->_screenObjects._inputMode == kInputConversation) { _action._inProgress = false; } else { if ((_action._inProgress || _vm->_game->_trigger) || @@ -577,6 +603,10 @@ void Scene::doAction() { _action._inProgress = false; if (_vm->_game->_triggerMode == SEQUENCE_TRIGGER_PARSER) _vm->_game->_trigger = 0; + + if (_vm->_gameConv->active() && (_vm->_gameConv->currentMode() == CONVMODE_1 || + _vm->_gameConv->currentMode() == CONVMODE_2)) + _vm->_gameConv->update(true); } void Scene::doSceneStep() { @@ -605,19 +635,29 @@ void Scene::checkKeyboard() { } } -void Scene::loadAnimation(const Common::String &resName, int trigger) { +int Scene::loadAnimation(const Common::String &resName, int trigger) { // WORKAROUND: If there's already a previous active animation used by the // scene, then free it before we create the new one - if (_activeAnimation) - freeAnimation(); + if ((_vm->getGameID() == GType_RexNebular) && _animation[0]) + freeAnimation(0); DepthSurface depthSurface; UserInterface interfaceSurface(_vm); - _activeAnimation = Animation::init(_vm, this); - _activeAnimation->load(interfaceSurface, depthSurface, resName, - _vm->_dithering ? ANIMFLAG_DITHER : 0, nullptr, nullptr); - _activeAnimation->startAnimation(trigger); + for (int i = 0; i < 10; i++) { + if (!_animation[i]) { + _animation[i] = Animation::init(_vm, this); + _animation[i]->load(interfaceSurface, depthSurface, resName, + _vm->_dithering ? ANIMFLAG_DITHER : 0, nullptr, nullptr); + _animation[i]->startAnimation(trigger); + + return i; + } + } + + error("Unable to find an available animation slot"); + + return -1; } void Scene::updateCursor() { @@ -658,9 +698,12 @@ void Scene::freeCurrentScene() { delete _animationData; _animationData = nullptr; } - if (_activeAnimation) { - delete _activeAnimation; - _activeAnimation = nullptr; + + for (int i = 0; i < 10; i++) { + if (_animation[i]) { + delete _animation[i]; + _animation[i] = nullptr; + } } _vm->_palette->_paletteUsage.load(nullptr); @@ -692,33 +735,40 @@ void Scene::resetScene() { } void Scene::freeAnimation() { - if (_activeAnimation) { - Player &player = _vm->_game->_player; + for (int j = 0; j < 10; j++) + freeAnimation(j); - if (!_freeAnimationFlag) { - _spriteSlots.fullRefresh(true); - _sequences.scan(); - } + _freeAnimationFlag = false; +} + +void Scene::freeAnimation(int idx) { + if (_animation[idx]) { + if (idx == 0) { + Player &player = _vm->_game->_player; + + if (!_freeAnimationFlag) { + _spriteSlots.fullRefresh(true); + _sequences.scan(); + } - // Refresh the player - if (player._visible) { - player._forceRefresh = true; - player.update(); + // Refresh the player + if (player._visible) { + player._forceRefresh = true; + player.update(); + } } // Remove any kernel messages in use by the animation - for (uint i = 0; i < _activeAnimation->_messages.size(); ++i) { - int msgIndex = _activeAnimation->_messages[i]._kernelMsgIndex; + for (uint i = 0; i < _animation[idx]->_messages.size(); ++i) { + int msgIndex = _animation[idx]->_messages[i]._kernelMsgIndex; if (msgIndex >= 0) _kernelMessages.remove(msgIndex); } // Delete the animation - delete _activeAnimation; - _activeAnimation = nullptr; + delete _animation[idx]; + _animation[idx] = nullptr; } - - _freeAnimationFlag = false; } void Scene::synchronize(Common::Serializer &s) { @@ -729,7 +779,107 @@ void Scene::synchronize(Common::Serializer &s) { s.syncAsByte(_roomChanged); s.syncAsUint16LE(_nextSceneId); s.syncAsUint16LE(_priorSceneId); + s.syncAsSint16LE(_variant); _dynamicHotspots.synchronize(s); } +void Scene::setAnimFrame(int id, int val) { + if ((id >= 0) && _animation[id]) + _animation[id]->setCurrentFrame(val); +} + +int Scene::getAnimFrame(int id) { + if ((id >= 0) && _animation[id]) + return _animation[id]->getCurrentFrame(); + + return -1; +} + +void Scene::setDynamicAnim(int id, int anim_id, int segment) { + if (id >= 0 && id <= DYNAMIC_HOTSPOTS_SIZE && _animation[anim_id]) { + _animation[anim_id]->_dynamicHotspotIndex = id; + if (_dynamicHotspots[id]._animIndex < 0) + _dynamicHotspots[id]._active = false; + _dynamicHotspots[id]._animIndex = anim_id; + + // TODO: Anim segments + + // NOTE: Only remove the TODO below when _dynamicHotspotIndex + // in the Animation class is actually used in the engine! + + warning("TODO: Scene::setDynamicAnim"); + } +} + +void Scene::setCamera(Common::Point pos) { + _posAdjust = pos; + warning("setCamera: Incomplete function"); +} + +void Scene::drawToBackground(int spriteId, int frameId, Common::Point pos, int depth, int scale) { + SpriteAsset &asset = *_sprites[spriteId]; + + if (pos.x == -32000) + pos.x = asset.getFramePos(frameId - 1).x; + if (pos.y == -32000) + pos.y = asset.getFramePos(frameId - 1).y; + + int slotIndex = _spriteSlots.add(); + SpriteSlot &slot = _spriteSlots[slotIndex]; + slot._spritesIndex = spriteId; + slot._frameNumber = frameId; + slot._seqIndex = 1; + slot._position = pos; + slot._depth = depth; + slot._scale = scale; + slot._flags = IMG_DELTA; +} + +void Scene::deleteSequence(int idx) { + if (_sequences[idx]._active && _sequences[idx]._dynamicHotspotIndex >= 0) + _dynamicHotspots.remove(_sequences[idx]._dynamicHotspotIndex); + + _sequences[idx]._active = false; + + if (!_sequences[idx]._doneFlag) { + warning("TODO: deleteSequence: Sequence %d not done", idx); + // TODO: This is wrong, and crashes Phantom at scene 102 when the door is opened + //doFrame(); // FIXME/CHECKME: Is this correct? + } else { + _sequences.remove(idx); + } +} + +void Scene::loadSpeech(int idx) { + _vm->_audio->setDefaultSoundGroup(); + // NOTE: The original actually preloads the speech sample here, but the samples + // are so small that it's not really worth it... + + // TODO: As the speech samples aren't cached anymore, _speechReady should be remove + _speechReady = idx; +} + +void Scene::playSpeech(int idx) { + _vm->_audio->stop(); + _vm->_audio->playSound(idx - 1); +} + +void Scene::sceneScale(int yFront, int maxScale, int yBack, int minScale) { + _sceneInfo->_yBandsEnd = yFront; + _sceneInfo->_maxScale = maxScale; + _sceneInfo->_yBandsStart = yBack; + _sceneInfo->_minScale = minScale; + + _bandsRange = _sceneInfo->_yBandsEnd - _sceneInfo->_yBandsStart; + _scaleRange = _sceneInfo->_maxScale - _sceneInfo->_minScale; +} + +void Scene::animations_tick() { + //warning("TODO: Implement _animations as an AnimationList and refactor (and check implementation)"); + for (int i = 0; i < 10; i++) { + if (_animation[i]) + _animation[i]->update(); + } +} + } // End of namespace MADS |