summaryrefslogtreecommitdiff
path: root/src/net/beinghandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/beinghandler.cpp')
-rw-r--r--src/net/beinghandler.cpp753
1 files changed, 285 insertions, 468 deletions
diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp
index 3e746eb5..8f1fb8fd 100644
--- a/src/net/beinghandler.cpp
+++ b/src/net/beinghandler.cpp
@@ -1,542 +1,359 @@
/*
* 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 <iostream>
+#include "beinghandler.h"
+
#include <SDL_types.h>
-#include "beinghandler.h"
#include "messagein.h"
#include "protocol.h"
#include "../being.h"
#include "../beingmanager.h"
-#include "../effectmanager.h"
#include "../game.h"
#include "../localplayer.h"
#include "../log.h"
+#include "../main.h"
#include "../npc.h"
-#include "../player_relations.h"
+#include "../particle.h"
+#include "../sound.h"
+
+#include "../gui/ok_dialog.h"
+
+#include "../utils/gettext.h"
+
+#include "gameserver/player.h"
const int EMOTION_TIME = 150; /**< Duration of emotion icon */
-BeingHandler::BeingHandler(bool enableSync):
- mSync(enableSync)
+BeingHandler::BeingHandler()
{
static const Uint16 _messages[] = {
- SMSG_BEING_VISIBLE,
- SMSG_BEING_MOVE,
- SMSG_BEING_MOVE2,
- SMSG_BEING_REMOVE,
- SMSG_BEING_ACTION,
- SMSG_BEING_SELFEFFECT,
- SMSG_BEING_EMOTION,
- SMSG_BEING_CHANGE_LOOKS,
- SMSG_BEING_CHANGE_LOOKS2,
- SMSG_BEING_NAME_RESPONSE,
- SMSG_PLAYER_UPDATE_1,
- SMSG_PLAYER_UPDATE_2,
- SMSG_PLAYER_MOVE,
- SMSG_PLAYER_STOP,
- SMSG_PLAYER_MOVE_TO_ATTACK,
- 0x0119,
- 0x0196,
+ GPMSG_BEING_ATTACK,
+ GPMSG_BEING_ENTER,
+ GPMSG_BEING_LEAVE,
+ GPMSG_BEINGS_MOVE,
+ GPMSG_BEINGS_DAMAGE,
+ GPMSG_BEING_ACTION_CHANGE,
+ GPMSG_BEING_LOOKS_CHANGE,
+ GPMSG_BEING_DIR_CHANGE,
0
};
handledMessages = _messages;
}
-void BeingHandler::handleMessage(MessageIn *msg)
+void BeingHandler::handleMessage(MessageIn &msg)
{
- Uint32 id;
- Uint16 job, speed;
- Uint16 headTop, headMid, headBottom;
- Uint16 shoes, gloves;
- Uint16 weapon, shield;
- Uint16 gmstatus;
- Sint16 param1;
- int stunMode;
- Uint32 statusEffects;
- Sint8 type;
- Uint16 status;
- Being *srcBeing, *dstBeing;
- int hairStyle, hairColor, flag;
-
- switch (msg->getId())
+ switch (msg.getId())
{
- case SMSG_BEING_VISIBLE:
- case SMSG_BEING_MOVE:
- // Information about a being in range
- id = msg->readInt32();
- speed = msg->readInt16();
- stunMode = msg->readInt16(); // opt1
- statusEffects = msg->readInt16(); // opt2
- statusEffects |= ((Uint32)msg->readInt16()) << 16; // option
- job = msg->readInt16(); // class
-
- dstBeing = beingManager->findBeing(id);
-
- if (!dstBeing)
- {
- // Being with id >= 110000000 and job 0 are better
- // known as ghosts, so don't create those.
- if (job == 0 && id >= 110000000)
- {
- break;
- }
-
- dstBeing = beingManager->createBeing(id, job);
- }
- else if (msg->getId() == 0x0078)
- {
- dstBeing->clearPath();
- dstBeing->mFrame = 0;
- dstBeing->mWalkTime = tick_time;
- dstBeing->setAction(Being::STAND);
- }
-
-
- // Prevent division by 0 when calculating frame
- if (speed == 0) { speed = 150; }
-
- dstBeing->setWalkSpeed(speed);
- dstBeing->mJob = job;
- hairStyle = msg->readInt16();
- dstBeing->setSprite(Being::WEAPON_SPRITE, msg->readInt16());
- headBottom = msg->readInt16();
-
- if (msg->getId() == SMSG_BEING_MOVE)
- {
- msg->readInt32(); // server tick
- }
-
- dstBeing->setSprite(Being::SHIELD_SPRITE, msg->readInt16());
- headTop = msg->readInt16();
- headMid = msg->readInt16();
- 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
- msg->readInt16(); // manner
- dstBeing->setStatusEffectBlock(32, msg->readInt16()); // opt3
- msg->readInt8(); // karma
- dstBeing->setGender(
- (msg->readInt8() == 0) ? GENDER_FEMALE : GENDER_MALE);
-
- // Set these after the gender, as the sprites may be gender-specific
- dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom);
- dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid);
- dstBeing->setSprite(Being::HAT_SPRITE, headTop);
- dstBeing->setSprite(Being::SHOE_SPRITE, shoes);
- dstBeing->setSprite(Being::GLOVES_SPRITE, gloves);
- dstBeing->setHairStyle(hairStyle, hairColor);
-
- if (msg->getId() == SMSG_BEING_MOVE)
- {
- Uint16 srcX, srcY, dstX, dstY;
- msg->readCoordinatePair(srcX, srcY, dstX, dstY);
- dstBeing->setAction(Being::STAND);
- dstBeing->mX = srcX;
- dstBeing->mY = srcY;
- dstBeing->setDestination(dstX, dstY);
- }
- else
- {
- Uint8 dir;
- msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir);
- dstBeing->setDirection(dir);
- }
-
- msg->readInt8(); // unknown
- msg->readInt8(); // unknown
- msg->readInt8(); // unknown / sit
-
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
- dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
+ case GPMSG_BEING_ENTER:
+ handleBeingEnterMessage(msg);
break;
-
- case SMSG_BEING_MOVE2:
- /*
- * A simplified movement packet, used by the
- * later versions of eAthena for both mobs and
- * players
- */
- dstBeing = beingManager->findBeing(msg->readInt32());
-
- Uint16 srcX, srcY, dstX, dstY;
- msg->readCoordinatePair(srcX, srcY, dstX, dstY);
- msg->readInt32(); // Server tick
-
- /*
- * This packet doesn't have enough info to actually
- * create a new being, so if the being isn't found,
- * we'll just pretend the packet didn't happen
- */
-
- if (dstBeing) {
- dstBeing->setAction(Being::STAND);
- dstBeing->mX = srcX;
- dstBeing->mY = srcY;
- dstBeing->setDestination(dstX, dstY);
- }
-
+ case GPMSG_BEING_LEAVE:
+ handleBeingLeaveMessage(msg);
break;
-
- case SMSG_BEING_REMOVE:
- // A being should be removed or has died
- dstBeing = beingManager->findBeing(msg->readInt32());
-
- if (!dstBeing)
- break;
-
- // If this is player's current target, clear it.
- if (dstBeing == player_node->getTarget())
- player_node->stopAttack();
-
- if (dstBeing == current_npc)
- current_npc->handleDeath();
-
- if (msg->readInt8() == 1)
- dstBeing->setAction(Being::DEAD);
- else
- beingManager->destroyBeing(dstBeing);
-
+ case GPMSG_BEINGS_MOVE:
+ handleBeingsMoveMessage(msg);
break;
-
- case SMSG_BEING_ACTION:
- srcBeing = beingManager->findBeing(msg->readInt32());
- dstBeing = beingManager->findBeing(msg->readInt32());
- msg->readInt32(); // server tick
- msg->readInt32(); // src speed
- msg->readInt32(); // dst speed
- param1 = msg->readInt16();
- msg->readInt16(); // param 2
- type = msg->readInt8();
- msg->readInt16(); // param 3
-
- switch (type)
- {
- case 0x0a: // Critical Damage
- if (dstBeing)
- dstBeing->showCrit();
- case 0x00: // Damage
- if (dstBeing)
- dstBeing->takeDamage(param1);
- if (srcBeing)
- srcBeing->handleAttack(dstBeing, param1);
- break;
-
- case 0x02: // Sit
- if (srcBeing)
- {
- srcBeing->mFrame = 0;
- srcBeing->setAction(Being::SIT);
- }
- break;
-
- case 0x03: // Stand up
- if (srcBeing)
- {
- srcBeing->mFrame = 0;
- srcBeing->setAction(Being::STAND);
- }
- break;
- }
+ case GPMSG_BEING_ATTACK:
+ handleBeingAttackMessage(msg);
break;
+ case GPMSG_BEINGS_DAMAGE:
+ handleBeingsDamageMessage(msg);
+ break;
+ case GPMSG_BEING_ACTION_CHANGE:
+ handleBeingActionChangeMessage(msg);
+ break;
+ case GPMSG_BEING_LOOKS_CHANGE:
+ handleBeingLooksChangeMessage(msg);
+ break;
+ case GPMSG_BEING_DIR_CHANGE:
+ handleBeingDirChangeMessage(msg);
+ break;
+ }
+}
- case SMSG_BEING_SELFEFFECT: {
- id = (Uint32)msg->readInt32();
- if (!beingManager->findBeing(id))
- break;
-
- int effectType = msg->readInt32();
- Being* being = beingManager->findBeing(id);
+static void handleLooks(Player *being, MessageIn &msg)
+{
+ // Order of sent slots. Has to be in sync with the server code.
+ static int const nb_slots = 4;
+ static int const slots[nb_slots] =
+ { Being::WEAPON_SPRITE, Being::HAT_SPRITE, Being::TOPCLOTHES_SPRITE,
+ Being::BOTTOMCLOTHES_SPRITE };
- effectManager->trigger(effectType, being);
+ int mask = msg.readInt8();
- break;
+ if (mask & (1 << 7))
+ {
+ // The equipment has to be cleared first.
+ for (int i = 0; i < nb_slots; ++i)
+ {
+ being->setSprite(slots[i], 0);
}
+ }
- case SMSG_BEING_EMOTION:
- if (!(dstBeing = beingManager->findBeing(msg->readInt32())))
- {
- break;
- }
-
- if (player_relations.hasPermission(dstBeing, PlayerRelation::EMOTE))
- dstBeing->setEmote(msg->readInt8(), EMOTION_TIME);
-
- break;
+ // Fill slots enumerated by the bitmask.
+ for (int i = 0; i < nb_slots; ++i)
+ {
+ if (!(mask & (1 << i))) continue;
+ int id = msg.readInt16();
+ being->setSprite(slots[i], id);
+ }
+}
- case SMSG_BEING_CHANGE_LOOKS:
- case SMSG_BEING_CHANGE_LOOKS2:
+void BeingHandler::handleBeingEnterMessage(MessageIn &msg)
+{
+ int type = msg.readInt8();
+ int id = msg.readInt16();
+ Being::Action action = (Being::Action)msg.readInt8();
+ int px = msg.readInt16();
+ int py = msg.readInt16();
+ Being *being;
+
+ switch (type)
+ {
+ case OBJECT_PLAYER:
{
- /*
- * SMSG_BEING_CHANGE_LOOKS (0x00c3) and
- * SMSG_BEING_CHANGE_LOOKS2 (0x01d7) do basically the same
- * thing. The difference is that ...LOOKS carries a single
- * 8 bit value, where ...LOOKS2 carries two 16 bit values.
- *
- * If type = 2, then the first 16 bit value is the weapon ID,
- * and the second 16 bit value is the shield ID. If no
- * shield is equipped, or type is not 2, then the second
- * 16 bit value will be 0.
- */
-
- if (!(dstBeing = beingManager->findBeing(msg->readInt32())))
+ std::string name = msg.readString();
+ if (player_node->getName() == name)
{
- break;
+ being = player_node;
+ being->setId(id);
}
-
- int type = msg->readInt8();
- int id = 0;
- int id2 = 0;
-
- if (msg->getId() == SMSG_BEING_CHANGE_LOOKS) {
- id = msg->readInt8();
- } else { // SMSG_BEING_CHANGE_LOOKS2
- id = msg->readInt16();
- id2 = msg->readInt16();
- }
-
- switch (type) {
- case 1: // eAthena LOOK_HAIR
- dstBeing->setHairStyle(id, -1);
- break;
- case 2: // Weapon ID in id, Shield ID in id2
- dstBeing->setSprite(Being::WEAPON_SPRITE, id);
- dstBeing->setSprite(Being::SHIELD_SPRITE, id2);
- break;
- case 3: // Change lower headgear for eAthena, pants for us
- dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, id);
- break;
- case 4: // Change upper headgear for eAthena, hat for us
- dstBeing->setSprite(Being::HAT_SPRITE, id);
- break;
- case 5: // Change middle headgear for eathena, armor for us
- dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, id);
- break;
- case 6: // eAthena LOOK_HAIR_COLOR
- dstBeing->setHairStyle(-1, id);
- break;
- case 8: // eAthena LOOK_SHIELD
- dstBeing->setSprite(Being::SHIELD_SPRITE, id);
- break;
- case 9: // eAthena LOOK_SHOES
- dstBeing->setSprite(Being::SHOE_SPRITE, id);
- break;
- case 10: // LOOK_GLOVES
- dstBeing->setSprite(Being::GLOVES_SPRITE, id);
- break;
- case 11: // LOOK_CAPE
- dstBeing->setSprite(Being::CAPE_SPRITE, id);
- break;
- case 12:
- dstBeing->setSprite(Being::MISC1_SPRITE, id);
- break;
- case 13:
- dstBeing->setSprite(Being::MISC2_SPRITE, id);
- break;
- default:
- logger->log("SMSG_BEING_CHANGE_LOOKS: unsupported type: "
- "%d, id: %d", type, id);
- break;
- }
- }
- break;
-
- case SMSG_BEING_NAME_RESPONSE:
- if ((dstBeing = beingManager->findBeing(msg->readInt32())))
+ else
{
- dstBeing->setName(msg->readString(24));
+ being = beingManager->createBeing(id, type, 0);
+ being->setName(name);
}
- break;
+ Player *p = static_cast< Player * >(being);
+ int hs = msg.readInt8(), hc = msg.readInt8();
+ p->setHairStyle(hs, hc);
+ p->setGender(msg.readInt8() == GENDER_MALE ?
+ GENDER_MALE : GENDER_FEMALE);
+ handleLooks(p, msg);
+ } break;
+
+ case OBJECT_MONSTER:
+ case OBJECT_NPC:
+ {
+ int subtype = msg.readInt16();
+ being = beingManager->createBeing(id, type, subtype);
+ std::string name = msg.readString();
+ if (name.length() > 0) being->setName(name);
+ } break;
+
+ default:
+ return;
+ }
- case SMSG_PLAYER_UPDATE_1:
- case SMSG_PLAYER_UPDATE_2:
- case SMSG_PLAYER_MOVE:
- // An update about a player, potentially including movement.
- id = msg->readInt32();
- speed = msg->readInt16();
- stunMode = msg->readInt16(); // opt1; Aethyra use this as cape
- statusEffects = msg->readInt16(); // opt2; Aethyra use this as misc1
- statusEffects |= ((Uint32) msg->readInt16())
- << 16; // status.options; Aethyra uses this as misc2
- job = msg->readInt16();
-
- dstBeing = beingManager->findBeing(id);
-
- if (!dstBeing)
- {
- dstBeing = beingManager->createBeing(id, job);
- }
+ being->setPosition(px, py);
+ being->setDestination(px, py);
+ being->setAction(action);
+}
- dstBeing->setWalkSpeed(speed);
- dstBeing->mJob = job;
- hairStyle = msg->readInt16();
- weapon = msg->readInt16();
- shield = msg->readInt16();
- headBottom = msg->readInt16();
+void BeingHandler::handleBeingLeaveMessage(MessageIn &msg)
+{
+ Being *being = beingManager->findBeing(msg.readInt16());
+ if (!being) return;
- if (msg->getId() == SMSG_PLAYER_MOVE)
- {
- msg->readInt32(); // server tick
- }
+ beingManager->destroyBeing(being);
+}
- headTop = msg->readInt16();
- headMid = msg->readInt16();
- hairColor = msg->readInt16();
- msg->readInt16(); // clothes color - Aethyra-"abused" as shoes, we ignore it
- msg->readInt16(); // head dir - Aethyra-"abused" as gloves, we ignore it
- msg->readInt32(); // guild
- msg->readInt16(); // emblem
- msg->readInt16(); // manner
- dstBeing->setStatusEffectBlock(32, msg->readInt16()); // opt3
- msg->readInt8(); // karma
- dstBeing->setGender(
- (msg->readInt8() == 0) ? GENDER_FEMALE : GENDER_MALE);
-
- // Set these after the gender, as the sprites may be gender-specific
- dstBeing->setSprite(Being::WEAPON_SPRITE, weapon);
- dstBeing->setSprite(Being::SHIELD_SPRITE, shield);
- dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom);
- dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid);
- dstBeing->setSprite(Being::HAT_SPRITE, headTop);
- //dstBeing->setSprite(Being::CAPE_SPRITE, cape);
- //dstBeing->setSprite(Being::MISC1_SPRITE, misc1);
- //dstBeing->setSprite(Being::MISC2_SPRITE, misc2);
- dstBeing->setHairStyle(hairStyle, hairColor);
-
- if (msg->getId() == SMSG_PLAYER_MOVE)
- {
- Uint16 srcX, srcY, dstX, dstY;
- msg->readCoordinatePair(srcX, srcY, dstX, dstY);
- dstBeing->mX = srcX;
- dstBeing->mY = srcY;
- dstBeing->setDestination(dstX, dstY);
- }
- else
+void BeingHandler::handleBeingsMoveMessage(MessageIn &msg)
+{
+ while (msg.getUnreadLength())
+ {
+ int id = msg.readInt16();
+ int flags = msg.readInt8();
+ Being *being = beingManager->findBeing(id);
+ int sx = 0;
+ int sy = 0;
+ int dx = 0;
+ int dy = 0;
+ int speed = 0;
+
+ printf("handleBeingsMoveMessage for %p (%s | %s)\n",
+ (void*) being,
+ (flags & MOVING_POSITION) ? "pos" : "",
+ (flags & MOVING_DESTINATION) ? "dest" : "");
+
+ if (flags & MOVING_POSITION)
+ {
+ Uint16 sx2, sy2;
+ msg.readCoordinates(sx2, sy2);
+ sx = sx2 * 32 + 16;
+ sy = sy2 * 32 + 16;
+ speed = msg.readInt8();
+ }
+ if (flags & MOVING_DESTINATION)
+ {
+ dx = msg.readInt16();
+ dy = msg.readInt16();
+ if (!(flags & MOVING_POSITION))
{
- Uint8 dir;
- msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir);
- dstBeing->setDirection(dir);
+ sx = dx;
+ sy = dy;
}
+ }
+ if (!being || !(flags & (MOVING_POSITION | MOVING_DESTINATION)))
+ {
+ continue;
+ }
+ if (speed)
+ {
+ /* The speed on the server is the cost of moving from one tile to
+ * the next. Beings get 1000 cost units per second. The speed is
+ * transferred as devided by 10, so that slower speeds fit in a
+ * byte. Here we convert the speed to pixels per second.
+ */
+ const float tilesPerSecond = 100.0f / speed;
+ being->setWalkSpeed((int) (tilesPerSecond * 32));
+ }
- gmstatus = msg->readInt16();
- if (gmstatus & 0x80)
- dstBeing->setGM();
+ // Ignore messages from the server for the local player
+ if (being == player_node)
+ continue;
- if (msg->getId() == SMSG_PLAYER_UPDATE_1)
- {
- switch (msg->readInt8())
- {
- case 1:
- if (dstBeing->getType() != Being::NPC)
- dstBeing->setAction(Being::DEAD);
- break;
-
- case 2:
- dstBeing->setAction(Being::SIT);
- break;
- }
- }
- else if (msg->getId() == SMSG_PLAYER_MOVE)
- {
- msg->readInt8(); // unknown
- }
+ // If being is a player, and he only moves a little, its ok to be a little out of sync
+ if (being->getType() == Being::PLAYER && abs(being->getPixelX() - dx) +
+ abs(being->getPixelY() - dy) < 2 * 32 &&
+ (dx != being->getDestination().x && dy != being->getDestination().y))
+ {
+ being->setDestination(being->getPixelX(),being->getPixelY());
+ continue;
+ }
+ if (abs(being->getPixelX() - sx) +
+ abs(being->getPixelY() - sy) > 10 * 32)
+ {
+ // Too large a desynchronization.
+ being->setPosition(sx, sy);
+ being->setDestination(dx, dy);
+ }
+ else if (!(flags & MOVING_POSITION))
+ {
+ being->setDestination(dx, dy);
+ }
+ else if (!(flags & MOVING_DESTINATION))
+ {
+ being->adjustCourse(sx, sy);
+ }
+ else
+ {
+ being->adjustCourse(sx, sy, dx, dy);
+ }
+ }
+}
- msg->readInt8(); // Lv
- msg->readInt8(); // unknown
+void BeingHandler::handleBeingAttackMessage(MessageIn &msg)
+{
+ Being *being = beingManager->findBeing(msg.readInt16());
+ int direction = msg.readInt8();
+ int attackType = msg.readInt8();
- dstBeing->mWalkTime = tick_time;
- dstBeing->mFrame = 0;
+ if (!being) return;
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
- dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
- break;
+ switch (direction)
+ {
+ case DIRECTION_UP: being->setDirection(Being::UP); break;
+ case DIRECTION_DOWN: being->setDirection(Being::DOWN); break;
+ case DIRECTION_LEFT: being->setDirection(Being::LEFT); break;
+ case DIRECTION_RIGHT: being->setDirection(Being::RIGHT); break;
+ }
- case SMSG_PLAYER_STOP:
- /*
- * Instruction from server to stop walking at x, y.
- *
- * Some people like having this enabled. Others absolutely
- * despise it. So I'm setting to so that it only affects the
- * local player if the person has set a key "EnableSync" to "1"
- * in their config.xml file.
- *
- * This packet will be honored for all other beings, regardless
- * of the config setting.
- */
+ being->setAction(Being::ATTACK, attackType);
+}
- id = msg->readInt32();
- if (mSync || id != player_node->getId()) {
- dstBeing = beingManager->findBeing(id);
- if (dstBeing) {
- dstBeing->mX = msg->readInt16();
- dstBeing->mY = msg->readInt16();
- if (dstBeing->mAction == Being::WALK) {
- dstBeing->mFrame = 0;
- dstBeing->setAction(Being::STAND);
- }
- }
- }
- break;
+void BeingHandler::handleBeingsDamageMessage(MessageIn &msg)
+{
+ while (msg.getUnreadLength())
+ {
+ Being *being = beingManager->findBeing(msg.readInt16());
+ int damage = msg.readInt16();
+ if (being)
+ {
+ being->takeDamage(damage);
+ }
+ }
+}
- case SMSG_PLAYER_MOVE_TO_ATTACK:
- /*
- * This is an *advisory* message, telling the client that
- * it needs to move the character before attacking
- * a target (out of range, obstruction in line of fire).
- * We can safely ignore this...
- */
- break;
+void BeingHandler::handleBeingActionChangeMessage(MessageIn &msg)
+{
+ Being* being = beingManager->findBeing(msg.readInt16());
+ Being::Action action = (Being::Action) msg.readInt8();
+ if (!being) return;
- case 0x0119:
- // Change in players' flags
- id = msg->readInt32();
- dstBeing = beingManager->findBeing(id);
- stunMode = msg->readInt16();
- statusEffects = msg->readInt16();
- statusEffects |= ((Uint32) msg->readInt16()) << 16;
- msg->readInt8();
-
- if (dstBeing) {
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
- dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
- }
- break;
+ being->setAction(action);
+
+ if (action == Being::DEAD && being==player_node)
+ {
+ 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!"),
+ _("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."),
+ _("Do you want your possessions identified?"), // Nethack reference
+ _("Sadly, no trace of you was ever found..."), // Secret of Mana reference
+ _("Annihilated."), // Final Fantasy VI reference
+ _("Looks like you got your head handed to you."), //Earthbound reference
+ _("You screwed up again, dump your body down the tubes and get you another one.") // Leisure Suit Larry 1 Reference
+
+ };
+ std::string message(deadMsg[rand()%13]);
+ message.append(_(" Press OK to respawn"));
+ OkDialog *dlg = new OkDialog(_("You died"), message);
+ dlg->addActionListener(&(Net::GameServer::Player::respawnListener));
+ }
+}
- case 0x0196:
- // Status change
- status = msg->readInt16();
- id = msg->readInt32();
- flag = msg->readInt8(); // 0: stop, 1: start
+void BeingHandler::handleBeingLooksChangeMessage(MessageIn &msg)
+{
+ Being *being = beingManager->findBeing(msg.readInt16());
+ if (!being || being->getType() != Being::PLAYER) return;
+ Player * player = static_cast< Player * >(being);
+ handleLooks(player, msg);
+ if (msg.getUnreadLength())
+ {
+ int style = msg.readInt16();
+ int color = msg.readInt16();
+ player->setHairStyle(style, color);
+ player->setGender((Gender)msg.readInt16());
+ }
+}
- dstBeing = beingManager->findBeing(id);
- if (dstBeing)
- dstBeing->setStatusEffect(status, flag);
- break;
+void BeingHandler::handleBeingDirChangeMessage(MessageIn &msg)
+{
+ Being *being = beingManager->findBeing(msg.readInt16());
+ if (!being) return;
+ int data = msg.readInt8();
+ switch (data)
+ {
+ case DIRECTION_UP: being->setDirection(Being::UP); break;
+ case DIRECTION_DOWN: being->setDirection(Being::DOWN); break;
+ case DIRECTION_LEFT: being->setDirection(Being::LEFT); break;
+ case DIRECTION_RIGHT: being->setDirection(Being::RIGHT); break;
}
}
+