diff options
author | Bjørn Lindeijer <bjorn@lindeijer.nl> | 2009-03-22 19:45:03 +0100 |
---|---|---|
committer | Bjørn Lindeijer <bjorn@lindeijer.nl> | 2009-03-22 19:45:56 +0100 |
commit | 0c43d04b438d41c277ae80402d4b4888db1a0b64 (patch) | |
tree | 3aaeb75ecd1bcbe85decedab5f1fa426fe0411e3 /src/net/playerhandler.cpp | |
parent | a7f5eaeb7f643658d356533a608f0f18d85b6d32 (diff) | |
parent | 401802c1d7a1b3d659bdc53a45d9a6292fc1121e (diff) | |
download | mana-0c43d04b438d41c277ae80402d4b4888db1a0b64.tar.gz mana-0c43d04b438d41c277ae80402d4b4888db1a0b64.tar.bz2 mana-0c43d04b438d41c277ae80402d4b4888db1a0b64.tar.xz mana-0c43d04b438d41c277ae80402d4b4888db1a0b64.zip |
Merged the tmwserv client with the eAthena client
This merge involved major changes on both sides, and as such took
several weeks. Lots of things are expected to be broken now, however, we
now have a single code base to improve and extend, which can be compiled
to support either eAthena or tmwserv.
In the coming months, the plan is to work towards a client that supports
both eAthena and tmwserv, without needing to be recompiled.
Conflicts:
Everywhere!
Diffstat (limited to 'src/net/playerhandler.cpp')
-rw-r--r-- | src/net/playerhandler.cpp | 482 |
1 files changed, 196 insertions, 286 deletions
diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index fc3506fb..b4e2f328 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -1,33 +1,34 @@ /* * The Mana World - * Copyright (C) 2004 The Mana World Development Team + * Copyright 2004 The Mana World Development Team * * This file is part of The Mana World. * - * This program is free software; you can redistribute it and/or modify + * The Mana World 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, + * The Mana World 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 + * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "messagein.h" #include "playerhandler.h" + +#include "messagein.h" #include "protocol.h" #include "../engine.h" #include "../localplayer.h" #include "../log.h" +#include "../particle.h" #include "../npc.h" -#include "../units.h" #include "../gui/buy.h" #include "../gui/chat.h" @@ -39,9 +40,6 @@ #include "../gui/skill.h" #include "../gui/viewport.h" -#include "../utils/stringutils.h" -#include "../utils/gettext.h" - // TODO Move somewhere else OkDialog *weightNotice = NULL; OkDialog *deathNotice = NULL; @@ -52,9 +50,10 @@ extern BuyDialog *buyDialog; extern SellDialog *sellDialog; extern Window *buySellDialog; -// Max. distance we are willing to scroll after a teleport; -// everything beyond will reset the port hard. -static const int MAP_TELEPORT_SCROLL_DISTANCE = 8; +/* Max. distance we are willing to scroll after a teleport; + * everything beyond will reset the port hard. + */ +static const int MAP_TELEPORT_SCROLL_DISTANCE = 8 * 32; /** * Listener used for handling the overweigth message. @@ -86,7 +85,7 @@ namespace { buyDialog->setVisible(false); sellDialog->setVisible(false); buySellDialog->setVisible(false); - if (current_npc) current_npc->handleDeath(); + current_npc = 0; } } deathListener; } @@ -94,317 +93,192 @@ namespace { PlayerHandler::PlayerHandler() { static const Uint16 _messages[] = { - SMSG_WALK_RESPONSE, - SMSG_PLAYER_WARP, - SMSG_PLAYER_STAT_UPDATE_1, - SMSG_PLAYER_STAT_UPDATE_2, - SMSG_PLAYER_STAT_UPDATE_3, - SMSG_PLAYER_STAT_UPDATE_4, - SMSG_PLAYER_STAT_UPDATE_5, - SMSG_PLAYER_STAT_UPDATE_6, - SMSG_PLAYER_ARROW_MESSAGE, + 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, 0 }; handledMessages = _messages; } -void PlayerHandler::handleMessage(MessageIn *msg) +void PlayerHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { - case SMSG_WALK_RESPONSE: - /* - * This client assumes that all walk messages succeed, - * and that the server will send a correction notice - * otherwise. - */ + case GPMSG_PLAYER_MAP_CHANGE: + handleMapChangeMessage(msg); break; - case SMSG_PLAYER_WARP: - { - std::string mapPath = msg->readString(16); - bool nearby; - Uint16 x = msg->readInt16(); - Uint16 y = msg->readInt16(); - - logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y); - - /* - * We must clear the local player's target *before* the call - * to changeMap, as it deletes all beings. - */ - player_node->stopAttack(); - - nearby = (engine->getCurrentMapName() == mapPath); - - // Switch the actual map, deleting the previous one if necessary - engine->changeMap(mapPath); + 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; - if (current_npc) current_npc->handleDeath(); - - float scrollOffsetX = 0.0f; - float scrollOffsetY = 0.0f; + case GPMSG_PLAYER_ATTRIBUTE_CHANGE: + { + logger->log("ATTRIBUTE UPDATE:"); + while (msg.getUnreadLength()) + { + int stat = msg.readInt8(); + int base = msg.readInt16(); + int value = msg.readInt16(); + logger->log("%d set to %d %d", stat, base, value); - /* Scroll if neccessary */ - if (!nearby - || (abs(x - player_node->mX) > MAP_TELEPORT_SCROLL_DISTANCE) - || (abs(y - player_node->mY) > MAP_TELEPORT_SCROLL_DISTANCE)) + if (stat == BASE_ATTR_HP) { - scrollOffsetX = (x - player_node->mX) * 32; - scrollOffsetY = (y - player_node->mY) * 32; + player_node->setMaxHp(base); + player_node->setHp(value); } + else if (stat < NB_CHARACTER_ATTRIBUTES) + { + if (stat >= CHAR_SKILL_BEGIN && stat < CHAR_SKILL_END + && player_node->getAttributeBase(stat) < base + && player_node->getAttributeBase(stat) > -1) + { + Particle* effect = particleEngine->addEffect("graphics/particles/skillup.particle.xml", 0, 0); + player_node->controlParticle(effect); + } - player_node->setAction(Being::STAND); - player_node->mFrame = 0; - player_node->mX = x; - player_node->mY = y; - - logger->log("Adjust scrolling by %d:%d", - (int)scrollOffsetX, - (int)scrollOffsetY); - - viewport->scrollBy(scrollOffsetX, scrollOffsetY); + player_node->setAttributeBase(stat, base); + player_node->setAttributeEffective(stat, value); + } + else + { + logger->log("Warning: server wants to update unknown " + "attribute %d to %d", stat, value); + } } - break; + } break; - case SMSG_PLAYER_STAT_UPDATE_1: + case GPMSG_PLAYER_EXP_CHANGE: + { + logger->log("EXP Update"); + while (msg.getUnreadLength()) { - Sint16 type = msg->readInt16(); - Uint32 value = msg->readInt32(); + int skill = msg.readInt8(); + int current = msg.readInt32(); + int next = msg.readInt32(); - switch (type) + if (skill < CHAR_SKILL_NB) { - //case 0x0000: - // player_node->setWalkSpeed(msg->readInt32()); - // break; - case 0x0005: player_node->mHp = value; break; - case 0x0006: player_node->mMaxHp = value; break; - case 0x0007: player_node->mMp = value; break; - case 0x0008: player_node->mMaxMp = value; break; - case 0x0009: - player_node->mStatsPointsToAttribute = value; - break; - case 0x000b: player_node->mLevel = value; break; - case 0x000c: - player_node->mSkillPoint = value; - skillDialog->update(); - break; - case 0x0018: - if (value >= player_node->mMaxWeight / 2 && - player_node->mTotalWeight < - player_node->mMaxWeight / 2) - { - weightNotice = new OkDialog(_("Message"), - _("You are carrying more than " - "half your weight. You are " - "unable to regain health.")); - weightNotice->addActionListener( - &weightListener); - } - player_node->mTotalWeight = value; - break; - case 0x0019: player_node->mMaxWeight = value; break; - case 0x0029: player_node->ATK = value; break; - case 0x002b: player_node->MATK = value; break; - case 0x002d: player_node->DEF = value; break; - case 0x002e: player_node->DEF_BONUS = value; break; - case 0x002f: player_node->MDEF = value; break; - case 0x0031: player_node->HIT = value; break; - case 0x0032: player_node->FLEE = value; break; - case 0x0035: player_node->mAttackSpeed = value; break; - case 0x0037: player_node->mJobLevel = value; break; + player_node->setExperience(skill, current, next); } - - if (player_node->mHp == 0 && !deathNotice) + else { - static char const *const deadMsg[] = - { - _("You are dead."), - _("We regret to inform you that your character was " - "killed in battle."), - _("You are not that alive anymore."), - _("The cold hands of the grim reaper are grabbing for " - "your soul."), - _("Game Over!"), - _("Insert coin to continue"), - _("No, kids. Your character did not really die. It... " - "err... went to a better place."), - _("Your plan of breaking your enemies weapon by " - "bashing it with your throat failed."), - _("I guess this did not run too well."), - // NetHack reference: - _("Do you want your possessions identified?"), - // Secret of Mana reference: - _("Sadly, no trace of you was ever found..."), - // Final Fantasy VI reference: - _("Annihilated."), - // Earthbound reference: - _("Looks like you got your head handed to you."), - // Leisure Suit Larry 1 reference: - _("You screwed up again, dump your body down the tubes " - "and get you another one."), - // Monty Python references (Dead Parrot sketch mostly): - _("You're not dead yet. You're just resting."), - _("You are no more."), - _("You have ceased to be."), - _("You've expired and gone to meet your maker."), - _("You're a stiff."), - _("Bereft of life, you rest in peace."), - _("If you weren't so animated, you'd be pushing up the " - "daisies."), - _("Your metabolic processes are now history."), - _("You're off the twig."), - _("You've kicked the bucket."), - _("You've shuffled off your mortal coil, run down the " - "curtain and joined the bleedin' choir invisibile."), - _("You are an ex-player."), - _("You're pining for the fjords.") - }; - std::string message(deadMsg[rand()%27]); - - deathNotice = new OkDialog(_("Message"), message); - deathNotice->addActionListener(&deathListener); - player_node->setAction(Being::DEAD); + logger->log("Warning: server wants to update experience of unknown " + "skill %d to %d / %d", skill, current, next); } } - break; + } break; - case SMSG_PLAYER_STAT_UPDATE_2: - switch (msg->readInt16()) { - case 0x0001: - player_node->setXp(msg->readInt32()); - break; - case 0x0002: - player_node->mJobXp = msg->readInt32(); - break; - case 0x0014: { - Uint32 curGp = player_node->mGp; - player_node->mGp = msg->readInt32(); - if (player_node->mGp > curGp) - chatWindow->chatLog(_("You picked up ") + - Units::formatCurrency(player_node->mGp - - curGp), BY_SERVER); - } - break; - case 0x0016: - player_node->mXpForNextLevel = msg->readInt32(); - break; - case 0x0017: - player_node->mJobXpForNextLevel = msg->readInt32(); - break; - } - break; - - case SMSG_PLAYER_STAT_UPDATE_3: - { - Sint32 type = msg->readInt32(); - Sint32 base = msg->readInt32(); - Sint32 bonus = msg->readInt32(); - Sint32 total = base + bonus; + case GPMSG_LEVELUP: + { + player_node->setLevel(msg.readInt16()); + player_node->setCharacterPoints(msg.readInt16()); + player_node->setCorrectionPoints(msg.readInt16()); + Particle* effect = particleEngine->addEffect("graphics/particles/levelup.particle.xml", 0, 0); + player_node->controlParticle(effect); + } break; - switch (type) { - case 0x000d: player_node->mAttr[LocalPlayer::STR] = total; - break; - case 0x000e: player_node->mAttr[LocalPlayer::AGI] = total; - break; - case 0x000f: player_node->mAttr[LocalPlayer::VIT] = total; - break; - case 0x0010: player_node->mAttr[LocalPlayer::INT] = total; - break; - case 0x0011: player_node->mAttr[LocalPlayer::DEX] = total; - break; - case 0x0012: player_node->mAttr[LocalPlayer::LUK] = total; - break; - } - } - break; - case SMSG_PLAYER_STAT_UPDATE_4: - { - Sint16 type = msg->readInt16(); - Sint8 fail = msg->readInt8(); - Sint8 value = msg->readInt8(); + case GPMSG_LEVEL_PROGRESS: + { + logger->log("Level Progress Update"); + player_node->setLevelProgress(msg.readInt8()); + } break; - if (fail != 1) - break; - switch (type) { - case 0x000d: player_node->mAttr[LocalPlayer::STR] = value; - break; - case 0x000e: player_node->mAttr[LocalPlayer::AGI] = value; - break; - case 0x000f: player_node->mAttr[LocalPlayer::VIT] = value; - break; - case 0x0010: player_node->mAttr[LocalPlayer::INT] = value; - break; - case 0x0011: player_node->mAttr[LocalPlayer::DEX] = value; - break; - case 0x0012: player_node->mAttr[LocalPlayer::LUK] = value; - break; - } + case GPMSG_RAISE_ATTRIBUTE_RESPONSE: + { + int errCode = msg.readInt8(); + int attrNum = msg.readInt8() - CHAR_ATTR_BEGIN; + 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 = player_node->getAttributeBase(attrNum) - 1; + player_node->setCharacterPoints(0); + player_node->setAttributeBase(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); + } break; } - break; - - // Updates stats and status points - case SMSG_PLAYER_STAT_UPDATE_5: - player_node->mStatsPointsToAttribute = msg->readInt16(); - player_node->mAttr[LocalPlayer::STR] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::STR] = msg->readInt8(); - player_node->mAttr[LocalPlayer::AGI] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::AGI] = msg->readInt8(); - player_node->mAttr[LocalPlayer::VIT] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::VIT] = msg->readInt8(); - player_node->mAttr[LocalPlayer::INT] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::INT] = msg->readInt8(); - player_node->mAttr[LocalPlayer::DEX] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::DEX] = msg->readInt8(); - player_node->mAttr[LocalPlayer::LUK] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::LUK] = msg->readInt8(); - player_node->ATK = msg->readInt16(); // ATK - player_node->ATK_BONUS = msg->readInt16(); // ATK bonus - player_node->MATK = msg->readInt16(); // MATK max - player_node->MATK_BONUS = msg->readInt16(); // MATK min - player_node->DEF = msg->readInt16(); // DEF - player_node->DEF_BONUS = msg->readInt16(); // DEF bonus - player_node->MDEF = msg->readInt16(); // MDEF - player_node->MDEF_BONUS = msg->readInt16(); // MDEF bonus - player_node->HIT = msg->readInt16(); // HIT - player_node->FLEE = msg->readInt16(); // FLEE - player_node->FLEE_BONUS = msg->readInt16(); // FLEE bonus - msg->readInt16(); // critical - msg->readInt16(); // unknown - break; + } break; - case SMSG_PLAYER_STAT_UPDATE_6: - switch (msg->readInt16()) { - case 0x0020: - player_node->mAttrUp[LocalPlayer::STR] = msg->readInt8(); - break; - case 0x0021: - player_node->mAttrUp[LocalPlayer::AGI] = msg->readInt8(); - break; - case 0x0022: - player_node->mAttrUp[LocalPlayer::VIT] = msg->readInt8(); - break; - case 0x0023: - player_node->mAttrUp[LocalPlayer::INT] = msg->readInt8(); - break; - case 0x0024: - player_node->mAttrUp[LocalPlayer::DEX] = msg->readInt8(); - break; - case 0x0025: - player_node->mAttrUp[LocalPlayer::LUK] = msg->readInt8(); + case GPMSG_LOWER_ATTRIBUTE_RESPONSE: + { + int errCode = msg.readInt8(); + int attrNum = msg.readInt8() - CHAR_ATTR_BEGIN; + 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 = player_node->getAttributeBase(attrNum) + 1; + player_node->setCorrectionPoints(0); + player_node->setAttributeBase(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); + } break; } - break; + } break; + /* case SMSG_PLAYER_ARROW_MESSAGE: { - Sint16 type = msg->readInt16(); + Sint16 type = msg.readInt16(); switch (type) { case 0: - chatWindow->chatLog(_("Equip arrows first"), + chatWindow->chatLog("Equip arrows first", BY_SERVER); break; default: @@ -413,5 +287,41 @@ void PlayerHandler::handleMessage(MessageIn *msg) } } break; + */ } } + +void +PlayerHandler::handleMapChangeMessage(MessageIn &msg) +{ + const std::string mapName = msg.readString(); + const unsigned short x = msg.readInt16(); + const unsigned short y = msg.readInt16(); + const bool nearby = (engine->getCurrentMapName() == mapName); + + logger->log("Changing map to %s (%d, %d)", mapName.c_str(), x, y); + + // Switch the actual map, deleting the previous one + engine->changeMap(mapName); + + current_npc = 0; + + const Vector &playerPos = player_node->getPosition(); + float scrollOffsetX = 0.0f; + float scrollOffsetY = 0.0f; + + /* Scroll if neccessary */ + if (!nearby + || (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); + + logger->log("Adjust scrolling by %d,%d", (int) scrollOffsetX, + (int) scrollOffsetY); + viewport->scrollBy(scrollOffsetX, scrollOffsetY); +} |