diff options
32 files changed, 786 insertions, 202 deletions
@@ -70,3 +70,6 @@ GTAGS # generated for nsis build translations/* + +# documentation generated by Doxygen +docs/SOURCE/html/* @@ -384,18 +384,12 @@ <Unit filename="src\net\ea\gamehandler.h" /> <Unit filename="src\net\ea\generalhandler.cpp" /> <Unit filename="src\net\ea\generalhandler.h" /> + <Unit filename="src\net\ea\gui\guildtab.cpp" /> + <Unit filename="src\net\ea\gui\guildtab.h" /> <Unit filename="src\net\ea\gui\partytab.cpp" /> <Unit filename="src\net\ea\gui\partytab.h" /> - <Unit filename="src\net\ea\guildhandler.cpp"> - <Option target="Unix eAthena" /> - <Option target="Windows" /> - <Option target="Unix" /> - </Unit> - <Unit filename="src\net\ea\guildhandler.h"> - <Option target="Unix eAthena" /> - <Option target="Windows" /> - <Option target="Unix" /> - </Unit> + <Unit filename="src\net\ea\guildhandler.cpp" /> + <Unit filename="src\net\ea\guildhandler.h" /> <Unit filename="src\net\ea\inventoryhandler.cpp" /> <Unit filename="src\net\ea\inventoryhandler.h" /> <Unit filename="src\net\ea\itemhandler.cpp" /> @@ -327,6 +327,8 @@ ./src/net/ea/generalhandler.h ./src/net/ea/guildhandler.cpp ./src/net/ea/guildhandler.h +./src/net/ea/gui/guildtab.cpp +./src/net/ea/gui/guildtab.h ./src/net/ea/gui/partytab.cpp ./src/net/ea/gui/partytab.h ./src/net/ea/inventoryhandler.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a7458ac..5cfbd1f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -493,6 +493,8 @@ SET(SRCS ) SET(SRCS_EA + net/ea/gui/guildtab.cpp + net/ea/gui/guildtab.h net/ea/gui/partytab.cpp net/ea/gui/partytab.h net/ea/adminhandler.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 0a34bddd..e7dc3685 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -446,6 +446,8 @@ mana_SOURCES += \ net/manaserv/tradehandler.h mana_SOURCES += \ + net/ea/gui/guildtab.cpp \ + net/ea/gui/guildtab.h \ net/ea/gui/partytab.cpp \ net/ea/gui/partytab.h \ net/ea/adminhandler.cpp \ diff --git a/src/being.cpp b/src/being.cpp index 247e193a..ce6c9e1b 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -127,6 +127,48 @@ void Being::setPosition(const Vector &pos) (int)pos.y - getHeight() - mText->getHeight() - 6); } +Position Being::checkNodeOffsets(Position position) +{ + // Pre-computing character's position in tiles + const int tx = position.x / 32; + const int ty = position.y / 32; + + // Pre-computing character's position offsets. + int fx = position.x % 32; + int fy = position.y % 32; + + // Compute the being radius: + // FIXME: the beings' radius should be obtained from xml values + // and stored into the Being ojects. + int radius = getWidth() / 2; + // FIXME: Hande beings with more than 1/2 tile radius by not letting them + // go or spawn in too narrow places. The server will have to be aware + // of being's radius value (in tiles) to handle this gracefully. + if (radius > 32 / 2) radius = 32 / 2; + // set a default value if no value returned. + if (radius < 1) radius = 32 / 3; + + // Fix coordinates so that the player does not seem to dig into walls. + if (fx > (32 - radius) && !mMap->getWalk(tx + 1, ty, getWalkMask())) + fx = 32 - radius; + else if (fx < radius && !mMap->getWalk(tx - 1, ty, getWalkMask())) + fx = radius; + else if (fy > (32 - radius) && !mMap->getWalk(tx, ty + 1, getWalkMask())) + fy = 32 - radius; + else if (fy < radius && !mMap->getWalk(tx, ty - 1, getWalkMask())) + fy = radius; + + // FIXME: Check also diagonal positions. + + // Test also the current character's position, to avoid the corner case + // where a player can approach an obstacle by walking from slightly + // under, diagonally. First part to the walk on water bug. + //if (offsetY < 16 && !mMap->getWalk(posX, posY - 1, getWalkMask())) + //fy = 16; + + return Position(tx * 32 + fx, ty * 32 + fy); +} + void Being::setDestination(int dstX, int dstY) { if (Net::getNetworkType() == ServerInfo::EATHENA) @@ -136,12 +178,22 @@ void Being::setDestination(int dstX, int dstY) return; } - mDest.x = dstX; - mDest.y = dstY; + // Check the walkability of the destination: + // If the destination is unwalkable, + // don't bother finding a path or set a destination. + if (!mMap->getWalk(dstX / 32, dstY / 32)) + return; + + // We check the destination in order to handle + // surrounding blocking tiles gracefully... + Position dest = checkNodeOffsets(dstX, dstY); + mDest.x = dest.x; + mDest.y = dest.y; int srcX = mPos.x; int srcY = mPos.y; - Path thisPath; + // We initialize an empty path... + Path thisPath = Path(); if (mMap) { @@ -175,6 +227,12 @@ void Being::setDestination(int dstX, int dstY) { it->x = (it->x * 32) + startX + (changeX * i); it->y = (it->y * 32) + startY + (changeY * i); + + // We check each path node and correct the + // tile position's offsets whenever needed. + Position pos = checkNodeOffsets(*it); + it->x = pos.x; + it->y = pos.y; i++; it++; } diff --git a/src/being.h b/src/being.h index 58fe4c77..5140717c 100644 --- a/src/being.h +++ b/src/being.h @@ -645,6 +645,17 @@ class Being : public Sprite, public ConfigListener ParticleVector mStatusParticleEffects; ParticleList mChildParticleEffects; + Vector mDest; /**< destination coordinates. */ + + /** + * Check the current position against surrounding + * blocking tiles, and correct the position offset within + * tile when needed. + */ + Position checkNodeOffsets(Position position); + Position checkNodeOffsets(int x, int y) + { return checkNodeOffsets(Position(x, y)); } + private: /** @@ -668,9 +679,8 @@ class Being : public Sprite, public ConfigListener */ Vector mWalkSpeed; - Vector mPos; - Vector mDest; - int mX, mY; /**< Position on tile */ + Vector mPos; /**< Position coordinates. */ + int mX, mY; /**< Position in tile */ int mDamageTaken; diff --git a/src/gui/palette.cpp b/src/gui/palette.cpp index e7c49c89..d2309399 100644 --- a/src/gui/palette.cpp +++ b/src/gui/palette.cpp @@ -99,6 +99,7 @@ Palette::Palette() : addColor(WHISPER, 0x00feaf, STATIC, indent + _("Whisper"), 'W'); addColor(IS, 0xa08527, STATIC, indent + _("Is"), 'I'); addColor(PARTY, 0xf48055, STATIC, indent + _("Party"), 'P'); + addColor(GUILD, 0xf48055, STATIC, indent + _("Guild"), 'U'); addColor(SERVER, 0x8415e2, STATIC, indent + _("Server"), 'S'); addColor(LOGGER, 0x919191, STATIC, indent + _("Logger"), 'L'); addColor(HYPERLINK, 0xe50d0d, STATIC, indent + _("Hyperlink"), '<'); diff --git a/src/gui/palette.h b/src/gui/palette.h index e353f318..0c1d2df0 100644 --- a/src/gui/palette.h +++ b/src/gui/palette.h @@ -71,6 +71,7 @@ class Palette : public gcn::ListModel ENTRY(WHISPER)\ ENTRY(IS)\ ENTRY(PARTY)\ + ENTRY(GUILD)\ ENTRY(SERVER)\ ENTRY(LOGGER)\ ENTRY(HYPERLINK)\ diff --git a/src/gui/setup_colors.cpp b/src/gui/setup_colors.cpp index c476e971..bc86e362 100644 --- a/src/gui/setup_colors.cpp +++ b/src/gui/setup_colors.cpp @@ -300,6 +300,7 @@ void Setup_Colors::valueChanged(const gcn::SelectionEvent &event) case Palette::WHISPER: case Palette::IS: case Palette::PARTY: + case Palette::GUILD: case Palette::SERVER: case Palette::LOGGER: case Palette::HYPERLINK: diff --git a/src/guild.cpp b/src/guild.cpp index b4ecaa7e..30c004bc 100644 --- a/src/guild.cpp +++ b/src/guild.cpp @@ -24,22 +24,19 @@ #include "beingmanager.h" #include "player.h" -GuildMember::GuildMember(int guildId, int id, const std::string &name): - Avatar(name), mId(id) +GuildMember::GuildMember(Guild *guild, int id, const std::string &name): + Avatar(name), mId(id), mGuild(guild) { - mGuild = Guild::getGuild(guildId); } -GuildMember::GuildMember(int guildId, int id): - mId(id) +GuildMember::GuildMember(Guild *guild, int id): + mId(id), mGuild(guild) { - mGuild = Guild::getGuild(guildId); } -GuildMember::GuildMember(int guildId, const std::string &name): - Avatar(name), mId(0) +GuildMember::GuildMember(Guild *guild, const std::string &name): + Avatar(name), mId(0), mGuild(guild) { - mGuild = Guild::getGuild(guildId); } Guild::GuildMap Guild::guilds; @@ -51,16 +48,49 @@ Guild::Guild(short id): guilds[id] = this; } -void Guild::addMember(GuildMember *member) +GuildMember *Guild::addMember(int id, const std::string &name) { - if (member->mGuild > 0 && member->mGuild != this) - throw "Member in another guild!"; + GuildMember *m; + if ((m = getMember(id))) + { + return m; + } + + m = new GuildMember(this, id, name); + + mMembers.push_back(m); - if (!isMember(member)) + return m; +} + +GuildMember *Guild::addMember(int id) +{ + GuildMember *m; + if ((m = getMember(id))) { - mMembers.push_back(member); - member->mGuild = this; + return m; } + + m = new GuildMember(this, id); + + mMembers.push_back(m); + + return m; +} + +GuildMember *Guild::addMember(const std::string &name) +{ + GuildMember *m; + if ((m = getMember(name))) + { + return m; + } + + m = new GuildMember(this, name); + + mMembers.push_back(m); + + return m; } GuildMember *Guild::getMember(int id) diff --git a/src/guild.h b/src/guild.h index 640e495e..a571597f 100644 --- a/src/guild.h +++ b/src/guild.h @@ -35,12 +35,6 @@ class Guild; class GuildMember : public Avatar { public: - GuildMember(int guildId, int id, const std::string &name); - - GuildMember(int guildId, int id); - - GuildMember(int guildId, const std::string &name); - int getID() const { return mId; } void setID(int id) { mId = id; } @@ -50,6 +44,12 @@ public: protected: friend class Guild; + GuildMember(Guild *guild, int id, const std::string &name); + + GuildMember(Guild *guild, int id); + + GuildMember(Guild *guild, const std::string &name); + int mId; Guild *mGuild; }; @@ -69,7 +69,17 @@ public: /** * Adds member to the list. */ - void addMember(GuildMember *member); + GuildMember *addMember(int id, const std::string &name); + + /** + * Adds member to the list. + */ + GuildMember *addMember(int id); + + /** + * Adds member to the list. + */ + GuildMember *addMember(const std::string &name); /** * Find a member by ID. diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 8133bf4a..d7f64113 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -98,7 +98,6 @@ LocalPlayer::LocalPlayer(int id, int job): mLastAction(-1), mWalkingDir(0), mPathSetByMouse(false), - mDestX(0), mDestY(0), mInventory(new Inventory(Net::getInventoryHandler() ->getSize(Net::InventoryHandler::INVENTORY))), mLocalWalkTime(-1), @@ -463,66 +462,17 @@ void LocalPlayer::setTarget(Being *target) void LocalPlayer::setDestination(int x, int y) { - if (Net::getNetworkType() == ServerInfo::MANASERV) - { - // Pre-computing character's destination in tiles - const int tx = x / 32; - const int ty = y / 32; - - // Check the walkability of the destination - // If the destination is a wall, don't go there! - if (!mMap->getWalk(tx, ty)) - return; - - // Pre-computing character's position useful variables. - Vector playerPosition = getPosition(); - const int posX = (int)(playerPosition.x / 32); - const int posY = (int)(playerPosition.y / 32); - const int offsetY = (int)playerPosition.y % 32; - - // check if we're finding a path to the seeked destination - // If the path is empty... and isn't on the same tile, - // then, it's an unvalid one. - if (posX != tx || posY != ty) - { - Path evaluatedPath = mMap->findPath(posX, posY, tx, ty, - getWalkMask()); - if (evaluatedPath.empty()) - return; - } - - // Pre-computing character's destination offsets. - int fx = x % 32; - int fy = y % 32; - - // Fix coordinates so that the player does not seem to dig into walls. - if (fx > 16 && !mMap->getWalk(tx + 1, ty, getWalkMask())) - fx = 16; - else if (fx < 16 && !mMap->getWalk(tx - 1, ty, getWalkMask())) - fx = 16; - else if (fy > 16 && !mMap->getWalk(tx, ty + 1, getWalkMask())) - fy = 16; - else if (fy < 16 && !mMap->getWalk(tx, ty - 1, getWalkMask())) - fy = 16; - - // Test also the current character's position, to avoid the corner case - // where a player can approach an obstacle by walking from slightly - // under, diagonally. First part to the walk on water bug. - if (offsetY < 16 && !mMap->getWalk(posX, posY - 1, getWalkMask())) - fy = 16; - - x = tx * 32 + fx; - y = ty * 32 + fy; - } - // Only send a new message to the server when destination changes - if (x != mDestX || y != mDestY) + if (x != mDest.x || y != mDest.y) { - mDestX = x; - mDestY = y; - Being::setDestination(x, y); - Net::getPlayerHandler()->setDestination(x, y, mDirection); + + // Manaserv: + // If the destination given to being class is accepted, + // we inform the Server. + if ((x == mDest.x && y == mDest.y) + || Net::getNetworkType() == ServerInfo::EATHENA) + Net::getPlayerHandler()->setDestination(x, y, mDirection); } mPickUpTarget = NULL; diff --git a/src/localplayer.h b/src/localplayer.h index c9f6c5b5..6279d546 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -474,8 +474,6 @@ class LocalPlayer : public Player 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 */ - int mDestX; /**< X coordinate of destination. */ - int mDestY; /**< Y coordinate of destination. */ std::vector<int> mStatusEffectIcons; @@ -27,9 +27,9 @@ * * \section Introduction Introduction * - * This is the documentation for the client of The Mana World - * (http://themanaworld.org). It is always a work in progress, with the intent - * to make it easier for new developers to grow familiar with the source code. + * This is the documentation for the Mana client (http://manasource.org). It is + * always a work in progress, with the intent to make it easier for new + * developers to grow familiar with the source code. * * \section General General information * @@ -44,11 +44,10 @@ * \link FloorItem FloorItems\endlink, they are drawn from top to bottom * by the map, interleaved with the tiles in the fringe layer. * - * The server is split up into an \link Net::AccountServer account - * server\endlink, a \link Net::ChatServer chat server\endlink and a \link - * Net::GameServer game server\endlink. There may be multiple game servers. - * Handling of incoming messages is spread over several \link MessageHandler - * MessageHanders\endlink. + * The client supports two servers, \link EAthena eAthena\endlink (the TMW + * version) and the \link ManaServ Mana server\endlink. To achieve this, the + * \link Net network communication layer\endlink is abstracted in many + * different interfaces, which have different implementations for each server. */ #ifdef HAVE_CONFIG_H diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp index 8803fafb..dbfc0f3b 100644 --- a/src/net/ea/beinghandler.cpp +++ b/src/net/ea/beinghandler.cpp @@ -25,6 +25,7 @@ #include "beingmanager.h" #include "client.h" #include "effectmanager.h" +#include "guild.h" #include "localplayer.h" #include "log.h" #include "npc.h" @@ -106,7 +107,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) int param1; int stunMode; Uint32 statusEffects; - int type; + int type, guild; Uint16 status; Being *srcBeing, *dstBeing; Player *player; @@ -179,9 +180,19 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) hairColor = msg.readInt16(); shoes = msg.readInt16(); // clothes color - "abused" as shoes gloves = msg.readInt16(); // head dir - "abused" as gloves - msg.readInt16(); // guild - msg.readInt16(); // unknown - msg.readInt16(); // unknown + guild = msg.readInt32(); // guild + if (player) + { + if (guild == 0) + { + player->clearGuilds(); + } + else + { + player->addGuild(Guild::getGuild(guild)); + } + } + msg.readInt16(); // guild emblem msg.readInt16(); // manner dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 msg.readInt8(); // karma diff --git a/src/net/ea/generalhandler.cpp b/src/net/ea/generalhandler.cpp index f7d495a6..6ca853fb 100644 --- a/src/net/ea/generalhandler.cpp +++ b/src/net/ea/generalhandler.cpp @@ -49,6 +49,7 @@ #include "net/ea/tradehandler.h" #include "net/ea/specialhandler.h" +#include "net/ea/gui/guildtab.h" #include "net/ea/gui/partytab.h" #include "net/messagein.h" @@ -68,6 +69,7 @@ namespace EAthena { ServerInfo charServer; ServerInfo mapServer; +extern Guild *eaGuild; extern Party *eaParty; GeneralHandler::GeneralHandler(): @@ -226,12 +228,14 @@ void GeneralHandler::guiWindowsLoaded() void GeneralHandler::guiWindowsUnloaded() { + socialWindow->removeTab(eaGuild); socialWindow->removeTab(eaParty); - if (partyTab) - { - delete partyTab; - partyTab = 0; - } + + delete guildTab; + guildTab = 0; + + delete partyTab; + partyTab = 0; } void GeneralHandler::clearHandlers() diff --git a/src/net/ea/gui/guildtab.cpp b/src/net/ea/gui/guildtab.cpp new file mode 100644 index 00000000..e88c289e --- /dev/null +++ b/src/net/ea/gui/guildtab.cpp @@ -0,0 +1,117 @@ +/* + * The Mana Client + * Copyright (C) 2008-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 "net/ea/gui/guildtab.h" + +#include "commandhandler.h" +#include "guild.h" +#include "localplayer.h" + +#include "gui/palette.h" + +#include "net/net.h" +#include "net/guildhandler.h" + +#include "resources/iteminfo.h" +#include "resources/itemdb.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" +#include "utils/stringutils.h" + +namespace EAthena { + +extern Guild *eaGuild; + +GuildTab::GuildTab() : + ChatTab(_("Guild")) +{ + setTabColor(&guiPalette->getColor(Palette::GUILD)); +} + +GuildTab::~GuildTab() +{ +} + +void GuildTab::handleInput(const std::string &msg) +{ + Net::getGuildHandler()->chat(eaGuild->getId(), msg); +} + +void GuildTab::showHelp() +{ + chatLog(_("/help > Display this help.")); + chatLog(_("/invite > Invite a player to your guild")); + chatLog(_("/leave > Leave the guild you are in")); + chatLog(_("/kick > Kick some one from the guild you are in")); +} + +bool GuildTab::handleCommand(const std::string &type, const std::string &args) +{ + if (type == "help") + { + if (args == "invite") + { + chatLog(_("Command: /invite <nick>")); + chatLog(_("This command invites <nick> to the guild you're in.")); + chatLog(_("If the <nick> has spaces in it, enclose it in " + "double quotes (\").")); + } + else if (args == "leave") + { + chatLog(_("Command: /leave")); + chatLog(_("This command causes the player to leave the guild.")); + } + else + return false; + } + else if (type == "create" || type == "new") + { + if (args.empty()) + chatLog(_("Guild name is missing."), BY_SERVER); + else + Net::getGuildHandler()->create(args); + } + else if (type == "invite") + { + Net::getGuildHandler()->invite(eaGuild->getId(), args); + } + else if (type == "leave") + { + Net::getGuildHandler()->leave(eaGuild->getId()); + } + else if (type == "kick") + { + Net::getGuildHandler()->kick(eaGuild->getMember(args)); + } + else + return false; + + return true; +} + +void GuildTab::getAutoCompleteList(std::vector<std::string> &names) const +{ + if (eaGuild) + eaGuild->getNames(names); +} + +} // namespace EAthena diff --git a/src/net/ea/gui/guildtab.h b/src/net/ea/gui/guildtab.h new file mode 100644 index 00000000..58c8f539 --- /dev/null +++ b/src/net/ea/gui/guildtab.h @@ -0,0 +1,52 @@ +/* + * The Mana Client + * Copyright (C) 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 EA_GUILDTAB_H +#define EA_GUILDTAB_H + +#include "gui/widgets/chattab.h" + +namespace EAthena { + +/** + * A tab for a guild chat channel. + */ +class GuildTab : public ChatTab +{ + public: + GuildTab(); + ~GuildTab(); + + void showHelp(); + + bool handleCommand(const std::string &type, const std::string &args); + + protected: + void handleInput(const std::string &msg); + + void getAutoCompleteList(std::vector<std::string> &names) const; +}; + +extern GuildTab *guildTab; + +} // namespace EAthena + +#endif // EA_GUILDTAB_H diff --git a/src/net/ea/guildhandler.cpp b/src/net/ea/guildhandler.cpp index 66576da4..bb2fdff7 100644 --- a/src/net/ea/guildhandler.cpp +++ b/src/net/ea/guildhandler.cpp @@ -20,26 +20,55 @@ #include "net/ea/guildhandler.h" +#include "guild.h" #include "localplayer.h" #include "log.h" -#include "gui/widgets/chattab.h" +#include "gui/socialwindow.h" #include "net/ea/messagein.h" #include "net/ea/protocol.h" +#include "net/ea/gui/guildtab.h" + #include "utils/gettext.h" extern Net::GuildHandler *guildHandler; namespace EAthena { +GuildTab *guildTab = 0; +Guild *eaGuild; + GuildHandler::GuildHandler() { static const Uint16 _messages[] = { SMSG_GUILD_CREATE_RESPONSE, - SMSG_GUILD_INVITE_ACK, + SMSG_GUILD_POSITION_INFO, + SMSG_GUILD_MEMBER_LOGIN, + SMSG_GUILD_MASTER_OR_MEMBER, + SMSG_GUILD_BASIC_INFO, + SMSG_GUILD_ALIANCE_INFO, + SMSG_GUILD_MEMBER_LIST, + SMSG_GUILD_POS_NAME_LIST, + SMSG_GUILD_POS_INFO_LIST, + SMSG_GUILD_POSITION_CHANGED, + SMSG_GUILD_MEMBER_POS_CHANGE, + SMSG_GUILD_EMBLEM, + SMSG_GUILD_SKILL_INFO, + SMSG_GUILD_NOTICE, SMSG_GUILD_INVITE, + SMSG_GUILD_INVITE_ACK, + SMSG_GUILD_LEAVE, + SMSG_GUILD_EXPULSION, + SMSG_GUILD_EXPULSION_LIST, + SMSG_GUILD_MESSAGE, + SMSG_GUILD_SKILL_UP, + SMSG_GUILD_REQ_ALLIANCE, + SMSG_GUILD_REQ_ALLIANCE_ACK, + SMSG_GUILD_DEL_ALLIANCE, + SMSG_GUILD_OPPOSITION_ACK, + SMSG_GUILD_BROKEN, 0 }; handledMessages = _messages; @@ -47,6 +76,12 @@ GuildHandler::GuildHandler() guildHandler = this; } +GuildHandler::~GuildHandler() +{ + delete guildTab; + guildTab = 0; +} + void GuildHandler::handleMessage(Net::MessageIn &msg) { switch (msg.getId()) @@ -73,53 +108,280 @@ void GuildHandler::handleMessage(Net::MessageIn &msg) } } break; - case SMSG_GUILD_INVITE_ACK: + + case SMSG_GUILD_POSITION_INFO: { - int flag = msg.readInt8(); + int guildId = msg.readInt32(); + int emblem = msg.readInt32(); + int posMode = msg.readInt32(); + msg.readInt32(); // Unused + msg.readInt8(); // Unused + std::string guildName = msg.readString(24); - if (flag == 0) + logger->log("Guild position info: %d %d %d %s\n", guildId, + emblem, posMode, guildName.c_str()); + } + break; + + case SMSG_GUILD_MEMBER_LOGIN: + msg.readInt32(); // Account ID + msg.readInt32(); // Char ID + msg.readInt32(); // Flag + break; + + case SMSG_GUILD_MASTER_OR_MEMBER: + msg.readInt32(); // Type (0x57 for member, 0xd7 for master) + break; + + case SMSG_GUILD_BASIC_INFO: + { + int guildID = msg.readInt32(); // Guild ID + msg.readInt32(); // Guild level + msg.readInt32(); // 'Connect member' (number online?) + msg.readInt32(); // 'Max member' + msg.readInt32(); // Average level + msg.readInt32(); // Exp + msg.readInt32(); // Next exp + msg.skip(16); // unused + std::string name = msg.readString(24); // Name + msg.readString(24); // Master's name + msg.readString(20); // Castles (ie: "Six Castles" or "None Taken") + + Guild *g = Guild::getGuild(guildID); + g->setName(name); + } + break; + + case SMSG_GUILD_ALIANCE_INFO: + { + int length = msg.readInt16(); + int count = (length - 4) / 32; + + for (int i = 0; i < count; i++) { - // Fail (already in guild, busy, etc) + msg.readInt32(); // 'Opposition' + msg.readInt32(); // Other guild ID + msg.readString(24); // Other guild name } - else if (flag == 1) + } + break; + + case SMSG_GUILD_MEMBER_LIST: + { + int length = msg.readInt16(); + int count = (length - 4) / 104; + + eaGuild->clearMembers(); + + for (int i = 0; i < count; i++) { - // Rejected + int id = msg.readInt32(); // Account ID + msg.readInt32(); // Char ID + msg.readInt16(); // Hair + msg.readInt16(); // Hair color + msg.readInt16(); // Gender + msg.readInt16(); // Class + msg.readInt16(); // Level + msg.readInt32(); // Exp + int online = msg.readInt32(); // Online + msg.readInt32(); // Position + msg.skip(50); // unused + std::string name = msg.readString(24); // Name + + GuildMember *m = eaGuild->addMember(id, name); + m->setOnline(online); } - else if (flag == 2) + } + break; + + case SMSG_GUILD_POS_NAME_LIST: + { + int length = msg.readInt16(); + int count = (length - 4) / 28; + + for (int i = 0; i < count; i++) { - // Accepted + msg.readInt32(); // ID + msg.readString(24); // Position name } - else if (flag == 3) + } + break; + + case SMSG_GUILD_POS_INFO_LIST: + { + int length = msg.readInt16(); + int count = (length - 4) / 16; + + for (int i = 0; i < count; i++) { - // Guild full + msg.readInt32(); // ID + msg.readInt32(); // Mode + msg.readInt32(); // Same ID + msg.readInt32(); // Exp mode } } break; + case SMSG_GUILD_POSITION_CHANGED: + msg.readInt16(); // Always 44 + msg.readInt32(); // ID + msg.readInt32(); // Mode + msg.readInt32(); // Same ID + msg.readInt32(); // Exp mode + msg.readString(24); // Name + break; + + case SMSG_GUILD_MEMBER_POS_CHANGE: + msg.readInt16(); // Always 16 + msg.readInt32(); // Account ID + msg.readInt32(); // Char ID + msg.readInt32(); // Position + break; + + case SMSG_GUILD_EMBLEM: + { + int length = msg.readInt16(); + + msg.readInt32(); // Guild ID + msg.readInt32(); // Emblem ID + msg.skip(length - 12); // Emblem data (unknown format) + } + break; + + case SMSG_GUILD_SKILL_INFO: + { + int length = msg.readInt16(); + int count = (length - 6) / 37; + + msg.readInt16(); // 'Skill point' + + for (int i = 0; i < count; i++) + { + msg.readInt16(); // ID + msg.readInt16(); // 'Info' (unknown atm) + msg.readInt16(); // unused + msg.readInt16(); // Level + msg.readInt16(); // SP + msg.readInt16(); // 'Range' + msg.skip(24); // unused + msg.readInt8(); // Can be increased + } + } + break; + + case SMSG_GUILD_NOTICE: + msg.readString(60); // Mes1 + msg.readString(120); // Mes2 + break; + case SMSG_GUILD_INVITE: { int guildId = msg.readInt32(); std::string guildName = msg.readString(24); - printf("Guild invite for %d (%s)\n", guildId, guildName.c_str()); + socialWindow->showGuildInvite(guildName, guildId, ""); + } + break; + + case SMSG_GUILD_INVITE_ACK: + { + int flag = msg.readInt8(); + + switch (flag) + { + case 0: + guildTab->chatLog(_("Could not inivte user to guild."), + BY_SERVER); + break; + + case 1: + guildTab->chatLog(_("User rejected guild invite."), + BY_SERVER); + break; + + case 2: + guildTab->chatLog(_("User is now part of your guild."), + BY_SERVER); + break; + + case 3: + guildTab->chatLog(_("Your guild is full."), + BY_SERVER); + break; - // TODO + default: + guildTab->chatLog(_("Unknown guild invite response."), + BY_SERVER); + break; + } } break; - case SMSG_GUILD_POSITION_INFO: + case SMSG_GUILD_LEAVE: + msg.readString(24); // Name + msg.readString(40); // Message + break; + + case SMSG_GUILD_EXPULSION: + msg.readString(24); // Name (of expulsed?) + msg.readString(40); // Message + msg.skip(24); // unused ("dummy") + break; + + case SMSG_GUILD_EXPULSION_LIST: { - int guildId = msg.readInt32(); - int emblem = msg.readInt32(); - int posMode = msg.readInt32(); - msg.readInt32(); // Unused - msg.readInt8(); // Unused - std::string guildName = msg.readString(24); + int length = msg.readInt16(); + int count = (length - 4) / 88; - logger->log("Guild position info: %d %d %d %s\n", guildId, - emblem, posMode, guildName.c_str()); + for (int i = 0; i < count; i++) + { + msg.readString(24); // Name (of expulsed?) + msg.readString(24); // 'Acc' (name of expulser?) + msg.readString(24); // Message + } + } + break; + + case SMSG_GUILD_MESSAGE: + { + int msgLength = msg.readInt16() - 4; + if (msgLength <= 0) + { + return; + } + guildTab->chatLog(msg.readString(msgLength)); } break; + + case SMSG_GUILD_SKILL_UP: + msg.readInt16(); // Skill ID + msg.readInt16(); // Level + msg.readInt16(); // SP + msg.readInt16(); // 'Range' + msg.readInt8(); // unused? (always 1) + break; + + case SMSG_GUILD_REQ_ALLIANCE: + msg.readInt32(); // Account ID + msg.readString(24); // Name + break; + + case SMSG_GUILD_REQ_ALLIANCE_ACK: + msg.readInt32(); // Flag + break; + + case SMSG_GUILD_DEL_ALLIANCE: + msg.readInt32(); // Guild ID + msg.readInt32(); // Flag + break; + + case SMSG_GUILD_OPPOSITION_ACK: + msg.readInt8(); // Flag + break; + + case SMSG_GUILD_BROKEN: + msg.readInt32(); // Flag + break; } } @@ -136,7 +398,7 @@ void GuildHandler::create(const std::string &name) void GuildHandler::invite(int guildId, const std::string &name) { - // TODO + // TODO? } void GuildHandler::invite(int guildId, Player *player) @@ -165,13 +427,13 @@ void GuildHandler::leave(int guildId) msg.writeString("", 30); // Message } -void GuildHandler::kick(GuildMember member) +void GuildHandler::kick(GuildMember *member, std::string reason) { MessageOut msg(CMSG_GUILD_EXPULSION); - msg.writeInt32(member.getGuild()->getId()); - msg.writeInt32(member.getID()); // Account ID + msg.writeInt32(member->getGuild()->getId()); + msg.writeInt32(member->getID()); // Account ID msg.writeInt32(0); // Char ID - msg.writeString("", 40); // Message + msg.writeString(reason, 40); // Message } void GuildHandler::chat(int guildId, const std::string &text) @@ -183,10 +445,18 @@ void GuildHandler::chat(int guildId, const std::string &text) void GuildHandler::memberList(int guildId) { - // TODO + // TODO four types of info requests: + // 0 = basic info + alliance info + // 1 = position name list + member list + // 2 = position name list + position info list + // 3 = skill info + // 4 = expulsion list + + MessageOut msg(CMSG_GUILD_REQUEST_INFO); + msg.writeInt32(1); // Request member list } -void GuildHandler::changeMemberPostion(GuildMember member, int level) +void GuildHandler::changeMemberPostion(GuildMember *member, int level) { // TODO } diff --git a/src/net/ea/guildhandler.h b/src/net/ea/guildhandler.h index 8b1753c7..df43a2a1 100644 --- a/src/net/ea/guildhandler.h +++ b/src/net/ea/guildhandler.h @@ -32,6 +32,8 @@ class GuildHandler : public Net::GuildHandler, public MessageHandler public: GuildHandler(); + ~GuildHandler(); + void handleMessage(Net::MessageIn &msg); void create(const std::string &name); @@ -44,13 +46,13 @@ class GuildHandler : public Net::GuildHandler, public MessageHandler void leave(int guildId); - void kick(GuildMember member); + void kick(GuildMember *member, std::string reason = ""); void chat(int guildId, const std::string &text); void memberList(int guildId); - void changeMemberPostion(GuildMember member, int level); + void changeMemberPostion(GuildMember *member, int level); void requestAlliance(int guildId, int otherGuildId); diff --git a/src/net/ea/inventoryhandler.cpp b/src/net/ea/inventoryhandler.cpp index 1a0e296c..decd4c2a 100644 --- a/src/net/ea/inventoryhandler.cpp +++ b/src/net/ea/inventoryhandler.cpp @@ -281,8 +281,8 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) * packets that update storage contents. */ player_node->setInStorage(true); - msg.readInt16(); // Storage capacity msg.readInt16(); // Used count + msg.readInt16(); // Storage capacity break; case SMSG_PLAYER_STORAGE_ADD: diff --git a/src/net/ea/partyhandler.cpp b/src/net/ea/partyhandler.cpp index 157898dc..3e12e4b4 100644 --- a/src/net/ea/partyhandler.cpp +++ b/src/net/ea/partyhandler.cpp @@ -68,11 +68,8 @@ PartyHandler::PartyHandler(): PartyHandler::~PartyHandler() { - if (partyTab) - { - delete partyTab; - partyTab = 0; - } + delete partyTab; + partyTab = 0; } void PartyHandler::handleMessage(Net::MessageIn &msg) @@ -104,10 +101,9 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) bool leader = msg.readInt8() == 0; bool online = msg.readInt8() == 0; - PartyMember *member = new PartyMember(PARTY_ID, id, nick); + PartyMember *member = eaParty->addMember(id, nick); member->setLeader(leader); member->setOnline(online); - eaParty->addMember(member); } } break; diff --git a/src/net/guildhandler.h b/src/net/guildhandler.h index 85b4cc8a..75683944 100644 --- a/src/net/guildhandler.h +++ b/src/net/guildhandler.h @@ -42,13 +42,13 @@ class GuildHandler virtual void leave(int guildId) = 0; - virtual void kick(GuildMember member) = 0; + virtual void kick(GuildMember *member, std::string reason = "") = 0; virtual void chat(int guildId, const std::string &text) = 0; virtual void memberList(int guildId) = 0; - virtual void changeMemberPostion(GuildMember member, int level) = 0; + virtual void changeMemberPostion(GuildMember *member, int level) = 0; virtual void requestAlliance(int guildId, int otherGuildId) = 0; diff --git a/src/net/manaserv/guildhandler.cpp b/src/net/manaserv/guildhandler.cpp index 0dfe8cde..253efb01 100644 --- a/src/net/manaserv/guildhandler.cpp +++ b/src/net/manaserv/guildhandler.cpp @@ -131,9 +131,8 @@ void GuildHandler::handleMessage(Net::MessageIn &msg) online = msg.readInt8(); if (name != "") { - member = new GuildMember(guildId, name); + member = guild->addMember(name); member->setOnline(online); - guild->addMember(member); } } } @@ -153,9 +152,8 @@ void GuildHandler::handleMessage(Net::MessageIn &msg) switch(eventId) { case GUILD_EVENT_NEW_PLAYER: - member = new GuildMember(guildId, name); + member = guild->addMember(name); member->setOnline(true); - guild->addMember(member); break; case GUILD_EVENT_LEAVING_PLAYER: @@ -296,7 +294,7 @@ void GuildHandler::leave(int guildId) chatServerConnection->send(msg); } -void GuildHandler::kick(GuildMember member) +void GuildHandler::kick(GuildMember *member, std::string reason) { // TODO } @@ -313,7 +311,7 @@ void GuildHandler::memberList(int guildId) chatServerConnection->send(msg); } -void GuildHandler::changeMemberPostion(GuildMember member, int level) +void GuildHandler::changeMemberPostion(GuildMember *member, int level) { /*MessageOut msg(PCMSG_GUILD_PROMOTE_MEMBER); msg.writeInt16(guildId); diff --git a/src/net/manaserv/guildhandler.h b/src/net/manaserv/guildhandler.h index 8fdd40a4..1b6d51b5 100644 --- a/src/net/manaserv/guildhandler.h +++ b/src/net/manaserv/guildhandler.h @@ -45,13 +45,13 @@ public: void leave(int guildId); - void kick(GuildMember member); + void kick(GuildMember *member, std::string reason = ""); void chat(int guildId, const std::string &text); void memberList(int guildId); - void changeMemberPostion(GuildMember member, int level); + void changeMemberPostion(GuildMember *member, int level); void requestAlliance(int guildId, int otherGuildId); diff --git a/src/net/manaserv/partyhandler.cpp b/src/net/manaserv/partyhandler.cpp index 9ec8d2b8..ec153fa8 100644 --- a/src/net/manaserv/partyhandler.cpp +++ b/src/net/manaserv/partyhandler.cpp @@ -109,8 +109,7 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) if (id == player_node->getId()) player_node->setParty(mParty); - PartyMember *member = new PartyMember(PARTY_ID, id, name); - mParty->addMember(member); + mParty->addMember(id, name); } break; case CPMSG_PARTY_MEMBER_LEFT: diff --git a/src/net/net.h b/src/net/net.h index f0539b29..9d9ee10e 100644 --- a/src/net/net.h +++ b/src/net/net.h @@ -23,7 +23,11 @@ #define NET_H /** - * \defgroup Network Core network layer + * \namespace Net + * + * The network communication layer. It is composed of a host of interfaces that + * interact with different aspects of the game. They have different + * implementations depending on the type of server the client is connecting to. */ #include "net/serverinfo.h" diff --git a/src/party.cpp b/src/party.cpp index a8e18b2d..3987f0fb 100644 --- a/src/party.cpp +++ b/src/party.cpp @@ -23,32 +23,19 @@ #include "beingmanager.h" #include "player.h" -PartyMember::PartyMember(int partyId, int id, const std::string &name): - Avatar(name), mId(id), mLeader(false) +PartyMember::PartyMember(Party *party, int id, const std::string &name): + Avatar(name), mId(id), mParty(party), mLeader(false) { - mParty = Party::getParty(partyId); - - if (beingManager) - { - Player *player = dynamic_cast<Player*>(beingManager->findBeing(id)); - if (player) - { - player->setParty(mParty); - } - } } -PartyMember::PartyMember(int PartyId, int id): - mId(id), mLeader(false) +PartyMember::PartyMember(Party *party, int id): + mId(id), mParty(party), mLeader(false) { - mParty = Party::getParty(PartyId); +} - if (beingManager) - { - Player *player = dynamic_cast<Player*>(beingManager->findBeing(id)); - if (player) - player->setParty(mParty); - } +PartyMember::PartyMember(Party *party, const std::string &name): + Avatar(name), mParty(party), mLeader(false) +{ } Party::PartyMap Party::parties; @@ -59,19 +46,49 @@ Party::Party(short id): { parties[id] = this; } +PartyMember *Party::addMember(int id, const std::string &name) +{ + PartyMember *m; + if ((m = getMember(id))) + { + return m; + } + + m = new PartyMember(this, id, name); -void Party::addMember(PartyMember *member) + mMembers.push_back(m); + + return m; +} + +PartyMember *Party::addMember(int id) { - if (member->mParty > 0 && member->mParty != this) + PartyMember *m; + if ((m = getMember(id))) { - throw "Member in another Party!"; + return m; } - if (!isMember(member)) + m = new PartyMember(this, id); + + mMembers.push_back(m); + + return m; +} + +PartyMember *Party::addMember(const std::string &name) +{ + PartyMember *m; + if ((m = getMember(name))) { - mMembers.push_back(member); - member->mParty = this; + return m; } + + m = new PartyMember(this, name); + + mMembers.push_back(m); + + return m; } PartyMember *Party::getMember(int id) diff --git a/src/party.h b/src/party.h index e109d7b6..e723cf37 100644 --- a/src/party.h +++ b/src/party.h @@ -34,12 +34,6 @@ class Party; class PartyMember : public Avatar { public: - PartyMember(int partyId, int id, const std::string &name); - - PartyMember(int partyId, int id); - - PartyMember(int partyId, const std::string &name); - int getID() const { return mId; } void setID(int id) { mId = id; } @@ -53,6 +47,12 @@ public: protected: friend class Party; + PartyMember(Party *party, int id, const std::string &name); + + PartyMember(Party *party, int id); + + PartyMember(Party *party, const std::string &name); + int mId; Party *mParty; bool mLeader; @@ -73,7 +73,17 @@ public: /** * Adds member to the list. */ - void addMember(PartyMember *member); + PartyMember *addMember(int id, const std::string &name); + + /** + * Adds member to the list. + */ + PartyMember *addMember(int id); + + /** + * Adds member to the list. + */ + PartyMember *addMember(const std::string &name); /** * Find a member by ID. diff --git a/src/player.cpp b/src/player.cpp index 5eb0163f..4fc5d523 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -220,6 +220,7 @@ void Player::setSpriteColor(unsigned int slot, const std::string &color) void Player::addGuild(Guild *guild) { mGuilds[guild->getId()] = guild; + guild->addMember(mId, mName); if (this == player_node && socialWindow) { @@ -234,6 +235,7 @@ void Player::removeGuild(int id) socialWindow->removeTab(mGuilds[id]); } + mGuilds[id]->removeMember(mId); mGuilds.erase(id); } @@ -264,6 +266,27 @@ Guild *Player::getGuild(int id) const 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) @@ -272,6 +295,16 @@ void Player::setParty(Party *party) Party *old = mParty; mParty = party; + if (old) + { + party->removeMember(mId); + } + + if (party) + { + party->addMember(mId, mName); + } + updateColors(); if (this == player_node && socialWindow) diff --git a/src/player.h b/src/player.h index 170bcb72..670f6d84 100644 --- a/src/player.h +++ b/src/player.h @@ -105,6 +105,16 @@ class Player : public Being 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(); } |