diff options
Diffstat (limited to 'src/net/ea/playerhandler.cpp')
-rw-r--r-- | src/net/ea/playerhandler.cpp | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/src/net/ea/playerhandler.cpp b/src/net/ea/playerhandler.cpp new file mode 100644 index 00000000..9f0acbb3 --- /dev/null +++ b/src/net/ea/playerhandler.cpp @@ -0,0 +1,417 @@ +/* + * The Mana World + * Copyright (C) 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 + * 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 "../messagein.h" +#include "playerhandler.h" +#include "protocol.h" + +#include "../../engine.h" +#include "../../localplayer.h" +#include "../../log.h" +#include "../../npc.h" +#include "../../units.h" + +#include "../../gui/buy.h" +#include "../../gui/chat.h" +#include "../../gui/gui.h" +#include "../../gui/npclistdialog.h" +#include "../../gui/npc_text.h" +#include "../../gui/ok_dialog.h" +#include "../../gui/sell.h" +#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; + +extern NpcListDialog *npcListDialog; +extern NpcTextDialog *npcTextDialog; +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; + +/** + * Listener used for handling the overweigth message. + */ +// TODO Move somewhere else +namespace { + struct WeightListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + weightNotice = NULL; + } + } weightListener; +} + +/** + * Listener used for handling death message. + */ +// TODO Move somewhere else +namespace { + struct DeathListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + player_node->revive(); + deathNotice = NULL; + npcListDialog->setVisible(false); + npcTextDialog->setVisible(false); + buyDialog->setVisible(false); + sellDialog->setVisible(false); + buySellDialog->setVisible(false); + if (current_npc) current_npc->handleDeath(); + } + } deathListener; +} + +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, + 0 + }; + handledMessages = _messages; +} + +void PlayerHandler::handleMessage(MessageIn &msg) +{ + 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. + */ + 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); + + if (current_npc) current_npc->handleDeath(); + + float scrollOffsetX = 0.0f; + float scrollOffsetY = 0.0f; + + /* Scroll if neccessary */ + if (!nearby + || (abs(x - player_node->mX) > MAP_TELEPORT_SCROLL_DISTANCE) + || (abs(y - player_node->mY) > MAP_TELEPORT_SCROLL_DISTANCE)) + { + scrollOffsetX = (x - player_node->mX) * 32; + scrollOffsetY = (y - player_node->mY) * 32; + } + + 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); + } + break; + + case SMSG_PLAYER_STAT_UPDATE_1: + { + Sint16 type = msg.readInt16(); + Uint32 value = msg.readInt32(); + + switch (type) + { + //case 0x0000: + // player_node->setWalkSpeed(msg.readInt32()); + // break; + case 0x0005: player_node->setHp(value); break; + case 0x0006: player_node->setMaxHp(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->setLevel(value); break; + case 0x000c: + player_node->mSkillPoint = value; + skillDialog->update(); + break; + case 0x0018: + if ((int) value >= player_node->getMaxWeight() / 2 && + player_node->getTotalWeight() < + player_node->getMaxWeight() / 2) + { + weightNotice = new OkDialog(_("Message"), + _("You are carrying more than " + "half your weight. You are " + "unable to regain health.")); + weightNotice->addActionListener( + &weightListener); + } + player_node->setTotalWeight(value); + break; + case 0x0019: player_node->setMaxWeight(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; + } + + if (player_node->getHp() == 0 && !deathNotice) + { + 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); + } + } + 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: { + int curGp = player_node->getMoney(); + player_node->setMoney(msg.readInt32()); + if (player_node->getMoney() > curGp) + chatWindow->chatLog(_("You picked up ") + + Units::formatCurrency(player_node->getMoney() + - 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; + + 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(); + + 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; + } + } + 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; + + 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(); + break; + } + break; + + case SMSG_PLAYER_ARROW_MESSAGE: + { + Sint16 type = msg.readInt16(); + + switch (type) { + case 0: + chatWindow->chatLog(_("Equip arrows first"), + BY_SERVER); + break; + default: + logger->log("0x013b: Unhandled message %i", type); + break; + } + } + break; + } +} |