summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Sehmisch <mana@crushnet.org>2011-03-14 20:56:40 +0100
committerPhilipp Sehmisch <mana@crushnet.org>2011-03-15 18:23:37 +0100
commit91e2779891973cdbefc6e07ca3dee7a432a05112 (patch)
tree7b594b3aead19f6550d66384c342a3d3668ec086
parent25a2abd09e3b76115ed0b6b1a02cdddc6c1c5bfc (diff)
downloadmana-client-91e2779891973cdbefc6e07ca3dee7a432a05112.tar.gz
mana-client-91e2779891973cdbefc6e07ca3dee7a432a05112.tar.bz2
mana-client-91e2779891973cdbefc6e07ca3dee7a432a05112.tar.xz
mana-client-91e2779891973cdbefc6e07ca3dee7a432a05112.zip
Implemented a screen shake effect system in the viewport class.
The screen can either be "nudged" in a random direction with a specific intensity or you can define an exact x and y intensity, decay factor and duration. On a tmwAthena server an effect is triggered when the player character dies. A method for stopping all shake effects is also implemented, but not used yet. I added a netcode message for Manaserv to trigger an effect server-sided. Because our protocol has currently no way to transport floating point values, the decay is transported as a fixed point value with 4 decimals which is entirely sufficient for this purpose.
-rw-r--r--src/gui/viewport.cpp38
-rw-r--r--src/gui/viewport.h28
-rw-r--r--src/net/manaserv/effecthandler.cpp38
-rw-r--r--src/net/manaserv/effecthandler.h1
-rw-r--r--src/net/manaserv/manaserv_protocol.h1
-rw-r--r--src/net/tmwa/playerhandler.cpp1
6 files changed, 106 insertions, 1 deletions
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index ac910d5f..9d03cab5 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -42,6 +42,8 @@
#include "utils/stringutils.h"
+#include <cmath>
+
extern volatile int tick_time;
Viewport::Viewport():
@@ -121,9 +123,9 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
if (mScrollLaziness < 1)
mScrollLaziness = 1; // Avoids division by zero
- // Apply lazy scrolling
while (lastTick < tick_time)
{
+ // Apply lazy scrolling
if (player_x > mPixelViewX + mScrollRadius)
{
mPixelViewX += (player_x - mPixelViewX - mScrollRadius) /
@@ -144,6 +146,22 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
mPixelViewY += (player_y - mPixelViewY + mScrollRadius) /
mScrollLaziness;
}
+
+ // manage shake effect
+ for (ShakeEffects::iterator i = mShakeEffects.begin();
+ i != mShakeEffects.end();
+ i++)
+ {
+ // apply the effect to viewport
+ mPixelViewX += i->x *= -i->decay;
+ mPixelViewY += i->y *= -i->decay;
+ // check death conditions
+ if (abs(i->x) + abs(i->y) < 1.0f ||
+ (i->duration > 0 && --i->duration == 0))
+ {
+ i = mShakeEffects.erase(i);
+ }
+ }
lastTick++;
}
@@ -222,6 +240,24 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
WindowContainer::draw(gcnGraphics);
}
+void Viewport::shakeScreen(int intensity)
+{
+ float direction = rand()%628 / 100.0f; // random value between 0 and 2PI
+ float x = std::sin(direction) * intensity;
+ float y = std::cos(direction) * intensity;
+ shakeScreen(x, y);
+}
+
+void Viewport::shakeScreen(float x, float y, float decay, unsigned duration)
+{
+ ShakeEffect effect;
+ effect.x = x;
+ effect.y = y;
+ effect.decay = decay;
+ effect.duration = duration;
+ mShakeEffects.push_back(effect);
+}
+
void Viewport::logic()
{
WindowContainer::logic();
diff --git a/src/gui/viewport.h b/src/gui/viewport.h
index 93e36b5b..f4db806b 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -29,6 +29,8 @@
#include <guichan/mouselistener.hpp>
+#include <list>
+
class ActorSprite;
class Being;
class BeingPopup;
@@ -153,6 +155,22 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
*/
void hideBeingPopup();
+ /**
+ * Makes the screen shake in a random direction
+ */
+ void shakeScreen(int intensity);
+
+ /**
+ * Makes the screen shake in a specific direction
+ */
+ void shakeScreen(float x, float y, float decay = 0.95f, unsigned duration = 0);
+
+ /**
+ * Stops all active screen shake effects
+ */
+ void shakeScreenStop()
+ { mShakeEffects.clear(); }
+
void event(Channels channel, const Mana::Event &event);
private:
@@ -190,6 +208,16 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
float mPixelViewY; /**< Current viewpoint in pixels. */
int mShowDebugPath; /**< Show a path from player to pointer. */
+ struct ShakeEffect
+ {
+ float x;
+ float y;
+ float decay;
+ unsigned duration;
+ };
+ typedef std::list<ShakeEffect> ShakeEffects;
+ ShakeEffects mShakeEffects;
+
bool mPlayerFollowMouse;
int mLocalWalkTime; /**< Timestamp before the next walk can be sent. */
diff --git a/src/net/manaserv/effecthandler.cpp b/src/net/manaserv/effecthandler.cpp
index 2df3fe0b..7051bedd 100644
--- a/src/net/manaserv/effecthandler.cpp
+++ b/src/net/manaserv/effecthandler.cpp
@@ -25,6 +25,8 @@
#include "effectmanager.h"
#include "log.h"
+#include "gui/viewport.h"
+
#include "net/messagein.h"
#include "net/manaserv/manaserv_protocol.h"
@@ -36,6 +38,7 @@ EffectHandler::EffectHandler()
static const Uint16 _messages[] = {
GPMSG_CREATE_EFFECT_POS,
GPMSG_CREATE_EFFECT_BEING,
+ GPMSG_SHAKE,
0
};
handledMessages = _messages;
@@ -51,6 +54,9 @@ void EffectHandler::handleMessage(Net::MessageIn &msg)
case GPMSG_CREATE_EFFECT_BEING:
handleCreateEffectBeing(msg);
break;
+ case GPMSG_SHAKE:
+ handleShake(msg);
+ break;
default:
break;
}
@@ -75,4 +81,36 @@ void EffectHandler::handleCreateEffectBeing(Net::MessageIn &msg)
logger->log("Warning: CreateEffect called for unknown being #%d", bid);
}
+void EffectHandler::handleShake(Net::MessageIn &msg)
+{
+ int16_t intensityX = 0;
+ int16_t intensityY = 0;
+ float decay;
+ int duration;
+
+ switch (msg.getUnreadLength())
+ {
+ case 4:
+ intensityX = msg.readInt16();
+ intensityY = msg.readInt16();
+ viewport->shakeScreen(intensityX, intensityY);
+ break;
+ case 6:
+ intensityX = msg.readInt16();
+ intensityY = msg.readInt16();
+ decay = msg.readInt16() / 10000.0f;
+ viewport->shakeScreen(intensityX, intensityY, decay);
+ break;
+ case 8:
+ intensityX = msg.readInt16();
+ intensityY = msg.readInt16();
+ decay = msg.readInt16() / 10000.0f;
+ duration = msg.readInt16();
+ viewport->shakeScreen(intensityX, intensityY, decay, duration);
+ break;
+ default:
+ logger->log("Warning: Received GPMSG_SHAKE message with unexpected length of %d bytes", msg.getUnreadLength());
+ }
+}
+
} // namespace ManaServ
diff --git a/src/net/manaserv/effecthandler.h b/src/net/manaserv/effecthandler.h
index a0445aad..d31c3421 100644
--- a/src/net/manaserv/effecthandler.h
+++ b/src/net/manaserv/effecthandler.h
@@ -36,6 +36,7 @@ class EffectHandler : public MessageHandler
private:
void handleCreateEffectPos(Net::MessageIn &msg);
void handleCreateEffectBeing(Net::MessageIn &msg);
+ void handleShake(Net::MessageIn &msg);
};
} // namespace ManaServ
diff --git a/src/net/manaserv/manaserv_protocol.h b/src/net/manaserv/manaserv_protocol.h
index 84f1c1a5..16e56183 100644
--- a/src/net/manaserv/manaserv_protocol.h
+++ b/src/net/manaserv/manaserv_protocol.h
@@ -163,6 +163,7 @@ enum {
GPMSG_BEINGS_DAMAGE = 0x0310, // { W being id, W amount }*
GPMSG_CREATE_EFFECT_POS = 0x0320, // W effect id, W*2 position
GPMSG_CREATE_EFFECT_BEING = 0x0321, // W effect id, W BeingID
+ GPMSG_SHAKE = 0x0330, // W intensityX, W intensityY, [W decay_times_10000, [W duration]]
// Guild
PCMSG_GUILD_CREATE = 0x0350, // S name
diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp
index b82968a3..725a00cc 100644
--- a/src/net/tmwa/playerhandler.cpp
+++ b/src/net/tmwa/playerhandler.cpp
@@ -282,6 +282,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
if (PlayerInfo::getAttribute(HP) == 0 && !deathNotice)
{
+ viewport->shakeScreen(100);
deathNotice = new OkDialog(_("Message"),
randomDeathMessage(),
false);