summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/being.cpp103
-rw-r--r--src/being.h19
-rw-r--r--src/engine.cpp1
-rw-r--r--src/engine.h5
-rw-r--r--src/net/beinghandler.cpp4
-rw-r--r--src/net/playerhandler.cpp18
-rw-r--r--src/particle.h9
-rw-r--r--src/player.h8
8 files changed, 163 insertions, 4 deletions
diff --git a/src/being.cpp b/src/being.cpp
index fbee967f..3a84ccd0 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -30,6 +30,8 @@
#include "log.h"
#include "map.h"
#include "particle.h"
+#include "sound.h"
+#include "localplayer.h"
#include "resources/itemdb.h"
#include "resources/resourcemanager.h"
@@ -49,6 +51,10 @@ const bool debug_movement = true;
#define HAIR_FILE "hair.xml"
+#include "utils/xml.h"
+
+#define BEING_EFFECTS_FILE "effects.xml"
+
int Being::instances = 0;
ImageSet *Being::emotionSet = NULL;
@@ -525,7 +531,7 @@ void Being::logic()
i != mChildParticleEffects.end();)
{
(*i)->setPosition(mPos.x, mPos.y);
- if (!(*i)->isAlive())
+ if ((*i)->isExtinct())
{
(*i)->kill();
i = mChildParticleEffects.erase(i);
@@ -695,3 +701,98 @@ initializeHair(void)
hairInitialized = 1;
}
+
+
+
+struct EffectDescription {
+ std::string mGFXEffect;
+ std::string mSFXEffect;
+};
+
+static EffectDescription *default_effect = NULL;
+static std::map<int, EffectDescription *> effects;
+static bool effects_initialized = false;
+
+static EffectDescription *
+getEffectDescription(xmlNodePtr node, int *id)
+{
+ EffectDescription *ed = new EffectDescription;
+
+ *id = atoi(XML::getProperty(node, "id", "-1").c_str());
+ ed->mSFXEffect = XML::getProperty(node, "audio", "");
+ ed->mGFXEffect = XML::getProperty(node, "particle", "");
+
+ return ed;
+}
+
+static EffectDescription *
+getEffectDescription(int effectId)
+{
+ if (!effects_initialized)
+ {
+ XML::Document doc(BEING_EFFECTS_FILE);
+ xmlNodePtr root = doc.rootNode();
+
+ if (!root || !xmlStrEqual(root->name, BAD_CAST "being-effects"))
+ {
+ logger->log("Error loading being effects file: "
+ BEING_EFFECTS_FILE);
+ return NULL;
+ }
+
+ for_each_xml_child_node(node, root)
+ {
+ int id;
+
+ if (xmlStrEqual(node->name, BAD_CAST "effect"))
+ {
+ EffectDescription *EffectDescription =
+ getEffectDescription(node, &id);
+ effects[id] = EffectDescription;
+ } else if (xmlStrEqual(node->name, BAD_CAST "default"))
+ {
+ EffectDescription *EffectDescription =
+ getEffectDescription(node, &id);
+
+ if (default_effect)
+ delete default_effect;
+
+ default_effect = EffectDescription;
+ }
+ }
+
+ effects_initialized = true;
+ } // done initializing
+
+ EffectDescription *ed = effects[effectId];
+
+ if (!ed)
+ return default_effect;
+ else
+ return ed;
+}
+
+void
+Being::internalTriggerEffect(int effectId, bool sfx, bool gfx)
+{
+ logger->log("Special effect #%d on %s", effectId,
+ getId() == player_node->getId() ? "self" : "other");
+
+ EffectDescription *ed = getEffectDescription(effectId);
+
+ if (!ed) {
+ logger->log("Unknown special effect and no default recorded");
+ return;
+ }
+
+ if (gfx && ed->mGFXEffect != "") {
+ Particle *selfFX;
+
+ selfFX = particleEngine->addEffect(ed->mGFXEffect, 0, 0);
+ controlParticle(selfFX);
+ }
+
+ if (sfx && ed->mSFXEffect != "") {
+ sound.playSfx(ed->mSFXEffect);
+ }
+}
diff --git a/src/being.h b/src/being.h
index 5e8cb2dc..9bf88d82 100644
--- a/src/being.h
+++ b/src/being.h
@@ -360,6 +360,15 @@ class Being : public Sprite
*/
const Path &getPath() const { return mPath; }
+ /**
+ * Triggers a visual effect, such as `level up'
+ *
+ * Only draws the visual effect, does not play sound effects
+ *
+ * \param effectId ID of the effect to trigger
+ */
+ virtual void
+ triggerEffect(int effectId) { internalTriggerEffect(effectId, false, true); }
static int getHairColorsNr(void);
@@ -379,6 +388,16 @@ class Being : public Sprite
virtual Map::BlockType getBlockType() const
{ return Map::BLOCKTYPE_NONE; }
+ /**
+ * Trigger visual effect, with components
+ *
+ * \param effectId ID of the effect to trigger
+ * \param sfx Whether to trigger sound effects
+ * \param gfx Whether to trigger graphical effects
+ */
+ void
+ internalTriggerEffect(int effectId, bool sfx, bool gfx);
+
Uint16 mId; /**< Unique being id */
Uint8 mSpriteDirection; /**< Facing direction */
Uint8 mDirection; /**< Walking direction */
diff --git a/src/engine.cpp b/src/engine.cpp
index db1ac3bd..f191280e 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -119,6 +119,7 @@ void Engine::changeMap(const std::string &mapPath)
}
mCurrentMap = newMap;
+ mMapName = mapPath;
}
void Engine::logic()
diff --git a/src/engine.h b/src/engine.h
index dbee1258..f676a271 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -23,6 +23,7 @@
#define _ENGINE_H
#include <iosfwd>
+#include <string>
class Map;
@@ -48,6 +49,9 @@ class Engine
*/
Map *getCurrentMap() { return mCurrentMap; }
+ const std::string &getCurrentMapName() { return mMapName; }
+
+
/**
* Sets the currently active map.
*/
@@ -60,6 +64,7 @@ class Engine
private:
Map *mCurrentMap;
+ std::string mMapName;
};
extern Engine *engine;
diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp
index 72371da5..f96cdcd5 100644
--- a/src/net/beinghandler.cpp
+++ b/src/net/beinghandler.cpp
@@ -32,6 +32,7 @@
#include "../localplayer.h"
#include "../log.h"
#include "../main.h"
+#include "../npc.h"
#include "../particle.h"
#include "../sound.h"
@@ -268,7 +269,7 @@ void BeingHandler::handleBeingAttackMessage(MessageIn &msg)
int attackType = msg.readInt8();
if (!being) return;
-
+
switch (direction)
{
case DIRECTION_UP: being->setDirection(Being::UP); break;
@@ -347,3 +348,4 @@ void BeingHandler::handleBeingDirChangeMessage(MessageIn &msg)
case DIRECTION_RIGHT: being->setDirection(Being::RIGHT); break;
}
}
+
diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp
index ad271f15..beb59250 100644
--- a/src/net/playerhandler.cpp
+++ b/src/net/playerhandler.cpp
@@ -50,6 +50,11 @@ extern BuyDialog *buyDialog;
extern SellDialog *sellDialog;
extern Window *buySellDialog;
+/* Max. distance we are willing to scroll after a teleport;
+ * everything beyond will reset the port hard.
+ */
+static const int MAP_TELEPORT_SCROLL_DISTANCE = 8 * 32;
+
/**
* Listener used for handling the overweigth message.
*/
@@ -292,6 +297,7 @@ PlayerHandler::handleMapChangeMessage(MessageIn &msg)
const std::string mapName = msg.readString();
const unsigned short x = msg.readInt16();
const unsigned short y = msg.readInt16();
+ const bool nearby = (engine->getCurrentMapName() == mapName);
logger->log("Changing map to %s (%d, %d)", mapName.c_str(), x, y);
@@ -301,8 +307,16 @@ PlayerHandler::handleMapChangeMessage(MessageIn &msg)
current_npc = 0;
const Vector &playerPos = player_node->getPosition();
- const float scrollOffsetX = x - (int) playerPos.x;
- const float scrollOffsetY = y - (int) playerPos.y;
+ float scrollOffsetX = 0.0f;
+ float scrollOffsetY = 0.0f;
+
+ /* Scroll if neccessary */
+ if (!nearby
+ || (abs(x - (int) playerPos.x) > MAP_TELEPORT_SCROLL_DISTANCE)
+ || (abs(y - (int) playerPos.y) > MAP_TELEPORT_SCROLL_DISTANCE)) {
+ scrollOffsetX = x - (int) playerPos.x;
+ scrollOffsetY = y - (int) playerPos.y;
+ }
player_node->setAction(Being::STAND);
player_node->setPosition(x, y);
diff --git a/src/particle.h b/src/particle.h
index 4a11c4cb..d98f2c39 100644
--- a/src/particle.h
+++ b/src/particle.h
@@ -161,6 +161,9 @@ class Particle : public Sprite
{ mPos.x += x; mPos.y += y; mPos.z += z; }
void
+ moveChildren(Vector change);
+
+ void
moveBy (Vector change)
{ mPos += change; }
@@ -271,6 +274,12 @@ class Particle : public Sprite
{ return mAlive; }
/**
+ * Determines whether the particle and its children are all dead
+ */
+ bool isExtinct()
+ { return !isAlive() && mChildParticles.empty(); }
+
+ /**
* Manually marks the particle for deletion.
*/
void kill()
diff --git a/src/player.h b/src/player.h
index 12f9d268..6880ca20 100644
--- a/src/player.h
+++ b/src/player.h
@@ -116,6 +116,14 @@ class Player : public Being
// Character guild information
std::map<int, Guild*> mGuilds;
+ /**
+ * Triggers a visual/audio effect, such as `level up'
+ *
+ * \param effect_id ID of the effect to trigger
+ */
+ virtual void
+ triggerEffect(int effectId) { internalTriggerEffect(effectId, true, true); }
+
private:
bool mInParty;
};