summaryrefslogtreecommitdiff
path: root/src/net/tmwa
diff options
context:
space:
mode:
authorYohann Ferreira <yohann_dot_ferreira_at_orange_dot_efer>2011-04-26 23:40:37 +0200
committerYohann Ferreira <yohann_dot_ferreira_at_orange_dot_efer>2011-04-26 23:40:37 +0200
commit2d0e84449b14615bdacb6f897791628662bbfd39 (patch)
tree08019ae6c24c6da25e25da027d04ad008c25d6a2 /src/net/tmwa
parent42605753159d7b63276351311e0fd43874a3366b (diff)
parent0056412ed33b941d72a175dcd3f025abcd8fc02b (diff)
downloadmana-2d0e84449b14615bdacb6f897791628662bbfd39.tar.gz
mana-2d0e84449b14615bdacb6f897791628662bbfd39.tar.bz2
mana-2d0e84449b14615bdacb6f897791628662bbfd39.tar.xz
mana-2d0e84449b14615bdacb6f897791628662bbfd39.zip
Made the client use a unique kind of movement code.
This is fixng many issues and (hopefully) will make the movement rendering much smoother. Merge branch 'master' of gitorious.org:~bertram/mana/mana-movement-code-merge Conflicts: src/being.cpp src/net/manaserv/beinghandler.cpp Resolves: TMW-Mantis #946. Reviewed-by: Thorbjorn.
Diffstat (limited to 'src/net/tmwa')
-rw-r--r--src/net/tmwa/beinghandler.cpp108
-rw-r--r--src/net/tmwa/charserverhandler.cpp6
-rw-r--r--src/net/tmwa/gamehandler.cpp15
-rw-r--r--src/net/tmwa/gamehandler.h7
-rw-r--r--src/net/tmwa/inventoryhandler.cpp23
-rw-r--r--src/net/tmwa/itemhandler.cpp14
-rw-r--r--src/net/tmwa/playerhandler.cpp60
-rw-r--r--src/net/tmwa/playerhandler.h7
8 files changed, 188 insertions, 52 deletions
diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp
index 61491692..960f08ed 100644
--- a/src/net/tmwa/beinghandler.cpp
+++ b/src/net/tmwa/beinghandler.cpp
@@ -20,11 +20,13 @@
*/
#include "net/tmwa/beinghandler.h"
+#include "net/tmwa/playerhandler.h"
#include "actorspritemanager.h"
#include "being.h"
#include "client.h"
#include "effectmanager.h"
+#include "game.h"
#include "guild.h"
#include "localplayer.h"
#include "log.h"
@@ -37,9 +39,13 @@
#include "resources/emotedb.h"
#include <iostream>
+#include <cmath>
namespace TmwAthena {
+// Number of pixels where we decide that the position doesn't need to be reset.
+static const float POS_DEST_DIFF_TOLERANCE = 48.0f;
+
BeingHandler::BeingHandler(bool enableSync):
mSync(enableSync)
{
@@ -95,13 +101,58 @@ Being *createBeing(int id, short job)
return being;
}
+static void handleMoveMessage(Map *map, Being *dstBeing,
+ Uint16 srcX, Uint16 srcY,
+ Uint16 dstX, Uint16 dstY)
+{
+ // Avoid dealing with flawed destination
+ if (map && dstBeing && srcX && srcY && dstX && dstY)
+ {
+ Vector pos = map->getTileCenter(srcX, srcY);
+ Vector dest = map->getTileCenter(dstX, dstY);
+
+ // Don't set the position as the movement algorithm
+ // can guess it and it would break the animation played,
+ // when we're close enough.
+ if (std::abs(dest.x - pos.x) > POS_DEST_DIFF_TOLERANCE
+ || std::abs(dest.y - pos.y) > POS_DEST_DIFF_TOLERANCE)
+ dstBeing->setPosition(pos);
+
+ dstBeing->setDestination(dest.x, dest.y);
+ }
+}
+
+static void handlePosMessage(Map *map, Being *dstBeing, Uint16 x, Uint16 y,
+ Uint8 dir = 0)
+{
+ // Avoid dealing with flawed destination
+ if (map && dstBeing && x && y)
+ {
+ Vector pos = map->getTileCenter(x, y);
+ Vector beingPos = dstBeing->getPosition();
+ // Don't set the position as the movement algorithm
+ // can guess it and it would break the animation played,
+ // when we're close enough.
+ if (std::abs(beingPos.x - pos.x) > POS_DEST_DIFF_TOLERANCE
+ || std::abs(beingPos.y - pos.y) > POS_DEST_DIFF_TOLERANCE)
+ dstBeing->setPosition(pos);
+
+ // Set also the destination to the desired position.
+ dstBeing->setDestination(pos.x, pos.y);
+
+ if (dir)
+ dstBeing->setDirection(dir);
+ }
+}
+
void BeingHandler::handleMessage(Net::MessageIn &msg)
{
if (!actorSpriteManager)
return;
int id;
- short job, speed, gender;
+ short job, gender;
+ float speed;
Uint16 headTop, headMid, headBottom;
Uint16 shoes, gloves;
Uint16 weapon, shield;
@@ -114,13 +165,16 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
Being *srcBeing, *dstBeing;
int hairStyle, hairColor, flag;
+ // Prepare useful translation variables
+ Map *map = Game::instance()->getCurrentMap();
+
switch (msg.getId())
{
case SMSG_BEING_VISIBLE:
case SMSG_BEING_MOVE:
// Information about a being in range
id = msg.readInt32();
- speed = msg.readInt16();
+ speed = (float)msg.readInt16();
stunMode = msg.readInt16(); // opt1
statusEffects = msg.readInt16(); // opt2
statusEffects |= ((Uint32)msg.readInt16()) << 16; // option
@@ -146,15 +200,14 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
if (msg.getId() == SMSG_BEING_VISIBLE)
{
dstBeing->clearPath();
- dstBeing->setActionTime(tick_time);
dstBeing->setAction(Being::STAND);
}
-
// Prevent division by 0 when calculating frame
- if (speed == 0) { speed = 150; }
+ if (speed == 0)
+ speed = 150.0f; // In ticks per tile * 10
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ dstBeing->setMoveSpeed(Vector(speed / 10, speed / 10));
dstBeing->setSubtype(job);
hairStyle = msg.readInt16();
weapon = msg.readInt16();
@@ -205,17 +258,14 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
{
Uint16 srcX, srcY, dstX, dstY;
msg.readCoordinatePair(srcX, srcY, dstX, dstY);
- dstBeing->setAction(Being::STAND);
- dstBeing->setTileCoords(srcX, srcY);
- dstBeing->setDestination(dstX, dstY);
+ handleMoveMessage(map, dstBeing, srcX, srcY, dstX, dstY);
}
else
{
Uint8 dir;
Uint16 x, y;
msg.readCoordinates(x, y, dir);
- dstBeing->setTileCoords(x, y);
- dstBeing->setDirection(dir);
+ handlePosMessage(map, dstBeing, x, y, dir);
}
msg.readInt8(); // unknown
@@ -235,6 +285,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
case SMSG_BEING_MOVE2:
+ {
/*
* A simplified movement packet, used by the
* later versions of eAthena for both mobs and
@@ -254,11 +305,8 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
Uint16 srcX, srcY, dstX, dstY;
msg.readCoordinatePair(srcX, srcY, dstX, dstY);
msg.readInt32(); // Server tick
-
- dstBeing->setAction(Being::STAND);
- dstBeing->setTileCoords(srcX, srcY);
- dstBeing->setDestination(dstX, dstY);
-
+ handleMoveMessage(map, dstBeing, srcX, srcY, dstX, dstY);
+ }
break;
case SMSG_BEING_REMOVE:
@@ -479,15 +527,17 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
}
break;
case SMSG_BEING_CHANGE_DIRECTION:
+ {
if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
break;
}
msg.readInt16(); // unused
-
- dstBeing->setDirection(msg.readInt8());
-
+ Uint8 dir = msg.readInt8();
+ if (dir)
+ dstBeing->setDirection(dir);
+ }
break;
case SMSG_PLAYER_UPDATE_1:
@@ -519,7 +569,12 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
}
}
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ // The original speed is ticks per tile * 10
+ if (speed)
+ dstBeing->setMoveSpeed(Vector(speed / 10, speed / 10));
+ else
+ dstBeing->setMoveSpeed(Net::getPlayerHandler()->getDefaultMoveSpeed());
+
dstBeing->setSubtype(job);
hairStyle = msg.readInt16();
weapon = msg.readInt16();
@@ -561,16 +616,14 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
{
Uint16 srcX, srcY, dstX, dstY;
msg.readCoordinatePair(srcX, srcY, dstX, dstY);
- dstBeing->setTileCoords(srcX, srcY);
- dstBeing->setDestination(dstX, dstY);
+ handleMoveMessage(map, dstBeing, srcX, srcY, dstX, dstY);
}
else
{
Uint8 dir;
Uint16 x, y;
msg.readCoordinates(x, y, dir);
- dstBeing->setTileCoords(x, y);
- dstBeing->setDirection(dir);
+ handlePosMessage(map, dstBeing, x, y, dir);
}
gmstatus = msg.readInt16();
@@ -598,9 +651,6 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
msg.readInt8(); // Lv
msg.readInt8(); // unknown
- dstBeing->setActionTime(tick_time);
- dstBeing->reset();
-
dstBeing->setStunMode(stunMode);
dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
@@ -628,9 +678,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
Uint16 x, y;
x = msg.readInt16();
y = msg.readInt16();
- dstBeing->setTileCoords(x, y);
- if (dstBeing->getCurrentAction() == Being::MOVE)
- dstBeing->setAction(Being::STAND);
+ handlePosMessage(map, dstBeing, x, y);
}
}
break;
diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp
index 1063ee39..e6dc84a2 100644
--- a/src/net/tmwa/charserverhandler.cpp
+++ b/src/net/tmwa/charserverhandler.cpp
@@ -185,7 +185,11 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg)
mNetwork->disconnect();
Client::setState(STATE_CHANGE_MAP);
- player_node->setTileCoords(x, y);
+ Map *map = player_node->getMap();
+ int tileWidth = map->getTileWidth();
+ int tileHeight = map->getTileHeight();
+ player_node->setPosition(Vector(x * tileWidth + tileWidth / 2,
+ y * tileHeight + tileHeight / 2));
player_node->setMap(0);
}
break;
diff --git a/src/net/tmwa/gamehandler.cpp b/src/net/tmwa/gamehandler.cpp
index 0b3c7d38..2194c77d 100644
--- a/src/net/tmwa/gamehandler.cpp
+++ b/src/net/tmwa/gamehandler.cpp
@@ -76,7 +76,8 @@ void GameHandler::handleMessage(Net::MessageIn &msg)
x, y, direction);
// Switch now or we'll have problems
Client::setState(STATE_GAME);
- player_node->setTileCoords(x, y);
+ // Stores the position until the map is loaded.
+ mTileX = x; mTileY = y;
} break;
case SMSG_SERVER_PING:
@@ -111,7 +112,17 @@ void GameHandler::event(Event::Channel channel, const Event &event)
{
if (event.getType() == Event::EnginesInitialized)
{
- Game::instance()->changeMap(mMap);
+ Game *game = Game::instance();
+ game->changeMap(mMap);
+ Map *map = game->getCurrentMap();
+ int tileWidth = map->getTileWidth();
+ int tileHeight = map->getTileHeight();
+ if (mTileX && mTileY)
+ {
+ player_node->setPosition(Vector(mTileX * tileWidth + tileWidth / 2,
+ mTileY * tileHeight + tileHeight / 2));
+ mTileX = mTileY = 0;
+ }
}
else if (event.getType() == Event::MapLoaded)
{
diff --git a/src/net/tmwa/gamehandler.h b/src/net/tmwa/gamehandler.h
index a1a2e7ec..016df18e 100644
--- a/src/net/tmwa/gamehandler.h
+++ b/src/net/tmwa/gamehandler.h
@@ -65,8 +65,13 @@ class GameHandler : public MessageHandler, public Net::GameHandler,
bool canUseMagicBar() const { return true; }
private:
- std::string mMap;
+ std::string mMap; ///< Keeps the map filename.
int mCharID; /// < Saved for map-server switching
+ /**
+ * Keeps the local character position until the map is loaded
+ * to permit the translation in pixels.
+ */
+ int mTileX, mTileY;
};
} // namespace TmwAthena
diff --git a/src/net/tmwa/inventoryhandler.cpp b/src/net/tmwa/inventoryhandler.cpp
index 18e8febc..1340a091 100644
--- a/src/net/tmwa/inventoryhandler.cpp
+++ b/src/net/tmwa/inventoryhandler.cpp
@@ -24,6 +24,7 @@
#include "configuration.h"
#include "equipment.h"
#include "event.h"
+#include "game.h"
#include "inventory.h"
#include "item.h"
#include "itemshortcut.h"
@@ -408,13 +409,33 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
flag = msg.readInt8();
if (!flag)
+ {
SERVER_NOTICE(_("Unable to unequip."))
+ }
else
+ {
mEquips.setEquipment(getSlot(equipType), -1);
+ // Reset the attack range to unarmed.
+ player_node->setAttackRange(ATTACK_RANGE_NOT_SET);
+ }
break;
case SMSG_PLAYER_ATTACK_RANGE:
- player_node->setAttackRange(msg.readInt16());
+ {
+ // The range is in tiles, so we translate it back to pixels
+ Map *map = Game::instance()->getCurrentMap();
+ if (map)
+ {
+ player_node->setAttackRange(msg.readInt16()
+ * map->getTileWidth());
+ }
+ else
+ {
+ logger->log("Couldn't set attacke range due to the lack"
+ "of an initialized map.");
+ player_node->setAttackRange(ATTACK_RANGE_NOT_SET);
+ }
+ }
break;
case SMSG_PLAYER_ARROW_EQUIP:
diff --git a/src/net/tmwa/itemhandler.cpp b/src/net/tmwa/itemhandler.cpp
index a8e98860..e452ccf2 100644
--- a/src/net/tmwa/itemhandler.cpp
+++ b/src/net/tmwa/itemhandler.cpp
@@ -21,12 +21,14 @@
#include "net/tmwa/itemhandler.h"
-#include "actorspritemanager.h"
-
#include "net/messagein.h"
#include "net/tmwa/protocol.h"
+#include "actorspritemanager.h"
+#include "game.h"
+#include "map.h"
+
namespace TmwAthena {
ItemHandler::ItemHandler()
@@ -54,7 +56,13 @@ void ItemHandler::handleMessage(Net::MessageIn &msg)
int y = msg.readInt16();
msg.skip(4); // amount,subX,subY / subX,subY,amount
- actorSpriteManager->createItem(id, itemId, x, y);
+ Game *game = Game::instance();
+ if (!game)
+ break;
+
+ if (Map *map = game->getCurrentMap())
+ actorSpriteManager->createItem(id, itemId,
+ map->getTileCenter(x, y));
}
break;
diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp
index ec004917..4bd637c3 100644
--- a/src/net/tmwa/playerhandler.cpp
+++ b/src/net/tmwa/playerhandler.cpp
@@ -20,7 +20,9 @@
*/
#include "net/tmwa/playerhandler.h"
+#include "net/tmwa/beinghandler.h"
+#include "client.h"
#include "event.h"
#include "game.h"
#include "localplayer.h"
@@ -198,20 +200,23 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
float scrollOffsetX = 0.0f;
float scrollOffsetY = 0.0f;
- /* Scroll if neccessary */
+ /* Scroll if necessary */
+ Map *map = game->getCurrentMap();
+ int tileX = player_node->getTileX();
+ int tileY = player_node->getTileY();
if (!sameMap
- || (abs(x - player_node->getTileX()) > MAP_TELEPORT_SCROLL_DISTANCE)
- || (abs(y - player_node->getTileY()) > MAP_TELEPORT_SCROLL_DISTANCE))
+ || (abs(x - tileX) > MAP_TELEPORT_SCROLL_DISTANCE)
+ || (abs(y - tileY) > MAP_TELEPORT_SCROLL_DISTANCE))
{
- Map *map = game->getCurrentMap();
- scrollOffsetX = (x - player_node->getTileX())
- * map->getTileWidth();
- scrollOffsetY = (y - player_node->getTileY())
- * map->getTileHeight();
+ scrollOffsetX = (x - tileX) * map->getTileWidth();
+ scrollOffsetY = (y - tileY) * map->getTileHeight();
}
player_node->setAction(Being::STAND);
- player_node->setTileCoords(x, y);
+ Vector pos = map->getTileCenter(x, y);
+ player_node->setPosition(pos);
+ // Stop movement
+ player_node->setDestination(pos.x, pos.y);
logger->log("Adjust scrolling by %d:%d", (int) scrollOffsetX,
(int) scrollOffsetY);
@@ -228,7 +233,8 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
switch (type)
{
case 0x0000:
- player_node->setWalkSpeed(Vector(value, value, 0));
+ player_node->setMoveSpeed(Vector(value / 10,
+ value / 10, 0));
break;
case 0x0004: break; // manner
case 0x0005: PlayerInfo::setAttribute(HP, value); break;
@@ -553,8 +559,12 @@ void PlayerHandler::setDirection(char direction)
void PlayerHandler::setDestination(int x, int y, int direction)
{
+ // The destination coordinates are received in pixel, so we translate them
+ // into tiles.
+ Map *map = Game::instance()->getCurrentMap();
MessageOut outMsg(CMSG_PLAYER_CHANGE_DEST);
- outMsg.writeCoordinates(x, y, direction);
+ outMsg.writeCoordinates(x / map->getTileWidth(), y / map->getTileHeight(),
+ direction);
}
void PlayerHandler::changeAction(Being::Action action)
@@ -603,11 +613,35 @@ int PlayerHandler::getJobLocation()
return JOB;
}
-Vector PlayerHandler::getDefaultWalkSpeed()
+Vector PlayerHandler::getDefaultMoveSpeed() const
{
// Return an normalized speed for any side
// as the offset is calculated elsewhere.
- return Vector(150, 150, 0);
+ // in ticks per tile.
+ return Vector(15.0f, 15.0f, 0.0f);
+}
+
+Vector PlayerHandler::getPixelsPerTickMoveSpeed(const Vector &speed, Map *map)
+{
+ Game *game = Game::instance();
+
+ if (game && !map)
+ map = game->getCurrentMap();
+
+ if (!map || speed.x == 0 || speed.y == 0)
+ {
+ logger->log("TmwAthena::PlayerHandler: Speed set to default: "
+ "Map not yet initialized or invalid speed.");
+ return getDefaultMoveSpeed();
+ }
+
+ Vector speedInTicks;
+
+ // speedInTicks.z = 0; // We don't use z for now.
+ speedInTicks.x = 1 / speed.x * (float)map->getTileWidth();
+ speedInTicks.y = 1 / speed.y * (float)map->getTileHeight();
+
+ return speedInTicks;
}
} // namespace TmwAthena
diff --git a/src/net/tmwa/playerhandler.h b/src/net/tmwa/playerhandler.h
index cb352110..63812f47 100644
--- a/src/net/tmwa/playerhandler.h
+++ b/src/net/tmwa/playerhandler.h
@@ -58,7 +58,12 @@ class PlayerHandler : public MessageHandler, public Net::PlayerHandler
int getJobLocation();
- Vector getDefaultWalkSpeed();
+ Vector getDefaultMoveSpeed() const;
+
+ Vector getPixelsPerTickMoveSpeed(const Vector &speed, Map *map = 0);
+
+ bool usePixelPrecision()
+ { return false; }
};
} // namespace TmwAthena