summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/Makefile.am2
-rw-r--r--src/being.cpp265
-rw-r--r--src/being.h125
-rw-r--r--src/beingmanager.cpp17
-rw-r--r--src/beingmanager.h39
-rw-r--r--src/engine.cpp12
-rw-r--r--src/engine.h7
-rw-r--r--src/equipment.cpp2
-rw-r--r--src/equipment.h2
-rw-r--r--src/flooritemmanager.cpp4
-rw-r--r--src/game.cpp678
-rw-r--r--src/gui/setup.cpp2
-rw-r--r--src/gui/setup_video.cpp22
-rw-r--r--src/gui/shop.cpp4
-rw-r--r--src/gui/skill.cpp4
-rw-r--r--src/gui/textbox.cpp12
-rw-r--r--src/gui/textbox.h13
-rw-r--r--src/gui/updatewindow.cpp2
-rw-r--r--src/gui/viewport.cpp143
-rw-r--r--src/gui/viewport.h25
-rw-r--r--src/gui/widgets/dropdown.cpp2
-rw-r--r--src/gui/window.cpp246
-rw-r--r--src/gui/window.h14
-rw-r--r--src/gui/windowcontainer.cpp4
-rw-r--r--src/imageparticle.cpp2
-rw-r--r--src/keyboardconfig.cpp3
-rw-r--r--src/keyboardconfig.h3
-rw-r--r--src/localplayer.cpp22
-rw-r--r--src/localplayer.h2
-rw-r--r--src/map.cpp226
-rw-r--r--src/map.h112
-rw-r--r--src/monster.cpp37
-rw-r--r--src/monster.h2
-rw-r--r--src/net/beinghandler.cpp11
-rw-r--r--src/net/equipmenthandler.cpp7
-rw-r--r--src/net/loginhandler.cpp2
-rw-r--r--src/net/playerhandler.cpp60
-rw-r--r--src/npc.cpp3
-rw-r--r--src/particle.cpp12
-rw-r--r--src/particle.h17
-rw-r--r--src/particleemitter.cpp29
-rw-r--r--src/particleemitter.h6
-rw-r--r--src/player.cpp12
-rw-r--r--src/resources/action.cpp5
-rw-r--r--src/resources/imageset.cpp7
-rw-r--r--src/resources/imageset.h8
-rw-r--r--src/resources/itemdb.cpp6
-rw-r--r--src/resources/mapreader.cpp218
-rw-r--r--src/resources/mapreader.h4
-rw-r--r--src/resources/monsterdb.cpp5
-rw-r--r--src/resources/monsterinfo.cpp5
-rw-r--r--src/resources/spritedef.cpp100
-rw-r--r--src/resources/spritedef.h8
-rw-r--r--src/sound.h2
-rw-r--r--src/textparticle.cpp2
-rw-r--r--src/tileset.h3
-rw-r--r--src/utils/dtor.h8
58 files changed, 1542 insertions, 1057 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e6ee7405..e6b9d3b1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -49,6 +49,8 @@ MARK_AS_ADVANCED(SDL_INCLUDE_DIR)
MARK_AS_ADVANCED(SDL_LIBRARY)
SET(SRCS
+ gui/widgets/dropdown.cpp
+ gui/widgets/dropdown.h
gui/widgets/resizegrip.cpp
gui/widgets/resizegrip.h
gui/box.cpp
@@ -159,6 +161,8 @@ SET(SRCS
gui/skill.h
gui/slider.cpp
gui/slider.h
+ gui/speechbubble.cpp
+ gui/speechbubble.h
gui/status.cpp
gui/status.h
gui/tabbedcontainer.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index d2fd5efb..f6d06536 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -117,6 +117,8 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \
gui/skill.h \
gui/slider.cpp \
gui/slider.h \
+ gui/speechbubble.cpp \
+ gui/speechbubble.h \
gui/status.cpp \
gui/status.h \
gui/tabbedcontainer.cpp \
diff --git a/src/being.cpp b/src/being.cpp
index fd1b67fe..1d7f5ee7 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -22,8 +22,8 @@
*/
#include "being.h"
-#include <algorithm>
#include <cassert>
+#include <cmath>
#include "animatedsprite.h"
#include "equipment.h"
@@ -32,7 +32,7 @@
#include "log.h"
#include "map.h"
#include "particle.h"
-#include "text.h"
+#include "sound.h"
#include "localplayer.h"
#include "resources/resourcemanager.h"
@@ -40,20 +40,22 @@
#include "resources/iteminfo.h"
#include "gui/gui.h"
+#include "gui/speechbubble.h"
#include "utils/dtor.h"
#include "utils/tostring.h"
+#include "utils/xml.h"
+
+#define BEING_EFFECTS_FILE "effects.xml"
+
int Being::instances = 0;
ImageSet *Being::emotionSet = NULL;
-static const int X_SPEECH_OFFSET = 18;
-static const int Y_SPEECH_OFFSET = 60;
-
Being::Being(int id, int job, Map *map):
mJob(job),
mX(0), mY(0),
- mAction(0),
+ mAction(STAND),
mWalkTime(0),
mEmotion(0), mEmotionTime(0),
mAttackSpeed(350),
@@ -73,6 +75,8 @@ Being::Being(int id, int job, Map *map):
{
setMap(map);
+ mSpeechBubble = new SpeechBubble();
+
if (instances == 0)
{
// Load the emotion set
@@ -82,13 +86,13 @@ Being::Being(int id, int job, Map *map):
}
instances++;
- mSpeech = 0;
+ mSpeech = "";
mIsGM = false;
}
Being::~Being()
{
- std::for_each(mSprites.begin(), mSprites.end(), make_dtor(mSprites));
+ delete_all(mSprites);
clearPath();
for ( std::list<Particle *>::iterator i = mChildParticleEffects.begin();
@@ -107,14 +111,11 @@ Being::~Being()
emotionSet->decRef();
emotionSet = NULL;
}
- if (mSpeech)
- {
- delete mSpeech;
- }
+
+ delete mSpeechBubble;
}
-void
-Being::setDestination(Uint16 destX, Uint16 destY)
+void Being::setDestination(Uint16 destX, Uint16 destY)
{
if (mMap)
{
@@ -122,14 +123,12 @@ Being::setDestination(Uint16 destX, Uint16 destY)
}
}
-void
-Being::clearPath()
+void Being::clearPath()
{
mPath.clear();
}
-void
-Being::setPath(const Path &path)
+void Being::setPath(const Path &path)
{
mPath = path;
@@ -140,36 +139,26 @@ Being::setPath(const Path &path)
}
}
-void
-Being::setHairStyle(int style, int color)
+void Being::setHairStyle(int style, int color)
{
mHairStyle = style < 0 ? mHairStyle : style % NR_HAIR_STYLES;
mHairColor = color < 0 ? mHairColor : color % NR_HAIR_COLORS;
}
-void
-Being::setSprite(int slot, int id, std::string color)
+void Being::setSprite(int slot, int id, std::string color)
{
assert(slot >= BASE_SPRITE && slot < VECTOREND_SPRITE);
mSpriteIDs[slot] = id;
mSpriteColors[slot] = color;
}
-void
-Being::setSpeech(const std::string &text, Uint32 time)
+void Being::setSpeech(const std::string &text, Uint32 time)
{
- if (mSpeech) // don't introduce a memory leak
- {
- delete mSpeech;
- }
- mSpeech = new Text(text, mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET,
- gcn::Graphics::CENTER, speechFont,
- gcn::Color(255, 255, 255));
+ mSpeech = text;
mSpeechTime = 500;
}
-void
-Being::takeDamage(int amount)
+void Being::takeDamage(int amount)
{
gcn::Font *font;
std::string damage = amount ? toString(amount) : "miss";
@@ -200,16 +189,14 @@ Being::takeDamage(int amount)
mPx + 16, mPy + 16);
}
-void
-Being::handleAttack(Being *victim, int damage)
+void Being::handleAttack(Being *victim, int damage)
{
setAction(Being::ATTACK);
mFrame = 0;
mWalkTime = tick_time;
}
-void
-Being::setMap(Map *map)
+void Being::setMap(Map *map)
{
// Remove sprite from potential previous map
if (mMap)
@@ -229,8 +216,7 @@ Being::setMap(Map *map)
mChildParticleEffects.clear();
}
-void
-Being::controlParticle(Particle *particle)
+void Being::controlParticle(Particle *particle)
{
if (particle)
{
@@ -240,8 +226,7 @@ Being::controlParticle(Particle *particle)
}
}
-void
-Being::setAction(Uint8 action)
+void Being::setAction(Action action)
{
SpriteAction currentAction = ACTION_INVALID;
switch (action)
@@ -294,10 +279,11 @@ Being::setAction(Uint8 action)
}
}
-
-void
-Being::setDirection(Uint8 direction)
+void Being::setDirection(Uint8 direction)
{
+ if (mDirection == direction)
+ return;
+
mDirection = direction;
SpriteDirection dir = getSpriteDirection();
@@ -308,8 +294,7 @@ Being::setDirection(Uint8 direction)
}
}
-SpriteDirection
-Being::getSpriteDirection() const
+SpriteDirection Being::getSpriteDirection() const
{
SpriteDirection dir;
@@ -325,15 +310,15 @@ Being::getSpriteDirection() const
{
dir = DIRECTION_RIGHT;
}
- else {
- dir = DIRECTION_LEFT;
+ else
+ {
+ dir = DIRECTION_LEFT;
}
-
+
return dir;
}
-void
-Being::nextStep()
+void Being::nextStep()
{
if (mPath.empty())
{
@@ -368,32 +353,23 @@ Being::nextStep()
mWalkTime += mWalkSpeed / 10;
}
-void
-Being::logic()
+void Being::logic()
{
// Reduce the time that speech is still displayed
- if (mSpeechTime > 0 && mSpeech)
- {
- if (--mSpeechTime == 0)
- {
- delete mSpeech;
- mSpeech = 0;
- }
- }
+ if (mSpeechTime > 0)
+ mSpeechTime--;
int oldPx = mPx;
int oldPy = mPy;
// Update pixel coordinates
mPx = mX * 32 + getXOffset();
mPy = mY * 32 + getYOffset();
+
if (mPx != oldPx || mPy != oldPy)
{
- if (mSpeech)
- {
- mSpeech->adviseXY(mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET);
- }
updateCoords();
}
+
if (mEmotion != 0)
{
mEmotionTime--;
@@ -412,25 +388,23 @@ Being::logic()
}
//Update particle effects
- for ( std::list<Particle *>::iterator i = mChildParticleEffects.begin();
- i != mChildParticleEffects.end();
-
- )
+ for (std::list<Particle *>::iterator i = mChildParticleEffects.begin();
+ i != mChildParticleEffects.end();)
{
(*i)->setPosition((float)mPx + 16.0f, (float)mPy + 32.0f);
- if (!(*i)->isAlive())
+ if ((*i)->isExtinct())
{
(*i)->kill();
i = mChildParticleEffects.erase(i);
}
- else {
+ else
+ {
i++;
}
}
}
-void
-Being::draw(Graphics *graphics, int offsetX, int offsetY) const
+void Being::draw(Graphics *graphics, int offsetX, int offsetY) const
{
int px = mPx + offsetX;
int py = mPy + offsetY;
@@ -444,8 +418,7 @@ Being::draw(Graphics *graphics, int offsetX, int offsetY) const
}
}
-void
-Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
+void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
{
if (!mEmotion)
return;
@@ -458,17 +431,39 @@ Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
graphics->drawImage(emotionSet->get(emotionIndex), px, py);
}
-Being::Type
-Being::getType() const
+void Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY)
+{
+ int px = mPx + offsetX;
+ int py = mPy + offsetY;
+
+ // Draw speech above this being
+ if (mSpeechTime > 0)
+ {
+ mSpeechBubble->setCaption(mName);
+ mSpeechBubble->setWindowName(mName);
+ // Not quite centered, but close enough. However, it's not too important to get
+ // it right right now, as it doesn't take bubble collision into account yet.
+ mSpeechBubble->setPosition(px - (mSpeechBubble->getWidth() * 4 / 11), py - 70 -
+ (mSpeechBubble->getNumRows()*14));
+ mSpeechBubble->setText( mSpeech );
+ mSpeechBubble->setVisible(true);
+ }
+ else if (mSpeechTime == 0)
+ {
+ mSpeechBubble->setVisible(false);
+ }
+}
+
+Being::Type Being::getType() const
{
return UNKNOWN;
}
-int
-Being::getOffset(char pos, char neg) const
+int Being::getOffset(char pos, char neg) const
{
// Check whether we're walking in the requested direction
- if (mAction != WALK || !(mDirection & (pos | neg))) {
+ if (mAction != WALK || !(mDirection & (pos | neg)))
+ {
return 0;
}
@@ -476,40 +471,132 @@ Being::getOffset(char pos, char neg) const
// We calculate the offset _from_ the _target_ location
offset -= 32;
- if (offset > 0) {
+ if (offset > 0)
+ {
offset = 0;
}
// Going into negative direction? Invert the offset.
- if (mDirection & pos) {
+ if (mDirection & pos)
+ {
offset = -offset;
}
return offset;
}
-
-int
-Being::getWidth() const
+int Being::getWidth() const
{
if (mSprites[BASE_SPRITE])
{
return mSprites[BASE_SPRITE]->getWidth();
}
- else {
+ else
+ {
return 0;
}
}
-int
-Being::getHeight() const
+int Being::getHeight() const
{
if (mSprites[BASE_SPRITE])
{
return mSprites[BASE_SPRITE]->getHeight();
}
- else {
+ else
+ {
return 0;
}
}
+
+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 f196f66c..b7f85c63 100644
--- a/src/being.h
+++ b/src/being.h
@@ -25,7 +25,6 @@
#define _TMW_BEING_H
#include <list>
-#include <memory>
#include <string>
#include <SDL_types.h>
#include <vector>
@@ -34,6 +33,8 @@
#include "map.h"
#include "animatedsprite.h"
+#include "gui/speechbubble.h"
+
#define NR_HAIR_STYLES 10
#define NR_HAIR_COLORS 16
@@ -47,7 +48,7 @@ class Map;
class Graphics;
class ImageSet;
class Particle;
-class Text;
+class SpeechBubble;
/**
* A position along a being's path.
@@ -116,20 +117,17 @@ class Being : public Sprite
/**
* Directions, to be used as bitmask values
*/
- static const char DOWN = 1;
- static const char LEFT = 2;
- static const char UP = 4;
- static const char RIGHT = 8;
+ enum { DOWN = 1, LEFT = 2, UP = 4, RIGHT = 8 };
Uint16 mJob; /**< Job (player job, npc, monster, ) */
Uint16 mX, mY; /**< Tile coordinates */
- Uint8 mAction; /**< Action the being is performing */
- Uint8 mFrame;
+ Action mAction; /**< Action the being is performing */
+ Uint16 mFrame;
Uint16 mWalkTime;
Uint8 mEmotion; /**< Currently showing emotion */
Uint8 mEmotionTime; /**< Time until emotion disappears */
- Uint16 mAttackSpeed; /**< Attack speed */
+ Uint16 mAttackSpeed; /**< Attack speed */
/**
* Constructor.
@@ -165,8 +163,7 @@ class Being : public Sprite
*
* @param amount The amount of damage.
*/
- virtual void
- takeDamage(int amount);
+ virtual void takeDamage(int amount);
/**
* Handles an attack of another being by this being.
@@ -174,22 +171,19 @@ class Being : public Sprite
* @param victim The attacked being.
* @param damage The amount of damage dealt (0 means miss).
*/
- virtual void
- handleAttack(Being *victim, int damage);
+ virtual void handleAttack(Being *victim, int damage);
/**
* Returns the name of the being.
*/
- const std::string&
- getName() const { return mName; }
+ const std::string& getName() const { return mName; }
/**
* Sets the name for the being.
*
* @param name The name that should appear.
*/
- virtual void
- setName(const std::string &name) { mName = name; }
+ virtual void setName(const std::string &name) { mName = name; }
/**
* Gets the hair color for this being.
@@ -206,47 +200,44 @@ class Being : public Sprite
/**
* Sets the hair style and color for this being.
*/
- virtual void
- setHairStyle(int style, int color);
+ virtual void setHairStyle(int style, int color);
/**
* Sets visible equipments for this being.
*/
- virtual void
- setSprite(int slot, int id, std::string color = "");
+ virtual void setSprite(int slot, int id, std::string color = "");
/**
* Sets the gender of this being.
*/
- virtual void
- setGender(int gender) { mGender = gender; }
+ virtual void setGender(int gender) { mGender = gender; }
/**
* Gets the gender of this being.
*/
- int
- getGender() const { return mGender; }
+ int getGender() const { return mGender; }
/**
* Makes this being take the next step of his path.
*/
- virtual void
- nextStep();
+ virtual void nextStep();
- virtual void
- setGM() { mIsGM = true; }
+ virtual void setGM() { mIsGM = true; }
/**
* Performs being logic.
*/
- virtual void
- logic();
+ virtual void logic();
+
+ /**
+ * Draws the speech text above the being.
+ */
+ void drawSpeech(Graphics *graphics, int offsetX, int offsetY);
/**
* Draws the emotion picture above the being.
*/
- void
- drawEmotion(Graphics *graphics, int offsetX, int offsetY);
+ void drawEmotion(Graphics *graphics, int offsetX, int offsetY);
/**
* Returns the type of the being.
@@ -256,26 +247,22 @@ class Being : public Sprite
/**
* Gets the walk speed.
*/
- Uint16
- getWalkSpeed() const { return mWalkSpeed; }
+ Uint16 getWalkSpeed() const { return mWalkSpeed; }
/**
* Sets the walk speed.
*/
- void
- setWalkSpeed(Uint16 speed) { mWalkSpeed = speed; }
+ void setWalkSpeed(Uint16 speed) { mWalkSpeed = speed; }
/**
* Gets the sprite id.
*/
- Uint32
- getId() const { return mId; }
+ Uint32 getId() const { return mId; }
/**
* Sets the sprite id.
*/
- void
- setId(Uint32 id) { mId = id; }
+ void setId(Uint32 id) { mId = id; }
/**
* Sets the map the being is on
@@ -285,8 +272,7 @@ class Being : public Sprite
/**
* Sets the current action.
*/
- virtual void
- setAction(Uint8 action);
+ virtual void setAction(Action action);
/**
* Returns the current direction.
@@ -299,50 +285,53 @@ class Being : public Sprite
void setDirection(Uint8 direction);
/**
+ * Gets the current action.
+ */
+ int getWalkTime() { return mWalkTime; }
+
+ /**
+ * Returns the direction the being is facing.
+ */
+ SpriteDirection getSpriteDirection() const;
+
+ /**
* Draws this being to the given graphics context.
*
* @see Sprite::draw(Graphics, int, int)
*/
- virtual void
- draw(Graphics *graphics, int offsetX, int offsetY) const;
+ virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
/**
* Returns the pixel X coordinate.
*/
- int
- getPixelX() const { return mPx; }
+ int getPixelX() const { return mPx; }
/**
* Returns the pixel Y coordinate.
*
* @see Sprite::getPixelY()
*/
- int
- getPixelY() const { return mPy; }
+ int getPixelY() const { return mPy; }
/**
* Get the current X pixel offset.
*/
- int
- getXOffset() const { return getOffset(LEFT, RIGHT); }
+ int getXOffset() const { return getOffset(LEFT, RIGHT); }
/**
* Get the current Y pixel offset.
*/
- int
- getYOffset() const { return getOffset(UP, DOWN); }
+ int getYOffset() const { return getOffset(UP, DOWN); }
/**
* Returns the horizontal size of the current base sprite of the being
*/
- virtual int
- getWidth() const;
+ virtual int getWidth() const;
/**
* Returns the vertical size of the current base sprite of the being
*/
- virtual int
- getHeight() const;
+ virtual int getHeight() const;
/**
* Returns the required size of a target cursor for this being.
@@ -361,6 +350,15 @@ class Being : public Sprite
mEmotionTime = emote_time;
}
+ /**
+ * 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); }
+
const std::auto_ptr<Equipment> mEquipment;
protected:
@@ -375,9 +373,13 @@ class Being : public Sprite
virtual void updateCoords() {}
/**
- * Returns the sprite direction of this being.
+ * 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
*/
- SpriteDirection getSpriteDirection() const;
+ void internalTriggerEffect(int effectId, bool sfx, bool gfx);
Uint32 mId; /**< Unique sprite id */
Uint16 mWalkSpeed; /**< Walking speed */
@@ -391,7 +393,7 @@ class Being : public Sprite
const ItemInfo* mEquippedWeapon;
Path mPath;
- Text *mSpeech;
+ std::string mSpeech;
Uint16 mHairStyle, mHairColor;
Uint8 mGender;
Uint32 mSpeechTime;
@@ -409,6 +411,9 @@ class Being : public Sprite
*/
int getOffset(char pos, char neg) const;
+ // Speech Bubble components
+ SpeechBubble *mSpeechBubble;
+
static int instances; /**< Number of Being instances */
static ImageSet *emotionSet; /**< Emoticons used by beings */
};
diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp
index 47729a92..f0ce9bd3 100644
--- a/src/beingmanager.cpp
+++ b/src/beingmanager.cpp
@@ -21,7 +21,7 @@
* $Id: beingmanager.cpp 4237 2008-05-14 18:57:32Z b_lindeijer $
*/
-#include <algorithm>
+#include <cassert>
#include "beingmanager.h"
@@ -124,7 +124,7 @@ Being* BeingManager::findBeing(Uint16 x, Uint16 y, Being::Type type)
return (i == mBeings.end()) ? NULL : *i;
}
-/*Being* BeingManager::findBeingByPixel(Uint16 x, Uint16 y)
+Being* BeingManager::findBeingByPixel(Uint16 x, Uint16 y)
{
BeingIterator itr = mBeings.begin();
BeingIterator itr_end = mBeings.end();
@@ -144,7 +144,7 @@ Being* BeingManager::findBeing(Uint16 x, Uint16 y, Being::Type type)
}
return NULL;
-}*/
+}
Being* BeingManager::findBeingByName(std::string name, Being::Type type)
{
@@ -159,8 +159,6 @@ Being* BeingManager::findBeingByName(std::string name, Being::Type type)
return NULL;
}
-
-
Beings& BeingManager::getAll()
{
return mBeings;
@@ -193,7 +191,7 @@ void BeingManager::clear()
mBeings.remove(player_node);
}
- for_each(mBeings.begin(), mBeings.end(), make_dtor(mBeings));
+ delete_all(mBeings);
mBeings.clear();
if (player_node)
@@ -208,9 +206,12 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
Being *closestBeing = NULL;
int dist = 0;
- for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++)
+ BeingIterator itr = mBeings.begin();
+ BeingIterator itr_end = mBeings.end();
+
+ for (; itr != itr_end; ++itr)
{
- Being *being = (*i);
+ Being *being = (*itr);
int d = abs(being->mX - x) + abs(being->mY - y);
if ((being->getType() == type || type == Being::UNKNOWN)
diff --git a/src/beingmanager.h b/src/beingmanager.h
index f8391855..6942ff54 100644
--- a/src/beingmanager.h
+++ b/src/beingmanager.h
@@ -51,7 +51,7 @@ class BeingManager
/**
* Create a being and add it to the list of beings.
*/
- Being* createBeing(Uint32 id, Uint16 job);
+ Being *createBeing(Uint32 id, Uint16 job);
/**
* Remove a Being.
@@ -62,33 +62,36 @@ class BeingManager
* Return a specific id Being.
*/
Being* findBeing(Uint32 id);
+ Being* findBeingByPixel(Uint16 x, Uint16 y);
/**
- * Return a being at specific coordinates.
+ * Returns a being at specific coordinates.
*/
Being* findBeing(Uint16 x, Uint16 y, Being::Type type = Being::UNKNOWN);
- //Being* findBeingByPixel(Uint16 x, Uint16 y);
- /**
- * Return a being nearest to specific coordinates.
- *
- * \param maxdist maximal distance. If minimal distance is larger,
- * no being is returned
- */
+ /**
+ * Returns a being nearest to specific coordinates.
+ *
+ * @param x X coordinate.
+ * @param y Y coordinate.
+ * @param maxdist Maximal distance. If minimal distance is larger,
+ * no being is returned.
+ * @param type The type of being to look for.
+ */
Being* findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
Being::Type type = Being::UNKNOWN);
- /**
- * Finds a being by name and (optionally) by type.
- */
+ /**
+ * Finds a being by name and (optionally) by type.
+ */
Being* findBeingByName(std::string name, Being::Type type = Being::UNKNOWN);
- /**
- * Return a being nearest to another being.
- *
- * \param maxdist maximal distance. If minimal distance is larger,
- * no being is returned
- */
+ /**
+ * Returns a being nearest to another being.
+ *
+ * \param maxdist maximal distance. If minimal distance is larger,
+ * no being is returned
+ */
Being* findNearestLivingBeing(Being *aroundBeing, int maxdist,
Being::Type type = Being::UNKNOWN);
diff --git a/src/engine.cpp b/src/engine.cpp
index d1912b0d..42054ffb 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -96,6 +96,17 @@ void Engine::changeMap(const std::string &mapPath)
if (newMap->hasProperty("minimap"))
{
mapImage = resman->getImage(newMap->getProperty("minimap"));
+
+ // Set the title for the Minimap
+ if (newMap->hasProperty("mapname"))
+ {
+ minimap->setCaption(newMap->getProperty("mapname"));
+ }
+ else
+ {
+ minimap->setCaption("Unknown");
+ logger->log("WARNING: Map file '%s' defines a minimap image but does not define a 'mapname' property", map_path.c_str());
+ }
}
minimap->setMapImage(mapImage);
beingManager->setMap(newMap);
@@ -120,6 +131,7 @@ void Engine::changeMap(const std::string &mapPath)
}
mCurrentMap = newMap;
+ mMapName = mapPath;
// Send "map loaded"
MessageOut outMsg(mNetwork);
diff --git a/src/engine.h b/src/engine.h
index ed76a595..52f1e63a 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -18,13 +18,14 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: engine.h 4000 2008-03-23 11:47:52Z b_lindeijer $
+ * $Id$
*/
#ifndef _ENGINE_H
#define _ENGINE_H
#include <iosfwd>
+#include <string>
class Map;
class Network;
@@ -51,6 +52,9 @@ class Engine
*/
Map *getCurrentMap() { return mCurrentMap; }
+ const std::string &getCurrentMapName() { return mMapName; }
+
+
/**
* Sets the currently active map.
*/
@@ -64,6 +68,7 @@ class Engine
private:
Map *mCurrentMap;
Network *mNetwork;
+ std::string mMapName;
};
extern Engine *engine;
diff --git a/src/equipment.cpp b/src/equipment.cpp
index 08e6fad1..491aff0c 100644
--- a/src/equipment.cpp
+++ b/src/equipment.cpp
@@ -41,12 +41,10 @@ Equipment::removeEquipment(Item *item)
if (i != mEquipment + EQUIPMENT_SIZE) {
*i = 0;
}
- item->setEquipped(false);
}
void Equipment::removeEquipment(int index)
{
- mEquipment[index]->setEquipped(false);
mEquipment[index] = 0;
}
diff --git a/src/equipment.h b/src/equipment.h
index fd7a9c1e..e497a156 100644
--- a/src/equipment.h
+++ b/src/equipment.h
@@ -24,6 +24,8 @@
#ifndef _TMW_EQUIPMENT_H_
#define _TMW_EQUIPMENT_H_
+#include <guichan/actionlistener.hpp>
+
class Item;
#define EQUIPMENT_SIZE 10
diff --git a/src/flooritemmanager.cpp b/src/flooritemmanager.cpp
index f6ad3442..fe64779b 100644
--- a/src/flooritemmanager.cpp
+++ b/src/flooritemmanager.cpp
@@ -21,8 +21,6 @@
* $Id: flooritemmanager.cpp 3754 2007-11-20 15:19:50Z b_lindeijer $
*/
-#include <algorithm>
-
#include "flooritemmanager.h"
#include "floor_item.h"
@@ -50,7 +48,7 @@ void FloorItemManager::destroy(FloorItem *item)
void FloorItemManager::clear()
{
- for_each(mFloorItems.begin(), mFloorItems.end(), make_dtor(mFloorItems));
+ delete_all(mFloorItems);
mFloorItems.clear();
}
diff --git a/src/game.cpp b/src/game.cpp
index 0562b75e..5e7ee1e8 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -68,6 +68,7 @@
#include "gui/status.h"
#include "gui/trade.h"
#include "gui/viewport.h"
+
#include "net/protocol.h"
#include "net/beinghandler.h"
#include "net/buysellhandler.h"
@@ -132,19 +133,19 @@ Particle* particleEngine = NULL;
const int MAX_TIME = 10000;
/**
- * Listener used for exitting handling.
+ * Listener used for exiting handling.
*/
namespace {
struct ExitListener : public gcn::ActionListener
{
- void action(const gcn::ActionEvent &event)
- {
- if (event.getId() == "yes" || event.getId() == "ok") {
- done = true;
+ void action(const gcn::ActionEvent &event)
+ {
+ if (event.getId() == "yes" || event.getId() == "ok") {
+ done = true;
+ }
+ exitConfirm = NULL;
+ disconnectedDialog = NULL;
}
- exitConfirm = NULL;
- disconnectedDialog = NULL;
- }
} exitListener;
}
@@ -171,11 +172,13 @@ Uint32 nextSecond(Uint32 interval, void *param)
int get_elapsed_time(int start_time)
{
- if (start_time <= tick_time) {
- return (tick_time - start_time) * 10;
+ if (start_time <= tick_time)
+ {
+ return (tick_time - start_time) * 10;
}
- else {
- return (tick_time + (MAX_TIME - start_time)) * 10;
+ else
+ {
+ return (tick_time + (MAX_TIME - start_time)) * 10;
}
}
@@ -218,8 +221,9 @@ void createGuiWindows(Network *network)
chatWindow->setVisible((bool) config.getValue(
chatWindow->getWindowName() + "Visible", true));
miniStatusWindow->setVisible((bool) config.getValue(
- miniStatusWindow->getWindowName() + "Visible",
- true));
+ miniStatusWindow->getWindowName() + "Visible", true));
+ buyDialog->setVisible(false);
+ sellDialog->setVisible(false);
menuWindow->setVisible((bool) config.getValue(
menuWindow->getWindowName() + "Visible", true));
itemShortcutWindow->setVisible((bool) config.getValue(
@@ -227,7 +231,7 @@ void createGuiWindows(Network *network)
if (config.getValue("logToChat", 0))
{
- logger->setChatWindow(chatWindow);
+ logger->setChatWindow(chatWindow);
}
}
@@ -369,15 +373,15 @@ bool saveScreenshot(SDL_Surface *screenshot)
if (ImageWriter::writePNG(screenshot, filename.str()))
{
- std::stringstream chatlogentry;
- chatlogentry << "Screenshot saved to " << filename.str().c_str();
- chatWindow->chatLog(chatlogentry.str(), BY_SERVER);
- return true;
+ std::stringstream chatlogentry;
+ chatlogentry << "Screenshot saved to " << filename.str().c_str();
+ chatWindow->chatLog(chatlogentry.str(), BY_SERVER);
+ return true;
}
else
{
- chatWindow->chatLog("Saving screenshot failed!", BY_SERVER);
- return false;
+ chatWindow->chatLog("Saving screenshot failed!", BY_SERVER);
+ return false;
}
}
@@ -420,18 +424,18 @@ void Game::logic()
if (!mMinFrameTime ||
get_elapsed_time(mDrawTime / 10) > mMinFrameTime)
{
- frame++;
- gui->draw();
- graphics->updateScreen();
- mDrawTime += mMinFrameTime;
-
- // Make sure to wrap mDrawTime, since tick_time will wrap.
- if (mDrawTime > MAX_TIME * 10)
- mDrawTime -= MAX_TIME * 10;
+ frame++;
+ gui->draw();
+ graphics->updateScreen();
+ mDrawTime += mMinFrameTime;
+
+ // Make sure to wrap mDrawTime, since tick_time will wrap.
+ if (mDrawTime > MAX_TIME * 10)
+ mDrawTime -= MAX_TIME * 10;
}
else
{
- SDL_Delay(10);
+ SDL_Delay(10);
}
}
else
@@ -448,12 +452,11 @@ void Game::logic()
{
if (!disconnectedDialog)
{
- disconnectedDialog = new
- OkDialog("Network Error",
- "The connection to the server was lost, the "
- "program will now quit");
- disconnectedDialog->addActionListener(&exitListener);
- disconnectedDialog->requestMoveToTop();
+ disconnectedDialog = new
+ OkDialog("Network Error",
+ "The connection to the server was lost, the program will now quit");
+ disconnectedDialog->addActionListener(&exitListener);
+ disconnectedDialog->requestMoveToTop();
}
}
}
@@ -463,273 +466,268 @@ void Game::handleInput()
{
if (joystick != NULL)
{
- joystick->update();
+ joystick->update();
}
// Events
SDL_Event event;
while (SDL_PollEvent(&event))
{
- bool used = false;
-
- // Keyboard events (for discontinuous keys)
- if (event.type == SDL_KEYDOWN)
- {
- gcn::Window *requestedWindow = NULL;
+ bool used = false;
- if (setupWindow->isVisible() &&
- keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE)
+ // Keyboard events (for discontinuous keys)
+ if (event.type == SDL_KEYDOWN)
{
- keyboard.setNewKey((int) event.key.keysym.sym);
- keyboard.callbackNewKey();
- keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE);
- return;
- }
- // Keys pressed together with Alt/Meta
- // Emotions and some internal gui windows
- #ifndef __APPLE__
- if (event.key.keysym.mod & KMOD_ALT)
- #else
- if (event.key.keysym.mod & KMOD_LMETA)
- #endif
- {
- switch (event.key.keysym.sym)
- {
- case SDLK_p:
- // Screenshot (picture, hence the p)
+ gcn::Window *requestedWindow = NULL;
+
+ if (setupWindow->isVisible() &&
+ keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE)
{
- SDL_Surface *screenshot =
- graphics->getScreenshot();
- if (!saveScreenshot(screenshot))
- {
- logger->
- log("Error: could not save Screenshot.");
- }
- SDL_FreeSurface(screenshot);
+ keyboard.setNewKey((int) event.key.keysym.sym);
+ keyboard.callbackNewKey();
+ keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE);
+ return;
}
- used = true;
- break;
-
- default:
- break;
-
- case SDLK_f:
- // Find path to mouse (debug purpose)
- viewport->toggleDebugPath();
- used = true;
- break;
-
- case SDLK_t:
- // Toggle accepting of incoming trade requests
+ // Keys pressed together with Alt/Meta
+ // Emotions and some internal gui windows
+ #ifndef __APPLE__
+ if (event.key.keysym.mod & KMOD_ALT)
+ #else
+ if (event.key.keysym.mod & KMOD_LMETA)
+ #endif
{
- unsigned int deflt = player_relations.getDefault();
- if (deflt & PlayerRelation::TRADE) {
- chatWindow->
- chatLog("Ignoring incoming trade requests",
- BY_SERVER);
- deflt &= ~PlayerRelation::TRADE;
- } else {
- chatWindow->chatLog("Accepting incoming trade "
- "requests", BY_SERVER);
- deflt |= PlayerRelation::TRADE;
- }
-
- player_relations.setDefault(deflt);
+ switch (event.key.keysym.sym)
+ {
+ case SDLK_p:
+ // Screenshot (picture, hence the p)
+ {
+ SDL_Surface *screenshot = graphics->getScreenshot();
+ if (!saveScreenshot(screenshot))
+ {
+ logger->log("Error: could not save Screenshot.");
+ }
+ SDL_FreeSurface(screenshot);
+ }
+ used = true;
+ break;
+
+ default:
+ break;
+
+ case SDLK_f:
+ // Find path to mouse (debug purpose)
+ viewport->toggleDebugPath();
+ used = true;
+ break;
+
+ case SDLK_t:
+ // Toggle accepting of incoming trade requests
+ {
+ unsigned int deflt = player_relations.getDefault();
+ if (deflt & PlayerRelation::TRADE) {
+ chatWindow->chatLog("Ignoring incoming trade requests", BY_SERVER);
+ deflt &= ~PlayerRelation::TRADE;
+ } else {
+ chatWindow->chatLog("Accepting incoming trade requests", BY_SERVER);
+ deflt |= PlayerRelation::TRADE;
+ }
+
+ player_relations.setDefault(deflt);
+ }
+ used = true;
+ break;
}
- used = true;
- break;
- }
-
- // Emotions
- Uint8 emotion;
- switch (event.key.keysym.sym)
- {
- case SDLK_1: emotion = 1; break;
- case SDLK_2: emotion = 2; break;
- case SDLK_3: emotion = 3; break;
- case SDLK_4: emotion = 4; break;
- case SDLK_5: emotion = 5; break;
- case SDLK_6: emotion = 6; break;
- case SDLK_7: emotion = 7; break;
- case SDLK_8: emotion = 8; break;
- case SDLK_9: emotion = 9; break;
- case SDLK_0: emotion = 10; break;
- case SDLK_MINUS: emotion = 11; break;
- case SDLK_EQUALS: emotion = 12; break;
- default: emotion = 0; break;
}
- if (emotion)
- {
- player_node->emote(emotion);
- used = true;
- }
- }
- switch (event.key.keysym.sym)
+ // Smilie
+ if (keyboard.isKeyActive(keyboard.KEY_SMILIE))
{
- case SDLK_PAGEUP:
- if (chatWindow->isVisible())
+ // Emotions
+ Uint8 emotion;
+ switch (event.key.keysym.sym)
{
- chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL);
- used = true;
+ case SDLK_1: emotion = 1; break;
+ case SDLK_2: emotion = 2; break;
+ case SDLK_3: emotion = 3; break;
+ case SDLK_4: emotion = 4; break;
+ case SDLK_5: emotion = 5; break;
+ case SDLK_6: emotion = 6; break;
+ case SDLK_7: emotion = 7; break;
+ case SDLK_8: emotion = 8; break;
+ case SDLK_9: emotion = 9; break;
+ case SDLK_0: emotion = 10; break;
+ case SDLK_MINUS: emotion = 11; break;
+ case SDLK_EQUALS: emotion = 12; break;
+ default: emotion = 0; break;
}
- break;
- case SDLK_PAGEDOWN:
- if (chatWindow->isVisible())
+ if (emotion)
{
- chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL);
- used = true;
+ player_node->emote(emotion);
+ used = true;
}
- break;
+ }
+ switch (event.key.keysym.sym)
+ {
+ case SDLK_PAGEUP:
+ if (chatWindow->isVisible())
+ {
+ chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL);
+ used = true;
+ }
+ break;
- case SDLK_F1:
- // In-game Help
- if (helpWindow->isVisible())
- {
- helpWindow->setVisible(false);
- }
- else
- {
- helpWindow->loadHelp("index");
- helpWindow->requestMoveToTop();
- }
- used = true;
- break;
+ case SDLK_PAGEDOWN:
+ if (chatWindow->isVisible())
+ {
+ chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL);
+ used = true;
+ }
+ break;
- case SDLK_F2: requestedWindow = statusWindow; break;
- case SDLK_F3: requestedWindow = inventoryWindow; break;
- case SDLK_F4: requestedWindow = equipmentWindow; break;
- case SDLK_F5: requestedWindow = skillDialog; break;
- case SDLK_F6: requestedWindow = minimap; break;
- case SDLK_F7: requestedWindow = chatWindow; break;
- case SDLK_F8: requestedWindow = itemShortcutWindow; break;
- case SDLK_F9: requestedWindow = setupWindow; break;
- case SDLK_F10: requestedWindow = debugWindow; break;
- //case SDLK_F11: requestedWindow = newSkillWindow; break;
-
- case SDLK_RETURN:
- // Input chat window
- if (chatWindow->isInputFocused() ||
- deathNotice != NULL ||
- weightNotice != NULL)
- {
- break;
- }
+ case SDLK_F1:
+ // In-game Help
+ if (helpWindow->isVisible())
+ {
+ helpWindow->setVisible(false);
+ }
+ else
+ {
+ helpWindow->loadHelp("index");
+ helpWindow->requestMoveToTop();
+ }
+ used = true;
+ break;
+
+ case SDLK_F2: requestedWindow = statusWindow; break;
+ case SDLK_F3: requestedWindow = inventoryWindow; break;
+ case SDLK_F4: requestedWindow = equipmentWindow; break;
+ case SDLK_F5: requestedWindow = skillDialog; break;
+ case SDLK_F6: requestedWindow = minimap; break;
+ case SDLK_F7: requestedWindow = chatWindow; break;
+ case SDLK_F8: requestedWindow = itemShortcutWindow; break;
+ case SDLK_F9: requestedWindow = setupWindow; break;
+ case SDLK_F10: requestedWindow = debugWindow; break;
+ //case SDLK_F11: requestedWindow = newSkillWindow; break;
+
+ case SDLK_RETURN:
+ // Input chat window
+ if (chatWindow->isInputFocused() ||
+ deathNotice != NULL ||
+ weightNotice != NULL)
+ {
+ break;
+ }
- // Quit by pressing Enter if the exit confirm is there
- if (exitConfirm)
- {
- done = true;
- }
- // Close the Browser if opened
- else if (helpWindow->isVisible())
- {
- helpWindow->setVisible(false);
- }
- // Close the config window, cancelling changes if opened
- else if (setupWindow->isVisible())
- {
- setupWindow->action(gcn::ActionEvent(NULL, "cancel"));
- }
- // Else, open the chat edit box
- else
- {
- chatWindow->requestChatFocus();
- used = true;
- }
- break;
- // Quitting confirmation dialog
- case SDLK_ESCAPE:
- if (!exitConfirm) {
- exitConfirm = new ConfirmDialog(
- "Quit", "Are you sure you want to quit?");
- exitConfirm->addActionListener(&exitListener);
- exitConfirm->requestMoveToTop();
- }
- else
- {
- exitConfirm->action(gcn::ActionEvent(NULL, "no"));
- }
- break;
+ // Quit by pressing Enter if the exit confirm is there
+ if (exitConfirm)
+ {
+ done = true;
+ }
+ // Close the Browser if opened
+ else if (helpWindow->isVisible())
+ {
+ helpWindow->setVisible(false);
+ }
+ // Close the config window, cancelling changes if opened
+ else if (setupWindow->isVisible())
+ {
+ setupWindow->action(gcn::ActionEvent(NULL, "cancel"));
+ }
+ // Else, open the chat edit box
+ else
+ {
+ chatWindow->requestChatFocus();
+ used = true;
+ }
+ break;
+ // Quitting confirmation dialog
+ case SDLK_ESCAPE:
+ if (!exitConfirm) {
+ exitConfirm = new ConfirmDialog(
+ "Quit", "Are you sure you want to quit?");
+ exitConfirm->addActionListener(&exitListener);
+ exitConfirm->requestMoveToTop();
+ }
+ else
+ {
+ exitConfirm->action(gcn::ActionEvent(NULL, "no"));
+ }
+ break;
- default:
- break;
+ default:
+ break;
}
if (keyboard.isEnabled() && !chatWindow->isInputFocused())
{
- const int tKey = keyboard.getKeyIndex(event.key.keysym.sym);
- // Checks if any item shortcut is pressed.
- for (int i = KeyboardConfig::KEY_SHORTCUT_0;
- i <= KeyboardConfig::KEY_SHORTCUT_9;
- i++)
- {
- if (tKey == i && !used) {
- itemShortcut->useItem(
- i - KeyboardConfig::KEY_SHORTCUT_0);
- break;
+ const int tKey = keyboard.getKeyIndex(event.key.keysym.sym);
+ // Checks if any item shortcut is pressed.
+ for (int i = KeyboardConfig::KEY_SHORTCUT_0;
+ i <= KeyboardConfig::KEY_SHORTCUT_9;
+ i++)
+ {
+ if (tKey == i && !used) {
+ itemShortcut->useItem(i - KeyboardConfig::KEY_SHORTCUT_0);
+ break;
}
}
switch (tKey) {
case KeyboardConfig::KEY_PICKUP:
{
- FloorItem *item =
- floorItemManager->findByCoordinates(
- player_node->mX, player_node->mY);
+ FloorItem *item = floorItemManager->findByCoordinates(
+ player_node->mX, player_node->mY);
// If none below the player, try the tile in front
// of the player
if (!item) {
- Uint16 x = player_node->mX;
- Uint16 y = player_node->mY;
- if (player_node->getDirection() & Being::UP)
- y--;
- if (player_node->getDirection() & Being::DOWN)
- y++;
- if (player_node->getDirection() & Being::LEFT)
- x--;
- if (player_node->getDirection() & Being::RIGHT)
- x++;
-
- item = floorItemManager->
- findByCoordinates(x, y);
+ Uint16 x = player_node->mX;
+ Uint16 y = player_node->mY;
+ switch (player_node->getSpriteDirection())
+ {
+ case DIRECTION_UP : --y; break;
+ case DIRECTION_DOWN : ++y; break;
+ case DIRECTION_LEFT : --x; break;
+ case DIRECTION_RIGHT: ++x; break;
+ default: break;
+ }
+ item = floorItemManager->findByCoordinates(x, y);
}
if (item)
- player_node->pickUp(item);
+ player_node->pickUp(item);
used = true;
}
break;
case KeyboardConfig::KEY_SIT:
- // Player sit action
- player_node->toggleSit();
- used = true;
- break;
+ // Player sit action
+ player_node->toggleSit();
+ used = true;
+ break;
case KeyboardConfig::KEY_HIDE_WINDOWS:
- // Hide certain windows
- if (!chatWindow->isInputFocused())
- {
- statusWindow->setVisible(false);
- inventoryWindow->setVisible(false);
- skillDialog->setVisible(false);
- setupWindow->setVisible(false);
- equipmentWindow->setVisible(false);
- helpWindow->setVisible(false);
- debugWindow->setVisible(false);
+ // Hide certain windows
+ if (!chatWindow->isInputFocused())
+ {
+ statusWindow->setVisible(false);
+ inventoryWindow->setVisible(false);
+ skillDialog->setVisible(false);
+ setupWindow->setVisible(false);
+ equipmentWindow->setVisible(false);
+ helpWindow->setVisible(false);
+ debugWindow->setVisible(false);
+ }
+ break;
}
- break;
- }
}
if (requestedWindow)
{
- requestedWindow->setVisible(!requestedWindow->isVisible());
- if (requestedWindow->isVisible())
- {
- requestedWindow->requestMoveToTop();
- }
- used = true;
+ requestedWindow->setVisible(!requestedWindow->isVisible());
+ if (requestedWindow->isVisible())
+ {
+ requestedWindow->requestMoveToTop();
+ }
+ used = true;
}
}
@@ -745,12 +743,12 @@ void Game::handleInput()
{
try
{
- guiInput->pushInput(event);
+ guiInput->pushInput(event);
}
catch (gcn::Exception e)
{
- const char* err = e.getMessage().c_str();
- logger->log("Warning: guichan input exception: %s", err);
+ const char* err = e.getMessage().c_str();
+ logger->log("Warning: guichan input exception: %s", err);
}
}
@@ -762,112 +760,106 @@ void Game::handleInput()
}
// Moving player around
if (player_node->mAction != Being::DEAD &&
- current_npc == 0 &&
- !chatWindow->isInputFocused())
+ current_npc == 0 &&
+ !chatWindow->isInputFocused())
{
- // Get the state of the keyboard keys
- keyboard.refreshActiveKeys();
+ // Get the state of the keyboard keys
+ keyboard.refreshActiveKeys();
- const Uint16 x = player_node->mX;
- const Uint16 y = player_node->mY;
- unsigned char direction = 0;
+ const Uint16 x = player_node->mX;
+ const Uint16 y = player_node->mY;
+ unsigned char direction = 0;
- // Translate pressed keys to movement and direction
- if (keyboard.isKeyActive(keyboard.KEY_MOVE_UP) ||
- (joystick && joystick->isUp()))
- {
- direction |= Being::UP;
- }
- else if (keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN) ||
- (joystick && joystick->isDown()))
- {
- direction |= Being::DOWN;
- }
+ // Translate pressed keys to movement and direction
+ if (keyboard.isKeyActive(keyboard.KEY_MOVE_UP) ||
+ (joystick && joystick->isUp()))
+ {
+ direction |= Being::UP;
+ }
+ else if (keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN) ||
+ (joystick && joystick->isDown()))
+ {
+ direction |= Being::DOWN;
+ }
- if (keyboard.isKeyActive(keyboard.KEY_MOVE_LEFT) ||
- (joystick && joystick->isLeft()))
- {
- direction |= Being::LEFT;
- }
- else if (keyboard.isKeyActive(keyboard.KEY_MOVE_RIGHT) ||
- (joystick && joystick->isRight()))
- {
- direction |= Being::RIGHT;
- }
+ if (keyboard.isKeyActive(keyboard.KEY_MOVE_LEFT) ||
+ (joystick && joystick->isLeft()))
+ {
+ direction |= Being::LEFT;
+ }
+ else if (keyboard.isKeyActive(keyboard.KEY_MOVE_RIGHT) ||
+ (joystick && joystick->isRight()))
+ {
+ direction |= Being::RIGHT;
+ }
- player_node->setWalkingDir(direction);
+ player_node->setWalkingDir(direction);
- // Attacking monsters
- if (keyboard.isKeyActive(keyboard.KEY_ATTACK) ||
- (joystick && joystick->buttonPressed(0)))
- {
- Being *target = NULL;
- bool newTarget = keyboard.isKeyActive(keyboard.KEY_TARGET);
- // A set target has highest priority
- if (newTarget || !player_node->getTarget())
+ // Attacking monsters
+ if (keyboard.isKeyActive(keyboard.KEY_ATTACK) ||
+ (joystick && joystick->buttonPressed(0)))
{
- Uint16 targetX = x, targetY = y;
-
- if (player_node->getDirection() & Being::UP)
- targetY--;
- if (player_node->getDirection() & Being::DOWN)
- targetY++;
- if (player_node->getDirection() & Being::LEFT)
- targetX--;
- if (player_node->getDirection() & Being::RIGHT)
- targetX++;
-
- // Attack priorioty is: Monster, Player, auto target
- target = beingManager->findBeing(
- targetX, targetY, Being::MONSTER);
- if (!target)
- target = beingManager->findBeing(
- targetX, targetY, Being::PLAYER);
- }
+ Being *target = beingManager->findNearestLivingBeing(x, y, 20, Being::MONSTER);
- player_node->attack(target, newTarget);
- }
+ bool newTarget = keyboard.isKeyActive(keyboard.KEY_TARGET);
+ // A set target has highest priority
+ if (newTarget || !player_node->getTarget())
+ {
+ Uint16 targetX = x, targetY = y;
- // Target the nearest player if 'q' is pressed
- if ( keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) )
- //if (keys[SDLK_q])
- {
- Being *target =
- beingManager->
- findNearestLivingBeing(player_node, 20, Being::PLAYER);
+ switch (player_node->getSpriteDirection())
+ {
+ case DIRECTION_UP : --targetY; break;
+ case DIRECTION_DOWN : ++targetY; break;
+ case DIRECTION_LEFT : --targetX; break;
+ case DIRECTION_RIGHT: ++targetX; break;
+ default: break;
+ }
- if (target)
- {
- player_node->setTarget(target);
- }
- }
+ // Attack priorioty is: Monster, Player, auto target
+ target = beingManager->findBeing(targetX, targetY, Being::MONSTER);
+ if (!target)
+ target = beingManager->findBeing(targetX, targetY, Being::PLAYER);
+ }
- // Target the nearest monster if 'a' pressed
- if ( keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) )
- //if (keys[SDLK_a])
- {
- Being *target =
- beingManager->findNearestLivingBeing(x, y, 20, Being::MONSTER);
+ player_node->attack(target, newTarget);
+ }
- if (target)
+ // Target the nearest player if 'q' is pressed
+ if ( keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) )
{
- player_node->setTarget(target);
+ Being *target = beingManager->findNearestLivingBeing(player_node, 20, Being::PLAYER);
+
+ if (target)
+ {
+ player_node->setTarget(target);
+ }
}
- }
- if (joystick)
- {
- if (joystick->buttonPressed(1))
+ // Target the nearest monster if 'a' pressed
+ if ( keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) )
{
- FloorItem *item = floorItemManager->findByCoordinates(x, y);
+ Being *target = beingManager->findNearestLivingBeing(x, y, 20, Being::MONSTER);
- if (item)
- player_node->pickUp(item);
+ if (target)
+ {
+ player_node->setTarget(target);
+ }
}
- else if (joystick->buttonPressed(2))
+
+ if (joystick)
{
- player_node->toggleSit();
+ if (joystick->buttonPressed(1))
+ {
+ FloorItem *item = floorItemManager->findByCoordinates(x, y);
+
+ if (item)
+ player_node->pickUp(item);
+ }
+ else if (joystick->buttonPressed(2))
+ {
+ player_node->toggleSit();
+ }
}
}
- }
}
diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp
index 9c562b68..8ec3bfd8 100644
--- a/src/gui/setup.cpp
+++ b/src/gui/setup.cpp
@@ -102,7 +102,7 @@ Setup::Setup():
Setup::~Setup()
{
- for_each(mTabs.begin(), mTabs.end(), make_dtor(mTabs));
+ delete_all(mTabs);
}
void Setup::action(const gcn::ActionEvent &event)
diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp
index 0e85138c..dd56ee2f 100644
--- a/src/gui/setup_video.cpp
+++ b/src/gui/setup_video.cpp
@@ -280,15 +280,17 @@ void Setup_Video::apply()
bool fullscreen = mFsCheckBox->isSelected();
if (fullscreen != (config.getValue("screen", 0) == 1))
{
+
+ /* Commented out the openGL test because
+ * the fullscreen mode change works fine, but
+ * will need to test it on windows so not
+ * deleting entirely until then --kraant*/
- /*Commented out the openGL test because
- * the fullscreen mode change works fine, but
- * will need to test it on windows so not
- * deleting entirely until then --kraant*/
-
+#ifdef WIN32
// checks for opengl usage
- /*if (!(config.getValue("opengl", 0) == 1))
- {*/
+ if (!(config.getValue("opengl", 0) == 1))
+ {
+#endif
if (!graphics->setFullscreen(fullscreen))
{
fullscreen = !fullscreen;
@@ -302,10 +304,12 @@ void Setup_Video::apply()
logger->error(error.str());
}
}
- /*} else {
+#ifdef WIN32
+ } else {
new OkDialog("Switching to full screen",
"Restart needed for changes to take effect.");
- }*/
+ }
+#endif
config.setValue("screen", fullscreen ? 1 : 0);
}
diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp
index 015e70d5..e7619547 100644
--- a/src/gui/shop.cpp
+++ b/src/gui/shop.cpp
@@ -25,8 +25,6 @@
#include "../utils/dtor.h"
-#include <algorithm>
-
ShopItems::~ShopItems()
{
clear();
@@ -61,7 +59,7 @@ ShopItem* ShopItems::at(int i) const
void ShopItems::clear()
{
- std::for_each(mShopItems.begin(), mShopItems.end(), make_dtor(mShopItems));
+ delete_all(mShopItems);
mShopItems.clear();
}
diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp
index e70fb3ef..8cf1e06d 100644
--- a/src/gui/skill.cpp
+++ b/src/gui/skill.cpp
@@ -21,8 +21,6 @@
* $Id: skill.cpp 3754 2007-11-20 15:19:50Z b_lindeijer $
*/
-#include <algorithm>
-
#include <guichan/widgets/label.hpp>
#include "skill.h"
@@ -186,6 +184,6 @@ void SkillDialog::setSkill(int id, int lvl, int mp)
void SkillDialog::cleanList()
{
- for_each(mSkillList.begin(), mSkillList.end(), make_dtor(mSkillList));
+ delete_all(mSkillList);
mSkillList.clear();
}
diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp
index 743d88b6..4976549f 100644
--- a/src/gui/textbox.cpp
+++ b/src/gui/textbox.cpp
@@ -60,6 +60,8 @@ void TextBox::setTextWrapped(const std::string &text)
text.substr(lastNewlinePos, newlinePos - lastNewlinePos);
std::string::size_type spacePos, lastSpacePos = 0;
int xpos = 0;
+ mMinWidth = getWidth();
+ bool longWord = false;
do
{
@@ -75,22 +77,28 @@ void TextBox::setTextWrapped(const std::string &text)
int width = getFont()->getWidth(word);
- if (xpos != 0 && xpos + width < getWidth())
+ if (xpos != 0 && xpos + width + getFont()->getWidth(" ") < getWidth())
{
xpos += width + getFont()->getWidth(" ");
wrappedStream << " " << word;
}
else if (lastSpacePos == 0)
{
+ if (xpos > mMinWidth)
+ {
+ longWord = true;
+ mMinWidth = xpos;
+ }
xpos += width;
wrappedStream << word;
}
else
{
+ if ((xpos < mMinWidth) && !longWord && spacePos != line.size())
+ mMinWidth = xpos;
xpos = width;
wrappedStream << "\n" << word;
}
-
lastSpacePos = spacePos + 1;
}
while (spacePos != line.size());
diff --git a/src/gui/textbox.h b/src/gui/textbox.h
index 7df30fd9..09819360 100644
--- a/src/gui/textbox.h
+++ b/src/gui/textbox.h
@@ -44,6 +44,19 @@ class TextBox : public gcn::TextBox {
* Sets the text after wrapping it to the current width of the widget.
*/
void setTextWrapped(const std::string &text);
+
+ /**
+ * Get the minimum text width for the text box.
+ */
+ int getMinWidth() { return mMinWidth; }
+
+ /**
+ * Set the minimum text width for the text box.
+ */
+ void setMinWidth(int width) { mMinWidth = width; }
+
+ private:
+ int mMinWidth;
};
#endif
diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp
index 22e361c5..b052e4b6 100644
--- a/src/gui/updatewindow.cpp
+++ b/src/gui/updatewindow.cpp
@@ -115,7 +115,7 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost,
mBrowserBox = new BrowserBox();
mScrollArea = new ScrollArea(mBrowserBox);
mLabel = new gcn::Label("Connecting...");
- mProgressBar = new ProgressBar(0.0, w - 10, 20, 37, 70, 200);
+ mProgressBar = new ProgressBar(0.0, w - 10, 20, 168, 116, 31);
mCancelButton = new Button("Cancel", "cancel", this);
mPlayButton = new Button("Play", "play", this);
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index 568c1ea3..95e0d2b6 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -33,6 +33,7 @@
#include "../configuration.h"
#include "../flooritemmanager.h"
#include "../graphics.h"
+#include "../keyboardconfig.h"
#include "../localplayer.h"
#include "../map.h"
#include "../monster.h"
@@ -49,6 +50,8 @@
#include <cassert>
+extern volatile int tick_time;
+
Viewport::Viewport():
mMap(0),
mPixelViewX(0.0f),
@@ -112,7 +115,8 @@ Viewport::loadTargetCursor(std::string filename, int width, int height,
mOutRangeImages[size] = currentImageSet;
mTargetCursorOutRange[size] = currentCursor;
}
- else {
+ else
+ {
mInRangeImages[size] = currentImageSet;
mTargetCursorInRange[size] = currentCursor;
}
@@ -223,52 +227,46 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
// Draw tiles and sprites
if (mMap)
{
- mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY, 0);
- drawTargetCursor(graphics);
- mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY, 1);
- mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY, 2);
- mMap->drawOverlay(graphics, mPixelViewX, mPixelViewY,
- (int) config.getValue("OverlayDetail", 2));
- }
+ mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY);
+ drawTargetCursor(graphics); // TODO: Draw the cursor with the sprite
- // Find a path from the player to the mouse, and draw it. This is for debug
- // purposes.
- if (mShowDebugPath && mMap)
- {
- // Get the current mouse position
- int mouseX, mouseY;
- SDL_GetMouseState(&mouseX, &mouseY);
- int mouseTileX = mouseX / 32 + mTileViewX;
- int mouseTileY = mouseY / 32 + mTileViewY;
+ // Find a path from the player to the mouse, and draw it. This is for debug
+ // purposes.
+ if (mShowDebugPath)
+ {
+ // Get the current mouse position
+ int mouseX, mouseY;
+ SDL_GetMouseState(&mouseX, &mouseY);
- Path debugPath = mMap->findPath(
- player_node->mX, player_node->mY,
- mouseTileX, mouseTileY);
+ int mouseTileX = mouseX / 32 + mTileViewX;
+ int mouseTileY = mouseY / 32 + mTileViewY;
- graphics->setColor(gcn::Color(255, 0, 0));
- for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++)
- {
- int squareX = i->x * 32 - (int) mPixelViewX + 12;
- int squareY = i->y * 32 - (int) mPixelViewY + 12;
+ Path debugPath = mMap->findPath(player_node->mX, player_node->mY, mouseTileX, mouseTileY);
- graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
- graphics->drawText(
- toString(mMap->getMetaTile(i->x, i->y)->Gcost),
- squareX + 4, squareY + 12, gcn::Graphics::CENTER);
+ graphics->setColor(gcn::Color(255, 0, 0));
+ for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++)
+ {
+ int squareX = i->x * 32 - (int) mPixelViewX + 12;
+ int squareY = i->y * 32 - (int) mPixelViewY + 12;
+
+ graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
+ graphics->drawText(toString(mMap->getMetaTile(i->x, i->y)->Gcost), squareX + 4, squareY + 12, gcn::Graphics::CENTER);
+ }
}
}
- // Draw text
+ // Draw names
if (textManager)
{
textManager->draw(graphics, mPixelViewX, mPixelViewY);
}
- // Draw player nickname, speech, and emotion sprite as needed
+ // Draw player speech, and emotion sprite as needed
Beings &beings = beingManager->getAll();
for (BeingIterator i = beings.begin(); i != beings.end(); i++)
{
+ (*i)->drawSpeech(graphics, -(int) mPixelViewX, -(int) mPixelViewY);
(*i)->drawEmotion(graphics, -(int) mPixelViewX, -(int) mPixelViewY);
}
@@ -276,8 +274,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
WindowContainer::draw(gcnGraphics);
}
-void
-Viewport::logic()
+void Viewport::logic()
{
WindowContainer::logic();
@@ -295,15 +292,14 @@ Viewport::logic()
mWalkTime = player_node->mWalkTime;
}
- for (int i = 0; i < 3; i++)
+ for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++)
{
mTargetCursorInRange[i]->update(10);
mTargetCursorOutRange[i]->update(10);
}
}
-void
-Viewport::drawTargetCursor(Graphics *graphics)
+void Viewport::drawTargetCursor(Graphics *graphics)
{
// Draw target marker if needed
Being *target = player_node->getTarget();
@@ -323,7 +319,8 @@ Viewport::drawTargetCursor(Graphics *graphics)
{
targetCursor = mTargetCursorOutRange[cursorSize]->getCurrentImage();
}
- else {
+ else
+ {
targetCursor = mTargetCursorInRange[cursorSize]->getCurrentImage();
}
@@ -332,11 +329,10 @@ Viewport::drawTargetCursor(Graphics *graphics)
int posY = target->getPixelY() + 16 - targetCursor->getHeight() / 2 - (int) mPixelViewY;
graphics->drawImage(targetCursor, posX, posY);
- }
+ }
}
-void
-Viewport::mousePressed(gcn::MouseEvent &event)
+void Viewport::mousePressed(gcn::MouseEvent &event)
{
// Check if we are alive and kickin'
if (!mMap || !player_node || player_node->mAction == Being::DEAD)
@@ -348,8 +344,10 @@ Viewport::mousePressed(gcn::MouseEvent &event)
mPlayerFollowMouse = false;
- int tilex = event.getX() / 32 + mTileViewX;
- int tiley = event.getY() / 32 + mTileViewY;
+ const int tilex = event.getX() / 32 + mTileViewX;
+ const int tiley = event.getY() / 32 + mTileViewY;
+ const int x = (int)((float) event.getX() + mPixelViewX);
+ const int y = (int)((float) event.getY() + mPixelViewY);
// Right click might open a popup
if (event.getButton() == gcn::MouseEvent::RIGHT)
@@ -357,11 +355,11 @@ Viewport::mousePressed(gcn::MouseEvent &event)
Being *being;
FloorItem *floorItem;
- if ((being = beingManager->findBeing(tilex, tiley)) &&
- being != player_node)
+ if ((being = beingManager->findBeingByPixel(x, y)) &&
+ being != player_node)
{
- mPopupMenu->showPopup(event.getX(), event.getY(), being);
- return;
+ mPopupMenu->showPopup(event.getX(), event.getY(), being);
+ return;
}
else if((floorItem = floorItemManager->findByCoordinates(tilex, tiley)))
{
@@ -382,12 +380,10 @@ Viewport::mousePressed(gcn::MouseEvent &event)
{
Being *being;
FloorItem *item;
-
+
// Interact with some being
-// int x = (int)((float) event.getX() + mPixelViewX);
-// int y = (int)((float) event.getY() + mPixelViewY);
-// if ((being = beingManager->findBeingByPixel(x, y)))
- if ((being = beingManager->findBeing(tilex, tiley)))
+// if ((being = beingManager->findBeing(tilex, tiley)))
+ if ((being = beingManager->findBeingByPixel(x, y)))
{
switch (being->getType())
{
@@ -400,59 +396,49 @@ Viewport::mousePressed(gcn::MouseEvent &event)
if (being->mAction == Being::DEAD)
break;
- if (player_node->withinAttackRange(being))
+ if (keyboard.isKeyActive(keyboard.KEY_TARGET) || player_node->withinAttackRange(being))
{
+ player_node->stopAttack();
+ player_node->setGotoTarget(being);
player_node->attack(being, true);
}
else
{
- Uint8 *keys = SDL_GetKeyState(NULL);
- if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]))
- {
- player_node->stopAttack();
- player_node->setGotoTarget(being);
- }
+ player_node->setDestination(tilex, tiley);
+ player_node->stopAttack();
}
break;
default:
break;
- }
+ }
}
// Pick up some item
else if ((item = floorItemManager->findByCoordinates(tilex, tiley)))
{
- player_node->pickUp(item);
+ player_node->pickUp(item);
}
// Just walk around
else
{
- // XXX XXX XXX REALLY UGLY!
- Uint8 *keys = SDL_GetKeyState(NULL);
- if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]))
- {
- player_node->setDestination(tilex, tiley);
- player_node->stopAttack();
- }
+ player_node->stopAttack();
+ player_node->setDestination(tilex, tiley);
mPlayerFollowMouse = true;
}
}
else if (event.getButton() == gcn::MouseEvent::MIDDLE)
{
// Find the being nearest to the clicked position
- Being *target = beingManager->findNearestLivingBeing(
- tilex, tiley,
- 20, Being::MONSTER);
-
+ Being *target = beingManager->findBeingByPixel(x, y);
+
if (target)
{
- player_node->setTarget(target);
+ player_node->setTarget(target);
}
}
}
-void
-Viewport::mouseDragged(gcn::MouseEvent &event)
+void Viewport::mouseDragged(gcn::MouseEvent &event)
{
if (!mMap || !player_node)
return;
@@ -465,20 +451,17 @@ Viewport::mouseDragged(gcn::MouseEvent &event)
}
}
-void
-Viewport::mouseReleased(gcn::MouseEvent &event)
+void Viewport::mouseReleased(gcn::MouseEvent &event)
{
mPlayerFollowMouse = false;
}
-void
-Viewport::showPopup(int x, int y, Item *item)
+void Viewport::showPopup(int x, int y, Item *item)
{
mPopupMenu->showPopup(x, y, item);
}
-void
-Viewport::optionChanged(const std::string &name)
+void Viewport::optionChanged(const std::string &name)
{
mScrollLaziness = (int) config.getValue("ScrollLaziness", 32);
mScrollRadius = (int) config.getValue("ScrollRadius", 32);
diff --git a/src/gui/viewport.h b/src/gui/viewport.h
index 44a877a6..325a7221 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: viewport.h 4247 2008-05-19 10:48:18Z b_lindeijer $
+ * $Id$
*/
#ifndef _TMW_VIEWPORT_H_
@@ -117,16 +117,16 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
optionChanged(const std::string &name);
/**
- * Returns camera x offset in tiles.
+ * Returns camera x offset in pixels.
*/
int
- getCameraX() { return mTileViewX; }
+ getCameraX() const { return (int) mPixelViewX; }
/**
- * Returns camera y offset in tiles.
+ * Returns camera y offset in pixels.
*/
int
- getCameraY() { return mTileViewY; }
+ getCameraY() const { return (int) mPixelViewY; }
/**
* Changes viewpoint by relative pixel coordinates.
@@ -138,22 +138,13 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
/**
* Helper function for loading target cursors
*/
- void
- loadTargetCursor(std::string filename, int width, int height,
- bool outRange, Being::TargetCursorSize size);
+ void loadTargetCursor(std::string filename, int width, int height,
+ bool outRange, Being::TargetCursorSize size);
/**
* Draws range based target cursor
*/
- void
- drawTargetCursor(Graphics *graphics);
-
- /**
- * Draws target name
- */
- void
- drawTargetName(Graphics *graphics);
-
+ void drawTargetCursor(Graphics *graphics);
Map *mMap; /**< The current map. */
diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp
index b33a55cf..9bf7452d 100644
--- a/src/gui/widgets/dropdown.cpp
+++ b/src/gui/widgets/dropdown.cpp
@@ -165,5 +165,5 @@ void DropDown::drawButton(gcn::Graphics *graphics)
int height = mDroppedDown ? mFoldedUpHeight : getHeight();
static_cast<Graphics*>(graphics)->
- drawImage(buttons[mDroppedDown][mPushed], getWidth() - height, 1);
+ drawImage(buttons[mDroppedDown][mPushed], getWidth() - height + 2, 1);
}
diff --git a/src/gui/window.cpp b/src/gui/window.cpp
index 55dac5e0..1a6f1ac6 100644
--- a/src/gui/window.cpp
+++ b/src/gui/window.cpp
@@ -18,11 +18,12 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: window.cpp 4207 2008-04-29 09:10:43Z b_lindeijer $
+ * $Id$
*/
#include <algorithm>
#include <climits>
+#include <cassert>
#include <guichan/exception.hpp>
#include <guichan/widgets/icon.hpp>
@@ -43,24 +44,28 @@
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
+#include "../utils/xml.h"
+
ConfigListener *Window::windowConfigListener = 0;
WindowContainer *Window::windowContainer = 0;
int Window::instances = 0;
int Window::mouseResize = 0;
ImageRect Window::border;
Image *Window::closeImage = NULL;
+bool Window::mAlphaChanged = false;
class WindowConfigListener : public ConfigListener
{
void optionChanged(const std::string &)
{
+ Window::mAlphaChanged = true;
for_each(Window::border.grid, Window::border.grid + 9,
std::bind2nd(std::mem_fun(&Image::setAlpha),
config.getValue("guialpha", 0.8)));
}
};
-Window::Window(const std::string& caption, bool modal, Window *parent):
+Window::Window(const std::string& caption, bool modal, Window *parent, const std::string& skin):
gcn::Window(caption),
mGrip(0),
mParent(parent),
@@ -72,7 +77,8 @@ Window::Window(const std::string& caption, bool modal, Window *parent):
mMinWinWidth(100),
mMinWinHeight(40),
mMaxWinWidth(INT_MAX),
- mMaxWinHeight(INT_MAX)
+ mMaxWinHeight(INT_MAX),
+ mSkin(skin)
{
logger->log("Window::Window(\"%s\")", caption.c_str());
@@ -80,23 +86,13 @@ Window::Window(const std::string& caption, bool modal, Window *parent):
throw GCN_EXCEPTION("Window::Window. no windowContainer set");
}
+ // Loads the skin
+ loadSkin(mSkin);
+
+ setGuiAlpha();
+
if (instances == 0)
{
- // Load static resources
- ResourceManager *resman = ResourceManager::getInstance();
- Image *dBorders = resman->getImage("graphics/gui/vscroll_grey.png");
- border.grid[0] = dBorders->getSubImage(0, 0, 4, 4);
- border.grid[1] = dBorders->getSubImage(4, 0, 3, 4);
- border.grid[2] = dBorders->getSubImage(7, 0, 4, 4);
- border.grid[3] = dBorders->getSubImage(0, 4, 4, 10);
- border.grid[4] = resman->getImage("graphics/gui/bg_quad_dis.png");
- border.grid[5] = dBorders->getSubImage(7, 4, 4, 10);
- border.grid[6] = dBorders->getSubImage(0, 15, 4, 4);
- border.grid[7] = dBorders->getSubImage(4, 15, 3, 4);
- border.grid[8] = dBorders->getSubImage(7, 15, 4, 4);
- dBorders->decRef();
- closeImage = resman->getImage("graphics/gui/close_button.png");
-
windowConfigListener = new WindowConfigListener();
// Send GUI alpha changed for initialization
windowConfigListener->optionChanged("guialpha");
@@ -135,14 +131,15 @@ Window::~Window()
const std::string &name = mWindowName;
// Saving X, Y and Width and Height for resizables in the config
- config.setValue(name + "WinX", getX());
- config.setValue(name + "WinY", getY());
- config.setValue(name + "Visible", isVisible());
-
- if (mGrip)
- {
- config.setValue(name + "WinWidth", getWidth());
- config.setValue(name + "WinHeight", getHeight());
+ if (!name.empty()) {
+ config.setValue(name + "WinX", getX());
+ config.setValue(name + "WinY", getY());
+ config.setValue(name + "Visible", isVisible());
+
+ if (mGrip) {
+ config.setValue(name + "WinWidth", getWidth());
+ config.setValue(name + "WinHeight", getHeight());
+ }
}
instances--;
@@ -154,15 +151,11 @@ Window::~Window()
windowConfigListener = NULL;
// Clean up static resources
- delete border.grid[0];
- delete border.grid[1];
- delete border.grid[2];
- delete border.grid[3];
- border.grid[4]->decRef();
- delete border.grid[5];
- delete border.grid[6];
- delete border.grid[7];
- delete border.grid[8];
+ for( int i = 0; i < 9; i++ )
+ {
+ delete border.grid[i];
+ border.grid[i] = NULL;
+ }
closeImage->decRef();
}
@@ -474,6 +467,7 @@ void
Window::loadWindowState()
{
const std::string &name = mWindowName;
+ assert(!name.empty());
setPosition((int) config.getValue(name + "WinX", mDefaultX),
(int) config.getValue(name + "WinY", mDefaultY));
@@ -536,3 +530,185 @@ int Window::getResizeHandles(gcn::MouseEvent &event)
return resizeHandles;
}
+
+void Window::setGuiAlpha()
+{
+ //logger->log("Window::setGuiAlpha: Alpha Value %f", config.getValue("guialpha", 0.8));
+ for(int i = 0; i < 9; i++)
+ {
+ //logger->log("Window::setGuiAlpha: Border Image (%i)", i);
+ border.grid[i]->setAlpha(config.getValue("guialpha", 0.8));
+ }
+
+ mAlphaChanged = false;
+}
+
+void Window::loadSkin(const std::string filename)
+{
+ const std::string windowId = Window::getId();
+
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ logger->log("Loading Window Skin '%s'.", filename.c_str());
+ logger->log("Loading Window ID '%s'.", windowId.c_str());
+
+
+ if(filename == "")
+ logger->error("Window::loadSkin(): Invalid File Name.");
+
+ // TODO:
+ // If there is an error loading the specified file, we should try to revert
+ // to a 'default' skin file. Only if the 'default' skin file can't be loaded
+ // should we have a terminating error.
+ XML::Document doc(filename);
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "skinset"))
+ {
+ logger->error("Widget Skinning error");
+ }
+
+ std::string skinSetImage;
+ skinSetImage = XML::getProperty(rootNode, "image", "");
+ Image *dBorders = NULL;
+ if(skinSetImage != "")
+ {
+ logger->log("Window::loadSkin(): <skinset> defines '%s' as a skin image.", skinSetImage.c_str());
+ dBorders = resman->getImage("graphics/gui/" + skinSetImage);//"graphics/gui/speech_bubble.png");
+ }
+ else
+ {
+ logger->error("Window::loadSkin(): Skinset does not define an image!");
+ }
+
+ //iterate <widget>'s
+ for_each_xml_child_node(widgetNode, rootNode)
+ {
+ if (!xmlStrEqual(widgetNode->name, BAD_CAST "widget"))
+ continue;
+
+ std::string widgetType;
+ widgetType = XML::getProperty(widgetNode, "type", "unknown");
+ if (widgetType == "Window")
+ {
+ // Iterate through <part>'s
+ // LEEOR / TODO:
+ // We need to make provisions to load in a CloseButton image. For now it
+ // can just be hard-coded.
+ for_each_xml_child_node(partNode, widgetNode)
+ {
+ if (!xmlStrEqual(partNode->name, BAD_CAST "part"))
+ {
+ continue;
+ }
+
+ std::string partType;
+ partType = XML::getProperty(partNode, "type", "unknown");
+ // TOP ROW
+ if(partType == "top-left-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[0] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "top-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[1] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "top-right-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[2] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+
+ // MIDDLE ROW
+ else if(partType == "left-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[3] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "bg-quad")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[4] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "right-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[5] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+
+ // BOTTOM ROW
+ else if(partType == "bottom-left-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[6] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "bottom-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[7] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "bottom-right-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[8] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+
+ // Part is of an uknown type.
+ else
+ {
+ logger->log("Window::loadSkin(): Unknown Part Type '%s'", partType.c_str());
+ }
+ }
+ }
+ // Widget is of an uknown type.
+ else
+ {
+ logger->log("Window::loadSkin(): Unknown Widget Type '%s'", widgetType.c_str());
+ }
+ }
+ dBorders->decRef();
+
+ logger->log("Finished loading Window Skin.");
+
+ // Hard-coded for now until we update the above code to look for window buttons.
+ closeImage = resman->getImage("graphics/gui/close_button.png");
+}
+
diff --git a/src/gui/window.h b/src/gui/window.h
index 8f288991..228cc37b 100644
--- a/src/gui/window.h
+++ b/src/gui/window.h
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: window.h 4207 2008-04-29 09:10:43Z b_lindeijer $
+ * $Id$
*/
#ifndef _TMW_WINDOW_H__
@@ -56,9 +56,10 @@ class Window : public gcn::Window, gcn::WidgetListener
* @param parent The parent window. This is the window standing above
* this one in the window hiearchy. When reordering,
* a window will never go below its parent window.
+ * @param skin The location where the window's skin XML can be found.
*/
Window(const std::string &caption = "Window", bool modal = false,
- Window *parent = NULL);
+ Window *parent = NULL, const std::string &skin = "graphics/gui/gui.xml");
/**
* Destructor.
@@ -237,6 +238,11 @@ class Window : public gcn::Window, gcn::WidgetListener
*/
virtual void resetToDefaultSize();
+ /**
+ * Loads a window skin
+ */
+ void loadSkin(const std::string filename);
+
enum ResizeHandles
{
TOP = 0x01,
@@ -255,6 +261,8 @@ class Window : public gcn::Window, gcn::WidgetListener
*/
int getResizeHandles(gcn::MouseEvent &event);
+ void setGuiAlpha();
+
GCContainer *mChrome; /**< Contained container */
ResizeGrip *mGrip; /**< Resize grip */
Window *mParent; /**< The parent window */
@@ -263,6 +271,7 @@ class Window : public gcn::Window, gcn::WidgetListener
bool mModal; /**< Window is modal */
bool mCloseButton; /**< Window has a close button */
bool mSticky; /**< Window resists minimization */
+ static bool mAlphaChanged; /**< Whether the alpha percent was changed */
int mMinWinWidth; /**< Minimum window width */
int mMinWinHeight; /**< Minimum window height */
int mMaxWinWidth; /**< Maximum window width */
@@ -271,6 +280,7 @@ class Window : public gcn::Window, gcn::WidgetListener
int mDefaultY; /**< Default window Y position */
int mDefaultWidth; /**< Default window width */
int mDefaultHeight; /**< Default window height */
+ std::string mSkin; /**< Name of the skin to use */
/** The window container windows add themselves to. */
static WindowContainer *windowContainer;
diff --git a/src/gui/windowcontainer.cpp b/src/gui/windowcontainer.cpp
index 0a0a0a55..05c2b5e9 100644
--- a/src/gui/windowcontainer.cpp
+++ b/src/gui/windowcontainer.cpp
@@ -21,15 +21,13 @@
* $Id: windowcontainer.cpp 3754 2007-11-20 15:19:50Z b_lindeijer $
*/
-#include <algorithm>
-
#include "windowcontainer.h"
#include "../utils/dtor.h"
void WindowContainer::logic()
{
- for_each(mDeathList.begin(), mDeathList.end(), make_dtor(mDeathList));
+ delete_all(mDeathList);
mDeathList.clear();
gcn::Container::logic();
diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp
index d4ff8f02..965434b0 100644
--- a/src/imageparticle.cpp
+++ b/src/imageparticle.cpp
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: imageparticle.cpp 4360 2008-06-23 14:44:20Z crush_tmw $
+ * $Id$
*/
#include "imageparticle.h"
diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp
index 5534b96e..9f558883 100644
--- a/src/keyboardconfig.cpp
+++ b/src/keyboardconfig.cpp
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: keyboardconfig.cpp 4255 2008-05-21 21:44:27Z crush_tmw $
+ * $Id$
*/
#include "keyboardconfig.h"
@@ -43,6 +43,7 @@ static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = {
{"keyMoveLeft", SDLK_LEFT, "Move Left"},
{"keyMoveRight", SDLK_RIGHT, "Move Right"},
{"keyAttack", SDLK_LCTRL, "Attack"},
+ {"keySmilie", SDLK_LALT, "Smilie"},
{"keyTarget", SDLK_LSHIFT, "Target"},
{"keyTargetClosest", SDLK_a, "Target Closest"},
{"keyTargetPlayer", SDLK_q, "Target Player"},
diff --git a/src/keyboardconfig.h b/src/keyboardconfig.h
index b98fcb7a..b57136dc 100644
--- a/src/keyboardconfig.h
+++ b/src/keyboardconfig.h
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: keyboardconfig.h 4255 2008-05-21 21:44:27Z crush_tmw $
+ * $Id$
*/
#ifndef _TMW_KEYBOARDCONFIG_H
@@ -151,6 +151,7 @@ class KeyboardConfig
KEY_MOVE_LEFT,
KEY_MOVE_RIGHT,
KEY_ATTACK,
+ KEY_SMILIE,
KEY_TARGET,
KEY_TARGET_CLOSEST,
KEY_TARGET_PLAYER,
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 554c52a6..66d37ddf 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: localplayer.cpp 4347 2008-06-12 09:06:01Z b_lindeijer $
+ * $Id$
*/
#include "localplayer.h"
@@ -48,8 +48,8 @@ LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map):
mAttackRange(0),
mXp(0), mNetwork(0),
mTarget(NULL), mPickUpTarget(NULL),
- mTrading(false), mInStorage(false),
- mGoingToTarget(false), mLastAction(-1),
+ mTrading(false), mGoingToTarget(false),
+ mLastAction(-1),
mWalkingDir(0), mDestX(0), mDestY(0),
mInventory(new Inventory(INVENTORY_SIZE)),
mStorage(new Inventory(STORAGE_SIZE))
@@ -65,6 +65,18 @@ LocalPlayer::~LocalPlayer()
void LocalPlayer::logic()
{
switch (mAction) {
+ case STAND:
+ break;
+
+ case SIT:
+ break;
+
+ case DEAD:
+ break;
+
+ case HURT:
+ break;
+
case WALK:
mFrame = (get_elapsed_time(mWalkTime) * 6) / mWalkSpeed;
if (mFrame >= 6) {
@@ -144,6 +156,9 @@ void LocalPlayer::unequipItem(Item *item)
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_PLAYER_UNEQUIP);
outMsg.writeInt16(item->getInvIndex());
+
+ // Tidy equipment directly to avoid weapon still shown bug, for instance
+ mEquipment->removeEquipment(item);
}
void LocalPlayer::useItem(Item *item)
@@ -183,7 +198,6 @@ void LocalPlayer::pickUp(FloorItem *item)
void LocalPlayer::walk(unsigned char dir)
{
-
if (!mMap || !dir)
return;
diff --git a/src/localplayer.h b/src/localplayer.h
index 1d865824..757c70eb 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: localplayer.h 4347 2008-06-12 09:06:01Z b_lindeijer $
+ * $Id$
*/
#ifndef _TMW_LOCALPLAYER_H
diff --git a/src/map.cpp b/src/map.cpp
index d9d3a319..ef622ad0 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -23,10 +23,11 @@
#include "map.h"
-#include <algorithm>
#include <queue>
+#include <cassert>
#include "beingmanager.h"
+#include "configuration.h"
#include "game.h"
#include "graphics.h"
#include "particle.h"
@@ -40,6 +41,8 @@
#include "utils/dtor.h"
#include "utils/tostring.h"
+extern volatile int tick_time;
+
/**
* A location on a tile map. Used for pathfinding, open list.
*/
@@ -62,6 +65,80 @@ struct Location
MetaTile *tile;
};
+MapLayer::MapLayer(int x, int y, int width, int height, bool isFringeLayer):
+ mX(x), mY(y),
+ mWidth(width), mHeight(height),
+ mIsFringeLayer(isFringeLayer)
+{
+ const int size = mWidth * mHeight;
+ mTiles = new Image*[size];
+ std::fill_n(mTiles, size, (Image*) 0);
+}
+
+MapLayer::~MapLayer()
+{
+ delete[] mTiles;
+}
+
+void MapLayer::setTile(int x, int y, Image *img)
+{
+ mTiles[x + y * mWidth] = img;
+}
+
+Image* MapLayer::getTile(int x, int y) const
+{
+ return mTiles[x + y * mWidth];
+}
+
+void MapLayer::draw(Graphics *graphics,
+ int startX, int startY,
+ int endX, int endY,
+ int scrollX, int scrollY,
+ const Sprites &sprites) const
+{
+ startX -= mX;
+ startY -= mY;
+ endX -= mX;
+ endY -= mY;
+
+ if (startX < 0) startX = 0;
+ if (startY < 0) startY = 0;
+ if (endX > mWidth) endX = mWidth;
+ if (endY > mHeight) endY = mHeight;
+
+ Sprites::const_iterator si = sprites.begin();
+
+ for (int y = startY; y < endY; y++)
+ {
+ // If drawing the fringe layer, make sure all sprites above this row of
+ // tiles have been drawn
+ if (mIsFringeLayer) {
+ while (si != sprites.end() && (*si)->getPixelY() <= y * 32 - 32) {
+ (*si)->draw(graphics, -scrollX, -scrollY);
+ si++;
+ }
+ }
+
+ for (int x = startX; x < endX; x++)
+ {
+ Image *img = getTile(x, y);
+ if (img) {
+ const int px = (x + mX) * 32 - scrollX;
+ const int py = (y + mY) * 32 - scrollY + 32 - img->getHeight();
+ graphics->drawImage(img, px, py);
+ }
+ }
+ }
+
+ // Draw any remaining sprites
+ if (mIsFringeLayer) {
+ while (si != sprites.end()) {
+ (*si)->draw(graphics, -scrollX, -scrollY);
+ si++;
+ }
+ }
+}
+
Map::Map(int width, int height, int tileWidth, int tileHeight):
mWidth(width), mHeight(height),
mTileWidth(tileWidth), mTileHeight(tileHeight),
@@ -69,23 +146,18 @@ Map::Map(int width, int height, int tileWidth, int tileHeight):
mOnClosedList(1), mOnOpenList(2),
mLastScrollX(0.0f), mLastScrollY(0.0f)
{
- int size = mWidth * mHeight;
+ const int size = mWidth * mHeight;
mMetaTiles = new MetaTile[size];
- mTiles = new Image*[size * 3];
- std::fill_n(mTiles, size * 3, (Image*)0);
}
Map::~Map()
{
- // clean up map data
+ // delete metadata, layers, tilesets and overlays
delete[] mMetaTiles;
- delete[] mTiles;
- // clean up tilesets
- for_each(mTilesets.begin(), mTilesets.end(), make_dtor(mTilesets));
- mTilesets.clear();
- // clean up overlays
- for_each(mOverlays.begin(), mOverlays.end(), make_dtor(mOverlays));
+ delete_all(mLayers);
+ delete_all(mTilesets);
+ delete_all(mOverlays);
}
void Map::initializeOverlays()
@@ -99,9 +171,9 @@ void Map::initializeOverlays()
const std::string name = "overlay" + toString(i);
Image *img = resman->getImage(getProperty(name + "image"));
- float speedX = getFloatProperty(name + "scrollX");
- float speedY = getFloatProperty(name + "scrollY");
- float parallax = getFloatProperty(name + "parallax");
+ const float speedX = getFloatProperty(name + "scrollX");
+ const float speedY = getFloatProperty(name + "scrollY");
+ const float parallax = getFloatProperty(name + "parallax");
if (img)
{
@@ -114,6 +186,11 @@ void Map::initializeOverlays()
}
}
+void Map::addLayer(MapLayer *layer)
+{
+ mLayers.push_back(layer);
+}
+
void Map::addTileset(Tileset *tileset)
{
mTilesets.push_back(tileset);
@@ -127,63 +204,32 @@ bool spriteCompare(const Sprite *a, const Sprite *b)
return a->getPixelY() < b->getPixelY();
}
-void Map::draw(Graphics *graphics, int scrollX, int scrollY, int layer)
+void Map::draw(Graphics *graphics, int scrollX, int scrollY)
{
int endPixelY = graphics->getHeight() + scrollY + mTileHeight - 1;
- // If drawing the fringe layer, make sure sprites are sorted
- SpriteIterator si;
- if (layer == 1)
- {
- mSprites.sort(spriteCompare);
- si = mSprites.begin();
- endPixelY += mMaxTileHeight - mTileHeight;
- }
+ // TODO: Do this per-layer
+ endPixelY += mMaxTileHeight - mTileHeight;
int startX = scrollX / mTileWidth;
int startY = scrollY / mTileHeight;
int endX = (graphics->getWidth() + scrollX + mTileWidth - 1) / mTileWidth;
int endY = endPixelY / mTileHeight;
- if (startX < 0) startX = 0;
- if (startY < 0) startY = 0;
- if (endX > mWidth) endX = mWidth;
- if (endY > mHeight) endY = mHeight;
+ // Make sure sprites are sorted
+ mSprites.sort(spriteCompare);
- for (int y = startY; y < endY; y++)
+ Layers::const_iterator layeri = mLayers.begin();
+ for (; layeri != mLayers.end(); ++layeri)
{
- // If drawing the fringe layer, make sure all sprites above this row of
- // tiles have been drawn
- if (layer == 1)
- {
- while (si != mSprites.end() && (*si)->getPixelY() <= y * 32 - 32)
- {
- (*si)->draw(graphics, -scrollX, -scrollY);
- si++;
- }
- }
-
- for (int x = startX; x < endX; x++)
- {
- Image *img = getTile(x, y, layer);
- if (img) {
- graphics->drawImage(img,
- x * mTileWidth - scrollX,
- y * mTileHeight - scrollY +
- mTileHeight - img->getHeight());
- }
- }
+ (*layeri)->draw(graphics,
+ startX, startY, endX, endY,
+ scrollX, scrollY,
+ mSprites);
}
- // Draw any remaining sprites
- if (layer == 1)
- {
- while (si != mSprites.end())
- {
- (*si)->draw(graphics, -scrollX, -scrollY);
- si++;
- }
- }
+ drawOverlay(graphics, scrollX, scrollY,
+ (int) config.getValue("OverlayDetail", 2));
}
void Map::drawOverlay(Graphics *graphics,
@@ -226,23 +272,10 @@ void Map::drawOverlay(Graphics *graphics,
};
}
-void Map::setTileWithGid(int x, int y, int layer, int gid)
-{
- if (layer == 3)
- {
- Tileset *set = getTilesetWithGid(gid);
- setWalk(x, y, (!set || (gid - set->getFirstGid() == 0)));
- }
- else if (layer < 3)
- {
- setTile(x, y, layer, getTileWithGid(gid));
- }
-}
-
class ContainsGidFunctor
{
public:
- bool operator() (Tileset* set)
+ bool operator() (Tileset* set) const
{
return (set->getFirstGid() <= gid &&
gid - set->getFirstGid() < (int)set->size());
@@ -255,27 +288,16 @@ Tileset* Map::getTilesetWithGid(int gid) const
containsGid.gid = gid;
Tilesets::const_iterator i = find_if(mTilesets.begin(), mTilesets.end(),
- containsGid);
+ containsGid);
return (i == mTilesets.end()) ? NULL : *i;
}
-Image* Map::getTileWithGid(int gid) const
-{
- Tileset *set = getTilesetWithGid(gid);
-
- if (set) {
- return set->get(gid - set->getFirstGid());
- }
-
- return NULL;
-}
-
void Map::setWalk(int x, int y, bool walkable)
{
mMetaTiles[x + y * mWidth].walkable = walkable;
}
-
+
bool Map::occupied(int x, int y) const
{
Beings &beings = beingManager->getAll();
@@ -293,7 +315,7 @@ bool Map::occupied(int x, int y) const
bool Map::tileCollides(int x, int y) const
{
- return !(contains(x, y) && mMetaTiles[x + y * mWidth].walkable);
+ return !(contains(x, y) && mMetaTiles[x + y * mWidth].walkable);
}
bool Map::contains(int x, int y) const
@@ -301,16 +323,6 @@ bool Map::contains(int x, int y) const
return x >= 0 && y >= 0 && x < mWidth && y < mHeight;
}
-void Map::setTile(int x, int y, int layer, Image *img)
-{
- mTiles[x + y * mWidth + layer * (mWidth * mHeight)] = img;
-}
-
-Image* Map::getTile(int x, int y, int layer)
-{
- return mTiles[x + y * mWidth + layer * (mWidth * mHeight)];
-}
-
MetaTile* Map::getMetaTile(int x, int y)
{
return &mMetaTiles[x + y * mWidth];
@@ -327,6 +339,8 @@ void Map::removeSprite(SpriteIterator iterator)
mSprites.erase(iterator);
}
+static int const basicCost = 100;
+
Path Map::findPath(int startX, int startY, int destX, int destY)
{
// Path to be built up (empty by default)
@@ -367,8 +381,8 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
for (int dx = -1; dx <= 1; dx++)
{
// Calculate location of tile to check
- int x = curr.x + dx;
- int y = curr.y + dy;
+ const int x = curr.x + dx;
+ const int y = curr.y + dy;
// Skip if if we're checking the same tile we're leaving from,
// or if the new location falls outside of the map boundaries
@@ -379,7 +393,8 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
MetaTile *newTile = getMetaTile(x, y);
- // Skip if the tile is on the closed list or collides unless its the destination tile
+ // Skip if the tile is on the closed list or collides unless
+ // its the destination tile
if (newTile->whichList == mOnClosedList ||
(tileCollides(x, y) && !(x == destX && y == destY)))
{
@@ -404,13 +419,6 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
// 14 for moving diagonal (sqrt(200) = 14.1421...)
int Gcost = curr.tile->Gcost + ((dx == 0 || dy == 0) ? 10 : 14);
- // It costs extra to walk through a being (needs to be enough
- // to make it more attractive to walk around).
- if (occupied(x, y))
- {
- Gcost += 30;
- }
-
// Skip if Gcost becomes too much
// Warning: probably not entirely accurate
if (Gcost > 200)
@@ -430,7 +438,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
// Update Gcost and Fcost of new tile
newTile->Gcost = Gcost;
- newTile->Fcost = newTile->Gcost + newTile->Hcost;
+ newTile->Fcost = Gcost + newTile->Hcost;
if (x != destX || y != destY) {
// Add this tile to the open list
@@ -447,7 +455,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
// Found a shorter route.
// Update Gcost and Fcost of the new tile
newTile->Gcost = Gcost;
- newTile->Fcost = newTile->Gcost + newTile->Hcost;
+ newTile->Fcost = Gcost + newTile->Hcost;
// Set the current tile as the parent of the new tile
newTile->parentX = curr.x;
@@ -488,7 +496,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
return path;
}
-void Map::addParticleEffect (std::string effectFile, int x, int y)
+void Map::addParticleEffect(const std::string &effectFile, int x, int y)
{
ParticleEffectData newEffect;
newEffect.file = effectFile;
diff --git a/src/map.h b/src/map.h
index 7695ba31..95532eb3 100644
--- a/src/map.h
+++ b/src/map.h
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: map.h 3887 2008-02-12 19:49:37Z umperio $
+ * $Id$
*/
#ifndef _TMW_MAP_H_
@@ -32,6 +32,7 @@
class AmbientOverlay;
class Graphics;
class Image;
+class MapLayer;
class Particle;
class Sprite;
class Tileset;
@@ -41,8 +42,7 @@ struct PATH_NODE;
typedef std::vector<Tileset*> Tilesets;
typedef std::list<Sprite*> Sprites;
typedef Sprites::iterator SpriteIterator;
-
-extern volatile int tick_time;
+typedef std::vector<MapLayer*> Layers;
/**
* A meta tile stores additional information about a location on a tile map.
@@ -67,6 +67,56 @@ struct MetaTile
};
/**
+ * A map layer. Stores a grid of tiles and their offset, and implements layer
+ * rendering.
+ */
+class MapLayer
+{
+ public:
+ /**
+ * Constructor, taking layer origin, size and whether this layer is the
+ * fringe layer. The fringe layer is the layer that draws the sprites.
+ * There can be only one fringe layer per map.
+ */
+ MapLayer(int x, int y, int width, int height, bool isFringeLayer);
+
+ /**
+ * Destructor.
+ */
+ ~MapLayer();
+
+ /**
+ * Set tile image, with x and y in layer coordinates.
+ */
+ void setTile(int x, int y, Image *img);
+
+ /**
+ * Get tile image, with x and y in layer coordinates.
+ */
+ Image *getTile(int x, int y) const;
+
+ /**
+ * Draws this layer to the given graphics context. The coordinates are
+ * expected to be in map range and will be translated to local layer
+ * coordinates and clipped to the layer's dimensions.
+ *
+ * The given sprites are only drawn when this layer is the fringe
+ * layer.
+ */
+ void draw(Graphics *graphics,
+ int startX, int startY,
+ int endX, int endY,
+ int scrollX, int scrollY,
+ const Sprites &sprites) const;
+
+ private:
+ int mX, mY;
+ int mWidth, mHeight;
+ bool mIsFringeLayer; /**< Whether the sprites are drawn. */
+ Image **mTiles;
+};
+
+/**
* A tile map.
*/
class Map : public Properties
@@ -89,39 +139,30 @@ class Map : public Properties
void initializeOverlays();
/**
- * Draws a map layer to the given graphics output.
- */
- void draw(Graphics *graphics, int scrollX, int scrollY, int layer);
-
- /**
- * Draws the overlay graphic to the given graphics output.
- */
- void
- drawOverlay(Graphics *graphics, float scrollX, float scrollY,
- int detail);
-
- /**
- * Adds a tileset to this map.
+ * Draws the map to the given graphics output. This method draws all
+ * layers, sprites and overlay effects.
+ *
+ * TODO: For efficiency reasons, this method could take into account
+ * the clipping rectangle set on the Graphics object. However,
+ * currently the map is always drawn full-screen.
*/
- void
- addTileset(Tileset *tileset);
+ void draw(Graphics *graphics, int scrollX, int scrollY);
/**
- * Sets a tile using a global tile id. Used by the layer loading
- * routine.
+ * Adds a layer to this map. The map takes ownership of the layer.
*/
- void
- setTileWithGid(int x, int y, int layer, int gid);
+ void addLayer(MapLayer *layer);
/**
- * Set tile ID.
+ * Adds a tileset to this map. The map takes ownership of the tileset.
*/
- void setTile(int x, int y, int layer, Image *img);
+ void addTileset(Tileset *tileset);
/**
- * Get tile ID.
+ * Finds the tile set that a tile with the given global id is part of.
*/
- Image *getTile(int x, int y, int layer);
+ Tileset*
+ getTilesetWithGid(int gid) const;
/**
* Get tile reference.
@@ -183,7 +224,7 @@ class Map : public Properties
/**
* Adds a particle effect
*/
- void addParticleEffect (std::string effectFile, int x, int y);
+ void addParticleEffect(const std::string &effectFile, int x, int y);
/**
* Initializes all added particle effects
@@ -193,15 +234,11 @@ class Map : public Properties
private:
/**
- * Converts a global tile id to the Image* pointing to the associated
- * tile image.
- */
- Image* getTileWithGid(int gid) const;
-
- /**
- * Finds the tile set that a tile with the given global id is part of.
+ * Draws the overlay graphic to the given graphics output.
*/
- Tileset* getTilesetWithGid(int gid) const;
+ void
+ drawOverlay(Graphics *graphics, float scrollX, float scrollY,
+ int detail);
/**
* Tells whether a tile is occupied by a being.
@@ -217,15 +254,14 @@ class Map : public Properties
int mTileWidth, mTileHeight;
int mMaxTileHeight;
MetaTile *mMetaTiles;
- Image **mTiles;
-
+ Layers mLayers;
Tilesets mTilesets;
Sprites mSprites;
// Pathfinding members
int mOnClosedList, mOnOpenList;
- // Overlay Data
+ // Overlay data
std::list<AmbientOverlay*> mOverlays;
float mLastScrollX;
float mLastScrollY;
diff --git a/src/monster.cpp b/src/monster.cpp
index d3e52520..2b6fadce 100644
--- a/src/monster.cpp
+++ b/src/monster.cpp
@@ -74,15 +74,13 @@ Monster::Monster(Uint32 id, Uint16 job, Map *map):
}
}
-Monster::~Monster() {
-
+Monster::~Monster()
+{
if (mText)
delete mText;
-
}
-void
-Monster::logic()
+void Monster::logic()
{
if (mAction != STAND)
{
@@ -97,14 +95,12 @@ Monster::logic()
Being::logic();
}
-Being::Type
-Monster::getType() const
+Being::Type Monster::getType() const
{
return MONSTER;
}
-void
-Monster::setAction(Uint8 action)
+void Monster::setAction(Action action)
{
SpriteAction currentAction = ACTION_INVALID;
@@ -122,11 +118,14 @@ Monster::setAction(Uint8 action)
mSprites[BASE_SPRITE]->reset();
break;
case STAND:
- currentAction = ACTION_STAND;
- break;
+ currentAction = ACTION_STAND;
+ break;
case HURT:
- // Not implemented yet
- break;
+ // Not implemented yet
+ break;
+ case SIT:
+ // Also not implemented yet
+ break;
}
if (currentAction != ACTION_INVALID)
@@ -142,8 +141,7 @@ Monster::setAction(Uint8 action)
}
}
-void
-Monster::handleAttack(Being *victim, int damage)
+void Monster::handleAttack(Being *victim, int damage)
{
Being::handleAttack(victim, damage);
@@ -151,21 +149,18 @@ Monster::handleAttack(Being *victim, int damage)
sound.playSfx(mi.getSound((damage > 0) ? MONSTER_EVENT_HIT : MONSTER_EVENT_MISS));
}
-void
-Monster::takeDamage(int amount)
+void Monster::takeDamage(int amount)
{
if (amount > 0) sound.playSfx(getInfo().getSound(MONSTER_EVENT_HURT));
Being::takeDamage(amount);
}
-Being::TargetCursorSize
-Monster::getTargetCursorSize() const
+Being::TargetCursorSize Monster::getTargetCursorSize() const
{
return getInfo().getTargetCursorSize();
}
-const MonsterInfo&
-Monster::getInfo() const
+const MonsterInfo& Monster::getInfo() const
{
return MonsterDB::get(mJob - 1002);
}
diff --git a/src/monster.h b/src/monster.h
index b613e96d..4839966a 100644
--- a/src/monster.h
+++ b/src/monster.h
@@ -38,7 +38,7 @@ class Monster : public Being
virtual void logic();
- virtual void setAction(Uint8 action);
+ virtual void setAction(Action action);
virtual Type getType() const;
diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp
index fbef02bd..7c9b8afd 100644
--- a/src/net/beinghandler.cpp
+++ b/src/net/beinghandler.cpp
@@ -23,6 +23,7 @@
#include "beinghandler.h"
+#include <iostream>
#include <SDL_types.h>
#include "messagein.h"
@@ -37,6 +38,7 @@
#include "../particle.h"
#include "../sound.h"
#include "../player_relations.h"
+#include "../npc.h"
const int EMOTION_TIME = 150; /**< Duration of emotion icon */
@@ -203,8 +205,13 @@ void BeingHandler::handleMessage(MessageIn *msg)
break;
// If this is player's current target, clear it.
- if (player_node->getTarget() == dstBeing)
+ if (dstBeing == player_node->getTarget())
+ {
player_node->stopAttack();
+ }
+
+ if (dstBeing == current_npc)
+ current_npc = NULL;
if (msg->readInt8() == 1)
{
@@ -464,7 +471,7 @@ void BeingHandler::handleMessage(MessageIn *msg)
msg->readInt8(); // unknown
dstBeing->mWalkTime = tick_time;
- dstBeing->mFrame = 0;
+ //dstBeing->mFrame = 0;
break;
case SMSG_PLAYER_STOP:
diff --git a/src/net/equipmenthandler.cpp b/src/net/equipmenthandler.cpp
index cc5d016c..0fc98175 100644
--- a/src/net/equipmenthandler.cpp
+++ b/src/net/equipmenthandler.cpp
@@ -156,6 +156,12 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
mask <<= 1;
position++;
}
+
+ item = inventory->getItem(index);
+ if (!item)
+ break;
+
+ item->setEquipped(false);
player_node->mEquipment->removeEquipment(position);
}
logger->log("Unequipping: %i %i(%i) %i",
@@ -174,6 +180,7 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
item = inventory->getItem(index);
if (item) {
+ item->setEquipped(true);
player_node->mEquipment->setArrows(item);
logger->log("Arrows equipped: %i", index);
}
diff --git a/src/net/loginhandler.cpp b/src/net/loginhandler.cpp
index 6505e39f..737d1762 100644
--- a/src/net/loginhandler.cpp
+++ b/src/net/loginhandler.cpp
@@ -113,7 +113,7 @@ void LoginHandler::handleMessage(MessageIn *msg)
errorMessage = "You have been blocked by the GM Team";
break;
case 6:
- errorMessage = "You have been banned for 5 minutes";
+ errorMessage = "You have been temporarily banned from the game. Please contact the GM team";
break;
case 9:
errorMessage = "This user name is already taken";
diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp
index e871b670..61e68295 100644
--- a/src/net/playerhandler.cpp
+++ b/src/net/playerhandler.cpp
@@ -52,6 +52,9 @@ extern BuyDialog *buyDialog;
extern SellDialog *sellDialog;
extern Window *buySellDialog;
+static const int MAP_TELEPORT_SCROLL_DISTANCE = 8; /* Max. distance we are willing to scroll after a teleport;
+ * everything beyond will reset the port hard. */
+
/**
* Listener used for handling the overweigth message.
*/
@@ -113,17 +116,13 @@ void PlayerHandler::handleMessage(MessageIn *msg)
* This client assumes that all walk messages succeed,
* and that the server will send a correction notice
* otherwise.
- *
- * Note that this packet is also used by eAthena to notify
- * the client of a server-generated auto-move. A patch has
- * been submitted to Mantis to eliminate these auto moves,
- * since they're inconsistent with the client design.
*/
break;
case SMSG_PLAYER_WARP:
{
std::string mapPath = msg->readString(16);
+ bool nearby;
Uint16 x = msg->readInt16();
Uint16 y = msg->readInt16();
@@ -135,13 +134,23 @@ void PlayerHandler::handleMessage(MessageIn *msg)
*/
player_node->stopAttack();
+ nearby = (engine->getCurrentMapName() == mapPath);
// Switch the actual map, deleting the previous one
engine->changeMap(mapPath);
current_npc = 0;
- float scrollOffsetX = (x - player_node->mX) * 32;
- float scrollOffsetY = (y - player_node->mY) * 32;
+ float scrollOffsetX = 0.0f;
+ float scrollOffsetY = 0.0f;
+
+ /* Scroll if neccessary */
+ if (!nearby
+ || (abs(x - player_node->mX) > MAP_TELEPORT_SCROLL_DISTANCE)
+ || (abs(y - player_node->mY) > MAP_TELEPORT_SCROLL_DISTANCE))
+ {
+ scrollOffsetX = (x - player_node->mX) * 32;
+ scrollOffsetY = (y - player_node->mY) * 32;
+ }
player_node->setAction(Being::STAND);
player_node->mFrame = 0;
@@ -204,8 +213,39 @@ void PlayerHandler::handleMessage(MessageIn *msg)
if (player_node->mHp == 0 && deathNotice == NULL)
{
- deathNotice = new OkDialog("Message",
- "You're now dead, press ok to restart");
+ static char const *const deadMsg[] =
+ {
+ "You are dead.",
+ "We regret to inform you that your character was killed in battle.",
+ "You are not that alive anymore.",
+ "The cold hands of the grim reaper are grabbing for your soul.",
+ "Game Over!",
+ "Insert coin to continue",
+ "No, kids. Your character did not really die. It... err... went to a better place.",
+ "Your plan of breaking your enemies weapon by bashing it with your throat failed.",
+ "I guess this did not run too well.",
+ "Do you want your possessions identified?", // Nethack reference
+ "Sadly, no trace of you was ever found...", // Secret of Mana reference
+ "Annihilated.", // Final Fantasy VI reference
+ "Looks like you got your head handed to you.", //Earthbound reference
+ "You screwed up again, dump your body down the tubes and get you another one.", // Leisure Suit Larry 1 Reference
+ "You're not dead yet. You're just resting.", // Monty Python reference from a couple of skits
+ "You are no more.", // Monty Python reference from the dead parrot sketch starting now
+ "You have ceased to be.",
+ "You've expired and gone to meet your maker.",
+ "You're a stiff.",
+ "Bereft of life, you rest in peace.",
+ "If you weren't so animated, you'd be pushing up the daisies.",
+ "Your metabolic processes are now history.",
+ "You're off the twig.",
+ "You've kicked the bucket.",
+ "You've shuffled off your mortal coil, run down the curtain and joined the bleedin' choir invisibile.",
+ "You are an ex-player.",
+ "You're pining for the fjords." // Monty Python reference from the dead parrot sketch
+ };
+ std::string message(deadMsg[rand()%27]);
+
+ deathNotice = new OkDialog("Message", message);
deathNotice->addActionListener(&deathListener);
player_node->setAction(Being::DEAD);
}
@@ -288,7 +328,7 @@ void PlayerHandler::handleMessage(MessageIn *msg)
}
break;
- // Updates stats and status points
+ // Updates stats and status points
case SMSG_PLAYER_STAT_UPDATE_5:
player_node->mStatsPointsToAttribute = msg->readInt16();
player_node->mAttr[LocalPlayer::STR] = msg->readInt8();
diff --git a/src/npc.cpp b/src/npc.cpp
index 1615ecd6..fe0b4598 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -86,7 +86,8 @@ void NPC::setName(const std::string &name)
mName = new Text(name, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET,
gcn::Graphics::CENTER, npcNameFont,
gcn::Color(200, 200, 255));
- }
+ Being::setName(name + " (NPC)");
+}
Being::Type
NPC::getType() const
diff --git a/src/particle.cpp b/src/particle.cpp
index 651fae41..8591838f 100644
--- a/src/particle.cpp
+++ b/src/particle.cpp
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: particle.cpp 4362 2008-06-24 12:29:33Z crush_tmw $
+ * $Id$
*/
#include <algorithm>
@@ -61,7 +61,7 @@ Particle::Particle(Map *map):
mAutoDelete(true),
mMap(map),
mGravity(0.0f),
- mRandomnes(0),
+ mRandomness(0),
mBounce(0.0f),
mFollow(false),
mTarget(NULL),
@@ -139,11 +139,11 @@ Particle::update()
}
}
- if (mRandomnes > 0)
+ if (mRandomness > 0)
{
- mVelocity.x += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f;
- mVelocity.y += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f;
- mVelocity.z += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f;
+ mVelocity.x += (rand()%mRandomness - rand()%mRandomness) / 1000.0f;
+ mVelocity.y += (rand()%mRandomness - rand()%mRandomness) / 1000.0f;
+ mVelocity.z += (rand()%mRandomness - rand()%mRandomness) / 1000.0f;
}
mVelocity.z -= mGravity;
diff --git a/src/particle.h b/src/particle.h
index d4a671c7..f281864d 100644
--- a/src/particle.h
+++ b/src/particle.h
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: particle.h 4362 2008-06-24 12:29:33Z crush_tmw $
+ * $Id$
*/
#ifndef _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; }
@@ -227,8 +230,8 @@ class Particle : public Sprite
* Sets the ammount of random vector changes
*/
void
- setRandomnes(int r)
- { mRandomnes = r; }
+ setRandomness(int r)
+ { mRandomness = r; }
/**
* Sets the ammount of velocity particles retain after
@@ -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()
@@ -303,7 +312,7 @@ class Particle : public Sprite
// dynamic particle
Vector mVelocity; /**< Speed in pixels per game-tick. */
float mGravity; /**< Downward acceleration in pixels per game-tick. */
- int mRandomnes; /**< Ammount of random vector change */
+ int mRandomness; /**< Ammount of random vector change */
float mBounce; /**< How much the particle bounces off when hitting the ground */
bool mFollow; /**< is this particle moved when its parent particle moves? */
diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp
index 996e3396..3e0a3d75 100644
--- a/src/particleemitter.cpp
+++ b/src/particleemitter.cpp
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: particleemitter.cpp 4362 2008-06-24 12:29:33Z crush_tmw $
+ * $Id$
*/
#include "particleemitter.h"
@@ -39,6 +39,7 @@
#define DEG_RAD_FACTOR 0.017453293f
ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map):
+ mOutputPauseLeft(0),
mParticleImage(0)
{
mMap = map;
@@ -52,7 +53,7 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *
mParticleAngleVertical.set(0.0f);
mParticlePower.set(0.0f);
mParticleGravity.set(0.0f);
- mParticleRandomnes.set(0);
+ mParticleRandomness.set(0);
mParticleBounce.set(0.0f);
mParticleFollow = false;
mParticleAcceleration.set(0.0f);
@@ -62,6 +63,7 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *
mParticleFadeOut.set(0);
mParticleFadeIn.set(0);
mOutput.set(1);
+ mOutputPause.set(0);
mParticleAlpha.set(1.0f);
for_each_xml_child_node(propertyNode, emitterNode)
@@ -117,9 +119,9 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *
{
mParticleGravity = readMinMax(propertyNode, 0.0f);
}
- else if (name == "randomnes")
+ else if (name == "randomnes" || name == "randomness") // legacy bug
{
- mParticleRandomnes = readMinMax(propertyNode, 0);
+ mParticleRandomness = readMinMax(propertyNode, 0);
}
else if (name == "bounce")
{
@@ -135,6 +137,11 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *
mOutput = readMinMax(propertyNode, 0);
mOutput.maxVal +=1;
}
+ else if (name == "output-pause")
+ {
+ mOutputPause = readMinMax(propertyNode, 0);
+ mOutputPauseLeft = mOutputPause.value();
+ }
else if (name == "acceleration")
{
mParticleAcceleration = readMinMax(propertyNode, 0.0f);
@@ -261,7 +268,7 @@ ParticleEmitter & ParticleEmitter::operator=(const ParticleEmitter &o)
mParticleAngleVertical = o.mParticleAngleVertical;
mParticlePower = o.mParticlePower;
mParticleGravity = o.mParticleGravity;
- mParticleRandomnes = o.mParticleRandomnes;
+ mParticleRandomness = o.mParticleRandomness;
mParticleBounce = o.mParticleBounce;
mParticleFollow = o.mParticleFollow;
mParticleTarget = o.mParticleTarget;
@@ -274,10 +281,13 @@ ParticleEmitter & ParticleEmitter::operator=(const ParticleEmitter &o)
mParticleAlpha = o.mParticleAlpha;
mMap = o.mMap;
mOutput = o.mOutput;
+ mOutputPause = o.mOutputPause;
mParticleImage = o.mParticleImage;
mParticleAnimation = o.mParticleAnimation;
mParticleChildEmitters = o.mParticleChildEmitters;
+ mOutputPauseLeft = 0;
+
if (mParticleImage) mParticleImage->incRef();
return *this;
@@ -308,6 +318,13 @@ ParticleEmitter::createParticles()
{
std::list<Particle *> newParticles;
+ if (mOutputPauseLeft > 0)
+ {
+ mOutputPauseLeft--;
+ return newParticles;
+ }
+ mOutputPauseLeft = mOutputPause.value();
+
for (int i = mOutput.value(); i > 0; i--)
{
// Limit maximum particles
@@ -342,7 +359,7 @@ ParticleEmitter::createParticles()
sin(angleH) * cos(angleV) * power,
sin(angleV) * power);
- newParticle->setRandomnes(mParticleRandomnes.value());
+ newParticle->setRandomness(mParticleRandomness.value());
newParticle->setGravity(mParticleGravity.value());
newParticle->setBounce(mParticleBounce.value());
newParticle->setFollow(mParticleFollow);
diff --git a/src/particleemitter.h b/src/particleemitter.h
index 481d4b44..5cf3fd46 100644
--- a/src/particleemitter.h
+++ b/src/particleemitter.h
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: particleemitter.h 4362 2008-06-24 12:29:33Z crush_tmw $
+ * $Id$
*/
#ifndef _PARTICLEEMITTER_H
@@ -97,7 +97,7 @@ class ParticleEmitter
* Vector changing of particles:
*/
MinMax<float> mParticleGravity;
- MinMax<int> mParticleRandomnes;
+ MinMax<int> mParticleRandomness;
MinMax<float> mParticleBounce;
bool mParticleFollow;
@@ -119,6 +119,8 @@ class ParticleEmitter
Map *mMap; /**< Map the particles are spawned on */
MinMax<int> mOutput; /**< Number of particles spawned per update */
+ MinMax<int> mOutputPause; /**< Pause in frames between two spawns */
+ int mOutputPauseLeft;
/*
* Graphical representation of the particle
diff --git a/src/player.cpp b/src/player.cpp
index 125407de..8380fdfe 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -75,6 +75,18 @@ void
Player::logic()
{
switch (mAction) {
+ case STAND:
+ break;
+
+ case SIT:
+ break;
+
+ case DEAD:
+ break;
+
+ case HURT:
+ break;
+
case WALK:
mFrame = (get_elapsed_time(mWalkTime) * 6) / mWalkSpeed;
if (mFrame >= 6) {
diff --git a/src/resources/action.cpp b/src/resources/action.cpp
index facd23fb..8ed099ea 100644
--- a/src/resources/action.cpp
+++ b/src/resources/action.cpp
@@ -23,8 +23,6 @@
#include "action.h"
-#include <algorithm>
-
#include "animation.h"
#include "../utils/dtor.h"
@@ -36,8 +34,7 @@ Action::Action()
Action::~Action()
{
- std::for_each(mAnimations.begin(), mAnimations.end(),
- make_dtor(mAnimations));
+ delete_all(mAnimations);
}
Animation*
diff --git a/src/resources/imageset.cpp b/src/resources/imageset.cpp
index 6228f4e4..b7263ec3 100644
--- a/src/resources/imageset.cpp
+++ b/src/resources/imageset.cpp
@@ -21,8 +21,6 @@
* $Id: imageset.cpp 4209 2008-04-29 12:58:21Z b_lindeijer $
*/
-#include <algorithm>
-
#include "imageset.h"
#include "../log.h"
@@ -46,11 +44,10 @@ ImageSet::ImageSet(Image *img, int width, int height)
ImageSet::~ImageSet()
{
- for_each(mImages.begin(), mImages.end(), make_dtor(mImages));
+ delete_all(mImages);
}
-Image*
-ImageSet::get(size_type i)
+Image* ImageSet::get(size_type i) const
{
if (i >= mImages.size())
{
diff --git a/src/resources/imageset.h b/src/resources/imageset.h
index 719e9769..e276dd06 100644
--- a/src/resources/imageset.h
+++ b/src/resources/imageset.h
@@ -47,12 +47,18 @@ class ImageSet : public Resource
*/
~ImageSet();
+ /**
+ * Returns the width of the images in the image set.
+ */
int getWidth() { return mWidth; };
+ /**
+ * Returns the height of the images in the image set.
+ */
int getHeight() { return mHeight; };
typedef std::vector<Image*>::size_type size_type;
- Image* get(size_type i);
+ Image* get(size_type i) const;
size_type size() { return mImages.size(); }
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index 6ae7b499..8999f651 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -21,7 +21,6 @@
* $Id: itemdb.cpp 4347 2008-06-12 09:06:01Z b_lindeijer $
*/
-#include <algorithm>
#include <cassert>
#include <libxml/tree.h>
@@ -146,7 +145,7 @@ void ItemDB::unload()
delete mUnknown;
mUnknown = NULL;
- for_each(mItemInfos.begin(), mItemInfos.end(), make_dtor(mItemInfos));
+ delete_all(mItemInfos);
mItemInfos.clear();
mLoaded = false;
}
@@ -177,8 +176,7 @@ void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node)
{
itemInfo->setSprite(filename, 0);
}
-
- if (gender == "female" || gender == "unisex")
+ else
{
itemInfo->setSprite(filename, 1);
}
diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp
index e2b47e66..ab3b0cae 100644
--- a/src/resources/mapreader.cpp
+++ b/src/resources/mapreader.cpp
@@ -145,8 +145,7 @@ inflateMemory(unsigned char *in, unsigned int inLength,
return outLength;
}
-Map*
-MapReader::readMap(const std::string &filename)
+Map* MapReader::readMap(const std::string &filename)
{
// Load the file through resource manager
ResourceManager *resman = ResourceManager::getInstance();
@@ -206,19 +205,13 @@ MapReader::readMap(const std::string &filename)
Map*
MapReader::readMap(xmlNodePtr node, const std::string &path)
{
- xmlChar *prop;
-
// Take the filename off the path
- std::string pathDir = path.substr(0, path.rfind("/") + 1);
-
- prop = xmlGetProp(node, BAD_CAST "version");
- xmlFree(prop);
+ const std::string pathDir = path.substr(0, path.rfind("/") + 1);
- int w = XML::getProperty(node, "width", 0);
- int h = XML::getProperty(node, "height", 0);
- int tilew = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
- int tileh = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
- int layerNr = 0;
+ const int w = XML::getProperty(node, "width", 0);
+ const int h = XML::getProperty(node, "height", 0);
+ const int tilew = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
+ const int tileh = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
Map *map = new Map(w, h, tilew, tileh);
for_each_xml_child_node(childNode, node)
@@ -232,9 +225,7 @@ MapReader::readMap(xmlNodePtr node, const std::string &path)
}
else if (xmlStrEqual(childNode->name, BAD_CAST "layer"))
{
- logger->log("- Loading layer %d", layerNr);
- readLayer(childNode, map, layerNr);
- layerNr++;
+ readLayer(childNode, map);
}
else if (xmlStrEqual(childNode->name, BAD_CAST "properties"))
{
@@ -246,15 +237,29 @@ MapReader::readMap(xmlNodePtr node, const std::string &path)
{
if (xmlStrEqual(objectNode->name, BAD_CAST "object"))
{
- std::string objName = XML::getProperty(objectNode, "name", "");
- std::string objType = XML::getProperty(objectNode, "type", "");
- int objX = XML::getProperty(objectNode, "x", 0);
- int objY = XML::getProperty(objectNode, "y", 0);
+ const std::string objType = XML::getProperty(objectNode, "type", "");
+
+ if (objType == "WARP" || objType == "NPC" ||
+ objType == "SCRIPT" || objType == "SPAWN")
+ {
+ // Silently skip server-side objects.
+ continue;
+ }
+
+ const std::string objName = XML::getProperty(objectNode, "name", "");
+ const int objX = XML::getProperty(objectNode, "x", 0);
+ const int objY = XML::getProperty(objectNode, "y", 0);
logger->log("- Loading object name: %s type: %s at %d:%d",
objName.c_str(), objType.c_str(), objX, objY);
+
if (objType == "PARTICLE_EFFECT")
{
+ if (objName.empty()) {
+ logger->log(" Warning: No particle file given");
+ continue;
+ }
+
map->addParticleEffect(objName, objX, objY);
}
else
@@ -271,8 +276,7 @@ MapReader::readMap(xmlNodePtr node, const std::string &path)
return map;
}
-void
-MapReader::readProperties(xmlNodePtr node, Properties* props)
+void MapReader::readProperties(xmlNodePtr node, Properties* props)
{
for_each_xml_child_node(childNode, node)
{
@@ -280,43 +284,65 @@ MapReader::readProperties(xmlNodePtr node, Properties* props)
continue;
// Example: <property name="name" value="value"/>
- xmlChar *name = xmlGetProp(childNode, BAD_CAST "name");
- xmlChar *value = xmlGetProp(childNode, BAD_CAST "value");
+ const std::string name = XML::getProperty(childNode, "name", "");
+ const std::string value = XML::getProperty(childNode, "value", "");
- if (name && value) {
- props->setProperty((const char*)name, (const char*)value);
- }
-
- if (name) xmlFree(name);
- if (value) xmlFree(value);
+ if (!name.empty() && !value.empty())
+ props->setProperty(name, value);
}
}
-void
-MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
+static void setTile(Map *map, MapLayer *layer, int x, int y, int gid)
+{
+ const Tileset * const set = map->getTilesetWithGid(gid);
+ if (layer) {
+ // Set regular tile on a layer
+ Image * const img = set ? set->get(gid - set->getFirstGid()) : 0;
+ layer->setTile(x, y, img);
+ } else {
+ // Set collision tile
+ map->setWalk(x, y, (!set || (gid - set->getFirstGid() == 0)));
+ }
+}
+
+void MapReader::readLayer(xmlNodePtr node, Map *map)
{
- int h = map->getHeight();
- int w = map->getWidth();
+ // Layers are not necessarily the same size as the map
+ const int w = XML::getProperty(node, "width", map->getWidth());
+ const int h = XML::getProperty(node, "height", map->getHeight());
+ const int offsetX = XML::getProperty(node, "xoffset", 0);
+ const int offsetY = XML::getProperty(node, "yoffset", 0);
+ const std::string name = XML::getProperty(node, "name", "");
+
+ const bool isFringeLayer = (name.substr(0,6) == "Fringe");
+ const bool isCollisionLayer = (name.substr(0,9) == "Collision");
+
+ MapLayer *layer = 0;
+
+ if (!isCollisionLayer) {
+ layer = new MapLayer(offsetX, offsetY, w, h, isFringeLayer);
+ map->addLayer(layer);
+ }
+
+ logger->log("- Loading layer \"%s\"", name.c_str());
int x = 0;
int y = 0;
-
- // Load the tile data. Layers are assumed to be map size, with (0,0) as
- // origin.
+
+ // Load the tile data
for_each_xml_child_node(childNode, node)
{
if (!xmlStrEqual(childNode->name, BAD_CAST "data"))
- continue;
-
- xmlChar *encoding = xmlGetProp(childNode, BAD_CAST "encoding");
- xmlChar *compression = xmlGetProp(childNode, BAD_CAST "compression");
-
- if (encoding && xmlStrEqual(encoding, BAD_CAST "base64"))
+ continue;
+
+ const std::string encoding =
+ XML::getProperty(childNode, "encoding", "");
+ const std::string compression =
+ XML::getProperty(childNode, "compression", "");
+
+ if (encoding == "base64")
{
- xmlFree(encoding);
-
- if (compression && !xmlStrEqual(compression, BAD_CAST "gzip")) {
+ if (!compression.empty() && compression != "gzip") {
logger->log("Warning: only gzip layer compression supported!");
- xmlFree(compression);
return;
}
@@ -324,15 +350,15 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
xmlNodePtr dataChild = childNode->xmlChildrenNode;
if (!dataChild)
continue;
-
+
int len = strlen((const char*)dataChild->content) + 1;
unsigned char *charData = new unsigned char[len + 1];
const char *charStart = (const char*)dataChild->content;
unsigned char *charIndex = charData;
-
+
while (*charStart) {
if (*charStart != ' ' && *charStart != '\t' &&
- *charStart != '\n')
+ *charStart != '\n')
{
*charIndex = *charStart;
charIndex++;
@@ -348,40 +374,34 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
delete[] charData;
if (binData) {
- if (compression) {
- if (xmlStrEqual(compression, BAD_CAST "gzip")) {
- // Inflate the gzipped layer data
- unsigned char *inflated;
- unsigned int inflatedSize =
- inflateMemory(binData, binLen, inflated);
-
- free(binData);
- binData = inflated;
- binLen = inflatedSize;
-
- if (inflated == NULL)
- {
- logger->log("Error: Could not decompress layer!");
- xmlFree(compression);
- return;
- }
+ if (compression == "gzip") {
+ // Inflate the gzipped layer data
+ unsigned char *inflated;
+ unsigned int inflatedSize =
+ inflateMemory(binData, binLen, inflated);
+
+ free(binData);
+ binData = inflated;
+ binLen = inflatedSize;
+
+ if (!inflated) {
+ logger->log("Error: Could not decompress layer!");
+ return;
}
- xmlFree(compression);
}
for (int i = 0; i < binLen - 3; i += 4) {
- int gid = binData[i] |
+ const int gid = binData[i] |
binData[i + 1] << 8 |
binData[i + 2] << 16 |
binData[i + 3] << 24;
- map->setTileWithGid(x, y, layer, gid);
-
+ setTile(map, layer, x, y, gid);
+
x++;
- if (x == w) {
+ if (x == w)
+ {
x = 0; y++;
-
- // When we're done, don't crash on too much data
if (y == h)
break;
}
@@ -390,29 +410,29 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
}
}
else {
- // Read plain XML map file
- for_each_xml_child_node(childNode2, childNode)
- {
- if (!xmlStrEqual(childNode2->name, BAD_CAST "tile"))
+ // Read plain XML map file
+ for_each_xml_child_node(childNode2, childNode)
+ {
+ if (!xmlStrEqual(childNode2->name, BAD_CAST "tile"))
continue;
-
- int gid = XML::getProperty(childNode2, "gid", -1);
- map->setTileWithGid(x, y, layer, gid);
-
- x++;
- if (x == w) {
- x = 0; y++;
- if (y >= h)
- break;
- }
- }
+
+ const int gid = XML::getProperty(childNode2, "gid", -1);
+ setTile(map, layer, x, y, gid);
+
+ x++;
+ if (x == w) {
+ x = 0; y++;
+ if (y >= h)
+ break;
+ }
+ }
}
-
+
if (y < h)
std::cerr << "TOO SMALL!\n";
if (x)
std::cerr << "TOO SMALL!\n";
-
+
// There can be only one data element
break;
}
@@ -429,20 +449,20 @@ MapReader::readTileset(xmlNodePtr node,
return NULL;
}
- int firstGid = XML::getProperty(node, "firstgid", 0);
- int tw = XML::getProperty(node, "tilewidth", map->getTileWidth());
- int th = XML::getProperty(node, "tileheight", map->getTileHeight());
+ const int firstGid = XML::getProperty(node, "firstgid", 0);
+ const int tw = XML::getProperty(node, "tilewidth", map->getTileWidth());
+ const int th = XML::getProperty(node, "tileheight", map->getTileHeight());
for_each_xml_child_node(childNode, node)
{
if (!xmlStrEqual(childNode->name, BAD_CAST "image"))
continue;
- xmlChar* source = xmlGetProp(childNode, BAD_CAST "source");
+ const std::string source = XML::getProperty(childNode, "source", "");
- if (source)
+ if (!source.empty())
{
- std::string sourceStr = std::string((const char*)source);
+ std::string sourceStr = source;
sourceStr.erase(0, 3); // Remove "../"
ResourceManager *resman = ResourceManager::getInstance();
@@ -452,14 +472,14 @@ MapReader::readTileset(xmlNodePtr node,
{
Tileset *set = new Tileset(tilebmp, tw, th, firstGid);
tilebmp->decRef();
- xmlFree(source);
return set;
}
else {
- logger->log("Warning: Failed to load tileset (%s)", source);
+ logger->log("Warning: Failed to load tileset (%s)", source.c_str());
}
}
+ // Only one image element expected
break;
}
diff --git a/src/resources/mapreader.h b/src/resources/mapreader.h
index 0d59fc9f..eb0d4873 100644
--- a/src/resources/mapreader.h
+++ b/src/resources/mapreader.h
@@ -63,10 +63,10 @@ class MapReader
readProperties(xmlNodePtr node, Properties* props);
/**
- * Reads a map layer.
+ * Reads a map layer and adds it to the given map.
*/
static void
- readLayer(xmlNodePtr node, Map *map, int layer);
+ readLayer(xmlNodePtr node, Map *map);
/**
* Reads a tile set.
diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp
index 847b99fe..73e9d666 100644
--- a/src/resources/monsterdb.cpp
+++ b/src/resources/monsterdb.cpp
@@ -21,8 +21,6 @@
* $Id: monsterdb.cpp 4255 2008-05-21 21:44:27Z crush_tmw $
*/
-#include <algorithm>
-
#include "monsterdb.h"
#include "resourcemanager.h"
@@ -143,8 +141,7 @@ MonsterDB::load()
void
MonsterDB::unload()
{
- for_each(mMonsterInfos.begin(), mMonsterInfos.end(),
- make_dtor(mMonsterInfos));
+ delete_all(mMonsterInfos);
mMonsterInfos.clear();
mLoaded = false;
diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp
index e492ccd3..19f2990b 100644
--- a/src/resources/monsterinfo.cpp
+++ b/src/resources/monsterinfo.cpp
@@ -21,8 +21,6 @@
* $Id: monsterinfo.cpp 2650 2006-09-03 15:00:47Z b_lindeijer $
*/
-#include <algorithm>
-
#include "monsterinfo.h"
#include "../utils/dtor.h"
@@ -35,8 +33,7 @@ MonsterInfo::MonsterInfo()
MonsterInfo::~MonsterInfo()
{
// kill vectors in mSoundEffects
- for_each (mSounds.begin(), mSounds.end(),
- make_dtor(mSounds));
+ delete_all(mSounds);
mSounds.clear();
}
diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp
index 550b2d1c..ebc60240 100644
--- a/src/resources/spritedef.cpp
+++ b/src/resources/spritedef.cpp
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: spritedef.cpp 4332 2008-06-05 07:33:12Z b_lindeijer $
+ * $Id$
*/
#include <set>
@@ -70,33 +70,8 @@ SpriteDef *SpriteDef::load(std::string const &animationFile, int variant)
}
}
- // Get the variant
- int variant_num = XML::getProperty(rootNode, "variants", 0);
- int variant_offset = 0;
-
- if (variant_num > 0 && variant < variant_num)
- {
- variant_offset = variant * XML::getProperty(rootNode, "variant_offset", 0);
- }
-
SpriteDef *def = new SpriteDef;
-
- for_each_xml_child_node(node, rootNode)
- {
- if (xmlStrEqual(node->name, BAD_CAST "imageset"))
- {
- def->loadImageSet(node, palettes);
- }
- else if (xmlStrEqual(node->name, BAD_CAST "action"))
- {
- def->loadAction(node, variant_offset);
- }
- else if (xmlStrEqual(node->name, BAD_CAST "include"))
- {
- def->includeSprite(node);
- }
- }
-
+ def->loadSprite(rootNode, variant, palettes);
def->substituteActions();
return def;
}
@@ -119,11 +94,47 @@ void SpriteDef::substituteActions()
substituteAction(ACTION_DEAD, ACTION_HURT);
}
+void SpriteDef::loadSprite(xmlNodePtr spriteNode, int variant,
+ const std::string &palettes)
+{
+ // Get the variant
+ const int variantCount = XML::getProperty(spriteNode, "variants", 0);
+ int variant_offset = 0;
+
+ if (variantCount > 0 && variant < variantCount)
+ {
+ variant_offset =
+ variant * XML::getProperty(spriteNode, "variant_offset", 0);
+ }
+
+ for_each_xml_child_node(node, spriteNode)
+ {
+ if (xmlStrEqual(node->name, BAD_CAST "imageset"))
+ {
+ loadImageSet(node, palettes);
+ }
+ else if (xmlStrEqual(node->name, BAD_CAST "action"))
+ {
+ loadAction(node, variant_offset);
+ }
+ else if (xmlStrEqual(node->name, BAD_CAST "include"))
+ {
+ includeSprite(node);
+ }
+ }
+}
+
void SpriteDef::loadImageSet(xmlNodePtr node, std::string const &palettes)
{
- int width = XML::getProperty(node, "width", 0);
- int height = XML::getProperty(node, "height", 0);
- std::string name = XML::getProperty(node, "name", "");
+ const std::string name = XML::getProperty(node, "name", "");
+
+ // We don't allow redefining image sets. This way, an included sprite
+ // definition will use the already loaded image set with the same name.
+ if (mImageSets.find(name) != mImageSets.end())
+ return;
+
+ const int width = XML::getProperty(node, "width", 0);
+ const int height = XML::getProperty(node, "height", 0);
std::string imageSrc = XML::getProperty(node, "src", "");
Dye::instantiate(imageSrc, palettes);
@@ -184,9 +195,9 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
Action *action, ImageSet *imageSet,
int variant_offset)
{
- std::string directionName =
+ const std::string directionName =
XML::getProperty(animationNode, "direction", "");
- SpriteDirection directionType = makeSpriteDirection(directionName);
+ const SpriteDirection directionType = makeSpriteDirection(directionName);
if (directionType == DIRECTION_INVALID)
{
@@ -201,7 +212,7 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
// Get animation frames
for_each_xml_child_node(frameNode, animationNode)
{
- int delay = XML::getProperty(frameNode, "delay", 0);
+ const int delay = XML::getProperty(frameNode, "delay", 0);
int offsetX = XML::getProperty(frameNode, "offsetX", 0);
int offsetY = XML::getProperty(frameNode, "offsetY", 0);
offsetY -= imageSet->getHeight() - 32;
@@ -209,7 +220,7 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
if (xmlStrEqual(frameNode->name, BAD_CAST "frame"))
{
- int index = XML::getProperty(frameNode, "index", -1);
+ const int index = XML::getProperty(frameNode, "index", -1);
if (index < 0)
{
@@ -230,7 +241,7 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
else if (xmlStrEqual(frameNode->name, BAD_CAST "sequence"))
{
int start = XML::getProperty(frameNode, "start", -1);
- int end = XML::getProperty(frameNode, "end", -1);
+ const int end = XML::getProperty(frameNode, "end", -1);
if (start < 0 || end < 0)
{
@@ -263,12 +274,23 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
void
SpriteDef::includeSprite(xmlNodePtr includeNode)
{
+ // TODO: Perform circular dependency check, since it's easy to crash the
+ // client this way.
const std::string filename = XML::getProperty(includeNode, "file", "");
- ResourceManager *resman = ResourceManager::getInstance();
- SpriteDef *sprite = resman->getSprite("graphics/sprites/" + filename);
- // TODO: Somehow implement actually including it
- sprite->decRef();
+ if (filename.empty())
+ return;
+
+ XML::Document doc("graphics/sprites/" + filename);
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "sprite"))
+ {
+ logger->log("Error, no sprite root node in %s", filename.c_str());
+ return;
+ }
+
+ loadSprite(rootNode, 0);
}
void
diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h
index 2872af06..72c2566f 100644
--- a/src/resources/spritedef.h
+++ b/src/resources/spritedef.h
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: spritedef.h 4255 2008-05-21 21:44:27Z crush_tmw $
+ * $Id$
*/
#ifndef _TMW_SPRITEDEF_H
@@ -92,6 +92,12 @@ class SpriteDef : public Resource
~SpriteDef();
/**
+ * Loads a sprite element.
+ */
+ void loadSprite(xmlNodePtr spriteNode, int variant,
+ const std::string &palettes = "");
+
+ /**
* Loads an imageset element.
*/
void loadImageSet(xmlNodePtr node, std::string const &palettes);
diff --git a/src/sound.h b/src/sound.h
index 038f299e..ebcd6442 100644
--- a/src/sound.h
+++ b/src/sound.h
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: sound.h 3606 2007-09-27 14:54:09Z b_lindeijer $
+ * $Id$
*/
#ifndef _TMW_SOUND_H
diff --git a/src/textparticle.cpp b/src/textparticle.cpp
index c4b432f3..89466006 100644
--- a/src/textparticle.cpp
+++ b/src/textparticle.cpp
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: textparticle.cpp 4360 2008-06-23 14:44:20Z crush_tmw $
+ * $Id$
*/
#include "textparticle.h"
diff --git a/src/tileset.h b/src/tileset.h
index 6272d64a..fb5593ef 100644
--- a/src/tileset.h
+++ b/src/tileset.h
@@ -44,8 +44,7 @@ class Tileset : public ImageSet
/**
* Returns the first gid.
*/
- int
- getFirstGid()
+ int getFirstGid() const
{
return mFirstGid;
}
diff --git a/src/utils/dtor.h b/src/utils/dtor.h
index 3b8aeb0e..29cde178 100644
--- a/src/utils/dtor.h
+++ b/src/utils/dtor.h
@@ -24,6 +24,7 @@
#ifndef _TMW_UTILS_DTOR_H
#define _TMW_UTILS_DTOR_H
+#include <algorithm>
#include <functional>
#include <utility>
@@ -46,4 +47,11 @@ inline dtor<typename Cont::value_type> make_dtor(Cont const&)
return dtor<typename Cont::value_type>();
}
+template<typename Container>
+inline void delete_all(Container &c)
+{
+ std::for_each(c.begin(), c.end(), make_dtor(c));
+}
+
+
#endif