diff options
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); +} |