summaryrefslogtreecommitdiff
path: root/src/net/manaserv/playerhandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/manaserv/playerhandler.cpp')
-rw-r--r--src/net/manaserv/playerhandler.cpp440
1 files changed, 440 insertions, 0 deletions
diff --git a/src/net/manaserv/playerhandler.cpp b/src/net/manaserv/playerhandler.cpp
new file mode 100644
index 000000000..3af82486c
--- /dev/null
+++ b/src/net/manaserv/playerhandler.cpp
@@ -0,0 +1,440 @@
+/*
+ * 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 "net/manaserv/playerhandler.h"
+#include "net/manaserv/beinghandler.h"
+
+#include "client.h"
+#include "effectmanager.h"
+#include "game.h"
+#include "localplayer.h"
+#include "log.h"
+#include "particle.h"
+#include "playerinfo.h"
+#include "configuration.h"
+
+#include "gui/chat.h"
+#include "gui/gui.h"
+#include "gui/okdialog.h"
+#include "gui/viewport.h"
+
+#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"
+#include "net/manaserv/attributes.h"
+
+/**
+ * Max. distance we are willing to scroll after a teleport;
+ * everything beyond will reset the port hard.
+ * 32 is the nominal tile width/height.
+ * @todo: Make this parameter read from config.
+ */
+static const int MAP_TELEPORT_SCROLL_DISTANCE = 8 * 32;
+
+extern Net::PlayerHandler *playerHandler;
+
+namespace ManaServ
+{
+
+void RespawnRequestListener::action(const gcn::ActionEvent &event _UNUSED_)
+{
+ Net::getPlayerHandler()->respawn();
+
+ ManaServ::NpcHandler *handler =
+ static_cast<ManaServ::NpcHandler*>(Net::getNpcHandler());
+ handler->clearDialogs();
+}
+
+extern Connection *gameServerConnection;
+
+PlayerHandler::PlayerHandler()
+{
+ static const Uint16 _messages[] =
+ {
+ GPMSG_PLAYER_MAP_CHANGE,
+ GPMSG_PLAYER_SERVER_CHANGE,
+ GPMSG_PLAYER_ATTRIBUTE_CHANGE,
+ GPMSG_PLAYER_EXP_CHANGE,
+ GPMSG_LEVELUP,
+ GPMSG_LEVEL_PROGRESS,
+ GPMSG_RAISE_ATTRIBUTE_RESPONSE,
+ GPMSG_LOWER_ATTRIBUTE_RESPONSE,
+ GPMSG_SPECIAL_STATUS,
+ 0
+ };
+ handledMessages = _messages;
+ playerHandler = this;
+}
+
+void PlayerHandler::handleMessage(Net::MessageIn &msg)
+{
+ switch (msg.getId())
+ {
+ case GPMSG_PLAYER_MAP_CHANGE:
+ handleMapChangeMessage(msg);
+ break;
+
+ case GPMSG_PLAYER_SERVER_CHANGE:
+ { // TODO: Implement reconnecting to another game server
+ std::string token = msg.readString(32);
+ std::string address = msg.readString();
+ int port = msg.readInt16();
+ logger->log("Changing server to %s:%d", address.c_str(), port);
+ } break;
+
+ case GPMSG_PLAYER_ATTRIBUTE_CHANGE:
+ {
+ logger->log1("ATTRIBUTE UPDATE:");
+ while (msg.getUnreadLength())
+ {
+ int attrId = msg.readInt16();
+ double base = msg.readInt32() / 256.0;
+ double value = msg.readInt32() / 256.0;
+
+ // Set the core player attribute the stat
+ // depending on attribute link.
+ int playerInfoId =
+ Attributes::getPlayerInfoIdFromAttrId(attrId);
+ if (playerInfoId > -1)
+ {
+ PlayerInfo::setAttribute(playerInfoId, value);
+ }
+ else
+ {
+ PlayerInfo::setStatBase(attrId, base);
+ PlayerInfo::setStatMod(attrId, value - base);
+ }
+ }
+ } break;
+
+ case GPMSG_PLAYER_EXP_CHANGE:
+ {
+ logger->log1("EXP Update");
+ while (msg.getUnreadLength())
+ {
+ int skill = msg.readInt16();
+ int current = msg.readInt32();
+ int next = msg.readInt32();
+
+ PlayerInfo::setStatExperience(skill, current, next);
+ }
+ } break;
+
+ case GPMSG_LEVELUP:
+ {
+ PlayerInfo::setAttribute(LEVEL, msg.readInt16());
+ PlayerInfo::setAttribute(CHAR_POINTS, msg.readInt16());
+ PlayerInfo::setAttribute(CORR_POINTS, msg.readInt16());
+ Particle* effect = particleEngine->addEffect(
+ paths.getStringValue("particles")
+ + paths.getStringValue("levelUpEffectFile")
+ , 0, 0);
+ player_node->controlParticle(effect);
+ } break;
+
+
+ case GPMSG_LEVEL_PROGRESS:
+ {
+ PlayerInfo::setAttribute(EXP, msg.readInt8());
+ } break;
+
+
+ case GPMSG_RAISE_ATTRIBUTE_RESPONSE:
+ {
+ int errCode = msg.readInt8();
+ int attrNum = msg.readInt16();
+ switch (errCode)
+ {
+ case ATTRIBMOD_OK:
+ {
+ // feel(acknowledgment);
+ } break;
+ case ATTRIBMOD_INVALID_ATTRIBUTE:
+ {
+ logger->log("Warning: Server denied increase of attribute"
+ " %d (unknown attribute) ", attrNum);
+ } break;
+ case ATTRIBMOD_NO_POINTS_LEFT:
+ {
+ // when the server says "you got no points" it
+ // 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 = 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 = PlayerInfo::getAttribute(CHAR_POINTS) - 1;
+ PlayerInfo::setAttribute(CHAR_POINTS, points);
+
+ int attrValue = PlayerInfo::getStatBase(attrNum) - 1;
+ PlayerInfo::setStatBase(attrNum, attrValue);
+ } break;
+ default:
+ break;
+ }
+ } break;
+
+ case GPMSG_LOWER_ATTRIBUTE_RESPONSE:
+ {
+ int errCode = msg.readInt8();
+ int attrNum = msg.readInt16();
+ switch (errCode)
+ {
+ case ATTRIBMOD_OK:
+ {
+ // feel(acknowledgment);
+ } break;
+ case ATTRIBMOD_INVALID_ATTRIBUTE:
+ {
+ logger->log("Warning: Server denied reduction of attribute"
+ " %d (unknown attribute) ", attrNum);
+ } break;
+ case ATTRIBMOD_NO_POINTS_LEFT:
+ {
+ // when the server says "you got no points" it
+ // 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 = PlayerInfo::getStatBase(attrNum) + 1;
+ PlayerInfo::setAttribute(CHAR_POINTS, 0);
+ PlayerInfo::setAttribute(CORR_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 = 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;
+ default:
+ break;
+ }
+
+ } break;
+
+ case GPMSG_SPECIAL_STATUS :
+ {
+ while (msg.getUnreadLength())
+ {
+ // { B specialID, L current, L max, L recharge }
+ int id = msg.readInt8();
+ int current = msg.readInt32();
+ int max = msg.readInt32();
+ int recharge = msg.readInt32();
+ PlayerInfo::setSpecialStatus(id, current, max, recharge);
+ }
+ } break;
+ /*
+ case SMSG_PLAYER_ARROW_MESSAGE:
+ {
+ Sint16 type = msg.readInt16();
+
+ switch (type)
+ {
+ case 0:
+ localChatTab->chatLog(_("Equip arrows first."),
+ BY_SERVER);
+ break;
+ default:
+ logger->log("0x013b: Unhandled message %i", type);
+ break;
+ }
+ }
+ break;
+ */
+ default:
+ break;
+ }
+}
+
+void PlayerHandler::handleMapChangeMessage(Net::MessageIn &msg)
+{
+ const std::string mapName = msg.readString();
+ const unsigned short x = msg.readInt16();
+ const unsigned short y = msg.readInt16();
+
+ Game *game = Game::instance();
+ const bool sameMap = (game->getCurrentMapName() == mapName);
+
+ logger->log("Changing map to %s (%d, %d)", mapName.c_str(), x, y);
+
+ // Switch the actual map, deleting the previous one
+ game->changeMap(mapName);
+
+ const Vector &playerPos = player_node->getPosition();
+ float scrollOffsetX = 0.0f;
+ float scrollOffsetY = 0.0f;
+
+ /* Scroll if neccessary */
+ if (!sameMap
+ || (abs(x - (int) playerPos.x) > MAP_TELEPORT_SCROLL_DISTANCE)
+ || (abs(y - (int) playerPos.y) > MAP_TELEPORT_SCROLL_DISTANCE))
+ {
+ scrollOffsetX = x - (int) playerPos.x;
+ scrollOffsetY = y - (int) playerPos.y;
+ }
+
+ player_node->setAction(Being::STAND);
+ player_node->setPosition(x, y);
+ player_node->setDestination(x, y);
+
+ logger->log("Adjust scrolling by %d,%d", (int) scrollOffsetX,
+ (int) scrollOffsetY);
+ viewport->scrollBy(scrollOffsetX, scrollOffsetY);
+}
+
+void PlayerHandler::attack(int id, bool keep _UNUSED_)
+{
+ MessageOut msg(PGMSG_ATTACK);
+ msg.writeInt16(id);
+ gameServerConnection->send(msg);
+}
+
+void PlayerHandler::stopAttack()
+{
+
+}
+
+void PlayerHandler::emote(int emoteId _UNUSED_)
+{
+ // TODO
+}
+
+void PlayerHandler::increaseAttribute(int attr)
+{
+ MessageOut msg(PGMSG_RAISE_ATTRIBUTE);
+ msg.writeInt16(attr);
+ gameServerConnection->send(msg);
+}
+
+void PlayerHandler::decreaseAttribute(int attr)
+{
+ MessageOut msg(PGMSG_LOWER_ATTRIBUTE);
+ msg.writeInt16(attr);
+ gameServerConnection->send(msg);
+}
+
+void PlayerHandler::increaseSkill(int skillId _UNUSED_)
+{
+ // Not used atm
+}
+
+void PlayerHandler::pickUp(FloorItem *floorItem)
+{
+ 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)
+{
+ MessageOut msg(PGMSG_DIRECTION_CHANGE);
+ msg.writeInt8(direction);
+ gameServerConnection->send(msg);
+}
+
+void PlayerHandler::setDestination(int x, int y, int /* direction */)
+{
+ MessageOut msg(PGMSG_WALK);
+ msg.writeInt16(x);
+ msg.writeInt16(y);
+ gameServerConnection->send(msg);
+}
+
+void PlayerHandler::changeAction(Being::Action action)
+{
+ player_node->setAction(action);
+
+ MessageOut msg(PGMSG_ACTION_CHANGE);
+ msg.writeInt8(action);
+ gameServerConnection->send(msg);
+}
+
+void PlayerHandler::respawn()
+{
+ MessageOut msg(PGMSG_RESPAWN);
+ gameServerConnection->send(msg);
+}
+
+void PlayerHandler::ignorePlayer(const std::string &player _UNUSED_,
+ bool ignore _UNUSED_)
+{
+ // TODO
+}
+
+void PlayerHandler::ignoreAll(bool ignore _UNUSED_)
+{
+ // TODO
+}
+
+bool PlayerHandler::canUseMagic()
+{
+ return true;
+}
+
+bool PlayerHandler::canCorrectAttributes()
+{
+ return true;
+}
+
+int PlayerHandler::getJobLocation()
+{
+ return -1;
+}
+
+Vector PlayerHandler::getDefaultWalkSpeed()
+{
+ // Return translation in pixels per ticks.
+ return ManaServ::BeingHandler::giveSpeedInPixelsPerTicks(6.0f);
+}
+
+} // namespace ManaServ