summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt26
-rw-r--r--src/Makefile.am28
-rw-r--r--src/actor.cpp58
-rw-r--r--src/actor.h128
-rw-r--r--src/actorsprite.cpp453
-rw-r--r--src/actorsprite.h232
-rw-r--r--src/actorspritemanager.cpp315
-rw-r--r--src/actorspritemanager.h (renamed from src/beingmanager.h)80
-rw-r--r--src/animatedsprite.cpp52
-rw-r--r--src/animatedsprite.h57
-rw-r--r--src/being.cpp806
-rw-r--r--src/being.h382
-rw-r--r--src/beingmanager.cpp296
-rw-r--r--src/chatlog.cpp177
-rw-r--r--src/chatlog.h73
-rw-r--r--src/client.cpp17
-rw-r--r--src/client.h1
-rw-r--r--src/compoundsprite.cpp367
-rw-r--r--src/compoundsprite.h105
-rw-r--r--src/flooritem.cpp57
-rw-r--r--src/flooritem.h76
-rw-r--r--src/flooritemmanager.cpp80
-rw-r--r--src/flooritemmanager.h54
-rw-r--r--src/game.cpp58
-rw-r--r--src/graphics.cpp10
-rw-r--r--src/graphics.h12
-rw-r--r--src/gui/beingpopup.cpp12
-rw-r--r--src/gui/beingpopup.h4
-rw-r--r--src/gui/buy.cpp7
-rw-r--r--src/gui/buysell.cpp2
-rw-r--r--src/gui/charcreatedialog.cpp2
-rw-r--r--src/gui/charcreatedialog.h4
-rw-r--r--src/gui/charselectdialog.h2
-rw-r--r--src/gui/chat.cpp14
-rw-r--r--src/gui/itempopup.cpp3
-rw-r--r--src/gui/minimap.cpp69
-rw-r--r--src/gui/ministatus.cpp20
-rw-r--r--src/gui/npcdialog.cpp1
-rw-r--r--src/gui/npcdialog.h1
-rw-r--r--src/gui/npcpostdialog.cpp2
-rw-r--r--src/gui/popupmenu.cpp51
-rw-r--r--src/gui/register.h2
-rw-r--r--src/gui/sell.cpp1
-rw-r--r--src/gui/serverdialog.cpp3
-rw-r--r--src/gui/setup_players.cpp23
-rw-r--r--src/gui/setup_players.h3
-rw-r--r--src/gui/skilldialog.cpp4
-rw-r--r--src/gui/socialwindow.cpp2
-rw-r--r--src/gui/statuswindow.cpp36
-rw-r--r--src/gui/viewport.cpp80
-rw-r--r--src/gui/viewport.h9
-rw-r--r--src/gui/widgets/chattab.cpp10
-rw-r--r--src/gui/widgets/chattab.h2
-rw-r--r--src/gui/widgets/playerbox.cpp16
-rw-r--r--src/gui/widgets/playerbox.h8
-rw-r--r--src/gui/widgets/whispertab.cpp7
-rw-r--r--src/gui/widgets/whispertab.h2
-rw-r--r--src/guild.cpp9
-rw-r--r--src/imageparticle.cpp10
-rw-r--r--src/imageparticle.h2
-rw-r--r--src/imagesprite.cpp44
-rw-r--r--src/imagesprite.h73
-rw-r--r--src/item.cpp3
-rw-r--r--src/localplayer.cpp105
-rw-r--r--src/localplayer.h30
-rw-r--r--src/main.cpp8
-rw-r--r--src/map.cpp70
-rw-r--r--src/map.h40
-rw-r--r--src/monster.cpp199
-rw-r--r--src/monster.h98
-rw-r--r--src/net/charhandler.h6
-rw-r--r--src/net/gamehandler.h5
-rw-r--r--src/net/guildhandler.h5
-rw-r--r--src/net/logindata.h2
-rw-r--r--src/net/manaserv/beinghandler.cpp44
-rw-r--r--src/net/manaserv/buysellhandler.cpp7
-rw-r--r--src/net/manaserv/charhandler.cpp6
-rw-r--r--src/net/manaserv/charhandler.h6
-rw-r--r--src/net/manaserv/chathandler.cpp4
-rw-r--r--src/net/manaserv/effecthandler.cpp4
-rw-r--r--src/net/manaserv/gamehandler.h6
-rw-r--r--src/net/manaserv/guildhandler.cpp4
-rw-r--r--src/net/manaserv/guildhandler.h2
-rw-r--r--src/net/manaserv/itemhandler.cpp9
-rw-r--r--src/net/manaserv/npchandler.cpp7
-rw-r--r--src/net/manaserv/partyhandler.cpp6
-rw-r--r--src/net/manaserv/partyhandler.h4
-rw-r--r--src/net/manaserv/playerhandler.cpp1
-rw-r--r--src/net/manaserv/tradehandler.cpp4
-rw-r--r--src/net/partyhandler.h6
-rw-r--r--src/net/tmwa/adminhandler.cpp2
-rw-r--r--src/net/tmwa/beinghandler.cpp172
-rw-r--r--src/net/tmwa/buysellhandler.cpp3
-rw-r--r--src/net/tmwa/charserverhandler.cpp6
-rw-r--r--src/net/tmwa/charserverhandler.h6
-rw-r--r--src/net/tmwa/chathandler.cpp4
-rw-r--r--src/net/tmwa/gamehandler.h3
-rw-r--r--src/net/tmwa/gui/guildtab.cpp7
-rw-r--r--src/net/tmwa/gui/guildtab.h2
-rw-r--r--src/net/tmwa/gui/partytab.cpp7
-rw-r--r--src/net/tmwa/gui/partytab.h2
-rw-r--r--src/net/tmwa/guildhandler.cpp4
-rw-r--r--src/net/tmwa/guildhandler.h2
-rw-r--r--src/net/tmwa/itemhandler.cpp8
-rw-r--r--src/net/tmwa/npchandler.cpp3
-rw-r--r--src/net/tmwa/partyhandler.cpp26
-rw-r--r--src/net/tmwa/partyhandler.h4
-rw-r--r--src/net/tmwa/playerhandler.cpp2
-rw-r--r--src/net/tmwa/token.h2
-rw-r--r--src/npc.cpp106
-rw-r--r--src/npc.h73
-rw-r--r--src/particle.cpp17
-rw-r--r--src/particle.h52
-rw-r--r--src/party.cpp8
-rw-r--r--src/player.cpp358
-rw-r--r--src/player.h161
-rw-r--r--src/playerrelations.cpp26
-rw-r--r--src/playerrelations.h3
-rw-r--r--src/resources/beinginfo.cpp107
-rw-r--r--src/resources/beinginfo.h132
-rw-r--r--src/resources/itemdb.cpp32
-rw-r--r--src/resources/iteminfo.h12
-rw-r--r--src/resources/monsterdb.cpp72
-rw-r--r--src/resources/monsterdb.h9
-rw-r--r--src/resources/monsterinfo.cpp98
-rw-r--r--src/resources/monsterinfo.h106
-rw-r--r--src/resources/npcdb.cpp53
-rw-r--r--src/resources/npcdb.h22
-rw-r--r--src/resources/spritedef.cpp3
-rw-r--r--src/resources/spritedef.h23
-rw-r--r--src/sprite.h89
-rw-r--r--src/text.cpp13
-rw-r--r--src/text.h6
-rw-r--r--src/textparticle.cpp6
-rw-r--r--src/textparticle.h2
-rw-r--r--src/utils/copynpaste.cpp1
136 files changed, 3870 insertions, 3216 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b15948d3..2df9ef49 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -348,6 +348,8 @@ SET(SRCS
resources/ambientoverlay.h
resources/animation.cpp
resources/animation.h
+ resources/beinginfo.cpp
+ resources/beinginfo.h
resources/colordb.cpp
resources/colordb.h
resources/dye.cpp
@@ -370,8 +372,6 @@ SET(SRCS
resources/mapreader.h
resources/monsterdb.cpp
resources/monsterdb.h
- resources/monsterinfo.cpp
- resources/monsterinfo.h
resources/music.cpp
resources/music.h
resources/npcdb.cpp
@@ -402,6 +402,12 @@ SET(SRCS
utils/mkdir.h
utils/xml.cpp
utils/xml.h
+ actor.cpp
+ actor.h
+ actorsprite.cpp
+ actorsprite.h
+ actorspritemanager.cpp
+ actorspritemanager.h
animatedsprite.cpp
animatedsprite.h
animationparticle.cpp
@@ -410,8 +416,8 @@ SET(SRCS
avatar.h
being.cpp
being.h
- beingmanager.cpp
- beingmanager.h
+ chatlog.cpp
+ chatlog.h
client.cpp
client.h
channel.cpp
@@ -420,6 +426,8 @@ SET(SRCS
channelmanager.h
commandhandler.cpp
commandhandler.h
+ compoundsprite.cpp
+ compoundsprite.h
configlistener.h
configuration.cpp
configuration.h
@@ -430,8 +438,6 @@ SET(SRCS
equipment.h
flooritem.cpp
flooritem.h
- flooritemmanager.cpp
- flooritemmanager.h
game.cpp
game.h
graphics.cpp
@@ -441,6 +447,8 @@ SET(SRCS
guild.h
imageparticle.cpp
imageparticle.h
+ imagesprite.cpp
+ imagesprite.h
inventory.cpp
inventory.h
item.cpp
@@ -459,10 +467,6 @@ SET(SRCS
main.h
map.cpp
map.h
- monster.cpp
- monster.h
- npc.cpp
- npc.h
openglgraphics.cpp
openglgraphics.h
particle.cpp
@@ -474,8 +478,6 @@ SET(SRCS
particleemitterprop.h
party.cpp
party.h
- player.cpp
- player.h
playerrelations.cpp
playerrelations.h
position.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index d12a9a56..2b18b693 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -228,9 +228,9 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
net/messagein.h \
net/messageout.cpp \
net/messageout.h \
- net/npchandler.h \
net/net.cpp \
net/net.h \
+ net/npchandler.h \
net/partyhandler.h \
net/playerhandler.h \
net/serverinfo.h \
@@ -245,6 +245,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
resources/ambientoverlay.h \
resources/animation.cpp \
resources/animation.h \
+ resources/beinginfo.cpp \
+ resources/beinginfo.h \
resources/colordb.cpp \
resources/colordb.h \
resources/dye.cpp \
@@ -267,8 +269,6 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
resources/mapreader.h \
resources/monsterdb.cpp \
resources/monsterdb.h \
- resources/monsterinfo.cpp \
- resources/monsterinfo.h \
resources/music.cpp \
resources/music.h \
resources/npcdb.cpp \
@@ -301,6 +301,12 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
utils/mutex.h \
utils/xml.cpp \
utils/xml.h \
+ actor.cpp \
+ actor.h \
+ actorsprite.cpp \
+ actorsprite.h \
+ actorspritemanager.cpp \
+ actorspritemanager.h \
animatedsprite.cpp \
animatedsprite.h \
animationparticle.cpp \
@@ -309,8 +315,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
avatar.h \
being.cpp \
being.h \
- beingmanager.cpp \
- beingmanager.h \
+ chatlog.cpp \
+ chatlog.h \
client.cpp \
client.h \
channel.cpp \
@@ -319,6 +325,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
channelmanager.h \
commandhandler.cpp \
commandhandler.h \
+ compoundsprite.cpp \
+ compoundsprite.h \
configlistener.h \
configuration.cpp \
configuration.h \
@@ -329,8 +337,6 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
equipment.h \
flooritem.cpp \
flooritem.h \
- flooritemmanager.cpp \
- flooritemmanager.h \
game.cpp \
game.h \
graphics.cpp \
@@ -340,6 +346,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
guild.h \
imageparticle.cpp \
imageparticle.h \
+ imagesprite.cpp \
+ imagesprite.h \
inventory.cpp \
inventory.h \
item.cpp \
@@ -358,10 +366,6 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
main.h \
map.cpp\
map.h \
- monster.cpp\
- monster.h \
- npc.cpp \
- npc.h \
openglgraphics.cpp\
openglgraphics.h \
particle.cpp \
@@ -373,8 +377,6 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
particleemitterprop.h \
party.cpp \
party.h \
- player.cpp \
- player.h \
playerrelations.cpp \
playerrelations.h \
position.cpp \
diff --git a/src/actor.cpp b/src/actor.cpp
new file mode 100644
index 00000000..44a89600
--- /dev/null
+++ b/src/actor.cpp
@@ -0,0 +1,58 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "actor.h"
+
+#include "map.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+Actor::Actor():
+ mMap(NULL)
+{}
+
+Actor::~Actor()
+{
+ setMap(NULL);
+}
+
+void Actor::setMap(Map *map)
+{
+ // Remove Actor from potential previous map
+ if (mMap)
+ mMap->removeActor(mMapActor);
+
+ mMap = map;
+
+ // Add Actor to potential new map
+ if (mMap)
+ mMapActor = mMap->addActor(this);
+}
+
+int Actor::getTileX() const
+{
+ return getPixelX() / mMap->getTileWidth();
+}
+
+int Actor::getTileY() const
+{
+ return getPixelY() / mMap->getTileHeight();
+}
diff --git a/src/actor.h b/src/actor.h
new file mode 100644
index 00000000..367bcd75
--- /dev/null
+++ b/src/actor.h
@@ -0,0 +1,128 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ACTOR_H
+#define ACTOR_H
+
+#include "vector.h"
+
+#include <list>
+
+class Actor;
+class Graphics;
+class Image;
+class Map;
+
+typedef std::list<Actor*> Actors;
+
+class Actor
+{
+public:
+ Actor();
+
+ virtual ~Actor();
+
+ /**
+ * Draws the Actor to the given graphics context.
+ *
+ * Note: this function could be simplified if the graphics context
+ * would support setting a translation offset. It already does this
+ * partly with the clipping rectangle support.
+ */
+ virtual bool draw(Graphics *graphics, int offsetX, int offsetY) const = 0;
+
+ /**
+ * Returns the horizontal size of the actors graphical representation
+ * in pixels or 0 when it is undefined.
+ */
+ virtual int getWidth() const
+ { return 0; }
+
+ /**
+ * Returns the vertical size of the actors graphical representation
+ * in pixels or 0 when it is undefined.
+ */
+ virtual int getHeight() const
+ { return 0; }
+
+ /**
+ * Returns the pixel position of this actor.
+ */
+ const Vector &getPosition() const
+ { return mPos; }
+
+ /**
+ * Sets the pixel position of this actor.
+ */
+ virtual void setPosition(const Vector &pos)
+ { mPos = pos; }
+
+ /**
+ * Returns the pixels X coordinate of the actor.
+ */
+ int getPixelX() const
+ { return (int) mPos.x; }
+
+ /**
+ * Returns the pixel Y coordinate of the actor.
+ */
+ virtual int getPixelY() const
+ { return (int) mPos.y; }
+
+ /**
+ * Returns the x coordinate in tiles of the actor.
+ */
+ virtual int getTileX() const;
+
+ /**
+ * Returns the y coordinate in tiles of the actor.
+ */
+ virtual int getTileY() const;
+
+ /**
+ * Returns the number of Image layers used to draw the actor.
+ */
+ virtual int getNumberOfLayers() const
+ { return 0; }
+
+ /**
+ * Returns the current alpha value used to draw the actor.
+ */
+ virtual float getAlpha() const = 0;
+
+ /**
+ * Sets the alpha value used to draw the actor.
+ */
+ virtual void setAlpha(float alpha) = 0;
+
+ void setMap(Map *map);
+
+ Map* getMap() const
+ { return mMap; }
+
+protected:
+ Map *mMap;
+ Vector mPos; /**< Position in pixels relative to map. */
+
+private:
+ Actors::iterator mMapActor;
+};
+
+#endif // ACTOR_H
diff --git a/src/actorsprite.cpp b/src/actorsprite.cpp
new file mode 100644
index 00000000..1104d810
--- /dev/null
+++ b/src/actorsprite.cpp
@@ -0,0 +1,453 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "actorsprite.h"
+
+#include "client.h"
+#include "effectmanager.h"
+#include "imagesprite.h"
+#include "localplayer.h"
+#include "log.h"
+#include "simpleanimation.h"
+#include "sound.h"
+#include "statuseffect.h"
+
+#include "gui/theme.h"
+
+#include "net/net.h"
+
+#include "resources/image.h"
+#include "resources/imageset.h"
+#include "resources/resourcemanager.h"
+
+#include <cassert>
+
+#define EFFECTS_FILE "effects.xml"
+
+ImageSet *ActorSprite::targetCursorImages[2][NUM_TC];
+SimpleAnimation *ActorSprite::targetCursor[2][NUM_TC];
+bool ActorSprite::loaded = false;
+
+ActorSprite::ActorSprite(int id):
+ mId(id),
+ mStunMode(0),
+ mStatusParticleEffects(&mStunParticleEffects, false),
+ mChildParticleEffects(&mStatusParticleEffects, false),
+ mMustResetParticles(false),
+ mUsedTargetCursor(NULL)
+{
+ //
+}
+
+ActorSprite::~ActorSprite()
+{
+ setMap(NULL);
+
+ mUsedTargetCursor = NULL;
+
+ if (player_node && player_node->getTarget() == this)
+ player_node->setTarget(NULL);
+}
+
+bool ActorSprite::draw(Graphics *graphics, int offsetX, int offsetY) const
+{
+ // TODO: Eventually, we probably should fix all sprite offsets so that
+ // these translations aren't necessary anymore. The sprites know
+ // best where their base point should be.
+ const int px = getPixelX() + offsetX - 16;
+ // Temporary fix to the Y offset.
+ const int py = getPixelY() + offsetY -
+ ((Net::getNetworkType() == ServerInfo::MANASERV) ? 15 : 32);
+
+ if (mUsedTargetCursor)
+ mUsedTargetCursor->draw(graphics, px, py);
+
+ return drawSpriteAt(graphics, px, py);
+}
+
+bool ActorSprite::drawSpriteAt(Graphics *graphics, int x, int y) const
+{
+ return CompoundSprite::draw(graphics, x, y);
+}
+
+void ActorSprite::logic()
+{
+ // Update sprite animations
+ update(tick_time * MILLISECONDS_IN_A_TICK);
+
+ // Restart status/particle effects, if needed
+ if (mMustResetParticles)
+ {
+ mMustResetParticles = false;
+ for (std::set<int>::iterator it = mStatusEffects.begin();
+ it != mStatusEffects.end(); it++)
+ {
+ const StatusEffect *effect = StatusEffect::getStatusEffect(*it, true);
+ if (effect && effect->particleEffectIsPersistent())
+ updateStatusEffect(*it, true);
+ }
+ }
+
+ // Update particle effects
+ mChildParticleEffects.moveTo(mPos.x, mPos.y);
+}
+
+void ActorSprite::actorLogic()
+{
+ // Update sprite animations
+ for (int size = TC_SMALL; size < NUM_TC; size++)
+ {
+ for (int type = TCT_NORMAL; type < NUM_TCT; type++)
+ {
+ if (targetCursor[type][size])
+ targetCursor[type][size]->update(tick_time * MILLISECONDS_IN_A_TICK);
+ }
+ }
+}
+
+void ActorSprite::setMap(Map* map)
+{
+ Actor::setMap(map);
+
+ // Clear particle effect list because child particles became invalid
+ mChildParticleEffects.clear();
+ mMustResetParticles = true; // Reset status particles on next redraw
+}
+
+void ActorSprite::controlParticle(Particle *particle)
+{
+ mChildParticleEffects.addLocally(particle);
+}
+
+void ActorSprite::setTargetType(TargetCursorType type)
+{
+ if (type == TCT_NONE)
+ untarget();
+ else
+ mUsedTargetCursor = targetCursor[type][getTargetCursorSize()];
+}
+
+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(EFFECTS_FILE);
+ xmlNodePtr root = doc.rootNode();
+
+ if (!root || !xmlStrEqual(root->name, BAD_CAST "being-effects"))
+ {
+ logger->log("Error loading being effects file: "
+ 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];
+
+ return ed ? ed : default_effect;
+}
+
+void ActorSprite::setStatusEffect(int index, bool active)
+{
+ const bool wasActive = mStatusEffects.find(index) != mStatusEffects.end();
+
+ if (active != wasActive)
+ {
+ updateStatusEffect(index, active);
+ if (active)
+ mStatusEffects.insert(index);
+ else
+ mStatusEffects.erase(index);
+ }
+}
+
+void ActorSprite::setStatusEffectBlock(int offset, Uint16 newEffects)
+{
+ for (int i = 0; i < STATUS_EFFECTS; i++)
+ {
+ int index = StatusEffect::blockEffectIndexToEffectIndex(offset + i);
+
+ if (index != -1)
+ setStatusEffect(index, (newEffects & (1 << i)) > 0);
+ }
+}
+
+void ActorSprite::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.empty())
+ {
+ Particle *selfFX;
+
+ selfFX = particleEngine->addEffect(ed->mGFXEffect, 0, 0);
+ controlParticle(selfFX);
+ }
+
+ if (sfx && !ed->mSFXEffect.empty())
+ sound.playSfx(ed->mSFXEffect);
+}
+
+void ActorSprite::updateStunMode(int oldMode, int newMode)
+{
+ handleStatusEffect(StatusEffect::getStatusEffect(oldMode, false), -1);
+ handleStatusEffect(StatusEffect::getStatusEffect(newMode, true), -1);
+}
+
+void ActorSprite::updateStatusEffect(int index, bool newStatus)
+{
+ handleStatusEffect(StatusEffect::getStatusEffect(index, newStatus), index);
+}
+
+void ActorSprite::handleStatusEffect(StatusEffect *effect, int effectId)
+{
+ if (!effect)
+ return;
+
+ // TODO: Find out how this is meant to be used
+ // (SpriteAction != Being::Action)
+ //SpriteAction action = effect->getAction();
+ //if (action != ACTION_INVALID)
+ // setAction(action);
+
+ Particle *particle = effect->getParticle();
+
+ if (effectId >= 0)
+ {
+ mStatusParticleEffects.setLocally(effectId, particle);
+ }
+ else
+ {
+ mStunParticleEffects.clearLocally();
+ if (particle)
+ mStunParticleEffects.addLocally(particle);
+ }
+}
+
+void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display,
+ bool forceDisplay)
+{
+ clear();
+
+ SpriteRefs it, it_end;
+
+ for (it = display.sprites.begin(), it_end = display.sprites.end();
+ it != it_end; it++)
+ {
+ std::string file = "graphics/sprites/" + (*it)->sprite;
+ int variant = (*it)->variant;
+ addSprite(AnimatedSprite::load(file, variant));
+ }
+
+ // Ensure that something is shown, if desired
+ if (size() == 0 && forceDisplay)
+ {
+ if (display.image.empty())
+ addSprite(AnimatedSprite::load("graphics/sprites/error.xml"));
+ else
+ {
+ ResourceManager *resman = ResourceManager::getInstance();
+ std::string imagePath = "graphics/items/" + display.image;
+ Image *img = resman->getImage(imagePath);
+
+ if (!img)
+ img = Theme::getImageFromTheme("unknown-item.png");
+
+ addSprite(new ImageSprite(img));
+ }
+ }
+
+ mChildParticleEffects.clear();
+
+ //setup particle effects
+ if (Particle::enabled)
+ {
+ std::list<std::string>::const_iterator it, it_end;
+ for (it = display.particles.begin(), it_end = display.particles.end();
+ it != it_end; it++)
+ {
+ Particle *p = particleEngine->addEffect(*it, 0, 0);
+ controlParticle(p);
+ }
+ }
+
+ mMustResetParticles = true;
+}
+
+void ActorSprite::load()
+{
+ if (loaded)
+ unload();
+
+ initTargetCursor();
+
+ loaded = true;
+}
+
+void ActorSprite::unload()
+{
+ if (!loaded)
+ return;
+
+ cleanupTargetCursors();
+ loaded = false;
+}
+
+static const char *cursorType(int type)
+{
+ switch (type)
+ {
+ case ActorSprite::TCT_IN_RANGE:
+ return "in-range";
+ case ActorSprite::TCT_NORMAL:
+ return "normal";
+ default:
+ assert(false);
+ }
+}
+
+static const char *cursorSize(int size)
+{
+ switch (size)
+ {
+ case ActorSprite::TC_LARGE:
+ return "l";
+ case ActorSprite::TC_MEDIUM:
+ return "m";
+ case ActorSprite::TC_SMALL:
+ return "s";
+ default:
+ assert(false);
+ }
+}
+
+void ActorSprite::initTargetCursor()
+{
+ static std::string targetCursor = "graphics/target-cursor-%s-%s.png";
+ static int targetWidths[NUM_TC] = {44, 62, 82};
+ static int targetHeights[NUM_TC] = {35, 44, 60};
+
+ // Load target cursors
+ for (int size = TC_SMALL; size < NUM_TC; size++)
+ {
+ for (int type = TCT_NORMAL; type < NUM_TCT; type++)
+ {
+ loadTargetCursor(strprintf(targetCursor.c_str(), cursorType(type),
+ cursorSize(size)), targetWidths[size],
+ targetHeights[size], type, size);
+ }
+ }
+}
+
+void ActorSprite::cleanupTargetCursors()
+{
+ for (int size = TC_SMALL; size < NUM_TC; size++)
+ {
+ for (int type = TCT_NORMAL; type < NUM_TCT; type++)
+ {
+ delete targetCursor[type][size];
+ if (targetCursorImages[type][size])
+ targetCursorImages[type][size]->decRef();
+ }
+ }
+}
+
+void ActorSprite::loadTargetCursor(const std::string &filename,
+ int width, int height, int type, int size)
+{
+ assert(size > -1);
+ assert(size < 3);
+
+ ResourceManager *resman = ResourceManager::getInstance();
+ ImageSet *currentImageSet = resman->getImageSet(filename, width, height);
+
+ if (!currentImageSet)
+ {
+ logger->log("Error loading target cursor: %s", filename.c_str());
+ return;
+ }
+
+ Animation *anim = new Animation;
+
+ for (unsigned int i = 0; i < currentImageSet->size(); ++i)
+ {
+ anim->addFrame(currentImageSet->get(i), 750,
+ (16 - (currentImageSet->getWidth() / 2)),
+ (16 - (currentImageSet->getHeight() / 2)));
+ }
+
+ SimpleAnimation *currentCursor = new SimpleAnimation(anim);
+
+ targetCursorImages[type][size] = currentImageSet;
+ targetCursor[type][size] = currentCursor;
+}
diff --git a/src/actorsprite.h b/src/actorsprite.h
new file mode 100644
index 00000000..e218ef74
--- /dev/null
+++ b/src/actorsprite.h
@@ -0,0 +1,232 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ACTORSPRITE_H
+#define ACTORSPRITE_H
+
+#include "actor.h"
+#include "compoundsprite.h"
+#include "map.h"
+#include "particlecontainer.h"
+
+#include <SDL_types.h>
+
+#include <set>
+
+class SimpleAnimation;
+class StatusEffect;
+
+class ActorSprite : public CompoundSprite, public Actor
+{
+public:
+ enum Type
+ {
+ UNKNOWN,
+ PLAYER,
+ NPC,
+ MONSTER,
+ FLOOR_ITEM
+ };
+
+ enum TargetCursorSize
+ {
+ TC_SMALL = 0,
+ TC_MEDIUM,
+ TC_LARGE,
+ NUM_TC
+ };
+
+ enum TargetCursorType
+ {
+ TCT_NONE = -1,
+ TCT_NORMAL = 0,
+ TCT_IN_RANGE,
+ NUM_TCT
+ };
+
+ ActorSprite(int id);
+
+ ~ActorSprite();
+
+ int getId() const
+ { return mId; }
+
+ void setId(int id) { mId = id; }
+
+ /**
+ * Returns the type of the ActorSprite.
+ */
+ virtual Type getType() const { return UNKNOWN; }
+
+ virtual bool draw(Graphics *graphics, int offsetX, int offsetY) const;
+
+ virtual bool drawSpriteAt(Graphics *graphics, int x, int y) const;
+
+ virtual void logic();
+
+ static void actorLogic();
+
+ void setMap(Map* map);
+
+ /**
+ * Gets the way the object blocks pathfinding for other objects
+ */
+ virtual Map::BlockType getBlockType() const
+ { return Map::BLOCKTYPE_NONE; }
+
+ /**
+ * Take control of a particle.
+ */
+ void controlParticle(Particle *particle);
+
+ /**
+ * Returns the required size of a target cursor for this being.
+ */
+ virtual TargetCursorSize getTargetCursorSize() const
+ { return TC_MEDIUM; }
+
+ /**
+ * Sets the target animation for this actor.
+ */
+ void setTargetType(TargetCursorType type);
+
+ /**
+ * Untargets the actor.
+ */
+ void untarget() { mUsedTargetCursor = NULL; }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Sets the actor's stun mode. If zero, the being is `normal', otherwise it
+ * is `stunned' in some fashion.
+ */
+ void setStunMode(int stunMode)
+ {
+ if (mStunMode != stunMode)
+ updateStunMode(mStunMode, stunMode);
+ mStunMode = stunMode;
+ }
+
+ void setStatusEffect(int index, bool active);
+
+ /**
+ * A status effect block is a 16 bit mask of status effects. We assign each
+ * such flag a block ID of offset + bitnr.
+ *
+ * These are NOT the same as the status effect indices.
+ */
+ void setStatusEffectBlock(int offset, Uint16 flags);
+
+ virtual void setAlpha(float alpha)
+ { CompoundSprite::setAlpha(alpha); }
+
+ virtual float getAlpha() const
+ { return CompoundSprite::getAlpha(); }
+
+ virtual int getWidth() const
+ { return CompoundSprite::getWidth(); }
+
+ virtual int getHeight() const
+ { return CompoundSprite::getHeight(); }
+
+ static void load();
+
+ static void unload();
+
+protected:
+ /**
+ * Trigger visual effect, with components
+ *
+ * \param effectId ID of the effect to trigger
+ * \param sfx Whether to trigger sound effects
+ * \param gfx Whether to trigger graphical effects
+ */
+ void internalTriggerEffect(int effectId, bool sfx, bool gfx);
+
+ /**
+ * Notify self that the stun mode has been updated. Invoked by
+ * setStunMode if something changed.
+ */
+ virtual void updateStunMode(int oldMode, int newMode);
+
+ /**
+ * Notify self that a status effect has flipped.
+ * The new flag is passed.
+ */
+ virtual void updateStatusEffect(int index, bool newStatus);
+
+ /**
+ * Handle an update to a status or stun effect
+ *
+ * \param The StatusEffect to effect
+ * \param effectId -1 for stun, otherwise the effect index
+ */
+ virtual void handleStatusEffect(StatusEffect *effect, int effectId);
+
+ void setupSpriteDisplay(const SpriteDisplay &display,
+ bool forceDisplay = true);
+
+ int mId;
+ Uint16 mStunMode; /**< Stun mode; zero if not stunned */
+ std::set<int> mStatusEffects; /**< set of active status effects */
+
+ ParticleList mStunParticleEffects;
+ ParticleVector mStatusParticleEffects;
+ ParticleList mChildParticleEffects;
+
+private:
+ /** Reset particle status effects on next redraw? */
+ bool mMustResetParticles;
+
+ /** Load the target cursors into memory */
+ static void initTargetCursor();
+
+ /** Remove the target cursors from memory */
+ static void cleanupTargetCursors();
+
+ /**
+ * Helper function for loading target cursors
+ */
+ static void loadTargetCursor(const std::string &filename,
+ int width, int height, int type, int size);
+
+ /** Images of the target cursor. */
+ static ImageSet *targetCursorImages[NUM_TCT][NUM_TC];
+
+ /** Animated target cursors. */
+ static SimpleAnimation *targetCursor[NUM_TCT][NUM_TC];
+
+ static bool loaded;
+
+ /** Target cursor being used */
+ SimpleAnimation *mUsedTargetCursor;
+};
+
+#endif // ACTORSPRITE_H
diff --git a/src/actorspritemanager.cpp b/src/actorspritemanager.cpp
new file mode 100644
index 00000000..ead469c2
--- /dev/null
+++ b/src/actorspritemanager.cpp
@@ -0,0 +1,315 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "actorspritemanager.h"
+
+#include "localplayer.h"
+
+#include "gui/viewport.h"
+
+#include "utils/stringutils.h"
+#include "utils/dtor.h"
+
+#include <cassert>
+
+#define for_actors ActorSpritesConstIterator it, it_end; \
+for (it = mActors.begin(), it_end = mActors.end() ; it != it_end; it++)
+
+class FindBeingFunctor
+{
+ public:
+ bool operator() (ActorSprite *actor)
+ {
+ if (actor->getType() == ActorSprite::FLOOR_ITEM)
+ return false;
+ Being* b = static_cast<Being*>(actor);
+
+ Uint16 other_y = y + ((b->getType() == ActorSprite::NPC) ? 1 : 0);
+ const Vector &pos = b->getPosition();
+ return ((int) pos.x / 32 == x &&
+ ((int) pos.y / 32 == y || (int) pos.y / 32 == other_y) &&
+ b->isAlive() &&
+ (type == ActorSprite::UNKNOWN || b->getType() == type));
+ }
+
+ Uint16 x, y;
+ ActorSprite::Type type;
+} beingFinder;
+
+ActorSpriteManager::ActorSpriteManager()
+{
+}
+
+ActorSpriteManager::~ActorSpriteManager()
+{
+ clear();
+}
+
+void ActorSpriteManager::setMap(Map *map)
+{
+ mMap = map;
+
+ if (player_node)
+ player_node->setMap(map);
+}
+
+void ActorSpriteManager::setPlayer(LocalPlayer *player)
+{
+ player_node = player;
+ mActors.push_back(player);
+}
+
+Being *ActorSpriteManager::createBeing(int id, ActorSprite::Type type, int subtype)
+{
+ Being *being = new Being(id, type, subtype, mMap);
+
+ mActors.push_back(being);
+ return being;
+}
+
+FloorItem *ActorSpriteManager::createItem(int id, int itemId, int x, int y)
+{
+ FloorItem *floorItem = new FloorItem(id, itemId, x, y, mMap);
+
+ mActors.push_back(floorItem);
+ return floorItem;
+}
+
+void ActorSpriteManager::destroy(ActorSprite *actor)
+{
+ if (!actor || actor == player_node)
+ return;
+
+ mDeleteActors.push_back(actor);
+}
+
+Being *ActorSpriteManager::findBeing(int id) const
+{
+ for_actors
+ {
+ ActorSprite *actor = *it;
+ if (actor->getId() == id &&
+ actor->getType() != ActorSprite::FLOOR_ITEM)
+ return static_cast<Being*>(actor);
+ }
+
+ return NULL;
+}
+
+Being *ActorSpriteManager::findBeing(int x, int y, ActorSprite::Type type) const
+{
+ beingFinder.x = x;
+ beingFinder.y = y;
+ beingFinder.type = type;
+
+ ActorSpritesConstIterator it = find_if(mActors.begin(), mActors.end(),
+ beingFinder);
+
+ return (it == mActors.end()) ? NULL : static_cast<Being*>(*it);
+}
+
+Being *ActorSpriteManager::findBeingByPixel(int x, int y) const
+{
+ for_actors
+ {
+ if ((*it)->getType() == ActorSprite::FLOOR_ITEM)
+ continue;
+
+ Being *being = static_cast<Being*>(*it);
+
+ int xtol = being->getWidth() / 2;
+ int uptol = being->getHeight();
+
+ if ((being->isAlive()) &&
+ (being != player_node) &&
+ (being->getPixelX() - xtol <= x) &&
+ (being->getPixelX() + xtol >= x) &&
+ (being->getPixelY() - uptol <= y) &&
+ (being->getPixelY() >= y))
+ return being;
+ }
+
+ return NULL;
+}
+
+FloorItem *ActorSpriteManager::findItem(int id) const
+{
+ for_actors
+ {
+ if ((*it)->getId() == id &&
+ (*it)->getType() == ActorSprite::FLOOR_ITEM)
+ {
+ return static_cast<FloorItem*>(*it);
+ }
+ }
+
+ return NULL;
+}
+
+FloorItem *ActorSpriteManager::findItem(int x, int y) const
+{
+ for_actors
+ {
+ if ((*it)->getTileX() == x && (*it)->getTileY() == y &&
+ (*it)->getType() == ActorSprite::FLOOR_ITEM)
+ {
+ return static_cast<FloorItem*>(*it);
+ }
+ }
+
+ return NULL;
+}
+
+Being *ActorSpriteManager::findBeingByName(const std::string &name,
+ ActorSprite::Type type) const
+{
+ for_actors
+ {
+ if ((*it)->getType() == ActorSprite::FLOOR_ITEM)
+ continue;
+
+ Being *being = static_cast<Being*>(*it);
+ if (being->getName() == name &&
+ (type == ActorSprite::UNKNOWN || type == being->getType()))
+ return being;
+ }
+ return NULL;
+}
+
+const ActorSprites &ActorSpriteManager::getAll() const
+{
+ return mActors;
+}
+
+void ActorSpriteManager::logic()
+{
+ for_actors
+ (*it)->logic();
+
+ for (it = mDeleteActors.begin(), it_end = mDeleteActors.end();
+ it != it_end; ++it)
+ {
+ viewport->clearHover(*it);
+ mActors.remove(*it);
+ delete *it;
+ }
+
+ mDeleteActors.clear();
+}
+
+void ActorSpriteManager::clear()
+{
+ if (player_node)
+ {
+ player_node->setTarget(0);
+ mActors.remove(player_node);
+ }
+
+ delete_all(mActors);
+ mActors.clear();
+ mDeleteActors.clear();
+
+ if (player_node)
+ mActors.push_back(player_node);
+}
+
+Being *ActorSpriteManager::findNearestLivingBeing(int x, int y,
+ int maxTileDist,
+ ActorSprite::Type type,
+ Being *excluded) const
+{
+ Being *closestBeing = 0;
+ int dist = 0;
+
+ const int maxDist = maxTileDist * 32;
+
+ for_actors
+ {
+ if ((*it)->getType() == ActorSprite::FLOOR_ITEM)
+ continue;
+
+ Being *being = static_cast<Being*>(*it);
+ const Vector &pos = being->getPosition();
+ int d = abs(((int) pos.x) - x) + abs(((int) pos.y) - y);
+
+ if ((being->getType() == type || type == ActorSprite::UNKNOWN)
+ && (d < dist || !closestBeing) // it is closer
+ && being->isAlive() // no dead beings
+ && being != excluded)
+ {
+ dist = d;
+ closestBeing = being;
+ }
+ }
+
+ return (maxDist >= dist) ? closestBeing : 0;
+}
+
+Being *ActorSpriteManager::findNearestLivingBeing(Being *aroundBeing,
+ int maxDist,
+ ActorSprite::Type type) const
+{
+ const Vector &pos = aroundBeing->getPosition();
+ return findNearestLivingBeing((int)pos.x, (int)pos.y, maxDist, type,
+ aroundBeing);
+}
+
+bool ActorSpriteManager::hasActorSprite(ActorSprite *actor) const
+{
+ for_actors
+ {
+ if (actor == *it)
+ return true;
+ }
+
+ return false;
+}
+
+void ActorSpriteManager::getPlayerNames(std::vector<std::string> &names,
+ bool npcNames)
+{
+ names.clear();
+
+ for_actors
+ {
+ if ((*it)->getType() == ActorSprite::FLOOR_ITEM)
+ continue;
+
+ Being *being = static_cast<Being*>(*it);
+ if ((being->getType() == ActorSprite::PLAYER
+ || (being->getType() == ActorSprite::NPC && npcNames))
+ && being->getName() != "")
+ names.push_back(being->getName());
+ }
+}
+
+void ActorSpriteManager::updatePlayerNames()
+{
+ for_actors
+ {
+ if ((*it)->getType() == ActorSprite::FLOOR_ITEM)
+ continue;
+
+ Being *being = static_cast<Being*>(*it);
+ if (being->getType() == ActorSprite::PLAYER && being->getName() != "")
+ being->updateName();
+ }
+}
diff --git a/src/beingmanager.h b/src/actorspritemanager.h
index 7fd63afe..93a2f4ed 100644
--- a/src/beingmanager.h
+++ b/src/actorspritemanager.h
@@ -19,25 +19,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef BEINGMANAGER_H
-#define BEINGMANAGER_H
+#ifndef ACTORSPRITEMANAGER_H
+#define ACTORSPRITEMANAGER_H
+#include "actorsprite.h"
#include "being.h"
+#include "flooritem.h"
class LocalPlayer;
class Map;
-typedef std::list<Being*> Beings;
+typedef std::list<ActorSprite*> ActorSprites;
+typedef ActorSprites::iterator ActorSpritesIterator;
+typedef ActorSprites::const_iterator ActorSpritesConstIterator;
-class BeingManager
+class ActorSpriteManager
{
public:
- BeingManager();
+ ActorSpriteManager();
- ~BeingManager();
+ ~ActorSpriteManager();
/**
- * Sets the map on which beings are created.
+ * Sets the map on which ActorSprites are created.
*/
void setMap(Map *map);
@@ -47,27 +51,48 @@ class BeingManager
void setPlayer(LocalPlayer *player);
/**
- * Create a being and add it to the list of beings.
+ * Create a Being and add it to the list of ActorSprites.
*/
- Being *createBeing(int id, Being::Type type, int subtype);
+ Being *createBeing(int id, ActorSprite::Type type, int subtype);
/**
- * Remove a Being.
+ * Create a FloorItem and add it to the list of ActorSprites.
*/
- void destroyBeing(Being *being);
+ FloorItem *createItem(int id, int itemId, int x, int y);
/**
- * Returns a specific id Being.
+ * Destroys the given ActorSprite at the end of
+ * ActorSpriteManager::logic.
+ */
+ void destroy(ActorSprite *actor);
+
+ /**
+ * Returns a specific Being, by id;
*/
Being *findBeing(int id) const;
/**
* Returns a being at specific coordinates.
*/
- Being *findBeing(int x, int y, Being::Type type = Being::UNKNOWN) const;
+ Being *findBeing(int x, int y,
+ ActorSprite::Type type = ActorSprite::UNKNOWN) const;
+
+ /**
+ * Returns a being at the specific pixel.
+ */
Being *findBeingByPixel(int x, int y) const;
/**
+ * Returns a specific FloorItem, by id.
+ */
+ FloorItem *findItem(int id) const;
+
+ /**
+ * Returns a FloorItem at specific coordinates.
+ */
+ FloorItem *findItem(int x, int y) const;
+
+ /**
* Returns a being nearest to specific coordinates.
*
* @param x X coordinate in pixels.
@@ -78,7 +103,7 @@ class BeingManager
* @param excluded The being to exclude from the search.
*/
Being *findNearestLivingBeing(int x, int y, int maxTileDist,
- Being::Type type = Being::UNKNOWN,
+ ActorSprite::Type type = Being::UNKNOWN,
Being *excluded = 0) const;
/**
@@ -90,35 +115,35 @@ class BeingManager
* @param type The type of being to look for.
*/
Being *findNearestLivingBeing(Being *aroundBeing, int maxTileDist,
- Being::Type type = Being::UNKNOWN) const;
+ ActorSprite::Type type = Being::UNKNOWN) const;
/**
* Finds a being by name and (optionally) by type.
*/
Being *findBeingByName(const std::string &name,
- Being::Type type = Being::UNKNOWN) const;
+ ActorSprite::Type type = Being::UNKNOWN) const;
/**
* Returns the whole list of beings.
*/
- const Beings &getAll() const;
+ const ActorSprites &getAll() const;
/**
- * Returns true if the given being is in the manager's list, false
- * otherwise.
+ * Returns true if the given ActorSprite is in the manager's list,
+ * false otherwise.
*
- * \param being the being to search for
+ * \param actor the ActorSprite to search for
*/
- bool hasBeing(Being *being) const;
+ bool hasActorSprite(ActorSprite *actor) const;
/**
- * Performs being logic and deletes dead beings when they have been
- * dead long enough.
+ * Performs ActorSprite logic and deletes ActorSprite scheduled to be
+ * deleted.
*/
void logic();
/**
- * Destroys all beings except the local player
+ * Destroys all ActorSprites except the local player
*/
void clear();
@@ -128,10 +153,11 @@ class BeingManager
void updatePlayerNames();
protected:
- Beings mBeings;
+ ActorSprites mActors;
+ ActorSprites mDeleteActors;
Map *mMap;
};
-extern BeingManager *beingManager;
+extern ActorSpriteManager *actorSpriteManager;
-#endif
+#endif // ACTORSPRITEMANAGER_H
diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp
index 59bf2f88..9ddc001c 100644
--- a/src/animatedsprite.cpp
+++ b/src/animatedsprite.cpp
@@ -41,11 +41,12 @@ AnimatedSprite::AnimatedSprite(SpriteDef *sprite):
mSprite(sprite),
mAction(0),
mAnimation(0),
- mFrame(0),
- mAlpha(1.0f)
+ mFrame(0)
{
assert(mSprite);
+ mAlpha = 1.0f;
+
// Take possession of the sprite
mSprite->incRef();
@@ -69,18 +70,22 @@ AnimatedSprite::~AnimatedSprite()
mSprite->decRef();
}
-void AnimatedSprite::reset()
+bool AnimatedSprite::reset()
{
+ bool ret = mFrameIndex !=0 || mFrameTime != 0 || mLastTime != 0;
+
mFrameIndex = 0;
mFrameTime = 0;
mLastTime = 0;
+
+ return ret;
}
-void AnimatedSprite::play(SpriteAction spriteAction)
+bool AnimatedSprite::play(SpriteAction spriteAction)
{
Action *action = mSprite->getAction(spriteAction);
if (!action)
- return;
+ return false;
mAction = action;
Animation *animation = mAction->getAnimation(mDirection);
@@ -91,10 +96,14 @@ void AnimatedSprite::play(SpriteAction spriteAction)
mFrame = mAnimation->getFrame(0);
reset();
+
+ return true;
}
+
+ return false;
}
-void AnimatedSprite::update(int time)
+bool AnimatedSprite::update(int time)
{
// Avoid freaking out at first frame or when tick_time overflows
if (time < mLastTime || mLastTime == 0)
@@ -102,16 +111,22 @@ void AnimatedSprite::update(int time)
// If not enough time has passed yet, do nothing
if (time <= mLastTime || !mAnimation)
- return;
+ return false;
unsigned int dt = time - mLastTime;
mLastTime = time;
+ Animation *animation = mAnimation;
+ Frame *frame = mFrame;
+
if (!updateCurrentAnimation(dt))
{
// Animation finished, reset to default
play(ACTION_STAND);
}
+
+ // Make sure something actually changed
+ return animation != mAnimation || frame != mFrame;
}
bool AnimatedSprite::updateCurrentAnimation(unsigned int time)
@@ -158,14 +173,14 @@ bool AnimatedSprite::draw(Graphics *graphics, int posX, int posY) const
posY + mFrame->offsetY);
}
-void AnimatedSprite::setDirection(SpriteDirection direction)
+bool AnimatedSprite::setDirection(SpriteDirection direction)
{
if (mDirection != direction)
{
mDirection = direction;
if (!mAction)
- return;
+ return false;
Animation *animation = mAction->getAnimation(mDirection);
@@ -175,7 +190,21 @@ void AnimatedSprite::setDirection(SpriteDirection direction)
mFrame = mAnimation->getFrame(0);
reset();
}
+
+ return true;
}
+
+ return false;
+}
+
+size_t AnimatedSprite::getCurrentFrame() const
+{
+ return mFrameIndex;
+}
+
+size_t AnimatedSprite::getFrameCount() const
+{
+ return mAnimation->getLength();
}
int AnimatedSprite::getWidth() const
@@ -193,3 +222,8 @@ int AnimatedSprite::getHeight() const
else
return 0;
}
+
+const Image* AnimatedSprite::getImage() const
+{
+ return mFrame ? mFrame->image : 0;
+}
diff --git a/src/animatedsprite.h b/src/animatedsprite.h
index 54b63cc0..67e9c7cb 100644
--- a/src/animatedsprite.h
+++ b/src/animatedsprite.h
@@ -22,19 +22,18 @@
#ifndef ANIMATEDSPRITE_H
#define ANIMATEDSPRITE_H
-#include "resources/spritedef.h"
+#include "sprite.h"
#include <map>
#include <string>
class Animation;
-class Graphics;
struct Frame;
/**
* Animates a sprite by adding playback state.
*/
-class AnimatedSprite
+class AnimatedSprite : public Sprite
{
public:
/**
@@ -53,59 +52,30 @@ class AnimatedSprite
static AnimatedSprite *load(const std::string &filename,
int variant = 0);
- /**
- * Destructor.
- */
virtual ~AnimatedSprite();
- /**
- * Resets the animated sprite.
- */
- void reset();
+ bool reset();
- /**
- * Plays an action using the current direction
- */
- void play(SpriteAction action);
+ bool play(SpriteAction action);
- /**
- * Inform the animation of the passed time so that it can output the
- * correct animation frame.
- */
- void update(int time);
+ bool update(int time);
- /**
- * Draw the current animation frame at the coordinates given in screen
- * pixels.
- */
bool draw(Graphics* graphics, int posX, int posY) const;
- /**
- * gets the width in pixels of the image of the current frame
- */
int getWidth() const;
- /**
- * gets the height in pixels of the image of the current frame
- */
int getHeight() const;
- /**
- * Sets the direction.
- */
- void setDirection(SpriteDirection direction);
+ const Image* getImage() const;
- /**
- * Sets the alpha value of the animated sprite
- */
- void setAlpha(float alpha)
- { mAlpha = alpha; }
+ bool setDirection(SpriteDirection direction);
- /**
- * Returns the current alpha opacity of the animated sprite.
- */
- virtual float getAlpha() const
- { return mAlpha; }
+ int getNumberOfLayers()
+ { return 1; }
+
+ size_t getCurrentFrame() const;
+
+ size_t getFrameCount() const;
private:
bool updateCurrentAnimation(unsigned int dt);
@@ -120,7 +90,6 @@ class AnimatedSprite
Action *mAction; /**< The currently active action. */
Animation *mAnimation; /**< The currently active animation. */
Frame *mFrame; /**< The currently active frame. */
- float mAlpha; /**< The alpha opacity used to draw */
};
#endif
diff --git a/src/being.cpp b/src/being.cpp
index 5c737c0c..5583b8c2 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -21,104 +21,167 @@
#include "being.h"
+#include "actorspritemanager.h"
#include "animatedsprite.h"
#include "client.h"
#include "configuration.h"
#include "effectmanager.h"
#include "graphics.h"
+#include "guild.h"
#include "localplayer.h"
#include "log.h"
#include "map.h"
#include "particle.h"
+#include "party.h"
#include "simpleanimation.h"
#include "sound.h"
+#include "sprite.h"
#include "text.h"
#include "statuseffect.h"
+#include "gui/buy.h"
+#include "gui/buysell.h"
#include "gui/gui.h"
+#include "gui/npcdialog.h"
+#include "gui/npcpostdialog.h"
+#include "gui/sell.h"
+#include "gui/socialwindow.h"
#include "gui/speechbubble.h"
#include "gui/theme.h"
#include "gui/userpalette.h"
+#include "net/charhandler.h"
+#include "net/gamehandler.h"
+#include "net/net.h"
+#include "net/npchandler.h"
+#include "net/playerhandler.h"
+
+#include "resources/beinginfo.h"
#include "resources/colordb.h"
#include "resources/emotedb.h"
#include "resources/image.h"
#include "resources/itemdb.h"
#include "resources/iteminfo.h"
+#include "resources/monsterdb.h"
+#include "resources/npcdb.h"
#include "resources/resourcemanager.h"
-
#include "utils/dtor.h"
#include "utils/stringutils.h"
#include "utils/xml.h"
-#include "net/net.h"
-#include "net/playerhandler.h"
#include <cassert>
#include <cmath>
-#define BEING_EFFECTS_FILE "effects.xml"
#define HAIR_FILE "hair.xml"
+#define PARTICLE_LOCATION "graphics/particles/"
static const int DEFAULT_BEING_WIDTH = 32;
static const int DEFAULT_BEING_HEIGHT = 32;
-
-
int Being::mNumberOfHairstyles = 1;
// TODO: mWalkTime used by eAthena only
-Being::Being(int id, int subtype, Map *map):
- mFrame(0),
- mWalkTime(0),
+Being::Being(int id, Type type, int subtype, Map *map):
+ ActorSprite(id),
+ mInfo(BeingInfo::Unknown),
+ mActionTime(0),
mEmotion(0), mEmotionTime(0),
mSpeechTime(0),
+ mAttackType(1),
mAttackSpeed(350),
mAction(STAND),
- mSubType(subtype),
- mId(id),
+ mSubType(0xFFFF),
mDirection(DOWN),
mSpriteDirection(DIRECTION_DOWN),
- mMap(NULL),
mDispName(0),
mShowName(false),
mEquippedWeapon(NULL),
mText(0),
- mStunMode(0),
- mAlpha(1.0f),
- mStatusParticleEffects(&mStunParticleEffects, false),
- mChildParticleEffects(&mStatusParticleEffects, false),
- mMustResetParticles(false),
+ mGender(GENDER_UNSPECIFIED),
+ mParty(NULL),
+ mIsGM(false),
+ mType(type),
mX(0), mY(0),
- mDamageTaken(0),
- mUsedTargetCursor(NULL)
+ mDamageTaken(0)
{
setMap(map);
+ setSubtype(subtype);
mSpeechBubble = new SpeechBubble;
- mNameColor = &userPalette->getColor(UserPalette::NPC);
- mTextColor = &Theme::getThemeColor(Theme::CHAT);
mWalkSpeed = Net::getPlayerHandler()->getDefaultWalkSpeed();
+
+ if (getType() == PLAYER)
+ mShowName = config.getValue("visiblenames", 1);
+
+ config.addListener("visiblenames", this);
+
+ if (getType() == PLAYER || getType() == NPC)
+ setShowName(true);
+
+ updateColors();
}
Being::~Being()
{
- mUsedTargetCursor = NULL;
- delete_all(mSprites);
-
- if (player_node && player_node->getTarget() == this)
- player_node->setTarget(NULL);
-
- setMap(NULL);
+ config.removeListener("visiblenames", this);
delete mSpeechBubble;
delete mDispName;
delete mText;
+ mSpeechBubble = 0;
+ mDispName = 0;
+ mText = 0;
+}
+
+void Being::setSubtype(Uint16 subtype)
+{
+ if (subtype == mSubType)
+ return;
+
+ mSubType = subtype;
+
+ if (getType() == MONSTER)
+ {
+ mInfo = MonsterDB::get(mSubType);
+ setName(mInfo->getName());
+ setupSpriteDisplay(mInfo->getDisplay());
+ }
+ else if (getType() == NPC)
+ {
+ mInfo = NPCDB::get(mSubType);
+ setupSpriteDisplay(mInfo->getDisplay(), false);
+ }
+ else if (getType() == PLAYER)
+ {
+ int id = -100 - subtype;
+
+ // Prevent showing errors when sprite doesn't exist
+ if (!ItemDB::exists(id))
+ id = -100;
+
+ setSprite(Net::getCharHandler()->baseSprite(), id);
+ }
+}
+
+ActorSprite::TargetCursorSize Being::getTargetCursorSize() const
+{
+ return mInfo->getTargetCursorSize();
+}
+
+unsigned char Being::getWalkMask() const
+{
+ return mInfo->getWalkMask();
+}
+
+Map::BlockType Being::getBlockType() const
+{
+ return mInfo->getBlockType();
}
void Being::setPosition(const Vector &pos)
{
- mPos = pos;
+ Actor::setPosition(pos);
updateCoords();
@@ -189,7 +252,7 @@ void Being::setPath(const Path &path)
mAction != WALK && mAction != DEAD)
{
nextTile();
- mWalkTime = tick_time;
+ mActionTime = tick_time;
}
}
@@ -292,6 +355,8 @@ void Being::takeDamage(Being *attacker, int amount, AttackType type)
if (amount > 0)
{
+ sound.playSfx(mInfo->getSound(SOUND_EVENT_HURT));
+
if (getType() == MONSTER)
{
mDamageTaken += amount;
@@ -310,42 +375,50 @@ void Being::handleAttack(Being *victim, int damage, AttackType type)
if (this != player_node)
setAction(Being::ATTACK, 1);
- if (getType() == PLAYER && victim)
- {
- if (mEquippedWeapon)
- {
- fireMissile(victim, mEquippedWeapon->getMissileParticle());
- }
- }
+ if (getType() == PLAYER && victim && mEquippedWeapon)
+ fireMissile(victim, mEquippedWeapon->getMissileParticle());
+ else
+ fireMissile(victim, mInfo->getAttack(mAttackType)->missileParticle);
+
if (Net::getNetworkType() == ServerInfo::TMWATHENA)
{
- mFrame = 0;
- mWalkTime = tick_time;
+ reset();
+ mActionTime = tick_time;
}
+
+ sound.playSfx(mInfo->getSound((damage > 0) ?
+ SOUND_EVENT_HIT : SOUND_EVENT_MISS));
}
void Being::setName(const std::string &name)
{
- mName = name;
-
- if (getShowName())
+ if (getType() == NPC)
+ {
+ mName = name.substr(0, name.find('#', 0));
showName();
+ }
+ else
+ {
+ mName = name;
+
+ if (getType() == PLAYER && getShowName())
+ showName();
+ }
}
void Being::setShowName(bool doShowName)
{
- bool oldShow = mShowName;
+ if (mShowName == doShowName)
+ return;
+
mShowName = doShowName;
- if (doShowName != oldShow)
+ if (doShowName)
+ showName();
+ else
{
- if (doShowName)
- showName();
- else
- {
- delete mDispName;
- mDispName = 0;
- }
+ delete mDispName;
+ mDispName = 0;
}
}
@@ -360,26 +433,99 @@ void Being::setGuildPos(const std::string &pos)
logger->log("Got guild position \"%s\" for being %s(%i)", pos.c_str(), mName.c_str(), mId);
}
-void Being::setMap(Map *map)
+void Being::addGuild(Guild *guild)
{
- // Remove sprite from potential previous map
- if (mMap)
- mMap->removeSprite(mMapSprite);
+ mGuilds[guild->getId()] = guild;
+ guild->addMember(mId, mName);
- mMap = map;
+ if (this == player_node && socialWindow)
+ {
+ socialWindow->addTab(guild);
+ }
+}
- // Add sprite to potential new map
- if (mMap)
- mMapSprite = mMap->addSprite(this);
+void Being::removeGuild(int id)
+{
+ if (this == player_node && socialWindow)
+ {
+ socialWindow->removeTab(mGuilds[id]);
+ }
+
+ mGuilds[id]->removeMember(mId);
+ mGuilds.erase(id);
+}
+
+Guild *Being::getGuild(const std::string &guildName) const
+{
+ std::map<int, Guild*>::const_iterator itr, itr_end = mGuilds.end();
+ for (itr = mGuilds.begin(); itr != itr_end; ++itr)
+ {
+ Guild *guild = itr->second;
+ if (guild->getName() == guildName)
+ {
+ return guild;
+ }
+ }
+
+ return NULL;
+}
+
+Guild *Being::getGuild(int id) const
+{
+ std::map<int, Guild*>::const_iterator itr;
+ itr = mGuilds.find(id);
+ if (itr != mGuilds.end())
+ {
+ return itr->second;
+ }
+
+ return NULL;
+}
+
+void Being::clearGuilds()
+{
+ std::map<int, Guild*>::const_iterator itr, itr_end = mGuilds.end();
+ for (itr = mGuilds.begin(); itr != itr_end; ++itr)
+ {
+ Guild *guild = itr->second;
- // Clear particle effect list because child particles became invalid
- mChildParticleEffects.clear();
- mMustResetParticles = true; // Reset status particles on next redraw
+ if (this == player_node && socialWindow)
+ socialWindow->removeTab(guild);
+
+ guild->removeMember(mId);
+ }
+
+ mGuilds.clear();
}
-void Being::controlParticle(Particle *particle)
+void Being::setParty(Party *party)
{
- mChildParticleEffects.addLocally(particle);
+ if (party == mParty)
+ return;
+
+ Party *old = mParty;
+ mParty = party;
+
+ if (old)
+ {
+ old->removeMember(mId);
+ }
+
+ if (party)
+ {
+ party->addMember(mId, mName);
+ }
+
+ updateColors();
+
+ if (this == player_node && socialWindow)
+ {
+ if (old)
+ socialWindow->removeTab(old);
+
+ if (party)
+ socialWindow->addTab(party);
+ }
}
void Being::fireMissile(Being *victim, const std::string &particle)
@@ -416,13 +562,40 @@ void Being::setAction(Action action, int attackType)
break;
case ATTACK:
if (mEquippedWeapon)
+ {
currentAction = mEquippedWeapon->getAttackType();
+ reset();
+ }
else
- currentAction = ACTION_ATTACK;
+ {
+ mAttackType = attackType;
+ currentAction = mInfo->getAttack(attackType)->action;
+ reset();
+
+ if (Net::getNetworkType() == ServerInfo::MANASERV)
+ {
+ int rotation = 0;
+ //attack particle effect
+ std::string particleEffect = mInfo->getAttack(attackType)
+ ->particleEffect;
+ if (!particleEffect.empty() && Particle::enabled)
+ {
+ switch (mSpriteDirection)
+ {
+ case DIRECTION_DOWN: rotation = 0; break;
+ case DIRECTION_LEFT: rotation = 90; break;
+ case DIRECTION_UP: rotation = 180; break;
+ case DIRECTION_RIGHT: rotation = 270; break;
+ default: break;
+ }
+ Particle *p;
+ p = particleEngine->addEffect(particleEffect, 0, 0,
+ rotation);
+ controlParticle(p);
+ }
+ }
+ }
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if (*it)
- (*it)->reset();
break;
case HURT:
//currentAction = ACTION_HURT; // Buggy: makes the player stop
@@ -431,6 +604,7 @@ void Being::setAction(Action action, int attackType)
break;
case DEAD:
currentAction = ACTION_DEAD;
+ sound.playSfx(mInfo->getSound(SOUND_EVENT_DIE));
break;
case STAND:
currentAction = ACTION_STAND;
@@ -439,11 +613,12 @@ void Being::setAction(Action action, int attackType)
if (currentAction != ACTION_INVALID)
{
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if (*it)
- (*it)->play(currentAction);
+ play(currentAction);
mAction = action;
}
+
+ if (currentAction != ACTION_WALK)
+ mActionTime = tick_time;
}
void Being::setDirection(Uint8 direction)
@@ -469,9 +644,7 @@ void Being::setDirection(Uint8 direction)
dir = DIRECTION_LEFT;
mSpriteDirection = dir;
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if (*it)
- (*it)->setDirection(dir);
+ CompoundSprite::setDirection(dir);
}
/** TODO: Used by eAthena only */
@@ -507,7 +680,7 @@ void Being::nextTile()
mX = pos.x;
mY = pos.y;
setAction(WALK);
- mWalkTime += (int)(mWalkSpeed.x / 10);
+ mActionTime += (int)(mWalkSpeed.x / 10);
}
int Being::getCollisionRadius() const
@@ -607,6 +780,69 @@ void Being::logic()
}
else if (Net::getNetworkType() == ServerInfo::TMWATHENA)
{
+ int frameCount = getFrameCount();
+
+ switch (mAction)
+ {
+ case STAND:
+ case SIT:
+ case DEAD:
+ case HURT:
+ break;
+
+ case WALK:
+ if ((int) ((get_elapsed_time(mActionTime) * frameCount)
+ / getWalkSpeed().x) >= frameCount)
+ nextTile();
+ break;
+
+ case ATTACK:
+ int rotation = 0;
+ std::string particleEffect = "";
+
+ int curFrame = (get_elapsed_time(mActionTime) * frameCount)
+ / mAttackSpeed;
+
+ //attack particle effect
+ if (mEquippedWeapon)
+ {
+ particleEffect = mEquippedWeapon->getParticleEffect();
+
+ if (!particleEffect.empty() &&
+ findSameSubstring(particleEffect,
+ PARTICLE_LOCATION).empty())
+ particleEffect = PARTICLE_LOCATION +
+ particleEffect;
+ }
+ else
+ {
+ particleEffect = mInfo->getAttack(mAttackType)
+ ->particleEffect;
+ }
+
+ if (!particleEffect.empty() && Particle::enabled
+ && curFrame == 1)
+ {
+ switch (mDirection)
+ {
+ case DOWN: rotation = 0; break;
+ case LEFT: rotation = 90; break;
+ case UP: rotation = 180; break;
+ case RIGHT: rotation = 270; break;
+ default: break;
+ }
+ Particle *p;
+ p = particleEngine->addEffect(particleEffect, 0, 0,
+ rotation);
+ controlParticle(p);
+ }
+
+ if (curFrame >= frameCount)
+ nextTile();
+
+ break;
+ }
+
// Update pixel coordinates
setPosition(mX * 32 + 16 + getXOffset(),
mY * 32 + 32 + getYOffset());
@@ -619,68 +855,18 @@ void Being::logic()
mEmotion = 0;
}
- // Update sprite animations
- if (mUsedTargetCursor)
- mUsedTargetCursor->update(tick_time * MILLISECONDS_IN_A_TICK);
-
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if (*it)
- (*it)->update(tick_time * MILLISECONDS_IN_A_TICK);
-
- // Restart status/particle effects, if needed
- if (mMustResetParticles)
- {
- mMustResetParticles = false;
- for (std::set<int>::iterator it = mStatusEffects.begin();
- it != mStatusEffects.end(); it++)
- {
- const StatusEffect *effect = StatusEffect::getStatusEffect(*it, true);
- if (effect && effect->particleEffectIsPersistent())
- updateStatusEffect(*it, true);
- }
- }
-
- // Update particle effects
- mChildParticleEffects.moveTo(mPos.x, mPos.y);
-}
-
-void Being::draw(Graphics *graphics, int offsetX, int offsetY) const
-{
- // TODO: Eventually, we probably should fix all sprite offsets so that
- // these translations aren't necessary anymore. The sprites know
- // best where their base point should be.
- const int px = getPixelX() + offsetX - 16;
- // Temporary fix to the Y offset.
- const int py = getPixelY() + offsetY -
- ((Net::getNetworkType() == ServerInfo::MANASERV) ? 15 : 32);
-
- if (mUsedTargetCursor)
- mUsedTargetCursor->draw(graphics, px, py);
-
- for (SpriteConstIterator it = mSprites.begin(); it != mSprites.end(); it++)
- {
- if (*it)
- {
- if ((*it)->getAlpha() != mAlpha)
- (*it)->setAlpha(mAlpha);
- (*it)->draw(graphics, px, py);
- }
- }
-}
+ ActorSprite::logic();
-void Being::drawSpriteAt(Graphics *graphics, int x, int y) const
-{
- const int px = x - 16;
- const int py = y - 32;
+ int frameCount = getFrameCount();
+ if (frameCount < 10)
+ frameCount = 10;
- for (SpriteConstIterator it = mSprites.begin(); it != mSprites.end(); it++)
+ if (!isAlive() && Net::getGameHandler()->removeDeadBeings() &&
+ (int) ((get_elapsed_time(mActionTime)
+ / getWalkSpeed().x) >= frameCount))
{
- if (*it)
- {
- if ((*it)->getAlpha() != mAlpha)
- (*it)->setAlpha(mAlpha);
- (*it)->draw(graphics, px, py);
- }
+ if (getType() != PLAYER)
+ actorSpriteManager->destroy(this);
}
}
@@ -751,67 +937,6 @@ void Being::drawSpeech(int offsetX, int offsetY)
}
}
-void Being::setStatusEffectBlock(int offset, Uint16 newEffects)
-{
- for (int i = 0; i < STATUS_EFFECTS; i++)
- {
- int index = StatusEffect::blockEffectIndexToEffectIndex(offset + i);
-
- if (index != -1)
- setStatusEffect(index, (newEffects & (1 << i)) > 0);
- }
-}
-
-void Being::handleStatusEffect(StatusEffect *effect, int effectId)
-{
- if (!effect)
- return;
-
- // TODO: Find out how this is meant to be used
- // (SpriteAction != Being::Action)
- //SpriteAction action = effect->getAction();
- //if (action != ACTION_INVALID)
- // setAction(action);
-
- Particle *particle = effect->getParticle();
-
- if (effectId >= 0)
- {
- mStatusParticleEffects.setLocally(effectId, particle);
- }
- else
- {
- mStunParticleEffects.clearLocally();
- if (particle)
- mStunParticleEffects.addLocally(particle);
- }
-}
-
-void Being::updateStunMode(int oldMode, int newMode)
-{
- handleStatusEffect(StatusEffect::getStatusEffect(oldMode, false), -1);
- handleStatusEffect(StatusEffect::getStatusEffect(newMode, true), -1);
-}
-
-void Being::updateStatusEffect(int index, bool newStatus)
-{
- handleStatusEffect(StatusEffect::getStatusEffect(index, newStatus), index);
-}
-
-void Being::setStatusEffect(int index, bool active)
-{
- const bool wasActive = mStatusEffects.find(index) != mStatusEffects.end();
-
- if (active != wasActive)
- {
- updateStatusEffect(index, active);
- if (active)
- mStatusEffects.insert(index);
- else
- mStatusEffects.erase(index);
- }
-}
-
/** TODO: eAthena only */
int Being::getOffset(char pos, char neg) const
{
@@ -824,9 +949,9 @@ int Being::getOffset(char pos, char neg) const
if (mMap)
{
offset = (pos == LEFT && neg == RIGHT) ?
- (int)((get_elapsed_time(mWalkTime)
+ (int)((get_elapsed_time(mActionTime)
* mMap->getTileWidth()) / mWalkSpeed.x) :
- (int)((get_elapsed_time(mWalkTime)
+ (int)((get_elapsed_time(mActionTime)
* mMap->getTileHeight()) / mWalkSpeed.y);
}
@@ -844,176 +969,182 @@ int Being::getOffset(char pos, char neg) const
int Being::getWidth() const
{
- AnimatedSprite *base = NULL;
-
- for (SpriteConstIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if ((base = (*it)))
- break;
-
- if (base)
- return std::max(base->getWidth(), DEFAULT_BEING_WIDTH);
-
- return DEFAULT_BEING_WIDTH;
+ return std::max(CompoundSprite::getWidth(), DEFAULT_BEING_WIDTH);
}
int Being::getHeight() const
{
- AnimatedSprite *base = NULL;
-
- for (SpriteConstIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if ((base = (*it)))
- break;
+ return std::max(CompoundSprite::getHeight(), DEFAULT_BEING_HEIGHT);
+}
- if (base)
- return std::max(base->getHeight(), DEFAULT_BEING_HEIGHT);
+void Being::updateCoords()
+{
+ if (!mDispName)
+ return;
- return DEFAULT_BEING_HEIGHT;
+ // Monster names show above the sprite instead of below it
+ if (getType() == MONSTER)
+ mDispName->adviseXY(getPixelX(),
+ getPixelY() - getHeight() - mDispName->getHeight());
+ else
+ mDispName->adviseXY(getPixelX(), getPixelY());
}
-void Being::setTargetAnimation(SimpleAnimation *animation)
+void Being::optionChanged(const std::string &value)
{
- mUsedTargetCursor = animation;
- mUsedTargetCursor->reset();
+ if (getType() == PLAYER && value == "visiblenames")
+ {
+ setShowName(config.getValue("visiblenames", 1));
+ }
}
-struct EffectDescription {
- std::string mGFXEffect;
- std::string mSFXEffect;
-};
-
-static EffectDescription *default_effect = NULL;
-static std::map<int, EffectDescription *> effects;
-static bool effects_initialized = false;
-
-static EffectDescription *getEffectDescription(xmlNodePtr node, int *id)
+void Being::flashName(int time)
{
- 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;
+ if (mDispName)
+ mDispName->flash(time);
}
-static EffectDescription *getEffectDescription(int effectId)
+void Being::showName()
{
- if (!effects_initialized)
- {
- XML::Document doc(BEING_EFFECTS_FILE);
- xmlNodePtr root = doc.rootNode();
+ delete mDispName;
+ mDispName = 0;
+ std::string mDisplayName(mName);
- if (!root || !xmlStrEqual(root->name, BAD_CAST "being-effects"))
- {
- logger->log("Error loading being effects file: "
- BEING_EFFECTS_FILE);
- return NULL;
- }
+ if (config.getValue("showgender", false))
+ {
+ if (getGender() == GENDER_FEMALE)
+ mDisplayName += " \u2640";
+ else if (getGender() == GENDER_MALE)
+ mDisplayName += " \u2642";
+ }
- for_each_xml_child_node(node, root)
+ if (getType() == MONSTER)
+ {
+ if (config.getValue("showMonstersTakedDamage", false))
{
- 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;
- }
+ mDisplayName += ", " + toString(getDamageTaken());
}
+ }
- effects_initialized = true;
- } // done initializing
+ gcn::Font *font = 0;
+ if (player_node && player_node->getTarget() == this
+ && getType() != MONSTER)
+ {
+ font = boldFont;
+ }
- EffectDescription *ed = effects[effectId];
+ mDispName = new FlashText(mDisplayName, getPixelX(), getPixelY(),
+ gcn::Graphics::CENTER, mNameColor, font);
- return ed ? ed : default_effect;
+ updateCoords();
}
-void Being::internalTriggerEffect(int effectId, bool sfx, bool gfx)
+void Being::updateColors()
{
- logger->log("Special effect #%d on %s", effectId,
- getId() == player_node->getId() ? "self" : "other");
-
- EffectDescription *ed = getEffectDescription(effectId);
-
- if (!ed)
+ if (getType() == MONSTER)
{
- logger->log("Unknown special effect and no default recorded");
- return;
+ mNameColor = &userPalette->getColor(UserPalette::MONSTER);
+ mTextColor = &userPalette->getColor(UserPalette::MONSTER);
}
-
- if (gfx && !ed->mGFXEffect.empty())
+ else if (getType() == NPC)
{
- Particle *selfFX;
-
- selfFX = particleEngine->addEffect(ed->mGFXEffect, 0, 0);
- controlParticle(selfFX);
+ mNameColor = &userPalette->getColor(UserPalette::NPC);
+ mTextColor = &userPalette->getColor(UserPalette::NPC);
+ }
+ else if (this == player_node)
+ {
+ mNameColor = &userPalette->getColor(UserPalette::SELF);
+ mTextColor = &Theme::getThemeColor(Theme::PLAYER);
}
+ else
+ {
+ mTextColor = &userPalette->getColor(Theme::PLAYER);
- if (sfx && !ed->mSFXEffect.empty())
- sound.playSfx(ed->mSFXEffect);
-}
+ if (mIsGM)
+ {
+ mTextColor = &userPalette->getColor(UserPalette::GM);
+ mNameColor = &userPalette->getColor(UserPalette::GM);
+ }
+ else if (mParty && mParty == player_node->getParty())
+ {
+ mNameColor = &userPalette->getColor(UserPalette::PARTY);
+ }
+ else
+ {
+ mNameColor = &userPalette->getColor(UserPalette::PC);
+ }
+ }
-void Being::updateCoords()
-{
if (mDispName)
{
- mDispName->adviseXY(getPixelX(), getPixelY());
+ mDispName->setColor(mNameColor);
}
}
-void Being::flashName(int time)
+void Being::setSprite(unsigned int slot, int id, const std::string &color,
+ bool isWeapon)
{
- if (mDispName)
- mDispName->flash(time);
-}
+ assert(slot < Net::getCharHandler()->maxSprite());
-void Being::showName()
-{
- delete mDispName;
- mDispName = 0;
- std::string mDisplayName(mName);
+ if (slot >= size())
+ ensureSize(slot + 1);
- if (getType() == PLAYER)
+ if (slot >= mSpriteIDs.size())
+ mSpriteIDs.resize(slot + 1, 0);
+
+ if (slot >= mSpriteColors.size())
+ mSpriteColors.resize(slot + 1, "");
+
+ // id = 0 means unequip
+ if (id == 0)
{
- if (config.getValue("showgender", false))
- {
- Player* player = static_cast<Player*>(this);
- if (player)
- {
- if (player->getGender() == GENDER_FEMALE)
- mDisplayName += " \u2640";
- else
- mDisplayName += " \u2642";
- }
- }
+ removeSprite(slot);
+
+ if (isWeapon)
+ mEquippedWeapon = NULL;
}
- else if (getType() == MONSTER)
+ else
{
- if (config.getValue("showMonstersTakedDamage", false))
+ std::string filename = ItemDB::get(id).getSprite(mGender);
+ AnimatedSprite *equipmentSprite = NULL;
+
+ if (!filename.empty())
{
- mDisplayName += ", " + toString(getDamageTaken());
+ if (!color.empty())
+ filename += "|" + color;
+
+ equipmentSprite = AnimatedSprite::load("graphics/sprites/" +
+ filename);
}
+
+ if (equipmentSprite)
+ equipmentSprite->setDirection(getSpriteDirection());
+
+ CompoundSprite::setSprite(slot, equipmentSprite);
+
+ if (isWeapon)
+ mEquippedWeapon = &ItemDB::get(id);
+
+ setAction(mAction);
}
- mDispName = new FlashText(mDisplayName, getPixelX(), getPixelY(),
- gcn::Graphics::CENTER, mNameColor);
+ mSpriteIDs[slot] = id;
+ mSpriteColors[slot] = color;
+}
+
+void Being::setSpriteID(unsigned int slot, int id)
+{
+ setSprite(slot, id, mSpriteColors[slot]);
+}
+
+void Being::setSpriteColor(unsigned int slot, const std::string &color)
+{
+ setSprite(slot, mSpriteIDs[slot], color);
}
int Being::getNumberOfLayers() const
{
- return mSprites.size();
+ return CompoundSprite::getNumberOfLayers();
}
void Being::load()
@@ -1033,3 +1164,44 @@ void Being::updateName()
if (mShowName)
showName();
}
+
+void Being::setGender(Gender gender)
+{
+ if (gender != mGender)
+ {
+ mGender = gender;
+
+ // Reload all subsprites
+ for (unsigned int i = 0; i < mSpriteIDs.size(); i++)
+ {
+ if (mSpriteIDs.at(i) != 0)
+ setSprite(i, mSpriteIDs.at(i), mSpriteColors.at(i));
+ }
+
+ updateName();
+ }
+}
+
+void Being::setGM(bool gm)
+{
+ mIsGM = gm;
+
+ updateColors();
+}
+
+bool Being::canTalk()
+{
+ return mType == NPC;
+}
+
+void Being::talkTo()
+{
+ Net::getNpcHandler()->talk(mId);
+}
+
+bool Being::isTalking()
+{
+ return NpcDialog::isActive() || BuyDialog::isActive() ||
+ SellDialog::isActive() || BuySellDialog::isActive() ||
+ NpcPostDialog::isActive();
+}
diff --git a/src/being.h b/src/being.h
index 3d3dfa71..75bb6c22 100644
--- a/src/being.h
+++ b/src/being.h
@@ -22,19 +22,18 @@
#ifndef BEING_H
#define BEING_H
+#include "actorsprite.h"
#include "configlistener.h"
#include "map.h"
#include "particlecontainer.h"
#include "position.h"
-#include "sprite.h"
#include "vector.h"
-#include "resources/spritedef.h"
-
#include <guichan/color.hpp>
#include <SDL_types.h>
+#include <map>
#include <set>
#include <string>
#include <vector>
@@ -45,31 +44,27 @@
#define SPEECH_TIME 500
#define SPEECH_MAX_TIME 1000
-class AnimatedSprite;
+class BeingInfo;
class FlashText;
-class Graphics;
-class Image;
+class Guild;
class ItemInfo;
class Item;
class Particle;
+class Party;
class Position;
-class SimpleAnimation;
class SpeechBubble;
class Text;
-class StatusEffect;
+enum Gender
+{
+ GENDER_MALE = 0,
+ GENDER_FEMALE = 1,
+ GENDER_UNSPECIFIED = 2
+};
-class Being : public Sprite, public ConfigListener
+class Being : public ActorSprite, public ConfigListener
{
public:
- enum Type
- {
- UNKNOWN,
- PLAYER,
- NPC,
- MONSTER
- };
-
/**
* Action the being is currently performing
* WARNING: Has to be in sync with the same enum in the Being class
@@ -85,14 +80,6 @@ class Being : public Sprite, public ConfigListener
HURT
};
- enum TargetCursorSize
- {
- TC_SMALL = 0,
- TC_MEDIUM,
- TC_LARGE,
- NUM_TC
- };
-
enum Speech
{
NO_SPEECH = 0,
@@ -122,29 +109,27 @@ class Being : public Sprite, public ConfigListener
* @param subtype partly determines the type of the being
* @param map the map the being is on
*/
- Being(int id, int subtype, Map *map);
+ Being(int id, Type type, int subtype, Map *map);
virtual ~Being();
+ Type getType() const { return mType; }
+
/**
* Removes all path nodes from this being.
*/
void clearPath();
/**
- * Returns the walk time.
- * Used to know which frame to display and trigger
- * the next Tile step.
- * TODO: Used by eAthena only?
+ * Returns the time spent in the current action.
*/
- int getWalkTime() const { return mWalkTime; }
+ int getActionTime() const { return mActionTime; }
/**
- * Set the current WalkTime value.
- * TODO: Used by eAthena only?
+ * Set the current action time.
* @see Ea::BeingHandler that set it to tick time.
*/
- void setWalkTime(int walkTime) { mWalkTime = walkTime; }
+ void setActionTime(int actionTime) { mActionTime = actionTime; }
/**
* Makes this being take the next tile of its path.
@@ -210,7 +195,7 @@ class Being : public Sprite, public ConfigListener
* @param damage the amount of damage recieved (0 means miss)
* @param type the attack type
*/
- virtual void takeDamage(Being *attacker, int damage, AttackType type);
+ void takeDamage(Being *attacker, int damage, AttackType type);
/**
* Handles an attack of another being by this being.
@@ -232,23 +217,82 @@ class Being : public Sprite, public ConfigListener
*
* @param name The name that should appear.
*/
- virtual void setName(const std::string &name);
+ void setName(const std::string &name);
bool getShowName() const
{ return mShowName; }
- virtual void setShowName(bool doShowName);
+ void setShowName(bool doShowName);
/**
- * Following are set from the server (mainly for players)
+ * Sets the name of the party the being is in. Shown in BeingPopup.
*/
void setPartyName(const std::string &name) { mPartyName = name; }
const std::string &getPartyName() const { return mPartyName; }
- virtual void setGuildName(const std::string &name);
+ /**
+ * Sets the name of the primary guild the being is in. Shown in
+ * BeingPopup (eventually).
+ */
+ void setGuildName(const std::string &name);
+
+ void setGuildPos(const std::string &pos);
- virtual void setGuildPos(const std::string &pos);
+ /**
+ * Adds a guild to the being.
+ */
+ void addGuild(Guild *guild);
+
+ /**
+ * Removers a guild from the being.
+ */
+ void removeGuild(int id);
+
+ /**
+ * Returns a pointer to the specified guild that the being is in.
+ */
+ Guild *getGuild(const std::string &guildName) const;
+
+ /**
+ * Returns a pointer to the specified guild that the being is in.
+ */
+ Guild *getGuild(int id) const;
+
+ /**
+ * Returns all guilds the being is in.
+ */
+ const std::map<int, Guild*> &getGuilds() const
+ { return mGuilds; }
+
+ /**
+ * Removes all guilds the being is in.
+ */
+ void clearGuilds();
+
+ /**
+ * Get number of guilds the being belongs to.
+ */
+ short getNumberOfGuilds() const
+ { return mGuilds.size(); }
+
+ bool isInParty() const
+ { return mParty != NULL; }
+
+ void setParty(Party *party);
+
+ Party *getParty() const
+ { return mParty; }
+
+ /**
+ * Sets visible equipments for this being.
+ */
+ void setSprite(unsigned int slot, int id,
+ const std::string &color = "", bool isWeapon = false);
+
+ void setSpriteID(unsigned int slot, int id);
+
+ void setSpriteColor(unsigned int slot, const std::string &color = "");
/**
* Get the number of hairstyles implemented
@@ -276,20 +320,27 @@ class Being : public Sprite, public ConfigListener
*/
void drawEmotion(Graphics *graphics, int offsetX, int offsetY);
- /**
- * Returns the type of the being.
- */
- virtual Type getType() const { return UNKNOWN; }
-
- /**
- * Return Being's current Job (player job, npc, monster, creature )
- */
Uint16 getSubType() const { return mSubType; }
/**
- * Set Being's current Job (player job, npc, monster, creature )
+ * Set Being's subtype (mostly for view for monsters and NPCs)
*/
- virtual void setSubtype(Uint16 subtype) { mSubType = subtype; }
+ void setSubtype(Uint16 subtype);
+
+ const BeingInfo *getInfo() const
+ { return mInfo; }
+
+ TargetCursorSize getTargetCursorSize() const;
+
+ /**
+ * Gets the way the object is blocked by other objects.
+ */
+ unsigned char getWalkMask() const;
+
+ /**
+ * Gets the way the monster blocks pathfinding for other objects
+ */
+ Map::BlockType getBlockType() const;
/**
* Sets the walk speed.
@@ -318,18 +369,6 @@ class Being : public Sprite, public ConfigListener
int getAttackSpeed() const { return mAttackSpeed; }
/**
- * Sets the sprite id.
- */
- void setId(int id) { mId = id; }
-
- int getId() const { return mId; }
-
- /**
- * Sets the map the being is on
- */
- void setMap(Map *map);
-
- /**
* Sets the current action.
*/
virtual void setAction(Action action, int attackType = 0);
@@ -355,65 +394,11 @@ class Being : public Sprite, public ConfigListener
void setDirection(Uint8 direction);
/**
- * Returns the being's current sprite frame number.
- */
- int getCurrentFrame() const { return mFrame; }
-
- /**
- * Set the being's current sprite frame number.
- */
- void setFrame(int frame) { mFrame = frame; }
-
- /**
* Returns the direction the being is facing.
*/
SpriteDirection getSpriteDirection() const
{ return SpriteDirection(mSpriteDirection); }
- /**
- * Draws this being to the given graphics context.
- *
- * @see Sprite::draw(Graphics, int, int)
- *
- * TODO: The following two functions should be combined.
- * at some point draw(), was changed to use mPx and mPy, with arugements
- * only for the offset, drawSpriteAt() takes x, and y and draws the sprite
- * exactly at those coords (though it does do some computing to work how the
- * old draw() worked).
- */
- virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
-
- virtual void drawSpriteAt(Graphics *graphics, int x, int y) const;
-
- /**
- * Set the alpha opacity used to draw the being.
- */
- virtual void setAlpha(float alpha)
- { mAlpha = alpha; }
-
- /**
- * Returns the current alpha opacity of the Being.
- */
- virtual float getAlpha() const
- { return mAlpha; }
-
- /**
- * Returns the X coordinate in pixels.
- */
- int getPixelX() const
- { return (int) mPos.x; }
-
- /**
- * Returns the Y coordinate in pixels.
- *
- * @see Sprite::getPixelY()
- */
- int getPixelY() const
- { return (int) mPos.y; }
-
- /**
- * Sets the position of this being.
- */
void setPosition(const Vector &pos);
/**
@@ -421,17 +406,12 @@ class Being : public Sprite, public ConfigListener
*
* @see setPosition(const Vector &pos)
*/
- void setPosition(float x, float y, float z = 0.0f)
+ inline void setPosition(float x, float y, float z = 0.0f)
{
setPosition(Vector(x, y, z));
}
/**
- * Returns the position of this being.
- */
- const Vector &getPosition() const { return mPos; }
-
- /**
* Returns the horizontal size of the current base sprite of the being.
*/
virtual int getWidth() const;
@@ -447,45 +427,17 @@ class Being : public Sprite, public ConfigListener
virtual int getCollisionRadius() const;
/**
- * Returns the required size of a target cursor for this being.
- */
- virtual Being::TargetCursorSize getTargetCursorSize() const
- { return TC_MEDIUM; }
-
- /**
- * Take control of a particle.
- */
- void controlParticle(Particle *particle);
-
- /**
* Shoots a missile particle from this being, to target being
*/
void fireMissile(Being *target, const std::string &particle);
/**
- * Gets the way the object is blocked by other objects.
- */
- virtual unsigned char getWalkMask() const
- { return 0x00; } //can walk through everything
-
- /**
* Returns the path this being is following. An empty path is returned
* when this being isn't following any path currently.
*/
const Path &getPath() const { return mPath; }
/**
- * Sets the target animation for this being.
- */
- void setTargetAnimation(SimpleAnimation *animation);
-
- /**
- * Untargets the being
- */
- void untarget() { mUsedTargetCursor = NULL; }
-
-
- /**
* Set the Emoticon type and time displayed above
* the being.
*/
@@ -501,45 +453,9 @@ class Being : public Sprite, public ConfigListener
*/
Uint8 getEmotion() const { return mEmotion; }
- /**
- * Sets the being's stun mode. If zero, the being is `normal',
- * otherwise it is `stunned' in some fashion.
- */
- void setStunMode(int stunMode)
- {
- if (mStunMode != stunMode)
- updateStunMode(mStunMode, stunMode);
- mStunMode = stunMode;
- };
-
- void setStatusEffect(int index, bool active);
-
- /**
- * A status effect block is a 16 bit mask of status effects.
- * We assign each such flag a block ID of offset + bitnr.
- *
- * These are NOT the same as the status effect indices.
- */
- void setStatusEffectBlock(int offset, Uint16 flags);
-
- /**
- * 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);
- }
-
- virtual AnimatedSprite *getSprite(int index) const
- { return mSprites[index]; }
-
static void load();
- virtual void optionChanged(const std::string &value) {}
+ virtual void optionChanged(const std::string &value);
void flashName(int time);
@@ -548,78 +464,65 @@ class Being : public Sprite, public ConfigListener
void updateName();
- protected:
/**
- * Sets the new path for this being.
+ * Sets the gender of this being.
*/
- void setPath(const Path &path);
+ virtual void setGender(Gender gender);
- /**
- * Updates name's location.
- */
- virtual void updateCoords();
+ Gender getGender() const
+ { return mGender; }
/**
- * Gets the way the object blocks pathfinding for other objects
+ * Whether or not this player is a GM.
*/
- virtual Map::BlockType getBlockType() const
- { return Map::BLOCKTYPE_NONE; }
+ bool isGM() const
+ { return mIsGM; }
/**
- * 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
+ * Triggers whether or not to show the name as a GM name.
*/
- void internalTriggerEffect(int effectId, bool sfx, bool gfx);
+ void setGM(bool gm);
- /**
- * Notify self that the stun mode has been updated. Invoked by
- * setStunMode if something changed.
- */
- virtual void updateStunMode(int oldMode, int newMode);
+ bool canTalk();
+
+ void talkTo();
+ static bool isTalking();
+
+ protected:
/**
- * Notify self that a status effect has flipped.
- * The new flag is passed.
+ * Sets the new path for this being.
*/
- virtual void updateStatusEffect(int index, bool newStatus);
+ void setPath(const Path &path);
/**
- * Handle an update to a status or stun effect
- *
- * \param The StatusEffect to effect
- * \param effectId -1 for stun, otherwise the effect index
+ * Updates name's location.
*/
- virtual void handleStatusEffect(StatusEffect *effect, int effectId);
+ void updateCoords();
- virtual void showName();
+ void showName();
- /** The current sprite Frame number to be displayed */
- int mFrame;
+ void updateColors();
- /** Used to trigger the nextStep (walking on next Tile)
- * TODO: Used by eAthena only?
- */
- int mWalkTime;
+ BeingInfo *mInfo;
+
+ int mActionTime; /**< Time spent in current action */
int mEmotion; /**< Currently showing emotion */
int mEmotionTime; /**< Time until emotion disappears */
/** Time until the last speech sentence disappears */
int mSpeechTime;
+ int mAttackType;
int mAttackSpeed; /**< Attack speed */
+
Action mAction; /**< Action the being is performing */
Uint16 mSubType; /**< Subtype (graphical view, basically) */
- int mId; /**< Unique sprite id */
Uint8 mDirection; /**< Facing direction */
Uint8 mSpriteDirection; /**< Facing direction */
- Map *mMap; /**< Map on which this being resides */
std::string mName; /**< Name of character */
std::string mPartyName;
- MapSprite mMapSprite;
/**
* Holds a text object when the being displays it's name, 0 otherwise
@@ -637,20 +540,18 @@ class Being : public Sprite, public ConfigListener
std::string mSpeech;
Text *mText;
const gcn::Color *mTextColor;
- Uint16 mStunMode; /**< Stun mode; zero if not stunned */
- std::set<int> mStatusEffects; /**< set of active status effects */
- typedef std::vector<AnimatedSprite*> Sprites;
- typedef Sprites::iterator SpriteIterator;
- typedef Sprites::const_iterator SpriteConstIterator;
- Sprites mSprites;
- float mAlpha; /**< Alpha opacity to draw the sprite */
+ Vector mDest; /**< destination coordinates. */
- ParticleList mStunParticleEffects;
- ParticleVector mStatusParticleEffects;
- ParticleList mChildParticleEffects;
+ std::vector<int> mSpriteIDs;
+ std::vector<std::string> mSpriteColors;
+ Gender mGender;
- Vector mDest; /**< destination coordinates. */
+ // Character guild information
+ std::map<int, Guild*> mGuilds;
+ Party *mParty;
+
+ bool mIsGM;
private:
@@ -661,8 +562,7 @@ class Being : public Sprite, public ConfigListener
*/
int getOffset(char pos, char neg) const;
- /** Reset particle status effects on next redraw? */
- bool mMustResetParticles;
+ const Type mType;
/** Speech Bubble components */
SpeechBubble *mSpeechBubble;
@@ -675,13 +575,9 @@ class Being : public Sprite, public ConfigListener
*/
Vector mWalkSpeed;
- Vector mPos; /**< Position coordinates. */
int mX, mY; /**< Position in tile */
int mDamageTaken;
-
- /** Target cursor being used */
- SimpleAnimation *mUsedTargetCursor;
};
#endif
diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp
deleted file mode 100644
index 656b297e..00000000
--- a/src/beingmanager.cpp
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "beingmanager.h"
-
-#include "localplayer.h"
-#include "monster.h"
-#include "npc.h"
-#include "player.h"
-
-#include "gui/viewport.h"
-
-#include "net/gamehandler.h"
-#include "net/net.h"
-
-#include "utils/stringutils.h"
-#include "utils/dtor.h"
-
-#include <cassert>
-
-class FindBeingFunctor
-{
- public:
- bool operator() (Being *being)
- {
- Uint16 other_y = y + ((being->getType() == Being::NPC) ? 1 : 0);
- const Vector &pos = being->getPosition();
- return ((int) pos.x / 32 == x &&
- ((int) pos.y / 32 == y || (int) pos.y / 32 == other_y) &&
- being->isAlive() &&
- (type == Being::UNKNOWN || being->getType() == type));
- }
-
- Uint16 x, y;
- Being::Type type;
-} beingFinder;
-
-BeingManager::BeingManager()
-{
-}
-
-BeingManager::~BeingManager()
-{
- clear();
-}
-
-void BeingManager::setMap(Map *map)
-{
- mMap = map;
- if (player_node)
- player_node->setMap(map);
-}
-
-void BeingManager::setPlayer(LocalPlayer *player)
-{
- player_node = player;
- mBeings.push_back(player);
-}
-
-Being *BeingManager::createBeing(int id, Being::Type type, int subtype)
-{
- Being *being;
-
- switch (type)
- {
- case Being::PLAYER:
- being = new Player(id, subtype, mMap);
- break;
- case Being::NPC:
- being = new NPC(id, subtype, mMap);
- break;
- case Being::MONSTER:
- being = new Monster(id, subtype, mMap);
- break;
- case Being::UNKNOWN:
- being = new Being(id, subtype, mMap);
- break;
- default:
- assert(false);
- }
-
- mBeings.push_back(being);
- return being;
-}
-
-void BeingManager::destroyBeing(Being *being)
-{
- mBeings.remove(being);
- viewport->clearHoverBeing(being);
- delete being;
-}
-
-Being *BeingManager::findBeing(int id) const
-{
- for (Beings::const_iterator i = mBeings.begin(), i_end = mBeings.end();
- i != i_end; ++i)
- {
- Being *being = (*i);
- if (being->getId() == id)
- return being;
- }
- return NULL;
-}
-
-Being *BeingManager::findBeing(int x, int y, Being::Type type) const
-{
- beingFinder.x = x;
- beingFinder.y = y;
- beingFinder.type = type;
-
- Beings::const_iterator i = find_if(mBeings.begin(), mBeings.end(),
- beingFinder);
-
- return (i == mBeings.end()) ? NULL : *i;
-}
-
-Being *BeingManager::findBeingByPixel(int x, int y) const
-{
- Beings::const_iterator itr = mBeings.begin();
- Beings::const_iterator itr_end = mBeings.end();
-
- for (; itr != itr_end; ++itr)
- {
- Being *being = (*itr);
-
- int xtol = being->getWidth() / 2;
- int uptol = being->getHeight();
-
- if ((being->isAlive()) &&
- (being != player_node) &&
- (being->getPixelX() - xtol <= x) &&
- (being->getPixelX() + xtol >= x) &&
- (being->getPixelY() - uptol <= y) &&
- (being->getPixelY() >= y))
- {
- return being;
- }
- }
-
- return NULL;
-}
-
-Being *BeingManager::findBeingByName(const std::string &name,
- Being::Type type) const
-{
- for (Beings::const_iterator i = mBeings.begin(), i_end = mBeings.end();
- i != i_end; ++i)
- {
- Being *being = (*i);
- if (being->getName() == name &&
- (type == Being::UNKNOWN || type == being->getType()))
- return being;
- }
- return NULL;
-}
-
-const Beings &BeingManager::getAll() const
-{
- return mBeings;
-}
-
-void BeingManager::logic()
-{
- Beings::iterator i = mBeings.begin();
- while (i != mBeings.end())
- {
- Being *being = (*i);
-
- being->logic();
-
- if (!being->isAlive() &&
- Net::getGameHandler()->removeDeadBeings() &&
- being->getCurrentFrame() >= 20)
- {
- delete being;
- i = mBeings.erase(i);
- }
- else
- {
- ++i;
- }
- }
-}
-
-void BeingManager::clear()
-{
- if (player_node)
- mBeings.remove(player_node);
-
- delete_all(mBeings);
- mBeings.clear();
-
- if (player_node)
- mBeings.push_back(player_node);
-}
-
-Being *BeingManager::findNearestLivingBeing(int x, int y,
- int maxTileDist, Being::Type type,
- Being *excluded) const
-{
- Being *closestBeing = 0;
- int dist = 0;
-
- const int maxDist = maxTileDist * 32;
-
- Beings::const_iterator itr = mBeings.begin();
- Beings::const_iterator itr_end = mBeings.end();
-
- for (; itr != itr_end; ++itr)
- {
- Being *being = (*itr);
- const Vector &pos = being->getPosition();
- int d = abs(((int) pos.x) - x) + abs(((int) pos.y) - y);
-
- if ((being->getType() == type || type == Being::UNKNOWN)
- && (d < dist || !closestBeing) // it is closer
- && being->isAlive() // no dead beings
- && being != excluded)
- {
- dist = d;
- closestBeing = being;
- }
- }
-
- return (maxDist >= dist) ? closestBeing : 0;
-}
-
-Being *BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxDist,
- Being::Type type) const
-{
- const Vector &pos = aroundBeing->getPosition();
- return findNearestLivingBeing((int)pos.x, (int)pos.y, maxDist, type,
- aroundBeing);
-}
-
-bool BeingManager::hasBeing(Being *being) const
-{
- for (Beings::const_iterator i = mBeings.begin(), i_end = mBeings.end();
- i != i_end; ++i)
- {
- if (being == *i)
- return true;
- }
-
- return false;
-}
-
-void BeingManager::getPlayerNames(std::vector<std::string> &names,
- bool npcNames)
-{
- Beings::iterator i = mBeings.begin();
- names.clear();
-
- while (i != mBeings.end())
- {
- Being *being = (*i);
- if ((being->getType() == Being::PLAYER
- || (being->getType() == Being::NPC && npcNames))
- && being->getName() != "")
- {
- names.push_back(being->getName());
- }
- ++i;
- }
-}
-
-void BeingManager::updatePlayerNames()
-{
- Beings::iterator i = mBeings.begin();
-
- while (i != mBeings.end())
- {
- Being *being = (*i);
- if (being->getType() == Being::PLAYER && being->getName() != "")
- being->updateName();
- ++i;
- }
-}
diff --git a/src/chatlog.cpp b/src/chatlog.cpp
new file mode 100644
index 00000000..1c43b403
--- /dev/null
+++ b/src/chatlog.cpp
@@ -0,0 +1,177 @@
+/*
+ * The Mana World
+ * Copyright (C) 2009-2010 The Mana Developers
+ *
+ * This file is part of The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "chatlog.h"
+
+#include <iostream>
+#include <sstream>
+#include <dirent.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifdef WIN32
+#include <windows.h>
+#elif defined __APPLE__
+#include <Carbon/Carbon.h>
+#endif
+
+#include "log.h"
+#include "configuration.h"
+
+#include "utils/stringutils.h"
+
+ChatLogger::ChatLogger()
+{
+}
+
+ChatLogger::~ChatLogger()
+{
+ if (mLogFile.is_open())
+ mLogFile.close();
+}
+
+void ChatLogger::setLogFile(const std::string &logFilename)
+{
+ if (mLogFile.is_open())
+ mLogFile.close();
+
+ mLogFile.open(logFilename.c_str(), std::ios_base::app);
+
+ if (!mLogFile.is_open())
+ {
+ std::cout << "Warning: error while opening " << logFilename <<
+ " for writing.\n";
+ }
+}
+
+void ChatLogger::setLogDir(const std::string &logDir)
+{
+ mLogDir = logDir;
+
+ if (mLogFile.is_open())
+ mLogFile.close();
+
+ DIR *dir = opendir(mLogDir.c_str());
+ if (!dir)
+ makeDir(mLogDir);
+ else
+ closedir(dir);
+}
+
+void ChatLogger::log(std::string str)
+{
+ std::string dateStr = getDateString();
+ if (!mLogFile.is_open() || dateStr != mLogDate)
+ {
+ mLogDate = dateStr;
+ setLogFile(strprintf("%s/%s/#General_%s.log", mLogDir.c_str(),
+ mServerName.c_str(), dateStr.c_str()));
+ }
+
+ str = removeColors(str);
+ writeTo(mLogFile, str);
+}
+
+void ChatLogger::log(std::string name, std::string str)
+{
+ std::ofstream logFile;
+ logFile.open(strprintf("%s/%s/%s_%s.log", mLogDir.c_str(), mServerName.c_str(),
+ secureName(name).c_str(), getDateString().c_str()).c_str(),
+ std::ios_base::app);
+
+ if (!logFile.is_open())
+ return;
+
+ str = removeColors(str);
+ writeTo(logFile, str);
+
+ if (logFile.is_open())
+ logFile.close();
+}
+
+std::string ChatLogger::getDateString() const
+{
+ std::string date;
+
+ time_t rawtime;
+ struct tm *timeinfo;
+ char buffer [80];
+
+ time (&rawtime);
+ timeinfo = localtime(&rawtime);
+
+ strftime(buffer, 79, "%y-%m-%d", timeinfo);
+ date = buffer;
+ return date;
+}
+
+std::string ChatLogger::secureName(std::string &name) const
+{
+ for (unsigned int f = 0; f < name.length(); f ++)
+ {
+ if (name[f] < '0' && name[f] > '9' && name[f] < 'a' && name[f] > 'z'
+ && name[f] < 'A' && name[f] > 'Z'
+ && name[f] != '-' && name[f] != '+' && name[f] != '='
+ && name[f] != '.' && name[f] != ','&& name[f] != ')'
+ && name[f] != '(' && name[f] != '[' && name[f] != ')')
+ {
+ name[f] = '_';
+ }
+ }
+ return name;
+}
+
+void ChatLogger::writeTo(std::ofstream &file, const std::string &str) const
+{
+ file << str << std::endl;
+}
+
+void ChatLogger::setServerName(const std::string &serverName)
+{
+ mServerName = serverName;
+ if (mServerName == "")
+ mServerName = config.getValue("MostUsedServerName0",
+ "server.themanaworld.org");
+
+ if (mLogFile.is_open())
+ mLogFile.close();
+
+ secureName(mServerName);
+ if (mLogDir != "")
+ {
+ DIR *dir = opendir((mLogDir + "/" + mServerName).c_str());
+ if (!dir)
+ makeDir(mLogDir + "/" + mServerName);
+ else
+ closedir(dir);
+ }
+}
+
+void ChatLogger::makeDir(const std::string &dir)
+{
+#ifdef WIN32
+ mkdir(dir.c_str());
+#else
+ mkdir(dir.c_str(), 0750);
+#endif
+}
diff --git a/src/chatlog.h b/src/chatlog.h
new file mode 100644
index 00000000..c359e953
--- /dev/null
+++ b/src/chatlog.h
@@ -0,0 +1,73 @@
+/*
+ * The Mana World
+ * Copyright (C) 2009-2010 The Mana Developers
+ *
+ * This file is part of The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _CHATLOG_H
+#define _CHATLOG_H
+
+#include <fstream>
+
+class ChatLogger
+{
+ public:
+ /**
+ * Constructor.
+ */
+ ChatLogger();
+
+ /**
+ * Destructor, closes log file.
+ */
+ ~ChatLogger();
+
+ void setLogDir(const std::string &logDir);
+
+ /**
+ * Enters a message in the log. The message will be timestamped.
+ */
+ void log(std::string str);
+
+ void log(std::string name, std::string str);
+
+ std::string getDateString() const;
+
+ std::string secureName(std::string &str) const;
+
+ void setServerName(const std::string &serverName);
+
+ private:
+ /**
+ * Sets the file to log to and opens it
+ */
+ void setLogFile(const std::string &logFilename);
+
+ void writeTo(std::ofstream &file, const std::string &str) const;
+
+ void makeDir(const std::string &dir);
+
+ std::ofstream mLogFile;
+ std::string mLogDir;
+ std::string mServerName;
+ std::string mLogDate;
+};
+
+extern ChatLogger *chatLogger;
+
+#endif
diff --git a/src/client.cpp b/src/client.cpp
index 4b6d3744..35292d22 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -22,6 +22,7 @@
#include "client.h"
#include "main.h"
+#include "chatlog.h"
#include "configuration.h"
#include "emoteshortcut.h"
#include "game.h"
@@ -110,6 +111,7 @@ LoginData loginData;
Configuration config; /**< XML file configuration reader */
Configuration branding; /**< XML branding information reader */
Logger *logger; /**< Log object */
+ChatLogger *chatLogger; /**< Chat log object */
KeyboardConfig keyboard;
UserPalette *userPalette;
@@ -219,6 +221,12 @@ Client::Client(const Options &options):
initHomeDir();
initConfiguration();
+ chatLogger = new ChatLogger;
+ if (options.chatLogDir == "")
+ chatLogger->setLogDir(mLocalDataDir + std::string("/logs/"));
+ else
+ chatLogger->setLogDir(options.chatLogDir);
+
// Configure logger
logger->setLogFile(mLocalDataDir + std::string("/mana.log"));
logger->setLogToStandardOut(config.getValue("logToStandardOut", 0));
@@ -400,6 +408,9 @@ Client::Client(const Options &options):
branding.getValue("defaultServerType", "tmwathena"));
}
+ if (chatLogger)
+ chatLogger->setServerName(mCurrentServer.hostname);
+
if (loginData.username.empty() && loginData.remember)
loginData.username = config.getValue("username", "");
@@ -737,6 +748,8 @@ int Client::exec()
StatusEffect::load();
Units::loadUnits();
+ ActorSprite::load();
+
mDesktop->reloadWallpaper();
mState = STATE_GET_CHARACTERS;
@@ -1147,7 +1160,7 @@ void Client::initUpdatesDir()
return;
// Remove any trailing slash at the end of the update host
- if (mUpdateHost.at(mUpdateHost.size() - 1) == '/')
+ if (!mUpdateHost.empty() && mUpdateHost.at(mUpdateHost.size() - 1) == '/')
mUpdateHost.resize(mUpdateHost.size() - 1);
// Parse out any "http://" or "ftp://", and set the updates directory
@@ -1155,7 +1168,7 @@ void Client::initUpdatesDir()
pos = mUpdateHost.find("://");
if (pos != mUpdateHost.npos)
{
- if (pos + 3 < mUpdateHost.length())
+ if (pos + 3 < mUpdateHost.length() && !mUpdateHost.empty())
{
updates << "updates/" << mUpdateHost.substr(pos + 3);
mUpdatesDir = updates.str();
diff --git a/src/client.h b/src/client.h
index 3c52ea37..836ac3f8 100644
--- a/src/client.h
+++ b/src/client.h
@@ -142,6 +142,7 @@ public:
std::string brandingPath;
std::string updateHost;
std::string dataPath;
+ std::string chatLogDir;
std::string configDir;
std::string localDataDir;
std::string screenshotDir;
diff --git a/src/compoundsprite.cpp b/src/compoundsprite.cpp
new file mode 100644
index 00000000..d1c6cd57
--- /dev/null
+++ b/src/compoundsprite.cpp
@@ -0,0 +1,367 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "compoundsprite.h"
+
+#include "game.h"
+#include "graphics.h"
+#include "openglgraphics.h"
+#include "map.h"
+
+#include "resources/image.h"
+
+#include "utils/dtor.h"
+
+#include <SDL.h>
+
+#define BUFFER_WIDTH 100
+#define BUFFER_HEIGHT 100
+
+CompoundSprite::CompoundSprite():
+ mImage(NULL),
+ mAlphaImage(NULL),
+ mNeedsRedraw(false)
+{
+ mAlpha = 1.0f;
+}
+
+CompoundSprite::~CompoundSprite()
+{
+ SpriteIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ delete (*it);
+
+ clear();
+
+ delete mImage;
+ delete mAlphaImage;
+}
+
+bool CompoundSprite::reset()
+{
+ bool ret = false;
+
+ SpriteIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if (*it)
+ ret |= (*it)->reset();
+
+ mNeedsRedraw |= ret;
+ return ret;
+}
+
+bool CompoundSprite::play(SpriteAction action)
+{
+ bool ret = false;
+
+ SpriteIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if (*it)
+ ret |= (*it)->play(action);
+
+ mNeedsRedraw |= ret;
+ return ret;
+}
+
+bool CompoundSprite::update(int time)
+{
+ bool ret = false;
+
+ SpriteIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if (*it)
+ ret |= (*it)->update(time);
+
+ mNeedsRedraw |= ret;
+ return ret;
+}
+
+bool CompoundSprite::draw(Graphics* graphics, int posX, int posY) const
+{
+ if (mNeedsRedraw)
+ redraw();
+
+ if (mAlpha == 1.0f && mImage)
+ {
+ return graphics->drawImage(mImage, posX + mOffsetX, posY + mOffsetY);
+ }
+ else if (mAlpha && mAlphaImage)
+ {
+ if (mAlphaImage->getAlpha() != mAlpha)
+ mAlphaImage->setAlpha(mAlpha);
+
+ return graphics->drawImage(mAlphaImage,
+ posX + mOffsetX, posY + mOffsetY);
+ }
+ else
+ {
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ {
+ if (*it)
+ {
+ if ((*it)->getAlpha() != mAlpha)
+ (*it)->setAlpha(mAlpha);
+ (*it)->draw(graphics, posX, posY);
+ }
+ }
+ }
+
+ return false;
+}
+
+int CompoundSprite::getWidth() const
+{
+ Sprite *base = NULL;
+
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if ((base = (*it)))
+ break;
+
+ if (base)
+ return base->getWidth();
+
+ return 0;
+}
+
+int CompoundSprite::getHeight() const
+{
+ Sprite *base = NULL;
+
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if ((base = (*it)))
+ break;
+
+ if (base)
+ return base->getHeight();
+
+ return 0;
+}
+
+const Image* CompoundSprite::getImage() const
+{
+ return mImage;
+}
+
+bool CompoundSprite::setDirection(SpriteDirection direction)
+{
+ bool ret = false;
+
+ SpriteIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if (*it)
+ ret |= (*it)->setDirection(direction);
+
+ mNeedsRedraw |= ret;
+ return ret;
+}
+
+int CompoundSprite::getNumberOfLayers() const
+{
+ if (mImage || mAlphaImage)
+ {
+ return 1;
+ }
+ else
+ {
+ return size();
+ }
+}
+
+size_t CompoundSprite::getCurrentFrame() const
+{
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if (*it)
+ return (*it)->getCurrentFrame();
+
+ return 0;
+}
+
+size_t CompoundSprite::getFrameCount() const
+{
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if (*it)
+ return (*it)->getFrameCount();
+
+ return 0;
+}
+
+void CompoundSprite::addSprite(Sprite* sprite)
+{
+ push_back(sprite);
+ mNeedsRedraw = true;
+}
+
+void CompoundSprite::setSprite(int layer, Sprite* sprite)
+{
+ // Skip if it won't change anything
+ if (at(layer) == sprite)
+ return;
+
+ if (at(layer))
+ delete at(layer);
+ at(layer) = sprite;
+ mNeedsRedraw = true;
+}
+
+void CompoundSprite::removeSprite(int layer)
+{
+ // Skip if it won't change anything
+ if (at(layer) == NULL)
+ return;
+
+ delete at(layer);
+ at(layer) = NULL;
+ mNeedsRedraw = true;
+}
+
+void CompoundSprite::clear()
+{
+ // Skip if it won't change anything
+ if (empty())
+ return;
+
+ std::vector<Sprite*>::clear();
+ mNeedsRedraw = true;
+}
+
+void CompoundSprite::ensureSize(size_t layerCount)
+{
+ // Skip if it won't change anything
+ if (size() >= layerCount)
+ return;
+
+ resize(layerCount, NULL);
+ mNeedsRedraw = true;
+}
+
+/**
+ * Returns the curent frame in the current animation of the given layer.
+ */
+size_t CompoundSprite::getCurrentFrame(size_t layer)
+{
+ if (layer >= size())
+ return 0;
+
+ Sprite *s = getSprite(layer);
+ if (s)
+ return s->getCurrentFrame();
+
+ return 0;
+}
+
+/**
+ * Returns the frame count in the current animation of the given layer.
+ */
+size_t CompoundSprite::getFrameCount(size_t layer)
+{
+ if (layer >= size())
+ return 0;
+
+ Sprite *s = getSprite(layer);
+ if (s)
+ return s->getFrameCount();
+
+ return 0;
+}
+
+void CompoundSprite::redraw() const
+{
+ // TODO OpenGL support
+ if (Image::getLoadAsOpenGL())
+ {
+ mNeedsRedraw = false;
+ return;
+ }
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ int rmask = 0xff000000;
+ int gmask = 0x00ff0000;
+ int bmask = 0x0000ff00;
+ int amask = 0x000000ff;
+#else
+ int rmask = 0x000000ff;
+ int gmask = 0x0000ff00;
+ int bmask = 0x00ff0000;
+ int amask = 0xff000000;
+#endif
+
+ SDL_Surface *surface = SDL_CreateRGBSurface(SDL_HWSURFACE,
+ BUFFER_WIDTH, BUFFER_HEIGHT,
+ 32, rmask, gmask, bmask, amask);
+
+ if (!surface)
+ return;
+
+ Graphics *graphics = new Graphics();
+ graphics->setBlitMode(Graphics::BLIT_GFX);
+ graphics->setTarget(surface);
+ graphics->_beginDraw();
+
+ int tileX = 32 / 2;
+ int tileY = 32;
+
+ Game *game = Game::instance();
+ if (game)
+ {
+ Map *map = game->getCurrentMap();
+ tileX = map->getTileWidth() / 2;
+ tileY = map->getTileWidth();
+ }
+
+ int posX = BUFFER_WIDTH / 2 - tileX;
+ int posY = BUFFER_HEIGHT - tileY;
+
+ mOffsetX = tileX - BUFFER_WIDTH / 2;
+ mOffsetY = tileY - BUFFER_HEIGHT;
+
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ {
+ if (*it)
+ {
+ (*it)->draw(graphics, posX, posY);
+ }
+ }
+
+ delete graphics;
+
+ SDL_Surface *surfaceA = SDL_CreateRGBSurface(SDL_HWSURFACE,
+ BUFFER_WIDTH, BUFFER_HEIGHT,
+ 32, rmask, gmask, bmask, amask);
+
+ SDL_SetAlpha(surface, 0, SDL_ALPHA_OPAQUE);
+ SDL_BlitSurface(surface, NULL, surfaceA, NULL);
+
+ delete mImage;
+ delete mAlphaImage;
+
+ mImage = Image::load(surface);
+ SDL_FreeSurface(surface);
+
+ mAlphaImage = Image::load(surfaceA);
+ SDL_FreeSurface(surfaceA);
+
+ mNeedsRedraw = false;
+}
diff --git a/src/compoundsprite.h b/src/compoundsprite.h
new file mode 100644
index 00000000..38c38453
--- /dev/null
+++ b/src/compoundsprite.h
@@ -0,0 +1,105 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COMPOUNDSPRITE_H
+#define COMPOUNDSPRITE_H
+
+#include "sprite.h"
+
+#include <vector>
+
+class Image;
+
+class CompoundSprite : public Sprite, private std::vector<Sprite*>
+{
+public:
+ CompoundSprite();
+
+ ~CompoundSprite();
+
+ virtual bool reset();
+
+ virtual bool play(SpriteAction action);
+
+ virtual bool update(int time);
+
+ virtual bool draw(Graphics* graphics, int posX, int posY) const;
+
+ /**
+ * Gets the width in pixels of the first sprite in the list.
+ */
+ virtual int getWidth() const;
+
+ /**
+ * Gets the height in pixels of the first sprite in the list.
+ */
+ virtual int getHeight() const;
+
+ virtual const Image* getImage() const;
+
+ virtual bool setDirection(SpriteDirection direction);
+
+ int getNumberOfLayers() const;
+
+ size_t getCurrentFrame() const;
+
+ size_t getFrameCount() const;
+
+ size_t size() const
+ { return std::vector<Sprite*>::size(); }
+
+ void addSprite(Sprite* sprite);
+
+ void setSprite(int layer, Sprite* sprite);
+
+ Sprite *getSprite(int layer) const
+ { return at(layer); }
+
+ void removeSprite(int layer);
+
+ void clear();
+
+ void ensureSize(size_t layerCount);
+
+ /**
+ * Returns the curent frame in the current animation of the given layer.
+ */
+ virtual size_t getCurrentFrame(size_t layer);
+
+ /**
+ * Returns the frame count in the current animation of the given layer.
+ */
+ virtual size_t getFrameCount(size_t layer);
+
+private:
+ typedef CompoundSprite::iterator SpriteIterator;
+ typedef CompoundSprite::const_iterator SpriteConstIterator;
+
+ void redraw() const;
+
+ mutable Image *mImage;
+ mutable Image *mAlphaImage;
+
+ mutable int mOffsetX, mOffsetY;
+
+ mutable bool mNeedsRedraw;
+};
+
+#endif // COMPOUNDSPRITE_H
diff --git a/src/flooritem.cpp b/src/flooritem.cpp
index c3442a86..84e07f35 100644
--- a/src/flooritem.cpp
+++ b/src/flooritem.cpp
@@ -21,59 +21,34 @@
#include "flooritem.h"
-#include "graphics.h"
-#include "item.h"
-#include "map.h"
+#include "net/net.h"
-#include "resources/image.h"
+#include "resources/itemdb.h"
+#include "resources/iteminfo.h"
FloorItem::FloorItem(int id,
int itemId,
int x,
int y,
Map *map):
- mId(id),
+ ActorSprite(id),
+ mItemId(itemId),
mX(x),
- mY(y),
- mMap(map),
- mAlpha(1.0f)
+ mY(y)
{
- // Create a corresponding item instance
- mItem = new Item(itemId);
+ setMap(map);
- // Add ourselves to the map
- mMapSprite = mMap->addSprite(this);
-}
-
-FloorItem::~FloorItem()
-{
- // Remove ourselves from the map
- mMap->removeSprite(mMapSprite);
+ // TODO: Eventually, we probably should fix all sprite offsets so that
+ // these translations aren't necessary anymore. The sprites know
+ // best where their base point should be.
+ mPos.x = x * map->getTileWidth() + 16;
+ mPos.y = y * map->getTileHeight() +
+ ((Net::getNetworkType() == ServerInfo::MANASERV) ? 15 : 32);
- delete mItem;
-}
-
-int FloorItem::getItemId() const
-{
- return mItem->getId();
+ setupSpriteDisplay(ItemDB::get(itemId).getDisplay());
}
-Item *FloorItem::getItem() const
+const ItemInfo &FloorItem::getInfo() const
{
- return mItem;
-}
-
-void FloorItem::draw(Graphics *graphics, int offsetX, int offsetY) const
-{
- if (mItem)
- {
- Image *image = mItem->getDrawImage();
-
- if (image)
- if (mAlpha != image->getAlpha())
- image->setAlpha(mAlpha);
-
- graphics->drawImage(image, mX * mMap->getTileWidth() + offsetX,
- mY * mMap->getTileHeight() + offsetY);
- }
+ return ItemDB::get(mId);
}
diff --git a/src/flooritem.h b/src/flooritem.h
index ec8c37cd..e599c939 100644
--- a/src/flooritem.h
+++ b/src/flooritem.h
@@ -22,19 +22,14 @@
#ifndef FLOORITEM_H
#define FLOORITEM_H
-#include "map.h"
-#include "sprite.h"
+#include "actorsprite.h"
-#include <list>
-
-class Graphics;
-class Image;
-class Item;
+class ItemInfo;
/**
* An item lying on the floor.
*/
-class FloorItem : public Sprite
+class FloorItem : public ActorSprite
{
public:
/**
@@ -52,72 +47,29 @@ class FloorItem : public Sprite
int y,
Map *map);
- ~FloorItem();
-
- /**
- * Returns instance ID of this item.
- */
- int getId() const { return mId; }
+ Type getType() const { return FLOOR_ITEM; }
/**
* Returns the item ID.
*/
- int getItemId() const;
-
- /**
- * Returns the item object. Useful for adding an item link for the
- * floor item to chat.
- */
- Item *getItem() const;
-
- /**
- * Returns the x coordinate in tiles.
- */
- int getX() const { return mX; }
+ int getItemId() const
+ { return mItemId; }
/**
- * Returns the y coordinate in tiles.
+ * Returns the item info for this floor item. Useful for adding an item
+ * link for the floor item to chat.
*/
- int getY() const { return mY; }
+ const ItemInfo &getInfo() const;
- /**
- * Returns the pixel y coordinate.
- *
- * @see Sprite::getPixelY()
- */
- int getPixelY() const
- { return mY * mMap->getTileHeight() + mMap->getTileHeight() / 2; }
-
- /**
- * Draws this floor item to the given graphics context.
- *
- * @see Sprite::draw(Graphics, int, int)
- */
- void draw(Graphics *graphics, int offsetX, int offsetY) const;
-
- /**
- * Sets the alpha value of the floor item
- */
- void setAlpha(float alpha)
- { mAlpha = alpha; }
-
- /**
- * Returns the current alpha opacity of the floor item.
- */
- virtual float getAlpha() const
- { return mAlpha; }
+ virtual int getTileX() const
+ { return mX; }
- /** We consider flooritems (at least for now) to be one layer-sprites */
- virtual int getNumberOfLayers() const
- { return 1; }
+ virtual int getTileY() const
+ { return mY; }
private:
- int mId;
+ int mItemId;
int mX, mY;
- Item *mItem;
- MapSprite mMapSprite;
- Map *mMap;
- float mAlpha;
};
#endif
diff --git a/src/flooritemmanager.cpp b/src/flooritemmanager.cpp
deleted file mode 100644
index a190a168..00000000
--- a/src/flooritemmanager.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "flooritemmanager.h"
-#include "flooritem.h"
-
-#include "game.h"
-
-#include "utils/dtor.h"
-
-FloorItemManager::~FloorItemManager()
-{
- clear();
-}
-
-FloorItem *FloorItemManager::create(int id, int itemId, int x, int y)
-{
- Map *map = Game::instance()->getCurrentMap();
- FloorItem *floorItem = new FloorItem(id, itemId, x, y, map);
- mFloorItems.push_back(floorItem);
- return floorItem;
-}
-
-void FloorItemManager::destroy(FloorItem *item)
-{
- mFloorItems.remove(item);
- delete item;
-}
-
-void FloorItemManager::clear()
-{
- delete_all(mFloorItems);
- mFloorItems.clear();
-}
-
-FloorItem *FloorItemManager::findById(int id) const
-{
- FloorItems::const_iterator i;
- for (i = mFloorItems.begin(); i != mFloorItems.end(); i++)
- {
- if ((*i)->getId() == id)
- {
- return *i;
- }
- }
-
- return NULL;
-}
-
-FloorItem *FloorItemManager::findByCoordinates(int x, int y) const
-{
- FloorItems::const_iterator i;
- for (i = mFloorItems.begin(); i != mFloorItems.end(); i++)
- {
- if ((*i)->getX() == x && (*i)->getY() == y)
- {
- return *i;
- }
- }
-
- return NULL;
-}
diff --git a/src/flooritemmanager.h b/src/flooritemmanager.h
deleted file mode 100644
index 62ca8dc2..00000000
--- a/src/flooritemmanager.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef FLOORITEMMANAGER_H
-#define FLOORITEMMANAGER_H
-
-#include <list>
-
-class FloorItem;
-class Map;
-
-class FloorItemManager
-{
- public:
- ~FloorItemManager();
-
- FloorItem *create(int id, int itemId, int x, int y);
-
- void destroy(FloorItem *item);
-
- void clear();
-
- FloorItem *findById(int id) const;
- FloorItem *findByCoordinates(int x, int y) const;
-
- private:
- typedef std::list<FloorItem*> FloorItems;
- typedef FloorItems::iterator FloorItemIterator;
- FloorItems mFloorItems;
-
-};
-
-// TODO Get rid of the global?
-extern FloorItemManager *floorItemManager;
-
-#endif
diff --git a/src/game.cpp b/src/game.cpp
index 79f21863..c867bda9 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -21,14 +21,14 @@
#include "game.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
+#include "actorsprite.h"
#include "channelmanager.h"
#include "client.h"
#include "commandhandler.h"
#include "configuration.h"
#include "effectmanager.h"
#include "emoteshortcut.h"
-#include "flooritemmanager.h"
#include "graphics.h"
#include "itemshortcut.h"
#include "joystick.h"
@@ -36,7 +36,6 @@
#include "localplayer.h"
#include "log.h"
#include "map.h"
-#include "npc.h"
#include "particle.h"
#include "playerrelations.h"
#include "sound.h"
@@ -115,8 +114,7 @@ OutfitWindow *outfitWindow;
SpecialsWindow *specialsWindow;
SocialWindow *socialWindow;
-BeingManager *beingManager = NULL;
-FloorItemManager *floorItemManager = NULL;
+ActorSpriteManager *actorSpriteManager = NULL;
ChannelManager *channelManager = NULL;
CommandHandler *commandHandler = NULL;
Particle *particleEngine = NULL;
@@ -130,9 +128,8 @@ ChatTab *localChatTab = NULL;
*/
static void initEngines()
{
- beingManager = new BeingManager;
+ actorSpriteManager = new ActorSpriteManager;
commandHandler = new CommandHandler;
- floorItemManager = new FloorItemManager;
channelManager = new ChannelManager;
effectManager = new EffectManager;
@@ -206,7 +203,7 @@ static void destroyGuiWindows()
Game *Game::mInstance = 0;
Game::Game():
- mLastTarget(Being::UNKNOWN),
+ mLastTarget(ActorSprite::UNKNOWN),
mCurrentMap(0), mMapName("")
{
assert(!mInstance);
@@ -233,7 +230,7 @@ Game::Game():
Net::getGameHandler()->inGame();
// Initialize beings
- beingManager->setPlayer(player_node);
+ actorSpriteManager->setPlayer(player_node);
/*
* To prevent the server from sending data before the client
@@ -261,10 +258,9 @@ Game::~Game()
destroyGuiWindows();
- del_0(beingManager)
+ del_0(actorSpriteManager)
if (Client::getState() != STATE_CHANGE_MAP)
del_0(player_node)
- del_0(floorItemManager)
del_0(channelManager)
del_0(commandHandler)
del_0(joystick)
@@ -334,7 +330,8 @@ void Game::logic()
handleInput();
// Handle all necessary game logic
- beingManager->logic();
+ ActorSprite::actorLogic();
+ actorSpriteManager->logic();
particleEngine->update();
if (mCurrentMap)
mCurrentMap->update();
@@ -449,7 +446,8 @@ void Game::handleInput()
}
- if (!chatWindow->isInputFocused() || (event.key.keysym.mod & KMOD_ALT))
+ if (!chatWindow->isInputFocused() || (event.key.keysym.mod &
+ KMOD_ALT))
{
if (keyboard.isKeyActive(keyboard.KEY_PREV_CHAT_TAB))
{
@@ -601,7 +599,7 @@ void Game::handleInput()
// off under eAthena.
FloorItem *item =
- floorItemManager->findByCoordinates(x, y);
+ actorSpriteManager->findItem(x, y);
// If none below the player, try the tile in front
// of the player
@@ -618,8 +616,7 @@ void Game::handleInput()
default: break;
}
- item = floorItemManager->findByCoordinates(
- x, y);
+ item = actorSpriteManager->findItem(x, y);
}
if (item)
@@ -753,7 +750,7 @@ void Game::handleInput()
return;
// Moving player around
- if (player_node->isAlive() && !NPC::isTalking() &&
+ if (player_node->isAlive() && !Being::isTalking() &&
!chatWindow->isInputFocused() && !quitDialog)
{
// Get the state of the keyboard keys
@@ -831,8 +828,8 @@ void Game::handleInput()
if (!player_node->getTarget())
{
// Only auto target Monsters
- target = beingManager->findNearestLivingBeing(player_node,
- 20, Being::MONSTER);
+ target = actorSpriteManager->findNearestLivingBeing(player_node,
+ 20, ActorSprite::MONSTER);
}
player_node->attack(target, newTarget);
}
@@ -844,16 +841,16 @@ void Game::handleInput()
(joystick && joystick->buttonPressed(3))) &&
!keyboard.isKeyActive(keyboard.KEY_TARGET))
{
- Being::Type currentTarget = Being::UNKNOWN;
+ ActorSprite::Type currentTarget = ActorSprite::UNKNOWN;
if (keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) ||
(joystick && joystick->buttonPressed(3)))
- currentTarget = Being::MONSTER;
+ currentTarget = ActorSprite::MONSTER;
else if (keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER))
- currentTarget = Being::PLAYER;
+ currentTarget = ActorSprite::PLAYER;
else if (keyboard.isKeyActive(keyboard.KEY_TARGET_NPC))
- currentTarget = Being::NPC;
+ currentTarget = ActorSprite::NPC;
- Being *target = beingManager->findNearestLivingBeing(player_node,
+ Being *target = actorSpriteManager->findNearestLivingBeing(player_node,
20, currentTarget);
if (target && (target != player_node->getTarget() ||
@@ -865,7 +862,7 @@ void Game::handleInput()
}
else
{
- mLastTarget = Being::UNKNOWN; // Reset last target
+ mLastTarget = ActorSprite::UNKNOWN; // Reset last target
}
// Talk to the nearest NPC if 't' pressed
@@ -876,8 +873,8 @@ void Game::handleInput()
if (target)
{
- if (target->getType() == Being::NPC)
- static_cast<NPC*>(target)->talk();
+ if (target->canTalk())
+ target->talkTo();
}
}
@@ -892,7 +889,7 @@ void Game::handleInput()
{
if (joystick->buttonPressed(1))
{
- FloorItem *item = floorItemManager->findByCoordinates(x, y);
+ FloorItem *item = actorSpriteManager->findItem(x, y);
if (item)
player_node->pickUp(item);
@@ -912,8 +909,7 @@ void Game::handleInput()
void Game::changeMap(const std::string &mapPath)
{
// Clean up floor items, beings and particles
- floorItemManager->clear();
- beingManager->clear();
+ actorSpriteManager->clear();
// Close the popup menu on map change so that invalid options can't be
// executed.
@@ -945,7 +941,7 @@ void Game::changeMap(const std::string &mapPath)
// Notify the minimap and beingManager about the map change
minimap->setMap(newMap);
- beingManager->setMap(newMap);
+ actorSpriteManager->setMap(newMap);
particleEngine->setMap(newMap);
viewport->setMap(newMap);
diff --git a/src/graphics.cpp b/src/graphics.cpp
index 9815e1ad..24f92544 100644
--- a/src/graphics.cpp
+++ b/src/graphics.cpp
@@ -27,12 +27,15 @@
#include "resources/image.h"
#include "resources/imageloader.h"
+#include <SDL_gfxBlitFunc.h>
+
Graphics::Graphics():
mWidth(0),
mHeight(0),
mBpp(0),
mFullscreen(false),
- mHWAccel(false)
+ mHWAccel(false),
+ mBlitMode(BLIT_NORMAL)
{
}
@@ -183,7 +186,10 @@ bool Graphics::drawImage(Image *image, int srcX, int srcY, int dstX, int dstY,
srcRect.w = width;
srcRect.h = height;
- return !(SDL_BlitSurface(image->mSDLSurface, &srcRect, mTarget, &dstRect) < 0);
+ if (mBlitMode == BLIT_NORMAL)
+ return !(SDL_BlitSurface(image->mSDLSurface, &srcRect, mTarget, &dstRect) < 0);
+ else
+ return !(SDL_gfxBlitRGBA(image->mSDLSurface, &srcRect, mTarget, &dstRect) < 0);
}
void Graphics::drawImage(gcn::Image const *image, int srcX, int srcY,
diff --git a/src/graphics.h b/src/graphics.h
index 211fb901..344c31c3 100644
--- a/src/graphics.h
+++ b/src/graphics.h
@@ -73,6 +73,11 @@ struct ImageRect
class Graphics : public gcn::SDLGraphics
{
public:
+ enum BlitMode {
+ BLIT_NORMAL = 0,
+ BLIT_GFX
+ };
+
/**
* Constructor.
*/
@@ -182,6 +187,12 @@ class Graphics : public gcn::SDLGraphics
drawImageRect(area.x, area.y, area.width, area.height, imgRect);
}
+ void setBlitMode(BlitMode mode)
+ { mBlitMode = mode; }
+
+ BlitMode getBlitMode()
+ { return mBlitMode; }
+
/**
* Updates the screen. This is done by either copying the buffer to the
* screen or swapping pages.
@@ -211,6 +222,7 @@ class Graphics : public gcn::SDLGraphics
int mBpp;
bool mFullscreen;
bool mHWAccel;
+ BlitMode mBlitMode;
};
extern Graphics *graphics;
diff --git a/src/gui/beingpopup.cpp b/src/gui/beingpopup.cpp
index 687b20c2..ee9fd66d 100644
--- a/src/gui/beingpopup.cpp
+++ b/src/gui/beingpopup.cpp
@@ -20,8 +20,8 @@
#include "gui/beingpopup.h"
+#include "being.h"
#include "graphics.h"
-#include "player.h"
#include "units.h"
#include "gui/gui.h"
@@ -57,21 +57,21 @@ BeingPopup::~BeingPopup()
{
}
-void BeingPopup::show(int x, int y, Player *p)
+void BeingPopup::show(int x, int y, Being *b)
{
- if (!p)
+ if (!b)
{
setVisible(false);
return;
}
- if (!(p->getPartyName().empty()))
+ if (!(b->getPartyName().empty()))
{
- mBeingName->setCaption(p->getName());
+ mBeingName->setCaption(b->getName());
mBeingName->adjustSize();
mBeingParty->setCaption(strprintf(_("Party: %s"),
- p->getPartyName().c_str()));
+ b->getPartyName().c_str()));
mBeingParty->adjustSize();
int minWidth = std::max(mBeingName->getWidth(),
diff --git a/src/gui/beingpopup.h b/src/gui/beingpopup.h
index f397e374..514a6e7e 100644
--- a/src/gui/beingpopup.h
+++ b/src/gui/beingpopup.h
@@ -23,8 +23,8 @@
#include "gui/widgets/popup.h"
+class Being;
class Label;
-class Player;
/**
* A popup that displays information about a being.
@@ -45,7 +45,7 @@ class BeingPopup : public Popup
/**
* Sets the info to be displayed given a particular player.
*/
- void show(int x, int y, Player *p);
+ void show(int x, int y, Being *b);
// TODO: Add a version for monsters, NPCs, etc?
diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp
index 031c53dd..a214c075 100644
--- a/src/gui/buy.cpp
+++ b/src/gui/buy.cpp
@@ -21,6 +21,9 @@
#include "gui/buy.h"
+#include "shopitem.h"
+#include "units.h"
+
#include "gui/setup.h"
#include "gui/widgets/button.h"
@@ -31,10 +34,6 @@
#include "gui/widgets/shoplistbox.h"
#include "gui/widgets/slider.h"
-#include "npc.h"
-#include "shopitem.h"
-#include "units.h"
-
#include "net/net.h"
#include "net/npchandler.h"
diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp
index c6b4ef41..3e810a4a 100644
--- a/src/gui/buysell.cpp
+++ b/src/gui/buysell.cpp
@@ -21,8 +21,6 @@
#include "buysell.h"
-#include "npc.h"
-
#include "gui/setup.h"
#include "gui/widgets/button.h"
diff --git a/src/gui/charcreatedialog.cpp b/src/gui/charcreatedialog.cpp
index e4a5fd01..a2cb2efb 100644
--- a/src/gui/charcreatedialog.cpp
+++ b/src/gui/charcreatedialog.cpp
@@ -54,7 +54,7 @@ CharCreateDialog::CharCreateDialog(CharSelectDialog *parent, int slot):
mCharSelectDialog(parent),
mSlot(slot)
{
- mPlayer = new Player(0, 0, NULL);
+ mPlayer = new Being(0, ActorSprite::PLAYER, 0, NULL);
mPlayer->setGender(GENDER_MALE);
int numberOfHairColors = ColorDB::size();
diff --git a/src/gui/charcreatedialog.h b/src/gui/charcreatedialog.h
index 902e650e..018de3f5 100644
--- a/src/gui/charcreatedialog.h
+++ b/src/gui/charcreatedialog.h
@@ -22,7 +22,7 @@
#ifndef CHAR_CREATE_DIALOG_H
#define CHAR_CREATE_DIALOG_H
-#include "player.h"
+#include "being.h"
#include "guichanfwd.h"
#include "gui/charselectdialog.h"
@@ -110,7 +110,7 @@ class CharCreateDialog : public Window, public gcn::ActionListener
gcn::Button *mCreateButton;
gcn::Button *mCancelButton;
- Player *mPlayer;
+ Being *mPlayer;
PlayerBox *mPlayerBox;
int mHairStyle;
diff --git a/src/gui/charselectdialog.h b/src/gui/charselectdialog.h
index b6e71715..6d565135 100644
--- a/src/gui/charselectdialog.h
+++ b/src/gui/charselectdialog.h
@@ -22,9 +22,9 @@
#ifndef CHAR_SELECT_H
#define CHAR_SELECT_H
+#include "being.h"
#include "guichanfwd.h"
#include "main.h"
-#include "player.h"
#include "gui/widgets/window.h"
diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp
index d53bcf0a..da1bd600 100644
--- a/src/gui/chat.cpp
+++ b/src/gui/chat.cpp
@@ -21,7 +21,7 @@
#include "chat.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "configuration.h"
#include "localplayer.h"
#include "party.h"
@@ -266,20 +266,20 @@ void ChatWindow::chatInput(const std::string &msg)
void ChatWindow::doPresent()
{
- const Beings &beings = beingManager->getAll();
+ const ActorSprites &actors = actorSpriteManager->getAll();
std::string response = "";
int playercount = 0;
- for (Beings::const_iterator bi = beings.begin(), be = beings.end();
- bi != be; ++bi)
+ for (ActorSpritesConstIterator it = actors.begin(), it_end = actors.end();
+ it != it_end; it++)
{
- if ((*bi)->getType() == Being::PLAYER)
+ if ((*it)->getType() == ActorSprite::PLAYER)
{
if (!response.empty())
{
response += ", ";
}
- response += (*bi)->getName();
+ response += static_cast<Being*>(*it)->getName();
++playercount;
}
}
@@ -531,7 +531,7 @@ void ChatWindow::autoComplete()
if (newName == "")
{
- beingManager->getPlayerNames(nameList, true);
+ actorSpriteManager->getPlayerNames(nameList, true);
newName = autoComplete(nameList, name);
}
if (newName == "")
diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp
index 2618810b..5e89bc35 100644
--- a/src/gui/itempopup.cpp
+++ b/src/gui/itempopup.cpp
@@ -102,7 +102,8 @@ void ItemPopup::setItem(const ItemInfo &item, bool showImage)
if (showImage)
{
ResourceManager *resman = ResourceManager::getInstance();
- Image *image = resman->getImage("graphics/items/" + item.getImageName());
+ Image *image = resman->getImage("graphics/items/" +
+ item.getDisplay().image);
mIcon->setImage(image);
if (image)
{
diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp
index 35844f64..1d01f48c 100644
--- a/src/gui/minimap.cpp
+++ b/src/gui/minimap.cpp
@@ -21,14 +21,13 @@
#include "gui/minimap.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "configuration.h"
#include "graphics.h"
#include "localplayer.h"
#include "log.h"
#include "map.h"
-#include "player.h"
#include "gui/setup.h"
#include "gui/userpalette.h"
@@ -185,52 +184,46 @@ void Minimap::draw(gcn::Graphics *graphics)
drawImage(mMapImage, mapOriginX, mapOriginY);
}
- const Beings &beings = beingManager->getAll();
+ const ActorSprites &actors = actorSpriteManager->getAll();
- for (Beings::const_iterator bi = beings.begin(), bi_end = beings.end();
- bi != bi_end; ++bi)
+ for (ActorSpritesConstIterator it = actors.begin(), it_end = actors.end();
+ it != it_end; it++)
{
- const Being *being = (*bi);
+ if ((*it)->getType() == ActorSprite::FLOOR_ITEM)
+ continue;
+
+ const Being *being = static_cast<Being*>(*it);
int dotSize = 2;
- switch (being->getType())
+ int type = UserPalette::PC;
+
+ if (being == player_node)
+ {
+ type = UserPalette::SELF;
+ dotSize = 3;
+ }
+ else if (being->isGM())
+ type = UserPalette::GM;
+ else if (being->isInParty())
+ type = UserPalette::PARTY;
+ else
{
- case Being::PLAYER:
- {
- const Player *player = static_cast<const Player*>(being);
-
- int type = UserPalette::PC;
-
- if (being == player_node)
- {
- type = UserPalette::SELF;
- dotSize = 3;
- }
- else if (player->isGM())
- {
- type = UserPalette::GM;
- }
- else if (player->isInParty())
- {
- type = UserPalette::PARTY;
- }
-
- graphics->setColor(userPalette->getColor(type));
+ switch (being->getType())
+ {
+ case ActorSprite::MONSTER:
+ graphics->setColor(userPalette->getColor(UserPalette::MONSTER));
break;
- }
-
- case Being::MONSTER:
- graphics->setColor(userPalette->getColor(UserPalette::MONSTER));
- break;
- case Being::NPC:
- graphics->setColor(userPalette->getColor(UserPalette::NPC));
- break;
+ case ActorSprite::NPC:
+ graphics->setColor(userPalette->getColor(UserPalette::NPC));
+ break;
- default:
- continue;
+ default:
+ continue;
+ }
}
+ graphics->setColor(userPalette->getColor(type));
const int offsetHeight = (int) ((dotSize - 1) * mHeightProportion);
const int offsetWidth = (int) ((dotSize - 1) * mWidthProportion);
diff --git a/src/gui/ministatus.cpp b/src/gui/ministatus.cpp
index 90581f61..c8c942fd 100644
--- a/src/gui/ministatus.cpp
+++ b/src/gui/ministatus.cpp
@@ -35,6 +35,7 @@
#include "net/net.h"
#include "net/playerhandler.h"
+#include "net/gamehandler.h"
#include "utils/gettext.h"
#include "utils/stringutils.h"
@@ -47,19 +48,28 @@ MiniStatusWindow::MiniStatusWindow():
int max = player_node->getMaxHp();
mHpBar = new ProgressBar(max ? (float) player_node->getHp() / max : 0,
100, 20, Theme::PROG_HP);
- max = player_node->getMaxMP();
- mMpBar = new ProgressBar(max ? (float) player_node->getMP() / max : 0,
+ if (Net::getGameHandler()->canUseMagicBar())
+ {
+ max = player_node->getMaxMP();
+ mMpBar = new ProgressBar(max ? (float) player_node->getMaxMP() / max : 0,
100, 20, Net::getPlayerHandler()->canUseMagic() ?
Theme::PROG_MP : Theme::PROG_NO_MP);
+ }
+ else
+ mMpBar = 0;
+
max = player_node->getExpNeeded();
mXpBar = new ProgressBar(max ? (float) player_node->getExp() / max : 0,
100, 20, Theme::PROG_EXP);
mHpBar->setPosition(0, 3);
- mMpBar->setPosition(mHpBar->getWidth() + 3, 3);
- mXpBar->setPosition(mMpBar->getX() + mMpBar->getWidth() + 3, 3);
+ if (mMpBar)
+ mMpBar->setPosition(mHpBar->getWidth() + 3, 3);
+ mXpBar->setPosition(mMpBar ? mMpBar->getX() + mMpBar->getWidth() + 3 :
+ mHpBar->getX() + mHpBar->getWidth() + 3, 3);
add(mHpBar);
- add(mMpBar);
+ if (mMpBar)
+ add(mMpBar);
add(mXpBar);
setContentSize(mXpBar->getX() + mXpBar->getWidth(),
diff --git a/src/gui/npcdialog.cpp b/src/gui/npcdialog.cpp
index 6d3995a7..4e9c0b01 100644
--- a/src/gui/npcdialog.cpp
+++ b/src/gui/npcdialog.cpp
@@ -22,7 +22,6 @@
#include "gui/npcdialog.h"
#include "configuration.h"
-#include "npc.h"
#include "gui/setup.h"
diff --git a/src/gui/npcdialog.h b/src/gui/npcdialog.h
index a8521ce9..26ff9c1a 100644
--- a/src/gui/npcdialog.h
+++ b/src/gui/npcdialog.h
@@ -23,7 +23,6 @@
#define NPCDIALOG_H
#include "configlistener.h"
-#include "npc.h"
#include "gui/widgets/window.h"
diff --git a/src/gui/npcpostdialog.cpp b/src/gui/npcpostdialog.cpp
index 19d0cf61..68a91f36 100644
--- a/src/gui/npcpostdialog.cpp
+++ b/src/gui/npcpostdialog.cpp
@@ -21,8 +21,6 @@
#include "gui/npcpostdialog.h"
-#include "npc.h"
-
#include "gui/widgets/button.h"
#include "gui/widgets/chattab.h"
#include "gui/widgets/label.h"
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index 520b4005..76569d38 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -21,14 +21,13 @@
#include "gui/popupmenu.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "flooritem.h"
#include "graphics.h"
#include "item.h"
#include "localplayer.h"
#include "log.h"
-#include "npc.h"
#include "playerrelations.h"
#include "gui/chat.h"
@@ -76,7 +75,7 @@ void PopupMenu::showPopup(int x, int y, Being *being)
switch (being->getType())
{
- case Being::PLAYER:
+ case ActorSprite::PLAYER:
{
// Players can be traded with.
mBrowserBox->addRow(strprintf("@@trade|%s@@",
@@ -145,7 +144,7 @@ void PopupMenu::showPopup(int x, int y, Being *being)
}
break;
- case Being::NPC:
+ case ActorSprite::NPC:
// NPCs can be talked to (single option, candidate for removal
// unless more options would be added)
mBrowserBox->addRow(strprintf("@@talk|%s@@",
@@ -153,7 +152,7 @@ void PopupMenu::showPopup(int x, int y, Being *being)
name.c_str()).c_str()));
break;
- case Being::MONSTER:
+ case ActorSprite::MONSTER:
{
// Monsters can be attacked
mBrowserBox->addRow(strprintf("@@attack|%s@@",
@@ -182,11 +181,11 @@ void PopupMenu::showPopup(int x, int y, Being *being)
void PopupMenu::showPopup(int x, int y, FloorItem *floorItem)
{
mFloorItem = floorItem;
- mItem = floorItem->getItem();
+ ItemInfo info = floorItem->getInfo();
mBrowserBox->clearRows();
// Floor item can be picked up (single option, candidate for removal)
- std::string name = ItemDB::get(mFloorItem->getItemId()).getName();
+ std::string name = info.getName();
mBrowserBox->addRow(strprintf("@@pickup|%s@@", strprintf(_("Pick up %s"),
name.c_str()).c_str()));
mBrowserBox->addRow(strprintf("@@chat|%s@@", _("Add to chat")));
@@ -200,16 +199,17 @@ void PopupMenu::showPopup(int x, int y, FloorItem *floorItem)
void PopupMenu::handleLink(const std::string &link)
{
- Being *being = beingManager->findBeing(mBeingId);
+ Being *being = actorSpriteManager->findBeing(mBeingId);
// Talk To action
- if (link == "talk" && being && being->getType() == Being::NPC)
+ if (link == "talk" && being && being->canTalk())
{
- static_cast<NPC*>(being)->talk();
+ being->talkTo();
}
// Trade action
- else if (link == "trade" && being && being->getType() == Being::PLAYER)
+ else if (link == "trade" && being &&
+ being->getType() == ActorSprite::PLAYER)
{
Net::getTradeHandler()->request(being);
tradePartnerName = being->getName();
@@ -223,27 +223,32 @@ void PopupMenu::handleLink(const std::string &link)
{
chatWindow->addInputText("/w \"" + being->getName() + "\" ");
}
- else if (link == "unignore" && being && being->getType() == Being::PLAYER)
+ else if (link == "unignore" && being &&
+ being->getType() == ActorSprite::PLAYER)
{
player_relations.setRelation(being->getName(), PlayerRelation::NEUTRAL);
}
- else if (link == "ignore" && being && being->getType() == Being::PLAYER)
+ else if (link == "ignore" && being &&
+ being->getType() == ActorSprite::PLAYER)
{
player_relations.setRelation(being->getName(), PlayerRelation::IGNORED);
}
- else if (link == "disregard" && being && being->getType() == Being::PLAYER)
+ else if (link == "disregard" && being &&
+ being->getType() == ActorSprite::PLAYER)
{
player_relations.setRelation(being->getName(), PlayerRelation::DISREGARDED);
}
- else if (link == "friend" && being && being->getType() == Being::PLAYER)
+ else if (link == "friend" && being &&
+ being->getType() == ActorSprite::PLAYER)
{
player_relations.setRelation(being->getName(), PlayerRelation::FRIEND);
}
// Guild action
- else if (link == "guild" && being && being->getType() == Being::PLAYER)
+ else if (link == "guild" && being &&
+ being->getType() == ActorSprite::PLAYER)
{
player_node->inviteToGuild(being);
}
@@ -283,7 +288,10 @@ void PopupMenu::handleLink(const std::string &link)
else if (link == "chat")
{
- chatWindow->addItemText(mItem->getInfo().getName());
+ if (mItem)
+ chatWindow->addItemText(mItem->getInfo().getName());
+ else if (mFloorItem)
+ chatWindow->addItemText(mFloorItem->getInfo().getName());
}
else if (link == "split")
@@ -310,9 +318,10 @@ void PopupMenu::handleLink(const std::string &link)
mItem);
}
- else if (link == "party" && being && being->getType() == Being::PLAYER)
+ else if (link == "party" && being &&
+ being->getType() == ActorSprite::PLAYER)
{
- Net::getPartyHandler()->invite(static_cast<Player*>(being));
+ Net::getPartyHandler()->invite(being);
}
else if (link == "name" && being)
@@ -323,8 +332,8 @@ void PopupMenu::handleLink(const std::string &link)
else if (link == "admin-kick" &&
being &&
- (being->getType() == Being::PLAYER ||
- being->getType() == Being::MONSTER))
+ (being->getType() == ActorSprite::PLAYER ||
+ being->getType() == ActorSprite::MONSTER))
{
Net::getAdminHandler()->kick(being->getId());
}
diff --git a/src/gui/register.h b/src/gui/register.h
index 645b0be8..3c65695b 100644
--- a/src/gui/register.h
+++ b/src/gui/register.h
@@ -22,8 +22,6 @@
#ifndef REGISTER_H
#define REGISTER_H
-#include "player.h"
-
#include "gui/widgets/window.h"
#include <guichan/actionlistener.hpp>
diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp
index 69ff7ed2..a4109033 100644
--- a/src/gui/sell.cpp
+++ b/src/gui/sell.cpp
@@ -21,7 +21,6 @@
#include "gui/sell.h"
-#include "npc.h"
#include "shopitem.h"
#include "units.h"
diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp
index 0762b00f..ad8ab3c8 100644
--- a/src/gui/serverdialog.cpp
+++ b/src/gui/serverdialog.cpp
@@ -21,6 +21,7 @@
#include "gui/serverdialog.h"
+#include "chatlog.h"
#include "client.h"
#include "configuration.h"
#include "gui.h"
@@ -347,6 +348,8 @@ void ServerDialog::action(const gcn::ActionEvent &event)
// Save the selected server
mServerInfo->save = true;
+ chatLogger->setServerName(mServerInfo->hostname);
+
saveCustomServers(*mServerInfo);
Client::setState(STATE_CONNECT_SERVER);
diff --git a/src/gui/setup_players.cpp b/src/gui/setup_players.cpp
index 802a5b2e..f7a39240 100644
--- a/src/gui/setup_players.cpp
+++ b/src/gui/setup_players.cpp
@@ -21,7 +21,7 @@
#include "gui/setup_players.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "configuration.h"
#include "log.h"
@@ -214,6 +214,7 @@ public:
#define ACTION_STRATEGY "strategy"
#define ACTION_WHISPER_TAB "whisper tab"
#define ACTION_SHOW_GENDER "show gender"
+#define ACTION_ENABLE_CHAT_LOG "enable log"
Setup_Players::Setup_Players():
mPlayerTableTitleModel(new StaticTableModel(1, COLUMNS_NR)),
@@ -229,7 +230,9 @@ Setup_Players::Setup_Players():
mWhisperTab(config.getValue("whispertab", false)),
mWhisperTabCheckBox(new CheckBox(_("Put all whispers in tabs"), mWhisperTab)),
mShowGender(config.getValue("showgender", false)),
- mShowGenderCheckBox(new CheckBox(_("Show gender"), mShowGender))
+ mShowGenderCheckBox(new CheckBox(_("Show gender"), mShowGender)),
+ mEnableChatLog(config.getValue("enableChatLog", false)),
+ mEnableChatLogCheckBox(new CheckBox(_("Enable Chat log"), mEnableChatLog))
{
setName(_("Players"));
@@ -279,6 +282,9 @@ Setup_Players::Setup_Players():
mShowGenderCheckBox->setActionEventId(ACTION_SHOW_GENDER);
mShowGenderCheckBox->addActionListener(this);
+ mEnableChatLogCheckBox->setActionEventId(ACTION_ENABLE_CHAT_LOG);
+ mEnableChatLogCheckBox->addActionListener(this);
+
reset();
// Do the layout
@@ -289,6 +295,7 @@ Setup_Players::Setup_Players():
place(0, 1, mPlayerScrollArea, 4, 4).setPadding(2);
place(0, 5, mDeleteButton);
place(0, 6, mShowGenderCheckBox, 2).setPadding(2);
+ place(0, 7, mEnableChatLogCheckBox, 2).setPadding(2);
place(2, 5, ignore_action_label);
place(2, 6, mIgnoreActionChoicesBox, 2).setPadding(2);
place(2, 7, mDefaultTrading);
@@ -345,8 +352,10 @@ void Setup_Players::apply()
config.setValue("showgender", mShowGender);
- if (beingManager && mShowGender != showGender)
- beingManager->updatePlayerNames();
+ if (actorSpriteManager && mShowGender != showGender)
+ actorSpriteManager->updatePlayerNames();
+
+ config.setValue("enableChatLog", mEnableChatLog);
}
void Setup_Players::cancel()
@@ -355,6 +364,8 @@ void Setup_Players::cancel()
mWhisperTabCheckBox->setSelected(mWhisperTab);
mShowGender = config.getValue("showgender", false);
mShowGenderCheckBox->setSelected(mShowGender);
+ mEnableChatLog = config.getValue("enableChatLog", false);
+ mEnableChatLogCheckBox->setSelected(mEnableChatLog);
}
void Setup_Players::action(const gcn::ActionEvent &event)
@@ -402,6 +413,10 @@ void Setup_Players::action(const gcn::ActionEvent &event)
{
mShowGender = mShowGenderCheckBox->isSelected();
}
+ else if (event.getId() == ACTION_ENABLE_CHAT_LOG)
+ {
+ mEnableChatLog = mEnableChatLogCheckBox->isSelected();
+ }
}
void Setup_Players::updatedPlayer(const std::string &name)
diff --git a/src/gui/setup_players.h b/src/gui/setup_players.h
index 5337b213..a62ffe1f 100644
--- a/src/gui/setup_players.h
+++ b/src/gui/setup_players.h
@@ -70,6 +70,9 @@ private:
bool mShowGender;
gcn::CheckBox *mShowGenderCheckBox;
+
+ bool mEnableChatLog;
+ gcn::CheckBox *mEnableChatLogCheckBox;
};
#endif
diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp
index 53528cee..683a6d43 100644
--- a/src/gui/skilldialog.cpp
+++ b/src/gui/skilldialog.cpp
@@ -240,10 +240,6 @@ void SkillDialog::action(const gcn::ActionEvent &event)
{
setVisible(false);
}
- else
- {
- printf("Unknown event '%s'\n", event.getId().c_str());
- }
}
std::string SkillDialog::update(int id)
diff --git a/src/gui/socialwindow.cpp b/src/gui/socialwindow.cpp
index 098ecbc5..25447f30 100644
--- a/src/gui/socialwindow.cpp
+++ b/src/gui/socialwindow.cpp
@@ -20,11 +20,9 @@
#include "gui/socialwindow.h"
-#include "beingmanager.h"
#include "guild.h"
#include "localplayer.h"
#include "party.h"
-#include "player.h"
#include "gui/confirmdialog.h"
#include "gui/okdialog.h"
diff --git a/src/gui/statuswindow.cpp b/src/gui/statuswindow.cpp
index ede85133..c8ebdc98 100644
--- a/src/gui/statuswindow.cpp
+++ b/src/gui/statuswindow.cpp
@@ -38,6 +38,7 @@
#include "net/net.h"
#include "net/playerhandler.h"
+#include "net/gamehandler.h"
#include "utils/gettext.h"
#include "utils/mathutils.h"
@@ -119,11 +120,15 @@ StatusWindow::StatusWindow():
mXpBar = new ProgressBar(max ? (float) player_node->getExp() / max : 0,
80, 15, Theme::PROG_EXP);
- max = player_node->getMaxMP();
- mMpLabel = new Label(_("MP:"));
- mMpBar = new ProgressBar(max ? (float) player_node->getMaxMP() / max : 0,
+ bool magicBar = Net::getGameHandler()->canUseMagicBar();
+ if (magicBar)
+ {
+ max = player_node->getMaxMP();
+ mMpLabel = new Label(_("MP:"));
+ mMpBar = new ProgressBar(max ? (float) player_node->getMaxMP() / max : 0,
80, 15, Net::getPlayerHandler()->canUseMagic() ?
Theme::PROG_MP : Theme::PROG_NO_MP);
+ }
place(0, 0, mLvlLabel, 3);
// 5, 0 Job Level
@@ -132,9 +137,12 @@ StatusWindow::StatusWindow():
place(1, 1, mHpBar, 4);
place(5, 1, mXpLabel).setPadding(3);
place(6, 1, mXpBar, 5);
- place(0, 2, mMpLabel).setPadding(3);
- // 5, 2 and 6, 2 Job Progress Bar
- place(1, 2, mMpBar, 4);
+ if (magicBar)
+ {
+ place(0, 2, mMpLabel).setPadding(3);
+ // 5, 2 and 6, 2 Job Progress Bar
+ place(1, 2, mMpBar, 4);
+ }
if (Net::getPlayerHandler()->getJobLocation() > 0)
{
@@ -179,16 +187,15 @@ StatusWindow::StatusWindow():
loadWindowState();
update(HP);
- update(MP);
+ if (magicBar)
+ update(MP);
update(EXP);
update(MONEY);
update(CHAR_POINTS); // This also updates all attributes (none atm)
update(LEVEL);
int job = Net::getPlayerHandler()->getJobLocation();
if (job > 0)
- {
update(job);
- }
}
std::string StatusWindow::update(int id)
@@ -306,6 +313,8 @@ void StatusWindow::addAttribute(int id, const std::string &name,
void StatusWindow::updateHPBar(ProgressBar *bar, bool showMax)
{
+ if (!bar)
+ return;
if (showMax)
bar->setText(toString(player_node->getHp()) +
@@ -322,6 +331,9 @@ void StatusWindow::updateHPBar(ProgressBar *bar, bool showMax)
void StatusWindow::updateMPBar(ProgressBar *bar, bool showMax)
{
+ if (!bar)
+ return;
+
if (showMax)
bar->setText(toString(player_node->getMP()) +
"/" + toString(player_node->getMaxMP()));
@@ -344,6 +356,9 @@ void StatusWindow::updateMPBar(ProgressBar *bar, bool showMax)
void StatusWindow::updateProgressBar(ProgressBar *bar, int value, int max,
bool percent)
{
+ if (!bar)
+ return;
+
if (max == 0)
{
bar->setText(_("Max"));
@@ -364,6 +379,9 @@ void StatusWindow::updateProgressBar(ProgressBar *bar, int value, int max,
void StatusWindow::updateXPBar(ProgressBar *bar, bool percent)
{
+ if (!bar)
+ return;
+
updateProgressBar(bar, player_node->getExp(),
player_node->getExpNeeded(), percent);
}
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index 99325db8..66f614a8 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -21,16 +21,13 @@
#include "gui/viewport.h"
+#include "actorspritemanager.h"
#include "client.h"
-#include "beingmanager.h"
#include "configuration.h"
-#include "flooritemmanager.h"
#include "graphics.h"
#include "keyboardconfig.h"
#include "localplayer.h"
#include "map.h"
-#include "monster.h"
-#include "npc.h"
#include "textmanager.h"
#include "gui/gui.h"
@@ -40,7 +37,6 @@
#include "net/net.h"
-#include "resources/monsterinfo.h"
#include "resources/resourcemanager.h"
#include "utils/stringutils.h"
@@ -207,12 +203,16 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
}
// Draw player names, speech, and emotion sprite as needed
- const Beings &beings = beingManager->getAll();
- for (Beings::const_iterator i = beings.begin(), i_end = beings.end();
- i != i_end; ++i)
+ const ActorSprites &actors = actorSpriteManager->getAll();
+ for (ActorSpritesConstIterator it = actors.begin(), it_end = actors.end();
+ it != it_end; it++)
{
- (*i)->drawSpeech((int) mPixelViewX, (int) mPixelViewY);
- (*i)->drawEmotion(graphics, (int) mPixelViewX, (int) mPixelViewY);
+ if ((*it)->getType() == ActorSprite::FLOOR_ITEM)
+ continue;
+
+ Being *b = static_cast<Being*>(*it);
+ b->drawSpeech((int) mPixelViewX, (int) mPixelViewY);
+ b->drawEmotion(graphics, (int) mPixelViewX, (int) mPixelViewY);
}
if (miniStatusWindow)
@@ -345,7 +345,7 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
return;
// Check if we are busy
- if (NPC::isTalking())
+ if (Being::isTalking())
return;
mPlayerFollowMouse = false;
@@ -381,33 +381,20 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
// Interact with some being
if (mHoverBeing)
{
- switch (mHoverBeing->getType())
+ if (mHoverBeing->canTalk())
+ mHoverBeing->talkTo();
+ else
{
- // Talk to NPCs
- case Being::NPC:
- static_cast<NPC*>(mHoverBeing)->talk();
- break;
-
- // Attack or walk to monsters or players
- case Being::MONSTER:
- case Being::PLAYER:
- // Ignore it if its dead
- if (!mHoverBeing->isAlive())
- break;
-
+ // Ignore it if its dead
+ if (mHoverBeing->isAlive())
+ {
if (player_node->withinAttackRange(mHoverBeing) ||
keyboard.isKeyActive(keyboard.KEY_ATTACK))
- {
player_node->attack(mHoverBeing,
!keyboard.isKeyActive(keyboard.KEY_TARGET));
- }
else
- {
player_node->setGotoTarget(mHoverBeing);
- }
- break;
- default:
- break;
+ }
}
// Picks up a item if we clicked on one
}
@@ -433,8 +420,8 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
else if (event.getButton() == gcn::MouseEvent::MIDDLE)
{
// Find the being nearest to the clicked position
- Being *target = beingManager->findNearestLivingBeing(
- pixelX, pixelY, 20, Being::MONSTER);
+ Being *target = actorSpriteManager->findNearestLivingBeing(
+ pixelX, pixelY, 20, ActorSprite::MONSTER);
if (target)
player_node->setTarget(target);
@@ -460,9 +447,9 @@ void Viewport::mouseDragged(gcn::MouseEvent &event)
}
else
{
- if (mLocalWalkTime != player_node->getWalkTime())
+ if (mLocalWalkTime != player_node->getActionTime())
{
- mLocalWalkTime = player_node->getWalkTime();
+ mLocalWalkTime = player_node->getActionTime();
int destX = (event.getX() + mPixelViewX + 16) /
mMap->getTileWidth();
int destY = (event.getY() + mPixelViewY + 16) /
@@ -507,27 +494,23 @@ void Viewport::mouseMoved(gcn::MouseEvent &event)
const int x = (event.getX() + (int) mPixelViewX);
const int y = (event.getY() + (int) mPixelViewY);
- mHoverBeing = beingManager->findBeingByPixel(x, y);
- if (mHoverBeing && mHoverBeing->getType() == Being::PLAYER)
- mBeingPopup->show(getMouseX(), getMouseY(),
- static_cast<Player*>(mHoverBeing));
- else
- mBeingPopup->setVisible(false);
+ mHoverBeing = actorSpriteManager->findBeingByPixel(x, y);
+ mBeingPopup->show(getMouseX(), getMouseY(), mHoverBeing);
- mHoverItem = floorItemManager->findByCoordinates(x / mMap->getTileWidth(),
- y / mMap->getTileHeight());
+ mHoverItem = actorSpriteManager->findItem(x / mMap->getTileWidth(),
+ y / mMap->getTileHeight());
if (mHoverBeing)
{
switch (mHoverBeing->getType())
{
// NPCs
- case Being::NPC:
+ case ActorSprite::NPC:
gui->setCursorType(Gui::CURSOR_TALK);
break;
// Monsters
- case Being::MONSTER:
+ case ActorSprite::MONSTER:
gui->setCursorType(Gui::CURSOR_FIGHT);
break;
default:
@@ -562,8 +545,11 @@ void Viewport::hideBeingPopup()
mBeingPopup->setVisible(false);
}
-void Viewport::clearHoverBeing(Being *being)
+void Viewport::clearHover(ActorSprite *actor)
{
- if (mHoverBeing == being)
+ if (mHoverBeing == actor)
mHoverBeing = 0;
+
+ if (mHoverItem == actor)
+ mHoverItem = 0;
}
diff --git a/src/gui/viewport.h b/src/gui/viewport.h
index 9658f934..f91504f2 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -22,7 +22,7 @@
#ifndef VIEWPORT_H
#define VIEWPORT_H
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "configlistener.h"
#include "position.h"
@@ -30,6 +30,7 @@
#include <guichan/mouselistener.hpp>
+class ActorSprite;
class Being;
class BeingPopup;
class FloorItem;
@@ -159,10 +160,10 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
void hideBeingPopup();
protected:
- friend class BeingManager;
+ friend class ActorSpriteManager;
- /// Clears the hovered being if it matches
- void clearHoverBeing(Being *being);
+ /// Clears any matching hovers
+ void clearHover(ActorSprite *actor);
private:
/**
diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp
index 39ea6887..8c300eca 100644
--- a/src/gui/widgets/chattab.cpp
+++ b/src/gui/widgets/chattab.cpp
@@ -21,6 +21,7 @@
#include "gui/widgets/chattab.h"
+#include "chatlog.h"
#include "commandhandler.h"
#include "configuration.h"
#include "localplayer.h"
@@ -180,6 +181,9 @@ void ChatTab::chatLog(std::string line, int own, bool ignoreRecord)
line = lineColor + timeStr.str() + tmp.nick + tmp.text;
+ if (config.getValue("enableChatLog", false))
+ saveToLogFile(line);
+
// We look if the Vertical Scroll Bar is set at the max before
// adding a row, otherwise the max will always be a row higher
// at comparison.
@@ -275,6 +279,12 @@ void ChatTab::handleCommand(const std::string &msg)
commandHandler->handleCommand(msg, this);
}
+void ChatTab::saveToLogFile(std::string &msg)
+{
+ if (chatLogger)
+ chatLogger->log(msg);
+}
+
void ChatTab::addRow(std::string &line)
{
std::string::size_type idx = 0;
diff --git a/src/gui/widgets/chattab.h b/src/gui/widgets/chattab.h
index 7fd3931e..2189a780 100644
--- a/src/gui/widgets/chattab.h
+++ b/src/gui/widgets/chattab.h
@@ -111,6 +111,8 @@ class ChatTab : public Tab
const std::string &args)
{ return false; }
+ virtual void saveToLogFile(std::string &msg);
+
protected:
friend class ChatWindow;
friend class WhisperWindow;
diff --git a/src/gui/widgets/playerbox.cpp b/src/gui/widgets/playerbox.cpp
index 57cbec6f..468c77f5 100644
--- a/src/gui/widgets/playerbox.cpp
+++ b/src/gui/widgets/playerbox.cpp
@@ -22,9 +22,9 @@
#include "gui/widgets/playerbox.h"
#include "animatedsprite.h"
+#include "being.h"
#include "configuration.h"
#include "graphics.h"
-#include "player.h"
#include "gui/theme.h"
@@ -36,8 +36,8 @@ int PlayerBox::instances = 0;
float PlayerBox::mAlpha = 1.0;
ImageRect PlayerBox::background;
-PlayerBox::PlayerBox(const Player *player):
- mPlayer(player)
+PlayerBox::PlayerBox(const Being *being):
+ mBeing(being)
{
setFrameSize(2);
@@ -72,7 +72,7 @@ PlayerBox::~PlayerBox()
{
instances--;
- mPlayer = 0;
+ mBeing = 0;
if (instances == 0)
{
@@ -82,13 +82,13 @@ PlayerBox::~PlayerBox()
void PlayerBox::draw(gcn::Graphics *graphics)
{
- if (mPlayer)
+ if (mBeing)
{
// Draw character
const int bs = getFrameSize();
- const int x = getWidth() / 2 + bs;
- const int y = getHeight() - bs;
- mPlayer->drawSpriteAt(static_cast<Graphics*>(graphics), x, y);
+ const int x = getWidth() / 2 + bs - 16;
+ const int y = getHeight() - bs - 32;
+ mBeing->drawSpriteAt(static_cast<Graphics*>(graphics), x, y);
}
if (config.getValue("guialpha", 0.8) != mAlpha)
diff --git a/src/gui/widgets/playerbox.h b/src/gui/widgets/playerbox.h
index 33b4a628..4505367f 100644
--- a/src/gui/widgets/playerbox.h
+++ b/src/gui/widgets/playerbox.h
@@ -24,8 +24,8 @@
#include <guichan/widgets/scrollarea.hpp>
+class Being;
class ImageRect;
-class Player;
/**
* A box showing a player character.
@@ -39,7 +39,7 @@ class PlayerBox : public gcn::ScrollArea
* Constructor. Takes the initial player character that this box should
* display, which defaults to <code>NULL</code>.
*/
- PlayerBox(const Player *player = 0);
+ PlayerBox(const Being *being = 0);
/**
* Destructor.
@@ -51,7 +51,7 @@ class PlayerBox : public gcn::ScrollArea
* player to <code>NULL</code> causes the box not to draw any
* character.
*/
- void setPlayer(const Player *player) { mPlayer = player; }
+ void setPlayer(const Being *being) { mBeing = being; }
/**
* Draws the scroll area.
@@ -64,7 +64,7 @@ class PlayerBox : public gcn::ScrollArea
void drawFrame(gcn::Graphics *graphics);
private:
- const Player *mPlayer; /**< The character used for display */
+ const Being *mBeing; /**< The character used for display */
static float mAlpha;
static int instances;
diff --git a/src/gui/widgets/whispertab.cpp b/src/gui/widgets/whispertab.cpp
index 858a2e6b..89ff72d3 100644
--- a/src/gui/widgets/whispertab.cpp
+++ b/src/gui/widgets/whispertab.cpp
@@ -21,6 +21,7 @@
#include "whispertab.h"
+#include "chatlog.h"
#include "commandhandler.h"
#include "localplayer.h"
@@ -114,3 +115,9 @@ bool WhisperTab::handleCommand(const std::string &type,
return true;
}
+
+void WhisperTab::saveToLogFile(std::string &msg)
+{
+ if (chatLogger)
+ chatLogger->log(getNick(), msg);
+} \ No newline at end of file
diff --git a/src/gui/widgets/whispertab.h b/src/gui/widgets/whispertab.h
index 447a8fe0..20a07449 100644
--- a/src/gui/widgets/whispertab.h
+++ b/src/gui/widgets/whispertab.h
@@ -39,6 +39,8 @@ class WhisperTab : public ChatTab
bool handleCommand(const std::string &type,
const std::string &args);
+ void saveToLogFile(std::string &msg);
+
protected:
friend class ChatWindow;
diff --git a/src/guild.cpp b/src/guild.cpp
index 029cde7f..00d8614e 100644
--- a/src/guild.cpp
+++ b/src/guild.cpp
@@ -21,8 +21,7 @@
#include "guild.h"
-#include "beingmanager.h"
-#include "player.h"
+#include "actorspritemanager.h"
GuildMember::GuildMember(Guild *guild, int id, const std::string &name):
Avatar(name), mId(id), mGuild(guild)
@@ -150,10 +149,8 @@ void Guild::removeFromMembers()
itr_end = mMembers.end();
while(itr != itr_end)
{
- Being *b = beingManager->findBeing((*itr)->getID());
-
- if (b->getType() == Being::PLAYER)
- static_cast<Player*>(b)->removeGuild(getId());
+ Being *b = actorSpriteManager->findBeing((*itr)->getID());
+ b->removeGuild(getId());
++itr;
}
}
diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp
index feb9548d..76c05d64 100644
--- a/src/imageparticle.cpp
+++ b/src/imageparticle.cpp
@@ -39,10 +39,10 @@ ImageParticle::~ImageParticle()
mImage->decRef();
}
-void ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
+bool ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
{
if (!mAlive || !mImage)
- return;
+ return false;
int screenX = (int) mPos.x + offsetX - mImage->getWidth() / 2;
int screenY = (int) mPos.y - (int)mPos.z + offsetY - mImage->getHeight()/2;
@@ -52,9 +52,7 @@ void ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
screenX > graphics->getWidth() ||
screenY + mImage->getHeight() < 0 ||
screenY > graphics->getHeight())
- {
- return;
- }
+ return false;
float alphafactor = mAlpha;
@@ -65,5 +63,5 @@ void ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
alphafactor *= (float) mLifetimePast / (float) mFadeIn;
mImage->setAlpha(alphafactor);
- graphics->drawImage(mImage, screenX, screenY);
+ return graphics->drawImage(mImage, screenX, screenY);
}
diff --git a/src/imageparticle.h b/src/imageparticle.h
index bc32400d..23909fa3 100644
--- a/src/imageparticle.h
+++ b/src/imageparticle.h
@@ -49,7 +49,7 @@ class ImageParticle : public Particle
/**
* Draws the particle image
*/
- virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
+ virtual bool draw(Graphics *graphics, int offsetX, int offsetY) const;
protected:
Image *mImage; /**< The image used for this particle. */
diff --git a/src/imagesprite.cpp b/src/imagesprite.cpp
new file mode 100644
index 00000000..504aba96
--- /dev/null
+++ b/src/imagesprite.cpp
@@ -0,0 +1,44 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "imagesprite.h"
+
+#include "graphics.h"
+
+ImageSprite::ImageSprite(Image *image):
+ mImage(image)
+{
+ mAlpha = mImage->getAlpha();
+
+ mImage->incRef();
+}
+
+ImageSprite::~ImageSprite()
+{
+ mImage->decRef();
+}
+
+bool ImageSprite::draw(Graphics* graphics, int posX, int posY) const
+{
+ if (mImage->getAlpha() != mAlpha)
+ mImage->setAlpha(mAlpha);
+
+ return graphics->drawImage(mImage, posX, posY);
+}
diff --git a/src/imagesprite.h b/src/imagesprite.h
new file mode 100644
index 00000000..8a195b8c
--- /dev/null
+++ b/src/imagesprite.h
@@ -0,0 +1,73 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IMAGESPRITE_H
+#define IMAGESPRITE_H
+
+#include "sprite.h"
+
+#include "resources/image.h"
+
+class Graphics;
+
+class ImageSprite : public Sprite
+{
+public:
+ ImageSprite(Image *image);
+
+ ~ImageSprite();
+
+ bool reset()
+ { return false; }
+
+ bool play(SpriteAction action)
+ { return false; }
+
+ bool update(int time)
+ { return false; }
+
+ bool draw(Graphics* graphics, int posX, int posY) const;
+
+ int getWidth() const
+ { return mImage->getWidth(); }
+
+ int getHeight() const
+ { return mImage->getHeight(); }
+
+ const Image* getImage() const
+ { return mImage; }
+
+ virtual bool setDirection(SpriteDirection direction)
+ { return false; }
+
+ int getNumberOfLayers()
+ { return 1; }
+
+ size_t getCurrentFrame() const
+ { return 0; }
+
+ size_t getFrameCount() const
+ { return 1; }
+
+private:
+ Image *mImage;
+};
+
+#endif // IMAGESPRITE_H
diff --git a/src/item.cpp b/src/item.cpp
index 79ccd2c3..19bb7c23 100644
--- a/src/item.cpp
+++ b/src/item.cpp
@@ -57,7 +57,8 @@ void Item::setId(int id)
mDrawImage->decRef();
ResourceManager *resman = ResourceManager::getInstance();
- std::string imagePath = "graphics/items/" + getInfo().getImageName();
+ SpriteDisplay display = getInfo().getDisplay();
+ std::string imagePath = "graphics/items/" + display.image;
mImage = resman->getImage(imagePath);
mDrawImage = resman->getImage(imagePath);
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index b06ea456..96062867 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -32,7 +32,6 @@
#include "item.h"
#include "log.h"
#include "map.h"
-#include "monster.h"
#include "particle.h"
#include "simpleanimation.h"
#include "sound.h"
@@ -80,7 +79,7 @@ const short walkingKeyboardDelay = 1000;
LocalPlayer *player_node = NULL;
LocalPlayer::LocalPlayer(int id, int subtype):
- Player(id, subtype, 0),
+ Being(id, PLAYER, subtype, 0),
mEquipment(new Equipment),
mAttackRange(0),
mTargetTime(-1),
@@ -113,11 +112,6 @@ LocalPlayer::LocalPlayer(int id, int subtype):
mUpdateName = true;
- mTextColor = &Theme::getThemeColor(Theme::PLAYER);
- mNameColor = &userPalette->getColor(UserPalette::SELF);
-
- initTargetCursor();
-
config.addListener("showownname", this);
setShowName(config.getValue("showownname", 1));
}
@@ -128,14 +122,6 @@ LocalPlayer::~LocalPlayer()
config.removeListener("showownname", this);
- for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++)
- {
- delete mTargetCursor[0][i];
- delete mTargetCursor[1][i];
- mTargetCursorImages[0][i]->decRef();
- mTargetCursorImages[1][i]->decRef();
- }
-
delete mAwayDialog;
delete mAwayListener;
}
@@ -200,11 +186,10 @@ void LocalPlayer::logic()
if (mTarget)
{
- if (mTarget->getType() == Being::NPC)
+ if (mTarget->getType() == ActorSprite::NPC)
{
// NPCs are always in range
- mTarget->setTargetAnimation(
- mTargetCursor[0][mTarget->getTargetCursorSize()]);
+ mTarget->setTargetType(TCT_IN_RANGE);
}
else
{
@@ -220,10 +205,10 @@ void LocalPlayer::logic()
abs(mTarget->getTileY() - getTileY());
const int attackRange = getAttackRange();
- const int inRange = rangeX > attackRange || rangeY > attackRange
- ? 1 : 0;
- mTarget->setTargetAnimation(
- mTargetCursor[inRange][mTarget->getTargetCursorSize()]);
+ const TargetCursorType targetType = rangeX > attackRange ||
+ rangeY > attackRange ?
+ TCT_NORMAL : TCT_IN_RANGE;
+ mTarget->setTargetType(targetType);
if (!mTarget->isAlive())
stopAttack();
@@ -233,7 +218,7 @@ void LocalPlayer::logic()
}
}
- Player::logic();
+ Being::logic();
}
void LocalPlayer::setAction(Action action, int attackType)
@@ -244,12 +229,7 @@ void LocalPlayer::setAction(Action action, int attackType)
setTarget(NULL);
}
- Player::setAction(action, attackType);
-}
-
-void LocalPlayer::setGM(bool gm)
-{
- mIsGM = gm;
+ Being::setAction(action, attackType);
}
void LocalPlayer::setGMLevel(int level)
@@ -635,7 +615,7 @@ void LocalPlayer::nextTile(unsigned char dir = 0)
}
- Player::nextTile();
+ Being::nextTile();
}
else
{
@@ -674,7 +654,6 @@ void LocalPlayer::inviteToGuild(Being *being)
{
if (being->getType() != PLAYER)
return;
- Player *player = static_cast<Player*>(being);
// TODO: Allow user to choose which guild to invite being to
// For now, just invite to the first guild you have permissions to invite with
@@ -684,7 +663,7 @@ void LocalPlayer::inviteToGuild(Being *being)
{
if (checkInviteRights(itr->second->getName()))
{
- Net::getGuildHandler()->invite(itr->second->getId(), player);
+ Net::getGuildHandler()->invite(itr->second->getId(), being);
return;
}
}
@@ -707,8 +686,8 @@ void LocalPlayer::setInvItem(int index, int id, int amount)
void LocalPlayer::pickUp(FloorItem *item)
{
- int dx = item->getX() - (int) getPosition().x / 32;
- int dy = item->getY() - (int) getPosition().y / 32;
+ int dx = item->getTileX() - (int) getPosition().x / 32;
+ int dy = item->getTileY() - (int) getPosition().y / 32;
if (dx * dx + dy * dy < 4)
{
@@ -719,12 +698,12 @@ void LocalPlayer::pickUp(FloorItem *item)
{
if (Net::getNetworkType() == ServerInfo::MANASERV)
{
- setDestination(item->getX() * 32 + 16, item->getY() * 32 + 16);
+ setDestination(item->getPixelX() + 16, item->getPixelY() + 16);
mPickUpTarget = item;
}
else
{
- setDestination(item->getX(), item->getY());
+ setDestination(item->getTileX(), item->getTileY());
mPickUpTarget = item;
stopAttack();
}
@@ -757,15 +736,24 @@ void LocalPlayer::setTarget(Being *target)
mTargetTime = -1;
}
+ Being *oldTarget = 0;
if (mTarget)
+ {
mTarget->untarget();
+ oldTarget = mTarget;
+ }
- if (mTarget && mTarget->getType() == Being::MONSTER)
+ if (mTarget && mTarget->getType() == ActorSprite::MONSTER)
mTarget->setShowName(false);
mTarget = target;
- if (target && target->getType() == Being::MONSTER)
+ if (oldTarget)
+ oldTarget->updateName();
+ if (mTarget)
+ mTarget->updateName();
+
+ if (target && target->getType() == ActorSprite::MONSTER)
target->setShowName(true);
}
@@ -966,7 +954,7 @@ void LocalPlayer::attack(Being *target, bool keep)
mKeepAttacking = keep;
- if (!target || target->getType() == Being::NPC)
+ if (!target || target->getType() == ActorSprite::NPC)
return;
if (mTarget != target || !mTarget)
@@ -1022,7 +1010,7 @@ void LocalPlayer::attack(Being *target, bool keep)
setDirection(LEFT);
}
- mWalkTime = tick_time;
+ mActionTime = tick_time;
mTargetTime = tick_time;
}
@@ -1375,43 +1363,6 @@ void LocalPlayer::handleStatusEffect(StatusEffect *effect, int effectId)
}
}
-void LocalPlayer::initTargetCursor()
-{
- // Load target cursors
- loadTargetCursor("target-cursor-blue-s.png", 44, 35, false, TC_SMALL);
- loadTargetCursor("target-cursor-red-s.png", 44, 35, true, TC_SMALL);
- loadTargetCursor("target-cursor-blue-m.png", 62, 44, false, TC_MEDIUM);
- loadTargetCursor("target-cursor-red-m.png", 62, 44, true, TC_MEDIUM);
- loadTargetCursor("target-cursor-blue-l.png", 82, 60, false, TC_LARGE);
- loadTargetCursor("target-cursor-red-l.png", 82, 60, true, TC_LARGE);
-}
-
-void LocalPlayer::loadTargetCursor(const std::string &filename,
- int width, int height,
- bool outRange, TargetCursorSize size)
-{
- assert(size > -1);
- assert(size < 3);
-
- ImageSet *currentImageSet = Theme::getImageSetFromTheme(filename,
- width, height);
- Animation *anim = new Animation;
-
- for (unsigned int i = 0; i < currentImageSet->size(); ++i)
- {
- anim->addFrame(currentImageSet->get(i), 75,
- (16 - (currentImageSet->getWidth() / 2)),
- (16 - (currentImageSet->getHeight() / 2)));
- }
-
- SimpleAnimation *currentCursor = new SimpleAnimation(anim);
-
- const int index = outRange ? 1 : 0;
-
- mTargetCursorImages[index][size] = currentImageSet;
- mTargetCursor[index][size] = currentCursor;
-}
-
void LocalPlayer::addMessageToQueue(const std::string &message, int color)
{
mMessages.push_back(MessagePair(message, color));
diff --git a/src/localplayer.h b/src/localplayer.h
index 2c06dfb5..a7ed33f8 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -22,7 +22,7 @@
#ifndef LOCALPLAYER_H
#define LOCALPLAYER_H
-#include "player.h"
+#include "being.h"
#include "gui/userpalette.h"
@@ -109,7 +109,7 @@ enum
/**
* The local player character.
*/
-class LocalPlayer : public Player
+class LocalPlayer : public Being
{
public:
/**
@@ -194,11 +194,6 @@ class LocalPlayer : public Player
void attack(Being *target = NULL, bool keep = false);
- /**
- * Triggers whether or not to show the name as a GM name.
- */
- virtual void setGM(bool gm);
-
void setGMLevel(int level);
void stopAttack();
@@ -403,7 +398,7 @@ class LocalPlayer : public Player
std::string getFollow() const { return mPlayerFollowed; }
/**
- * Tells the engine wether to check
+ * Tells the engine whether to check
* if the Player Name is to be displayed.
*/
void setCheckNameSetting(bool checked) { mUpdateName = checked; }
@@ -424,9 +419,6 @@ class LocalPlayer : public Player
virtual void handleStatusEffect(StatusEffect *effect, int effectId);
- // Colors don't change for local player
- virtual void updateColors() {}
-
void startWalking(unsigned char dir);
int mAttackRange;
@@ -479,22 +471,6 @@ class LocalPlayer : public Player
int mLocalWalkTime; /**< Timestamp used to control keyboard walk
messages flooding */
- /** Load the target cursors into memory */
- void initTargetCursor();
-
- /**
- * Helper function for loading target cursors
- */
- void loadTargetCursor(const std::string &filename,
- int width, int height,
- bool outRange, Being::TargetCursorSize size);
-
- /** Images of the target cursor. */
- ImageSet *mTargetCursorImages[2][NUM_TC];
-
- /** Animated target cursors. */
- SimpleAnimation *mTargetCursor[2][NUM_TC];
-
typedef std::pair<std::string, int> MessagePair;
/** Queued exp messages*/
std::list<MessagePair> mMessages;
diff --git a/src/main.cpp b/src/main.cpp
index 56019976..0dd00f56 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -41,6 +41,10 @@ static void printHelp()
std::cout
<< _("mana [options] [mana-file]") << endl << endl
+ << _("[mana-file] : The mana file is an XML file (.mana)") << endl
+ << _(" used to set custom parameters") << endl
+ << _(" to the mana client.")
+ << endl << endl
<< _("Options:") << endl
<< _(" -v --version : Display the version") << endl
<< _(" -h --help : Display this help") << endl
@@ -56,6 +60,7 @@ static void printHelp()
<< _(" -u --skip-update : Skip the update downloads") << endl
<< _(" -d --data : Directory to load game data from") << endl
<< _(" -L --localdata-dir : Directory to use as local data directory") << endl
+ << _(" -l --chat-log-dir : Chat log dir to use") << endl
<< _(" --screenshot-dir : Directory to store screenshots") << endl
#ifdef USE_OPENGL
<< _(" --no-opengl : Disable OpenGL for this session") << endl
@@ -86,6 +91,7 @@ static void parseOptions(int argc, char *argv[], Client::Options &options)
{ "skip-update", no_argument, 0, 'u' },
{ "username", required_argument, 0, 'U' },
{ "no-opengl", no_argument, 0, 'O' },
+ { "chat-log-dir", required_argument, 0, 'l' },
{ "version", no_argument, 0, 'v' },
{ "screenshot-dir", required_argument, 0, 'i' },
{ 0 }
@@ -144,6 +150,8 @@ static void parseOptions(int argc, char *argv[], Client::Options &options)
case 'O':
options.noOpenGL = true;
break;
+ case 'l':
+ options.chatLogDir = std::string(optarg);
case 'i':
options.screenshotDir = optarg;
break;
diff --git a/src/map.cpp b/src/map.cpp
index 52459415..33bbccb1 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -21,13 +21,12 @@
#include "map.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "client.h"
#include "configuration.h"
#include "graphics.h"
#include "particle.h"
#include "simpleanimation.h"
-#include "sprite.h"
#include "tileset.h"
#include "resources/ambientlayer.h"
@@ -122,7 +121,7 @@ Image* MapLayer::getTile(int x, int y) const
void MapLayer::draw(Graphics *graphics, int startX, int startY,
int endX, int endY, int scrollX, int scrollY,
- const MapSprites &sprites, int debugFlags) const
+ const Actors &actors, int debugFlags) const
{
startX -= mX;
startY -= mY;
@@ -134,19 +133,18 @@ void MapLayer::draw(Graphics *graphics, int startX, int startY,
if (endX > mWidth) endX = mWidth;
if (endY > mHeight) endY = mHeight;
- MapSprites::const_iterator si = sprites.begin();
+ Actors::const_iterator ai = actors.begin();
for (int y = startY; y < endY; y++)
{
- // If drawing the fringe layer, make sure all sprites above this row of
+ // If drawing the fringe layer, make sure all actors above this row of
// tiles have been drawn
if (mIsFringeLayer)
{
- while (si != sprites.end() && (*si)->getPixelY() <= y * 32)
+ while (ai != actors.end() && (*ai)->getPixelY() <= y * 32)
{
- (*si)->setAlpha(1.0f);
- (*si)->draw(graphics, -scrollX, -scrollY);
- si++;
+ (*ai)->draw(graphics, -scrollX, -scrollY);
+ ai++;
}
}
@@ -163,14 +161,13 @@ void MapLayer::draw(Graphics *graphics, int startX, int startY,
}
}
- // Draw any remaining sprites
+ // Draw any remaining actors
if (mIsFringeLayer)
{
- while (si != sprites.end())
+ while (ai != actors.end())
{
- (*si)->setAlpha(1.0f);
- (*si)->draw(graphics, -scrollX, -scrollY);
- si++;
+ (*ai)->draw(graphics, -scrollX, -scrollY);
+ ai++;
}
}
}
@@ -283,7 +280,7 @@ void Map::addTileset(Tileset *tileset)
mMaxTileHeight = tileset->getHeight();
}
-bool spriteCompare(const Sprite *a, const Sprite *b)
+bool actorCompare(const Actor *a, const Actor *b)
{
return a->getPixelY() < b->getPixelY();
}
@@ -309,9 +306,9 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY)
int endX = (graphics->getWidth() + scrollX + mTileWidth - 1) / mTileWidth;
int endY = endPixelY / mTileHeight;
- // Make sure sprites are sorted ascending by Y-coordinate
+ // Make sure actors are sorted ascending by Y-coordinate
// so that they overlap correctly
- mSprites.sort(spriteCompare);
+ mActors.sort(actorCompare);
// update scrolling of all ambient layers
updateAmbientLayers(scrollX, scrollY);
@@ -327,24 +324,25 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY)
(*layeri)->draw(graphics,
startX, startY, endX, endY,
scrollX, scrollY,
- mSprites, mDebugFlags);
+ mActors, mDebugFlags);
}
// Draws beings with a lower opacity to make them visible
// even when covered by a wall or some other elements...
- MapSprites::const_iterator si = mSprites.begin();
- while (si != mSprites.end())
+ Actors::const_iterator ai = mActors.begin();
+ while (ai != mActors.end())
{
- if (Sprite *sprite = *si)
+ if (Actor *actor = *ai)
{
- // For now, just draw sprites with only one layer.
- if (sprite->getNumberOfLayers() == 1)
+ // For now, just draw actors with only one layer.
+ if (actor->getNumberOfLayers() == 1)
{
- sprite->setAlpha(0.3f);
- sprite->draw(graphics, -scrollX, -scrollY);
+ actor->setAlpha(0.3f);
+ actor->draw(graphics, -scrollX, -scrollY);
+ actor->setAlpha(1.0f);
}
}
- si++;
+ ai++;
}
drawAmbientLayers(graphics, FOREGROUND_LAYERS, scrollX, scrollY,
@@ -534,12 +532,14 @@ bool Map::getWalk(int x, int y, unsigned char walkmask) const
bool Map::occupied(int x, int y) const
{
- const Beings &beings = beingManager->getAll();
- for (Beings::const_iterator i = beings.begin(); i != beings.end(); i++)
+ const ActorSprites &actors = actorSpriteManager->getAll();
+ ActorSpritesConstIterator it, it_end;
+ for (it = actors.begin(), it_end = actors.end(); it != it_end; it++)
{
- const Being *being = *i;
+ const ActorSprite *actor = *it;
- if (being->getTileX() == x && being->getTileY() == y)
+ if (actor->getTileX() == x && actor->getTileY() == y &&
+ actor->getType() != ActorSprite::FLOOR_ITEM)
return true;
}
@@ -556,15 +556,15 @@ MetaTile *Map::getMetaTile(int x, int y) const
return &mMetaTiles[x + y * mWidth];
}
-MapSprite Map::addSprite(Sprite *sprite)
+Actors::iterator Map::addActor(Actor *actor)
{
- mSprites.push_front(sprite);
- return mSprites.begin();
+ mActors.push_front(actor);
+ return mActors.begin();
}
-void Map::removeSprite(MapSprite iterator)
+void Map::removeActor(Actors::iterator iterator)
{
- mSprites.erase(iterator);
+ mActors.erase(iterator);
}
const std::string Map::getMusicFile() const
diff --git a/src/map.h b/src/map.h
index 9fc32232..86a5d3ee 100644
--- a/src/map.h
+++ b/src/map.h
@@ -22,6 +22,7 @@
#ifndef MAP_H
#define MAP_H
+#include "actor.h"
#include "position.h"
#include "properties.h"
@@ -31,16 +32,12 @@
class Animation;
class AmbientLayer;
class Graphics;
-class Image;
class MapLayer;
class Particle;
class SimpleAnimation;
-class Sprite;
class Tileset;
typedef std::vector<Tileset*> Tilesets;
-typedef std::list<Sprite*> MapSprites;
-typedef MapSprites::iterator MapSprite;
typedef std::vector<MapLayer*> Layers;
/**
@@ -91,7 +88,7 @@ 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.
+ * fringe layer. The fringe layer is the layer that draws the actors.
* There can be only one fringe layer per map.
*/
MapLayer(int x, int y, int width, int height, bool isFringeLayer);
@@ -121,20 +118,20 @@ class MapLayer
* 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
+ * The given actors 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 MapSprites &sprites,
+ const Actors &actors,
int mDebugFlags) const;
private:
int mX, mY;
int mWidth, mHeight;
- bool mIsFringeLayer; /**< Whether the sprites are drawn. */
+ bool mIsFringeLayer; /**< Whether the actors are drawn. */
Image **mTiles;
};
@@ -190,7 +187,7 @@ class Map : public Properties
/**
* Draws the map to the given graphics output. This method draws all
- * layers, sprites and overlay effects.
+ * layers, actors and overlay effects.
*
* TODO: For efficiency reasons, this method could take into account
* the clipping rectangle set on the Graphics object. However,
@@ -295,16 +292,6 @@ class Map : public Properties
unsigned char walkmask, int maxCost = 20);
/**
- * Adds a sprite to the map.
- */
- MapSprite addSprite(Sprite *sprite);
-
- /**
- * Removes a sprite from the map.
- */
- void removeSprite(MapSprite iterator);
-
- /**
* Adds a particle effect
*/
void addParticleEffect(const std::string &effectFile, int x, int y, int w = 0, int h = 0);
@@ -329,6 +316,19 @@ class Map : public Properties
*/
TileAnimation *getAnimationForGid(int gid) const;
+ protected:
+ friend class Actor;
+
+ /**
+ * Adds an actor to the map.
+ */
+ Actors::iterator addActor(Actor *actor);
+
+ /**
+ * Removes an actor from the map.
+ */
+ void removeActor(Actors::iterator iterator);
+
private:
enum LayerType
@@ -364,7 +364,7 @@ class Map : public Properties
MetaTile *mMetaTiles;
Layers mLayers;
Tilesets mTilesets;
- MapSprites mSprites;
+ Actors mActors;
// debug flags
int mDebugFlags;
diff --git a/src/monster.cpp b/src/monster.cpp
deleted file mode 100644
index d25c6c90..00000000
--- a/src/monster.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "monster.h"
-
-#include "animatedsprite.h"
-#include "client.h"
-#include "localplayer.h"
-#include "particle.h"
-#include "sound.h"
-#include "text.h"
-
-#include "gui/userpalette.h"
-
-#include "net/net.h"
-
-#include "resources/monsterdb.h"
-#include "resources/monsterinfo.h"
-
-Monster::Monster(int id, int subtype, Map *map):
- Being(id, subtype, map),
- mAttackType(1)
-{
- setSubtype(subtype);
-
- mNameColor = &userPalette->getColor(UserPalette::MONSTER);
- mTextColor = &userPalette->getColor(UserPalette::MONSTER);
-
- Being::setName(getInfo().getName());
-}
-
-void Monster::logic()
-{
- if ((Net::getNetworkType() == ServerInfo::TMWATHENA) && (mAction != STAND))
- {
- mFrame = (int) ((get_elapsed_time(mWalkTime) * 4) / getWalkSpeed().x);
-
- if (mFrame >= 4 && mAction != DEAD)
- nextTile();
- }
-
- Being::logic();
-}
-
-
-void Monster::setAction(Action action, int attackType)
-{
- SpriteAction currentAction = ACTION_INVALID;
- int rotation = 0;
- std::string particleEffect;
-
- switch (action)
- {
- case WALK:
- currentAction = ACTION_WALK;
- break;
- case DEAD:
- currentAction = ACTION_DEAD;
- sound.playSfx(getInfo().getSound(MONSTER_EVENT_DIE));
- break;
- case ATTACK:
- mAttackType = attackType;
- currentAction = getInfo().getAttackAction(attackType);
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- (*it)->reset();
-
- //attack particle effect
- particleEffect = getInfo().getAttackParticleEffect(attackType);
- if (!particleEffect.empty() && Particle::enabled)
- {
- switch (mSpriteDirection)
- {
- case DIRECTION_DOWN: rotation = 0; break;
- case DIRECTION_LEFT: rotation = 90; break;
- case DIRECTION_UP: rotation = 180; break;
- case DIRECTION_RIGHT: rotation = 270; break;
- default: break;
- }
- Particle *p;
- p = particleEngine->addEffect(particleEffect, 0, 0, rotation);
- controlParticle(p);
- }
- break;
- case STAND:
- currentAction = ACTION_STAND;
- break;
- case HURT:
- // Not implemented yet
- break;
- case SIT:
- // Also not implemented yet
- break;
- }
-
- if (currentAction != ACTION_INVALID)
- {
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if (*it)
- (*it)->play(currentAction);
- mAction = action;
- }
-}
-
-void Monster::setSubtype(Uint16 subtype)
-{
- Being::setSubtype(subtype);
-
- const MonsterInfo &info = getInfo();
-
- // Setup Monster sprites
- const std::list<std::string> &sprites = info.getSprites();
-
- mSprites.clear();
- for (std::list<std::string>::const_iterator i = sprites.begin();
- i != sprites.end(); i++)
- {
- std::string file = "graphics/sprites/" + *i;
- mSprites.push_back(AnimatedSprite::load(file));
- }
-
- // Ensure that something is shown
- if (mSprites.size() == 0)
- {
- mSprites.push_back(AnimatedSprite::load("graphics/sprites/error.xml"));
- }
-
- if (Particle::enabled)
- {
- const std::list<std::string> &particleEffects = info.getParticleEffects();
- for (std::list<std::string>::const_iterator i = particleEffects.begin();
- i != particleEffects.end(); i++)
- {
- controlParticle(particleEngine->addEffect((*i), 0, 0));
- }
- }
-}
-
-void Monster::handleAttack(Being *victim, int damage, AttackType type)
-{
- Being::handleAttack(victim, damage, type);
-
- const MonsterInfo &mi = getInfo();
- sound.playSfx(mi.getSound((damage > 0) ?
- MONSTER_EVENT_HIT : MONSTER_EVENT_MISS));
-
- fireMissile(victim, mi.getAttackMissileParticle(mAttackType));
-}
-
-void Monster::takeDamage(Being *attacker, int amount, AttackType type)
-{
- if (amount > 0)
- sound.playSfx(getInfo().getSound(MONSTER_EVENT_HURT));
-
- Being::takeDamage(attacker, amount, type);
-}
-
-Being::TargetCursorSize Monster::getTargetCursorSize() const
-{
- return getInfo().getTargetCursorSize();
-}
-
-const MonsterInfo &Monster::getInfo() const
-{
- return MonsterDB::get(mSubType);
-}
-
-void Monster::updateCoords()
-{
- if (mDispName)
- {
- mDispName->adviseXY(getPixelX(),
- getPixelY() - getHeight() - mDispName->getHeight());
- }
-}
-
-void Monster::showName()
-{
- Being::showName();
-
- updateCoords();
-}
diff --git a/src/monster.h b/src/monster.h
deleted file mode 100644
index 9bb8e3b9..00000000
--- a/src/monster.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MONSTER_H
-#define MONSTER_H
-
-#include "being.h"
-
-class MonsterInfo;
-class Text;
-
-class Monster : public Being
-{
- public:
- Monster(int id, int subtype, Map *map);
-
- virtual void logic();
-
- virtual void setAction(Action action, int attackType = 0);
-
- virtual Type getType() const { return MONSTER; }
-
- virtual void setSubtype(Uint16 subtype);
-
- virtual TargetCursorSize
- getTargetCursorSize() const;
-
- /**
- * Handles an attack of another being by this monster. Plays a hit or
- * miss sound when appropriate.
- *
- * @param victim the victim being
- * @param damage the amount of damage dealt (0 means miss)
- * @param type the attack type
- */
- virtual void handleAttack(Being *victim, int damage, AttackType type);
-
- /**
- * Puts a damage bubble above this monster and plays the hurt sound
- *
- * @param attacker the attacking being
- * @param damage the amount of damage recieved (0 means miss)
- * @param type the attack type
- */
- virtual void takeDamage(Being *attacker, int amount, AttackType type);
-
- /**
- * Returns the MonsterInfo, with static data about this monster.
- */
- const MonsterInfo& getInfo() const;
-
- /**
- * Gets the way the monster is blocked by other objects
- */
- virtual unsigned char getWalkMask() const
- {
- return Map::BLOCKMASK_WALL
- | Map::BLOCKMASK_CHARACTER
- | Map::BLOCKMASK_MONSTER;
- }
-
- protected:
- /**
- * Gets the way the monster blocks pathfinding for other objects
- */
- virtual Map::BlockType getBlockType() const
- { return Map::BLOCKTYPE_MONSTER; }
-
- /**
- * Update the text when the monster moves
- */
- void updateCoords();
-
- void showName();
-
- private:
- int mAttackType;
-};
-
-#endif
diff --git a/src/net/charhandler.h b/src/net/charhandler.h
index 4a813e21..e3c8cfd6 100644
--- a/src/net/charhandler.h
+++ b/src/net/charhandler.h
@@ -75,11 +75,11 @@ class CharHandler
virtual void switchCharacter() = 0;
- virtual int baseSprite() const = 0;
+ virtual unsigned int baseSprite() const = 0;
- virtual int hairSprite() const = 0;
+ virtual unsigned int hairSprite() const = 0;
- virtual int maxSprite() const = 0;
+ virtual unsigned int maxSprite() const = 0;
virtual ~CharHandler() {}
diff --git a/src/net/gamehandler.h b/src/net/gamehandler.h
index 774de16c..8d29a55b 100644
--- a/src/net/gamehandler.h
+++ b/src/net/gamehandler.h
@@ -49,6 +49,11 @@ class GameHandler
virtual bool removeDeadBeings() const = 0;
+ /**
+ * Tells whether the protocol is using the MP statu bar
+ */
+ virtual bool canUseMagicBar() const = 0;
+
virtual ~GameHandler() {}
};
diff --git a/src/net/guildhandler.h b/src/net/guildhandler.h
index 1696b2d5..e4513cbb 100644
--- a/src/net/guildhandler.h
+++ b/src/net/guildhandler.h
@@ -23,10 +23,11 @@
#define GUILDHANDLER_H
#include "guild.h"
-#include "player.h"
#include <iosfwd>
+class Being;
+
namespace Net {
class GuildHandler
@@ -40,7 +41,7 @@ class GuildHandler
virtual void invite(int guildId, const std::string &name) = 0;
- virtual void invite(int guildId, Player *player) = 0;
+ virtual void invite(int guildId, Being *being) = 0;
virtual void inviteResponse(int guildId, bool response) = 0;
diff --git a/src/net/logindata.h b/src/net/logindata.h
index 9bbeed4f..021a57f3 100644
--- a/src/net/logindata.h
+++ b/src/net/logindata.h
@@ -22,7 +22,7 @@
#ifndef LOGINDATA_H
#define LOGINDATA_H
-#include "player.h"
+#include "being.h"
#include "net/serverinfo.h"
diff --git a/src/net/manaserv/beinghandler.cpp b/src/net/manaserv/beinghandler.cpp
index b08af749..57830680 100644
--- a/src/net/manaserv/beinghandler.cpp
+++ b/src/net/manaserv/beinghandler.cpp
@@ -21,13 +21,12 @@
#include "net/manaserv/beinghandler.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "client.h"
#include "game.h"
#include "localplayer.h"
#include "log.h"
-#include "npc.h"
#include "particle.h"
#include "gui/okdialog.h"
@@ -121,7 +120,7 @@ Vector BeingHandler::giveSpeedInPixelsPerTicks(float speedInTilesPerSeconds)
return speedInTicks;
}
-static void handleLooks(Player *being, Net::MessageIn &msg)
+static void handleLooks(Being *being, Net::MessageIn &msg)
{
// Order of sent slots. Has to be in sync with the server code.
static int const nb_slots = 4;
@@ -170,23 +169,23 @@ void BeingHandler::handleBeingEnterMessage(Net::MessageIn &msg)
}
else
{
- being = beingManager->createBeing(id, Being::PLAYER, 0);
+ being = actorSpriteManager->createBeing(id,
+ ActorSprite::PLAYER, 0);
being->setName(name);
}
- Player *p = static_cast< Player * >(being);
int hs = msg.readInt8(), hc = msg.readInt8();
- p->setSprite(SPRITE_HAIR, hs * -1, ColorDB::get(hc));
- p->setGender(msg.readInt8() == GENDER_MALE ?
- GENDER_MALE : GENDER_FEMALE);
- handleLooks(p, msg);
+ being->setSprite(SPRITE_HAIR, hs * -1, ColorDB::get(hc));
+ being->setGender(msg.readInt8() == GENDER_MALE ?
+ GENDER_MALE : GENDER_FEMALE);
+ handleLooks(being, msg);
} break;
case OBJECT_MONSTER:
case OBJECT_NPC:
{
int subtype = msg.readInt16();
- being = beingManager->createBeing(id, type == OBJECT_MONSTER ?
- Being::MONSTER : Being::NPC, subtype);
+ being = actorSpriteManager->createBeing(id, type == OBJECT_MONSTER
+ ? ActorSprite::MONSTER : ActorSprite::NPC, subtype);
std::string name = msg.readString();
if (name.length() > 0) being->setName(name);
} break;
@@ -202,11 +201,11 @@ void BeingHandler::handleBeingEnterMessage(Net::MessageIn &msg)
void BeingHandler::handleBeingLeaveMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
if (!being)
return;
- beingManager->destroyBeing(being);
+ actorSpriteManager->destroy(being);
}
void BeingHandler::handleBeingsMoveMessage(Net::MessageIn &msg)
@@ -215,7 +214,7 @@ void BeingHandler::handleBeingsMoveMessage(Net::MessageIn &msg)
{
int id = msg.readInt16();
int flags = msg.readInt8();
- Being *being = beingManager->findBeing(id);
+ Being *being = actorSpriteManager->findBeing(id);
int sx = 0;
int sy = 0;
int speed = 0;
@@ -257,7 +256,7 @@ void BeingHandler::handleBeingsMoveMessage(Net::MessageIn &msg)
void BeingHandler::handleBeingAttackMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
const int direction = msg.readInt8();
const int attackType = msg.readInt8();
@@ -279,7 +278,7 @@ void BeingHandler::handleBeingsDamageMessage(Net::MessageIn &msg)
{
while (msg.getUnreadLength())
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
int damage = msg.readInt16();
if (being)
{
@@ -290,7 +289,7 @@ void BeingHandler::handleBeingsDamageMessage(Net::MessageIn &msg)
void BeingHandler::handleBeingActionChangeMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
Being::Action action = (Being::Action) msg.readInt8();
if (!being)
return;
@@ -329,22 +328,21 @@ void BeingHandler::handleBeingActionChangeMessage(Net::MessageIn &msg)
void BeingHandler::handleBeingLooksChangeMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
- if (!being || being->getType() != Being::PLAYER)
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
+ if (!being || being->getType() != ActorSprite::PLAYER)
return;
- Player *player = static_cast<Player *>(being);
- handleLooks(player, msg);
+ handleLooks(being, msg);
if (msg.getUnreadLength())
{
int style = msg.readInt16();
int color = msg.readInt16();
- player->setSprite(SPRITE_HAIR, style * -1, ColorDB::get(color));
+ being->setSprite(SPRITE_HAIR, style * -1, ColorDB::get(color));
}
}
void BeingHandler::handleBeingDirChangeMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
if (!being)
return;
int data = msg.readInt8();
diff --git a/src/net/manaserv/buysellhandler.cpp b/src/net/manaserv/buysellhandler.cpp
index a4ce6aa0..cfd55e2e 100644
--- a/src/net/manaserv/buysellhandler.cpp
+++ b/src/net/manaserv/buysellhandler.cpp
@@ -21,10 +21,9 @@
#include "net/manaserv/buysellhandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "item.h"
#include "localplayer.h"
-#include "npc.h"
#include "gui/buy.h"
#include "gui/chat.h"
@@ -49,8 +48,8 @@ BuySellHandler::BuySellHandler()
void BuySellHandler::handleMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
- if (!being || being->getType() != Being::NPC)
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
+ if (!being || being->getType() != ActorSprite::NPC)
{
return;
}
diff --git a/src/net/manaserv/charhandler.cpp b/src/net/manaserv/charhandler.cpp
index e6723226..e2c67f35 100644
--- a/src/net/manaserv/charhandler.cpp
+++ b/src/net/manaserv/charhandler.cpp
@@ -319,17 +319,17 @@ void CharHandler::switchCharacter()
gameHandler->quit(true);
}
-int CharHandler::baseSprite() const
+unsigned int CharHandler::baseSprite() const
{
return SPRITE_BASE;
}
-int CharHandler::hairSprite() const
+unsigned int CharHandler::hairSprite() const
{
return SPRITE_HAIR;
}
-int CharHandler::maxSprite() const
+unsigned int CharHandler::maxSprite() const
{
return SPRITE_VECTOREND;
}
diff --git a/src/net/manaserv/charhandler.h b/src/net/manaserv/charhandler.h
index 26a7bf4e..dac4a29e 100644
--- a/src/net/manaserv/charhandler.h
+++ b/src/net/manaserv/charhandler.h
@@ -65,11 +65,11 @@ class CharHandler : public MessageHandler, public Net::CharHandler
void switchCharacter();
- int baseSprite() const;
+ unsigned int baseSprite() const;
- int hairSprite() const;
+ unsigned int hairSprite() const;
- int maxSprite() const;
+ unsigned int maxSprite() const;
void clear();
diff --git a/src/net/manaserv/chathandler.cpp b/src/net/manaserv/chathandler.cpp
index a452281f..37ce2bf5 100644
--- a/src/net/manaserv/chathandler.cpp
+++ b/src/net/manaserv/chathandler.cpp
@@ -21,8 +21,8 @@
#include "net/manaserv/chathandler.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "client.h"
#include "channel.h"
#include "channelmanager.h"
@@ -153,7 +153,7 @@ void ChatHandler::handleGameChatMessage(Net::MessageIn &msg)
return;
}
- Being *being = beingManager->findBeing(id);
+ Being *being = actorSpriteManager->findBeing(id);
std::string mes;
if (being)
diff --git a/src/net/manaserv/effecthandler.cpp b/src/net/manaserv/effecthandler.cpp
index 27db9b59..c803b441 100644
--- a/src/net/manaserv/effecthandler.cpp
+++ b/src/net/manaserv/effecthandler.cpp
@@ -21,7 +21,7 @@
#include "net/manaserv/effecthandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "effectmanager.h"
#include "log.h"
@@ -68,7 +68,7 @@ void EffectHandler::handleCreateEffectBeing(Net::MessageIn &msg)
{
int eid = msg.readInt16();
int bid = msg.readInt16();
- Being* b = beingManager->findBeing(bid);
+ Being* b = actorSpriteManager->findBeing(bid);
if (b)
effectManager->trigger(eid, b);
else
diff --git a/src/net/manaserv/gamehandler.h b/src/net/manaserv/gamehandler.h
index dde1748f..912b308e 100644
--- a/src/net/manaserv/gamehandler.h
+++ b/src/net/manaserv/gamehandler.h
@@ -53,12 +53,16 @@ class GameHandler : public MessageHandler, public Net::GameHandler
void quit() { quit(false); }
void ping(int tick);
-
+
bool removeDeadBeings() const { return false; }
void clear();
void gameLoading();
+
+ /** The ManaServ protocol doesn't use the Mp Main status bar. */
+ bool canUseMagicBar() const { return false; }
+
};
} // namespace ManaServ
diff --git a/src/net/manaserv/guildhandler.cpp b/src/net/manaserv/guildhandler.cpp
index 253efb01..1fbfdf21 100644
--- a/src/net/manaserv/guildhandler.cpp
+++ b/src/net/manaserv/guildhandler.cpp
@@ -275,9 +275,9 @@ void GuildHandler::invite(int guildId, const std::string &name)
chatServerConnection->send(msg);
}
-void GuildHandler::invite(int guildId, Player *player)
+void GuildHandler::invite(int guildId, Being *being)
{
- invite(guildId, player->getName());
+ invite(guildId, being->getName());
}
void GuildHandler::inviteResponse(int guildId, bool response)
diff --git a/src/net/manaserv/guildhandler.h b/src/net/manaserv/guildhandler.h
index 9929d135..bde677fb 100644
--- a/src/net/manaserv/guildhandler.h
+++ b/src/net/manaserv/guildhandler.h
@@ -41,7 +41,7 @@ public:
void invite(int guildId, const std::string &name);
- void invite(int guidId, Player *player);
+ void invite(int guidId, Being *being);
void inviteResponse(int guidId, bool response);
diff --git a/src/net/manaserv/itemhandler.cpp b/src/net/manaserv/itemhandler.cpp
index dc3b9f14..200e7fac 100644
--- a/src/net/manaserv/itemhandler.cpp
+++ b/src/net/manaserv/itemhandler.cpp
@@ -21,7 +21,7 @@
#include "net/manaserv/itemhandler.h"
-#include "flooritemmanager.h"
+#include "actorspritemanager.h"
#include "net/manaserv/protocol.h"
#include "net/manaserv/messagein.h"
@@ -62,8 +62,7 @@ void ItemHandler::handleMessage(Net::MessageIn &msg)
{
if (Map *map = game->getCurrentMap())
{
- floorItemManager->create(id,
- itemId,
+ actorSpriteManager->createItem(id, itemId,
x / map->getTileWidth(),
y / map->getTileHeight());
}
@@ -75,9 +74,9 @@ void ItemHandler::handleMessage(Net::MessageIn &msg)
}
}
}
- else if (FloorItem *item = floorItemManager->findById(id))
+ else if (FloorItem *item = actorSpriteManager->findItem(id))
{
- floorItemManager->destroy(item);
+ actorSpriteManager->destroy(item);
}
}
} break;
diff --git a/src/net/manaserv/npchandler.cpp b/src/net/manaserv/npchandler.cpp
index 392ec4fd..509f26e1 100644
--- a/src/net/manaserv/npchandler.cpp
+++ b/src/net/manaserv/npchandler.cpp
@@ -21,8 +21,7 @@
#include "net/manaserv/npchandler.h"
-#include "beingmanager.h"
-#include "npc.h"
+#include "actorspritemanager.h"
#include "gui/npcdialog.h"
#include "gui/npcpostdialog.h"
@@ -56,8 +55,8 @@ NpcHandler::NpcHandler()
void NpcHandler::handleMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
- if (!being || being->getType() != Being::NPC)
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
+ if (!being || being->getType() != ActorSprite::NPC)
{
return;
}
diff --git a/src/net/manaserv/partyhandler.cpp b/src/net/manaserv/partyhandler.cpp
index ec153fa8..2fd48f57 100644
--- a/src/net/manaserv/partyhandler.cpp
+++ b/src/net/manaserv/partyhandler.cpp
@@ -136,9 +136,9 @@ void PartyHandler::join(int partyId)
// TODO
}
-void PartyHandler::invite(Player *player)
+void PartyHandler::invite(Being *being)
{
- invite(player->getName());
+ invite(being->getName());
}
void PartyHandler::invite(const std::string &name)
@@ -167,7 +167,7 @@ void PartyHandler::leave()
chatServerConnection->send(msg);
}
-void PartyHandler::kick(Player *player)
+void PartyHandler::kick(Being *being)
{
// TODO
}
diff --git a/src/net/manaserv/partyhandler.h b/src/net/manaserv/partyhandler.h
index 0777b49e..29dc280d 100644
--- a/src/net/manaserv/partyhandler.h
+++ b/src/net/manaserv/partyhandler.h
@@ -43,7 +43,7 @@ public:
void join(int partyId);
- void invite(Player *player);
+ void invite(Being *being);
void invite(const std::string &name);
@@ -51,7 +51,7 @@ public:
void leave();
- void kick(Player *player);
+ void kick(Being *being);
void kick(const std::string &name);
diff --git a/src/net/manaserv/playerhandler.cpp b/src/net/manaserv/playerhandler.cpp
index f6207800..60fa5b29 100644
--- a/src/net/manaserv/playerhandler.cpp
+++ b/src/net/manaserv/playerhandler.cpp
@@ -28,7 +28,6 @@
#include "localplayer.h"
#include "log.h"
#include "particle.h"
-#include "npc.h"
#include "gui/chat.h"
#include "gui/gui.h"
diff --git a/src/net/manaserv/tradehandler.cpp b/src/net/manaserv/tradehandler.cpp
index 234a18d6..b6169ac9 100644
--- a/src/net/manaserv/tradehandler.cpp
+++ b/src/net/manaserv/tradehandler.cpp
@@ -21,7 +21,7 @@
#include "net/manaserv/tradehandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "item.h"
#include "localplayer.h"
@@ -104,7 +104,7 @@ void TradeHandler::handleMessage(Net::MessageIn &msg)
{
case GPMSG_TRADE_REQUEST:
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
if (!being || !mAcceptTradeRequests)
{
respond(false);
diff --git a/src/net/partyhandler.h b/src/net/partyhandler.h
index dd1103fc..ba2ed458 100644
--- a/src/net/partyhandler.h
+++ b/src/net/partyhandler.h
@@ -24,7 +24,7 @@
#include <string>
-class Player;
+class Being;
enum PartyShare {
PARTY_SHARE_UNKNOWN = -1,
@@ -42,7 +42,7 @@ class PartyHandler
virtual void join(int partyId) = 0;
- virtual void invite(Player *player) = 0;
+ virtual void invite(Being *player) = 0;
virtual void invite(const std::string &name) = 0;
@@ -50,7 +50,7 @@ class PartyHandler
virtual void leave() = 0;
- virtual void kick(Player *player) = 0;
+ virtual void kick(Being *player) = 0;
virtual void kick(const std::string &name) = 0;
diff --git a/src/net/tmwa/adminhandler.cpp b/src/net/tmwa/adminhandler.cpp
index e56d5a44..da089b2b 100644
--- a/src/net/tmwa/adminhandler.cpp
+++ b/src/net/tmwa/adminhandler.cpp
@@ -21,8 +21,8 @@
#include "net/tmwa/adminhandler.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "game.h"
#include "playerrelations.h"
diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp
index 04690c50..5c89cd31 100644
--- a/src/net/tmwa/beinghandler.cpp
+++ b/src/net/tmwa/beinghandler.cpp
@@ -21,14 +21,13 @@
#include "net/tmwa/beinghandler.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "client.h"
#include "effectmanager.h"
#include "guild.h"
#include "localplayer.h"
#include "log.h"
-#include "npc.h"
#include "party.h"
#include "playerrelations.h"
@@ -74,19 +73,19 @@ BeingHandler::BeingHandler(bool enableSync):
Being *createBeing(int id, short job)
{
- Being::Type type = Being::UNKNOWN;
+ ActorSprite::Type type = ActorSprite::UNKNOWN;
if (job <= 25 || (job >= 4001 && job <= 4049))
- type = Being::PLAYER;
+ type = ActorSprite::PLAYER;
else if (job >= 46 && job <= 1000)
- type = Being::NPC;
+ type = ActorSprite::NPC;
else if (job > 1000 && job <= 2000)
- type = Being::MONSTER;
+ type = ActorSprite::MONSTER;
else if (job == 45)
return NULL; // Skip portals
- Being *being = beingManager->createBeing(id, type, job);
+ Being *being = actorSpriteManager->createBeing(id, type, job);
- if (type == Being::PLAYER || type == Being::NPC)
+ if (type == ActorSprite::PLAYER || type == ActorSprite::NPC)
{
MessageOut outMsg(0x0094);
outMsg.writeInt32(id);//readLong(2));
@@ -97,7 +96,7 @@ Being *createBeing(int id, short job)
void BeingHandler::handleMessage(Net::MessageIn &msg)
{
- if (!beingManager)
+ if (!actorSpriteManager)
return;
int id;
@@ -112,7 +111,6 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
int type, guild;
Uint16 status;
Being *srcBeing, *dstBeing;
- Player *player = 0;
int hairStyle, hairColor, flag;
std::string player_followed;
@@ -128,7 +126,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
statusEffects |= ((Uint32)msg.readInt16()) << 16; // option
job = msg.readInt16(); // class
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
if (!dstBeing)
{
@@ -145,14 +143,10 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
}
- if (dstBeing->getType() == Being::PLAYER)
- player = static_cast<Player*>(dstBeing);
-
- if (msg.getId() == 0x0078)
+ if (msg.getId() == SMSG_BEING_VISIBLE)
{
dstBeing->clearPath();
- dstBeing->setFrame(0);
- dstBeing->setWalkTime(tick_time);
+ dstBeing->setActionTime(tick_time);
dstBeing->setAction(Being::STAND);
}
@@ -178,16 +172,13 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
shoes = msg.readInt16(); // clothes color - "abused" as shoes
gloves = msg.readInt16(); // head dir - "abused" as gloves
guild = msg.readInt32(); // guild
- if (player)
+ if (guild == 0)
{
- if (guild == 0)
- {
- player->clearGuilds();
- }
- else
- {
- player->addGuild(Guild::getGuild(guild));
- }
+ dstBeing->clearGuilds();
+ }
+ else
+ {
+ dstBeing->addGuild(Guild::getGuild(guild));
}
msg.readInt16(); // guild emblem
msg.readInt16(); // manner
@@ -195,19 +186,19 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
msg.readInt8(); // karma
gender = msg.readInt8();
- if (player)
+ if (dstBeing->getType() == ActorSprite::PLAYER)
{
- player->setGender((gender == 0)
- ? GENDER_FEMALE : GENDER_MALE);
+ dstBeing->setGender((gender == 0)
+ ? GENDER_FEMALE : GENDER_MALE);
// Set these after the gender, as the sprites may be gender-specific
- player->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor));
- player->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
- player->setSprite(SPRITE_TOPCLOTHES, headMid);
- player->setSprite(SPRITE_HAT, headTop);
- player->setSprite(SPRITE_SHOE, shoes);
- player->setSprite(SPRITE_GLOVES, gloves);
- player->setSprite(SPRITE_WEAPON, weapon, "", true);
- player->setSprite(SPRITE_SHIELD, shield);
+ dstBeing->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor));
+ dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
+ dstBeing->setSprite(SPRITE_TOPCLOTHES, headMid);
+ dstBeing->setSprite(SPRITE_HAT, headTop);
+ dstBeing->setSprite(SPRITE_SHOE, shoes);
+ dstBeing->setSprite(SPRITE_GLOVES, gloves);
+ dstBeing->setSprite(SPRITE_WEAPON, weapon, "", true);
+ dstBeing->setSprite(SPRITE_SHIELD, shield);
}
if (msg.getId() == SMSG_BEING_MOVE)
@@ -242,7 +233,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
* later versions of eAthena for both mobs and
* players
*/
- dstBeing = beingManager->findBeing(msg.readInt32());
+ dstBeing = actorSpriteManager->findBeing(msg.readInt32());
Uint16 srcX, srcY, dstX, dstY;
msg.readCoordinatePair(srcX, srcY, dstX, dstY);
@@ -267,7 +258,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
// A being should be removed or has died
id = msg.readInt32();
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
if (!dstBeing)
break;
@@ -289,7 +280,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
if (msg.readInt8() == 1)
dstBeing->setAction(Being::DEAD);
else
- beingManager->destroyBeing(dstBeing);
+ actorSpriteManager->destroy(dstBeing);
break;
@@ -297,7 +288,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
// A being changed mortality status
id = msg.readInt32();
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
if (!dstBeing)
break;
@@ -313,8 +304,8 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
case SMSG_SKILL_DAMAGE:
msg.readInt16(); // Skill Id
- srcBeing = beingManager->findBeing(msg.readInt32());
- dstBeing = beingManager->findBeing(msg.readInt32());
+ srcBeing = actorSpriteManager->findBeing(msg.readInt32());
+ dstBeing = actorSpriteManager->findBeing(msg.readInt32());
msg.readInt32(); // Server tick
msg.readInt32(); // src speed
msg.readInt32(); // dst speed
@@ -329,8 +320,8 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
case SMSG_BEING_ACTION:
- srcBeing = beingManager->findBeing(msg.readInt32());
- dstBeing = beingManager->findBeing(msg.readInt32());
+ srcBeing = actorSpriteManager->findBeing(msg.readInt32());
+ dstBeing = actorSpriteManager->findBeing(msg.readInt32());
msg.readInt32(); // server tick
msg.readInt32(); // src speed
msg.readInt32(); // dst speed
@@ -357,7 +348,6 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
case 0x02: // Sit
if (srcBeing)
{
- srcBeing->setFrame(0);
srcBeing->setAction(Being::SIT);
}
break;
@@ -365,7 +355,6 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
case 0x03: // Stand up
if (srcBeing)
{
- srcBeing->setFrame(0);
srcBeing->setAction(Being::STAND);
}
break;
@@ -374,11 +363,11 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
case SMSG_BEING_SELFEFFECT: {
id = (Uint32)msg.readInt32();
- if (!beingManager->findBeing(id))
+ if (!actorSpriteManager->findBeing(id))
break;
int effectType = msg.readInt32();
- Being* being = beingManager->findBeing(id);
+ Being* being = actorSpriteManager->findBeing(id);
effectManager->trigger(effectType, being);
@@ -386,7 +375,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
}
case SMSG_BEING_EMOTION:
- if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
+ if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
break;
}
@@ -415,14 +404,11 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
* 16 bit value will be 0.
*/
- if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
+ if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
break;
}
- if (dstBeing->getType() == Being::PLAYER)
- player = static_cast<Player*>(dstBeing);
-
int type = msg.readInt8();
int id = 0;
int id2 = 0;
@@ -440,41 +426,41 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
switch (type)
{
case 1: // eAthena LOOK_HAIR
- player->setSpriteID(SPRITE_HAIR, id *-1);
+ dstBeing->setSpriteID(SPRITE_HAIR, id *-1);
break;
case 2: // Weapon ID in id, Shield ID in id2
- player->setSprite(SPRITE_WEAPON, id, "", true);
- player->setSprite(SPRITE_SHIELD, id2);
+ dstBeing->setSprite(SPRITE_WEAPON, id, "", true);
+ dstBeing->setSprite(SPRITE_SHIELD, id2);
break;
case 3: // Change lower headgear for eAthena, pants for us
- player->setSprite(SPRITE_BOTTOMCLOTHES, id);
+ dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, id);
break;
case 4: // Change upper headgear for eAthena, hat for us
- player->setSprite(SPRITE_HAT, id);
+ dstBeing->setSprite(SPRITE_HAT, id);
break;
case 5: // Change middle headgear for eathena, armor for us
- player->setSprite(SPRITE_TOPCLOTHES, id);
+ dstBeing->setSprite(SPRITE_TOPCLOTHES, id);
break;
case 6: // eAthena LOOK_HAIR_COLOR
- player->setSpriteColor(SPRITE_HAIR, ColorDB::get(id));
+ dstBeing->setSpriteColor(SPRITE_HAIR, ColorDB::get(id));
break;
case 8: // eAthena LOOK_SHIELD
- player->setSprite(SPRITE_SHIELD, id);
+ dstBeing->setSprite(SPRITE_SHIELD, id);
break;
case 9: // eAthena LOOK_SHOES
- player->setSprite(SPRITE_SHOE, id);
+ dstBeing->setSprite(SPRITE_SHOE, id);
break;
case 10: // LOOK_GLOVES
- player->setSprite(SPRITE_GLOVES, id);
+ dstBeing->setSprite(SPRITE_GLOVES, id);
break;
case 11: // LOOK_CAPE
- player->setSprite(SPRITE_CAPE, id);
+ dstBeing->setSprite(SPRITE_CAPE, id);
break;
case 12:
- player->setSprite(SPRITE_MISC1, id);
+ dstBeing->setSprite(SPRITE_MISC1, id);
break;
case 13:
- player->setSprite(SPRITE_MISC2, id);
+ dstBeing->setSprite(SPRITE_MISC2, id);
break;
default:
logger->log("SMSG_BEING_CHANGE_LOOKS: unsupported type: "
@@ -485,13 +471,13 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
case SMSG_BEING_NAME_RESPONSE:
- if ((dstBeing = beingManager->findBeing(msg.readInt32())))
+ if ((dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
dstBeing->setName(msg.readString(24));
}
break;
case SMSG_PLAYER_GUILD_PARTY_INFO:
- if ((dstBeing = beingManager->findBeing(msg.readInt32())))
+ if ((dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
dstBeing->setPartyName(msg.readString(24));
dstBeing->setGuildName(msg.readString(24));
@@ -500,7 +486,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
}
break;
case SMSG_BEING_CHANGE_DIRECTION:
- if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
+ if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
break;
}
@@ -523,7 +509,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
<< 16; // status.options; Aethyra uses this as misc2
job = msg.readInt16();
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
if (!dstBeing)
{
@@ -533,13 +519,10 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
}
- if (dstBeing->getType() == Being::PLAYER)
- player = static_cast<Player*>(dstBeing);
-
if (Party *party = player_node->getParty()){
if (party->isMember(id))
{
- player->setParty(party);
+ dstBeing->setParty(party);
}
}
@@ -565,21 +548,21 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
msg.readInt16(); // manner
dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3
msg.readInt8(); // karma
- player->setGender((msg.readInt8() == 0)
+ dstBeing->setGender((msg.readInt8() == 0)
? GENDER_FEMALE : GENDER_MALE);
// Set these after the gender, as the sprites may be gender-specific
- player->setSprite(SPRITE_WEAPON, weapon, "", true);
- player->setSprite(SPRITE_SHIELD, shield);
- //player->setSprite(SPRITE_SHOE, shoes);
- player->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
- player->setSprite(SPRITE_TOPCLOTHES, headMid);
- player->setSprite(SPRITE_HAT, headTop);
- //player->setSprite(SPRITE_GLOVES, gloves);
- //player->setSprite(SPRITE_CAPE, cape);
- //player->setSprite(SPRITE_MISC1, misc1);
- //player->setSprite(SPRITE_MISC2, misc2);
- player->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor));
+ dstBeing->setSprite(SPRITE_WEAPON, weapon, "", true);
+ dstBeing->setSprite(SPRITE_SHIELD, shield);
+ //dstBeing->setSprite(SPRITE_SHOE, shoes);
+ dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
+ dstBeing->setSprite(SPRITE_TOPCLOTHES, headMid);
+ dstBeing->setSprite(SPRITE_HAT, headTop);
+ //dstBeing->setSprite(SPRITE_GLOVES, gloves);
+ //dstBeing->setSprite(SPRITE_CAPE, cape);
+ //dstBeing->setSprite(SPRITE_MISC1, misc1);
+ //dstBeing->setSprite(SPRITE_MISC2, misc2);
+ dstBeing->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor));
if (msg.getId() == SMSG_PLAYER_MOVE)
{
@@ -609,7 +592,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
gmstatus = msg.readInt16();
if (gmstatus & 0x80)
- player->setGM(true);
+ dstBeing->setGM(true);
if (msg.getId() == SMSG_PLAYER_UPDATE_1)
{
@@ -632,8 +615,8 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
msg.readInt8(); // Lv
msg.readInt8(); // unknown
- dstBeing->setWalkTime(tick_time);
- dstBeing->setFrame(0);
+ dstBeing->setActionTime(tick_time);
+ dstBeing->reset();
dstBeing->setStunMode(stunMode);
dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
@@ -656,7 +639,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
id = msg.readInt32();
if (mSync || id != player_node->getId())
{
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
if (dstBeing)
{
Uint16 x, y;
@@ -664,10 +647,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
y = msg.readInt16();
dstBeing->setTileCoords(x, y);
if (dstBeing->getCurrentAction() == Being::WALK)
- {
- dstBeing->setFrame(0);
dstBeing->setAction(Being::STAND);
- }
}
}
break;
@@ -684,7 +664,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
case SMSG_PLAYER_STATUS_CHANGE:
// Change in players' flags
id = msg.readInt32();
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
stunMode = msg.readInt16();
statusEffects = msg.readInt16();
statusEffects |= ((Uint32) msg.readInt16()) << 16;
@@ -704,7 +684,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
id = msg.readInt32();
flag = msg.readInt8(); // 0: stop, 1: start
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
if (dstBeing)
dstBeing->setStatusEffect(status, flag);
break;
diff --git a/src/net/tmwa/buysellhandler.cpp b/src/net/tmwa/buysellhandler.cpp
index 209f034d..4a478396 100644
--- a/src/net/tmwa/buysellhandler.cpp
+++ b/src/net/tmwa/buysellhandler.cpp
@@ -21,11 +21,10 @@
#include "net/tmwa/buysellhandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "inventory.h"
#include "item.h"
#include "localplayer.h"
-#include "npc.h"
#include "gui/buy.h"
#include "gui/buysell.h"
diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp
index 8711f031..8f15691c 100644
--- a/src/net/tmwa/charserverhandler.cpp
+++ b/src/net/tmwa/charserverhandler.cpp
@@ -312,17 +312,17 @@ void CharServerHandler::switchCharacter()
outMsg.writeInt8(1);
}
-int CharServerHandler::baseSprite() const
+unsigned int CharServerHandler::baseSprite() const
{
return SPRITE_BASE;
}
-int CharServerHandler::hairSprite() const
+unsigned int CharServerHandler::hairSprite() const
{
return SPRITE_HAIR;
}
-int CharServerHandler::maxSprite() const
+unsigned int CharServerHandler::maxSprite() const
{
return SPRITE_VECTOREND;
}
diff --git a/src/net/tmwa/charserverhandler.h b/src/net/tmwa/charserverhandler.h
index e80d22c4..52bac811 100644
--- a/src/net/tmwa/charserverhandler.h
+++ b/src/net/tmwa/charserverhandler.h
@@ -63,11 +63,11 @@ class CharServerHandler : public MessageHandler, public Net::CharHandler
void switchCharacter();
- int baseSprite() const;
+ unsigned int baseSprite() const;
- int hairSprite() const;
+ unsigned int hairSprite() const;
- int maxSprite() const;
+ unsigned int maxSprite() const;
void connect();
diff --git a/src/net/tmwa/chathandler.cpp b/src/net/tmwa/chathandler.cpp
index 640d04c1..493df0e5 100644
--- a/src/net/tmwa/chathandler.cpp
+++ b/src/net/tmwa/chathandler.cpp
@@ -21,8 +21,8 @@
#include "net/tmwa/chathandler.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "game.h"
#include "localplayer.h"
#include "playerrelations.h"
@@ -112,7 +112,7 @@ void ChatHandler::handleMessage(Net::MessageIn &msg)
// Received speech from being
case SMSG_BEING_CHAT: {
chatMsgLength = msg.readInt16() - 8;
- being = beingManager->findBeing(msg.readInt32());
+ being = actorSpriteManager->findBeing(msg.readInt32());
if (!being || chatMsgLength <= 0)
break;
diff --git a/src/net/tmwa/gamehandler.h b/src/net/tmwa/gamehandler.h
index ca8d27e6..101e7972 100644
--- a/src/net/tmwa/gamehandler.h
+++ b/src/net/tmwa/gamehandler.h
@@ -60,6 +60,9 @@ class GameHandler : public MessageHandler, public Net::GameHandler
void setMap(const std::string map);
+ /** The tmwa protocol is making use of the Mp Main status bar. */
+ bool canUseMagicBar() const { return true; }
+
private:
std::string mMap;
int mCharID; /// < Saved for map-server switching
diff --git a/src/net/tmwa/gui/guildtab.cpp b/src/net/tmwa/gui/guildtab.cpp
index 794ad5cc..8b788bad 100644
--- a/src/net/tmwa/gui/guildtab.cpp
+++ b/src/net/tmwa/gui/guildtab.cpp
@@ -21,6 +21,7 @@
#include "net/tmwa/gui/guildtab.h"
+#include "chatlog.h"
#include "commandhandler.h"
#include "guild.h"
#include "localplayer.h"
@@ -114,4 +115,10 @@ void GuildTab::getAutoCompleteList(std::vector<std::string> &names) const
taGuild->getNames(names);
}
+void GuildTab::saveToLogFile(std::string &msg)
+{
+ if (chatLogger)
+ chatLogger->log("#Guild", msg);
+}
+
} // namespace TmwAthena
diff --git a/src/net/tmwa/gui/guildtab.h b/src/net/tmwa/gui/guildtab.h
index 031c81bf..12e15e16 100644
--- a/src/net/tmwa/gui/guildtab.h
+++ b/src/net/tmwa/gui/guildtab.h
@@ -39,6 +39,8 @@ class GuildTab : public ChatTab
bool handleCommand(const std::string &type, const std::string &args);
+ void saveToLogFile(std::string &msg);
+
protected:
void handleInput(const std::string &msg);
diff --git a/src/net/tmwa/gui/partytab.cpp b/src/net/tmwa/gui/partytab.cpp
index 03dadb04..0f3e8e24 100644
--- a/src/net/tmwa/gui/partytab.cpp
+++ b/src/net/tmwa/gui/partytab.cpp
@@ -21,6 +21,7 @@
#include "net/tmwa/gui/partytab.h"
+#include "chatlog.h"
#include "commandhandler.h"
#include "localplayer.h"
#include "party.h"
@@ -206,4 +207,10 @@ void PartyTab::getAutoCompleteList(std::vector<std::string> &names) const
p->getNames(names);
}
+void PartyTab::saveToLogFile(std::string &msg)
+{
+ if (chatLogger)
+ chatLogger->log("#Party", msg);
+}
+
} // namespace TmwAthena
diff --git a/src/net/tmwa/gui/partytab.h b/src/net/tmwa/gui/partytab.h
index 62027726..4c16ab46 100644
--- a/src/net/tmwa/gui/partytab.h
+++ b/src/net/tmwa/gui/partytab.h
@@ -39,6 +39,8 @@ class PartyTab : public ChatTab
bool handleCommand(const std::string &type, const std::string &args);
+ void saveToLogFile(std::string &msg);
+
protected:
void handleInput(const std::string &msg);
diff --git a/src/net/tmwa/guildhandler.cpp b/src/net/tmwa/guildhandler.cpp
index 8a106841..3d3b0ab2 100644
--- a/src/net/tmwa/guildhandler.cpp
+++ b/src/net/tmwa/guildhandler.cpp
@@ -401,10 +401,10 @@ void GuildHandler::invite(int guildId, const std::string &name)
// TODO?
}
-void GuildHandler::invite(int guildId, Player *player)
+void GuildHandler::invite(int guildId, Being *being)
{
MessageOut msg(CMSG_GUILD_INVITE);
- msg.writeInt32(player->getId());
+ msg.writeInt32(being->getId());
msg.writeInt32(0); // Unused
msg.writeInt32(0); // Unused
}
diff --git a/src/net/tmwa/guildhandler.h b/src/net/tmwa/guildhandler.h
index 39dbe486..8bde222f 100644
--- a/src/net/tmwa/guildhandler.h
+++ b/src/net/tmwa/guildhandler.h
@@ -40,7 +40,7 @@ class GuildHandler : public Net::GuildHandler, public MessageHandler
void invite(int guildId, const std::string &name);
- void invite(int guildId, Player *player);
+ void invite(int guildId, Being *being);
void inviteResponse(int guildId, bool response);
diff --git a/src/net/tmwa/itemhandler.cpp b/src/net/tmwa/itemhandler.cpp
index abc8103b..a8e98860 100644
--- a/src/net/tmwa/itemhandler.cpp
+++ b/src/net/tmwa/itemhandler.cpp
@@ -21,7 +21,7 @@
#include "net/tmwa/itemhandler.h"
-#include "flooritemmanager.h"
+#include "actorspritemanager.h"
#include "net/messagein.h"
@@ -54,13 +54,13 @@ void ItemHandler::handleMessage(Net::MessageIn &msg)
int y = msg.readInt16();
msg.skip(4); // amount,subX,subY / subX,subY,amount
- floorItemManager->create(id, itemId, x, y);
+ actorSpriteManager->createItem(id, itemId, x, y);
}
break;
case SMSG_ITEM_REMOVE:
- if (FloorItem *item = floorItemManager->findById(msg.readInt32()))
- floorItemManager->destroy(item);
+ if (FloorItem *item = actorSpriteManager->findItem(msg.readInt32()))
+ actorSpriteManager->destroy(item);
break;
}
}
diff --git a/src/net/tmwa/npchandler.cpp b/src/net/tmwa/npchandler.cpp
index 5888c679..bd655fa6 100644
--- a/src/net/tmwa/npchandler.cpp
+++ b/src/net/tmwa/npchandler.cpp
@@ -21,9 +21,8 @@
#include "net/tmwa/npchandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "localplayer.h"
-#include "npc.h"
#include "gui/npcdialog.h"
diff --git a/src/net/tmwa/partyhandler.cpp b/src/net/tmwa/partyhandler.cpp
index 440b75f4..21b66e66 100644
--- a/src/net/tmwa/partyhandler.cpp
+++ b/src/net/tmwa/partyhandler.cpp
@@ -20,7 +20,7 @@
#include "net/tmwa/partyhandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "localplayer.h"
#include "log.h"
@@ -143,12 +143,9 @@ void PartyHandler::handleMessage(Net::MessageIn &msg)
std::string nick = "";
Being *being;
- if (!(being = beingManager->findBeing(id)))
+ if (!(being = actorSpriteManager->findBeing(id)))
{
- if (being->getType() == Being::PLAYER)
- {
- nick = being->getName();
- }
+ nick = being->getName();
}
socialWindow->showPartyInvite(partyName, nick);
@@ -252,9 +249,8 @@ void PartyHandler::handleMessage(Net::MessageIn &msg)
partyTab->chatLog(strprintf(_("%s has left your party."),
nick.c_str()), BY_SERVER);
- Being *b = beingManager->findBeing(id);
- if (b->getType() == Being::PLAYER)
- static_cast<Player*>(b)->setParty(NULL);
+ Being *b = actorSpriteManager->findBeing(id);
+ b->setParty(NULL);
taParty->removeMember(id);
}
@@ -274,9 +270,9 @@ void PartyHandler::handleMessage(Net::MessageIn &msg)
// The server only sends this when the member is in range, so
// lets make sure they get the party hilight.
- if (Being *b = beingManager->findBeing(id))
+ if (Being *b = actorSpriteManager->findBeing(id))
{
- static_cast<Player*>(b)->setParty(taParty);
+ b->setParty(taParty);
}
}
break;
@@ -319,10 +315,10 @@ void PartyHandler::join(int partyId)
// TODO?
}
-void PartyHandler::invite(Player *player)
+void PartyHandler::invite(Being *being)
{
MessageOut outMsg(CMSG_PARTY_INVITE);
- outMsg.writeInt32(player->getId());
+ outMsg.writeInt32(being->getId());
}
void PartyHandler::invite(const std::string &name)
@@ -353,10 +349,10 @@ void PartyHandler::leave()
MessageOut outMsg(CMSG_PARTY_LEAVE);
}
-void PartyHandler::kick(Player *player)
+void PartyHandler::kick(Being *being)
{
MessageOut outMsg(CMSG_PARTY_KICK);
- outMsg.writeInt32(player->getId());
+ outMsg.writeInt32(being->getId());
outMsg.writeString("", 24); //Unused
}
diff --git a/src/net/tmwa/partyhandler.h b/src/net/tmwa/partyhandler.h
index fc8d741f..5afc8e53 100644
--- a/src/net/tmwa/partyhandler.h
+++ b/src/net/tmwa/partyhandler.h
@@ -43,7 +43,7 @@ class PartyHandler : public MessageHandler, public Net::PartyHandler
void join(int partyId);
- void invite(Player *player);
+ void invite(Being *being);
void invite(const std::string &name);
@@ -51,7 +51,7 @@ class PartyHandler : public MessageHandler, public Net::PartyHandler
void leave();
- void kick(Player *player);
+ void kick(Being *being);
void kick(const std::string &name);
diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp
index 5aab94b8..26c7e922 100644
--- a/src/net/tmwa/playerhandler.cpp
+++ b/src/net/tmwa/playerhandler.cpp
@@ -24,7 +24,6 @@
#include "game.h"
#include "localplayer.h"
#include "log.h"
-#include "npc.h"
#include "units.h"
#include "gui/buy.h"
@@ -217,7 +216,6 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
}
player_node->setAction(Being::STAND);
- player_node->setFrame(0);
player_node->setTileCoords(x, y);
logger->log("Adjust scrolling by %d:%d", (int) scrollOffsetX,
diff --git a/src/net/tmwa/token.h b/src/net/tmwa/token.h
index d2a21012..3e781cd8 100644
--- a/src/net/tmwa/token.h
+++ b/src/net/tmwa/token.h
@@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "player.h"
+#include "being.h"
#ifndef NET_TA_TOKEN_H
#define NET_TA_TOKEN_H
diff --git a/src/npc.cpp b/src/npc.cpp
deleted file mode 100644
index cdfe5193..00000000
--- a/src/npc.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "animatedsprite.h"
-#include "beingmanager.h"
-#include "npc.h"
-#include "particle.h"
-#include "text.h"
-
-#include "gui/buy.h"
-#include "gui/buysell.h"
-#include "gui/npcdialog.h"
-#include "gui/npcpostdialog.h"
-#include "gui/userpalette.h"
-#include "gui/sell.h"
-
-#include "net/net.h"
-#include "net/npchandler.h"
-
-#include "resources/npcdb.h"
-
-NPC::NPC(int id, int subtype, Map *map):
- Player(id, subtype, map, true)
-{
- setSubtype(subtype);
-
- setShowName(true);
-}
-
-void NPC::setName(const std::string &name)
-{
- const std::string displayName = name.substr(0, name.find('#', 0));
-
- Being::setName(displayName);
-
- mNameColor = &userPalette->getColor(UserPalette::NPC);
-
- mDispName->setColor(mNameColor);
-}
-
-void NPC::setSubtype(Uint16 subtype)
-{
- Being::setSubtype(subtype);
-
- NPCInfo info = NPCDB::get(subtype);
-
- mSprites.clear();
- // Setup NPC sprites
- for (std::list<NPCsprite*>::const_iterator i = info.sprites.begin();
- i != info.sprites.end();
- i++)
- {
- std::string file = "graphics/sprites/" + (*i)->sprite;
- int variant = (*i)->variant;
- mSprites.push_back(AnimatedSprite::load(file, variant));
- mSpriteIDs.push_back(0);
- mSpriteColors.push_back("");
- }
-
- if (Particle::enabled)
- {
- //setup particle effects
- for (std::list<std::string>::const_iterator i = info.particles.begin();
- i != info.particles.end();
- i++)
- {
- Particle *p = particleEngine->addEffect(*i, 0, 0);
- this->controlParticle(p);
- }
- }
-}
-
-void NPC::talk()
-{
- Net::getNpcHandler()->talk(mId);
-}
-
-void NPC::setSprite(unsigned int slot, int id, const std::string &color)
-{
- // Do nothing
-}
-
-bool NPC::isTalking()
-{
- return NpcDialog::isActive() || BuyDialog::isActive() ||
- SellDialog::isActive() || BuySellDialog::isActive() ||
- NpcPostDialog::isActive();
-}
diff --git a/src/npc.h b/src/npc.h
deleted file mode 100644
index 0abd2395..00000000
--- a/src/npc.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NPC_H
-#define NPC_H
-
-#include "player.h"
-
-class Graphics;
-class Text;
-
-class NPC : public Player
-{
- public:
- NPC(int id, int subtype, Map *map);
-
- void setName(const std::string &name);
-
- virtual Type getType() const { return Being::NPC; }
-
- virtual void setSubtype(Uint16 subtype);
-
- void talk();
-
- void setSprite(unsigned int slot, int id,
- const std::string &color = "");
-
- /**
- * Gets the way an NPC is blocked by other things on the map
- */
- virtual unsigned char getWalkMask() const
- {
- return Map::BLOCKMASK_WALL
- | Map::BLOCKMASK_CHARACTER
- | Map::BLOCKMASK_MONSTER;
- }
-
- /** We consider NPCs (at least for now) to be one layer-sprites */
- virtual int getNumberOfLayers() const
- { return 1; }
-
- static bool isTalking();
-
- protected:
- /**
- * Gets the way a monster blocks pathfinding for other objects
- */
- virtual Map::BlockType getBlockType() const
- { return Map::BLOCKTYPE_CHARACTER; } //blocks like a player character
-
- // Colors don't change for NPCs
- virtual void updateColors() {}
-};
-
-#endif
diff --git a/src/particle.cpp b/src/particle.cpp
index 84161c9f..6a3fd7da 100644
--- a/src/particle.cpp
+++ b/src/particle.cpp
@@ -63,7 +63,6 @@ Particle::Particle(Map *map):
mFadeIn(0),
mAlpha(1.0f),
mAutoDelete(true),
- mMap(map),
mAllowSizeAdjust(false),
mGravity(0.0f),
mRandomness(0),
@@ -74,16 +73,12 @@ Particle::Particle(Map *map):
mInvDieDistance(-1.0f),
mMomentum(1.0f)
{
+ setMap(map);
Particle::particleCount++;
- if (mMap)
- setSpriteIterator(mMap->addSprite(this));
}
Particle::~Particle()
{
- // Remove from map sprite list
- if (mMap)
- mMap->removeSprite(mSpriteIterator);
// Delete child emitters and child particles
clear();
Particle::particleCount--;
@@ -99,8 +94,9 @@ void Particle::setupEngine()
logger->log("Particle engine set up");
}
-void Particle::draw(Graphics *, int, int) const
+bool Particle::draw(Graphics *, int, int) const
{
+ return false;
}
bool Particle::update()
@@ -393,13 +389,6 @@ void Particle::adjustEmitterSize(int w, int h)
}
}
-void Particle::setMap(Map *map)
-{
- mMap = map;
- if (mMap)
- setSpriteIterator(mMap->addSprite(this));
-}
-
void Particle::clear()
{
delete_all(mChildEmitters);
diff --git a/src/particle.h b/src/particle.h
index 0690e8c4..2be169c1 100644
--- a/src/particle.h
+++ b/src/particle.h
@@ -22,8 +22,8 @@
#ifndef PARTICLE_H
#define PARTICLE_H
+#include "actor.h"
#include "guichanfwd.h"
-#include "sprite.h"
#include "vector.h"
#include <list>
@@ -41,7 +41,7 @@ typedef Emitters::iterator EmitterIterator;
/**
* A particle spawned by a ParticleEmitter.
*/
-class Particle : public Sprite
+class Particle : public Actor
{
public:
static const float PARTICLE_SKY; /**< Maximum Z position of particles */
@@ -83,7 +83,7 @@ class Particle : public Sprite
/**
* Draws the particle image.
*/
- virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
+ virtual bool draw(Graphics *graphics, int offsetX, int offsetY) const;
/**
* Necessary for sorting with the other sprites.
@@ -92,12 +92,6 @@ class Particle : public Sprite
{ return (int) (mPos.y + mPos.z) - 64; }
/**
- * Sets the map the particle is on.
- */
- void setMap(Map *map);
-
-
- /**
* Creates a blank particle as a child of the current particle
* Useful for creating target particles
*/
@@ -142,12 +136,6 @@ class Particle : public Sprite
void moveTo(float x, float y);
/**
- * Returns the particle position.
- */
- const Vector& getPosition() const
- { return mPos; }
-
- /**
* Changes the particle position relative
*/
void moveBy (const Vector &change);
@@ -173,32 +161,6 @@ class Particle : public Sprite
{ mFadeIn = fadeIn; }
/**
- * Sets the alpha value of the particle
- */
- void setAlpha(float alpha)
- { mAlpha = alpha; }
-
- /**
- * Returns the current alpha opacity of the particle.
- */
- virtual float getAlpha() const
- { return mAlpha; }
-
- /**
- * Sets the sprite iterator of the particle on the current map to make
- * it easier to remove the particle from the map when it is destroyed.
- */
- void setSpriteIterator(std::list<Sprite*>::iterator spriteIterator)
- { mSpriteIterator = spriteIterator; }
-
- /**
- * Gets the sprite iterator of the particle on the current map.
- */
- std::list<Sprite*>::iterator
- getSpriteIterator() const
- { return mSpriteIterator; }
-
- /**
* Sets the current velocity in 3 dimensional space.
*/
void setVelocity(float x, float y, float z)
@@ -285,9 +247,13 @@ class Particle : public Sprite
virtual int getNumberOfLayers() const
{ return 1; }
+ virtual float getAlpha() const
+ { return 1.0f; }
+
+ virtual void setAlpha(float alpha) {}
+
protected:
bool mAlive; /**< Is the particle supposed to be drawn and updated?*/
- Vector mPos; /**< Position in pixels relative to map. */
int mLifetimeLeft; /**< Lifetime left in game ticks*/
int mLifetimePast; /**< Age of the particle in game ticks*/
int mFadeOut; /**< Lifetime in game ticks left where fading out begins*/
@@ -296,8 +262,6 @@ class Particle : public Sprite
// generic properties
bool mAutoDelete; /**< May the particle request its deletion by the parent particle? */
- Map *mMap; /**< Map the particle is on. */
- std::list<Sprite*>::iterator mSpriteIterator; /**< iterator of the particle on the current map */
Emitters mChildEmitters; /**< List of child emitters. */
Particles mChildParticles; /**< List of particles controlled by this particle */
bool mAllowSizeAdjust; /**< Can the effect size be adjusted by the object props in the map file? */
diff --git a/src/party.cpp b/src/party.cpp
index 75283916..77174d52 100644
--- a/src/party.cpp
+++ b/src/party.cpp
@@ -20,8 +20,7 @@
#include "party.h"
-#include "beingmanager.h"
-#include "player.h"
+#include "actorspritemanager.h"
PartyMember::PartyMember(Party *party, int id, const std::string &name):
Avatar(name), mId(id), mParty(party), mLeader(false)
@@ -144,9 +143,8 @@ void Party::removeFromMembers()
itr_end = mMembers.end();
while(itr != itr_end)
{
- Being *b = beingManager->findBeing((*itr)->getID());
- if (b->getType() == Being::PLAYER)
- static_cast<Player*>(b)->setParty(NULL);
+ Being *b = actorSpriteManager->findBeing((*itr)->getID());
+ b->setParty(NULL);
++itr;
}
}
diff --git a/src/player.cpp b/src/player.cpp
deleted file mode 100644
index 1f706cb8..00000000
--- a/src/player.cpp
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "player.h"
-
-#include "animatedsprite.h"
-#include "client.h"
-#include "configuration.h"
-#include "guild.h"
-#include "localplayer.h"
-#include "particle.h"
-#include "party.h"
-#include "text.h"
-
-#include "gui/socialwindow.h"
-#include "gui/theme.h"
-#include "gui/userpalette.h"
-
-#include "net/charhandler.h"
-#include "net/net.h"
-
-#include "resources/colordb.h"
-#include "resources/itemdb.h"
-#include "resources/iteminfo.h"
-
-#include "utils/stringutils.h"
-
-Player::Player(int id, int subtype, Map *map, bool isNPC):
- Being(id, subtype, map),
- mGender(GENDER_UNSPECIFIED),
- mParty(NULL),
- mIsGM(false)
-{
- if (!isNPC)
- {
- for (int i = 0; i < Net::getCharHandler()->maxSprite(); i++)
- {
- mSprites.push_back(NULL);
- mSpriteIDs.push_back(0);
- mSpriteColors.push_back("");
- }
-
- setSubtype(subtype);
- }
- mShowName = config.getValue("visiblenames", 1);
- config.addListener("visiblenames", this);
-
- updateColors();
-}
-
-Player::~Player()
-{
- config.removeListener("visiblenames", this);
-}
-
-void Player::logic()
-{
- if (Net::getNetworkType() == ServerInfo::TMWATHENA)
- {
- switch (mAction)
- {
- case STAND:
- case SIT:
- case DEAD:
- case HURT:
- break;
-
- case WALK:
- mFrame = (int) ((get_elapsed_time(mWalkTime) * 6)
- / getWalkSpeed().x);
- if (mFrame >= 6)
- nextTile();
- break;
-
- case ATTACK:
- int rotation = 0;
- std::string particleEffect = "";
- int frames = 4;
-
- if (mEquippedWeapon &&
- mEquippedWeapon->getAttackType() == ACTION_ATTACK_BOW)
- {
- frames = 5;
- }
-
- mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed;
-
- //attack particle effect
- if (mEquippedWeapon)
- particleEffect = mEquippedWeapon->getParticleEffect();
-
- if (!particleEffect.empty() && Particle::enabled && mFrame == 1)
- {
- switch (mDirection)
- {
- case DOWN: rotation = 0; break;
- case LEFT: rotation = 90; break;
- case UP: rotation = 180; break;
- case RIGHT: rotation = 270; break;
- default: break;
- }
- Particle *p;
- p = particleEngine->addEffect("graphics/particles/" +
- particleEffect, 0, 0, rotation);
- controlParticle(p);
- }
-
- if (mFrame >= frames)
- nextTile();
-
- break;
- }
- }
-
- Being::logic();
-}
-
-void Player::setSubtype(Uint16 subtype)
-{
- Being::setSubtype(subtype);
-
- int id = -100 - subtype;
- if (ItemDB::exists(id)) // Prevent showing errors when sprite doesn't exist
- setSprite(Net::getCharHandler()->baseSprite(), id);
- else
- setSprite(Net::getCharHandler()->baseSprite(), -100);
-}
-
-void Player::setGender(Gender gender)
-{
- if (gender != mGender)
- {
- mGender = gender;
-
- // Reload all subsprites
- for (unsigned int i = 0; i < mSprites.size(); i++)
- {
- if (mSpriteIDs.at(i) != 0)
- setSprite(i, mSpriteIDs.at(i), mSpriteColors.at(i));
- }
- }
-}
-
-void Player::setGM(bool gm)
-{
- mIsGM = gm;
-
- updateColors();
-}
-
-void Player::setSprite(int slot, int id, const std::string &color,
- bool isWeapon)
-{
- if (getType() == NPC)
- return;
-
- assert(slot < Net::getCharHandler()->maxSprite());
-
- // id = 0 means unequip
- if (id == 0)
- {
- delete mSprites[slot];
- mSprites[slot] = NULL;
-
- if (isWeapon)
- mEquippedWeapon = NULL;
- }
- else
- {
- std::string filename = ItemDB::get(id).getSprite(mGender);
- AnimatedSprite *equipmentSprite = NULL;
-
- if (!filename.empty())
- {
- if (!color.empty())
- filename += "|" + color;
-
- equipmentSprite = AnimatedSprite::load("graphics/sprites/" +
- filename);
- }
-
- if (equipmentSprite)
- equipmentSprite->setDirection(getSpriteDirection());
-
- if (mSprites[slot])
- delete mSprites[slot];
-
- mSprites[slot] = equipmentSprite;
-
- if (isWeapon)
- mEquippedWeapon = &ItemDB::get(id);
-
- setAction(mAction);
- }
-
- mSpriteIDs[slot] = id;
- mSpriteColors[slot] = color;
-}
-
-void Player::setSpriteID(unsigned int slot, int id)
-{
- setSprite(slot, id, mSpriteColors[slot]);
-}
-
-void Player::setSpriteColor(unsigned int slot, const std::string &color)
-{
- setSprite(slot, mSpriteIDs[slot], color);
-}
-
-void Player::addGuild(Guild *guild)
-{
- mGuilds[guild->getId()] = guild;
- guild->addMember(mId, mName);
-
- if (this == player_node && socialWindow)
- {
- socialWindow->addTab(guild);
- }
-}
-
-void Player::removeGuild(int id)
-{
- if (this == player_node && socialWindow)
- {
- socialWindow->removeTab(mGuilds[id]);
- }
-
- mGuilds[id]->removeMember(mId);
- mGuilds.erase(id);
-}
-
-Guild *Player::getGuild(const std::string &guildName) const
-{
- std::map<int, Guild*>::const_iterator itr, itr_end = mGuilds.end();
- for (itr = mGuilds.begin(); itr != itr_end; ++itr)
- {
- Guild *guild = itr->second;
- if (guild->getName() == guildName)
- {
- return guild;
- }
- }
-
- return NULL;
-}
-
-Guild *Player::getGuild(int id) const
-{
- std::map<int, Guild*>::const_iterator itr;
- itr = mGuilds.find(id);
- if (itr != mGuilds.end())
- {
- return itr->second;
- }
-
- return NULL;
-}
-
-const std::map<int, Guild*> &Player::getGuilds() const
-{
- return mGuilds;
-}
-
-void Player::clearGuilds()
-{
- std::map<int, Guild*>::const_iterator itr, itr_end = mGuilds.end();
- for (itr = mGuilds.begin(); itr != itr_end; ++itr)
- {
- Guild *guild = itr->second;
-
- if (this == player_node && socialWindow)
- socialWindow->removeTab(guild);
-
- guild->removeMember(mId);
- }
-
- mGuilds.clear();
-}
-
-void Player::setParty(Party *party)
-{
- if (party == mParty)
- return;
-
- Party *old = mParty;
- mParty = party;
-
- if (old)
- {
- old->removeMember(mId);
- }
-
- if (party)
- {
- party->addMember(mId, mName);
- }
-
- updateColors();
-
- if (this == player_node && socialWindow)
- {
- if (old)
- socialWindow->removeTab(old);
-
- if (party)
- socialWindow->addTab(party);
- }
-}
-
-void Player::optionChanged(const std::string &value)
-{
- if (value == "visiblenames")
- {
- setShowName(config.getValue("visiblenames", 1));
- }
-}
-
-void Player::updateColors()
-{
- mTextColor = &userPalette->getColor(Theme::PLAYER);
-
- if (mIsGM)
- {
- mTextColor = &userPalette->getColor(Theme::GM);
- mNameColor = &userPalette->getColor(UserPalette::GM);
- }
- else if (mParty && mParty == player_node->getParty())
- {
- mNameColor = &userPalette->getColor(UserPalette::PARTY);
- }
- else
- {
- mNameColor = &userPalette->getColor(UserPalette::PC);
- }
-
- if (mDispName)
- {
- mDispName->setColor(mNameColor);
- }
-}
diff --git a/src/player.h b/src/player.h
deleted file mode 100644
index e75870a0..00000000
--- a/src/player.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PLAYER_H
-#define PLAYER_H
-
-#include "being.h"
-
-class Graphics;
-class Guild;
-class Map;
-class Party;
-
-enum Gender
-{
- GENDER_MALE = 0,
- GENDER_FEMALE = 1,
- GENDER_UNSPECIFIED = 2
-};
-
-/**
- * A player being. Players have their name drawn beneath them. This class also
- * implements player-specific loading of base sprite, hair sprite and equipment
- * sprites.
- */
-class Player : public Being
-{
- public:
- /**
- * Constructor.
- */
- Player(int id, int subtype, Map *map, bool isNPC = false);
-
- ~Player();
-
- virtual void logic();
-
- virtual Type getType() const { return PLAYER; }
-
- virtual void setSubtype(Uint16 subtype);
-
- /**
- * Sets the gender of this being.
- */
- virtual void setGender(Gender gender);
-
- Gender getGender() const { return mGender; }
-
- /**
- * Whether or not this player is a GM.
- */
- bool isGM() const { return mIsGM; }
-
- /**
- * Triggers whether or not to show the name as a GM name.
- */
- virtual void setGM(bool gm);
-
- /**
- * Sets visible equipments for this player.
- */
- virtual void setSprite(int slot, int id,
- const std::string &color = "",
- bool isWeapon = false);
-
- virtual void setSpriteID(unsigned int slot, int id);
-
- virtual void setSpriteColor(unsigned int slot,
- const std::string &color = "");
-
- /**
- * Adds a guild to the player.
- */
- void addGuild(Guild *guild);
-
- /**
- * Removers a guild from the player.
- */
- void removeGuild(int id);
-
- /**
- * Returns a pointer to the specified guild.
- */
- Guild *getGuild(const std::string &guildName) const;
-
- /**
- * Returns a pointer to the guild with matching id.
- */
- Guild *getGuild(int id) const;
-
- /**
- * Returns all guilds the player is in.
- */
- const std::map<int, Guild*> &getGuilds() const;
-
- /**
- * Removes all guilds the player is in.
- */
- void clearGuilds();
-
- /**
- * Get number of guilds the player belongs to.
- */
- short getNumberOfGuilds() const { return mGuilds.size(); }
-
- bool isInParty() const { return mParty != NULL; }
-
- void setParty(Party *party);
-
- Party *getParty() const { return mParty; }
-
- /**
- * Gets the way the character is blocked by other objects.
- */
- virtual unsigned char getWalkMask() const
- { return Map::BLOCKMASK_WALL | Map::BLOCKMASK_MONSTER; }
-
- /**
- * Called when a option (set with config.addListener()) is changed
- */
- virtual void optionChanged(const std::string &value);
-
- protected:
- /**
- * Gets the way the monster blocks pathfinding for other objects.
- */
- virtual Map::BlockType getBlockType() const
- { return Map::BLOCKTYPE_CHARACTER; }
-
- virtual void updateColors();
-
- Gender mGender;
- std::vector<int> mSpriteIDs;
- std::vector<std::string> mSpriteColors;
-
- // Character guild information
- std::map<int, Guild*> mGuilds;
- Party *mParty;
-
- bool mIsGM;
-};
-
-#endif
diff --git a/src/playerrelations.cpp b/src/playerrelations.cpp
index 14d9eb6b..f5d3d01b 100644
--- a/src/playerrelations.cpp
+++ b/src/playerrelations.cpp
@@ -21,11 +21,10 @@
#include <algorithm>
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "configuration.h"
#include "graphics.h"
-#include "player.h"
#include "playerrelations.h"
#include "utils/dtor.h"
@@ -214,7 +213,7 @@ unsigned int PlayerRelationsManager::checkPermissionSilently(const std::string &
bool PlayerRelationsManager::hasPermission(Being *being, unsigned int flags)
{
- if (being->getType() == Being::PLAYER)
+ if (being->getType() == ActorSprite::PLAYER)
return hasPermission(being->getName(), flags) == flags;
return true;
}
@@ -230,9 +229,10 @@ bool PlayerRelationsManager::hasPermission(const std::string &name,
// execute `ignore' strategy, if possible
if (mIgnoreStrategy)
{
- Being *b = beingManager->findBeingByName(name, Being::PLAYER);
- if (b && b->getType() == Being::PLAYER)
- mIgnoreStrategy->ignore(static_cast<Player *>(b), rejections);
+ Being *b = actorSpriteManager->findBeingByName(name,
+ ActorSprite::PLAYER);
+ if (b && b->getType() == ActorSprite::PLAYER)
+ mIgnoreStrategy->ignore(b, rejections);
}
}
@@ -313,7 +313,7 @@ public:
mShortName = PLAYER_IGNORE_STRATEGY_NOP;
}
- virtual void ignore(Player *player, unsigned int flags)
+ virtual void ignore(Being *being, unsigned int flags)
{
}
};
@@ -327,9 +327,9 @@ public:
mShortName = "dotdotdot";
}
- virtual void ignore(Player *player, unsigned int flags)
+ virtual void ignore(Being *being, unsigned int flags)
{
- player->setSpeech("...", 500);
+ being->setSpeech("...", 500);
}
};
@@ -343,9 +343,9 @@ public:
mShortName = "blinkname";
}
- virtual void ignore(Player *player, unsigned int flags)
+ virtual void ignore(Being *being, unsigned int flags)
{
- player->flashName(200);
+ being->flashName(200);
}
};
@@ -359,9 +359,9 @@ public:
mShortName = shortname;
}
- virtual void ignore(Player *player, unsigned int flags)
+ virtual void ignore(Being *being, unsigned int flags)
{
- player->setEmote(mEmotion, IGNORE_EMOTE_TIME);
+ being->setEmote(mEmotion, IGNORE_EMOTE_TIME);
}
private:
int mEmotion;
diff --git a/src/playerrelations.h b/src/playerrelations.h
index 3ff1e5fd..d6ca31ad 100644
--- a/src/playerrelations.h
+++ b/src/playerrelations.h
@@ -28,7 +28,6 @@
#include <vector>
class Being;
-class Player;
struct PlayerRelation
{
@@ -73,7 +72,7 @@ public:
/**
* Handle the ignoring of the indicated action by the indicated player.
*/
- virtual void ignore(Player *player, unsigned int flags) = 0;
+ virtual void ignore(Being *being, unsigned int flags) = 0;
};
class PlayerRelationsListener
diff --git a/src/resources/beinginfo.cpp b/src/resources/beinginfo.cpp
new file mode 100644
index 00000000..c9447283
--- /dev/null
+++ b/src/resources/beinginfo.cpp
@@ -0,0 +1,107 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "resources/beinginfo.h"
+
+#include "log.h"
+
+#include "utils/dtor.h"
+#include "utils/gettext.h"
+
+BeingInfo *BeingInfo::Unknown = new BeingInfo;
+
+BeingInfo::BeingInfo():
+ mName(_("unnamed")),
+ mTargetCursorSize(ActorSprite::TC_MEDIUM),
+ mWalkMask(Map::BLOCKMASK_WALL | Map::BLOCKMASK_CHARACTER
+ | Map::BLOCKMASK_MONSTER),
+ mBlockType(Map::BLOCKTYPE_CHARACTER)
+{
+ SpriteDisplay display;
+ display.sprites.push_back(SpriteReference::Empty);
+
+ setDisplay(display);
+}
+
+BeingInfo::~BeingInfo()
+{
+ delete_all(mSounds);
+ delete_all(mAttacks);
+ mSounds.clear();
+}
+
+void BeingInfo::setDisplay(SpriteDisplay display)
+{
+ mDisplay = display;
+}
+
+void BeingInfo::setTargetCursorSize(const std::string &size)
+{
+ if (size == "small")
+ setTargetCursorSize(ActorSprite::TC_SMALL);
+ else if (size == "medium")
+ setTargetCursorSize(ActorSprite::TC_MEDIUM);
+ else if (size == "large")
+ setTargetCursorSize(ActorSprite::TC_LARGE);
+ else
+ {
+ logger->log("Unknown target cursor type \"%s\" for %s - using medium "
+ "sized one", size.c_str(), getName().c_str());
+ setTargetCursorSize(ActorSprite::TC_MEDIUM);
+ }
+}
+
+void BeingInfo::addSound(SoundEvent event, const std::string &filename)
+{
+ if (mSounds.find(event) == mSounds.end())
+ {
+ mSounds[event] = new std::vector<std::string>;
+ }
+
+ mSounds[event]->push_back("sfx/" + filename);
+}
+
+const std::string &BeingInfo::getSound(SoundEvent event) const
+{
+ static std::string empty("");
+
+ SoundEvents::const_iterator i = mSounds.find(event);
+ return (i == mSounds.end()) ? empty :
+ i->second->at(rand() % i->second->size());
+}
+
+const Attack *BeingInfo::getAttack(int type) const
+{
+ static Attack *empty = new Attack(ACTION_ATTACK, "", "");
+
+ Attacks::const_iterator i = mAttacks.find(type);
+ return (i == mAttacks.end()) ? empty : (*i).second;
+}
+
+void BeingInfo::addAttack(int id, SpriteAction action,
+ const std::string &particleEffect,
+ const std::string &missileParticle)
+{
+ if (mAttacks[id])
+ delete mAttacks[id];
+
+ mAttacks[id] = new Attack(action, particleEffect, missileParticle);
+}
diff --git a/src/resources/beinginfo.h b/src/resources/beinginfo.h
new file mode 100644
index 00000000..8485ac6c
--- /dev/null
+++ b/src/resources/beinginfo.h
@@ -0,0 +1,132 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef BEINGINFO_H
+#define BEINGINFO_H
+
+#include "actorsprite.h"
+
+#include "resources/spritedef.h"
+
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+struct Attack {
+ SpriteAction action;
+ std::string particleEffect;
+ std::string missileParticle;
+
+ Attack(SpriteAction action, std::string particleEffect,
+ std::string missileParticle)
+ {
+ this->action = action;
+ this->particleEffect = particleEffect;
+ this->missileParticle = missileParticle;
+ }
+};
+
+typedef std::map<int, Attack*> Attacks;
+
+enum SoundEvent
+{
+ SOUND_EVENT_HIT,
+ SOUND_EVENT_MISS,
+ SOUND_EVENT_HURT,
+ SOUND_EVENT_DIE
+};
+
+typedef std::map<SoundEvent, std::vector<std::string>* > SoundEvents;
+
+/**
+ * Holds information about a certain type of monster. This includes the name
+ * of the monster, the sprite to display and the sounds the monster makes.
+ *
+ * @see MonsterDB
+ * @see NPCDB
+ */
+class BeingInfo
+{
+ public:
+ static BeingInfo *Unknown;
+
+ BeingInfo();
+
+ ~BeingInfo();
+
+ void setName(const std::string &name) { mName = name; }
+
+ const std::string &getName() const
+ { return mName; }
+
+ void setDisplay(SpriteDisplay display);
+
+ const SpriteDisplay &getDisplay() const
+ { return mDisplay; }
+
+ void setTargetCursorSize(const std::string &size);
+
+ void setTargetCursorSize(ActorSprite::TargetCursorSize targetSize)
+ { mTargetCursorSize = targetSize; }
+
+ ActorSprite::TargetCursorSize getTargetCursorSize() const
+ { return mTargetCursorSize; }
+
+ void addSound(SoundEvent event, const std::string &filename);
+
+ const std::string &getSound(SoundEvent event) const;
+
+ void addAttack(int id, SpriteAction action,
+ const std::string &particleEffect,
+ const std::string &missileParticle);
+
+ const Attack *getAttack(int type) const;
+
+ void setWalkMask(unsigned char mask)
+ { mWalkMask = mask; }
+
+ /**
+ * Gets the way the being is blocked by other objects
+ */
+ unsigned char getWalkMask() const
+ { return mWalkMask; }
+
+ void setBlockType(Map::BlockType blockType)
+ { mBlockType = blockType; }
+
+ Map::BlockType getBlockType() const
+ { return mBlockType; }
+
+ private:
+ SpriteDisplay mDisplay;
+ std::string mName;
+ ActorSprite::TargetCursorSize mTargetCursorSize;
+ SoundEvents mSounds;
+ Attacks mAttacks;
+ unsigned char mWalkMask;
+ Map::BlockType mBlockType;
+};
+
+typedef std::map<int, BeingInfo*> BeingInfos;
+typedef BeingInfos::iterator BeingInfoIterator;
+
+#endif // BEINGINFO_H
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index 077012c7..205268e5 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -46,6 +46,7 @@ namespace
// Forward declarations
static void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node);
static void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node);
+static void loadFloorSprite(SpriteDisplay *display, xmlNodePtr node);
static char const *const fields[][2] =
{
@@ -114,7 +115,7 @@ void ItemDB::load()
mUnknown = new ItemInfo;
mUnknown->setName(_("Unknown item"));
- mUnknown->setImageName("");
+ mUnknown->setDisplay(SpriteDisplay());
mUnknown->setSprite("error.xml", GENDER_MALE);
mUnknown->setSprite("error.xml", GENDER_FEMALE);
@@ -154,9 +155,11 @@ void ItemDB::load()
int attackRange = XML::getProperty(node, "attack-range", 0);
std::string missileParticle = XML::getProperty(node, "missile-particle", "");
+ SpriteDisplay display;
+ display.image = image;
+
ItemInfo *itemInfo = new ItemInfo;
itemInfo->setId(id);
- itemInfo->setImageName(image);
itemInfo->setName(name.empty() ? _("unnamed") : name);
itemInfo->setDescription(description);
itemInfo->setType(itemTypeFromString(typeStr));
@@ -202,8 +205,14 @@ void ItemDB::load()
{
loadSoundRef(itemInfo, itemChild);
}
+ else if (xmlStrEqual(itemChild->name, BAD_CAST "floor"))
+ {
+ loadFloorSprite(&display, itemChild);
+ }
}
+ itemInfo->setDisplay(display);
+
mItemInfos[id] = itemInfo;
if (!name.empty())
{
@@ -334,3 +343,22 @@ void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node)
event.c_str());
}
}
+
+void loadFloorSprite(SpriteDisplay *display, xmlNodePtr floorNode)
+{
+ for_each_xml_child_node(spriteNode, floorNode)
+ {
+ if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
+ {
+ SpriteReference *currentSprite = new SpriteReference;
+ currentSprite->sprite = (const char*)spriteNode->xmlChildrenNode->content;
+ currentSprite->variant = XML::getProperty(spriteNode, "variant", 0);
+ display->sprites.push_back(currentSprite);
+ }
+ else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx"))
+ {
+ std::string particlefx = (const char*)spriteNode->xmlChildrenNode->content;
+ display->particles.push_back(particlefx);
+ }
+ }
+}
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index a7c0ddca..d9fc05cc 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -22,7 +22,7 @@
#ifndef ITEMINFO_H
#define ITEMINFO_H
-#include "player.h"
+#include "being.h"
#include "resources/spritedef.h"
@@ -143,11 +143,11 @@ class ItemInfo
std::string getParticleEffect() const { return mParticle; }
- void setImageName(const std::string &imageName)
- { mImageName = imageName; }
+ void setDisplay(SpriteDisplay display)
+ { mDisplay = display; }
- const std::string &getImageName() const
- { return mImageName; }
+ const SpriteDisplay &getDisplay() const
+ { return mDisplay; }
void setDescription(const std::string &description)
{ mDescription = description; }
@@ -201,7 +201,7 @@ class ItemInfo
const std::string &getSound(EquipmentSoundEvent event) const;
protected:
- std::string mImageName; /**< The filename of the icon image. */
+ SpriteDisplay mDisplay; /**< Display info (like icon) */
std::string mName;
std::string mDescription; /**< Short description. */
std::string mEffect; /**< Description of effects. */
diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp
index 5a796f5f..0732bb19 100644
--- a/src/resources/monsterdb.cpp
+++ b/src/resources/monsterdb.cpp
@@ -23,20 +23,19 @@
#include "log.h"
-#include "resources/monsterinfo.h"
+#include "net/net.h"
+
+#include "resources/beinginfo.h"
#include "utils/dtor.h"
#include "utils/gettext.h"
#include "utils/xml.h"
-#include "net/net.h"
-
#define OLD_TMWATHENA_OFFSET 1002
namespace
{
- MonsterDB::MonsterInfos mMonsterInfos;
- MonsterInfo mUnknown;
+ BeingInfos mMonsterInfos;
bool mLoaded = false;
}
@@ -45,8 +44,6 @@ void MonsterDB::load()
if (mLoaded)
unload();
- mUnknown.addSprite("error.xml");
-
logger->log("Initializing monster database...");
XML::Document doc("monsters.xml");
@@ -68,39 +65,29 @@ void MonsterDB::load()
continue;
}
- MonsterInfo *currentInfo = new MonsterInfo;
+ BeingInfo *currentInfo = new BeingInfo;
+
+ currentInfo->setWalkMask(Map::BLOCKMASK_WALL
+ | Map::BLOCKMASK_CHARACTER
+ | Map::BLOCKMASK_MONSTER);
+ currentInfo->setBlockType(Map::BLOCKTYPE_MONSTER);
currentInfo->setName(XML::getProperty(monsterNode, "name", _("unnamed")));
- std::string targetCursor;
- targetCursor = XML::getProperty(monsterNode, "targetCursor", "medium");
- if (targetCursor == "small")
- {
- currentInfo->setTargetCursorSize(Being::TC_SMALL);
- }
- else if (targetCursor == "medium")
- {
- currentInfo->setTargetCursorSize(Being::TC_MEDIUM);
- }
- else if (targetCursor == "large")
- {
- currentInfo->setTargetCursorSize(Being::TC_LARGE);
- }
- else
- {
- logger->log("MonsterDB: Unknown target cursor type \"%s\" for %s -"
- "using medium sized one",
- targetCursor.c_str(), currentInfo->getName().c_str());
- currentInfo->setTargetCursorSize(Being::TC_MEDIUM);
- }
+ currentInfo->setTargetCursorSize(XML::getProperty(monsterNode,
+ "targetCursor", "medium"));
+
+ SpriteDisplay display;
//iterate <sprite>s and <sound>s
for_each_xml_child_node(spriteNode, monsterNode)
{
if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
{
- currentInfo->addSprite(
- (const char*) spriteNode->xmlChildrenNode->content);
+ SpriteReference *currentSprite = new SpriteReference;
+ currentSprite->sprite = (const char*)spriteNode->xmlChildrenNode->content;
+ currentSprite->variant = XML::getProperty(spriteNode, "variant", 0);
+ display.sprites.push_back(currentSprite);
}
else if (xmlStrEqual(spriteNode->name, BAD_CAST "sound"))
{
@@ -110,19 +97,19 @@ void MonsterDB::load()
if (event == "hit")
{
- currentInfo->addSound(MONSTER_EVENT_HIT, filename);
+ currentInfo->addSound(SOUND_EVENT_HIT, filename);
}
else if (event == "miss")
{
- currentInfo->addSound(MONSTER_EVENT_MISS, filename);
+ currentInfo->addSound(SOUND_EVENT_MISS, filename);
}
else if (event == "hurt")
{
- currentInfo->addSound(MONSTER_EVENT_HURT, filename);
+ currentInfo->addSound(SOUND_EVENT_HURT, filename);
}
else if (event == "die")
{
- currentInfo->addSound(MONSTER_EVENT_DIE, filename);
+ currentInfo->addSound(SOUND_EVENT_DIE, filename);
}
else
{
@@ -141,14 +128,17 @@ void MonsterDB::load()
XML::getProperty(spriteNode, "action", "attack"));
const std::string missileParticle = XML::getProperty(
spriteNode, "missile-particle", "");
- currentInfo->addMonsterAttack(id, particleEffect, spriteAction, missileParticle);
+ currentInfo->addAttack(id, spriteAction,
+ particleEffect, missileParticle);
}
else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx"))
{
- currentInfo->addParticleEffect(
+ display.particles.push_back(
(const char*) spriteNode->xmlChildrenNode->content);
}
}
+ currentInfo->setDisplay(display);
+
mMonsterInfos[XML::getProperty(monsterNode, "id", 0) + offset] = currentInfo;
}
@@ -164,17 +154,17 @@ void MonsterDB::unload()
}
-const MonsterInfo &MonsterDB::get(int id)
+BeingInfo *MonsterDB::get(int id)
{
- MonsterInfoIterator i = mMonsterInfos.find(id);
+ BeingInfoIterator i = mMonsterInfos.find(id);
if (i == mMonsterInfos.end())
{
logger->log("MonsterDB: Warning, unknown monster ID %d requested", id);
- return mUnknown;
+ return BeingInfo::Unknown;
}
else
{
- return *(i->second);
+ return i->second;
}
}
diff --git a/src/resources/monsterdb.h b/src/resources/monsterdb.h
index 0fc8d2cf..50f70438 100644
--- a/src/resources/monsterdb.h
+++ b/src/resources/monsterdb.h
@@ -22,9 +22,7 @@
#ifndef MONSTER_DB_H
#define MONSTER_DB_H
-#include <map>
-
-class MonsterInfo;
+class BeingInfo;
/**
* Monster information database.
@@ -35,10 +33,7 @@ namespace MonsterDB
void unload();
- const MonsterInfo &get(int id);
-
- typedef std::map<int, MonsterInfo*> MonsterInfos;
- typedef MonsterInfos::iterator MonsterInfoIterator;
+ BeingInfo *get(int id);
}
#endif
diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp
deleted file mode 100644
index 9104c721..00000000
--- a/src/resources/monsterinfo.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "resources/monsterinfo.h"
-
-#include "utils/dtor.h"
-#include "utils/gettext.h"
-
-MonsterInfo::MonsterInfo():
- mName(_("unnamed")),
- mTargetCursorSize(Being::TC_MEDIUM)
-{
-}
-
-MonsterInfo::~MonsterInfo()
-{
- // kill vectors in mSoundEffects
- delete_all(mSounds);
- delete_all(mMonsterAttacks);
- mSounds.clear();
-}
-
-void MonsterInfo::addSound(MonsterSoundEvent event, const std::string &filename)
-{
- if (mSounds.find(event) == mSounds.end())
- {
- mSounds[event] = new std::vector<std::string>;
- }
-
- mSounds[event]->push_back("sfx/" + filename);
-}
-
-const std::string &MonsterInfo::getSound(MonsterSoundEvent event) const
-{
- static std::string empty("");
- std::map<MonsterSoundEvent, std::vector<std::string>* >::const_iterator i =
- mSounds.find(event);
- return (i == mSounds.end()) ? empty :
- i->second->at(rand() % i->second->size());
-}
-
-const std::string &MonsterInfo::getAttackParticleEffect(int attackType) const
-{
- static std::string empty("");
- std::map<int, MonsterAttack*>::const_iterator i =
- mMonsterAttacks.find(attackType);
- return (i == mMonsterAttacks.end()) ? empty : (*i).second->particleEffect;
-}
-
-const std::string &MonsterInfo::getAttackMissileParticle(int attackType) const
-{
- static std::string empty("");
- std::map<int, MonsterAttack*>::const_iterator i =
- mMonsterAttacks.find(attackType);
- return (i == mMonsterAttacks.end()) ? empty : (*i).second->missileParticle;
-}
-
-SpriteAction MonsterInfo::getAttackAction(int attackType) const
-{
- std::map<int, MonsterAttack*>::const_iterator i =
- mMonsterAttacks.find(attackType);
- return (i == mMonsterAttacks.end()) ? ACTION_ATTACK : (*i).second->action;
-}
-
-void MonsterInfo::addMonsterAttack(int id,
- const std::string &particleEffect,
- SpriteAction action,
- const std::string &missileParticle)
-{
- MonsterAttack *a = new MonsterAttack;
- a->particleEffect = particleEffect;
- a->missileParticle = missileParticle;
- a->action = action;
- mMonsterAttacks[id] = a;
-}
-
-void MonsterInfo::addParticleEffect(const std::string &filename)
-{
- mParticleEffects.push_back(filename);
-}
diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h
deleted file mode 100644
index f074254a..00000000
--- a/src/resources/monsterinfo.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MONSTERINFO_H
-#define MONSTERINFO_H
-
-#include "being.h"
-
-#include <list>
-#include <map>
-#include <string>
-#include <vector>
-
-enum MonsterSoundEvent
-{
- MONSTER_EVENT_HIT,
- MONSTER_EVENT_MISS,
- MONSTER_EVENT_HURT,
- MONSTER_EVENT_DIE
-};
-
-struct MonsterAttack
-{
- std::string missileParticle;
- std::string particleEffect;
- SpriteAction action;
-};
-
-/**
- * Holds information about a certain type of monster. This includes the name
- * of the monster, the sprite to display and the sounds the monster makes.
- *
- * @see MonsterDB
- */
-class MonsterInfo
-{
- public:
- MonsterInfo();
-
- ~MonsterInfo();
-
- void setName(const std::string &name) { mName = name; }
-
- void addSprite(const std::string &filename)
- { mSprites.push_back(filename); }
-
- void setTargetCursorSize(Being::TargetCursorSize targetCursorSize)
- { mTargetCursorSize = targetCursorSize; }
-
- void addSound(MonsterSoundEvent event, const std::string &filename);
-
- void addParticleEffect(const std::string &filename);
-
- const std::string &getName() const
- { return mName; }
-
- const std::list<std::string>& getSprites() const
- { return mSprites; }
-
- Being::TargetCursorSize getTargetCursorSize() const
- { return mTargetCursorSize; }
-
- const std::string &getSound(MonsterSoundEvent event) const;
-
- void addMonsterAttack(int id,
- const std::string &particleEffect,
- SpriteAction action,
- const std::string &missileParticle);
-
- const std::string &getAttackParticleEffect(int attackType) const;
-
- const std::string &getAttackMissileParticle(int attackType) const;
-
- SpriteAction getAttackAction(int attackType) const;
-
- const std::list<std::string>& getParticleEffects() const
- { return mParticleEffects; }
-
- private:
- std::string mName;
- std::list<std::string> mSprites;
- Being::TargetCursorSize mTargetCursorSize;
- std::map<MonsterSoundEvent, std::vector<std::string>* > mSounds;
- std::map<int, MonsterAttack*> mMonsterAttacks;
- std::list<std::string> mParticleEffects;
-};
-
-#endif // MONSTERINFO_H
diff --git a/src/resources/npcdb.cpp b/src/resources/npcdb.cpp
index bc36a3b4..4f0ee10d 100644
--- a/src/resources/npcdb.cpp
+++ b/src/resources/npcdb.cpp
@@ -23,12 +23,14 @@
#include "log.h"
+#include "resources/beinginfo.h"
+
+#include "utils/dtor.h"
#include "utils/xml.h"
namespace
{
- NPCInfos mNPCInfos;
- NPCInfo mUnknown;
+ BeingInfos mNPCInfos;
bool mLoaded = false;
}
@@ -37,11 +39,6 @@ void NPCDB::load()
if (mLoaded)
unload();
- NPCsprite *unknownSprite = new NPCsprite;
- unknownSprite->sprite = "error.xml";
- unknownSprite->variant = 0;
- mUnknown.sprites.push_back(unknownSprite);
-
logger->log("Initializing NPC database...");
XML::Document doc("npcs.xml");
@@ -65,23 +62,30 @@ void NPCDB::load()
continue;
}
- NPCInfo *currentInfo = new NPCInfo;
+ BeingInfo *currentInfo = new BeingInfo;
+ currentInfo->setTargetCursorSize(XML::getProperty(npcNode,
+ "targetCursor", "medium"));
+
+ SpriteDisplay display;
for_each_xml_child_node(spriteNode, npcNode)
{
if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
{
- NPCsprite *currentSprite = new NPCsprite;
+ SpriteReference *currentSprite = new SpriteReference;
currentSprite->sprite = (const char*)spriteNode->xmlChildrenNode->content;
currentSprite->variant = XML::getProperty(spriteNode, "variant", 0);
- currentInfo->sprites.push_back(currentSprite);
+ display.sprites.push_back(currentSprite);
}
else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx"))
{
std::string particlefx = (const char*)spriteNode->xmlChildrenNode->content;
- currentInfo->particles.push_back(particlefx);
+ display.particles.push_back(particlefx);
}
}
+
+ currentInfo->setDisplay(display);
+
mNPCInfos[id] = currentInfo;
}
@@ -90,40 +94,23 @@ void NPCDB::load()
void NPCDB::unload()
{
- for ( NPCInfosIterator i = mNPCInfos.begin();
- i != mNPCInfos.end();
- i++)
- {
- while (!i->second->sprites.empty())
- {
- delete i->second->sprites.front();
- i->second->sprites.pop_front();
- }
- delete i->second;
- }
-
+ delete_all(mNPCInfos);
mNPCInfos.clear();
- while (!mUnknown.sprites.empty())
- {
- delete mUnknown.sprites.front();
- mUnknown.sprites.pop_front();
- }
-
mLoaded = false;
}
-const NPCInfo& NPCDB::get(int id)
+BeingInfo *NPCDB::get(int id)
{
- NPCInfosIterator i = mNPCInfos.find(id);
+ BeingInfoIterator i = mNPCInfos.find(id);
if (i == mNPCInfos.end())
{
logger->log("NPCDB: Warning, unknown NPC ID %d requested", id);
- return mUnknown;
+ return BeingInfo::Unknown;
}
else
{
- return *(i->second);
+ return i->second;
}
}
diff --git a/src/resources/npcdb.h b/src/resources/npcdb.h
index 9da873e4..b0c89c80 100644
--- a/src/resources/npcdb.h
+++ b/src/resources/npcdb.h
@@ -22,23 +22,7 @@
#ifndef NPC_DB_H
#define NPC_DB_H
-#include <list>
-#include <map>
-#include <string>
-
-struct NPCsprite
-{
- std::string sprite;
- int variant;
-};
-
-struct NPCInfo
-{
- std::list<NPCsprite*> sprites;
- std::list<std::string> particles;
-};
-
-typedef std::map<int, NPCInfo*> NPCInfos;
+class BeingInfo;
/**
* NPC information database.
@@ -49,9 +33,7 @@ namespace NPCDB
void unload();
- const NPCInfo& get(int id);
-
- typedef NPCInfos::iterator NPCInfosIterator;
+ BeingInfo *get(int id);
}
#endif
diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp
index 55b38546..03787569 100644
--- a/src/resources/spritedef.cpp
+++ b/src/resources/spritedef.cpp
@@ -30,10 +30,13 @@
#include "resources/imageset.h"
#include "resources/resourcemanager.h"
+#include "utils/dtor.h"
#include "utils/xml.h"
#include <set>
+SpriteReference *SpriteReference::Empty = new SpriteReference("error.xml", 0);
+
Action *SpriteDef::getAction(SpriteAction action) const
{
Actions::const_iterator i = mActions.find(action);
diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h
index 5bb6078e..bc9ae45f 100644
--- a/src/resources/spritedef.h
+++ b/src/resources/spritedef.h
@@ -26,12 +26,35 @@
#include <libxml/tree.h>
+#include <list>
#include <map>
#include <string>
class Action;
class ImageSet;
+struct SpriteReference
+{
+ static SpriteReference *Empty;
+
+ SpriteReference() {}
+
+ SpriteReference(std::string sprite, int variant)
+ { this->sprite = sprite; this->variant = variant; }
+
+ std::string sprite;
+ int variant;
+};
+
+struct SpriteDisplay
+{
+ std::string image;
+ std::list<SpriteReference*> sprites;
+ std::list<std::string> particles;
+};
+
+typedef std::list<SpriteReference*>::const_iterator SpriteRefs;
+
enum SpriteAction
{
ACTION_DEFAULT = 0,
diff --git a/src/sprite.h b/src/sprite.h
index 847c01a6..cce41f1d 100644
--- a/src/sprite.h
+++ b/src/sprite.h
@@ -1,7 +1,6 @@
/*
* The Mana Client
- * Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2010 The Mana Developers
*
* This file is part of The Mana Client.
*
@@ -22,64 +21,90 @@
#ifndef SPRITE_H
#define SPRITE_H
+#include "resources/spritedef.h"
+
class Graphics;
+class Image;
-/**
- * A sprite is some visible object on a map. This abstract class defines the
- * interface used by the map to sort and display the sprite.
- */
class Sprite
{
public:
+ virtual ~Sprite() {}
+
+ /**
+ * Resets the sprite.
+ *
+ * @returns true if the sprite changed, false otherwise
+ */
+ virtual bool reset() = 0;
+
/**
- * Destructor.
+ * Plays an action using the current direction.
+ *
+ * @returns true if the sprite changed, false otherwise
*/
- virtual
- ~Sprite() {}
+ virtual bool play(SpriteAction action) = 0;
/**
- * Draws the sprite to the given graphics context.
+ * Inform the animation of the passed time so that it can output the
+ * correct animation frame.
*
- * Note: this function could be simplified if the graphics context
- * would support setting a translation offset. It already does this
- * partly with the clipping rectangle support.
+ * @returns true if the sprite changed, false otherwise
*/
- virtual void draw(Graphics *graphics, int offsetX, int offsetY) const = 0;
+ virtual bool update(int time) = 0;
/**
- * Returns the horizontal size of the sprites graphical representation
- * in pixels or 0 when it is undefined.
+ * Draw the current animation frame at the coordinates given in screen
+ * pixels.
*/
- virtual int getWidth() const
- { return 0; }
+ virtual bool draw(Graphics* graphics, int posX, int posY) const = 0;
/**
- * Returns the vertical size of the sprites graphical representation
- * in pixels or 0 when it is undefined.
+ * Gets the width in pixels of the image of the current frame
*/
- virtual int getHeight() const
- { return 0; }
+ virtual int getWidth() const = 0;
/**
- * Returns the pixel Y coordinate of the sprite.
+ * Gets the height in pixels of the image of the current frame
*/
- virtual int getPixelY() const = 0;
+ virtual int getHeight() const = 0;
/**
- * Returns the number of Image layers used to draw the sprite.
+ * Returns a reference to the current image being drawn.
*/
- virtual int getNumberOfLayers() const
- { return 0; }
+ virtual const Image* getImage() const = 0;
/**
- * Returns the current alpha value used to draw the sprite.
+ * Sets the direction.
+ *
+ * @returns true if the sprite changed, false otherwise
*/
- virtual float getAlpha() const = 0;
+ virtual bool setDirection(SpriteDirection direction) = 0;
/**
- * Sets the alpha value used to draw the sprite.
+ * Sets the alpha value of the animated sprite
*/
- virtual void setAlpha(float alpha) = 0;
+ virtual void setAlpha(float alpha)
+ { mAlpha = alpha; }
+
+ /**
+ * Returns the current alpha opacity of the animated sprite.
+ */
+ virtual float getAlpha() const
+ { return mAlpha; }
+
+ /**
+ * Returns the current frame number for the sprite.
+ */
+ virtual size_t getCurrentFrame() const = 0;
+
+ /**
+ * Returns the frame count for the sprite.
+ */
+ virtual size_t getFrameCount() const = 0;
+
+ protected:
+ float mAlpha; /**< The alpha opacity used to draw */
};
-#endif
+#endif // SPRITE_H
diff --git a/src/text.cpp b/src/text.cpp
index f6c71dba..9f970872 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -41,12 +41,17 @@ Image *Text::mBubbleArrow;
Text::Text(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- const gcn::Color* color, bool isSpeech) :
+ const gcn::Color* color, bool isSpeech,
+ gcn::Font *font) :
mText(text),
mColor(color),
- mFont(gui->getFont()),
mIsSpeech(isSpeech)
{
+ if (!font)
+ mFont = gui->getFont();
+ else
+ mFont = font;
+
if (textManager == 0)
{
textManager = new TextManager;
@@ -145,8 +150,8 @@ void Text::draw(gcn::Graphics *graphics, int xOff, int yOff)
FlashText::FlashText(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- const gcn::Color *color) :
- Text(text, x, y, alignment, color),
+ const gcn::Color *color, gcn::Font *font) :
+ Text(text, x, y, alignment, color, false, font),
mTime(0)
{
}
diff --git a/src/text.h b/src/text.h
index fcfaf6ed..c884b394 100644
--- a/src/text.h
+++ b/src/text.h
@@ -40,7 +40,8 @@ class Text
*/
Text(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- const gcn::Color *color, bool isSpeech = false);
+ const gcn::Color *color, bool isSpeech = false,
+ gcn::Font *font = 0);
/**
* Destructor. The text is removed from the screen.
@@ -84,7 +85,8 @@ class FlashText : public Text
public:
FlashText(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- const gcn::Color* color);
+ const gcn::Color* color,
+ gcn::Font *font = 0);
/**
* Remove the text from the screen
diff --git a/src/textparticle.cpp b/src/textparticle.cpp
index e6226449..827343fa 100644
--- a/src/textparticle.cpp
+++ b/src/textparticle.cpp
@@ -36,10 +36,10 @@ TextParticle::TextParticle(Map *map, const std::string &text,
{
}
-void TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
+bool TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
{
if (!mAlive)
- return;
+ return false;
int screenX = (int) mPos.x + offsetX;
int screenY = (int) mPos.y - (int) mPos.z + offsetY;
@@ -58,4 +58,6 @@ void TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
TextRenderer::renderText(graphics, mText,
screenX, screenY, gcn::Graphics::CENTER,
color, mTextFont, mOutline, false);
+
+ return true;
}
diff --git a/src/textparticle.h b/src/textparticle.h
index a61bf8d9..7d99a057 100644
--- a/src/textparticle.h
+++ b/src/textparticle.h
@@ -38,7 +38,7 @@ class TextParticle : public Particle
/**
* Draws the particle image.
*/
- virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
+ virtual bool draw(Graphics *graphics, int offsetX, int offsetY) const;
// hack to improve text visibility
virtual int getPixelY() const
diff --git a/src/utils/copynpaste.cpp b/src/utils/copynpaste.cpp
index 31aa7bf9..3d2e3b80 100644
--- a/src/utils/copynpaste.cpp
+++ b/src/utils/copynpaste.cpp
@@ -269,7 +269,6 @@ static char* getSelection(Display *dpy, Window us, Atom selection)
return (char*)data;
}
}
- printf("Timeout\n");
return NULL;
}