summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBjørn Lindeijer <bjorn@lindeijer.nl>2008-08-28 18:01:15 +0000
committerBjørn Lindeijer <bjorn@lindeijer.nl>2008-08-28 18:01:15 +0000
commitb506fe0ff8a2039167aa7c349087af4dd03e1921 (patch)
tree36989bca6fa259815f92e1d3553b4cc97d8f8133 /src
parentb98b6256262da9aafd9e8e1f93744db321d4d1ad (diff)
downloadMana-b506fe0ff8a2039167aa7c349087af4dd03e1921.tar.gz
Mana-b506fe0ff8a2039167aa7c349087af4dd03e1921.tar.bz2
Mana-b506fe0ff8a2039167aa7c349087af4dd03e1921.tar.xz
Mana-b506fe0ff8a2039167aa7c349087af4dd03e1921.zip
Applied patch put together by Jaxad0127 with changes from the Aethyra project.
Improves compatibility with the newer version of eAthena and works around an initialization bug.
Diffstat (limited to 'src')
-rw-r--r--src/being.h4
-rw-r--r--src/game.cpp24
-rw-r--r--src/net/beinghandler.cpp145
-rw-r--r--src/net/beinghandler.h6
-rw-r--r--src/net/charserverhandler.cpp7
-rw-r--r--src/net/playerhandler.cpp7
-rw-r--r--src/net/protocol.h5
7 files changed, 169 insertions, 29 deletions
diff --git a/src/being.h b/src/being.h
index 5ea8c0be..046f7b9a 100644
--- a/src/being.h
+++ b/src/being.h
@@ -93,8 +93,12 @@ class Being : public Sprite
SHOE_SPRITE,
BOTTOMCLOTHES_SPRITE,
TOPCLOTHES_SPRITE,
+ MISC1_SPRITE,
+ MISC2_SPRITE,
HAIR_SPRITE,
HAT_SPRITE,
+ CAPE_SPRITE,
+ GLOVES_SPRITE,
WEAPON_SPRITE,
SHIELD_SPRITE,
VECTOREND_SPRITE
diff --git a/src/game.cpp b/src/game.cpp
index 37375ca2..aaf5242c 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -69,6 +69,7 @@
#include "gui/trade.h"
#include "gui/viewport.h"
+#include "net/protocol.h"
#include "net/beinghandler.h"
#include "net/buysellhandler.h"
#include "net/chathandler.h"
@@ -80,6 +81,7 @@
#include "net/playerhandler.h"
#include "net/skillhandler.h"
#include "net/tradehandler.h"
+#include "net/messageout.h"
#include "resources/imagewriter.h"
@@ -260,7 +262,7 @@ void destroyGuiWindows()
Game::Game(Network *network):
mNetwork(network),
- mBeingHandler(new BeingHandler()),
+ mBeingHandler(new BeingHandler(config.getValue("EnableSync", 0) == 1)),
mBuySellHandler(new BuySellHandler()),
mChatHandler(new ChatHandler()),
mEquipmentHandler(new EquipmentHandler()),
@@ -291,7 +293,6 @@ Game::Game(Network *network):
// Initialize beings
beingManager->setPlayer(player_node);
player_node->setNetwork(network);
- engine->changeMap(map_path);
Joystick::init();
// TODO: The user should be able to choose which one to use
@@ -311,6 +312,25 @@ Game::Game(Network *network):
network->registerHandler(mPlayerHandler.get());
network->registerHandler(mSkillHandler.get());
network->registerHandler(mTradeHandler.get());
+
+ /*
+ * THIS IS A TEMPORARY WORKAROUND!
+ *
+ * To prevent the server from sending data before the client has
+ * initialized, it's been modified to wait for a "ping" from the client to
+ * complete its initialization.
+ *
+ * The real fix is to make sure we are not throwing away messages in the
+ * network buffer due to not having registered the handlers above straight
+ * after receiving a login success from the map server.
+ *
+ * The response from eAthena on this packet is ignored by the client.
+ */
+ MessageOut msg(mNetwork);
+ msg.writeInt16(CMSG_CLIENT_PING);
+ msg.writeInt32(tick_time);
+
+ engine->changeMap(map_path);
}
Game::~Game()
diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp
index be8412d9..c43c674f 100644
--- a/src/net/beinghandler.cpp
+++ b/src/net/beinghandler.cpp
@@ -40,11 +40,13 @@
const int EMOTION_TIME = 150; /**< Duration of emotion icon */
-BeingHandler::BeingHandler()
+BeingHandler::BeingHandler(bool enableSync):
+ mSync(enableSync)
{
static const Uint16 _messages[] = {
SMSG_BEING_VISIBLE,
SMSG_BEING_MOVE,
+ SMSG_BEING_MOVE2,
SMSG_BEING_REMOVE,
SMSG_BEING_ACTION,
SMSG_BEING_LEVELUP,
@@ -55,6 +57,8 @@ BeingHandler::BeingHandler()
SMSG_PLAYER_UPDATE_1,
SMSG_PLAYER_UPDATE_2,
SMSG_PLAYER_MOVE,
+ SMSG_PLAYER_STOP,
+ SMSG_PLAYER_MOVE_TO_ATTACK,
0x0119,
0
};
@@ -66,6 +70,8 @@ void BeingHandler::handleMessage(MessageIn *msg)
Uint32 id;
Uint16 job, speed;
Uint16 headTop, headMid, headBottom;
+ Uint16 shoes, gloves, cape, misc1, misc2;
+ Uint16 weapon, shield;
Sint16 param1;
Sint8 type;
Being *srcBeing, *dstBeing;
@@ -78,8 +84,8 @@ void BeingHandler::handleMessage(MessageIn *msg)
// Information about a being in range
id = msg->readInt32();
speed = msg->readInt16();
- msg->readInt16(); // unknown
- msg->readInt16(); // unknown
+ msg->readInt16(); // opt1
+ msg->readInt16(); // opt2
msg->readInt16(); // option
job = msg->readInt16(); // class
@@ -122,8 +128,10 @@ void BeingHandler::handleMessage(MessageIn *msg)
headTop = msg->readInt16();
headMid = msg->readInt16();
hairColor = msg->readInt16();
- msg->readInt16(); // clothes color -not used
+ msg->readInt16(); // clothes color - not used
msg->readInt16(); // head dir
+ shoes = 0;
+ gloves = 0;
msg->readInt16(); // guild
msg->readInt16(); // unknown
msg->readInt16(); // unknown
@@ -133,9 +141,11 @@ void BeingHandler::handleMessage(MessageIn *msg)
dstBeing->setGender(1 - msg->readInt8()); // gender
// 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::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)
@@ -159,6 +169,33 @@ void BeingHandler::handleMessage(MessageIn *msg)
msg->readInt8(); // unknown / sit
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);
+ }
+
+ break;
+
case SMSG_BEING_REMOVE:
// A being should be removed or has died
dstBeing = beingManager->findBeing(msg->readInt32());
@@ -166,6 +203,11 @@ void BeingHandler::handleMessage(MessageIn *msg)
if (!dstBeing)
break;
+ if (dstBeing == player_node->getTarget())
+ {
+ player_node->stopAttack();
+ }
+
if (msg->readInt8() == 1)
{
dstBeing->setAction(Being::DEAD);
@@ -175,10 +217,6 @@ void BeingHandler::handleMessage(MessageIn *msg)
beingManager->destroyBeing(dstBeing);
}
- if (dstBeing == player_node->getTarget())
- {
- player_node->stopAttack();
- }
break;
case SMSG_BEING_ACTION:
@@ -257,7 +295,7 @@ void BeingHandler::handleMessage(MessageIn *msg)
case SMSG_BEING_CHANGE_LOOKS2:
{
/*
- * SMSG_BEING_CHANGE_LOOKS (0x00c3) and
+ * 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.
@@ -288,7 +326,7 @@ void BeingHandler::handleMessage(MessageIn *msg)
case 1: // eAthena LOOK_HAIR
dstBeing->setHairStyle(id, -1);
break;
- case 2: // Weapon ID in id, Shield ID in id2
+ case 2: // Weapon ID in id, Shield ID in id2
dstBeing->setSprite(Being::WEAPON_SPRITE, id);
dstBeing->setSprite(Being::SHIELD_SPRITE, id2);
break;
@@ -304,9 +342,24 @@ void BeingHandler::handleMessage(MessageIn *msg)
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);
@@ -328,9 +381,9 @@ void BeingHandler::handleMessage(MessageIn *msg)
// An update about a player, potentially including movement.
id = msg->readInt32();
speed = msg->readInt16();
- msg->readInt16(); // option 1
- msg->readInt16(); // option 2
- msg->readInt16(); // option
+ cape = msg->readInt16();
+ misc1 = msg->readInt16();
+ misc2 = msg->readInt16();
job = msg->readInt16();
dstBeing = beingManager->findBeing(id);
@@ -343,9 +396,9 @@ void BeingHandler::handleMessage(MessageIn *msg)
dstBeing->setWalkSpeed(speed);
dstBeing->mJob = job;
hairStyle = msg->readInt16();
- dstBeing->setSprite(Being::WEAPON_SPRITE, msg->readInt16());
- dstBeing->setSprite(Being::SHIELD_SPRITE, msg->readInt16());
- headBottom = msg->readInt16();
+ weapon = msg->readInt16();
+ shield = msg->readInt16();
+ headBottom = msg->readInt16();
if (msg->getId() == SMSG_PLAYER_MOVE)
{
@@ -355,7 +408,9 @@ void BeingHandler::handleMessage(MessageIn *msg)
headTop = msg->readInt16();
headMid = msg->readInt16();
hairColor = msg->readInt16();
- msg->readInt16(); // clothes color - not used
+ shoes = 0;
+ gloves = 0;
+ msg->readInt16(); // clothes color - not used
msg->readInt16(); // head dir
msg->readInt32(); // guild
msg->readInt32(); // emblem
@@ -364,9 +419,18 @@ void BeingHandler::handleMessage(MessageIn *msg)
dstBeing->setGender(1 - msg->readInt8()); // gender
// Set these after the gender, as the sprites may be gender-specific
- dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom);
+ 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::SHOE_SPRITE, shoes);
+ // Compensation for the unpatched TMW server
+ if (gloves > 10)
+ dstBeing->setSprite(Being::GLOVES_SPRITE, gloves);
+ 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)
@@ -384,8 +448,7 @@ void BeingHandler::handleMessage(MessageIn *msg)
dstBeing->setDirection(dir);
}
- msg->readInt8(); // unknown
- msg->readInt8(); // unknown
+ msg->readInt16(); // GM status
if (msg->getId() == SMSG_PLAYER_UPDATE_1)
{
@@ -406,6 +469,42 @@ void BeingHandler::handleMessage(MessageIn *msg)
dstBeing->mFrame = 0;
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.
+ */
+
+ 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;
+
+ 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;
+
case 0x0119:
// Change in players look
logger->log("0x0119 %i %i %i %x %i", msg->readInt32(),
diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h
index 03012f39..5d6d91a4 100644
--- a/src/net/beinghandler.h
+++ b/src/net/beinghandler.h
@@ -29,9 +29,13 @@
class BeingHandler : public MessageHandler
{
public:
- BeingHandler();
+ BeingHandler(bool);
void handleMessage(MessageIn *msg);
+
+ private:
+ // Should we honor server "Stop Walking" packets
+ bool mSync;
};
#endif
diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp
index c49c7640..baa841f4 100644
--- a/src/net/charserverhandler.cpp
+++ b/src/net/charserverhandler.cpp
@@ -191,7 +191,10 @@ LocalPlayer* CharServerHandler::readPlayerData(MessageIn &msg, int &slot)
tempPlayer->mGp = msg.readInt32();
tempPlayer->mJobXp = msg.readInt32();
tempPlayer->mJobLevel = msg.readInt32();
- msg.skip(8); // unknown
+ tempPlayer->setSprite(Being::SHOE_SPRITE, msg.readInt16());
+ tempPlayer->setSprite(Being::GLOVES_SPRITE, msg.readInt16());
+ tempPlayer->setSprite(Being::CAPE_SPRITE, msg.readInt16());
+ tempPlayer->setSprite(Being::MISC1_SPRITE, msg.readInt16());
msg.readInt32(); // option
msg.readInt32(); // karma
msg.readInt32(); // manner
@@ -213,7 +216,7 @@ LocalPlayer* CharServerHandler::readPlayerData(MessageIn &msg, int &slot)
tempPlayer->setSprite(Being::TOPCLOTHES_SPRITE, msg.readInt16()); // head option mid
int hairColor = msg.readInt16();
tempPlayer->setHairStyle(hairStyle, hairColor);
- msg.readInt16(); // unknown
+ tempPlayer->setSprite(Being::MISC2_SPRITE, msg.readInt16());
tempPlayer->setName(msg.readString(24));
for (int i = 0; i < 6; i++) {
tempPlayer->mAttr[i] = msg.readInt8();
diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp
index 2502c144..463868db 100644
--- a/src/net/playerhandler.cpp
+++ b/src/net/playerhandler.cpp
@@ -123,6 +123,12 @@ void PlayerHandler::handleMessage(MessageIn *msg)
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();
+
// Switch the actual map, deleting the previous one
engine->changeMap(mapPath);
@@ -132,7 +138,6 @@ void PlayerHandler::handleMessage(MessageIn *msg)
float scrollOffsetY = (y - player_node->mY) * 32;
player_node->setAction(Being::STAND);
- player_node->stopAttack();
player_node->mFrame = 0;
player_node->mX = x;
player_node->mY = y;
diff --git a/src/net/protocol.h b/src/net/protocol.h
index eb41a9ac..a2aa50c3 100644
--- a/src/net/protocol.h
+++ b/src/net/protocol.h
@@ -30,6 +30,8 @@
#define SMSG_PLAYER_UPDATE_1 0x01d8
#define SMSG_PLAYER_UPDATE_2 0x01d9
#define SMSG_PLAYER_MOVE 0x01da /**< A nearby player moves */
+#define SMSG_PLAYER_STOP 0x0088 /**< Stop walking, set position */
+#define SMSG_PLAYER_MOVE_TO_ATTACK 0x0139 /**< Move to within attack range */
#define SMSG_PLAYER_STAT_UPDATE_1 0x00b0
#define SMSG_PLAYER_STAT_UPDATE_2 0x00b1
#define SMSG_PLAYER_STAT_UPDATE_3 0x0141
@@ -56,6 +58,8 @@
#define SMSG_ITEM_REMOVE 0x00a1 /**< An item disappers */
#define SMSG_BEING_VISIBLE 0x0078
#define SMSG_BEING_MOVE 0x007b /**< A nearby monster moves */
+#define SMSG_BEING_SPAWN 0x007c /**< A being spawns nearby */
+#define SMSG_BEING_MOVE2 0x0086 /**< New eAthena being moves */
#define SMSG_BEING_REMOVE 0x0080
#define SMSG_BEING_CHANGE_LOOKS 0x00c3
#define SMSG_BEING_CHANGE_LOOKS2 0x01d7 /**< Same as 0x00c3, but 16 bit ID */
@@ -87,6 +91,7 @@
#define SMSG_TRADE_COMPLETE 0x00f0
// Packets from client to server
+#define CMSG_CLIENT_PING 0x007e /**< Send to server with tick */
#define CMSG_TRADE_RESPONSE 0x00e6
#define CMSG_ITEM_PICKUP 0x009f
#define CMSG_MAP_LOADED 0x007d