summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog91
-rw-r--r--The Mana World.dev41
-rwxr-xr-xconfigure.ac3
-rw-r--r--src/Makefile.am6
-rw-r--r--src/being.cpp17
-rw-r--r--src/being.h13
-rw-r--r--src/engine.cpp23
-rwxr-xr-xsrc/floor_item.cpp17
-rwxr-xr-xsrc/floor_item.h46
-rw-r--r--src/game.cpp1802
-rw-r--r--src/game.h15
-rw-r--r--src/gui/buy.cpp10
-rw-r--r--src/gui/buysell.cpp8
-rw-r--r--src/gui/char_select.cpp213
-rw-r--r--src/gui/char_server.cpp123
-rw-r--r--src/gui/chargedialog.cpp11
-rw-r--r--src/gui/chat.cpp10
-rw-r--r--src/gui/inventorywindow.cpp3
-rw-r--r--src/gui/login.cpp246
-rw-r--r--src/gui/npc.cpp38
-rw-r--r--src/gui/npc.h17
-rw-r--r--src/gui/npc_text.cpp18
-rw-r--r--src/gui/npc_text.h12
-rw-r--r--src/gui/popupmenu.cpp46
-rw-r--r--src/gui/requesttrade.cpp16
-rw-r--r--src/gui/requesttrade.h8
-rw-r--r--src/gui/sell.cpp10
-rw-r--r--src/gui/skill.cpp9
-rw-r--r--src/gui/stats.cpp58
-rw-r--r--src/gui/status.cpp28
-rw-r--r--src/gui/status.h8
-rw-r--r--src/gui/trade.cpp41
-rw-r--r--src/inventory.cpp38
-rw-r--r--src/log.h2
-rw-r--r--src/main.cpp6
-rw-r--r--src/net/messagein.cpp151
-rw-r--r--src/net/messagein.h94
-rw-r--r--src/net/messageout.cpp130
-rw-r--r--src/net/messageout.h80
-rw-r--r--src/net/network.cpp361
-rw-r--r--src/net/network.h79
-rw-r--r--src/net/packet.cpp40
-rw-r--r--src/net/packet.h47
-rw-r--r--src/net/protocol.cpp188
-rw-r--r--src/net/protocol.h96
-rw-r--r--src/net/win2linux.h51
-rw-r--r--src/net/win2mac.cpp14
-rw-r--r--src/net/win2mac.h7
-rw-r--r--src/playerinfo.h16
-rw-r--r--src/serverinfo.h15
50 files changed, 2704 insertions, 1718 deletions
diff --git a/ChangeLog b/ChangeLog
index 75de5af1..123c62d0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,30 @@
2005-09-13 Eugenio Favalli <elvenprogrammer@gmail.com>
* The Mana World.dev: Updated to last changes.
+ * The Mana World.dev: Added latest changes to the proper branch.
+ * src/gui/login.cpp, src/net/messageout.cpp, src/net/messageout.h,
+ src/net/network.cpp, src/net/network.h: Started to use MessageOut to
+ send login data.
2005-09-13 Björn Steinbrink <B.Steinbrink@gmx.de>
+ * ChangeLog, The Mana World.dev, configure.ac, src/Makefile.am,
+ src/being.cpp, src/being.h, src/engine.cpp, src/floor_item.cpp,
+ src/floor_item.h, src/game.cpp, src/game.h, src/inventory.cpp,
+ src/log.h, src/main.cpp, src/playerinfo.h, src/serverinfo.h,
+ src/gui/buy.cpp, src/gui/buysell.cpp, src/gui/char_select.cpp,
+ src/gui/char_server.cpp, src/gui/chargedialog.cpp, src/gui/chat.cpp,
+ src/gui/inventorywindow.cpp, src/gui/login.cpp, src/gui/npc.cpp,
+ src/gui/npc.h, src/gui/npc_text.cpp, src/gui/npc_text.h,
+ src/gui/popupmenu.cpp, src/gui/requesttrade.cpp,
+ src/gui/requesttrade.h, src/gui/sell.cpp, src/gui/skill.cpp,
+ src/gui/stats.cpp, src/gui/status.cpp, src/gui/status.h,
+ src/gui/trade.cpp, src/net/messagein.cpp, src/net/messagein.h,
+ src/net/messageout.cpp, src/net/messageout.h, src/net/network.cpp,
+ src/net/network.h, src/net/packet.cpp, src/net/packet.h,
+ src/net/protocol.cpp, src/net/protocol.h, src/net/win2linux.h,
+ src/net/win2mac.cpp, src/net/win2mac.h: Merged with SDL_NET_TEST
+ branch.
* src/being.cpp, src/being.h, src/game.cpp: Simplify remove_node.
* src/being.cpp, src/being.h, src/game.cpp: Merged createBeing and
add_node into createBeing.
@@ -14,9 +35,23 @@
src/gui/login.cpp, src/gui/login.h, src/gui/updatewindow.cpp,
src/gui/updatewindow.h: Unified the loops for the various dialogs that
are shown before the actual game starts.
+ * src/gui/login.cpp: Removed a close_session call i missed.
+ * src/gui/login.cpp: Close the session only when it was opened.
2005-09-13 Bjørn Lindeijer <bjorn@lindeijer.nl>
+ * src/floor_item.cpp, src/floor_item.h, src/engine.cpp,
+ popupmenu.cpp: Made members private and provided more convenient
+ constructor.
+ * src/net/messageout.cpp: Fixed bug in destructor.
+ * src/net/network.cpp: Initialize buffers and enforce only a single
+ session at a time.
+ * src/game.cpp, src/net/protocol.h: Converted all incoming messages
+ handled in game.cpp to use the MessageIn class. This is a huge change
+ so please test if everything is still working correctly.
+ * src/gui/npc.cpp, src/gui/npc.h, src/gui/npc_text.cpp,
+ src/gui/npc_text.h: Changed argument from char* to std::string for
+ convenience.
* src/gui/setup.cpp, src/gui/setup.h: Enabled OpenGL checkbox and
added messagebox informing the user that apply this change requires
restarting the client.
@@ -39,15 +74,69 @@
* data/help/changes.txt, data/help/commands.txt: Added 0.0.16 changes.
* data/maps/new_7-1.tmx.gz: Fixed well being in the wrong layer.
+2005-09-11 Bjørn Lindeijer <bjorn@lindeijer.nl>
+
+ * src/net/network.cpp: Improved error reporting a bit and got rid of
+ loop for sending data, which shouldn't be necessary according to
+ SDL_net documentation.
+ * src/Makefile.am, src/being.cpp, src/being.h, src/engine.cpp,
+ src/game.cpp, src/main.cpp, src/playerinfo.h, src/gui/char_server.cpp,
+ src/gui/chargedialog.cpp, src/gui/chat.cpp,
+ src/gui/inventorywindow.cpp, src/gui/popupmenu.cpp, src/gui/skill.cpp,
+ src/gui/stats.cpp, src/gui/status.cpp, src/gui/status.h,
+ src/net/protocol.cpp: Changed char_info into the array it's used as
+ for character selection and introduced player_info as the pointer to
+ the player information. Should help towards support for multiple
+ characters on the same account. Also changed PLAYER_INFO name field to
+ a std::string.
+ * src/net/win2mac.cpp, src/net/win2mac.h: A bit of clean up.
+ * src/net/packet.h, src/net/packet.cpp, src/net/messagein.h,
+ src/net/messagein.cpp, src/net/messageout.h, src/net/messageout.cpp:
+ Added these packet reading/writing helpers, taken from the new server
+ in development.
+ * src/gui/char_select.cpp: Made new character message be parsed
+ using MessageIn. Many other incoming messages should be ready to be
+ ported similarly, simplifying the parsing of packets because of
+ automatic incrementation of the read position.
+ * src/game.cpp, src/game.h, src/gui/popupmenu.cpp,
+ src/gui/requesttrade.cpp, src/gui/requesttrade.h: Changed
+ tradePartnerName to std::string.
+ * src/net/win2linux.h: Removed because it became redundant with
+ the use of SDL_net.
+ * src/game.cpp, src/game.h, src/gui/char_select.cpp,
+ src/net/messagein.cpp, src/net/messagein.h, src/net/network.cpp,
+ src/net/network.h: Got rid of usage of Packet by MessageIn,
+ simplifying both its usage and implementation. Now also handling
+ response to character selection through MessageIn.
+ * src/main.cpp, src/serverinfo.h, src/gui/char_select.cpp,
+ src/gui/char_server.cpp, src/gui/login.cpp, src/net/network.cpp,
+ src/net/network.h, src/net/protocol.cpp, src/net/protocol.h:
+ Introduced get_next_message function to reduce duplication of that
+ process. Also now MessageIn is used for all incoming messages handled
+ during the login sequence.
+ * src/being.cpp, src/being.h, src/game.cpp, src/game.h,
+ src/inventory.cpp, src/serverinfo.h, src/gui/login.cpp,
+ src/gui/trade.cpp, src/net/messagein.cpp, src/net/messagein.h,
+ src/net/network.cpp, src/net/protocol.cpp, src/net/protocol.h: Added
+ readCoordinates and readCoordinatePair to MessageIn for reading the
+ specific ways eAthena sends sends those, and converted part of
+ game.cpp to use the MessageIn class. Also simplified cases where
+ flush() was still called in a loop for sending and added asserts to
+ MessageIn methods.
+
2005-09-10 Bjørn Lindeijer <bjorn@lindeijer.nl>
* src/log.cpp: Committed patch by Nayr for displaying a messagebox
when an error occurs on MacOS.
+2005-09-10 Björn Steinbrink <B.Steinbrink@gmx.de>
+
+ * configure.ac: Add check for SDL_net.
+
2005-09-09 Eugenio Favalli <elvenprogrammer@gmail.com>
* src/game.cpp: Fixes to dropped items network code
-
+
2005-09-09 Bjørn Lindeijer <bjorn@lindeijer.nl>
* src/net/win2linux.h: Removed inclusion of malloc.h header as it
diff --git a/The Mana World.dev b/The Mana World.dev
index be26c0f1..ef8b7765 100644
--- a/The Mana World.dev
+++ b/The Mana World.dev
@@ -1,7 +1,7 @@
[Project]
FileName=The Mana World.dev
Name=tmw
-UnitCount=161
+UnitCount=167
Type=0
Ver=1
ObjFiles=
@@ -11,8 +11,8 @@ PrivateResource=The_Mana_World_private.rc
ResourceIncludes=
MakeIncludes=
Compiler=
-CppCompiler=-DUSE_OPENGL_@@_-DDEBUG_@@__@@_
-Linker=-lopengl32_@@_-lwsock32_@@_-lmingw32_@@_-lguichan_@@_-lguichan_sdl_@@_-lguichan_opengl_@@_-lSDLmain_@@_-lSDL_@@_-lSDL_image_@@_-lSDL_mixer_@@_-lcurl_@@_-lphysfs_@@_-lxml2_@@_-lz_@@_
+CppCompiler=-DUSE_OPENGL_@@_
+Linker=-lguichan_@@_-lguichan_sdl_@@_-lguichan_opengl_@@_-lwsock32_@@_-lSDL_image_@@_-lSDL_mixer_@@_-lSDL_net_@@_-lmingw32_@@_-lSDLmain_@@_-lSDL_@@_-lxml2_@@_-lopengl32_@@_-lz_@@_-lphysfs_@@_-lcurl_@@_
IsCpp=1
Icon=The Mana World.ico
ExeOutput=
@@ -1617,6 +1617,26 @@ Priority=1000
OverrideBuildCmd=0
BuildCmd=
+[Unit166]
+FileName=src\net\messagein.cpp
+CompileCpp=1
+Folder=net/source
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit167]
+FileName=src\net\messagein.h
+CompileCpp=1
+Folder=net/header
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
[Unit160]
FileName=src\resources\sdlimageloader.cpp
CompileCpp=1
@@ -1668,9 +1688,9 @@ OverrideBuildCmd=0
BuildCmd=
[Unit162]
-FileName=src\net\messageout.h
+FileName=src\net\messageout.cpp
CompileCpp=1
-Folder=net/header
+Folder=net/source
Compile=1
Link=1
Priority=1000
@@ -1678,9 +1698,9 @@ OverrideBuildCmd=0
BuildCmd=
[Unit163]
-FileName=src\net\messagein.cpp
+FileName=src\net\messageout.h
CompileCpp=1
-Folder=net/source
+Folder=net/header
Compile=1
Link=1
Priority=1000
@@ -1688,7 +1708,7 @@ OverrideBuildCmd=0
BuildCmd=
[Unit164]
-FileName=src\net\messageout.cpp
+FileName=src\net\packet.cpp
CompileCpp=1
Folder=net/source
Compile=1
@@ -1698,12 +1718,11 @@ OverrideBuildCmd=0
BuildCmd=
[Unit165]
-FileName=src\net\packet.cpp
+FileName=src\net\packet.h
CompileCpp=1
-Folder=net/source
+Folder=net/header
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
-
diff --git a/configure.ac b/configure.ac
index 4073dcb7..4c63e860 100755
--- a/configure.ac
+++ b/configure.ac
@@ -40,6 +40,9 @@ AC_CHECK_LIB(SDL_mixer, Mix_OpenAudio, ,
AC_MSG_ERROR([ *** Unable to find SDL_mixer library
(http://www.libsdl.org/projects/SDL_mixer/)]))
+AC_CHECK_LIB(SDL_net, SDLNet_Init, ,
+AC_MSG_ERROR([ *** Unable to find SDL_net library]))
+
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([arpa/inet.h fcntl.h malloc.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h])
diff --git a/src/Makefile.am b/src/Makefile.am
index 5172a6d2..850a7f2c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -104,8 +104,14 @@ tmw_SOURCES = graphic/spriteset.cpp \
gui/hbox.cpp \
gui/updatewindow.h \
gui/updatewindow.cpp \
+ net/messagein.cpp \
+ net/messagein.h \
+ net/messageout.cpp \
+ net/messageout.h \
net/network.cpp \
net/network.h \
+ net/packet.cpp \
+ net/packet.h \
net/protocol.cpp \
net/protocol.h \
net/win2linux.h \
diff --git a/src/being.cpp b/src/being.cpp
index 2bb0beff..3fdc2f2b 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -64,10 +64,11 @@ Being* createBeing(unsigned int id, unsigned short job, Map *map)
beings.push_back(being);
// If the being is a player, request the name
- if (being->getType() == Being::PLAYER) {
- WFIFOW(0) = net_w_value(0x0094);
- WFIFOL(2) = net_l_value(RFIFOL(2));
- WFIFOSET(6);
+ if (being->getType() == Being::PLAYER)
+ {
+ writeWord(0, 0x0094);
+ writeLong(2, being->getId());//readLong(2));
+ writeSet(6);
}
// If the being is a monster then load the monsterset
else if (being->job >= 1002 &&
@@ -100,7 +101,7 @@ void remove_node(Being *being)
Being *findNode(unsigned int id)
{
std::list<Being*>::iterator i;
- for (i = beings.begin(); i != beings.end(); i++) {
+ for (i = beings.begin(); i != beings.end(); i++) {
Being *being = (*i);
if (being->getId() == id) {
return being;
@@ -166,7 +167,6 @@ Being::Being():
damage_time(0),
showSpeech(false), showDamage(false)
{
- strcpy(name, "");
}
Being::~Being()
@@ -245,11 +245,6 @@ void Being::setMap(Map *map)
this->map = map;
}
-void Being::setName(char *text)
-{
- strcpy(name, text);
-}
-
void Being::nextStep()
{
if (!path.empty())
diff --git a/src/being.h b/src/being.h
index 2a9a8421..98aaeb80 100644
--- a/src/being.h
+++ b/src/being.h
@@ -87,7 +87,6 @@ class Being
unsigned char emotion_time; /**< Time until emotion disappears */
unsigned int text_x, text_y; // temp solution to fix speech position
- char name[24]; /**< Name of character */
unsigned short aspd; /**< Attack speed */
/**
@@ -129,11 +128,18 @@ class Being
void setDamage(const std::string &text, int time);
/**
- * Sets the name for the being
+ * Returns the name of the being.
+ */
+ const std::string&
+ getName() { return mName; }
+
+ /**
+ * Sets the name for the being.
*
* @param text The name that should appear.
*/
- void setName(char *name);
+ void
+ setName(const std::string &name) { mName = name; }
/**
* Sets the hair color for this being.
@@ -225,6 +231,7 @@ class Being
unsigned int speech_time;
unsigned int damage_time;
bool showSpeech, showDamage;
+ std::string mName; /**< Name of character */
/**
* Sets the new path for this being.
diff --git a/src/engine.cpp b/src/engine.cpp
index 97ba1c2c..956fbfa6 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -279,12 +279,13 @@ void Engine::draw()
for (std::list<FloorItem*>::iterator i = floorItems.begin(); i != floorItems.end(); i++)
{
FloorItem *floorItem = (*i);
- if (itemDb->getItemInfo(floorItem->id)->getImage() > 0) {
+ if (itemDb->getItemInfo(floorItem->getItemId())->getImage() > 0) {
Image *image = itemset->spriteset[itemDb->getItemInfo(
- floorItem->id)->getImage() - 1];
+ floorItem->getItemId())->getImage() - 1];
graphics->drawImage(image,
- floorItem->x * 32 - map_x, floorItem->y * 32 - map_y);
+ floorItem->getX() * 32 - map_x,
+ floorItem->getY() * 32 - map_y);
}
}
@@ -297,10 +298,6 @@ void Engine::draw()
int x = being->x * 32 - map_x;
int y = being->y * 32 - map_y;
-#ifdef DEBUG
- graphics->setColor(gcn::Color(0, 0, 255));
- graphics->drawRectangle(gcn::Rectangle(x & ~31, y & ~31, 32, 32));
-#endif
int frame;
switch (being->getType())
{
@@ -323,10 +320,6 @@ void Engine::draw()
graphics->drawImage(playerset->spriteset[frame + 16 * dir],
being->text_x - 16, being->text_y - 32);
- //if (being->action == ATTACK)
- //{
- // std::cout << being->name << " " << being->getWeapon() << std::endl;
- //}
if (being->getWeapon() != 0 && being->action == Being::ATTACK) {
Image *image = weaponset->spriteset[
16 * (being->getWeapon() - 1) + 4 * being->frame + dir];
@@ -351,9 +344,9 @@ void Engine::draw()
}
graphics->setFont(speechFont);
- graphics->drawText(being->name,
- being->text_x + 15, being->text_y + 30,
- gcn::Graphics::CENTER);
+ graphics->drawText(being->getName(),
+ being->text_x + 15, being->text_y + 30,
+ gcn::Graphics::CENTER);
graphics->setFont(gui->getFont());
break;
@@ -465,6 +458,7 @@ void Engine::draw()
gcn::Graphics::CENTER);
}
+#ifdef DEBUG
std::stringstream debugStream;
debugStream << "[" << fps << " fps] " << mouseTileX << ", " << mouseTileY;
@@ -477,6 +471,7 @@ void Engine::draw()
debugInfo->setCaption(debugStream.str());
debugInfo->adjustSize();
+#endif
gui->draw();
}
diff --git a/src/floor_item.cpp b/src/floor_item.cpp
index d7c597fe..691c5acd 100755
--- a/src/floor_item.cpp
+++ b/src/floor_item.cpp
@@ -45,7 +45,7 @@ void remove_floor_item(unsigned int int_id)
{
std::list<FloorItem *>::iterator i;
for (i = floorItems.begin(); i != floorItems.end(); i++) {
- if ((*i)->int_id == int_id) {
+ if ((*i)->getId() == int_id) {
delete (*i);
floorItems.erase(i);
return;
@@ -58,9 +58,9 @@ unsigned int find_floor_item_by_cor(unsigned short x, unsigned short y)
std::list<FloorItem *>::iterator i;
for (i = floorItems.begin(); i != floorItems.end(); i++) {
FloorItem *floorItem = (*i);
- if (floorItem->x == x && floorItem->y == y)
+ if (floorItem->getX() == x && floorItem->getY() == y)
{
- return floorItem->int_id;
+ return floorItem->getId();
}
}
return 0;
@@ -71,18 +71,9 @@ FloorItem *find_floor_item_by_id(unsigned int int_id)
std::list<FloorItem*>::iterator i;
for (i = floorItems.begin(); i != floorItems.end(); i++) {
FloorItem *floorItem = (*i);
- if (floorItem->int_id == int_id) {
+ if (floorItem->getId() == int_id) {
return floorItem;
}
}
return NULL;
}
-
-FloorItem::FloorItem():
- id(0), int_id(0), x(0), y(0)
-{
-}
-
-FloorItem::~FloorItem()
-{
-}
diff --git a/src/floor_item.h b/src/floor_item.h
index 2c31525e..cd3293b4 100755
--- a/src/floor_item.h
+++ b/src/floor_item.h
@@ -24,22 +24,50 @@
#ifndef _TMW_FLOORITEM_H
#define _TMW_FLOORITEM_H
-class FloorItem {
- private:
+/**
+ * An item lying on the floor.
+ */
+class FloorItem
+{
public:
- unsigned int id;
- unsigned int int_id;
- unsigned short x, y;
-
/**
* Constructor.
*/
- FloorItem();
+ FloorItem(unsigned int id,
+ unsigned int itemId,
+ unsigned short x,
+ unsigned short y):
+ id(itemId),
+ int_id(id),
+ x(x),
+ y(y)
+ {
+ }
/**
- * Destructor.
+ * Returns instance id of this item.
*/
- ~FloorItem();
+ unsigned int getId() { return int_id; }
+
+ /**
+ * Returns the item id.
+ */
+ unsigned int getItemId() { return id; }
+
+ /**
+ * Returns the x coordinate.
+ */
+ unsigned short getX() { return x; }
+
+ /**
+ * Returns the y coordinate.
+ */
+ unsigned short getY() { return y; }
+
+ private:
+ unsigned int id;
+ unsigned int int_id;
+ unsigned short x, y;
};
/** Removes all items from the list */
diff --git a/src/game.cpp b/src/game.cpp
index c2620742..ba860822 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -72,7 +72,7 @@
extern Graphics *graphics;
char map_path[480];
-char tradePartnerName[24];
+std::string tradePartnerName;
bool refresh_beings = false;
unsigned char keyb_state;
@@ -81,7 +81,7 @@ volatile bool action_time = false;
int server_tick;
int fps = 0, frame = 0, current_npc = 0;
bool displayPathToMouse = false;
-int startX = 0, startY = 0;
+unsigned short startX = 0, startY = 0;
int gameTime = 0;
Being *autoTarget = NULL;
Engine *engine = NULL;
@@ -121,9 +121,9 @@ const int MAX_TIME = 10000;
class DeatchNoticeListener : public gcn::ActionListener {
public:
void action(const std::string &eventId) {
- WFIFOW(0) = net_w_value(0x00b2);
- WFIFOB(2) = 0;
- WFIFOSET(3);
+ writeWord(0, 0x00b2);
+ writeByte(2, 0);
+ writeSet(3);
deathNotice = NULL;
}
} deathNoticeListener;
@@ -298,14 +298,15 @@ void do_init()
player_node->x = startX;
player_node->y = startY;
player_node->speed = 150;
- player_node->setHairColor(char_info->hair_color);
- player_node->setHairStyle(char_info->hair_style);
+ player_node->setHairColor(player_info->hair_color);
+ player_node->setHairStyle(player_info->hair_style);
- if (char_info->weapon == 11) {
- char_info->weapon = 2;
+ if (player_info->weapon == 11)
+ {
+ player_info->weapon = 2;
}
- player_node->setWeapon(char_info->weapon);
+ player_node->setWeapon(player_info->weapon);
remove("packet.list");
@@ -489,9 +490,9 @@ void do_input()
else if (deathNotice)
{
deathNotice->action("ok");
- WFIFOW(0) = net_w_value(0x00b2);
- WFIFOB(2) = 0;
- WFIFOSET(3);
+ writeWord(0, 0x00b2);
+ writeByte(2, 0);
+ writeSet(3);
deathNotice = NULL;
}
// Close the Browser if opened
@@ -539,9 +540,9 @@ void do_input()
if (id)
{
- WFIFOW(0) = net_w_value(0x009f);
- WFIFOL(2) = net_l_value(id);
- WFIFOSET(6);
+ writeWord(0, 0x009f);
+ writeLong(2, id);
+ writeSet(6);
}
used = true;
}
@@ -639,9 +640,9 @@ void do_input()
if (emotion)
{
- WFIFOW(0) = net_w_value(0x00bf);
- WFIFOB(2) = emotion;
- WFIFOSET(3);
+ writeWord(0, 0x00bf);
+ writeByte(2, emotion);
+ writeSet(3);
action_time = false;
used = true;
}
@@ -676,20 +677,20 @@ void do_input()
{
// Player default: trade
case Being::PLAYER:
- WFIFOW(0) = net_w_value(0x00e4);
- WFIFOL(2) = net_l_value(target->getId());
- WFIFOSET(6);
- strcpy(tradePartnerName, target->name);
+ writeWord(0, 0x00e4);
+ writeLong(2, target->getId());
+ writeSet(6);
+ tradePartnerName = target->getName();
break;
// NPC default: talk
case Being::NPC:
if (!current_npc)
{
- WFIFOW(0) = net_w_value(0x0090);
- WFIFOL(2) = net_l_value(target->getId());
- WFIFOB(6) = 0;
- WFIFOSET(7);
+ writeWord(0, 0x0090);
+ writeLong(2, target->getId());
+ writeByte(6, 0);
+ writeSet(7);
current_npc = target->getId();
}
break;
@@ -730,26 +731,30 @@ void do_input()
// "sqrt(dx*dx + dy*dy) < 2" is equal to "dx*dx + dy*dy < 4"
if ((dx*dx + dy*dy) < 4)
{
- WFIFOW(0) = net_w_value(0x009f);
- WFIFOL(2) = net_l_value(floorItemId);
- WFIFOSET(6);
+ writeWord(0, 0x009f);
+ writeLong(2, floorItemId);
+ writeSet(6);
}
}
- // Just cancel the popup menu if shown, and don't make the character walk
+ // Just cancel the popup menu if shown, and don't make the
+ // character walk
if (popupMenu->isVisible() == true)
{
- // If we click elsewhere than in the window, do not use the event
+ // If we click elsewhere than in the window, do not use
+ // the event
// The user wanted to close the popup.
- // Still buggy : Wonder if the x, y, width, and height aren't reported partially
- // with these functions.
- if (event.button.x >= (popupMenu->getX() + popupMenu->getWidth()) ||
- event.button.x < popupMenu->getX() ||
- event.button.y >= (popupMenu->getY() + popupMenu->getHeight()) ||
- event.button.y < popupMenu->getY())
+ // Still buggy : Wonder if the x, y, width, and height
+ // aren't reported partially with these functions.
+ if (event.button.x >=
+ (popupMenu->getX() + popupMenu->getWidth()) ||
+ event.button.x < popupMenu->getX() ||
+ event.button.y >=
+ (popupMenu->getY() + popupMenu->getHeight()) ||
+ event.button.y < popupMenu->getY())
{
- used = true;
- popupMenu->setVisible(false);
+ used = true;
+ popupMenu->setVisible(false);
}
}
@@ -795,7 +800,7 @@ void do_input()
}
} // End while
-
+
// Moving player around
if ((player_node->action != Being::DEAD) && (current_npc == 0) &&
!chatWindow->isFocused())
@@ -875,7 +880,7 @@ void do_input()
yDirection = 0;
// Choose a straight direction when diagonal target is blocked
- if ((yDirection != 0) && (xDirection != 0) &&
+ if ((yDirection != 0) && (xDirection != 0) &&
!tiledMap->getWalk(x + xDirection, y + yDirection))
xDirection = 0;
@@ -919,9 +924,9 @@ void do_input()
if (id != 0)
{
- WFIFOW(0) = net_w_value(0x009f);
- WFIFOL(2) = net_l_value(id);
- WFIFOSET(6);
+ writeWord(0, 0x009f);
+ writeLong(2, id);
+ writeSet(6);
}
}
else if (joy[JOY_BTN2] && action_time)
@@ -935,145 +940,175 @@ void do_input()
}
}
-int get_packet_length(short id)
-{
- int len = get_length(id);
- if (len == -1) len = RFIFOW(2);
- return len;
-}
-
void do_parse()
{
- unsigned short id;
- char *temp;
- Being *being = NULL;
- FloorItem *floorItem = NULL;
- int len, n_items;
+ int n_items;
Map *tiledMap = engine->getCurrentMap();
Equipment *equipment = Equipment::getInstance();
// We need at least 2 bytes to identify a packet
- if (in_size >= 2) {
- // Check if the received packet is complete
- while (in_size >= (len = get_packet_length(id = RFIFOW(0)))) {
-#ifdef DEBUG
- printf("Packet_ID: %x\n", RFIFOW(0));
-#endif
-
- // Parse packet based on their id
- switch (id)
- {
- case SMSG_LOGIN_SUCCESS:
- // Connected to game server succesfully, set spawn point
- player_node->x = get_x(RFIFOP(6));
- player_node->y = get_y(RFIFOP(6));
- break;
+ while (in_size >= 2)
+ {
+ MessageIn msg = get_next_message();
+
+ // Parse packet based on their id
+ switch (msg.getId())
+ {
+ case SMSG_LOGIN_SUCCESS:
+ // Connected to game server succesfully, set spawn point
+ {
+ msg.readLong(); // server tick
+ msg.readCoordinates(player_node->x,
+ player_node->y,
+ player_node->direction);
+ msg.skip(2); // unknown
+ }
+ break;
// Received speech from being
- case SMSG_BEING_CHAT:
- being = findNode(RFIFOL(4));
- if (being != NULL)
+ case SMSG_BEING_CHAT:
+ {
+ int chatMsgLength = msg.readShort() - 8;
+ Being *being = findNode(msg.readLong());
+
+ if (being != NULL && chatMsgLength > 0)
{
- int length = RFIFOW(2) - 8;
- temp = (char*)malloc(length + 1);
- temp[length] = '\0';
- memcpy(temp, RFIFOP(8), length);
- std::string msg = std::string(temp);
- msg.erase(0, msg.find(" : ", 0) + 3);
+ std::string chatMsg = msg.readString(chatMsgLength);
- being->setSpeech(msg, SPEECH_TIME);
- chatWindow->chat_log(temp, BY_OTHER);
+ chatWindow->chat_log(chatMsg, BY_OTHER);
- free(temp);
+ chatMsg.erase(0, chatMsg.find(" : ", 0) + 3);
+ being->setSpeech(chatMsg, SPEECH_TIME);
}
- break;
+ }
+ break;
- case SMSG_MY_BEING_CHAT:
- case SMSG_GM_CHAT:
- if (RFIFOW(2) > 4)
+ case SMSG_PLAYER_CHAT:
+ case SMSG_GM_CHAT:
+ {
+ int chatMsgLength = msg.readShort() - 4;
+
+ if (chatMsgLength > 0)
{
- int length = RFIFOW(2) - 4;
- temp = (char*)malloc(length + 1);
- temp[length] = '\0';
- memcpy(temp, RFIFOP(4), length);
- std::string msg = std::string(temp);
- unsigned int pos = msg.find(" : ", 0);
-
- if (id == 0x008e)
+ std::string chatMsg = msg.readString(chatMsgLength);
+
+ if (msg.getId() == SMSG_PLAYER_CHAT)
{
+ chatWindow->chat_log(chatMsg, BY_PLAYER);
+
+ unsigned int pos = chatMsg.find(" : ", 0);
if (pos != std::string::npos)
{
- msg.erase(0, pos + 3);
+ chatMsg.erase(0, pos + 3);
}
- player_node->setSpeech(msg, SPEECH_TIME);
- chatWindow->chat_log(temp, BY_PLAYER);
+ player_node->setSpeech(chatMsg, SPEECH_TIME);
}
- else
+ else
{
- chatWindow->chat_log(temp, BY_GM);
+ chatWindow->chat_log(chatMsg, BY_GM);
}
-
- free(temp);
- }
- break;
-
- case SMSG_WALK_RESPONSE:
- // It is assumed by the client any request to walk actually
- // succeeds on the server. The plan is to have a correction
- // message when the server senses the client has the wrong
- // idea.
- break;
-
- // Add new being / stop monster
- case 0x0078:
-
- int beingId;
- beingId = RFIFOL(2);
- int beingJob;
- beingJob = RFIFOW(14);
-
- // Being with id >= 110000000 and job 0 are better known
- // as ghosts, so don't create those.
- if (beingJob == 0 && beingId >= 110000000)
- {
- break;
}
+ }
+ break;
+
+ case SMSG_WALK_RESPONSE:
+ // It is assumed by the client any request to walk actually
+ // succeeds on the server. The plan is to have a correction
+ // message when the server senses the client has the wrong
+ // idea.
+ break;
+
+ case SMSG_BEING_VISIBLE:
+ case SMSG_BEING_MOVE:
+ // Information about a being in range
+ {
+ int id = msg.readLong();
+ unsigned short speed = msg.readShort();
+ msg.readShort(); // unknown
+ msg.readShort(); // unknown
+ msg.readShort(); // option
+ unsigned short job = msg.readShort(); // class
- being = findNode(beingId);
+ Being *being = findNode(id);
if (being == NULL)
{
- being = createBeing(beingId, beingJob, tiledMap);
- being->speed = RFIFOW(6);
- if (being->speed == 0) {
- // Else division by 0 when calculating frame
- being->speed = 150;
+ // Being with id >= 110000000 and job 0 are better
+ // known as ghosts, so don't create those.
+ if (job == 0 && id >= 110000000)
+ {
+ break;
}
- being->setHairStyle(RFIFOW(16));
- being->setHairColor(RFIFOW(28));
- being->setWeapon(RFIFOW(18));
- being->setMap(tiledMap);
+
+ being = createBeing(id, job, tiledMap);
}
- else
+ else if (msg.getId() == 0x0078)
{
being->clearPath();
- //being->setWeapon(RFIFOW(18));
being->frame = 0;
being->walk_time = tick_time;
being->action = Being::STAND;
}
- being->x = get_x(RFIFOP(46));
- being->y = get_y(RFIFOP(46));
- being->direction = get_direction(RFIFOP(46));
- break;
- case SMSG_REMOVE_BEING:
- // A being should be removed or has died
- being = findNode(RFIFOL(2));
+ // Prevent division by 0 when calculating frame
+ if (speed == 0) { speed = 150; }
+
+ being->speed = speed;
+ being->job = job;
+ being->setHairStyle(msg.readShort());
+ being->setWeapon(msg.readShort());
+ msg.readShort(); // head option bottom
+
+ if (msg.getId() == SMSG_BEING_MOVE)
+ {
+ msg.readLong(); // server tick
+ }
+
+ msg.readShort(); // shield
+ msg.readShort(); // head option top
+ msg.readShort(); // head option mid
+ being->setHairColor(msg.readShort());
+ msg.readShort(); // unknown
+ msg.readShort(); // head dir
+ msg.readShort(); // guild
+ msg.readShort(); // unknown
+ msg.readShort(); // unknown
+ msg.readShort(); // manner
+ msg.readShort(); // karma
+ msg.readByte(); // unknown
+ msg.readByte(); // sex
+
+ if (msg.getId() == SMSG_BEING_MOVE)
+ {
+ unsigned short srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY);
+ being->action = Being::STAND;
+ being->x = srcX;
+ being->y = srcY;
+ being->setDestination(dstX, dstY);
+ }
+ else
+ {
+ msg.readCoordinates(being->x, being->y,
+ being->direction);
+ }
+
+ msg.readByte(); // unknown
+ msg.readByte(); // unknown
+ msg.readByte(); // unknown / sit
+ }
+ break;
+
+ case SMSG_BEING_REMOVE:
+ // A being should be removed or has died
+ {
+ Being *being = findNode(msg.readLong());
+
if (being != NULL)
{
- if (RFIFOB(6) == 1)
- { // Death
+ if (msg.readByte() == 1)
+ {
+ // Death
switch (being->getType())
{
case Being::MONSTER:
@@ -1086,275 +1121,326 @@ void do_parse()
being->action = Being::DEAD;
break;
}
- //remove_node(RFIFOL(2));
}
- else {
+ else
+ {
remove_node(being);
}
- if (being == autoTarget) {
+ if (being == autoTarget)
+ {
autoTarget = NULL;
}
}
- break;
+ }
+ break;
+
+ case SMSG_PLAYER_UPDATE_1:
+ case SMSG_PLAYER_UPDATE_2:
+ case SMSG_PLAYER_MOVE:
+ // An update about a player, potentially including movement.
+ {
+ int id = msg.readLong();
+ unsigned short speed = msg.readShort();
+ msg.readShort(); // option 1
+ msg.readShort(); // option 2
+ msg.readShort(); // option
+ unsigned short job = msg.readShort();
- case SMSG_PLAYER_UPDATE_1:
- case SMSG_PLAYER_UPDATE_2:
- // A message about a player, doesn't include movement.
- being = findNode(RFIFOL(2));
+ Being *being = findNode(id);
- if (being == NULL)
+ if (being == NULL)
{
- being = createBeing(RFIFOL(2), RFIFOW(14), tiledMap);
+ being = createBeing(id, job, tiledMap);
}
- being->speed = RFIFOW(6);
- being->job = RFIFOW(14);
- being->setHairStyle(RFIFOW(16));
- being->setHairColor(RFIFOW(28));
- being->x = get_x(RFIFOP(46));
- being->y = get_y(RFIFOP(46));
- being->direction = get_direction(RFIFOP(46));
- being->walk_time = tick_time;
- being->frame = 0;
- being->setWeaponById(RFIFOW(18));
+ being->speed = speed;
+ being->job = job;
+ being->setHairStyle(msg.readShort());
+ being->setWeaponById(msg.readShort()); // item id 1
+ msg.readShort(); // item id 2
+ msg.readShort(); // head option bottom
- if (RFIFOB(51) == 2)
+ if (msg.getId() == SMSG_PLAYER_MOVE)
{
- being->action = Being::SIT;
+ msg.readLong(); // server tick
}
- break;
- case SMSG_MOVE_BEING:
- // A being nearby is moving
- being = findNode(RFIFOL(2));
-
- if (being == NULL)
+ msg.readShort(); // head option top
+ msg.readShort(); // head option mid
+ being->setHairColor(msg.readShort());
+ msg.readShort(); // unknown
+ msg.readShort(); // head dir
+ msg.readLong(); // guild
+ msg.readLong(); // emblem
+ msg.readShort(); // manner
+ msg.readByte(); // karma
+ msg.readByte(); // sex
+
+ if (msg.getId() == SMSG_PLAYER_MOVE)
{
- being = createBeing(RFIFOL(2), RFIFOW(14), tiledMap);
+ unsigned short srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY);
+ being->x = srcX;
+ being->y = srcY;
+ being->setDestination(dstX, dstY);
+ }
+ else
+ {
+ msg.readCoordinates(being->x, being->y,
+ being->direction);
}
- being->action = Being::STAND;
- being->x = get_src_x(RFIFOP(50));
- being->y = get_src_y(RFIFOP(50));
- being->speed = RFIFOW(6);
- being->job = RFIFOW(14);
- being->setDestination(
- get_dest_x(RFIFOP(50)),
- get_dest_y(RFIFOP(50)));
- break;
-
- case SMSG_MOVE_PLAYER_BEING:
- // A nearby player being moves
- being = findNode(RFIFOL(2));
+ msg.readByte(); // unknown
+ msg.readByte(); // unknown
- if (being == NULL)
+ if (msg.getId() == SMSG_PLAYER_UPDATE_1)
{
- being = createBeing(RFIFOL(2), RFIFOW(14), tiledMap);
+ if (msg.readByte() == 2)
+ {
+ being->action = Being::SIT;
+ }
+ }
+ else if (msg.getId() == SMSG_PLAYER_MOVE)
+ {
+ msg.readByte(); // unknown
}
- being->speed = RFIFOW(6);
- being->job = RFIFOW(14);
- being->x = get_src_x(RFIFOP(50));
- being->y = get_src_y(RFIFOP(50));
- being->setHairStyle(RFIFOW(16));
- being->setWeaponById(RFIFOW(18));
- being->setHairColor(RFIFOW(32));
-
- being->setDestination(
- get_dest_x(RFIFOP(50)),
- get_dest_y(RFIFOP(50)));
- break;
+ msg.readByte(); // Lv
+ msg.readByte(); // unknown
- // NPC dialog
- case 0x00b4:
- npcTextDialog->addText(RFIFOP(8));
- npcListDialog->setVisible(false);
- npcTextDialog->setVisible(true);
- current_npc = RFIFOL(4);
+ being->walk_time = tick_time;
+ being->frame = 0;
+ }
+ break;
+
+ case SMSG_NPC_MESSAGE:
+ msg.readShort(); // length
+ current_npc = msg.readLong();
+ npcTextDialog->addText(msg.readString(msg.getLength() - 8));
+ npcListDialog->setVisible(false);
+ npcTextDialog->setVisible(true);
+ break;
+
+ case SMSG_NPC_NEXT:
+ case SMSG_NPC_CLOSE:
+ // Next/Close button in NPC dialog, currently unused
+ break;
+
+ case SMSG_TRADE_REQUEST:
+ // If a trade window or request window is already open, send a
+ // trade cancel to any other trade request.
+ //
+ // Note that it would be nice if the server would prevent this
+ // situation, and that the requesting player would get a
+ // special message about the player being occupied.
+
+ if (tradeWindow->isVisible() == true || requestTradeDialogOpen)
+ {
+ writeWord(0, CMSG_TRADE_RESPONSE);
+ writeByte(2, 0x04);
+ writeSet(3);
break;
+ }
- // Trade: Receiving a request to trade
- case 0x00e5:
- // If a trade window is already open, send a trade cancel
- // to any other trade request.
- // It would still be nice to implement an independent message
- // that the person you want to trade with can't do that now.
- if (tradeWindow->isVisible() == true)
- {
- // 0xff packet means cancel
- WFIFOW(0) = net_w_value(0x00e6);
- WFIFOB(2) = net_b_value(4);
- WFIFOSET(3);
+ requestTradeDialogOpen = true;
+ tradePartnerName = msg.readString(24);
+ new RequestTradeDialog(tradePartnerName);
+ break;
+
+ case SMSG_TRADE_RESPONSE:
+ switch (msg.readByte())
+ {
+ case 0: // Too far away
+ chatWindow->chat_log("Trading isn't possible. "
+ "Trade partner is too far away.",
+ BY_SERVER);
break;
+ case 1: // Character doesn't exist
+ chatWindow->chat_log("Trading isn't possible. "
+ "Character doesn't exist.",
+ BY_SERVER);
+ break;
+ case 2: // Invite request check failed...
+ chatWindow->chat_log("Trade cancelled due to an "
+ "unknown reason.", BY_SERVER);
+ break;
+ case 3: // Trade accepted
+ tradeWindow->reset();
+ tradeWindow->setCaption(
+ "Trade: You and " + tradePartnerName);
+ tradeWindow->setVisible(true);
+ requestTradeDialogOpen = false;
+ break;
+ case 4: // Trade cancelled
+ chatWindow->chat_log("Trade cancelled.", BY_SERVER);
+ tradeWindow->setVisible(false);
+ break;
+ default: // Shouldn't happen as well, but to be sure
+ chatWindow->chat_log("Unhandled trade cancel packet",
+ BY_SERVER);
+ break;
+ }
+ break;
+
+ case SMSG_TRADE_ITEM_ADD:
+ {
+ long amount = msg.readLong();
+ short type = msg.readShort();
+ msg.readByte(); // identified flag
+ msg.readByte(); // attribute
+ msg.readByte(); // refine
+ msg.skip(8); // card (4 shorts)
+
+ // TODO: handle also identified, etc
+ if (type == 0) {
+ tradeWindow->addMoney(amount);
+ } else {
+ tradeWindow->addItem(type, false, amount, false);
}
- if (!requestTradeDialogOpen)
- {
- requestTradeDialogOpen = true;
- strcpy(tradePartnerName, RFIFOP(2));
- new RequestTradeDialog(RFIFOP(2));
- }
- break;
+ }
+ break;
- // Trade: Response
- case 0x00e7:
- switch (RFIFOB(2))
+ case SMSG_TRADE_ITEM_ADD_RESPONSE:
+ // Trade: New Item add response (was 0x00ea, now 01b1)
+ {
+ Item *item = inventory->getItem(msg.readShort());
+ short quantity = msg.readShort();
+
+ switch (msg.readByte())
{
case 0:
- // too far away
- chatWindow->chat_log("Trading isn't possible. Trade partner is too far away.", BY_SERVER);
+ // Successfully added item
+ if (item->isEquipment() && item->isEquipped())
+ {
+ inventory->unequipItem(item);
+ }
+ tradeWindow->addItem(item->getId(), true, quantity,
+ item->isEquipment());
+ item->increaseQuantity(-quantity);
break;
case 1:
- // Character doesn't exist
- chatWindow->chat_log("Trading isn't possible. Character doesn't exist.", BY_SERVER);
- break;
- case 2:
- // invite request check failed...
- chatWindow->chat_log("Trade cancelled due to an unknown reason.", BY_SERVER);
- break;
- case 3:
- // Trade accepted
- tradeWindow->reset();
- tradeWindow->setCaption((std::string)"Trade: You and " + (std::string)tradePartnerName);
- tradeWindow->setVisible(true);
- requestTradeDialogOpen = false;
- break;
- case 4:
- // Trade cancelled
- chatWindow->chat_log("Trade cancelled.", BY_SERVER);
- tradeWindow->setVisible(false);
+ // Add item failed - player overweighted
+ chatWindow->chat_log("Failed adding item. Trade "
+ "partner is over weighted.",
+ BY_SERVER);
break;
default:
- // Shouldn't happen as well, but to be sure
- chatWindow->chat_log("Unhandled trade cancel packet",
- BY_SERVER);
+ chatWindow->chat_log("Failed adding item for "
+ "unknown reason.", BY_SERVER);
break;
}
- break;
- // Trade: Item added on trade partner's side
- case 0x00e9:
- // TODO: handle also identified, etc
- if (RFIFOW(6) == 0)
- {
- tradeWindow->addMoney(RFIFOL(2));
- }
- else
- {
- tradeWindow->addItem(RFIFOW(6), false, RFIFOL(2), false);
- }
- break;
- // Trade: New Item add response
- case 0x01b1:
- {
- Item *item = inventory->getItem(RFIFOW(2));
- switch (RFIFOB(6))
- {
- case 0:
- // Successfully added item
- if (item->isEquipment() && item->isEquipped())
- {
- inventory->unequipItem(item);
- }
- tradeWindow->addItem(
- item->getId(), true, RFIFOW(4),
- item->isEquipment());
- item->increaseQuantity(-RFIFOW(4));
- break;
- case 1:
- // Add item failed - player overweighted
- chatWindow->chat_log("Failed adding item. Trade "
- "partner is over weighted.", BY_SERVER);
- break;
- default:
- //printf("Unhandled 0x00ea byte!\n");
- break;
- }
- }
- break;
- // Trade received Ok message
- case 0x00ec:
- // 0 means ok from myself, 1 means ok from other;
- tradeWindow->receivedOk((RFIFOB(2) == 0));
- break;
-
- // Trade cancelled
- case 0x00ee:
- chatWindow->chat_log("Trade cancelled.", BY_SERVER);
- tradeWindow->setVisible(false);
- tradeWindow->reset();
- break;
-
- // Trade completed
- case 0x00f0:
- chatWindow->chat_log("Trade completed.", BY_SERVER);
- tradeWindow->setVisible(false);
- tradeWindow->reset();
- break;
- // Get the items
- // Only called on map load / warp
- case 0x01ee:
- // Reset all items to not load them twice on map change
+ }
+ break;
+
+ case SMSG_TRADE_OK:
+ // 0 means ok from myself, 1 means ok from other;
+ tradeWindow->receivedOk(msg.readByte() == 0);
+ break;
+
+ case SMSG_TRADE_CANCEL:
+ chatWindow->chat_log("Trade canceled.", BY_SERVER);
+ tradeWindow->setVisible(false);
+ tradeWindow->reset();
+ break;
+
+ case SMSG_TRADE_COMPLETE:
+ chatWindow->chat_log("Trade completed.", BY_SERVER);
+ tradeWindow->setVisible(false);
+ tradeWindow->reset();
+ break;
+
+ case SMSG_PLAYER_INVENTORY:
+ {
+ // Only called on map load / warp. First reset all items
+ // to not load them twice on map change.
inventory->resetItems();
+ msg.readShort(); // length
+ int number = (msg.getLength() - 4) / 18;
- for (int loop = 0; loop < (RFIFOW(2) - 4) / 18; loop++)
+ for (int loop = 0; loop < number; loop++)
{
- inventory->addItem(RFIFOW(4 + loop * 18),
- RFIFOW(4 + loop * 18 + 2),
- RFIFOW(4 + loop * 18 + 6), false);
+ short index = msg.readShort();
+ short itemId = msg.readShort();
+ msg.readByte(); // type
+ msg.readByte(); // identify flag
+ short amount = msg.readShort();
+ msg.skip(2); // unknown
+ msg.skip(8); // card (4 shorts)
+
+ inventory->addItem(index, itemId, amount, false);
+
// Trick because arrows are not considered equipment
- if (RFIFOW(4 + loop * 18 + 2) == 1199 ||
- RFIFOW(4 + loop * 18 + 2) == 529)
+ if (itemId == 1199 || itemId == 529)
{
- inventory->getItem(
- RFIFOW(4 + loop * 18))->setEquipment(true);
+ inventory->getItem(index)->setEquipment(true);
}
}
- break;
+ }
+ break;
- // Get the equipments
- case 0x00a4:
+ case SMSG_PLAYER_EQUIPMENT:
+ {
+ msg.readShort(); // length
+ int number = (msg.getLength() - 4) / 20;
- for (int loop = 0; loop < ((RFIFOW(2) - 4) / 20); loop++)
+ for (int loop = 0; loop < number; loop++)
{
- inventory->addItem(RFIFOW(4 + loop * 20),
- RFIFOW(4 + loop * 20 + 2), 1, true);
- if (RFIFOW(4 + loop * 20 + 8))
+ short index = msg.readShort();
+ short itemId = msg.readShort();
+ msg.readByte(); // type
+ msg.readByte(); // identify flag
+ msg.readShort(); // equip type
+ short equipPoint = msg.readShort();
+ msg.readByte(); // attribute
+ msg.readByte(); // refine
+ msg.skip(8); // card
+
+ inventory->addItem(index, itemId, 1, true);
+
+ if (equipPoint)
{
int mask = 1;
int position = 0;
- while(!(RFIFOW(4+loop*20+8) & mask))
+ while (!(equipPoint & mask))
{
- mask *= 2;
+ mask <<= 1;
position++;
}
- Item *item = inventory->getItem(RFIFOW(4+loop*20));
+ Item *item = inventory->getItem(index);
item->setEquipped(true);
equipment->setEquipment(position - 1, item);
}
}
- break;
- // Can I use the item?
- case 0x00a8:
- if (RFIFOB(6) == 0)
- {
+ }
+ break;
+
+ case SMSG_ITEM_USE_RESPONSE:
+ {
+ short index = msg.readShort();
+ short amount = msg.readShort();
+
+ if (msg.readByte() == 0) {
chatWindow->chat_log("Failed to use item", BY_SERVER);
+ } else {
+ inventory->getItem(index)->setQuantity(amount);
}
- else
- {
- inventory->getItem(RFIFOW(2))->setQuantity(RFIFOW(4));
- }
- break;
- // Warp
- case 0x0091:
- memset(map_path, '\0', 480);
- strcat(map_path, "maps/");
- strncat(map_path, RFIFOP(2), 497 - strlen(map_path));
- logger->log("Warping to %s (%d, %d)",
- map_path, RFIFOW(18), RFIFOW(20));
+ }
+ break;
+
+ case SMSG_PLAYER_WARP:
+ {
+ // Set new map path
+ strcpy(map_path,
+ std::string("maps/" + msg.readString(16)).c_str());
strcpy(strrchr(map_path, '.') + 1, "tmx.gz");
- Map *oldMap;
- oldMap = tiledMap;
+ int x = msg.readShort();
+ int y = msg.readShort();
+
+ logger->log("Warping to %s (%d, %d)", map_path, x, y);
+
+ Map *oldMap = tiledMap;
tiledMap = MapReader::readMap(map_path);
if (tiledMap)
@@ -1371,21 +1457,23 @@ void do_parse()
delete (*i);
}
beings.clear();
+
autoTarget = NULL;
+ current_npc = 0;
// Re-add the local player node
beings.push_back(player_node);
player_node->action = Being::STAND;
player_node->frame = 0;
- player_node->x = RFIFOW(18);
- player_node->y = RFIFOW(20);
+ player_node->x = x;
+ player_node->y = y;
player_node->setMap(tiledMap);
- current_npc = 0;
+
// Send "map loaded"
- WFIFOW(0) = net_w_value(0x007d);
- WFIFOSET(2);
- while (out_size > 0) flush();
+ writeWord(0, 0x007d);
+ writeSet(2);
+ flush();
engine->setCurrentMap(tiledMap);
}
else
@@ -1393,491 +1481,611 @@ void do_parse()
logger->error("Could not find map file");
}
if (oldMap) delete oldMap;
- break;
- // Action failed (ex. sit because you have not reached the right level)
- case 0x0110:
- CHATSKILL action;
- action.skill = RFIFOW(2);
- action.bskill = RFIFOW(4);
- action.unused = RFIFOW(6);
- action.success = RFIFOB(8);
- action.reason = RFIFOB(9);
- if(action.success != SKILL_FAILED &&
- action.bskill == BSKILL_EMOTE ) {
- printf("Action: %d/%d", action.bskill, action.success);
- }
- chatWindow->chat_log(action);
- break;
- // Update stat values
- case 0x00b0:
- switch(RFIFOW(2)) {
- //case 0x0000:
- // player_node->speed;
- // break;
- case 0x0005:
- char_info->hp = RFIFOW(4);
- break;
- case 0x0006:
- char_info->max_hp = RFIFOW(4);
- break;
- case 0x0007:
- char_info->sp = RFIFOW(4);
- break;
- case 0x0008:
- char_info->max_sp = RFIFOW(4);
- break;
- case 0x000b:
- char_info->lv = RFIFOW(4);
- break;
- case 0x000c:
- char_info->skill_point = RFIFOW(4);
- skillDialog->setPoints(char_info->skill_point);
- break;
- case 0x0018:
- char_info->totalWeight = RFIFOW(4);
- break;
- case 0x0019:
- char_info->maxWeight = RFIFOW(4);
- break;
- case 0x0037:
- char_info->job_lv = RFIFOW(4);
- break;
- case 0x0009:
- char_info->statsPointsToAttribute = RFIFOW(4);
- break;
- case 0x0035:
- player_node->aspd = RFIFOW(4);
- break;
- }
- if (char_info->hp == 0 && deathNotice == NULL) {
- deathNotice = new OkDialog("Message",
- "You're now dead, press ok to restart",
- &deathNoticeListener);
- deathNotice->releaseModalFocus();
- player_node->action = Being::DEAD;
- }
- break;
- // Stop walking
+ }
+ break;
+
+ case SMSG_SKILL_FAILED:
+ // Action failed (ex. sit because you have not reached the
+ // right level)
+ CHATSKILL action;
+ action.skill = msg.readShort();
+ action.bskill = msg.readShort();
+ action.unused = msg.readShort(); // unknown
+ action.success = msg.readByte();
+ action.reason = msg.readByte();
+ if (action.success != SKILL_FAILED &&
+ action.bskill == BSKILL_EMOTE)
+ {
+ printf("Action: %d/%d", action.bskill, action.success);
+ }
+ chatWindow->chat_log(action);
+ break;
+
+ case SMSG_PLAYER_STAT_UPDATE_1:
+ switch (msg.readShort())
+ {
+ //case 0x0000:
+ // player_node->speed = msg.readLong();
+ // break;
+ case 0x0005:
+ player_info->hp = msg.readLong();
+ break;
+ case 0x0006:
+ player_info->max_hp = msg.readLong();
+ break;
+ case 0x0007:
+ player_info->sp = msg.readLong();
+ break;
+ case 0x0008:
+ player_info->max_sp = msg.readLong();
+ break;
+ case 0x000b:
+ player_info->lv = msg.readLong();
+ break;
+ case 0x000c:
+ player_info->skill_point = msg.readLong();
+ skillDialog->setPoints(player_info->skill_point);
+ break;
+ case 0x0018:
+ player_info->totalWeight = msg.readLong();
+ break;
+ case 0x0019:
+ player_info->maxWeight = msg.readLong();
+ break;
+ case 0x0037:
+ player_info->job_lv = msg.readLong();
+ break;
+ case 0x0009:
+ player_info->statsPointsToAttribute = msg.readLong();
+ break;
+ case 0x0035:
+ player_node->aspd = msg.readLong();
+ break;
+ }
+
+ if (player_info->hp == 0 && deathNotice == NULL)
+ {
+ deathNotice = new OkDialog("Message",
+ "You're now dead, press ok to restart",
+ &deathNoticeListener);
+ deathNotice->releaseModalFocus();
+ player_node->action = Being::DEAD;
+ }
+ break;
+
+ // Stop walking
// case 0x0088: // Disabled because giving some problems
- //if (being = findNode(RFIFOL(2))) {
- // if (being->getId()!=player_node->getId()) {
- // being->action = STAND;
- // being->frame = 0;
- // set_coordinates(being->coordinates, RFIFOW(6), RFIFOW(8), get_direction(being->coordinates));
- // }
- //}
- //break;
- // Damage, sit, stand up
- case 0x008a:
- switch (RFIFOB(26)) {
+ //if (being = findNode(readLong(2))) {
+ // if (being->getId() != player_node->getId()) {
+ // being->action = STAND;
+ // being->frame = 0;
+ // set_coordinates(being->coordinates,
+ // readWord(6), readWord(8),
+ // get_direction(being->coordinates));
+ // }
+ //}
+ //break;
+
+ case SMSG_BEING_ACTION:
+ {
+ Being *srcBeing = findNode(msg.readLong());
+ Being *dstBeing = findNode(msg.readLong());
+ msg.readLong(); // server tick
+ msg.readLong(); // src speed
+ msg.readLong(); // dst speed
+ short param1 = msg.readShort();
+ msg.readShort(); // param 2
+ char type = msg.readByte();
+ msg.readShort(); // param 3
+
+ switch (type)
+ {
case 0: // Damage
- being = findNode(RFIFOL(6));
- if (being != NULL) {
-
- if (RFIFOW(22) == 0) {
- // Yellow
- being->setDamage("miss", SPEECH_TIME);
- } else {
- // Blue for monster, red for player
- std::stringstream ss;
- ss << RFIFOW(22);
- being->setDamage(ss.str(), SPEECH_TIME);
- }
-
- if (RFIFOL(2) != player_node->getId()) { // buggy
- being = findNode(RFIFOL(2));
- if (being) {
- being->action = Being::ATTACK;
- being->frame = 0;
- being->walk_time = tick_time;
- being->frame = 0;
- }
- }
+ if (dstBeing == NULL) break;
+
+ if (param1 == 0) {
+ // Yellow
+ dstBeing->setDamage("miss", SPEECH_TIME);
+ } else {
+ // Blue for monster, red for player
+ std::stringstream ss;
+ ss << param1;
+ dstBeing->setDamage(ss.str(), SPEECH_TIME);
}
- break;
- case 2: // Sit
- case 3: // Stand up
- being = findNode(RFIFOL(2));
- if (being != NULL) {
- being->frame = 0;
- if (RFIFOB(26) == 2) {
- being->action = Being::SIT;
- }
- else if (RFIFOB(26) == 3) {
- being->action = Being::STAND;
- }
+
+ if (srcBeing != NULL &&
+ srcBeing != player_node)
+ {
+ // buggy
+ srcBeing->action = Being::ATTACK;
+ srcBeing->frame = 0;
+ srcBeing->walk_time = tick_time;
+ srcBeing->frame = 0;
}
break;
- }
- break;
- // Status change
- case 0x00b1:
- switch (RFIFOW(2)) {
- case 1:
- char_info->xp = RFIFOL(4);
- break;
- case 2:
- char_info->job_xp = RFIFOL(4);
- break;
- case 20:
- char_info->gp = RFIFOL(4);
- break;
- case 0x0016:
- char_info->xpForNextLevel = RFIFOL(4);
+
+ case 2: // Sit
+ if (srcBeing == NULL) break;
+ srcBeing->frame = 0;
+ srcBeing->action = Being::SIT;
break;
- case 0x0017:
- char_info->jobXpForNextLevel = RFIFOL(4);
+
+ case 3: // Stand up
+ if (srcBeing == NULL) break;
+ srcBeing->frame = 0;
+ srcBeing->action = Being::STAND;
break;
}
- break;
- // Level up
- case 0x019b:
+ }
+ break;
+
+ case SMSG_PLAYER_STAT_UPDATE_2:
+ switch (msg.readShort()) {
+ case 0x0001:
+ player_info->xp = msg.readLong();
+ break;
+ case 0x0002:
+ player_info->job_xp = msg.readLong();
+ break;
+ case 0x0014:
+ player_info->gp = msg.readLong();
+ break;
+ case 0x0016:
+ player_info->xpForNextLevel = msg.readLong();
+ break;
+ case 0x0017:
+ player_info->jobXpForNextLevel = msg.readLong();
+ break;
+ }
+ break;
+
+ case SMSG_BEING_LEVELUP:
+ if ((unsigned long)msg.readLong() == player_node->getId()) {
logger->log("Level up");
- if (RFIFOL(2) == player_node->getId()) {
- sound.playSfx("sfx/levelup.ogg");
- }
- break;
- // Emotion
- case 0x00c0:
- being = findNode(RFIFOL(2));
- if(being) {
- being->emotion = RFIFOB(6);
- being->emotion_time = EMOTION_TIME;
- }
- break;
- // Update skill values
- case 0x0141:
- switch(RFIFOL(2)) {
- case 0x000d:
- char_info->STR = RFIFOL(6) + RFIFOL(10); // Base + Bonus
- break;
- case 0x000e:
- char_info->AGI = RFIFOL(6) + RFIFOL(10);
- break;
- case 0x000f:
- char_info->VIT = RFIFOL(6) + RFIFOL(10);
- break;
- case 0x0010:
- char_info->INT = RFIFOL(6) + RFIFOL(10);
- break;
- case 0x0011:
- char_info->DEX = RFIFOL(6) + RFIFOL(10);
- break;
- case 0x0012:
- char_info->LUK = RFIFOL(6) + RFIFOL(10);
- break;
+ sound.playSfx("sfx/levelup.ogg");
+ } else {
+ logger->log("Someone else went level up");
+ }
+ msg.readLong(); // type
+ break;
+
+ case SMSG_BEING_EMOTION:
+ {
+ Being *being = findNode(msg.readLong());
+ if (being == NULL) break;
+
+ being->emotion = msg.readByte();
+ being->emotion_time = EMOTION_TIME;
+ }
+ break;
+
+ case SMSG_PLAYER_STAT_UPDATE_3:
+ {
+ long type = msg.readLong();
+ long base = msg.readLong();
+ long bonus = msg.readLong();
+ long total = base + bonus;
+
+ switch (type) {
+ case 0x000d: player_info->STR = total; break;
+ case 0x000e: player_info->AGI = total; break;
+ case 0x000f: player_info->VIT = total; break;
+ case 0x0010: player_info->INT = total; break;
+ case 0x0011: player_info->DEX = total; break;
+ case 0x0012: player_info->LUK = total; break;
}
- break;
- // Buy/Sell dialog
- case 0x00c4:
- buyDialog->setVisible(false);
- buyDialog->reset();
- sellDialog->setVisible(false);
+ }
+ break;
+
+ case SMSG_NPC_BUY_SELL_CHOICE:
+ buyDialog->setVisible(false);
+ buyDialog->reset();
+ sellDialog->setVisible(false);
+ sellDialog->reset();
+ buySellDialog->setVisible(true);
+ current_npc = msg.readLong();
+ break;
+
+ case SMSG_NPC_BUY:
+ msg.readShort(); // length
+ n_items = (msg.getLength() - 4) / 11;
+ buyDialog->reset();
+ buyDialog->setMoney(player_info->gp);
+ buyDialog->setVisible(true);
+
+ for (int k = 0; k < n_items; k++)
+ {
+ long value = msg.readLong();
+ msg.readLong(); // DCvalue
+ msg.readByte(); // type
+ short itemId = msg.readShort();
+ buyDialog->addItem(itemId, value);
+ }
+ break;
+
+ case SMSG_NPC_SELL:
+ msg.readShort(); // length
+ n_items = (msg.getLength() - 4) / 10;
+ if (n_items > 0) {
sellDialog->reset();
- buySellDialog->setVisible(true);
- current_npc = RFIFOL(2);
- break;
- // Buy dialog
- case 0x00c6:
- n_items = (len - 4) / 11;
- buyDialog->reset();
- buyDialog->setMoney(char_info->gp);
- buyDialog->setVisible(true);
- for (int k = 0; k < n_items; k++) {
- buyDialog->addItem(RFIFOW(4 + 11 * k + 9), RFIFOL(4 + 11 * k));
- }
- break;
- // Sell dialog
- case 0x00c7:
- n_items = (len - 4) / 10;
- if (n_items > 0) {
- sellDialog->reset();
- sellDialog->setVisible(true);
- for (int k = 0; k < n_items; k++) {
- Item *item = inventory->getItem(RFIFOW(4 + 10 * k));
- if (item && !(item->isEquipped())) {
- sellDialog->addItem(item, RFIFOL(4 + 10 * k + 2));
- }
+ sellDialog->setVisible(true);
+
+ for (int k = 0; k < n_items; k++)
+ {
+ short index = msg.readShort();
+ long value = msg.readLong();
+ msg.readLong(); // OCvalue
+
+ Item *item = inventory->getItem(index);
+ if (item && !(item->isEquipped())) {
+ sellDialog->addItem(item, value);
}
}
- else {
- chatWindow->chat_log("Nothing to sell", BY_SERVER);
- current_npc = 0;
- }
- break;
- // Answer to buy
- case 0x00ca:
- if (RFIFOB(2) == 0)
- chatWindow->chat_log("Thanks for buying", BY_SERVER);
- else
- chatWindow->chat_log("Unable to buy", BY_SERVER);
- break;
- // Answer to sell
- case 0x00cb:
- if (RFIFOB(2) == 0)
- chatWindow->chat_log("Thanks for selling", BY_SERVER);
- else
- chatWindow->chat_log("Unable to sell", BY_SERVER);
- break;
- // Add item to inventory after you bought it/picked up
- case 0x00a0:
- if (RFIFOB(22) > 0)
- chatWindow->chat_log("Unable to pick up item", BY_SERVER);
- else {
- inventory->addItem(RFIFOW(2), RFIFOW(6),
- RFIFOW(4), RFIFOW(19) != 0);
+ }
+ else {
+ chatWindow->chat_log("Nothing to sell", BY_SERVER);
+ current_npc = 0;
+ }
+ break;
+
+ case SMSG_NPC_BUY_RESPONSE:
+ if (msg.readByte() == 0) {
+ chatWindow->chat_log("Thanks for buying", BY_SERVER);
+ } else {
+ chatWindow->chat_log("Unable to buy", BY_SERVER);
+ }
+ break;
+
+ case SMSG_NPC_SELL_RESPONSE:
+ if (msg.readByte() == 0) {
+ chatWindow->chat_log("Thanks for selling", BY_SERVER);
+ } else {
+ chatWindow->chat_log("Unable to sell", BY_SERVER);
+ }
+ break;
+
+ case SMSG_PLAYER_INVENTORY_ADD:
+ {
+ short index = msg.readShort();
+ short amount = msg.readShort();
+ short itemId = msg.readShort();
+ msg.readByte(); // identify flag
+ msg.readByte(); // attribute
+ msg.readByte(); // refine
+ msg.skip(8); // card
+ short equipType = msg.readShort();
+ msg.readByte(); // type
+ char fail = msg.readByte();
+
+ if (fail > 0) {
+ chatWindow->chat_log("Unable to pick up item",
+ BY_SERVER);
+ } else {
+ inventory->addItem(index, itemId, amount,
+ equipType != 0);
}
- break;
- // Decrease quantity of an item in inventory
- case 0x00af:
- inventory->getItem(RFIFOW(2))->increaseQuantity(-RFIFOW(4));
- break;
- // Use an item
- case 0x01c8:
- inventory->getItem(RFIFOW(2))->setQuantity( RFIFOW(10));
- break;
- // Skill list TAG
- case 0x010f:
- n_items = (len - 4) / 37;
- skillDialog->cleanList();
- for (int k = 0; k < n_items; k++)
+ }
+ break;
+
+ case SMSG_PLAYER_INVENTORY_REMOVE:
+ {
+ short index = msg.readShort();
+ short amount = msg.readShort();
+ inventory->getItem(index)->increaseQuantity(-amount);
+ }
+ break;
+
+ case SMSG_PLAYER_INVENTORY_USE:
+ {
+ short index = msg.readShort();
+ msg.readShort(); // item id
+ msg.readLong(); // id
+ short amountLeft = msg.readShort();
+ msg.readByte(); // type
+
+ inventory->getItem(index)->setQuantity(amountLeft);
+ }
+ break;
+
+ case SMSG_PLAYER_SKILLS:
+ msg.readShort(); // length
+ n_items = (msg.getLength() - 4) / 37;
+ skillDialog->cleanList();
+
+ for (int k = 0; k < n_items; k++)
+ {
+ short skillId = msg.readShort();
+ msg.readShort(); // target type
+ msg.readShort(); // unknown
+ short level = msg.readShort();
+ short sp = msg.readShort();
+ msg.readShort(); // range
+ std::string skillName = msg.readString(24);
+ char up = msg.readByte();
+
+ if (level != 0 || up != 0)
{
- if (RFIFOW(4 + k * 37 + 6) != 0 ||
- RFIFOB(4 + k * 37 + 36)!=0)
- {
- int skillId = RFIFOW(4 + k * 37);
- if (skillDialog->hasSkill(skillId)) {
- skillDialog->setSkill(skillId,
- RFIFOW(4 + k * 37 + 6),
- RFIFOB(4 + k * 37 + 36));
- }
- else {
- skillDialog->addSkill(
- RFIFOW(4 + k * 37),
- RFIFOW(4 + k * 37 + 6),
- RFIFOW(4 + k * 37 + 8));
- }
+ if (skillDialog->hasSkill(skillId)) {
+ skillDialog->setSkill(skillId, level, sp);
+ }
+ else {
+ skillDialog->addSkill(skillId, level, sp);
}
}
- break;
- // Display MVP player
- case 0x010c:
- chatWindow->chat_log("MVP player", BY_SERVER);
- break;
- // Item found/dropped
- case 0x009d:
- case 0x009e:
- floorItem = new FloorItem();
- floorItem->id = RFIFOW(6);
- floorItem->x = RFIFOW(9);
- floorItem->y = RFIFOW(11);
- floorItem->int_id = RFIFOL(2);
- add_floor_item(floorItem);
- break;
- // Item disappearing
- case 0x00a1:
- remove_floor_item(RFIFOL(2));
- break;
- // Next/Close button in NPC dialog
- case 0x00b5:
- case 0x00b6:
- // Unused
- break;
- // List in NPC dialog
- case 0x00b7:
- current_npc = RFIFOL(4);
- // RFIFOW(2) seems to be the full packet length, thus -8
- npcListDialog->parseItems(RFIFOP(8), RFIFOW(2)-8);
- npcListDialog->setVisible(true);
- break;
+ }
+ break;
- case SMSG_CHANGE_BEING_LOOKS:
- being = findNode(RFIFOL(2));
- if (being) {
- switch (RFIFOB(6)) {
+ case 0x010c:
+ // Display MVP player
+ msg.readLong(); // id
+ chatWindow->chat_log("MVP player", BY_SERVER);
+ break;
+
+ case SMSG_ITEM_VISIBLE:
+ case SMSG_ITEM_DROPPED:
+ {
+ long id = msg.readLong();
+ short itemId = msg.readShort();
+ msg.readByte(); // identify flag
+ short x = msg.readShort();
+ short y = msg.readShort();
+ msg.skip(4); // amount,subX,subY / subX,subY,amount
+
+ add_floor_item(new FloorItem(id, itemId, x, y));
+ }
+ break;
+
+ case SMSG_ITEM_REMOVE:
+ remove_floor_item(msg.readLong());
+ break;
+
+ case SMSG_NPC_CHOICE:
+ msg.readShort(); // length
+ current_npc = msg.readLong();
+ npcListDialog->parseItems(msg.readString(msg.getLength() - 8));
+ npcListDialog->setVisible(true);
+ break;
+
+ case SMSG_BEING_CHANGE_LOOKS:
+ {
+ Being *being = findNode(msg.readLong());
+
+ if (being)
+ {
+ switch (msg.readByte()) {
case 1:
- being->setHairStyle(RFIFOB(7));
+ being->setHairStyle(msg.readByte());
break;
case 2:
- being->setWeapon(RFIFOB(7));
- break;
+ being->setWeapon(msg.readByte());
+ break;
case 6:
- being->setHairColor(RFIFOB(7));
+ being->setHairColor(msg.readByte());
+ break;
+ default:
+ msg.readByte(); // unsupported
break;
}
}
- break;
+ }
+ break;
- // Answer to equip item
- case 0x00aa:
- logger->log("Equipping: %i %i %i", RFIFOW(2), RFIFOW(4), RFIFOB(6));
- if (RFIFOB(6) == 0)
- chatWindow->chat_log("Unable to equip.", BY_SERVER);
- else {
- if(RFIFOW(4)) {
- int mask = 1;
- int position = 0;
- while(!(RFIFOW(4) & mask)) {
- mask *= 2;
- position++;
- }
- logger->log("Position %i", position-1);
- Item *item = equipment->getEquipment(position - 1);
- if (item)
- item->setEquipped(false);
+ case SMSG_PLAYER_EQUIP:
+ {
+ short index = msg.readShort();
+ short equipPoint = msg.readShort();
+ char type = msg.readByte();
- item = inventory->getItem(RFIFOW(2));
- item->setEquipped(true);
- equipment->setEquipment(position - 1, item);
- player_node->setWeaponById(item->getId());
+ logger->log("Equipping: %i %i %i",
+ index, equipPoint, type);
+
+ if (type == 0) {
+ chatWindow->chat_log("Unable to equip.", BY_SERVER);
+ }
+ else if (equipPoint)
+ {
+ // Unequip any existing equipped item in this position
+ int mask = 1;
+ int position = 0;
+ while (!equipPoint & mask) {
+ mask <<= 1;
+ position++;
}
+ logger->log("Position %i", position - 1);
+ Item *item = equipment->getEquipment(position - 1);
+ if (item) {
+ item->setEquipped(false);
+ }
+
+ item = inventory->getItem(index);
+ item->setEquipped(true);
+ equipment->setEquipment(position - 1, item);
+ player_node->setWeaponById(item->getId());
}
- break;
- // Equipment related
- case 0x01d7:
- being = findNode(RFIFOL(2));
+ }
+ break;
+
+ case 0x01d7:
+ // Equipment related
+ {
+ Being *being = findNode(msg.readLong());
+ msg.readByte(); // equip point
+ short itemId1 = msg.readShort();
+ msg.readShort(); // item id 2
+
if (being != NULL)
{
- being->setWeaponById(RFIFOW(7));
+ being->setWeaponById(itemId1);
}
- //logger->log("1d7 %i %i %i %i", RFIFOL(2), RFIFOB(6), RFIFOW(7), RFIFOW(9));
- break;
+ }
+ break;
+
+ case SMSG_PLAYER_UNEQUIP:
+ {
+ short index = msg.readShort();
+ short equipPoint = msg.readShort();
+ char type = msg.readByte();
- // Answer to unequip item
- case 0x00ac:
- if (RFIFOB(6) == 0)
+ if (type == 0) {
chatWindow->chat_log("Unable to unequip.", BY_SERVER);
- else {
- if(RFIFOW(4)) {
- int mask = 1;
- int position = 0;
- while(!(RFIFOW(4) & mask)) {
- mask *= 2;
- position++;
- }
+ break;
+ }
- Item *item = inventory->getItem(RFIFOW(2));
- item->setEquipped(false);
- switch (item->getId()) {
- case 529:
- case 1199:
- equipment->setArrows(NULL);
- break;
- case 521:
- case 522:
- case 530:
- case 536:
- case 1200:
- case 1201:
- player_node->setWeapon(0);
- break; // TODO : why this break ? shouldn't a weapon be unequipped in inventory too ?
- default:
- equipment->removeEquipment(position - 1);
- break;
- }
- logger->log("Unequipping: %i %i(%i) %i", RFIFOW(2),RFIFOW(4),RFIFOB(6), position -1);
- }
+ if (equipPoint == 0) {
+ // No point given, no point in searching
+ break;
}
- break;
- // Arrows equipped
- case 0x013c:
- if (RFIFOW(2) > 1) {
- Item *item = inventory->getItem(RFIFOW(2));
- item->setEquipped(true);
- equipment->setArrows(item);
- logger->log("Arrows equipped: %i", RFIFOW(2));
+
+ int mask = 1;
+ int position = 0;
+ while (!equipPoint & mask) {
+ mask <<= 1;
+ position++;
}
- break;
- // Various messages
- case 0x013b:
- if (RFIFOW(2) == 0)
- chatWindow->chat_log("Equip arrows first", BY_SERVER);
- else
- logger->log("0x013b: Unhandled message %i", RFIFOW(2));
- break;
- // Updates a stat value
- case 0x00bc:
- if(RFIFOB(4)) {
- switch(RFIFOW(2)) {
- case 0x000d:
- char_info->STR = RFIFOB(5);
- break;
- case 0x000e:
- char_info->AGI = RFIFOB(5);
- break;
- case 0x000f:
- char_info->VIT = RFIFOB(5);
- break;
- case 0x0010:
- char_info->INT = RFIFOB(5);
+
+ Item *item = inventory->getItem(index);
+
+ if (item != NULL)
+ {
+ item->setEquipped(false);
+
+ switch (item->getId()) {
+ case 529:
+ case 1199:
+ equipment->setArrows(NULL);
break;
- case 0x0011:
- char_info->DEX = RFIFOB(5);
+ case 521:
+ case 522:
+ case 530:
+ case 536:
+ case 1200:
+ case 1201:
+ player_node->setWeapon(0);
+ // TODO: Why this break? Shouldn't a weapon be
+ // unequipped in inventory too?
break;
- case 0x0012:
- char_info->LUK = RFIFOB(5);
+ default:
+ equipment->removeEquipment(position - 1);
break;
}
+ logger->log("Unequipping: %i %i(%i) %i",
+ index, equipPoint, type, position - 1);
}
- break;
- // Updates stats and status points
- case 0x00bd:
- char_info->statsPointsToAttribute = RFIFOW(2);
- char_info->STR = RFIFOB(4);
- char_info->STRUp = RFIFOB(5);
- char_info->AGI = RFIFOB(6);
- char_info->AGIUp = RFIFOB(7);
- char_info->VIT = RFIFOB(8);
- char_info->VITUp = RFIFOB(9);
- char_info->INT = RFIFOB(10);
- char_info->INTUp = RFIFOB(11);
- char_info->DEX = RFIFOB(12);
- char_info->DEXUp = RFIFOB(13);
- char_info->LUK = RFIFOB(14);
- char_info->LUKUp = RFIFOB(15);
- break;
- // Updates status point
- case 0x00be:
- switch(RFIFOW(2)) {
- case 0x0020:
- char_info->STRUp = RFIFOB(4);
- break;
- case 0x0021:
- char_info->AGIUp = RFIFOB(4);
- break;
- case 0x0022:
- char_info->VITUp = RFIFOB(4);
- break;
- case 0x0023:
- char_info->INTUp = RFIFOB(4);
- break;
- case 0x0024:
- char_info->DEXUp = RFIFOB(4);
+ }
+ break;
+
+ case SMSG_PLAYER_ARROW_EQUIP:
+ {
+ short id = msg.readShort();
+
+ if (id > 1) {
+ Item *item = inventory->getItem(id);
+ if (item) {
+ item->setEquipped(true);
+ equipment->setArrows(item);
+ logger->log("Arrows equipped: %i", id);
+ }
+ }
+ }
+ break;
+
+ case SMSG_PLAYER_ARROW_MESSAGE:
+ {
+ short type = msg.readShort();
+
+ switch (type) {
+ case 0:
+ chatWindow->chat_log("Equip arrows first",
+ BY_SERVER);
break;
- case 0x0025:
- char_info->LUKUp = RFIFOB(4);
+ default:
+ logger->log("0x013b: Unhandled message %i", type);
break;
}
- break;
- // Get being name
- case 0x0095:
- being = findNode(RFIFOL(2));
- if (being)
+ }
+ break;
+
+ case SMSG_PLAYER_STAT_UPDATE_4:
+ {
+ short type = msg.readShort();
+ char fail = msg.readByte();
+ char value = msg.readByte();
+
+ if (fail == 1)
{
- //std::cout << RFIFOL(2) << " is " << RFIFOP(6) << std::endl;
- strcpy(being->name, RFIFOP(6));
+ switch (type) {
+ case 0x000d: player_info->STR = value; break;
+ case 0x000e: player_info->AGI = value; break;
+ case 0x000f: player_info->VIT = value; break;
+ case 0x0010: player_info->INT = value; break;
+ case 0x0011: player_info->DEX = value; break;
+ case 0x0012: player_info->LUK = value; break;
+ }
}
- break;
+ }
+ break;
+
+ // Updates stats and status points
+ case SMSG_PLAYER_STAT_UPDATE_5:
+ player_info->statsPointsToAttribute = msg.readShort();
+ player_info->STR = msg.readByte();
+ player_info->STRUp = msg.readByte();
+ player_info->AGI = msg.readByte();
+ player_info->AGIUp = msg.readByte();
+ player_info->VIT = msg.readByte();
+ player_info->VITUp = msg.readByte();
+ player_info->INT = msg.readByte();
+ player_info->INTUp = msg.readByte();
+ player_info->DEX = msg.readByte();
+ player_info->DEXUp = msg.readByte();
+ player_info->LUK = msg.readByte();
+ player_info->LUKUp = msg.readByte();
+ msg.readShort(); // ATK
+ msg.readShort(); // ATK bonus
+ msg.readShort(); // MATK max
+ msg.readShort(); // MATK min
+ msg.readShort(); // DEF
+ msg.readShort(); // DEF bonus
+ msg.readShort(); // MDEF
+ msg.readShort(); // MDEF bonus
+ msg.readShort(); // HIT
+ msg.readShort(); // FLEE
+ msg.readShort(); // FLEE bonus
+ msg.readShort(); // critical
+ msg.readShort(); // unknown
+ break;
+
+ case SMSG_PLAYER_STAT_UPDATE_6:
+ switch (msg.readShort()) {
+ case 0x0020: player_info->STRUp = msg.readByte(); break;
+ case 0x0021: player_info->AGIUp = msg.readByte(); break;
+ case 0x0022: player_info->VITUp = msg.readByte(); break;
+ case 0x0023: player_info->INTUp = msg.readByte(); break;
+ case 0x0024: player_info->DEXUp = msg.readByte(); break;
+ case 0x0025: player_info->LUKUp = msg.readByte(); break;
+ }
+ break;
+
+ case SMSG_BEING_NAME_RESPONSE:
+ {
+ Being *being = findNode(msg.readLong());
+
+ if (being) {
+ being->setName(msg.readString(24));
+ }
+ }
+ break;
+
+ case 0x0119:
// Change in players look
- case 0x0119:
- break;
- // Manage non implemented packets
- default:
- logger->log("Unhandled packet: %x", id);
- break;
- }
+ break;
- RFIFOSKIP(len);
+ default:
+ // Manage non implemented packets
+ logger->log("Unhandled packet: %x", msg.getId());
+ break;
}
+
+ skip(msg.getLength());
}
}
diff --git a/src/game.h b/src/game.h
index 0be487e0..d819a245 100644
--- a/src/game.h
+++ b/src/game.h
@@ -21,8 +21,10 @@
* $Id$
*/
-#ifndef _TMW_GAME_H
-#define _TMW_GAME_H
+#ifndef _TMW_GAME_
+#define _TMW_GAME_
+
+#include <string>
#define SPEECH_TIME 80
#define SPEECH_MAX_TIME 100
@@ -31,12 +33,12 @@
#define IDLE 255
extern char map_path[480];
-extern char tradePartnerName[24];
+extern std::string tradePartnerName;
extern int fps, frame, current_npc;
extern volatile int tick_time;
extern int server_tick;
extern bool displayPathToMouse;
-extern int startX, startY;
+extern unsigned short startX, startY;
enum {
JOY_UP,
@@ -78,11 +80,6 @@ void do_parse();
void do_exit();
/**
- * Calculate packet length
- */
-int get_packet_length(short);
-
-/**
* Returns elapsed time. (Warning: very unsafe function, it supposes the delay
* is always < 10 seconds)
*/
diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp
index 926f478e..3a32824a 100644
--- a/src/gui/buy.cpp
+++ b/src/gui/buy.cpp
@@ -235,11 +235,11 @@ void BuyDialog::action(const std::string& eventId)
// there a better way to ensure this fails in an _obivous_ way in C++?
else if (eventId == "buy" && (m_amountItems > 0 &&
m_amountItems <= m_maxItems)) {
- WFIFOW(0) = net_w_value(0x00c8);
- WFIFOW(2) = net_w_value(8);
- WFIFOW(4) = net_w_value(m_amountItems);
- WFIFOW(6) = net_w_value(shopInventory[selectedItem].id);
- WFIFOSET(8);
+ writeWord(0, 0x00c8);
+ writeWord(2, 8);
+ writeWord(4, m_amountItems);
+ writeWord(6, shopInventory[selectedItem].id);
+ writeSet(8);
// update money !
m_money -= m_amountItems * shopInventory[selectedItem].price;
diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp
index c81744dc..6a56e67f 100644
--- a/src/gui/buysell.cpp
+++ b/src/gui/buysell.cpp
@@ -77,10 +77,10 @@ void BuySellDialog::action(const std::string& eventId)
current_npc = 0;
}
if (actionId > -1) {
- WFIFOW(0) = net_w_value(0x00c5);
- WFIFOL(2) = net_l_value(current_npc);
- WFIFOB(6) = net_b_value(actionId);
- WFIFOSET(7);
+ writeWord(0, 0x00c5);
+ writeLong(2, current_npc);
+ writeByte(6, actionId);
+ writeSet(7);
}
setVisible(false);
diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp
index 6389f5b0..071708b8 100644
--- a/src/gui/char_select.cpp
+++ b/src/gui/char_select.cpp
@@ -33,13 +33,11 @@
#include "playerbox.h"
#include "textfield.h"
#include "windowcontainer.h"
-
#include "../being.h"
#include "../game.h"
#include "../log.h"
#include "../main.h"
#include "../playerinfo.h"
-
#include "../net/network.h"
#include "../net/protocol.h"
@@ -134,7 +132,6 @@ void CharSelectDialog::action(const std::string& eventId)
if (eventId == "ok" && n_character > 0) {
// Start game
serverCharSelect();
- close_session();
}
else if (eventId == "cancel") {
state = EXIT;
@@ -192,90 +189,99 @@ void CharSelectDialog::setPlayerInfo(PLAYER_INFO *pi)
void CharSelectDialog::serverCharDelete()
{
// Request character deletion
- WFIFOW(0) = net_w_value(0x0068);
- WFIFOL(2) = net_l_value(char_info->id);
- WFIFOSET(46);
+ writeWord(0, 0x0068);
+ writeLong(2, char_info[0]->id);
+ writeSet(46);
+
+ MessageIn msg = get_next_message();
- while ((in_size < 2) || (out_size > 0)) flush();
- if (RFIFOW(0) == 0x006f) {
- RFIFOSKIP(2);
+ if (msg.getId() == 0x006f)
+ {
+ skip(msg.getLength());
+ delete char_info[0];
free(char_info);
n_character = 0;
setPlayerInfo(NULL);
new OkDialog(this, "Info", "Player deleted");
}
- else if (RFIFOW(0) == 0x0070) {
+ else if (msg.getId() == 0x0070)
+ {
new OkDialog(this, "Error", "Failed to delete character.");
- RFIFOSKIP(3);
+ skip(msg.getLength());
}
else {
new OkDialog(this, "Error", "Unknown");
+ skip(msg.getLength());
}
}
void CharSelectDialog::serverCharSelect()
{
// Request character selection
- WFIFOW(0) = net_w_value(0x0066);
- WFIFOB(2) = net_b_value(0);
- WFIFOSET(3);
+ writeWord(0, 0x0066);
+ writeByte(2, 0);
+ writeSet(3);
- while ((in_size < 3) || (out_size > 0)) {
- flush();
- }
+ MessageIn msg = get_next_message();
- logger->log("CharSelect: Packet ID: %x, Length: %d, Packet_in_size %d",
- RFIFOW(0),
- get_length(RFIFOW(0)),
- RFIFOW(2));
- logger->log("CharSelect: In_size: %d", in_size);
+ logger->log("CharSelect: Packet ID: %x, Length: %d, in_size: %d",
+ msg.getId(), msg.getLength(), in_size);
- if (RFIFOW(0) == 0x0071) {
- while (in_size < 28) {
- flush();
- }
- char_ID = RFIFOL(2);
-
- char mapName[17];
- mapName[17] = 0;
- strncpy(mapName, RFIFOP(6), 16);
-
- memset(map_path, '\0', 480);
- strcat(map_path, "maps/");
- strncat(map_path, mapName, 479 - strlen(map_path));
- map_address = RFIFOL(22);
- map_port = RFIFOW(26);
+ if (msg.getId() == 0x0071)
+ {
+ char_ID = msg.readLong();
+ std::string mapPath = "maps/" + msg.readString(16);
+ strcpy(map_path, mapPath.c_str());
+ map_address = msg.readLong();
+ map_port = msg.readShort();
+ player_info = char_info[0];
state = GAME;
- logger->log("CharSelect: Map: %s", mapName);
- logger->log("CharSelect: Server: %s:%d", iptostring(map_address), map_port);
- RFIFOSKIP(28);
+ logger->log("CharSelect: Map: %s", map_path);
+ logger->log("CharSelect: Server: %s:%d", iptostring(map_address),
+ map_port);
close_session();
}
- else if (RFIFOW(0) == 0x006c) {
- switch (RFIFOB(2)) {
+ else if (msg.getId() == 0x006c)
+ {
+ switch (msg.readByte()) {
case 0:
new OkDialog(this, "Error", "Access denied");
break;
case 1:
new OkDialog(this, "Error", "Cannot use this ID");
break;
+ default:
+ new OkDialog(this, "Error",
+ "Unknown failure to select character");
+ break;
}
- RFIFOSKIP(3);
+ skip(msg.getLength());
}
- else if (RFIFOW(0) == 0x0081) {
- new OkDialog(this, "Error",
- "Map server is down, please try again later");
+ else if (msg.getId() == 0x0081)
+ {
+ switch (msg.readByte()) {
+ case 3:
+ new OkDialog(this, "Error", "Speed hack detected");
+ break;
+ case 8:
+ new OkDialog(this, "Error", "Duplicated login");
+ break;
+ default:
+ new OkDialog(this, "Error", "Unkown error with 0x0081");
+ break;
+ }
close_session();
state = LOGIN;
}
+
// Todo: add other packets
}
void CharSelectDialog::logic()
{
if (n_character > 0) {
- setPlayerInfo(char_info);
+ setPlayerInfo(char_info[0]);
}
}
@@ -391,63 +397,84 @@ void CharCreateDialog::action(const std::string& eventId)
playerBox->hairStyle %= NR_HAIR_STYLES;
}
-std::string CharCreateDialog::getName() {
+std::string CharCreateDialog::getName()
+{
return nameField->getText();
}
void CharCreateDialog::serverCharCreate()
{
- n_character = 1;
-
- WFIFOW(0) = net_w_value(0x0067);
- strcpy(WFIFOP(2), getName().c_str());
- WFIFOB(26) = net_b_value(5);
- WFIFOB(27) = net_b_value(5);
- WFIFOB(28) = net_b_value(5);
- WFIFOB(29) = net_b_value(5);
- WFIFOB(30) = net_b_value(5);
- WFIFOB(31) = net_b_value(5);
- WFIFOB(32) = net_b_value(0);
- WFIFOW(33) = net_w_value(playerBox->hairColor + 1);
- WFIFOW(35) = net_w_value(playerBox->hairStyle + 1);
- WFIFOSET(37);
-
- while ((in_size < 3) || (out_size > 0)) flush();
- if (RFIFOW(0) == 0x006d) {
- while (in_size < 108) flush();
- char_info = (PLAYER_INFO *)malloc(sizeof(PLAYER_INFO));
- char_info->id = RFIFOL(2);//account_ID;
- memset(char_info->name, '\0', 24);
- strcpy(char_info[0].name, RFIFOP(2 + 74));
- char_info->hp = RFIFOW(2 + 42);
- char_info->max_hp = RFIFOW(2 + 44);
- char_info->sp = RFIFOW(2 + 46);
- char_info->max_sp = RFIFOW(2 + 48);
- char_info->job_lv = RFIFOL(2 + 16);
- char_info->job_xp = RFIFOL(2 + 12);
- char_info->lv = RFIFOW(2 + 58);
- char_info->xp = RFIFOL(2 + 4);
- char_info->gp = RFIFOL(2 + 8);
- char_info->STR = RFIFOB(2 + 98);
- char_info->AGI = RFIFOB(2 + 99);
- char_info->VIT = RFIFOB(2 + 100);
- char_info->INT = RFIFOB(2 + 101);
- char_info->DEX = RFIFOB(2 + 102);
- char_info->LUK = RFIFOB(2 + 103);
- char_info->hair_style = RFIFOW(2 + 54);
- char_info->hair_color = RFIFOW(2 + 70);
- char_info->weapon = RFIFOW(2 + 56);
- RFIFOSKIP(108);
- //n_character++;
- } else if (RFIFOW(0) == 0x006e) {
+ writeWord(0, 0x0067);
+ strcpy(writePointer(2), getName().c_str());
+ writeByte(26, 5);
+ writeByte(27, 5);
+ writeByte(28, 5);
+ writeByte(29, 5);
+ writeByte(30, 5);
+ writeByte(31, 5);
+ writeByte(32, 0);
+ writeWord(33, playerBox->hairColor + 1);
+ writeWord(35, playerBox->hairStyle + 1);
+ writeSet(37);
+
+ MessageIn msg = get_next_message();
+
+ if (msg.getId() == 0x006d)
+ {
+ char_info = (PLAYER_INFO**)malloc(sizeof(PLAYER_INFO*));
+ char_info[0] = new PLAYER_INFO;
+
+ char_info[0]->id = msg.readLong();
+ char_info[0]->xp = msg.readLong();
+ char_info[0]->gp = msg.readLong();
+ char_info[0]->job_xp = msg.readLong();
+ char_info[0]->job_lv = msg.readLong();
+ msg.skip(8); // unknown
+ msg.readLong(); // option
+ msg.readLong(); // karma
+ msg.readLong(); // manner
+ msg.skip(2); // unknown
+ char_info[0]->hp = msg.readShort();
+ char_info[0]->max_hp = msg.readShort();
+ char_info[0]->sp = msg.readShort();
+ char_info[0]->max_sp = msg.readShort();
+ msg.readShort(); // speed
+ msg.readShort(); // class
+ char_info[0]->hair_style = msg.readShort();
+ char_info[0]->weapon = msg.readShort();
+ char_info[0]->lv = msg.readShort();
+ msg.readShort(); // skill point
+ msg.readShort(); // head bottom
+ msg.readShort(); // shield
+ msg.readShort(); // head option top
+ msg.readShort(); // head option mid
+ char_info[0]->hair_color = msg.readShort();
+ msg.readShort(); // unknown
+ char_info[0]->name = msg.readString(24);
+ char_info[0]->STR = msg.readByte();
+ char_info[0]->AGI = msg.readByte();
+ char_info[0]->VIT = msg.readByte();
+ char_info[0]->INT = msg.readByte();
+ char_info[0]->DEX = msg.readByte();
+ char_info[0]->LUK = msg.readByte();
+ msg.readByte(); // character number
+ msg.readByte(); // unknown
+
+ n_character = 1;
+ }
+ else if (msg.getId() == 0x006e)
+ {
new OkDialog(this, "Error", "Failed to create character");
- RFIFOSKIP(3);
n_character = 0;
- } else {
+ }
+ else
+ {
new OkDialog(this, "Error", "Unknown error");
n_character = 0;
}
+ skip(msg.getLength());
+
// Remove window when succeeded
if (n_character == 1) {
windowContainer->scheduleDelete(this);
diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp
index b4b01350..d3abfe7c 100644
--- a/src/gui/char_server.cpp
+++ b/src/gui/char_server.cpp
@@ -23,6 +23,7 @@
#include "char_server.h"
+#include <sstream>
#include <SDL.h>
#include "button.h"
@@ -37,6 +38,8 @@
#include "../net/network.h"
+extern SERVER_INFO **server_info;
+
char server[30];
@@ -107,15 +110,16 @@ void ServerSelectDialog::action(const std::string& eventId)
}
-int ServerListModel::getNumberOfElements() {
+int ServerListModel::getNumberOfElements()
+{
return n_server;
}
-std::string ServerListModel::getElementAt(int i) {
- static char buffer[30];
- sprintf(buffer, "%s (%i)", server_info[i].name,
- server_info[i].online_users);
- return buffer;
+std::string ServerListModel::getElementAt(int i)
+{
+ std::stringstream s;
+ s << server_info[i]->name << " (" << server_info[i]->online_users << ")";
+ return s.str();
}
void charServerInputHandler(SDL_KeyboardEvent *keyEvent)
@@ -130,12 +134,12 @@ void server_char_server(int serverIndex)
{
int ret;
state = LOGIN;
- const char *ipstring = iptostring(server_info[serverIndex].address);
+ const char *ipstring = iptostring(server_info[serverIndex]->address);
// Connect to char server
- ret = open_session(ipstring, server_info[serverIndex].port);
+ ret = open_session(ipstring, server_info[serverIndex]->port);
- if (ret == SOCKET_ERROR)
+ if (ret == -1)
{
std::string str = std::string("Unable to connect to char server ") +
std::string(ipstring);
@@ -144,74 +148,93 @@ void server_char_server(int serverIndex)
}
// Send login infos
- WFIFOW(0) = net_w_value(0x0065);
- WFIFOL(2) = net_l_value(account_ID);
- WFIFOL(6) = net_l_value(session_ID1);
- WFIFOL(10) = net_l_value(session_ID2);
- WFIFOW(14) = 0;
- WFIFOB(16) = net_b_value(sex);
- WFIFOSET(17);
-
+ writeWord(0, 0x0065);
+ writeLong(2, account_ID);
+ writeLong(6, session_ID1);
+ writeLong(10, session_ID2);
+ writeWord(14, 0);
+ writeByte(16, sex);
+ writeSet(17);
+
+ // Skipping a mysterious 4 bytes
while ((in_size < 4) || (out_size > 0)) flush();
- RFIFOSKIP(4);
+ skip(4);
- while (in_size < 3) flush();
+ MessageIn msg = get_next_message();
- if (RFIFOW(0) == 0x006b)
+ if (msg.getId() == 0x006b)
{
- while (in_size < RFIFOW(2)) flush();
+ // Skip length word and an additional mysterious 20 bytes
+ msg.skip(2 + 20);
- n_character = (RFIFOW(2) - 24) / 106;
- char_info = (PLAYER_INFO*)malloc(sizeof(PLAYER_INFO) * n_character);
+ // Derive number of characters from message length
+ n_character = (msg.getLength() - 24) / 106;
+ char_info = (PLAYER_INFO**)malloc(sizeof(PLAYER_INFO*) * n_character);
for (int i = 0; i < n_character; i++)
{
- int n = 24 + 106 * i;
- char_info[i].id = RFIFOL(n);
- strcpy(char_info[i].name, RFIFOP(n + 74));
- char_info[i].hp = RFIFOW( n+ 42);
- char_info[i].max_hp = RFIFOW(n + 44);
- char_info[i].xp = RFIFOL(n + 4);
- char_info[i].gp = RFIFOL(n + 8);
- char_info[i].job_xp = RFIFOL(n + 12);
- char_info[i].job_lv = RFIFOL(n + 16);
- char_info[i].sp = RFIFOW(n + 46);
- char_info[i].max_sp = RFIFOW(n + 48);
- char_info[i].lv = RFIFOW(n + 58);
- char_info[i].STR = RFIFOB(n + 98);
- char_info[i].AGI = RFIFOB(n + 99);
- char_info[i].VIT = RFIFOB(n + 100);
- char_info[i].INT = RFIFOB(n + 101);
- char_info[i].DEX = RFIFOB(n + 102);
- char_info[i].LUK = RFIFOB(n + 103);
- char_info[i].hair_style = RFIFOW(n + 54);
- char_info[i].hair_color = RFIFOW(n + 70);
- char_info[i].weapon = RFIFOW(n + 56);
+ char_info[i] = new PLAYER_INFO;
+
+ char_info[i]->id = msg.readLong();
+ char_info[i]->xp = msg.readLong();
+ char_info[i]->gp = msg.readLong();
+ char_info[i]->job_xp = msg.readLong();
+ char_info[i]->job_lv = msg.readLong();
+ msg.skip(8); // unknown
+ msg.readLong(); // option
+ msg.readLong(); // karma
+ msg.readLong(); // manner
+ msg.skip(2); // unknown
+ char_info[i]->hp = msg.readShort();
+ char_info[i]->max_hp = msg.readShort();
+ char_info[i]->sp = msg.readShort();
+ char_info[i]->max_sp = msg.readShort();
+ msg.readShort(); // speed
+ msg.readShort(); // class
+ char_info[i]->hair_style = msg.readShort();
+ char_info[i]->weapon = msg.readShort();
+ char_info[i]->lv = msg.readShort();
+ msg.readShort(); // skill point
+ msg.readShort(); // head bottom
+ msg.readShort(); // shield
+ msg.readShort(); // head option top
+ msg.readShort(); // head option mid
+ char_info[i]->hair_color = msg.readShort();
+ msg.readShort(); // unknown
+ char_info[i]->name = msg.readString(24);
+ char_info[i]->STR = msg.readByte();
+ char_info[i]->AGI = msg.readByte();
+ char_info[i]->VIT = msg.readByte();
+ char_info[i]->INT = msg.readByte();
+ char_info[i]->DEX = msg.readByte();
+ char_info[i]->LUK = msg.readByte();
+ msg.readByte(); // character number
+ msg.readByte(); // unknown
}
state = CHAR_SELECT;
logger->log("CharServer: Player: %s (Packet ID: %x, Length: %d)",
- char_info->name, RFIFOW(0), RFIFOW(2));
-
+ char_info[0]->name.c_str(), msg.getId(), msg.getLength());
- RFIFOSKIP(RFIFOW(2));
+ skip(msg.getLength());
}
- else if (RFIFOW(0) == 0x006c)
+ else if (msg.getId() == 0x006c)
{
std::string errorStr;
- switch (RFIFOB(2)) {
+ switch (msg.readByte()) {
case 0: errorStr = "Access denied"; break;
case 1: errorStr = "Cannot use this ID"; break;
default: errorStr = "Rejected from server"; break;
}
new OkDialog("Error", errorStr);
- RFIFOSKIP(3);
+ skip(msg.getLength());
close_session();
}
else
{
new OkDialog("Error", "Unknown error");
+ skip(msg.getLength());
}
// Todo: add other packets
}
diff --git a/src/gui/chargedialog.cpp b/src/gui/chargedialog.cpp
index 5a475d72..797d5129 100644
--- a/src/gui/chargedialog.cpp
+++ b/src/gui/chargedialog.cpp
@@ -52,12 +52,15 @@ void ChargeDialog::action(const std::string& eventId)
void ChargeDialog::logic()
{
// calculate time since the last attack was made
- char_info->lastAttackTime += .01; // this a hack until someone explains
+ player_info->lastAttackTime += .01; // this a hack until someone explains
// to me how to work the timer
- if(char_info->lastAttackTime > 1){char_info->lastAttackTime=1;}
-
+ if (player_info->lastAttackTime > 1)
+ {
+ player_info->lastAttackTime = 1;
+ }
+
// reset the progress bar to display accurate time since attack
- progBar->setProgress(char_info->lastAttackTime);
+ progBar->setProgress(player_info->lastAttackTime);
Window::logic();
}
diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp
index 72de3c83..e6dabaaa 100644
--- a/src/gui/chat.cpp
+++ b/src/gui/chat.cpp
@@ -169,7 +169,7 @@ void ChatWindow::action(const std::string& eventId)
curHist = history.end();
// Send the message to the server
- chat_send(char_info[0].name, message.c_str());
+ chat_send(player_info->name.c_str(), message.c_str());
// Clear the text from the chat input
chatInput->setText("");
@@ -217,10 +217,10 @@ char *ChatWindow::chat_send(std::string nick, std::string msg)
msg += "\0";
// send processed message
- WFIFOW(0) = net_w_value(packid);
- WFIFOW(2) = net_w_value((unsigned short)(msg.length()+4));
- memcpy(WFIFOP(4), msg.c_str(), msg.length());
- WFIFOSET((int)msg.length()+4);
+ writeWord(0, packid);
+ writeWord(2, (unsigned short)(msg.length() + 4));
+ memcpy(writePointer(4), msg.c_str(), msg.length());
+ writeSet((int)msg.length()+4);
nick = msg = "";
return "";
}
diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp
index b89f19a3..b65979db 100644
--- a/src/gui/inventorywindow.cpp
+++ b/src/gui/inventorywindow.cpp
@@ -105,7 +105,8 @@ void InventoryWindow::logic()
// Update weight information
std::stringstream tempstr;
- tempstr << "Total Weight: " << char_info->totalWeight << " - Maximum Weight: " << char_info->maxWeight;
+ tempstr << "Total Weight: " << player_info->totalWeight
+ << " - Maximum Weight: " << player_info->maxWeight;
weightLabel->setCaption(tempstr.str());
weightLabel->adjustSize();
}
diff --git a/src/gui/login.cpp b/src/gui/login.cpp
index 9913eb25..bc39c15f 100644
--- a/src/gui/login.cpp
+++ b/src/gui/login.cpp
@@ -30,6 +30,10 @@
#include <guichan/widgets/label.hpp>
#include "../main.h"
+#include "../configuration.h"
+#include "../graphics.h"
+#include "../log.h"
+#include "../serverinfo.h"
#include "button.h"
#include "checkbox.h"
@@ -37,13 +41,10 @@
#include "textfield.h"
#include "ok_dialog.h"
-#include "../configuration.h"
-#include "../log.h"
-#include "../serverinfo.h"
-
#include "../net/network.h"
OkDialog *wrongLoginNotice = NULL;
+SERVER_INFO **server_info;
WrongUsernameNoticeListener wrongUsernameNoticeListener;
WrongPasswordNoticeListener wrongPasswordNoticeListener;
@@ -56,11 +57,11 @@ void WrongPasswordNoticeListener::setLoginDialog(
void WrongPasswordNoticeListener::action(const std::string &eventId)
{
- // Reset the password and put the caret ready to retype it.
- mLoginDialog->passField->setText("");
- mLoginDialog->passField->setCaretPosition(0);
- mLoginDialog->passField->requestFocus();
- wrongLoginNotice = NULL;
+ // Reset the password and put the caret ready to retype it.
+ mLoginDialog->passField->setText("");
+ mLoginDialog->passField->setCaretPosition(0);
+ mLoginDialog->passField->requestFocus();
+ wrongLoginNotice = NULL;
}
void WrongUsernameNoticeListener::setLoginDialog(
@@ -174,61 +175,73 @@ LoginDialog::~LoginDialog()
void LoginDialog::action(const std::string& eventId)
{
- if (eventId == "ok") {
+ if (eventId == "ok")
+ {
const std::string user = userField->getText();
logger->log("Network: Username is %s", user.c_str());
// Store config settings
config.setValue("remember", keepCheck->isMarked());
- if (keepCheck->isMarked()) {
+
+ if (keepCheck->isMarked())
+ {
config.setValue("username", user);
config.setValue("host", serverField->getText());
- } else {
+ }
+ else
+ {
config.setValue("username", "");
}
// Check login
- if (user.length() == 0) {
- wrongLoginNotice = new OkDialog("Error", "Enter your username first", &wrongUsernameNoticeListener);
- } else {
- switch (attemptLogin(user, passField->getText()) )
- {
- case LOGIN_UNKNOWN_ERROR:
- wrongLoginNotice = new OkDialog("Error", "Unknown Error.");
- default:
- break;
-
- case LOGIN_WRONG_PASSWORD:
- wrongLoginNotice = new OkDialog("Error", "Wrong Password", &wrongPasswordNoticeListener);
- break;
-
- case LOGIN_UNREGISTERED_ID:
- wrongLoginNotice = new OkDialog("Error", "Unregistered ID.");
- break;
-
- case LOGIN_EXPIRED:
- wrongLoginNotice = new OkDialog("Error", "This ID is expired");
- break;
-
- case LOGIN_REJECTED:
- wrongLoginNotice = new OkDialog("Error", "Rejected from server");
- break;
-
- case LOGIN_BLOCKED:
- wrongLoginNotice = new OkDialog("Error", "You have been blocked by the GM Team");
- break;
-
- case LOGIN_USERNAME_TWICE:
- wrongLoginNotice = new OkDialog("Error", "The username does already exist.");
- break;
-
+ if (user.length() == 0)
+ {
+ wrongLoginNotice = new OkDialog("Error",
+ "Enter your username first",
+ &wrongUsernameNoticeListener);
+ }
+ else
+ {
+ int ret = attemptLogin(user, passField->getText());
+ if (ret == LOGIN_WRONG_PASSWORD)
+ {
+ wrongLoginNotice = new OkDialog("Error", "Wrong Password",
+ &wrongPasswordNoticeListener);
+ }
+ else if (ret != LOGIN_OK)
+ {
+ std::string errorMsg = "Unknown error.";
+
+ switch (ret)
+ {
+ case LOGIN_UNREGISTERED_ID:
+ errorMsg = "Unregistered ID.";
+ break;
+ case LOGIN_EXPIRED:
+ errorMsg = "This ID is expired";
+ break;
+ case LOGIN_REJECTED:
+ errorMsg = "Rejected from server";
+ break;
+ case LOGIN_BLOCKED:
+ errorMsg = "You have been blocked by the GM Team";
+ break;
+ case LOGIN_USERNAME_TWICE:
+ errorMsg = "The username does already exist.";
+ break;
+ }
+
+ wrongLoginNotice = new OkDialog("Error", errorMsg);
}
- close_session();
}
- } else if (eventId == "cancel") {
+ }
+ else if (eventId == "cancel")
+ {
state = EXIT;
- } else if (eventId == "register") {
+ }
+ else if (eventId == "register")
+ {
const std::string user = userField->getText();
logger->log("LoginDialog::register Username is %s", user.c_str());
@@ -241,46 +254,57 @@ void LoginDialog::action(const std::string& eventId)
}
// Check login
- if (user.length() == 0) // No username
+ if (user.length() == 0)
{
- wrongLoginNotice = new OkDialog("Error", "Enter your username first.", &wrongUsernameNoticeListener);
+ // No username
+ wrongLoginNotice = new OkDialog("Error",
+ "Enter your username first.",
+ &wrongUsernameNoticeListener);
}
- else if (user.length() < LEN_MIN_USERNAME) // Name too short
+ else if (user.length() < LEN_MIN_USERNAME)
{
+ // Name too short
std::stringstream errorMessage;
errorMessage << "The username needs to be at least ";
errorMessage << LEN_MIN_USERNAME;
errorMessage << " characters long.";
- wrongLoginNotice = new OkDialog("Error", errorMessage.str(), &wrongUsernameNoticeListener);
+ wrongLoginNotice = new OkDialog("Error", errorMessage.str(),
+ &wrongUsernameNoticeListener);
}
- else if (user.length() > LEN_MAX_USERNAME - 1 ) // Name too long
+ else if (user.length() > LEN_MAX_USERNAME - 1 )
{
+ // Name too long
std::stringstream errorMessage;
errorMessage << "The username needs to be less than ";
errorMessage << LEN_MAX_USERNAME;
errorMessage << " characters long.";
- wrongLoginNotice = new OkDialog("Error", errorMessage.str(), &wrongUsernameNoticeListener);
+ wrongLoginNotice = new OkDialog("Error", errorMessage.str(),
+ &wrongUsernameNoticeListener);
}
- else if (passField->getText().length() < LEN_MIN_PASSWORD) // Pass too short
+ else if (passField->getText().length() < LEN_MIN_PASSWORD)
{
+ // Pass too short
std::stringstream errorMessage;
errorMessage << "The password needs to be at least ";
errorMessage << LEN_MIN_PASSWORD;
errorMessage << " characters long.";
- wrongLoginNotice = new OkDialog("Error", errorMessage.str(), &wrongPasswordNoticeListener);
+ wrongLoginNotice = new OkDialog("Error", errorMessage.str(),
+ &wrongPasswordNoticeListener);
}
- else if (passField->getText().length() > LEN_MAX_PASSWORD - 1 ) // Pass too long
+ else if (passField->getText().length() > LEN_MAX_PASSWORD - 1 )
{
+ // Pass too long
std::stringstream errorMessage;
errorMessage << "The password needs to be less than ";
errorMessage << LEN_MAX_PASSWORD;
errorMessage << " characters long.";
- wrongLoginNotice = new OkDialog("Error", errorMessage.str(), &wrongPasswordNoticeListener);
+ wrongLoginNotice = new OkDialog("Error", errorMessage.str(),
+ &wrongPasswordNoticeListener);
}
- else // If no errors, register the new user.
+ else
{
+ // No errors detected, register the new user.
attemptLogin(user + "_M", passField->getText());
- close_session();
}
}
}
@@ -293,7 +317,8 @@ void loginInputHandler(SDL_KeyboardEvent *keyEvent)
}
}
-int attemptLogin(const std::string& user, const std::string& pass) {
+int attemptLogin(const std::string& user, const std::string& pass)
+{
int ret;
// Connect to login server
@@ -301,55 +326,69 @@ int attemptLogin(const std::string& user, const std::string& pass) {
config.getValue("host", "animesites.de").c_str(),
(short)config.getValue("port", 0));
- if (ret == SOCKET_ERROR) {
+ if (ret == -1) {
state = LOGIN;
- wrongLoginNotice = new OkDialog("Error", "Unable to connect to login server");
+ wrongLoginNotice = new OkDialog("Error",
+ "Unable to connect to login server");
return LOGIN_NO_CONNECTION;
}
- // Send login infos
- WFIFOW(0) = net_w_value(0x0064);
+ // Send login infos
+ MessageOut outMsg;
+ outMsg.writeShort(0x0064);
+ outMsg.writeLong(0); // client version
+ outMsg.writeString(user, 24);
+ outMsg.writeString(pass, 24);
+ outMsg.writeByte(0); // unknown
+ // TODO: still have to use writeSet as skip for reading
+ writeSet(55);
+
+ // Receive reply
+ MessageIn msg = get_next_message();
- WFIFOL(2) = 0;
+ // Login ok
+ if (msg.getId() == 0x0069)
+ {
+ // Skip the length word
+ msg.skip(2);
- memcpy(WFIFOP(6), user.c_str(), LEN_MAX_USERNAME - 1);
- memcpy(WFIFOP(30), pass.c_str(), LEN_MAX_PASSWORD - 1);
- WFIFOB(54) = 0;
- WFIFOSET(55);
+ n_server = (msg.getLength() - 47) / 32;
+ server_info = (SERVER_INFO**)malloc(sizeof(SERVER_INFO*) * n_server);
- while ((in_size < 23) || (out_size > 0)) {
- flush();
- }
+ session_ID1 = msg.readLong();
+ account_ID = msg.readLong();
+ session_ID2 = msg.readLong();
+ msg.skip(30); // unknown
+ sex = msg.readByte();
- // Login ok
- if (RFIFOW(0) == 0x0069) {
- while (in_size < RFIFOW(2)) {
- flush();
- }
- n_server = (RFIFOW(2) - 47) / 32;
- server_info = (SERVER_INFO*)malloc(sizeof(SERVER_INFO) * n_server);
- account_ID = RFIFOL(8);
- session_ID1 = RFIFOL(4);
- session_ID2 = RFIFOL(12);
- sex = RFIFOB(46);
- for (int i = 0; i < n_server; i++) {
- server_info[i].address = RFIFOL(47 + 32 * i);
- memcpy(server_info[i].name, RFIFOP(47 + 32 * i + 6), 20);
- server_info[i].online_users = RFIFOW(47 + 32 * i + 26);
- server_info[i].port = RFIFOW(47 + 32 * i + 4);
- state = CHAR_SERVER;
+ for (int i = 0; i < n_server; i++)
+ {
+ server_info[i] = new SERVER_INFO;
+
+ server_info[i]->address = msg.readLong();
+ server_info[i]->port = msg.readShort();
+ server_info[i]->name = msg.readString(20);
+ server_info[i]->online_users = msg.readLong();
+ msg.skip(2); // unknown
+
+ logger->log("Network: Server: %s (%s:%d)",
+ server_info[i]->name.c_str(),
+ iptostring(server_info[i]->address),
+ server_info[i]->port);
}
- logger->log("Network: Server: %s (%s:%d)", server_info[0].name,
- iptostring(server_info[0].address),
- server_info[0].port);
- RFIFOSKIP(RFIFOW(2));
- return LOGIN_OK;
+
+ state = CHAR_SERVER;
+
+ skip(msg.getLength());
+ ret = LOGIN_OK;
}
- else if (RFIFOW(0) == 0x006a) {
- logger->log("Login::error code: %i", RFIFOB(2));
+ else if (msg.getId() == 0x006a)
+ {
+ int loginError = msg.readByte();
+ logger->log("Login::error code: %i", loginError);
ret = 0;
- switch (RFIFOB(2)) {
+ switch (loginError) {
case 0:
ret = LOGIN_UNREGISTERED_ID;
break;
@@ -369,13 +408,16 @@ int attemptLogin(const std::string& user, const std::string& pass) {
ret = LOGIN_USERNAME_TWICE;
break;
}
+ skip(msg.getLength());
state = LOGIN;
- RFIFOSKIP(23);
- return ret;
}
else {
+ skip(msg.getLength());
state = LOGIN;
- return LOGIN_UNKNOWN_ERROR;
+ ret = LOGIN_UNKNOWN_ERROR;
}
// Todo: add other packets, also encrypted
+
+ close_session();
+ return ret;
}
diff --git a/src/gui/npc.cpp b/src/gui/npc.cpp
index 0756d809..c8d426f3 100644
--- a/src/gui/npc.cpp
+++ b/src/gui/npc.cpp
@@ -70,20 +70,23 @@ NpcListDialog::~NpcListDialog()
delete scrollArea;
}
-int NpcListDialog::getNumberOfElements()
+int
+NpcListDialog::getNumberOfElements()
{
return items.size();
}
-std::string NpcListDialog::getElementAt(int i)
+std::string
+NpcListDialog::getElementAt(int i)
{
return items[i];
}
-void NpcListDialog::parseItems(const char *string, unsigned short len) {
- char *copy = new char[len + 1];
- strncpy(copy, string, len);
- copy[len] = 0;
+void
+NpcListDialog::parseItems(const std::string &itemString)
+{
+ char *copy = new char[itemString.length() + 1];
+ strcpy(copy, itemString.c_str());
char *token = strtok(copy, ":");
while (token) {
@@ -94,20 +97,23 @@ void NpcListDialog::parseItems(const char *string, unsigned short len) {
delete[] copy;
}
-void NpcListDialog::reset() {
+void
+NpcListDialog::reset()
+{
items.clear();
}
-void NpcListDialog::action(const std::string& eventId)
+void
+NpcListDialog::action(const std::string& eventId)
{
if (eventId == "ok") {
// Send the selected index back to the server
int selectedIndex = itemList->getSelected();
if (selectedIndex > -1) {
- WFIFOW(0) = net_w_value(0x00b8);
- WFIFOL(2) = net_l_value(current_npc);
- WFIFOB(6) = net_b_value(selectedIndex + 1);
- WFIFOSET(7);
+ writeWord(0, 0x00b8);
+ writeLong(2, current_npc);
+ writeByte(6, selectedIndex + 1);
+ writeSet(7);
setVisible(false);
current_npc = 0;
reset();
@@ -115,10 +121,10 @@ void NpcListDialog::action(const std::string& eventId)
}
else if (eventId == "cancel") {
// 0xff packet means cancel
- WFIFOW(0) = net_w_value(0x00b8);
- WFIFOL(2) = net_l_value(current_npc);
- WFIFOB(6) = net_b_value(0xff);
- WFIFOSET(7);
+ writeWord(0, 0x00b8);
+ writeLong(2, current_npc);
+ writeByte(6, 0xff);
+ writeSet(7);
setVisible(false);
reset();
current_npc = 0;
diff --git a/src/gui/npc.h b/src/gui/npc.h
index 336bad62..e9960cd2 100644
--- a/src/gui/npc.h
+++ b/src/gui/npc.h
@@ -58,29 +58,34 @@ class NpcListDialog : public Window, public gcn::ActionListener,
/**
* Called when receiving actions from the widgets.
*/
- void action(const std::string& eventId);
+ void
+ action(const std::string& eventId);
/**
* Returns the number of items in the choices list.
*/
- int getNumberOfElements();
+ int
+ getNumberOfElements();
/**
* Returns the name of item number i of the choices list.
*/
- std::string getElementAt(int i);
+ std::string
+ getElementAt(int i);
/**
* Fills the options list for an NPC dialog.
*
- * @param string A string with the options separated with colons.
+ * @param itemString A string with the options separated with colons.
*/
- void parseItems(const char *string, unsigned short len);
+ void
+ parseItems(const std::string &itemString);
/**
* Resets the list by removing all items.
*/
- void reset();
+ void
+ reset();
private:
gcn::Button *okButton;
diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp
index 7fc59343..67a9e9a3 100644
--- a/src/gui/npc_text.cpp
+++ b/src/gui/npc_text.cpp
@@ -61,22 +61,24 @@ NpcTextDialog::~NpcTextDialog()
delete scrollArea;
}
-void NpcTextDialog::setText(const char *text)
+void
+NpcTextDialog::setText(const char *text)
{
textBox->setText(text);
}
-void NpcTextDialog::addText(const char *text)
+void
+NpcTextDialog::addText(const std::string &text)
{
- textBox->setText(
- textBox->getText() + std::string(text) + std::string("\n"));
+ textBox->setText(textBox->getText() + text + "\n");
}
-void NpcTextDialog::action(const std::string& eventId)
+void
+NpcTextDialog::action(const std::string& eventId)
{
- WFIFOW(0) = net_w_value(0x00b9);
- WFIFOL(2) = net_l_value(current_npc);
- WFIFOSET(6);
+ writeWord(0, 0x00b9);
+ writeLong(2, current_npc);
+ writeSet(6);
setText("");
setVisible(false);
current_npc = 0;
diff --git a/src/gui/npc_text.h b/src/gui/npc_text.h
index 41301aa9..02fae7f4 100644
--- a/src/gui/npc_text.h
+++ b/src/gui/npc_text.h
@@ -25,11 +25,10 @@
#define _TMW_NPC_TEXT_H
#include <iosfwd>
-
+#include <string>
#include <guichan/actionlistener.hpp>
#include "window.h"
-
#include "../guichanfwd.h"
/**
@@ -55,14 +54,16 @@ class NpcTextDialog : public Window, public gcn::ActionListener
/**
* Called when receiving actions from the widgets.
*/
- void action(const std::string& eventId);
+ void
+ action(const std::string &eventId);
/**
* Sets the text shows in the dialog.
*
* @param string The new text.
*/
- void setText(const char *string);
+ void
+ setText(const char *string);
/**
* Adds the text to the text shows in the dialog. Also adds a newline
@@ -70,7 +71,8 @@ class NpcTextDialog : public Window, public gcn::ActionListener
*
* @param string The text to add.
*/
- void addText(const char *string);
+ void
+ addText(const std::string &string);
private:
gcn::Button *okButton;
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index 85b1b43a..3ea3e141 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -72,22 +72,22 @@ PopupMenu::~PopupMenu()
void PopupMenu::showPopup(int x, int y, Being *being)
{
- std::string name;
-
this->being = being;
browserBox->clearRows();
switch (being->getType())
{
case Being::PLAYER:
- // Players can be traded with. Later also attack, follow and
- // add as buddy will be options in this menu.
-
- name = being->name;
- //browserBox->addRow("@@attack|Attack " + name + "@@");
- browserBox->addRow("@@trade|Trade With " + name + "@@");
- //browserBox->addRow("@@follow|Follow " + name + "@@");
- //browserBox->addRow("@@buddy|Add " + name + " to Buddy List@@");
+ {
+ // Players can be traded with. Later also attack, follow and
+ // add as buddy will be options in this menu.
+ const std::string &name = being->getName();
+ browserBox->addRow("@@trade|Trade With " + name + "@@");
+
+ //browserBox->addRow("@@attack|Attack " + name + "@@");
+ //browserBox->addRow("@@follow|Follow " + name + "@@");
+ //browserBox->addRow("@@buddy|Add " + name + " to Buddy List@@");
+ }
break;
case Being::NPC:
@@ -114,7 +114,7 @@ void PopupMenu::showPopup(int x, int y, FloorItem *floorItem)
browserBox->clearRows();
// Floor item can be picked up (single option, candidate for removal)
- std::string name = itemDb->getItemInfo(floorItem->id)->getName();
+ std::string name = itemDb->getItemInfo(floorItem->getItemId())->getName();
browserBox->addRow("@@pickup|Pick Up " + name + "@@");
//browserBox->addRow("@@look|Look To@@");
@@ -130,22 +130,22 @@ void PopupMenu::handleLink(const std::string& link)
if ((link == "talk") && being && being->getType() == Being::NPC &&
(current_npc == 0))
{
- WFIFOW(0) = net_w_value(0x0090);
- WFIFOL(2) = net_l_value(being->getId());
- WFIFOB(6) = 0;
- WFIFOSET(7);
+ writeWord(0, 0x0090);
+ writeLong(2, being->getId());
+ writeByte(6, 0);
+ writeSet(7);
current_npc = being->getId();
}
// Trade action
else if ((link == "trade") && being && being->getType() == Being::PLAYER)
{
- WFIFOW(0) = net_w_value(0x00e4);
- WFIFOL(2) = net_l_value(being->getId());
- WFIFOSET(6);
+ writeWord(0, 0x00e4);
+ writeLong(2, being->getId());
+ writeSet(6);
//tradePartner.flush();
//tradePartner << "Trade: You and " << being->name<< "";
- strcpy(tradePartnerName, being->name);
+ tradePartnerName = being->getName();
}
/*
// Follow Player action
@@ -160,15 +160,15 @@ void PopupMenu::handleLink(const std::string& link)
if (!buddyWindow->isVisible())
buddyWindow->setVisible(true);
- buddyWindow->addBuddy(being->name);
+ buddyWindow->addBuddy(being->getName());
}*/
// Pick Up Floor Item action
else if ((link == "pickup") && floorItem)
{
- WFIFOW(0) = net_w_value(0x009f);
- WFIFOL(2) = net_l_value(floorItem->int_id);
- WFIFOSET(6);
+ writeWord(0, 0x009f);
+ writeLong(2, floorItem->getId());
+ writeSet(6);
}
// Look To action
diff --git a/src/gui/requesttrade.cpp b/src/gui/requesttrade.cpp
index 35654562..e3b70fd3 100644
--- a/src/gui/requesttrade.cpp
+++ b/src/gui/requesttrade.cpp
@@ -24,16 +24,14 @@
#include "requesttrade.h"
#include <sstream>
-
#include <guichan/widgets/label.hpp>
#include "button.h"
-
#include "../net/network.h"
bool requestTradeDialogOpen = false;
-RequestTradeDialog::RequestTradeDialog(const char *name):
+RequestTradeDialog::RequestTradeDialog(const std::string &name):
Window("Request for Trade", true)
{
nameLabel[0] = new gcn::Label("");
@@ -88,16 +86,16 @@ void RequestTradeDialog::action(const std::string& eventId)
{
if (eventId == "accept") {
// Send the selected index back to the server
- WFIFOW(0) = net_w_value(0x00e6);
- WFIFOB(2) = net_b_value(3);
- WFIFOSET(3);
+ writeWord(0, 0x00e6);
+ writeByte(2, 3);
+ writeSet(3);
scheduleDelete();
}
else if (eventId == "cancel") {
// 0xff packet means cancel
- WFIFOW(0) = net_w_value(0x00e6);
- WFIFOB(2) = net_b_value(4);
- WFIFOSET(3);
+ writeWord(0, 0x00e6);
+ writeByte(2, 4);
+ writeSet(3);
requestTradeDialogOpen = false;
scheduleDelete();
}
diff --git a/src/gui/requesttrade.h b/src/gui/requesttrade.h
index 8c9ac29a..4cd33a49 100644
--- a/src/gui/requesttrade.h
+++ b/src/gui/requesttrade.h
@@ -21,15 +21,13 @@
* $Id$
*/
-#ifndef _TMW_REQUESTTRADE_H
-#define _TMW_REQUESTTRADE_H
+#ifndef _TMW_REQUESTTRADE_
+#define _TMW_REQUESTTRADE_
#include <iosfwd>
-
#include <guichan/actionlistener.hpp>
#include "window.h"
-
#include "../guichanfwd.h"
extern bool requestTradeDialogOpen;
@@ -47,7 +45,7 @@ class RequestTradeDialog : public Window, public gcn::ActionListener
*
* @see Window::Window
*/
- RequestTradeDialog(const char *name);
+ RequestTradeDialog(const std::string &name);
/**
* Destructor.
diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp
index 2684fc2a..b6cbe5df 100644
--- a/src/gui/sell.cpp
+++ b/src/gui/sell.cpp
@@ -230,11 +230,11 @@ void SellDialog::action(const std::string& eventId)
// Attempt sell
assert(m_amountItems > 0 && m_amountItems <= m_maxItems);
- WFIFOW(0) = net_w_value(0x00c9);
- WFIFOW(2) = net_w_value(8);
- WFIFOW(4) = net_w_value(shopInventory[selectedItem].index);
- WFIFOW(6) = net_w_value(m_amountItems);
- WFIFOSET(8);
+ writeWord(0, 0x00c9);
+ writeWord(2, 8);
+ writeWord(4, shopInventory[selectedItem].index);
+ writeWord(6, m_amountItems);
+ writeSet(8);
m_maxItems -= m_amountItems;
m_amountItems = 0;
diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp
index 5244b2f3..0e641768 100644
--- a/src/gui/skill.cpp
+++ b/src/gui/skill.cpp
@@ -122,12 +122,11 @@ void SkillDialog::action(const std::string& eventId)
{
// Increment skill
int selectedSkill = skillListBox->getSelected();
- if (char_info->skill_point > 0 && selectedSkill >= 0)
+ if (player_info->skill_point > 0 && selectedSkill >= 0)
{
- WFIFOW(0) = net_w_value(0x0112);
- WFIFOW(2) = net_w_value(
- skillList[selectedSkill]->id);
- WFIFOSET(4);
+ writeWord(0, 0x0112);
+ writeWord(2, skillList[selectedSkill]->id);
+ writeSet(4);
}
}
else if (eventId == "skill")
diff --git a/src/gui/stats.cpp b/src/gui/stats.cpp
index f03d2bfc..22f51827 100644
--- a/src/gui/stats.cpp
+++ b/src/gui/stats.cpp
@@ -89,36 +89,36 @@ void StatsWindow::update(){
std::stringstream remainingStatsPointsStr;
statsStr[0] << "Strength:";
- figureStr[0] << (int)char_info->STR;
+ figureStr[0] << (int)player_info->STR;
statsStr[1] << "Agility:";
- figureStr[1] << (int)char_info->AGI;
+ figureStr[1] << (int)player_info->AGI;
statsStr[2] << "Vitality:";
- figureStr[2] << (int)char_info->VIT;
+ figureStr[2] << (int)player_info->VIT;
statsStr[3] << "Intelligence:";
- figureStr[3] << (int)char_info->INT;
+ figureStr[3] << (int)player_info->INT;
statsStr[4] << "Dexterity:";
- figureStr[4] << (int)char_info->DEX;
+ figureStr[4] << (int)player_info->DEX;
statsStr[5] << "Luck:";
- figureStr[5] << (int)char_info->LUK;
+ figureStr[5] << (int)player_info->LUK;
- int statusPoints = char_info->statsPointsToAttribute;
+ int statusPoints = player_info->statsPointsToAttribute;
remainingStatsPointsStr << "Remaining Status Points: " << statusPoints;
-
- pointsStr[0] << (int)char_info->STRUp;
- pointsStr[1] << (int)char_info->AGIUp;
- pointsStr[2] << (int)char_info->VITUp;
- pointsStr[3] << (int)char_info->INTUp;
- pointsStr[4] << (int)char_info->DEXUp;
- pointsStr[5] << (int)char_info->LUKUp;
+
+ pointsStr[0] << (int)player_info->STRUp;
+ pointsStr[1] << (int)player_info->AGIUp;
+ pointsStr[2] << (int)player_info->VITUp;
+ pointsStr[3] << (int)player_info->INTUp;
+ pointsStr[4] << (int)player_info->DEXUp;
+ pointsStr[5] << (int)player_info->LUKUp;
// Enable buttons for which there are enough status points
- statsButton[0]->setEnabled(char_info->STRUp <= statusPoints);
- statsButton[1]->setEnabled(char_info->AGIUp <= statusPoints);
- statsButton[2]->setEnabled(char_info->VITUp <= statusPoints);
- statsButton[3]->setEnabled(char_info->INTUp <= statusPoints);
- statsButton[4]->setEnabled(char_info->DEXUp <= statusPoints);
- statsButton[5]->setEnabled(char_info->LUKUp <= statusPoints);
+ statsButton[0]->setEnabled(player_info->STRUp <= statusPoints);
+ statsButton[1]->setEnabled(player_info->AGIUp <= statusPoints);
+ statsButton[2]->setEnabled(player_info->VITUp <= statusPoints);
+ statsButton[3]->setEnabled(player_info->INTUp <= statusPoints);
+ statsButton[4]->setEnabled(player_info->DEXUp <= statusPoints);
+ statsButton[5]->setEnabled(player_info->LUKUp <= statusPoints);
// Update labels
for (i = 0; i < 6; i++) {
@@ -150,28 +150,28 @@ void StatsWindow::draw(gcn::Graphics *graphics)
}
void StatsWindow::action(const std::string& eventId) {
- WFIFOW(0) = net_w_value(0x00bb);
+ writeWord(0, 0x00bb);
if (eventId == "STR") {
- WFIFOW(2) = net_w_value(0x000d);
+ writeWord(2, 0x000d);
}
if (eventId == "AGI") {
- WFIFOW(2) = net_w_value(0x000e);
+ writeWord(2, 0x000e);
}
if (eventId == "VIT") {
- WFIFOW(2) = net_w_value(0x000f);
+ writeWord(2, 0x000f);
}
if (eventId == "INT") {
- WFIFOW(2) = net_w_value(0x0010);
+ writeWord(2, 0x0010);
}
if (eventId == "DEX") {
- WFIFOW(2) = net_w_value(0x0011);
+ writeWord(2, 0x0011);
}
if (eventId == "LUK") {
- WFIFOW(2) = net_w_value(0x0012);
+ writeWord(2, 0x0012);
}
flush();
- WFIFOW(4) = net_b_value(1);
- WFIFOSET(5);
+ writeByte(4, 1);
+ writeSet(5);
}
diff --git a/src/gui/status.cpp b/src/gui/status.cpp
index 7ba14fc7..7964768b 100644
--- a/src/gui/status.cpp
+++ b/src/gui/status.cpp
@@ -157,36 +157,36 @@ void StatusWindow::update()
char *tempstr = new char[64];
sprintf(tempstr, "%s Lvl: % 2i Job: % 2i GP: % 2i",
- char_info->name, char_info->lv, char_info->job_lv,
- char_info->gp);
+ player_info->name.c_str(), player_info->lv, player_info->job_lv,
+ player_info->gp);
setCaption(tempstr);
- sprintf(tempstr, "%d/%d", char_info->hp, char_info->max_hp);
+ sprintf(tempstr, "%d/%d", player_info->hp, player_info->max_hp);
hpValue->setCaption(tempstr);
hpValue->adjustSize();
- sprintf(tempstr, "%d/%d", char_info->sp, char_info->max_sp);
+ sprintf(tempstr, "%d/%d", player_info->sp, player_info->max_sp);
spValue->setCaption(tempstr);
spValue->adjustSize();
sprintf(tempstr, "Exp: %d/%d",
- (int)char_info->xp, (int)char_info->xpForNextLevel);
+ (int)player_info->xp, (int)player_info->xpForNextLevel);
expLabel->setCaption(tempstr);
expLabel->adjustSize();
sprintf(tempstr, "Job: %d/%d",
- (int)char_info->job_xp, (int)char_info->jobXpForNextLevel);
+ (int)player_info->job_xp, (int)player_info->jobXpForNextLevel);
jobExpLabel->setCaption(tempstr);
jobExpLabel->adjustSize();
// HP Bar coloration
- if (char_info->hp < int(char_info->max_hp / 3))
+ if (player_info->hp < int(player_info->max_hp / 3))
{
healthBar->setColor(223, 32, 32); // Red
}
else
{
- if (char_info->hp < int((char_info->max_hp / 3) * 2))
+ if (player_info->hp < int((player_info->max_hp / 3) * 2))
{
healthBar->setColor(230, 171, 34); // Orange
}
@@ -196,12 +196,14 @@ void StatusWindow::update()
}
}
- healthBar->setProgress((float)char_info->hp / (float)char_info->max_hp);
+ healthBar->setProgress((float)player_info->hp /
+ (float)player_info->max_hp);
- xpBar->setProgress(
- (float)char_info->xp / (float)char_info->xpForNextLevel);
- jobXpBar->setProgress(
- (float)char_info->job_xp / (float)char_info->jobXpForNextLevel);
+ xpBar->setProgress((float)player_info->xp /
+ (float)player_info->xpForNextLevel);
+
+ jobXpBar->setProgress((float)player_info->job_xp /
+ (float)player_info->jobXpForNextLevel);
delete[] tempstr;
}
diff --git a/src/gui/status.h b/src/gui/status.h
index d6abd7af..99fbadf5 100644
--- a/src/gui/status.h
+++ b/src/gui/status.h
@@ -64,7 +64,7 @@ class StatusWindow : public Window, public gcn::ActionListener {
private:
/**
- * Updates this dialog with values from PLAYER_INFO *char_info
+ * Updates this dialog with values from <code>player_info</code>
*/
void update();
@@ -73,7 +73,11 @@ class StatusWindow : public Window, public gcn::ActionListener {
gcn::Label *expLabel, *jobExpLabel;
ProgressBar *healthBar, *manaBar;
ProgressBar *xpBar, *jobXpBar;
- gcn::Button *statsButton, *skillsButton, *inventoryButton, *setupButton, *equipmentButton;
+ gcn::Button *statsButton;
+ gcn::Button *skillsButton;
+ gcn::Button *inventoryButton;
+ gcn::Button *setupButton;
+ gcn::Button *equipmentButton;
};
extern StatusWindow *statusWindow;
diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp
index f42ca1e0..e18dc969 100644
--- a/src/gui/trade.cpp
+++ b/src/gui/trade.cpp
@@ -161,8 +161,7 @@ void TradeWindow::addMoney(int amount)
moneyLabel->adjustSize();
}
-void TradeWindow::addItem(int id, bool own, int quantity,
- bool equipment)
+void TradeWindow::addItem(int id, bool own, int quantity, bool equipment)
{
if (own) {
myInventory->addItem(id, quantity, equipment);
@@ -241,11 +240,11 @@ void TradeWindow::receivedOk(bool own)
void TradeWindow::tradeItem(Item *item, int quantity)
{
- WFIFOW(0) = net_w_value(0x00e8);
- WFIFOW(2) = net_w_value(item->getInvIndex());
- WFIFOL(4) = net_l_value(quantity);
- WFIFOSET(8);
- while ((out_size > 0)) flush();
+ writeWord(0, 0x00e8);
+ writeWord(2, item->getInvIndex());
+ writeLong(4, quantity);
+ writeSet(8);
+ flush();
}
void TradeWindow::mouseClick(int x, int y, int button, int count)
@@ -314,9 +313,9 @@ void TradeWindow::action(const std::string &eventId)
}
else if (eventId == "cancel")
{
- WFIFOW(0) = net_w_value(0x00ed);
- WFIFOSET(2);
- while ((out_size > 0)) flush();
+ writeWord(0, 0x00ed);
+ writeSet(2);
+ flush();
}
else if (eventId == "ok")
{
@@ -328,23 +327,23 @@ void TradeWindow::action(const std::string &eventId)
tempMoney[1] << tempInt;
moneyField->setText(tempMoney[1].str());
- WFIFOW(0) = net_w_value(0x00e8);
- WFIFOW(2) = net_w_value(0);
- WFIFOL(4) = net_l_value(tempInt);
- WFIFOSET(8);
- while ((out_size > 0)) flush();
+ writeWord(0, 0x00e8);
+ writeWord(2, 0);
+ writeLong(4, tempInt);
+ writeSet(8);
+ flush();
} else {
moneyField->setText("");
}
moneyField->setEnabled(false);
- WFIFOW(0) = net_w_value(0x00eb);
- WFIFOSET(2);
- while ((out_size > 0)) flush();
+ writeWord(0, 0x00eb);
+ writeSet(2);
+ flush();
}
else if (eventId == "trade")
{
- WFIFOW(0) = net_w_value(0x00ef);
- WFIFOSET(2);
- while ((out_size > 0)) flush();
+ writeWord(0, 0x00ef);
+ writeSet(2);
+ flush();
}
}
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 9e3ad375..cf39f042 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -90,41 +90,41 @@ bool Inventory::contains(Item *item)
int Inventory::useItem(Item *item)
{
- WFIFOW(0) = net_w_value(0x00a7);
- WFIFOW(2) = net_w_value(item->getInvIndex());
- WFIFOL(4) = net_l_value(item->getId());
+ writeWord(0, 0x00a7);
+ writeWord(2, item->getInvIndex());
+ writeLong(4, item->getId());
// Note: id is dest of item, usually player_node->account_ID ??
- WFIFOSET(8);
- while ((out_size > 0)) flush();
+ writeSet(8);
+ flush();
return 0;
}
int Inventory::dropItem(Item *item, int quantity)
{
// TODO: Fix wrong coordinates of drops, serverside?
- WFIFOW(0) = net_w_value(0x00a2);
- WFIFOW(2) = net_w_value(item->getInvIndex());
- WFIFOW(4) = net_w_value(quantity);
- WFIFOSET(6);
- while ((out_size > 0)) flush();
+ writeWord(0, 0x00a2);
+ writeWord(2, item->getInvIndex());
+ writeWord(4, quantity);
+ writeSet(6);
+ flush();
return 0;
}
void Inventory::equipItem(Item *item)
{
- WFIFOW(0) = net_w_value(0x00a9);
- WFIFOW(2) = net_w_value(item->getInvIndex());
- WFIFOW(4) = net_w_value(0);
- WFIFOSET(6);
- while ((out_size > 0)) flush();
+ writeWord(0, 0x00a9);
+ writeWord(2, item->getInvIndex());
+ writeWord(4, 0);
+ writeSet(6);
+ flush();
}
void Inventory::unequipItem(Item *item)
{
- WFIFOW(0) = net_w_value(0x00ab);
- WFIFOW(2) = net_w_value(item->getInvIndex());
- WFIFOSET(4);
- while ((out_size > 0)) flush();
+ writeWord(0, 0x00ab);
+ writeWord(2, item->getInvIndex());
+ writeSet(4);
+ flush();
// Tidy equipment directly to avoid weapon still shown bug, by instance
Equipment::getInstance()->removeEquipment(item);
diff --git a/src/log.h b/src/log.h
index 297df88f..c74fe482 100644
--- a/src/log.h
+++ b/src/log.h
@@ -48,7 +48,7 @@ class Logger
/**
* Log an error and quit. The error will pop-up in Windows and will be
- * printed to standard error everywhere else.
+ * printed to standard error everywhere else.
*/
void error(const std::string &error_text);
diff --git a/src/main.cpp b/src/main.cpp
index 4ea181a5..4da837c8 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -62,13 +62,11 @@
#include "resources/image.h"
#include "resources/resourcemanager.h"
-struct SERVER_INFO;
-
// Account infos
int account_ID, session_ID1, session_ID2;
char sex, n_server, n_character;
-SERVER_INFO *server_info;
-PLAYER_INFO *char_info = new PLAYER_INFO;
+PLAYER_INFO **char_info;
+PLAYER_INFO *player_info;
Spriteset *hairset = NULL, *playerset = NULL;
Graphics *graphics;
diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp
new file mode 100644
index 00000000..2710d132
--- /dev/null
+++ b/src/net/messagein.cpp
@@ -0,0 +1,151 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * 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.
+ *
+ * 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "messagein.h"
+#include <SDL_net.h>
+#ifdef MACOSX
+#include "win2mac.h"
+#endif
+
+#define MAKEWORD(low,high) \
+ ((unsigned short)(((unsigned char)(low)) | \
+ ((unsigned short)((unsigned char)(high))) << 8))
+
+
+MessageIn::MessageIn(const char *data, unsigned int length):
+ mData(data),
+ mLength(length),
+ mPos(0)
+{
+ // Read the message ID
+ mId = readShort();
+}
+
+char
+MessageIn::readByte()
+{
+ assert(mPos < mLength);
+ return mData[mPos++];
+}
+
+short
+MessageIn::readShort()
+{
+ assert(mPos + 2 <= mLength);
+ mPos += 2;
+#ifdef MACOSX
+ return DR_SwapTwoBytes(*(short*)(mData + (mPos - 2)));
+#else
+ return (*(short*)(mData + (mPos - 2)));
+#endif
+}
+
+long
+MessageIn::readLong()
+{
+ assert(mPos + 4 <= mLength);
+ mPos += 4;
+#ifdef MACOSX
+ return DR_SwapFourBytes(*(long*)(mData + (mPos - 4)));
+#else
+ return (*(long*)(mData + (mPos - 4)));
+#endif
+}
+
+void
+MessageIn::readCoordinates(unsigned short &x,
+ unsigned short &y,
+ unsigned char &direction)
+{
+ assert(mPos + 3 <= mLength);
+
+ const char *data = mData + mPos;
+ short temp;
+
+ temp = MAKEWORD(data[1] & 0x00c0, data[0] & 0x00ff);
+ x = temp >> 6;
+ temp = MAKEWORD(data[2] & 0x00f0, data[1] & 0x003f);
+ y = temp >> 4;
+
+ direction = data[2] & 0x000f;
+
+ mPos += 3;
+}
+
+void
+MessageIn::readCoordinatePair(unsigned short &srcX, unsigned short &srcY,
+ unsigned short &dstX, unsigned short &dstY)
+{
+ assert(mPos + 5 <= mLength);
+
+ const char *data = mData + mPos;
+ short temp;
+
+ temp = MAKEWORD(data[3], data[2] & 0x000f);
+ dstX = temp >> 2;
+
+ dstY = MAKEWORD(data[4], data[3] & 0x0003);
+
+ temp = MAKEWORD(data[1], data[0]);
+ srcX = temp >> 6;
+
+ temp = MAKEWORD(data[2], data[1] & 0x003f);
+ srcY = temp >> 4;
+
+ mPos += 5;
+}
+
+void
+MessageIn::skip(unsigned int length)
+{
+ assert(mPos + length <= mLength);
+ mPos += length;
+}
+
+std::string
+MessageIn::readString(int length)
+{
+ int stringLength = 0;
+ std::string readString = "";
+
+ // Get string length
+ if (length < 0) {
+ stringLength = readShort();
+ } else {
+ stringLength = length;
+ }
+
+ // Make sure there is enough data available
+ assert(mPos + length <= mLength);
+
+ // Read the string
+ char *tmpString = new char[stringLength + 1];
+ memcpy(tmpString, (void*)&mData[mPos], stringLength);
+ tmpString[stringLength] = 0;
+ mPos += stringLength;
+
+ readString = tmpString;
+ delete tmpString;
+
+ return readString;
+}
diff --git a/src/net/messagein.h b/src/net/messagein.h
new file mode 100644
index 00000000..9a61ce7d
--- /dev/null
+++ b/src/net/messagein.h
@@ -0,0 +1,94 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * 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.
+ *
+ * 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_MESSAGEIN_
+#define _TMW_MESSAGEIN_
+
+#include <string>
+
+/**
+ * Used for parsing an incoming message.
+ */
+class MessageIn
+{
+ public:
+ /**
+ * Constructor.
+ */
+ MessageIn(const char *data, unsigned int length);
+
+ /**
+ * Returns the message ID.
+ */
+ short
+ getId() { return mId; }
+
+ /**
+ * Returns the message length.
+ */
+ unsigned int
+ getLength() { return mLength; }
+
+ char readByte(); /**< Reads a byte. */
+ short readShort(); /**< Reads a short. */
+ long readLong(); /**< Reads a long. */
+
+ /**
+ * Reads a special 3 byte block used by eAthena, containing x and y
+ * coordinates and direction.
+ */
+ void
+ readCoordinates(unsigned short &x,
+ unsigned short &y,
+ unsigned char &direction);
+
+ /**
+ * Reads a special 5 byte block used by eAthena, containing a source
+ * and destination coordinate pair.
+ */
+ void
+ readCoordinatePair(unsigned short &srcX, unsigned short &srcY,
+ unsigned short &dstX, unsigned short &dstY);
+
+ /**
+ * Skips a given number of bytes.
+ */
+ void
+ skip(unsigned int length);
+
+ /**
+ * Reads a string. If a length is not given (-1), it is assumed
+ * that the length of the string is stored in a short at the
+ * start of the string.
+ */
+ std::string
+ readString(int length = -1);
+
+ private:
+ const char* mData; /**< The message data. */
+ unsigned int mLength; /**< The length of the data. */
+ unsigned int mPos; /**< The position in the data. */
+ short mId; /**< The message ID. */
+};
+
+#endif
diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp
new file mode 100644
index 00000000..871ba43a
--- /dev/null
+++ b/src/net/messageout.cpp
@@ -0,0 +1,130 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * 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.
+ *
+ * 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "messageout.h"
+
+#include <iostream>
+#include <SDL_net.h>
+
+#include "network.h"
+
+MessageOut::MessageOut():
+ mPacket(0),
+ mData(0),
+ mDataSize(0),
+ mPos(0)
+{
+ // TODO: data not to be already allocated, keep it this way unitl full
+ // conversion
+ mData = out;
+}
+
+MessageOut::~MessageOut()
+{
+ if (mPacket) {
+ delete mPacket;
+ }
+
+ // Don't free this data for now, see above.
+ //if (mData) {
+ // free(mData);
+ //}
+}
+
+void MessageOut::expand(size_t bytes)
+{
+ mData = (char*)realloc(mData, bytes);
+ mDataSize = bytes;
+}
+
+void MessageOut::writeByte(char value)
+{
+ expand(mPos + sizeof(char));
+ mData[mPos] = value;
+ mPos += sizeof(char);
+}
+
+void MessageOut::writeShort(short value)
+{
+ expand(mPos + sizeof(short));
+#ifdef MACOSX
+ (*(short *)(mData + mPos)) = DR_SwapTwoBytes(value);
+#else
+ (*(short *)(mData + mPos)) = value;
+#endif
+ //SDLNet_Write16(value, &mData[mPos]);
+ mPos += sizeof(short);
+}
+
+void MessageOut::writeLong(long value)
+{
+ expand(mPos + sizeof(long));
+#ifdef MACOSX
+ (*(long *)(mData + mPos)) = DR_SwapFourBytes(value);
+#else
+ (*(long *)(mData + mPos)) = value;
+#endif
+ //SDLNet_Write32(value, &mData[mPos]);
+ mPos += sizeof(long);
+}
+
+void MessageOut::writeString(const std::string &string, int length)
+{
+ std::string toWrite = string;
+
+ if (length < 0)
+ {
+ // Write the length at the start if not fixed
+ writeShort(string.length());
+ toWrite = string;
+
+ expand(mPos + string.length());
+ }
+ else
+ {
+ // Make sure the length of the string is no longer than specified
+ toWrite = string.substr(0, length);
+ expand(mPos + length);
+ }
+
+ // Write the actual string
+ memcpy(&mData[mPos], (void*)toWrite.c_str(), toWrite.length());
+ mPos += toWrite.length();
+
+ // Pad remaining space with zeros
+ if (length > (int)toWrite.length())
+ {
+ memset(&mData[mPos], '\0', length - toWrite.length());
+ mPos += length - toWrite.length();
+ }
+}
+
+const Packet *MessageOut::getPacket()
+{
+ if (!mPacket)
+ {
+ mPacket = new Packet(mData, mDataSize);
+ }
+
+ return mPacket;
+}
diff --git a/src/net/messageout.h b/src/net/messageout.h
new file mode 100644
index 00000000..d836b43f
--- /dev/null
+++ b/src/net/messageout.h
@@ -0,0 +1,80 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * 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.
+ *
+ * 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_MESSAGEOUT_
+#define _TMW_MESSAGEOUT_
+
+#include <string>
+
+#include "packet.h"
+
+/**
+ * Used for building an outgoing message.
+ */
+class MessageOut
+{
+ public:
+ /**
+ * Constructor.
+ */
+ MessageOut();
+
+ /**
+ * Destructor.
+ */
+ ~MessageOut();
+
+ void writeByte(char value); /**< Writes a byte. */
+ void writeShort(short value); /**< Writes a short. */
+ void writeLong(long value); /**< Writes a long. */
+
+ /**
+ * Writes a string. If a fixed length is not given (-1), it is stored
+ * as a short at the start of the string.
+ */
+ void writeString(const std::string &string, int length = -1);
+
+ /**
+ * Returns an instance of Packet derived from the written data. Use for
+ * sending the packet. No more writing to the packet may be done after
+ * a call to this method.
+ */
+ const Packet *getPacket();
+
+ private:
+ /**
+ * Expand the packet data to be able to hold more data.
+ *
+ * NOTE: For performance enhancements this method could allocate extra
+ * memory in advance instead of expanding size every time more data is
+ * added.
+ */
+ void expand(unsigned int size);
+
+ Packet *mPacket; /**< Created packet. */
+ char *mData; /**< Data building up. */
+ unsigned int mDataSize; /**< Size of data. */
+ unsigned int mPos; /**< Position in the data. */
+};
+
+#endif
diff --git a/src/net/network.cpp b/src/net/network.cpp
index b0d27be9..6624ee1e 100644
--- a/src/net/network.cpp
+++ b/src/net/network.cpp
@@ -23,162 +23,309 @@
#include "../log.h"
#include "network.h"
+#include "protocol.h"
+#ifdef MACOSX
+#include "win2mac.h"
+#endif
#ifndef WIN32
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#endif
+#include <sstream>
/** Warning: buffers and other variables are shared,
so there can be only one connection active at a time */
-int buffer_size = 65536;
-char *in, *out;
-int in_size, out_size;
+short packet_lengths[] = {
+ 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// #0x0040
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 55, 17, 3, 37, 46, -1, 23, -1, 3,108, 3, 2,
+ 3, 28, 19, 11, 3, -1, 9, 5, 54, 53, 58, 60, 41, 2, 6, 6,
+// #0x0080
+ 7, 3, 2, 2, 2, 5, 16, 12, 10, 7, 29, 23, -1, -1, -1, 0,
+ 7, 22, 28, 2, 6, 30, -1, -1, 3, -1, -1, 5, 9, 17, 17, 6,
+ 23, 6, 6, -1, -1, -1, -1, 8, 7, 6, 7, 4, 7, 0, -1, 6,
+ 8, 8, 3, 3, -1, 6, 6, -1, 7, 6, 2, 5, 6, 44, 5, 3,
+// #0x00C0
+ 7, 2, 6, 8, 6, 7, -1, -1, -1, -1, 3, 3, 6, 6, 2, 27,
+ 3, 4, 4, 2, -1, -1, 3, -1, 6, 14, 3, -1, 28, 29, -1, -1,
+ 30, 30, 26, 2, 6, 26, 3, 3, 8, 19, 5, 2, 3, 2, 2, 2,
+ 3, 2, 6, 8, 21, 8, 8, 2, 2, 26, 3, -1, 6, 27, 30, 10,
+// #0x0100
+ 2, 6, 6, 30, 79, 31, 10, 10, -1, -1, 4, 6, 6, 2, 11, -1,
+ 10, 39, 4, 10, 31, 35, 10, 18, 2, 13, 15, 20, 68, 2, 3, 16,
+ 6, 14, -1, -1, 21, 8, 8, 8, 8, 8, 2, 2, 3, 4, 2, -1,
+ 6, 86, 6, -1, -1, 7, -1, 6, 3, 16, 4, 4, 4, 6, 24, 26,
+// #0x0140
+ 22, 14, 6, 10, 23, 19, 6, 39, 8, 9, 6, 27, -1, 2, 6, 6,
+ 110, 6, -1, -1, -1, -1, -1, 6, -1, 54, 66, 54, 90, 42, 6, 42,
+ -1, -1, -1, -1, -1, 30, -1, 3, 14, 3, 30, 10, 43, 14,186,182,
+ 14, 30, 10, 3, -1, 6,106, -1, 4, 5, 4, -1, 6, 7, -1, -1,
+// #0x0180
+ 6, 3,106, 10, 10, 34, 0, 6, 8, 4, 4, 4, 29, -1, 10, 6,
+ 90, 86, 24, 6, 30,102, 9, 4, 8, 4, 14, 10, 4, 6, 2, 6,
+ 3, 3, 35, 5, 11, 26, -1, 4, 4, 6, 10, 12, 6, -1, 4, 4,
+ 11, 7, -1, 67, 12, 18,114, 6, 3, 6, 26, 26, 26, 26, 2, 3,
+// #0x01C0
+ 2, 14, 10, -1, 22, 22, 4, 2, 13, 97, 0, 9, 9, 29, 6, 28,
+ 8, 14, 10, 35, 6, 8, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6,
+ 30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1,
+ -1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10,
+// #0x200
+ 26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
-SOCKET sock;
-SOCKADDR_IN addr;
-// File descriptors attached to socket
-fd_set read_socket;
-fd_set write_socket;
+unsigned int buffer_size = 65536;
+char *in = NULL;
+char *out = NULL;
+unsigned int in_size = 0;
+unsigned int out_size = 0;
+bool connectionOpen = false;
-void WFIFOSET(int len)
-{
- if (out_size + len >= buffer_size) {
- logger->log("Warning: Output buffer full");
- }
- else {
- out_size += len;
- }
-}
+TCPsocket sock;
+SDLNet_SocketSet set;
char *iptostring(int address)
{
- short temp1, temp2;
static char asciiIP[16];
- temp1 = LOWORD(address);
- temp2 = HIWORD(address);
- sprintf(asciiIP, "%i.%i.%i.%i", LOBYTE(temp1), HIBYTE(temp1), LOBYTE(temp2), HIBYTE(temp2));
+ sprintf(asciiIP, "%i.%i.%i.%i",
+ (unsigned char)(address),
+ (unsigned char)(address >> 8),
+ (unsigned char)(address >> 16),
+ (unsigned char)(address >> 24));
+
return asciiIP;
}
-SOCKET open_session(const char* address, short port)
+int open_session(const char* address, short port)
{
- #ifdef WIN32
- WSADATA wsda;
- #endif
- struct hostent *server;
- int ret;
-
- // Init WinSock and connect the socket
- #ifdef WIN32
- WSAStartup(MAKEWORD(2,0), &wsda);
- #endif
-
- sock = socket(PF_INET, SOCK_STREAM, 0); // Create socket for current session
- if(sock==SOCKET_ERROR)return SOCKET_ERROR;
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = inet_addr(address);
- if(addr.sin_addr.s_addr == INADDR_NONE){
- server = NULL;
- server = gethostbyname(address);
- if(server == NULL)return SOCKET_ERROR;
- memcpy(&addr.sin_addr, server->h_addr_list[0], server->h_length);
+ assert(!connectionOpen);
+
+ // Initialize SDL_net
+ if (SDLNet_Init() == -1)
+ {
+ logger->log("Error in SDLNet_Init(): %s", SDLNet_GetError());
+ return -1;
}
- ret = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
- if(ret == SOCKET_ERROR)return SOCKET_ERROR;
+ IPaddress ip;
+
+ // Resolve host name
+ if (SDLNet_ResolveHost(&ip, address, port) == -1)
+ {
+ logger->log("Error in SDLNet_ResolveHost(): %s", SDLNet_GetError());
+ return -1;
+ }
+
+ // Create the socket for the current session
+ sock = SDLNet_TCP_Open(&ip);
+ if (!sock)
+ {
+ logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError());
+ return -1;
+ }
+
+ // Create a socket set to listen to socket
+ set = SDLNet_AllocSocketSet(1);
+ if (!set)
+ {
+ logger->log("Error in SDLNet_AllocSocketSet(): %s", SDLNet_GetError());
+ return -1;
+ }
+
+ // Add the socket to the set
+ int ret = SDLNet_TCP_AddSocket(set, sock);
+ if (ret == -1)
+ {
+ logger->log("Error in SDLNet_AddSocket(): %s", SDLNet_GetError());
+ return -1;
+ }
// Init buffers
- in = (char *)malloc(buffer_size);
- out = (char *)malloc(buffer_size);
+ in = (char*)malloc(buffer_size);
+ out = (char*)malloc(buffer_size);
memset(in, '\0', buffer_size);
memset(out, '\0', buffer_size);
in_size = 0;
out_size = 0;
- FD_CLR(sock, &read_socket);
- FD_CLR(sock, &write_socket);
- return sock;
+ logger->log("Network::Started session with %s:%i", address, port);
+ connectionOpen = true;
+
+ return 0;
}
void close_session()
{
- FD_CLR(sock,&read_socket);
- FD_CLR(sock,&write_socket);
- closesocket(sock);
- if(in!=NULL) {
+ assert(connectionOpen);
+
+ // Remove the socket from the socket set
+ int ret = SDLNet_TCP_DelSocket(set, sock);
+ if (ret == -1)
+ {
+ logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError());
+ }
+
+ // Close the TCP connection
+ SDLNet_TCP_Close(sock);
+
+ // Free the socket set
+ SDLNet_FreeSocketSet(set);
+ set = NULL;
+
+ // Clear buffers
+ if (in != NULL)
+ {
free(in);
+ in = NULL;
}
- if(out!=NULL) {
+
+ if (out != NULL)
+ {
free(out);
+ out = NULL;
}
- in = NULL;
- out = NULL;
+
in_size = 0;
out_size = 0;
- WSACleanup();
+
+ // Shutdown the network API
+ SDLNet_Quit();
+
+ logger->log("Network::Closed session");
+ connectionOpen = false;
}
void flush()
{
- int ret = 0;
- void *buf = out;
- timeval time_out;
-
- // Init the time_out struct to 0s so it won't block
- time_out.tv_sec=0;
- time_out.tv_usec=0;
-
- // Clear file descriptors and set them to socket
- FD_ZERO(&read_socket);
- FD_ZERO(&write_socket);
- FD_SET(sock, &read_socket);
- FD_SET(sock, &write_socket);
-
- // Check if socket has available data by evaluating attached file descriptors
- select(FD_SETSIZE, &read_socket, &write_socket, NULL, &time_out);
-
- // Send data if available
- if(FD_ISSET(sock, &write_socket)) {
- // While there wasn't a error or sent the whole data: handles partial packet send
- while((ret!=SOCKET_ERROR)&&(out_size>0)) {
- ret = send(sock, (char *)buf, out_size, 0);
-
- if(ret!=SOCKET_ERROR && ret>0) {
- buf = (char*)buf+ret;
- out_size -= ret;
- }
+ int numReady = SDLNet_CheckSockets(set, 0);
+ if (numReady == -1)
+ {
+ logger->log("Error: SDLNet_CheckSockets");
+ return;
+ }
+ else if (numReady)
+ {
+ // Receive data from the socket
+ int ret = SDLNet_TCP_Recv(sock, in + in_size, buffer_size - in_size);
+ if (ret <= 0)
+ {
+ logger->log("Warning: unknown error when receiving data");
+ logger->log("SDLNet_GetError(): %s", SDLNet_GetError());
+ // The client disconnected, notify it somewhere
+ logger->error("Disconnected from server");
+ return;
+ }
+ else {
+ in_size += ret;
+ }
+ }
+
+ // Send all available data, waits if not all data can be sent immediately
+ if (out_size > 0)
+ {
+ int ret = SDLNet_TCP_Send(sock, (char*)out, out_size);
+ if (ret < (int)out_size)
+ {
+ // It is likely that the server disconnected
+ std::stringstream ss;
+ ss << "Error in SDLNet_TCP_Send(): " << SDLNet_GetError();
+ logger->error(ss.str());
+ return;
}
- if (ret == SOCKET_ERROR) {
- logger->error("Socket Error");
-#ifdef WIN32
- logger->log("Error: Socket error: %i ", WSAGetLastError());
- if (WSAGetLastError() == 10053)
- logger->log("Error: Packet size error");
- /** Probably the last packet you sent, was defined with
- * wrong size: WFIFOSET(size);
- */
+ out_size -= ret;
+ }
+}
+
+unsigned short readWord(int pos)
+{
+#ifdef MACOSX
+ return DR_SwapTwoBytes((*(unsigned short*)(in+(pos))));
#else
- logger->log("Error: Undefined socket error");
+ return (*(unsigned short *)(in+(pos)));
#endif
- }
+}
+
+MessageIn
+get_next_message()
+{
+ // At least 2 bytes should be received for the message ID
+ while (in_size < 2) flush();
+
+ int length = packet_lengths[readWord(0)];
+
+ if (length == -1)
+ {
+ // Another 2 bytes should be received for the length
+ while (in_size < 4) flush();
+ length = readWord(2);
}
- // Read data, if available
- if (FD_ISSET(sock, &read_socket)) {
- /* There's no check for partial received packets because at this level
- the app doesn't know packet length, but it will done when parsing received data */
- ret = recv(sock, in+in_size, RFIFOSPACE, 0);
- if (ret == SOCKET_ERROR) {
-#ifdef WIN32
- logger->log("Error: Socket error: %i ", WSAGetLastError());
+#ifdef DEBUG
+ printf("Received packet 0x%x of length %d\n", readWord(0), length);
+#endif
+
+ // Make sure the whole packet is received
+ while (in_size < (unsigned int)length) flush();
+
+ return MessageIn(in, length);
+}
+
+void writeByte(int pos, unsigned char value)//writeByte(unsigned char value)
+{
+ (*(unsigned char *)(out + pos + out_size)) = value;
+ //out_size++;
+}
+
+void writeWord(int pos, unsigned short value)//writeWord(unsigned short value)
+{
+#ifdef MACOSX
+ (*(unsigned short *)(out + pos + out_size)) = DR_SwapTwoBytes(value);
+#else
+ (*(unsigned short *)(out + pos + out_size)) = value;
+#endif
+ //SDLNet_Write16(value, (out + (pos + out_size)));
+ //out_size += 2;
+}
+
+void writeLong(int pos, unsigned int value)//writeLong(int value)
+{
+#ifdef MACOSX
+ (*(unsigned int *)(out + pos + out_size)) = DR_SwapFourBytes(value);
#else
- logger->log("Error: Undefined socket error");
+ (*(unsigned int *)(out + pos + out_size)) = value;
#endif
- } else RFIFOSET(ret); // Set size of available data to read
+ //SDLNet_Write32((Uint32)value, (out + (pos + out_size)));
+ //out_size += 4;
+}
+
+char *writePointer(int pos)//writeString(const std::string &string, int length)
+{
+ return (out+(pos+out_size));
+ //memcpy((out + out_size), string.c_str(), length);
+ //out_size += length;
+}
+
+void writeSet(unsigned int value)
+{
+ if (out_size + value >= buffer_size) {
+ logger->log("Warning: Output buffer full");
+ }
+ else {
+ out_size += value;
}
}
+
+void skip(int len)
+{
+ memcpy(in, in + len, in_size - len);
+ in_size -= len;
+}
diff --git a/src/net/network.h b/src/net/network.h
index cc5e542f..a037c6fa 100644
--- a/src/net/network.h
+++ b/src/net/network.h
@@ -21,67 +21,20 @@
* $Id$
*/
-#ifndef _TMW_NETWORK_H
-#define _TMW_NETWORK_H
-
-#ifndef WIN32
-#include "win2linux.h"
-#else
-#include <winsock.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef MACOSX
-#include "win2mac.h"
-#endif
-
-/** Macros to write in output buffer, pos is the location where to write data
- After you wrote len bytes, you have to use WFIFOSET */
-#define WFIFOSPACE (buffer_size-out_size) // Number of bytes currently written in uotput buffer
-#define WFIFOP(pos) (out+(pos+out_size)) // Return a pointer to a specific location in output buffer
-#define WFIFOB(pos) (*(unsigned char *)(out+pos+out_size)) // Write a byte (1 byte)
-#define WFIFOW(pos) (*(unsigned short *)(out+pos+out_size)) // Write a word (2 byte)
-#define WFIFOL(pos) (*(unsigned int *)(out+pos+out_size)) // Write a long (4 byte)
-//#define WFIFOSET(len) out_size+=len // Increase size of written data
-
-#ifdef MACOSX
- #define net_b_value(id) (id)
- #define net_w_value(id) DR_SwapTwoBytes(id)
- #define net_l_value(id) DR_SwapFourBytes(id)
-#else
- #define net_b_value(id) (id)
- #define net_w_value(id) (id)
- #define net_l_value(id) (id)
-#endif
+#ifndef _TMW_NETWORK_
+#define _TMW_NETWORK_
+#include <string>
-/** Macros to read from input buffer, pos is the location of data to be read
- After you read len bytes, you should use RFIFOSKIP */
-#define RFIFOP(pos) (in+(pos)) // Get a pointer from a specific location in input buffer
-
-#ifdef MACOSX
- #define RFIFOB(pos) ((*(unsigned char*)(in+(pos)))) // Read a byte
- #define RFIFOW(pos) DR_SwapTwoBytes((*(unsigned short*)(in+(pos)))) // Read a word
- #define RFIFOL(pos) DR_SwapFourBytes((*(unsigned int*)(in+(pos)))) // Read a long
-#else
- #define RFIFOB(pos) (*(unsigned char*)(in+(pos))) // Read a byte
- #define RFIFOW(pos) (*(unsigned short*)(in+(pos))) // Read a word
- #define RFIFOL(pos) (*(unsigned int*)(in+(pos))) // Read a long
-#endif
-
-#define RFIFOSKIP(len) (memcpy(in,in+len,in_size-len));in_size-=len; // Empty len bytes from input buffer
-#define RFIFOSPACE (buffer_size-in_size) // Return input buffer size
-#define RFIFOSET(len) in_size+=len;
-
-/** Increase size of written data */
-void WFIFOSET(int len);
+#include "SDL_net.h"
+#include "messagein.h"
+#include "messageout.h"
/** Convert an address from int format to string */
char *iptostring(int address);
/** Open a session with a server */
-SOCKET open_session(const char* address, short port);
+int open_session(const char* address, short port);
/** Close a session */
void close_session();
@@ -89,7 +42,21 @@ void close_session();
/** Send and receive data waiting in the buffers */
void flush();
-extern char *in, *out; // Input, output buffer
-extern int in_size, out_size; // Input, output buffer size
+/**
+ * Returns the next arriving message, waiting for it if necessary.
+ */
+MessageIn get_next_message();
+extern char *out;
+
+
+void writeByte(int pos, unsigned char value);//writeByte(char value);
+void writeWord(int pos, unsigned short value);//writeWord(short value);
+void writeLong(int pos, unsigned int value);//writeLong(int value);
+char *writePointer(int pos); //writeString(const std::string &string, int length);
+void writeSet(unsigned int value);
+void skip(int len);
+
+extern unsigned int in_size; /**< Amount of data in input buffer. */
+extern unsigned int out_size; /**< Amount of data in output buffer. */
#endif
diff --git a/src/net/packet.cpp b/src/net/packet.cpp
new file mode 100644
index 00000000..b8ee1e7f
--- /dev/null
+++ b/src/net/packet.cpp
@@ -0,0 +1,40 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * 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.
+ *
+ * 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "packet.h"
+#include <string.h>
+#include <cstdlib>
+
+Packet::Packet(const char *data, int length):
+ length(length)
+{
+ // Create a copy of the data
+ this->data = new char[length];
+ memcpy(this->data, data, length);
+}
+
+Packet::~Packet()
+{
+ // Clean up the data
+ delete[] data;
+}
diff --git a/src/net/packet.h b/src/net/packet.h
new file mode 100644
index 00000000..6b9fd18d
--- /dev/null
+++ b/src/net/packet.h
@@ -0,0 +1,47 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * 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.
+ *
+ * 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_PACKET_
+#define _TMW_PACKET_
+
+/**
+ * A packet wraps a certain amount of bytes for sending and receiving.
+ */
+class Packet
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Packet(const char *data, int length);
+
+ /**
+ * Destructor.
+ */
+ ~Packet();
+
+ char *data; /**< Packet data */
+ unsigned int length; /**< Length of data in bytes */
+};
+
+#endif
diff --git a/src/net/protocol.cpp b/src/net/protocol.cpp
index ce27b7ea..17076b90 100644
--- a/src/net/protocol.cpp
+++ b/src/net/protocol.cpp
@@ -23,10 +23,6 @@
#include "protocol.h"
-#ifndef WIN32
-#include "win2linux.h"
-#endif
-
#include "network.h"
#include "../being.h"
@@ -36,111 +32,24 @@
#include "../playerinfo.h"
#include "../sound.h"
+#define LOBYTE(w) ((unsigned char)(w))
+#define HIBYTE(w) ((unsigned char)(((unsigned short)(w)) >> 8))
-short packet_lengths[] = {
- 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// #0x0040
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 55, 17, 3, 37, 46, -1, 23, -1, 3,108, 3, 2,
- 3, 28, 19, 11, 3, -1, 9, 5, 54, 53, 58, 60, 41, 2, 6, 6,
-// #0x0080
- 7, 3, 2, 2, 2, 5, 16, 12, 10, 7, 29, 23, -1, -1, -1, 0,
- 7, 22, 28, 2, 6, 30, -1, -1, 3, -1, -1, 5, 9, 17, 17, 6,
- 23, 6, 6, -1, -1, -1, -1, 8, 7, 6, 7, 4, 7, 0, -1, 6,
- 8, 8, 3, 3, -1, 6, 6, -1, 7, 6, 2, 5, 6, 44, 5, 3,
-// #0x00C0
- 7, 2, 6, 8, 6, 7, -1, -1, -1, -1, 3, 3, 6, 6, 2, 27,
- 3, 4, 4, 2, -1, -1, 3, -1, 6, 14, 3, -1, 28, 29, -1, -1,
- 30, 30, 26, 2, 6, 26, 3, 3, 8, 19, 5, 2, 3, 2, 2, 2,
- 3, 2, 6, 8, 21, 8, 8, 2, 2, 26, 3, -1, 6, 27, 30, 10,
-// #0x0100
- 2, 6, 6, 30, 79, 31, 10, 10, -1, -1, 4, 6, 6, 2, 11, -1,
- 10, 39, 4, 10, 31, 35, 10, 18, 2, 13, 15, 20, 68, 2, 3, 16,
- 6, 14, -1, -1, 21, 8, 8, 8, 8, 8, 2, 2, 3, 4, 2, -1,
- 6, 86, 6, -1, -1, 7, -1, 6, 3, 16, 4, 4, 4, 6, 24, 26,
-// #0x0140
- 22, 14, 6, 10, 23, 19, 6, 39, 8, 9, 6, 27, -1, 2, 6, 6,
- 110, 6, -1, -1, -1, -1, -1, 6, -1, 54, 66, 54, 90, 42, 6, 42,
- -1, -1, -1, -1, -1, 30, -1, 3, 14, 3, 30, 10, 43, 14,186,182,
- 14, 30, 10, 3, -1, 6,106, -1, 4, 5, 4, -1, 6, 7, -1, -1,
-// #0x0180
- 6, 3,106, 10, 10, 34, 0, 6, 8, 4, 4, 4, 29, -1, 10, 6,
- 90, 86, 24, 6, 30,102, 9, 4, 8, 4, 14, 10, 4, 6, 2, 6,
- 3, 3, 35, 5, 11, 26, -1, 4, 4, 6, 10, 12, 6, -1, 4, 4,
- 11, 7, -1, 67, 12, 18,114, 6, 3, 6, 26, 26, 26, 26, 2, 3,
-// #0x01C0
- 2, 14, 10, -1, 22, 22, 4, 2, 13, 97, 0, 9, 9, 29, 6, 28,
- 8, 14, 10, 35, 6, 8, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6,
- 30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1,
- -1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10,
-// #0x200
- 26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-short get_length(short id) {
- return packet_lengths[id];
-}
-
-unsigned short get_dest_x(const char *data) {
- short temp;
- temp = MAKEWORD(data[3], data[2] & 0x000f);
- temp >>= 2;
- return temp;
-}
-
-unsigned short get_dest_y(const char *data) {
- return MAKEWORD(data[4], data[3] & 0x0003);
-}
-
-unsigned short get_src_x(const char *data) {
- short temp;
- temp = MAKEWORD(data[1], data[0]);
- temp >>= 6;
- return temp;
-}
-
-unsigned short get_src_y(const char *data) {
- short temp;
- temp = MAKEWORD(data[2], data[1] & 0x003f);
- temp >>= 4;
- return temp;
-}
-
-unsigned char get_src_direction(char data) {
+unsigned char get_src_direction(char data)
+{
data >>= 4;
return data;
}
-unsigned char get_dest_direction(char data) {
+unsigned char get_dest_direction(char data)
+{
return data & 0x000f;
}
-unsigned short get_x(const char *data) {
- short temp;
- temp = MAKEWORD(data[1] & 0x00c0, data[0] & 0x00ff);
- temp >>= 6;
- return temp;
-}
-
-unsigned short get_y(const char *data) {
- short temp;
- if (!data) throw "Corrupted data";
- temp = MAKEWORD(data[2] & 0x00f0, data[1] & 0x003f);
- temp >>= 4;
- return temp;
-}
-
-unsigned char get_direction(const char *data) {
- return data[2] & 0x000f;
-}
-
-void set_coordinates(char *data, unsigned short x, unsigned short y,
- unsigned char direction)
+void set_coordinates(char *data,
+ unsigned short x,
+ unsigned short y,
+ unsigned char direction)
{
short temp;
temp = x;
@@ -149,7 +58,7 @@ void set_coordinates(char *data, unsigned short x, unsigned short y,
data[1] = 1;
data[2] = 2;
data[0] = HIBYTE(temp);
- data[1] = LOBYTE(temp);
+ data[1] = (unsigned char)(temp);
temp = y;
temp <<= 4;
data[1] |= HIBYTE(temp);
@@ -160,7 +69,7 @@ void set_coordinates(char *data, unsigned short x, unsigned short y,
void map_start()
{
// Connect to map server
- if (open_session(iptostring(map_address), map_port) == SOCKET_ERROR)
+ if (open_session(iptostring(map_address), map_port) == -1)
{
logger->log("Warning: Unable to connect to map server");
throw "Unable to connect to map server";
@@ -168,63 +77,70 @@ void map_start()
}
// Send login infos
- WFIFOW(0) = net_w_value(0x0072);
- WFIFOL(2) = net_l_value(account_ID);
- WFIFOL(6) = net_l_value(char_ID);
- WFIFOL(10) = net_l_value(session_ID1);
- WFIFOL(14) = net_l_value(session_ID2);
- WFIFOB(18) = net_b_value(sex);
- WFIFOSET(19);
-
+ writeWord(0, 0x0072);
+ writeLong(2, account_ID);
+ writeLong(6, char_ID);
+ writeLong(10, session_ID1);
+ writeLong(14, session_ID2);
+ writeByte(18, sex);
+ writeSet(19);
+
+ // Skip a mysterious 4 bytes
while ((in_size < 4)|| (out_size > 0)) flush();
- RFIFOSKIP(4);
+ skip(4);
- while (in_size < 2) flush();
+ MessageIn msg = get_next_message();
- if (RFIFOW(0) == SMSG_LOGIN_SUCCESS) {
- while (in_size < 11) flush();
- startX = get_x(RFIFOP(6));
- startY = get_y(RFIFOP(6));
- int direction = get_direction(RFIFOP(6));
+ if (msg.getId() == SMSG_LOGIN_SUCCESS)
+ {
+ unsigned char direction;
+ msg.readLong(); // server tick
+ msg.readCoordinates(startX, startY, direction);
+ msg.skip(2); // unknown
logger->log("Protocol: Player start position: (%d, %d), Direction: %d",
startX, startY, direction);
- RFIFOSKIP(11);
- } else if (0x0081) {
+ }
+ else if (msg.getId() == 0x0081)
+ {
logger->log("Warning: Map server D/C");
- } else {
+ }
+ else
+ {
logger->error("Unknown packet: map_start");
}
+ skip(msg.getLength());
+
// Send "map loaded"
- WFIFOW(0) = net_w_value(0x007d);
- WFIFOSET(2);
- while (out_size > 0) flush();
+ writeWord(0, 0x007d);
+ writeSet(2);
+ flush();
}
void walk(unsigned short x, unsigned short y, unsigned char direction)
{
char temp[3];
set_coordinates(temp, x, y, direction);
- WFIFOW(0) = net_w_value(0x0085);
- memcpy(WFIFOP(2), temp, 3);
- WFIFOSET(5);
+ writeWord(0, 0x0085);
+ memcpy(writePointer(2), temp, 3);
+ writeSet(5);
}
void speak(char *speech)
{
int len = (int)strlen(speech);
- WFIFOW(0) = net_w_value(0x008c);
- WFIFOW(2) = net_w_value(len + 4);
- memcpy(WFIFOP(4), speech, len);
- WFIFOSET(len + 4);
+ writeWord(0, 0x008c);
+ writeWord(2, len + 4);
+ memcpy(writePointer(4), speech, len);
+ writeSet(len + 4);
}
void action(char type, int id)
{
- WFIFOW(0) = net_w_value(0x0089);
- WFIFOL(2) = net_l_value(id);
- WFIFOB(6) = net_b_value(type);
- WFIFOSET(7);
+ writeWord(0, 0x0089);
+ writeLong(2, id);
+ writeByte(6, type);
+ writeSet(7);
}
Being* attack(unsigned short x, unsigned short y, unsigned char direction)
@@ -278,7 +194,7 @@ void attack(Being *target)
}
// Implement charging attacks here
- char_info->lastAttackTime = 0;
+ player_info->lastAttackTime = 0;
player_node->action = Being::ATTACK;
action(0, target->getId());
diff --git a/src/net/protocol.h b/src/net/protocol.h
index 3fa039ba..69b36783 100644
--- a/src/net/protocol.h
+++ b/src/net/protocol.h
@@ -21,52 +21,74 @@
* $Id$
*/
-#ifndef _TMW_PROTOCOL_H
-#define _TMW_PROTOCOL_H
+#ifndef _TMW_PROTOCOL_
+#define _TMW_PROTOCOL_
class Being;
// Packets from server to client
-#define SMSG_LOGIN_SUCCESS 0x0073 /**< Logged in, starting location */
-#define SMSG_REMOVE_BEING 0x0080 /**< Died, logged out, teleport ... */
-#define SMSG_MOVE_BEING 0x007b /**< A nearby monster moves */
-#define SMSG_PLAYER_UPDATE_1 0x01d8
-#define SMSG_PLAYER_UPDATE_2 0x01d9
-#define SMSG_MOVE_PLAYER_BEING 0x01da /**< A nearby player moves */
-#define SMSG_CHANGE_BEING_LOOKS 0x00c3
-#define SMSG_BEING_CHAT 0x008d /**< A being talks */
-#define SMSG_MY_BEING_CHAT 0x008e /**< My being talks */
-#define SMSG_GM_CHAT 0x009a /**< GM announce */
-#define SMSG_WALK_RESPONSE 0x0087
+#define SMSG_LOGIN_SUCCESS 0x0073 /**< Contains starting location */
+#define SMSG_PLAYER_UPDATE_1 0x01d8
+#define SMSG_PLAYER_UPDATE_2 0x01d9
+#define SMSG_PLAYER_MOVE 0x01da /**< A nearby player moves */
+#define SMSG_PLAYER_STAT_UPDATE_1 0x00b0
+#define SMSG_PLAYER_STAT_UPDATE_2 0x00b1
+#define SMSG_PLAYER_STAT_UPDATE_3 0x0141
+#define SMSG_PLAYER_STAT_UPDATE_4 0x00bc
+#define SMSG_PLAYER_STAT_UPDATE_5 0x00bd
+#define SMSG_PLAYER_STAT_UPDATE_6 0x00be
+#define SMSG_PLAYER_WARP 0x0091 /**< Warp player to map/location */
+#define SMSG_PLAYER_INVENTORY 0x01ee
+#define SMSG_PLAYER_INVENTORY_ADD 0x00a0
+#define SMSG_PLAYER_INVENTORY_REMOVE 0x00af
+#define SMSG_PLAYER_INVENTORY_USE 0x01c8
+#define SMSG_PLAYER_EQUIPMENT 0x00a4
+#define SMSG_PLAYER_EQUIP 0x00aa
+#define SMSG_PLAYER_UNEQUIP 0x00ac
+#define SMSG_PLAYER_ARROW_EQUIP 0x013c
+#define SMSG_PLAYER_ARROW_MESSAGE 0x013b
+#define SMSG_PLAYER_SKILLS 0x010f
+#define SMSG_SKILL_FAILED 0x0110
+#define SMSG_ITEM_USE_RESPONSE 0x00a8
+#define SMSG_ITEM_VISIBLE 0x009d /**< An item is on the floor */
+#define SMSG_ITEM_DROPPED 0x009e /**< An item is dropped */
+#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_REMOVE 0x0080
+#define SMSG_BEING_CHANGE_LOOKS 0x00c3
+#define SMSG_BEING_LEVELUP 0x019b
+#define SMSG_BEING_EMOTION 0x00c0
+#define SMSG_BEING_ACTION 0x008a /**< Attack, sit, stand up, ... */
+#define SMSG_BEING_CHAT 0x008d /**< A being talks */
+#define SMSG_BEING_NAME_RESPONSE 0x0095 /**< Has to be requested */
+#define SMSG_NPC_MESSAGE 0x00b4
+#define SMSG_NPC_NEXT 0x00b5
+#define SMSG_NPC_CLOSE 0x00b6
+#define SMSG_NPC_CHOICE 0x00b7 /**< Display a choice */
+#define SMSG_NPC_BUY_SELL_CHOICE 0x00c4
+#define SMSG_NPC_BUY 0x00c6
+#define SMSG_NPC_SELL 0x00c7
+#define SMSG_NPC_BUY_RESPONSE 0x00ca
+#define SMSG_NPC_SELL_RESPONSE 0x00cb
+#define SMSG_PLAYER_CHAT 0x008e /**< Player talks */
+#define SMSG_GM_CHAT 0x009a /**< GM announce */
+#define SMSG_WALK_RESPONSE 0x0087
+#define SMSG_TRADE_REQUEST 0x00e5 /**< Receiving a request to trade */
+#define SMSG_TRADE_RESPONSE 0x00e7
+#define SMSG_TRADE_ITEM_ADD 0x00e9
+#define SMSG_TRADE_ITEM_ADD_RESPONSE 0x01b1 /**< Not standard eAthena! */
+#define SMSG_TRADE_OK 0x00ec
+#define SMSG_TRADE_CANCEL 0x00ee
+#define SMSG_TRADE_COMPLETE 0x00f0
+
+// Packets from client to server
+#define CMSG_TRADE_RESPONSE 0x00e6
-/** Packet length by id */
-short get_length(short id);
-
-/** Decodes x coord */
-unsigned short get_x(const char *data);
-
-/** Decodes y coord */
-unsigned short get_y(const char *data);
-
-/** Decodes direction */
-unsigned char get_direction(const char *data);
-
-/** Decodes src x coord */
-unsigned short get_src_x(const char *data);
-
-/** Decodes src y coord */
-unsigned short get_src_y(const char *data);
-
/** Decodes src direction */
unsigned char get_src_direction(char data);
-/** Decodes dest x coord */
-unsigned short get_dest_x(const char *data);
-
-/** Decodes dest y coord */
-unsigned short get_dest_y(const char *data);
-
/** Decodes dest direction */
unsigned char get_dest_direction(char data);
diff --git a/src/net/win2linux.h b/src/net/win2linux.h
deleted file mode 100644
index 1371f4d9..00000000
--- a/src/net/win2linux.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-typedef unsigned char BYTE;
-typedef unsigned short WORD;
-#define MAKEWORD(low,high) \
- ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8))
-#define closesocket(a) close(a)
-#define SOCKET int
-#define SOCKET_ERROR -1
-#define SOCKADDR_IN struct sockaddr_in
-typedef struct sockaddr SOCKADDR;
-typedef SOCKADDR * LPSOCKADDR;
-#define WSACleanup() ;
-
-
-
-typedef unsigned short WORD;
-typedef unsigned long int LWORD;
-typedef unsigned char BYTE;
-#define LOBYTE(w) ((BYTE) (w) )
-#define HIBYTE(w) ((BYTE) (((WORD)(w)) >> 8) )
-#define LOWORD(l) ((WORD) (l) )
-#define HIWORD(l) ((WORD) (((LWORD)(l)) >> 16) )
-#define HANDLE int
-#define HANDLE int
-#define PHANDLE int
-#define SMALL_RECT int
-//#define WORD int
-#define DWORD int
-#define PDWORD int
-#define BOOL int
-#define LPBOOL int
-#define LPSTR int
-#define LPTSTR int
-#define LPCTSTR int
-#define LPDWORD int
-#define LPVOID int
-#define WINAPI
-
-#define LOBYTE(w) ((BYTE) (w) )
-#define HIBYTE(w) ((BYTE) (((WORD)(w)) >> 8) )
-#define LPTHREAD_START_ROUTINE void *(*)(void *)
-#define CloseHandle close
diff --git a/src/net/win2mac.cpp b/src/net/win2mac.cpp
index 6ddc59cc..d6da2cf2 100644
--- a/src/net/win2mac.cpp
+++ b/src/net/win2mac.cpp
@@ -1,5 +1,7 @@
#include "win2mac.h"
+#define SWAP( a, b ) { char c; c=a; a=b; b=c; }
+
UInt32 DR_SwapFourBytes(UInt32 dw)
{
UInt32 tmp;
@@ -21,15 +23,9 @@ UInt16 DR_SwapTwoBytes(UInt16 w)
char* SwapChar(char charlist[])
{
for (int i = 0; i < 24 / 2; i++)
- SWAP(charlist[i],charlist[24 - i]);
- return charlist;
-}
+ {
+ SWAP(charlist[i], charlist[24 - i]);
+ }
-/*
-char* SwapChar(char charlist[])
-{
- for (int i = 0; i < sizeof(charlist) * 4 / 2; i++)
- SWAP(charlist[i],charlist[sizeof(charlist) * 4 - i]);
return charlist;
}
-*/
diff --git a/src/net/win2mac.h b/src/net/win2mac.h
index 8159f4a3..29102fae 100644
--- a/src/net/win2mac.h
+++ b/src/net/win2mac.h
@@ -1,13 +1,10 @@
-#ifndef _TMW_MAC_H
-#define _TMW_MAC_H
+#ifndef _TMW_WIN2MAC_
+#define _TMW_WIN2MAC_
#include <stdio.h>
#define UInt16 unsigned short int
-#define INT16 short int
#define UInt32 unsigned long int
-#define INT32 long int
-#define SWAP( a, b ) { char c; c=a; a=b; b=c; }
UInt32 DR_SwapFourBytes(UInt32 dw);
UInt16 DR_SwapTwoBytes(UInt16 w);
diff --git a/src/playerinfo.h b/src/playerinfo.h
index 29109fb6..c4028131 100644
--- a/src/playerinfo.h
+++ b/src/playerinfo.h
@@ -21,15 +21,16 @@
* $Id$
*/
-#ifndef _TMW_PLAYERINFO_H
-#define _TMW_PLAYERINFO_H
+#ifndef _TMW_PLAYERINFO_
+#define _TMW_PLAYERINFO_
-#include <vector>
+#include <string>
-struct PLAYER_INFO {
+struct PLAYER_INFO
+{
int id;
- float lastAttackTime; // used to synchronize the charge dialog
- char name[24];
+ float lastAttackTime; /**< Used to synchronize the charge dialog */
+ std::string name; /**< Player name */
short hp, max_hp, sp, max_sp, lv;
short statsPointsToAttribute;
int xp, xpForNextLevel, gp, job_xp, jobXpForNextLevel, job_lv;
@@ -40,6 +41,7 @@ struct PLAYER_INFO {
short weapon;
};
-extern PLAYER_INFO *char_info;
+extern PLAYER_INFO **char_info;
+extern PLAYER_INFO *player_info;
#endif
diff --git a/src/serverinfo.h b/src/serverinfo.h
index be3fccaa..b317b87b 100644
--- a/src/serverinfo.h
+++ b/src/serverinfo.h
@@ -21,16 +21,17 @@
* $Id$
*/
-#ifndef _TMW_SERVERINFO_H
-#define _TMW_SERVERINFO_H
+#ifndef _TMW_SERVERINFO_
+#define _TMW_SERVERINFO_
-typedef struct {
+#include <string>
+
+struct SERVER_INFO
+{
int address;
short port;
- char name[20];
+ std::string name;
short online_users;
-} SERVER_INFO;
-
-extern SERVER_INFO *server_info;
+};
#endif