diff options
Diffstat (limited to 'src')
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 @@ -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) { } @@ -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; } |