diff options
Diffstat (limited to 'src')
256 files changed, 8324 insertions, 5804 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 38589505..bc44a05c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -301,8 +301,6 @@ SET(SRCS gui/textdialog.h gui/textpopup.cpp gui/textpopup.h - gui/theme.cpp - gui/theme.h gui/trade.cpp gui/trade.h gui/truetypefont.cpp @@ -311,8 +309,6 @@ SET(SRCS gui/unregisterdialog.h gui/updatewindow.cpp gui/updatewindow.h - gui/userpalette.cpp - gui/userpalette.h gui/viewport.cpp gui/viewport.h gui/windowmenu.cpp @@ -353,6 +349,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 @@ -375,8 +373,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 @@ -387,8 +383,14 @@ SET(SRCS resources/resourcemanager.h resources/soundeffect.h resources/soundeffect.cpp + resources/specialdb.cpp + resources/specialdb.h resources/spritedef.h resources/spritedef.cpp + resources/theme.cpp + resources/theme.h + resources/userpalette.cpp + resources/userpalette.h resources/wallpaper.cpp resources/wallpaper.h utils/base64.cpp @@ -409,6 +411,12 @@ SET(SRCS utils/xml.h utils/zlib.cpp utils/zlib.h + actor.cpp + actor.h + actorsprite.cpp + actorsprite.h + actorspritemanager.cpp + actorspritemanager.h animatedsprite.cpp animatedsprite.h animationparticle.cpp @@ -417,8 +425,8 @@ SET(SRCS avatar.h being.cpp being.h - beingmanager.cpp - beingmanager.h + chatlog.cpp + chatlog.h client.cpp client.h channel.cpp @@ -427,18 +435,22 @@ SET(SRCS channelmanager.h commandhandler.cpp commandhandler.h + compoundsprite.cpp + compoundsprite.h configlistener.h configuration.cpp configuration.h + defaults.cpp + defaults.h effectmanager.cpp effectmanager.h emoteshortcut.cpp emoteshortcut.h equipment.h + event.cpp + event.h flooritem.cpp flooritem.h - flooritemmanager.cpp - flooritemmanager.h game.cpp game.h graphics.cpp @@ -448,6 +460,8 @@ SET(SRCS guild.h imageparticle.cpp imageparticle.h + imagesprite.cpp + imagesprite.h inventory.cpp inventory.h item.cpp @@ -458,6 +472,8 @@ SET(SRCS joystick.h keyboardconfig.cpp keyboardconfig.h + listener.cpp + listener.h localplayer.cpp localplayer.h log.cpp @@ -466,10 +482,6 @@ SET(SRCS main.h map.cpp map.h - monster.cpp - monster.h - npc.cpp - npc.h openglgraphics.cpp openglgraphics.h particle.cpp @@ -481,8 +493,8 @@ SET(SRCS particleemitterprop.h party.cpp party.h - player.cpp - player.h + playerinfo.cpp + playerinfo.h playerrelations.cpp playerrelations.h position.cpp @@ -509,6 +521,7 @@ SET(SRCS tileset.h units.cpp units.h + variabledata.h vector.cpp vector.h ) @@ -575,6 +588,7 @@ SET(SRCS_MANA net/manaserv/chathandler.h net/manaserv/connection.cpp net/manaserv/connection.h + net/manaserv/defines.h net/manaserv/effecthandler.cpp net/manaserv/effecthandler.h net/manaserv/gamehandler.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 1f2391a8..fa72eb08 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -193,8 +193,6 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ gui/textdialog.h \ gui/textpopup.cpp \ gui/textpopup.h \ - gui/theme.cpp \ - gui/theme.h \ gui/trade.cpp \ gui/trade.h \ gui/truetypefont.cpp \ @@ -203,8 +201,6 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ gui/unregisterdialog.h \ gui/updatewindow.cpp \ gui/updatewindow.h \ - gui/userpalette.cpp \ - gui/userpalette.h \ gui/viewport.cpp \ gui/viewport.h \ gui/windowmenu.cpp \ @@ -228,9 +224,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 +241,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 +265,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 \ @@ -279,8 +275,14 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ resources/resourcemanager.h \ resources/soundeffect.h \ resources/soundeffect.cpp \ + resources/specialdb.h \ + resources/specialdb.cpp \ resources/spritedef.h \ resources/spritedef.cpp \ + resources/theme.cpp \ + resources/theme.h \ + resources/userpalette.cpp \ + resources/userpalette.h \ resources/wallpaper.cpp \ resources/wallpaper.h \ utils/base64.cpp \ @@ -303,6 +305,13 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ utils/xml.h \ utils/zlib.cpp \ utils/zlib.h \ + actor.cpp \ + actor.h \ + actorsprite.cpp \ + actorsprite.h \ + actorspritelistener.h \ + actorspritemanager.cpp \ + actorspritemanager.h \ animatedsprite.cpp \ animatedsprite.h \ animationparticle.cpp \ @@ -311,8 +320,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 \ @@ -321,18 +330,22 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ channelmanager.h \ commandhandler.cpp \ commandhandler.h \ + compoundsprite.cpp \ + compoundsprite.h \ configlistener.h \ configuration.cpp \ configuration.h \ + defaults.cpp \ + defaults.h \ effectmanager.cpp \ effectmanager.h \ emoteshortcut.cpp \ emoteshortcut.h \ equipment.h \ + event.cpp \ + event.h \ flooritem.cpp \ flooritem.h \ - flooritemmanager.cpp \ - flooritemmanager.h \ game.cpp \ game.h \ graphics.cpp \ @@ -342,6 +355,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ guild.h \ imageparticle.cpp \ imageparticle.h \ + imagesprite.cpp \ + imagesprite.h \ inventory.cpp \ inventory.h \ item.cpp \ @@ -352,6 +367,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ joystick.h \ keyboardconfig.cpp \ keyboardconfig.h \ + listener.cpp \ + listener.h \ localplayer.cpp \ localplayer.h \ log.cpp \ @@ -360,10 +377,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 \ @@ -375,8 +388,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ particleemitterprop.h \ party.cpp \ party.h \ - player.cpp \ - player.h \ + playerinfo.cpp \ + playerinfo.h \ playerrelations.cpp \ playerrelations.h \ position.cpp \ @@ -403,6 +416,7 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ tileset.h \ units.cpp \ units.h \ + variabledata.h \ vector.cpp \ vector.h \ winver.h @@ -420,6 +434,7 @@ mana_SOURCES += \ net/manaserv/chathandler.h \ net/manaserv/connection.cpp \ net/manaserv/connection.h \ + net/manaserv/defines.h \ net/manaserv/effecthandler.cpp \ net/manaserv/effecthandler.h \ net/manaserv/gamehandler.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..ff12822c --- /dev/null +++ b/src/actorsprite.cpp @@ -0,0 +1,464 @@ +/* + * 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 "event.h" +#include "imagesprite.h" +#include "localplayer.h" +#include "log.h" +#include "simpleanimation.h" +#include "sound.h" +#include "statuseffect.h" + +#include "net/net.h" + +#include "resources/image.h" +#include "resources/imageset.h" +#include "resources/resourcemanager.h" +#include "resources/theme.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; + + // Notify listeners of the destruction. + Mana::Event event("Destroyed"); + event.setActor("source", this); + event.trigger("ActorSprite"); +} + +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->reset(); + mUsedTargetCursor->update(tick_time * MILLISECONDS_IN_A_TICK); + 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() +{ +} + +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) +{ + if (this == player_node) + { + Mana::Event event("Stun"); + event.setInt("oldMode", oldMode); + event.setInt("newMode", newMode); + event.trigger("ActorSprite"); + } + + handleStatusEffect(StatusEffect::getStatusEffect(oldMode, false), -1); + handleStatusEffect(StatusEffect::getStatusEffect(newMode, true), -1); +} + +void ActorSprite::updateStatusEffect(int index, bool newStatus) +{ + if (this == player_node) + { + Mana::Event event("UpdateStatusEffect"); + event.setInt("index", index); + event.setBool("newStatus", newStatus); + event.trigger("ActorSprite"); + } + + 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), 75, + (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..ab945d2f --- /dev/null +++ b/src/actorsprite.h @@ -0,0 +1,233 @@ +/* + * 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> +#include <list> + +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..88618ccd --- /dev/null +++ b/src/actorspritemanager.cpp @@ -0,0 +1,312 @@ +/* + * 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 "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.insert(player); +} + +Being *ActorSpriteManager::createBeing(int id, ActorSprite::Type type, int subtype) +{ + Being *being = new Being(id, type, subtype, mMap); + + mActors.insert(being); + return being; +} + +FloorItem *ActorSpriteManager::createItem(int id, int itemId, int x, int y) +{ + FloorItem *floorItem = new FloorItem(id, itemId, x, y, mMap); + + mActors.insert(floorItem); + return floorItem; +} + +void ActorSpriteManager::destroy(ActorSprite *actor) +{ + if (!actor || actor == player_node) + return; + + mDeleteActors.insert(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) + { + mActors.erase(*it); + delete *it; + } + + mDeleteActors.clear(); +} + +void ActorSpriteManager::clear() +{ + if (player_node) + mActors.erase(player_node); + + for_actors + delete *it; + mActors.clear(); + mDeleteActors.clear(); + + if (player_node) + mActors.insert(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..d9d5b534 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::set<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..ec666d80 100644 --- a/src/animatedsprite.cpp +++ b/src/animatedsprite.cpp @@ -41,16 +41,17 @@ 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(); // Play the stand animation by default - play(ACTION_STAND); + play(SpriteAction::STAND); } AnimatedSprite *AnimatedSprite::load(const std::string &filename, int variant) @@ -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(std::string 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); + play(SpriteAction::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..bd39c267 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(std::string 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 d2dfc855..1b95b17d 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -21,104 +21,163 @@ #include "being.h" +#include "actorspritemanager.h" #include "animatedsprite.h" #include "client.h" #include "configuration.h" #include "effectmanager.h" +#include "event.h" #include "graphics.h" +#include "guild.h" #include "localplayer.h" #include "log.h" #include "map.h" #include "particle.h" +#include "party.h" +#include "playerrelations.h" #include "simpleanimation.h" #include "sound.h" +#include "sprite.h" #include "text.h" #include "statuseffect.h" #include "gui/gui.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/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 "resources/theme.h" +#include "resources/userpalette.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" 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.getBoolValue("visiblenames"); + + config.addListener("visiblenames", this); + + if (getType() == PLAYER || getType() == NPC) + setShowName(true); + + updateColors(); + listen("Chat"); } 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(); @@ -152,8 +211,9 @@ void Being::setDestination(int dstX, int dstY) Position dest = mMap->checkNodeOffsets(getCollisionRadius(), getWalkMask(), dstX, dstY); - Path thisPath = mMap->findPixelPath(mPos.x, mPos.y, dest.x, dest.y, - getCollisionRadius(), getWalkMask()); + Path thisPath = mMap->findPixelPath((int) mPos.x, (int) mPos.y, + dest.x, dest.y, + getCollisionRadius(), getWalkMask()); if (thisPath.empty()) { @@ -186,10 +246,10 @@ void Being::setPath(const Path &path) mPath = path; if ((Net::getNetworkType() == ServerInfo::TMWATHENA) && - mAction != WALK && mAction != DEAD) + mAction != MOVE && mAction != DEAD) { nextTile(); - mWalkTime = tick_time; + mActionTime = tick_time; } } @@ -235,7 +295,7 @@ void Being::setSpeech(const std::string &text, int time) if (!mSpeech.empty()) mSpeechTime = time <= SPEECH_MAX_TIME ? time : SPEECH_MAX_TIME; - const int speech = (int) config.getValue("speech", TEXT_OVERHEAD); + const int speech = config.getIntValue("speech"); if (speech == TEXT_OVERHEAD) { if (mText) @@ -292,6 +352,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 +372,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 +430,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); +} - // Clear particle effect list because child particles became invalid - mChildParticleEffects.clear(); - mMustResetParticles = true; // Reset status particles on next redraw +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; } -void Being::controlParticle(Particle *particle) +Guild *Being::getGuild(int id) const { - mChildParticleEffects.addLocally(particle); + 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; + + if (this == player_node && socialWindow) + socialWindow->removeTab(guild); + + guild->removeMember(mId); + } + + mGuilds.clear(); +} + +void Being::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 Being::fireMissile(Being *victim, const std::string &particle) @@ -404,46 +547,79 @@ void Being::fireMissile(Being *victim, const std::string &particle) void Being::setAction(Action action, int attackType) { - SpriteAction currentAction = ACTION_INVALID; + std::string currentAction = SpriteAction::INVALID; switch (action) { - case WALK: - currentAction = ACTION_WALK; + case MOVE: + currentAction = SpriteAction::MOVE; + // Note: When adding a run action, + // Differentiate walk and run with action name, + // while using only the ACTION_MOVE. break; case SIT: - currentAction = ACTION_SIT; + currentAction = SpriteAction::SIT; break; case ATTACK: if (mEquippedWeapon) - currentAction = mEquippedWeapon->getAttackType(); + { + currentAction = mEquippedWeapon->getAttackAction(); + 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 + //currentAction = SpriteAction::HURT;// Buggy: makes the player stop // attacking and unable to attack - // again until he moves + // again until he moves. + // TODO: fix this! break; case DEAD: - currentAction = ACTION_DEAD; + currentAction = SpriteAction::DEAD; + sound.playSfx(mInfo->getSound(SOUND_EVENT_DIE)); break; case STAND: - currentAction = ACTION_STAND; + currentAction = SpriteAction::STAND; break; } - if (currentAction != ACTION_INVALID) + if (currentAction != SpriteAction::INVALID) { - for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++) - if (*it) - (*it)->play(currentAction); + play(currentAction); mAction = action; } + + if (currentAction != SpriteAction::MOVE) + mActionTime = tick_time; } void Being::setDirection(Uint8 direction) @@ -469,9 +645,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 */ @@ -506,8 +680,8 @@ void Being::nextTile() mX = pos.x; mY = pos.y; - setAction(WALK); - mWalkTime += (int)(mWalkSpeed.x / 10); + setAction(MOVE); + mActionTime += (int)(mWalkSpeed.x / 10); } int Being::getCollisionRadius() const @@ -570,8 +744,8 @@ void Being::logic() else setPosition(mPos + diff); - if (mAction != WALK) - setAction(WALK); + if (mAction != MOVE) + setAction(MOVE); // Update the player sprite direction. // N.B.: We only change this if the distance is more than one pixel. @@ -600,13 +774,76 @@ void Being::logic() // remove it and go to the next one. mPath.pop_front(); } - else if (mAction == WALK) + else if (mAction == MOVE) { setAction(STAND); } } else if (Net::getNetworkType() == ServerInfo::TMWATHENA) { + int frameCount = getFrameCount(); + + switch (mAction) + { + case STAND: + case SIT: + case DEAD: + case HURT: + break; + + case MOVE: + 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, + paths.getStringValue("particles")).empty()) + particleEffect = paths.getStringValue("particles") + + 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 +856,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); } } @@ -701,7 +888,7 @@ void Being::drawSpeech(int offsetX, int offsetY) { const int px = getPixelX() - offsetX; const int py = getPixelY() - offsetY; - const int speech = (int) config.getValue("speech", TEXT_OVERHEAD); + const int speech = config.getIntValue("speech"); // Draw speech above this being if (mSpeechTime == 0) @@ -751,72 +938,11 @@ 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 { // Check whether we're walking in the requested direction - if (mAction != WALK || !(mDirection & (pos | neg))) + if (mAction != MOVE || !(mDirection & (pos | neg))) return 0; int offset = 0; @@ -824,9 +950,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 +970,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.getBoolValue("visiblenames")); + } } -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.getBoolValue("showgender")) + { + 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.getBoolValue("showMonstersTakedDamage")) { - 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( + paths.getStringValue("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() @@ -1023,7 +1155,7 @@ void Being::load() int hairstyles = 1; while (ItemDB::get(-hairstyles).getSprite(GENDER_MALE) != - paths.getValue("spriteErrorFile", "error.xml")) + paths.getStringValue("spriteErrorFile")) hairstyles++; mNumberOfHairstyles = hairstyles; @@ -1034,3 +1166,57 @@ 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() +{ + Mana::Event event("doTalk"); + event.setInt("npcId", mId); + event.trigger("NPC"); +} + +void Being::event(const std::string &channel, const Mana::Event &event) +{ + if (channel == "Chat" && + (event.getName() == "Being" || event.getName() == "Player") && + event.getInt("permissions") & PlayerRelation::SPEECH_FLOAT) + { + try + { + if (mId == event.getInt("beingId")) + { + setSpeech(event.getString("text")); + } + } + catch (Mana::BadEvent badEvent) + {} + } +} diff --git a/src/being.h b/src/being.h index 71b3e2cf..a55e2d3a 100644 --- a/src/being.h +++ b/src/being.h @@ -22,19 +22,19 @@ #ifndef BEING_H #define BEING_H +#include "actorsprite.h" #include "configlistener.h" +#include "listener.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 +45,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 Mana::Listener { 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 @@ -78,21 +74,13 @@ class Being : public Sprite, public ConfigListener enum Action { STAND, - WALK, + MOVE, ATTACK, SIT, DEAD, HURT }; - enum TargetCursorSize - { - TC_SMALL = 0, - TC_MEDIUM, - TC_LARGE, - NUM_TC - }; - enum Speech { NO_SPEECH = 0, @@ -128,29 +116,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. @@ -216,7 +202,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. @@ -238,23 +224,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 @@ -282,20 +327,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. @@ -324,18 +376,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); @@ -361,65 +401,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); /** @@ -427,17 +413,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; @@ -453,45 +434,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. */ @@ -507,45 +460,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); @@ -554,78 +471,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(); + void event(const std::string &channel, const Mana::Event &event); + + 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 @@ -643,20 +547,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: @@ -667,8 +569,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; @@ -681,13 +582,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..d45bea22 --- /dev/null +++ b/src/chatlog.cpp @@ -0,0 +1,176 @@ +/* + * 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.getStringValue("MostUsedServerName0"); + + 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 b63550e6..1e1d17a9 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -22,8 +22,10 @@ #include "client.h" #include "main.h" +#include "chatlog.h" #include "configuration.h" #include "emoteshortcut.h" +#include "event.h" #include "game.h" #include "itemshortcut.h" #include "keyboardconfig.h" @@ -47,10 +49,8 @@ #include "gui/sdlinput.h" #include "gui/serverdialog.h" #include "gui/setup.h" -#include "gui/theme.h" #include "gui/unregisterdialog.h" #include "gui/updatewindow.h" -#include "gui/userpalette.h" #include "gui/worldselectdialog.h" #include "gui/widgets/button.h" @@ -69,8 +69,11 @@ #include "resources/image.h" #include "resources/itemdb.h" #include "resources/monsterdb.h" +#include "resources/specialdb.h" #include "resources/npcdb.h" #include "resources/resourcemanager.h" +#include "resources/theme.h" +#include "resources/userpalette.h" #include "utils/gettext.h" #include "utils/mkdir.h" @@ -111,6 +114,7 @@ Configuration config; /**< XML file configuration reader */ Configuration branding; /**< XML branding information reader */ Configuration paths; /**< XML default paths information reader */ Logger *logger; /**< Log object */ +ChatLogger *chatLogger; /**< Chat log object */ KeyboardConfig keyboard; UserPalette *userPalette; @@ -215,14 +219,21 @@ Client::Client(const Options &options): if (!options.brandingPath.empty()) { branding.init(options.brandingPath); + branding.setDefaultValues(getBrandingDefaults()); } 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)); + logger->setLogToStandardOut(config.getBoolValue("logToStandardOut")); // Log the mana version logger->log("Mana %s", FULL_VERSION); @@ -326,11 +337,11 @@ Client::Client(const Options &options): graphics = new Graphics; #endif - const int width = (int) config.getValue("screenwidth", defaultScreenWidth); - const int height = (int) config.getValue("screenheight", defaultScreenHeight); + const int width = config.getIntValue("screenwidth"); + const int height = config.getIntValue("screenheight"); const int bpp = 0; - const bool fullscreen = ((int) config.getValue("screen", 0) == 1); - const bool hwaccel = ((int) config.getValue("hwaccel", 0) == 1); + const bool fullscreen = config.getBoolValue("screen"); + const bool hwaccel = config.getBoolValue("hwaccel"); // Try to set the desired video mode if (!graphics->setVideoMode(width, height, bpp, fullscreen, hwaccel)) @@ -353,13 +364,11 @@ Client::Client(const Options &options): // Initialize sound engine try { - if (config.getValue("sound", 0) == 1) + if (config.getBoolValue("sound")) sound.init(); - sound.setSfxVolume((int) config.getValue("sfxVolume", - defaultSfxVolume)); - sound.setMusicVolume((int) config.getValue("musicVolume", - defaultMusicVolume)); + sound.setSfxVolume(config.getIntValue("sfxVolume")); + sound.setMusicVolume(config.getIntValue("musicVolume")); } catch (const char *err) { @@ -384,25 +393,25 @@ Client::Client(const Options &options): mCurrentServer.port = options.serverPort; loginData.username = options.username; loginData.password = options.password; - loginData.remember = config.getValue("remember", 0); + loginData.remember = config.getBoolValue("remember"); loginData.registerLogin = false; if (mCurrentServer.hostname.empty()) - { - mCurrentServer.hostname = branding.getValue("defaultServer", - "").c_str(); - } + mCurrentServer.hostname = branding.getValue("defaultServer","").c_str(); if (mCurrentServer.port == 0) { mCurrentServer.port = (short) branding.getValue("defaultPort", - DEFAULT_PORT); + DEFAULT_PORT); mCurrentServer.type = ServerInfo::parseType( - branding.getValue("defaultServerType", "tmwathena")); + branding.getValue("defaultServerType", "tmwathena")); } + if (chatLogger) + chatLogger->setServerName(mCurrentServer.hostname); + if (loginData.username.empty() && loginData.remember) - loginData.username = config.getValue("username", ""); + loginData.username = config.getStringValue("username"); if (mState != STATE_ERROR) mState = STATE_CHOOSE_SERVER; @@ -416,6 +425,9 @@ Client::Client(const Options &options): SDL_initFramerate(&mFpsManager); config.addListener("fpslimit", this); optionChanged("fpslimit"); + + // Initialize PlayerInfo + PlayerInfo::init(); } Client::~Client() @@ -561,10 +573,8 @@ int Client::exec() - 3, 3); top->add(mSetupButton); - int screenWidth = (int) config.getValue("screenwidth", - defaultScreenWidth); - int screenHeight = (int) config.getValue("screenheight", - defaultScreenHeight); + int screenWidth = config.getIntValue("screenwidth"); + int screenHeight = config.getIntValue("screenheight"); mDesktop->setSize(screenWidth, screenHeight); } @@ -576,9 +586,12 @@ int Client::exec() if (mState != mOldState) { - Net::GeneralHandler *generalHandler = Net::getGeneralHandler(); - if (generalHandler) - generalHandler->stateChanged(mOldState, mState); + { + Mana::Event event("StateChange"); + event.setInt("oldState", mOldState); + event.setInt("newState", mState); + event.trigger("Client"); + } if (mOldState == STATE_GAME) { @@ -730,17 +743,21 @@ int Client::exec() // Read default paths file 'data/paths.xml' paths.init("paths.xml", true); + paths.setDefaultValues(getPathsDefaults()); // Load XML databases ColorDB::load(); ItemDB::load(); Being::load(); // Hairstyles MonsterDB::load(); + SpecialDB::load(); NPCDB::load(); EmoteDB::load(); StatusEffect::load(); Units::loadUnits(); + ActorSprite::load(); + mDesktop->reloadWallpaper(); mState = STATE_GET_CHARACTERS; @@ -766,7 +783,7 @@ int Client::exec() mOptions.character, CharSelectDialog::Choose)) { ((CharSelectDialog*) mCurrentDialog)->selectByName( - config.getValue("lastCharacter", ""), + config.getStringValue("lastCharacter"), mOptions.chooseDefault ? CharSelectDialog::Choose : CharSelectDialog::Focus); @@ -978,7 +995,7 @@ int Client::exec() void Client::optionChanged(const std::string &name) { - const int fpsLimit = (int) config.getValue("fpslimit", 60); + const int fpsLimit = config.getIntValue("fpslimit"); mLimitFps = fpsLimit > 0; if (mLimitFps) SDL_setFramerate(&mFpsManager, fpsLimit); @@ -1129,6 +1146,7 @@ void Client::initConfiguration() { fclose(configFile); config.init(configPath); + config.setDefaultValues(getConfigDefaults()); } } @@ -1143,7 +1161,7 @@ void Client::initUpdatesDir() // If updatesHost is currently empty, fill it from config file if (mUpdateHost.empty()) { - mUpdateHost = config.getValue("updatehost", ""); + mUpdateHost = config.getStringValue("updatehost"); } // Don't go out of range int he next check @@ -1151,7 +1169,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 @@ -1159,7 +1177,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(); @@ -1221,7 +1239,7 @@ void Client::initScreenshotDir() else { std::string configScreenshotDir = - config.getValue("screenshotDirectory", ""); + config.getStringValue("screenshotDirectory"); if (!configScreenshotDir.empty()) mScreenshotDir = configScreenshotDir; else @@ -1236,7 +1254,7 @@ void Client::initScreenshotDir() } config.setValue("screenshotDirectory", mScreenshotDir); - if (config.getValue("useScreenshotDirectorySuffix", true)) + if (config.getBoolValue("useScreenshotDirectorySuffix")) { std::string configScreenshotSuffix = config.getValue("screenshotDirectorySuffix", 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/commandhandler.cpp b/src/commandhandler.cpp index dab51c8f..a39e13bd 100644 --- a/src/commandhandler.cpp +++ b/src/commandhandler.cpp @@ -27,8 +27,6 @@ #include "localplayer.h" #include "playerrelations.h" -#include "gui/chat.h" - #include "gui/widgets/channeltab.h" #include "gui/widgets/chattab.h" @@ -389,7 +387,7 @@ void CommandHandler::handleMsg(const std::string &args, ChatTab *tab) if (tempNick.compare(playerName) == 0 || args.empty()) return; - chatWindow->whisper(recvnick, msg, true); + chatWindow->whisper(recvnick, msg, BY_PLAYER); } else tab->chatLog(_("Cannot send empty whispers!"), BY_SERVER); diff --git a/src/compoundsprite.cpp b/src/compoundsprite.cpp new file mode 100644 index 00000000..293e170c --- /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(std::string 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..3b443219 --- /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(std::string 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/configuration.cpp b/src/configuration.cpp index d8b11034..a6f691d8 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -98,6 +98,126 @@ ConfigurationObject::~ConfigurationObject() clear(); } +void Configuration::cleanDefaults() +{ + if (mDefaultsData) + { + for (DefaultsData::const_iterator iter = mDefaultsData->begin(); + iter != mDefaultsData->end(); iter++) + { + if (iter->second) + delete(iter->second); + } + mDefaultsData->clear(); + delete mDefaultsData; + mDefaultsData = 0; + } +} + +Configuration::~Configuration() +{ + cleanDefaults(); +} + +void Configuration::setDefaultValues(DefaultsData *defaultsData) +{ + cleanDefaults(); + mDefaultsData = defaultsData; +} + +int Configuration::getIntValue(const std::string &key) const +{ + int defaultValue = 0; + if (mDefaultsData) + { + DefaultsData::const_iterator itdef = mDefaultsData->find(key); + + if (itdef != mDefaultsData->end() && itdef->second + && itdef->second->getType() == Mana::VariableData::DATA_INT) + { + defaultValue = ((Mana::IntData*)itdef->second)->getData(); + } + else + { + logger->log("%s: No integer value in registry for key %s", + mConfigPath.c_str(), key.c_str()); + } + } + Options::const_iterator iter = mOptions.find(key); + return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : defaultValue; +} + +std::string Configuration::getStringValue(const std::string &key) const +{ + std::string defaultValue = ""; + if (mDefaultsData) + { + DefaultsData::const_iterator itdef = mDefaultsData->find(key); + + if (itdef != mDefaultsData->end() && itdef->second + && itdef->second->getType() == Mana::VariableData::DATA_STRING) + { + defaultValue = ((Mana::StringData*)itdef->second)->getData(); + } + else + { + logger->log("%s: No string value in registry for key %s", + mConfigPath.c_str(), key.c_str()); + } + } + Options::const_iterator iter = mOptions.find(key); + return (iter != mOptions.end()) ? iter->second : defaultValue; +} + + +float Configuration::getFloatValue(const std::string &key) const +{ + float defaultValue = 0.0f; + if (mDefaultsData) + { + DefaultsData::const_iterator itdef = mDefaultsData->find(key); + + if (itdef != mDefaultsData->end() && itdef->second + && itdef->second->getType() == Mana::VariableData::DATA_FLOAT) + { + defaultValue = ((Mana::FloatData*)itdef->second)->getData(); + } + else + { + logger->log("%s: No float value in registry for key %s", + mConfigPath.c_str(), key.c_str()); + } + } + Options::const_iterator iter = mOptions.find(key); + return (iter != mOptions.end()) ? atof(iter->second.c_str()) : defaultValue; +} + +bool Configuration::getBoolValue(const std::string &key) const +{ + bool defaultValue = false; + if (mDefaultsData) + { + DefaultsData::const_iterator itdef = mDefaultsData->find(key); + + if (itdef != mDefaultsData->end() && itdef->second + && itdef->second->getType() == Mana::VariableData::DATA_BOOL) + { + defaultValue = ((Mana::BoolData*)itdef->second)->getData(); + } + else + { + logger->log("%s: No boolean value in registry for key %s", + mConfigPath.c_str(), key.c_str()); + } + } + + Options::const_iterator iter = mOptions.find(key); + if (iter != mOptions.end()) + return getBoolFromString(iter->second); + else + return defaultValue; +} + void ConfigurationObject::initFromXML(xmlNodePtr parent_node) { clear(); diff --git a/src/configuration.h b/src/configuration.h index 908d13a4..761cc43b 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -23,6 +23,7 @@ #define CONFIGURATION_H #include "utils/stringutils.h" +#include "defaults.h" #include <libxml/xmlwriter.h> @@ -192,7 +193,7 @@ class ConfigurationObject class Configuration : public ConfigurationObject { public: - virtual ~Configuration() {} + ~Configuration(); /** * Reads config file and parse all options into memory. @@ -203,6 +204,13 @@ class Configuration : public ConfigurationObject void init(const std::string &filename, bool useResManager = false); /** + * Set the default values for each keys. + * + * @param defaultsData data used as defaults. + */ + void setDefaultValues(DefaultsData *defaultsData); + + /** * Writes the current settings back to the config file. */ void write(); @@ -238,14 +246,30 @@ class Configuration : public ConfigurationObject inline void setValue(const std::string &key, bool value) { setValue(key, value ? "1" : "0"); } + /** + * returns a value corresponding to the given key. + * The default value returned in based on fallbacks registry. + * @see defaults.h + */ + int getIntValue(const std::string &key) const; + float getFloatValue(const std::string &key) const; + std::string getStringValue(const std::string &key) const; + bool getBoolValue(const std::string &key) const; + private: + /** + * Clean up the default values member. + */ + void cleanDefaults(); + typedef std::list<ConfigListener*> Listeners; typedef Listeners::iterator ListenerIterator; typedef std::map<std::string, Listeners> ListenerMap; typedef ListenerMap::iterator ListenerMapIterator; ListenerMap mListenerMap; - std::string mConfigPath; /**< Location of config file */ + std::string mConfigPath; /**< Location of config file */ + DefaultsData *mDefaultsData; /**< Defaults of value for a given key */ }; extern Configuration branding; diff --git a/src/defaults.cpp b/src/defaults.cpp new file mode 100644 index 00000000..c08fb357 --- /dev/null +++ b/src/defaults.cpp @@ -0,0 +1,182 @@ +/* + * 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 "defaults.h" + +#include "utils/stringutils.h" + +#include "being.h" +#include "graphics.h" +#include "client.h" + +#include <stdlib.h> + +using namespace Mana; + +VariableData* createData(int defData) +{ + return new IntData(defData); +} + +VariableData* createData(double defData) +{ + return new FloatData(defData); +} + +VariableData* createData(float defData) +{ + return new FloatData(defData); +} + +VariableData* createData(const std::string &defData) +{ + return new StringData(defData); +} + +VariableData* createData(const char* defData) +{ + return new StringData(defData); +} + +VariableData* createData(bool defData) +{ + return new BoolData(defData); +} + +#define AddDEF(defaultsData, key, value) \ + defaultsData->insert(std::pair<std::string, VariableData*> \ + (key, createData(value))); + + +DefaultsData* getConfigDefaults() +{ + DefaultsData* configData = new DefaultsData; + // Init main config defaults + AddDEF(configData, "OverlayDetail", 2); + AddDEF(configData, "speechBubblecolor", "000000"); + AddDEF(configData, "speechBubbleAlpha", 1.0f); + AddDEF(configData, "MostUsedServerName0", "server.themanaworld.org"); + AddDEF(configData, "visiblenames", true); + AddDEF(configData, "speech", Being::TEXT_OVERHEAD); + AddDEF(configData, "showgender", false); + AddDEF(configData, "showMonstersTakedDamage", false); + AddDEF(configData, "particleMaxCount", 3000); + AddDEF(configData, "particleFastPhysics", 0); + AddDEF(configData, "particleEmitterSkip", 1); + AddDEF(configData, "particleeffects", true); + AddDEF(configData, "logToStandardOut", false); + AddDEF(configData, "opengl", false); + AddDEF(configData, "screenwidth", defaultScreenWidth); + AddDEF(configData, "screenheight", defaultScreenHeight); + AddDEF(configData, "screen", false); + AddDEF(configData, "hwaccel", false); + AddDEF(configData, "sound", false); + AddDEF(configData, "sfxVolume", 100); + AddDEF(configData, "musicVolume", 60); + AddDEF(configData, "remember", false); + AddDEF(configData, "username", ""); + AddDEF(configData, "lastCharacter", ""); + AddDEF(configData, "fpslimit", 60); + AddDEF(configData, "updatehost", ""); + AddDEF(configData, "screenshotDirectory", ""); + AddDEF(configData, "useScreenshotDirectorySuffix", true); + AddDEF(configData, "screenshotDirectorySuffix", ""); + AddDEF(configData, "EnableSync", false); + AddDEF(configData, "joystickEnabled", false); + AddDEF(configData, "upTolerance", 100); + AddDEF(configData, "downTolerance", 100); + AddDEF(configData, "leftTolerance", 100); + AddDEF(configData, "rightTolerance", 100); + AddDEF(configData, "logNpcInGui", true); + AddDEF(configData, "download-music", false); + AddDEF(configData, "guialpha", 0.8f); + AddDEF(configData, "ChatLogLength", 0); + AddDEF(configData, "enableChatLog", false); + AddDEF(configData, "whispertab", false); + AddDEF(configData, "customcursor", true); + AddDEF(configData, "showownname", false); + AddDEF(configData, "showpickupparticle", false); + AddDEF(configData, "showpickupchat", true); + AddDEF(configData, "fontSize", 11); + AddDEF(configData, "ReturnToggles", false); + AddDEF(configData, "ScrollLaziness", 16); + AddDEF(configData, "ScrollRadius", 0); + AddDEF(configData, "ScrollCenterOffsetX", 0); + AddDEF(configData, "ScrollCenterOffsetY", 0); + AddDEF(configData, "onlineServerList", ""); + AddDEF(configData, "theme", ""); + + return configData; +} + +DefaultsData* getBrandingDefaults() +{ + DefaultsData* brandingData = new DefaultsData; + // Init config defaults + AddDEF(brandingData, "wallpapersPath", ""); + AddDEF(brandingData, "wallpapersFile", ""); + AddDEF(brandingData, "appName", "Mana"); + AddDEF(brandingData, "appIcon", "icons/mana.png"); + AddDEF(brandingData, "loginMusic", "Magick - Real.ogg"); + AddDEF(brandingData, "defaultServer", ""); + AddDEF(brandingData, "defaultPort", DEFAULT_PORT); + AddDEF(brandingData, "defaultServerType", "tmwathena"); + AddDEF(brandingData, "onlineServerList", "a"); + AddDEF(brandingData, "appShort", "mana"); + AddDEF(brandingData, "defaultUpdateHost", ""); + AddDEF(brandingData, "helpPath", ""); + AddDEF(brandingData, "onlineServerList", ""); + AddDEF(brandingData, "guiThemePath", ""); + AddDEF(brandingData, "theme", ""); + AddDEF(brandingData, "font", "fonts/dejavusans.ttf"); + AddDEF(brandingData, "boldFont", "fonts/dejavusans-bold.ttf"); + + return brandingData; +} + +DefaultsData* getPathsDefaults() +{ + DefaultsData *pathsData = new DefaultsData; + // Init paths.xml defaults + AddDEF(pathsData, "itemIcons", "graphics/items/"); + AddDEF(pathsData, "unknownItemFile", "unknown-item.png"); + AddDEF(pathsData, "sprites", "graphics/sprites/"); + AddDEF(pathsData, "spriteErrorFile", "error.xml"); + + AddDEF(pathsData, "particles", "graphics/particles/"); + AddDEF(pathsData, "levelUpEffectFile", "levelup.particle.xml"); + AddDEF(pathsData, "portalEffectFile", "warparea.particle.xml"); + + AddDEF(pathsData, "minimaps", "graphics/minimaps/"); + AddDEF(pathsData, "maps", "maps/"); + + AddDEF(pathsData, "sfx", "sfx/"); + AddDEF(pathsData, "attackSfxFile", "fist-swish.ogg"); + AddDEF(pathsData, "music", "music/"); + + AddDEF(pathsData, "wallpapers", "graphics/images/"); + AddDEF(pathsData, "wallpaperFile", "login_wallpaper.png"); + + AddDEF(pathsData, "help", "help/"); + + return pathsData; +} + +#undef AddDEF diff --git a/src/defaults.h b/src/defaults.h new file mode 100644 index 00000000..b9dfa511 --- /dev/null +++ b/src/defaults.h @@ -0,0 +1,34 @@ +/* + * 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 DEFAULTS_H +#define DEFAULTS_H + +#include <map> +#include <string> +#include "variabledata.h" + +typedef std::map<std::string, Mana::VariableData*> DefaultsData; + +DefaultsData* getConfigDefaults(); +DefaultsData* getBrandingDefaults(); +DefaultsData* getPathsDefaults(); + +#endif diff --git a/src/event.cpp b/src/event.cpp new file mode 100644 index 00000000..3ca4c5e2 --- /dev/null +++ b/src/event.cpp @@ -0,0 +1,255 @@ +/* + * 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 "event.h" + +#include "listener.h" +#include "variabledata.h" + +namespace Mana +{ + +ListenMap Event::mBindings; + +Event::~Event() +{ + VariableMap::iterator it = mData.begin(); + while (it != mData.end()) + { + delete it->second; + it++; + } +} + +// Integers + +void Event::setInt(const std::string &key, int value) throw (BadEvent) +{ + if (mData.find(key) != mData.end()) + throw KEY_ALREADY_EXISTS; + + mData[key] = new IntData(value); +} + +int Event::getInt(const std::string &key) const throw (BadEvent) +{ + VariableMap::const_iterator it = mData.find(key); + if (it == mData.end()) + throw BAD_KEY; + + if (it->second->getType() != VariableData::DATA_INT) + throw BAD_VALUE; + + return static_cast<IntData *>(it->second)->getData(); +} + +bool Event::hasInt(const std::string &key) const +{ + VariableMap::const_iterator it = mData.find(key); + return !(it == mData.end() + || it->second->getType() != VariableData::DATA_INT); +} + +// Strings + +void Event::setString(const std::string &key, const std::string &value) throw (BadEvent) +{ + if (mData.find(key) != mData.end()) + throw KEY_ALREADY_EXISTS; + + mData[key] = new StringData(value); +} + +const std::string &Event::getString(const std::string &key) const throw (BadEvent) +{ + VariableMap::const_iterator it = mData.find(key); + if (it == mData.end()) + throw BAD_KEY; + + if (it->second->getType() != VariableData::DATA_STRING) + throw BAD_VALUE; + + return static_cast<StringData *>(it->second)->getData(); +} + + +bool Event::hasString(const std::string &key) const +{ + VariableMap::const_iterator it = mData.find(key); + return !(it == mData.end() + || it->second->getType() != VariableData::DATA_STRING); +} + +// Floats + +void Event::setFloat(const std::string &key, double value) throw (BadEvent) +{ + if (mData.find(key) != mData.end()) + throw KEY_ALREADY_EXISTS; + + mData[key] = new FloatData(value); +} + +double Event::getFloat(const std::string &key) const throw (BadEvent) +{ + VariableMap::const_iterator it = mData.find(key); + if (it == mData.end()) + throw BAD_KEY; + + if (it->second->getType() != VariableData::DATA_FLOAT) + throw BAD_VALUE; + + return static_cast<FloatData *>(it->second)->getData(); +} + +bool Event::hasFloat(const std::string &key) const +{ + VariableMap::const_iterator it = mData.find(key); + return !(it == mData.end() + || it->second->getType() != VariableData::DATA_FLOAT); +} + +// Booleans + +void Event::setBool(const std::string &key, bool value) throw (BadEvent) +{ + if (mData.find(key) != mData.end()) + throw KEY_ALREADY_EXISTS; + + mData[key] = new BoolData(value); +} + +bool Event::getBool(const std::string &key) const throw (BadEvent) +{ + VariableMap::const_iterator it = mData.find(key); + if (it == mData.end()) + throw BAD_KEY; + + if (it->second->getType() != VariableData::DATA_BOOL) + throw BAD_VALUE; + + return static_cast<BoolData *>(it->second)->getData(); +} + +bool Event::hasBool(const std::string &key) const +{ + VariableMap::const_iterator it = mData.find(key); + return !(it == mData.end() + || it->second->getType() != VariableData::DATA_BOOL); +} + +// Items + +void Event::setItem(const std::string &key, Item *value) throw (BadEvent) +{ + if (mData.find(key) != mData.end()) + throw KEY_ALREADY_EXISTS; + + mData[key] = new ItemData(value); +} + +Item *Event::getItem(const std::string &key) const throw (BadEvent) +{ + VariableMap::const_iterator it = mData.find(key); + if (it == mData.end()) + throw BAD_KEY; + + if (it->second->getType() != VariableData::DATA_ITEM) + throw BAD_VALUE; + + return static_cast<ItemData *>(it->second)->getData(); +} + +bool Event::hasItem(const std::string &key) const +{ + VariableMap::const_iterator it = mData.find(key); + return !(it == mData.end() + || it->second->getType() != VariableData::DATA_ITEM); +} + +// Actors + +void Event::setActor(const std::string &key, ActorSprite *value) throw (BadEvent) +{ + if (mData.find(key) != mData.end()) + throw KEY_ALREADY_EXISTS; + + mData[key] = new ActorData(value); +} + +ActorSprite *Event::getActor(const std::string &key) const throw (BadEvent) +{ + VariableMap::const_iterator it = mData.find(key); + if (it == mData.end()) + throw BAD_KEY; + + if (it->second->getType() != VariableData::DATA_ACTOR) + throw BAD_VALUE; + + return static_cast<ActorData *>(it->second)->getData(); +} + +bool Event::hasActor(const std::string &key) const +{ + VariableMap::const_iterator it = mData.find(key); + return !(it == mData.end() + || it->second->getType() != VariableData::DATA_ACTOR); +} + +// Triggers + +void Event::trigger(const std::string &channel, const Event &event) +{ + ListenMap::iterator it = mBindings.find(channel); + + // Make sure something is listening + if (it == mBindings.end()) + return; + + // Loop though all listeners + ListenerSet::iterator lit = it->second.begin(); + while (lit != it->second.end()) + { + (*lit)->event(channel, event); + lit++; + } +} + +void Event::bind(Listener *listener, const std::string &channel) +{ + mBindings[channel].insert(listener); +} + +void Event::unbind(Listener *listener, const std::string &channel) +{ + mBindings[channel].erase(listener); +} + +void Event::remove(Listener *listener) +{ + ListenMap::iterator it = mBindings.begin(); + while (it != mBindings.end()) + { + it->second.erase(listener); + it++; + } +} + +} // namespace Mana diff --git a/src/event.h b/src/event.h new file mode 100644 index 00000000..c7382fc1 --- /dev/null +++ b/src/event.h @@ -0,0 +1,269 @@ +/* + * 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 EVENT_H +#define EVENT_H + +#include <map> +#include <set> +#include <string> + +class ActorSprite; +class Item; + +namespace Mana +{ + +// Possible exception that can be thrown +enum BadEvent { + BAD_KEY, + BAD_VALUE, + KEY_ALREADY_EXISTS +}; + +class Listener; + +typedef std::set<Listener *> ListenerSet; +typedef std::map<std::string, ListenerSet > ListenMap; + +class VariableData; +typedef std::map<std::string, VariableData *> VariableMap; + +#define SERVER_NOTICE(message) { \ +Mana::Event event("ServerNotice"); \ +event.setString("message", message); \ +event.trigger("Notices", event); } + +class Event +{ +public: + /** + * Makes an event with the given name. + */ + Event(const std::string &name) + { mEventName = name; } + + ~Event(); + + /** + * Returns the name of the event. + */ + const std::string &getName() const + { return mEventName; } + +// Integers + + /** + * Sets the given variable to the given integer, if it isn't already set. + */ + void setInt(const std::string &key, int value) throw (BadEvent); + + /** + * Returns the given variable if it is set and an integer. + */ + int getInt(const std::string &key) const throw (BadEvent); + + /** + * Returns the given variable if it is set and an integer, returning the + * given default otherwise. + */ + inline int getInt(const std::string &key, int defaultValue) const + { try { return getInt(key); } catch (BadEvent) { return defaultValue; }} + + /** + * Returns true if the given variable exists and is an integer. + */ + bool hasInt(const std::string &key) const; + +// Strings + + /** + * Sets the given variable to the given string, if it isn't already set. + */ + void setString(const std::string &key, const std::string &value) throw (BadEvent); + + /** + * Returns the given variable if it is set and a string. + */ + const std::string &getString(const std::string &key) const throw (BadEvent); + + /** + * Returns the given variable if it is set and a string, returning the + * given default otherwise. + */ + inline std::string getString(const std::string &key, + const std::string &defaultValue) const + { try { return getString(key); } catch (BadEvent) { return defaultValue; }} + + /** + * Returns true if the given variable exists and is a string. + */ + bool hasString(const std::string &key) const; + +// Floats + + /** + * Sets the given variable to the given floating-point, if it isn't already + * set. + */ + void setFloat(const std::string &key, double value) throw (BadEvent); + + /** + * Returns the given variable if it is set and a floating-point. + */ + double getFloat(const std::string &key) const throw (BadEvent); + + /** + * Returns the given variable if it is set and a floating-point, returning + * the given default otherwise. + */ + inline double getFloat(const std::string &key, float defaultValue) const + { try { return getFloat(key); } catch (BadEvent) { return defaultValue; }} + + /** + * Returns true if the given variable exists and is a floating-point. + */ + bool hasFloat(const std::string &key) const; + +// Booleans + + /** + * Sets the given variable to the given boolean, if it isn't already set. + */ + void setBool(const std::string &key, bool value) throw (BadEvent); + + /** + * Returns the given variable if it is set and a boolean. + */ + bool getBool(const std::string &key) const throw (BadEvent); + + /** + * Returns the given variable if it is set and a boolean, returning the + * given default otherwise. + */ + inline bool getBool(const std::string &key, bool defaultValue) const + { try { return getBool(key); } catch (BadEvent) { return defaultValue; }} + + /** + * Returns true if the given variable exists and is a boolean. + */ + bool hasBool(const std::string &key) const; + +// Items + + /** + * Sets the given variable to the given Item, if it isn't already set. + */ + void setItem(const std::string &key, Item *value) throw (BadEvent); + + /** + * Returns the given variable if it is set and an Item. + */ + Item *getItem(const std::string &key) const throw (BadEvent); + + /** + * Returns the given variable if it is set and an Item, returning the + * given default otherwise. + */ + inline Item *getItem(const std::string &key, Item *defaultValue) const + { try { return getItem(key); } catch (BadEvent) { return defaultValue; }} + + /** + * Returns true if the given variable exists and is an Item. + */ + bool hasItem(const std::string &key) const; + +// ActorSprites + + /** + * Sets the given variable to the given actor, if it isn't already set. + */ + void setActor(const std::string &key, ActorSprite *value) throw (BadEvent); + + /** + * Returns the given variable if it is set and an actor. + */ + ActorSprite *getActor(const std::string &key) const throw (BadEvent); + + /** + * Returns the given variable if it is set and an actor, returning the + * given default otherwise. + */ + inline ActorSprite *getActor(const std::string &key, + ActorSprite *defaultValue) const + { try { return getActor(key); } catch (BadEvent) { return defaultValue; }} + + /** + * Returns true if the given variable exists and is an actor. + */ + bool hasActor(const std::string &key) const; + +// Triggers + + /** + * Sends this event to all classes listening to the given channel. + */ + inline void trigger(const std::string &channel) const + { trigger(channel, *this); } + + /** + * Sends the given event to all classes listening to the given channel. + */ + static void trigger(const std::string &channel, const Event &event); + + /** + * Sends an empty event with the given name to all classes listening to the + * given channel. + */ + static inline void trigger(const std::string& channel, + const std::string& name) + { trigger(channel, Mana::Event(name)); } + +protected: + friend class Listener; + + /** + * Binds the given listener to the given channel. The listener will receive + * all events triggered on the channel. + */ + static void bind(Listener *listener, const std::string &channel); + + /** + * Unbinds the given listener from the given channel. The listener will no + * longer receive any events from the channel. + */ + static void unbind(Listener *listener, const std::string &channel); + + /** + * Unbinds the given listener from all channels. + */ + static void remove(Listener *listener); + +private: + static ListenMap mBindings; + + std::string mEventName; + + VariableMap mData; +}; + +} // namespace Mana + +#endif 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/game.cpp b/src/game.cpp index ec5e6b13..9035ba6a 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -21,14 +21,15 @@ #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 "event.h" #include "emoteshortcut.h" -#include "flooritemmanager.h" #include "graphics.h" #include "itemshortcut.h" #include "joystick.h" @@ -36,7 +37,6 @@ #include "localplayer.h" #include "log.h" #include "map.h" -#include "npc.h" #include "particle.h" #include "playerrelations.h" #include "sound.h" @@ -115,8 +115,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,14 +129,17 @@ ChatTab *localChatTab = NULL; */ static void initEngines() { - beingManager = new BeingManager; + Mana::Event::trigger("Game", "EnginesInitalizing"); + + actorSpriteManager = new ActorSpriteManager; commandHandler = new CommandHandler; - floorItemManager = new FloorItemManager; channelManager = new ChannelManager; effectManager = new EffectManager; particleEngine = new Particle(NULL); particleEngine->setupEngine(); + + Mana::Event::trigger("Game", "EnginesInitalized"); } /** @@ -145,15 +147,17 @@ static void initEngines() */ static void createGuiWindows() { + Mana::Event::trigger("Game", "GuiWindowsLoading"); + setupWindow->clearWindowsForReset(); // Create dialogs chatWindow = new ChatWindow; tradeWindow = new TradeWindow; - equipmentWindow = new EquipmentWindow(player_node->mEquipment.get()); + equipmentWindow = new EquipmentWindow(PlayerInfo::getEquipment()); statusWindow = new StatusWindow; miniStatusWindow = new MiniStatusWindow; - inventoryWindow = new InventoryWindow(player_node->getInventory()); + inventoryWindow = new InventoryWindow(PlayerInfo::getInventory()); skillDialog = new SkillDialog; minimap = new Minimap; helpWindow = new HelpWindow; @@ -168,12 +172,9 @@ static void createGuiWindows() localChatTab = new ChatTab(_("General")); - if (config.getValue("logToChat", 0)) - { - logger->setChatWindow(chatWindow); - } + NpcDialog::setup(); - Net::getGeneralHandler()->guiWindowsLoaded(); + Mana::Event::trigger("Game", "GuiWindowsLoaded"); } #define del_0(X) { delete X; X = 0; } @@ -183,8 +184,8 @@ static void createGuiWindows() */ static void destroyGuiWindows() { - Net::getGeneralHandler()->guiWindowsUnloaded(); - logger->setChatWindow(NULL); + Mana::Event::trigger("Game", "GuiWindowsUnloading"); + del_0(localChatTab) // Need to do this first, so it can remove itself del_0(chatWindow) del_0(statusWindow) @@ -201,12 +202,16 @@ static void destroyGuiWindows() del_0(outfitWindow) del_0(specialsWindow) del_0(socialWindow) + + Mana::Event::trigger("NPC", "CloseAll"); // Cleanup remaining NPC dialogs + + Mana::Event::trigger("Game", "GuiWindowsUnloaded"); } Game *Game::mInstance = 0; Game::Game(): - mLastTarget(Being::UNKNOWN), + mLastTarget(ActorSprite::UNKNOWN), mCurrentMap(0), mMapName("") { assert(!mInstance); @@ -230,10 +235,8 @@ Game::Game(): initEngines(); - Net::getGameHandler()->inGame(); - // Initialize beings - beingManager->setPlayer(player_node); + actorSpriteManager->setPlayer(player_node); /* * To prevent the server from sending data before the client @@ -253,18 +256,21 @@ Game::Game(): joystick = new Joystick(0); setupWindow->setInGame(true); + + Mana::Event::trigger("Game", "Constructed"); } Game::~Game() { + Mana::Event::trigger("Game", "Destructing"); + delete mWindowMenu; 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) @@ -273,6 +279,8 @@ Game::~Game() del_0(mCurrentMap) mInstance = 0; + + Mana::Event::trigger("Game", "Destructed"); } static bool saveScreenshot() @@ -316,11 +324,11 @@ static bool saveScreenshot() std::stringstream chatlogentry; // TODO: Make it one complete gettext string below chatlogentry << _("Screenshot saved as ") << filenameSuffix.str(); - localChatTab->chatLog(chatlogentry.str(), BY_SERVER); + SERVER_NOTICE(chatlogentry.str()) } else { - localChatTab->chatLog(_("Saving screenshot failed!"), BY_SERVER); + SERVER_NOTICE(_("Saving screenshot failed!")) logger->log("Error: could not save screenshot."); } @@ -334,7 +342,8 @@ void Game::logic() handleInput(); // Handle all necessary game logic - beingManager->logic(); + ActorSprite::actorLogic(); + actorSpriteManager->logic(); particleEngine->update(); if (mCurrentMap) mCurrentMap->update(); @@ -392,7 +401,7 @@ void Game::handleInput() // send straight to gui for certain windows if (quitDialog || TextDialog::isActive() || - NpcPostDialog::isActive()) + PlayerInfo::getNPCPostCount() > 0) { try { @@ -449,7 +458,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 +611,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 +628,7 @@ void Game::handleInput() default: break; } - item = floorItemManager->findByCoordinates( - x, y); + item = actorSpriteManager->findItem(x, y); } if (item) @@ -698,16 +707,12 @@ void Game::handleInput() unsigned int deflt = player_relations.getDefault(); if (deflt & PlayerRelation::TRADE) { - localChatTab->chatLog( - _("Ignoring incoming trade requests"), - BY_SERVER); + SERVER_NOTICE(_("Ignoring incoming trade requests")) deflt &= ~PlayerRelation::TRADE; } else { - localChatTab->chatLog( - _("Accepting incoming trade requests"), - BY_SERVER); + SERVER_NOTICE(_("Accepting incoming trade requests")) deflt |= PlayerRelation::TRADE; } @@ -753,7 +758,7 @@ void Game::handleInput() return; // Moving player around - if (player_node->isAlive() && !NPC::isTalking() && + if (player_node->isAlive() && !PlayerInfo::isTalking() && !chatWindow->isInputFocused() && !quitDialog) { // Get the state of the keyboard keys @@ -831,8 +836,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 +849,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 +870,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 +881,8 @@ void Game::handleInput() if (target) { - if (target->getType() == Being::NPC) - static_cast<NPC*>(target)->talk(); + if (target->canTalk()) + target->talkTo(); } } @@ -892,7 +897,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 +917,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. @@ -946,7 +950,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); @@ -963,5 +967,7 @@ void Game::changeMap(const std::string &mapPath) delete mCurrentMap; mCurrentMap = newMap; - Net::getGameHandler()->mapLoaded(mapPath); + Mana::Event event("MapLoaded"); + event.setString("mapPath", mapPath); + event.trigger("Game"); } 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..cc135e07 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -21,6 +21,10 @@ #include "gui/buy.h" +#include "playerinfo.h" +#include "shopitem.h" +#include "units.h" + #include "gui/setup.h" #include "gui/widgets/button.h" @@ -31,10 +35,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" @@ -112,6 +112,8 @@ BuyDialog::BuyDialog(int npcId): instances.push_back(this); setVisible(true); + + PlayerInfo::setBuySellState(BUYSELL_BUYING); } BuyDialog::~BuyDialog() @@ -119,6 +121,9 @@ BuyDialog::~BuyDialog() delete mShopItems; instances.remove(this); + + if (PlayerInfo::getBuySellState() == BUYSELL_BUYING) + PlayerInfo::setBuySellState(BUYSELL_NONE); } void BuyDialog::setMoney(int amount) diff --git a/src/gui/buy.h b/src/gui/buy.h index 4b273bcc..c3cb3229 100644 --- a/src/gui/buy.h +++ b/src/gui/buy.h @@ -100,11 +100,6 @@ class BuyDialog : public Window, public gcn::ActionListener, void setVisible(bool visible); /** - * Returns true if any instances exist. - */ - static bool isActive() { return instances.size() > 0; } - - /** * Closes all instances. */ static void closeAll(); diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp index c6b4ef41..4419ffcc 100644 --- a/src/gui/buysell.cpp +++ b/src/gui/buysell.cpp @@ -21,7 +21,7 @@ #include "buysell.h" -#include "npc.h" +#include "playerinfo.h" #include "gui/setup.h" @@ -67,11 +67,16 @@ BuySellDialog::BuySellDialog(int npcId): instances.push_back(this); setVisible(true); + + PlayerInfo::setBuySellState(BUYSELL_CHOOSING); } BuySellDialog::~BuySellDialog() { instances.remove(this); + + if (PlayerInfo::getBuySellState() == BUYSELL_CHOOSING) + PlayerInfo::setBuySellState(BUYSELL_NONE); } void BuySellDialog::setVisible(bool visible) diff --git a/src/gui/buysell.h b/src/gui/buysell.h index cf7ec91e..3408821a 100644 --- a/src/gui/buysell.h +++ b/src/gui/buysell.h @@ -52,11 +52,6 @@ class BuySellDialog : public Window, public gcn::ActionListener void action(const gcn::ActionEvent &event); /** - * Returns true if any instances exist. - */ - static bool isActive() { return instances.size() > 0; } - - /** * Closes all instances. */ static void closeAll(); 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.cpp b/src/gui/charselectdialog.cpp index e22c4daf..9d6050f8 100644 --- a/src/gui/charselectdialog.cpp +++ b/src/gui/charselectdialog.cpp @@ -388,8 +388,10 @@ void CharacterDisplay::update() mButton->setCaption(_("Choose")); mButton->setActionEventId("use"); mName->setCaption(strprintf("%s", character->getName().c_str())); - mLevel->setCaption(strprintf("Level %d", character->getLevel())); - mMoney->setCaption(Units::formatCurrency(character->getMoney())); + mLevel->setCaption(strprintf("Level %d", + mCharacter->data.mAttributes[LEVEL])); + mMoney->setCaption(Units::formatCurrency( + mCharacter->data.mAttributes[MONEY])); mDelete->setVisible(true); } 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 f87a8a3d..b1d4b131 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -21,10 +21,11 @@ #include "chat.h" -#include "beingmanager.h" +#include "actorspritemanager.h" #include "configuration.h" #include "localplayer.h" #include "party.h" +#include "playerrelations.h" #include "gui/recorder.h" #include "gui/setup.h" @@ -77,6 +78,9 @@ ChatWindow::ChatWindow(): Window(_("Chat")), mTmpVisible(false) { + listen("Chat"); + listen("Notices"); + setWindowName("Chat"); setupWindow->registerWindowForReset(this); @@ -108,7 +112,7 @@ ChatWindow::ChatWindow(): mChatInput->addKeyListener(this); mCurHist = mHistory.end(); - mReturnToggles = config.getValue("ReturnToggles", "0") == "1"; + mReturnToggles = config.getBoolValue("ReturnToggles"); mRecorder = new Recorder(this); } @@ -281,20 +285,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; } } @@ -408,6 +412,40 @@ void ChatWindow::keyPressed(gcn::KeyEvent &event) } } +void ChatWindow::event(const std::string &channel, const Mana::Event &event) +{ + if (channel == "Notices") + { + if (event.getName() == "ServerNotice") + localChatTab->chatLog(event.getString("message"), BY_SERVER); + } + else if (channel == "Chat") + { + if (event.getName() == "Whisper") + { + whisper(event.getString("nick"), event.getString("message")); + } + else if (event.getName() == "WhisperError") + { + whisper(event.getString("nick"), + event.getString("error"), BY_SERVER); + } + else if (event.getName() == "Player") + { + localChatTab->chatLog(event.getString("message"), BY_PLAYER); + } + else if (event.getName() == "Announcement") + { + localChatTab->chatLog(event.getString("message"), BY_GM); + } + else if (event.getName() == "Being") + { + if (event.getInt("permissions") & PlayerRelation::SPEECH_LOG) + localChatTab->chatLog(event.getString("message"), BY_OTHER); + } + } +} + void ChatWindow::addInputText(const std::string &text) { const int caretPos = mChatInput->getCaretPosition(); @@ -446,7 +484,7 @@ void ChatWindow::setRecordingFile(const std::string &msg) } void ChatWindow::whisper(const std::string &nick, - const std::string &mes, bool own) + const std::string &mes, Own own) { if (mes.empty()) return; @@ -465,15 +503,19 @@ void ChatWindow::whisper(const std::string &nick, if (i != mWhispers.end()) tab = i->second; - else if (config.getValue("whispertab", true)) + else if (config.getBoolValue("whispertab")) tab = addWhisperTab(nick); if (tab) { - if (own) + if (own == BY_PLAYER) { tab->chatInput(mes); } + else if (own == BY_SERVER) + { + tab->chatLog(mes); + } else { tab->chatLog(nick, mes); @@ -482,7 +524,7 @@ void ChatWindow::whisper(const std::string &nick, } else { - if (own) + if (own == BY_PLAYER) { Net::getChatHandler()->privateMessage(nick, mes); @@ -546,7 +588,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/chat.h b/src/gui/chat.h index e49d02c9..db5fe293 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -22,6 +22,8 @@ #ifndef CHAT_H #define CHAT_H +#include "listener.h" + #include "gui/widgets/window.h" #include <guichan/actionlistener.hpp> @@ -35,8 +37,8 @@ #include <vector> class BrowserBox; -class Channel; class ChatTab; +class Channel; class ChatInput; class Recorder; class ScrollArea; @@ -47,12 +49,24 @@ class WhisperTab; #define DEFAULT_CHAT_WINDOW_SCROLL 7 // 1 means `1/8th of the window size'. +enum Own +{ + BY_GM, + BY_PLAYER, + BY_OTHER, + BY_SERVER, + BY_CHANNEL, + ACT_WHISPER, // getting whispered at + ACT_IS, // equivalent to "/me" on IRC + BY_LOGGER +}; + /** One item in the chat log */ struct CHATLOG { std::string nick; std::string text; - int own; + Own own; }; /** @@ -62,7 +76,8 @@ struct CHATLOG */ class ChatWindow : public Window, public gcn::ActionListener, - public gcn::KeyListener + public gcn::KeyListener, + public Mana::Listener { public: /** @@ -147,6 +162,7 @@ class ChatWindow : public Window, void mousePressed(gcn::MouseEvent &event); void mouseDragged(gcn::MouseEvent &event); + void event(const std::string &channel, const Mana::Event &event); /** * Scrolls the chat window @@ -170,7 +186,7 @@ class ChatWindow : public Window, void doPresent(); void whisper(const std::string &nick, const std::string &mes, - bool own = false); + Own own = BY_OTHER); ChatTab *addWhisperTab(const std::string &nick, bool switchTo = false); diff --git a/src/gui/emotepopup.cpp b/src/gui/emotepopup.cpp index 7c05e263..f9dc8e0f 100644 --- a/src/gui/emotepopup.cpp +++ b/src/gui/emotepopup.cpp @@ -29,11 +29,10 @@ #include "localplayer.h" #include "log.h" -#include "gui/theme.h" - #include "resources/emotedb.h" #include "resources/image.h" #include "resources/iteminfo.h" +#include "resources/theme.h" #include "utils/dtor.h" @@ -61,7 +60,7 @@ EmotePopup::EmotePopup(): if (!mSelectionImage) logger->error("Unable to load selection.png"); - mSelectionImage->setAlpha(config.getValue("guialpha", 0.8)); + mSelectionImage->setAlpha(config.getFloatValue("guialpha")); addMouseListener(this); recalculateSize(); diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index 43e330f4..474a9cb6 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -29,7 +29,6 @@ #include "gui/equipmentwindow.h" #include "gui/itempopup.h" -#include "gui/theme.h" #include "gui/setup.h" #include "gui/viewport.h" @@ -41,6 +40,7 @@ #include "resources/image.h" #include "resources/iteminfo.h" #include "resources/resourcemanager.h" +#include "resources/theme.h" #include "utils/gettext.h" #include "utils/stringutils.h" @@ -158,7 +158,7 @@ void EquipmentWindow::action(const gcn::ActionEvent &event) if (event.getId() == "unequip" && mSelected > -1) { Item *item = mEquipment->getEquipment(mSelected); - Net::getInventoryHandler()->unequipItem(item); + item->doEvent("doUnequip"); setSelected(-1); } } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index df2ddadf..f8dc3e82 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -24,7 +24,6 @@ #include "gui/focushandler.h" #include "gui/palette.h" #include "gui/sdlinput.h" -#include "gui/theme.h" #include "gui/truetypefont.h" #include "gui/widgets/window.h" @@ -39,6 +38,7 @@ #include "resources/imageset.h" #include "resources/imageloader.h" #include "resources/resourcemanager.h" +#include "resources/theme.h" #include <guichan/exception.hpp> #include <guichan/image.hpp> @@ -61,7 +61,7 @@ class GuiConfigListener : public ConfigListener { if (name == "customcursor") { - bool bCustomCursor = config.getValue("customcursor", 1) == 1; + bool bCustomCursor = config.getBoolValue("customcursor"); mGui->setUseCustomCursor(bCustomCursor); } } @@ -104,7 +104,7 @@ Gui::Gui(Graphics *graphics): ResourceManager *resman = ResourceManager::getInstance(); // Set global font - const int fontSize = (int) config.getValue("fontSize", 11); + const int fontSize = config.getValue("fontSize", 11); std::string fontFile = branding.getValue("font", "fonts/dejavusans.ttf"); std::string path = resman->getPath(fontFile); @@ -135,7 +135,7 @@ Gui::Gui(Graphics *graphics): gcn::Widget::setGlobalFont(mGuiFont); // Initialize mouse cursor and listen for changes to the option - setUseCustomCursor(config.getValue("customcursor", 1) == 1); + setUseCustomCursor(config.getBoolValue("customcursor")); mConfigListener = new GuiConfigListener(this); config.addListener("customcursor", mConfigListener); } diff --git a/src/gui/help.cpp b/src/gui/help.cpp index f3c6a0af..aca036c1 100644 --- a/src/gui/help.cpp +++ b/src/gui/help.cpp @@ -94,9 +94,9 @@ void HelpWindow::loadHelp(const std::string &helpFile) void HelpWindow::loadFile(const std::string &file) { ResourceManager *resman = ResourceManager::getInstance(); - std::string helpPath = branding.getValue("helpPath", ""); + std::string helpPath = branding.getStringValue("helpPath"); if (helpPath.empty()) - helpPath = paths.getValue("help", "help/"); + helpPath = paths.getStringValue("help"); std::vector<std::string> lines = resman->loadTextFile(helpPath + file + ".txt"); diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index 591ebd2f..5df1d4ba 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -23,14 +23,13 @@ #include "inventory.h" #include "item.h" -#include "localplayer.h" #include "units.h" #include "keyboardconfig.h" +#include "playerinfo.h" #include "gui/itemamount.h" #include "gui/setup.h" #include "gui/sdlinput.h" -#include "gui/theme.h" #include "gui/viewport.h" #include "gui/widgets/button.h" @@ -44,6 +43,7 @@ #include "net/net.h" #include "resources/iteminfo.h" +#include "resources/theme.h" #include "utils/gettext.h" #include "utils/stringutils.h" @@ -60,6 +60,8 @@ InventoryWindow::InventoryWindow(Inventory *inventory): mInventory(inventory), mSplit(false) { + listen("Attributes"); + setWindowName(isMainInventory() ? "Inventory" : "Storage"); setupWindow->registerWindowForReset(this); setResizable(true); @@ -138,13 +140,19 @@ InventoryWindow::InventoryWindow(Inventory *inventory): slotsChanged(mInventory); if (!isMainInventory()) + { setVisible(true); + PlayerInfo::setStorageCount(PlayerInfo::getStorageCount() + 1); + } } InventoryWindow::~InventoryWindow() { instances.remove(this); mInventory->removeInventoyListener(this); + + if (!isMainInventory()) + PlayerInfo::setStorageCount(PlayerInfo::getStorageCount() - 1); } void InventoryWindow::action(const gcn::ActionEvent &event) @@ -180,12 +188,12 @@ void InventoryWindow::action(const gcn::ActionEvent &event) if (item->isEquipment()) { if (item->isEquipped()) - Net::getInventoryHandler()->unequipItem(item); + item->doEvent("doUnequip"); else - Net::getInventoryHandler()->equipItem(item); + item->doEvent("doEquip"); } else - Net::getInventoryHandler()->useItem(item); + item->doEvent("doUse"); } else if (event.getId() == "drop") { @@ -234,20 +242,30 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event) if (event.getButton() == gcn::MouseEvent::LEFT) { - if (isStorageActive() && keyboard.isKeyActive(keyboard.KEY_EMOTE)) + if (instances.size() > 1 && keyboard.isKeyActive(keyboard.KEY_EMOTE)) { Item *item = mItems->getSelectedItem(); if(!item) return; if (mInventory->isMainInventory()) - Net::getInventoryHandler()->moveItem(Inventory::INVENTORY, - item->getInvIndex(), item->getQuantity(), - Inventory::STORAGE); + { + Mana::Event event("doMove"); + event.setItem("item", item); + event.setInt("amount", item->getQuantity()); + event.setInt("source", Inventory::INVENTORY); + event.setInt("destination", Inventory::STORAGE); + event.trigger("Item"); + } else - Net::getInventoryHandler()->moveItem(Inventory::STORAGE, - item->getInvIndex(), item->getQuantity(), - Inventory::INVENTORY); + { + Mana::Event event("doMove"); + event.setItem("item", item); + event.setInt("amount", item->getQuantity()); + event.setInt("source", Inventory::STORAGE); + event.setInt("destination", Inventory::INVENTORY); + event.trigger("Item"); + } } } } @@ -336,15 +354,36 @@ void InventoryWindow::close() } else { - Net::getInventoryHandler()->closeStorage(Inventory::STORAGE); + Mana::Event event("doCloseInventory"); + event.setInt("type", mInventory->getType()); + event.trigger("Item"); scheduleDelete(); } } +void InventoryWindow::event(const std::string &channel, const Mana::Event &event) +{ + if (event.getName() == "UpdateAttribute") + { + int id = event.getInt("id"); + if (id == TOTAL_WEIGHT || + id == MAX_WEIGHT) + { + updateWeight(); + } + } +} + void InventoryWindow::updateWeight() { - int total = player_node->getTotalWeight(); - int max = player_node->getMaxWeight(); + if (!isMainInventory()) + return; + + int total = PlayerInfo::getAttribute(TOTAL_WEIGHT); + int max = PlayerInfo::getAttribute(MAX_WEIGHT); + + if (max <= 0) + return; // Adjust progress bar mWeightBar->setProgress((float) total / max); diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index f611e934..af72106b 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -23,6 +23,7 @@ #define INVENTORYWINDOW_H #include "inventory.h" +#include "listener.h" #include "gui/widgets/window.h" @@ -47,7 +48,8 @@ class InventoryWindow : public Window, public gcn::ActionListener, public gcn::KeyListener, public gcn::SelectionListener, - public InventoryListener + public InventoryListener, + public Mana::Listener { public: /** @@ -100,22 +102,20 @@ class InventoryWindow : public Window, * window has been closed. */ void close(); - - /** - * Updates the weight bar. - */ - void updateWeight(); void slotsChanged(Inventory* inventory); bool isMainInventory() { return mInventory->isMainInventory(); } + void event(const std::string &channel, const Mana::Event &event); + + private: /** - * Returns true if any instances exist. + * Updates the weight bar. */ - static bool isStorageActive() { return instances.size() > 1; } + void updateWeight(); + - private: typedef std::list<InventoryWindow*> WindowList; static WindowList instances; diff --git a/src/gui/itemamount.cpp b/src/gui/itemamount.cpp index a98a67ab..aed8d11d 100644 --- a/src/gui/itemamount.cpp +++ b/src/gui/itemamount.cpp @@ -47,20 +47,30 @@ void ItemAmountWindow::finish(Item *item, int amount, Usage usage) tradeWindow->tradeItem(item, amount); break; case ItemDrop: - Net::getInventoryHandler()->dropItem(item, amount); + item->doEvent("doDrop", amount); break; case ItemSplit: - Net::getInventoryHandler()->splitItem(item, amount); + item->doEvent("doSplit", amount); break; case StoreAdd: - Net::getInventoryHandler()->moveItem(Inventory::INVENTORY, - item->getInvIndex(), amount, - Inventory::STORAGE); + { + Mana::Event event("doMove"); + event.setItem("item", item); + event.setInt("amount", amount); + event.setInt("source", Inventory::INVENTORY); + event.setInt("destination", Inventory::STORAGE); + event.trigger("Item"); + } break; case StoreRemove: - Net::getInventoryHandler()->moveItem(Inventory::STORAGE, - item->getInvIndex(), amount, - Inventory::INVENTORY); + { + Mana::Event event("doMove"); + event.setItem("item", item); + event.setInt("amount", amount); + event.setInt("source", Inventory::STORAGE); + event.setInt("destination", Inventory::INVENTORY); + event.trigger("Item"); + } break; default: break; diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp index 0cde9395..c926670a 100644 --- a/src/gui/itempopup.cpp +++ b/src/gui/itempopup.cpp @@ -26,9 +26,9 @@ #include "units.h" #include "gui/gui.h" -#include "gui/theme.h" #include "gui/widgets/icon.h" +#include "gui/widgets/label.h" #include "gui/widgets/textbox.h" #include "utils/gettext.h" @@ -36,6 +36,7 @@ #include "resources/image.h" #include "resources/resourcemanager.h" +#include "resources/theme.h" #include <guichan/font.hpp> @@ -46,7 +47,7 @@ ItemPopup::ItemPopup(): mIcon(0) { // Item Name - mItemName = new gcn::Label; + mItemName = new Label; mItemName->setFont(boldFont); mItemName->setPosition(getPadding(), getPadding()); @@ -103,8 +104,9 @@ void ItemPopup::setItem(const ItemInfo &item, bool showImage) { ResourceManager *resman = ResourceManager::getInstance(); Image *image = resman->getImage( - paths.getValue("itemIcons", "graphics/items/") - + item.getImageName()); + paths.getStringValue("itemIcons") + + item.getDisplay().image); + mIcon->setImage(image); if (image) { diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp index 35844f64..dd447f95 100644 --- a/src/gui/minimap.cpp +++ b/src/gui/minimap.cpp @@ -21,20 +21,19 @@ #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" #include "resources/image.h" #include "resources/resourcemanager.h" +#include "resources/userpalette.h" #include "utils/gettext.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..1642d1b0 100644 --- a/src/gui/ministatus.cpp +++ b/src/gui/ministatus.cpp @@ -24,17 +24,20 @@ #include "animatedsprite.h" #include "configuration.h" #include "graphics.h" -#include "localplayer.h" +#include "playerinfo.h" +#include "statuseffect.h" #include "gui/gui.h" #include "gui/statuswindow.h" #include "gui/textpopup.h" -#include "gui/theme.h" #include "gui/widgets/progressbar.h" #include "net/net.h" #include "net/playerhandler.h" +#include "net/gamehandler.h" + +#include "resources/theme.h" #include "utils/gettext.h" #include "utils/stringutils.h" @@ -44,22 +47,36 @@ extern volatile int tick_time; MiniStatusWindow::MiniStatusWindow(): Popup("MiniStatus") { - 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, - 100, 20, Net::getPlayerHandler()->canUseMagic() ? - Theme::PROG_MP : Theme::PROG_NO_MP); - max = player_node->getExpNeeded(); - mXpBar = new ProgressBar(max ? (float) player_node->getExp() / max : 0, - 100, 20, Theme::PROG_EXP); + listen("Attributes"); + + mHpBar = new ProgressBar(0, 100, 20, Theme::PROG_HP); + StatusWindow::updateHPBar(mHpBar); + + if (Net::getGameHandler()->canUseMagicBar()) + { + mMpBar = new ProgressBar(0, 100, 20, + Net::getPlayerHandler()->canUseMagic() + ? Theme::PROG_MP : Theme::PROG_NO_MP); + + StatusWindow::updateMPBar(mMpBar); + } + else + mMpBar = 0; + + mXpBar = new ProgressBar(0, 100, 20, Theme::PROG_EXP); + StatusWindow::updateXPBar(mXpBar); + + // Add the progressbars to the window + 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(), @@ -70,8 +87,6 @@ MiniStatusWindow::MiniStatusWindow(): mTextPopup = new TextPopup(); addMouseListener(this); - - update(StatusWindow::HP); } void MiniStatusWindow::setIcon(int index, AnimatedSprite *sprite) @@ -104,19 +119,82 @@ void MiniStatusWindow::drawIcons(Graphics *graphics) } } -void MiniStatusWindow::update(int id) +void MiniStatusWindow::event(const std::string &channel, const Mana::Event &event) { - if (id == StatusWindow::HP) - { - StatusWindow::updateHPBar(mHpBar); - } - else if (id == StatusWindow::MP) + if (channel == "Attributes") { - StatusWindow::updateMPBar(mMpBar); + if (event.getName() == "UpdateAttribute") + { + int id = event.getInt("id"); + if (id == HP || id == MAX_HP) + { + StatusWindow::updateHPBar(mHpBar); + } + else if (id == MP || id == MAX_MP) + { + StatusWindow::updateMPBar(mMpBar); + } + else if (id == EXP || id == EXP_NEEDED) + { + StatusWindow::updateXPBar(mXpBar); + } + } } - else if (id == StatusWindow::EXP) + else if (channel == "ActorSprite") { - StatusWindow::updateXPBar(mXpBar); + if (event.getName() == "UpdateStatusEffect") + { + int index = event.getInt("index"); + bool newStatus = event.getBool("newStatus"); + + StatusEffect *effect = StatusEffect::getStatusEffect(index, + newStatus); + + if (effect) + { + effect->deliverMessage(); + effect->playSFX(); + + AnimatedSprite *sprite = effect->getIcon(); + + typedef std::vector<int> IntMap; + + if (!sprite) + { + // delete sprite, if necessary + for (unsigned int i = 0; i < mStatusEffectIcons.size();) + if (mStatusEffectIcons[i] == index) + { + mStatusEffectIcons.erase(mStatusEffectIcons.begin() + + i); + miniStatusWindow->eraseIcon(i); + } + else + i++; + } + else + { + // replace sprite or append + bool found = false; + + for (unsigned int i = 0; i < mStatusEffectIcons.size(); + i++) + if (mStatusEffectIcons[i] == index) + { + miniStatusWindow->setIcon(i, sprite); + found = true; + break; + } + + if (!found) + { // add new + int offset = mStatusEffectIcons.size(); + miniStatusWindow->setIcon(offset, sprite); + mStatusEffectIcons.push_back(index); + } + } + } + } } } @@ -152,23 +230,23 @@ void MiniStatusWindow::mouseMoved(gcn::MouseEvent &event) if (event.getSource() == mXpBar) { mTextPopup->show(x + getX(), y + getY(), - strprintf("%u/%u", player_node->getExp(), - player_node->getExpNeeded()), + strprintf("%u/%u", PlayerInfo::getAttribute(EXP), + PlayerInfo::getAttribute(EXP_NEEDED)), strprintf("%s: %u", _("Need"), - player_node->getExpNeeded() - - player_node->getExp())); + PlayerInfo::getAttribute(EXP_NEEDED) + - PlayerInfo::getAttribute(EXP))); } else if (event.getSource() == mHpBar) { mTextPopup->show(x + getX(), y + getY(), - strprintf("%u/%u", player_node->getHp(), - player_node->getMaxHp())); + strprintf("%u/%u", PlayerInfo::getAttribute(HP), + PlayerInfo::getAttribute(MAX_HP))); } else if (event.getSource() == mMpBar) { mTextPopup->show(x + getX(), y + getY(), - strprintf("%u/%u", player_node->getMP(), - player_node->getMaxMP())); + strprintf("%u/%u", PlayerInfo::getAttribute(MP), + PlayerInfo::getAttribute(MAX_MP))); } else { @@ -182,5 +260,3 @@ void MiniStatusWindow::mouseExited(gcn::MouseEvent &event) mTextPopup->setVisible(false); } - - diff --git a/src/gui/ministatus.h b/src/gui/ministatus.h index bb8d4094..077eedeb 100644 --- a/src/gui/ministatus.h +++ b/src/gui/ministatus.h @@ -22,6 +22,8 @@ #ifndef MINISTATUS_H #define MINISTATUS_H +#include "listener.h" + #include "gui/widgets/popup.h" #include <vector> @@ -36,21 +38,14 @@ class TextPopup; * * \ingroup Interface */ -class MiniStatusWindow : public Popup +class MiniStatusWindow : public Popup, public Mana::Listener { public: MiniStatusWindow(); - /** - * Sets one of the icons. - */ - void setIcon(int index, AnimatedSprite *sprite); - - void eraseIcon(int index); - void drawIcons(Graphics *graphics); - void update(int id); // Same types as status window + void event(const std::string &channel, const Mana::Event &event); void logic(); // Updates icons @@ -63,6 +58,13 @@ class MiniStatusWindow : public Popup private: bool isInBar(ProgressBar *bar, int x, int y) const; + /** + * Sets one of the icons. + */ + void setIcon(int index, AnimatedSprite *sprite); + + void eraseIcon(int index); + /* * Mini Status Bars */ @@ -71,6 +73,7 @@ class MiniStatusWindow : public Popup ProgressBar *mXpBar; TextPopup *mTextPopup; + std::vector<int> mStatusEffectIcons; std::vector<AnimatedSprite *> mIcons; }; diff --git a/src/gui/npcdialog.cpp b/src/gui/npcdialog.cpp index 6d3995a7..935962a0 100644 --- a/src/gui/npcdialog.cpp +++ b/src/gui/npcdialog.cpp @@ -22,8 +22,11 @@ #include "gui/npcdialog.h" #include "configuration.h" -#include "npc.h" +#include "event.h" +#include "listener.h" +#include "playerinfo.h" +#include "gui/npcpostdialog.h" #include "gui/setup.h" #include "gui/widgets/button.h" @@ -34,9 +37,6 @@ #include "gui/widgets/textbox.h" #include "gui/widgets/textfield.h" -#include "net/net.h" -#include "net/npchandler.h" - #include "utils/gettext.h" #include "utils/stringutils.h" @@ -47,12 +47,32 @@ #define CAPTION_CLOSE _("Close") #define CAPTION_SUBMIT _("Submit") +#define NpcEvent(name) Mana::Event event(name);\ +event.setInt("npcId", mNpcId); + +typedef std::map<int, NpcDialog*> NpcDialogs; + +class NpcEventListener : public Mana::Listener +{ +public: + void event(const std::string &channel, const Mana::Event &event); + + NpcDialog *getDialog(int id, bool make = true); + + void removeDialog(int id); + +private: + NpcDialogs mNpcDialogs; +}; + +static NpcEventListener *npcListener = NULL; + NpcDialog::DialogList NpcDialog::instances; NpcDialog::NpcDialog(int npcId) : Window(_("NPC")), mNpcId(npcId), - mLogInteraction(config.getValue("logNpcInGui", true)), + mLogInteraction(config.getBoolValue("logNpcInGui")), mDefaultInt(0), mInputState(NPC_INPUT_NONE), mActionState(NPC_ACTION_WAIT) @@ -124,6 +144,8 @@ NpcDialog::NpcDialog(int npcId) requestFocus(); config.addListener("logNpcInGui", this); + PlayerInfo::setNPCInteractionCount(PlayerInfo::getNPCInteractionCount() + + 1); } NpcDialog::~NpcDialog() @@ -140,6 +162,10 @@ NpcDialog::~NpcDialog() instances.remove(this); config.removeListener("logNpcInGui", this); + PlayerInfo::setNPCInteractionCount(PlayerInfo::getNPCInteractionCount() + - 1); + + npcListener->removeDialog(mNpcId); } void NpcDialog::setText(const std::string &text) @@ -192,27 +218,32 @@ void NpcDialog::action(const gcn::ActionEvent &event) if (mInputState == NPC_INPUT_LIST) { - int choice = 0; int selectedIndex = mItemList->getSelected(); if (selectedIndex >= (int) mItems.size() || selectedIndex < 0) - { return; - } - choice = selectedIndex + 1; + printText = mItems[selectedIndex]; - Net::getNpcHandler()->listInput(mNpcId, choice); + NpcEvent("doMenu") + event.setInt("choice", selectedIndex + 1); + event.trigger("NPC"); } else if (mInputState == NPC_INPUT_STRING) { printText = mTextField->getText(); - Net::getNpcHandler()->stringInput(mNpcId, printText); + + NpcEvent("doStringInput") + event.setString("value", printText); + event.trigger("NPC"); } else if (mInputState == NPC_INPUT_INTEGER) { printText = strprintf("%d", mIntField->getValue()); - Net::getNpcHandler()->integerInput(mNpcId, mIntField->getValue()); + + NpcEvent("doIntegerInput") + event.setInt("value", mIntField->getValue()); + event.trigger("NPC"); } // addText will auto remove the input layout addText(strprintf("\n> \"%s\"\n", printText.c_str()), false); @@ -250,12 +281,15 @@ void NpcDialog::action(const gcn::ActionEvent &event) void NpcDialog::nextDialog() { - Net::getNpcHandler()->nextDialog(mNpcId); + NpcEvent("doNext"); + event.trigger("NPC"); } void NpcDialog::closeDialog() { - Net::getNpcHandler()->closeDialog(mNpcId); + NpcEvent("doClose"); + event.trigger("NPC"); + close(); } int NpcDialog::getNumberOfElements() @@ -281,15 +315,6 @@ void NpcDialog::addChoice(const std::string &choice) mItems.push_back(choice); } -void NpcDialog::parseListItems(const std::string &itemString) -{ - std::istringstream iss(itemString); - - std::string tmp; - while (getline(iss, tmp, ':')) - mItems.push_back(tmp); -} - void NpcDialog::textRequest(const std::string &defaultText) { mActionState = NPC_ACTION_INPUT; @@ -370,7 +395,7 @@ void NpcDialog::optionChanged(const std::string &name) { if (name == "logNpcInGui") { - mLogInteraction = config.getValue("logNpcInGui", true); + mLogInteraction = config.getBoolValue("logNpcInGui"); } } @@ -404,6 +429,16 @@ void NpcDialog::closeAll() } } +void NpcDialog::setup() +{ + if (npcListener) + return; + + npcListener = new NpcEventListener(); + + npcListener->listen("NPC"); +} + void NpcDialog::buildLayout() { clearLayout(); @@ -470,3 +505,125 @@ void NpcDialog::buildLayout() mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); } + +void NpcEventListener::event(const std::string &channel, + const Mana::Event &event) +{ + if (channel != "NPC") + return; + + if (event.getName() == "Message") + { + NpcDialog *dialog = getDialog(event.getInt("id")); + + dialog->addText(event.getString("text")); + } + else if (event.getName() == "Menu") + { + NpcDialog *dialog = getDialog(event.getInt("id")); + + dialog->choiceRequest(); + + int count = event.getInt("choiceCount"); + for (int i = 1; i <= count; i++) + dialog->addChoice(event.getString("choice" + toString(i))); + } + else if (event.getName() == "IntegerInput") + { + NpcDialog *dialog = getDialog(event.getInt("id")); + + int defaultValue = event.getInt("default", 0); + int min = event.getInt("min", 0); + int max = event.getInt("max", 2147483647); + + dialog->integerRequest(defaultValue, min, max); + } + else if (event.getName() == "StringInput") + { + NpcDialog *dialog = getDialog(event.getInt("id")); + + try + { + dialog->textRequest(event.getString("default")); + } + catch (Mana::BadEvent) + { + dialog->textRequest(""); + } + } + else if (event.getName() == "Next") + { + int id = event.getInt("id"); + NpcDialog *dialog = getDialog(id, false); + + if (!dialog) + { + int mNpcId = id; + NpcEvent("doNext"); + event.trigger("NPC"); + return; + } + + dialog->showNextButton(); + } + else if (event.getName() == "Close") + { + int id = event.getInt("id"); + NpcDialog *dialog = getDialog(id, false); + + if (!dialog) + { + int mNpcId = id; + NpcEvent("doClose"); + event.trigger("NPC"); + return; + } + + dialog->showCloseButton(); + } + else if (event.getName() == "CloseAll") + { + NpcDialog::closeAll(); + } + else if (event.getName() == "End") + { + int id = event.getInt("id"); + NpcDialog *dialog = getDialog(id, false); + + if (dialog) + dialog->close(); + } + else if (event.getName() == "Post") + { + new NpcPostDialog(event.getInt("id")); + } +} + +NpcDialog *NpcEventListener::getDialog(int id, bool make) +{ + NpcDialogs::iterator diag = mNpcDialogs.find(id); + NpcDialog *dialog = 0; + + if (diag == mNpcDialogs.end()) + { + // Empty dialogs don't help + if (make) + { + dialog = new NpcDialog(id); + mNpcDialogs[id] = dialog; + } + } + else + { + dialog = diag->second; + } + + return dialog; +} + +void NpcEventListener::removeDialog(int id) +{ + NpcDialogs::iterator it = mNpcDialogs.find(id); + if (it != mNpcDialogs.end()) + mNpcDialogs.erase(it); +} diff --git a/src/gui/npcdialog.h b/src/gui/npcdialog.h index a8521ce9..5850ecca 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" @@ -120,13 +119,6 @@ class NpcDialog : public Window, public gcn::ActionListener, void addChoice(const std::string &); /** - * Fills the options list for an NPC dialog. - * - * @param itemString A string with the options separated with colons. - */ - void parseListItems(const std::string &itemString); - - /** * Requests a text string from the user. */ void textRequest(const std::string &defaultText = ""); @@ -138,8 +130,7 @@ class NpcDialog : public Window, public gcn::ActionListener, /** * Requests a interger from the user. */ - void integerRequest(int defaultValue = 0, int min = 0, - int max = 2147483647); + void integerRequest(int defaultValue, int min, int max); void move(int amount); @@ -155,11 +146,6 @@ class NpcDialog : public Window, public gcn::ActionListener, void optionChanged(const std::string &name); /** - * Returns true if any instances exist. - */ - static bool isActive() { return instances.size() > 0; } - - /** * Returns the first active instance. Useful for pushing user * interaction. */ @@ -170,6 +156,8 @@ class NpcDialog : public Window, public gcn::ActionListener, */ static void closeAll(); + static void setup(); + private: typedef std::list<NpcDialog*> DialogList; static DialogList instances; diff --git a/src/gui/npcpostdialog.cpp b/src/gui/npcpostdialog.cpp index 19d0cf61..0662515e 100644 --- a/src/gui/npcpostdialog.cpp +++ b/src/gui/npcpostdialog.cpp @@ -21,18 +21,15 @@ #include "gui/npcpostdialog.h" -#include "npc.h" +#include "event.h" +#include "playerinfo.h" #include "gui/widgets/button.h" -#include "gui/widgets/chattab.h" #include "gui/widgets/label.h" #include "gui/widgets/textbox.h" #include "gui/widgets/textfield.h" #include "gui/widgets/scrollarea.h" -#include "net/net.h" -#include "net/npchandler.h" - #include "utils/gettext.h" NpcPostDialog::DialogList NpcPostDialog::instances; @@ -80,11 +77,14 @@ NpcPostDialog::NpcPostDialog(int npcId): instances.push_back(this); setVisible(true); + + PlayerInfo::setNPCPostCount(PlayerInfo::getNPCPostCount() + 1); } NpcPostDialog::~NpcPostDialog() { instances.remove(this); + PlayerInfo::setNPCPostCount(PlayerInfo::getNPCPostCount() - 1); } void NpcPostDialog::action(const gcn::ActionEvent &event) @@ -93,13 +93,15 @@ void NpcPostDialog::action(const gcn::ActionEvent &event) { if (mSender->getText().empty() || mText->getText().empty()) { - localChatTab->chatLog(_("Failed to send as sender or letter " - "invalid.")); + SERVER_NOTICE(_("Failed to send as sender or letter invalid.")) } else { - Net::getNpcHandler()->sendLetter(mNpcId, mSender->getText(), - mText->getText()); + Mana::Event event("doSendLetter"); + event.setInt("npcId", mNpcId); + event.setString("recipient", mSender->getText()); + event.setString("text", mText->getText()); + event.trigger("NPC"); } setVisible(false); } diff --git a/src/gui/npcpostdialog.h b/src/gui/npcpostdialog.h index ad0053a3..248e4515 100644 --- a/src/gui/npcpostdialog.h +++ b/src/gui/npcpostdialog.h @@ -47,11 +47,6 @@ public: void setVisible(bool visible); /** - * Returns true if any instances exist. - */ - static bool isActive() { return instances.size() > 0; } - - /** * Closes all instances. */ static void closeAll(); diff --git a/src/gui/outfitwindow.cpp b/src/gui/outfitwindow.cpp index 89bf47da..f16ebd39 100644 --- a/src/gui/outfitwindow.cpp +++ b/src/gui/outfitwindow.cpp @@ -22,18 +22,17 @@ #include "outfitwindow.h" #include "configuration.h" -#include "localplayer.h" +#include "equipment.h" #include "graphics.h" #include "inventory.h" -#include "equipment.h" #include "item.h" #include "log.h" +#include "playerinfo.h" #include "gui/chat.h" #include "gui/widgets/button.h" #include "gui/widgets/checkbox.h" -#include "gui/widgets/chattab.h" #include "gui/widgets/label.h" #include "gui/widgets/layout.h" @@ -168,11 +167,11 @@ void OutfitWindow::wearOutfit(int outfit) Item *item; for (int i = 0; i < OUTFIT_ITEM_COUNT; i++) { - item = player_node->getInventory()->findItem(mItems[outfit][i]); + item = PlayerInfo::getInventory()->findItem(mItems[outfit][i]); if (item && !item->isEquipped() && item->getQuantity()) { if (item->isEquipment()) - Net::getInventoryHandler()->equipItem(item); + item->doEvent("doEquip"); } } } @@ -206,7 +205,7 @@ void OutfitWindow::draw(gcn::Graphics *graphics) } Item *item = - player_node->getInventory()->findItem(mItems[mCurrentOutfit][i]); + PlayerInfo::getInventory()->findItem(mItems[mCurrentOutfit][i]); if (item) { // Draw item icon. @@ -245,7 +244,7 @@ void OutfitWindow::mouseDragged(gcn::MouseEvent &event) const int itemId = mItems[mCurrentOutfit][index]; if (itemId < 0) return; - Item *item = player_node->getInventory()->findItem(itemId); + Item *item = PlayerInfo::getInventory()->findItem(itemId); if (item) { mItemMoved = item; @@ -319,7 +318,7 @@ int OutfitWindow::getIndexFromGrid(int pointX, int pointY) const void OutfitWindow::unequipNotInOutfit(int outfit) { - Inventory *inventory = player_node->getInventory(); + Inventory *inventory = PlayerInfo::getInventory(); if (!inventory) return; @@ -338,7 +337,10 @@ void OutfitWindow::unequipNotInOutfit(int outfit) } if (!found) { - Net::getInventoryHandler()->unequipItem(inventory->getItem(i)); + Item *item = inventory->getItem(i); + + if (item) + item->doEvent("doUnequip"); } } } diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index 520b4005..41ecafc9 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -21,14 +21,14 @@ #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 "playerinfo.h" #include "playerrelations.h" #include "gui/chat.h" @@ -76,7 +76,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 +145,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 +153,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 +182,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 +200,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 +224,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); } @@ -271,19 +277,20 @@ void PopupMenu::handleLink(const std::string &link) if (mItem->isEquipment()) { if (mItem->isEquipped()) - Net::getInventoryHandler()->unequipItem(mItem); + mItem->doEvent("doUnequip"); else - Net::getInventoryHandler()->equipItem(mItem); + mItem->doEvent("doEquip"); } else - { - Net::getInventoryHandler()->useItem(mItem); - } + mItem->doEvent("doUse"); } 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 +317,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 +331,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()); } @@ -372,7 +380,7 @@ void PopupMenu::showPopup(Window *parent, int x, int y, Item *item, mBrowserBox->addRow(strprintf("@@split|%s@@", _("Split"))); } - if (InventoryWindow::isStorageActive()) + if (PlayerInfo::getStorageCount() > 0) { mBrowserBox->addRow(strprintf("@@store|%s@@", _("Store"))); } diff --git a/src/gui/recorder.cpp b/src/gui/recorder.cpp index 257afd7f..2345369e 100644 --- a/src/gui/recorder.cpp +++ b/src/gui/recorder.cpp @@ -21,11 +21,11 @@ #include "gui/recorder.h" #include "client.h" +#include "event.h" #include "gui/chat.h" #include "gui/widgets/button.h" -#include "gui/widgets/chattab.h" #include "gui/widgets/layout.h" #include "gui/widgets/windowcontainer.h" @@ -84,16 +84,16 @@ void Recorder::setRecordingFile(const std::string &msg) * Message should go after mStream is closed so that it isn't * recorded. */ - localChatTab->chatLog(_("Finishing recording."), BY_SERVER); + SERVER_NOTICE(_("Finishing recording.")) } else { - localChatTab->chatLog(_("Not currently recording."), BY_SERVER); + SERVER_NOTICE(_("Not currently recording.")) } } else if (mStream.is_open()) { - localChatTab->chatLog(_("Already recording."), BY_SERVER); + SERVER_NOTICE(_("Already recording.")) } else { @@ -101,7 +101,7 @@ void Recorder::setRecordingFile(const std::string &msg) * Message should go before mStream is opened so that it isn't * recorded. */ - localChatTab->chatLog(_("Starting to record..."), BY_SERVER); + SERVER_NOTICE(_("Starting to record...")) const std::string file = Client::getLocalDataDirectory() + "/" + msgCopy; mStream.open(file.c_str(), std::ios_base::trunc); @@ -109,7 +109,7 @@ void Recorder::setRecordingFile(const std::string &msg) if (mStream.is_open()) setVisible(true); else - localChatTab->chatLog(_("Failed to start recording."), BY_SERVER); + SERVER_NOTICE(_("Failed to start recording.")) } } 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..83f01d7f 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -21,7 +21,7 @@ #include "gui/sell.h" -#include "npc.h" +#include "playerinfo.h" #include "shopitem.h" #include "units.h" @@ -111,6 +111,8 @@ SellDialog::SellDialog(int npcId): instances.push_back(this); setVisible(true); + + PlayerInfo::setBuySellState(BUYSELL_SELLING); } SellDialog::~SellDialog() @@ -118,6 +120,9 @@ SellDialog::~SellDialog() delete mShopItems; instances.remove(this); + + if (PlayerInfo::getBuySellState() == BUYSELL_SELLING) + PlayerInfo::setBuySellState(BUYSELL_NONE); } void SellDialog::reset() @@ -197,6 +202,11 @@ void SellDialog::action(const gcn::ActionEvent &event) // the inventory index of the next Duplicate otherwise. itemIndex = item->getCurrentInvIndex(); sellCount = item->sellCurrentDuplicate(mAmountItems); + + // For Manaserv, the Item id is to be given as index. + if ((Net::getNetworkType() == ServerInfo::MANASERV)) + itemIndex = item->getId(); + Net::getNpcHandler()->sellItem(mNpcId, itemIndex, sellCount); mAmountItems -= sellCount; } diff --git a/src/gui/sell.h b/src/gui/sell.h index 32a4dc55..c286dcc2 100644 --- a/src/gui/sell.h +++ b/src/gui/sell.h @@ -86,11 +86,6 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener void setVisible(bool visible); /** - * Returns true if any instances exist. - */ - static bool isActive() { return instances.size() > 0; } - - /** * Closes all instances. */ static void closeAll(); diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index 0762b00f..115b582c 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" @@ -29,7 +30,6 @@ #include "gui/okdialog.h" #include "gui/sdlinput.h" -#include "gui/theme.h" #include "gui/widgets/button.h" #include "gui/widgets/dropdown.h" @@ -41,10 +41,11 @@ #include "net/net.h" +#include "resources/theme.h" + #include "utils/gettext.h" #include "utils/stringutils.h" #include "utils/xml.h" -#include "widgets/dropdown.h" #include <guichan/font.hpp> @@ -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); @@ -482,10 +485,10 @@ void ServerDialog::setFieldsReadOnly(bool readOnly) void ServerDialog::downloadServerList() { // Try to load the configuration value for the onlineServerList - std::string listFile = branding.getValue("onlineServerList", std::string()); + std::string listFile = branding.getStringValue("onlineServerList"); if (listFile.empty()) - listFile = config.getValue("onlineServerList", std::string()); + listFile = config.getStringValue("onlineServerList"); // Fall back to manasource.org when neither branding nor config set it if (listFile.empty()) diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp index 2c6b89e8..8e9f5e98 100644 --- a/src/gui/setup_audio.cpp +++ b/src/gui/setup_audio.cpp @@ -35,10 +35,10 @@ #include "utils/gettext.h" Setup_Audio::Setup_Audio(): - mMusicVolume((int)config.getValue("musicVolume", 60)), - mSfxVolume((int)config.getValue("sfxVolume", 100)), - mSoundEnabled(config.getValue("sound", 0)), - mDownloadEnabled(config.getValue("download-music", false)), + mMusicVolume(config.getIntValue("musicVolume")), + mSfxVolume(config.getIntValue("sfxVolume")), + mSoundEnabled(config.getBoolValue("sound")), + mDownloadEnabled(config.getBoolValue("download-music")), mSoundCheckBox(new CheckBox(_("Sound"), mSoundEnabled)), mDownloadMusicCheckBox(new CheckBox(_("Download music"), mDownloadEnabled)), mSfxSlider(new Slider(0, sound.getMaxVolume())), @@ -82,14 +82,14 @@ void Setup_Audio::apply() { mSoundEnabled = mSoundCheckBox->isSelected(); mDownloadEnabled = mDownloadMusicCheckBox->isSelected(); - mSfxVolume = (int) config.getValue("sfxVolume", 100); - mMusicVolume = (int) config.getValue("musicVolume", 60); + mSfxVolume = config.getIntValue("sfxVolume"); + mMusicVolume = config.getIntValue("musicVolume"); config.setValue("sound", mSoundEnabled); // Display a message if user has selected to download music, // And if downloadmusic is not already enabled - if (mDownloadEnabled && !config.getValue("download-music", false)) + if (mDownloadEnabled && !config.getBoolValue("download-music")) { new OkDialog(_("Notice"),_("You may have to restart your client if you want to download new music")); } diff --git a/src/gui/setup_colors.cpp b/src/gui/setup_colors.cpp index 12dba82a..6b3b3fec 100644 --- a/src/gui/setup_colors.cpp +++ b/src/gui/setup_colors.cpp @@ -23,8 +23,6 @@ #include "configuration.h" #include "gui/gui.h" -#include "gui/theme.h" -#include "gui/userpalette.h" #include "gui/widgets/browserbox.h" #include "gui/widgets/itemlinkhandler.h" @@ -36,6 +34,9 @@ #include "gui/widgets/textfield.h" #include "gui/widgets/textpreview.h" +#include "resources/theme.h" +#include "resources/userpalette.h" + #include "utils/gettext.h" #include "utils/stringutils.h" diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp index 965f5712..7ac5b5ed 100644 --- a/src/gui/setup_joystick.cpp +++ b/src/gui/setup_joystick.cpp @@ -40,7 +40,7 @@ Setup_Joystick::Setup_Joystick(): { setName(_("Joystick")); - mOriginalJoystickEnabled = !config.getValue("joystickEnabled", false); + mOriginalJoystickEnabled = !config.getBoolValue("joystickEnabled"); mJoystickEnabled->setSelected(mOriginalJoystickEnabled); mJoystickEnabled->addActionListener(this); diff --git a/src/gui/setup_players.cpp b/src/gui/setup_players.cpp index 802a5b2e..cbe0e264 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)), @@ -226,10 +227,12 @@ Setup_Players::Setup_Players(): mDefaultWhisper(new CheckBox(_("Allow whispers"), player_relations.getDefault() & PlayerRelation::WHISPER)), mDeleteButton(new Button(_("Delete"), ACTION_DELETE, this)), - mWhisperTab(config.getValue("whispertab", false)), + mWhisperTab(config.getBoolValue("whispertab")), mWhisperTabCheckBox(new CheckBox(_("Put all whispers in tabs"), mWhisperTab)), - mShowGender(config.getValue("showgender", false)), - mShowGenderCheckBox(new CheckBox(_("Show gender"), mShowGender)) + mShowGender(config.getBoolValue("showgender")), + mShowGenderCheckBox(new CheckBox(_("Show gender"), mShowGender)), + mEnableChatLog(config.getBoolValue("enableChatLog")), + 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); @@ -341,20 +348,24 @@ void Setup_Players::apply() PlayerRelation::WHISPER : 0)); config.setValue("whispertab", mWhisperTab); - bool showGender = config.getValue("showgender", false); + bool showGender = config.getBoolValue("showgender"); config.setValue("showgender", mShowGender); - if (beingManager && mShowGender != showGender) - beingManager->updatePlayerNames(); + if (actorSpriteManager && mShowGender != showGender) + actorSpriteManager->updatePlayerNames(); + + config.setValue("enableChatLog", mEnableChatLog); } void Setup_Players::cancel() { - mWhisperTab = config.getValue("whispertab", false); + mWhisperTab = config.getBoolValue("whispertab"); mWhisperTabCheckBox->setSelected(mWhisperTab); - mShowGender = config.getValue("showgender", false); + mShowGender = config.getBoolValue("showgender"); mShowGenderCheckBox->setSelected(mShowGender); + mEnableChatLog = config.getBoolValue("enableChatLog"); + 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/setup_video.cpp b/src/gui/setup_video.cpp index 81ce8107..bbfae738 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -171,7 +171,7 @@ static const char *speechModeToString(Being::Speech mode) const char *Setup_Video::overlayDetailToString(int detail) { if (detail == -1) - detail = config.getValue("OverlayDetail", -1); + detail = config.getIntValue("OverlayDetail"); switch (detail) { @@ -185,7 +185,7 @@ const char *Setup_Video::overlayDetailToString(int detail) const char *Setup_Video::particleDetailToString(int detail) { if (detail == -1) - detail = 3 - config.getValue("particleEmitterSkip", -1); + detail = 3 - config.getIntValue("particleEmitterSkip"); switch (detail) { @@ -198,21 +198,19 @@ const char *Setup_Video::particleDetailToString(int detail) } Setup_Video::Setup_Video(): - mFullScreenEnabled(config.getValue("screen", false)), - mOpenGLEnabled(config.getValue("opengl", false)), - mCustomCursorEnabled(config.getValue("customcursor", true)), - mShowMonsterDamageEnabled(config.getValue("showMonstersTakedDamage", - false)), - mVisibleNamesEnabled(config.getValue("visiblenames", true)), - mParticleEffectsEnabled(config.getValue("particleeffects", true)), - mNameEnabled(config.getValue("showownname", false)), - mNPCLogEnabled(config.getValue("logNpcInGui", true)), - mPickupChatEnabled(config.getValue("showpickupchat", true)), - mPickupParticleEnabled(config.getValue("showpickupparticle", false)), - mOpacity(config.getValue("guialpha", 0.8)), - mFps((int) config.getValue("fpslimit", 60)), - mSpeechMode(static_cast<Being::Speech>( - config.getValue("speech", Being::TEXT_OVERHEAD))), + mFullScreenEnabled(config.getBoolValue("screen")), + mOpenGLEnabled(config.getBoolValue("opengl")), + mCustomCursorEnabled(config.getBoolValue("customcursor")), + mShowMonsterDamageEnabled(config.getBoolValue("showMonstersTakedDamage")), + mVisibleNamesEnabled(config.getBoolValue("visiblenames")), + mParticleEffectsEnabled(config.getBoolValue("particleeffects")), + mNameEnabled(config.getBoolValue("showownname")), + mNPCLogEnabled(config.getBoolValue("logNpcInGui")), + mPickupChatEnabled(config.getBoolValue("showpickupchat")), + mPickupParticleEnabled(config.getBoolValue("showpickupparticle")), + mOpacity(config.getFloatValue("guialpha")), + mFps(config.getIntValue("fpslimit")), + mSpeechMode(static_cast<Being::Speech>(config.getIntValue("speech"))), mModeListModel(new ModeListModel), mModeList(new ListBox(mModeListModel)), mFsCheckBox(new CheckBox(_("Full screen"), mFullScreenEnabled)), @@ -237,13 +235,13 @@ Setup_Video::Setup_Video(): mFpsCheckBox(new CheckBox(_("FPS limit:"))), mFpsSlider(new Slider(10, 120)), mFpsLabel(new Label), - mOverlayDetail((int) config.getValue("OverlayDetail", 2)), + mOverlayDetail(config.getIntValue("OverlayDetail")), mOverlayDetailSlider(new Slider(0, 2)), mOverlayDetailField(new Label), - mParticleDetail(3 - (int) config.getValue("particleEmitterSkip", 1)), + mParticleDetail(3 - config.getIntValue("particleEmitterSkip")), mParticleDetailSlider(new Slider(0, 3)), mParticleDetailField(new Label), - mFontSize((int) config.getValue("fontSize", 11)) + mFontSize(config.getIntValue("fontSize")) { setName(_("Video")); @@ -388,7 +386,7 @@ void Setup_Video::apply() { // Full screen changes bool fullscreen = mFsCheckBox->isSelected(); - if (fullscreen != (config.getValue("screen", false) == 1)) + if (fullscreen != config.getBoolValue("screen")) { /* The OpenGL test is only necessary on Windows, since switching * to/from full screen works fine on Linux. On Windows we'd have to @@ -399,7 +397,7 @@ void Setup_Video::apply() #if defined(WIN32) || defined(__APPLE__) // checks for opengl usage - if (!(config.getValue("opengl", false) == 1)) + if (!config.getBoolValue("opengl")) { #endif if (!graphics->setFullscreen(fullscreen)) @@ -452,20 +450,20 @@ void Setup_Video::apply() config.setValue("fontSize", mFontSizeDropDown->getSelected() + 10); // We sync old and new values at apply time - mFullScreenEnabled = config.getValue("screen", false); - mCustomCursorEnabled = config.getValue("customcursor", true); - mShowMonsterDamageEnabled = config.getValue("showMonstersTakedDamage", false); - mVisibleNamesEnabled = config.getValue("visiblenames", true); - mParticleEffectsEnabled = config.getValue("particleeffects", true); - mNameEnabled = config.getValue("showownname", false); - mNPCLogEnabled = config.getValue("logNpcInGui", true); + mFullScreenEnabled = config.getBoolValue("screen"); + mCustomCursorEnabled = config.getBoolValue("customcursor"); + mShowMonsterDamageEnabled = config.getBoolValue("showMonstersTakedDamage"); + mVisibleNamesEnabled = config.getBoolValue("visiblenames"); + mParticleEffectsEnabled = config.getBoolValue("particleeffects"); + mNameEnabled = config.getBoolValue("showownname"); + mNPCLogEnabled = config.getBoolValue("logNpcInGui"); mSpeechMode = static_cast<Being::Speech>( - config.getValue("speech", Being::TEXT_OVERHEAD)); - mOpacity = config.getValue("guialpha", 0.8); - mOverlayDetail = (int) config.getValue("OverlayDetail", 2); - mOpenGLEnabled = config.getValue("opengl", false); - mPickupChatEnabled = config.getValue("showpickupchat", true); - mPickupParticleEnabled = config.getValue("showpickupparticle", false); + config.getIntValue("speech")); + mOpacity = config.getFloatValue("guialpha"); + mOverlayDetail = config.getIntValue("OverlayDetail"); + mOpenGLEnabled = config.getBoolValue("opengl"); + mPickupChatEnabled = config.getBoolValue("showpickupchat"); + mPickupParticleEnabled = config.getBoolValue("showpickupparticle"); } void Setup_Video::cancel() diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp index 53528cee..168553f6 100644 --- a/src/gui/skilldialog.cpp +++ b/src/gui/skilldialog.cpp @@ -21,11 +21,11 @@ #include "gui/skilldialog.h" -#include "localplayer.h" #include "log.h" +#include "playerinfo.h" +#include "configuration.h" #include "gui/setup.h" -#include "gui/theme.h" #include "gui/widgets/button.h" #include "gui/widgets/container.h" @@ -43,6 +43,7 @@ #include "resources/image.h" #include "resources/resourcemanager.h" +#include "resources/theme.h" #include "utils/dtor.h" #include "utils/gettext.h" @@ -87,7 +88,8 @@ struct SkillInfo } else { - icon = Theme::getImageFromTheme("unknown-item.png"); + icon = Theme::getImageFromTheme( + paths.getStringValue("unknownItemFile")); } } @@ -240,10 +242,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) @@ -263,7 +261,7 @@ std::string SkillDialog::update(int id) void SkillDialog::update() { mPointsLabel->setCaption(strprintf(_("Skill points available: %d"), - player_node->getSkillPoints())); + PlayerInfo::getAttribute(SKILL_POINTS))); mPointsLabel->adjustSize(); for (SkillMap::iterator it = mSkills.begin(); it != mSkills.end(); it++) @@ -414,10 +412,10 @@ void SkillModel::updateVisibilities() void SkillInfo::update() { - int baseLevel = player_node->getAttributeBase(id); - int effLevel = player_node->getAttributeEffective(id); + int baseLevel = PlayerInfo::getStatBase(id); + int effLevel = PlayerInfo::getStatEffective(id); - std::pair<int, int> exp = player_node->getExperience(id); + std::pair<int, int> exp = PlayerInfo::getStatExperience(id); if (!modifiable && baseLevel == 0 && effLevel == 0 && exp.second == 0) { diff --git a/src/gui/skilldialog.h b/src/gui/skilldialog.h index 95f8ef25..764f9d51 100644 --- a/src/gui/skilldialog.h +++ b/src/gui/skilldialog.h @@ -19,8 +19,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SKILL_H -#define SKILL_H +#ifndef SKILLDIALOG_H +#define SKILLDIALOG_H #include "guichanfwd.h" diff --git a/src/gui/socialwindow.cpp b/src/gui/socialwindow.cpp index 098ecbc5..88cd5732 100644 --- a/src/gui/socialwindow.cpp +++ b/src/gui/socialwindow.cpp @@ -20,22 +20,19 @@ #include "gui/socialwindow.h" -#include "beingmanager.h" +#include "event.h" #include "guild.h" #include "localplayer.h" #include "party.h" -#include "player.h" #include "gui/confirmdialog.h" #include "gui/okdialog.h" #include "gui/setup.h" #include "gui/textdialog.h" -#include "gui/theme.h" #include "gui/widgets/avatarlistbox.h" #include "gui/widgets/browserbox.h" #include "gui/widgets/button.h" -#include "gui/widgets/chattab.h" #include "gui/widgets/container.h" #include "gui/widgets/label.h" #include "gui/widgets/layouthelper.h" @@ -49,6 +46,8 @@ #include "net/guildhandler.h" #include "net/partyhandler.h" +#include "resources/theme.h" + #include "utils/dtor.h" #include "utils/gettext.h" #include "utils/stringutils.h" @@ -123,10 +122,9 @@ public: std::string name = mInviteDialog->getText(); Net::getGuildHandler()->invite(mGuild->getId(), name); - localChatTab->chatLog(strprintf(_("Invited user %s to guild %s."), + SERVER_NOTICE(strprintf(_("Invited user %s to guild %s."), name.c_str(), - mGuild->getName().c_str()), - BY_SERVER); + mGuild->getName().c_str())) mInviteDialog = NULL; } else if (event.getId() == "~do invite") @@ -136,8 +134,8 @@ public: else if (event.getId() == "yes") { Net::getGuildHandler()->leave(mGuild->getId()); - localChatTab->chatLog(strprintf(_("Guild %s quit requested."), - mGuild->getName().c_str()), BY_SERVER); + SERVER_NOTICE(strprintf(_("Guild %s quit requested."), + mGuild->getName().c_str())) mConfirmDialog = NULL; } else if (event.getId() == "~yes") @@ -204,8 +202,8 @@ public: std::string name = mInviteDialog->getText(); Net::getPartyHandler()->invite(name); - localChatTab->chatLog(strprintf(_("Invited user %s to party."), - name.c_str()), BY_SERVER); + SERVER_NOTICE(strprintf(_("Invited user %s to party."), + name.c_str())) mInviteDialog = NULL; } else if (event.getId() == "~do invite") @@ -215,8 +213,8 @@ public: else if (event.getId() == "yes") { Net::getPartyHandler()->leave(); - localChatTab->chatLog(strprintf(_("Party %s quit requested."), - mParty->getName().c_str()), BY_SERVER); + SERVER_NOTICE(strprintf(_("Party %s quit requested."), + mParty->getName().c_str())) mConfirmDialog = NULL; } else if (event.getId() == "~yes") @@ -440,14 +438,14 @@ void SocialWindow::action(const gcn::ActionEvent &event) // check if they accepted the invite if (eventId == "yes") { - localChatTab->chatLog(strprintf(_("Accepted party invite from %s."), - mPartyInviter.c_str())); + SERVER_NOTICE(strprintf(_("Accepted party invite from %s."), + mPartyInviter.c_str())) Net::getPartyHandler()->inviteResponse(mPartyInviter, true); } else if (eventId == "no") { - localChatTab->chatLog(strprintf(_("Rejected party invite from %s."), - mPartyInviter.c_str())); + SERVER_NOTICE(strprintf(_("Rejected party invite from %s."), + mPartyInviter.c_str())) Net::getPartyHandler()->inviteResponse(mPartyInviter, false); } @@ -459,14 +457,14 @@ void SocialWindow::action(const gcn::ActionEvent &event) // check if they accepted the invite if (eventId == "yes") { - localChatTab->chatLog(strprintf(_("Accepted guild invite from %s."), - mPartyInviter.c_str())); + SERVER_NOTICE(strprintf(_("Accepted guild invite from %s."), + mPartyInviter.c_str())) Net::getGuildHandler()->inviteResponse(mGuildInvited, true); } else if (eventId == "no") { - localChatTab->chatLog(strprintf(_("Rejected guild invite from %s."), - mPartyInviter.c_str())); + SERVER_NOTICE(strprintf(_("Rejected guild invite from %s."), + mPartyInviter.c_str())) Net::getGuildHandler()->inviteResponse(mGuildInvited, false); } @@ -499,8 +497,8 @@ void SocialWindow::action(const gcn::ActionEvent &event) } Net::getGuildHandler()->create(name); - localChatTab->chatLog(strprintf(_("Creating guild called %s."), - name.c_str()), BY_SERVER); + SERVER_NOTICE(strprintf(_("Creating guild called %s."), + name.c_str())) mGuildCreateDialog = NULL; } @@ -519,8 +517,8 @@ void SocialWindow::action(const gcn::ActionEvent &event) } Net::getPartyHandler()->create(name); - localChatTab->chatLog(strprintf(_("Creating party called %s."), - name.c_str()), BY_SERVER); + SERVER_NOTICE(strprintf(_("Creating party called %s."), + name.c_str())); mPartyCreateDialog = NULL; } @@ -545,14 +543,14 @@ void SocialWindow::showGuildInvite(const std::string &guildName, // check there isnt already an invite showing if (mGuildInvited != 0) { - localChatTab->chatLog(_("Received guild request, but one already " - "exists."), BY_SERVER); + SERVER_NOTICE(_("Received guild request, but one already " + "exists.")) return; } std::string msg = strprintf(_("%s has invited you to join the guild %s."), inviterName.c_str(), guildName.c_str()); - localChatTab->chatLog(msg, BY_SERVER); + SERVER_NOTICE(msg) // show invite mGuildAcceptDialog = new ConfirmDialog(_("Accept Guild Invite"), msg, this); @@ -567,8 +565,7 @@ void SocialWindow::showPartyInvite(const std::string &partyName, // check there isnt already an invite showing if (mPartyInviter != "") { - localChatTab->chatLog(_("Received party request, but one already " - "exists."), BY_SERVER); + SERVER_NOTICE(_("Received party request, but one already exists.")) return; } @@ -599,7 +596,7 @@ void SocialWindow::showPartyInvite(const std::string &partyName, } } - localChatTab->chatLog(msg, BY_SERVER); + SERVER_NOTICE(msg) // show invite mPartyAcceptDialog = new ConfirmDialog(_("Accept Party Invite"), msg, this); diff --git a/src/gui/specialswindow.cpp b/src/gui/specialswindow.cpp index 44551825..b511e4a3 100644 --- a/src/gui/specialswindow.cpp +++ b/src/gui/specialswindow.cpp @@ -20,11 +20,9 @@ #include "gui/specialswindow.h" -#include "localplayer.h" #include "log.h" #include "gui/setup.h" -#include "gui/theme.h" #include "gui/widgets/button.h" #include "gui/widgets/container.h" @@ -42,6 +40,9 @@ #include "net/net.h" #include "net/specialhandler.h" +#include "resources/specialdb.h" +#include "resources/theme.h" + #include "utils/dtor.h" #include "utils/gettext.h" #include "utils/stringutils.h" @@ -54,31 +55,24 @@ class SpecialEntry; -struct SpecialInfo -{ - unsigned short id; - std::string name; - std::string icon; - SpecialEntry *display; -}; class SpecialEntry : public Container { public: SpecialEntry(SpecialInfo *info); - void update(); + void update(int current, int needed); protected: friend class SpecialsWindow; SpecialInfo *mInfo; private: - Icon *mIcon; - Label *mNameLabel; - Label *mLevelLabel; - Label *mTechLabel; - Button *mUse; + Icon *mIcon; // icon to display + Label *mNameLabel; // name to display + Label *mLevelLabel; // level number label (only shown when applicable) + Button *mUse; // use button (only shown when applicable) + ProgressBar *mRechargeBar; // recharge bar (only shown when applicable) }; SpecialsWindow::SpecialsWindow(): @@ -102,7 +96,6 @@ SpecialsWindow::SpecialsWindow(): SpecialsWindow::~SpecialsWindow() { // Clear gui - loadSpecials(""); } void SpecialsWindow::action(const gcn::ActionEvent &event) @@ -127,91 +120,70 @@ void SpecialsWindow::action(const gcn::ActionEvent &event) } } -std::string SpecialsWindow::update(int id) -{ - // TODO - - return std::string(); -} - -void SpecialsWindow::loadSpecials(const std::string &file) +void SpecialsWindow::draw(gcn::Graphics *graphics) { - // TODO: mTabs->clear(); - while (mTabs->getSelectedTabIndex() != -1) + // update the progress bars + std::map<int, Special> specialData = PlayerInfo::getSpecialStatus(); + bool foundNew = false; + unsigned int found = 0; // number of entries in specialData which match mEntries + + for (std::map<int, Special>::iterator i = specialData.begin(); + i != specialData.end(); + i++) { - mTabs->removeTabWithIndex(mTabs->getSelectedTabIndex()); - } - - for (SpecialMap::iterator it = mSpecials.begin(); it != mSpecials.end(); it++) - { - delete (*it).second->display; + std::map<int, SpecialEntry *>::iterator e = mEntries.find(i->first); + if (e == mEntries.end()) + { + // found a new special - abort update and rebuild from scratch + foundNew = true; + break; + } else { + // update progress bar of special + e->second->update(i->second.currentMana, i->second.neededMana); + found++; + } } - delete_all(mSpecials); - mSpecials.clear(); + // a rebuild is needed when a) the number of specials changed or b) an existing entry isn't found anymore + if (foundNew || found != mEntries.size()) rebuild(specialData); - if (file.length() == 0) - return; + Window::draw(graphics); +} - XML::Document doc(file); - xmlNodePtr root = doc.rootNode(); +void SpecialsWindow::rebuild(const std::map<int, Special> &specialData) +{ + make_dtor(mEntries); + mEntries.clear(); + int vPos = 0; //vertical position of next placed element - if (!root || !xmlStrEqual(root->name, BAD_CAST "specials")) + for (std::map<int, Special>::const_iterator i = specialData.begin(); + i != specialData.end(); + i++) { - logger->log("Error loading specials file: %s", file.c_str()); - return; - } - - int setCount = 0; - std::string setName; - ScrollArea *scroll; - FlowContainer *container; + logger->log("Updating special GUI for %d", i->first); - for_each_xml_child_node(set, root) - { - if (xmlStrEqual(set->name, BAD_CAST "set")) + SpecialInfo* info = SpecialDB::get(i->first); + if (info) { - setCount++; - setName = XML::getProperty(set, "name", strprintf(_("Specials Set %d"), setCount)); - - container = new FlowContainer(SPECIALS_WIDTH, SPECIALS_HEIGHT); - container->setOpaque(false); - scroll = new ScrollArea(container); - scroll->setOpaque(false); - scroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); - scroll->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS); - - mTabs->addTab(setName, scroll); - for_each_xml_child_node(node, set) - { - if (xmlStrEqual(node->name, BAD_CAST "special")) - { - int id = atoi(XML::getProperty(node, "id", "-1").c_str()); - if (id == -1) - continue; - std::string name = XML::getProperty(node, "name", strprintf(_("Special %d"), id)); - std::string icon = XML::getProperty(node, "icon", ""); - - SpecialInfo *special = new SpecialInfo; - special->id = id; - special->name = name; - special->icon = icon; - special->display = new SpecialEntry(special); - - container->add(special->display); - - mSpecials[id] = special; - } - } + info->rechargeCurrent = i->second.currentMana; + info->rechargeNeeded = i->second.neededMana; + SpecialEntry* entry = new SpecialEntry(info); + entry->setPosition(0, vPos); + vPos += entry->getHeight(); + add(entry); + mEntries[i->first] = entry; + } else { + logger->log("Warning: No info available of special %d", i->first); } } } + SpecialEntry::SpecialEntry(SpecialInfo *info) : mInfo(info), mIcon(NULL), - mNameLabel(new Label(info->name)), - mLevelLabel(new Label("999")), - mUse(new Button("Use", "use", specialsWindow)) + mLevelLabel(NULL), + mUse(NULL), + mRechargeBar(NULL) { setFrameSize(1); setOpaque(false); @@ -225,21 +197,42 @@ SpecialEntry::SpecialEntry(SpecialInfo *info) : mIcon->setPosition(1, 0); add(mIcon); + + mNameLabel = new Label(info->name); mNameLabel->setPosition(35, 0); add(mNameLabel); - mLevelLabel->setPosition(getWidth() - mLevelLabel->getWidth(), 0); - add(mLevelLabel); + if (info->hasLevel) + { + mLevelLabel = new Label(toString(info->level)); + mLevelLabel->setPosition(getWidth() - mLevelLabel->getWidth(), 0); + add(mLevelLabel); + } + - mNameLabel->setWidth(mLevelLabel->getX() - mNameLabel->getX() - 1); + if (info->isActive) + { + mUse = new Button("Use", "use", specialsWindow); + mUse->setPosition(getWidth() - mUse->getWidth(), 13); + add(mUse); + } - mUse->setPosition(getWidth() - mUse->getWidth(), 13); - add(mUse); + if (info->hasRechargeBar) + { + float progress = (float)info->rechargeCurrent / (float)info->rechargeNeeded; + mRechargeBar = new ProgressBar(progress, 100, 10, Theme::PROG_MP); + mRechargeBar->setSmoothProgress(false); + mRechargeBar->setPosition(0, 13); + add(mRechargeBar); + } - update(); } -void SpecialEntry::update() +void SpecialEntry::update(int current, int needed) { - // TODO + if (mRechargeBar) + { + float progress = (float)current / (float)needed; + mRechargeBar->setProgress(progress); + } } diff --git a/src/gui/specialswindow.h b/src/gui/specialswindow.h index 81384856..85abe3a4 100644 --- a/src/gui/specialswindow.h +++ b/src/gui/specialswindow.h @@ -25,6 +25,8 @@ #include "guichanfwd.h" +#include "playerinfo.h" + #include "gui/widgets/window.h" #include <guichan/actionlistener.hpp> @@ -36,7 +38,7 @@ class ScrollArea; class Tab; class TabbedArea; -struct SpecialInfo; +struct SpecialEntry; class SpecialsWindow : public Window, public gcn::ActionListener { public: @@ -49,20 +51,14 @@ class SpecialsWindow : public Window, public gcn::ActionListener { */ void action(const gcn::ActionEvent &actionEvent); - /** - * Update the given special's display - */ - std::string update(int id); - - void loadSpecials(const std::string &file); - - bool hasSpecials() { return !mSpecials.empty(); } + void draw(gcn::Graphics *graphics); private: - std::vector<gcn::Button *> mSpellButtons; - typedef std::map<int, SpecialInfo*> SpecialMap; - SpecialMap mSpecials; + // (re)constructs the list of specials + void rebuild(const std::map<int, Special> &specialData); + TabbedArea *mTabs; + std::map<int, SpecialEntry *> mEntries; }; extern SpecialsWindow *specialsWindow; diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp index 08d00038..e0a9f8a0 100644 --- a/src/gui/speechbubble.cpp +++ b/src/gui/speechbubble.cpp @@ -25,10 +25,12 @@ #include "graphics.h" #include "gui/gui.h" -#include "gui/theme.h" +#include "gui/widgets/label.h" #include "gui/widgets/textbox.h" +#include "resources/theme.h" + #include <guichan/font.hpp> #include <guichan/widgets/label.hpp> @@ -40,7 +42,7 @@ SpeechBubble::SpeechBubble(): setMinWidth(29); setMinHeight(29); - mCaption = new gcn::Label; + mCaption = new Label; mCaption->setFont(boldFont); mSpeechBox = new TextBox; diff --git a/src/gui/speechbubble.h b/src/gui/speechbubble.h index 8682ab7e..6017398a 100644 --- a/src/gui/speechbubble.h +++ b/src/gui/speechbubble.h @@ -23,10 +23,10 @@ #ifndef SPEECHBUBBLE_H #define SPEECHBUBBLE_H -#include "gui/theme.h" - #include "gui/widgets/popup.h" +#include "resources/theme.h" + class TextBox; class SpeechBubble : public Popup diff --git a/src/gui/statuswindow.cpp b/src/gui/statuswindow.cpp index ede85133..493f5ee6 100644 --- a/src/gui/statuswindow.cpp +++ b/src/gui/statuswindow.cpp @@ -22,11 +22,10 @@ #include "gui/statuswindow.h" #include "localplayer.h" +#include "playerinfo.h" #include "units.h" -#include "gui/ministatus.h" #include "gui/setup.h" -#include "gui/theme.h" #include "gui/widgets/button.h" #include "gui/widgets/label.h" @@ -38,6 +37,9 @@ #include "net/net.h" #include "net/playerhandler.h" +#include "net/gamehandler.h" + +#include "resources/theme.h" #include "utils/gettext.h" #include "utils/mathutils.h" @@ -94,6 +96,8 @@ class ChangeDisplay : public AttrDisplay, gcn::ActionListener StatusWindow::StatusWindow(): Window(player_node->getName()) { + listen("Attributes"); + setWindowName("Status"); setupWindow->registerWindowForReset(this); setResizable(true); @@ -109,21 +113,25 @@ StatusWindow::StatusWindow(): mLvlLabel = new Label(strprintf(_("Level: %d"), 0)); mMoneyLabel = new Label(strprintf(_("Money: %s"), "")); - int max = player_node->getMaxHp(); + int max = PlayerInfo::getAttribute(MAX_HP); mHpLabel = new Label(_("HP:")); - mHpBar = new ProgressBar(max ? (float) player_node->getHp() / max: 0, + mHpBar = new ProgressBar(max ? (float) PlayerInfo::getAttribute(HP) / max: 0, 80, 15, Theme::PROG_HP); - max = player_node->getExpNeeded(); + max = PlayerInfo::getAttribute(EXP_NEEDED); mXpLabel = new Label(_("Exp:")); - mXpBar = new ProgressBar(max ? (float) player_node->getExp() / max : 0, + mXpBar = new ProgressBar(max ? (float) PlayerInfo::getAttribute(EXP) / 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 = PlayerInfo::getAttribute(MAX_MP); + mMpLabel = new Label(_("MP:")); + mMpBar = new ProgressBar(max ? (float) PlayerInfo::getAttribute(MAX_MP) / 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 +140,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) { @@ -178,98 +189,101 @@ StatusWindow::StatusWindow(): loadWindowState(); - update(HP); - 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) -{ - if (miniStatusWindow) - miniStatusWindow->update(id); - - if (id == HP) - { - updateHPBar(mHpBar, true); - - return _("HP"); - } - else if (id == MP) - { + // Update bars + updateHPBar(mHpBar, true); + if (magicBar) updateMPBar(mMpBar, true); + updateXPBar(mXpBar, false); - return _("MP"); - } - else if (id == EXP) - { - updateXPBar(mXpBar, false); - return _("Exp"); - } - else if (id == MONEY) - { - int money = player_node->getMoney(); - mMoneyLabel->setCaption(strprintf(_("Money: %s"), - Units::formatCurrency(money).c_str())); - mMoneyLabel->adjustSize(); - - return _("Money"); - } - else if (id == Net::getPlayerHandler()->getJobLocation()) - { - mJobLvlLabel->setCaption(strprintf(_("Job: %d"), - player_node->getAttributeBase(id))); - mJobLvlLabel->adjustSize(); + mMoneyLabel->setCaption(strprintf(_("Money: %s"), + Units::formatCurrency(PlayerInfo::getAttribute(MONEY)).c_str())); + mMoneyLabel->adjustSize(); + mCharacterPointsLabel->setCaption(strprintf(_("Character points: %d"), + PlayerInfo::getAttribute(CHAR_POINTS))); + mCharacterPointsLabel->adjustSize(); - updateProgressBar(mJobBar, id, false); + mLvlLabel->setCaption(strprintf(_("Level: %d"), + PlayerInfo::getAttribute(LEVEL))); + mLvlLabel->adjustSize(); +} - return _("Job"); - } - else if (id == CHAR_POINTS) +void StatusWindow::event(const std::string &channel, const Mana::Event &event) +{ + if (event.getName() == "UpdateAttribute") { - mCharacterPointsLabel->setCaption(strprintf(_("Character points: %d"), - player_node->getCharacterPoints())); - mCharacterPointsLabel->adjustSize(); - - if (Net::getPlayerHandler()->canCorrectAttributes()) - { - mCorrectionPointsLabel->setCaption(strprintf(_("Correction points: %d"), - player_node->getCorrectionPoints())); - mCorrectionPointsLabel->adjustSize(); - } - - for (Attrs::iterator it = mAttrs.begin(); it != mAttrs.end(); it++) + switch(event.getInt("id")) { - it->second->update(); + case HP: case MAX_HP: + updateHPBar(mHpBar, true); + break; + + case MP: case MAX_MP: + updateMPBar(mMpBar, true); + break; + + case EXP: case EXP_NEEDED: + updateXPBar(mXpBar, false); + break; + + case MONEY: + mMoneyLabel->setCaption(strprintf(_("Money: %s"), + Units::formatCurrency( + event.getInt("newValue")).c_str())); + mMoneyLabel->adjustSize(); + break; + + case CHAR_POINTS: + mCharacterPointsLabel->setCaption(strprintf( + _("Character points: %d"), + event.getInt("newValue"))); + mCharacterPointsLabel->adjustSize(); + // Update all attributes + for (Attrs::iterator it = mAttrs.begin(); + it != mAttrs.end(); it++) + it->second->update(); + break; + + case CORR_POINTS: + mCorrectionPointsLabel->setCaption(strprintf( + _("Correction points: %d"), + event.getInt("newValue"))); + mCorrectionPointsLabel->adjustSize(); + // Update all attributes + for (Attrs::iterator it = mAttrs.begin(); + it != mAttrs.end(); it++) + it->second->update(); + break; + + case LEVEL: + mLvlLabel->setCaption(strprintf(_("Level: %d"), + event.getInt("newValue"))); + mLvlLabel->adjustSize(); + break; } } - else if (id == LEVEL) + else if (event.getName() == "UpdateStat") { - mLvlLabel->setCaption(strprintf(_("Level: %d"), - player_node->getLevel())); - mLvlLabel->adjustSize(); + int id = event.getInt("id"); - return _("Level"); - } - else - { - Attrs::iterator it = mAttrs.find(id); + if (id == Net::getPlayerHandler()->getJobLocation()) + { + + mJobLvlLabel->setCaption(strprintf(_("Job: %d"), + PlayerInfo::getStatBase(id))); + mJobLvlLabel->adjustSize(); - if (it != mAttrs.end()) + updateProgressBar(mJobBar, id, false); + } + else { - return it->second->update(); + Attrs::iterator it = mAttrs.find(id); + if (it != mAttrs.end()) + { + it->second->update(); + } } } - - return ""; } void StatusWindow::setPointsNeeded(int id, int needed) @@ -306,32 +320,37 @@ 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()) + - "/" + toString(player_node->getMaxHp())); + bar->setText(toString(PlayerInfo::getAttribute(HP)) + + "/" + toString(PlayerInfo::getAttribute(MAX_HP))); else - bar->setText(toString(player_node->getHp())); + bar->setText(toString(PlayerInfo::getAttribute(HP))); float prog = 1.0; - if (player_node->getMaxHp() > 0) - prog = (float) player_node->getHp() / player_node->getMaxHp(); + if (PlayerInfo::getAttribute(MAX_HP) > 0) + prog = (float) PlayerInfo::getAttribute(HP) / PlayerInfo::getAttribute(MAX_HP); bar->setProgress(prog); } void StatusWindow::updateMPBar(ProgressBar *bar, bool showMax) { + if (!bar) + return; + if (showMax) - bar->setText(toString(player_node->getMP()) + - "/" + toString(player_node->getMaxMP())); + bar->setText(toString(PlayerInfo::getAttribute(MP)) + + "/" + toString(PlayerInfo::getAttribute(MAX_MP))); else - bar->setText(toString(player_node->getMP())); + bar->setText(toString(PlayerInfo::getAttribute(MP))); float prog = 1.0f; - if (player_node->getMaxMP() > 0) - prog = (float) player_node->getMP() / player_node->getMaxMP(); + if (PlayerInfo::getAttribute(MAX_MP) > 0) + prog = (float) PlayerInfo::getAttribute(MP) / PlayerInfo::getAttribute(MAX_MP); if (Net::getPlayerHandler()->canUseMagic()) bar->setProgressPalette(Theme::PROG_MP); @@ -344,6 +363,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,13 +386,16 @@ void StatusWindow::updateProgressBar(ProgressBar *bar, int value, int max, void StatusWindow::updateXPBar(ProgressBar *bar, bool percent) { - updateProgressBar(bar, player_node->getExp(), - player_node->getExpNeeded(), percent); + if (!bar) + return; + + updateProgressBar(bar, PlayerInfo::getAttribute(EXP), + PlayerInfo::getAttribute(EXP_NEEDED), percent); } void StatusWindow::updateProgressBar(ProgressBar *bar, int id, bool percent) { - std::pair<int, int> exp = player_node->getExperience(id); + std::pair<int, int> exp = PlayerInfo::getStatExperience(id); updateProgressBar(bar, exp.first, exp.second, percent); } @@ -395,8 +420,8 @@ AttrDisplay::~AttrDisplay() std::string AttrDisplay::update() { - int base = player_node->getAttributeBase(mId); - int bonus = player_node->getAttributeEffective(mId) - base; + int base = PlayerInfo::getStatBase(mId); + int bonus = PlayerInfo::getStatMod(mId); std::string value = toString(base); if (bonus) value += strprintf(" (%+d)", bonus); @@ -460,9 +485,9 @@ std::string ChangeDisplay::update() if (mDec) { - mDec->setEnabled(player_node->getCorrectionPoints()); + mDec->setEnabled(PlayerInfo::getAttribute(CORR_POINTS)); } - mInc->setEnabled(player_node->getCharacterPoints() >= mNeeded && + mInc->setEnabled(PlayerInfo::getAttribute(CHAR_POINTS) >= mNeeded && mNeeded > 0); return AttrDisplay::update(); @@ -480,24 +505,25 @@ void ChangeDisplay::action(const gcn::ActionEvent &event) if (Net::getPlayerHandler()->canCorrectAttributes() && event.getSource() == mDec) { - int newcorpoints = player_node->getCorrectionPoints() - 1; - player_node->setCorrectionPoints(newcorpoints); - int newpoints = player_node->getCharacterPoints() + 1; - player_node->setCharacterPoints(newpoints); - int newbase = player_node->getAttributeBase(mId) - 1; - player_node->setAttributeBase(mId, newbase); - int newmod = player_node->getAttributeEffective(mId) - 1; - player_node->setAttributeEffective(mId, newmod); + int newcorpoints = PlayerInfo::getAttribute(CORR_POINTS) - 1; + PlayerInfo::setAttribute(CORR_POINTS, newcorpoints); + + int newpoints = PlayerInfo::getAttribute(CHAR_POINTS) + 1; + PlayerInfo::setAttribute(CHAR_POINTS, newpoints); + + int newbase = PlayerInfo::getStatBase(mId) - 1; + PlayerInfo::setStatBase(mId, newbase); + Net::getPlayerHandler()->decreaseAttribute(mId); } else if (event.getSource() == mInc) { - int newpoints = player_node->getCharacterPoints() - 1; - player_node->setCharacterPoints(newpoints); - int newbase = player_node->getAttributeBase(mId) + 1; - player_node->setAttributeBase(mId, newbase); - int newmod = player_node->getAttributeEffective(mId) + 1; - player_node->setAttributeEffective(mId, newmod); + int newpoints = PlayerInfo::getAttribute(CHAR_POINTS) - 1; + PlayerInfo::setAttribute(CHAR_POINTS, newpoints); + + int newbase = PlayerInfo::getStatBase(mId) + 1; + PlayerInfo::setStatBase(mId, newbase); + Net::getPlayerHandler()->increaseAttribute(mId); } } diff --git a/src/gui/statuswindow.h b/src/gui/statuswindow.h index a1fc4b4b..5be09b6a 100644 --- a/src/gui/statuswindow.h +++ b/src/gui/statuswindow.h @@ -23,6 +23,7 @@ #define STATUS_H #include "guichanfwd.h" +#include "listener.h" #include "gui/widgets/window.h" @@ -40,24 +41,15 @@ class VertContainer; * * \ingroup Interface */ -class StatusWindow : public Window +class StatusWindow : public Window, public Mana::Listener { public: - enum { // Some update constants - HP = -1, - MP = -2, - EXP = -3, - MONEY = -4, - CHAR_POINTS = -5, - LEVEL = -6 - }; - /** * Constructor. */ StatusWindow(); - std::string update(int id); + void event(const std::string &channel, const Mana::Event &event); void setPointsNeeded(int id, int needed); diff --git a/src/gui/textpopup.cpp b/src/gui/textpopup.cpp index 6aeae319..d0a0c495 100644 --- a/src/gui/textpopup.cpp +++ b/src/gui/textpopup.cpp @@ -26,6 +26,8 @@ #include "gui/gui.h" #include "gui/palette.h" +#include "gui/widgets/label.h" + #include "graphics.h" #include "units.h" @@ -40,10 +42,10 @@ TextPopup::TextPopup(): { const int fontHeight = getFont()->getHeight(); - mText1 = new gcn::Label; + mText1 = new Label; mText1->setPosition(getPadding(), getPadding()); - mText2 = new gcn::Label; + mText2 = new Label; mText2->setPosition(getPadding(), fontHeight + getPadding()); add(mText1); diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp index dcb38e8e..bfb61c33 100644 --- a/src/gui/trade.cpp +++ b/src/gui/trade.cpp @@ -21,9 +21,11 @@ #include "gui/trade.h" +#include "event.h" #include "inventory.h" #include "item.h" #include "localplayer.h" +#include "playerinfo.h" #include "units.h" #include "gui/inventorywindow.h" @@ -31,7 +33,6 @@ #include "gui/setup.h" #include "gui/widgets/button.h" -#include "gui/widgets/chattab.h" #include "gui/widgets/itemcontainer.h" #include "gui/widgets/label.h" #include "gui/widgets/scrollarea.h" @@ -59,7 +60,7 @@ TradeWindow::TradeWindow(): mMyInventory(new Inventory(Inventory::TRADE)), mPartnerInventory(new Inventory(Inventory::TRADE)), mStatus(PROPOSING) -{ +{ setWindowName("Trade"); setResizable(true); setCloseButton(true); @@ -96,7 +97,7 @@ TradeWindow::TradeWindow(): mMoneyLabel = new Label(strprintf(_("You get %s"), "")); gcn::Label *mMoneyLabel2 = new Label(_("You give:")); - + mMoneyField = new TextField; mMoneyField->setWidth(40); mMoneyChangeButton = new Button(_("Change"), "money", this); @@ -270,9 +271,8 @@ void TradeWindow::action(const gcn::ActionEvent &event) if (mMyInventory->contains(item)) { - localChatTab->chatLog(_("Failed adding item. You can not " - "overlap one kind of item on the window."), - BY_SERVER); + SERVER_NOTICE(_("Failed adding item. You can not " + "overlap one kind of item on the window.")) return; } @@ -285,7 +285,7 @@ void TradeWindow::action(const gcn::ActionEvent &event) { setVisible(false); reset(); - player_node->setTrading(false); + PlayerInfo::setTrading(false); Net::getTradeHandler()->cancel(); } @@ -310,11 +310,10 @@ void TradeWindow::action(const gcn::ActionEvent &event) return; int v = atoi(mMoneyField->getText().c_str()); - int curMoney = player_node->getMoney(); + int curMoney = PlayerInfo::getAttribute(MONEY); if (v > curMoney) { - localChatTab->chatLog(_("You don't have enough money."), - BY_SERVER); + SERVER_NOTICE(_("You don't have enough money.")) v = curMoney; } Net::getTradeHandler()->setMoney(v); diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index 7448a102..23d23b5e 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -476,7 +476,7 @@ void UpdaterWindow::logic() // This statement checks to see if the file type is music, and if download-music is true // If it fails, this statement returns true, and results in not downloading the file // Else it will ignore the break, and download the file. - if ( !(thisFile.type == "music" && config.getValue("download-music", false)) ) + if ( !(thisFile.type == "music" && config.getBoolValue("download-music")) ) { mUpdateIndex++; break; diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 99325db8..972920a5 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -21,16 +21,14 @@ #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 "playerinfo.h" #include "textmanager.h" #include "gui/gui.h" @@ -40,7 +38,6 @@ #include "net/net.h" -#include "resources/monsterinfo.h" #include "resources/resourcemanager.h" #include "utils/stringutils.h" @@ -62,10 +59,10 @@ Viewport::Viewport(): setOpaque(false); addMouseListener(this); - mScrollLaziness = (int) config.getValue("ScrollLaziness", 16); - mScrollRadius = (int) config.getValue("ScrollRadius", 0); - mScrollCenterOffsetX = (int) config.getValue("ScrollCenterOffsetX", 0); - mScrollCenterOffsetY = (int) config.getValue("ScrollCenterOffsetY", 0); + mScrollLaziness = config.getIntValue("ScrollLaziness"); + mScrollRadius = config.getIntValue("ScrollRadius"); + mScrollCenterOffsetX = config.getIntValue("ScrollCenterOffsetX"); + mScrollCenterOffsetY = config.getIntValue("ScrollCenterOffsetY"); config.addListener("ScrollLaziness", this); config.addListener("ScrollRadius", this); @@ -74,6 +71,8 @@ Viewport::Viewport(): mBeingPopup = new BeingPopup; setFocusable(true); + + listen("ActorSprite"); } Viewport::~Viewport() @@ -207,12 +206,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 +348,7 @@ void Viewport::mousePressed(gcn::MouseEvent &event) return; // Check if we are busy - if (NPC::isTalking()) + if (PlayerInfo::isTalking()) return; mPlayerFollowMouse = false; @@ -381,33 +384,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 +423,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 +450,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) / @@ -494,8 +484,8 @@ void Viewport::closePopupMenu() void Viewport::optionChanged(const std::string &name) { - mScrollLaziness = (int) config.getValue("ScrollLaziness", 32); - mScrollRadius = (int) config.getValue("ScrollRadius", 32); + mScrollLaziness = config.getIntValue("ScrollLaziness"); + mScrollRadius = config.getIntValue("ScrollRadius"); } void Viewport::mouseMoved(gcn::MouseEvent &event) @@ -507,27 +497,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: @@ -549,7 +535,7 @@ void Viewport::mouseMoved(gcn::MouseEvent &event) void Viewport::toggleDebugPath() { mShowDebugPath++; - if (mShowDebugPath > Map::MAP_SPECIAL) + if (mShowDebugPath > Map::MAP_SPECIAL3) mShowDebugPath = Map::MAP_NORMAL; if (mMap) { @@ -562,8 +548,16 @@ void Viewport::hideBeingPopup() mBeingPopup->setVisible(false); } -void Viewport::clearHoverBeing(Being *being) +void Viewport::event(const std::string &channel, const Mana::Event &event) { - if (mHoverBeing == being) - mHoverBeing = 0; + if (channel == "ActorSprite" && event.getName() == "Destroyed") + { + ActorSprite *actor = event.getActor("source"); + + if (mHoverBeing == actor) + mHoverBeing = 0; + + if (mHoverItem == actor) + mHoverItem = 0; + } } diff --git a/src/gui/viewport.h b/src/gui/viewport.h index 9658f934..c54b9860 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -22,14 +22,16 @@ #ifndef VIEWPORT_H #define VIEWPORT_H -#include "beingmanager.h" +#include "actorspritemanager.h" #include "configlistener.h" +#include "listener.h" #include "position.h" #include "gui/widgets/windowcontainer.h" #include <guichan/mouselistener.hpp> +class ActorSprite; class Being; class BeingPopup; class FloorItem; @@ -52,7 +54,7 @@ const int walkingMouseDelay = 500; * coordinates. */ class Viewport : public WindowContainer, public gcn::MouseListener, - public ConfigListener + public ConfigListener, public Mana::Listener { public: /** @@ -158,11 +160,7 @@ class Viewport : public WindowContainer, public gcn::MouseListener, */ void hideBeingPopup(); - protected: - friend class BeingManager; - - /// Clears the hovered being if it matches - void clearHoverBeing(Being *being); + void event(const std::string &channel, const Mana::Event &event); private: /** diff --git a/src/gui/widgets/avatarlistbox.cpp b/src/gui/widgets/avatarlistbox.cpp index 6ec4d1e8..6551aa04 100644 --- a/src/gui/widgets/avatarlistbox.cpp +++ b/src/gui/widgets/avatarlistbox.cpp @@ -25,10 +25,10 @@ #include "gui/chat.h" #include "gui/gui.h" #include "gui/palette.h" -#include "gui/theme.h" #include "resources/image.h" #include "resources/resourcemanager.h" +#include "resources/theme.h" #include "utils/stringutils.h" diff --git a/src/gui/widgets/browserbox.cpp b/src/gui/widgets/browserbox.cpp index d43afed7..d890f138 100644 --- a/src/gui/widgets/browserbox.cpp +++ b/src/gui/widgets/browserbox.cpp @@ -21,10 +21,10 @@ #include "gui/widgets/browserbox.h" -#include "gui/theme.h" - #include "gui/widgets/linkhandler.h" +#include "resources/theme.h" + #include <guichan/graphics.hpp> #include <guichan/font.hpp> #include <guichan/cliprectangle.hpp> diff --git a/src/gui/widgets/button.cpp b/src/gui/widgets/button.cpp index 26e0ad90..3d3a07c2 100644 --- a/src/gui/widgets/button.cpp +++ b/src/gui/widgets/button.cpp @@ -25,9 +25,9 @@ #include "graphics.h" #include "gui/palette.h" -#include "gui/theme.h" #include "resources/image.h" +#include "resources/theme.h" #include "utils/dtor.h" @@ -125,8 +125,8 @@ Button::~Button() void Button::updateAlpha() { - float alpha = std::max(config.getValue("guialpha", 0.8f), - (double) Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.getFloatValue("guialpha"), + Theme::instance()->getMinimumOpacity()); if (mAlpha != alpha) { diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp index 39ea6887..fbde2c9c 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" @@ -50,7 +51,7 @@ ChatTab::ChatTab(const std::string &name) : Tab() mTextOutput = new BrowserBox(BrowserBox::AUTO_WRAP); mTextOutput->setOpaque(false); - mTextOutput->setMaxRow((int) config.getValue("ChatLogLength", 0)); + mTextOutput->setMaxRow((int) config.getIntValue("ChatLogLength")); mTextOutput->setLinkHandler(chatWindow->mItemLinkHandler); mScrollArea = new ScrollArea(mTextOutput); @@ -71,7 +72,7 @@ ChatTab::~ChatTab() delete mScrollArea; } -void ChatTab::chatLog(std::string line, int own, bool ignoreRecord) +void ChatTab::chatLog(std::string line, Own own, bool ignoreRecord) { // Trim whitespace trim(line); @@ -180,6 +181,9 @@ void ChatTab::chatLog(std::string line, int own, bool ignoreRecord) line = lineColor + timeStr.str() + tmp.nick + tmp.text; + if (config.getBoolValue("enableChatLog")) + 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..f5682668 100644 --- a/src/gui/widgets/chattab.h +++ b/src/gui/widgets/chattab.h @@ -30,18 +30,6 @@ class BrowserBox; class Recorder; class ScrollArea; -enum -{ - BY_GM, - BY_PLAYER, - BY_OTHER, - BY_SERVER, - BY_CHANNEL, - ACT_WHISPER, // getting whispered at - ACT_IS, // equivalent to "/me" on IRC - BY_LOGGER -}; - /** * A tab for the chat window. This is special to ease chat handling. */ @@ -62,7 +50,8 @@ class ChatTab : public Tab * @param channelName which channel to send the message to. * @param ignoreRecord should this not be recorded? */ - void chatLog(std::string line, int own = BY_SERVER, bool ignoreRecord = false); + void chatLog(std::string line, Own own = BY_SERVER, + bool ignoreRecord = false); /** * Adds the text to the message list @@ -111,6 +100,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/checkbox.cpp b/src/gui/widgets/checkbox.cpp index f9002166..6a44132d 100644 --- a/src/gui/widgets/checkbox.cpp +++ b/src/gui/widgets/checkbox.cpp @@ -25,9 +25,9 @@ #include "graphics.h" #include "gui/palette.h" -#include "gui/theme.h" #include "resources/image.h" +#include "resources/theme.h" int CheckBox::instances = 0; float CheckBox::mAlpha = 1.0; @@ -92,8 +92,8 @@ void CheckBox::draw(gcn::Graphics* graphics) void CheckBox::updateAlpha() { - float alpha = std::max(config.getValue("guialpha", 0.8f), - (double) Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.getFloatValue("guialpha"), + Theme::instance()->getMinimumOpacity()); if (mAlpha != alpha) { diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp index 6c3417e7..ced9c38b 100644 --- a/src/gui/widgets/dropdown.cpp +++ b/src/gui/widgets/dropdown.cpp @@ -26,12 +26,12 @@ #include "gui/palette.h" #include "gui/sdlinput.h" -#include "gui/theme.h" #include "gui/widgets/listbox.h" #include "gui/widgets/scrollarea.h" #include "resources/image.h" +#include "resources/theme.h" #include "utils/dtor.h" @@ -110,8 +110,8 @@ DropDown::~DropDown() void DropDown::updateAlpha() { - float alpha = std::max(config.getValue("guialpha", 0.8f), - (double) Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.getFloatValue("guialpha"), + Theme::instance()->getMinimumOpacity()); if (mAlpha != alpha) { diff --git a/src/gui/widgets/emoteshortcutcontainer.cpp b/src/gui/widgets/emoteshortcutcontainer.cpp index 82fb9f8d..7a24c464 100644 --- a/src/gui/widgets/emoteshortcutcontainer.cpp +++ b/src/gui/widgets/emoteshortcutcontainer.cpp @@ -32,10 +32,10 @@ #include "log.h" #include "gui/palette.h" -#include "gui/theme.h" #include "resources/emotedb.h" #include "resources/image.h" +#include "resources/theme.h" #include "utils/dtor.h" @@ -51,7 +51,7 @@ EmoteShortcutContainer::EmoteShortcutContainer(): mBackgroundImg = Theme::getImageFromTheme("item_shortcut_bgr.png"); - mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8)); + mBackgroundImg->setAlpha(config.getFloatValue("guialpha")); // Setup emote sprites for (int i = 0; i <= EmoteDB::getLast(); i++) @@ -72,9 +72,9 @@ EmoteShortcutContainer::~EmoteShortcutContainer() void EmoteShortcutContainer::draw(gcn::Graphics *graphics) { - if (config.getValue("guialpha", 0.8) != mAlpha) + if (config.getFloatValue("guialpha") != mAlpha) { - mAlpha = config.getValue("guialpha", 0.8); + mAlpha = config.getFloatValue("guialpha"); mBackgroundImg->setAlpha(mAlpha); } diff --git a/src/gui/widgets/itemcontainer.cpp b/src/gui/widgets/itemcontainer.cpp index 7648eb24..a9df95a6 100644 --- a/src/gui/widgets/itemcontainer.cpp +++ b/src/gui/widgets/itemcontainer.cpp @@ -32,7 +32,6 @@ #include "gui/outfitwindow.h" #include "gui/palette.h" #include "gui/sdlinput.h" -#include "gui/theme.h" #include "gui/viewport.h" #include "net/net.h" @@ -40,6 +39,7 @@ #include "resources/image.h" #include "resources/iteminfo.h" +#include "resources/theme.h" #include "utils/stringutils.h" @@ -260,12 +260,12 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event) if (item->isEquipment()) { if (item->isEquipped()) - Net::getInventoryHandler()->unequipItem(item); + item->doEvent("doUnequip"); else - Net::getInventoryHandler()->equipItem(item); + item->doEvent("doEquip"); } else - Net::getInventoryHandler()->useItem(item); + item->doEvent("doUse"); } else @@ -275,18 +275,17 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event) } else if (item && item->getId()) { - if(event.getClickCount() == 2) + if(event.getClickCount() == 2) { if (item->isEquipment()) { if (item->isEquipped()) - Net::getInventoryHandler()->unequipItem(item); + item->doEvent("doUnequip"); else - Net::getInventoryHandler()->equipItem(item); + item->doEvent("doEquip"); } else - Net::getInventoryHandler()->useItem(item); - + item->doEvent("doUse"); } else { @@ -337,7 +336,14 @@ void ItemContainer::mouseReleased(gcn::MouseEvent &event) return; if (index == mSelectedIndex || mSelectedIndex == -1) return; - Net::getInventoryHandler()->moveItem(mSelectedIndex, index); + + Item *item = getSelectedItem(); + { + Mana::Event event("doMove"); + event.setItem("item", item); + event.setInt("newIndex", index); + event.trigger("Item"); + } selectNone(); } @@ -404,8 +410,11 @@ void ItemContainer::keyAction() mSelectedIndex != -1 && mHighlightedIndex != -1) { - Net::getInventoryHandler()->moveItem( - mSelectedIndex, mHighlightedIndex); + Item *item = getSelectedItem(); + Mana::Event event("doMove"); + event.setItem("item", item); + event.setInt("newIndex", mHighlightedIndex); + event.trigger("Item"); setSelectedIndex(mHighlightedIndex); } // If the highlight is on an item then select it. @@ -417,8 +426,11 @@ void ItemContainer::keyAction() // If the highlight is on a blank space then move it. else if (mSelectedIndex != -1) { - Net::getInventoryHandler()->moveItem( - mSelectedIndex, mHighlightedIndex); + Item *item = getSelectedItem(); + Mana::Event event("doMove"); + event.setItem("item", item); + event.setInt("newIndex", mHighlightedIndex); + event.trigger("Item"); selectNone(); } } diff --git a/src/gui/widgets/itemshortcutcontainer.cpp b/src/gui/widgets/itemshortcutcontainer.cpp index 83efd4d4..f2982de9 100644 --- a/src/gui/widgets/itemshortcutcontainer.cpp +++ b/src/gui/widgets/itemshortcutcontainer.cpp @@ -27,16 +27,16 @@ #include "item.h" #include "itemshortcut.h" #include "keyboardconfig.h" -#include "localplayer.h" +#include "playerinfo.h" #include "gui/inventorywindow.h" #include "gui/itempopup.h" #include "gui/palette.h" -#include "gui/theme.h" #include "gui/viewport.h" #include "resources/image.h" #include "resources/iteminfo.h" +#include "resources/theme.h" #include "utils/stringutils.h" @@ -53,7 +53,7 @@ ItemShortcutContainer::ItemShortcutContainer(): mBackgroundImg = Theme::getImageFromTheme("item_shortcut_bgr.png"); mMaxItems = itemShortcut->getItemCount(); - mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8)); + mBackgroundImg->setAlpha(config.getFloatValue("guialpha")); mBoxHeight = mBackgroundImg->getHeight(); mBoxWidth = mBackgroundImg->getWidth(); @@ -67,9 +67,9 @@ ItemShortcutContainer::~ItemShortcutContainer() void ItemShortcutContainer::draw(gcn::Graphics *graphics) { - if (config.getValue("guialpha", 0.8) != mAlpha) + if (config.getFloatValue("guialpha") != mAlpha) { - mAlpha = config.getValue("guialpha", 0.8); + mAlpha = config.getFloatValue("guialpha"); mBackgroundImg->setAlpha(mAlpha); } @@ -94,7 +94,7 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics) continue; Item *item = - player_node->getInventory()->findItem(itemShortcut->getItem(i)); + PlayerInfo::getInventory()->findItem(itemShortcut->getItem(i)); if (item) { @@ -151,7 +151,7 @@ void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) if (itemId < 0) return; - Item *item = player_node->getInventory()->findItem(itemId); + Item *item = PlayerInfo::getInventory()->findItem(itemId); if (item) { @@ -187,7 +187,7 @@ void ItemShortcutContainer::mousePressed(gcn::MouseEvent &event) } else if (event.getButton() == gcn::MouseEvent::RIGHT) { - Item *item = player_node->getInventory()-> + Item *item = PlayerInfo::getInventory()-> findItem(itemShortcut->getItem(index)); if (!item) @@ -240,7 +240,7 @@ void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event) if (itemId < 0) return; - Item *item = player_node->getInventory()->findItem(itemId); + Item *item = PlayerInfo::getInventory()->findItem(itemId); if (item) { diff --git a/src/gui/widgets/label.cpp b/src/gui/widgets/label.cpp index 4c607edf..939e9fc0 100644 --- a/src/gui/widgets/label.cpp +++ b/src/gui/widgets/label.cpp @@ -20,19 +20,20 @@ #include "gui/widgets/label.h" -#include "gui/theme.h" +#include "resources/theme.h" Label::Label() { + setForegroundColor(Theme::getThemeColor(Theme::TEXT)); } Label::Label(const std::string &caption) : gcn::Label(caption) { + setForegroundColor(Theme::getThemeColor(Theme::TEXT)); } void Label::draw(gcn::Graphics *graphics) { - setForegroundColor(Theme::getThemeColor(Theme::TEXT)); gcn::Label::draw(static_cast<gcn::Graphics*>(graphics)); } diff --git a/src/gui/widgets/listbox.cpp b/src/gui/widgets/listbox.cpp index ef591023..d79d8d0c 100644 --- a/src/gui/widgets/listbox.cpp +++ b/src/gui/widgets/listbox.cpp @@ -25,7 +25,8 @@ #include "gui/palette.h" #include "gui/sdlinput.h" -#include "gui/theme.h" + +#include "resources/theme.h" #include <guichan/font.hpp> #include <guichan/graphics.hpp> @@ -45,8 +46,8 @@ ListBox::~ListBox() void ListBox::updateAlpha() { - float alpha = std::max(config.getValue("guialpha", 0.8), - (double) Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.getFloatValue("guialpha"), + Theme::instance()->getMinimumOpacity()); if (mAlpha != alpha) mAlpha = alpha; diff --git a/src/gui/widgets/playerbox.cpp b/src/gui/widgets/playerbox.cpp index 57cbec6f..559ac5a6 100644 --- a/src/gui/widgets/playerbox.cpp +++ b/src/gui/widgets/playerbox.cpp @@ -22,13 +22,12 @@ #include "gui/widgets/playerbox.h" #include "animatedsprite.h" +#include "being.h" #include "configuration.h" #include "graphics.h" -#include "player.h" - -#include "gui/theme.h" #include "resources/image.h" +#include "resources/theme.h" #include "utils/dtor.h" @@ -36,8 +35,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); @@ -57,7 +56,7 @@ PlayerBox::PlayerBox(const Player *player): bggridx[x], bggridy[y], bggridx[x + 1] - bggridx[x] + 1, bggridy[y + 1] - bggridy[y] + 1); - background.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); + background.grid[a]->setAlpha(config.getFloatValue("guialpha")); a++; } } @@ -72,7 +71,7 @@ PlayerBox::~PlayerBox() { instances--; - mPlayer = 0; + mBeing = 0; if (instances == 0) { @@ -82,20 +81,20 @@ 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) + if (config.getFloatValue("guialpha") != mAlpha) { for (int a = 0; a < 9; a++) { - background.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); + background.grid[a]->setAlpha(config.getFloatValue("guialpha")); } } } 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/popup.cpp b/src/gui/widgets/popup.cpp index 4dc58f72..e242bcf4 100644 --- a/src/gui/widgets/popup.cpp +++ b/src/gui/widgets/popup.cpp @@ -26,12 +26,12 @@ #include "graphics.h" #include "log.h" -#include "gui/theme.h" #include "gui/viewport.h" #include "gui/widgets/windowcontainer.h" #include "resources/image.h" +#include "resources/theme.h" #include <guichan/exception.hpp> diff --git a/src/gui/widgets/progressbar.cpp b/src/gui/widgets/progressbar.cpp index 028658ab..15838952 100644 --- a/src/gui/widgets/progressbar.cpp +++ b/src/gui/widgets/progressbar.cpp @@ -27,9 +27,9 @@ #include "gui/gui.h" #include "gui/palette.h" -#include "gui/theme.h" #include "resources/image.h" +#include "resources/theme.h" #include "utils/dtor.h" @@ -123,8 +123,8 @@ void ProgressBar::logic() void ProgressBar::updateAlpha() { - float alpha = std::max(config.getValue("guialpha", 0.8), - (double) Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.getFloatValue("guialpha"), + Theme::instance()->getMinimumOpacity()); if (mAlpha != alpha) { diff --git a/src/gui/widgets/progressindicator.cpp b/src/gui/widgets/progressindicator.cpp index 6bda617f..91b40751 100644 --- a/src/gui/widgets/progressindicator.cpp +++ b/src/gui/widgets/progressindicator.cpp @@ -23,11 +23,10 @@ #include "graphics.h" #include "simpleanimation.h" -#include "gui/theme.h" - #include "resources/animation.h" #include "resources/imageset.h" #include "resources/resourcemanager.h" +#include "resources/theme.h" #include <guichan/widgets/label.hpp> diff --git a/src/gui/widgets/radiobutton.cpp b/src/gui/widgets/radiobutton.cpp index 96797225..1296feb6 100644 --- a/src/gui/widgets/radiobutton.cpp +++ b/src/gui/widgets/radiobutton.cpp @@ -24,9 +24,8 @@ #include "configuration.h" #include "graphics.h" -#include "gui/theme.h" - #include "resources/image.h" +#include "resources/theme.h" int RadioButton::instances = 0; float RadioButton::mAlpha = 1.0; @@ -78,9 +77,9 @@ RadioButton::~RadioButton() void RadioButton::drawBox(gcn::Graphics* graphics) { - if (config.getValue("guialpha", 0.8) != mAlpha) + if (config.getFloatValue("guialpha") != mAlpha) { - mAlpha = config.getValue("guialpha", 0.8); + mAlpha = config.getFloatValue("guialpha"); radioNormal->setAlpha(mAlpha); radioChecked->setAlpha(mAlpha); radioDisabled->setAlpha(mAlpha); diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp index f0c3691c..7850643f 100644 --- a/src/gui/widgets/resizegrip.cpp +++ b/src/gui/widgets/resizegrip.cpp @@ -24,9 +24,8 @@ #include "configuration.h" #include "graphics.h" -#include "gui/theme.h" - #include "resources/image.h" +#include "resources/theme.h" #include <guichan/graphics.hpp> @@ -59,9 +58,9 @@ ResizeGrip::~ResizeGrip() void ResizeGrip::draw(gcn::Graphics *graphics) { - if (config.getValue("guialpha", 0.8) != mAlpha) + if (config.getFloatValue("guialpha") != mAlpha) { - mAlpha = config.getValue("guialpha", 0.8); + mAlpha = config.getFloatValue("guialpha"); gripImage->setAlpha(mAlpha); } diff --git a/src/gui/widgets/scrollarea.cpp b/src/gui/widgets/scrollarea.cpp index 0c7f4d7d..7d42883a 100644 --- a/src/gui/widgets/scrollarea.cpp +++ b/src/gui/widgets/scrollarea.cpp @@ -24,9 +24,8 @@ #include "configuration.h" #include "graphics.h" -#include "gui/theme.h" - #include "resources/image.h" +#include "resources/theme.h" #include "utils/dtor.h" @@ -108,7 +107,7 @@ void ScrollArea::init() bggridx[x], bggridy[y], bggridx[x + 1] - bggridx[x] + 1, bggridy[y + 1] - bggridy[y] + 1); - background.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); + background.grid[a]->setAlpha(config.getFloatValue("guialpha")); a++; } } @@ -135,8 +134,8 @@ void ScrollArea::init() vsgridx[x], vsgridy[y], vsgridx[x + 1] - vsgridx[x], vsgridy[y + 1] - vsgridy[y]); - vMarker.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); - vMarkerHi.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); + vMarker.grid[a]->setAlpha(config.getFloatValue("guialpha")); + vMarkerHi.grid[a]->setAlpha(config.getFloatValue("guialpha")); a++; } } @@ -213,8 +212,8 @@ void ScrollArea::logic() void ScrollArea::updateAlpha() { - float alpha = std::max(config.getValue("guialpha", 0.8), - (double) Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.getFloatValue("guialpha"), + Theme::instance()->getMinimumOpacity()); if (alpha != mAlpha) { diff --git a/src/gui/widgets/shoplistbox.cpp b/src/gui/widgets/shoplistbox.cpp index 2f5fab34..c0a79500 100644 --- a/src/gui/widgets/shoplistbox.cpp +++ b/src/gui/widgets/shoplistbox.cpp @@ -26,12 +26,12 @@ #include "shopitem.h" #include "gui/itempopup.h" -#include "gui/theme.h" #include "gui/viewport.h" #include "gui/widgets/shopitems.h" #include "resources/image.h" +#include "resources/theme.h" #include <guichan/font.hpp> #include <guichan/listmodel.hpp> @@ -71,8 +71,8 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) if (!mListModel) return; - if (config.getValue("guialpha", 0.8) != mAlpha) - mAlpha = config.getValue("guialpha", 0.8); + if (config.getFloatValue("guialpha") != mAlpha) + mAlpha = config.getFloatValue("guialpha"); int alpha = (int)(mAlpha * 255.0f); const gcn::Color* highlightColor = diff --git a/src/gui/widgets/slider.cpp b/src/gui/widgets/slider.cpp index 6a9a5c7c..c044d55d 100644 --- a/src/gui/widgets/slider.cpp +++ b/src/gui/widgets/slider.cpp @@ -24,9 +24,8 @@ #include "configuration.h" #include "graphics.h" -#include "gui/theme.h" - #include "resources/image.h" +#include "resources/theme.h" Image *Slider::hStart, *Slider::hMid, *Slider::hEnd, *Slider::hGrip; Image *Slider::vStart, *Slider::vMid, *Slider::vEnd, *Slider::vGrip; @@ -126,8 +125,8 @@ void Slider::init() void Slider::updateAlpha() { - float alpha = std::max(config.getValue("guialpha", 0.8), - (double) Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.getFloatValue("guialpha"), + Theme::instance()->getMinimumOpacity()); if (alpha != mAlpha) { diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp index 2ab126dd..10a51afe 100644 --- a/src/gui/widgets/tab.cpp +++ b/src/gui/widgets/tab.cpp @@ -25,11 +25,11 @@ #include "graphics.h" #include "gui/palette.h" -#include "gui/theme.h" #include "gui/widgets/tabbedarea.h" #include "resources/image.h" +#include "resources/theme.h" #include "utils/dtor.h" @@ -118,8 +118,8 @@ void Tab::init() void Tab::updateAlpha() { - float alpha = std::max(config.getValue("guialpha", 0.8), - (double) Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.getFloatValue("guialpha"), + Theme::instance()->getMinimumOpacity()); // TODO We don't need to do this for every tab on every draw // Maybe use a config listener to do it as the value changes. diff --git a/src/gui/widgets/table.cpp b/src/gui/widgets/table.cpp index f0887ed7..3d8680ce 100644 --- a/src/gui/widgets/table.cpp +++ b/src/gui/widgets/table.cpp @@ -24,7 +24,8 @@ #include "configuration.h" #include "gui/sdlinput.h" -#include "gui/theme.h" + +#include "resources/theme.h" #include "utils/dtor.h" @@ -270,8 +271,8 @@ void GuiTable::draw(gcn::Graphics* graphics) if (!mModel) return; - if (config.getValue("guialpha", 0.8) != mAlpha) - mAlpha = config.getValue("guialpha", 0.8); + if (config.getFloatValue("guialpha") != mAlpha) + mAlpha = config.getFloatValue("guialpha"); if (mOpaque) { diff --git a/src/gui/widgets/textbox.cpp b/src/gui/widgets/textbox.cpp index f248f35d..5b112e54 100644 --- a/src/gui/widgets/textbox.cpp +++ b/src/gui/widgets/textbox.cpp @@ -21,7 +21,7 @@ #include "gui/widgets/textbox.h" -#include "gui/theme.h" +#include "resources/theme.h" #include <guichan/font.hpp> diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp index 4453f522..9696cd59 100644 --- a/src/gui/widgets/textfield.cpp +++ b/src/gui/widgets/textfield.cpp @@ -26,9 +26,9 @@ #include "gui/palette.h" #include "gui/sdlinput.h" -#include "gui/theme.h" #include "resources/image.h" +#include "resources/theme.h" #include "utils/copynpaste.h" #include "utils/dtor.h" @@ -65,7 +65,7 @@ TextField::TextField(const std::string &text, bool loseFocusOnTab): gridx[x], gridy[y], gridx[x + 1] - gridx[x] + 1, gridy[y + 1] - gridy[y] + 1); - skin.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); + skin.grid[a]->setAlpha(config.getFloatValue("guialpha")); a++; } } @@ -86,8 +86,8 @@ TextField::~TextField() void TextField::updateAlpha() { - float alpha = std::max(config.getValue("guialpha", 0.8), - (double) Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.getFloatValue("guialpha"), + Theme::instance()->getMinimumOpacity()); if (alpha != mAlpha) { diff --git a/src/gui/widgets/textpreview.cpp b/src/gui/widgets/textpreview.cpp index 10426d7c..869ebd35 100644 --- a/src/gui/widgets/textpreview.cpp +++ b/src/gui/widgets/textpreview.cpp @@ -45,8 +45,8 @@ TextPreview::TextPreview(const std::string &text): void TextPreview::draw(gcn::Graphics* graphics) { - if (config.getValue("guialpha", 0.8) != mAlpha) - mAlpha = config.getValue("guialpha", 0.8); + if (config.getFloatValue("guialpha") != mAlpha) + mAlpha = config.getFloatValue("guialpha"); int alpha = (int) (mAlpha * 255.0f); diff --git a/src/gui/widgets/whispertab.cpp b/src/gui/widgets/whispertab.cpp index 7542e251..864f1f51 100644 --- a/src/gui/widgets/whispertab.cpp +++ b/src/gui/widgets/whispertab.cpp @@ -21,14 +21,15 @@ #include "whispertab.h" +#include "chatlog.h" #include "commandhandler.h" #include "localplayer.h" -#include "gui/theme.h" - #include "net/chathandler.h" #include "net/net.h" +#include "resources/theme.h" + #include "utils/gettext.h" #include "utils/stringutils.h" @@ -115,3 +116,9 @@ bool WhisperTab::handleCommand(const std::string &type, return true; } + +void WhisperTab::saveToLogFile(std::string &msg) +{ + if (chatLogger) + chatLogger->log(getNick(), msg); +} 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/gui/widgets/window.cpp b/src/gui/widgets/window.cpp index 118ee7c0..aa8e6df3 100644 --- a/src/gui/widgets/window.cpp +++ b/src/gui/widgets/window.cpp @@ -26,7 +26,6 @@ #include "gui/gui.h" #include "gui/palette.h" -#include "gui/theme.h" #include "gui/viewport.h" #include "gui/widgets/layout.h" @@ -34,6 +33,7 @@ #include "gui/widgets/windowcontainer.h" #include "resources/image.h" +#include "resources/theme.h" #include <guichan/exception.hpp> #include <guichan/focushandler.hpp> @@ -697,8 +697,8 @@ int Window::getResizeHandles(gcn::MouseEvent &event) int Window::getGuiAlpha() { - float alpha = std::max(config.getValue("guialpha", 0.8), - (double) Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.getFloatValue("guialpha"), + Theme::instance()->getMinimumOpacity()); return (int) (alpha * 255.0f); } diff --git a/src/gui/windowmenu.cpp b/src/gui/windowmenu.cpp index 5af5a202..76e6bc1f 100644 --- a/src/gui/windowmenu.cpp +++ b/src/gui/windowmenu.cpp @@ -58,7 +58,7 @@ WindowMenu::WindowMenu(): if (skillDialog->hasSkills()) addButton(N_("Skills"), x, h); - if (specialsWindow->hasSpecials()) + // if (specialsWindow->hasSpecials()) addButton(N_("Specials"), x, h); addButton(N_("Social"), x, h); 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..3a3678d9 --- /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(std::string 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/inventory.cpp b/src/inventory.cpp index a6038c85..7684b54c 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -19,6 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "event.h" #include "inventory.h" #include "item.h" #include "log.h" @@ -36,7 +37,7 @@ struct SlotUsed : public std::unary_function<Item*, bool> } }; -Inventory::Inventory(int type, int size): +Inventory::Inventory(Type type, int size): mType(type), mSize(size == -1 ? Net::getInventoryHandler()->getSize(type) : size), mUsed(0) diff --git a/src/inventory.h b/src/inventory.h index 0ee516d6..088dfb8f 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -43,7 +43,7 @@ class Inventory public: static const int NO_SLOT_INDEX = -1; /**< Slot has no index. */ - enum { + enum Type { INVENTORY, STORAGE, TRADE, @@ -56,7 +56,7 @@ class Inventory * * @param size the number of items that fit in the inventory */ - Inventory(int type, int size = -1); + Inventory(Type type, int size = -1); /** * Destructor. @@ -143,7 +143,7 @@ class Inventory void distributeSlotsChangedEvent(); - int mType; + Type mType; Item **mItems; /**< The holder of items */ int mSize; /**< The max number of inventory items */ int mUsed; /**< THe number of slots in use */ diff --git a/src/item.cpp b/src/item.cpp index b434387e..7a8ccf6d 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -21,12 +21,13 @@ #include "item.h" -#include "gui/theme.h" +#include "configuration.h" +#include "event.h" #include "resources/image.h" #include "resources/iteminfo.h" #include "resources/resourcemanager.h" -#include "configuration.h" +#include "resources/theme.h" Item::Item(int id, int quantity, bool equipment, bool equipped): mImage(0), @@ -58,8 +59,9 @@ void Item::setId(int id) mDrawImage->decRef(); ResourceManager *resman = ResourceManager::getInstance(); - std::string imagePath = paths.getValue("itemIcons", "graphics/items/") - + getInfo().getImageName(); + SpriteDisplay display = getInfo().getDisplay(); + std::string imagePath = paths.getStringValue("itemIcons") + + display.image; mImage = resman->getImage(imagePath); mDrawImage = resman->getImage(imagePath); @@ -72,3 +74,18 @@ void Item::setId(int id) paths.getValue("unknownItemFile", "unknown-item.png")); } + +void Item::doEvent(const std::string &eventName) +{ + Mana::Event event(eventName); + event.setItem("item", this); + event.trigger("Item"); +} + +void Item::doEvent(const std::string &eventName, int amount) +{ + Mana::Event event(eventName); + event.setItem("item", this); + event.setInt("amount", amount); + event.trigger("Item"); +} @@ -118,6 +118,10 @@ class Item */ int getInvIndex() const { return mInvIndex; } + void doEvent(const std::string &eventName); + + void doEvent(const std::string &eventName, int amount); + /** * Returns information about this item type. */ diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp index 88b04347..eaf16889 100644 --- a/src/itemshortcut.cpp +++ b/src/itemshortcut.cpp @@ -20,10 +20,11 @@ */ #include "configuration.h" +#include "event.h" #include "inventory.h" #include "item.h" #include "itemshortcut.h" -#include "localplayer.h" +#include "playerinfo.h" #include "net/inventoryhandler.h" #include "net/net.h" @@ -66,20 +67,18 @@ void ItemShortcut::useItem(int index) { if (mItems[index]) { - Item *item = player_node->getInventory()->findItem(mItems[index]); + Item *item = PlayerInfo::getInventory()->findItem(mItems[index]); if (item && item->getQuantity()) { if (item->isEquipment()) { if (item->isEquipped()) - Net::getInventoryHandler()->unequipItem(item); + item->doEvent("doUnequip"); else - Net::getInventoryHandler()->equipItem(item); + item->doEvent("doEquip"); } else - { - Net::getInventoryHandler()->useItem(item); - } + item->doEvent("doUse"); } } } diff --git a/src/joystick.cpp b/src/joystick.cpp index f440c61f..9864a12b 100644 --- a/src/joystick.cpp +++ b/src/joystick.cpp @@ -61,11 +61,11 @@ Joystick::Joystick(int no): logger->log("Hats: %i", SDL_JoystickNumHats(mJoystick)); logger->log("Buttons: %i", SDL_JoystickNumButtons(mJoystick)); - mEnabled = (int) config.getValue("joystickEnabled", 0) != 0; - mUpTolerance = (int) config.getValue("upTolerance", 100); - mDownTolerance = (int) config.getValue("downTolerance", 100); - mLeftTolerance = (int) config.getValue("leftTolerance", 100); - mRightTolerance = (int) config.getValue("rightTolerance", 100); + mEnabled = config.getBoolValue("joystickEnabled"); + mUpTolerance = config.getIntValue("upTolerance"); + mDownTolerance = config.getIntValue("downTolerance"); + mLeftTolerance = config.getIntValue("leftTolerance"); + mRightTolerance = config.getIntValue("rightTolerance"); } Joystick::~Joystick() diff --git a/src/listener.cpp b/src/listener.cpp new file mode 100644 index 00000000..a9182c42 --- /dev/null +++ b/src/listener.cpp @@ -0,0 +1,43 @@ +/* + * 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 "listener.h" + +#include "event.h" + +namespace Mana +{ + +Listener::~Listener() +{ + Event::remove(this); +} + +void Listener::listen(const std::string &channel) +{ + Event::bind(this, channel); +} + +void Listener::ignore(const std::string &channel) +{ + Event::unbind(this, channel); +} + +} // namespace Mana diff --git a/src/flooritemmanager.h b/src/listener.h index 62ca8dc2..db7b3221 100644 --- a/src/flooritemmanager.h +++ b/src/listener.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. * @@ -19,36 +18,28 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef FLOORITEMMANAGER_H -#define FLOORITEMMANAGER_H +#ifndef LISTENER_H +#define LISTENER_H -#include <list> +#include "event.h" -class FloorItem; -class Map; +#include <string> -class FloorItemManager +namespace Mana { - public: - ~FloorItemManager(); - FloorItem *create(int id, int itemId, int x, int y); - - void destroy(FloorItem *item); - - void clear(); +class Listener +{ +public: + virtual ~Listener(); - FloorItem *findById(int id) const; - FloorItem *findByCoordinates(int x, int y) const; + void listen(const std::string &channel); - private: - typedef std::list<FloorItem*> FloorItems; - typedef FloorItems::iterator FloorItemIterator; - FloorItems mFloorItems; + void ignore(const std::string &channel); + virtual void event(const std::string &channel, const Event &event) = 0; }; -// TODO Get rid of the global? -extern FloorItemManager *floorItemManager; +} // namespace Mana #endif diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 9c64c6dc..4577fd16 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -24,29 +24,21 @@ #include "client.h" #include "configuration.h" #include "effectmanager.h" -#include "equipment.h" +#include "event.h" #include "flooritem.h" #include "graphics.h" #include "guild.h" -#include "inventory.h" #include "item.h" #include "log.h" #include "map.h" -#include "monster.h" #include "particle.h" +#include "playerinfo.h" #include "simpleanimation.h" #include "sound.h" -#include "statuseffect.h" #include "text.h" #include "gui/gui.h" -#include "gui/inventorywindow.h" -#include "gui/ministatus.h" #include "gui/okdialog.h" -#include "gui/skilldialog.h" -#include "gui/statuswindow.h" -#include "gui/theme.h" -#include "gui/userpalette.h" #include "gui/widgets/chattab.h" @@ -61,9 +53,10 @@ #include "resources/animation.h" #include "resources/imageset.h" -#include "resources/itemdb.h" #include "resources/iteminfo.h" #include "resources/resourcemanager.h" +#include "resources/theme.h" +#include "resources/userpalette.h" #include "utils/gettext.h" #include "utils/stringutils.h" @@ -80,62 +73,39 @@ const short walkingKeyboardDelay = 1000; LocalPlayer *player_node = NULL; LocalPlayer::LocalPlayer(int id, int subtype): - Player(id, subtype, 0), - mEquipment(new Equipment), + Being(id, PLAYER, subtype, 0), mAttackRange(0), mTargetTime(-1), mLastTarget(-1), - mCharacterPoints(0), - mCorrectionPoints(0), - mSpecialRechargeUpdateNeeded(0), - mLevel(1), - mExp(0), mExpNeeded(0), - mMp(0), mMaxMp(0), - mMoney(0), - mTotalWeight(1), mMaxWeight(1), - mHp(1), mMaxHp(1), - mSkillPoints(0), mTarget(NULL), mPlayerFollowed(""), mPickUpTarget(NULL), - mTrading(false), mGoingToTarget(false), mKeepAttacking(false), + mGoingToTarget(false), mKeepAttacking(false), mLastAction(-1), mWalkingDir(0), mPathSetByMouse(false), - mInventory(new Inventory(Inventory::INVENTORY)), mLocalWalkTime(-1), mMessageTime(0), mAwayDialog(0), mAfkTime(0), mAwayMode(false) { + listen("Attributes"); + mAwayListener = new AwayListener(); mUpdateName = true; - mTextColor = &Theme::getThemeColor(Theme::PLAYER); - mNameColor = &userPalette->getColor(UserPalette::SELF); - - initTargetCursor(); - config.addListener("showownname", this); setShowName(config.getValue("showownname", 1)); + + listen("ActorSprite"); } LocalPlayer::~LocalPlayer() { - delete mInventory; - 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; } @@ -170,21 +140,7 @@ void LocalPlayer::logic() mMessageTime--; } - if ((mSpecialRechargeUpdateNeeded%11) == 0) - { - mSpecialRechargeUpdateNeeded = 0; - for (std::map<int, Special>::iterator i = mSpecials.begin(); - i != mSpecials.end(); - i++) - { - i->second.currentMana += i->second.recharge; - if (i->second.currentMana > i->second.neededMana) - { - i->second.currentMana = i->second.neededMana; - } - } - } - mSpecialRechargeUpdateNeeded++; + PlayerInfo::logic(); // Targeting allowed 4 times a second if (get_elapsed_time(mLastTarget) >= 250) @@ -200,11 +156,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 +175,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 +188,7 @@ void LocalPlayer::logic() } } - Player::logic(); + Being::logic(); } void LocalPlayer::setAction(Action action, int attackType) @@ -244,12 +199,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 +585,7 @@ void LocalPlayer::nextTile(unsigned char dir = 0) } - Player::nextTile(); + Being::nextTile(); } else { @@ -674,7 +624,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,31 +633,19 @@ 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; } } } -void LocalPlayer::clearInventory() -{ - mEquipment->clear(); - mInventory->clear(); -} - -void LocalPlayer::setInvItem(int index, int id, int amount) -{ - bool equipment = false; - int itemType = ItemDB::get(id).getType(); - if (itemType != ITEM_UNUSABLE && itemType != ITEM_USABLE) - equipment = true; - mInventory->setItem(index, id, amount, equipment); -} - void LocalPlayer::pickUp(FloorItem *item) { - int dx = item->getX() - (int) getPosition().x / 32; - int dy = item->getY() - (int) getPosition().y / 32; + if (!item) + return; + + int dx = item->getTileX() - (int) getPosition().x / 32; + int dy = item->getTileY() - (int) getPosition().y / 32; if (dx * dx + dy * dy < 4) { @@ -719,12 +656,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 +694,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); } @@ -822,11 +768,11 @@ void LocalPlayer::setWalkingDir(int dir) mWalkingDir = dir; // If we're not already walking, start walking. - if (mAction != WALK && dir) + if (mAction != MOVE && dir) { startWalking(dir); } - else if (mAction == WALK && (Net::getNetworkType() == ServerInfo::MANASERV)) + else if (mAction == MOVE && (Net::getNetworkType() == ServerInfo::MANASERV)) { nextTile(dir); } @@ -839,7 +785,7 @@ void LocalPlayer::startWalking(unsigned char dir) if (!mMap || !dir) return; - if (mAction == WALK && !mPath.empty()) + if (mAction == MOVE && !mPath.empty()) { // Just finish the current action, otherwise we get out of sync if (Net::getNetworkType() == ServerInfo::MANASERV) @@ -894,7 +840,7 @@ void LocalPlayer::startWalking(unsigned char dir) void LocalPlayer::stopWalking(bool sendToServer) { - if (mAction == WALK && mWalkingDir) + if (mAction == MOVE && mWalkingDir) { mWalkingDir = 0; mLocalWalkTime = 0; @@ -938,20 +884,6 @@ void LocalPlayer::emote(Uint8 emotion) Net::getPlayerHandler()->emote(emotion); } -void LocalPlayer::useSpecial(int special) -{ - Net::getSpecialHandler()->use(special); -} - -void LocalPlayer::setSpecialStatus(int id, int current, int max, int recharge) -{ - logger->log("SpecialUpdate Skill #%d -- (%d/%d) -> %d", id, current, max, - recharge); - mSpecials[id].currentMana = current; - mSpecials[id].neededMana = max; - mSpecials[id].recharge = recharge; -} - void LocalPlayer::attack(Being *target, bool keep) { if (Net::getNetworkType() == ServerInfo::MANASERV) @@ -966,7 +898,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) @@ -974,6 +906,7 @@ void LocalPlayer::attack(Being *target, bool keep) mLastTarget = -1; setTarget(target); } + if (Net::getNetworkType() == ServerInfo::MANASERV) { Vector plaPos = this->getPosition(); @@ -1022,7 +955,7 @@ void LocalPlayer::attack(Being *target, bool keep) setDirection(LEFT); } - mWalkTime = tick_time; + mActionTime = tick_time; mTargetTime = tick_time; } @@ -1053,196 +986,13 @@ void LocalPlayer::stopAttack() mLastTarget = -1; } -void LocalPlayer::raiseAttribute(int attr) -{ - // we assume that the server allows the change. - // When not we will undo it later. - mCharacterPoints--; - IntMap::iterator it = mAttributeBase.find(attr); - if (it != mAttributeBase.end()) - (*it).second++; - Net::getPlayerHandler()->increaseAttribute(attr); -} - -void LocalPlayer::lowerAttribute(int attr) -{ - // we assume that the server allows the change. - // When not we will undo it later. - mCorrectionPoints--; - mCharacterPoints++; - IntMap::iterator it = mAttributeBase.find(attr); - if (it != mAttributeBase.end()) - (*it).second--; - Net::getPlayerHandler()->decreaseAttribute(attr); -} - -void LocalPlayer::setTotalWeight(int value) -{ - mTotalWeight = value; - - inventoryWindow->updateWeight(); -} - -void LocalPlayer::setMaxWeight(int value) -{ - mMaxWeight = value; - - inventoryWindow->updateWeight(); -} - -void LocalPlayer::setAttributeBase(int num, int value, bool notify) -{ - int old = mAttributeBase[num]; - - mAttributeBase[num] = value; - if (skillDialog) - { - if (skillDialog->update(num).empty() || !(value > old)) - return; - - if (old != 0 && notify) - effectManager->trigger(1, this); - } - - if (statusWindow) - statusWindow->update(num); -} - -void LocalPlayer::setAttributeEffective(int num, int value) -{ - mAttributeEffective[num] = value; - if (skillDialog) - skillDialog->update(num); - - if (statusWindow) - statusWindow->update(num); -} - -void LocalPlayer::setCharacterPoints(int n) -{ - mCharacterPoints = n; - - if (statusWindow) - statusWindow->update(StatusWindow::CHAR_POINTS); -} - -void LocalPlayer::setCorrectionPoints(int n) -{ - mCorrectionPoints = n; - - if (statusWindow) - statusWindow->update(StatusWindow::CHAR_POINTS); -} - -void LocalPlayer::setSkillPoints(int points) -{ - mSkillPoints = points; - if (skillDialog) - skillDialog->update(); -} - -void LocalPlayer::setExperience(int skill, int current, int next, bool notify) -{ - std::pair<int, int> cur = getExperience(skill); - int diff = current - cur.first; - - cur = std::pair<int, int>(current, next); - - mSkillExp[skill] = cur; - - std::string name; - if (skillDialog) - name = skillDialog->update(skill); - - if (mMap && notify && cur.first != -1 && diff > 0 && !name.empty()) - { - addMessageToQueue(strprintf("%d %s xp", diff, name.c_str())); - } - - if (statusWindow) - statusWindow->update(skill); -} - -std::pair<int, int> LocalPlayer::getExperience(int skill) -{ - return mSkillExp[skill]; -} - -void LocalPlayer::setHp(int value) -{ - mHp = value; - - if (statusWindow) - statusWindow->update(StatusWindow::HP); -} - -void LocalPlayer::setMaxHp(int value) -{ - mMaxHp = value; - - if (statusWindow) - statusWindow->update(StatusWindow::HP); -} - -void LocalPlayer::setLevel(int value) -{ - mLevel = value; - - if (statusWindow) - statusWindow->update(StatusWindow::LEVEL); -} - -void LocalPlayer::setExp(int value, bool notify) -{ - if (mMap && notify && value > mExp) - { - addMessageToQueue(toString(value - mExp) + " xp"); - } - mExp = value; - - if (statusWindow) - statusWindow->update(StatusWindow::EXP); -} - -void LocalPlayer::setExpNeeded(int value) -{ - mExpNeeded = value; - - if (statusWindow) - statusWindow->update(StatusWindow::EXP); -} - -void LocalPlayer::setMP(int value) -{ - mMp = value; - - if (statusWindow) - statusWindow->update(StatusWindow::MP); -} - -void LocalPlayer::setMaxMP(int value) -{ - mMaxMp = value; - - if (statusWindow) - statusWindow->update(StatusWindow::MP); -} - -void LocalPlayer::setMoney(int value) -{ - mMoney = value; - - if (statusWindow) - statusWindow->update(StatusWindow::MONEY); -} - void LocalPlayer::pickedUp(const ItemInfo &itemInfo, int amount) { if (!amount) { if (config.getValue("showpickupchat", 1)) { - localChatTab->chatLog(_("Unable to pick up item."), BY_SERVER); + SERVER_NOTICE(_("Unable to pick up item.")) } } else @@ -1251,10 +1001,9 @@ void LocalPlayer::pickedUp(const ItemInfo &itemInfo, int amount) { // TRANSLATORS: This sentence may be translated differently // for different grammatical numbers (singular, plural, ...) - localChatTab->chatLog(strprintf(ngettext("You picked up %d " + SERVER_NOTICE(strprintf(ngettext("You picked up %d " "[@@%d|%s@@].", "You picked up %d [@@%d|%s@@].", amount), - amount, itemInfo.getId(), itemInfo.getName().c_str()), - BY_SERVER); + amount, itemInfo.getId(), itemInfo.getName().c_str())) } if (mMap && config.getValue("showpickupparticle", 0)) @@ -1273,7 +1022,8 @@ int LocalPlayer::getAttackRange() } else { - Item *weapon = mEquipment->getEquipment(EQUIP_FIGHT1_SLOT); + // TODO: Fix this to be more generic + Item *weapon = PlayerInfo::getEquipment(EQUIP_FIGHT1_SLOT); if (weapon) { const ItemInfo info = weapon->getInfo(); @@ -1325,102 +1075,49 @@ void LocalPlayer::setGotoTarget(Being *target) } } -extern MiniStatusWindow *miniStatusWindow; +void LocalPlayer::addMessageToQueue(const std::string &message, int color) +{ + mMessages.push_back(MessagePair(message, color)); +} -void LocalPlayer::handleStatusEffect(StatusEffect *effect, int effectId) +void LocalPlayer::optionChanged(const std::string &value) { - Being::handleStatusEffect(effect, effectId); + if (value == "showownname") + { + setShowName(config.getValue("showownname", 1)); + } +} - if (effect) +void LocalPlayer::event(const std::string &channel, const Mana::Event &event) +{ + if (channel == "ActorSprite") { - effect->deliverMessage(); - effect->playSFX(); + if (event.getName() == "Destroyed") + { + ActorSprite *actor = event.getActor("source"); - AnimatedSprite *sprite = effect->getIcon(); + if (mPickUpTarget == actor) + mPickUpTarget = 0; - if (!sprite) - { - // delete sprite, if necessary - for (unsigned int i = 0; i < mStatusEffectIcons.size();) - if (mStatusEffectIcons[i] == effectId) - { - mStatusEffectIcons.erase(mStatusEffectIcons.begin() + i); - miniStatusWindow->eraseIcon(i); - } - else - i++; + if (mTarget == actor) + mTarget = 0; } - else + } + else if (channel == "Attributes") + { + if (event.getName() == "UpdateAttribute") { - // replace sprite or append - bool found = false; - - for (unsigned int i = 0; i < mStatusEffectIcons.size(); i++) - if (mStatusEffectIcons[i] == effectId) - { - miniStatusWindow->setIcon(i, sprite); - found = true; - break; - } + if (event.getInt("id") == EXP) + { + int change = event.getInt("newValue") + - event.getInt("oldValue"); - if (!found) - { // add new - int offset = mStatusEffectIcons.size(); - miniStatusWindow->setIcon(offset, sprite); - mStatusEffectIcons.push_back(effectId); + addMessageToQueue(toString(change) + " xp"); } } } -} - -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)); -} - -void LocalPlayer::optionChanged(const std::string &value) -{ - if (value == "showownname") - { - setShowName(config.getValue("showownname", 1)); - } + Being::event(channel, event); } void LocalPlayer::changeAwayMode() diff --git a/src/localplayer.h b/src/localplayer.h index 2c06dfb5..6b50091a 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -22,9 +22,9 @@ #ifndef LOCALPLAYER_H #define LOCALPLAYER_H -#include "player.h" +#include "being.h" -#include "gui/userpalette.h" +#include "resources/userpalette.h" #include <guichan/actionlistener.hpp> @@ -32,84 +32,22 @@ #include <vector> class ChatTab; -class Equipment; class FloorItem; class ImageSet; -class Inventory; class Item; class Map; class OkDialog; - -struct Special -{ - int currentMana; - int neededMana; - int recharge; -}; - class AwayListener : public gcn::ActionListener { public: void action(const gcn::ActionEvent &event); }; - -/** - * Attributes used during combat. Available to all the beings. - */ -enum -{ -BASE_ATTR_BEGIN = 0, - BASE_ATTR_PHY_ATK_MIN = BASE_ATTR_BEGIN, - BASE_ATTR_PHY_ATK_DELTA, - /**< Physical attack power. */ - BASE_ATTR_MAG_ATK, /**< Magical attack power. */ - BASE_ATTR_PHY_RES, /**< Resistance to physical damage. */ - BASE_ATTR_MAG_RES, /**< Resistance to magical damage. */ - BASE_ATTR_EVADE, /**< Ability to avoid hits. */ - BASE_ATTR_HIT, /**< Ability to hit stuff. */ - BASE_ATTR_HP, /**< Hit Points (Base value: maximum, Modded value: current) */ - BASE_ATTR_HP_REGEN,/**< number of HP regenerated every 10 game ticks */ - BASE_ATTR_END, - BASE_ATTR_NB = BASE_ATTR_END - BASE_ATTR_BEGIN, - - BASE_ELEM_BEGIN = BASE_ATTR_END, - BASE_ELEM_NEUTRAL = BASE_ELEM_BEGIN, - BASE_ELEM_FIRE, - BASE_ELEM_WATER, - BASE_ELEM_EARTH, - BASE_ELEM_AIR, - BASE_ELEM_SACRED, - BASE_ELEM_DEATH, - BASE_ELEM_END, - BASE_ELEM_NB = BASE_ELEM_END - BASE_ELEM_BEGIN, - - NB_BEING_ATTRIBUTES = BASE_ELEM_END -}; - -/** - * Attributes of characters. Used to derive being attributes. - */ -enum -{ - CHAR_ATTR_BEGIN = NB_BEING_ATTRIBUTES, - CHAR_ATTR_STRENGTH = CHAR_ATTR_BEGIN, - CHAR_ATTR_AGILITY, - CHAR_ATTR_DEXTERITY, - CHAR_ATTR_VITALITY, - CHAR_ATTR_INTELLIGENCE, - CHAR_ATTR_WILLPOWER, - CHAR_ATTR_END, - CHAR_ATTR_NB = CHAR_ATTR_END - CHAR_ATTR_BEGIN, - - NB_CHARACTER_ATTRIBUTES = CHAR_ATTR_END -}; - /** * The local player character. */ -class LocalPlayer : public Player +class LocalPlayer : public Being { public: /** @@ -144,11 +82,6 @@ class LocalPlayer : public Player virtual void nextTile(unsigned char dir); /** - * Returns the player's inventory. - */ - Inventory *getInventory() const { return mInventory; } - - /** * Check the player has permission to invite users to specific guild */ bool checkInviteRights(const std::string &guildName); @@ -158,9 +91,6 @@ class LocalPlayer : public Player */ void inviteToGuild(Being *being); - void clearInventory(); - void setInvItem(int index, int id, int amount); - void pickUp(FloorItem *item); /** @@ -172,33 +102,8 @@ class LocalPlayer : public Player * Gets the attack range. */ int getAttackRange(); - - /** - * Returns true when the player is ready to accept a trade offer. - * Returns false otherwise. - */ - bool tradeRequestOk() const { return !mTrading; } - - /** - * Sets the trading state of the player, i.e. whether or not he is - * currently involved into some trade. - */ - void setTrading(bool trading) { mTrading = trading; } - - void useSpecial(int id); - - void setSpecialStatus(int id, int current, int max, int recharge); - - const std::map<int, Special> &getSpecialStatus() const - { return mSpecials; } - 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(); @@ -257,16 +162,6 @@ class LocalPlayer : public Player */ void stopWalking(bool sendToServer = true); - /** - * Uses a character point to raise an attribute - */ - void raiseAttribute(int attr); - - /** - * Uses a correction point to lower an attribute - */ - void lowerAttribute(int attr); - void toggleSit(); void emote(Uint8 emotion); @@ -275,85 +170,6 @@ class LocalPlayer : public Player */ void pickedUp(const ItemInfo &itemInfo, int amount); - int getHp() const - { return mHp; } - - int getMaxHp() const - { return mMaxHp; } - - void setHp(int value); - - void setMaxHp(int value); - - int getLevel() const - { return mLevel; } - - void setLevel(int value); - - void setExp(int value, bool notify = true); - - int getExp() const - { return mExp; } - - void setExpNeeded(int value); - - int getExpNeeded() const - { return mExpNeeded; } - - void setMP(int value); - - int getMP() const - { return mMp; } - - void setMaxMP(int value); - - int getMaxMP() const - { return mMaxMp; } - - int getMoney() const - { return mMoney; } - - void setMoney(int value); - - int getTotalWeight() const - { return mTotalWeight; } - - void setTotalWeight(int value); - - int getMaxWeight() const - { return mMaxWeight; } - - void setMaxWeight(int value); - - int getAttributeBase(int num) - { return mAttributeBase[num]; } - - void setAttributeBase(int num, int value, bool notify = true); - - int getAttributeEffective(int num) - { return mAttributeEffective[num]; } - - void setAttributeEffective(int num, int value); - - int getCharacterPoints() const - { return mCharacterPoints; } - - void setCharacterPoints(int n); - - int getCorrectionPoints() const - { return mCorrectionPoints; } - - void setCorrectionPoints(int n); - - int getSkillPoints() const - { return mSkillPoints; } - - void setSkillPoints(int points); - - void setExperience(int skill, int current, int next, bool notify = true); - - std::pair<int, int> getExperience(int skill); - /** Tells that the path has been set by mouse. */ void pathSetByMouse() { mPathSetByMouse = true; } @@ -379,6 +195,8 @@ class LocalPlayer : public Player */ void optionChanged(const std::string &value); + void event(const std::string &channel, const Mana::Event &event); + /** * set a following player by right clicking. */ @@ -403,7 +221,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; } @@ -414,19 +232,10 @@ class LocalPlayer : public Player */ bool getCheckNameSetting() const { return mUpdateName; } - /** Keeps the Equipment related values */ - const std::auto_ptr<Equipment> mEquipment; - protected: - /** Whether or not the name settings have changed */ bool mUpdateName; - virtual void handleStatusEffect(StatusEffect *effect, int effectId); - - // Colors don't change for local player - virtual void updateColors() {} - void startWalking(unsigned char dir); int mAttackRange; @@ -434,26 +243,6 @@ class LocalPlayer : public Player int mTargetTime; /** How long the being has been targeted **/ int mLastTarget; /** Time stamp of last targeting action, -1 if none. */ - // Character status: - typedef std::map<int, int> IntMap; - IntMap mAttributeBase; - IntMap mAttributeEffective; - std::map<int, std::pair<int, int> > mSkillExp; - int mCharacterPoints; - int mCorrectionPoints; - int mLevelProgress; - std::map<int, Special> mSpecials; - char mSpecialRechargeUpdateNeeded; - int mLevel; - int mExp, mExpNeeded; - int mMp, mMaxMp; - int mMoney; - int mTotalWeight; - int mMaxWeight; - int mHp; - int mMaxHp; - int mSkillPoints; - int mGMLevel; Being *mTarget; @@ -465,38 +254,17 @@ class LocalPlayer : public Player FloorItem *mPickUpTarget; - bool mTrading; bool mGoingToTarget; bool mKeepAttacking; /** Whether or not to continue to attack */ int mLastAction; /**< Time stamp of the last action, -1 if none. */ int mWalkingDir; /**< The direction the player is walking in. */ bool mPathSetByMouse; /**< Tells if the path was set using mouse */ - std::vector<int> mStatusEffectIcons; - - Inventory *mInventory; - 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*/ + /** Queued messages*/ std::list<MessagePair> mMessages; int mMessageTime; AwayListener *mAwayListener; diff --git a/src/log.cpp b/src/log.cpp index 5880e108..a147c107 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -21,8 +21,6 @@ #include "log.h" -#include "gui/widgets/chattab.h" - #ifdef WIN32 #include <windows.h> #elif __APPLE__ @@ -32,11 +30,12 @@ #include <sys/time.h> #include <iostream> #include <sstream> +#include <stdarg.h> +#include <stdio.h> #include <stdlib.h> Logger::Logger(): - mLogToStandardOut(true), - mChatWindow(NULL) + mLogToStandardOut(true) { } @@ -99,11 +98,6 @@ void Logger::log(const char *log_text, ...) std::cout << timeStr.str() << buf << std::endl; } - if (mChatWindow) - { - localChatTab->chatLog(buf, BY_LOGGER); - } - // Delete temporary buffer delete[] buf; } @@ -24,8 +24,6 @@ #include <fstream> -class ChatWindow; - /** * The Log Class : Useful to write debug or info messages */ @@ -53,11 +51,6 @@ class Logger void setLogToStandardOut(bool value) { mLogToStandardOut = value; } /** - * Enables logging to chat window - */ - void setChatWindow(ChatWindow *window) { mChatWindow = window; } - - /** * Enters a message in the log. The message will be timestamped. */ void log(const char *log_text, ...) @@ -75,7 +68,6 @@ class Logger private: std::ofstream mLogFile; bool mLogToStandardOut; - ChatWindow *mChatWindow; }; extern Logger *logger; diff --git a/src/main.cpp b/src/main.cpp index 29713c27..f3962c40 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,6 +40,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 @@ -55,6 +59,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 @@ -85,6 +90,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 } @@ -143,6 +149,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 f1f8d091..367083b6 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,47 +133,86 @@ 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(); + + int dx = (mX * 32) - scrollX; + int dy = (mY * 32) - scrollY + 32; for (int y = startY; y < endY; y++) { - // If drawing the fringe layer, make sure all sprites above this row of + int y32 = y * 32; + + // 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++; } } - for (int x = startX; x < endX; x++) + if (debugFlags != Map::MAP_SPECIAL3) { - Image *img = getTile(x, y); - if (img) + const int py0 = y32 + dy; + + for (int x = startX; x < endX; x++) { - const int px = (x + mX) * 32 - scrollX; - const int py = (y + mY) * 32 - scrollY + 32 - img->getHeight(); - if (debugFlags != Map::MAP_SPECIAL || img->getHeight() <= 32) - graphics->drawImage(img, px, py); + Image *img = getTile(x, y); + if (img) + { + const int px = (x * 32) + dx; + const int py = py0 - img->getHeight(); + if ((debugFlags != Map::MAP_SPECIAL + && debugFlags != Map::MAP_SPECIAL2) + || img->getHeight() <= 32) + { + int width = 0; + int c = getTileDrawWidth(x, y, endX, width); + if (!c) + { + graphics->drawImage(img, px, py); + } + else + { + graphics->drawImagePattern(img, px, py, + width, img->getHeight()); + } + x += c; + } + } } } } - // 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++; } } } +int MapLayer::getTileDrawWidth(int x1, int y1, int endX, int &width) const +{ + Image *img1 = getTile(x1, y1); + int c = 0; + width = img1->getWidth(); + for (int x = x1 + 1; x < endX; x++) + { + Image *img = getTile(x, y1); + if (img != img1) + break; + c ++; + width += img->getWidth(); + } + return c; +} + Map::Map(int width, int height, int tileWidth, int tileHeight): mWidth(width), mHeight(height), mTileWidth(tileWidth), mTileHeight(tileHeight), @@ -283,7 +321,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,46 +347,69 @@ 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); // Draw backgrounds drawAmbientLayers(graphics, BACKGROUND_LAYERS, scrollX, scrollY, - (int) config.getValue("OverlayDetail", 2)); + config.getIntValue("OverlayDetail")); // draw the game world Layers::const_iterator layeri = mLayers.begin(); - for (; layeri != mLayers.end(); ++layeri) + + bool overFringe = false; + + if (mDebugFlags == MAP_SPECIAL3) + { + for (; layeri != mLayers.end(); ++layeri) + { + if ((*layeri)->isFringeLayer()) + { + (*layeri)->draw(graphics, + startX, startY, endX, endY, + scrollX, scrollY, + mActors, mDebugFlags); + } + } + } + else { - (*layeri)->draw(graphics, - startX, startY, endX, endY, - scrollX, scrollY, - mSprites, mDebugFlags); + for (; layeri != mLayers.end() && !overFringe; ++layeri) + { + if ((*layeri)->isFringeLayer() && mDebugFlags == MAP_SPECIAL2) + overFringe = true; + + (*layeri)->draw(graphics, + startX, startY, endX, endY, + scrollX, scrollY, + 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, - (int) config.getValue("OverlayDetail", 2)); + config.getIntValue("OverlayDetail")); } void Map::drawCollision(Graphics *graphics, int scrollX, int scrollY, @@ -524,12 +585,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; } @@ -546,15 +609,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 @@ -893,7 +956,7 @@ void Map::initializeParticleEffects(Particle *particleEngine) { Particle *p; - if (config.getValue("particleeffects", 1)) + if (config.getBoolValue("particleeffects")) { for (std::list<ParticleEffectData>::iterator i = particleEffects.begin(); i != particleEffects.end(); @@ -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,25 @@ 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; + bool isFringeLayer() + { return mIsFringeLayer; } + + int getTileDrawWidth(int x1, int y1, int endX, int &width) const; + private: int mX, mY; int mWidth, mHeight; - bool mIsFringeLayer; /**< Whether the sprites are drawn. */ + bool mIsFringeLayer; /**< Whether the actors are drawn. */ Image **mTiles; }; @@ -164,7 +166,9 @@ class Map : public Properties { MAP_NORMAL = 0, MAP_DEBUG = 1, - MAP_SPECIAL = 2 + MAP_SPECIAL = 2, + MAP_SPECIAL2 = 3, + MAP_SPECIAL3 = 4 }; /** @@ -190,7 +194,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 +299,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 +323,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 +371,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 ca156821..00000000 --- a/src/monster.cpp +++ /dev/null @@ -1,203 +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" -#include "configuration.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 = paths.getValue("sprites", - "graphics/sprites/") + *i; - mSprites.push_back(AnimatedSprite::load(file)); - } - - // Ensure that something is shown - if (mSprites.size() == 0) - { - mSprites.push_back(AnimatedSprite::load( - paths.getValue("sprites", "graphics/sprites/") + - paths.getValue("spriteErrorFile", "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/adminhandler.h b/src/net/adminhandler.h index 23e9abc0..3ed96dbd 100644 --- a/src/net/adminhandler.h +++ b/src/net/adminhandler.h @@ -29,6 +29,8 @@ namespace Net { class AdminHandler { public: + virtual ~AdminHandler() {} + virtual void announce(const std::string &text) = 0; virtual void localAnnounce(const std::string &text) = 0; @@ -49,8 +51,6 @@ class AdminHandler virtual void mute(int playerId, int type, int limit) = 0; - virtual ~AdminHandler() {} - // TODO }; diff --git a/src/net/charhandler.h b/src/net/charhandler.h index 4a813e21..c2be5714 100644 --- a/src/net/charhandler.h +++ b/src/net/charhandler.h @@ -24,13 +24,13 @@ #include "localplayer.h" #include "logindata.h" +#include "playerinfo.h" #include <iosfwd> #include <vector> class CharCreateDialog; class CharSelectDialog; -class LocalPlayer; namespace Net { @@ -52,6 +52,7 @@ struct Character int slot; /**< The index in the list of characters */ LocalPlayer *dummy; /**< A dummy representing this character */ + PlayerInfoBackend data; }; typedef std::list<Character*> Characters; @@ -59,6 +60,8 @@ typedef std::list<Character*> Characters; class CharHandler { public: + virtual ~CharHandler() {} + virtual void setCharSelectDialog(CharSelectDialog *window) = 0; virtual void setCharCreateDialog(CharCreateDialog *window) = 0; @@ -75,13 +78,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 ~CharHandler() {} + virtual unsigned int maxSprite() const = 0; protected: CharHandler(): diff --git a/src/net/chathandler.h b/src/net/chathandler.h index d1449698..fbaa8dba 100644 --- a/src/net/chathandler.h +++ b/src/net/chathandler.h @@ -28,6 +28,8 @@ namespace Net { class ChatHandler { public: + virtual ~ChatHandler() {} + virtual void talk(const std::string &text) = 0; virtual void me(const std::string &text) = 0; @@ -53,8 +55,6 @@ class ChatHandler virtual void kickUser(int channelId, const std::string &name) = 0; virtual void who() = 0; - - virtual ~ChatHandler() {} }; } diff --git a/src/net/download.cpp b/src/net/download.cpp index a2cd4910..83ab180f 100644 --- a/src/net/download.cpp +++ b/src/net/download.cpp @@ -221,8 +221,8 @@ int Download::downloadThread(void *ptr) } curl_easy_setopt(d->mCurl, CURLOPT_USERAGENT, - strprintf(PACKAGE_EXTENDED_VERSION, branding - .getValue("appShort", "mana").c_str()).c_str()); + strprintf(PACKAGE_EXTENDED_VERSION, + branding.getStringValue("appShort").c_str()).c_str()); curl_easy_setopt(d->mCurl, CURLOPT_ERRORBUFFER, d->mError); curl_easy_setopt(d->mCurl, CURLOPT_URL, d->mUrl.c_str()); curl_easy_setopt(d->mCurl, CURLOPT_NOPROGRESS, 0); diff --git a/src/net/gamehandler.h b/src/net/gamehandler.h index 774de16c..9b0c8d95 100644 --- a/src/net/gamehandler.h +++ b/src/net/gamehandler.h @@ -31,16 +31,14 @@ namespace Net { class GameHandler { public: + virtual ~GameHandler() {} + virtual void connect() = 0; virtual bool isConnected() = 0; virtual void disconnect() = 0; - virtual void inGame() = 0; - - virtual void mapLoaded(const std::string &mapName) = 0; - virtual void who() = 0; virtual void quit() = 0; @@ -49,7 +47,10 @@ class GameHandler virtual bool removeDeadBeings() const = 0; - virtual ~GameHandler() {} + /** + * Tells whether the protocol is using the MP status bar + */ + virtual bool canUseMagicBar() const = 0; }; } // namespace Net diff --git a/src/net/generalhandler.h b/src/net/generalhandler.h index 222b430a..1d8c66af 100644 --- a/src/net/generalhandler.h +++ b/src/net/generalhandler.h @@ -40,13 +40,7 @@ class GeneralHandler virtual void flushNetwork() = 0; - virtual void guiWindowsLoaded() = 0; - - virtual void guiWindowsUnloaded() = 0; - virtual void clearHandlers() = 0; - - virtual void stateChanged(State oldState, State newState) = 0; }; } // namespace Net 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/inventoryhandler.h b/src/net/inventoryhandler.h index e48043a7..93b56a40 100644 --- a/src/net/inventoryhandler.h +++ b/src/net/inventoryhandler.h @@ -32,33 +32,12 @@ namespace Net { class InventoryHandler { public: - virtual void equipItem(const Item *item) = 0; - - virtual void unequipItem(const Item *item) = 0; - - virtual void useItem(const Item *item) = 0; - - virtual void dropItem(const Item *item, int amount) = 0; + virtual ~InventoryHandler() {} virtual bool canSplit(const Item *item) = 0; - virtual void splitItem(const Item *item, int amount) = 0; - - virtual void moveItem(int oldIndex, int newIndex) = 0; - - virtual void openStorage(int type) = 0; - - virtual void closeStorage(int type) = 0; - - //void changeCart() = 0; - - virtual void moveItem(int source, int slot, int amount, - int destination) = 0; - // TODO: fix/remove me virtual size_t getSize(int type) const = 0; - - virtual ~InventoryHandler() {} }; } // namespace Net 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 8df9a8ab..63c1e13f 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; @@ -145,7 +144,7 @@ static void handleLooks(Player *being, Net::MessageIn &msg) { if (!(mask & (1 << i))) continue; int id = msg.readInt16(); - being->setSprite(slots[i], id); + being->setSprite(slots[i], id,"", (slots[i] == SPRITE_WEAPON)); } } @@ -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..d4187db7 100644 --- a/src/net/manaserv/buysellhandler.cpp +++ b/src/net/manaserv/buysellhandler.cpp @@ -21,13 +21,11 @@ #include "net/manaserv/buysellhandler.h" -#include "beingmanager.h" +#include "actorspritemanager.h" #include "item.h" -#include "localplayer.h" -#include "npc.h" +#include "playerinfo.h" #include "gui/buy.h" -#include "gui/chat.h" #include "gui/sell.h" #include "net/messagein.h" @@ -49,8 +47,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; } @@ -64,7 +62,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) BuyDialog* dialog = new BuyDialog(npcId); dialog->reset(); - dialog->setMoney(player_node->getMoney()); + dialog->setMoney(PlayerInfo::getAttribute(MONEY)); while (msg.getUnreadLength()) { @@ -81,7 +79,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) SellDialog* dialog = new SellDialog(npcId); dialog->reset(); - dialog->setMoney(player_node->getMoney()); + dialog->setMoney(PlayerInfo::getAttribute(MONEY)); while (msg.getUnreadLength()) { diff --git a/src/net/manaserv/charhandler.cpp b/src/net/manaserv/charhandler.cpp index e6723226..7e401455 100644 --- a/src/net/manaserv/charhandler.cpp +++ b/src/net/manaserv/charhandler.cpp @@ -233,6 +233,7 @@ void CharHandler::handleCharacterSelectResponse(Net::MessageIn &msg) // Prevent the selected local player from being deleted player_node = mSelectedCharacter->dummy; + PlayerInfo::setBackend(mSelectedCharacter->data); mSelectedCharacter->dummy = 0; Client::setState(STATE_CONNECT_GAME); @@ -319,17 +320,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; } @@ -355,14 +356,14 @@ void CharHandler::updateCharacters() player->setGender(info.gender); player->setSprite(SPRITE_HAIR, info.hairStyle * -1, ColorDB::get(info.hairColor)); - player->setLevel(info.level); - player->setCharacterPoints(info.characterPoints); - player->setCorrectionPoints(info.correctionPoints); - player->setMoney(info.money); + character->data.mAttributes[LEVEL] = info.level; + character->data.mAttributes[CHAR_POINTS] = info.characterPoints; + character->data.mAttributes[CORR_POINTS] = info.correctionPoints; + character->data.mAttributes[MONEY] = info.money; for (int i = 0; i < 7; i++) { - player->setAttributeBase(i, info.attribute[i], false); + character->data.mStats[i].base = info.attribute[i]; } mCharacters.push_back(character); 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..147bab0a 100644 --- a/src/net/manaserv/chathandler.cpp +++ b/src/net/manaserv/chathandler.cpp @@ -21,13 +21,13 @@ #include "net/manaserv/chathandler.h" +#include "actorspritemanager.h" #include "being.h" -#include "beingmanager.h" #include "client.h" #include "channel.h" #include "channelmanager.h" - -#include "gui/chat.h" +#include "event.h" +#include "playerrelations.h" #include "gui/widgets/channeltab.h" @@ -149,22 +149,29 @@ void ChatHandler::handleGameChatMessage(Net::MessageIn &msg) if (id == 0) { - localChatTab->chatLog(chatMsg, BY_SERVER); + SERVER_NOTICE(chatMsg) return; } - Being *being = beingManager->findBeing(id); + Being *being = actorSpriteManager->findBeing(id); std::string mes; if (being) { mes = being->getName() + " : " + chatMsg; - being->setSpeech(chatMsg, SPEECH_TIME); } else mes = "Unknown : " + chatMsg; - localChatTab->chatLog(mes, being == player_node ? BY_PLAYER : BY_OTHER); + Mana::Event event(being == player_node ? "Player" : "Being"); + event.setString("message", mes); + event.setString("text", chatMsg); + event.setString("nick", being->getName()); + event.setInt("beingId", id); + event.setInt("permissions", player_relations + .checkPermissionSilently(being->getName(), + PlayerRelation::SPEECH_LOG | PlayerRelation::SPEECH_FLOAT)); + event.trigger("Chat"); } void ChatHandler::handleEnterChannelResponse(Net::MessageIn &msg) @@ -198,13 +205,13 @@ void ChatHandler::handleEnterChannelResponse(Net::MessageIn &msg) } else { - localChatTab->chatLog(_("Error joining channel."), BY_SERVER); + SERVER_NOTICE(_("Error joining channel.")) } } void ChatHandler::handleListChannelsResponse(Net::MessageIn &msg) { - localChatTab->chatLog(_("Listing channels."), BY_SERVER); + SERVER_NOTICE(_("Listing channels.")) while (msg.getUnreadLength()) { std::string channelName = msg.readString(); @@ -214,9 +221,9 @@ void ChatHandler::handleListChannelsResponse(Net::MessageIn &msg) numUsers << msg.readInt16(); channelName += " - "; channelName += numUsers.str(); - localChatTab->chatLog(channelName, BY_SERVER); + SERVER_NOTICE(channelName) } - localChatTab->chatLog(_("End of channel list."), BY_SERVER); + SERVER_NOTICE(_("End of channel list.")) } void ChatHandler::handlePrivateMessage(Net::MessageIn &msg) @@ -224,13 +231,18 @@ void ChatHandler::handlePrivateMessage(Net::MessageIn &msg) std::string userNick = msg.readString(); std::string chatMsg = msg.readString(); - chatWindow->whisper(userNick, chatMsg); + Mana::Event event("Whisper"); + event.setString("nick", userNick); + event.setString("message", chatMsg); + event.trigger("Chat"); } void ChatHandler::handleAnnouncement(Net::MessageIn &msg) { std::string chatMsg = msg.readString(); - localChatTab->chatLog(chatMsg, BY_GM); + Mana::Event event("Announcement"); + event.setString("message", chatMsg); + event.trigger("Chat"); } void ChatHandler::handleChatMessage(Net::MessageIn &msg) @@ -341,7 +353,7 @@ void ChatHandler::handleWhoResponse(Net::MessageIn &msg) { break; } - localChatTab->chatLog(userNick, BY_SERVER); + SERVER_NOTICE(userNick) } } diff --git a/src/net/manaserv/connection.cpp b/src/net/manaserv/connection.cpp index fbd2ed22..b404191f 100644 --- a/src/net/manaserv/connection.cpp +++ b/src/net/manaserv/connection.cpp @@ -60,7 +60,7 @@ bool Connection::connect(const std::string &address, short port) enetAddress.port = port; // Initiate the connection, allocating channel 0. -#ifdef ENET_VERSION_MAJOR +#if defined(ENET_VERSION) && ENET_VERSION >= ENET_CUTOFF mConnection = enet_host_connect(mClient, &enetAddress, 1, 0); #else mConnection = enet_host_connect(mClient, &enetAddress, 1); diff --git a/src/net/manaserv/connection.h b/src/net/manaserv/connection.h index b39f8957..808a6d40 100644 --- a/src/net/manaserv/connection.h +++ b/src/net/manaserv/connection.h @@ -26,6 +26,12 @@ #include <iosfwd> +#ifdef ENET_VERSION_CREATE +#define ENET_CUTOFF ENET_VERSION_CREATE(1,3,0) +#else +#define ENET_CUTOFF 0xFFFFFFFF +#endif + namespace ManaServ { class MessageOut; diff --git a/src/net/manaserv/defines.h b/src/net/manaserv/defines.h new file mode 100644 index 00000000..e97866df --- /dev/null +++ b/src/net/manaserv/defines.h @@ -0,0 +1,76 @@ +/* + * 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 MANASERV_DEFINES_H +#define MANASERV_DEFINES_H + +/** + * Attributes used during combat. Available to all the beings. + */ +enum +{ +BASE_ATTR_BEGIN = 0, + BASE_ATTR_PHY_ATK_MIN = BASE_ATTR_BEGIN, + BASE_ATTR_PHY_ATK_DELTA, + /**< Physical attack power. */ + BASE_ATTR_MAG_ATK, /**< Magical attack power. */ + BASE_ATTR_PHY_RES, /**< Resistance to physical damage. */ + BASE_ATTR_MAG_RES, /**< Resistance to magical damage. */ + BASE_ATTR_EVADE, /**< Ability to avoid hits. */ + BASE_ATTR_HIT, /**< Ability to hit stuff. */ + BASE_ATTR_HP, /**< Hit Points (Base value: maximum, Modded value: current) */ + BASE_ATTR_HP_REGEN,/**< number of HP regenerated every 10 game ticks */ + BASE_ATTR_END, + BASE_ATTR_NB = BASE_ATTR_END - BASE_ATTR_BEGIN, + + BASE_ELEM_BEGIN = BASE_ATTR_END, + BASE_ELEM_NEUTRAL = BASE_ELEM_BEGIN, + BASE_ELEM_FIRE, + BASE_ELEM_WATER, + BASE_ELEM_EARTH, + BASE_ELEM_AIR, + BASE_ELEM_SACRED, + BASE_ELEM_DEATH, + BASE_ELEM_END, + BASE_ELEM_NB = BASE_ELEM_END - BASE_ELEM_BEGIN, + + NB_BEING_ATTRIBUTES = BASE_ELEM_END +}; + +/** + * Attributes of characters. Used to derive being attributes. + */ +enum +{ + CHAR_ATTR_BEGIN = NB_BEING_ATTRIBUTES, + CHAR_ATTR_STRENGTH = CHAR_ATTR_BEGIN, + CHAR_ATTR_AGILITY, + CHAR_ATTR_DEXTERITY, + CHAR_ATTR_VITALITY, + CHAR_ATTR_INTELLIGENCE, + CHAR_ATTR_WILLPOWER, + CHAR_ATTR_END, + CHAR_ATTR_NB = CHAR_ATTR_END - CHAR_ATTR_BEGIN, + + NB_CHARACTER_ATTRIBUTES = CHAR_ATTR_END +}; + +#endif // MANASERV_DEFINES_H 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.cpp b/src/net/manaserv/gamehandler.cpp index 5e29a896..3cb9f0ea 100644 --- a/src/net/manaserv/gamehandler.cpp +++ b/src/net/manaserv/gamehandler.cpp @@ -115,16 +115,6 @@ void GameHandler::disconnect() chatHandler->disconnect(); } -void GameHandler::inGame() -{ - // TODO -} - -void GameHandler::mapLoaded(const std::string &mapName) -{ - // TODO -} - void GameHandler::who() { // TODO diff --git a/src/net/manaserv/gamehandler.h b/src/net/manaserv/gamehandler.h index dde1748f..2e9f37fe 100644 --- a/src/net/manaserv/gamehandler.h +++ b/src/net/manaserv/gamehandler.h @@ -42,10 +42,6 @@ class GameHandler : public MessageHandler, public Net::GameHandler void disconnect(); - void inGame(); - - void mapLoaded(const std::string &mapName); - void who(); void quit(bool reconnectAccount); @@ -53,12 +49,15 @@ 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 status bar. */ + bool canUseMagicBar() const { return false; } }; } // namespace ManaServ diff --git a/src/net/manaserv/generalhandler.cpp b/src/net/manaserv/generalhandler.cpp index 0d3073f1..210e3043 100644 --- a/src/net/manaserv/generalhandler.cpp +++ b/src/net/manaserv/generalhandler.cpp @@ -90,6 +90,9 @@ GeneralHandler::GeneralHandler(): chatServerConnection = getConnection(); generalHandler = this; + + listen("Client"); + listen("Game"); } void GeneralHandler::load() @@ -163,38 +166,40 @@ void GeneralHandler::flushNetwork() } } -void GeneralHandler::guiWindowsLoaded() -{ - inventoryWindow->setSplitAllowed(true); - skillDialog->loadSkills("mana-skills.xml"); - specialsWindow->loadSpecials("specials.xml"); - - player_node->setExpNeeded(100); - - Stats::informStatusWindow(); -} - -void GeneralHandler::guiWindowsUnloaded() -{ - // TODO -} - void GeneralHandler::clearHandlers() { clearNetworkHandlers(); } -void GeneralHandler::stateChanged(State oldState, State newState) +void GeneralHandler::event(const std::string &channel, + const Mana::Event &event) { - if (newState == STATE_GAME) + if (channel == "Client") { - GameHandler *game = static_cast<GameHandler*>(Net::getGameHandler()); - game->gameLoading(); + int newState = event.getInt("newState"); + + if (newState == STATE_GAME) + { + GameHandler *game = static_cast<GameHandler*>(Net::getGameHandler()); + game->gameLoading(); + } + else if (newState == STATE_LOAD_DATA) + { + Stats::load(); + Stats::informItemDB(); + } } - else if (newState == STATE_LOAD_DATA) + else if (channel == "Game") { - Stats::load(); - Stats::informItemDB(); + if (event.getName() == "GuiWindowsLoaded") + { + inventoryWindow->setSplitAllowed(true); + skillDialog->loadSkills("mana-skills.xml"); + + PlayerInfo::setAttribute(EXP_NEEDED, 100); + + Stats::informStatusWindow(); + } } } diff --git a/src/net/manaserv/generalhandler.h b/src/net/manaserv/generalhandler.h index 58b95529..2a203e8c 100644 --- a/src/net/manaserv/generalhandler.h +++ b/src/net/manaserv/generalhandler.h @@ -22,6 +22,8 @@ #ifndef NET_MANASERV_GENERALHANDLER_H #define NET_MANASERV_GENERALHANDLER_H +#include "listener.h" + #include "net/generalhandler.h" #include "net/net.h" @@ -29,7 +31,7 @@ namespace ManaServ { -class GeneralHandler : public Net::GeneralHandler +class GeneralHandler : public Net::GeneralHandler, public Mana::Listener { public: GeneralHandler(); @@ -42,13 +44,9 @@ class GeneralHandler : public Net::GeneralHandler void flushNetwork(); - void guiWindowsLoaded(); - - void guiWindowsUnloaded(); - void clearHandlers(); - void stateChanged(State oldState, State newState); + void event(const std::string &channel, const Mana::Event &event); protected: MessageHandlerPtr mBeingHandler; diff --git a/src/net/manaserv/guildhandler.cpp b/src/net/manaserv/guildhandler.cpp index 253efb01..821d70bd 100644 --- a/src/net/manaserv/guildhandler.cpp +++ b/src/net/manaserv/guildhandler.cpp @@ -21,16 +21,17 @@ #include "net/manaserv/guildhandler.h" +#include "event.h" #include "guild.h" #include "log.h" #include "localplayer.h" #include "channel.h" #include "channelmanager.h" -#include "gui/widgets/channeltab.h" -#include "gui/chat.h" #include "gui/socialwindow.h" +#include "gui/widgets/channeltab.h" + #include "net/messagein.h" #include "net/net.h" @@ -78,12 +79,12 @@ void GuildHandler::handleMessage(Net::MessageIn &msg) if (msg.readInt8() == ERRMSG_OK) { // TODO - Acknowledge guild was created - localChatTab->chatLog(_("Guild created.")); + SERVER_NOTICE(_("Guild created.")) joinedGuild(msg); } else { - localChatTab->chatLog(_("Error creating guild.")); + SERVER_NOTICE(_("Error creating guild.")) } } break; @@ -93,7 +94,7 @@ void GuildHandler::handleMessage(Net::MessageIn &msg) if (msg.readInt8() == ERRMSG_OK) { // TODO - Acknowledge invite was sent - localChatTab->chatLog(_("Invite sent.")); + SERVER_NOTICE(_("Invite sent.")) } } break; @@ -200,12 +201,12 @@ void GuildHandler::handleMessage(Net::MessageIn &msg) if (msg.readInt8() == ERRMSG_OK) { // promotion succeeded - localChatTab->chatLog(_("Member was promoted successfully.")); + SERVER_NOTICE(_("Member was promoted successfully.")) } else { // promotion failed - localChatTab->chatLog(_("Failed to promote member.")); + SERVER_NOTICE(_("Failed to promote member.")) } } @@ -275,9 +276,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/inventoryhandler.cpp b/src/net/manaserv/inventoryhandler.cpp index 76fca7ae..28de9c1e 100644 --- a/src/net/manaserv/inventoryhandler.cpp +++ b/src/net/manaserv/inventoryhandler.cpp @@ -26,8 +26,7 @@ #include "item.h" #include "itemshortcut.h" #include "localplayer.h" - -#include "gui/chat.h" +#include "playerinfo.h" #include "net/manaserv/connection.h" #include "net/manaserv/messagein.h" @@ -36,8 +35,6 @@ #include "resources/iteminfo.h" -#include "log.h" // <<< REMOVE ME! - extern Net::InventoryHandler *inventoryHandler; namespace ManaServ { @@ -53,6 +50,8 @@ InventoryHandler::InventoryHandler() }; handledMessages = _messages; inventoryHandler = this; + + listen("Item"); } void InventoryHandler::handleMessage(Net::MessageIn &msg) @@ -60,8 +59,8 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) switch (msg.getId()) { case GPMSG_INVENTORY_FULL: - player_node->clearInventory(); - player_node->mEquipment->setBackend(&mEquips); + PlayerInfo::clearInventory(); + PlayerInfo::getEquipment()->setBackend(&mEquips); // no break! case GPMSG_INVENTORY: @@ -70,7 +69,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) unsigned int slot = msg.readInt8(); if (slot == 255) { - player_node->setMoney(msg.readInt32()); + PlayerInfo::setAttribute(MONEY, msg.readInt32()); continue; } @@ -82,45 +81,94 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) else if (slot >= 32 && slot < 32 + getSize(Inventory::INVENTORY)) { int amount = id ? msg.readInt8() : 0; - player_node->setInvItem(slot - 32, id, amount); + PlayerInfo::setInventoryItem(slot - 32, id, amount); } }; break; } } -void InventoryHandler::equipItem(const Item *item) -{ - MessageOut msg(PGMSG_EQUIP); - msg.writeInt8(item->getInvIndex()); - gameServerConnection->send(msg); -} - -void InventoryHandler::unequipItem(const Item *item) -{ - MessageOut msg(PGMSG_UNEQUIP); - msg.writeInt8(item->getInvIndex()); - gameServerConnection->send(msg); - - // Tidy equipment directly to avoid weapon still shown bug, for instance - int equipSlot = item->getInvIndex(); - logger->log("Unequipping %d", equipSlot); - mEquips.setEquipment(equipSlot, 0); -} - -void InventoryHandler::useItem(const Item *item) +void InventoryHandler::event(const std::string &channel, + const Mana::Event &event) { - MessageOut msg(PGMSG_USE_ITEM); - msg.writeInt8(item->getInvIndex()); - gameServerConnection->send(msg); -} + if (channel == "Item") + { + Item *item = event.getItem("item"); + + if (!item) + return; + + int index = item->getInvIndex(); + + if (event.getName() == "doEquip") + { + MessageOut msg(PGMSG_EQUIP); + msg.writeInt8(index); + gameServerConnection->send(msg); + } + else if (event.getName() == "doUnequip") + { + MessageOut msg(PGMSG_UNEQUIP); + msg.writeInt8(index); + gameServerConnection->send(msg); + + // Tidy equipment directly to avoid weapon still shown bug, for instance + mEquips.setEquipment(index, 0); + } + else if (event.getName() == "doUse") + { + MessageOut msg(PGMSG_USE_ITEM); + msg.writeInt8(index); + gameServerConnection->send(msg); + } + else if (event.getName() == "doDrop") + { + int amount = event.getInt("amount", 1); + + MessageOut msg(PGMSG_DROP); + msg.writeInt8(index); + msg.writeInt8(amount); + gameServerConnection->send(msg); + } + else if (event.getName() == "doSplit") + { + int amount = event.getInt("amount", 1); + + int newIndex = PlayerInfo::getInventory()->getFreeSlot(); + if (newIndex > Inventory::NO_SLOT_INDEX) + { + MessageOut msg(PGMSG_MOVE_ITEM); + msg.writeInt8(index); + msg.writeInt8(newIndex); + msg.writeInt8(amount); + gameServerConnection->send(msg); + } + } + else if (event.getName() == "doMove") + { + int newIndex = event.getInt("newIndex", -1); + + if (newIndex >= 0) + { + if (index == newIndex) + return; + + MessageOut msg(PGMSG_MOVE_ITEM); + msg.writeInt8(index); + msg.writeInt8(newIndex); + msg.writeInt8(item->getQuantity()); + gameServerConnection->send(msg); + } + else + { + /*int source = event.getInt("source"); + int destination = event.getInt("destination"); + int amount = event.getInt("amount", 1);*/ -void InventoryHandler::dropItem(const Item *item, int amount) -{ - MessageOut msg(PGMSG_DROP); - msg.writeInt8(item->getInvIndex()); - msg.writeInt8(amount); - gameServerConnection->send(msg); + // TODO + } + } + } } bool InventoryHandler::canSplit(const Item *item) @@ -128,48 +176,6 @@ bool InventoryHandler::canSplit(const Item *item) return item && !item->isEquipment() && item->getQuantity() > 1; } -void InventoryHandler::splitItem(const Item *item, int amount) -{ - int newIndex = player_node->getInventory()->getFreeSlot(); - if (newIndex > Inventory::NO_SLOT_INDEX) - { - MessageOut msg(PGMSG_MOVE_ITEM); - msg.writeInt8(item->getInvIndex()); - msg.writeInt8(newIndex); - msg.writeInt8(amount); - gameServerConnection->send(msg); - } -} - -void InventoryHandler::moveItem(int oldIndex, int newIndex) -{ - if (oldIndex == newIndex) - return; - - MessageOut msg(PGMSG_MOVE_ITEM); - msg.writeInt8(oldIndex); - msg.writeInt8(newIndex); - msg.writeInt8(player_node->getInventory()->getItem(oldIndex) - ->getQuantity()); - gameServerConnection->send(msg); -} - -void InventoryHandler::openStorage(int type) -{ - // TODO -} - -void InventoryHandler::closeStorage(int type) -{ - // TODO -} - -void InventoryHandler::moveItem(int source, int slot, int amount, - int destination) -{ - // TODO -} - size_t InventoryHandler::getSize(int type) const { switch (type) diff --git a/src/net/manaserv/inventoryhandler.h b/src/net/manaserv/inventoryhandler.h index fd08b95e..a1673e99 100644 --- a/src/net/manaserv/inventoryhandler.h +++ b/src/net/manaserv/inventoryhandler.h @@ -23,6 +23,7 @@ #define NET_MANASERV_INVENTORYHANDLER_H #include "equipment.h" +#include "listener.h" #include "net/inventoryhandler.h" @@ -67,34 +68,18 @@ class EquipBackend : public Equipment::Backend Item *mEquipment[EQUIPMENT_SIZE]; }; -class InventoryHandler : public MessageHandler, Net::InventoryHandler +class InventoryHandler : public MessageHandler, Net::InventoryHandler, + public Mana::Listener { public: InventoryHandler(); void handleMessage(Net::MessageIn &msg); - void equipItem(const Item *item); - - void unequipItem(const Item *item); - - void useItem(const Item *item); - - void dropItem(const Item *item, int amount); + void event(const std::string &channel, const Mana::Event &event); bool canSplit(const Item *item); - void splitItem(const Item *item, int amount); - - void moveItem(int oldIndex, int newIndex); - - void openStorage(int type); - - void closeStorage(int type); - - void moveItem(int source, int slot, int amount, - int destination); - size_t getSize(int type) const; private: 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/network.cpp b/src/net/manaserv/network.cpp index 636585c9..a5bf6186 100644 --- a/src/net/manaserv/network.cpp +++ b/src/net/manaserv/network.cpp @@ -53,7 +53,7 @@ void initialize() logger->error("Failed to initialize ENet."); } -#ifdef ENET_VERSION_MAJOR +#if defined(ENET_VERSION) && ENET_VERSION >= ENET_CUTOFF client = enet_host_create(NULL, 3, 0, 0, 0); #else client = enet_host_create(NULL, 3, 0, 0); diff --git a/src/net/manaserv/npchandler.cpp b/src/net/manaserv/npchandler.cpp index 392ec4fd..f7e04c1b 100644 --- a/src/net/manaserv/npchandler.cpp +++ b/src/net/manaserv/npchandler.cpp @@ -21,17 +21,16 @@ #include "net/manaserv/npchandler.h" -#include "beingmanager.h" -#include "npc.h" - -#include "gui/npcdialog.h" -#include "gui/npcpostdialog.h" +#include "actorspritemanager.h" +#include "event.h" #include "net/manaserv/connection.h" #include "net/manaserv/messagein.h" #include "net/manaserv/messageout.h" #include "net/manaserv/protocol.h" +#include "utils/stringutils.h" + extern Net::NpcHandler *npcHandler; namespace ManaServ { @@ -52,143 +51,131 @@ NpcHandler::NpcHandler() }; handledMessages = _messages; npcHandler = this; + + listen("NPC"); } 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; } - int npcId = being->getId(); - NpcDialogs::iterator diag = mNpcDialogs.find(npcId); - NpcDialog *dialog; - - if (diag == mNpcDialogs.end()) - { - if (msg.getId() == GPMSG_NPC_ERROR || msg.getId() == GPMSG_NPC_CLOSE) - return; // Dialog is pointless in these cases - - dialog = new NpcDialog(npcId); - Wrapper wrap; - wrap.dialog = dialog; - mNpcDialogs[npcId] = wrap; - } - else - { - dialog = diag->second.dialog; - } + int npcId = being->getId(), count = 0; + Mana::Event *event = 0; switch (msg.getId()) { - case GPMSG_NPC_CHOICE: - dialog->choiceRequest(); - while (msg.getUnreadLength()) - { - dialog->addChoice(msg.readString()); - } - break; - - case GPMSG_NPC_NUMBER: + case GPMSG_NPC_CHOICE: + event = new Mana::Event("Menu"); + event->setInt("id", npcId); + while (msg.getUnreadLength()) { - int min_num = msg.readInt32(); - int max_num = msg.readInt32(); - dialog->integerRequest(msg.readInt32(), min_num, max_num); - break; + count++; + event->setString("choice" + toString(count), msg.readString()); } - - case GPMSG_NPC_STRING: - dialog->textRequest(""); - break; - - case GPMSG_NPC_POST: - { - new NpcPostDialog(npcId); - break; - } - - case GPMSG_NPC_ERROR: - dialog->close(); - if (diag != mNpcDialogs.end()) - { - mNpcDialogs.erase(diag); - } - break; - - case GPMSG_NPC_MESSAGE: - dialog->addText(msg.readString(msg.getUnreadLength())); - dialog->showNextButton(); - break; - - case GPMSG_NPC_CLOSE: - dialog->showCloseButton(); - break; + event->setInt("choiceCount", count); + event->trigger("NPC"); + break; + + case GPMSG_NPC_NUMBER: + event = new Mana::Event("IntegerInput"); + event->setInt("id", npcId); + event->setInt("min", msg.readInt32()); + event->setInt("max", msg.readInt32()); + event->setInt("default", msg.readInt32()); + event->trigger("NPC"); + break; + + case GPMSG_NPC_STRING: + event = new Mana::Event("StringInput"); + event->setInt("id", npcId); + event->trigger("NPC"); + break; + + case GPMSG_NPC_POST: + event = new Mana::Event("Post"); + event->setInt("id", npcId); + event->trigger("NPC"); + break; + + case GPMSG_NPC_ERROR: + event = new Mana::Event("End"); + event->setInt("id", npcId); + event->trigger("NPC"); + break; + + case GPMSG_NPC_MESSAGE: + event = new Mana::Event("Message"); + event->setInt("id", npcId); + event->setString("text", msg.readString(msg.getUnreadLength())); + event->trigger("NPC"); + delete event; + + event = new Mana::Event("Next"); + event->setInt("id", npcId); + event->trigger("NPC"); + break; + + case GPMSG_NPC_CLOSE: + event = new Mana::Event("Close"); + event->setInt("id", npcId); + event->trigger("NPC"); + break; } -} -void NpcHandler::talk(int npcId) -{ - MessageOut msg(PGMSG_NPC_TALK); - msg.writeInt16(npcId); - gameServerConnection->send(msg); -} - -void NpcHandler::nextDialog(int npcId) -{ - MessageOut msg(PGMSG_NPC_TALK_NEXT); - msg.writeInt16(npcId); - gameServerConnection->send(msg); + delete event; } -void NpcHandler::closeDialog(int npcId) +void NpcHandler::event(const std::string &channel, const Mana::Event &event) { - MessageOut msg(PGMSG_NPC_TALK_NEXT); - msg.writeInt16(npcId); - gameServerConnection->send(msg); - - NpcDialogs::iterator it = mNpcDialogs.find(npcId); - if (it != mNpcDialogs.end()) + if (channel == "NPC") { - (*it).second.dialog->close(); - mNpcDialogs.erase(it); + if (event.getName() == "doTalk") + { + MessageOut msg(PGMSG_NPC_TALK); + msg.writeInt16(event.getInt("npcId")); + gameServerConnection->send(msg); + } + else if (event.getName() == "doNext" || event.getName() == "doClose") + { + MessageOut msg(PGMSG_NPC_TALK_NEXT); + msg.writeInt16(event.getInt("npcId")); + gameServerConnection->send(msg); + } + else if (event.getName() == "doMenu") + { + MessageOut msg(PGMSG_NPC_SELECT); + msg.writeInt16(event.getInt("npcId")); + msg.writeInt8(event.getInt("choice")); + gameServerConnection->send(msg); + } + else if (event.getName() == "doIntegerInput") + { + MessageOut msg(PGMSG_NPC_NUMBER); + msg.writeInt16(event.getInt("npcId")); + msg.writeInt32(event.getInt("value")); + gameServerConnection->send(msg); + } + else if (event.getName() == "doStringInput") + { + MessageOut msg(PGMSG_NPC_STRING); + msg.writeInt16(event.getInt("npcId")); + msg.writeString(event.getString("value")); + gameServerConnection->send(msg); + } + else if (event.getName() == "doSendLetter") + { + MessageOut msg(PGMSG_NPC_POST_SEND); + msg.writeString(event.getString("recipient")); + msg.writeString(event.getString("text")); + gameServerConnection->send(msg); + } } } -void NpcHandler::listInput(int npcId, int value) -{ - MessageOut msg(PGMSG_NPC_SELECT); - msg.writeInt16(npcId); - msg.writeInt8(value); - gameServerConnection->send(msg); -} - -void NpcHandler::integerInput(int npcId, int value) -{ - MessageOut msg(PGMSG_NPC_NUMBER); - msg.writeInt16(npcId); - msg.writeInt32(value); - gameServerConnection->send(msg); -} - -void NpcHandler::stringInput(int npcId, const std::string &value) -{ - MessageOut msg(PGMSG_NPC_STRING); - msg.writeInt16(npcId); - msg.writeString(value); - gameServerConnection->send(msg); -} - -void NpcHandler::sendLetter(int npcId, const std::string &recipient, - const std::string &text) -{ - MessageOut msg(PGMSG_NPC_POST_SEND); - msg.writeString(recipient); - msg.writeString(text); - gameServerConnection->send(msg); -} - void NpcHandler::startShopping(int beingId) { // TODO @@ -225,9 +212,4 @@ void NpcHandler::endShopping(int beingId) // TODO } -void NpcHandler::clearDialogs() -{ - mNpcDialogs.clear(); -} - } // namespace ManaServ diff --git a/src/net/manaserv/npchandler.h b/src/net/manaserv/npchandler.h index 689fdc1d..14e8a50a 100644 --- a/src/net/manaserv/npchandler.h +++ b/src/net/manaserv/npchandler.h @@ -22,37 +22,25 @@ #ifndef NET_MANASERV_NPCHANDLER_H #define NET_MANASERV_NPCHANDLER_H +#include "listener.h" + #include "net/npchandler.h" #include "net/manaserv/messagehandler.h" #include <map> -class NpcDialog; - namespace ManaServ { -class NpcHandler : public MessageHandler, public Net::NpcHandler +class NpcHandler : public MessageHandler, public Net::NpcHandler, + public Mana::Listener { public: NpcHandler(); void handleMessage(Net::MessageIn &msg); - void talk(int npcId); - - void nextDialog(int npcId); - - void closeDialog(int npcId); - - void listInput(int npcId, int value); - - void integerInput(int npcId, int value); - - void stringInput(int npcId, const std::string &value); - - void sendLetter(int npcId, const std::string &recipient, - const std::string &text); + void event(const std::string &channel, const Mana::Event &event); void startShopping(int beingId); @@ -65,15 +53,6 @@ class NpcHandler : public MessageHandler, public Net::NpcHandler void sellItem(int beingId, int itemId, int amount); void endShopping(int beingId); - - void clearDialogs(); - - private: - typedef struct { - NpcDialog* dialog; - } Wrapper; - typedef std::map<int, Wrapper> NpcDialogs; - NpcDialogs mNpcDialogs; }; } // namespace ManaServ diff --git a/src/net/manaserv/partyhandler.cpp b/src/net/manaserv/partyhandler.cpp index ec153fa8..370d6496 100644 --- a/src/net/manaserv/partyhandler.cpp +++ b/src/net/manaserv/partyhandler.cpp @@ -21,13 +21,12 @@ #include "net/manaserv/partyhandler.h" +#include "event.h" #include "log.h" #include "localplayer.h" #include "gui/socialwindow.h" -#include "gui/widgets/chattab.h" - #include "net/manaserv/connection.h" #include "net/manaserv/messagein.h" #include "net/manaserv/messageout.h" @@ -85,7 +84,7 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) if (msg.readInt8() == ERRMSG_OK) { // - localChatTab->chatLog(_("Joined party.")); + SERVER_NOTICE(_("Joined party.")); } } @@ -103,7 +102,7 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) int id = msg.readInt16(); // being id std::string name = msg.readString(); - localChatTab->chatLog(strprintf(_("%s joined the party."), + SERVER_NOTICE(strprintf(_("%s joined the party."), name.c_str())); if (id == player_node->getId()) @@ -120,8 +119,8 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) case CPMSG_PARTY_REJECTED: { std::string name = msg.readString(); - localChatTab->chatLog(strprintf(_("%s rejected your invite."), - name.c_str())); + SERVER_NOTICE(strprintf( + _("%s rejected your invite."), name.c_str())); } break; } } @@ -136,9 +135,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 +166,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 33367927..db2dcf7a 100644 --- a/src/net/manaserv/playerhandler.cpp +++ b/src/net/manaserv/playerhandler.cpp @@ -24,14 +24,14 @@ #include "client.h" #include "effectmanager.h" +#include "event.h" #include "game.h" #include "localplayer.h" #include "log.h" #include "particle.h" -#include "npc.h" +#include "playerinfo.h" #include "configuration.h" -#include "gui/chat.h" #include "gui/gui.h" #include "gui/okdialog.h" #include "gui/viewport.h" @@ -39,9 +39,9 @@ #include "net/net.h" #include "net/manaserv/connection.h" +#include "net/manaserv/defines.h" #include "net/manaserv/messagein.h" #include "net/manaserv/messageout.h" -#include "net/manaserv/npchandler.h" #include "net/manaserv/protocol.h" /** @@ -64,9 +64,7 @@ void RespawnRequestListener::action(const gcn::ActionEvent &event) { Net::getPlayerHandler()->respawn(); - ManaServ::NpcHandler *handler = - static_cast<ManaServ::NpcHandler*>(Net::getNpcHandler()); - handler->clearDialogs(); + Mana::Event::trigger("NPC", "CloseAll"); } PlayerHandler::PlayerHandler() @@ -122,13 +120,13 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) if (stat == BASE_ATTR_HP) { - player_node->setMaxHp(base); - player_node->setHp(value); + PlayerInfo::setAttribute(MAX_HP, base); + PlayerInfo::setAttribute(HP, value); } else { - player_node->setAttributeBase(stat, base); - player_node->setAttributeEffective(stat, value); + PlayerInfo::setStatBase(stat, base); + PlayerInfo::setStatMod(stat, value - base); } } } break; @@ -142,26 +140,26 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) int current = msg.readInt32(); int next = msg.readInt32(); - player_node->setExperience(skill, current, next); + PlayerInfo::setStatExperience(skill, current, next); } } break; case GPMSG_LEVELUP: { - player_node->setLevel(msg.readInt16()); - player_node->setCharacterPoints(msg.readInt16()); - player_node->setCorrectionPoints(msg.readInt16()); + PlayerInfo::setAttribute(LEVEL, msg.readInt16()); + PlayerInfo::setAttribute(CHAR_POINTS, msg.readInt16()); + PlayerInfo::setAttribute(CORR_POINTS, msg.readInt16()); Particle* effect = particleEngine->addEffect( - paths.getValue("particles", "graphics/particles/") - + paths.getValue("levelUpEffectFile", "levelup.particle.xml"), - 0, 0); + paths.getStringValue("particles") + + paths.getStringValue("levelUpEffectFile") + ,0, 0); player_node->controlParticle(effect); } break; case GPMSG_LEVEL_PROGRESS: { - player_node->setExp(msg.readInt8(), false); + PlayerInfo::setAttribute(EXP, msg.readInt8()); } break; @@ -185,18 +183,19 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) // has to be correct. The server is always right! // undo attribute change and set points to 0 logger->log("Warning: Server denied increase of attribute %d (no points left) ", attrNum); - int attrValue = player_node->getAttributeBase(attrNum) - 1; - player_node->setCharacterPoints(0); - player_node->setAttributeBase(attrNum, attrValue); + int attrValue = PlayerInfo::getStatBase(attrNum) - 1; + PlayerInfo::setAttribute(CHAR_POINTS, 0); + PlayerInfo::setStatBase(attrNum, attrValue); } break; case ATTRIBMOD_DENIED: { // undo attribute change logger->log("Warning: Server denied increase of attribute %d (reason unknown) ", attrNum); - int points = player_node->getCharacterPoints() - 1; - player_node->setCharacterPoints(points); - int attrValue = player_node->getAttributeBase(attrNum) - 1; - player_node->setAttributeBase(attrNum, attrValue); + int points = PlayerInfo::getAttribute(CHAR_POINTS) - 1; + PlayerInfo::setAttribute(CHAR_POINTS, points); + + int attrValue = PlayerInfo::getStatBase(attrNum) - 1; + PlayerInfo::setStatBase(attrNum, attrValue); } break; } } break; @@ -221,21 +220,23 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) // has to be correct. The server is always right! // undo attribute change and set points to 0 logger->log("Warning: Server denied reduction of attribute %d (no points left) ", attrNum); - int attrValue = player_node->getAttributeBase(attrNum) + 1; - player_node->setCorrectionPoints(0); - player_node->setAttributeBase(attrNum, attrValue); + int attrValue = PlayerInfo::getStatBase(attrNum) + 1; + PlayerInfo::setAttribute(CHAR_POINTS, 0); + PlayerInfo::setStatBase(attrNum, attrValue); break; } break; case ATTRIBMOD_DENIED: { // undo attribute change logger->log("Warning: Server denied reduction of attribute %d (reason unknown) ", attrNum); - int charaPoints = player_node->getCharacterPoints() - 1; - player_node->setCharacterPoints(charaPoints); - int correctPoints = player_node->getCorrectionPoints() + 1; - player_node->setCorrectionPoints(correctPoints); - int attrValue = player_node->getAttributeBase(attrNum) + 1; - player_node->setAttributeBase(attrNum, attrValue); + int charaPoints = PlayerInfo::getAttribute(CHAR_POINTS) - 1; + PlayerInfo::setAttribute(CHAR_POINTS, charaPoints); + + int correctPoints = PlayerInfo::getAttribute(CORR_POINTS) + 1; + PlayerInfo::setAttribute(CORR_POINTS, correctPoints); + + int attrValue = PlayerInfo::getStatBase(attrNum) + 1; + PlayerInfo::setStatBase(attrNum, attrValue); } break; } @@ -250,7 +251,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) int current = msg.readInt32(); int max = msg.readInt32(); int recharge = msg.readInt32(); - player_node->setSpecialStatus(id, current, max, recharge); + PlayerInfo::setSpecialStatus(id, current, max, recharge); } } break; /* @@ -343,11 +344,14 @@ void PlayerHandler::increaseSkill(int skillId) void PlayerHandler::pickUp(FloorItem *floorItem) { - int id = floorItem->getId(); - MessageOut msg(PGMSG_PICKUP); - msg.writeInt16(id >> 16); - msg.writeInt16(id & 0xFFFF); - gameServerConnection->send(msg); + if (floorItem) + { + int id = floorItem->getId(); + MessageOut msg(PGMSG_PICKUP); + msg.writeInt16(id >> 16); + msg.writeInt16(id & 0xFFFF); + gameServerConnection->send(msg); + } } void PlayerHandler::setDirection(char direction) diff --git a/src/net/manaserv/tradehandler.cpp b/src/net/manaserv/tradehandler.cpp index 234a18d6..30ff6890 100644 --- a/src/net/manaserv/tradehandler.cpp +++ b/src/net/manaserv/tradehandler.cpp @@ -21,15 +21,15 @@ #include "net/manaserv/tradehandler.h" -#include "beingmanager.h" +#include "actorspritemanager.h" +#include "event.h" #include "item.h" #include "localplayer.h" +#include "playerinfo.h" #include "gui/confirmdialog.h" #include "gui/trade.h" -#include "gui/widgets/chattab.h" - #include "net/net.h" #include "net/manaserv/connection.h" @@ -86,16 +86,15 @@ TradeHandler::TradeHandler(): }; handledMessages = _messages; tradeHandler = this; - } void TradeHandler::setAcceptTradeRequests(bool acceptTradeRequests) { mAcceptTradeRequests = acceptTradeRequests; if (mAcceptTradeRequests) - localChatTab->chatLog(_("Accepting incoming trade requests."), BY_SERVER); + SERVER_NOTICE(_("Accepting incoming trade requests.")) else - localChatTab->chatLog(_("Ignoring incoming trade requests."), BY_SERVER); + SERVER_NOTICE(_("Ignoring incoming trade requests.")) } void TradeHandler::handleMessage(Net::MessageIn &msg) @@ -104,13 +103,13 @@ 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); break; } - player_node->setTrading(true); + PlayerInfo::setTrading(true); tradePartnerName = being->getName(); tradePartnerID = being->getId(); ConfirmDialog *dlg = new ConfirmDialog(_("Request for Trade"), @@ -144,19 +143,19 @@ void TradeHandler::handleMessage(Net::MessageIn &msg) case GPMSG_TRADE_AGREED: tradeWindow->receivedOk(false); break; - + case GPMSG_TRADE_CANCEL: - localChatTab->chatLog(_("Trade canceled."), BY_SERVER); + SERVER_NOTICE(_("Trade canceled.")) tradeWindow->setVisible(false); tradeWindow->reset(); - player_node->setTrading(false); + PlayerInfo::setTrading(false); break; case GPMSG_TRADE_COMPLETE: - localChatTab->chatLog(_("Trade completed."), BY_SERVER); + SERVER_NOTICE(_("Trade completed.")) tradeWindow->setVisible(false); tradeWindow->reset(); - player_node->setTrading(false); + PlayerInfo::setTrading(false); break; } } @@ -177,7 +176,7 @@ void TradeHandler::respond(bool accept) gameServerConnection->send(msg); if (!accept) - player_node->setTrading(false); + PlayerInfo::setTrading(false); } void TradeHandler::addItem(Item *item, int amount) diff --git a/src/net/npchandler.h b/src/net/npchandler.h index bba8dc31..fb8ab7ec 100644 --- a/src/net/npchandler.h +++ b/src/net/npchandler.h @@ -29,20 +29,7 @@ namespace Net { class NpcHandler { public: - virtual void talk(int npcId) = 0; - - virtual void nextDialog(int npcId) = 0; - - virtual void closeDialog(int npcId) = 0; - - virtual void listInput(int npcId, int value) = 0; - - virtual void integerInput(int npcId, int value) = 0; - - virtual void stringInput(int npcId, const std::string &value) = 0; - - virtual void sendLetter(int npcId, const std::string &recipient, - const std::string &text) = 0; + virtual ~NpcHandler() {} virtual void startShopping(int beingId) = 0; @@ -55,8 +42,6 @@ class NpcHandler virtual void sellItem(int beingId, int itemId, int amount) = 0; virtual void endShopping(int beingId) = 0; - - virtual ~NpcHandler() {} }; } // namespace Net diff --git a/src/net/partyhandler.h b/src/net/partyhandler.h index dd1103fc..7ca13546 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, @@ -38,11 +38,13 @@ namespace Net { class PartyHandler { public: + virtual ~PartyHandler() {} + virtual void create(const std::string &name = "") = 0; 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 +52,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; @@ -69,8 +71,6 @@ class PartyHandler // virtual void options() = 0; // virtual void message() = 0; - - virtual ~PartyHandler() {} }; } // namespace Net diff --git a/src/net/playerhandler.h b/src/net/playerhandler.h index 399afb5e..b3534b83 100644 --- a/src/net/playerhandler.h +++ b/src/net/playerhandler.h @@ -31,6 +31,8 @@ namespace Net { class PlayerHandler { public: + virtual ~PlayerHandler() {} + virtual void attack(int id) = 0; virtual void emote(int emoteId) = 0; @@ -62,8 +64,6 @@ class PlayerHandler virtual int getJobLocation() = 0; virtual Vector getDefaultWalkSpeed() = 0; - - virtual ~PlayerHandler() {} }; } // namespace Net diff --git a/src/net/specialhandler.h b/src/net/specialhandler.h index 21e3a4b7..89fcdf7d 100644 --- a/src/net/specialhandler.h +++ b/src/net/specialhandler.h @@ -28,6 +28,8 @@ namespace Net { class SpecialHandler { public: + virtual ~SpecialHandler () {} + virtual void use(int id) = 0; virtual void use(int id, int level, int beingId) = 0; @@ -35,8 +37,6 @@ class SpecialHandler virtual void use(int id, int level, int x, int y) = 0; virtual void use(int id, const std::string &map) = 0; - - virtual ~SpecialHandler () {} }; } diff --git a/src/net/tmwa/adminhandler.cpp b/src/net/tmwa/adminhandler.cpp index e56d5a44..b72c2a13 100644 --- a/src/net/tmwa/adminhandler.cpp +++ b/src/net/tmwa/adminhandler.cpp @@ -21,13 +21,12 @@ #include "net/tmwa/adminhandler.h" +#include "actorspritemanager.h" #include "being.h" -#include "beingmanager.h" +#include "event.h" #include "game.h" #include "playerrelations.h" -#include "gui/widgets/chattab.h" - #include "net/chathandler.h" #include "net/net.h" @@ -60,9 +59,9 @@ void AdminHandler::handleMessage(Net::MessageIn &msg) case SMSG_ADMIN_KICK_ACK: id = msg.readInt32(); if (id == 0) - localChatTab->chatLog(_("Kick failed!"), BY_SERVER); + SERVER_NOTICE(_("Kick failed!")) else - localChatTab->chatLog(_("Kick succeeded!"), BY_SERVER); + SERVER_NOTICE(_("Kick succeeded!")) break; } } diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp index 04690c50..543beec2 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,11 +233,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) * later versions of eAthena for both mobs and * players */ - dstBeing = beingManager->findBeing(msg.readInt32()); - - Uint16 srcX, srcY, dstX, dstY; - msg.readCoordinatePair(srcX, srcY, dstX, dstY); - msg.readInt32(); // Server tick + dstBeing = actorSpriteManager->findBeing(msg.readInt32()); /* * This packet doesn't have enough info to actually @@ -254,21 +241,23 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) * we'll just pretend the packet didn't happen */ - if (dstBeing) - { - dstBeing->setAction(Being::STAND); - dstBeing->setTileCoords(srcX, srcY); - dstBeing->setDestination(dstX, dstY); - } + if (!dstBeing) + break; + + Uint16 srcX, srcY, dstX, dstY; + msg.readCoordinatePair(srcX, srcY, dstX, dstY); + msg.readInt32(); // Server tick + + dstBeing->setAction(Being::STAND); + dstBeing->setTileCoords(srcX, srcY); + dstBeing->setDestination(dstX, dstY); break; case SMSG_BEING_REMOVE: // A being should be removed or has died id = msg.readInt32(); - - dstBeing = beingManager->findBeing(id); - + dstBeing = actorSpriteManager->findBeing(id); if (!dstBeing) break; @@ -289,16 +278,14 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) if (msg.readInt8() == 1) dstBeing->setAction(Being::DEAD); else - beingManager->destroyBeing(dstBeing); + actorSpriteManager->destroy(dstBeing); break; case SMSG_BEING_RESURRECT: // A being changed mortality status id = msg.readInt32(); - - dstBeing = beingManager->findBeing(id); - + dstBeing = actorSpriteManager->findBeing(id); if (!dstBeing) break; @@ -313,8 +300,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 +316,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 +344,6 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) case 0x02: // Sit if (srcBeing) { - srcBeing->setFrame(0); srcBeing->setAction(Being::SIT); } break; @@ -365,7 +351,6 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) case 0x03: // Stand up if (srcBeing) { - srcBeing->setFrame(0); srcBeing->setAction(Being::STAND); } break; @@ -374,19 +359,18 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) case SMSG_BEING_SELFEFFECT: { id = (Uint32)msg.readInt32(); - if (!beingManager->findBeing(id)) + Being* being = actorSpriteManager->findBeing(id); + if (!being) break; int effectType = msg.readInt32(); - Being* being = beingManager->findBeing(id); effectManager->trigger(effectType, being); - break; } case SMSG_BEING_EMOTION: - if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) + if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32()))) { break; } @@ -415,14 +399,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 +421,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 +466,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 +481,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 +504,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 +514,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 +543,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 +587,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 +610,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,18 +634,15 @@ 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; x = msg.readInt16(); y = msg.readInt16(); dstBeing->setTileCoords(x, y); - if (dstBeing->getCurrentAction() == Being::WALK) - { - dstBeing->setFrame(0); + if (dstBeing->getCurrentAction() == Being::MOVE) dstBeing->setAction(Being::STAND); - } } } break; @@ -684,18 +659,18 @@ 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); + if (!dstBeing) + break; + stunMode = msg.readInt16(); statusEffects = msg.readInt16(); statusEffects |= ((Uint32) msg.readInt16()) << 16; - msg.readInt8(); + msg.readInt8(); // Unused? - if (dstBeing) - { - dstBeing->setStunMode(stunMode); - dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); - dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); - } + dstBeing->setStunMode(stunMode); + dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); + dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); break; case SMSG_BEING_STATUS_CHANGE: @@ -704,7 +679,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..5368ba9d 100644 --- a/src/net/tmwa/buysellhandler.cpp +++ b/src/net/tmwa/buysellhandler.cpp @@ -21,18 +21,17 @@ #include "net/tmwa/buysellhandler.h" -#include "beingmanager.h" +#include "actorspritemanager.h" +#include "event.h" #include "inventory.h" #include "item.h" #include "localplayer.h" -#include "npc.h" +#include "playerinfo.h" #include "gui/buy.h" #include "gui/buysell.h" #include "gui/sell.h" -#include "gui/widgets/chattab.h" - #include "net/messagein.h" #include "net/tmwa/protocol.h" @@ -62,7 +61,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) switch (msg.getId()) { case SMSG_NPC_BUY_SELL_CHOICE: - if (!BuySellDialog::isActive()) + if (PlayerInfo::getBuySellState() != BUYSELL_CHOOSING) { mNpcId = msg.readInt32(); new BuySellDialog(mNpcId); @@ -73,7 +72,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) msg.readInt16(); // length n_items = (msg.getLength() - 4) / 11; mBuyDialog = new BuyDialog(mNpcId); - mBuyDialog->setMoney(player_node->getMoney()); + mBuyDialog->setMoney(PlayerInfo::getAttribute(MONEY)); for (int k = 0; k < n_items; k++) { @@ -91,7 +90,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) if (n_items > 0) { SellDialog *dialog = new SellDialog(mNpcId); - dialog->setMoney(player_node->getMoney()); + dialog->setMoney(PlayerInfo::getAttribute(MONEY)); for (int k = 0; k < n_items; k++) { @@ -99,7 +98,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) int value = msg.readInt32(); msg.readInt32(); // OCvalue - Item *item = player_node->getInventory()->getItem(index); + Item *item = PlayerInfo::getInventory()->getItem(index); if (item && !(item->isEquipped())) dialog->addItem(item, value); @@ -107,29 +106,29 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) } else { - localChatTab->chatLog(_("Nothing to sell."), BY_SERVER); + SERVER_NOTICE(_("Nothing to sell.")) } break; case SMSG_NPC_BUY_RESPONSE: if (msg.readInt8() == 0) { - localChatTab->chatLog(_("Thanks for buying."), BY_SERVER); + SERVER_NOTICE(_("Thanks for buying.")) } else { // Reset player money since buy dialog already assumed purchase // would go fine - mBuyDialog->setMoney(player_node->getMoney()); - localChatTab->chatLog(_("Unable to buy."), BY_SERVER); + mBuyDialog->setMoney(PlayerInfo::getAttribute(MONEY)); + SERVER_NOTICE(_("Unable to buy.")) } break; case SMSG_NPC_SELL_RESPONSE: if (msg.readInt8() == 0) - localChatTab->chatLog(_("Thanks for selling."), BY_SERVER); + SERVER_NOTICE(_("Thanks for selling.")) else - localChatTab->chatLog(_("Unable to sell."), BY_SERVER); + SERVER_NOTICE(_("Unable to sell.")) break; } diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp index 8711f031..820864ce 100644 --- a/src/net/tmwa/charserverhandler.cpp +++ b/src/net/tmwa/charserverhandler.cpp @@ -83,12 +83,10 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg) for (int i = 0; i < count; ++i) { Net::Character *character = new Net::Character; - int slot; - character->dummy = readPlayerData(msg, &slot); - character->slot = slot; + readPlayerData(msg, character); mCharacters.push_back(character); logger->log("CharServer: Player: %s (%d)", - character->dummy->getName().c_str(), slot); + character->dummy->getName().c_str(), character->slot); } Client::setState(STATE_CHAR_SELECT); @@ -115,9 +113,7 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg) case SMSG_CHAR_CREATE_SUCCEEDED: { Net::Character *character = new Net::Character; - int slot; - character->dummy = readPlayerData(msg, &slot); - character->slot = slot; + readPlayerData(msg, character); mCharacters.push_back(character); updateCharSelectDialog(); @@ -162,6 +158,8 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg) // Prevent the selected local player from being deleted player_node = mSelectedCharacter->dummy; + PlayerInfo::setBackend(mSelectedCharacter->data); + mSelectedCharacter->dummy = 0; delete_all(mCharacters); @@ -191,7 +189,7 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg) } } -LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int *slot) +void CharServerHandler::readPlayerData(Net::MessageIn &msg, Net::Character *character) { const Token &token = static_cast<LoginHandler*>(Net::getLoginHandler())->getToken(); @@ -199,30 +197,37 @@ LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int *slot) LocalPlayer *tempPlayer = new LocalPlayer(msg.readInt32(), 0); tempPlayer->setGender(token.sex); - tempPlayer->setExp(msg.readInt32()); - tempPlayer->setMoney(msg.readInt32()); - tempPlayer->setExperience(JOB, msg.readInt32(), 1); + character->data.mAttributes[EXP] = msg.readInt32(); + character->data.mAttributes[MONEY] = msg.readInt32(); + character->data.mStats[JOB].exp = msg.readInt32(); + int temp = msg.readInt32(); - tempPlayer->setAttributeBase(JOB, temp, false); - tempPlayer->setAttributeEffective(JOB, temp); + character->data.mStats[JOB].base = temp; + character->data.mStats[JOB].mod = temp; + tempPlayer->setSprite(SPRITE_SHOE, msg.readInt16()); tempPlayer->setSprite(SPRITE_GLOVES, msg.readInt16()); tempPlayer->setSprite(SPRITE_CAPE, msg.readInt16()); tempPlayer->setSprite(SPRITE_MISC1, msg.readInt16()); + msg.readInt32(); // option msg.readInt32(); // karma msg.readInt32(); // manner msg.skip(2); // unknown - tempPlayer->setHp(msg.readInt16()); - tempPlayer->setMaxHp(msg.readInt16()); - tempPlayer->setMP(msg.readInt16()); - tempPlayer->setMaxMP(msg.readInt16()); + + character->data.mAttributes[HP] = msg.readInt16(); + character->data.mAttributes[MAX_HP] = msg.readInt16(); + character->data.mAttributes[MP] = msg.readInt16(); + character->data.mAttributes[MAX_MP] = msg.readInt16(); + msg.readInt16(); // speed tempPlayer->setSubtype(msg.readInt16()); // class (used for race) int hairStyle = msg.readInt16(); Uint16 weapon = msg.readInt16(); tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", true); - tempPlayer->setLevel(msg.readInt16()); + + character->data.mAttributes[LEVEL] = msg.readInt16(); + msg.readInt16(); // skill point tempPlayer->setSprite(SPRITE_BOTTOMCLOTHES, msg.readInt16()); // head bottom tempPlayer->setSprite(SPRITE_SHIELD, msg.readInt16()); @@ -231,12 +236,14 @@ LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int *slot) tempPlayer->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(msg.readInt16())); tempPlayer->setSprite(SPRITE_MISC2, msg.readInt16()); tempPlayer->setName(msg.readString(24)); + + character->dummy = tempPlayer; + for (int i = 0; i < 6; i++) - tempPlayer->setAttributeBase(i + STR, msg.readInt8(), false); - *slot = msg.readInt8(); // character slot - msg.readInt8(); // unknown + character->data.mStats[i + STR].base = msg.readInt8(); - return tempPlayer; + character->slot = msg.readInt8(); // character slot + msg.readInt8(); // unknown } void CharServerHandler::setCharSelectDialog(CharSelectDialog *window) @@ -312,17 +319,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..2076cbae 100644 --- a/src/net/tmwa/charserverhandler.h +++ b/src/net/tmwa/charserverhandler.h @@ -63,16 +63,16 @@ 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(); private: - LocalPlayer *readPlayerData(Net::MessageIn &msg, int *slot); + void readPlayerData(Net::MessageIn &msg, Net::Character *character); }; } // namespace TmwAthena diff --git a/src/net/tmwa/chathandler.cpp b/src/net/tmwa/chathandler.cpp index 00d29662..2b647f68 100644 --- a/src/net/tmwa/chathandler.cpp +++ b/src/net/tmwa/chathandler.cpp @@ -21,14 +21,13 @@ #include "net/tmwa/chathandler.h" +#include "actorspritemanager.h" #include "being.h" -#include "beingmanager.h" +#include "event.h" #include "game.h" #include "localplayer.h" #include "playerrelations.h" -#include "gui/widgets/chattab.h" - #include "net/messagein.h" #include "net/messageout.h" @@ -60,8 +59,6 @@ ChatHandler::ChatHandler() void ChatHandler::handleMessage(Net::MessageIn &msg) { - if (!localChatTab) return; - Being *being; std::string chatMsg; std::string nick; @@ -70,19 +67,36 @@ void ChatHandler::handleMessage(Net::MessageIn &msg) switch (msg.getId()) { case SMSG_WHISPER_RESPONSE: + if (mSentWhispers.empty()) + nick = "user"; + else + { + nick = mSentWhispers.front(); + mSentWhispers.pop(); + } + switch (msg.readInt8()) { case 0x00: - // comment out since we'll local echo in chat.cpp instead, then only report failures - //localChatTab->chatLog("Whisper sent", BY_SERVER); + // Success (don't need to report) break; case 0x01: - localChatTab->chatLog(_("Whisper could not be sent, user " - "is offline."), BY_SERVER); + { + Mana::Event event("WhisperError"); + event.setString("nick", nick); + event.setString("error", strprintf(_("Whisper could " + "not be sent, %s is offline."), nick.c_str())); + event.trigger("Chat"); + } break; case 0x02: - localChatTab->chatLog(_("Whisper could not be sent, " - "ignored by user."), BY_SERVER); + { + Mana::Event event("WhisperError"); + event.setString("nick", nick); + event.setString("error", strprintf(_("Whisper could " + "not be sent, ignored by %s."), nick.c_str())); + event.Event::trigger("Chat"); + } break; } break; @@ -100,11 +114,16 @@ void ChatHandler::handleMessage(Net::MessageIn &msg) if (nick != "Server") { if (player_relations.hasPermission(nick, PlayerRelation::WHISPER)) - chatWindow->whisper(nick, chatMsg); + { + Mana::Event event("Whisper"); + event.setString("nick", nick); + event.setString("message", chatMsg); + event.trigger("Chat"); + } } else { - localChatTab->chatLog(chatMsg, BY_SERVER); + SERVER_NOTICE(chatMsg) } break; @@ -113,7 +132,8 @@ void ChatHandler::handleMessage(Net::MessageIn &msg) case SMSG_BEING_CHAT: { chatMsgLength = msg.readInt16() - 8; - being = beingManager->findBeing(msg.readInt32()); + int beingId = msg.readInt32(); + being = actorSpriteManager->findBeing(beingId); if (!being || chatMsgLength <= 0) break; @@ -135,23 +155,33 @@ void ChatHandler::handleMessage(Net::MessageIn &msg) chatMsg.erase(0, pos + 3); } - trim(chatMsg); + int perms; - // We use getIgnorePlayer instead of ignoringPlayer here - // because ignorePlayer' side effects are triggered - // right below for Being::IGNORE_SPEECH_FLOAT. - if (player_relations.checkPermissionSilently(sender_name, - PlayerRelation::SPEECH_LOG) && chatWindow) + if (being->getType() == Being::PLAYER) { - localChatTab->chatLog(removeColors(sender_name) + " : " - + chatMsg, BY_OTHER); + perms = player_relations.checkPermissionSilently(sender_name, + PlayerRelation::SPEECH_LOG | PlayerRelation::SPEECH_FLOAT); } - - if (player_relations.hasPermission(sender_name, - PlayerRelation::SPEECH_FLOAT)) + else { - being->setSpeech(chatMsg, SPEECH_TIME); + perms = player_relations.getDefault() + & (PlayerRelation::SPEECH_LOG + | PlayerRelation::SPEECH_FLOAT); } + + trim(chatMsg); + + std::string reducedMessage = chatMsg; + chatMsg = removeColors(sender_name) + " : " + reducedMessage; + + Mana::Event event("Being"); + event.setString("message", chatMsg); + event.setString("text", reducedMessage); + event.setString("nick", sender_name); + event.setInt("beingId", beingId); + event.setInt("permissions", perms); + event.trigger("Chat"); + break; } @@ -164,22 +194,32 @@ void ChatHandler::handleMessage(Net::MessageIn &msg) break; chatMsg = msg.readString(chatMsgLength); - std::string::size_type pos = chatMsg.find(" : ", 0); if (msg.getId() == SMSG_PLAYER_CHAT) { - localChatTab->chatLog(chatMsg, BY_PLAYER); + std::string::size_type pos = chatMsg.find(" : ", 0); + std::string mes = chatMsg; if (pos != std::string::npos) chatMsg.erase(0, pos + 3); trim(chatMsg); - player_node->setSpeech(chatMsg, SPEECH_TIME); + Mana::Event event("Player"); + event.setString("message", mes); + event.setString("text", chatMsg); + event.setString("nick", player_node->getName()); + event.setInt("beingId", player_node->getId()); + event.setInt("permissions", player_relations.getDefault() + & (PlayerRelation::SPEECH_LOG + | PlayerRelation::SPEECH_FLOAT)); + event.trigger("Chat"); } else { - localChatTab->chatLog(chatMsg, BY_GM); + Mana::Event event("Announcement"); + event.setString("message", chatMsg); + event.trigger("Chat"); } break; } @@ -187,7 +227,7 @@ void ChatHandler::handleMessage(Net::MessageIn &msg) case SMSG_MVP: // Display MVP player msg.readInt32(); // id - localChatTab->chatLog(_("MVP player."), BY_SERVER); + SERVER_NOTICE(_("MVP player.")) break; } } @@ -216,47 +256,49 @@ void ChatHandler::privateMessage(const std::string &recipient, outMsg.writeInt16(text.length() + 28); outMsg.writeString(recipient, 24); outMsg.writeString(text, text.length()); + + mSentWhispers.push(recipient); } void ChatHandler::channelList() { - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); + SERVER_NOTICE(_("Channels are not supported!")) } void ChatHandler::enterChannel(const std::string &channel, const std::string &password) { - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); + SERVER_NOTICE(_("Channels are not supported!")) } void ChatHandler::quitChannel(int channelId) { - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); + SERVER_NOTICE(_("Channels are not supported!")) } void ChatHandler::sendToChannel(int channelId, const std::string &text) { - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); + SERVER_NOTICE(_("Channels are not supported!")) } void ChatHandler::userList(const std::string &channel) { - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); + SERVER_NOTICE(_("Channels are not supported!")) } void ChatHandler::setChannelTopic(int channelId, const std::string &text) { - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); + SERVER_NOTICE(_("Channels are not supported!")) } void ChatHandler::setUserMode(int channelId, const std::string &name, int mode) { - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); + SERVER_NOTICE(_("Channels are not supported!")) } void ChatHandler::kickUser(int channelId, const std::string &name) { - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); + SERVER_NOTICE(_("Channels are not supported!")) } void ChatHandler::who() diff --git a/src/net/tmwa/chathandler.h b/src/net/tmwa/chathandler.h index 3e035f7e..6426a71e 100644 --- a/src/net/tmwa/chathandler.h +++ b/src/net/tmwa/chathandler.h @@ -27,6 +27,8 @@ #include "net/tmwa/messagehandler.h" +#include <queue> + namespace TmwAthena { class ChatHandler : public MessageHandler, public Net::ChatHandler @@ -61,6 +63,10 @@ class ChatHandler : public MessageHandler, public Net::ChatHandler void kickUser(int channelId, const std::string &name); void who(); + + private: + typedef std::queue<std::string> WhisperQueue; + WhisperQueue mSentWhispers; }; } // namespace TmwAthena diff --git a/src/net/tmwa/gamehandler.cpp b/src/net/tmwa/gamehandler.cpp index 435d5d30..334a2e37 100644 --- a/src/net/tmwa/gamehandler.cpp +++ b/src/net/tmwa/gamehandler.cpp @@ -22,12 +22,11 @@ #include "net/tmwa/gamehandler.h" #include "client.h" +#include "event.h" #include "game.h" #include "localplayer.h" #include "log.h" -#include "gui/widgets/chattab.h" - #include "gui/okdialog.h" #include "net/messagein.h" @@ -58,6 +57,8 @@ GameHandler::GameHandler() }; handledMessages = _messages; gameHandler = this; + + listen("Game"); } void GameHandler::handleMessage(Net::MessageIn &msg) @@ -84,8 +85,7 @@ void GameHandler::handleMessage(Net::MessageIn &msg) break; case SMSG_WHO_ANSWER: - localChatTab->chatLog(strprintf(_("Online users: %d"), - msg.readInt32()), BY_SERVER); + SERVER_NOTICE(strprintf(_("Online users: %d"), msg.readInt32())) break; case SMSG_CHAR_SWITCH_RESPONSE: @@ -105,6 +105,21 @@ void GameHandler::handleMessage(Net::MessageIn &msg) } } +void GameHandler::event(const std::string &channel, const Mana::Event &event) +{ + if (channel == "Game") + { + if (event.getName() == "EnginesInitalized") + { + Game::instance()->changeMap(mMap); + } + else if (event.getName() == "MapLoaded") + { + MessageOut outMsg(CMSG_MAP_LOADED); + } + } +} + void GameHandler::connect() { mNetwork->connect(mapServer); @@ -142,16 +157,6 @@ void GameHandler::disconnect() mNetwork->disconnect(); } -void GameHandler::inGame() -{ - Game::instance()->changeMap(mMap); -} - -void GameHandler::mapLoaded(const std::string &mapName) -{ - MessageOut outMsg(CMSG_MAP_LOADED); -} - void GameHandler::who() { } diff --git a/src/net/tmwa/gamehandler.h b/src/net/tmwa/gamehandler.h index ca8d27e6..6bdcbaef 100644 --- a/src/net/tmwa/gamehandler.h +++ b/src/net/tmwa/gamehandler.h @@ -22,6 +22,8 @@ #ifndef NET_TA_MAPHANDLER_H #define NET_TA_MAPHANDLER_H +#include "listener.h" + #include "net/gamehandler.h" #include "net/net.h" #include "net/serverinfo.h" @@ -31,23 +33,22 @@ namespace TmwAthena { -class GameHandler : public MessageHandler, public Net::GameHandler +class GameHandler : public MessageHandler, public Net::GameHandler, + public Mana::Listener { public: GameHandler(); void handleMessage(Net::MessageIn &msg); + void event(const std::string &channel, const Mana::Event &event); + void connect(); bool isConnected(); void disconnect(); - void inGame(); - - void mapLoaded(const std::string &mapName); - void who(); void quit(); @@ -60,6 +61,9 @@ class GameHandler : public MessageHandler, public Net::GameHandler void setMap(const std::string map); + /** The tmwAthena protocol is making use of the MP status bar. */ + bool canUseMagicBar() const { return true; } + private: std::string mMap; int mCharID; /// < Saved for map-server switching diff --git a/src/net/tmwa/generalhandler.cpp b/src/net/tmwa/generalhandler.cpp index 14f48055..8d69767f 100644 --- a/src/net/tmwa/generalhandler.cpp +++ b/src/net/tmwa/generalhandler.cpp @@ -32,6 +32,10 @@ #include "gui/socialwindow.h" #include "gui/statuswindow.h" +#include "net/messagein.h" +#include "net/messageout.h" +#include "net/serverinfo.h" + #include "net/tmwa/adminhandler.h" #include "net/tmwa/beinghandler.h" #include "net/tmwa/buysellhandler.h" @@ -53,9 +57,6 @@ #include "net/tmwa/gui/guildtab.h" #include "net/tmwa/gui/partytab.h" -#include "net/messagein.h" -#include "net/messageout.h" - #include "resources/itemdb.h" #include "utils/gettext.h" @@ -75,7 +76,7 @@ extern Party *taParty; GeneralHandler::GeneralHandler(): mAdminHandler(new AdminHandler), - mBeingHandler(new BeingHandler(config.getValue("EnableSync", 0) == 1)), + mBeingHandler(new BeingHandler(config.getBoolValue("EnableSync"))), mBuySellHandler(new BuySellHandler), mCharHandler(new CharServerHandler), mChatHandler(new ChatHandler), @@ -106,6 +107,8 @@ GeneralHandler::GeneralHandler(): stats.push_back(ItemDB::Stat("luck", _("Luck %+d"))); ItemDB::setStatsList(stats); + + listen("Game"); } GeneralHandler::~GeneralHandler() @@ -209,47 +212,48 @@ void GeneralHandler::flushNetwork() } } -void GeneralHandler::guiWindowsLoaded() -{ - inventoryWindow->setSplitAllowed(false); - skillDialog->loadSkills("ea-skills.xml"); - - statusWindow->addAttribute(STR, _("Strength"), true, ""); - statusWindow->addAttribute(AGI, _("Agility"), true, ""); - statusWindow->addAttribute(VIT, _("Vitality"), true, ""); - statusWindow->addAttribute(INT, _("Intelligence"), true, ""); - statusWindow->addAttribute(DEX, _("Dexterity"), true, ""); - statusWindow->addAttribute(LUK, _("Luck"), true, ""); - - statusWindow->addAttribute(ATK, _("Attack"), false, ""); - statusWindow->addAttribute(DEF, _("Defense"), false, ""); - statusWindow->addAttribute(MATK, _("M.Attack"), false, ""); - statusWindow->addAttribute(MDEF, _("M.Defense"), false, ""); - statusWindow->addAttribute(HIT, _("% Accuracy"), false, ""); - statusWindow->addAttribute(FLEE, _("% Evade"), false, ""); - statusWindow->addAttribute(CRIT, _("% Critical"), false, ""); -} - -void GeneralHandler::guiWindowsUnloaded() -{ - socialWindow->removeTab(taGuild); - socialWindow->removeTab(taParty); - - delete guildTab; - guildTab = 0; - - delete partyTab; - partyTab = 0; -} - void GeneralHandler::clearHandlers() { mNetwork->clearHandlers(); } -void GeneralHandler::stateChanged(State oldState, State newState) +void GeneralHandler::event(const std::string &channel, + const Mana::Event &event) { - // + if (channel == "Game") + { + if (event.getName() == "GuiWindowsLoaded") + { + inventoryWindow->setSplitAllowed(false); + skillDialog->loadSkills("ea-skills.xml"); + + statusWindow->addAttribute(STR, _("Strength"), true, ""); + statusWindow->addAttribute(AGI, _("Agility"), true, ""); + statusWindow->addAttribute(VIT, _("Vitality"), true, ""); + statusWindow->addAttribute(INT, _("Intelligence"), true, ""); + statusWindow->addAttribute(DEX, _("Dexterity"), true, ""); + statusWindow->addAttribute(LUK, _("Luck"), true, ""); + + statusWindow->addAttribute(ATK, _("Attack"), false, ""); + statusWindow->addAttribute(DEF, _("Defense"), false, ""); + statusWindow->addAttribute(MATK, _("M.Attack"), false, ""); + statusWindow->addAttribute(MDEF, _("M.Defense"), false, ""); + statusWindow->addAttribute(HIT, _("% Accuracy"), false, ""); + statusWindow->addAttribute(FLEE, _("% Evade"), false, ""); + statusWindow->addAttribute(CRIT, _("% Critical"), false, ""); + } + else if (event.getName() == "GuiWindowsUnloading") + { + socialWindow->removeTab(taGuild); + socialWindow->removeTab(taParty); + + delete guildTab; + guildTab = 0; + + delete partyTab; + partyTab = 0; + } + } } } // namespace TmwAthena diff --git a/src/net/tmwa/generalhandler.h b/src/net/tmwa/generalhandler.h index d680f215..f7f78759 100644 --- a/src/net/tmwa/generalhandler.h +++ b/src/net/tmwa/generalhandler.h @@ -22,15 +22,17 @@ #ifndef NET_TMWA_GENERALHANDLER_H #define NET_TMWA_GENERALHANDLER_H +#include "listener.h" + #include "net/generalhandler.h" #include "net/net.h" -#include "net/serverinfo.h" #include "net/tmwa/messagehandler.h" namespace TmwAthena { -class GeneralHandler : public MessageHandler, public Net::GeneralHandler +class GeneralHandler : public MessageHandler, public Net::GeneralHandler, + public Mana::Listener { public: GeneralHandler(); @@ -47,13 +49,9 @@ class GeneralHandler : public MessageHandler, public Net::GeneralHandler void flushNetwork(); - void guiWindowsLoaded(); - - void guiWindowsUnloaded(); - void clearHandlers(); - void stateChanged(State oldState, State newState); + void event(const std::string &channel, const Mana::Event &event); protected: MessageHandlerPtr mAdminHandler; diff --git a/src/net/tmwa/gui/guildtab.cpp b/src/net/tmwa/gui/guildtab.cpp index 794ad5cc..ca922e55 100644 --- a/src/net/tmwa/gui/guildtab.cpp +++ b/src/net/tmwa/gui/guildtab.cpp @@ -21,17 +21,17 @@ #include "net/tmwa/gui/guildtab.h" +#include "chatlog.h" #include "commandhandler.h" #include "guild.h" #include "localplayer.h" -#include "gui/theme.h" - #include "net/net.h" #include "net/guildhandler.h" #include "resources/iteminfo.h" #include "resources/itemdb.h" +#include "resources/theme.h" #include "utils/dtor.h" #include "utils/gettext.h" @@ -114,4 +114,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..d5781971 100644 --- a/src/net/tmwa/gui/partytab.cpp +++ b/src/net/tmwa/gui/partytab.cpp @@ -21,17 +21,17 @@ #include "net/tmwa/gui/partytab.h" +#include "chatlog.h" #include "commandhandler.h" #include "localplayer.h" #include "party.h" -#include "gui/theme.h" - #include "net/net.h" #include "net/partyhandler.h" #include "resources/iteminfo.h" #include "resources/itemdb.h" +#include "resources/theme.h" #include "utils/dtor.h" #include "utils/gettext.h" @@ -206,4 +206,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..67fe5d98 100644 --- a/src/net/tmwa/guildhandler.cpp +++ b/src/net/tmwa/guildhandler.cpp @@ -21,6 +21,7 @@ #include "net/tmwa/guildhandler.h" #include "guild.h" +#include "event.h" #include "localplayer.h" #include "log.h" @@ -387,8 +388,7 @@ void GuildHandler::handleMessage(Net::MessageIn &msg) void GuildHandler::create(const std::string &name) { - localChatTab->chatLog(_("Guild creation isn't supported yet."), - BY_SERVER); + SERVER_NOTICE(_("Guild creation isn't supported yet.")) return; MessageOut msg(CMSG_GUILD_CREATE); @@ -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/inventoryhandler.cpp b/src/net/tmwa/inventoryhandler.cpp index fd979dc6..46eb6258 100644 --- a/src/net/tmwa/inventoryhandler.cpp +++ b/src/net/tmwa/inventoryhandler.cpp @@ -23,6 +23,7 @@ #include "configuration.h" #include "equipment.h" +#include "event.h" #include "inventory.h" #include "item.h" #include "itemshortcut.h" @@ -108,6 +109,8 @@ InventoryHandler::InventoryHandler() mStorage = 0; mStorageWindow = 0; + + listen("Item"); } InventoryHandler::~InventoryHandler() @@ -126,7 +129,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) int number, flag; int index, amount, itemId, equipType, arrow; int identified, cards[4], itemType; - Inventory *inventory = player_node->getInventory(); + Inventory *inventory = PlayerInfo::getInventory(); switch (msg.getId()) { @@ -136,7 +139,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) { // Clear inventory - this will be a complete refresh mEquips.clear(); - player_node->mEquipment->setBackend(&mEquips); + PlayerInfo::getEquipment()->setBackend(&mEquips); inventory->clear(); } @@ -276,7 +279,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) if (msg.readInt8() == 0) { - localChatTab->chatLog(_("Failed to use item."), BY_SERVER); + SERVER_NOTICE(_("Failed to use item.")) } else { @@ -386,7 +389,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) flag = msg.readInt8(); if (!flag) - localChatTab->chatLog(_("Unable to equip."), BY_SERVER); + SERVER_NOTICE(_("Unable to equip.")) else mEquips.setEquipment(getSlot(equipType), index); break; @@ -397,7 +400,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) flag = msg.readInt8(); if (!flag) - localChatTab->chatLog(_("Unable to unequip."), BY_SERVER); + SERVER_NOTICE(_("Unable to unequip.")) else mEquips.setEquipment(getSlot(equipType), -1); break; @@ -420,41 +423,85 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) } } -void InventoryHandler::equipItem(const Item *item) +void InventoryHandler::event(const std::string &channel, + const Mana::Event &event) { - if (!item) - return; - - MessageOut outMsg(CMSG_PLAYER_EQUIP); - outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); - outMsg.writeInt16(0); -} + if (channel == "Item") + { + if (event.getName() == "doCloseInventory") + { + // No need to worry about type + MessageOut outMsg(CMSG_CLOSE_STORAGE); + } + else + { + Item *item = event.getItem("item"); -void InventoryHandler::unequipItem(const Item *item) -{ - if (!item) - return; + if (!item) + return; - MessageOut outMsg(CMSG_PLAYER_UNEQUIP); - outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); -} + int index = item->getInvIndex() + INVENTORY_OFFSET; -void InventoryHandler::useItem(const Item *item) -{ - if (!item) - return; + if (event.getName() == "doEquip") + { + MessageOut outMsg(CMSG_PLAYER_EQUIP); + outMsg.writeInt16(index); + outMsg.writeInt16(0); + } + else if (event.getName() == "doUnequip") + { + MessageOut outMsg(CMSG_PLAYER_UNEQUIP); + outMsg.writeInt16(index); + } + else if (event.getName() == "doUse") + { + MessageOut outMsg(CMSG_PLAYER_INVENTORY_USE); + outMsg.writeInt16(index); + outMsg.writeInt32(item->getId()); // unused + } + else if (event.getName() == "doDrop") + { + int amount = event.getInt("amount", 1); - MessageOut outMsg(CMSG_PLAYER_INVENTORY_USE); - outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); - outMsg.writeInt32(item->getId()); // unused -} + // TODO: Fix wrong coordinates of drops, serverside? + // (what's wrong here?) + MessageOut outMsg(CMSG_PLAYER_INVENTORY_DROP); + outMsg.writeInt16(index); + outMsg.writeInt16(amount); + } + else if (event.getName() == "doMove") + { + int newIndex = event.getInt("newIndex", -1); -void InventoryHandler::dropItem(const Item *item, int amount) -{ - // TODO: Fix wrong coordinates of drops, serverside? (what's wrong here?) - MessageOut outMsg(CMSG_PLAYER_INVENTORY_DROP); - outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); - outMsg.writeInt16(amount); + if (newIndex >= 0) + { + // Not implemented for tmwAthena (possible?) + } + else + { + int source = event.getInt("source"); + int destination = event.getInt("destination"); + int amount = event.getInt("amount", 1); + + if (source == Inventory::INVENTORY + && destination == Inventory::STORAGE) + { + MessageOut outMsg(CMSG_MOVE_TO_STORAGE); + outMsg.writeInt16(index); + outMsg.writeInt32(amount); + } + else if (source == Inventory::STORAGE + && destination == Inventory::INVENTORY) + { + MessageOut outMsg(CSMG_MOVE_FROM_STORAGE); + outMsg.writeInt16(index - INVENTORY_OFFSET + + STORAGE_OFFSET); + outMsg.writeInt32(amount); + } + } + } + } + } } bool InventoryHandler::canSplit(const Item *item) @@ -462,43 +509,6 @@ bool InventoryHandler::canSplit(const Item *item) return false; } -void InventoryHandler::splitItem(const Item *item, int amount) -{ - // Not implemented for eAthena (possible?) -} - -void InventoryHandler::moveItem(int oldIndex, int newIndex) -{ - // Not implemented for eAthena (possible?) -} - -void InventoryHandler::openStorage(int type) -{ - // Doesn't apply to eAthena, since opening happens through NPCs? -} - -void InventoryHandler::closeStorage(int type) -{ - MessageOut outMsg(CMSG_CLOSE_STORAGE); -} - -void InventoryHandler::moveItem(int source, int slot, int amount, - int destination) -{ - if (source == Inventory::INVENTORY && destination == Inventory::STORAGE) - { - MessageOut outMsg(CMSG_MOVE_TO_STORAGE); - outMsg.writeInt16(slot + INVENTORY_OFFSET); - outMsg.writeInt32(amount); - } - else if (source == Inventory::STORAGE && destination == Inventory::INVENTORY) - { - MessageOut outMsg(CSMG_MOVE_FROM_STORAGE); - outMsg.writeInt16(slot + STORAGE_OFFSET); - outMsg.writeInt32(amount); - } -} - size_t InventoryHandler::getSize(int type) const { switch (type) diff --git a/src/net/tmwa/inventoryhandler.h b/src/net/tmwa/inventoryhandler.h index 82738afe..18d73517 100644 --- a/src/net/tmwa/inventoryhandler.h +++ b/src/net/tmwa/inventoryhandler.h @@ -24,7 +24,8 @@ #include "equipment.h" #include "inventory.h" -#include "localplayer.h" +#include "listener.h" +#include "playerinfo.h" #include "gui/inventorywindow.h" @@ -51,7 +52,7 @@ class EquipBackend : public Equipment::Backend { { return NULL; } - return player_node->getInventory()->getItem(invyIndex); + return PlayerInfo::getInventory()->getItem(invyIndex); } void clear() @@ -60,7 +61,7 @@ class EquipBackend : public Equipment::Backend { { if (mEquipment[i] != -1) { - Item* item = player_node->getInventory()->getItem(i); + Item* item = PlayerInfo::getInventory()->getItem(i); if (item) { item->setEquipped(false); @@ -74,7 +75,7 @@ class EquipBackend : public Equipment::Backend { void setEquipment(int index, int inventoryIndex) { // Unequip existing item - Item* item = player_node->getInventory()->getItem(mEquipment[index]); + Item* item = PlayerInfo::getInventory()->getItem(mEquipment[index]); if (item) { item->setEquipped(false); @@ -82,7 +83,7 @@ class EquipBackend : public Equipment::Backend { mEquipment[index] = inventoryIndex; - item = player_node->getInventory()->getItem(inventoryIndex); + item = PlayerInfo::getInventory()->getItem(inventoryIndex); if (item) { item->setEquipped(true); @@ -115,7 +116,8 @@ class InventoryItem typedef std::list<InventoryItem> InventoryItems; -class InventoryHandler : public MessageHandler, public Net::InventoryHandler +class InventoryHandler : public MessageHandler, public Net::InventoryHandler, + public Mana::Listener { public: enum { @@ -129,27 +131,10 @@ class InventoryHandler : public MessageHandler, public Net::InventoryHandler void handleMessage(Net::MessageIn &msg); - void equipItem(const Item *item); - - void unequipItem(const Item *item); - - void useItem(const Item *item); - - void dropItem(const Item *item, int amount); + void event(const std::string &channel, const Mana::Event &event); bool canSplit(const Item *item); - void splitItem(const Item *item, int amount); - - void moveItem(int oldIndex, int newIndex); - - void openStorage(int type); - - void closeStorage(int type); - - void moveItem(int source, int slot, int amount, - int destination); - size_t getSize(int type) const; private: 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..e1615fec 100644 --- a/src/net/tmwa/npchandler.cpp +++ b/src/net/tmwa/npchandler.cpp @@ -21,11 +21,9 @@ #include "net/tmwa/npchandler.h" -#include "beingmanager.h" +#include "actorspritemanager.h" +#include "event.h" #include "localplayer.h" -#include "npc.h" - -#include "gui/npcdialog.h" #include "net/messagein.h" #include "net/messageout.h" @@ -34,10 +32,27 @@ #include "net/tmwa/protocol.h" +#include "utils/stringutils.h" + #include <SDL_types.h> extern Net::NpcHandler *npcHandler; +static void parseMenu(Mana::Event *event, const std::string &options) +{ + std::istringstream iss(options); + + int count = 0; + std::string tmp; + while (getline(iss, tmp, ':')) + { + count++; + event->setString("choice" + toString(count), tmp); + } + + event->setInt("choiceCount", count); +} + namespace TmwAthena { NpcHandler::NpcHandler() @@ -53,6 +68,8 @@ NpcHandler::NpcHandler() }; handledMessages = _messages; npcHandler = this; + + listen("NPC"); } void NpcHandler::handleMessage(Net::MessageIn &msg) @@ -63,126 +80,103 @@ void NpcHandler::handleMessage(Net::MessageIn &msg) } int npcId = msg.readInt32(); - NpcDialogs::iterator diag = mNpcDialogs.find(npcId); - NpcDialog *dialog = 0; - - if (diag == mNpcDialogs.end()) - { - // Empty dialogs don't help - if (msg.getId() == SMSG_NPC_CLOSE) - { - closeDialog(npcId); - return; - } - else if (msg.getId() == SMSG_NPC_NEXT) - { - nextDialog(npcId); - return; - } - else - { - dialog = new NpcDialog(npcId); - Wrapper wrap; - wrap.dialog = dialog; - mNpcDialogs[npcId] = wrap; - } - } - else - { - dialog = diag->second.dialog; - } + Mana::Event *event = 0; switch (msg.getId()) { - case SMSG_NPC_CHOICE: - dialog->choiceRequest(); - dialog->parseListItems(msg.readString(msg.getLength() - 8)); - break; - - case SMSG_NPC_MESSAGE: - dialog->addText(msg.readString(msg.getLength() - 8)); - break; - - case SMSG_NPC_CLOSE: - // Show the close button - dialog->showCloseButton(); - break; - - case SMSG_NPC_NEXT: - // Show the next button - dialog->showNextButton(); - break; - - case SMSG_NPC_INT_INPUT: - // Request for an integer - dialog->integerRequest(0); - break; - - case SMSG_NPC_STR_INPUT: - // Request for a string - dialog->textRequest(""); - break; + case SMSG_NPC_CHOICE: + event = new Mana::Event("Menu"); + event->setInt("id", npcId); + parseMenu(event, msg.readString(msg.getLength() - 8)); + event->trigger("NPC"); + break; + + case SMSG_NPC_MESSAGE: + event = new Mana::Event("Message"); + event->setInt("id", npcId); + event->setString("text", msg.readString(msg.getLength() - 8)); + event->trigger("NPC"); + break; + + case SMSG_NPC_CLOSE: + // Show the close button + event = new Mana::Event("Close"); + event->setInt("id", npcId); + event->trigger("NPC"); + break; + + case SMSG_NPC_NEXT: + // Show the next button + event = new Mana::Event("Next"); + event->setInt("id", npcId); + event->trigger("NPC"); + break; + + case SMSG_NPC_INT_INPUT: + // Request for an integer + event = new Mana::Event("IntegerInput"); + event->setInt("id", npcId); + event->trigger("NPC"); + break; + + case SMSG_NPC_STR_INPUT: + // Request for a string + event = new Mana::Event("StringInput"); + event->setInt("id", npcId); + event->trigger("NPC"); + break; } + delete event; + if (player_node->getCurrentAction() != Being::SIT) player_node->setAction(Being::STAND); } -void NpcHandler::talk(int npcId) +void NpcHandler::event(const std::string &channel, const Mana::Event &event) { - MessageOut outMsg(CMSG_NPC_TALK); - outMsg.writeInt32(npcId); - outMsg.writeInt8(0); // Unused -} - -void NpcHandler::nextDialog(int npcId) -{ - MessageOut outMsg(CMSG_NPC_NEXT_REQUEST); - outMsg.writeInt32(npcId); -} - -void NpcHandler::closeDialog(int npcId) -{ - MessageOut outMsg(CMSG_NPC_CLOSE); - outMsg.writeInt32(npcId); - - NpcDialogs::iterator it = mNpcDialogs.find(npcId); - if (it != mNpcDialogs.end()) + if (channel == "NPC") { - (*it).second.dialog->close(); - mNpcDialogs.erase(it); + if (event.getName() == "doTalk") + { + MessageOut outMsg(CMSG_NPC_TALK); + outMsg.writeInt32(event.getInt("npcId")); + outMsg.writeInt8(0); // Unused + } + else if (event.getName() == "doNext") + { + MessageOut outMsg(CMSG_NPC_NEXT_REQUEST); + outMsg.writeInt32(event.getInt("npcId")); + } + else if (event.getName() == "doClose") + { + MessageOut outMsg(CMSG_NPC_CLOSE); + outMsg.writeInt32(event.getInt("npcId")); + } + else if (event.getName() == "doMenu") + { + MessageOut outMsg(CMSG_NPC_LIST_CHOICE); + outMsg.writeInt32(event.getInt("npcId")); + outMsg.writeInt8(event.getInt("choice")); + } + else if (event.getName() == "doIntegerInput") + { + MessageOut outMsg(CMSG_NPC_INT_RESPONSE); + outMsg.writeInt32(event.getInt("npcId")); + outMsg.writeInt32(event.getInt("value")); + } + else if (event.getName() == "doStringInput") + { + const std::string &value = event.getString("value"); + MessageOut outMsg(CMSG_NPC_STR_RESPONSE); + outMsg.writeInt16(value.length() + 9); + outMsg.writeInt32(event.getInt("npcId")); + outMsg.writeString(value, value.length()); + outMsg.writeInt8(0); // Prevent problems with string reading + } } } -void NpcHandler::listInput(int npcId, int value) -{ - MessageOut outMsg(CMSG_NPC_LIST_CHOICE); - outMsg.writeInt32(npcId); - outMsg.writeInt8(value); -} - -void NpcHandler::integerInput(int npcId, int value) -{ - MessageOut outMsg(CMSG_NPC_INT_RESPONSE); - outMsg.writeInt32(npcId); - outMsg.writeInt32(value); -} - -void NpcHandler::stringInput(int npcId, const std::string &value) -{ - MessageOut outMsg(CMSG_NPC_STR_RESPONSE); - outMsg.writeInt16(value.length() + 9); - outMsg.writeInt32(npcId); - outMsg.writeString(value, value.length()); - outMsg.writeInt8(0); // Prevent problems with string reading -} - -void NpcHandler::sendLetter(int npcId, const std::string &recipient, - const std::string &text) -{ - // TODO -} - void NpcHandler::startShopping(int beingId) { // TODO @@ -223,9 +217,4 @@ void NpcHandler::endShopping(int beingId) // TODO } -void NpcHandler::clearDialogs() -{ - mNpcDialogs.clear(); -} - } // namespace TmwAthena diff --git a/src/net/tmwa/npchandler.h b/src/net/tmwa/npchandler.h index bd696bdd..93c9f6ec 100644 --- a/src/net/tmwa/npchandler.h +++ b/src/net/tmwa/npchandler.h @@ -22,38 +22,25 @@ #ifndef NET_TA_NPCHANDLER_H #define NET_TA_NPCHANDLER_H -#include "net/net.h" +#include "listener.h" + #include "net/npchandler.h" #include "net/tmwa/messagehandler.h" #include <map> -class NpcDialog; - namespace TmwAthena { -class NpcHandler : public MessageHandler, public Net::NpcHandler +class NpcHandler : public MessageHandler, public Net::NpcHandler, + public Mana::Listener { public: NpcHandler(); void handleMessage(Net::MessageIn &msg); - void talk(int npcId); - - void nextDialog(int npcId); - - void closeDialog(int npcId); - - void listInput(int npcId, int value); - - void integerInput(int npcId, int value); - - void stringInput(int npcId, const std::string &value); - - void sendLetter(int npcId, const std::string &recipient, - const std::string &text); + void event(const std::string &channel, const Mana::Event &event); void startShopping(int beingId); @@ -66,15 +53,6 @@ class NpcHandler : public MessageHandler, public Net::NpcHandler void sellItem(int beingId, int itemId, int amount); void endShopping(int beingId); - - void clearDialogs(); - - private: - typedef struct { - NpcDialog* dialog; - } Wrapper; - typedef std::map<int, Wrapper> NpcDialogs; - NpcDialogs mNpcDialogs; }; } // namespace TmwAthena diff --git a/src/net/tmwa/partyhandler.cpp b/src/net/tmwa/partyhandler.cpp index e86d41fa..3d7aa263 100644 --- a/src/net/tmwa/partyhandler.cpp +++ b/src/net/tmwa/partyhandler.cpp @@ -20,7 +20,8 @@ #include "net/tmwa/partyhandler.h" -#include "beingmanager.h" +#include "actorspritemanager.h" +#include "event.h" #include "localplayer.h" #include "log.h" @@ -78,12 +79,9 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) { case SMSG_PARTY_CREATE: if (msg.readInt8()) - localChatTab->chatLog(_("Could not create party."), BY_SERVER); + SERVER_NOTICE(_("Could not create party.")) else - { - localChatTab->chatLog(_("Party successfully created."), - BY_SERVER); - } + SERVER_NOTICE(_("Party successfully created.")) break; case SMSG_PARTY_INFO: { @@ -143,12 +141,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); @@ -238,8 +233,7 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) { taParty->removeFromMembers(); taParty->clearMembers(); - localChatTab->chatLog(_("You have left the party."), - BY_SERVER); + SERVER_NOTICE(_("You have left the party.")) if (partyTab) { delete partyTab; @@ -252,9 +246,10 @@ 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); + if (Being *b = actorSpriteManager->findBeing(id)) + { + b->setParty(NULL); + } taParty->removeMember(id); } @@ -274,9 +269,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 +314,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) @@ -334,8 +329,7 @@ void PartyHandler::invite(const std::string &name) } else { - localChatTab->chatLog(_("You can only inivte when you are in a party!"), - BY_SERVER); + SERVER_NOTICE(_("You can only inivte when you are in a party!")) } // TODO? @@ -353,10 +347,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..6a1e8918 100644 --- a/src/net/tmwa/playerhandler.cpp +++ b/src/net/tmwa/playerhandler.cpp @@ -21,28 +21,25 @@ #include "net/tmwa/playerhandler.h" +#include "event.h" #include "game.h" #include "localplayer.h" #include "log.h" -#include "npc.h" +#include "playerinfo.h" #include "units.h" #include "gui/buy.h" #include "gui/buysell.h" #include "gui/gui.h" -#include "gui/npcdialog.h" #include "gui/okdialog.h" #include "gui/sell.h" #include "gui/statuswindow.h" #include "gui/viewport.h" -#include "gui/widgets/chattab.h" - #include "net/messagein.h" #include "net/messageout.h" #include "net/tmwa/protocol.h" -#include "net/tmwa/npchandler.h" #include "utils/stringutils.h" #include "utils/gettext.h" @@ -54,9 +51,6 @@ extern OkDialog *deathNotice; // everything beyond will reset the port hard. static const int MAP_TELEPORT_SCROLL_DISTANCE = 8; -#define ATTR_BONUS(atr) \ -(player_node->getAttributeEffective(atr) - player_node->getAttributeBase(atr)) - // TODO Move somewhere else namespace { @@ -83,14 +77,11 @@ namespace { BuyDialog::closeAll(); BuySellDialog::closeAll(); - NpcDialog::closeAll(); SellDialog::closeAll(); viewport->closePopupMenu(); - TmwAthena::NpcHandler *handler = - static_cast<TmwAthena::NpcHandler*>(Net::getNpcHandler()); - handler->clearDialogs(); + Mana::Event::trigger("NPC", "CloseAll"); } } deathListener; @@ -217,7 +208,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, @@ -238,17 +228,17 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) player_node->setWalkSpeed(Vector(value, value, 0)); break; case 0x0004: break; // manner - case 0x0005: player_node->setHp(value); break; - case 0x0006: player_node->setMaxHp(value); break; - case 0x0007: player_node->setMP(value); break; - case 0x0008: player_node->setMaxMP(value); break; - case 0x0009: player_node->setCharacterPoints(value); break; - case 0x000b: player_node->setLevel(value); break; - case 0x000c: player_node->setSkillPoints(value); break; + case 0x0005: PlayerInfo::setAttribute(HP, value); break; + case 0x0006: PlayerInfo::setAttribute(MAX_HP, value); break; + case 0x0007: PlayerInfo::setAttribute(MP, value); break; + case 0x0008: PlayerInfo::setAttribute(MAX_MP, value); break; + case 0x0009: PlayerInfo::setAttribute(CHAR_POINTS, value); break; + case 0x000b: PlayerInfo::setAttribute(LEVEL, value); break; + case 0x000c: PlayerInfo::setAttribute(SKILL_POINTS, value); break; case 0x0018: - if (value >= player_node->getMaxWeight() / 2 && - player_node->getTotalWeight() < - player_node->getMaxWeight() / 2) + if (value >= PlayerInfo::getAttribute(MAX_WEIGHT) / 2 && + PlayerInfo::getAttribute(TOTAL_WEIGHT) < + PlayerInfo::getAttribute(MAX_WEIGHT) / 2) { weightNotice = new OkDialog(_("Message"), _("You are carrying more than " @@ -257,59 +247,37 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) weightNotice->addActionListener( &weightListener); } - player_node->setTotalWeight(value); + PlayerInfo::setAttribute(TOTAL_WEIGHT, value); break; - case 0x0019: player_node->setMaxWeight(value); break; + case 0x0019: PlayerInfo::setAttribute(MAX_WEIGHT, value); break; - case 0x0029: player_node->setAttributeEffective(ATK, value - + ATTR_BONUS(ATK)); - player_node->setAttributeBase(ATK, value); - break; - case 0x002a: value += player_node->getAttributeBase(ATK); - player_node->setAttributeEffective(ATK, value); break; - - case 0x002b: player_node->setAttributeEffective(MATK, value - + ATTR_BONUS(MATK)); - player_node->setAttributeBase(MATK, value); - if (statusWindow) - statusWindow->update(StatusWindow::MP); - break; - case 0x002c: value += player_node->getAttributeBase(MATK); - player_node->setAttributeEffective(MATK, value); - if (statusWindow) - statusWindow->update(StatusWindow::MP); - break; - case 0x002d: player_node->setAttributeEffective(DEF, value - + ATTR_BONUS(DEF)); - player_node->setAttributeBase(DEF, value); break; - case 0x002e: value += player_node->getAttributeBase(DEF); - player_node->setAttributeEffective(DEF, value); break; - - case 0x002f: player_node->setAttributeEffective(MDEF, value - + ATTR_BONUS(MDEF)); - player_node->setAttributeBase(MDEF, value); break; - case 0x0030: value += player_node->getAttributeBase(MDEF); - player_node->setAttributeEffective(MDEF, value); break; - - case 0x0031: player_node->setAttributeBase(HIT, value); - player_node->setAttributeEffective(HIT, value); break; - - case 0x0032: player_node->setAttributeEffective(FLEE, value - + ATTR_BONUS(FLEE)); - player_node->setAttributeBase(FLEE, value); break; - case 0x0033: value += player_node->getAttributeBase(FLEE); - player_node->setAttributeEffective(FLEE, value); break; - - case 0x0034: player_node->setAttributeBase(CRIT, value); - player_node->setAttributeEffective(CRIT, value); break; + case 0x0029: PlayerInfo::setStatBase(ATK, value); break; + case 0x002a: PlayerInfo::setStatMod(ATK, value); break; + + case 0x002b: PlayerInfo::setStatBase(MATK, value); break; + case 0x002c: PlayerInfo::setStatMod(MATK, value); break; + + case 0x002d: PlayerInfo::setStatBase(DEF, value); break; + case 0x002e: PlayerInfo::setStatMod(DEF, value); break; + + case 0x002f: PlayerInfo::setStatBase(MDEF, value); break; + case 0x0030: PlayerInfo::setStatMod(MDEF, value); break; + + case 0x0031: PlayerInfo::setStatBase(HIT, value); break; + + case 0x0032: PlayerInfo::setStatBase(FLEE, value); break; + case 0x0033: PlayerInfo::setStatMod(FLEE, value); break; + + case 0x0034: PlayerInfo::setStatBase(CRIT, value); break; case 0x0035: player_node->setAttackSpeed(value); break; - case 0x0037: player_node->setAttributeBase(JOB, value); - player_node->setAttributeEffective(JOB, value); break; + + case 0x0037: PlayerInfo::setStatBase(JOB, value); break; + case 500: player_node->setGMLevel(value); break; } - if (player_node->getHp() == 0 && !deathNotice) + if (PlayerInfo::getAttribute(HP) == 0 && !deathNotice) { deathNotice = new OkDialog(_("Message"), randomDeathMessage(), @@ -324,29 +292,29 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) switch (msg.readInt16()) { case 0x0001: - player_node->setExp(msg.readInt32()); + PlayerInfo::setAttribute(EXP, msg.readInt32()); break; case 0x0002: - player_node->setExperience(JOB, msg.readInt32(), - player_node->getExperience(JOB).second); + PlayerInfo::setStatExperience(JOB, msg.readInt32(), + PlayerInfo::getStatExperience(JOB).second); break; case 0x0014: { - int curGp = player_node->getMoney(); - player_node->setMoney(msg.readInt32()); - if (player_node->getMoney() > curGp) - localChatTab->chatLog(strprintf(_("You picked up " - "%s."), - Units::formatCurrency(player_node->getMoney() - - curGp).c_str()), BY_SERVER); + int oldMoney = PlayerInfo::getAttribute(MONEY); + int newMoney = msg.readInt32(); + PlayerInfo::setAttribute(MONEY, newMoney); + if (newMoney > oldMoney) + SERVER_NOTICE(strprintf(_("You picked up %s."), + Units::formatCurrency(newMoney - + oldMoney).c_str())) } break; case 0x0016: - player_node->setExpNeeded(msg.readInt32()); + PlayerInfo::setAttribute(EXP_NEEDED, msg.readInt32()); break; case 0x0017: - player_node->setExperience(JOB, - player_node->getExperience(JOB).first, - msg.readInt32()); + PlayerInfo::setStatExperience(JOB, + PlayerInfo::getStatExperience(JOB).first, + msg.readInt32()); break; } break; @@ -357,8 +325,8 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) int base = msg.readInt32(); int bonus = msg.readInt32(); - player_node->setAttributeBase(type, base); - player_node->setAttributeEffective(type, base + bonus); + PlayerInfo::setStatBase(type, base, false); + PlayerInfo::setStatMod(type, bonus); } break; @@ -370,25 +338,20 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) if (ok != 1) { - localChatTab->chatLog(_("Cannot raise skill!"), - BY_SERVER); + SERVER_NOTICE(_("Cannot raise skill!")) } - int bonus = ATTR_BONUS(type); - - player_node->setAttributeBase(type, value); - player_node->setAttributeEffective(type, value + bonus); + PlayerInfo::setStatBase(type, value); } break; // Updates stats and status points case SMSG_PLAYER_STAT_UPDATE_5: - player_node->setCharacterPoints(msg.readInt16()); + PlayerInfo::setAttribute(CHAR_POINTS, msg.readInt16()); { int val = msg.readInt8(); - player_node->setAttributeEffective(STR, val + ATTR_BONUS(STR)); - player_node->setAttributeBase(STR, val); + PlayerInfo::setStatBase(STR, val); if (val >= 99) { statusWindow->setPointsNeeded(STR, 0); @@ -400,8 +363,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) } val = msg.readInt8(); - player_node->setAttributeEffective(AGI, val + ATTR_BONUS(AGI)); - player_node->setAttributeBase(AGI, val); + PlayerInfo::setStatBase(AGI, val); if (val >= 99) { statusWindow->setPointsNeeded(AGI, 0); @@ -413,8 +375,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) } val = msg.readInt8(); - player_node->setAttributeEffective(VIT, val + ATTR_BONUS(VIT)); - player_node->setAttributeBase(VIT, val); + PlayerInfo::setStatBase(VIT, val); if (val >= 99) { statusWindow->setPointsNeeded(VIT, 0); @@ -426,8 +387,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) } val = msg.readInt8(); - player_node->setAttributeEffective(INT, val + ATTR_BONUS(INT)); - player_node->setAttributeBase(INT, val); + PlayerInfo::setStatBase(INT, val); if (val >= 99) { statusWindow->setPointsNeeded(INT, 0); @@ -439,8 +399,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) } val = msg.readInt8(); - player_node->setAttributeEffective(DEX, val + ATTR_BONUS(DEX)); - player_node->setAttributeBase(DEX, val); + PlayerInfo::setStatBase(DEX, val); if (val >= 99) { statusWindow->setPointsNeeded(DEX, 0); @@ -452,8 +411,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) } val = msg.readInt8(); - player_node->setAttributeEffective(LUK, val + ATTR_BONUS(LUK)); - player_node->setAttributeBase(LUK, val); + PlayerInfo::setStatBase(LUK, val); if (val >= 99) { statusWindow->setPointsNeeded(LUK, 0); @@ -464,39 +422,25 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) statusWindow->setPointsNeeded(LUK, msg.readInt8()); } - val = msg.readInt16(); // ATK - player_node->setAttributeBase(ATK, val); - val += msg.readInt16(); // ATK bonus - player_node->setAttributeEffective(ATK, val); - - val = msg.readInt16(); // MATK - player_node->setAttributeBase(MATK, val); - val += msg.readInt16(); // MATK bonus - player_node->setAttributeEffective(MATK, val); - statusWindow->update(StatusWindow::MP); - - val = msg.readInt16(); // DEF - player_node->setAttributeBase(DEF, val); - val += msg.readInt16(); // DEF bonus - player_node->setAttributeEffective(DEF, val); - - val = msg.readInt16(); // MDEF - player_node->setAttributeBase(MDEF, val); - val += msg.readInt16(); // MDEF bonus - player_node->setAttributeEffective(MDEF, val); - - val = msg.readInt16(); // HIT - player_node->setAttributeBase(HIT, val); - player_node->setAttributeEffective(HIT, val); - - val = msg.readInt16(); // FLEE - player_node->setAttributeBase(FLEE, val); - val += msg.readInt16(); // FLEE bonus - player_node->setAttributeEffective(FLEE, val); - - val = msg.readInt16(); - player_node->setAttributeBase(CRIT, val); - player_node->setAttributeEffective(CRIT, val); + PlayerInfo::setStatBase(ATK, msg.readInt16(), false); + PlayerInfo::setStatMod(ATK, msg.readInt16()); + + PlayerInfo::setStatBase(MATK, msg.readInt16(), false); + PlayerInfo::setStatMod(MATK, msg.readInt16()); + + + PlayerInfo::setStatBase(DEF, msg.readInt16(), false); + PlayerInfo::setStatMod(DEF, msg.readInt16()); + + PlayerInfo::setStatBase(MDEF, msg.readInt16(), false); + PlayerInfo::setStatMod(MDEF, msg.readInt16()); + + PlayerInfo::setStatBase(HIT, msg.readInt16()); + + PlayerInfo::setStatBase(FLEE, msg.readInt16(), false); + PlayerInfo::setStatMod(FLEE, msg.readInt16()); + + PlayerInfo::setStatBase(CRIT, msg.readInt16()); } msg.readInt16(); // manner @@ -533,8 +477,9 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) switch (type) { case 0: - localChatTab->chatLog(_("Equip arrows first."), - BY_SERVER); + { + SERVER_NOTICE(_("Equip arrows first.")) + } break; default: logger->log("0x013b: Unhandled message %i", type); @@ -575,7 +520,7 @@ void PlayerHandler::decreaseAttribute(int attr) void PlayerHandler::increaseSkill(int skillId) { - if (player_node->getSkillPoints() <= 0) + if (PlayerInfo::getAttribute(SKILL_POINTS) <= 0) return; MessageOut outMsg(CMSG_SKILL_LEVELUP_REQUEST); @@ -584,8 +529,11 @@ void PlayerHandler::increaseSkill(int skillId) void PlayerHandler::pickUp(FloorItem *floorItem) { - MessageOut outMsg(CMSG_ITEM_PICKUP); - outMsg.writeInt32(floorItem->getId()); + if (floorItem) + { + MessageOut outMsg(CMSG_ITEM_PICKUP); + outMsg.writeInt32(floorItem->getId()); + } } void PlayerHandler::setDirection(char direction) @@ -634,7 +582,7 @@ void PlayerHandler::ignoreAll(bool ignore) bool PlayerHandler::canUseMagic() { - return player_node->getAttributeEffective(MATK) > 0; + return PlayerInfo::getStatEffective(MATK) > 0; } bool PlayerHandler::canCorrectAttributes() diff --git a/src/net/tmwa/specialhandler.cpp b/src/net/tmwa/specialhandler.cpp index c5f5d540..577bda7e 100644 --- a/src/net/tmwa/specialhandler.cpp +++ b/src/net/tmwa/specialhandler.cpp @@ -21,13 +21,12 @@ #include "net/tmwa/specialhandler.h" -#include "localplayer.h" +#include "event.h" #include "log.h" +#include "playerinfo.h" #include "gui/skilldialog.h" -#include "gui/widgets/chattab.h" - #include "net/messagein.h" #include "net/messageout.h" @@ -105,8 +104,7 @@ void SpecialHandler::handleMessage(Net::MessageIn &msg) msg.skip(24); // unused int up = msg.readInt8(); - player_node->setAttributeBase(skillId, level); - player_node->setAttributeEffective(skillId, level); + PlayerInfo::setStatBase(skillId, level); skillDialog->setModifiable(skillId, up); } break; @@ -119,8 +117,7 @@ void SpecialHandler::handleMessage(Net::MessageIn &msg) msg.readInt16(); // range int up = msg.readInt8(); - player_node->setAttributeBase(skillId, level); - player_node->setAttributeEffective(skillId, level); + PlayerInfo::setStatBase(skillId, level); skillDialog->setModifiable(skillId, up); } break; @@ -218,7 +215,7 @@ void SpecialHandler::handleMessage(Net::MessageIn &msg) } } - localChatTab->chatLog(msg); + SERVER_NOTICE(msg) break; } } 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/net/tmwa/tradehandler.cpp b/src/net/tmwa/tradehandler.cpp index 9089f8e6..05ca3f87 100644 --- a/src/net/tmwa/tradehandler.cpp +++ b/src/net/tmwa/tradehandler.cpp @@ -21,16 +21,16 @@ #include "net/tmwa/tradehandler.h" +#include "event.h" #include "inventory.h" #include "item.h" #include "localplayer.h" +#include "playerinfo.h" #include "playerrelations.h" #include "gui/confirmdialog.h" #include "gui/trade.h" -#include "gui/widgets/chattab.h" - #include "net/inventoryhandler.h" #include "net/messagein.h" #include "net/messageout.h" @@ -96,14 +96,14 @@ void TradeHandler::handleMessage(Net::MessageIn &msg) if (player_relations.hasPermission(tradePartnerName, PlayerRelation::TRADE)) { - if (!player_node->tradeRequestOk() || confirmDlg) + if (PlayerInfo::isTrading() || confirmDlg) { Net::getTradeHandler()->respond(false); break; } tradePartnerName = tradePartnerNameTemp; - player_node->setTrading(true); + PlayerInfo::setTrading(true); confirmDlg = new ConfirmDialog(_("Request for Trade"), strprintf(_("%s wants to trade with you, do you " "accept?"), tradePartnerName.c_str())); @@ -121,16 +121,16 @@ void TradeHandler::handleMessage(Net::MessageIn &msg) switch (msg.readInt8()) { case 0: // Too far away - localChatTab->chatLog(_("Trading isn't possible. Trade " - "partner is too far away."), BY_SERVER); + SERVER_NOTICE(_("Trading isn't possible. Trade " + "partner is too far away.")) break; case 1: // Character doesn't exist - localChatTab->chatLog(_("Trading isn't possible. Character " - "doesn't exist."), BY_SERVER); + SERVER_NOTICE(_("Trading isn't possible. Character " + "doesn't exist.")) break; case 2: // Invite request check failed... - localChatTab->chatLog(_("Trade cancelled due to an unknown " - "reason."), BY_SERVER); + SERVER_NOTICE(_("Trade cancelled due to an unknown " + "reason.")) break; case 3: // Trade accepted tradeWindow->reset(); @@ -141,17 +141,15 @@ void TradeHandler::handleMessage(Net::MessageIn &msg) case 4: // Trade cancelled if (player_relations.hasPermission(tradePartnerName, PlayerRelation::SPEECH_LOG)) - localChatTab->chatLog(strprintf(_("Trade with %s " - "cancelled."), tradePartnerName.c_str()), - BY_SERVER); + SERVER_NOTICE(strprintf(_("Trade with %s cancelled."), + tradePartnerName.c_str())) // otherwise ignore silently tradeWindow->setVisible(false); - player_node->setTrading(false); + PlayerInfo::setTrading(false); break; default: // Shouldn't happen as well, but to be sure - localChatTab->chatLog(_("Unhandled trade cancel packet."), - BY_SERVER); + SERVER_NOTICE(_("Unhandled trade cancel packet.")) break; } break; @@ -177,7 +175,7 @@ void TradeHandler::handleMessage(Net::MessageIn &msg) // Trade: New Item add response (was 0x00ea, now 01b1) { const int index = msg.readInt16() - INVENTORY_OFFSET; - Item *item = player_node->getInventory()->getItem(index); + Item *item = PlayerInfo::getInventory()->getItem(index); if (!item) { tradeWindow->receivedOk(true); @@ -191,7 +189,7 @@ void TradeHandler::handleMessage(Net::MessageIn &msg) // Successfully added item if (item->isEquipment() && item->isEquipped()) { - Net::getInventoryHandler()->unequipItem(item); + item->doEvent("doUnequip"); } tradeWindow->addItem(item->getId(), true, quantity, item->isEquipment()); @@ -199,17 +197,17 @@ void TradeHandler::handleMessage(Net::MessageIn &msg) break; case 1: // Add item failed - player overweighted - localChatTab->chatLog(_("Failed adding item. Trade " - "partner is over weighted."), BY_SERVER); + SERVER_NOTICE(_("Failed adding item. Trade " + "partner is over weighted.")) break; case 2: // Add item failed - player has no free slot - localChatTab->chatLog(_("Failed adding item. Trade " - "partner has no free slot."), BY_SERVER); + SERVER_NOTICE(_("Failed adding item. Trade " + "partner has no free slot.")) break; default: - localChatTab->chatLog(_("Failed adding item for " - "unknown reason."), BY_SERVER); + SERVER_NOTICE(_("Failed adding item for " + "unknown reason.")) break; } } @@ -221,17 +219,17 @@ void TradeHandler::handleMessage(Net::MessageIn &msg) break; case SMSG_TRADE_CANCEL: - localChatTab->chatLog(_("Trade canceled."), BY_SERVER); + SERVER_NOTICE(_("Trade canceled.")) tradeWindow->setVisible(false); tradeWindow->reset(); - player_node->setTrading(false); + PlayerInfo::setTrading(false); break; case SMSG_TRADE_COMPLETE: - localChatTab->chatLog(_("Trade completed."), BY_SERVER); + SERVER_NOTICE(_("Trade completed.")) tradeWindow->setVisible(false); tradeWindow->reset(); - player_node->setTrading(false); + PlayerInfo::setTrading(false); break; } } @@ -245,7 +243,7 @@ void TradeHandler::request(Being *being) void TradeHandler::respond(bool accept) { if (!accept) - player_node->setTrading(false); + PlayerInfo::setTrading(false); MessageOut outMsg(CMSG_TRADE_RESPONSE); outMsg.writeInt8(accept ? 3 : 4); diff --git a/src/net/tradehandler.h b/src/net/tradehandler.h index 30798c41..ea3c4550 100644 --- a/src/net/tradehandler.h +++ b/src/net/tradehandler.h @@ -30,6 +30,8 @@ namespace Net { class TradeHandler { public: + virtual ~TradeHandler() {} + virtual void request(Being *being) {} virtual void respond(bool accept) {} @@ -45,8 +47,6 @@ class TradeHandler virtual void finish() {} virtual void cancel() {} - - virtual ~TradeHandler() {} }; } diff --git a/src/npc.cpp b/src/npc.cpp deleted file mode 100644 index a3c26618..00000000 --- a/src/npc.cpp +++ /dev/null @@ -1,108 +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" -#include "configuration.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 = paths.getValue("sprites", - "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..e3c45a9f 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--; @@ -91,16 +86,17 @@ Particle::~Particle() void Particle::setupEngine() { - Particle::maxCount = (int)config.getValue("particleMaxCount", 3000); - Particle::fastPhysics = (int)config.getValue("particleFastPhysics", 0); - Particle::emitterSkip = (int)config.getValue("particleEmitterSkip", 1) + 1; - Particle::enabled = (bool)config.getValue("particleeffects", true); + Particle::maxCount = config.getIntValue("particleMaxCount"); + Particle::fastPhysics = config.getIntValue("particleFastPhysics"); + Particle::emitterSkip = config.getIntValue("particleEmitterSkip") + 1; + Particle::enabled = config.getBoolValue("particleeffects"); disableAutoDelete(); 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..99295792 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,9 @@ 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()); + if (b) + b->setParty(NULL); ++itr; } } diff --git a/src/player.cpp b/src/player.cpp deleted file mode 100644 index e6102b6a..00000000 --- a/src/player.cpp +++ /dev/null @@ -1,360 +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( - paths.getValue("particles", - "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( - paths.getValue("sprites", "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/playerinfo.cpp b/src/playerinfo.cpp new file mode 100644 index 00000000..cebd15dc --- /dev/null +++ b/src/playerinfo.cpp @@ -0,0 +1,405 @@ +/* + * 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 "playerinfo.h" + +#include "client.h" +#include "equipment.h" +#include "event.h" +#include "inventory.h" +#include "listener.h" +#include "log.h" + +#include "resources/itemdb.h" +#include "resources/iteminfo.h" + +namespace PlayerInfo { + +class PlayerLogic; + +PlayerLogic *mListener = 0; + +PlayerInfoBackend mData; + +Inventory *mInventory = 0; +Equipment *mEquipment = 0; + +bool mStorageCount = 0; + +bool mNPCCount = 0; +bool mNPCPostCount = 0; + +BuySellState mBuySellState = BUYSELL_NONE; +bool mTrading = false; + +std::map<int, Special> mSpecials; +char mSpecialRechargeUpdateNeeded = 0; + +int mLevelProgress = 0; + +// --- Triggers --------------------------------------------------------------- + +void triggerAttr(int id, int old) +{ + Mana::Event event("UpdateAttribute"); + event.setInt("id", id); + event.setInt("oldValue", old); + event.setInt("newValue", mData.mAttributes.find(id)->second); + event.trigger("Attributes"); +} + +void triggerStat(int id, const std::string &changed, int old1, int old2 = 0) +{ + StatMap::iterator it = mData.mStats.find(id); + Mana::Event event("UpdateStat"); + event.setInt("id", id); + event.setInt("base", it->second.base); + event.setInt("mod", it->second.mod); + event.setInt("exp", it->second.exp); + event.setInt("expNeeded", it->second.expNeed); + event.setString("changed", changed); + event.setInt("oldValue1", old1); + event.setInt("oldValue2", old2); + event.trigger("Attributes"); +} + +// --- Attributes ------------------------------------------------------------- + +int getAttribute(int id) +{ + IntMap::const_iterator it = mData.mAttributes.find(id); + if (it != mData.mAttributes.end()) + return it->second; + else + return 0; +} + +void setAttribute(int id, int value, bool notify) +{ + int old = mData.mAttributes[id]; + mData.mAttributes[id] = value; + if (notify) + triggerAttr(id, old); +} + +// --- Stats ------------------------------------------------------------------ + +int getStatBase(int id) +{ + StatMap::const_iterator it = mData.mStats.find(id); + if (it != mData.mStats.end()) + return it->second.base; + else + return 0; +} + +void setStatBase(int id, int value, bool notify) +{ + int old = mData.mStats[id].base; + mData.mStats[id].base = value; + if (notify) + triggerStat(id, "base", old); +} + +int getStatMod(int id) +{ + StatMap::const_iterator it = mData.mStats.find(id); + if (it != mData.mStats.end()) + return it->second.mod; + else + return 0; +} + +void setStatMod(int id, int value, bool notify) +{ + int old = mData.mStats[id].mod; + mData.mStats[id].mod = value; + if (notify) + triggerStat(id, "mod", old); +} + +int getStatEffective(int id) +{ + StatMap::const_iterator it = mData.mStats.find(id); + if (it != mData.mStats.end()) + return it->second.base + it->second.mod; + else + return 0; +} + +std::pair<int, int> getStatExperience(int id) +{ + StatMap::const_iterator it = mData.mStats.find(id); + int a, b; + if (it != mData.mStats.end()) + { + a = it->second.exp; + b = it->second.expNeed; + } + else + { + a = 0; + b = 0; + } + return std::pair<int, int>(a, b); +} + +void setStatExperience(int id, int have, int need, bool notify) +{ + int oldExp = mData.mStats[id].exp; + int oldExpNeed = mData.mStats[id].expNeed; + mData.mStats[id].exp = have; + mData.mStats[id].expNeed = need; + if (notify) + triggerStat(id, "exp", oldExp, oldExpNeed); +} + +// --- Inventory / Equipment -------------------------------------------------- + +Inventory *getInventory() +{ + return mInventory; +} + +void clearInventory() +{ + mEquipment->clear(); + mInventory->clear(); +} + +void setInventoryItem(int index, int id, int amount) +{ + bool equipment = false; + int itemType = ItemDB::get(id).getType(); + if (itemType != ITEM_UNUSABLE && itemType != ITEM_USABLE) + equipment = true; + mInventory->setItem(index, id, amount, equipment); +} + +Equipment *getEquipment() +{ + return mEquipment; +} + +Item *getEquipment(unsigned int slot) +{ + return mEquipment->getEquipment(slot); +} + +void setEquipmentBackend(Equipment::Backend *backend) +{ + mEquipment->setBackend(backend); +} + +int getStorageCount() +{ + return mStorageCount; +} + +void setStorageCount(int count) +{ + int old = mStorageCount; + mStorageCount = count; + + if (count != old) + { + Mana::Event event("StorageCount"); + event.setInt("oldCount", old); + event.setInt("newCount", count); + event.trigger("Storage"); + } +} + +// -- NPC --------------------------------------------------------------------- + +int getNPCInteractionCount() +{ + return mNPCCount; +} + +void setNPCInteractionCount(int count) +{ + int old = mNPCCount; + mNPCCount = count; + + if (count != old) + { + Mana::Event event("NPCCount"); + event.setInt("oldCount", old); + event.setInt("newCount", count); + event.trigger("NPC"); + } +} + +int getNPCPostCount() +{ + return mNPCPostCount; +} + +void setNPCPostCount(int count) +{ + int old = mNPCPostCount; + mNPCPostCount = count; + + if (count != old) + { + Mana::Event event("PostCount"); + event.setInt("oldCount", old); + event.setInt("newCount", count); + event.trigger("NPC"); + } +} + +// -- Buy/Sell/Trade ---------------------------------------------------------- + +BuySellState getBuySellState() +{ + return mBuySellState; +} + +void setBuySellState(BuySellState buySellState) +{ + BuySellState old = mBuySellState; + mBuySellState = buySellState; + + if (buySellState != old) + { + Mana::Event event("StateChange"); + event.setInt("oldState", old); + event.setInt("newState", buySellState); + event.trigger("BuySell"); + } +} + +bool isTrading() +{ + return mTrading; +} + +void setTrading(bool trading) +{ + bool notify = mTrading != trading; + mTrading = trading; + + if (notify) + { + Mana::Event event("Trading"); + event.setBool("trading", trading); + event.trigger("Status"); + } +} + +// --- Specials --------------------------------------------------------------- + +void setSpecialStatus(int id, int current, int max, int recharge) +{ + logger->log("SpecialUpdate Skill #%d -- (%d/%d) -> %d", id, current, max, + recharge); + mSpecials[id].currentMana = current; + mSpecials[id].neededMana = max; + mSpecials[id].recharge = recharge; +} + +const SpecialsMap &getSpecialStatus() +{ + return mSpecials; +} + +// --- Misc ------------------------------------------------------------------- + +void setBackend(const PlayerInfoBackend &backend) +{ + mData = backend; +} + +bool isTalking() +{ + return getNPCInteractionCount() || getNPCPostCount() + || getBuySellState() != BUYSELL_NONE; +} + +void logic() +{ + if ((mSpecialRechargeUpdateNeeded%11) == 0) + { + mSpecialRechargeUpdateNeeded = 0; + for (SpecialsMap::iterator it = mSpecials.begin(), + it_end = mSpecials.end(); it != it_end; it++) + { + it->second.currentMana += it->second.recharge; + if (it->second.currentMana > it->second.neededMana) + { + it->second.currentMana = it->second.neededMana; + } + } + } + mSpecialRechargeUpdateNeeded++; +} + +class PlayerLogic : Mana::Listener +{ +public: + PlayerLogic() + { + listen("Client"); + listen("Game"); + } + + void event(const std::string &channel, const Mana::Event &event) + { + if (channel == "Client") + { + if (event.getName() == "StateChange") + { + int newState = event.getInt("newState"); + + if (newState == STATE_GAME) + { + if (mInventory == 0) + { + mInventory = new Inventory(Inventory::INVENTORY); + mEquipment = new Equipment(); + } + } + } + } + else if (channel == "Game") + { + if (event.getName() == "Destructed") + { + delete mInventory; + delete mEquipment; + + mInventory = 0; + mEquipment = 0; + } + } + } +}; + +void init() +{ + if (mListener) + return; + + mListener = new PlayerLogic(); +} + +} // namespace PlayerInfo diff --git a/src/playerinfo.h b/src/playerinfo.h new file mode 100644 index 00000000..43e7da6e --- /dev/null +++ b/src/playerinfo.h @@ -0,0 +1,273 @@ +/* + * 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 PLAYERINFO_H +#define PLAYERINFO_H + +#include <map> +#include <string> + +/** + * Standard attributes for players. + */ +enum Attribute +{ + LEVEL, + HP, MAX_HP, + MP, MAX_MP, + EXP, EXP_NEEDED, + MONEY, + TOTAL_WEIGHT, MAX_WEIGHT, + SKILL_POINTS, + CHAR_POINTS, CORR_POINTS +}; + +/** + * Stat information storage structure. + */ +struct Stat +{ + int base; + int mod; + int exp; + int expNeed; +}; + +typedef std::map<int, int> IntMap; +typedef std::map<int, Stat> StatMap; + +/** + * Backend for core player information. + */ +struct PlayerInfoBackend +{ + IntMap mAttributes; + StatMap mStats; +}; + +class Equipment; +class Inventory; +class Item; + +enum BuySellState +{ + BUYSELL_NONE, + BUYSELL_CHOOSING, + BUYSELL_BUYING, + BUYSELL_SELLING +}; + +/** + * Special information storage structure. + */ +struct Special +{ + int currentMana; + int neededMana; + int recharge; +}; + +typedef std::map<int, Special> SpecialsMap; + +/** + * A database like namespace which holds global info about the localplayer + * + * NOTE: 'bool notify' is used to determine if a event is to be triggered. + */ +namespace PlayerInfo +{ + +// --- Attributes ------------------------------------------------------------- + + /** + * Returns the value of the given attribute. + */ + int getAttribute(int id); + + /** + * Changes the value of the given attribute. + */ + void setAttribute(int id, int value, bool notify = true); + +// --- Stats ------------------------------------------------------------------ + + /** + * Returns the base value of the given stat. + */ + int getStatBase(int id); + + /** + * Changes the base value of the given stat. + */ + void setStatBase(int id, int value, bool notify = true); + + /** + * Returns the modifier for the given stat. + */ + int getStatMod(int id); + + /** + * Changes the modifier for the given stat. + */ + void setStatMod(int id, int value, bool notify = true); + + /** + * Returns the current effective value of the given stat. Effective is base + * + mod + */ + int getStatEffective(int id); + + /** + * Changes the level of the given stat. + */ + void setStatLevel(int id, int value, bool notify = true); + + /** + * Returns the experience of the given stat. + */ + std::pair<int, int> getStatExperience(int id); + + /** + * Changes the experience of the given stat. + */ + void setStatExperience(int id, int have, int need, bool notify = true); + +// --- Inventory / Equipment / Storage ---------------------------------------- + + /** + * Returns the player's inventory. + */ + Inventory *getInventory(); + + /** + * Clears the player's inventory and equipment. + */ + void clearInventory(); + + /** + * Changes the inventory item at the given slot. + */ + void setInventoryItem(int index, int id, int amount); + + /** + * Returns the player's equipment. + */ + Equipment *getEquipment(); + + /** + * Returns the player's equipment at the given slot. + */ + Item *getEquipment(unsigned int slot); + + /** + * Returns the number of currently open storage windows. + */ + int getStorageCount(); + + /** + * Sets the number of currently open storage windows. + */ + void setStorageCount(int count); + +// -- NPC --------------------------------------------------------------------- + + /** + * Returns the number of currently open NPC interaction windows. + */ + int getNPCInteractionCount(); + + /** + * Sets the number of currently open NPC interaction windows. + */ + void setNPCInteractionCount(int count); + + /** + * Returns the number of currently open NPC post windows. + */ + int getNPCPostCount(); + + /** + * Sets the number of currently open NPC post windows. + */ + void setNPCPostCount(int count); + +// -- Buy/Sell/Trade ---------------------------------------------------------- + + /** + * Returns the current buy, sell, or related interaction the player is + * involved in. + */ + BuySellState getBuySellState(); + + /** + * Sets which buy, sell, or related interaction the player is currently + * involved in. + */ + void setBuySellState(BuySellState buySellState); + + /** + * Returns true if the player is involved in a trade at the moment, false + * otherwise. + */ + bool isTrading(); + + /** + * Sets whether the player is currently involved in trade or not. + */ + void setTrading(bool trading); + +// --- Specials --------------------------------------------------------------- + + /** + * Changes the status of the given special. + */ + void setSpecialStatus(int id, int current, int max, int recharge); + + /** + * Returns the status of the given special. + */ + const SpecialsMap &getSpecialStatus(); + +// --- Misc ------------------------------------------------------------------- + + /** + * Changes the internal PlayerInfoBackend reference; + */ + void setBackend(const PlayerInfoBackend &backend); + + /** + * Returns true if the player is involved in a NPC interaction, false + * otherwise. + */ + bool isTalking(); + + /** + * Does necessary updates every tick. + */ + void logic(); + + /** + * Initializes some internals. + */ + void init(); + +} // namespace PlayerInfo + +#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..e8824391 --- /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(SpriteAction::ATTACK, "", ""); + + Attacks::const_iterator i = mAttacks.find(type); + return (i == mAttacks.end()) ? empty : (*i).second; +} + +void BeingInfo::addAttack(int id, std::string 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..52390976 --- /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 { + std::string action; + std::string particleEffect; + std::string missileParticle; + + Attack(std::string 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, std::string 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/emotedb.cpp b/src/resources/emotedb.cpp index c24e760b..bd8a8e38 100644 --- a/src/resources/emotedb.cpp +++ b/src/resources/emotedb.cpp @@ -43,7 +43,7 @@ void EmoteDB::load() EmoteSprite *unknownSprite = new EmoteSprite; unknownSprite->sprite = AnimatedSprite::load( - paths.getValue("spriteErrorFile", "error.xml") ); + paths.getStringValue("spriteErrorFile")); unknownSprite->name = "unknown"; mUnknown.sprites.push_back(unknownSprite); @@ -78,8 +78,7 @@ void EmoteDB::load() if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite")) { EmoteSprite *currentSprite = new EmoteSprite; - std::string file = paths.getValue("sprites", - "graphics/sprites/") + std::string file = paths.getStringValue("sprites") + (std::string) (const char*) spriteNode->xmlChildrenNode->content; currentSprite->sprite = AnimatedSprite::load(file, diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 3fdee021..a8eed123 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -47,6 +47,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] = { @@ -84,22 +85,6 @@ static ItemType itemTypeFromString(const std::string &name, int id = 0) else return ITEM_UNUSABLE; } -static WeaponType weaponTypeFromString(const std::string &name, int id = 0) -{ - if (name=="knife") return WPNTYPE_KNIFE; - else if (name=="sword") return WPNTYPE_SWORD; - else if (name=="polearm") return WPNTYPE_POLEARM; - else if (name=="staff") return WPNTYPE_STAFF; - else if (name=="whip") return WPNTYPE_WHIP; - else if (name=="bow") return WPNTYPE_BOW; - else if (name=="shooting") return WPNTYPE_SHOOTING; - else if (name=="mace") return WPNTYPE_MACE; - else if (name=="axe") return WPNTYPE_AXE; - else if (name=="thrown") return WPNTYPE_THROWN; - - else return WPNTYPE_NONE; -} - static std::string normalized(const std::string &name) { std::string normalized = name; @@ -115,8 +100,8 @@ void ItemDB::load() mUnknown = new ItemInfo; mUnknown->setName(_("Unknown item")); - mUnknown->setImageName(""); - std::string errFile = paths.getValue("spriteErrorFile", "error.xml"); + mUnknown->setDisplay(SpriteDisplay()); + std::string errFile = paths.getStringValue("spriteErrorFile"); mUnknown->setSprite(errFile, GENDER_MALE); mUnknown->setSprite(errFile, GENDER_FEMALE); @@ -152,19 +137,21 @@ void ItemDB::load() std::string name = XML::getProperty(node, "name", ""); std::string image = XML::getProperty(node, "image", ""); std::string description = XML::getProperty(node, "description", ""); - int weaponType = weaponTypeFromString(XML::getProperty(node, "weapon-type", "")); + std::string attackAction = XML::getProperty(node, "attack-action", ""); 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)); itemInfo->setView(view); itemInfo->setWeight(weight); - itemInfo->setWeaponType(weaponType); + itemInfo->setAttackAction(attackAction); itemInfo->setAttackRange(attackRange); itemInfo->setMissileParticle(missileParticle); @@ -204,8 +191,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()) { @@ -222,7 +215,7 @@ void ItemDB::load() } } - if (weaponType > 0) + if (!attackAction.empty()) if (attackRange == 0) logger->log("ItemDB: Missing attack range from weapon %i!", id); @@ -336,3 +329,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.cpp b/src/resources/iteminfo.cpp index 4b1d82ea..1cd3c546 100644 --- a/src/resources/iteminfo.cpp +++ b/src/resources/iteminfo.cpp @@ -41,35 +41,17 @@ const std::string &ItemInfo::getSprite(Gender gender) const } } -void ItemInfo::setWeaponType(int type) +void ItemInfo::setAttackAction(std::string attackAction) { - // See server item.hpp file for type values. - switch (type) - { - case WPNTYPE_NONE: - mAttackType = ACTION_DEFAULT; - break; - case WPNTYPE_KNIFE: - case WPNTYPE_SWORD: - mAttackType = ACTION_ATTACK_STAB; - break; - case WPNTYPE_THROWN: - mAttackType = ACTION_ATTACK_THROW; - break; - case WPNTYPE_BOW: - mAttackType = ACTION_ATTACK_BOW; - break; - case WPNTYPE_POLEARM: - mAttackType = ACTION_ATTACK_SWING; - break; - default: - mAttackType = ACTION_ATTACK; - } + if (attackAction.empty()) + mAttackAction = SpriteAction::ATTACK; // (Equal to unarmed animation) + else + mAttackAction = attackAction; } void ItemInfo::addSound(EquipmentSoundEvent event, const std::string &filename) { - mSounds[event].push_back(paths.getValue("sfx", "sfx/") + filename); + mSounds[event].push_back(paths.getStringValue("sfx") + filename); } const std::string &ItemInfo::getSound(EquipmentSoundEvent event) const diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h index a7c0ddca..ac747e33 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" @@ -90,24 +90,6 @@ enum ItemType }; /** - * Enumeration of available weapon's types. - */ -enum WeaponType -{ - WPNTYPE_NONE = 0, - WPNTYPE_KNIFE, - WPNTYPE_SWORD, - WPNTYPE_POLEARM, - WPNTYPE_STAFF, - WPNTYPE_WHIP, - WPNTYPE_BOW, - WPNTYPE_SHOOTING, - WPNTYPE_MACE, - WPNTYPE_AXE, - WPNTYPE_THROWN -}; - -/** * Defines a class for storing item infos. This includes information used when * the item is equipped. */ @@ -122,7 +104,7 @@ class ItemInfo mWeight(0), mView(0), mId(0), - mAttackType(ACTION_DEFAULT) + mAttackAction(SpriteAction::INVALID) { } @@ -143,11 +125,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; } @@ -180,15 +162,15 @@ class ItemInfo const std::string &getSprite(Gender gender) const; - void setWeaponType(int); + void setAttackAction(std::string attackAction); // Handlers for seting and getting the string used for particles when attacking void setMissileParticle(std::string s) { mMissileParticle = s; } std::string getMissileParticle() const { return mMissileParticle; } - SpriteAction getAttackType() const - { return mAttackType; } + std::string getAttackAction() const + { return mAttackAction; } int getAttackRange() const { return mAttackRange; } @@ -201,7 +183,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. */ @@ -211,9 +193,13 @@ class ItemInfo int mView; /**< Item ID of how this item looks. */ int mId; /**< Item ID */ - // Equipment related members - SpriteAction mAttackType; /**< Attack type, in case of weapon. */ - int mAttackRange; /**< Attack range, will be zero if non weapon. */ + // Equipment related members. + /** Attack type, in case of weapon. + * See SpriteAction in spritedef.h for more info. + * Attack action sub-types (bow, sword, ...) are defined in items.xml. + */ + std::string mAttackAction; + int mAttackRange; /**< Attack range, will be zero if non weapon. */ // Particle to be shown when weapon attacks std::string mMissileParticle; diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index b7c4fd72..b30bec0a 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -185,11 +185,9 @@ Map *MapReader::readMap(xmlNodePtr node, const std::string &path) if (config.getValue("showWarps", 1)) { map->addParticleEffect( - paths.getValue("particles", - "graphics/particles/") - + paths.getValue("portalEffectFile", - "warparea.particle.xml"), - objX, objY, objW, objH); + paths.getStringValue("particles") + + paths.getStringValue("portalEffectFile"), + objX, objY, objW, objH); } } else diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp index b08d87f2..6bc64a89 100644 --- a/src/resources/monsterdb.cpp +++ b/src/resources/monsterdb.cpp @@ -23,21 +23,21 @@ #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" #include "configuration.h" #define OLD_TMWATHENA_OFFSET 1002 namespace { - MonsterDB::MonsterInfos mMonsterInfos; - MonsterInfo mUnknown; + BeingInfos mMonsterInfos; bool mLoaded = false; } @@ -46,8 +46,6 @@ void MonsterDB::load() if (mLoaded) unload(); - mUnknown.addSprite(paths.getValue("spriteErrorFile", "error.xml")); - logger->log("Initializing monster database..."); XML::Document doc("monsters.xml"); @@ -69,39 +67,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")) { @@ -111,19 +99,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 { @@ -138,18 +126,22 @@ void MonsterDB::load() const int id = XML::getProperty(spriteNode, "id", 0); const std::string particleEffect = XML::getProperty( spriteNode, "particle-effect", ""); - SpriteAction spriteAction = SpriteDef::makeSpriteAction( - XML::getProperty(spriteNode, "action", "attack")); + const std::string spriteAction = 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; } @@ -165,17 +157,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 12cdbe3e..00000000 --- a/src/resources/monsterinfo.cpp +++ /dev/null @@ -1,100 +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" -#include "configuration.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(paths.getValue("sfx", "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 21a2e9a1..ec22c225 100644 --- a/src/resources/npcdb.cpp +++ b/src/resources/npcdb.cpp @@ -23,13 +23,15 @@ #include "log.h" +#include "resources/beinginfo.h" + +#include "utils/dtor.h" #include "utils/xml.h" #include "configuration.h" namespace { - NPCInfos mNPCInfos; - NPCInfo mUnknown; + BeingInfos mNPCInfos; bool mLoaded = false; } @@ -38,12 +40,6 @@ void NPCDB::load() if (mLoaded) unload(); - NPCsprite *unknownSprite = new NPCsprite; - unknownSprite->sprite = paths.getValue("spriteErrorFile", - "error.xml"); - unknownSprite->variant = 0; - mUnknown.sprites.push_back(unknownSprite); - logger->log("Initializing NPC database..."); XML::Document doc("npcs.xml"); @@ -67,23 +63,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; } @@ -92,40 +95,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/specialdb.cpp b/src/resources/specialdb.cpp new file mode 100644 index 00000000..ac591c4f --- /dev/null +++ b/src/resources/specialdb.cpp @@ -0,0 +1,132 @@ +/* + * 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 "resources/specialdb.h" + +#include "log.h" + +#include "utils/dtor.h" +#include "utils/xml.h" + + +namespace +{ + SpecialInfos mSpecialInfos; + bool mLoaded = false; +} + +SpecialInfo::TargetMode SpecialDB::targetModeFromString(const std::string& str) +{ + if (str=="self") return SpecialInfo::TARGET_SELF; + else if (str=="friend") return SpecialInfo::TARGET_FRIEND; + else if (str=="enemy") return SpecialInfo::TARGET_ENEMY; + else if (str=="being") return SpecialInfo::TARGET_BEING; + else if (str=="point") return SpecialInfo::TARGET_POINT; + + logger->log("SpecialDB: Warning, unknown target mode \"%s\"", str.c_str() ); + return SpecialInfo::TARGET_SELF; +} + +void SpecialDB::load() +{ + if (mLoaded) + unload(); + + logger->log("Initializing special database..."); + + XML::Document doc("specials.xml"); + xmlNodePtr root = doc.rootNode(); + + if (!root || !xmlStrEqual(root->name, BAD_CAST "specials")) + { + logger->log("Error loading specials file specials.xml"); + return; + } + + std::string setName; + + for_each_xml_child_node(set, root) + { + if (xmlStrEqual(set->name, BAD_CAST "set")) + { + setName = XML::getProperty(set, "name", "Actions"); + + + for_each_xml_child_node(special, set) + { + if (xmlStrEqual(special->name, BAD_CAST "special")) + { + SpecialInfo *info = new SpecialInfo(); + int id = XML::getProperty(special, "id", 0); + info->id = id; + info->set = setName; + info->name = XML::getProperty(special, "name", ""); + info->icon = XML::getProperty(special, "icon", ""); + + info->isActive = XML::getBoolProperty(special, "active", false); + info->targetMode = targetModeFromString(XML::getProperty(special, "target", "self")); + + info->level = XML::getProperty(special, "level", -1); + info->hasLevel = info->level > -1; + + info->hasRechargeBar = XML::getBoolProperty(special, "recharge", false); + info->rechargeNeeded = 0; + info->rechargeCurrent = 0; + + if (mSpecialInfos.find(id) != mSpecialInfos.end()) + { + logger->log("SpecialDB: Duplicate special ID %d (ignoring)", id); + } else { + mSpecialInfos[id] = info; + } + } + } + } + } + + mLoaded = true; +} + +void SpecialDB::unload() +{ + + delete_all(mSpecialInfos); + mSpecialInfos.clear(); + + mLoaded = false; +} + + +SpecialInfo *SpecialDB::get(int id) +{ + + SpecialInfos::iterator i = mSpecialInfos.find(id); + + if (i == mSpecialInfos.end()) + { + return NULL; + } + else + { + return i->second; + } + return NULL; +} + diff --git a/src/resources/specialdb.h b/src/resources/specialdb.h new file mode 100644 index 00000000..38612c2a --- /dev/null +++ b/src/resources/specialdb.h @@ -0,0 +1,72 @@ +/* + * 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 SPECIAL_DB_H +#define SPECIAL_DB_H + +#include <string> +#include <map> + +struct SpecialInfo +{ + enum TargetMode + { + TARGET_SELF, // no target selection + TARGET_FRIEND, // target friendly being + TARGET_ENEMY, // target hostile being + TARGET_BEING, // target any being + TARGET_POINT // target map location + }; + int id; + std::string set; // tab on which the special is shown + std::string name; // displayed name of special + std::string icon; // filename of graphical icon + + bool isActive; // true when the special can be used + TargetMode targetMode; // target mode + + bool hasLevel; // true when the special has levels + int level; // level of special when applicable + + bool hasRechargeBar; // true when the special has a recharge bar + int rechargeNeeded; // maximum recharge when applicable + int rechargeCurrent; // current recharge when applicable +}; + +/** + * Special information database. + */ +namespace SpecialDB +{ + void load(); + + void unload(); + + /** gets the special info for ID. Will return 0 when it is + * a server-specific special. + */ + SpecialInfo *get(int id); + + SpecialInfo::TargetMode targetModeFromString(const std::string& str); +} + +typedef std::map<int, SpecialInfo *> SpecialInfos; + +#endif diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp index c524c43c..311c9d1a 100644 --- a/src/resources/spritedef.cpp +++ b/src/resources/spritedef.cpp @@ -36,13 +36,16 @@ #include <set> -Action *SpriteDef::getAction(SpriteAction action) const +SpriteReference *SpriteReference::Empty = new SpriteReference( + paths.getStringValue("spriteErrorFile"), 0); + +Action *SpriteDef::getAction(const std::string &action) const { Actions::const_iterator i = mActions.find(action); if (i == mActions.end()) { - logger->log("Warning: no action \"%u\" defined!", action); + logger->log("Warning: no action \"%s\" defined!", action.c_str()); return NULL; } @@ -63,9 +66,8 @@ SpriteDef *SpriteDef::load(const std::string &animationFile, int variant) { logger->log("Error, failed to parse %s", animationFile.c_str()); - std::string errorFile = paths.getValue("sprites", "graphics/sprites") - + paths.getValue("spriteErrorFile", - "error.xml"); + std::string errorFile = paths.getStringValue("sprites") + + paths.getStringValue("spriteErrorFile"); if (animationFile != errorFile) { return load(errorFile, 0); @@ -82,22 +84,29 @@ SpriteDef *SpriteDef::load(const std::string &animationFile, int variant) return def; } +void SpriteDef::substituteAction(std::string complete, std::string with) +{ + if (mActions.find(complete) == mActions.end()) + { + Actions::iterator i = mActions.find(with); + if (i != mActions.end()) + { + mActions[complete] = i->second; + } + } +} + void SpriteDef::substituteActions() { - substituteAction(ACTION_STAND, ACTION_DEFAULT); - substituteAction(ACTION_WALK, ACTION_STAND); - substituteAction(ACTION_WALK, ACTION_RUN); - substituteAction(ACTION_ATTACK, ACTION_STAND); - substituteAction(ACTION_ATTACK_SWING, ACTION_ATTACK); - substituteAction(ACTION_ATTACK_STAB, ACTION_ATTACK_SWING); - substituteAction(ACTION_ATTACK_BOW, ACTION_ATTACK_STAB); - substituteAction(ACTION_ATTACK_THROW, ACTION_ATTACK_SWING); - substituteAction(ACTION_CAST_MAGIC, ACTION_ATTACK_SWING); - substituteAction(ACTION_USE_ITEM, ACTION_CAST_MAGIC); - substituteAction(ACTION_SIT, ACTION_STAND); - substituteAction(ACTION_SLEEP, ACTION_SIT); - substituteAction(ACTION_HURT, ACTION_STAND); - substituteAction(ACTION_DEAD, ACTION_HURT); + substituteAction(SpriteAction::STAND, SpriteAction::DEFAULT); + substituteAction(SpriteAction::MOVE, SpriteAction::STAND); + substituteAction(SpriteAction::ATTACK, SpriteAction::STAND); + substituteAction(SpriteAction::CAST_MAGIC, SpriteAction::ATTACK); + substituteAction(SpriteAction::USE_ITEM, SpriteAction::CAST_MAGIC); + substituteAction(SpriteAction::SIT, SpriteAction::STAND); + substituteAction(SpriteAction::SLEEP, SpriteAction::SIT); + substituteAction(SpriteAction::HURT, SpriteAction::STAND); + substituteAction(SpriteAction::DEAD, SpriteAction::HURT); } void SpriteDef::loadSprite(xmlNodePtr spriteNode, int variant, @@ -169,20 +178,19 @@ void SpriteDef::loadAction(xmlNodePtr node, int variant_offset) } ImageSet *imageSet = si->second; - SpriteAction actionType = makeSpriteAction(actionName); - if (actionType == ACTION_INVALID) + if (actionName == SpriteAction::INVALID) { logger->log("Warning: Unknown action \"%s\" defined in %s", actionName.c_str(), getIdPath().c_str()); return; } Action *action = new Action; - mActions[actionType] = action; + mActions[actionName] = action; // When first action set it as default direction - if (mActions.empty()) + if (mActions.size() == 1) { - mActions[ACTION_DEFAULT] = action; + mActions[SpriteAction::DEFAULT] = action; } // Load animations @@ -283,8 +291,7 @@ void SpriteDef::includeSprite(xmlNodePtr includeNode) if (filename.empty()) return; - XML::Document doc(paths.getValue("sprites", "graphics/sprites/") - + filename); + XML::Document doc(paths.getStringValue("sprites") + filename); xmlNodePtr rootNode = doc.rootNode(); if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "sprite")) @@ -296,18 +303,6 @@ void SpriteDef::includeSprite(xmlNodePtr includeNode) loadSprite(rootNode, 0); } -void SpriteDef::substituteAction(SpriteAction complete, SpriteAction with) -{ - if (mActions.find(complete) == mActions.end()) - { - Actions::iterator i = mActions.find(with); - if (i != mActions.end()) - { - mActions[complete] = i->second; - } - } -} - SpriteDef::~SpriteDef() { // Actions are shared, so ensure they are deleted only once. @@ -331,63 +326,6 @@ SpriteDef::~SpriteDef() } } -SpriteAction SpriteDef::makeSpriteAction(const std::string &action) -{ - if (action.empty() || action == "default") - return ACTION_DEFAULT; - - if (action == "stand") - return ACTION_STAND; - else if (action == "walk") - return ACTION_WALK; - else if (action == "run") - return ACTION_RUN; - else if (action == "attack") - return ACTION_ATTACK; - else if (action == "attack_swing") - return ACTION_ATTACK_SWING; - else if (action == "attack_stab") - return ACTION_ATTACK_STAB; - else if (action == "attack_bow") - return ACTION_ATTACK_BOW; - else if (action == "attack_throw") - return ACTION_ATTACK_THROW; - else if (action == "special0") - return ACTION_SPECIAL_0; - else if (action == "special1") - return ACTION_SPECIAL_1; - else if (action == "special2") - return ACTION_SPECIAL_2; - else if (action == "special3") - return ACTION_SPECIAL_3; - else if (action == "special4") - return ACTION_SPECIAL_4; - else if (action == "special5") - return ACTION_SPECIAL_5; - else if (action == "special6") - return ACTION_SPECIAL_6; - else if (action == "special7") - return ACTION_SPECIAL_7; - else if (action == "special8") - return ACTION_SPECIAL_8; - else if (action == "special9") - return ACTION_SPECIAL_9; - else if (action == "cast_magic") - return ACTION_CAST_MAGIC; - else if (action == "use_item") - return ACTION_USE_ITEM; - else if (action == "sit") - return ACTION_SIT; - else if (action == "sleep") - return ACTION_SLEEP; - else if (action == "hurt") - return ACTION_HURT; - else if (action == "dead") - return ACTION_DEAD; - else - return ACTION_INVALID; -} - SpriteDirection SpriteDef::makeSpriteDirection(const std::string &direction) { if (direction.empty() || direction == "default") diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h index 5bb6078e..18a70c9b 100644 --- a/src/resources/spritedef.h +++ b/src/resources/spritedef.h @@ -26,42 +26,60 @@ #include <libxml/tree.h> +#include <list> #include <map> #include <string> class Action; class ImageSet; -enum SpriteAction +struct SpriteReference { - ACTION_DEFAULT = 0, - ACTION_STAND, - ACTION_WALK, - ACTION_RUN, - ACTION_ATTACK, - ACTION_ATTACK_SWING, - ACTION_ATTACK_STAB, - ACTION_ATTACK_BOW, - ACTION_ATTACK_THROW, - ACTION_SPECIAL_0, - ACTION_SPECIAL_1, - ACTION_SPECIAL_2, - ACTION_SPECIAL_3, - ACTION_SPECIAL_4, - ACTION_SPECIAL_5, - ACTION_SPECIAL_6, - ACTION_SPECIAL_7, - ACTION_SPECIAL_8, - ACTION_SPECIAL_9, - ACTION_CAST_MAGIC, - ACTION_USE_ITEM, - ACTION_SIT, - ACTION_SLEEP, - ACTION_HURT, - ACTION_DEAD, - ACTION_INVALID + 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; + +/* + * Remember those are the main action. + * Action subtypes, e.g.: "attack_bow" are to be passed by items.xml after + * an ACTION_ATTACK call. + * Which special to be use to to be passed with the USE_SPECIAL call. + * Running, walking, ... is a sub-type of moving. + * ... + * Please don't add hard-coded subtypes here! + */ +namespace SpriteAction +{ + static const std::string DEFAULT = "stand"; + static const std::string STAND = "stand"; + static const std::string SIT = "sit"; + static const std::string SLEEP = "sleep"; + static const std::string DEAD = "dead"; + static const std::string MOVE = "walk"; + static const std::string ATTACK = "attack"; + static const std::string HURT = "hurt"; + static const std::string USE_SPECIAL = "special"; + static const std::string CAST_MAGIC = "magic"; + static const std::string USE_ITEM = "item"; + static const std::string INVALID = ""; +} + enum SpriteDirection { DIRECTION_DEFAULT = 0, @@ -86,12 +104,7 @@ class SpriteDef : public Resource /** * Returns the specified action. */ - Action *getAction(SpriteAction action) const; - - /** - * Converts a string into a SpriteAction enum. - */ - static SpriteAction makeSpriteAction(const std::string &action); + Action *getAction(const std::string &action) const; /** * Converts a string into a SpriteDirection enum. @@ -147,12 +160,12 @@ class SpriteDef : public Resource * When there are no animations defined for the action "complete", its * animations become a copy of those of the action "with". */ - void substituteAction(SpriteAction complete, SpriteAction with); + void substituteAction(std::string complete, std::string with); typedef std::map<std::string, ImageSet*> ImageSets; typedef ImageSets::iterator ImageSetIterator; - typedef std::map<SpriteAction, Action*> Actions; + typedef std::map<std::string, Action*> Actions; ImageSets mImageSets; Actions mActions; diff --git a/src/gui/theme.cpp b/src/resources/theme.cpp index 12de1f91..6633f1e0 100644 --- a/src/gui/theme.cpp +++ b/src/resources/theme.cpp @@ -21,7 +21,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "gui/theme.h" +#include "resources/theme.h" #include "client.h" #include "configuration.h" @@ -48,7 +48,7 @@ Theme *Theme::mInstance = 0; static void initDefaultThemePath() { ResourceManager *resman = ResourceManager::getInstance(); - defaultThemePath = branding.getValue("guiThemePath", ""); + defaultThemePath = branding.getStringValue("guiThemePath"); if (!defaultThemePath.empty() && resman->isDirectory(defaultThemePath)) return; @@ -81,8 +81,8 @@ Skin::~Skin() void Skin::updateAlpha(float minimumOpacityAllowed) { - const float alpha = std::max((double)minimumOpacityAllowed, - config.getValue("guialpha", 0.8f)); + const float alpha = std::max(minimumOpacityAllowed, + config.getFloatValue("guialpha")); for_each(mBorder.grid, mBorder.grid + 9, std::bind2nd(std::mem_fun(&Image::setAlpha), alpha)); @@ -339,9 +339,9 @@ bool Theme::tryThemePath(std::string themePath) void Theme::prepareThemePath() { // Try theme from settings - if (!tryThemePath(config.getValue("theme", ""))) + if (!tryThemePath(config.getStringValue("theme"))) // Try theme from branding - if (!tryThemePath(branding.getValue("theme", ""))) + if (!tryThemePath(branding.getStringValue("theme"))) // Use default mThemePath = defaultThemePath; diff --git a/src/gui/theme.h b/src/resources/theme.h index 6798bed5..6798bed5 100644 --- a/src/gui/theme.h +++ b/src/resources/theme.h diff --git a/src/gui/userpalette.cpp b/src/resources/userpalette.cpp index 0f30b752..5067c794 100644 --- a/src/gui/userpalette.cpp +++ b/src/resources/userpalette.cpp @@ -20,7 +20,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "userpalette.h" +#include "resources/userpalette.h" #include "configuration.h" #include "client.h" diff --git a/src/gui/userpalette.h b/src/resources/userpalette.h index 82bcea1c..82bcea1c 100644 --- a/src/gui/userpalette.h +++ b/src/resources/userpalette.h diff --git a/src/resources/wallpaper.cpp b/src/resources/wallpaper.cpp index 22bbda9c..06675ab1 100644 --- a/src/resources/wallpaper.cpp +++ b/src/resources/wallpaper.cpp @@ -53,26 +53,20 @@ static void initDefaultWallpaperPaths() ResourceManager *resman = ResourceManager::getInstance(); // Init the path - wallpaperPath = branding.getValue("wallpapersPath", ""); + wallpaperPath = branding.getStringValue("wallpapersPath"); if (!wallpaperPath.empty() && resman->isDirectory(wallpaperPath)) return; else - wallpaperPath = paths.getValue("wallpapers", ""); - - if (wallpaperPath.empty() || !resman->isDirectory(wallpaperPath)) - wallpaperPath = "graphics/images/"; + wallpaperPath = paths.getValue("wallpapers", "graphics/images/"); // Init the default file - wallpaperFile = branding.getValue("wallpaperFile", ""); + wallpaperFile = branding.getStringValue("wallpaperFile"); - if (!wallpaperFile.empty() && resman->isDirectory(wallpaperFile)) + if (!wallpaperFile.empty()) return; else - wallpaperFile = paths.getValue("wallpaperFile", ""); - - if (wallpaperFile.empty() || !resman->isDirectory(wallpaperFile)) - wallpaperFile = "login_wallpaper.png"; + wallpaperFile = paths.getValue("wallpaperFile", "login_wallpaper.png"); } bool wallpaperCompare(WallpaperData a, WallpaperData b) @@ -82,7 +76,7 @@ bool wallpaperCompare(WallpaperData a, WallpaperData b) return (aa > ab || (aa == ab && a.width > b.width)); } - +#include <iostream> void Wallpaper::loadWallpapers() { wallpaperData.clear(); diff --git a/src/simpleanimation.cpp b/src/simpleanimation.cpp index a8d33a43..7ef433ea 100644 --- a/src/simpleanimation.cpp +++ b/src/simpleanimation.cpp @@ -33,14 +33,16 @@ SimpleAnimation::SimpleAnimation(Animation *animation): mAnimation(animation), mAnimationTime(0), mAnimationPhase(0), - mCurrentFrame(mAnimation->getFrame(0)) + mCurrentFrame(mAnimation->getFrame(0)), + mInitialized(true) { } SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): mAnimation(new Animation), mAnimationTime(0), - mAnimationPhase(0) + mAnimationPhase(0), + mInitialized(false) { initializeAnimation(animationNode); mCurrentFrame = mAnimation->getFrame(0); @@ -48,7 +50,8 @@ SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): SimpleAnimation::~SimpleAnimation() { - delete mAnimation; + if (mAnimation) + delete mAnimation; } bool SimpleAnimation::draw(Graphics *graphics, int posX, int posY) const @@ -79,38 +82,55 @@ void SimpleAnimation::setFrame(int frame) void SimpleAnimation::update(int timePassed) { - mAnimationTime += timePassed; - - while (mAnimationTime > mCurrentFrame->delay && mCurrentFrame->delay > 0) + if (mInitialized) { - mAnimationTime -= mCurrentFrame->delay; - mAnimationPhase++; + mAnimationTime += timePassed; - if (mAnimationPhase >= mAnimation->getLength()) - mAnimationPhase = 0; + while (mAnimationTime > mCurrentFrame->delay && mCurrentFrame->delay > 0) + { + mAnimationTime -= mCurrentFrame->delay; + mAnimationPhase++; - mCurrentFrame = mAnimation->getFrame(mAnimationPhase); + if (mAnimationPhase >= mAnimation->getLength()) + mAnimationPhase = 0; + + mCurrentFrame = mAnimation->getFrame(mAnimationPhase); + } } } int SimpleAnimation::getLength() const { - return mAnimation->getLength(); + if (mAnimation) + return mAnimation->getLength(); + else + return 0; } Image *SimpleAnimation::getCurrentImage() const { - return mCurrentFrame->image; + if (mCurrentFrame) + return mCurrentFrame->image; + else + return NULL; } void SimpleAnimation::initializeAnimation(xmlNodePtr animationNode) { + mInitialized = false; + + if (!animationNode) + return; + ImageSet *imageset = ResourceManager::getInstance()->getImageSet( XML::getProperty(animationNode, "imageset", ""), XML::getProperty(animationNode, "width", 0), XML::getProperty(animationNode, "height", 0) ); + if (!imageset) + return; + // Get animation frames for ( xmlNodePtr frameNode = animationNode->xmlChildrenNode; frameNode; @@ -172,4 +192,6 @@ void SimpleAnimation::initializeAnimation(xmlNodePtr animationNode) mAnimation->addTerminator(); } } + + mInitialized = true; } diff --git a/src/simpleanimation.h b/src/simpleanimation.h index a8a43b33..e679442e 100644 --- a/src/simpleanimation.h +++ b/src/simpleanimation.h @@ -78,6 +78,9 @@ class SimpleAnimation /** Current animation phase. */ Frame *mCurrentFrame; + + /** Tell whether the animation is ready */ + bool mInitialized; }; #endif diff --git a/src/sound.cpp b/src/sound.cpp index 241e25e4..a859cb6e 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -142,7 +142,7 @@ void Sound::setSfxVolume(int volume) static Mix_Music *loadMusic(const std::string &filename) { ResourceManager *resman = ResourceManager::getInstance(); - std::string path = resman->getPath("music/" + filename); + std::string path = resman->getPath(paths.getStringValue("music") + filename); if (path.find(".zip/") != std::string::npos || path.find(".zip\\") != std::string::npos) @@ -152,7 +152,7 @@ static Mix_Music *loadMusic(const std::string &filename) logger->log("Loading music \"%s\" from temporary file tempMusic.ogg", path.c_str()); bool success = resman->copyFile( - paths.getValue("music", "music/") + paths.getStringValue("music") + filename, "tempMusic.ogg"); if (success) path = resman->getPath("tempMusic.ogg"); @@ -240,7 +240,7 @@ void Sound::playSfx(const std::string &path) ResourceManager *resman = ResourceManager::getInstance(); SoundEffect *sample = resman->getSoundEffect( - paths.getValue("sfx", "sfx/") + path); + paths.getStringValue("sfx") + path); if (sample) { logger->log("Sound::playSfx() Playing: %s", path.c_str()); diff --git a/src/sprite.h b/src/sprite.h index 847c01a6..38db8b41 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(std::string 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/statuseffect.cpp b/src/statuseffect.cpp index 1f913f4a..d7c3f17a 100644 --- a/src/statuseffect.cpp +++ b/src/statuseffect.cpp @@ -21,11 +21,10 @@ #include "statuseffect.h" +#include "event.h" #include "log.h" #include "sound.h" -#include "gui/widgets/chattab.h" - #include "utils/xml.h" #include "configuration.h" @@ -52,7 +51,7 @@ void StatusEffect::playSFX() void StatusEffect::deliverMessage() { if (!mMessage.empty()) - localChatTab->chatLog(mMessage, BY_SERVER); + SERVER_NOTICE(mMessage) } Particle *StatusEffect::getParticle() @@ -70,22 +69,22 @@ AnimatedSprite *StatusEffect::getIcon() else { AnimatedSprite *sprite = AnimatedSprite::load( - paths.getValue("sprites", "graphics/sprites/") + mIcon); + paths.getStringValue("sprites") + mIcon); if (false && sprite) { - sprite->play(ACTION_DEFAULT); + sprite->play(SpriteAction::DEFAULT); sprite->reset(); } return sprite; } } -SpriteAction StatusEffect::getAction() +std::string StatusEffect::getAction() { if (mAction.empty()) - return ACTION_INVALID; + return SpriteAction::INVALID; else - return SpriteDef::makeSpriteAction(mAction); + return mAction; } diff --git a/src/statuseffect.h b/src/statuseffect.h index fc0e7336..3f715a16 100644 --- a/src/statuseffect.h +++ b/src/statuseffect.h @@ -56,9 +56,9 @@ public: AnimatedSprite *getIcon(); /** - * Retrieves an action to perform, or ACTION_INVALID + * Retrieves an action to perform, or SpriteAction::INVALID */ - SpriteAction getAction(); + std::string getAction(); /** * Determines whether the particle effect should be restarted when the diff --git a/src/text.cpp b/src/text.cpp index f6c71dba..216b02e2 100644 --- a/src/text.cpp +++ b/src/text.cpp @@ -28,10 +28,10 @@ #include "gui/gui.h" #include "gui/palette.h" -#include "gui/theme.h" #include "resources/resourcemanager.h" #include "resources/image.h" +#include "resources/theme.h" #include <guichan/font.hpp> @@ -41,17 +41,22 @@ 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; Image *sbImage = Theme::getImageFromTheme("bubble.png|W:#" - + config.getValue("speechBubblecolor", "000000")); + + config.getStringValue("speechBubblecolor")); mBubble.grid[0] = sbImage->getSubImage(0, 0, 5, 5); mBubble.grid[1] = sbImage->getSubImage(5, 0, 5, 5); mBubble.grid[2] = sbImage->getSubImage(10, 0, 5, 5); @@ -62,7 +67,7 @@ Text::Text(const std::string &text, int x, int y, mBubble.grid[7] = sbImage->getSubImage(5, 10, 5, 5); mBubble.grid[8] = sbImage->getSubImage(10, 10, 5, 5); mBubbleArrow = sbImage->getSubImage(0, 15, 15, 10); - const float bubbleAlpha = config.getValue("speechBubbleAlpha", 1.0); + const float bubbleAlpha = config.getFloatValue("speechBubbleAlpha"); for (int i = 0; i < 9; i++) { mBubble.grid[i]->setAlpha(bubbleAlpha); @@ -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/textrenderer.h b/src/textrenderer.h index 4da868f1..fccdd3c7 100644 --- a/src/textrenderer.h +++ b/src/textrenderer.h @@ -24,7 +24,7 @@ #include "graphics.h" -#include "gui/theme.h" +#include "resources/theme.h" /** * Class for text rendering. Used by the TextParticle, the Text and FlashText 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; } diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp index 9fe3de14..3988c769 100644 --- a/src/utils/stringutils.cpp +++ b/src/utils/stringutils.cpp @@ -26,7 +26,7 @@ #include <cstdarg> #include <cstdio> -const int UTF8_MAX_SIZE = 10; +static int UTF8_MAX_SIZE = 10; std::string &trim(std::string &str) { @@ -174,4 +174,16 @@ const char* getSafeUtf8String(std::string text) memcpy(buf, text.c_str(), text.size()); memset(buf + text.size(), 0, UTF8_MAX_SIZE); return buf; -}
\ No newline at end of file +} + +bool getBoolFromString(const std::string &text) +{ + std::string txt = text; + toLower(trim(txt)); + if (txt == "true" || txt == "yes" || txt == "on" || txt == "1") + return true; + else if (txt == "false" || txt == "no" || txt == "off" || txt == "0") + return false; + else + return (bool) atoi(txt.c_str()); +} diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h index ec82e240..7c14b1e5 100644 --- a/src/utils/stringutils.h +++ b/src/utils/stringutils.h @@ -125,4 +125,12 @@ const std::string findSameSubstring(const std::string &str1, const std::string & const char* getSafeUtf8String(std::string text); +/** + * Returns a bool value depending on the given string value. + * + * @param text the string used to get the bool value + * @return a boolean value.. + */ +bool getBoolFromString(const std::string &text); + #endif // UTILS_STRINGUTILS_H diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp index 9835f88c..2bcb6f24 100644 --- a/src/utils/xml.cpp +++ b/src/utils/xml.cpp @@ -21,15 +21,19 @@ #include "utils/xml.h" +#include <iostream> +#include <fstream> +#include <cstring> + +#include <libxml/parser.h> +#include <libxml/xmlerror.h> + #include "log.h" #include "resources/resourcemanager.h" #include "utils/zlib.h" -#include <libxml/parser.h> -#include <libxml/xmlerror.h> - namespace XML { static void xmlLogger(void *ctx, xmlErrorPtr error); @@ -129,6 +133,15 @@ namespace XML return def; } + bool getBoolProperty(xmlNodePtr node, const char* name, bool def) + { + xmlChar *prop = xmlGetProp(node, BAD_CAST name); + + if (xmlStrEqual(prop, BAD_CAST "true" ) ) return true; + if (xmlStrEqual(prop, BAD_CAST "false") ) return false; + return def; + } + xmlNodePtr findFirstChildByName(xmlNodePtr parent, const char *name) { for_each_xml_child_node(child, parent) @@ -149,7 +162,7 @@ namespace XML logger->log("Error in unknown xml file on line %d", error->line); - logger->log(error->message); + logger->log("%s", error->message); // No need to keep errors around xmlCtxtResetLastError(error->ctxt); diff --git a/src/utils/xml.h b/src/utils/xml.h index 8ffecb76..48e66787 100644 --- a/src/utils/xml.h +++ b/src/utils/xml.h @@ -60,14 +60,14 @@ namespace XML }; /** - * Gets an integer property from an xmlNodePtr. + * Gets an floating point property from an xmlNodePtr. */ - int getProperty(xmlNodePtr node, const char *name, int def); + double getFloatProperty(xmlNodePtr node, const char *name, double def); /** - * Gets an floating point property from an xmlNodePtr. + * Gets an integer property from an xmlNodePtr. */ - double getFloatProperty(xmlNodePtr node, const char *name, double def); + int getProperty(xmlNodePtr node, const char *name, int def); /** * Gets a string property from an xmlNodePtr. @@ -76,6 +76,11 @@ namespace XML const std::string &def); /** + * Gets a boolean property from an xmlNodePtr. + */ + bool getBoolProperty(xmlNodePtr node, const char *name, bool def); + + /** * Finds the first child node with the given name */ xmlNodePtr findFirstChildByName(xmlNodePtr parent, const char *name); diff --git a/src/variabledata.h b/src/variabledata.h new file mode 100644 index 00000000..19e09795 --- /dev/null +++ b/src/variabledata.h @@ -0,0 +1,131 @@ +/* + * 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 VARIABLEDATA_H +#define VARIABLEDATA_H + +#include <string> + +class ActorSprite; +class Item; + +namespace Mana +{ + +class VariableData +{ + public: + enum DataType + { + DATA_NONE, + DATA_INT, + DATA_STRING, + DATA_FLOAT, + DATA_BOOL, + DATA_ITEM, + DATA_ACTOR + }; + + virtual ~VariableData() {}; + + virtual int getType() const = 0; +}; + +class IntData : public VariableData +{ +public: + IntData(int value) { mData = value; } + + int getData() const { return mData; } + + int getType() const { return DATA_INT; } + +private: + int mData; +}; + +class StringData : public VariableData +{ +public: + StringData(const std::string &value) { mData = value; } + + const std::string &getData() const { return mData; } + + int getType() const { return DATA_STRING; } + +private: + std::string mData; +}; + +class FloatData : public VariableData +{ +public: + FloatData(double value) { mData = value; } + + double getData() const { return mData; } + + int getType() const { return DATA_FLOAT; } + +private: + double mData; +}; + +class BoolData : public VariableData +{ +public: + BoolData(bool value) { mData = value; } + + bool getData() const { return mData; } + + int getType() const { return DATA_BOOL; } + +private: + bool mData; +}; + +class ItemData : public VariableData +{ +public: + ItemData(Item *value) { mData = value; } + + Item *getData() const { return mData; } + + int getType() const { return DATA_ITEM; } + +private: + Item *mData; +}; + +class ActorData : public VariableData +{ +public: + ActorData(ActorSprite *value) { mData = value; } + + ActorSprite *getData() const { return mData; } + + int getType() const { return DATA_ACTOR; } + +private: + ActorSprite *mData; +}; + +} // namespace Mana + +#endif |