diff options
-rw-r--r-- | engines/pegasus/graphics.cpp | 99 | ||||
-rw-r--r-- | engines/pegasus/graphics.h | 6 | ||||
-rw-r--r-- | engines/pegasus/neighborhood/neighborhood.cpp | 7 |
3 files changed, 109 insertions, 3 deletions
diff --git a/engines/pegasus/graphics.cpp b/engines/pegasus/graphics.cpp index 1e529d0e07..8b83ed7a32 100644 --- a/engines/pegasus/graphics.cpp +++ b/engines/pegasus/graphics.cpp @@ -212,5 +212,104 @@ void GraphicsManager::doFadeInSync(const TimeValue, const TimeValue, uint32) { void GraphicsManager::markCursorAsDirty() { _modifiedScreen = true; } + +void GraphicsManager::newShakePoint(int32 index1, int32 index2, int32 maxRadius) { + int32 index3 = (index1 + index2) >> 1; + + if (maxRadius == 0) { + _shakeOffsets[index3].x = ((_shakeOffsets[index1].x + _shakeOffsets[index2].x) >> 1); + _shakeOffsets[index3].y = ((_shakeOffsets[index1].y + _shakeOffsets[index2].y) >> 1); + } else { + double angle = (int32)(_vm->getRandomNumber(360 - 1) * 3.1415926535 / 180); + int32 radius = maxRadius; + _shakeOffsets[index3].x = (int32)(((_shakeOffsets[index1].x + _shakeOffsets[index2].x) >> 1) + + cos(angle) / 2 * radius); + _shakeOffsets[index3].y = (int32)(((_shakeOffsets[index1].y + _shakeOffsets[index2].y) >> 1) + + sin(angle) * radius); + } + + if (index1 < index3 - 1) + newShakePoint(index1, index3, maxRadius * 2 / 3); + + if (index3 < index2 - 1) + newShakePoint(index3, index2, maxRadius * 2 / 3); +} + +void GraphicsManager::shakeTheWorld(TimeValue duration, TimeScale scale) { + if (duration == 0 || scale == 0) + return; + + _shakeOffsets[0].x = 0; + _shakeOffsets[0].y = 0; + _shakeOffsets[(kMaxShakeOffsets - 1) / 4].x = 0; + _shakeOffsets[(kMaxShakeOffsets - 1) / 4].y = 0; + _shakeOffsets[(kMaxShakeOffsets - 1) / 2].x = 0; + _shakeOffsets[(kMaxShakeOffsets - 1) / 2].y = 0; + _shakeOffsets[(kMaxShakeOffsets - 1) * 3 / 4].x = 0; + _shakeOffsets[(kMaxShakeOffsets - 1) * 3 / 4].y = 0; + _shakeOffsets[kMaxShakeOffsets - 1].x = 0; + _shakeOffsets[kMaxShakeOffsets - 1].y = 0; + + newShakePoint(0, (kMaxShakeOffsets - 1) / 4, 8); + newShakePoint((kMaxShakeOffsets - 1) / 4, (kMaxShakeOffsets - 1) / 2, 6); + newShakePoint((kMaxShakeOffsets - 1) / 2, (kMaxShakeOffsets - 1) * 3 / 4, 4); + newShakePoint((kMaxShakeOffsets - 1) * 3 / 4, kMaxShakeOffsets - 1, 3); + + Common::Point lastOffset(0, 0); + + // Convert to millis + duration = duration * 1000 / scale; + + uint32 startTime = g_system->getMillis(); + + while (g_system->getMillis() < startTime + duration) { + Common::Point thisOffset = _shakeOffsets[(g_system->getMillis() - startTime) * (kMaxShakeOffsets - 1) / duration]; + if (thisOffset != lastOffset) { + // Fill the screen with black + Graphics::Surface *screen = g_system->lockScreen(); + screen->fillRect(Common::Rect(0, 0, 640, 480), g_system->getScreenFormat().RGBToColor(0, 0, 0)); + g_system->unlockScreen(); + + // Calculate the src/dst offsets and the width/height + int32 srcOffsetX, dstOffsetX, width; + + if (thisOffset.x > 0) { + srcOffsetX = 0; + dstOffsetX = thisOffset.x; + width = 640 - dstOffsetX; + } else { + srcOffsetX = -thisOffset.x; + dstOffsetX = 0; + width = 640 - srcOffsetX; + } + + int32 srcOffsetY, dstOffsetY, height; + + if (thisOffset.y > 0) { + srcOffsetY = 0; + dstOffsetY = thisOffset.y; + height = 480 - dstOffsetY; + } else { + srcOffsetY = -thisOffset.y; + dstOffsetY = 0; + height = 480 - srcOffsetY; + } + + // Now copy to the screen + g_system->copyRectToScreen((byte *)_workArea.getBasePtr(srcOffsetX, srcOffsetY), _workArea.pitch, + dstOffsetX, dstOffsetY, width, height); + g_system->updateScreen(); + + lastOffset = thisOffset; + } + + g_system->delayMillis(10); + } + + if (lastOffset.x != 0 || lastOffset.y != 0) { + g_system->copyRectToScreen((byte *)_workArea.pixels, _workArea.pitch, 0, 0, 640, 480); + g_system->updateScreen(); + } +} } // End of namespace Pegasus diff --git a/engines/pegasus/graphics.h b/engines/pegasus/graphics.h index e1b339843f..c68c2dec76 100644 --- a/engines/pegasus/graphics.h +++ b/engines/pegasus/graphics.h @@ -57,6 +57,7 @@ public: Graphics::Surface *getWorkArea() { return &_workArea; } void clearScreen(); DisplayElement *findDisplayElement(const tDisplayElementID id); + void shakeTheWorld(TimeValue time, TimeScale scale); // These default to black void doFadeOutSync(const TimeValue = kOneSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, uint32 color = 0); @@ -73,6 +74,11 @@ private: tDisplayOrder _backLayer, _frontLayer; DisplayElement *_firstDisplayElement, *_lastDisplayElement; Graphics::Surface _workArea; + + // Shake Shake Shake! + static const int kMaxShakeOffsets = 17; + Common::Point _shakeOffsets[kMaxShakeOffsets]; + void newShakePoint(int32 index1, int32 index2, int32 maxRadius); }; } // End of namespace Pegasus diff --git a/engines/pegasus/neighborhood/neighborhood.cpp b/engines/pegasus/neighborhood/neighborhood.cpp index f6da38692b..5d8f386d15 100644 --- a/engines/pegasus/neighborhood/neighborhood.cpp +++ b/engines/pegasus/neighborhood/neighborhood.cpp @@ -30,6 +30,7 @@ #include "pegasus/cursor.h" #include "pegasus/energymonitor.h" #include "pegasus/gamestate.h" +#include "pegasus/graphics.h" #include "pegasus/input.h" #include "pegasus/interaction.h" #include "pegasus/interface.h" @@ -726,7 +727,8 @@ void Neighborhood::turnTo(const tDirectionConstant direction) { if (g_map) g_map->moveToMapLocation(GameState.getCurrentNeighborhood(), GameState.getCurrentRoom(), direction); - _pushIn.copyToCurrentPort(); + // FIXME: This isn't right. Crazy TGWorldSaver stuff + //_pushIn.copyToCurrentPort(); // Added 2/10/97. Shouldn't this be here? Shouldn't we set the current activation to // always when turning to a new view? @@ -1419,8 +1421,7 @@ void Neighborhood::newInteraction(const tInteractionID interactionID) { } void Neighborhood::bumpIntoWall() { - // TODO - warning("bump"); + _vm->_gfx->shakeTheWorld(15, 30); } void Neighborhood::zoomUpOrBump() { |