From 3ae525b05858af105cc7e3eb6ac7316fc2f5bbd5 Mon Sep 17 00:00:00 2001 From: Bertram Date: Fri, 16 Apr 2010 13:58:56 +0200 Subject: Changed eAthena protocol name to TmwAthena and changed the config files accordingly. This makes room for the actual eAthena protocol future inclusion. --- mana.cbp | 92 ++--- mana.files | 92 ++--- src/CMakeLists.txt | 96 ++--- src/Makefile.am | 92 ++--- src/being.cpp | 8 +- src/gui/serverdialog.cpp | 16 +- src/gui/skilldialog.cpp | 2 +- src/gui/viewport.cpp | 4 +- src/localplayer.cpp | 10 +- src/monster.cpp | 2 +- src/net/ea/adminhandler.cpp | 131 ------- src/net/ea/adminhandler.h | 62 ---- src/net/ea/beinghandler.cpp | 714 ------------------------------------- src/net/ea/beinghandler.h | 43 --- src/net/ea/buysellhandler.cpp | 138 ------- src/net/ea/buysellhandler.h | 45 --- src/net/ea/charserverhandler.cpp | 352 ------------------ src/net/ea/charserverhandler.h | 80 ----- src/net/ea/chathandler.cpp | 248 ------------- src/net/ea/chathandler.h | 68 ---- src/net/ea/gamehandler.cpp | 174 --------- src/net/ea/gamehandler.h | 70 ---- src/net/ea/generalhandler.cpp | 255 ------------- src/net/ea/generalhandler.h | 78 ---- src/net/ea/gui/guildtab.cpp | 117 ------ src/net/ea/gui/guildtab.h | 52 --- src/net/ea/gui/partytab.cpp | 209 ----------- src/net/ea/gui/partytab.h | 52 --- src/net/ea/guildhandler.cpp | 480 ------------------------- src/net/ea/guildhandler.h | 71 ---- src/net/ea/inventoryhandler.cpp | 519 --------------------------- src/net/ea/inventoryhandler.h | 164 --------- src/net/ea/itemhandler.cpp | 68 ---- src/net/ea/itemhandler.h | 39 -- src/net/ea/loginhandler.cpp | 315 ---------------- src/net/ea/loginhandler.h | 94 ----- src/net/ea/messagehandler.cpp | 47 --- src/net/ea/messagehandler.h | 58 --- src/net/ea/messagein.cpp | 74 ---- src/net/ea/messagein.h | 51 --- src/net/ea/messageout.cpp | 128 ------- src/net/ea/messageout.h | 64 ---- src/net/ea/network.cpp | 478 ------------------------- src/net/ea/network.h | 130 ------- src/net/ea/npchandler.cpp | 226 ------------ src/net/ea/npchandler.h | 80 ----- src/net/ea/partyhandler.cpp | 411 --------------------- src/net/ea/partyhandler.h | 76 ---- src/net/ea/playerhandler.cpp | 652 --------------------------------- src/net/ea/playerhandler.h | 66 ---- src/net/ea/protocol.h | 311 ---------------- src/net/ea/specialhandler.cpp | 255 ------------- src/net/ea/specialhandler.h | 50 --- src/net/ea/token.h | 43 --- src/net/ea/tradehandler.cpp | 288 --------------- src/net/ea/tradehandler.h | 58 --- src/net/net.cpp | 6 +- src/net/serverinfo.h | 9 +- src/net/tmwa/adminhandler.cpp | 131 +++++++ src/net/tmwa/adminhandler.h | 62 ++++ src/net/tmwa/beinghandler.cpp | 714 +++++++++++++++++++++++++++++++++++++ src/net/tmwa/beinghandler.h | 43 +++ src/net/tmwa/buysellhandler.cpp | 138 +++++++ src/net/tmwa/buysellhandler.h | 45 +++ src/net/tmwa/charserverhandler.cpp | 352 ++++++++++++++++++ src/net/tmwa/charserverhandler.h | 80 +++++ src/net/tmwa/chathandler.cpp | 248 +++++++++++++ src/net/tmwa/chathandler.h | 68 ++++ src/net/tmwa/gamehandler.cpp | 174 +++++++++ src/net/tmwa/gamehandler.h | 70 ++++ src/net/tmwa/generalhandler.cpp | 255 +++++++++++++ src/net/tmwa/generalhandler.h | 78 ++++ src/net/tmwa/gui/guildtab.cpp | 117 ++++++ src/net/tmwa/gui/guildtab.h | 52 +++ src/net/tmwa/gui/partytab.cpp | 209 +++++++++++ src/net/tmwa/gui/partytab.h | 52 +++ src/net/tmwa/guildhandler.cpp | 480 +++++++++++++++++++++++++ src/net/tmwa/guildhandler.h | 71 ++++ src/net/tmwa/inventoryhandler.cpp | 519 +++++++++++++++++++++++++++ src/net/tmwa/inventoryhandler.h | 164 +++++++++ src/net/tmwa/itemhandler.cpp | 68 ++++ src/net/tmwa/itemhandler.h | 39 ++ src/net/tmwa/loginhandler.cpp | 315 ++++++++++++++++ src/net/tmwa/loginhandler.h | 94 +++++ src/net/tmwa/messagehandler.cpp | 47 +++ src/net/tmwa/messagehandler.h | 58 +++ src/net/tmwa/messagein.cpp | 74 ++++ src/net/tmwa/messagein.h | 51 +++ src/net/tmwa/messageout.cpp | 128 +++++++ src/net/tmwa/messageout.h | 64 ++++ src/net/tmwa/network.cpp | 478 +++++++++++++++++++++++++ src/net/tmwa/network.h | 130 +++++++ src/net/tmwa/npchandler.cpp | 226 ++++++++++++ src/net/tmwa/npchandler.h | 80 +++++ src/net/tmwa/partyhandler.cpp | 411 +++++++++++++++++++++ src/net/tmwa/partyhandler.h | 76 ++++ src/net/tmwa/playerhandler.cpp | 652 +++++++++++++++++++++++++++++++++ src/net/tmwa/playerhandler.h | 66 ++++ src/net/tmwa/protocol.h | 311 ++++++++++++++++ src/net/tmwa/specialhandler.cpp | 255 +++++++++++++ src/net/tmwa/specialhandler.h | 50 +++ src/net/tmwa/token.h | 43 +++ src/net/tmwa/tradehandler.cpp | 288 +++++++++++++++ src/net/tmwa/tradehandler.h | 58 +++ src/player.cpp | 2 +- src/resources/monsterdb.cpp | 4 +- 106 files changed, 8403 insertions(+), 8400 deletions(-) delete mode 100644 src/net/ea/adminhandler.cpp delete mode 100644 src/net/ea/adminhandler.h delete mode 100644 src/net/ea/beinghandler.cpp delete mode 100644 src/net/ea/beinghandler.h delete mode 100644 src/net/ea/buysellhandler.cpp delete mode 100644 src/net/ea/buysellhandler.h delete mode 100644 src/net/ea/charserverhandler.cpp delete mode 100644 src/net/ea/charserverhandler.h delete mode 100644 src/net/ea/chathandler.cpp delete mode 100644 src/net/ea/chathandler.h delete mode 100644 src/net/ea/gamehandler.cpp delete mode 100644 src/net/ea/gamehandler.h delete mode 100644 src/net/ea/generalhandler.cpp delete mode 100644 src/net/ea/generalhandler.h delete mode 100644 src/net/ea/gui/guildtab.cpp delete mode 100644 src/net/ea/gui/guildtab.h delete mode 100644 src/net/ea/gui/partytab.cpp delete mode 100644 src/net/ea/gui/partytab.h delete mode 100644 src/net/ea/guildhandler.cpp delete mode 100644 src/net/ea/guildhandler.h delete mode 100644 src/net/ea/inventoryhandler.cpp delete mode 100644 src/net/ea/inventoryhandler.h delete mode 100644 src/net/ea/itemhandler.cpp delete mode 100644 src/net/ea/itemhandler.h delete mode 100644 src/net/ea/loginhandler.cpp delete mode 100644 src/net/ea/loginhandler.h delete mode 100644 src/net/ea/messagehandler.cpp delete mode 100644 src/net/ea/messagehandler.h delete mode 100644 src/net/ea/messagein.cpp delete mode 100644 src/net/ea/messagein.h delete mode 100644 src/net/ea/messageout.cpp delete mode 100644 src/net/ea/messageout.h delete mode 100644 src/net/ea/network.cpp delete mode 100644 src/net/ea/network.h delete mode 100644 src/net/ea/npchandler.cpp delete mode 100644 src/net/ea/npchandler.h delete mode 100644 src/net/ea/partyhandler.cpp delete mode 100644 src/net/ea/partyhandler.h delete mode 100644 src/net/ea/playerhandler.cpp delete mode 100644 src/net/ea/playerhandler.h delete mode 100644 src/net/ea/protocol.h delete mode 100644 src/net/ea/specialhandler.cpp delete mode 100644 src/net/ea/specialhandler.h delete mode 100644 src/net/ea/token.h delete mode 100644 src/net/ea/tradehandler.cpp delete mode 100644 src/net/ea/tradehandler.h create mode 100644 src/net/tmwa/adminhandler.cpp create mode 100644 src/net/tmwa/adminhandler.h create mode 100644 src/net/tmwa/beinghandler.cpp create mode 100644 src/net/tmwa/beinghandler.h create mode 100644 src/net/tmwa/buysellhandler.cpp create mode 100644 src/net/tmwa/buysellhandler.h create mode 100644 src/net/tmwa/charserverhandler.cpp create mode 100644 src/net/tmwa/charserverhandler.h create mode 100644 src/net/tmwa/chathandler.cpp create mode 100644 src/net/tmwa/chathandler.h create mode 100644 src/net/tmwa/gamehandler.cpp create mode 100644 src/net/tmwa/gamehandler.h create mode 100644 src/net/tmwa/generalhandler.cpp create mode 100644 src/net/tmwa/generalhandler.h create mode 100644 src/net/tmwa/gui/guildtab.cpp create mode 100644 src/net/tmwa/gui/guildtab.h create mode 100644 src/net/tmwa/gui/partytab.cpp create mode 100644 src/net/tmwa/gui/partytab.h create mode 100644 src/net/tmwa/guildhandler.cpp create mode 100644 src/net/tmwa/guildhandler.h create mode 100644 src/net/tmwa/inventoryhandler.cpp create mode 100644 src/net/tmwa/inventoryhandler.h create mode 100644 src/net/tmwa/itemhandler.cpp create mode 100644 src/net/tmwa/itemhandler.h create mode 100644 src/net/tmwa/loginhandler.cpp create mode 100644 src/net/tmwa/loginhandler.h create mode 100644 src/net/tmwa/messagehandler.cpp create mode 100644 src/net/tmwa/messagehandler.h create mode 100644 src/net/tmwa/messagein.cpp create mode 100644 src/net/tmwa/messagein.h create mode 100644 src/net/tmwa/messageout.cpp create mode 100644 src/net/tmwa/messageout.h create mode 100644 src/net/tmwa/network.cpp create mode 100644 src/net/tmwa/network.h create mode 100644 src/net/tmwa/npchandler.cpp create mode 100644 src/net/tmwa/npchandler.h create mode 100644 src/net/tmwa/partyhandler.cpp create mode 100644 src/net/tmwa/partyhandler.h create mode 100644 src/net/tmwa/playerhandler.cpp create mode 100644 src/net/tmwa/playerhandler.h create mode 100644 src/net/tmwa/protocol.h create mode 100644 src/net/tmwa/specialhandler.cpp create mode 100644 src/net/tmwa/specialhandler.h create mode 100644 src/net/tmwa/token.h create mode 100644 src/net/tmwa/tradehandler.cpp create mode 100644 src/net/tmwa/tradehandler.h diff --git a/mana.cbp b/mana.cbp index d8cde0e9..3d3b85e0 100644 --- a/mana.cbp +++ b/mana.cbp @@ -372,52 +372,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mana.files b/mana.files index eb5f8ad2..552ab8a6 100644 --- a/mana.files +++ b/mana.files @@ -310,52 +310,52 @@ ./src/net/chathandler.h ./src/net/download.cpp ./src/net/download.h -./src/net/ea/adminhandler.cpp -./src/net/ea/adminhandler.h -./src/net/ea/beinghandler.cpp -./src/net/ea/beinghandler.h -./src/net/ea/buysellhandler.cpp -./src/net/ea/buysellhandler.h -./src/net/ea/charserverhandler.cpp -./src/net/ea/charserverhandler.h -./src/net/ea/chathandler.cpp -./src/net/ea/chathandler.h -./src/net/ea/gamehandler.cpp -./src/net/ea/gamehandler.h -./src/net/ea/generalhandler.cpp -./src/net/ea/generalhandler.h -./src/net/ea/gui/guildtab.cpp -./src/net/ea/gui/guildtab.h -./src/net/ea/guildhandler.cpp -./src/net/ea/guildhandler.h -./src/net/ea/gui/partytab.cpp -./src/net/ea/gui/partytab.h -./src/net/ea/inventoryhandler.cpp -./src/net/ea/inventoryhandler.h -./src/net/ea/itemhandler.cpp -./src/net/ea/itemhandler.h -./src/net/ea/loginhandler.cpp -./src/net/ea/loginhandler.h -./src/net/ea/messagehandler.cpp -./src/net/ea/messagehandler.h -./src/net/ea/messagein.cpp -./src/net/ea/messagein.h -./src/net/ea/messageout.cpp -./src/net/ea/messageout.h -./src/net/ea/network.cpp -./src/net/ea/network.h -./src/net/ea/npchandler.cpp -./src/net/ea/npchandler.h -./src/net/ea/partyhandler.cpp -./src/net/ea/partyhandler.h -./src/net/ea/playerhandler.cpp -./src/net/ea/playerhandler.h -./src/net/ea/protocol.h -./src/net/ea/specialhandler.cpp -./src/net/ea/specialhandler.h -./src/net/ea/token.h -./src/net/ea/tradehandler.cpp -./src/net/ea/tradehandler.h +./src/net/tmwa/adminhandler.cpp +./src/net/tmwa/adminhandler.h +./src/net/tmwa/beinghandler.cpp +./src/net/tmwa/beinghandler.h +./src/net/tmwa/buysellhandler.cpp +./src/net/tmwa/buysellhandler.h +./src/net/tmwa/charserverhandler.cpp +./src/net/tmwa/charserverhandler.h +./src/net/tmwa/chathandler.cpp +./src/net/tmwa/chathandler.h +./src/net/tmwa/gamehandler.cpp +./src/net/tmwa/gamehandler.h +./src/net/tmwa/generalhandler.cpp +./src/net/tmwa/generalhandler.h +./src/net/tmwa/gui/guildtab.cpp +./src/net/tmwa/gui/guildtab.h +./src/net/tmwa/guildhandler.cpp +./src/net/tmwa/guildhandler.h +./src/net/tmwa/gui/partytab.cpp +./src/net/tmwa/gui/partytab.h +./src/net/tmwa/inventoryhandler.cpp +./src/net/tmwa/inventoryhandler.h +./src/net/tmwa/itemhandler.cpp +./src/net/tmwa/itemhandler.h +./src/net/tmwa/loginhandler.cpp +./src/net/tmwa/loginhandler.h +./src/net/tmwa/messagehandler.cpp +./src/net/tmwa/messagehandler.h +./src/net/tmwa/messagein.cpp +./src/net/tmwa/messagein.h +./src/net/tmwa/messageout.cpp +./src/net/tmwa/messageout.h +./src/net/tmwa/network.cpp +./src/net/tmwa/network.h +./src/net/tmwa/npchandler.cpp +./src/net/tmwa/npchandler.h +./src/net/tmwa/partyhandler.cpp +./src/net/tmwa/partyhandler.h +./src/net/tmwa/playerhandler.cpp +./src/net/tmwa/playerhandler.h +./src/net/tmwa/protocol.h +./src/net/tmwa/specialhandler.cpp +./src/net/tmwa/specialhandler.h +./src/net/tmwa/token.h +./src/net/tmwa/tradehandler.cpp +./src/net/tmwa/tradehandler.h ./src/net/gamehandler.h ./src/net/generalhandler.h ./src/net/guildhandler.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a0bcac83..02a08bfe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -504,53 +504,53 @@ SET(SRCS vector.h ) -SET(SRCS_EA - net/ea/gui/guildtab.cpp - net/ea/gui/guildtab.h - net/ea/gui/partytab.cpp - net/ea/gui/partytab.h - net/ea/adminhandler.cpp - net/ea/adminhandler.h - net/ea/beinghandler.cpp - net/ea/beinghandler.h - net/ea/buysellhandler.cpp - net/ea/buysellhandler.h - net/ea/charserverhandler.cpp - net/ea/charserverhandler.h - net/ea/chathandler.cpp - net/ea/chathandler.h - net/ea/gamehandler.cpp - net/ea/gamehandler.h - net/ea/generalhandler.cpp - net/ea/generalhandler.h - net/ea/guildhandler.cpp - net/ea/guildhandler.h - net/ea/inventoryhandler.cpp - net/ea/inventoryhandler.h - net/ea/itemhandler.cpp - net/ea/itemhandler.h - net/ea/loginhandler.cpp - net/ea/loginhandler.h - net/ea/messagehandler.cpp - net/ea/messagehandler.h - net/ea/messagein.cpp - net/ea/messagein.h - net/ea/messageout.cpp - net/ea/messageout.h - net/ea/network.cpp - net/ea/network.h - net/ea/npchandler.cpp - net/ea/npchandler.h - net/ea/partyhandler.cpp - net/ea/partyhandler.h - net/ea/playerhandler.cpp - net/ea/playerhandler.h - net/ea/protocol.h - net/ea/specialhandler.cpp - net/ea/specialhandler.h - net/ea/token.h - net/ea/tradehandler.cpp - net/ea/tradehandler.h +SET(SRCS_TMWA + net/tmwa/gui/guildtab.cpp + net/tmwa/gui/guildtab.h + net/tmwa/gui/partytab.cpp + net/tmwa/gui/partytab.h + net/tmwa/adminhandler.cpp + net/tmwa/adminhandler.h + net/tmwa/beinghandler.cpp + net/tmwa/beinghandler.h + net/tmwa/buysellhandler.cpp + net/tmwa/buysellhandler.h + net/tmwa/charserverhandler.cpp + net/tmwa/charserverhandler.h + net/tmwa/chathandler.cpp + net/tmwa/chathandler.h + net/tmwa/gamehandler.cpp + net/tmwa/gamehandler.h + net/tmwa/generalhandler.cpp + net/tmwa/generalhandler.h + net/tmwa/guildhandler.cpp + net/tmwa/guildhandler.h + net/tmwa/inventoryhandler.cpp + net/tmwa/inventoryhandler.h + net/tmwa/itemhandler.cpp + net/tmwa/itemhandler.h + net/tmwa/loginhandler.cpp + net/tmwa/loginhandler.h + net/tmwa/messagehandler.cpp + net/tmwa/messagehandler.h + net/tmwa/messagein.cpp + net/tmwa/messagein.h + net/tmwa/messageout.cpp + net/tmwa/messageout.h + net/tmwa/network.cpp + net/tmwa/network.h + net/tmwa/npchandler.cpp + net/tmwa/npchandler.h + net/tmwa/partyhandler.cpp + net/tmwa/partyhandler.h + net/tmwa/playerhandler.cpp + net/tmwa/playerhandler.h + net/tmwa/protocol.h + net/tmwa/specialhandler.cpp + net/tmwa/specialhandler.h + net/tmwa/token.h + net/tmwa/tradehandler.cpp + net/tmwa/tradehandler.h ) SET(SRCS_MANA @@ -614,7 +614,7 @@ ENDIF () SET (PROGRAMS mana) -ADD_EXECUTABLE(mana WIN32 ${SRCS} ${SRCS_MANA} ${SRCS_EA}) +ADD_EXECUTABLE(mana WIN32 ${SRCS} ${SRCS_MANA} ${SRCS_TMWA}) TARGET_LINK_LIBRARIES(mana ${SDLGFX_LIBRARIES} diff --git a/src/Makefile.am b/src/Makefile.am index 035d4e1f..9748dd67 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -455,52 +455,52 @@ mana_SOURCES += \ net/manaserv/tradehandler.h mana_SOURCES += \ - net/ea/gui/guildtab.cpp \ - net/ea/gui/guildtab.h \ - net/ea/gui/partytab.cpp \ - net/ea/gui/partytab.h \ - net/ea/adminhandler.cpp \ - net/ea/adminhandler.h \ - net/ea/beinghandler.cpp \ - net/ea/beinghandler.h \ - net/ea/buysellhandler.cpp \ - net/ea/buysellhandler.h \ - net/ea/charserverhandler.cpp \ - net/ea/charserverhandler.h \ - net/ea/chathandler.cpp \ - net/ea/chathandler.h \ - net/ea/gamehandler.cpp \ - net/ea/gamehandler.h \ - net/ea/generalhandler.cpp \ - net/ea/generalhandler.h \ - net/ea/guildhandler.cpp \ - net/ea/guildhandler.h \ - net/ea/inventoryhandler.cpp \ - net/ea/inventoryhandler.h \ - net/ea/itemhandler.cpp \ - net/ea/itemhandler.h \ - net/ea/loginhandler.cpp \ - net/ea/loginhandler.h \ - net/ea/messagehandler.cpp \ - net/ea/messagehandler.h \ - net/ea/messagein.cpp \ - net/ea/messagein.h \ - net/ea/messageout.cpp \ - net/ea/messageout.h \ - net/ea/network.cpp \ - net/ea/network.h \ - net/ea/npchandler.cpp \ - net/ea/npchandler.h \ - net/ea/partyhandler.cpp \ - net/ea/partyhandler.h \ - net/ea/playerhandler.cpp \ - net/ea/playerhandler.h \ - net/ea/protocol.h \ - net/ea/specialhandler.cpp \ - net/ea/specialhandler.h \ - net/ea/token.h \ - net/ea/tradehandler.cpp \ - net/ea/tradehandler.h + net/tmwa/gui/guildtab.cpp \ + net/tmwa/gui/guildtab.h \ + net/tmwa/gui/partytab.cpp \ + net/tmwa/gui/partytab.h \ + net/tmwa/adminhandler.cpp \ + net/tmwa/adminhandler.h \ + net/tmwa/beinghandler.cpp \ + net/tmwa/beinghandler.h \ + net/tmwa/buysellhandler.cpp \ + net/tmwa/buysellhandler.h \ + net/tmwa/charserverhandler.cpp \ + net/tmwa/charserverhandler.h \ + net/tmwa/chathandler.cpp \ + net/tmwa/chathandler.h \ + net/tmwa/gamehandler.cpp \ + net/tmwa/gamehandler.h \ + net/tmwa/generalhandler.cpp \ + net/tmwa/generalhandler.h \ + net/tmwa/guildhandler.cpp \ + net/tmwa/guildhandler.h \ + net/tmwa/inventoryhandler.cpp \ + net/tmwa/inventoryhandler.h \ + net/tmwa/itemhandler.cpp \ + net/tmwa/itemhandler.h \ + net/tmwa/loginhandler.cpp \ + net/tmwa/loginhandler.h \ + net/tmwa/messagehandler.cpp \ + net/tmwa/messagehandler.h \ + net/tmwa/messagein.cpp \ + net/tmwa/messagein.h \ + net/tmwa/messageout.cpp \ + net/tmwa/messageout.h \ + net/tmwa/network.cpp \ + net/tmwa/network.h \ + net/tmwa/npchandler.cpp \ + net/tmwa/npchandler.h \ + net/tmwa/partyhandler.cpp \ + net/tmwa/partyhandler.h \ + net/tmwa/playerhandler.cpp \ + net/tmwa/playerhandler.h \ + net/tmwa/protocol.h \ + net/tmwa/specialhandler.cpp \ + net/tmwa/specialhandler.h \ + net/tmwa/token.h \ + net/tmwa/tradehandler.cpp \ + net/tmwa/tradehandler.h EXTRA_DIST = CMakeLists.txt \ winver.h.in diff --git a/src/being.cpp b/src/being.cpp index 47c31c36..5c737c0c 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -129,7 +129,7 @@ void Being::setPosition(const Vector &pos) void Being::setDestination(int dstX, int dstY) { - if (Net::getNetworkType() == ServerInfo::EATHENA) + if (Net::getNetworkType() == ServerInfo::TMWATHENA) { if (mMap) setPath(mMap->findPath(mX, mY, dstX, dstY, getWalkMask())); @@ -185,7 +185,7 @@ void Being::setPath(const Path &path) { mPath = path; - if ((Net::getNetworkType() == ServerInfo::EATHENA) && + if ((Net::getNetworkType() == ServerInfo::TMWATHENA) && mAction != WALK && mAction != DEAD) { nextTile(); @@ -317,7 +317,7 @@ void Being::handleAttack(Being *victim, int damage, AttackType type) fireMissile(victim, mEquippedWeapon->getMissileParticle()); } } - if (Net::getNetworkType() == ServerInfo::EATHENA) + if (Net::getNetworkType() == ServerInfo::TMWATHENA) { mFrame = 0; mWalkTime = tick_time; @@ -605,7 +605,7 @@ void Being::logic() setAction(STAND); } } - else if (Net::getNetworkType() == ServerInfo::EATHENA) + else if (Net::getNetworkType() == ServerInfo::TMWATHENA) { // Update pixel coordinates setPosition(mX * 32 + 16 + getXOffset(), diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index dfe809bc..0fba5638 100644 --- a/src/gui/serverdialog.cpp +++ b/src/gui/serverdialog.cpp @@ -57,10 +57,10 @@ static std::string serverTypeToString(ServerInfo::Type type) { switch (type) { - case ServerInfo::EATHENA: - return "eAthena"; + case ServerInfo::TMWATHENA: + return "TmwAthena"; case ServerInfo::MANASERV: - return "manaserv"; + return "ManaServ"; default: return ""; } @@ -71,7 +71,7 @@ static unsigned short defaultPortForServerType(ServerInfo::Type type) switch (type) { default: - case ServerInfo::EATHENA: + case ServerInfo::TMWATHENA: return 6901; case ServerInfo::MANASERV: return 9601; @@ -116,9 +116,9 @@ void ServersListModel::setVersionString(int index, const std::string &version) std::string TypeListModel::getElementAt(int elementIndex) { if (elementIndex == 0) - return "eAthena"; + return "TmwAthena"; else if (elementIndex == 1) - return "Manaserv"; + return "ManaServ"; else return "Unknown"; } @@ -332,7 +332,7 @@ void ServerDialog::action(const gcn::ActionEvent &event) switch (mTypeField->getSelected()) { case 0: - mServerInfo->type = ServerInfo::EATHENA; + mServerInfo->type = ServerInfo::TMWATHENA; break; case 1: mServerInfo->type = ServerInfo::MANASERV; @@ -398,7 +398,7 @@ void ServerDialog::valueChanged(const gcn::SelectionEvent &) mPortField->setText(toString(myServer.port)); switch (myServer.type) { - case ServerInfo::EATHENA: + case ServerInfo::TMWATHENA: case ServerInfo::UNKNOWN: mTypeField->setSelected(0); break; diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp index 0a5b8d71..528e8539 100644 --- a/src/gui/skilldialog.cpp +++ b/src/gui/skilldialog.cpp @@ -301,7 +301,7 @@ void SkillDialog::loadSkills(const std::string &file) { logger->log("Error loading skills file: %s", file.c_str()); - if (Net::getNetworkType() == ServerInfo::EATHENA) + if (Net::getNetworkType() == ServerInfo::TMWATHENA) { SkillModel *model = new SkillModel(); SkillInfo *skill = new SkillInfo; diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index ac9bfb2e..99325db8 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -261,7 +261,7 @@ void Viewport::_drawDebugPath(Graphics *graphics) Path debugPath; - if (Net::getNetworkType() == ServerInfo::EATHENA) + if (Net::getNetworkType() == ServerInfo::TMWATHENA) { const int mouseTileX = (mMouseX + (int) mPixelViewX) / 32; const int mouseTileY = (mMouseY + (int) mPixelViewY) / 32; @@ -305,7 +305,7 @@ void Viewport::_drawPath(Graphics *graphics, const Path &path, { graphics->setColor(color); - if (Net::getNetworkType() == ServerInfo::EATHENA) + if (Net::getNetworkType() == ServerInfo::TMWATHENA) { for (Path::const_iterator i = path.begin(); i != path.end(); ++i) { diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 961248dc..ff7961b9 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -594,7 +594,7 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) void LocalPlayer::nextTile(unsigned char dir = 0) { - if (Net::getNetworkType() == ServerInfo::EATHENA) + if (Net::getNetworkType() == ServerInfo::TMWATHENA) { // TODO: Fix picking up when reaching target (this method is obsolete) // TODO: Fix holding walking button to keep walking smoothly @@ -768,7 +768,7 @@ void LocalPlayer::setDestination(int x, int y) // If the destination given to being class is accepted, // we inform the Server. if ((x == mDest.x && y == mDest.y) - || Net::getNetworkType() == ServerInfo::EATHENA) + || Net::getNetworkType() == ServerInfo::TMWATHENA) Net::getPlayerHandler()->setDestination(x, y, mDirection); } @@ -823,7 +823,7 @@ void LocalPlayer::setWalkingDir(int dir) void LocalPlayer::startWalking(unsigned char dir) { // This function is called by setWalkingDir(), - // but also by nextTile() for eAthena... + // but also by nextTile() for TMW-Athena... if (!mMap || !dir) return; @@ -850,7 +850,7 @@ void LocalPlayer::startWalking(unsigned char dir) if (dir & RIGHT) dx++; - if (Net::getNetworkType() == ServerInfo::EATHENA) + if (Net::getNetworkType() == ServerInfo::TMWATHENA) { // Prevent skipping corners over colliding tiles if (dx && !mMap->getWalk(getTileX() + dx, getTileY(), getWalkMask())) @@ -1028,7 +1028,7 @@ void LocalPlayer::attack(Being *target, bool keep) } Net::getPlayerHandler()->attack(target->getId()); - if ((Net::getNetworkType() == ServerInfo::EATHENA) && !keep) + if ((Net::getNetworkType() == ServerInfo::TMWATHENA) && !keep) stopAttack(); } diff --git a/src/monster.cpp b/src/monster.cpp index 0876b08d..d25c6c90 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -49,7 +49,7 @@ Monster::Monster(int id, int subtype, Map *map): void Monster::logic() { - if ((Net::getNetworkType() == ServerInfo::EATHENA) && (mAction != STAND)) + if ((Net::getNetworkType() == ServerInfo::TMWATHENA) && (mAction != STAND)) { mFrame = (int) ((get_elapsed_time(mWalkTime) * 4) / getWalkSpeed().x); diff --git a/src/net/ea/adminhandler.cpp b/src/net/ea/adminhandler.cpp deleted file mode 100644 index 010a932e..00000000 --- a/src/net/ea/adminhandler.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/adminhandler.h" - -#include "being.h" -#include "beingmanager.h" -#include "game.h" -#include "playerrelations.h" - -#include "gui/widgets/chattab.h" - -#include "net/chathandler.h" -#include "net/net.h" - -#include "net/ea/protocol.h" - -#include "utils/gettext.h" -#include "utils/stringutils.h" - -#include - -extern Net::AdminHandler *adminHandler; - -namespace EAthena { - -AdminHandler::AdminHandler() -{ - static const Uint16 _messages[] = { - SMSG_ADMIN_KICK_ACK, - 0 - }; - handledMessages = _messages; - adminHandler = this; -} - -void AdminHandler::handleMessage(Net::MessageIn &msg) -{ - int id; - switch (msg.getId()) - { - case SMSG_ADMIN_KICK_ACK: - id = msg.readInt32(); - if (id == 0) - localChatTab->chatLog(_("Kick failed!"), BY_SERVER); - else - localChatTab->chatLog(_("Kick succeeded!"), BY_SERVER); - break; - } -} - -void AdminHandler::announce(const std::string &text) -{ - MessageOut outMsg(CMSG_ADMIN_ANNOUNCE); - outMsg.writeInt16(text.length() + 4); - outMsg.writeString(text, text.length()); -} - -void AdminHandler::localAnnounce(const std::string &text) -{ - MessageOut outMsg(CMSG_ADMIN_LOCAL_ANNOUNCE); - outMsg.writeInt16(text.length() + 4); - outMsg.writeString(text, text.length()); -} - -void AdminHandler::hide(bool hide) -{ - MessageOut outMsg(CMSG_ADMIN_HIDE); - outMsg.writeInt32(0); //unused -} - -void AdminHandler::kick(int playerId) -{ - MessageOut outMsg(CMSG_ADMIN_KICK); - outMsg.writeInt32(playerId); -} - -void AdminHandler::kick(const std::string &name) -{ - Net::getChatHandler()->talk("@kick " + name); -} - -void AdminHandler::ban(int playerId) -{ - // Not supported -} - -void AdminHandler::ban(const std::string &name) -{ - Net::getChatHandler()->talk("@ban " + name); -} - -void AdminHandler::unban(int playerId) -{ - // Not supported -} - -void AdminHandler::unban(const std::string &name) -{ - Net::getChatHandler()->talk("@unban " + name); -} - -void AdminHandler::mute(int playerId, int type, int limit) -{ - return; // Still looking into this - - MessageOut outMsg(CMSG_ADMIN_MUTE); - outMsg.writeInt32(playerId); - outMsg.writeInt8(type); - outMsg.writeInt16(limit); -} - -} // namespace EAthena diff --git a/src/net/ea/adminhandler.h b/src/net/ea/adminhandler.h deleted file mode 100644 index 8847ecb3..00000000 --- a/src/net/ea/adminhandler.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_ADMINHANDLER_H -#define NET_EA_ADMINHANDLER_H - -#include "net/adminhandler.h" -#include "net/net.h" - -#include "net/ea/messagehandler.h" - -namespace EAthena { - -class AdminHandler : public MessageHandler, public Net::AdminHandler -{ - public: - AdminHandler(); - - void handleMessage(Net::MessageIn &msg); - - void announce(const std::string &text); - - void localAnnounce(const std::string &text); - - void hide(bool hide); - - void kick(int playerId); - - void kick(const std::string &name); - - void ban(int playerId); - - void ban(const std::string &name); - - void unban(int playerId); - - void unban(const std::string &name); - - void mute(int playerId, int type, int limit); -}; - -} // namespace EAthena - -#endif // NET_EA_ADMINHANDLER_H diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp deleted file mode 100644 index 55df2ede..00000000 --- a/src/net/ea/beinghandler.cpp +++ /dev/null @@ -1,714 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/beinghandler.h" - -#include "being.h" -#include "beingmanager.h" -#include "client.h" -#include "effectmanager.h" -#include "guild.h" -#include "localplayer.h" -#include "log.h" -#include "npc.h" -#include "party.h" -#include "playerrelations.h" - -#include "net/ea/protocol.h" - -#include "resources/colordb.h" - -#include - -namespace EAthena { - -const int EMOTION_TIME = 150; /**< Duration of emotion icon */ - -BeingHandler::BeingHandler(bool enableSync): - mSync(enableSync) -{ - static const Uint16 _messages[] = { - SMSG_BEING_VISIBLE, - SMSG_BEING_MOVE, - SMSG_BEING_MOVE2, - SMSG_BEING_REMOVE, - SMSG_SKILL_DAMAGE, - SMSG_BEING_ACTION, - SMSG_BEING_SELFEFFECT, - SMSG_BEING_EMOTION, - SMSG_BEING_CHANGE_LOOKS, - SMSG_BEING_CHANGE_LOOKS2, - SMSG_BEING_NAME_RESPONSE, - SMSG_PLAYER_GUILD_PARTY_INFO, - SMSG_BEING_CHANGE_DIRECTION, - SMSG_PLAYER_UPDATE_1, - SMSG_PLAYER_UPDATE_2, - SMSG_PLAYER_MOVE, - SMSG_PLAYER_STOP, - SMSG_PLAYER_MOVE_TO_ATTACK, - SMSG_PLAYER_STATUS_CHANGE, - SMSG_BEING_STATUS_CHANGE, - SMSG_BEING_RESURRECT, - 0 - }; - handledMessages = _messages; -} - -Being *createBeing(int id, short job) -{ - Being::Type type = Being::UNKNOWN; - if (job <= 25 || (job >= 4001 && job <= 4049)) - type = Being::PLAYER; - else if (job >= 46 && job <= 1000) - type = Being::NPC; - else if (job > 1000 && job <= 2000) - type = Being::MONSTER; - else if (job == 45) - return NULL; // Skip portals - - Being *being = beingManager->createBeing(id, type, job); - - if (type == Being::PLAYER || type == Being::NPC) - { - MessageOut outMsg(0x0094); - outMsg.writeInt32(id);//readLong(2)); - } - - return being; -} - -void BeingHandler::handleMessage(Net::MessageIn &msg) -{ - if (!beingManager) - return; - - int id; - short job, speed, gender; - Uint16 headTop, headMid, headBottom; - Uint16 shoes, gloves; - Uint16 weapon, shield; - Uint16 gmstatus; - int param1; - int stunMode; - Uint32 statusEffects; - int type, guild; - Uint16 status; - Being *srcBeing, *dstBeing; - Player *player = 0; - int hairStyle, hairColor, flag; - std::string player_followed; - - switch (msg.getId()) - { - case SMSG_BEING_VISIBLE: - case SMSG_BEING_MOVE: - // Information about a being in range - id = msg.readInt32(); - speed = msg.readInt16(); - stunMode = msg.readInt16(); // opt1 - statusEffects = msg.readInt16(); // opt2 - statusEffects |= ((Uint32)msg.readInt16()) << 16; // option - job = msg.readInt16(); // class - - dstBeing = beingManager->findBeing(id); - - if (!dstBeing) - { - // Being with id >= 110000000 and job 0 are better - // known as ghosts, so don't create those. - if (job == 0 && id >= 110000000) - { - break; - } - - dstBeing = createBeing(id, job); - - if (!dstBeing) - break; - } - - if (dstBeing->getType() == Being::PLAYER) - player = static_cast(dstBeing); - - if (msg.getId() == 0x0078) - { - dstBeing->clearPath(); - dstBeing->setFrame(0); - dstBeing->setWalkTime(tick_time); - dstBeing->setAction(Being::STAND); - } - - - // Prevent division by 0 when calculating frame - if (speed == 0) { speed = 150; } - - dstBeing->setWalkSpeed(Vector(speed, speed, 0)); - dstBeing->setSubtype(job); - hairStyle = msg.readInt16(); - weapon = msg.readInt16(); - headBottom = msg.readInt16(); - - if (msg.getId() == SMSG_BEING_MOVE) - { - msg.readInt32(); // server tick - } - - shield = msg.readInt16(); - headTop = msg.readInt16(); - headMid = msg.readInt16(); - hairColor = msg.readInt16(); - shoes = msg.readInt16(); // clothes color - "abused" as shoes - gloves = msg.readInt16(); // head dir - "abused" as gloves - guild = msg.readInt32(); // guild - if (player) - { - if (guild == 0) - { - player->clearGuilds(); - } - else - { - player->addGuild(Guild::getGuild(guild)); - } - } - msg.readInt16(); // guild emblem - msg.readInt16(); // manner - dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 - msg.readInt8(); // karma - gender = msg.readInt8(); - - if (player) - { - player->setGender((gender == 0) - ? GENDER_FEMALE : GENDER_MALE); - // Set these after the gender, as the sprites may be gender-specific - player->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor)); - player->setSprite(SPRITE_BOTTOMCLOTHES, headBottom); - player->setSprite(SPRITE_TOPCLOTHES, headMid); - player->setSprite(SPRITE_HAT, headTop); - player->setSprite(SPRITE_SHOE, shoes); - player->setSprite(SPRITE_GLOVES, gloves); - player->setSprite(SPRITE_WEAPON, weapon, "", true); - player->setSprite(SPRITE_SHIELD, shield); - } - - if (msg.getId() == SMSG_BEING_MOVE) - { - Uint16 srcX, srcY, dstX, dstY; - msg.readCoordinatePair(srcX, srcY, dstX, dstY); - dstBeing->setAction(Being::STAND); - dstBeing->setTileCoords(srcX, srcY); - dstBeing->setDestination(dstX, dstY); - } - else - { - Uint8 dir; - Uint16 x, y; - msg.readCoordinates(x, y, dir); - dstBeing->setTileCoords(x, y); - dstBeing->setDirection(dir); - } - - msg.readInt8(); // unknown - msg.readInt8(); // unknown - msg.readInt8(); // unknown / sit - - dstBeing->setStunMode(stunMode); - dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); - dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); - break; - - case SMSG_BEING_MOVE2: - /* - * A simplified movement packet, used by the - * later versions of eAthena for both mobs and - * players - */ - dstBeing = beingManager->findBeing(msg.readInt32()); - - Uint16 srcX, srcY, dstX, dstY; - msg.readCoordinatePair(srcX, srcY, dstX, dstY); - msg.readInt32(); // Server tick - - /* - * This packet doesn't have enough info to actually - * create a new being, so if the being isn't found, - * we'll just pretend the packet didn't happen - */ - - if (dstBeing) - { - dstBeing->setAction(Being::STAND); - dstBeing->setTileCoords(srcX, srcY); - dstBeing->setDestination(dstX, dstY); - } - - break; - - case SMSG_BEING_REMOVE: - // A being should be removed or has died - id = msg.readInt32(); - - dstBeing = beingManager->findBeing(id); - - if (!dstBeing) - break; - - player_followed = player_node->getFollow(); - - if (!player_followed.empty()) - { - if (dstBeing->getName() == player_followed) - { - player_node->setDestination(player_node->getNextDestX(), player_node->getNextDestY()); - } - } - - // If this is player's current target, clear it. - if (dstBeing == player_node->getTarget()) - player_node->stopAttack(); - - if (msg.readInt8() == 1) - dstBeing->setAction(Being::DEAD); - else - beingManager->destroyBeing(dstBeing); - - break; - - case SMSG_BEING_RESURRECT: - // A being changed mortality status - id = msg.readInt32(); - - dstBeing = beingManager->findBeing(id); - - if (!dstBeing) - break; - - // If this is player's current target, clear it. - if (dstBeing == player_node->getTarget()) - player_node->stopAttack(); - - if (msg.readInt8() == 1) - dstBeing->setAction(Being::STAND); - - break; - - case SMSG_SKILL_DAMAGE: - msg.readInt16(); // Skill Id - srcBeing = beingManager->findBeing(msg.readInt32()); - dstBeing = beingManager->findBeing(msg.readInt32()); - msg.readInt32(); // Server tick - msg.readInt32(); // src speed - msg.readInt32(); // dst speed - param1 = msg.readInt32(); // Damage - msg.readInt16(); // Skill level - msg.readInt16(); // Div - msg.readInt8(); // Skill hit/type (?) - if (dstBeing) - dstBeing->takeDamage(srcBeing, param1, Being::HIT); // Perhaps a new skill attack type should be created and used? - if (srcBeing) - srcBeing->handleAttack(dstBeing, param1, Being::HIT); - break; - - case SMSG_BEING_ACTION: - srcBeing = beingManager->findBeing(msg.readInt32()); - dstBeing = beingManager->findBeing(msg.readInt32()); - msg.readInt32(); // server tick - msg.readInt32(); // src speed - msg.readInt32(); // dst speed - param1 = msg.readInt16(); - msg.readInt16(); // param 2 - type = msg.readInt8(); - msg.readInt16(); // param 3 - - switch (type) - { - case Being::HIT: // Damage - case Being::CRITICAL: // Critical Damage - case Being::MULTI: // Critical Damage - case Being::REFLECT: // Reflected Damage - case Being::FLEE: // Lucky Dodge - if (dstBeing) - dstBeing->takeDamage(srcBeing, param1, - (Being::AttackType)type); - if (srcBeing) - srcBeing->handleAttack(dstBeing, param1, - (Being::AttackType)type); - break; - - case 0x02: // Sit - if (srcBeing) - { - srcBeing->setFrame(0); - srcBeing->setAction(Being::SIT); - } - break; - - case 0x03: // Stand up - if (srcBeing) - { - srcBeing->setFrame(0); - srcBeing->setAction(Being::STAND); - } - break; - } - break; - - case SMSG_BEING_SELFEFFECT: { - id = (Uint32)msg.readInt32(); - if (!beingManager->findBeing(id)) - break; - - int effectType = msg.readInt32(); - Being* being = beingManager->findBeing(id); - - effectManager->trigger(effectType, being); - - break; - } - - case SMSG_BEING_EMOTION: - if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) - { - break; - } - - if (player_relations.hasPermission(dstBeing, PlayerRelation::EMOTE)) - { - // only set emote if one doesnt already exist - if (!dstBeing->getEmotion()) - dstBeing->setEmote(msg.readInt8(), EMOTION_TIME); - } - - break; - - case SMSG_BEING_CHANGE_LOOKS: - case SMSG_BEING_CHANGE_LOOKS2: - { - /* - * SMSG_BEING_CHANGE_LOOKS (0x00c3) and - * SMSG_BEING_CHANGE_LOOKS2 (0x01d7) do basically the same - * thing. The difference is that ...LOOKS carries a single - * 8 bit value, where ...LOOKS2 carries two 16 bit values. - * - * If type = 2, then the first 16 bit value is the weapon ID, - * and the second 16 bit value is the shield ID. If no - * shield is equipped, or type is not 2, then the second - * 16 bit value will be 0. - */ - - if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) - { - break; - } - - if (dstBeing->getType() == Being::PLAYER) - player = static_cast(dstBeing); - - int type = msg.readInt8(); - int id = 0; - int id2 = 0; - - if (msg.getId() == SMSG_BEING_CHANGE_LOOKS) - { - id = msg.readInt8(); - } - else - { // SMSG_BEING_CHANGE_LOOKS2 - id = msg.readInt16(); - id2 = msg.readInt16(); - } - - switch (type) - { - case 1: // eAthena LOOK_HAIR - player->setSpriteID(SPRITE_HAIR, id *-1); - break; - case 2: // Weapon ID in id, Shield ID in id2 - player->setSprite(SPRITE_WEAPON, id, "", true); - player->setSprite(SPRITE_SHIELD, id2); - break; - case 3: // Change lower headgear for eAthena, pants for us - player->setSprite(SPRITE_BOTTOMCLOTHES, id); - break; - case 4: // Change upper headgear for eAthena, hat for us - player->setSprite(SPRITE_HAT, id); - break; - case 5: // Change middle headgear for eathena, armor for us - player->setSprite(SPRITE_TOPCLOTHES, id); - break; - case 6: // eAthena LOOK_HAIR_COLOR - player->setSpriteColor(SPRITE_HAIR, ColorDB::get(id)); - break; - case 8: // eAthena LOOK_SHIELD - player->setSprite(SPRITE_SHIELD, id); - break; - case 9: // eAthena LOOK_SHOES - player->setSprite(SPRITE_SHOE, id); - break; - case 10: // LOOK_GLOVES - player->setSprite(SPRITE_GLOVES, id); - break; - case 11: // LOOK_CAPE - player->setSprite(SPRITE_CAPE, id); - break; - case 12: - player->setSprite(SPRITE_MISC1, id); - break; - case 13: - player->setSprite(SPRITE_MISC2, id); - break; - default: - logger->log("SMSG_BEING_CHANGE_LOOKS: unsupported type: " - "%d, id: %d", type, id); - break; - } - } - break; - - case SMSG_BEING_NAME_RESPONSE: - if ((dstBeing = beingManager->findBeing(msg.readInt32()))) - { - dstBeing->setName(msg.readString(24)); - } - break; - case SMSG_PLAYER_GUILD_PARTY_INFO: - if ((dstBeing = beingManager->findBeing(msg.readInt32()))) - { - dstBeing->setPartyName(msg.readString(24)); - dstBeing->setGuildName(msg.readString(24)); - dstBeing->setGuildPos(msg.readString(24)); - msg.readString(24); // Discard this - } - break; - case SMSG_BEING_CHANGE_DIRECTION: - if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) - { - break; - } - - msg.readInt16(); // unused - - dstBeing->setDirection(msg.readInt8()); - - break; - - case SMSG_PLAYER_UPDATE_1: - case SMSG_PLAYER_UPDATE_2: - case SMSG_PLAYER_MOVE: - // An update about a player, potentially including movement. - id = msg.readInt32(); - speed = msg.readInt16(); - stunMode = msg.readInt16(); // opt1; Aethyra use this as cape - statusEffects = msg.readInt16(); // opt2; Aethyra use this as misc1 - statusEffects |= ((Uint32) msg.readInt16()) - << 16; // status.options; Aethyra uses this as misc2 - job = msg.readInt16(); - - dstBeing = beingManager->findBeing(id); - - if (!dstBeing) - { - dstBeing = createBeing(id, job); - - if (!dstBeing) - break; - } - - if (dstBeing->getType() == Being::PLAYER) - player = static_cast(dstBeing); - - if (Party *party = player_node->getParty()){ - if (party->isMember(id)) - { - player->setParty(party); - } - } - - dstBeing->setWalkSpeed(Vector(speed, speed, 0)); - dstBeing->setSubtype(job); - hairStyle = msg.readInt16(); - weapon = msg.readInt16(); - shield = msg.readInt16(); - headBottom = msg.readInt16(); - - if (msg.getId() == SMSG_PLAYER_MOVE) - { - msg.readInt32(); // server tick - } - - headTop = msg.readInt16(); - headMid = msg.readInt16(); - hairColor = msg.readInt16(); - shoes = msg.readInt16(); - gloves = msg.readInt16(); - msg.readInt32(); // guild - msg.readInt16(); // emblem - msg.readInt16(); // manner - dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 - msg.readInt8(); // karma - player->setGender((msg.readInt8() == 0) - ? GENDER_FEMALE : GENDER_MALE); - - // Set these after the gender, as the sprites may be gender-specific - player->setSprite(SPRITE_WEAPON, weapon, "", true); - player->setSprite(SPRITE_SHIELD, shield); - //player->setSprite(SPRITE_SHOE, shoes); - player->setSprite(SPRITE_BOTTOMCLOTHES, headBottom); - player->setSprite(SPRITE_TOPCLOTHES, headMid); - player->setSprite(SPRITE_HAT, headTop); - //player->setSprite(SPRITE_GLOVES, gloves); - //player->setSprite(SPRITE_CAPE, cape); - //player->setSprite(SPRITE_MISC1, misc1); - //player->setSprite(SPRITE_MISC2, misc2); - player->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor)); - - if (msg.getId() == SMSG_PLAYER_MOVE) - { - Uint16 srcX, srcY, dstX, dstY; - msg.readCoordinatePair(srcX, srcY, dstX, dstY); - dstBeing->setTileCoords(srcX, srcY); - dstBeing->setDestination(dstX, dstY); - - player_followed = player_node->getFollow(); - if (!player_followed.empty()) - { - if (dstBeing->getName() == player_followed) - { - player_node->setNextDest(dstX, dstY); - player_node->setDestination(srcX, srcY); - } - } - } - else - { - Uint8 dir; - Uint16 x, y; - msg.readCoordinates(x, y, dir); - dstBeing->setTileCoords(x, y); - dstBeing->setDirection(dir); - } - - gmstatus = msg.readInt16(); - if (gmstatus & 0x80) - player->setGM(true); - - if (msg.getId() == SMSG_PLAYER_UPDATE_1) - { - switch (msg.readInt8()) - { - case 1: - dstBeing->setAction(Being::DEAD); - break; - - case 2: - dstBeing->setAction(Being::SIT); - break; - } - } - else if (msg.getId() == SMSG_PLAYER_MOVE) - { - msg.readInt8(); // unknown - } - - msg.readInt8(); // Lv - msg.readInt8(); // unknown - - dstBeing->setWalkTime(tick_time); - dstBeing->setFrame(0); - - dstBeing->setStunMode(stunMode); - dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); - dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); - break; - - case SMSG_PLAYER_STOP: - /* - * Instruction from server to stop walking at x, y. - * - * Some people like having this enabled. Others absolutely - * despise it. So I'm setting to so that it only affects the - * local player if the person has set a key "EnableSync" to "1" - * in their config.xml file. - * - * This packet will be honored for all other beings, regardless - * of the config setting. - */ - - id = msg.readInt32(); - if (mSync || id != player_node->getId()) - { - dstBeing = beingManager->findBeing(id); - if (dstBeing) - { - Uint16 x, y; - x = msg.readInt16(); - y = msg.readInt16(); - dstBeing->setTileCoords(x, y); - if (dstBeing->getCurrentAction() == Being::WALK) - { - dstBeing->setFrame(0); - dstBeing->setAction(Being::STAND); - } - } - } - break; - - case SMSG_PLAYER_MOVE_TO_ATTACK: - /* - * This is an *advisory* message, telling the client that - * it needs to move the character before attacking - * a target (out of range, obstruction in line of fire). - * We can safely ignore this... - */ - break; - - case SMSG_PLAYER_STATUS_CHANGE: - // Change in players' flags - id = msg.readInt32(); - dstBeing = beingManager->findBeing(id); - stunMode = msg.readInt16(); - statusEffects = msg.readInt16(); - statusEffects |= ((Uint32) msg.readInt16()) << 16; - msg.readInt8(); - - if (dstBeing) - { - dstBeing->setStunMode(stunMode); - dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); - dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); - } - break; - - case SMSG_BEING_STATUS_CHANGE: - // Status change - status = msg.readInt16(); - id = msg.readInt32(); - flag = msg.readInt8(); // 0: stop, 1: start - - dstBeing = beingManager->findBeing(id); - if (dstBeing) - dstBeing->setStatusEffect(status, flag); - break; - } -} - -} // namespace EAthena diff --git a/src/net/ea/beinghandler.h b/src/net/ea/beinghandler.h deleted file mode 100644 index b946b3f6..00000000 --- a/src/net/ea/beinghandler.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_BEINGHANDLER_H -#define NET_EA_BEINGHANDLER_H - -#include "net/ea/messagehandler.h" - -namespace EAthena { - -class BeingHandler : public MessageHandler -{ - public: - BeingHandler(bool enableSync); - - virtual void handleMessage(Net::MessageIn &msg); - - private: - // Should we honor server "Stop Walking" packets - bool mSync; -}; - -} // namespace EAthena - -#endif // NET_EA_BEINGHANDLER_H diff --git a/src/net/ea/buysellhandler.cpp b/src/net/ea/buysellhandler.cpp deleted file mode 100644 index 0e4f1be9..00000000 --- a/src/net/ea/buysellhandler.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/buysellhandler.h" - -#include "beingmanager.h" -#include "inventory.h" -#include "item.h" -#include "localplayer.h" -#include "npc.h" - -#include "gui/buy.h" -#include "gui/buysell.h" -#include "gui/sell.h" - -#include "gui/widgets/chattab.h" - -#include "net/messagein.h" - -#include "net/ea/protocol.h" - -#include "utils/gettext.h" - -namespace EAthena { - -BuySellHandler::BuySellHandler() -{ - static const Uint16 _messages[] = { - SMSG_NPC_BUY_SELL_CHOICE, - SMSG_NPC_BUY, - SMSG_NPC_SELL, - SMSG_NPC_BUY_RESPONSE, - SMSG_NPC_SELL_RESPONSE, - 0 - }; - mNpcId = 0; - handledMessages = _messages; -} - -void BuySellHandler::handleMessage(Net::MessageIn &msg) -{ - int n_items; - - switch (msg.getId()) - { - case SMSG_NPC_BUY_SELL_CHOICE: - if (!BuySellDialog::isActive()) - { - mNpcId = msg.readInt32(); - new BuySellDialog(mNpcId); - } - break; - - case SMSG_NPC_BUY: - msg.readInt16(); // length - n_items = (msg.getLength() - 4) / 11; - mBuyDialog = new BuyDialog(mNpcId); - mBuyDialog->setMoney(player_node->getMoney()); - - for (int k = 0; k < n_items; k++) - { - int value = msg.readInt32(); - msg.readInt32(); // DCvalue - msg.readInt8(); // type - int itemId = msg.readInt16(); - mBuyDialog->addItem(itemId, 0, value); - } - break; - - case SMSG_NPC_SELL: - msg.readInt16(); // length - n_items = (msg.getLength() - 4) / 10; - if (n_items > 0) - { - SellDialog *dialog = new SellDialog(mNpcId); - dialog->setMoney(player_node->getMoney()); - - for (int k = 0; k < n_items; k++) - { - int index = msg.readInt16() - INVENTORY_OFFSET; - int value = msg.readInt32(); - msg.readInt32(); // OCvalue - - Item *item = player_node->getInventory()->getItem(index); - - if (item && !(item->isEquipped())) - dialog->addItem(item, value); - } - } - else - { - localChatTab->chatLog(_("Nothing to sell."), BY_SERVER); - } - break; - - case SMSG_NPC_BUY_RESPONSE: - if (msg.readInt8() == 0) - { - localChatTab->chatLog(_("Thanks for buying."), BY_SERVER); - } - else - { - // Reset player money since buy dialog already assumed purchase - // would go fine - mBuyDialog->setMoney(player_node->getMoney()); - localChatTab->chatLog(_("Unable to buy."), BY_SERVER); - } - break; - - case SMSG_NPC_SELL_RESPONSE: - if (msg.readInt8() == 0) - localChatTab->chatLog(_("Thanks for selling."), BY_SERVER); - else - localChatTab->chatLog(_("Unable to sell."), BY_SERVER); - - break; - } -} - -} // namespace EAthena diff --git a/src/net/ea/buysellhandler.h b/src/net/ea/buysellhandler.h deleted file mode 100644 index 320a9dd2..00000000 --- a/src/net/ea/buysellhandler.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_BUYSELLHANDLER_H -#define NET_EA_BUYSELLHANDLER_H - -#include "net/ea/messagehandler.h" - -class BuyDialog; - -namespace EAthena { - -class BuySellHandler : public MessageHandler -{ - public: - BuySellHandler(); - - virtual void handleMessage(Net::MessageIn &msg); - - private: - int mNpcId; - BuyDialog *mBuyDialog; -}; - -} // namespace EAthena - -#endif // NET_EA_BUYSELLHANDLER_H diff --git a/src/net/ea/charserverhandler.cpp b/src/net/ea/charserverhandler.cpp deleted file mode 100644 index 6f1506b5..00000000 --- a/src/net/ea/charserverhandler.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/charserverhandler.h" - -#include "client.h" -#include "game.h" -#include "log.h" - -#include "gui/charcreatedialog.h" -#include "gui/okdialog.h" - -#include "net/logindata.h" -#include "net/messagein.h" -#include "net/messageout.h" -#include "net/net.h" - -#include "net/ea/gamehandler.h" -#include "net/ea/loginhandler.h" -#include "net/ea/network.h" -#include "net/ea/protocol.h" - -#include "resources/colordb.h" - -#include "utils/dtor.h" -#include "utils/gettext.h" -#include "utils/stringutils.h" - -extern Net::CharHandler *charHandler; - -namespace EAthena { - -extern ServerInfo charServer; -extern ServerInfo mapServer; - -CharServerHandler::CharServerHandler() -{ - static const Uint16 _messages[] = { - SMSG_CHAR_LOGIN, - SMSG_CHAR_LOGIN_ERROR, - SMSG_CHAR_CREATE_SUCCEEDED, - SMSG_CHAR_CREATE_FAILED, - SMSG_CHAR_DELETE_SUCCEEDED, - SMSG_CHAR_DELETE_FAILED, - SMSG_CHAR_MAP_INFO, - SMSG_CHANGE_MAP_SERVER, - 0 - }; - handledMessages = _messages; - charHandler = this; -} - -void CharServerHandler::handleMessage(Net::MessageIn &msg) -{ - logger->log("CharServerHandler: Packet ID: %x, Length: %d", - msg.getId(), msg.getLength()); - - switch (msg.getId()) - { - case SMSG_CHAR_LOGIN: - { - msg.skip(2); // Length word - msg.skip(20); // Unused - - // Derive number of characters from message length - const int count = (msg.getLength() - 24) / 106; - - for (int i = 0; i < count; ++i) - { - Net::Character *character = new Net::Character; - int slot; - character->dummy = readPlayerData(msg, &slot); - character->slot = slot; - mCharacters.push_back(character); - logger->log("CharServer: Player: %s (%d)", - character->dummy->getName().c_str(), slot); - } - - Client::setState(STATE_CHAR_SELECT); - } - break; - - case SMSG_CHAR_LOGIN_ERROR: - switch (msg.readInt8()) - { - case 0: - errorMessage = _("Access denied."); - break; - case 1: - errorMessage = _("Cannot use this ID."); - break; - default: - errorMessage = _("Unknown failure to select character."); - break; - } - unlockCharSelectDialog(); - break; - - case SMSG_CHAR_CREATE_SUCCEEDED: - { - Net::Character *character = new Net::Character; - int slot; - character->dummy = readPlayerData(msg, &slot); - character->slot = slot; - mCharacters.push_back(character); - - updateCharSelectDialog(); - - // Close the character create dialog - if (mCharCreateDialog) - { - mCharCreateDialog->scheduleDelete(); - mCharCreateDialog = 0; - } - } - break; - - case SMSG_CHAR_CREATE_FAILED: - new OkDialog(_("Error"), _("Failed to create character. Most " - "likely the name is already taken.")); - if (mCharCreateDialog) - mCharCreateDialog->unlock(); - break; - - case SMSG_CHAR_DELETE_SUCCEEDED: - delete mSelectedCharacter; - mCharacters.remove(mSelectedCharacter); - mSelectedCharacter = 0; - updateCharSelectDialog(); - unlockCharSelectDialog(); - new OkDialog(_("Info"), _("Character deleted.")); - break; - - case SMSG_CHAR_DELETE_FAILED: - unlockCharSelectDialog(); - new OkDialog(_("Error"), _("Failed to delete character.")); - break; - - case SMSG_CHAR_MAP_INFO: - { - msg.skip(4); // CharID, must be the same as player_node->charID - GameHandler *gh = static_cast(Net::getGameHandler()); - gh->setMap(msg.readString(16)); - mapServer.hostname = ipToString(msg.readInt32()); - mapServer.port = msg.readInt16(); - - // Prevent the selected local player from being deleted - player_node = mSelectedCharacter->dummy; - mSelectedCharacter->dummy = 0; - - delete_all(mCharacters); - mCharacters.clear(); - updateCharSelectDialog(); - - mNetwork->disconnect(); - Client::setState(STATE_CONNECT_GAME); - } - break; - - case SMSG_CHANGE_MAP_SERVER: - { - GameHandler *gh = static_cast(Net::getGameHandler()); - gh->setMap(msg.readString(16)); - int x = msg.readInt16(); - int y = msg.readInt16(); - mapServer.hostname = ipToString(msg.readInt32()); - mapServer.port = msg.readInt16(); - - mNetwork->disconnect(); - Client::setState(STATE_CHANGE_MAP); - player_node->setTileCoords(x, y); - player_node->setMap(0); - } - break; - } -} - -LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int *slot) -{ - const Token &token = - static_cast(Net::getLoginHandler())->getToken(); - - LocalPlayer *tempPlayer = new LocalPlayer(msg.readInt32(), 0); - tempPlayer->setGender(token.sex); - - tempPlayer->setExp(msg.readInt32()); - tempPlayer->setMoney(msg.readInt32()); - tempPlayer->setExperience(JOB, msg.readInt32(), 1); - int temp = msg.readInt32(); - tempPlayer->setAttributeBase(JOB, temp, false); - tempPlayer->setAttributeEffective(JOB, temp); - tempPlayer->setSprite(SPRITE_SHOE, msg.readInt16()); - tempPlayer->setSprite(SPRITE_GLOVES, msg.readInt16()); - tempPlayer->setSprite(SPRITE_CAPE, msg.readInt16()); - tempPlayer->setSprite(SPRITE_MISC1, msg.readInt16()); - msg.readInt32(); // option - msg.readInt32(); // karma - msg.readInt32(); // manner - msg.skip(2); // unknown - tempPlayer->setHp(msg.readInt16()); - tempPlayer->setMaxHp(msg.readInt16()); - tempPlayer->setMP(msg.readInt16()); - tempPlayer->setMaxMP(msg.readInt16()); - msg.readInt16(); // speed - tempPlayer->setSubtype(msg.readInt16()); // class (used for race) - int hairStyle = msg.readInt16(); - Uint16 weapon = msg.readInt16(); - tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", true); - tempPlayer->setLevel(msg.readInt16()); - msg.readInt16(); // skill point - tempPlayer->setSprite(SPRITE_BOTTOMCLOTHES, msg.readInt16()); // head bottom - tempPlayer->setSprite(SPRITE_SHIELD, msg.readInt16()); - tempPlayer->setSprite(SPRITE_HAT, msg.readInt16()); // head option top - tempPlayer->setSprite(SPRITE_TOPCLOTHES, msg.readInt16()); // head option mid - tempPlayer->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(msg.readInt16())); - tempPlayer->setSprite(SPRITE_MISC2, msg.readInt16()); - tempPlayer->setName(msg.readString(24)); - for (int i = 0; i < 6; i++) - tempPlayer->setAttributeBase(i + STR, msg.readInt8(), false); - *slot = msg.readInt8(); // character slot - msg.readInt8(); // unknown - - return tempPlayer; -} - -void CharServerHandler::setCharSelectDialog(CharSelectDialog *window) -{ - mCharSelectDialog = window; - updateCharSelectDialog(); -} - -void CharServerHandler::setCharCreateDialog(CharCreateDialog *window) -{ - mCharCreateDialog = window; - - if (!mCharCreateDialog) - return; - - std::vector attributes; - attributes.push_back(_("Strength:")); - attributes.push_back(_("Agility:")); - attributes.push_back(_("Vitality:")); - attributes.push_back(_("Intelligence:")); - attributes.push_back(_("Dexterity:")); - attributes.push_back(_("Luck:")); - - const Token &token = - static_cast(Net::getLoginHandler())->getToken(); - - mCharCreateDialog->setAttributes(attributes, 30, 1, 9); - mCharCreateDialog->setFixedGender(true, token.sex); -} - -void CharServerHandler::requestCharacters() -{ - connect(); -} - -void CharServerHandler::chooseCharacter(Net::Character *character) -{ - mSelectedCharacter = character; - mCharSelectDialog = 0; - - MessageOut outMsg(CMSG_CHAR_SELECT); - outMsg.writeInt8(mSelectedCharacter->slot); -} - -void CharServerHandler::newCharacter(const std::string &name, int slot, - bool gender, int hairstyle, int hairColor, - const std::vector &stats) -{ - MessageOut outMsg(CMSG_CHAR_CREATE); - outMsg.writeString(name, 24); - for (int i = 0; i < 6; i++) - { - outMsg.writeInt8(stats[i]); - } - outMsg.writeInt8(slot); - outMsg.writeInt16(hairColor); - outMsg.writeInt16(hairstyle); -} - -void CharServerHandler::deleteCharacter(Net::Character *character) -{ - mSelectedCharacter = character; - - MessageOut outMsg(CMSG_CHAR_DELETE); - outMsg.writeInt32(mSelectedCharacter->dummy->getId()); - outMsg.writeString("a@a.com", 40); -} - -void CharServerHandler::switchCharacter() -{ - // This is really a map-server packet - MessageOut outMsg(CMSG_PLAYER_RESTART); - outMsg.writeInt8(1); -} - -int CharServerHandler::baseSprite() const -{ - return SPRITE_BASE; -} - -int CharServerHandler::hairSprite() const -{ - return SPRITE_HAIR; -} - -int CharServerHandler::maxSprite() const -{ - return SPRITE_VECTOREND; -} - -void CharServerHandler::connect() -{ - const Token &token = - static_cast(Net::getLoginHandler())->getToken(); - - mNetwork->disconnect(); - mNetwork->connect(charServer); - MessageOut outMsg(CMSG_CHAR_SERVER_CONNECT); - outMsg.writeInt32(token.account_ID); - outMsg.writeInt32(token.session_ID1); - outMsg.writeInt32(token.session_ID2); - // [Fate] The next word is unused by the old char server, so we squeeze in - // mana client version information - outMsg.writeInt16(CLIENT_PROTOCOL_VERSION); - outMsg.writeInt8((token.sex == GENDER_MALE) ? 1 : 0); - - // We get 4 useless bytes before the real answer comes in (what are these?) - mNetwork->skip(4); -} - -} // namespace EAthena diff --git a/src/net/ea/charserverhandler.h b/src/net/ea/charserverhandler.h deleted file mode 100644 index 8f1b5d73..00000000 --- a/src/net/ea/charserverhandler.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_CHARSERVERHANDLER_H -#define NET_EA_CHARSERVERHANDLER_H - -#include "net/charhandler.h" -#include "net/serverinfo.h" - -#include "net/ea/messagehandler.h" -#include "net/ea/token.h" - -class LoginData; - -namespace EAthena { - -/** - * Deals with incoming messages from the character server. - */ -class CharServerHandler : public MessageHandler, public Net::CharHandler -{ - public: - CharServerHandler(); - - virtual void handleMessage(Net::MessageIn &msg); - - void setCharSelectDialog(CharSelectDialog *window); - - /** - * Sets the character create dialog. The handler will clean up this - * dialog when a new character is succesfully created, and will unlock - * the dialog when a new character failed to be created. - */ - void setCharCreateDialog(CharCreateDialog *window); - - void requestCharacters(); - - void chooseCharacter(Net::Character *character); - - void newCharacter(const std::string &name, int slot, bool gender, - int hairstyle, int hairColor, - const std::vector &stats); - - void deleteCharacter(Net::Character *character); - - void switchCharacter(); - - int baseSprite() const; - - int hairSprite() const; - - int maxSprite() const; - - void connect(); - - private: - LocalPlayer *readPlayerData(Net::MessageIn &msg, int *slot); -}; - -} // namespace EAthena - -#endif // NET_EA_CHARSERVERHANDLER_H diff --git a/src/net/ea/chathandler.cpp b/src/net/ea/chathandler.cpp deleted file mode 100644 index 096ca631..00000000 --- a/src/net/ea/chathandler.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/chathandler.h" - -#include "being.h" -#include "beingmanager.h" -#include "game.h" -#include "localplayer.h" -#include "playerrelations.h" - -#include "gui/widgets/chattab.h" - -#include "net/messagein.h" -#include "net/messageout.h" - -#include "net/ea/protocol.h" - -#include "utils/gettext.h" -#include "utils/stringutils.h" - -#include - -extern Net::ChatHandler *chatHandler; - -namespace EAthena { - -ChatHandler::ChatHandler() -{ - static const Uint16 _messages[] = { - SMSG_BEING_CHAT, - SMSG_PLAYER_CHAT, - SMSG_WHISPER, - SMSG_WHISPER_RESPONSE, - SMSG_GM_CHAT, - SMSG_MVP, // MVP - 0 - }; - handledMessages = _messages; - chatHandler = this; -} - -void ChatHandler::handleMessage(Net::MessageIn &msg) -{ - if (!localChatTab) return; - - Being *being; - std::string chatMsg; - std::string nick; - int chatMsgLength; - - switch (msg.getId()) - { - case SMSG_WHISPER_RESPONSE: - switch (msg.readInt8()) - { - case 0x00: - // comment out since we'll local echo in chat.cpp instead, then only report failures - //localChatTab->chatLog("Whisper sent", BY_SERVER); - break; - case 0x01: - localChatTab->chatLog(_("Whisper could not be sent, user " - "is offline."), BY_SERVER); - break; - case 0x02: - localChatTab->chatLog(_("Whisper could not be sent, " - "ignored by user."), BY_SERVER); - break; - } - break; - - // Received whisper - case SMSG_WHISPER: - chatMsgLength = msg.readInt16() - 28; - nick = msg.readString(24); - - if (chatMsgLength <= 0) - break; - - chatMsg = msg.readString(chatMsgLength); - - if (nick != "Server") - { - if (player_relations.hasPermission(nick, PlayerRelation::WHISPER)) - chatWindow->whisper(nick, chatMsg); - } - else - { - localChatTab->chatLog(chatMsg, BY_SERVER); - } - - break; - - // Received speech from being - case SMSG_BEING_CHAT: { - chatMsgLength = msg.readInt16() - 8; - being = beingManager->findBeing(msg.readInt32()); - - if (!being || chatMsgLength <= 0) - break; - - chatMsg = msg.readString(chatMsgLength); - - std::string::size_type pos = chatMsg.find(" : ", 0); - std::string sender_name = ((pos == std::string::npos) - ? "" - : chatMsg.substr(0, pos)); - - // We use getIgnorePlayer instead of ignoringPlayer here because ignorePlayer' side - // effects are triggered right below for Being::IGNORE_SPEECH_FLOAT. - if (player_relations.checkPermissionSilently(sender_name, PlayerRelation::SPEECH_LOG)) - localChatTab->chatLog(chatMsg, BY_OTHER); - - chatMsg.erase(0, pos + 3); - trim(chatMsg); - - if (player_relations.hasPermission(sender_name, PlayerRelation::SPEECH_FLOAT)) - being->setSpeech(chatMsg, SPEECH_TIME); - break; - } - - case SMSG_PLAYER_CHAT: - case SMSG_GM_CHAT: { - chatMsgLength = msg.readInt16() - 4; - - if (chatMsgLength <= 0) - break; - - chatMsg = msg.readString(chatMsgLength); - std::string::size_type pos = chatMsg.find(" : ", 0); - - if (msg.getId() == SMSG_PLAYER_CHAT) - { - localChatTab->chatLog(chatMsg, BY_PLAYER); - - if (pos != std::string::npos) - chatMsg.erase(0, pos + 3); - - trim(chatMsg); - - player_node->setSpeech(chatMsg, SPEECH_TIME); - } - else - { - localChatTab->chatLog(chatMsg, BY_GM); - } - break; - } - - case SMSG_MVP: - // Display MVP player - msg.readInt32(); // id - localChatTab->chatLog(_("MVP player."), BY_SERVER); - break; - } -} - -void ChatHandler::talk(const std::string &text) -{ - std::string mes = player_node->getName() + " : " + text; - - MessageOut outMsg(CMSG_CHAT_MESSAGE); - // Added + 1 in order to let eAthena parse admin commands correctly - outMsg.writeInt16(mes.length() + 4 + 1); - outMsg.writeString(mes, mes.length() + 1); -} - -void ChatHandler::me(const std::string &text) -{ - std::string action = strprintf("*%s*", text.c_str()); - - talk(action); -} - -void ChatHandler::privateMessage(const std::string &recipient, - const std::string &text) -{ - MessageOut outMsg(CMSG_CHAT_WHISPER); - outMsg.writeInt16(text.length() + 28); - outMsg.writeString(recipient, 24); - outMsg.writeString(text, text.length()); -} - -void ChatHandler::channelList() -{ - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); -} - -void ChatHandler::enterChannel(const std::string &channel, - const std::string &password) -{ - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); -} - -void ChatHandler::quitChannel(int channelId) -{ - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); -} - -void ChatHandler::sendToChannel(int channelId, const std::string &text) -{ - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); -} - -void ChatHandler::userList(const std::string &channel) -{ - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); -} - -void ChatHandler::setChannelTopic(int channelId, const std::string &text) -{ - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); -} - -void ChatHandler::setUserMode(int channelId, const std::string &name, int mode) -{ - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); -} - -void ChatHandler::kickUser(int channelId, const std::string &name) -{ - localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); -} - -void ChatHandler::who() -{ - MessageOut outMsg(CMSG_WHO_REQUEST); -} - -} // namespace EAthena diff --git a/src/net/ea/chathandler.h b/src/net/ea/chathandler.h deleted file mode 100644 index aceb05a2..00000000 --- a/src/net/ea/chathandler.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_CHATHANDLER_H -#define NET_EA_CHATHANDLER_H - -#include "net/chathandler.h" -#include "net/net.h" - -#include "net/ea/messagehandler.h" - -namespace EAthena { - -class ChatHandler : public MessageHandler, public Net::ChatHandler -{ - public: - ChatHandler(); - - void handleMessage(Net::MessageIn &msg); - - void talk(const std::string &text); - - void me(const std::string &text); - - void privateMessage(const std::string &recipient, - const std::string &text); - - void channelList(); - - void enterChannel(const std::string &channel, - const std::string &password); - - void quitChannel(int channelId); - - void sendToChannel(int channelId, const std::string &text); - - void userList(const std::string &channel); - - void setChannelTopic(int channelId, const std::string &text); - - void setUserMode(int channelId, const std::string &name, int mode); - - void kickUser(int channelId, const std::string &name); - - void who(); -}; - -} // namespace EAthena - -#endif // NET_EA_CHATHANDLER_H diff --git a/src/net/ea/gamehandler.cpp b/src/net/ea/gamehandler.cpp deleted file mode 100644 index cabaf763..00000000 --- a/src/net/ea/gamehandler.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/gamehandler.h" - -#include "client.h" -#include "game.h" -#include "localplayer.h" -#include "log.h" - -#include "gui/widgets/chattab.h" - -#include "gui/okdialog.h" - -#include "net/messagein.h" -#include "net/messageout.h" - -#include "net/ea/loginhandler.h" -#include "net/ea/network.h" -#include "net/ea/protocol.h" - -#include "utils/gettext.h" -#include "utils/stringutils.h" - -extern Net::GameHandler *gameHandler; - -namespace EAthena { - -extern ServerInfo mapServer; - -GameHandler::GameHandler() -{ - static const Uint16 _messages[] = { - SMSG_MAP_LOGIN_SUCCESS, - SMSG_SERVER_PING, - SMSG_WHO_ANSWER, - SMSG_CHAR_SWITCH_RESPONSE, - SMSG_MAP_QUIT_RESPONSE, - 0 - }; - handledMessages = _messages; - gameHandler = this; -} - -void GameHandler::handleMessage(Net::MessageIn &msg) -{ - switch (msg.getId()) - { - case SMSG_MAP_LOGIN_SUCCESS: - { - unsigned char direction; - Uint16 x, y; - msg.readInt32(); // server tick - msg.readCoordinates(x, y, direction); - msg.skip(2); // unknown - logger->log("Protocol: Player start position: (%d, %d), Direction: %d", - x, y, direction); - // Switch now or we'll have problems - Client::setState(STATE_GAME); - player_node->setTileCoords(x, y); - } break; - - case SMSG_SERVER_PING: - // We ignore this for now - // int tick = msg.readInt32() - break; - - case SMSG_WHO_ANSWER: - localChatTab->chatLog(strprintf(_("Online users: %d"), - msg.readInt32()), BY_SERVER); - break; - - case SMSG_CHAR_SWITCH_RESPONSE: - if (msg.readInt8()) - { - Client::setState(STATE_SWITCH_CHARACTER); - } - break; - - case SMSG_MAP_QUIT_RESPONSE: - if (msg.readInt8()) - { - new OkDialog(_("Game"), _("Request to quit denied!"), NULL); - } - break; - } -} - -void GameHandler::connect() -{ - mNetwork->connect(mapServer); - - const Token &token = - static_cast(Net::getLoginHandler())->getToken(); - - - if (Client::getState() == STATE_CONNECT_GAME) - { - mCharID = player_node->getId(); - // Change the player's ID to the account ID to match what eAthena uses - player_node->setId(token.account_ID); - } - - // Send login infos - MessageOut outMsg(CMSG_MAP_SERVER_CONNECT); - outMsg.writeInt32(token.account_ID); - outMsg.writeInt32(mCharID); - outMsg.writeInt32(token.session_ID1); - outMsg.writeInt32(token.session_ID2); - outMsg.writeInt8((token.sex == GENDER_MALE) ? 1 : 0); - - // We get 4 useless bytes before the real answer comes in (what are these?) - mNetwork->skip(4); -} - -bool GameHandler::isConnected() -{ - return mNetwork->isConnected(); -} - -void GameHandler::disconnect() -{ - mNetwork->disconnect(); -} - -void GameHandler::inGame() -{ - Game::instance()->changeMap(mMap); -} - -void GameHandler::mapLoaded(const std::string &mapName) -{ - MessageOut outMsg(CMSG_MAP_LOADED); -} - -void GameHandler::who() -{ -} - -void GameHandler::quit() -{ - MessageOut outMsg(CMSG_CLIENT_QUIT); -} - -void GameHandler::ping(int tick) -{ - MessageOut msg(CMSG_CLIENT_PING); - msg.writeInt32(tick); -} - -void GameHandler::setMap(const std::string map) -{ - mMap = map.substr(0, map.rfind(".")); -} - -} // namespace EAthena diff --git a/src/net/ea/gamehandler.h b/src/net/ea/gamehandler.h deleted file mode 100644 index b8b6626d..00000000 --- a/src/net/ea/gamehandler.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_MAPHANDLER_H -#define NET_EA_MAPHANDLER_H - -#include "net/gamehandler.h" -#include "net/net.h" -#include "net/serverinfo.h" - -#include "net/ea/messagehandler.h" -#include "net/ea/token.h" - -namespace EAthena { - -class GameHandler : public MessageHandler, public Net::GameHandler -{ - public: - GameHandler(); - - void handleMessage(Net::MessageIn &msg); - - void connect(); - - bool isConnected(); - - void disconnect(); - - void inGame(); - - void mapLoaded(const std::string &mapName); - - void who(); - - void quit(); - - void ping(int tick); - - bool removeDeadBeings() const { return true; } - - void clear(); - - void setMap(const std::string map); - - private: - std::string mMap; - int mCharID; /// < Saved for map-server switching -}; - -} // namespace EAthena - -#endif // NET_EA_MAPHANDLER_H diff --git a/src/net/ea/generalhandler.cpp b/src/net/ea/generalhandler.cpp deleted file mode 100644 index 047aee63..00000000 --- a/src/net/ea/generalhandler.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/generalhandler.h" - -#include "client.h" -#include "configuration.h" -#include "log.h" - -#include "gui/charselectdialog.h" -#include "gui/inventorywindow.h" -#include "gui/register.h" -#include "gui/skilldialog.h" -#include "gui/socialwindow.h" -#include "gui/statuswindow.h" - -#include "net/ea/adminhandler.h" -#include "net/ea/beinghandler.h" -#include "net/ea/buysellhandler.h" -#include "net/ea/chathandler.h" -#include "net/ea/charserverhandler.h" -#include "net/ea/gamehandler.h" -#include "net/ea/guildhandler.h" -#include "net/ea/inventoryhandler.h" -#include "net/ea/itemhandler.h" -#include "net/ea/loginhandler.h" -#include "net/ea/network.h" -#include "net/ea/npchandler.h" -#include "net/ea/partyhandler.h" -#include "net/ea/playerhandler.h" -#include "net/ea/protocol.h" -#include "net/ea/tradehandler.h" -#include "net/ea/specialhandler.h" - -#include "net/ea/gui/guildtab.h" -#include "net/ea/gui/partytab.h" - -#include "net/messagein.h" -#include "net/messageout.h" - -#include "resources/itemdb.h" - -#include "utils/gettext.h" - -#include -#include - -extern Net::GeneralHandler *generalHandler; - -namespace EAthena { - -ServerInfo charServer; -ServerInfo mapServer; - -extern Guild *eaGuild; -extern Party *eaParty; - -GeneralHandler::GeneralHandler(): - mAdminHandler(new AdminHandler), - mBeingHandler(new BeingHandler(config.getValue("EnableSync", 0) == 1)), - mBuySellHandler(new BuySellHandler), - mCharHandler(new CharServerHandler), - mChatHandler(new ChatHandler), - mGameHandler(new GameHandler), - mGuildHandler(new GuildHandler), - mInventoryHandler(new InventoryHandler), - mItemHandler(new ItemHandler), - mLoginHandler(new LoginHandler), - mNpcHandler(new NpcHandler), - mPartyHandler(new PartyHandler), - mPlayerHandler(new PlayerHandler), - mSpecialHandler(new SpecialHandler), - mTradeHandler(new TradeHandler) -{ - static const Uint16 _messages[] = { - SMSG_CONNECTION_PROBLEM, - 0 - }; - handledMessages = _messages; - generalHandler = this; - - std::list stats; - stats.push_back(ItemDB::Stat("str", N_("Strength %+d"))); - stats.push_back(ItemDB::Stat("agi", N_("Agility %+d"))); - stats.push_back(ItemDB::Stat("vit", N_("Vitality %+d"))); - stats.push_back(ItemDB::Stat("int", N_("Intelligence %+d"))); - stats.push_back(ItemDB::Stat("dex", N_("Dexterity %+d"))); - stats.push_back(ItemDB::Stat("luck", N_("Luck %+d"))); - - ItemDB::setStatsList(stats); -} - -GeneralHandler::~GeneralHandler() -{ - delete mNetwork; -} - -void GeneralHandler::handleMessage(Net::MessageIn &msg) -{ - int code; - - switch (msg.getId()) - { - case SMSG_CONNECTION_PROBLEM: - code = msg.readInt8(); - logger->log("Connection problem: %i", code); - - switch (code) - { - case 0: - errorMessage = _("Authentication failed."); - break; - case 1: - errorMessage = _("No servers available."); - break; - case 2: - if (Client::getState() == STATE_GAME) - errorMessage = _("Someone else is trying to use this " - "account."); - else - errorMessage = _("This account is already logged in."); - break; - case 3: - errorMessage = _("Speed hack detected."); - break; - case 8: - errorMessage = _("Duplicated login."); - break; - default: - errorMessage = _("Unknown connection error."); - break; - } - Client::setState(STATE_ERROR); - break; - } -} - -void GeneralHandler::load() -{ - (new Network)->registerHandler(this); - - mNetwork->registerHandler(mAdminHandler.get()); - mNetwork->registerHandler(mBeingHandler.get()); - mNetwork->registerHandler(mBuySellHandler.get()); - mNetwork->registerHandler(mChatHandler.get()); - mNetwork->registerHandler(mCharHandler.get()); - mNetwork->registerHandler(mGameHandler.get()); - mNetwork->registerHandler(mGuildHandler.get()); - mNetwork->registerHandler(mInventoryHandler.get()); - mNetwork->registerHandler(mItemHandler.get()); - mNetwork->registerHandler(mLoginHandler.get()); - mNetwork->registerHandler(mNpcHandler.get()); - mNetwork->registerHandler(mPlayerHandler.get()); - mNetwork->registerHandler(mSpecialHandler.get()); - mNetwork->registerHandler(mTradeHandler.get()); - mNetwork->registerHandler(mPartyHandler.get()); -} - -void GeneralHandler::reload() -{ - if (mNetwork) - mNetwork->disconnect(); - - static_cast(mLoginHandler.get())->clearWorlds(); - static_cast(mCharHandler.get())->setCharCreateDialog(0); - static_cast(mCharHandler.get())->setCharSelectDialog(0); -} - -void GeneralHandler::unload() -{ - if (mNetwork) - mNetwork->clearHandlers(); -} - -void GeneralHandler::flushNetwork() -{ - if (!mNetwork) - return; - - mNetwork->flush(); - mNetwork->dispatchMessages(); - - if (mNetwork->getState() == Network::NET_ERROR) - { - if (!mNetwork->getError().empty()) - errorMessage = mNetwork->getError(); - else - errorMessage = _("Got disconnected from server!"); - - Client::setState(STATE_ERROR); - } -} - -void GeneralHandler::guiWindowsLoaded() -{ - inventoryWindow->setSplitAllowed(false); - skillDialog->loadSkills("ea-skills.xml"); - - statusWindow->addAttribute(STR, _("Strength"), true); - statusWindow->addAttribute(AGI, _("Agility"), true); - statusWindow->addAttribute(VIT, _("Vitality"), true); - statusWindow->addAttribute(INT, _("Intelligence"), true); - statusWindow->addAttribute(DEX, _("Dexterity"), true); - statusWindow->addAttribute(LUK, _("Luck"), true); - - statusWindow->addAttribute(ATK, _("Attack"), false); - statusWindow->addAttribute(DEF, _("Defense"), false); - statusWindow->addAttribute(MATK, _("M.Attack"), false); - statusWindow->addAttribute(MDEF, _("M.Defense"), false); - statusWindow->addAttribute(HIT, _("% Accuracy"), false); - statusWindow->addAttribute(FLEE, _("% Evade"), false); - statusWindow->addAttribute(CRIT, _("% Critical"), false); -} - -void GeneralHandler::guiWindowsUnloaded() -{ - socialWindow->removeTab(eaGuild); - socialWindow->removeTab(eaParty); - - delete guildTab; - guildTab = 0; - - delete partyTab; - partyTab = 0; -} - -void GeneralHandler::clearHandlers() -{ - mNetwork->clearHandlers(); -} - -void GeneralHandler::stateChanged(State oldState, State newState) -{ - // -} - -} // namespace EAthena diff --git a/src/net/ea/generalhandler.h b/src/net/ea/generalhandler.h deleted file mode 100644 index f0857abe..00000000 --- a/src/net/ea/generalhandler.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_GENERALHANDLER_H -#define NET_EA_GENERALHANDLER_H - -#include "net/generalhandler.h" -#include "net/net.h" -#include "net/serverinfo.h" - -#include "net/ea/messagehandler.h" - -namespace EAthena { - -class GeneralHandler : public MessageHandler, public Net::GeneralHandler -{ - public: - GeneralHandler(); - - ~GeneralHandler(); - - void handleMessage(Net::MessageIn &msg); - - void load(); - - void reload(); - - void unload(); - - void flushNetwork(); - - void guiWindowsLoaded(); - - void guiWindowsUnloaded(); - - void clearHandlers(); - - void stateChanged(State oldState, State newState); - - protected: - MessageHandlerPtr mAdminHandler; - MessageHandlerPtr mBeingHandler; - MessageHandlerPtr mBuySellHandler; - MessageHandlerPtr mCharHandler; - MessageHandlerPtr mChatHandler; - MessageHandlerPtr mGameHandler; - MessageHandlerPtr mGuildHandler; - MessageHandlerPtr mInventoryHandler; - MessageHandlerPtr mItemHandler; - MessageHandlerPtr mLoginHandler; - MessageHandlerPtr mNpcHandler; - MessageHandlerPtr mPartyHandler; - MessageHandlerPtr mPlayerHandler; - MessageHandlerPtr mSpecialHandler; - MessageHandlerPtr mTradeHandler; -}; - -} // namespace EAthena - -#endif // NET_EA_GENERALHANDLER_H diff --git a/src/net/ea/gui/guildtab.cpp b/src/net/ea/gui/guildtab.cpp deleted file mode 100644 index e6fddf4f..00000000 --- a/src/net/ea/gui/guildtab.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/gui/guildtab.h" - -#include "commandhandler.h" -#include "guild.h" -#include "localplayer.h" - -#include "gui/theme.h" - -#include "net/net.h" -#include "net/guildhandler.h" - -#include "resources/iteminfo.h" -#include "resources/itemdb.h" - -#include "utils/dtor.h" -#include "utils/gettext.h" -#include "utils/stringutils.h" - -namespace EAthena { - -extern Guild *eaGuild; - -GuildTab::GuildTab() : - ChatTab(_("Guild")) -{ - setTabColor(&Theme::getThemeColor(Theme::GUILD)); -} - -GuildTab::~GuildTab() -{ -} - -void GuildTab::handleInput(const std::string &msg) -{ - Net::getGuildHandler()->chat(eaGuild->getId(), msg); -} - -void GuildTab::showHelp() -{ - chatLog(_("/help > Display this help.")); - chatLog(_("/invite > Invite a player to your guild")); - chatLog(_("/leave > Leave the guild you are in")); - chatLog(_("/kick > Kick some one from the guild you are in")); -} - -bool GuildTab::handleCommand(const std::string &type, const std::string &args) -{ - if (type == "help") - { - if (args == "invite") - { - chatLog(_("Command: /invite ")); - chatLog(_("This command invites to the guild you're in.")); - chatLog(_("If the has spaces in it, enclose it in " - "double quotes (\").")); - } - else if (args == "leave") - { - chatLog(_("Command: /leave")); - chatLog(_("This command causes the player to leave the guild.")); - } - else - return false; - } - else if (type == "create" || type == "new") - { - if (args.empty()) - chatLog(_("Guild name is missing."), BY_SERVER); - else - Net::getGuildHandler()->create(args); - } - else if (type == "invite") - { - Net::getGuildHandler()->invite(eaGuild->getId(), args); - } - else if (type == "leave") - { - Net::getGuildHandler()->leave(eaGuild->getId()); - } - else if (type == "kick") - { - Net::getGuildHandler()->kick(eaGuild->getMember(args)); - } - else - return false; - - return true; -} - -void GuildTab::getAutoCompleteList(std::vector &names) const -{ - if (eaGuild) - eaGuild->getNames(names); -} - -} // namespace EAthena diff --git a/src/net/ea/gui/guildtab.h b/src/net/ea/gui/guildtab.h deleted file mode 100644 index 58c8f539..00000000 --- a/src/net/ea/gui/guildtab.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef EA_GUILDTAB_H -#define EA_GUILDTAB_H - -#include "gui/widgets/chattab.h" - -namespace EAthena { - -/** - * A tab for a guild chat channel. - */ -class GuildTab : public ChatTab -{ - public: - GuildTab(); - ~GuildTab(); - - void showHelp(); - - bool handleCommand(const std::string &type, const std::string &args); - - protected: - void handleInput(const std::string &msg); - - void getAutoCompleteList(std::vector &names) const; -}; - -extern GuildTab *guildTab; - -} // namespace EAthena - -#endif // EA_GUILDTAB_H diff --git a/src/net/ea/gui/partytab.cpp b/src/net/ea/gui/partytab.cpp deleted file mode 100644 index 85311352..00000000 --- a/src/net/ea/gui/partytab.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/gui/partytab.h" - -#include "commandhandler.h" -#include "localplayer.h" -#include "party.h" - -#include "gui/theme.h" - -#include "net/net.h" -#include "net/partyhandler.h" - -#include "resources/iteminfo.h" -#include "resources/itemdb.h" - -#include "utils/dtor.h" -#include "utils/gettext.h" -#include "utils/stringutils.h" - -namespace EAthena { - -PartyTab::PartyTab() : - ChatTab(_("Party")) -{ - setTabColor(&Theme::getThemeColor(Theme::PARTY)); -} - -PartyTab::~PartyTab() -{ -} - -void PartyTab::handleInput(const std::string &msg) -{ - Net::getPartyHandler()->chat(msg); -} - -void PartyTab::showHelp() -{ - chatLog(_("/help > Display this help.")); - chatLog(_("/invite > Invite a player to your party")); - chatLog(_("/leave > Leave the party you are in")); - chatLog(_("/kick > Kick some one from the party you are in")); - chatLog(_("/item > Show/change party item sharing options")); - chatLog(_("/exp > Show/change party experience sharing options")); -} - -bool PartyTab::handleCommand(const std::string &type, const std::string &args) -{ - if (type == "help") - { - if (args == "invite") - { - chatLog(_("Command: /invite ")); - chatLog(_("This command invites to party with you.")); - chatLog(_("If the has spaces in it, enclose it in " - "double quotes (\").")); - } - else if (args == "leave") - { - chatLog(_("Command: /leave")); - chatLog(_("This command causes the player to leave the party.")); - } - else if (args == "item") - { - chatLog(_("Command: /item ")); - chatLog(_("This command changes the party's item sharing policy.")); - chatLog(_(" can be one of \"1\", \"yes\", \"true\" to " - "enable item sharing, or \"0\", \"no\", \"false\" to " - "disable item sharing.")); - chatLog(_("Command: /item")); - chatLog(_("This command displays the party's current item sharing policy.")); - } - else if (args == "exp") - { - chatLog(_("Command: /exp ")); - chatLog(_("This command changes the party's experience sharing policy.")); - chatLog(_(" can be one of \"1\", \"yes\", \"true\" to " - "enable experience sharing, or \"0\", \"no\", \"false\" to " - "disable experience sharing.")); - chatLog(_("Command: /exp")); - chatLog(_("This command displays the party's current experience sharing policy.")); - } - else - return false; - } - else if (type == "create" || type == "new") - { - if (args.empty()) - chatLog(_("Party name is missing."), BY_SERVER); - else - Net::getPartyHandler()->create(args); - } - else if (type == "invite") - { - Net::getPartyHandler()->invite(args); - } - else if (type == "leave") - { - Net::getPartyHandler()->leave(); - } - else if (type == "kick") - { - Net::getPartyHandler()->kick(args); - } - else if (type == "item") - { - if (args.empty()) - { - switch (Net::getPartyHandler()->getShareItems()) - { - case PARTY_SHARE: - chatLog(_("Item sharing enabled."), BY_SERVER); - return true; - case PARTY_SHARE_NO: - chatLog(_("Item sharing disabled."), BY_SERVER); - return true; - case PARTY_SHARE_NOT_POSSIBLE: - chatLog(_("Item sharing not possible."), BY_SERVER); - return true; - case PARTY_SHARE_UNKNOWN: - chatLog(_("Item sharing unknown."), BY_SERVER); - return true; - } - } - - char opt = CommandHandler::parseBoolean(args); - - switch (opt) - { - case 1: - Net::getPartyHandler()->setShareItems(PARTY_SHARE); - break; - case 0: - Net::getPartyHandler()->setShareItems(PARTY_SHARE_NO); - break; - case -1: - chatLog(strprintf(BOOLEAN_OPTIONS, "item")); - } - } - else if (type == "exp") - { - if (args.empty()) - { - switch (Net::getPartyHandler()->getShareExperience()) - { - case PARTY_SHARE: - chatLog(_("Experience sharing enabled."), BY_SERVER); - return true; - case PARTY_SHARE_NO: - chatLog(_("Experience sharing disabled."), BY_SERVER); - return true; - case PARTY_SHARE_NOT_POSSIBLE: - chatLog(_("Experience sharing not possible."), BY_SERVER); - return true; - case PARTY_SHARE_UNKNOWN: - chatLog(_("Experience sharing unknown."), BY_SERVER); - return true; - } - } - - char opt = CommandHandler::parseBoolean(args); - - switch (opt) - { - case 1: - Net::getPartyHandler()->setShareExperience(PARTY_SHARE); - break; - case 0: - Net::getPartyHandler()->setShareExperience(PARTY_SHARE_NO); - break; - case -1: - chatLog(strprintf(BOOLEAN_OPTIONS, "exp")); - } - } - else - return false; - - return true; -} - -void PartyTab::getAutoCompleteList(std::vector &names) const -{ - Party *p = player_node->getParty(); - - if (p) - p->getNames(names); -} - -} // namespace EAthena diff --git a/src/net/ea/gui/partytab.h b/src/net/ea/gui/partytab.h deleted file mode 100644 index af111836..00000000 --- a/src/net/ea/gui/partytab.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef EA_PARTYTAB_H -#define EA_PARTYTAB_H - -#include "gui/widgets/chattab.h" - -namespace EAthena { - -/** - * A tab for a party chat channel. - */ -class PartyTab : public ChatTab -{ - public: - PartyTab(); - ~PartyTab(); - - void showHelp(); - - bool handleCommand(const std::string &type, const std::string &args); - - protected: - void handleInput(const std::string &msg); - - virtual void getAutoCompleteList(std::vector&) const; -}; - -extern PartyTab *partyTab; - -} // namespace EAthena - -#endif // EA_PARTYTAB_H diff --git a/src/net/ea/guildhandler.cpp b/src/net/ea/guildhandler.cpp deleted file mode 100644 index bb2fdff7..00000000 --- a/src/net/ea/guildhandler.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/guildhandler.h" - -#include "guild.h" -#include "localplayer.h" -#include "log.h" - -#include "gui/socialwindow.h" - -#include "net/ea/messagein.h" -#include "net/ea/protocol.h" - -#include "net/ea/gui/guildtab.h" - -#include "utils/gettext.h" - -extern Net::GuildHandler *guildHandler; - -namespace EAthena { - -GuildTab *guildTab = 0; -Guild *eaGuild; - -GuildHandler::GuildHandler() -{ - static const Uint16 _messages[] = { - SMSG_GUILD_CREATE_RESPONSE, - SMSG_GUILD_POSITION_INFO, - SMSG_GUILD_MEMBER_LOGIN, - SMSG_GUILD_MASTER_OR_MEMBER, - SMSG_GUILD_BASIC_INFO, - SMSG_GUILD_ALIANCE_INFO, - SMSG_GUILD_MEMBER_LIST, - SMSG_GUILD_POS_NAME_LIST, - SMSG_GUILD_POS_INFO_LIST, - SMSG_GUILD_POSITION_CHANGED, - SMSG_GUILD_MEMBER_POS_CHANGE, - SMSG_GUILD_EMBLEM, - SMSG_GUILD_SKILL_INFO, - SMSG_GUILD_NOTICE, - SMSG_GUILD_INVITE, - SMSG_GUILD_INVITE_ACK, - SMSG_GUILD_LEAVE, - SMSG_GUILD_EXPULSION, - SMSG_GUILD_EXPULSION_LIST, - SMSG_GUILD_MESSAGE, - SMSG_GUILD_SKILL_UP, - SMSG_GUILD_REQ_ALLIANCE, - SMSG_GUILD_REQ_ALLIANCE_ACK, - SMSG_GUILD_DEL_ALLIANCE, - SMSG_GUILD_OPPOSITION_ACK, - SMSG_GUILD_BROKEN, - 0 - }; - handledMessages = _messages; - - guildHandler = this; -} - -GuildHandler::~GuildHandler() -{ - delete guildTab; - guildTab = 0; -} - -void GuildHandler::handleMessage(Net::MessageIn &msg) -{ - switch (msg.getId()) - { - case SMSG_GUILD_CREATE_RESPONSE: - { - int flag = msg.readInt8(); - - if (flag == 0) - { - // Success - } - else if (flag == 1) - { - // Already in a guild - } - else if (flag == 2) - { - // Unable to make (likely name already in use) - } - else if (flag == 3) - { - // Emperium check failed - } - } - break; - - case SMSG_GUILD_POSITION_INFO: - { - int guildId = msg.readInt32(); - int emblem = msg.readInt32(); - int posMode = msg.readInt32(); - msg.readInt32(); // Unused - msg.readInt8(); // Unused - std::string guildName = msg.readString(24); - - logger->log("Guild position info: %d %d %d %s\n", guildId, - emblem, posMode, guildName.c_str()); - } - break; - - case SMSG_GUILD_MEMBER_LOGIN: - msg.readInt32(); // Account ID - msg.readInt32(); // Char ID - msg.readInt32(); // Flag - break; - - case SMSG_GUILD_MASTER_OR_MEMBER: - msg.readInt32(); // Type (0x57 for member, 0xd7 for master) - break; - - case SMSG_GUILD_BASIC_INFO: - { - int guildID = msg.readInt32(); // Guild ID - msg.readInt32(); // Guild level - msg.readInt32(); // 'Connect member' (number online?) - msg.readInt32(); // 'Max member' - msg.readInt32(); // Average level - msg.readInt32(); // Exp - msg.readInt32(); // Next exp - msg.skip(16); // unused - std::string name = msg.readString(24); // Name - msg.readString(24); // Master's name - msg.readString(20); // Castles (ie: "Six Castles" or "None Taken") - - Guild *g = Guild::getGuild(guildID); - g->setName(name); - } - break; - - case SMSG_GUILD_ALIANCE_INFO: - { - int length = msg.readInt16(); - int count = (length - 4) / 32; - - for (int i = 0; i < count; i++) - { - msg.readInt32(); // 'Opposition' - msg.readInt32(); // Other guild ID - msg.readString(24); // Other guild name - } - } - break; - - case SMSG_GUILD_MEMBER_LIST: - { - int length = msg.readInt16(); - int count = (length - 4) / 104; - - eaGuild->clearMembers(); - - for (int i = 0; i < count; i++) - { - int id = msg.readInt32(); // Account ID - msg.readInt32(); // Char ID - msg.readInt16(); // Hair - msg.readInt16(); // Hair color - msg.readInt16(); // Gender - msg.readInt16(); // Class - msg.readInt16(); // Level - msg.readInt32(); // Exp - int online = msg.readInt32(); // Online - msg.readInt32(); // Position - msg.skip(50); // unused - std::string name = msg.readString(24); // Name - - GuildMember *m = eaGuild->addMember(id, name); - m->setOnline(online); - } - } - break; - - case SMSG_GUILD_POS_NAME_LIST: - { - int length = msg.readInt16(); - int count = (length - 4) / 28; - - for (int i = 0; i < count; i++) - { - msg.readInt32(); // ID - msg.readString(24); // Position name - } - } - break; - - case SMSG_GUILD_POS_INFO_LIST: - { - int length = msg.readInt16(); - int count = (length - 4) / 16; - - for (int i = 0; i < count; i++) - { - msg.readInt32(); // ID - msg.readInt32(); // Mode - msg.readInt32(); // Same ID - msg.readInt32(); // Exp mode - } - } - break; - - case SMSG_GUILD_POSITION_CHANGED: - msg.readInt16(); // Always 44 - msg.readInt32(); // ID - msg.readInt32(); // Mode - msg.readInt32(); // Same ID - msg.readInt32(); // Exp mode - msg.readString(24); // Name - break; - - case SMSG_GUILD_MEMBER_POS_CHANGE: - msg.readInt16(); // Always 16 - msg.readInt32(); // Account ID - msg.readInt32(); // Char ID - msg.readInt32(); // Position - break; - - case SMSG_GUILD_EMBLEM: - { - int length = msg.readInt16(); - - msg.readInt32(); // Guild ID - msg.readInt32(); // Emblem ID - msg.skip(length - 12); // Emblem data (unknown format) - } - break; - - case SMSG_GUILD_SKILL_INFO: - { - int length = msg.readInt16(); - int count = (length - 6) / 37; - - msg.readInt16(); // 'Skill point' - - for (int i = 0; i < count; i++) - { - msg.readInt16(); // ID - msg.readInt16(); // 'Info' (unknown atm) - msg.readInt16(); // unused - msg.readInt16(); // Level - msg.readInt16(); // SP - msg.readInt16(); // 'Range' - msg.skip(24); // unused - msg.readInt8(); // Can be increased - } - } - break; - - case SMSG_GUILD_NOTICE: - msg.readString(60); // Mes1 - msg.readString(120); // Mes2 - break; - - case SMSG_GUILD_INVITE: - { - int guildId = msg.readInt32(); - std::string guildName = msg.readString(24); - - socialWindow->showGuildInvite(guildName, guildId, ""); - } - break; - - case SMSG_GUILD_INVITE_ACK: - { - int flag = msg.readInt8(); - - switch (flag) - { - case 0: - guildTab->chatLog(_("Could not inivte user to guild."), - BY_SERVER); - break; - - case 1: - guildTab->chatLog(_("User rejected guild invite."), - BY_SERVER); - break; - - case 2: - guildTab->chatLog(_("User is now part of your guild."), - BY_SERVER); - break; - - case 3: - guildTab->chatLog(_("Your guild is full."), - BY_SERVER); - break; - - default: - guildTab->chatLog(_("Unknown guild invite response."), - BY_SERVER); - break; - } - } - break; - - case SMSG_GUILD_LEAVE: - msg.readString(24); // Name - msg.readString(40); // Message - break; - - case SMSG_GUILD_EXPULSION: - msg.readString(24); // Name (of expulsed?) - msg.readString(40); // Message - msg.skip(24); // unused ("dummy") - break; - - case SMSG_GUILD_EXPULSION_LIST: - { - int length = msg.readInt16(); - int count = (length - 4) / 88; - - for (int i = 0; i < count; i++) - { - msg.readString(24); // Name (of expulsed?) - msg.readString(24); // 'Acc' (name of expulser?) - msg.readString(24); // Message - } - } - break; - - case SMSG_GUILD_MESSAGE: - { - int msgLength = msg.readInt16() - 4; - if (msgLength <= 0) - { - return; - } - guildTab->chatLog(msg.readString(msgLength)); - } - break; - - case SMSG_GUILD_SKILL_UP: - msg.readInt16(); // Skill ID - msg.readInt16(); // Level - msg.readInt16(); // SP - msg.readInt16(); // 'Range' - msg.readInt8(); // unused? (always 1) - break; - - case SMSG_GUILD_REQ_ALLIANCE: - msg.readInt32(); // Account ID - msg.readString(24); // Name - break; - - case SMSG_GUILD_REQ_ALLIANCE_ACK: - msg.readInt32(); // Flag - break; - - case SMSG_GUILD_DEL_ALLIANCE: - msg.readInt32(); // Guild ID - msg.readInt32(); // Flag - break; - - case SMSG_GUILD_OPPOSITION_ACK: - msg.readInt8(); // Flag - break; - - case SMSG_GUILD_BROKEN: - msg.readInt32(); // Flag - break; - } -} - -void GuildHandler::create(const std::string &name) -{ - localChatTab->chatLog(_("Guild creation isn't supported yet."), - BY_SERVER); - return; - - MessageOut msg(CMSG_GUILD_CREATE); - msg.writeInt32(0); // Unused - msg.writeString(name, 24); -} - -void GuildHandler::invite(int guildId, const std::string &name) -{ - // TODO? -} - -void GuildHandler::invite(int guildId, Player *player) -{ - MessageOut msg(CMSG_GUILD_INVITE); - msg.writeInt32(player->getId()); - msg.writeInt32(0); // Unused - msg.writeInt32(0); // Unused -} - -void GuildHandler::inviteResponse(int guildId, bool response) -{ - MessageOut msg(CMSG_GUILD_INVITE_REPLY); - msg.writeInt32(guildId); - msg.writeInt8(response); - msg.writeInt8(0); // Unused - msg.writeInt16(0); // Unused -} - -void GuildHandler::leave(int guildId) -{ - MessageOut msg(CMSG_GUILD_LEAVE); - msg.writeInt32(guildId); - msg.writeInt32(0); // Account ID - msg.writeInt32(player_node->getId()); - msg.writeString("", 30); // Message -} - -void GuildHandler::kick(GuildMember *member, std::string reason) -{ - MessageOut msg(CMSG_GUILD_EXPULSION); - msg.writeInt32(member->getGuild()->getId()); - msg.writeInt32(member->getID()); // Account ID - msg.writeInt32(0); // Char ID - msg.writeString(reason, 40); // Message -} - -void GuildHandler::chat(int guildId, const std::string &text) -{ - MessageOut msg(CMSG_GUILD_MESSAGE); - msg.writeInt16(text.size() + 4); - msg.writeString(text); -} - -void GuildHandler::memberList(int guildId) -{ - // TODO four types of info requests: - // 0 = basic info + alliance info - // 1 = position name list + member list - // 2 = position name list + position info list - // 3 = skill info - // 4 = expulsion list - - MessageOut msg(CMSG_GUILD_REQUEST_INFO); - msg.writeInt32(1); // Request member list -} - -void GuildHandler::changeMemberPostion(GuildMember *member, int level) -{ - // TODO -} - -void GuildHandler::requestAlliance(int guildId, int otherGuildId) -{ - // TODO -} - -void GuildHandler::requestAllianceResponse(int guildId, int otherGuildId, - bool response) -{ - // TODO -} - -void GuildHandler::endAlliance(int guildId, int otherGuildId) -{ - // TODO -} - -} diff --git a/src/net/ea/guildhandler.h b/src/net/ea/guildhandler.h deleted file mode 100644 index df43a2a1..00000000 --- a/src/net/ea/guildhandler.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_GUILDHANDLER_H -#define NET_EA_GUILDHANDLER_H - -#include "net/guildhandler.h" - -#include "net/ea/messagehandler.h" - -namespace EAthena { - -class GuildHandler : public Net::GuildHandler, public MessageHandler -{ - public: - GuildHandler(); - - ~GuildHandler(); - - void handleMessage(Net::MessageIn &msg); - - void create(const std::string &name); - - void invite(int guildId, const std::string &name); - - void invite(int guildId, Player *player); - - void inviteResponse(int guildId, bool response); - - void leave(int guildId); - - void kick(GuildMember *member, std::string reason = ""); - - void chat(int guildId, const std::string &text); - - void memberList(int guildId); - - void changeMemberPostion(GuildMember *member, int level); - - void requestAlliance(int guildId, int otherGuildId); - - void requestAllianceResponse(int guildId, int otherGuildId, - bool response); - - void endAlliance(int guildId, int otherGuildId); - - private: - // eAthena only supports one guild per player - Guild *mGuild; -}; - -} - -#endif // NET_EA_GUILDHANDLER_H diff --git a/src/net/ea/inventoryhandler.cpp b/src/net/ea/inventoryhandler.cpp deleted file mode 100644 index 36d024f6..00000000 --- a/src/net/ea/inventoryhandler.cpp +++ /dev/null @@ -1,519 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/inventoryhandler.h" - -#include "configuration.h" -#include "equipment.h" -#include "inventory.h" -#include "item.h" -#include "itemshortcut.h" -#include "localplayer.h" -#include "log.h" - -#include "gui/widgets/chattab.h" - -#include "net/messagein.h" -#include "net/messageout.h" - -#include "net/ea/protocol.h" - -#include "resources/iteminfo.h" - -#include "utils/gettext.h" -#include "utils/stringutils.h" - -#include - -extern Net::InventoryHandler *inventoryHandler; - -const Equipment::Slot EQUIP_POINTS[Equipment::EQUIP_VECTOREND] = { - Equipment::EQUIP_LEGS_SLOT, - Equipment::EQUIP_FIGHT1_SLOT, - Equipment::EQUIP_GLOVES_SLOT, - Equipment::EQUIP_RING2_SLOT, - Equipment::EQUIP_RING1_SLOT, - Equipment::EQUIP_FIGHT2_SLOT, - Equipment::EQUIP_FEET_SLOT, - Equipment::EQUIP_NECK_SLOT, - Equipment::EQUIP_HEAD_SLOT, - Equipment::EQUIP_TORSO_SLOT, - Equipment::EQUIP_PROJECTILE_SLOT}; - -namespace EAthena { - -int getSlot(int eAthenaSlot) -{ - if (eAthenaSlot == 0) - { - return Equipment::EQUIP_VECTOREND; - } - - if (eAthenaSlot & 0x8000) - return Equipment::EQUIP_PROJECTILE_SLOT; - - int mask = 1; - int position = 0; - while (!(eAthenaSlot & mask)) - { - mask <<= 1; - position++; - } - return EQUIP_POINTS[position]; -} - -enum { debugInventory = 1 }; - -InventoryHandler::InventoryHandler() -{ - static const Uint16 _messages[] = { - SMSG_PLAYER_INVENTORY, - SMSG_PLAYER_INVENTORY_ADD, - SMSG_PLAYER_INVENTORY_REMOVE, - SMSG_PLAYER_INVENTORY_USE, - SMSG_ITEM_USE_RESPONSE, - SMSG_PLAYER_STORAGE_ITEMS, - SMSG_PLAYER_STORAGE_EQUIP, - SMSG_PLAYER_STORAGE_STATUS, - SMSG_PLAYER_STORAGE_ADD, - SMSG_PLAYER_STORAGE_REMOVE, - SMSG_PLAYER_STORAGE_CLOSE, - SMSG_PLAYER_EQUIPMENT, - SMSG_PLAYER_EQUIP, - SMSG_PLAYER_UNEQUIP, - SMSG_PLAYER_ARROW_EQUIP, - SMSG_PLAYER_ATTACK_RANGE, - 0 - }; - handledMessages = _messages; - inventoryHandler = this; - - mStorage = 0; - mStorageWindow = 0; -} - -InventoryHandler::~InventoryHandler() -{ - if (mStorageWindow) - { - mStorageWindow->close(); - mStorageWindow = 0; - } - - delete mStorage; -} - -void InventoryHandler::handleMessage(Net::MessageIn &msg) -{ - int number, flag; - int index, amount, itemId, equipType, arrow; - int identified, cards[4], itemType; - Inventory *inventory = player_node->getInventory(); - - switch (msg.getId()) - { - case SMSG_PLAYER_INVENTORY: - case SMSG_PLAYER_STORAGE_ITEMS: - if (msg.getId() == SMSG_PLAYER_INVENTORY) - { - // Clear inventory - this will be a complete refresh - mEquips.clear(); - player_node->mEquipment->setBackend(&mEquips); - - inventory->clear(); - } - else - { - mInventoryItems.clear(); - } - - msg.readInt16(); // length - number = (msg.getLength() - 4) / 18; - - for (int loop = 0; loop < number; loop++) - { - index = msg.readInt16(); - itemId = msg.readInt16(); - itemType = msg.readInt8(); - identified = msg.readInt8(); - amount = msg.readInt16(); - arrow = msg.readInt16(); - for (int i = 0; i < 4; i++) - cards[i] = msg.readInt16(); - - index -= (msg.getId() == SMSG_PLAYER_INVENTORY) ? - INVENTORY_OFFSET : STORAGE_OFFSET; - - if (debugInventory) - { - logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " - "Qty: %d, Cards: %d, %d, %d, %d", - index, itemId, itemType, identified, amount, - cards[0], cards[1], cards[2], cards[3]); - } - - if (msg.getId() == SMSG_PLAYER_INVENTORY) - { - // Trick because arrows are not considered equipment - bool isEquipment = arrow & 0x8000; - - inventory->setItem(index, itemId, amount, isEquipment); - } - else - { - mInventoryItems.push_back(InventoryItem(index, itemId, - amount, false)); - } - } - break; - - case SMSG_PLAYER_STORAGE_EQUIP: - msg.readInt16(); // length - number = (msg.getLength() - 4) / 20; - - for (int loop = 0; loop < number; loop++) - { - index = msg.readInt16() - STORAGE_OFFSET; - itemId = msg.readInt16(); - itemType = msg.readInt8(); - identified = msg.readInt8(); - amount = 1; - msg.readInt16(); // Equip Point? - msg.readInt16(); // Another Equip Point? - msg.readInt8(); // Attribute (broken) - msg.readInt8(); // Refine level - for (int i = 0; i < 4; i++) - cards[i] = msg.readInt16(); - - if (debugInventory) - { - logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " - "Qty: %d, Cards: %d, %d, %d, %d", - index, itemId, itemType, identified, amount, - cards[0], cards[1], cards[2], cards[3]); - } - - mInventoryItems.push_back(InventoryItem(index, itemId, amount, - false)); - } - break; - - case SMSG_PLAYER_INVENTORY_ADD: - index = msg.readInt16() - INVENTORY_OFFSET; - amount = msg.readInt16(); - itemId = msg.readInt16(); - identified = msg.readInt8(); - msg.readInt8(); // attribute - msg.readInt8(); // refine - for (int i = 0; i < 4; i++) - cards[i] = msg.readInt16(); - equipType = msg.readInt16(); - itemType = msg.readInt8(); - - { - const ItemInfo &itemInfo = ItemDB::get(itemId); - - if (msg.readInt8() > 0) - { - player_node->pickedUp(itemInfo, 0); - } - else - { - player_node->pickedUp(itemInfo, amount); - - Item *item = inventory->getItem(index); - - if (item && item->getId() == itemId) - amount += inventory->getItem(index)->getQuantity(); - - inventory->setItem(index, itemId, amount, equipType != 0); - } - } break; - - case SMSG_PLAYER_INVENTORY_REMOVE: - index = msg.readInt16() - INVENTORY_OFFSET; - amount = msg.readInt16(); - if (Item *item = inventory->getItem(index)) - { - item->increaseQuantity(-amount); - if (item->getQuantity() == 0) - inventory->removeItemAt(index); - } - break; - - case SMSG_PLAYER_INVENTORY_USE: - index = msg.readInt16() - INVENTORY_OFFSET; - msg.readInt16(); // item id - msg.readInt32(); // id - amount = msg.readInt16(); - msg.readInt8(); // type - - if (Item *item = inventory->getItem(index)) - item->setQuantity(amount); - break; - - case SMSG_ITEM_USE_RESPONSE: - index = msg.readInt16() - INVENTORY_OFFSET; - amount = msg.readInt16(); - - if (msg.readInt8() == 0) - { - localChatTab->chatLog(_("Failed to use item."), BY_SERVER); - } - else - { - if (Item *item = inventory->getItem(index)) - item->setQuantity(amount); - } - break; - - case SMSG_PLAYER_STORAGE_STATUS: - /* - * This is the closest we get to an "Open Storage" packet from the - * server. It always comes after the two SMSG_PLAYER_STORAGE_... - * packets that update storage contents. - */ - { - msg.readInt16(); // Used count - int size = msg.readInt16(); // Max size - - if (!mStorage) - mStorage = new Inventory(Inventory::STORAGE, size); - - InventoryItems::iterator it = mInventoryItems.begin(); - InventoryItems::iterator it_end = mInventoryItems.end(); - for (; it != it_end; it++) - mStorage->setItem((*it).slot, (*it).id, (*it).quantity, - (*it).equip); - mInventoryItems.clear(); - - if (!mStorageWindow) - mStorageWindow = new InventoryWindow(mStorage); - } - break; - - case SMSG_PLAYER_STORAGE_ADD: - // Move an item into storage - index = msg.readInt16() - STORAGE_OFFSET; - amount = msg.readInt32(); - itemId = msg.readInt16(); - identified = msg.readInt8(); - msg.readInt8(); // attribute - msg.readInt8(); // refine - for (int i = 0; i < 4; i++) - cards[i] = msg.readInt16(); - - if (Item *item = mStorage->getItem(index)) - { - item->setId(itemId); - item->increaseQuantity(amount); - } - else - { - mStorage->setItem(index, itemId, amount, false); - } - break; - - case SMSG_PLAYER_STORAGE_REMOVE: - // Move an item out of storage - index = msg.readInt16() - STORAGE_OFFSET; - amount = msg.readInt16(); - if (Item *item = mStorage->getItem(index)) - { - item->increaseQuantity(-amount); - if (item->getQuantity() == 0) - mStorage->removeItemAt(index); - } - break; - - case SMSG_PLAYER_STORAGE_CLOSE: - // Storage access has been closed - - // Storage window deletes itself - mStorageWindow = 0; - - mStorage->clear(); - delete mStorage; - mStorage = 0; - break; - - case SMSG_PLAYER_EQUIPMENT: - msg.readInt16(); // length - number = (msg.getLength() - 4) / 20; - - for (int loop = 0; loop < number; loop++) - { - index = msg.readInt16() - INVENTORY_OFFSET; - itemId = msg.readInt16(); - msg.readInt8(); // type - msg.readInt8(); // identify flag - msg.readInt16(); // equip type - equipType = msg.readInt16(); - msg.readInt8(); // attribute - msg.readInt8(); // refine - msg.skip(8); // card - - inventory->setItem(index, itemId, 1, true); - - if (equipType) - { - mEquips.setEquipment(getSlot(equipType), index); - } - } - break; - - case SMSG_PLAYER_EQUIP: - index = msg.readInt16() - INVENTORY_OFFSET; - equipType = msg.readInt16(); - flag = msg.readInt8(); - - if (!flag) - localChatTab->chatLog(_("Unable to equip."), BY_SERVER); - else - mEquips.setEquipment(getSlot(equipType), index); - break; - - case SMSG_PLAYER_UNEQUIP: - index = msg.readInt16() - INVENTORY_OFFSET; - equipType = msg.readInt16(); - flag = msg.readInt8(); - - if (!flag) - localChatTab->chatLog(_("Unable to unequip."), BY_SERVER); - else - mEquips.setEquipment(getSlot(equipType), -1); - break; - - case SMSG_PLAYER_ATTACK_RANGE: - player_node->setAttackRange(msg.readInt16()); - break; - - case SMSG_PLAYER_ARROW_EQUIP: - index = msg.readInt16(); - - if (index <= 1) - break; - - index -= INVENTORY_OFFSET; - - logger->log("Arrows equipped: %i", index); - mEquips.setEquipment(Equipment::EQUIP_PROJECTILE_SLOT, index); - break; - } -} - -void InventoryHandler::equipItem(const Item *item) -{ - if (!item) - return; - - MessageOut outMsg(CMSG_PLAYER_EQUIP); - outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); - outMsg.writeInt16(0); -} - -void InventoryHandler::unequipItem(const Item *item) -{ - if (!item) - return; - - MessageOut outMsg(CMSG_PLAYER_UNEQUIP); - outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); -} - -void InventoryHandler::useItem(const Item *item) -{ - if (!item) - return; - - MessageOut outMsg(CMSG_PLAYER_INVENTORY_USE); - outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); - outMsg.writeInt32(item->getId()); // unused -} - -void InventoryHandler::dropItem(const Item *item, int amount) -{ - // TODO: Fix wrong coordinates of drops, serverside? (what's wrong here?) - MessageOut outMsg(CMSG_PLAYER_INVENTORY_DROP); - outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); - outMsg.writeInt16(amount); -} - -bool InventoryHandler::canSplit(const Item *item) -{ - return false; -} - -void InventoryHandler::splitItem(const Item *item, int amount) -{ - // Not implemented for eAthena (possible?) -} - -void InventoryHandler::moveItem(int oldIndex, int newIndex) -{ - // Not implemented for eAthena (possible?) -} - -void InventoryHandler::openStorage(int type) -{ - // Doesn't apply to eAthena, since opening happens through NPCs? -} - -void InventoryHandler::closeStorage(int type) -{ - MessageOut outMsg(CMSG_CLOSE_STORAGE); -} - -void InventoryHandler::moveItem(int source, int slot, int amount, - int destination) -{ - if (source == Inventory::INVENTORY && destination == Inventory::STORAGE) - { - MessageOut outMsg(CMSG_MOVE_TO_STORAGE); - outMsg.writeInt16(slot + INVENTORY_OFFSET); - outMsg.writeInt32(amount); - } - else if (source == Inventory::STORAGE && destination == Inventory::INVENTORY) - { - MessageOut outMsg(CSMG_MOVE_FROM_STORAGE); - outMsg.writeInt16(slot + STORAGE_OFFSET); - outMsg.writeInt32(amount); - } -} - -size_t InventoryHandler::getSize(int type) const -{ - switch (type) - { - case Inventory::INVENTORY: - return 100; - case Inventory::STORAGE: - return 0; // Comes from server after items - case Inventory::TRADE: - return 12; - case GUILD_STORAGE: - return 0; // Comes from server after items - default: - return 0; - } -} - -} // namespace EAthena diff --git a/src/net/ea/inventoryhandler.h b/src/net/ea/inventoryhandler.h deleted file mode 100644 index cb127af9..00000000 --- a/src/net/ea/inventoryhandler.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_INVENTORYHANDLER_H -#define NET_EA_INVENTORYHANDLER_H - -#include "equipment.h" -#include "inventory.h" -#include "localplayer.h" - -#include "gui/inventorywindow.h" - -#include "net/inventoryhandler.h" -#include "net/net.h" - -#include "net/ea/messagehandler.h" - -#include - -namespace EAthena { - -class EquipBackend : public Equipment::Backend { - public: - EquipBackend() - { - memset(mEquipment, -1, sizeof(mEquipment)); - } - - Item *getEquipment(int index) const - { - int invyIndex = mEquipment[index]; - if (invyIndex == -1) - { - return NULL; - } - return player_node->getInventory()->getItem(invyIndex); - } - - void clear() - { - for (int i = 0; i < EQUIPMENT_SIZE; i++) - { - if (mEquipment[i] != -1) - { - Item* item = player_node->getInventory()->getItem(i); - if (item) - { - item->setEquipped(false); - } - } - - mEquipment[i] = -1; - } - } - - void setEquipment(int index, int inventoryIndex) - { - // Unequip existing item - Item* item = player_node->getInventory()->getItem(mEquipment[index]); - if (item) - { - item->setEquipped(false); - } - - mEquipment[index] = inventoryIndex; - - item = player_node->getInventory()->getItem(inventoryIndex); - if (item) - { - item->setEquipped(true); - } - } - - private: - int mEquipment[EQUIPMENT_SIZE]; -}; - -/** - * Used to cache storage data until we get size data for it. - */ -class InventoryItem -{ - public: - int slot; - int id; - int quantity; - bool equip; - - InventoryItem(int slot, int id, int quantity, bool equip) - { - this->slot = slot; - this->id = id; - this->quantity = quantity; - this->equip = equip; - } -}; - -typedef std::list InventoryItems; - -class InventoryHandler : public MessageHandler, public Net::InventoryHandler -{ - public: - enum { - GUILD_STORAGE = Inventory::TYPE_END, - CART - }; - - InventoryHandler(); - - ~InventoryHandler(); - - void handleMessage(Net::MessageIn &msg); - - void equipItem(const Item *item); - - void unequipItem(const Item *item); - - void useItem(const Item *item); - - void dropItem(const Item *item, int amount); - - bool canSplit(const Item *item); - - void splitItem(const Item *item, int amount); - - void moveItem(int oldIndex, int newIndex); - - void openStorage(int type); - - void closeStorage(int type); - - void moveItem(int source, int slot, int amount, - int destination); - - size_t getSize(int type) const; - - private: - EquipBackend mEquips; - InventoryItems mInventoryItems; - Inventory *mStorage; - InventoryWindow *mStorageWindow; -}; - -} // namespace EAthena - -#endif // NET_EA_INVENTORYHANDLER_H diff --git a/src/net/ea/itemhandler.cpp b/src/net/ea/itemhandler.cpp deleted file mode 100644 index e3c55c92..00000000 --- a/src/net/ea/itemhandler.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/itemhandler.h" - -#include "flooritemmanager.h" - -#include "net/messagein.h" - -#include "net/ea/protocol.h" - -namespace EAthena { - -ItemHandler::ItemHandler() -{ - static const Uint16 _messages[] = { - SMSG_ITEM_VISIBLE, - SMSG_ITEM_DROPPED, - SMSG_ITEM_REMOVE, - 0 - }; - handledMessages = _messages; -} - -void ItemHandler::handleMessage(Net::MessageIn &msg) -{ - switch (msg.getId()) - { - case SMSG_ITEM_VISIBLE: - case SMSG_ITEM_DROPPED: - { - int id = msg.readInt32(); - int itemId = msg.readInt16(); - msg.readInt8(); // identify flag - int x = msg.readInt16(); - int y = msg.readInt16(); - msg.skip(4); // amount,subX,subY / subX,subY,amount - - floorItemManager->create(id, itemId, x, y); - } - break; - - case SMSG_ITEM_REMOVE: - if (FloorItem *item = floorItemManager->findById(msg.readInt32())) - floorItemManager->destroy(item); - break; - } -} - -} // namespace EAthena diff --git a/src/net/ea/itemhandler.h b/src/net/ea/itemhandler.h deleted file mode 100644 index 7d2bab3d..00000000 --- a/src/net/ea/itemhandler.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_ITEMHANDLER_H -#define NET_EA_ITEMHANDLER_H - -#include "net/ea/messagehandler.h" - -namespace EAthena { - -class ItemHandler : public MessageHandler -{ - public: - ItemHandler(); - - virtual void handleMessage(Net::MessageIn &msg); -}; - -} // namespace EAthena - -#endif // NET_EA_ITEMHANDLER_H diff --git a/src/net/ea/loginhandler.cpp b/src/net/ea/loginhandler.cpp deleted file mode 100644 index 42ba0c61..00000000 --- a/src/net/ea/loginhandler.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/loginhandler.h" - -#include "client.h" -#include "log.h" - -#include "net/logindata.h" -#include "net/messagein.h" -#include "net/messageout.h" - -#include "net/ea/network.h" -#include "net/ea/protocol.h" - -#include "utils/dtor.h" -#include "utils/gettext.h" -#include "utils/stringutils.h" - -extern Net::LoginHandler *loginHandler; - -namespace EAthena { - -extern ServerInfo charServer; - -LoginHandler::LoginHandler(): - mRegistrationEnabled(true) -{ - static const Uint16 _messages[] = { - SMSG_UPDATE_HOST, - SMSG_LOGIN_DATA, - SMSG_LOGIN_ERROR, - SMSG_CHAR_PASSWORD_RESPONSE, - SMSG_SERVER_VERSION_RESPONSE, - 0 - }; - handledMessages = _messages; - loginHandler = this; -} - -LoginHandler::~LoginHandler() -{ - delete_all(mWorlds); -} - -void LoginHandler::handleMessage(Net::MessageIn &msg) -{ - int code, worldCount; - - switch (msg.getId()) - { - case SMSG_CHAR_PASSWORD_RESPONSE: - { - // 0: acc not found, 1: success, 2: password mismatch, 3: pass too short - int errMsg = msg.readInt8(); - // Successful pass change - if (errMsg == 1) - { - Client::setState(STATE_CHANGEPASSWORD_SUCCESS); - } - // pass change failed - else - { - switch (errMsg) - { - case 0: - errorMessage = _("Account was not found. Please re-login."); - break; - case 2: - errorMessage = _("Old password incorrect."); - break; - case 3: - errorMessage = _("New password too short."); - break; - default: - errorMessage = _("Unknown error."); - break; - } - Client::setState(STATE_ACCOUNTCHANGE_ERROR); - } - } - break; - - case SMSG_UPDATE_HOST: - int len; - - len = msg.readInt16() - 4; - mUpdateHost = msg.readString(len); - loginData.updateHost = mUpdateHost; - - logger->log("Received update host \"%s\" from login server.", - mUpdateHost.c_str()); - break; - - case SMSG_LOGIN_DATA: - // Skip the length word - msg.skip(2); - - clearWorlds(); - - worldCount = (msg.getLength() - 47) / 32; - - mToken.session_ID1 = msg.readInt32(); - mToken.account_ID = msg.readInt32(); - mToken.session_ID2 = msg.readInt32(); - msg.skip(30); // unknown - mToken.sex = msg.readInt8() ? GENDER_MALE : GENDER_FEMALE; - - for (int i = 0; i < worldCount; i++) - { - WorldInfo *world = new WorldInfo; - - world->address = msg.readInt32(); - world->port = msg.readInt16(); - world->name = msg.readString(20); - world->online_users = msg.readInt32(); - world->updateHost = mUpdateHost; - msg.skip(2); // unknown - - logger->log("Network: Server: %s (%s:%d)", - world->name.c_str(), - ipToString(world->address), - world->port); - - mWorlds.push_back(world); - } - Client::setState(STATE_WORLD_SELECT); - break; - - case SMSG_LOGIN_ERROR: - code = msg.readInt8(); - logger->log("Login::error code: %i", code); - - switch (code) - { - case 0: - errorMessage = _("Unregistered ID."); - break; - case 1: - errorMessage = _("Wrong password."); - break; - case 2: - errorMessage = _("Account expired."); - break; - case 3: - errorMessage = _("Rejected from server."); - break; - case 4: - errorMessage = _("You have been permanently banned from " - "the game. Please contact the GM team."); - break; - case 6: - errorMessage = strprintf(_("You have been temporarily " - "banned from the game until " - "%s.\nPlease contact the GM " - "team via the forums."), - msg.readString(20).c_str()); - break; - case 9: - errorMessage = _("This user name is already taken."); - break; - default: - errorMessage = _("Unknown error."); - break; - } - Client::setState(STATE_ERROR); - break; - - case SMSG_SERVER_VERSION_RESPONSE: - { - // TODO: verify these! - msg.readInt8(); // -1 - msg.readInt8(); // T - msg.readInt8(); // M - msg.readInt8(); // W - - unsigned int options = msg.readInt32(); - - if (options & 1) - { - // Registeration not allowed - mRegistrationEnabled = false; - } - - //state = STATE_LOGIN; - } - break; - } -} - -void LoginHandler::connect() -{ - mNetwork->connect(mServer); - MessageOut outMsg(CMSG_SERVER_VERSION_REQUEST); -} - -bool LoginHandler::isConnected() -{ - return mNetwork->isConnected(); -} - -void LoginHandler::disconnect() -{ - if (mNetwork->getServer() == mServer) - mNetwork->disconnect(); -} - -bool LoginHandler::isRegistrationEnabled() -{ - return mRegistrationEnabled; -} - -void LoginHandler::getRegistrationDetails() -{ - // Not supported, so move on - Client::setState(STATE_REGISTER); -} - -void LoginHandler::loginAccount(LoginData *loginData) -{ - sendLoginRegister(loginData->username, loginData->password); -} - -void LoginHandler::logout() -{ - // TODO -} - -void LoginHandler::changeEmail(const std::string &email) -{ - // TODO -} - -void LoginHandler::changePassword(const std::string &username, - const std::string &oldPassword, - const std::string &newPassword) -{ - MessageOut outMsg(CMSG_CHAR_PASSWORD_CHANGE); - outMsg.writeString(oldPassword, 24); - outMsg.writeString(newPassword, 24); -} - -void LoginHandler::chooseServer(unsigned int server) -{ - if (server >= mWorlds.size()) - return; - - charServer.clear(); - charServer.hostname = ipToString(mWorlds[server]->address); - charServer.port = mWorlds[server]->port; - - Client::setState(STATE_UPDATE); -} - -void LoginHandler::registerAccount(LoginData *loginData) -{ - std::string username = loginData->username; - username.append((loginData->gender == GENDER_FEMALE) ? "_F" : "_M"); - - sendLoginRegister(username, loginData->password); -} - -void LoginHandler::unregisterAccount(const std::string &username, - const std::string &password) -{ - // TODO -} - -void LoginHandler::sendLoginRegister(const std::string &username, - const std::string &password) -{ - MessageOut outMsg(0x0064); - outMsg.writeInt32(0); // client version - outMsg.writeString(username, 24); - outMsg.writeString(password, 24); - - /* - * eAthena calls the last byte "client version 2", but it isn't used at - * at all. We're retasking it, as a bit mask: - * 0 - can handle the 0x63 "update host" packet - * 1 - defaults to the first char-server (instead of the last) - */ - outMsg.writeInt8(0x03); -} - -Worlds LoginHandler::getWorlds() const -{ - return mWorlds; -} - -void LoginHandler::clearWorlds() -{ - delete_all(mWorlds); - mWorlds.clear(); -} - -} // namespace EAthena diff --git a/src/net/ea/loginhandler.h b/src/net/ea/loginhandler.h deleted file mode 100644 index 1dd4f52c..00000000 --- a/src/net/ea/loginhandler.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_LOGINHANDLER_H -#define NET_EA_LOGINHANDLER_H - -#include "net/loginhandler.h" - -#include "net/ea/messagehandler.h" -#include "net/ea/token.h" - -#include - -struct LoginData; - -namespace EAthena { - -class LoginHandler : public MessageHandler, public Net::LoginHandler -{ - public: - LoginHandler(); - - ~LoginHandler(); - - void handleMessage(Net::MessageIn &msg); - - void connect(); - - bool isConnected(); - - void disconnect(); - - int supportedOptionalActions() const - { return SetGenderOnRegister; } - - bool isRegistrationEnabled(); - - void getRegistrationDetails(); - - unsigned int getMaxPasswordLength() const { return 25; } - - void loginAccount(LoginData *loginData); - - void logout(); - - void changeEmail(const std::string &email); - - void changePassword(const std::string &username, - const std::string &oldPassword, - const std::string &newPassword); - - void chooseServer(unsigned int server); - - void registerAccount(LoginData *loginData); - - void unregisterAccount(const std::string &username, - const std::string &password); - - Worlds getWorlds() const; - void clearWorlds(); - - const Token &getToken() const { return mToken; } - - private: - void sendLoginRegister(const std::string &username, - const std::string &password); - - bool mRegistrationEnabled; - std::string mUpdateHost; - Worlds mWorlds; - Token mToken; -}; - -} // namespace EAthena - -#endif // NET_EA_LOGINHANDLER_H diff --git a/src/net/ea/messagehandler.cpp b/src/net/ea/messagehandler.cpp deleted file mode 100644 index c1fdd3fd..00000000 --- a/src/net/ea/messagehandler.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/messagehandler.h" - -#include "net/ea/network.h" - -#include - -namespace EAthena { - -MessageHandler::MessageHandler() - : mNetwork(NULL) -{ -} - -MessageHandler::~MessageHandler() -{ - if (mNetwork) - mNetwork->unregisterHandler(this); -} - -void MessageHandler::setNetwork(Network *network) -{ - assert(!(network && mNetwork)); - mNetwork = network; -} - -} diff --git a/src/net/ea/messagehandler.h b/src/net/ea/messagehandler.h deleted file mode 100644 index aa4090c5..00000000 --- a/src/net/ea/messagehandler.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_MESSAGEHANDLER_H -#define NET_EA_MESSAGEHANDLER_H - -#include "net/messagehandler.h" -#include "net/messagein.h" - -#include "net/ea/messageout.h" - -#include - -#include - -namespace EAthena { - -class Network; - -/** - * \ingroup Network - */ -class MessageHandler : public Net::MessageHandler -{ - public: - MessageHandler(); - - ~MessageHandler(); - - void setNetwork(Network *network); - - protected: - Network *mNetwork; -}; - -typedef const std::auto_ptr MessageHandlerPtr; - -} - -#endif // NET_EA_MESSAGEHANDLER_H diff --git a/src/net/ea/messagein.cpp b/src/net/ea/messagein.cpp deleted file mode 100644 index f7463677..00000000 --- a/src/net/ea/messagein.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/messagein.h" - -#include -#include - -#define MAKEWORD(low,high) \ - ((unsigned short)(((unsigned char)(low)) | \ - ((unsigned short)((unsigned char)(high))) << 8)) - -namespace EAthena { - -MessageIn::MessageIn(const char *data, unsigned int length): - Net::MessageIn(data, length) -{ - // Read the message ID - mId = readInt16(); -} - -int MessageIn::readInt16() -{ - Sint16 value = -1; - if (mPos + 2 <= mLength) - { -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - Sint16 swap; - memcpy(&swap, mData + mPos, sizeof(Sint16)); - value = SDL_Swap16(swap); -#else - memcpy(&value, mData + mPos, sizeof(Sint16)); -#endif - } - mPos += 2; - return value; -} - -int MessageIn::readInt32() -{ - Sint32 value = -1; - if (mPos + 4 <= mLength) - { -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - Sint32 swap; - memcpy(&swap, mData + mPos, sizeof(Sint32)); - value = SDL_Swap32(swap); -#else - memcpy(&value, mData + mPos, sizeof(Sint32)); -#endif - } - mPos += 4; - return value; -} - -} diff --git a/src/net/ea/messagein.h b/src/net/ea/messagein.h deleted file mode 100644 index 625d1595..00000000 --- a/src/net/ea/messagein.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_MESSAGEIN_H -#define NET_EA_MESSAGEIN_H - -#include "net/messagein.h" - -#include -#include - -namespace EAthena { - -/** - * Used for parsing an incoming message. - * - * \ingroup Network - */ - class MessageIn : public Net::MessageIn -{ - public: - /** - * Constructor. - */ - MessageIn(const char *data, unsigned int length); - - int readInt16(); /**< Reads a short. */ - int readInt32(); /**< Reads a long. */ -}; - -} - -#endif // NET_EA_MESSAGEIN_H diff --git a/src/net/ea/messageout.cpp b/src/net/ea/messageout.cpp deleted file mode 100644 index 844580a9..00000000 --- a/src/net/ea/messageout.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/messageout.h" - -#include "net/ea/network.h" - -#include -#include - -#include -#include - -namespace EAthena { - -MessageOut::MessageOut(short id): - Net::MessageOut(id) -{ - mNetwork = EAthena::Network::instance(); - mData = mNetwork->mOutBuffer + mNetwork->mOutSize; - writeInt16(id); -} - -void MessageOut::expand(size_t bytes) -{ - mNetwork->mOutSize += bytes; -} - -void MessageOut::writeInt16(Sint16 value) -{ - expand(2); -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - Sint16 swap=SDL_Swap16(value); - memcpy(mData + mPos, &swap, sizeof(Sint16)); -#else - memcpy(mData + mPos, &value, sizeof(Sint16)); -#endif - mPos += 2; -} - -void MessageOut::writeInt32(Sint32 value) -{ - expand(4); -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - Sint32 swap=SDL_Swap32(value); - memcpy(mData + mPos, &swap, sizeof(Sint32)); -#else - memcpy(mData + mPos, &value, sizeof(Sint32)); -#endif - mPos += 4; -} - -#define LOBYTE(w) ((unsigned char)(w)) -#define HIBYTE(w) ((unsigned char)(((unsigned short)(w)) >> 8)) - -void MessageOut::writeCoordinates(unsigned short x, unsigned short y, - unsigned char direction) -{ - char *data = mData + mPos; - mNetwork->mOutSize += 3; - mPos += 3; - - short temp; - temp = x; - temp <<= 6; - data[0] = 0; - data[1] = 1; - data[2] = 2; - data[0] = HIBYTE(temp); - data[1] = (unsigned char) temp; - temp = y; - temp <<= 4; - data[1] |= HIBYTE(temp); - data[2] = LOBYTE(temp); - - // Translate direction to eAthena format - switch (direction) - { - case 1: - direction = 0; - break; - case 3: - direction = 1; - break; - case 2: - direction = 2; - break; - case 6: - direction = 3; - break; - case 4: - direction = 4; - break; - case 12: - direction = 5; - break; - case 8: - direction = 6; - break; - case 9: - direction = 7; - break; - default: - // OOPSIE! Impossible or unknown - direction = (unsigned char) -1; - } - data[2] |= direction; -} - -} // namespace EAthena diff --git a/src/net/ea/messageout.h b/src/net/ea/messageout.h deleted file mode 100644 index a418f459..00000000 --- a/src/net/ea/messageout.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_MESSAGEOUT_H -#define NET_EA_MESSAGEOUT_H - -#include "net/messageout.h" - -#include -#include - -namespace EAthena { - -class Network; - -/** - * Used for building an outgoing message. - * - * \ingroup Network - */ -class MessageOut : public Net::MessageOut -{ - public: - /** - * Constructor. - */ - MessageOut(short id); - - void writeInt16(Sint16 value); /**< Writes a short. */ - void writeInt32(Sint32 value); /**< Writes a long. */ - - /** - * Encodes coordinates and direction in 3 bytes. - */ - void writeCoordinates(unsigned short x, unsigned short y, - unsigned char direction); - - private: - void expand(size_t size); - - Network *mNetwork; -}; - -} - -#endif // NET_EA_MESSAGEOUT_H diff --git a/src/net/ea/network.cpp b/src/net/ea/network.cpp deleted file mode 100644 index 0467241f..00000000 --- a/src/net/ea/network.cpp +++ /dev/null @@ -1,478 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/network.h" - -#include "log.h" - -#include "net/messagehandler.h" -#include "net/messagein.h" - -#include "net/ea/protocol.h" - -#include "utils/gettext.h" -#include "utils/stringutils.h" - -#include -#include - -/** Warning: buffers and other variables are shared, - so there can be only one connection active at a time */ - -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, 50, 3, -1, 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, -// #0x2000 - 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, -}; - -const unsigned int BUFFER_SIZE = 65536; - -namespace EAthena { - -int networkThread(void *data) -{ - Network *network = static_cast(data); - - if (!network->realConnect()) - return -1; - - network->receive(); - - return 0; -} - -Network *Network::mInstance = 0; - -Network::Network(): - mSocket(0), - mInBuffer(new char[BUFFER_SIZE]), - mOutBuffer(new char[BUFFER_SIZE]), - mInSize(0), mOutSize(0), - mToSkip(0), - mState(IDLE), - mWorkerThread(0) -{ - SDLNet_Init(); - - mMutex = SDL_CreateMutex(); - mInstance = this; -} - -Network::~Network() -{ - clearHandlers(); - - if (mState != IDLE && mState != NET_ERROR) - disconnect(); - - SDL_DestroyMutex(mMutex); - mInstance = 0; - - delete[] mInBuffer; - delete[] mOutBuffer; - - SDLNet_Quit(); -} - -bool Network::connect(ServerInfo server) -{ - if (mState != IDLE && mState != NET_ERROR) - { - logger->log("Tried to connect an already connected socket!"); - assert(false); - return false; - } - - if (server.hostname.empty()) - { - setError(_("Empty address given to Network::connect()!")); - return false; - } - - logger->log("Network::Connecting to %s:%i", server.hostname.c_str(), - server.port); - - mServer.hostname = server.hostname; - mServer.port = server.port; - - // Reset to sane values - mOutSize = 0; - mInSize = 0; - mToSkip = 0; - - mState = CONNECTING; - mWorkerThread = SDL_CreateThread(networkThread, this); - if (!mWorkerThread) - { - setError("Unable to create network worker thread"); - return false; - } - - return true; -} - -void Network::disconnect() -{ - mState = IDLE; - - if (mWorkerThread) - { - SDL_WaitThread(mWorkerThread, NULL); - mWorkerThread = NULL; - } - - if (mSocket) - { - SDLNet_TCP_Close(mSocket); - mSocket = 0; - } -} - -void Network::registerHandler(MessageHandler *handler) -{ - for (const Uint16 *i = handler->handledMessages; *i; ++i) - { - mMessageHandlers[*i] = handler; - } - - handler->setNetwork(this); -} - -void Network::unregisterHandler(MessageHandler *handler) -{ - for (const Uint16 *i = handler->handledMessages; *i; ++i) - { - mMessageHandlers.erase(*i); - } - - handler->setNetwork(0); -} - -void Network::clearHandlers() -{ - MessageHandlerIterator i; - for (i = mMessageHandlers.begin(); i != mMessageHandlers.end(); ++i) - { - i->second->setNetwork(0); - } - mMessageHandlers.clear(); -} - -void Network::dispatchMessages() -{ - while (messageReady()) - { - MessageIn msg = getNextMessage(); - - MessageHandlerIterator iter = mMessageHandlers.find(msg.getId()); - - if (msg.getLength() == 0) - logger->error("Zero length packet received. Exiting."); - - if (iter != mMessageHandlers.end()) - { - iter->second->handleMessage(msg); - } - else - { - logger->log("Unhandled packet: %x", msg.getId()); - } - - skip(msg.getLength()); - } -} - -void Network::flush() -{ - if (!mOutSize || mState != CONNECTED) - return; - - int ret; - - - SDL_mutexP(mMutex); - ret = SDLNet_TCP_Send(mSocket, mOutBuffer, mOutSize); - if (ret < (int)mOutSize) - { - setError("Error in SDLNet_TCP_Send(): " + - std::string(SDLNet_GetError())); - } - mOutSize = 0; - SDL_mutexV(mMutex); -} - -void Network::skip(int len) -{ - SDL_mutexP(mMutex); - mToSkip += len; - if (!mInSize) - { - SDL_mutexV(mMutex); - return; - } - - if (mInSize >= mToSkip) - { - mInSize -= mToSkip; - memmove(mInBuffer, mInBuffer + mToSkip, mInSize); - mToSkip = 0; - } - else - { - mToSkip -= mInSize; - mInSize = 0; - } - SDL_mutexV(mMutex); -} - -bool Network::messageReady() -{ - int len = -1, msgId; - - SDL_mutexP(mMutex); - if (mInSize >= 2) - { - msgId = readWord(0); - if (msgId == SMSG_SERVER_VERSION_RESPONSE) - len = 10; - else - len = packet_lengths[msgId]; - - if (len == -1 && mInSize > 4) - len = readWord(2); - - } - - bool ret = (mInSize >= static_cast(len)); - SDL_mutexV(mMutex); - - return ret; -} - -MessageIn Network::getNextMessage() -{ - while (!messageReady()) - { - if (mState == NET_ERROR) - break; - } - - SDL_mutexP(mMutex); - int msgId = readWord(0); - int len; - if (msgId == SMSG_SERVER_VERSION_RESPONSE) - len = 10; - else - len = packet_lengths[msgId]; - - if (len == -1) - len = readWord(2); - -#ifdef DEBUG - logger->log("Received packet 0x%x of length %d\n", msgId, len); -#endif - - MessageIn msg(mInBuffer, len); - SDL_mutexV(mMutex); - - return msg; -} - -bool Network::realConnect() -{ - IPaddress ipAddress; - - if (SDLNet_ResolveHost(&ipAddress, mServer.hostname.c_str(), - mServer.port) == -1) - { - std::string errorMessage = _("Unable to resolve host \"") + - mServer.hostname + "\""; - setError(errorMessage); - logger->log("SDLNet_ResolveHost: %s", errorMessage.c_str()); - return false; - } - - mState = CONNECTING; - - mSocket = SDLNet_TCP_Open(&ipAddress); - if (!mSocket) - { - logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); - setError(SDLNet_GetError()); - return false; - } - - logger->log("Network::Started session with %s:%i", - ipToString(ipAddress.host), ipAddress.port); - - mState = CONNECTED; - - return true; -} - -void Network::receive() -{ - SDLNet_SocketSet set; - - if (!(set = SDLNet_AllocSocketSet(1))) - { - setError("Error in SDLNet_AllocSocketSet(): " + - std::string(SDLNet_GetError())); - return; - } - - if (SDLNet_TCP_AddSocket(set, mSocket) == -1) - { - setError("Error in SDLNet_AddSocket(): " + - std::string(SDLNet_GetError())); - } - - while (mState == CONNECTED) - { - // TODO Try to get this to block all the time while still being able - // to escape the loop - int numReady = SDLNet_CheckSockets(set, ((Uint32)500)); - int ret; - switch (numReady) - { - case -1: - logger->log("Error: SDLNet_CheckSockets"); - // FALLTHROUGH - case 0: - break; - - case 1: - // Receive data from the socket - SDL_mutexP(mMutex); - ret = SDLNet_TCP_Recv(mSocket, mInBuffer + mInSize, BUFFER_SIZE - mInSize); - - if (!ret) - { - // We got disconnected - mState = IDLE; - logger->log("Disconnected."); - } - else if (ret < 0) - { - setError(_("Connection to server terminated. ") + - std::string(SDLNet_GetError())); - } - else - { - mInSize += ret; - if (mToSkip) - { - if (mInSize >= mToSkip) - { - mInSize -= mToSkip; - memmove(mInBuffer, mInBuffer + mToSkip, mInSize); - mToSkip = 0; - } - else - { - mToSkip -= mInSize; - mInSize = 0; - } - } - } - SDL_mutexV(mMutex); - break; - - default: - // more than one socket is ready.. - // this should not happen since we only listen once socket. - std::stringstream errorStream; - errorStream << "Error in SDLNet_TCP_Recv(), " << numReady - << " sockets are ready: " << SDLNet_GetError(); - setError(errorStream.str()); - break; - } - } - - if (SDLNet_TCP_DelSocket(set, mSocket) == -1) - { - logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); - } - - SDLNet_FreeSocketSet(set); -} - -Network *Network::instance() -{ - return mInstance; -} - -void Network::setError(const std::string &error) -{ - logger->log("Network error: %s", error.c_str()); - mError = error; - mState = NET_ERROR; -} - -Uint16 Network::readWord(int pos) -{ -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - return SDL_Swap16((*(Uint16*)(mInBuffer+(pos)))); -#else - return (*(Uint16*)(mInBuffer+(pos))); -#endif -} - -} // namespace EAthena diff --git a/src/net/ea/network.h b/src/net/ea/network.h deleted file mode 100644 index 0b391bf0..00000000 --- a/src/net/ea/network.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_NETWORK_H -#define NET_EA_NETWORK_H - -#include "net/serverinfo.h" - -#include "net/ea/messagehandler.h" -#include "net/ea/messagein.h" -#include "net/ea/messageout.h" - -#include -#include - -#include -#include - -/** - * Protocol version, reported to the eAthena char and mapserver who can adjust - * the protocol accordingly. - */ -#define CLIENT_PROTOCOL_VERSION 1 - -namespace EAthena { - -class Network -{ - public: - Network(); - - ~Network(); - - bool connect(ServerInfo server); - - void disconnect(); - - ServerInfo getServer() const - { return mServer; } - - void registerHandler(MessageHandler *handler); - - void unregisterHandler(MessageHandler *handler); - - void clearHandlers(); - - int getState() const { return mState; } - - const std::string &getError() const { return mError; } - - bool isConnected() const { return mState == CONNECTED; } - - int getInSize() const { return mInSize; } - - void skip(int len); - - bool messageReady(); - - MessageIn getNextMessage(); - - void dispatchMessages(); - - void flush(); - - // ERROR replaced by NET_ERROR because already defined in Windows - enum { - IDLE, - CONNECTED, - CONNECTING, - DATA, - NET_ERROR - }; - - protected: - friend int networkThread(void *data); - friend class MessageOut; - - static Network *instance(); - - void setError(const std::string &error); - - Uint16 readWord(int pos); - - bool realConnect(); - - void receive(); - - TCPsocket mSocket; - - ServerInfo mServer; - - char *mInBuffer, *mOutBuffer; - unsigned int mInSize, mOutSize; - - unsigned int mToSkip; - - int mState; - std::string mError; - - SDL_Thread *mWorkerThread; - SDL_mutex *mMutex; - - typedef std::map MessageHandlers; - typedef MessageHandlers::iterator MessageHandlerIterator; - MessageHandlers mMessageHandlers; - - static Network *mInstance; -}; - -} // namespace EAthena - -#endif // NET_EA_NETWORK_H diff --git a/src/net/ea/npchandler.cpp b/src/net/ea/npchandler.cpp deleted file mode 100644 index dfd56cf1..00000000 --- a/src/net/ea/npchandler.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/npchandler.h" - -#include "beingmanager.h" -#include "localplayer.h" -#include "npc.h" - -#include "gui/npcdialog.h" - -#include "net/messagein.h" -#include "net/messageout.h" -#include "net/net.h" -#include "net/npchandler.h" - -#include "net/ea/protocol.h" - -#include - -extern Net::NpcHandler *npcHandler; - -namespace EAthena { - -NpcHandler::NpcHandler() -{ - static const Uint16 _messages[] = { - SMSG_NPC_CHOICE, - SMSG_NPC_MESSAGE, - SMSG_NPC_NEXT, - SMSG_NPC_CLOSE, - SMSG_NPC_INT_INPUT, - SMSG_NPC_STR_INPUT, - 0 - }; - handledMessages = _messages; - npcHandler = this; -} - -void NpcHandler::handleMessage(Net::MessageIn &msg) -{ - if (msg.getId() == SMSG_NPC_CHOICE || msg.getId() == SMSG_NPC_MESSAGE) - { - msg.readInt16(); // length - } - - int npcId = msg.readInt32(); - NpcDialogs::iterator diag = mNpcDialogs.find(npcId); - NpcDialog *dialog = 0; - - if (diag == mNpcDialogs.end()) - { - // Empty dialogs don't help - if (msg.getId() == SMSG_NPC_CLOSE) - { - closeDialog(npcId); - return; - } - else if (msg.getId() == SMSG_NPC_NEXT) - { - nextDialog(npcId); - return; - } - else - { - dialog = new NpcDialog(npcId); - Wrapper wrap; - wrap.dialog = dialog; - mNpcDialogs[npcId] = wrap; - } - } - else - { - dialog = diag->second.dialog; - } - - switch (msg.getId()) - { - case SMSG_NPC_CHOICE: - dialog->choiceRequest(); - dialog->parseListItems(msg.readString(msg.getLength() - 8)); - break; - - case SMSG_NPC_MESSAGE: - dialog->addText(msg.readString(msg.getLength() - 8)); - break; - - case SMSG_NPC_CLOSE: - // Show the close button - dialog->showCloseButton(); - break; - - case SMSG_NPC_NEXT: - // Show the next button - dialog->showNextButton(); - break; - - case SMSG_NPC_INT_INPUT: - // Request for an integer - dialog->integerRequest(0); - break; - - case SMSG_NPC_STR_INPUT: - // Request for a string - dialog->textRequest(""); - break; - } - - if (player_node->getCurrentAction() != Being::SIT) - player_node->setAction(Being::STAND); -} - -void NpcHandler::talk(int npcId) -{ - MessageOut outMsg(CMSG_NPC_TALK); - outMsg.writeInt32(npcId); - outMsg.writeInt8(0); // Unused -} - -void NpcHandler::nextDialog(int npcId) -{ - MessageOut outMsg(CMSG_NPC_NEXT_REQUEST); - outMsg.writeInt32(npcId); -} - -void NpcHandler::closeDialog(int npcId) -{ - MessageOut outMsg(CMSG_NPC_CLOSE); - outMsg.writeInt32(npcId); - - NpcDialogs::iterator it = mNpcDialogs.find(npcId); - if (it != mNpcDialogs.end()) - { - (*it).second.dialog->close(); - mNpcDialogs.erase(it); - } -} - -void NpcHandler::listInput(int npcId, int value) -{ - MessageOut outMsg(CMSG_NPC_LIST_CHOICE); - outMsg.writeInt32(npcId); - outMsg.writeInt8(value); -} - -void NpcHandler::integerInput(int npcId, int value) -{ - MessageOut outMsg(CMSG_NPC_INT_RESPONSE); - outMsg.writeInt32(npcId); - outMsg.writeInt32(value); -} - -void NpcHandler::stringInput(int npcId, const std::string &value) -{ - MessageOut outMsg(CMSG_NPC_STR_RESPONSE); - outMsg.writeInt16(value.length() + 9); - outMsg.writeInt32(npcId); - outMsg.writeString(value, value.length()); - outMsg.writeInt8(0); // Prevent problems with string reading -} - -void NpcHandler::sendLetter(int npcId, const std::string &recipient, - const std::string &text) -{ - // TODO -} - -void NpcHandler::startShopping(int beingId) -{ - // TODO -} - -void NpcHandler::buy(int beingId) -{ - MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST); - outMsg.writeInt32(beingId); - outMsg.writeInt8(0); // Buy -} - -void NpcHandler::sell(int beingId) -{ - MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST); - outMsg.writeInt32(beingId); - outMsg.writeInt8(1); // Sell -} - -void NpcHandler::buyItem(int beingId, int itemId, int amount) -{ - MessageOut outMsg(CMSG_NPC_BUY_REQUEST); - outMsg.writeInt16(8); // One item (length of packet) - outMsg.writeInt16(amount); - outMsg.writeInt16(itemId); -} - -void NpcHandler::sellItem(int beingId, int itemId, int amount) -{ - MessageOut outMsg(CMSG_NPC_SELL_REQUEST); - outMsg.writeInt16(8); // One item (length of packet) - outMsg.writeInt16(itemId + INVENTORY_OFFSET); - outMsg.writeInt16(amount); -} - -void NpcHandler::endShopping(int beingId) -{ - // TODO -} - -} // namespace EAthena diff --git a/src/net/ea/npchandler.h b/src/net/ea/npchandler.h deleted file mode 100644 index f6d8e8a5..00000000 --- a/src/net/ea/npchandler.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_NPCHANDLER_H -#define NET_EA_NPCHANDLER_H - -#include "net/net.h" -#include "net/npchandler.h" - -#include "net/ea/messagehandler.h" - -#include - -class NpcDialog; - -namespace EAthena { - -class NpcHandler : public MessageHandler, public Net::NpcHandler -{ - public: - NpcHandler(); - - void handleMessage(Net::MessageIn &msg); - - void talk(int npcId); - - void nextDialog(int npcId); - - void closeDialog(int npcId); - - void listInput(int npcId, int value); - - void integerInput(int npcId, int value); - - void stringInput(int npcId, const std::string &value); - - void sendLetter(int npcId, const std::string &recipient, - const std::string &text); - - void startShopping(int beingId); - - void buy(int beingId); - - void sell(int beingId); - - void buyItem(int beingId, int itemId, int amount); - - void sellItem(int beingId, int itemId, int amount); - - void endShopping(int beingId); - - private: - typedef struct { - NpcDialog* dialog; - } Wrapper; - typedef std::map NpcDialogs; - NpcDialogs mNpcDialogs; -}; - -} // namespace EAthena - -#endif // NET_EA_NPCHANDLER_H diff --git a/src/net/ea/partyhandler.cpp b/src/net/ea/partyhandler.cpp deleted file mode 100644 index f27318d6..00000000 --- a/src/net/ea/partyhandler.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2008 Lloyd Bryant - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/partyhandler.h" - -#include "beingmanager.h" -#include "localplayer.h" -#include "log.h" - -#include "gui/socialwindow.h" - -#include "net/messagein.h" -#include "net/messageout.h" - -#include "net/ea/protocol.h" - -#include "net/ea/gui/partytab.h" - -#include "utils/gettext.h" -#include "utils/stringutils.h" - -#define PARTY_ID 1 - -extern Net::PartyHandler *partyHandler; - -namespace EAthena { - -PartyTab *partyTab = 0; -Party *eaParty; - -PartyHandler::PartyHandler(): - mShareExp(PARTY_SHARE_UNKNOWN), mShareItems(PARTY_SHARE_UNKNOWN) -{ - static const Uint16 _messages[] = { - SMSG_PARTY_CREATE, - SMSG_PARTY_INFO, - SMSG_PARTY_INVITE_RESPONSE, - SMSG_PARTY_INVITED, - SMSG_PARTY_SETTINGS, - SMSG_PARTY_MOVE, - SMSG_PARTY_LEAVE, - SMSG_PARTY_UPDATE_HP, - SMSG_PARTY_UPDATE_COORDS, - SMSG_PARTY_MESSAGE, - 0 - }; - handledMessages = _messages; - partyHandler = this; - eaParty = Party::getParty(1); -} - -PartyHandler::~PartyHandler() -{ - delete partyTab; - partyTab = 0; -} - -void PartyHandler::handleMessage(Net::MessageIn &msg) -{ - switch (msg.getId()) - { - case SMSG_PARTY_CREATE: - if (msg.readInt8()) - localChatTab->chatLog(_("Could not create party."), BY_SERVER); - else - { - localChatTab->chatLog(_("Party successfully created."), - BY_SERVER); - } - break; - case SMSG_PARTY_INFO: - { - eaParty->clearMembers(); - - int length = msg.readInt16(); - eaParty->setName(msg.readString(24)); - int count = (length - 28) / 46; - - for (int i = 0; i < count; i++) - { - int id = msg.readInt32(); - std::string nick = msg.readString(24); - std::string map = msg.readString(16); - bool leader = msg.readInt8() == 0; - bool online = msg.readInt8() == 0; - - PartyMember *member = eaParty->addMember(id, nick); - member->setLeader(leader); - member->setOnline(online); - } - - player_node->setParty(eaParty); - } - break; - case SMSG_PARTY_INVITE_RESPONSE: - { - if (!partyTab) - break; - - std::string nick = msg.readString(24); - switch (msg.readInt8()) - { - case 0: - partyTab->chatLog(strprintf(_("%s is already a member of a party."), - nick.c_str()), BY_SERVER); - break; - case 1: - partyTab->chatLog(strprintf(_("%s refused your invitation."), - nick.c_str()), BY_SERVER); - break; - case 2: - partyTab->chatLog(strprintf(_("%s is now a member of your party."), - nick.c_str()), BY_SERVER); - break; - default: - partyTab->chatLog(strprintf(_("Unknown invite response for %s."), - nick.c_str()), BY_SERVER); - break; - } - break; - } - case SMSG_PARTY_INVITED: - { - int id = msg.readInt32(); - std::string partyName = msg.readString(24); - std::string nick = ""; - Being *being; - - if (!(being = beingManager->findBeing(id))) - { - if (being->getType() == Being::PLAYER) - { - nick = being->getName(); - } - } - - socialWindow->showPartyInvite(partyName, nick); - break; - } - case SMSG_PARTY_SETTINGS: - { - if (!partyTab) - { - if (!chatWindow) - break; - - partyTab = new PartyTab(); - } - - // These seem to indicate the sharing mode for exp and items - short exp = msg.readInt16(); - short item = msg.readInt16(); - - switch (exp) - { - case PARTY_SHARE: - if (mShareExp == PARTY_SHARE) - break; - mShareExp = PARTY_SHARE; - partyTab->chatLog(_("Experience sharing enabled."), BY_SERVER); - break; - case PARTY_SHARE_NO: - if (mShareExp == PARTY_SHARE_NO) - break; - mShareExp = PARTY_SHARE_NO; - partyTab->chatLog(_("Experience sharing disabled."), BY_SERVER); - break; - case PARTY_SHARE_NOT_POSSIBLE: - if (mShareExp == PARTY_SHARE_NOT_POSSIBLE) - break; - mShareExp = PARTY_SHARE_NOT_POSSIBLE; - partyTab->chatLog(_("Experience sharing not possible."), BY_SERVER); - break; - default: - logger->log("Unknown party exp option: %d\n", exp); - } - - switch (item) - { - case PARTY_SHARE: - if (mShareItems == PARTY_SHARE) - break; - mShareItems = PARTY_SHARE; - partyTab->chatLog(_("Item sharing enabled."), BY_SERVER); - break; - case PARTY_SHARE_NO: - if (mShareItems == PARTY_SHARE_NO) - break; - mShareItems = PARTY_SHARE_NO; - partyTab->chatLog(_("Item sharing disabled."), BY_SERVER); - break; - case PARTY_SHARE_NOT_POSSIBLE: - if (mShareItems == PARTY_SHARE_NOT_POSSIBLE) - break; - mShareItems = PARTY_SHARE_NOT_POSSIBLE; - partyTab->chatLog(_("Item sharing not possible."), BY_SERVER); - break; - default: - logger->log("Unknown party item option: %d\n", exp); - } - break; - } - case SMSG_PARTY_MOVE: - { - msg.readInt32(); // id - msg.skip(4); - msg.readInt16(); // x - msg.readInt16(); // y - msg.readInt8(); // online (if 0) - msg.readString(24); // party - msg.readString(24); // nick - msg.readString(16); // map - } - break; - case SMSG_PARTY_LEAVE: - { - int id = msg.readInt32(); - std::string nick = msg.readString(24); - msg.readInt8(); // fail - if (id == player_node->getId()) - { - eaParty->removeFromMembers(); - eaParty->clearMembers(); - localChatTab->chatLog(_("You have left the party."), - BY_SERVER); - if (partyTab) - { - delete partyTab; - partyTab = 0; - } - socialWindow->removeTab(eaParty); - } - else - { - partyTab->chatLog(strprintf(_("%s has left your party."), - nick.c_str()), BY_SERVER); - - Being *b = beingManager->findBeing(id); - if (b->getType() == Being::PLAYER) - static_cast(b)->setParty(NULL); - - eaParty->removeMember(id); - } - break; - } - case SMSG_PARTY_UPDATE_HP: - { - int id = msg.readInt32(); - int hp = msg.readInt16(); - int maxhp = msg.readInt16(); - PartyMember *m = eaParty->getMember(id); - if (m) - { - m->setHp(hp); - m->setMaxHp(maxhp); - } - - // The server only sends this when the member is in range, so - // lets make sure they get the party hilight. - if (Being *b = beingManager->findBeing(id)) - { - static_cast(b)->setParty(eaParty); - } - } - break; - case SMSG_PARTY_UPDATE_COORDS: - { - msg.readInt32(); // id - msg.readInt16(); // x - msg.readInt16(); // y - } - break; - case SMSG_PARTY_MESSAGE: - { - int msgLength = msg.readInt16() - 8; - if (msgLength <= 0) - { - return; - } - int id = msg.readInt32(); - std::string chatMsg = msg.readString(msgLength); - - PartyMember *member = eaParty->getMember(id); - if (member) - partyTab->chatLog(member->getName(), chatMsg); - else - partyTab->chatLog(strprintf(_("An unknown member tried to " - "say: %s"), chatMsg.c_str()), BY_SERVER); - } - break; - } -} - -void PartyHandler::create(const std::string &name) -{ - MessageOut outMsg(CMSG_PARTY_CREATE); - outMsg.writeString(name.substr(0, 23), 24); -} - -void PartyHandler::join(int partyId) -{ - // TODO? -} - -void PartyHandler::invite(Player *player) -{ - MessageOut outMsg(CMSG_PARTY_INVITE); - outMsg.writeInt32(player->getId()); -} - -void PartyHandler::invite(const std::string &name) -{ - if (partyTab) - { - partyTab->chatLog(_("Inviting like this isn't supported at the moment."), - BY_SERVER); - } - else - { - localChatTab->chatLog(_("You can only inivte when you are in a party!"), - BY_SERVER); - } - - // TODO? -} - -void PartyHandler::inviteResponse(const std::string &inviter, bool accept) -{ - MessageOut outMsg(CMSG_PARTY_INVITED); - outMsg.writeInt32(player_node->getId()); - outMsg.writeInt32(accept ? 1 : 0); -} - -void PartyHandler::leave() -{ - MessageOut outMsg(CMSG_PARTY_LEAVE); -} - -void PartyHandler::kick(Player *player) -{ - MessageOut outMsg(CMSG_PARTY_KICK); - outMsg.writeInt32(player->getId()); - outMsg.writeString("", 24); //Unused -} - -void PartyHandler::kick(const std::string &name) -{ - PartyMember *m = eaParty->getMember(name); - if (!m) - { - partyTab->chatLog(strprintf(_("%s is not in your party!"), name.c_str()), - BY_SERVER); - return; - } - - MessageOut outMsg(CMSG_PARTY_KICK); - outMsg.writeInt32(m->getID()); - outMsg.writeString(name, 24); //Unused -} - -void PartyHandler::chat(const std::string &text) -{ - MessageOut outMsg(CMSG_PARTY_MESSAGE); - outMsg.writeInt16(text.length() + 4); - outMsg.writeString(text, text.length()); -} - -void PartyHandler::requestPartyMembers() -{ - // Our eAthena doesn't have this message - // Not needed anyways -} - -void PartyHandler::setShareExperience(PartyShare share) -{ - if (share == PARTY_SHARE_NOT_POSSIBLE) - return; - - MessageOut outMsg(CMSG_PARTY_SETTINGS); - outMsg.writeInt16(share); - outMsg.writeInt16(mShareItems); -} - -void PartyHandler::setShareItems(PartyShare share) -{ - if (share == PARTY_SHARE_NOT_POSSIBLE) - return; - - MessageOut outMsg(CMSG_PARTY_SETTINGS); - outMsg.writeInt16(mShareExp); - outMsg.writeInt16(share); -} - -} // namespace EAthena diff --git a/src/net/ea/partyhandler.h b/src/net/ea/partyhandler.h deleted file mode 100644 index 09f05bb3..00000000 --- a/src/net/ea/partyhandler.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2008 Lloyd Bryant - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_PARTYHANDLER_H -#define NET_EA_PARTYHANDLER_H - -#include "net/net.h" -#include "net/partyhandler.h" - -#include "net/ea/messagehandler.h" - -#include "party.h" - -namespace EAthena { - -class PartyHandler : public MessageHandler, public Net::PartyHandler -{ - public: - PartyHandler(); - - ~PartyHandler(); - - void handleMessage(Net::MessageIn &msg); - - void create(const std::string &name = ""); - - void join(int partyId); - - void invite(Player *player); - - void invite(const std::string &name); - - void inviteResponse(const std::string &inviter, bool accept); - - void leave(); - - void kick(Player *player); - - void kick(const std::string &name); - - void chat(const std::string &text); - - void requestPartyMembers(); - - PartyShare getShareExperience() { return mShareExp; } - - void setShareExperience(PartyShare share); - - PartyShare getShareItems() { return mShareItems; } - - void setShareItems(PartyShare share); - - private: - PartyShare mShareExp, mShareItems; -}; - -} // namespace EAthena - -#endif // NET_EA_PARTYHANDLER_H diff --git a/src/net/ea/playerhandler.cpp b/src/net/ea/playerhandler.cpp deleted file mode 100644 index 6aeb5168..00000000 --- a/src/net/ea/playerhandler.cpp +++ /dev/null @@ -1,652 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/playerhandler.h" - -#include "game.h" -#include "localplayer.h" -#include "log.h" -#include "npc.h" -#include "units.h" - -#include "gui/buy.h" -#include "gui/buysell.h" -#include "gui/gui.h" -#include "gui/npcdialog.h" -#include "gui/okdialog.h" -#include "gui/sell.h" -#include "gui/statuswindow.h" -#include "gui/viewport.h" - -#include "gui/widgets/chattab.h" - -#include "net/messagein.h" -#include "net/messageout.h" - -#include "net/ea/protocol.h" - -#include "utils/stringutils.h" -#include "utils/gettext.h" - -extern OkDialog *weightNotice; -extern OkDialog *deathNotice; - -// Max. distance we are willing to scroll after a teleport; -// everything beyond will reset the port hard. -static const int MAP_TELEPORT_SCROLL_DISTANCE = 8; - -#define ATTR_BONUS(atr) \ -(player_node->getAttributeEffective(atr) - player_node->getAttributeBase(atr)) - -// TODO Move somewhere else -namespace { - - /** - * Listener used for handling the overweigth message. - */ - struct WeightListener : public gcn::ActionListener - { - void action(const gcn::ActionEvent &event) - { - weightNotice = NULL; - } - } weightListener; - - /** - * Listener used for handling death message. - */ - struct DeathListener : public gcn::ActionListener - { - void action(const gcn::ActionEvent &event) - { - Net::getPlayerHandler()->respawn(); - deathNotice = NULL; - - BuyDialog::closeAll(); - BuySellDialog::closeAll(); - NpcDialog::closeAll(); - SellDialog::closeAll(); - - viewport->closePopupMenu(); - } - } deathListener; - -} // anonymous namespace - -static const char *randomDeathMessage() -{ - static char const *const deadMsg[] = - { - N_("You are dead."), - N_("We regret to inform you that your character was killed in " - "battle."), - N_("You are not that alive anymore."), - N_("The cold hands of the grim reaper are grabbing for your soul."), - N_("Game Over!"), - N_("Insert coin to continue."), - N_("No, kids. Your character did not really die. It... " - "err... went to a better place."), - N_("Your plan of breaking your enemies weapon by " - "bashing it with your throat failed."), - N_("I guess this did not run too well."), - // NetHack reference: - N_("Do you want your possessions identified?"), - // Secret of Mana reference: - N_("Sadly, no trace of you was ever found..."), - // Final Fantasy VI reference: - N_("Annihilated."), - // Earthbound reference: - N_("Looks like you got your head handed to you."), - // Leisure Suit Larry 1 reference: - N_("You screwed up again, dump your body down the tubes " - "and get you another one."), - // Monty Python references (Dead Parrot sketch mostly): - N_("You're not dead yet. You're just resting."), - N_("You are no more."), - N_("You have ceased to be."), - N_("You've expired and gone to meet your maker."), - N_("You're a stiff."), - N_("Bereft of life, you rest in peace."), - N_("If you weren't so animated, you'd be pushing up the daisies."), - N_("Your metabolic processes are now history."), - N_("You're off the twig."), - N_("You've kicked the bucket."), - N_("You've shuffled off your mortal coil, run down the " - "curtain and joined the bleedin' choir invisibile."), - N_("You are an ex-player."), - N_("You're pining for the fjords.") - }; - - const int random = rand() % (sizeof(deadMsg) / sizeof(deadMsg[0])); - return gettext(deadMsg[random]); -} - -extern Net::PlayerHandler *playerHandler; - -namespace EAthena { - -PlayerHandler::PlayerHandler() -{ - static const Uint16 _messages[] = { - SMSG_WALK_RESPONSE, - SMSG_PLAYER_WARP, - SMSG_PLAYER_STAT_UPDATE_1, - SMSG_PLAYER_STAT_UPDATE_2, - SMSG_PLAYER_STAT_UPDATE_3, - SMSG_PLAYER_STAT_UPDATE_4, - SMSG_PLAYER_STAT_UPDATE_5, - SMSG_PLAYER_STAT_UPDATE_6, - SMSG_PLAYER_ARROW_MESSAGE, - 0 - }; - handledMessages = _messages; - playerHandler = this; -} - -void PlayerHandler::handleMessage(Net::MessageIn &msg) -{ - switch (msg.getId()) - { - case SMSG_WALK_RESPONSE: - /* - * This client assumes that all walk messages succeed, - * and that the server will send a correction notice - * otherwise. - */ - break; - - case SMSG_PLAYER_WARP: - { - std::string mapPath = msg.readString(16); - int x = msg.readInt16(); - int y = msg.readInt16(); - - logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y); - - /* - * We must clear the local player's target *before* the call - * to changeMap, as it deletes all beings. - */ - player_node->stopAttack(); - - Game *game = Game::instance(); - - const std::string ¤tMapName = game->getCurrentMapName(); - bool sameMap = (currentMapName == mapPath); - - // Switch the actual map, deleting the previous one if necessary - mapPath = mapPath.substr(0, mapPath.rfind(".")); - game->changeMap(mapPath); - - float scrollOffsetX = 0.0f; - float scrollOffsetY = 0.0f; - - /* Scroll if neccessary */ - if (!sameMap - || (abs(x - player_node->getTileX()) > MAP_TELEPORT_SCROLL_DISTANCE) - || (abs(y - player_node->getTileY()) > MAP_TELEPORT_SCROLL_DISTANCE)) - { - Map *map = game->getCurrentMap(); - scrollOffsetX = (x - player_node->getTileX()) - * map->getTileWidth(); - scrollOffsetY = (y - player_node->getTileY()) - * map->getTileHeight(); - } - - player_node->setAction(Being::STAND); - player_node->setFrame(0); - player_node->setTileCoords(x, y); - - logger->log("Adjust scrolling by %d:%d", (int) scrollOffsetX, - (int) scrollOffsetY); - - viewport->scrollBy(scrollOffsetX, scrollOffsetY); - } - break; - - case SMSG_PLAYER_STAT_UPDATE_1: - { - int type = msg.readInt16(); - int value = msg.readInt32(); - - switch (type) - { - case 0x0000: - player_node->setWalkSpeed(Vector(value, value, 0)); - break; - case 0x0004: break; // manner - case 0x0005: player_node->setHp(value); break; - case 0x0006: player_node->setMaxHp(value); break; - case 0x0007: player_node->setMP(value); break; - case 0x0008: player_node->setMaxMP(value); break; - case 0x0009: player_node->setCharacterPoints(value); break; - case 0x000b: player_node->setLevel(value); break; - case 0x000c: player_node->setSkillPoints(value); break; - case 0x0018: - if (value >= player_node->getMaxWeight() / 2 && - player_node->getTotalWeight() < - player_node->getMaxWeight() / 2) - { - weightNotice = new OkDialog(_("Message"), - _("You are carrying more than " - "half your weight. You are " - "unable to regain health.")); - weightNotice->addActionListener( - &weightListener); - } - player_node->setTotalWeight(value); - break; - case 0x0019: player_node->setMaxWeight(value); break; - - case 0x0029: player_node->setAttributeEffective(ATK, value - + ATTR_BONUS(ATK)); - player_node->setAttributeBase(ATK, value); - break; - case 0x002a: value += player_node->getAttributeBase(ATK); - player_node->setAttributeEffective(ATK, value); break; - - case 0x002b: player_node->setAttributeEffective(MATK, value - + ATTR_BONUS(MATK)); - player_node->setAttributeBase(MATK, value); - if (statusWindow) - statusWindow->update(StatusWindow::MP); - break; - case 0x002c: value += player_node->getAttributeBase(MATK); - player_node->setAttributeEffective(MATK, value); - if (statusWindow) - statusWindow->update(StatusWindow::MP); - break; - case 0x002d: player_node->setAttributeEffective(DEF, value - + ATTR_BONUS(DEF)); - player_node->setAttributeBase(DEF, value); break; - case 0x002e: value += player_node->getAttributeBase(DEF); - player_node->setAttributeEffective(DEF, value); break; - - case 0x002f: player_node->setAttributeEffective(MDEF, value - + ATTR_BONUS(MDEF)); - player_node->setAttributeBase(MDEF, value); break; - case 0x0030: value += player_node->getAttributeBase(MDEF); - player_node->setAttributeEffective(MDEF, value); break; - - case 0x0031: player_node->setAttributeBase(HIT, value); - player_node->setAttributeEffective(HIT, value); break; - - case 0x0032: player_node->setAttributeEffective(FLEE, value - + ATTR_BONUS(FLEE)); - player_node->setAttributeBase(FLEE, value); break; - case 0x0033: value += player_node->getAttributeBase(FLEE); - player_node->setAttributeEffective(FLEE, value); break; - - case 0x0034: player_node->setAttributeBase(CRIT, value); - player_node->setAttributeEffective(CRIT, value); break; - - case 0x0035: player_node->setAttackSpeed(value); break; - case 0x0037: player_node->setAttributeBase(JOB, value); - player_node->setAttributeEffective(JOB, value); break; - case 500: player_node->setGMLevel(value); break; - } - - if (player_node->getHp() == 0 && !deathNotice) - { - deathNotice = new OkDialog(_("Message"), - randomDeathMessage(), - false); - deathNotice->addActionListener(&deathListener); - player_node->setAction(Being::DEAD); - } - } - break; - - case SMSG_PLAYER_STAT_UPDATE_2: - switch (msg.readInt16()) - { - case 0x0001: - player_node->setExp(msg.readInt32()); - break; - case 0x0002: - player_node->setExperience(JOB, msg.readInt32(), - player_node->getExperience(JOB).second); - break; - case 0x0014: { - int curGp = player_node->getMoney(); - player_node->setMoney(msg.readInt32()); - if (player_node->getMoney() > curGp) - localChatTab->chatLog(strprintf(_("You picked up " - "%s."), - Units::formatCurrency(player_node->getMoney() - - curGp).c_str()), BY_SERVER); - } - break; - case 0x0016: - player_node->setExpNeeded(msg.readInt32()); - break; - case 0x0017: - player_node->setExperience(JOB, - player_node->getExperience(JOB).first, - msg.readInt32()); - break; - } - break; - - case SMSG_PLAYER_STAT_UPDATE_3: // Update a base attribute - { - int type = msg.readInt32(); - int base = msg.readInt32(); - int bonus = msg.readInt32(); - - player_node->setAttributeBase(type, base); - player_node->setAttributeEffective(type, base + bonus); - } - break; - - case SMSG_PLAYER_STAT_UPDATE_4: // Attribute increase ack - { - int type = msg.readInt16(); - int ok = msg.readInt8(); - int value = msg.readInt8(); - - if (ok != 1) - { - localChatTab->chatLog(_("Cannot raise skill!"), - BY_SERVER); - } - - int bonus = ATTR_BONUS(type); - - player_node->setAttributeBase(type, value); - player_node->setAttributeEffective(type, value + bonus); - } - break; - - // Updates stats and status points - case SMSG_PLAYER_STAT_UPDATE_5: - player_node->setCharacterPoints(msg.readInt16()); - - { - int val = msg.readInt8(); - player_node->setAttributeEffective(STR, val + ATTR_BONUS(STR)); - player_node->setAttributeBase(STR, val); - if (val >= 99) - { - statusWindow->setPointsNeeded(STR, 0); - msg.readInt8(); - } - else - { - statusWindow->setPointsNeeded(STR, msg.readInt8()); - } - - val = msg.readInt8(); - player_node->setAttributeEffective(AGI, val + ATTR_BONUS(AGI)); - player_node->setAttributeBase(AGI, val); - if (val >= 99) - { - statusWindow->setPointsNeeded(AGI, 0); - msg.readInt8(); - } - else - { - statusWindow->setPointsNeeded(AGI, msg.readInt8()); - } - - val = msg.readInt8(); - player_node->setAttributeEffective(VIT, val + ATTR_BONUS(VIT)); - player_node->setAttributeBase(VIT, val); - if (val >= 99) - { - statusWindow->setPointsNeeded(VIT, 0); - msg.readInt8(); - } - else - { - statusWindow->setPointsNeeded(VIT, msg.readInt8()); - } - - val = msg.readInt8(); - player_node->setAttributeEffective(INT, val + ATTR_BONUS(INT)); - player_node->setAttributeBase(INT, val); - if (val >= 99) - { - statusWindow->setPointsNeeded(INT, 0); - msg.readInt8(); - } - else - { - statusWindow->setPointsNeeded(INT, msg.readInt8()); - } - - val = msg.readInt8(); - player_node->setAttributeEffective(DEX, val + ATTR_BONUS(DEX)); - player_node->setAttributeBase(DEX, val); - if (val >= 99) - { - statusWindow->setPointsNeeded(DEX, 0); - msg.readInt8(); - } - else - { - statusWindow->setPointsNeeded(DEX, msg.readInt8()); - } - - val = msg.readInt8(); - player_node->setAttributeEffective(LUK, val + ATTR_BONUS(LUK)); - player_node->setAttributeBase(LUK, val); - if (val >= 99) - { - statusWindow->setPointsNeeded(LUK, 0); - msg.readInt8(); - } - else - { - statusWindow->setPointsNeeded(LUK, msg.readInt8()); - } - - val = msg.readInt16(); // ATK - player_node->setAttributeBase(ATK, val); - val += msg.readInt16(); // ATK bonus - player_node->setAttributeEffective(ATK, val); - - val = msg.readInt16(); // MATK - player_node->setAttributeBase(MATK, val); - val += msg.readInt16(); // MATK bonus - player_node->setAttributeEffective(MATK, val); - statusWindow->update(StatusWindow::MP); - - val = msg.readInt16(); // DEF - player_node->setAttributeBase(DEF, val); - val += msg.readInt16(); // DEF bonus - player_node->setAttributeEffective(DEF, val); - - val = msg.readInt16(); // MDEF - player_node->setAttributeBase(MDEF, val); - val += msg.readInt16(); // MDEF bonus - player_node->setAttributeEffective(MDEF, val); - - val = msg.readInt16(); // HIT - player_node->setAttributeBase(HIT, val); - player_node->setAttributeEffective(HIT, val); - - val = msg.readInt16(); // FLEE - player_node->setAttributeBase(FLEE, val); - val += msg.readInt16(); // FLEE bonus - player_node->setAttributeEffective(FLEE, val); - - val = msg.readInt16(); - player_node->setAttributeBase(CRIT, val); - player_node->setAttributeEffective(CRIT, val); - } - - msg.readInt16(); // manner - break; - - case SMSG_PLAYER_STAT_UPDATE_6: - switch (msg.readInt16()) - { - case 0x0020: - statusWindow->setPointsNeeded(STR, msg.readInt8()); - break; - case 0x0021: - statusWindow->setPointsNeeded(AGI, msg.readInt8()); - break; - case 0x0022: - statusWindow->setPointsNeeded(VIT, msg.readInt8()); - break; - case 0x0023: - statusWindow->setPointsNeeded(INT, msg.readInt8()); - break; - case 0x0024: - statusWindow->setPointsNeeded(DEX, msg.readInt8()); - break; - case 0x0025: - statusWindow->setPointsNeeded(LUK, msg.readInt8()); - break; - } - break; - - case SMSG_PLAYER_ARROW_MESSAGE: - { - int type = msg.readInt16(); - - switch (type) - { - case 0: - localChatTab->chatLog(_("Equip arrows first."), - BY_SERVER); - break; - default: - logger->log("0x013b: Unhandled message %i", type); - break; - } - } - break; - } -} - -void PlayerHandler::attack(int id) -{ - MessageOut outMsg(CMSG_PLAYER_ATTACK); - outMsg.writeInt32(id); - outMsg.writeInt8(0); -} - -void PlayerHandler::emote(int emoteId) -{ - MessageOut outMsg(CMSG_PLAYER_EMOTE); - outMsg.writeInt8(emoteId); -} - -void PlayerHandler::increaseAttribute(int attr) -{ - if (attr >= STR && attr <= LUK) - { - MessageOut outMsg(CMSG_STAT_UPDATE_REQUEST); - outMsg.writeInt16(attr); - outMsg.writeInt8(1); - } -} - -void PlayerHandler::decreaseAttribute(int attr) -{ - // Supported by eA? -} - -void PlayerHandler::increaseSkill(int skillId) -{ - if (player_node->getSkillPoints() <= 0) - return; - - MessageOut outMsg(CMSG_SKILL_LEVELUP_REQUEST); - outMsg.writeInt16(skillId); -} - -void PlayerHandler::pickUp(FloorItem *floorItem) -{ - MessageOut outMsg(CMSG_ITEM_PICKUP); - outMsg.writeInt32(floorItem->getId()); -} - -void PlayerHandler::setDirection(char direction) -{ - MessageOut outMsg(CMSG_PLAYER_CHANGE_DIR); - outMsg.writeInt16(0); - outMsg.writeInt8(direction); -} - -void PlayerHandler::setDestination(int x, int y, int direction) -{ - MessageOut outMsg(CMSG_PLAYER_CHANGE_DEST); - outMsg.writeCoordinates(x, y, direction); -} - -void PlayerHandler::changeAction(Being::Action action) -{ - char type; - switch (action) - { - case Being::SIT: type = 2; break; - case Being::STAND: type = 3; break; - default: return; - } - - MessageOut outMsg(CMSG_PLAYER_CHANGE_ACT); - outMsg.writeInt32(0); - outMsg.writeInt8(type); -} - -void PlayerHandler::respawn() -{ - MessageOut outMsg(CMSG_PLAYER_RESTART); - outMsg.writeInt8(0); -} - -void PlayerHandler::ignorePlayer(const std::string &player, bool ignore) -{ - // TODO -} - -void PlayerHandler::ignoreAll(bool ignore) -{ - // TODO -} - -bool PlayerHandler::canUseMagic() -{ - return player_node->getAttributeEffective(MATK) > 0; -} - -bool PlayerHandler::canCorrectAttributes() -{ - return false; -} - -int PlayerHandler::getJobLocation() -{ - return JOB; -} - -Vector PlayerHandler::getDefaultWalkSpeed() -{ - // Return an normalized speed for any side - // as the offset is calculated elsewhere. - return Vector(150, 150, 0); -} - -} // namespace EAthena diff --git a/src/net/ea/playerhandler.h b/src/net/ea/playerhandler.h deleted file mode 100644 index d963c812..00000000 --- a/src/net/ea/playerhandler.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_PLAYERHANDLER_H -#define NET_EA_PLAYERHANDLER_H - -#include "net/net.h" -#include "net/playerhandler.h" - -#include "net/ea/messagehandler.h" - -namespace EAthena { - -class PlayerHandler : public MessageHandler, public Net::PlayerHandler -{ - public: - PlayerHandler(); - - void handleMessage(Net::MessageIn &msg); - - void attack(int id); - void emote(int emoteId); - - void increaseAttribute(int attr); - void decreaseAttribute(int attr); - void increaseSkill(int skillId); - - void pickUp(FloorItem *floorItem); - void setDirection(char direction); - void setDestination(int x, int y, int direction = -1); - void changeAction(Being::Action action); - - void respawn(); - - void ignorePlayer(const std::string &player, bool ignore); - void ignoreAll(bool ignore); - - bool canUseMagic(); - bool canCorrectAttributes(); - - int getJobLocation(); - - Vector getDefaultWalkSpeed(); -}; - -} // namespace EAthena - -#endif // NET_EA_PLAYERHANDLER_H diff --git a/src/net/ea/protocol.h b/src/net/ea/protocol.h deleted file mode 100644 index 2d9c13c3..00000000 --- a/src/net/ea/protocol.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef EA_PROTOCOL_H -#define EA_PROTOCOL_H - -enum { - JOB = 0xa, - - STR = 0xd, - AGI, - VIT, - INT, - DEX, - LUK, - - ATK, - DEF, - MATK, - MDEF, - HIT, - FLEE, - CRIT -}; - -enum -{ - SPRITE_BASE = 0, - SPRITE_SHOE, - SPRITE_BOTTOMCLOTHES, - SPRITE_TOPCLOTHES, - SPRITE_MISC1, - SPRITE_MISC2, - SPRITE_HAIR, - SPRITE_HAT, - SPRITE_CAPE, - SPRITE_GLOVES, - SPRITE_WEAPON, - SPRITE_SHIELD, - SPRITE_VECTOREND -}; - -static const int INVENTORY_OFFSET = 2; -static const int STORAGE_OFFSET = 1; - -/********************************* - * Packets from server to client * - *********************************/ -#define SMSG_SERVER_VERSION_RESPONSE 0x7531 - -#define SMSG_SERVER_PING 0x007f /**< Contains server tick */ -#define SMSG_CONNECTION_PROBLEM 0x0081 - -#define SMSG_UPDATE_HOST 0x0063 /**< Custom update host packet */ -#define SMSG_LOGIN_DATA 0x0069 -#define SMSG_LOGIN_ERROR 0x006a - -#define SMSG_CHAR_LOGIN 0x006b -#define SMSG_CHAR_LOGIN_ERROR 0x006c -#define SMSG_CHAR_CREATE_SUCCEEDED 0x006d -#define SMSG_CHAR_CREATE_FAILED 0x006e -#define SMSG_CHAR_DELETE_SUCCEEDED 0x006f -#define SMSG_CHAR_DELETE_FAILED 0x0070 -#define SMSG_CHAR_MAP_INFO 0x0071 -#define SMSG_CHAR_PASSWORD_RESPONSE 0x0062 /**< Custom packet reply to password change request */ - -#define SMSG_CHAR_SWITCH_RESPONSE 0x00b3 -#define SMSG_CHANGE_MAP_SERVER 0x0092 - -#define SMSG_MAP_LOGIN_SUCCESS 0x0073 /**< Contains starting location */ -#define SMSG_MAP_QUIT_RESPONSE 0x018b -#define SMSG_PLAYER_UPDATE_1 0x01d8 -#define SMSG_PLAYER_UPDATE_2 0x01d9 -#define SMSG_PLAYER_MOVE 0x01da /**< A nearby player moves */ -#define SMSG_PLAYER_STOP 0x0088 /**< Stop walking, set position */ -#define SMSG_PLAYER_MOVE_TO_ATTACK 0x0139 /**< Move to within attack range */ -#define SMSG_PLAYER_STAT_UPDATE_1 0x00b0 -#define SMSG_PLAYER_STAT_UPDATE_2 0x00b1 -#define SMSG_PLAYER_STAT_UPDATE_3 0x0141 -#define SMSG_PLAYER_STAT_UPDATE_4 0x00bc -#define SMSG_PLAYER_STAT_UPDATE_5 0x00bd -#define SMSG_PLAYER_STAT_UPDATE_6 0x00be -#define SMSG_WHO_ANSWER 0x00c2 -#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_ATTACK_RANGE 0x013a -#define SMSG_PLAYER_ARROW_EQUIP 0x013c -#define SMSG_PLAYER_ARROW_MESSAGE 0x013b -#define SMSG_PLAYER_SKILLS 0x010f -#define SMSG_PLAYER_SKILL_UP 0x010e -#define SMSG_SKILL_FAILED 0x0110 -#define SMSG_SKILL_DAMAGE 0x01de -#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_SPAWN 0x007c /**< A being spawns nearby */ -#define SMSG_BEING_MOVE2 0x0086 /**< New eAthena being moves */ -#define SMSG_BEING_REMOVE 0x0080 -#define SMSG_BEING_CHANGE_LOOKS 0x00c3 -#define SMSG_BEING_CHANGE_LOOKS2 0x01d7 /**< Same as 0x00c3, but 16 bit ID */ -#define SMSG_BEING_SELFEFFECT 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_BEING_CHANGE_DIRECTION 0x009c -#define SMSG_BEING_RESURRECT 0x0148 - -#define SMSG_PLAYER_STATUS_CHANGE 0x0119 -#define SMSG_PLAYER_GUILD_PARTY_INFO 0x0195 -#define SMSG_BEING_STATUS_CHANGE 0x0196 - -#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_NPC_INT_INPUT 0x0142 /**< Integer input */ -#define SMSG_NPC_STR_INPUT 0x01d4 /**< String input */ -#define SMSG_PLAYER_CHAT 0x008e /**< Player talks */ -#define SMSG_WHISPER 0x0097 /**< Whisper Recieved */ -#define SMSG_WHISPER_RESPONSE 0x0098 -#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 - -#define SMSG_PARTY_CREATE 0x00fa -#define SMSG_PARTY_INFO 0x00fb -#define SMSG_PARTY_INVITE_RESPONSE 0x00fd -#define SMSG_PARTY_INVITED 0x00fe -#define SMSG_PARTY_SETTINGS 0x0101 -#define SMSG_PARTY_MOVE 0x0104 -#define SMSG_PARTY_LEAVE 0x0105 -#define SMSG_PARTY_UPDATE_HP 0x0106 -#define SMSG_PARTY_UPDATE_COORDS 0x0107 -#define SMSG_PARTY_MESSAGE 0x0109 - -#define SMSG_PLAYER_STORAGE_ITEMS 0x01f0 /**< Item list for storage */ -#define SMSG_PLAYER_STORAGE_EQUIP 0x00a6 /**< Equipment list for storage */ -#define SMSG_PLAYER_STORAGE_STATUS 0x00f2 /**< Slots used and total slots */ -#define SMSG_PLAYER_STORAGE_ADD 0x00f4 /**< Add item/equip to storage */ -#define SMSG_PLAYER_STORAGE_REMOVE 0x00f6 /**< Remove item/equip from storage */ -#define SMSG_PLAYER_STORAGE_CLOSE 0x00f8 /**< Storage access closed */ - -#define SMSG_ADMIN_KICK_ACK 0x00cd - -#define SMSG_GUILD_CREATE_RESPONSE 0x0167 -#define SMSG_GUILD_POSITION_INFO 0x016c -#define SMSG_GUILD_MEMBER_LOGIN 0x016d -#define SMSG_GUILD_MASTER_OR_MEMBER 0x014e -#define SMSG_GUILD_BASIC_INFO 0x01b6 -#define SMSG_GUILD_ALIANCE_INFO 0x014c -#define SMSG_GUILD_MEMBER_LIST 0x0154 -#define SMSG_GUILD_POS_NAME_LIST 0x0166 -#define SMSG_GUILD_POS_INFO_LIST 0x0160 -#define SMSG_GUILD_POSITION_CHANGED 0x0174 -#define SMSG_GUILD_MEMBER_POS_CHANGE 0x0156 -#define SMSG_GUILD_EMBLEM 0x0152 -#define SMSG_GUILD_SKILL_INFO 0x0162 -#define SMSG_GUILD_NOTICE 0x016f -#define SMSG_GUILD_INVITE 0x016a -#define SMSG_GUILD_INVITE_ACK 0x0169 -#define SMSG_GUILD_LEAVE 0x015a -#define SMSG_GUILD_EXPULSION 0x015c -#define SMSG_GUILD_EXPULSION_LIST 0x0163 -#define SMSG_GUILD_MESSAGE 0x017f -#define SMSG_GUILD_SKILL_UP 0x010e -#define SMSG_GUILD_REQ_ALLIANCE 0x0171 -#define SMSG_GUILD_REQ_ALLIANCE_ACK 0x0173 -#define SMSG_GUILD_DEL_ALLIANCE 0x0184 -#define SMSG_GUILD_OPPOSITION_ACK 0x0181 -#define SMSG_GUILD_BROKEN 0x015e - -#define SMSG_MVP 0x010c - -/********************************** - * Packets from client to server * - **********************************/ -#define CMSG_SERVER_VERSION_REQUEST 0x7530 - -#define CMSG_CHAR_PASSWORD_CHANGE 0x0061 /**< Custom change password packet */ -#define CMSG_CHAR_SERVER_CONNECT 0x0065 -#define CMSG_CHAR_SELECT 0x0066 -#define CMSG_CHAR_CREATE 0x0067 -#define CMSG_CHAR_DELETE 0x0068 - -#define CMSG_MAP_SERVER_CONNECT 0x0072 -#define CMSG_CLIENT_PING 0x007e /**< Send to server with tick */ -#define CMSG_MAP_LOADED 0x007d -#define CMSG_CLIENT_QUIT 0x018A - -#define CMSG_CHAT_MESSAGE 0x008c -#define CMSG_CHAT_WHISPER 0x0096 -#define CMSG_CHAT_ANNOUNCE 0x0099 -#define CMSG_CHAT_WHO 0x00c1 - -#define CMSG_SKILL_LEVELUP_REQUEST 0x0112 -#define CMSG_STAT_UPDATE_REQUEST 0x00bb -#define CMSG_SKILL_USE_BEING 0x0113 -#define CMSG_SKILL_USE_POSITION 0x0116 -// Variant of 0x116 with 80 char string at end (unsure of use) -#define CMSG_SKILL_USE_POSITION_MORE 0x0190 -#define CMSG_SKILL_USE_MAP 0x011b - -#define CMSG_PLAYER_INVENTORY_USE 0x00a7 -#define CMSG_PLAYER_INVENTORY_DROP 0x00a2 -#define CMSG_PLAYER_EQUIP 0x00a9 -#define CMSG_PLAYER_UNEQUIP 0x00ab - -#define CMSG_ITEM_PICKUP 0x009f -#define CMSG_PLAYER_CHANGE_DIR 0x009b -#define CMSG_PLAYER_CHANGE_DEST 0x0085 -#define CMSG_PLAYER_CHANGE_ACT 0x0089 -#define CMSG_PLAYER_RESTART 0x00b2 -#define CMSG_PLAYER_EMOTE 0x00bf -#define CMSG_PLAYER_ATTACK 0x0089 -#define CMSG_WHO_REQUEST 0x00c1 - -#define CMSG_NPC_TALK 0x0090 -#define CMSG_NPC_NEXT_REQUEST 0x00b9 -#define CMSG_NPC_CLOSE 0x0146 -#define CMSG_NPC_LIST_CHOICE 0x00b8 -#define CMSG_NPC_INT_RESPONSE 0x0143 -#define CMSG_NPC_STR_RESPONSE 0x01d5 -#define CMSG_NPC_BUY_SELL_REQUEST 0x00c5 -#define CMSG_NPC_BUY_REQUEST 0x00c8 -#define CMSG_NPC_SELL_REQUEST 0x00c9 - -#define CMSG_TRADE_REQUEST 0x00e4 -#define CMSG_TRADE_RESPONSE 0x00e6 -#define CMSG_TRADE_ITEM_ADD_REQUEST 0x00e8 -#define CMSG_TRADE_CANCEL_REQUEST 0x00ed -#define CMSG_TRADE_ADD_COMPLETE 0x00eb -#define CMSG_TRADE_OK 0x00ef - -#define CMSG_PARTY_CREATE 0x00f9 -#define CMSG_PARTY_INVITE 0x00fc -#define CMSG_PARTY_INVITED 0x00ff -#define CMSG_PARTY_LEAVE 0x0100 -#define CMSG_PARTY_SETTINGS 0x0102 -#define CMSG_PARTY_KICK 0x0103 -#define CMSG_PARTY_MESSAGE 0x0108 - -#define CMSG_MOVE_TO_STORAGE 0x00f3 /** Move item to storage */ -#define CSMG_MOVE_FROM_STORAGE 0x00f5 /** Remove item from storage */ -#define CMSG_CLOSE_STORAGE 0x00f7 /** Request storage close */ - -#define CMSG_ADMIN_ANNOUNCE 0x0099 -#define CMSG_ADMIN_LOCAL_ANNOUNCE 0x019C -#define CMSG_ADMIN_HIDE 0x019D -#define CMSG_ADMIN_KICK 0x00CC -#define CMSG_ADMIN_MUTE 0x0149 - -#define CMSG_GUILD_CHECK_MASTER 0x014d -#define CMSG_GUILD_REQUEST_INFO 0x014f -#define CMSG_GUILD_REQUEST_EMBLEM 0x0151 -#define CMSG_GUILD_CHANGE_EMBLEM 0x0153 -#define CMSG_GUILD_CHANGE_MEMBER_POS 0x0155 -#define CMSG_GUILD_LEAVE 0x0159 -#define CMSG_GUILD_EXPULSION 0x015b -#define CMSG_GUILD_BREAK 0x015d -#define CMSG_GUILD_CHANGE_POS_INFO 0x0161 -#define CMSG_GUILD_CREATE 0x0165 -#define CMSG_GUILD_INVITE 0x0168 -#define CMSG_GUILD_INVITE_REPLY 0x016b -#define CMSG_GUILD_CHANGE_NOTICE 0x016e -#define CMSG_GUILD_ALLIANCE_REQUEST 0x0170 -#define CMSG_GUILD_ALLIANCE_REPLY 0x0172 -#define CMSG_GUILD_MESSAGE 0x017e -#define CMSG_GUILD_OPPOSITION 0x0180 -#define CMSG_GUILD_ALLIANCE_DELETE 0x0183 - -#endif diff --git a/src/net/ea/specialhandler.cpp b/src/net/ea/specialhandler.cpp deleted file mode 100644 index 4a7bb765..00000000 --- a/src/net/ea/specialhandler.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/specialhandler.h" - -#include "localplayer.h" -#include "log.h" - -#include "gui/skilldialog.h" - -#include "gui/widgets/chattab.h" - -#include "net/messagein.h" -#include "net/messageout.h" - -#include "net/ea/protocol.h" - -#include "utils/gettext.h" - -/** job dependend identifiers (?) */ -#define SKILL_BASIC 0x0001 -#define SKILL_WARP 0x001b -#define SKILL_STEAL 0x0032 -#define SKILL_ENVENOM 0x0034 - -/** basic skills identifiers */ -#define BSKILL_TRADE 0x0000 -#define BSKILL_EMOTE 0x0001 -#define BSKILL_SIT 0x0002 -#define BSKILL_CREATECHAT 0x0003 -#define BSKILL_JOINPARTY 0x0004 -#define BSKILL_SHOUT 0x0005 -#define BSKILL_PK 0x0006 // ?? -#define BSKILL_SETALLIGN 0x0007 // ?? - -/** reasons why action failed */ -#define RFAIL_SKILLDEP 0x00 -#define RFAIL_INSUFHP 0x01 -#define RFAIL_INSUFSP 0x02 -#define RFAIL_NOMEMO 0x03 -#define RFAIL_SKILLDELAY 0x04 -#define RFAIL_ZENY 0x05 -#define RFAIL_WEAPON 0x06 -#define RFAIL_REDGEM 0x07 -#define RFAIL_BLUEGEM 0x08 -#define RFAIL_OVERWEIGHT 0x09 -#define RFAIL_GENERIC 0x0a - -/** should always be zero if failed */ -#define SKILL_FAILED 0x00 - -extern Net::SpecialHandler *specialHandler; - -namespace EAthena { - -SpecialHandler::SpecialHandler() -{ - static const Uint16 _messages[] = { - SMSG_PLAYER_SKILLS, - SMSG_SKILL_FAILED, - SMSG_PLAYER_SKILL_UP, - 0 - }; - handledMessages = _messages; - specialHandler = this; -} - -void SpecialHandler::handleMessage(Net::MessageIn &msg) -{ - int skillCount; - int skillId; - - switch (msg.getId()) - { - case SMSG_PLAYER_SKILLS: - msg.readInt16(); // length - skillCount = (msg.getLength() - 4) / 37; - - for (int k = 0; k < skillCount; k++) - { - skillId = msg.readInt16(); - msg.readInt16(); // target type - msg.skip(2); // unused - int level = msg.readInt16(); - msg.readInt16(); // sp - msg.readInt16(); // range - msg.skip(24); // unused - int up = msg.readInt8(); - - player_node->setAttributeBase(skillId, level); - player_node->setAttributeEffective(skillId, level); - skillDialog->setModifiable(skillId, up); - } - break; - - case SMSG_PLAYER_SKILL_UP: - { - skillId = msg.readInt16(); - int level = msg.readInt16(); - msg.readInt16(); // sp - msg.readInt16(); // range - int up = msg.readInt8(); - - player_node->setAttributeBase(skillId, level); - player_node->setAttributeEffective(skillId, level); - skillDialog->setModifiable(skillId, up); - } - break; - - case SMSG_SKILL_FAILED: - // Action failed (ex. sit because you have not reached the - // right level) - skillId = msg.readInt16(); - short bskill = msg.readInt16(); - msg.readInt16(); // unknown - char success = msg.readInt8(); - char reason = msg.readInt8(); - if (success != SKILL_FAILED && bskill == BSKILL_EMOTE) - { - logger->log("Action: %d/%d", bskill, success); - } - - std::string msg; - if (success == SKILL_FAILED && skillId == SKILL_BASIC) - { - switch (bskill) - { - case BSKILL_TRADE: - msg = _("Trade failed!"); - break; - case BSKILL_EMOTE: - msg = _("Emote failed!"); - break; - case BSKILL_SIT: - msg = _("Sit failed!"); - break; - case BSKILL_CREATECHAT: - msg = _("Chat creating failed!"); - break; - case BSKILL_JOINPARTY: - msg = _("Could not join party!"); - break; - case BSKILL_SHOUT: - msg = _("Cannot shout!"); - break; - } - - msg += " "; - - switch (reason) - { - case RFAIL_SKILLDEP: - msg += _("You have not yet reached a high enough lvl!"); - break; - case RFAIL_INSUFHP: - msg += _("Insufficient HP!"); - break; - case RFAIL_INSUFSP: - msg += _("Insufficient SP!"); - break; - case RFAIL_NOMEMO: - msg += _("You have no memos!"); - break; - case RFAIL_SKILLDELAY: - msg += _("You cannot do that right now!"); - break; - case RFAIL_ZENY: - msg += _("Seems you need more money... ;-)"); - break; - case RFAIL_WEAPON: - msg += _("You cannot use this skill with that kind of weapon!"); - break; - case RFAIL_REDGEM: - msg += _("You need another red gem!"); - break; - case RFAIL_BLUEGEM: - msg += _("You need another blue gem!"); - break; - case RFAIL_OVERWEIGHT: - msg += _("You're carrying to much to do this!"); - break; - default: - msg += _("Huh? What's that?"); - break; - } - } - else - { - switch (skillId) - { - case SKILL_WARP : - msg = _("Warp failed..."); - break; - case SKILL_STEAL : - msg = _("Could not steal anything..."); - break; - case SKILL_ENVENOM : - msg = _("Poison had no effect..."); - break; - } - } - - localChatTab->chatLog(msg); - break; - } -} - -void SpecialHandler::use(int id) -{ - // TODO -} - -void SpecialHandler::use(int id, int level, int beingId) -{ - MessageOut outMsg(CMSG_SKILL_USE_BEING); - outMsg.writeInt16(level); - outMsg.writeInt16(id); - outMsg.writeInt16(beingId); -} - -void SpecialHandler::use(int id, int level, int x, int y) -{ - MessageOut outMsg(CMSG_SKILL_USE_POSITION); - outMsg.writeInt16(level); - outMsg.writeInt16(id); - outMsg.writeInt16(x); - outMsg.writeInt16(y); -} - -void SpecialHandler::use(int id, const std::string &map) -{ - MessageOut outMsg(CMSG_SKILL_USE_MAP); - outMsg.writeInt16(id); - outMsg.writeString(map, 16); -} - -} // namespace EAthena diff --git a/src/net/ea/specialhandler.h b/src/net/ea/specialhandler.h deleted file mode 100644 index 3ac27f8b..00000000 --- a/src/net/ea/specialhandler.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_SKILLHANDLER_H -#define NET_EA_SKILLHANDLER_H - -#include "net/net.h" -#include "net/specialhandler.h" - -#include "net/ea/messagehandler.h" - -namespace EAthena { - -class SpecialHandler : public MessageHandler, public Net::SpecialHandler -{ - public: - SpecialHandler(); - - void handleMessage(Net::MessageIn &msg); - - void use(int id); - - void use(int id, int level, int beingId); - - void use(int id, int level, int x, int y); - - void use(int id, const std::string &map); -}; - -} // namespace EAthena - -#endif // NET_EA_SKILLHANDLER_H diff --git a/src/net/ea/token.h b/src/net/ea/token.h deleted file mode 100644 index 19884c7b..00000000 --- a/src/net/ea/token.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "player.h" - -#ifndef NET_EA_TOKEN_H -#define NET_EA_TOKEN_H - -struct Token -{ - int account_ID; - int session_ID1; - int session_ID2; - Gender sex; - - void clear() - { - account_ID = 0; - session_ID1 = 0; - session_ID2 = 0; - sex = GENDER_UNSPECIFIED; - } -}; - -#endif // NET_EA_TOKEN_H diff --git a/src/net/ea/tradehandler.cpp b/src/net/ea/tradehandler.cpp deleted file mode 100644 index 797a1523..00000000 --- a/src/net/ea/tradehandler.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "net/ea/tradehandler.h" - -#include "inventory.h" -#include "item.h" -#include "localplayer.h" -#include "playerrelations.h" - -#include "gui/confirmdialog.h" -#include "gui/trade.h" - -#include "gui/widgets/chattab.h" - -#include "net/inventoryhandler.h" -#include "net/messagein.h" -#include "net/messageout.h" - -#include "net/ea/protocol.h" - -#include "utils/gettext.h" -#include "utils/stringutils.h" - -extern std::string tradePartnerName; -ConfirmDialog *confirmDlg; - -/** - * Listener for request trade dialogs - */ -namespace { - struct RequestTradeListener : public gcn::ActionListener - { - void action(const gcn::ActionEvent &event) - { - confirmDlg = 0; - Net::getTradeHandler()->respond(event.getId() == "yes"); - } - } listener; -} - -extern Net::TradeHandler *tradeHandler; - -namespace EAthena { - -TradeHandler::TradeHandler() -{ - static const Uint16 _messages[] = { - SMSG_TRADE_REQUEST, - SMSG_TRADE_RESPONSE, - SMSG_TRADE_ITEM_ADD, - SMSG_TRADE_ITEM_ADD_RESPONSE, - SMSG_TRADE_OK, - SMSG_TRADE_CANCEL, - SMSG_TRADE_COMPLETE, - 0 - }; - handledMessages = _messages; - tradeHandler = this; - confirmDlg = 0; -} - - -void TradeHandler::handleMessage(Net::MessageIn &msg) -{ - switch (msg.getId()) - { - 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. - std::string tradePartnerNameTemp = msg.readString(24); - - if (player_relations.hasPermission(tradePartnerName, - PlayerRelation::TRADE)) - { - if (!player_node->tradeRequestOk() || confirmDlg) - { - Net::getTradeHandler()->respond(false); - break; - } - - tradePartnerName = tradePartnerNameTemp; - player_node->setTrading(true); - confirmDlg = new ConfirmDialog(_("Request for Trade"), - strprintf(_("%s wants to trade with you, do you " - "accept?"), tradePartnerName.c_str())); - confirmDlg->addActionListener(&listener); - } - else - { - Net::getTradeHandler()->respond(false); - break; - } - } - break; - - case SMSG_TRADE_RESPONSE: - switch (msg.readInt8()) - { - case 0: // Too far away - localChatTab->chatLog(_("Trading isn't possible. Trade " - "partner is too far away."), BY_SERVER); - break; - case 1: // Character doesn't exist - localChatTab->chatLog(_("Trading isn't possible. Character " - "doesn't exist."), BY_SERVER); - break; - case 2: // Invite request check failed... - localChatTab->chatLog(_("Trade cancelled due to an unknown " - "reason."), BY_SERVER); - break; - case 3: // Trade accepted - tradeWindow->reset(); - tradeWindow->setCaption(strprintf(_("Trade: You and %s"), - tradePartnerName.c_str())); - tradeWindow->setVisible(true); - break; - case 4: // Trade cancelled - if (player_relations.hasPermission(tradePartnerName, - PlayerRelation::SPEECH_LOG)) - localChatTab->chatLog(strprintf(_("Trade with %s " - "cancelled."), tradePartnerName.c_str()), - BY_SERVER); - // otherwise ignore silently - - tradeWindow->setVisible(false); - player_node->setTrading(false); - break; - default: // Shouldn't happen as well, but to be sure - localChatTab->chatLog(_("Unhandled trade cancel packet."), - BY_SERVER); - break; - } - break; - - case SMSG_TRADE_ITEM_ADD: - { - int amount = msg.readInt32(); - int type = msg.readInt16(); - msg.readInt8(); // identified flag - msg.readInt8(); // attribute - msg.readInt8(); // refine - msg.skip(8); // card (4 shorts) - - // TODO: handle also identified, etc - if (type == 0) - tradeWindow->setMoney(amount); - else - tradeWindow->addItem(type, false, amount, false); - } - break; - - case SMSG_TRADE_ITEM_ADD_RESPONSE: - // Trade: New Item add response (was 0x00ea, now 01b1) - { - const int index = msg.readInt16() - INVENTORY_OFFSET; - Item *item = player_node->getInventory()->getItem(index); - if (!item) - { - tradeWindow->receivedOk(true); - return; - } - int quantity = msg.readInt16(); - - switch (msg.readInt8()) - { - case 0: - // Successfully added item - if (item->isEquipment() && item->isEquipped()) - { - Net::getInventoryHandler()->unequipItem(item); - } - tradeWindow->addItem(item->getId(), true, quantity, - item->isEquipment()); - item->increaseQuantity(-quantity); - break; - case 1: - // Add item failed - player overweighted - localChatTab->chatLog(_("Failed adding item. Trade " - "partner is over weighted."), BY_SERVER); - break; - case 2: - // Add item failed - player has no free slot - localChatTab->chatLog(_("Failed adding item. Trade " - "partner has no free slot."), BY_SERVER); - break; - default: - localChatTab->chatLog(_("Failed adding item for " - "unknown reason."), BY_SERVER); - break; - } - } - break; - - case SMSG_TRADE_OK: - // 0 means ok from myself, 1 means ok from other; - tradeWindow->receivedOk(msg.readInt8() == 0); - break; - - case SMSG_TRADE_CANCEL: - localChatTab->chatLog(_("Trade canceled."), BY_SERVER); - tradeWindow->setVisible(false); - tradeWindow->reset(); - player_node->setTrading(false); - break; - - case SMSG_TRADE_COMPLETE: - localChatTab->chatLog(_("Trade completed."), BY_SERVER); - tradeWindow->setVisible(false); - tradeWindow->reset(); - player_node->setTrading(false); - break; - } -} - -void TradeHandler::request(Being *being) -{ - MessageOut outMsg(CMSG_TRADE_REQUEST); - outMsg.writeInt32(being->getId()); -} - -void TradeHandler::respond(bool accept) -{ - if (!accept) - player_node->setTrading(false); - - MessageOut outMsg(CMSG_TRADE_RESPONSE); - outMsg.writeInt8(accept ? 3 : 4); -} - -void TradeHandler::addItem(Item *item, int amount) -{ - MessageOut outMsg(CMSG_TRADE_ITEM_ADD_REQUEST); - outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); - outMsg.writeInt32(amount); -} - -void TradeHandler::removeItem(int slotNum, int amount) -{ - // TODO -} - -void TradeHandler::setMoney(int amount) -{ - MessageOut outMsg(CMSG_TRADE_ITEM_ADD_REQUEST); - outMsg.writeInt16(0); - outMsg.writeInt32(amount); -} - -void TradeHandler::confirm() -{ - MessageOut outMsg(CMSG_TRADE_ADD_COMPLETE); -} - -void TradeHandler::finish() -{ - MessageOut outMsg(CMSG_TRADE_OK); -} - -void TradeHandler::cancel() -{ - MessageOut outMsg(CMSG_TRADE_CANCEL_REQUEST); -} - -} // namespace EAthena diff --git a/src/net/ea/tradehandler.h b/src/net/ea/tradehandler.h deleted file mode 100644 index b6bf3560..00000000 --- a/src/net/ea/tradehandler.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef NET_EA_TRADEHANDLER_H -#define NET_EA_TRADEHANDLER_H - -#include "net/net.h" -#include "net/tradehandler.h" - -#include "net/ea/messagehandler.h" - -namespace EAthena { - -class TradeHandler : public MessageHandler, public Net::TradeHandler -{ - public: - TradeHandler(); - - void handleMessage(Net::MessageIn &msg); - - void request(Being *being); - - void respond(bool accept); - - void addItem(Item *item, int amount); - - void removeItem(int slotNum, int amount); - - void setMoney(int amount); - - void confirm(); - - void finish(); - - void cancel(); -}; - -} // namespace EAthena - -#endif // NET_EA_TRADEHANDLER_H diff --git a/src/net/net.cpp b/src/net/net.cpp index f7ab3897..5e7c989f 100644 --- a/src/net/net.cpp +++ b/src/net/net.cpp @@ -37,7 +37,7 @@ #include "net/specialhandler.h" #include "net/tradehandler.h" -#include "net/ea/generalhandler.h" +#include "net/tmwa/generalhandler.h" #include "net/manaserv/generalhandler.h" @@ -149,8 +149,8 @@ void connectToServer(const ServerInfo &server) new ManaServ::GeneralHandler; break; - case ServerInfo::EATHENA: - new EAthena::GeneralHandler; + case ServerInfo::TMWATHENA: + new TmwAthena::GeneralHandler; break; default: diff --git a/src/net/serverinfo.h b/src/net/serverinfo.h index 8b5b8f9d..b888cbbf 100644 --- a/src/net/serverinfo.h +++ b/src/net/serverinfo.h @@ -33,7 +33,7 @@ public: enum Type { UNKNOWN, MANASERV, - EATHENA + TMWATHENA }; typedef std::pair VersionString; @@ -99,8 +99,11 @@ public: static Type parseType(const std::string &type) { - if (compareStrI(type, "eathena") == 0) - return EATHENA; + if (compareStrI(type, "tmwathena") == 0) + return TMWATHENA; + // Used for backward compatibility + else if (compareStrI(type, "eathena") == 0) + return TMWATHENA; else if (compareStrI(type, "manaserv") == 0) return MANASERV; diff --git a/src/net/tmwa/adminhandler.cpp b/src/net/tmwa/adminhandler.cpp new file mode 100644 index 00000000..e56d5a44 --- /dev/null +++ b/src/net/tmwa/adminhandler.cpp @@ -0,0 +1,131 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/adminhandler.h" + +#include "being.h" +#include "beingmanager.h" +#include "game.h" +#include "playerrelations.h" + +#include "gui/widgets/chattab.h" + +#include "net/chathandler.h" +#include "net/net.h" + +#include "net/tmwa/protocol.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#include + +extern Net::AdminHandler *adminHandler; + +namespace TmwAthena { + +AdminHandler::AdminHandler() +{ + static const Uint16 _messages[] = { + SMSG_ADMIN_KICK_ACK, + 0 + }; + handledMessages = _messages; + adminHandler = this; +} + +void AdminHandler::handleMessage(Net::MessageIn &msg) +{ + int id; + switch (msg.getId()) + { + case SMSG_ADMIN_KICK_ACK: + id = msg.readInt32(); + if (id == 0) + localChatTab->chatLog(_("Kick failed!"), BY_SERVER); + else + localChatTab->chatLog(_("Kick succeeded!"), BY_SERVER); + break; + } +} + +void AdminHandler::announce(const std::string &text) +{ + MessageOut outMsg(CMSG_ADMIN_ANNOUNCE); + outMsg.writeInt16(text.length() + 4); + outMsg.writeString(text, text.length()); +} + +void AdminHandler::localAnnounce(const std::string &text) +{ + MessageOut outMsg(CMSG_ADMIN_LOCAL_ANNOUNCE); + outMsg.writeInt16(text.length() + 4); + outMsg.writeString(text, text.length()); +} + +void AdminHandler::hide(bool hide) +{ + MessageOut outMsg(CMSG_ADMIN_HIDE); + outMsg.writeInt32(0); //unused +} + +void AdminHandler::kick(int playerId) +{ + MessageOut outMsg(CMSG_ADMIN_KICK); + outMsg.writeInt32(playerId); +} + +void AdminHandler::kick(const std::string &name) +{ + Net::getChatHandler()->talk("@kick " + name); +} + +void AdminHandler::ban(int playerId) +{ + // Not supported +} + +void AdminHandler::ban(const std::string &name) +{ + Net::getChatHandler()->talk("@ban " + name); +} + +void AdminHandler::unban(int playerId) +{ + // Not supported +} + +void AdminHandler::unban(const std::string &name) +{ + Net::getChatHandler()->talk("@unban " + name); +} + +void AdminHandler::mute(int playerId, int type, int limit) +{ + return; // Still looking into this + + MessageOut outMsg(CMSG_ADMIN_MUTE); + outMsg.writeInt32(playerId); + outMsg.writeInt8(type); + outMsg.writeInt16(limit); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/adminhandler.h b/src/net/tmwa/adminhandler.h new file mode 100644 index 00000000..7d5b4fb5 --- /dev/null +++ b/src/net/tmwa/adminhandler.h @@ -0,0 +1,62 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_ADMINHANDLER_H +#define NET_TA_ADMINHANDLER_H + +#include "net/adminhandler.h" +#include "net/net.h" + +#include "net/tmwa/messagehandler.h" + +namespace TmwAthena { + +class AdminHandler : public MessageHandler, public Net::AdminHandler +{ + public: + AdminHandler(); + + void handleMessage(Net::MessageIn &msg); + + void announce(const std::string &text); + + void localAnnounce(const std::string &text); + + void hide(bool hide); + + void kick(int playerId); + + void kick(const std::string &name); + + void ban(int playerId); + + void ban(const std::string &name); + + void unban(int playerId); + + void unban(const std::string &name); + + void mute(int playerId, int type, int limit); +}; + +} // namespace TmwAthena + +#endif // NET_TA_ADMINHANDLER_H diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp new file mode 100644 index 00000000..04690c50 --- /dev/null +++ b/src/net/tmwa/beinghandler.cpp @@ -0,0 +1,714 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/beinghandler.h" + +#include "being.h" +#include "beingmanager.h" +#include "client.h" +#include "effectmanager.h" +#include "guild.h" +#include "localplayer.h" +#include "log.h" +#include "npc.h" +#include "party.h" +#include "playerrelations.h" + +#include "net/tmwa/protocol.h" + +#include "resources/colordb.h" + +#include + +namespace TmwAthena { + +const int EMOTION_TIME = 150; /**< Duration of emotion icon */ + +BeingHandler::BeingHandler(bool enableSync): + mSync(enableSync) +{ + static const Uint16 _messages[] = { + SMSG_BEING_VISIBLE, + SMSG_BEING_MOVE, + SMSG_BEING_MOVE2, + SMSG_BEING_REMOVE, + SMSG_SKILL_DAMAGE, + SMSG_BEING_ACTION, + SMSG_BEING_SELFEFFECT, + SMSG_BEING_EMOTION, + SMSG_BEING_CHANGE_LOOKS, + SMSG_BEING_CHANGE_LOOKS2, + SMSG_BEING_NAME_RESPONSE, + SMSG_PLAYER_GUILD_PARTY_INFO, + SMSG_BEING_CHANGE_DIRECTION, + SMSG_PLAYER_UPDATE_1, + SMSG_PLAYER_UPDATE_2, + SMSG_PLAYER_MOVE, + SMSG_PLAYER_STOP, + SMSG_PLAYER_MOVE_TO_ATTACK, + SMSG_PLAYER_STATUS_CHANGE, + SMSG_BEING_STATUS_CHANGE, + SMSG_BEING_RESURRECT, + 0 + }; + handledMessages = _messages; +} + +Being *createBeing(int id, short job) +{ + Being::Type type = Being::UNKNOWN; + if (job <= 25 || (job >= 4001 && job <= 4049)) + type = Being::PLAYER; + else if (job >= 46 && job <= 1000) + type = Being::NPC; + else if (job > 1000 && job <= 2000) + type = Being::MONSTER; + else if (job == 45) + return NULL; // Skip portals + + Being *being = beingManager->createBeing(id, type, job); + + if (type == Being::PLAYER || type == Being::NPC) + { + MessageOut outMsg(0x0094); + outMsg.writeInt32(id);//readLong(2)); + } + + return being; +} + +void BeingHandler::handleMessage(Net::MessageIn &msg) +{ + if (!beingManager) + return; + + int id; + short job, speed, gender; + Uint16 headTop, headMid, headBottom; + Uint16 shoes, gloves; + Uint16 weapon, shield; + Uint16 gmstatus; + int param1; + int stunMode; + Uint32 statusEffects; + int type, guild; + Uint16 status; + Being *srcBeing, *dstBeing; + Player *player = 0; + int hairStyle, hairColor, flag; + std::string player_followed; + + switch (msg.getId()) + { + case SMSG_BEING_VISIBLE: + case SMSG_BEING_MOVE: + // Information about a being in range + id = msg.readInt32(); + speed = msg.readInt16(); + stunMode = msg.readInt16(); // opt1 + statusEffects = msg.readInt16(); // opt2 + statusEffects |= ((Uint32)msg.readInt16()) << 16; // option + job = msg.readInt16(); // class + + dstBeing = beingManager->findBeing(id); + + if (!dstBeing) + { + // Being with id >= 110000000 and job 0 are better + // known as ghosts, so don't create those. + if (job == 0 && id >= 110000000) + { + break; + } + + dstBeing = createBeing(id, job); + + if (!dstBeing) + break; + } + + if (dstBeing->getType() == Being::PLAYER) + player = static_cast(dstBeing); + + if (msg.getId() == 0x0078) + { + dstBeing->clearPath(); + dstBeing->setFrame(0); + dstBeing->setWalkTime(tick_time); + dstBeing->setAction(Being::STAND); + } + + + // Prevent division by 0 when calculating frame + if (speed == 0) { speed = 150; } + + dstBeing->setWalkSpeed(Vector(speed, speed, 0)); + dstBeing->setSubtype(job); + hairStyle = msg.readInt16(); + weapon = msg.readInt16(); + headBottom = msg.readInt16(); + + if (msg.getId() == SMSG_BEING_MOVE) + { + msg.readInt32(); // server tick + } + + shield = msg.readInt16(); + headTop = msg.readInt16(); + headMid = msg.readInt16(); + hairColor = msg.readInt16(); + shoes = msg.readInt16(); // clothes color - "abused" as shoes + gloves = msg.readInt16(); // head dir - "abused" as gloves + guild = msg.readInt32(); // guild + if (player) + { + if (guild == 0) + { + player->clearGuilds(); + } + else + { + player->addGuild(Guild::getGuild(guild)); + } + } + msg.readInt16(); // guild emblem + msg.readInt16(); // manner + dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 + msg.readInt8(); // karma + gender = msg.readInt8(); + + if (player) + { + player->setGender((gender == 0) + ? GENDER_FEMALE : GENDER_MALE); + // Set these after the gender, as the sprites may be gender-specific + player->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor)); + player->setSprite(SPRITE_BOTTOMCLOTHES, headBottom); + player->setSprite(SPRITE_TOPCLOTHES, headMid); + player->setSprite(SPRITE_HAT, headTop); + player->setSprite(SPRITE_SHOE, shoes); + player->setSprite(SPRITE_GLOVES, gloves); + player->setSprite(SPRITE_WEAPON, weapon, "", true); + player->setSprite(SPRITE_SHIELD, shield); + } + + if (msg.getId() == SMSG_BEING_MOVE) + { + Uint16 srcX, srcY, dstX, dstY; + msg.readCoordinatePair(srcX, srcY, dstX, dstY); + dstBeing->setAction(Being::STAND); + dstBeing->setTileCoords(srcX, srcY); + dstBeing->setDestination(dstX, dstY); + } + else + { + Uint8 dir; + Uint16 x, y; + msg.readCoordinates(x, y, dir); + dstBeing->setTileCoords(x, y); + dstBeing->setDirection(dir); + } + + msg.readInt8(); // unknown + msg.readInt8(); // unknown + msg.readInt8(); // unknown / sit + + dstBeing->setStunMode(stunMode); + dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); + dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); + break; + + case SMSG_BEING_MOVE2: + /* + * A simplified movement packet, used by the + * later versions of eAthena for both mobs and + * players + */ + dstBeing = beingManager->findBeing(msg.readInt32()); + + Uint16 srcX, srcY, dstX, dstY; + msg.readCoordinatePair(srcX, srcY, dstX, dstY); + msg.readInt32(); // Server tick + + /* + * This packet doesn't have enough info to actually + * create a new being, so if the being isn't found, + * we'll just pretend the packet didn't happen + */ + + if (dstBeing) + { + dstBeing->setAction(Being::STAND); + dstBeing->setTileCoords(srcX, srcY); + dstBeing->setDestination(dstX, dstY); + } + + break; + + case SMSG_BEING_REMOVE: + // A being should be removed or has died + id = msg.readInt32(); + + dstBeing = beingManager->findBeing(id); + + if (!dstBeing) + break; + + player_followed = player_node->getFollow(); + + if (!player_followed.empty()) + { + if (dstBeing->getName() == player_followed) + { + player_node->setDestination(player_node->getNextDestX(), player_node->getNextDestY()); + } + } + + // If this is player's current target, clear it. + if (dstBeing == player_node->getTarget()) + player_node->stopAttack(); + + if (msg.readInt8() == 1) + dstBeing->setAction(Being::DEAD); + else + beingManager->destroyBeing(dstBeing); + + break; + + case SMSG_BEING_RESURRECT: + // A being changed mortality status + id = msg.readInt32(); + + dstBeing = beingManager->findBeing(id); + + if (!dstBeing) + break; + + // If this is player's current target, clear it. + if (dstBeing == player_node->getTarget()) + player_node->stopAttack(); + + if (msg.readInt8() == 1) + dstBeing->setAction(Being::STAND); + + break; + + case SMSG_SKILL_DAMAGE: + msg.readInt16(); // Skill Id + srcBeing = beingManager->findBeing(msg.readInt32()); + dstBeing = beingManager->findBeing(msg.readInt32()); + msg.readInt32(); // Server tick + msg.readInt32(); // src speed + msg.readInt32(); // dst speed + param1 = msg.readInt32(); // Damage + msg.readInt16(); // Skill level + msg.readInt16(); // Div + msg.readInt8(); // Skill hit/type (?) + if (dstBeing) + dstBeing->takeDamage(srcBeing, param1, Being::HIT); // Perhaps a new skill attack type should be created and used? + if (srcBeing) + srcBeing->handleAttack(dstBeing, param1, Being::HIT); + break; + + case SMSG_BEING_ACTION: + srcBeing = beingManager->findBeing(msg.readInt32()); + dstBeing = beingManager->findBeing(msg.readInt32()); + msg.readInt32(); // server tick + msg.readInt32(); // src speed + msg.readInt32(); // dst speed + param1 = msg.readInt16(); + msg.readInt16(); // param 2 + type = msg.readInt8(); + msg.readInt16(); // param 3 + + switch (type) + { + case Being::HIT: // Damage + case Being::CRITICAL: // Critical Damage + case Being::MULTI: // Critical Damage + case Being::REFLECT: // Reflected Damage + case Being::FLEE: // Lucky Dodge + if (dstBeing) + dstBeing->takeDamage(srcBeing, param1, + (Being::AttackType)type); + if (srcBeing) + srcBeing->handleAttack(dstBeing, param1, + (Being::AttackType)type); + break; + + case 0x02: // Sit + if (srcBeing) + { + srcBeing->setFrame(0); + srcBeing->setAction(Being::SIT); + } + break; + + case 0x03: // Stand up + if (srcBeing) + { + srcBeing->setFrame(0); + srcBeing->setAction(Being::STAND); + } + break; + } + break; + + case SMSG_BEING_SELFEFFECT: { + id = (Uint32)msg.readInt32(); + if (!beingManager->findBeing(id)) + break; + + int effectType = msg.readInt32(); + Being* being = beingManager->findBeing(id); + + effectManager->trigger(effectType, being); + + break; + } + + case SMSG_BEING_EMOTION: + if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) + { + break; + } + + if (player_relations.hasPermission(dstBeing, PlayerRelation::EMOTE)) + { + // only set emote if one doesnt already exist + if (!dstBeing->getEmotion()) + dstBeing->setEmote(msg.readInt8(), EMOTION_TIME); + } + + break; + + case SMSG_BEING_CHANGE_LOOKS: + case SMSG_BEING_CHANGE_LOOKS2: + { + /* + * SMSG_BEING_CHANGE_LOOKS (0x00c3) and + * SMSG_BEING_CHANGE_LOOKS2 (0x01d7) do basically the same + * thing. The difference is that ...LOOKS carries a single + * 8 bit value, where ...LOOKS2 carries two 16 bit values. + * + * If type = 2, then the first 16 bit value is the weapon ID, + * and the second 16 bit value is the shield ID. If no + * shield is equipped, or type is not 2, then the second + * 16 bit value will be 0. + */ + + if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) + { + break; + } + + if (dstBeing->getType() == Being::PLAYER) + player = static_cast(dstBeing); + + int type = msg.readInt8(); + int id = 0; + int id2 = 0; + + if (msg.getId() == SMSG_BEING_CHANGE_LOOKS) + { + id = msg.readInt8(); + } + else + { // SMSG_BEING_CHANGE_LOOKS2 + id = msg.readInt16(); + id2 = msg.readInt16(); + } + + switch (type) + { + case 1: // eAthena LOOK_HAIR + player->setSpriteID(SPRITE_HAIR, id *-1); + break; + case 2: // Weapon ID in id, Shield ID in id2 + player->setSprite(SPRITE_WEAPON, id, "", true); + player->setSprite(SPRITE_SHIELD, id2); + break; + case 3: // Change lower headgear for eAthena, pants for us + player->setSprite(SPRITE_BOTTOMCLOTHES, id); + break; + case 4: // Change upper headgear for eAthena, hat for us + player->setSprite(SPRITE_HAT, id); + break; + case 5: // Change middle headgear for eathena, armor for us + player->setSprite(SPRITE_TOPCLOTHES, id); + break; + case 6: // eAthena LOOK_HAIR_COLOR + player->setSpriteColor(SPRITE_HAIR, ColorDB::get(id)); + break; + case 8: // eAthena LOOK_SHIELD + player->setSprite(SPRITE_SHIELD, id); + break; + case 9: // eAthena LOOK_SHOES + player->setSprite(SPRITE_SHOE, id); + break; + case 10: // LOOK_GLOVES + player->setSprite(SPRITE_GLOVES, id); + break; + case 11: // LOOK_CAPE + player->setSprite(SPRITE_CAPE, id); + break; + case 12: + player->setSprite(SPRITE_MISC1, id); + break; + case 13: + player->setSprite(SPRITE_MISC2, id); + break; + default: + logger->log("SMSG_BEING_CHANGE_LOOKS: unsupported type: " + "%d, id: %d", type, id); + break; + } + } + break; + + case SMSG_BEING_NAME_RESPONSE: + if ((dstBeing = beingManager->findBeing(msg.readInt32()))) + { + dstBeing->setName(msg.readString(24)); + } + break; + case SMSG_PLAYER_GUILD_PARTY_INFO: + if ((dstBeing = beingManager->findBeing(msg.readInt32()))) + { + dstBeing->setPartyName(msg.readString(24)); + dstBeing->setGuildName(msg.readString(24)); + dstBeing->setGuildPos(msg.readString(24)); + msg.readString(24); // Discard this + } + break; + case SMSG_BEING_CHANGE_DIRECTION: + if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) + { + break; + } + + msg.readInt16(); // unused + + dstBeing->setDirection(msg.readInt8()); + + break; + + case SMSG_PLAYER_UPDATE_1: + case SMSG_PLAYER_UPDATE_2: + case SMSG_PLAYER_MOVE: + // An update about a player, potentially including movement. + id = msg.readInt32(); + speed = msg.readInt16(); + stunMode = msg.readInt16(); // opt1; Aethyra use this as cape + statusEffects = msg.readInt16(); // opt2; Aethyra use this as misc1 + statusEffects |= ((Uint32) msg.readInt16()) + << 16; // status.options; Aethyra uses this as misc2 + job = msg.readInt16(); + + dstBeing = beingManager->findBeing(id); + + if (!dstBeing) + { + dstBeing = createBeing(id, job); + + if (!dstBeing) + break; + } + + if (dstBeing->getType() == Being::PLAYER) + player = static_cast(dstBeing); + + if (Party *party = player_node->getParty()){ + if (party->isMember(id)) + { + player->setParty(party); + } + } + + dstBeing->setWalkSpeed(Vector(speed, speed, 0)); + dstBeing->setSubtype(job); + hairStyle = msg.readInt16(); + weapon = msg.readInt16(); + shield = msg.readInt16(); + headBottom = msg.readInt16(); + + if (msg.getId() == SMSG_PLAYER_MOVE) + { + msg.readInt32(); // server tick + } + + headTop = msg.readInt16(); + headMid = msg.readInt16(); + hairColor = msg.readInt16(); + shoes = msg.readInt16(); + gloves = msg.readInt16(); + msg.readInt32(); // guild + msg.readInt16(); // emblem + msg.readInt16(); // manner + dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 + msg.readInt8(); // karma + player->setGender((msg.readInt8() == 0) + ? GENDER_FEMALE : GENDER_MALE); + + // Set these after the gender, as the sprites may be gender-specific + player->setSprite(SPRITE_WEAPON, weapon, "", true); + player->setSprite(SPRITE_SHIELD, shield); + //player->setSprite(SPRITE_SHOE, shoes); + player->setSprite(SPRITE_BOTTOMCLOTHES, headBottom); + player->setSprite(SPRITE_TOPCLOTHES, headMid); + player->setSprite(SPRITE_HAT, headTop); + //player->setSprite(SPRITE_GLOVES, gloves); + //player->setSprite(SPRITE_CAPE, cape); + //player->setSprite(SPRITE_MISC1, misc1); + //player->setSprite(SPRITE_MISC2, misc2); + player->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor)); + + if (msg.getId() == SMSG_PLAYER_MOVE) + { + Uint16 srcX, srcY, dstX, dstY; + msg.readCoordinatePair(srcX, srcY, dstX, dstY); + dstBeing->setTileCoords(srcX, srcY); + dstBeing->setDestination(dstX, dstY); + + player_followed = player_node->getFollow(); + if (!player_followed.empty()) + { + if (dstBeing->getName() == player_followed) + { + player_node->setNextDest(dstX, dstY); + player_node->setDestination(srcX, srcY); + } + } + } + else + { + Uint8 dir; + Uint16 x, y; + msg.readCoordinates(x, y, dir); + dstBeing->setTileCoords(x, y); + dstBeing->setDirection(dir); + } + + gmstatus = msg.readInt16(); + if (gmstatus & 0x80) + player->setGM(true); + + if (msg.getId() == SMSG_PLAYER_UPDATE_1) + { + switch (msg.readInt8()) + { + case 1: + dstBeing->setAction(Being::DEAD); + break; + + case 2: + dstBeing->setAction(Being::SIT); + break; + } + } + else if (msg.getId() == SMSG_PLAYER_MOVE) + { + msg.readInt8(); // unknown + } + + msg.readInt8(); // Lv + msg.readInt8(); // unknown + + dstBeing->setWalkTime(tick_time); + dstBeing->setFrame(0); + + dstBeing->setStunMode(stunMode); + dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); + dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); + break; + + case SMSG_PLAYER_STOP: + /* + * Instruction from server to stop walking at x, y. + * + * Some people like having this enabled. Others absolutely + * despise it. So I'm setting to so that it only affects the + * local player if the person has set a key "EnableSync" to "1" + * in their config.xml file. + * + * This packet will be honored for all other beings, regardless + * of the config setting. + */ + + id = msg.readInt32(); + if (mSync || id != player_node->getId()) + { + dstBeing = beingManager->findBeing(id); + if (dstBeing) + { + Uint16 x, y; + x = msg.readInt16(); + y = msg.readInt16(); + dstBeing->setTileCoords(x, y); + if (dstBeing->getCurrentAction() == Being::WALK) + { + dstBeing->setFrame(0); + dstBeing->setAction(Being::STAND); + } + } + } + break; + + case SMSG_PLAYER_MOVE_TO_ATTACK: + /* + * This is an *advisory* message, telling the client that + * it needs to move the character before attacking + * a target (out of range, obstruction in line of fire). + * We can safely ignore this... + */ + break; + + case SMSG_PLAYER_STATUS_CHANGE: + // Change in players' flags + id = msg.readInt32(); + dstBeing = beingManager->findBeing(id); + stunMode = msg.readInt16(); + statusEffects = msg.readInt16(); + statusEffects |= ((Uint32) msg.readInt16()) << 16; + msg.readInt8(); + + if (dstBeing) + { + dstBeing->setStunMode(stunMode); + dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); + dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); + } + break; + + case SMSG_BEING_STATUS_CHANGE: + // Status change + status = msg.readInt16(); + id = msg.readInt32(); + flag = msg.readInt8(); // 0: stop, 1: start + + dstBeing = beingManager->findBeing(id); + if (dstBeing) + dstBeing->setStatusEffect(status, flag); + break; + } +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/beinghandler.h b/src/net/tmwa/beinghandler.h new file mode 100644 index 00000000..ab833af0 --- /dev/null +++ b/src/net/tmwa/beinghandler.h @@ -0,0 +1,43 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_BEINGHANDLER_H +#define NET_TA_BEINGHANDLER_H + +#include "net/tmwa/messagehandler.h" + +namespace TmwAthena { + +class BeingHandler : public MessageHandler +{ + public: + BeingHandler(bool enableSync); + + virtual void handleMessage(Net::MessageIn &msg); + + private: + // Should we honor server "Stop Walking" packets + bool mSync; +}; + +} // namespace TmwAthena + +#endif // NET_TA_BEINGHANDLER_H diff --git a/src/net/tmwa/buysellhandler.cpp b/src/net/tmwa/buysellhandler.cpp new file mode 100644 index 00000000..209f034d --- /dev/null +++ b/src/net/tmwa/buysellhandler.cpp @@ -0,0 +1,138 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/buysellhandler.h" + +#include "beingmanager.h" +#include "inventory.h" +#include "item.h" +#include "localplayer.h" +#include "npc.h" + +#include "gui/buy.h" +#include "gui/buysell.h" +#include "gui/sell.h" + +#include "gui/widgets/chattab.h" + +#include "net/messagein.h" + +#include "net/tmwa/protocol.h" + +#include "utils/gettext.h" + +namespace TmwAthena { + +BuySellHandler::BuySellHandler() +{ + static const Uint16 _messages[] = { + SMSG_NPC_BUY_SELL_CHOICE, + SMSG_NPC_BUY, + SMSG_NPC_SELL, + SMSG_NPC_BUY_RESPONSE, + SMSG_NPC_SELL_RESPONSE, + 0 + }; + mNpcId = 0; + handledMessages = _messages; +} + +void BuySellHandler::handleMessage(Net::MessageIn &msg) +{ + int n_items; + + switch (msg.getId()) + { + case SMSG_NPC_BUY_SELL_CHOICE: + if (!BuySellDialog::isActive()) + { + mNpcId = msg.readInt32(); + new BuySellDialog(mNpcId); + } + break; + + case SMSG_NPC_BUY: + msg.readInt16(); // length + n_items = (msg.getLength() - 4) / 11; + mBuyDialog = new BuyDialog(mNpcId); + mBuyDialog->setMoney(player_node->getMoney()); + + for (int k = 0; k < n_items; k++) + { + int value = msg.readInt32(); + msg.readInt32(); // DCvalue + msg.readInt8(); // type + int itemId = msg.readInt16(); + mBuyDialog->addItem(itemId, 0, value); + } + break; + + case SMSG_NPC_SELL: + msg.readInt16(); // length + n_items = (msg.getLength() - 4) / 10; + if (n_items > 0) + { + SellDialog *dialog = new SellDialog(mNpcId); + dialog->setMoney(player_node->getMoney()); + + for (int k = 0; k < n_items; k++) + { + int index = msg.readInt16() - INVENTORY_OFFSET; + int value = msg.readInt32(); + msg.readInt32(); // OCvalue + + Item *item = player_node->getInventory()->getItem(index); + + if (item && !(item->isEquipped())) + dialog->addItem(item, value); + } + } + else + { + localChatTab->chatLog(_("Nothing to sell."), BY_SERVER); + } + break; + + case SMSG_NPC_BUY_RESPONSE: + if (msg.readInt8() == 0) + { + localChatTab->chatLog(_("Thanks for buying."), BY_SERVER); + } + else + { + // Reset player money since buy dialog already assumed purchase + // would go fine + mBuyDialog->setMoney(player_node->getMoney()); + localChatTab->chatLog(_("Unable to buy."), BY_SERVER); + } + break; + + case SMSG_NPC_SELL_RESPONSE: + if (msg.readInt8() == 0) + localChatTab->chatLog(_("Thanks for selling."), BY_SERVER); + else + localChatTab->chatLog(_("Unable to sell."), BY_SERVER); + + break; + } +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/buysellhandler.h b/src/net/tmwa/buysellhandler.h new file mode 100644 index 00000000..6ba0df93 --- /dev/null +++ b/src/net/tmwa/buysellhandler.h @@ -0,0 +1,45 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_BUYSELLHANDLER_H +#define NET_TA_BUYSELLHANDLER_H + +#include "net/tmwa/messagehandler.h" + +class BuyDialog; + +namespace TmwAthena { + +class BuySellHandler : public MessageHandler +{ + public: + BuySellHandler(); + + virtual void handleMessage(Net::MessageIn &msg); + + private: + int mNpcId; + BuyDialog *mBuyDialog; +}; + +} // namespace TmwAthena + +#endif // NET_TA_BUYSELLHANDLER_H diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp new file mode 100644 index 00000000..f91dfc77 --- /dev/null +++ b/src/net/tmwa/charserverhandler.cpp @@ -0,0 +1,352 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/charserverhandler.h" + +#include "client.h" +#include "game.h" +#include "log.h" + +#include "gui/charcreatedialog.h" +#include "gui/okdialog.h" + +#include "net/logindata.h" +#include "net/messagein.h" +#include "net/messageout.h" +#include "net/net.h" + +#include "net/tmwa/gamehandler.h" +#include "net/tmwa/loginhandler.h" +#include "net/tmwa/network.h" +#include "net/tmwa/protocol.h" + +#include "resources/colordb.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" +#include "utils/stringutils.h" + +extern Net::CharHandler *charHandler; + +namespace TmwAthena { + +extern ServerInfo charServer; +extern ServerInfo mapServer; + +CharServerHandler::CharServerHandler() +{ + static const Uint16 _messages[] = { + SMSG_CHAR_LOGIN, + SMSG_CHAR_LOGIN_ERROR, + SMSG_CHAR_CREATE_SUCCEEDED, + SMSG_CHAR_CREATE_FAILED, + SMSG_CHAR_DELETE_SUCCEEDED, + SMSG_CHAR_DELETE_FAILED, + SMSG_CHAR_MAP_INFO, + SMSG_CHANGE_MAP_SERVER, + 0 + }; + handledMessages = _messages; + charHandler = this; +} + +void CharServerHandler::handleMessage(Net::MessageIn &msg) +{ + logger->log("CharServerHandler: Packet ID: %x, Length: %d", + msg.getId(), msg.getLength()); + + switch (msg.getId()) + { + case SMSG_CHAR_LOGIN: + { + msg.skip(2); // Length word + msg.skip(20); // Unused + + // Derive number of characters from message length + const int count = (msg.getLength() - 24) / 106; + + for (int i = 0; i < count; ++i) + { + Net::Character *character = new Net::Character; + int slot; + character->dummy = readPlayerData(msg, &slot); + character->slot = slot; + mCharacters.push_back(character); + logger->log("CharServer: Player: %s (%d)", + character->dummy->getName().c_str(), slot); + } + + Client::setState(STATE_CHAR_SELECT); + } + break; + + case SMSG_CHAR_LOGIN_ERROR: + switch (msg.readInt8()) + { + case 0: + errorMessage = _("Access denied."); + break; + case 1: + errorMessage = _("Cannot use this ID."); + break; + default: + errorMessage = _("Unknown failure to select character."); + break; + } + unlockCharSelectDialog(); + break; + + case SMSG_CHAR_CREATE_SUCCEEDED: + { + Net::Character *character = new Net::Character; + int slot; + character->dummy = readPlayerData(msg, &slot); + character->slot = slot; + mCharacters.push_back(character); + + updateCharSelectDialog(); + + // Close the character create dialog + if (mCharCreateDialog) + { + mCharCreateDialog->scheduleDelete(); + mCharCreateDialog = 0; + } + } + break; + + case SMSG_CHAR_CREATE_FAILED: + new OkDialog(_("Error"), _("Failed to create character. Most " + "likely the name is already taken.")); + if (mCharCreateDialog) + mCharCreateDialog->unlock(); + break; + + case SMSG_CHAR_DELETE_SUCCEEDED: + delete mSelectedCharacter; + mCharacters.remove(mSelectedCharacter); + mSelectedCharacter = 0; + updateCharSelectDialog(); + unlockCharSelectDialog(); + new OkDialog(_("Info"), _("Character deleted.")); + break; + + case SMSG_CHAR_DELETE_FAILED: + unlockCharSelectDialog(); + new OkDialog(_("Error"), _("Failed to delete character.")); + break; + + case SMSG_CHAR_MAP_INFO: + { + msg.skip(4); // CharID, must be the same as player_node->charID + GameHandler *gh = static_cast(Net::getGameHandler()); + gh->setMap(msg.readString(16)); + mapServer.hostname = ipToString(msg.readInt32()); + mapServer.port = msg.readInt16(); + + // Prevent the selected local player from being deleted + player_node = mSelectedCharacter->dummy; + mSelectedCharacter->dummy = 0; + + delete_all(mCharacters); + mCharacters.clear(); + updateCharSelectDialog(); + + mNetwork->disconnect(); + Client::setState(STATE_CONNECT_GAME); + } + break; + + case SMSG_CHANGE_MAP_SERVER: + { + GameHandler *gh = static_cast(Net::getGameHandler()); + gh->setMap(msg.readString(16)); + int x = msg.readInt16(); + int y = msg.readInt16(); + mapServer.hostname = ipToString(msg.readInt32()); + mapServer.port = msg.readInt16(); + + mNetwork->disconnect(); + Client::setState(STATE_CHANGE_MAP); + player_node->setTileCoords(x, y); + player_node->setMap(0); + } + break; + } +} + +LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int *slot) +{ + const Token &token = + static_cast(Net::getLoginHandler())->getToken(); + + LocalPlayer *tempPlayer = new LocalPlayer(msg.readInt32(), 0); + tempPlayer->setGender(token.sex); + + tempPlayer->setExp(msg.readInt32()); + tempPlayer->setMoney(msg.readInt32()); + tempPlayer->setExperience(JOB, msg.readInt32(), 1); + int temp = msg.readInt32(); + tempPlayer->setAttributeBase(JOB, temp, false); + tempPlayer->setAttributeEffective(JOB, temp); + tempPlayer->setSprite(SPRITE_SHOE, msg.readInt16()); + tempPlayer->setSprite(SPRITE_GLOVES, msg.readInt16()); + tempPlayer->setSprite(SPRITE_CAPE, msg.readInt16()); + tempPlayer->setSprite(SPRITE_MISC1, msg.readInt16()); + msg.readInt32(); // option + msg.readInt32(); // karma + msg.readInt32(); // manner + msg.skip(2); // unknown + tempPlayer->setHp(msg.readInt16()); + tempPlayer->setMaxHp(msg.readInt16()); + tempPlayer->setMP(msg.readInt16()); + tempPlayer->setMaxMP(msg.readInt16()); + msg.readInt16(); // speed + tempPlayer->setSubtype(msg.readInt16()); // class (used for race) + int hairStyle = msg.readInt16(); + Uint16 weapon = msg.readInt16(); + tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", true); + tempPlayer->setLevel(msg.readInt16()); + msg.readInt16(); // skill point + tempPlayer->setSprite(SPRITE_BOTTOMCLOTHES, msg.readInt16()); // head bottom + tempPlayer->setSprite(SPRITE_SHIELD, msg.readInt16()); + tempPlayer->setSprite(SPRITE_HAT, msg.readInt16()); // head option top + tempPlayer->setSprite(SPRITE_TOPCLOTHES, msg.readInt16()); // head option mid + tempPlayer->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(msg.readInt16())); + tempPlayer->setSprite(SPRITE_MISC2, msg.readInt16()); + tempPlayer->setName(msg.readString(24)); + for (int i = 0; i < 6; i++) + tempPlayer->setAttributeBase(i + STR, msg.readInt8(), false); + *slot = msg.readInt8(); // character slot + msg.readInt8(); // unknown + + return tempPlayer; +} + +void CharServerHandler::setCharSelectDialog(CharSelectDialog *window) +{ + mCharSelectDialog = window; + updateCharSelectDialog(); +} + +void CharServerHandler::setCharCreateDialog(CharCreateDialog *window) +{ + mCharCreateDialog = window; + + if (!mCharCreateDialog) + return; + + std::vector attributes; + attributes.push_back(_("Strength:")); + attributes.push_back(_("Agility:")); + attributes.push_back(_("Vitality:")); + attributes.push_back(_("Intelligence:")); + attributes.push_back(_("Dexterity:")); + attributes.push_back(_("Luck:")); + + const Token &token = + static_cast(Net::getLoginHandler())->getToken(); + + mCharCreateDialog->setAttributes(attributes, 30, 1, 9); + mCharCreateDialog->setFixedGender(true, token.sex); +} + +void CharServerHandler::requestCharacters() +{ + connect(); +} + +void CharServerHandler::chooseCharacter(Net::Character *character) +{ + mSelectedCharacter = character; + mCharSelectDialog = 0; + + MessageOut outMsg(CMSG_CHAR_SELECT); + outMsg.writeInt8(mSelectedCharacter->slot); +} + +void CharServerHandler::newCharacter(const std::string &name, int slot, + bool gender, int hairstyle, int hairColor, + const std::vector &stats) +{ + MessageOut outMsg(CMSG_CHAR_CREATE); + outMsg.writeString(name, 24); + for (int i = 0; i < 6; i++) + { + outMsg.writeInt8(stats[i]); + } + outMsg.writeInt8(slot); + outMsg.writeInt16(hairColor); + outMsg.writeInt16(hairstyle); +} + +void CharServerHandler::deleteCharacter(Net::Character *character) +{ + mSelectedCharacter = character; + + MessageOut outMsg(CMSG_CHAR_DELETE); + outMsg.writeInt32(mSelectedCharacter->dummy->getId()); + outMsg.writeString("a@a.com", 40); +} + +void CharServerHandler::switchCharacter() +{ + // This is really a map-server packet + MessageOut outMsg(CMSG_PLAYER_RESTART); + outMsg.writeInt8(1); +} + +int CharServerHandler::baseSprite() const +{ + return SPRITE_BASE; +} + +int CharServerHandler::hairSprite() const +{ + return SPRITE_HAIR; +} + +int CharServerHandler::maxSprite() const +{ + return SPRITE_VECTOREND; +} + +void CharServerHandler::connect() +{ + const Token &token = + static_cast(Net::getLoginHandler())->getToken(); + + mNetwork->disconnect(); + mNetwork->connect(charServer); + MessageOut outMsg(CMSG_CHAR_SERVER_CONNECT); + outMsg.writeInt32(token.account_ID); + outMsg.writeInt32(token.session_ID1); + outMsg.writeInt32(token.session_ID2); + // [Fate] The next word is unused by the old char server, so we squeeze in + // mana client version information + outMsg.writeInt16(CLIENT_PROTOCOL_VERSION); + outMsg.writeInt8((token.sex == GENDER_MALE) ? 1 : 0); + + // We get 4 useless bytes before the real answer comes in (what are these?) + mNetwork->skip(4); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/charserverhandler.h b/src/net/tmwa/charserverhandler.h new file mode 100644 index 00000000..e80d22c4 --- /dev/null +++ b/src/net/tmwa/charserverhandler.h @@ -0,0 +1,80 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_CHARSERVERHANDLER_H +#define NET_TA_CHARSERVERHANDLER_H + +#include "net/charhandler.h" +#include "net/serverinfo.h" + +#include "net/tmwa/messagehandler.h" +#include "net/tmwa/token.h" + +class LoginData; + +namespace TmwAthena { + +/** + * Deals with incoming messages from the character server. + */ +class CharServerHandler : public MessageHandler, public Net::CharHandler +{ + public: + CharServerHandler(); + + virtual void handleMessage(Net::MessageIn &msg); + + void setCharSelectDialog(CharSelectDialog *window); + + /** + * Sets the character create dialog. The handler will clean up this + * dialog when a new character is succesfully created, and will unlock + * the dialog when a new character failed to be created. + */ + void setCharCreateDialog(CharCreateDialog *window); + + void requestCharacters(); + + void chooseCharacter(Net::Character *character); + + void newCharacter(const std::string &name, int slot, bool gender, + int hairstyle, int hairColor, + const std::vector &stats); + + void deleteCharacter(Net::Character *character); + + void switchCharacter(); + + int baseSprite() const; + + int hairSprite() const; + + int maxSprite() const; + + void connect(); + + private: + LocalPlayer *readPlayerData(Net::MessageIn &msg, int *slot); +}; + +} // namespace TmwAthena + +#endif // NET_TA_CHARSERVERHANDLER_H diff --git a/src/net/tmwa/chathandler.cpp b/src/net/tmwa/chathandler.cpp new file mode 100644 index 00000000..640d04c1 --- /dev/null +++ b/src/net/tmwa/chathandler.cpp @@ -0,0 +1,248 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/chathandler.h" + +#include "being.h" +#include "beingmanager.h" +#include "game.h" +#include "localplayer.h" +#include "playerrelations.h" + +#include "gui/widgets/chattab.h" + +#include "net/messagein.h" +#include "net/messageout.h" + +#include "net/tmwa/protocol.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#include + +extern Net::ChatHandler *chatHandler; + +namespace TmwAthena { + +ChatHandler::ChatHandler() +{ + static const Uint16 _messages[] = { + SMSG_BEING_CHAT, + SMSG_PLAYER_CHAT, + SMSG_WHISPER, + SMSG_WHISPER_RESPONSE, + SMSG_GM_CHAT, + SMSG_MVP, // MVP + 0 + }; + handledMessages = _messages; + chatHandler = this; +} + +void ChatHandler::handleMessage(Net::MessageIn &msg) +{ + if (!localChatTab) return; + + Being *being; + std::string chatMsg; + std::string nick; + int chatMsgLength; + + switch (msg.getId()) + { + case SMSG_WHISPER_RESPONSE: + switch (msg.readInt8()) + { + case 0x00: + // comment out since we'll local echo in chat.cpp instead, then only report failures + //localChatTab->chatLog("Whisper sent", BY_SERVER); + break; + case 0x01: + localChatTab->chatLog(_("Whisper could not be sent, user " + "is offline."), BY_SERVER); + break; + case 0x02: + localChatTab->chatLog(_("Whisper could not be sent, " + "ignored by user."), BY_SERVER); + break; + } + break; + + // Received whisper + case SMSG_WHISPER: + chatMsgLength = msg.readInt16() - 28; + nick = msg.readString(24); + + if (chatMsgLength <= 0) + break; + + chatMsg = msg.readString(chatMsgLength); + + if (nick != "Server") + { + if (player_relations.hasPermission(nick, PlayerRelation::WHISPER)) + chatWindow->whisper(nick, chatMsg); + } + else + { + localChatTab->chatLog(chatMsg, BY_SERVER); + } + + break; + + // Received speech from being + case SMSG_BEING_CHAT: { + chatMsgLength = msg.readInt16() - 8; + being = beingManager->findBeing(msg.readInt32()); + + if (!being || chatMsgLength <= 0) + break; + + chatMsg = msg.readString(chatMsgLength); + + std::string::size_type pos = chatMsg.find(" : ", 0); + std::string sender_name = ((pos == std::string::npos) + ? "" + : chatMsg.substr(0, pos)); + + // We use getIgnorePlayer instead of ignoringPlayer here because ignorePlayer' side + // effects are triggered right below for Being::IGNORE_SPEECH_FLOAT. + if (player_relations.checkPermissionSilently(sender_name, PlayerRelation::SPEECH_LOG)) + localChatTab->chatLog(chatMsg, BY_OTHER); + + chatMsg.erase(0, pos + 3); + trim(chatMsg); + + if (player_relations.hasPermission(sender_name, PlayerRelation::SPEECH_FLOAT)) + being->setSpeech(chatMsg, SPEECH_TIME); + break; + } + + case SMSG_PLAYER_CHAT: + case SMSG_GM_CHAT: { + chatMsgLength = msg.readInt16() - 4; + + if (chatMsgLength <= 0) + break; + + chatMsg = msg.readString(chatMsgLength); + std::string::size_type pos = chatMsg.find(" : ", 0); + + if (msg.getId() == SMSG_PLAYER_CHAT) + { + localChatTab->chatLog(chatMsg, BY_PLAYER); + + if (pos != std::string::npos) + chatMsg.erase(0, pos + 3); + + trim(chatMsg); + + player_node->setSpeech(chatMsg, SPEECH_TIME); + } + else + { + localChatTab->chatLog(chatMsg, BY_GM); + } + break; + } + + case SMSG_MVP: + // Display MVP player + msg.readInt32(); // id + localChatTab->chatLog(_("MVP player."), BY_SERVER); + break; + } +} + +void ChatHandler::talk(const std::string &text) +{ + std::string mes = player_node->getName() + " : " + text; + + MessageOut outMsg(CMSG_CHAT_MESSAGE); + // Added + 1 in order to let eAthena parse admin commands correctly + outMsg.writeInt16(mes.length() + 4 + 1); + outMsg.writeString(mes, mes.length() + 1); +} + +void ChatHandler::me(const std::string &text) +{ + std::string action = strprintf("*%s*", text.c_str()); + + talk(action); +} + +void ChatHandler::privateMessage(const std::string &recipient, + const std::string &text) +{ + MessageOut outMsg(CMSG_CHAT_WHISPER); + outMsg.writeInt16(text.length() + 28); + outMsg.writeString(recipient, 24); + outMsg.writeString(text, text.length()); +} + +void ChatHandler::channelList() +{ + localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); +} + +void ChatHandler::enterChannel(const std::string &channel, + const std::string &password) +{ + localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); +} + +void ChatHandler::quitChannel(int channelId) +{ + localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); +} + +void ChatHandler::sendToChannel(int channelId, const std::string &text) +{ + localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); +} + +void ChatHandler::userList(const std::string &channel) +{ + localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); +} + +void ChatHandler::setChannelTopic(int channelId, const std::string &text) +{ + localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); +} + +void ChatHandler::setUserMode(int channelId, const std::string &name, int mode) +{ + localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); +} + +void ChatHandler::kickUser(int channelId, const std::string &name) +{ + localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER); +} + +void ChatHandler::who() +{ + MessageOut outMsg(CMSG_WHO_REQUEST); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/chathandler.h b/src/net/tmwa/chathandler.h new file mode 100644 index 00000000..3e035f7e --- /dev/null +++ b/src/net/tmwa/chathandler.h @@ -0,0 +1,68 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_CHATHANDLER_H +#define NET_TA_CHATHANDLER_H + +#include "net/chathandler.h" +#include "net/net.h" + +#include "net/tmwa/messagehandler.h" + +namespace TmwAthena { + +class ChatHandler : public MessageHandler, public Net::ChatHandler +{ + public: + ChatHandler(); + + void handleMessage(Net::MessageIn &msg); + + void talk(const std::string &text); + + void me(const std::string &text); + + void privateMessage(const std::string &recipient, + const std::string &text); + + void channelList(); + + void enterChannel(const std::string &channel, + const std::string &password); + + void quitChannel(int channelId); + + void sendToChannel(int channelId, const std::string &text); + + void userList(const std::string &channel); + + void setChannelTopic(int channelId, const std::string &text); + + void setUserMode(int channelId, const std::string &name, int mode); + + void kickUser(int channelId, const std::string &name); + + void who(); +}; + +} // namespace TmwAthena + +#endif // NET_TA_CHATHANDLER_H diff --git a/src/net/tmwa/gamehandler.cpp b/src/net/tmwa/gamehandler.cpp new file mode 100644 index 00000000..179d98e4 --- /dev/null +++ b/src/net/tmwa/gamehandler.cpp @@ -0,0 +1,174 @@ +/* + * The Mana Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/gamehandler.h" + +#include "client.h" +#include "game.h" +#include "localplayer.h" +#include "log.h" + +#include "gui/widgets/chattab.h" + +#include "gui/okdialog.h" + +#include "net/messagein.h" +#include "net/messageout.h" + +#include "net/tmwa/loginhandler.h" +#include "net/tmwa/network.h" +#include "net/tmwa/protocol.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +extern Net::GameHandler *gameHandler; + +namespace TmwAthena { + +extern ServerInfo mapServer; + +GameHandler::GameHandler() +{ + static const Uint16 _messages[] = { + SMSG_MAP_LOGIN_SUCCESS, + SMSG_SERVER_PING, + SMSG_WHO_ANSWER, + SMSG_CHAR_SWITCH_RESPONSE, + SMSG_MAP_QUIT_RESPONSE, + 0 + }; + handledMessages = _messages; + gameHandler = this; +} + +void GameHandler::handleMessage(Net::MessageIn &msg) +{ + switch (msg.getId()) + { + case SMSG_MAP_LOGIN_SUCCESS: + { + unsigned char direction; + Uint16 x, y; + msg.readInt32(); // server tick + msg.readCoordinates(x, y, direction); + msg.skip(2); // unknown + logger->log("Protocol: Player start position: (%d, %d), Direction: %d", + x, y, direction); + // Switch now or we'll have problems + Client::setState(STATE_GAME); + player_node->setTileCoords(x, y); + } break; + + case SMSG_SERVER_PING: + // We ignore this for now + // int tick = msg.readInt32() + break; + + case SMSG_WHO_ANSWER: + localChatTab->chatLog(strprintf(_("Online users: %d"), + msg.readInt32()), BY_SERVER); + break; + + case SMSG_CHAR_SWITCH_RESPONSE: + if (msg.readInt8()) + { + Client::setState(STATE_SWITCH_CHARACTER); + } + break; + + case SMSG_MAP_QUIT_RESPONSE: + if (msg.readInt8()) + { + new OkDialog(_("Game"), _("Request to quit denied!"), NULL); + } + break; + } +} + +void GameHandler::connect() +{ + mNetwork->connect(mapServer); + + const Token &token = + static_cast(Net::getLoginHandler())->getToken(); + + + if (Client::getState() == STATE_CONNECT_GAME) + { + mCharID = player_node->getId(); + // Change the player's ID to the account ID to match what eAthena uses + player_node->setId(token.account_ID); + } + + // Send login infos + MessageOut outMsg(CMSG_MAP_SERVER_CONNECT); + outMsg.writeInt32(token.account_ID); + outMsg.writeInt32(mCharID); + outMsg.writeInt32(token.session_ID1); + outMsg.writeInt32(token.session_ID2); + outMsg.writeInt8((token.sex == GENDER_MALE) ? 1 : 0); + + // We get 4 useless bytes before the real answer comes in (what are these?) + mNetwork->skip(4); +} + +bool GameHandler::isConnected() +{ + return mNetwork->isConnected(); +} + +void GameHandler::disconnect() +{ + mNetwork->disconnect(); +} + +void GameHandler::inGame() +{ + Game::instance()->changeMap(mMap); +} + +void GameHandler::mapLoaded(const std::string &mapName) +{ + MessageOut outMsg(CMSG_MAP_LOADED); +} + +void GameHandler::who() +{ +} + +void GameHandler::quit() +{ + MessageOut outMsg(CMSG_CLIENT_QUIT); +} + +void GameHandler::ping(int tick) +{ + MessageOut msg(CMSG_CLIENT_PING); + msg.writeInt32(tick); +} + +void GameHandler::setMap(const std::string map) +{ + mMap = map.substr(0, map.rfind(".")); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/gamehandler.h b/src/net/tmwa/gamehandler.h new file mode 100644 index 00000000..ca8d27e6 --- /dev/null +++ b/src/net/tmwa/gamehandler.h @@ -0,0 +1,70 @@ +/* + * The Mana Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_MAPHANDLER_H +#define NET_TA_MAPHANDLER_H + +#include "net/gamehandler.h" +#include "net/net.h" +#include "net/serverinfo.h" + +#include "net/tmwa/messagehandler.h" +#include "net/tmwa/token.h" + +namespace TmwAthena { + +class GameHandler : public MessageHandler, public Net::GameHandler +{ + public: + GameHandler(); + + void handleMessage(Net::MessageIn &msg); + + void connect(); + + bool isConnected(); + + void disconnect(); + + void inGame(); + + void mapLoaded(const std::string &mapName); + + void who(); + + void quit(); + + void ping(int tick); + + bool removeDeadBeings() const { return true; } + + void clear(); + + void setMap(const std::string map); + + private: + std::string mMap; + int mCharID; /// < Saved for map-server switching +}; + +} // namespace TmwAthena + +#endif // NET_TA_MAPHANDLER_H diff --git a/src/net/tmwa/generalhandler.cpp b/src/net/tmwa/generalhandler.cpp new file mode 100644 index 00000000..a975abe8 --- /dev/null +++ b/src/net/tmwa/generalhandler.cpp @@ -0,0 +1,255 @@ +/* + * The Mana Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/generalhandler.h" + +#include "client.h" +#include "configuration.h" +#include "log.h" + +#include "gui/charselectdialog.h" +#include "gui/inventorywindow.h" +#include "gui/register.h" +#include "gui/skilldialog.h" +#include "gui/socialwindow.h" +#include "gui/statuswindow.h" + +#include "net/tmwa/adminhandler.h" +#include "net/tmwa/beinghandler.h" +#include "net/tmwa/buysellhandler.h" +#include "net/tmwa/chathandler.h" +#include "net/tmwa/charserverhandler.h" +#include "net/tmwa/gamehandler.h" +#include "net/tmwa/guildhandler.h" +#include "net/tmwa/inventoryhandler.h" +#include "net/tmwa/itemhandler.h" +#include "net/tmwa/loginhandler.h" +#include "net/tmwa/network.h" +#include "net/tmwa/npchandler.h" +#include "net/tmwa/partyhandler.h" +#include "net/tmwa/playerhandler.h" +#include "net/tmwa/protocol.h" +#include "net/tmwa/tradehandler.h" +#include "net/tmwa/specialhandler.h" + +#include "net/tmwa/gui/guildtab.h" +#include "net/tmwa/gui/partytab.h" + +#include "net/messagein.h" +#include "net/messageout.h" + +#include "resources/itemdb.h" + +#include "utils/gettext.h" + +#include +#include + +extern Net::GeneralHandler *generalHandler; + +namespace TmwAthena { + +ServerInfo charServer; +ServerInfo mapServer; + +extern Guild *taGuild; +extern Party *taParty; + +GeneralHandler::GeneralHandler(): + mAdminHandler(new AdminHandler), + mBeingHandler(new BeingHandler(config.getValue("EnableSync", 0) == 1)), + mBuySellHandler(new BuySellHandler), + mCharHandler(new CharServerHandler), + mChatHandler(new ChatHandler), + mGameHandler(new GameHandler), + mGuildHandler(new GuildHandler), + mInventoryHandler(new InventoryHandler), + mItemHandler(new ItemHandler), + mLoginHandler(new LoginHandler), + mNpcHandler(new NpcHandler), + mPartyHandler(new PartyHandler), + mPlayerHandler(new PlayerHandler), + mSpecialHandler(new SpecialHandler), + mTradeHandler(new TradeHandler) +{ + static const Uint16 _messages[] = { + SMSG_CONNECTION_PROBLEM, + 0 + }; + handledMessages = _messages; + generalHandler = this; + + std::list stats; + stats.push_back(ItemDB::Stat("str", N_("Strength %+d"))); + stats.push_back(ItemDB::Stat("agi", N_("Agility %+d"))); + stats.push_back(ItemDB::Stat("vit", N_("Vitality %+d"))); + stats.push_back(ItemDB::Stat("int", N_("Intelligence %+d"))); + stats.push_back(ItemDB::Stat("dex", N_("Dexterity %+d"))); + stats.push_back(ItemDB::Stat("luck", N_("Luck %+d"))); + + ItemDB::setStatsList(stats); +} + +GeneralHandler::~GeneralHandler() +{ + delete mNetwork; +} + +void GeneralHandler::handleMessage(Net::MessageIn &msg) +{ + int code; + + switch (msg.getId()) + { + case SMSG_CONNECTION_PROBLEM: + code = msg.readInt8(); + logger->log("Connection problem: %i", code); + + switch (code) + { + case 0: + errorMessage = _("Authentication failed."); + break; + case 1: + errorMessage = _("No servers available."); + break; + case 2: + if (Client::getState() == STATE_GAME) + errorMessage = _("Someone else is trying to use this " + "account."); + else + errorMessage = _("This account is already logged in."); + break; + case 3: + errorMessage = _("Speed hack detected."); + break; + case 8: + errorMessage = _("Duplicated login."); + break; + default: + errorMessage = _("Unknown connection error."); + break; + } + Client::setState(STATE_ERROR); + break; + } +} + +void GeneralHandler::load() +{ + (new Network)->registerHandler(this); + + mNetwork->registerHandler(mAdminHandler.get()); + mNetwork->registerHandler(mBeingHandler.get()); + mNetwork->registerHandler(mBuySellHandler.get()); + mNetwork->registerHandler(mChatHandler.get()); + mNetwork->registerHandler(mCharHandler.get()); + mNetwork->registerHandler(mGameHandler.get()); + mNetwork->registerHandler(mGuildHandler.get()); + mNetwork->registerHandler(mInventoryHandler.get()); + mNetwork->registerHandler(mItemHandler.get()); + mNetwork->registerHandler(mLoginHandler.get()); + mNetwork->registerHandler(mNpcHandler.get()); + mNetwork->registerHandler(mPlayerHandler.get()); + mNetwork->registerHandler(mSpecialHandler.get()); + mNetwork->registerHandler(mTradeHandler.get()); + mNetwork->registerHandler(mPartyHandler.get()); +} + +void GeneralHandler::reload() +{ + if (mNetwork) + mNetwork->disconnect(); + + static_cast(mLoginHandler.get())->clearWorlds(); + static_cast(mCharHandler.get())->setCharCreateDialog(0); + static_cast(mCharHandler.get())->setCharSelectDialog(0); +} + +void GeneralHandler::unload() +{ + if (mNetwork) + mNetwork->clearHandlers(); +} + +void GeneralHandler::flushNetwork() +{ + if (!mNetwork) + return; + + mNetwork->flush(); + mNetwork->dispatchMessages(); + + if (mNetwork->getState() == Network::NET_ERROR) + { + if (!mNetwork->getError().empty()) + errorMessage = mNetwork->getError(); + else + errorMessage = _("Got disconnected from server!"); + + Client::setState(STATE_ERROR); + } +} + +void GeneralHandler::guiWindowsLoaded() +{ + inventoryWindow->setSplitAllowed(false); + skillDialog->loadSkills("ea-skills.xml"); + + statusWindow->addAttribute(STR, _("Strength"), true); + statusWindow->addAttribute(AGI, _("Agility"), true); + statusWindow->addAttribute(VIT, _("Vitality"), true); + statusWindow->addAttribute(INT, _("Intelligence"), true); + statusWindow->addAttribute(DEX, _("Dexterity"), true); + statusWindow->addAttribute(LUK, _("Luck"), true); + + statusWindow->addAttribute(ATK, _("Attack"), false); + statusWindow->addAttribute(DEF, _("Defense"), false); + statusWindow->addAttribute(MATK, _("M.Attack"), false); + statusWindow->addAttribute(MDEF, _("M.Defense"), false); + statusWindow->addAttribute(HIT, _("% Accuracy"), false); + statusWindow->addAttribute(FLEE, _("% Evade"), false); + statusWindow->addAttribute(CRIT, _("% Critical"), false); +} + +void GeneralHandler::guiWindowsUnloaded() +{ + socialWindow->removeTab(taGuild); + socialWindow->removeTab(taParty); + + delete guildTab; + guildTab = 0; + + delete partyTab; + partyTab = 0; +} + +void GeneralHandler::clearHandlers() +{ + mNetwork->clearHandlers(); +} + +void GeneralHandler::stateChanged(State oldState, State newState) +{ + // +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/generalhandler.h b/src/net/tmwa/generalhandler.h new file mode 100644 index 00000000..d680f215 --- /dev/null +++ b/src/net/tmwa/generalhandler.h @@ -0,0 +1,78 @@ +/* + * The Mana Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TMWA_GENERALHANDLER_H +#define NET_TMWA_GENERALHANDLER_H + +#include "net/generalhandler.h" +#include "net/net.h" +#include "net/serverinfo.h" + +#include "net/tmwa/messagehandler.h" + +namespace TmwAthena { + +class GeneralHandler : public MessageHandler, public Net::GeneralHandler +{ + public: + GeneralHandler(); + + ~GeneralHandler(); + + void handleMessage(Net::MessageIn &msg); + + void load(); + + void reload(); + + void unload(); + + void flushNetwork(); + + void guiWindowsLoaded(); + + void guiWindowsUnloaded(); + + void clearHandlers(); + + void stateChanged(State oldState, State newState); + + protected: + MessageHandlerPtr mAdminHandler; + MessageHandlerPtr mBeingHandler; + MessageHandlerPtr mBuySellHandler; + MessageHandlerPtr mCharHandler; + MessageHandlerPtr mChatHandler; + MessageHandlerPtr mGameHandler; + MessageHandlerPtr mGuildHandler; + MessageHandlerPtr mInventoryHandler; + MessageHandlerPtr mItemHandler; + MessageHandlerPtr mLoginHandler; + MessageHandlerPtr mNpcHandler; + MessageHandlerPtr mPartyHandler; + MessageHandlerPtr mPlayerHandler; + MessageHandlerPtr mSpecialHandler; + MessageHandlerPtr mTradeHandler; +}; + +} // namespace TmwAthena + +#endif // NET_TA_GENERALHANDLER_H diff --git a/src/net/tmwa/gui/guildtab.cpp b/src/net/tmwa/gui/guildtab.cpp new file mode 100644 index 00000000..794ad5cc --- /dev/null +++ b/src/net/tmwa/gui/guildtab.cpp @@ -0,0 +1,117 @@ +/* + * The Mana Client + * Copyright (C) 2008-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/gui/guildtab.h" + +#include "commandhandler.h" +#include "guild.h" +#include "localplayer.h" + +#include "gui/theme.h" + +#include "net/net.h" +#include "net/guildhandler.h" + +#include "resources/iteminfo.h" +#include "resources/itemdb.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" +#include "utils/stringutils.h" + +namespace TmwAthena { + +extern Guild *taGuild; + +GuildTab::GuildTab() : + ChatTab(_("Guild")) +{ + setTabColor(&Theme::getThemeColor(Theme::GUILD)); +} + +GuildTab::~GuildTab() +{ +} + +void GuildTab::handleInput(const std::string &msg) +{ + Net::getGuildHandler()->chat(taGuild->getId(), msg); +} + +void GuildTab::showHelp() +{ + chatLog(_("/help > Display this help.")); + chatLog(_("/invite > Invite a player to your guild")); + chatLog(_("/leave > Leave the guild you are in")); + chatLog(_("/kick > Kick some one from the guild you are in")); +} + +bool GuildTab::handleCommand(const std::string &type, const std::string &args) +{ + if (type == "help") + { + if (args == "invite") + { + chatLog(_("Command: /invite ")); + chatLog(_("This command invites to the guild you're in.")); + chatLog(_("If the has spaces in it, enclose it in " + "double quotes (\").")); + } + else if (args == "leave") + { + chatLog(_("Command: /leave")); + chatLog(_("This command causes the player to leave the guild.")); + } + else + return false; + } + else if (type == "create" || type == "new") + { + if (args.empty()) + chatLog(_("Guild name is missing."), BY_SERVER); + else + Net::getGuildHandler()->create(args); + } + else if (type == "invite") + { + Net::getGuildHandler()->invite(taGuild->getId(), args); + } + else if (type == "leave") + { + Net::getGuildHandler()->leave(taGuild->getId()); + } + else if (type == "kick") + { + Net::getGuildHandler()->kick(taGuild->getMember(args)); + } + else + return false; + + return true; +} + +void GuildTab::getAutoCompleteList(std::vector &names) const +{ + if (taGuild) + taGuild->getNames(names); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/gui/guildtab.h b/src/net/tmwa/gui/guildtab.h new file mode 100644 index 00000000..031c81bf --- /dev/null +++ b/src/net/tmwa/gui/guildtab.h @@ -0,0 +1,52 @@ +/* + * The Mana Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TA_GUILDTAB_H +#define TA_GUILDTAB_H + +#include "gui/widgets/chattab.h" + +namespace TmwAthena { + +/** + * A tab for a guild chat channel. + */ +class GuildTab : public ChatTab +{ + public: + GuildTab(); + ~GuildTab(); + + void showHelp(); + + bool handleCommand(const std::string &type, const std::string &args); + + protected: + void handleInput(const std::string &msg); + + void getAutoCompleteList(std::vector &names) const; +}; + +extern GuildTab *guildTab; + +} // namespace TmwAthena + +#endif // TA_GUILDTAB_H diff --git a/src/net/tmwa/gui/partytab.cpp b/src/net/tmwa/gui/partytab.cpp new file mode 100644 index 00000000..03dadb04 --- /dev/null +++ b/src/net/tmwa/gui/partytab.cpp @@ -0,0 +1,209 @@ +/* + * The Mana Client + * Copyright (C) 2008-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/gui/partytab.h" + +#include "commandhandler.h" +#include "localplayer.h" +#include "party.h" + +#include "gui/theme.h" + +#include "net/net.h" +#include "net/partyhandler.h" + +#include "resources/iteminfo.h" +#include "resources/itemdb.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" +#include "utils/stringutils.h" + +namespace TmwAthena { + +PartyTab::PartyTab() : + ChatTab(_("Party")) +{ + setTabColor(&Theme::getThemeColor(Theme::PARTY)); +} + +PartyTab::~PartyTab() +{ +} + +void PartyTab::handleInput(const std::string &msg) +{ + Net::getPartyHandler()->chat(msg); +} + +void PartyTab::showHelp() +{ + chatLog(_("/help > Display this help.")); + chatLog(_("/invite > Invite a player to your party")); + chatLog(_("/leave > Leave the party you are in")); + chatLog(_("/kick > Kick some one from the party you are in")); + chatLog(_("/item > Show/change party item sharing options")); + chatLog(_("/exp > Show/change party experience sharing options")); +} + +bool PartyTab::handleCommand(const std::string &type, const std::string &args) +{ + if (type == "help") + { + if (args == "invite") + { + chatLog(_("Command: /invite ")); + chatLog(_("This command invites to party with you.")); + chatLog(_("If the has spaces in it, enclose it in " + "double quotes (\").")); + } + else if (args == "leave") + { + chatLog(_("Command: /leave")); + chatLog(_("This command causes the player to leave the party.")); + } + else if (args == "item") + { + chatLog(_("Command: /item ")); + chatLog(_("This command changes the party's item sharing policy.")); + chatLog(_(" can be one of \"1\", \"yes\", \"true\" to " + "enable item sharing, or \"0\", \"no\", \"false\" to " + "disable item sharing.")); + chatLog(_("Command: /item")); + chatLog(_("This command displays the party's current item sharing policy.")); + } + else if (args == "exp") + { + chatLog(_("Command: /exp ")); + chatLog(_("This command changes the party's experience sharing policy.")); + chatLog(_(" can be one of \"1\", \"yes\", \"true\" to " + "enable experience sharing, or \"0\", \"no\", \"false\" to " + "disable experience sharing.")); + chatLog(_("Command: /exp")); + chatLog(_("This command displays the party's current experience sharing policy.")); + } + else + return false; + } + else if (type == "create" || type == "new") + { + if (args.empty()) + chatLog(_("Party name is missing."), BY_SERVER); + else + Net::getPartyHandler()->create(args); + } + else if (type == "invite") + { + Net::getPartyHandler()->invite(args); + } + else if (type == "leave") + { + Net::getPartyHandler()->leave(); + } + else if (type == "kick") + { + Net::getPartyHandler()->kick(args); + } + else if (type == "item") + { + if (args.empty()) + { + switch (Net::getPartyHandler()->getShareItems()) + { + case PARTY_SHARE: + chatLog(_("Item sharing enabled."), BY_SERVER); + return true; + case PARTY_SHARE_NO: + chatLog(_("Item sharing disabled."), BY_SERVER); + return true; + case PARTY_SHARE_NOT_POSSIBLE: + chatLog(_("Item sharing not possible."), BY_SERVER); + return true; + case PARTY_SHARE_UNKNOWN: + chatLog(_("Item sharing unknown."), BY_SERVER); + return true; + } + } + + char opt = CommandHandler::parseBoolean(args); + + switch (opt) + { + case 1: + Net::getPartyHandler()->setShareItems(PARTY_SHARE); + break; + case 0: + Net::getPartyHandler()->setShareItems(PARTY_SHARE_NO); + break; + case -1: + chatLog(strprintf(BOOLEAN_OPTIONS, "item")); + } + } + else if (type == "exp") + { + if (args.empty()) + { + switch (Net::getPartyHandler()->getShareExperience()) + { + case PARTY_SHARE: + chatLog(_("Experience sharing enabled."), BY_SERVER); + return true; + case PARTY_SHARE_NO: + chatLog(_("Experience sharing disabled."), BY_SERVER); + return true; + case PARTY_SHARE_NOT_POSSIBLE: + chatLog(_("Experience sharing not possible."), BY_SERVER); + return true; + case PARTY_SHARE_UNKNOWN: + chatLog(_("Experience sharing unknown."), BY_SERVER); + return true; + } + } + + char opt = CommandHandler::parseBoolean(args); + + switch (opt) + { + case 1: + Net::getPartyHandler()->setShareExperience(PARTY_SHARE); + break; + case 0: + Net::getPartyHandler()->setShareExperience(PARTY_SHARE_NO); + break; + case -1: + chatLog(strprintf(BOOLEAN_OPTIONS, "exp")); + } + } + else + return false; + + return true; +} + +void PartyTab::getAutoCompleteList(std::vector &names) const +{ + Party *p = player_node->getParty(); + + if (p) + p->getNames(names); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/gui/partytab.h b/src/net/tmwa/gui/partytab.h new file mode 100644 index 00000000..62027726 --- /dev/null +++ b/src/net/tmwa/gui/partytab.h @@ -0,0 +1,52 @@ +/* + * The Mana Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TA_PARTYTAB_H +#define TA_PARTYTAB_H + +#include "gui/widgets/chattab.h" + +namespace TmwAthena { + +/** + * A tab for a party chat channel. + */ +class PartyTab : public ChatTab +{ + public: + PartyTab(); + ~PartyTab(); + + void showHelp(); + + bool handleCommand(const std::string &type, const std::string &args); + + protected: + void handleInput(const std::string &msg); + + virtual void getAutoCompleteList(std::vector&) const; +}; + +extern PartyTab *partyTab; + +} // namespace TmwAthena + +#endif // TA_PARTYTAB_H diff --git a/src/net/tmwa/guildhandler.cpp b/src/net/tmwa/guildhandler.cpp new file mode 100644 index 00000000..8a106841 --- /dev/null +++ b/src/net/tmwa/guildhandler.cpp @@ -0,0 +1,480 @@ +/* + * The Mana Client + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/guildhandler.h" + +#include "guild.h" +#include "localplayer.h" +#include "log.h" + +#include "gui/socialwindow.h" + +#include "net/tmwa/messagein.h" +#include "net/tmwa/protocol.h" + +#include "net/tmwa/gui/guildtab.h" + +#include "utils/gettext.h" + +extern Net::GuildHandler *guildHandler; + +namespace TmwAthena { + +GuildTab *guildTab = 0; +Guild *taGuild; + +GuildHandler::GuildHandler() +{ + static const Uint16 _messages[] = { + SMSG_GUILD_CREATE_RESPONSE, + SMSG_GUILD_POSITION_INFO, + SMSG_GUILD_MEMBER_LOGIN, + SMSG_GUILD_MASTER_OR_MEMBER, + SMSG_GUILD_BASIC_INFO, + SMSG_GUILD_ALIANCE_INFO, + SMSG_GUILD_MEMBER_LIST, + SMSG_GUILD_POS_NAME_LIST, + SMSG_GUILD_POS_INFO_LIST, + SMSG_GUILD_POSITION_CHANGED, + SMSG_GUILD_MEMBER_POS_CHANGE, + SMSG_GUILD_EMBLEM, + SMSG_GUILD_SKILL_INFO, + SMSG_GUILD_NOTICE, + SMSG_GUILD_INVITE, + SMSG_GUILD_INVITE_ACK, + SMSG_GUILD_LEAVE, + SMSG_GUILD_EXPULSION, + SMSG_GUILD_EXPULSION_LIST, + SMSG_GUILD_MESSAGE, + SMSG_GUILD_SKILL_UP, + SMSG_GUILD_REQ_ALLIANCE, + SMSG_GUILD_REQ_ALLIANCE_ACK, + SMSG_GUILD_DEL_ALLIANCE, + SMSG_GUILD_OPPOSITION_ACK, + SMSG_GUILD_BROKEN, + 0 + }; + handledMessages = _messages; + + guildHandler = this; +} + +GuildHandler::~GuildHandler() +{ + delete guildTab; + guildTab = 0; +} + +void GuildHandler::handleMessage(Net::MessageIn &msg) +{ + switch (msg.getId()) + { + case SMSG_GUILD_CREATE_RESPONSE: + { + int flag = msg.readInt8(); + + if (flag == 0) + { + // Success + } + else if (flag == 1) + { + // Already in a guild + } + else if (flag == 2) + { + // Unable to make (likely name already in use) + } + else if (flag == 3) + { + // Emperium check failed + } + } + break; + + case SMSG_GUILD_POSITION_INFO: + { + int guildId = msg.readInt32(); + int emblem = msg.readInt32(); + int posMode = msg.readInt32(); + msg.readInt32(); // Unused + msg.readInt8(); // Unused + std::string guildName = msg.readString(24); + + logger->log("Guild position info: %d %d %d %s\n", guildId, + emblem, posMode, guildName.c_str()); + } + break; + + case SMSG_GUILD_MEMBER_LOGIN: + msg.readInt32(); // Account ID + msg.readInt32(); // Char ID + msg.readInt32(); // Flag + break; + + case SMSG_GUILD_MASTER_OR_MEMBER: + msg.readInt32(); // Type (0x57 for member, 0xd7 for master) + break; + + case SMSG_GUILD_BASIC_INFO: + { + int guildID = msg.readInt32(); // Guild ID + msg.readInt32(); // Guild level + msg.readInt32(); // 'Connect member' (number online?) + msg.readInt32(); // 'Max member' + msg.readInt32(); // Average level + msg.readInt32(); // Exp + msg.readInt32(); // Next exp + msg.skip(16); // unused + std::string name = msg.readString(24); // Name + msg.readString(24); // Master's name + msg.readString(20); // Castles (ie: "Six Castles" or "None Taken") + + Guild *g = Guild::getGuild(guildID); + g->setName(name); + } + break; + + case SMSG_GUILD_ALIANCE_INFO: + { + int length = msg.readInt16(); + int count = (length - 4) / 32; + + for (int i = 0; i < count; i++) + { + msg.readInt32(); // 'Opposition' + msg.readInt32(); // Other guild ID + msg.readString(24); // Other guild name + } + } + break; + + case SMSG_GUILD_MEMBER_LIST: + { + int length = msg.readInt16(); + int count = (length - 4) / 104; + + taGuild->clearMembers(); + + for (int i = 0; i < count; i++) + { + int id = msg.readInt32(); // Account ID + msg.readInt32(); // Char ID + msg.readInt16(); // Hair + msg.readInt16(); // Hair color + msg.readInt16(); // Gender + msg.readInt16(); // Class + msg.readInt16(); // Level + msg.readInt32(); // Exp + int online = msg.readInt32(); // Online + msg.readInt32(); // Position + msg.skip(50); // unused + std::string name = msg.readString(24); // Name + + GuildMember *m = taGuild->addMember(id, name); + m->setOnline(online); + } + } + break; + + case SMSG_GUILD_POS_NAME_LIST: + { + int length = msg.readInt16(); + int count = (length - 4) / 28; + + for (int i = 0; i < count; i++) + { + msg.readInt32(); // ID + msg.readString(24); // Position name + } + } + break; + + case SMSG_GUILD_POS_INFO_LIST: + { + int length = msg.readInt16(); + int count = (length - 4) / 16; + + for (int i = 0; i < count; i++) + { + msg.readInt32(); // ID + msg.readInt32(); // Mode + msg.readInt32(); // Same ID + msg.readInt32(); // Exp mode + } + } + break; + + case SMSG_GUILD_POSITION_CHANGED: + msg.readInt16(); // Always 44 + msg.readInt32(); // ID + msg.readInt32(); // Mode + msg.readInt32(); // Same ID + msg.readInt32(); // Exp mode + msg.readString(24); // Name + break; + + case SMSG_GUILD_MEMBER_POS_CHANGE: + msg.readInt16(); // Always 16 + msg.readInt32(); // Account ID + msg.readInt32(); // Char ID + msg.readInt32(); // Position + break; + + case SMSG_GUILD_EMBLEM: + { + int length = msg.readInt16(); + + msg.readInt32(); // Guild ID + msg.readInt32(); // Emblem ID + msg.skip(length - 12); // Emblem data (unknown format) + } + break; + + case SMSG_GUILD_SKILL_INFO: + { + int length = msg.readInt16(); + int count = (length - 6) / 37; + + msg.readInt16(); // 'Skill point' + + for (int i = 0; i < count; i++) + { + msg.readInt16(); // ID + msg.readInt16(); // 'Info' (unknown atm) + msg.readInt16(); // unused + msg.readInt16(); // Level + msg.readInt16(); // SP + msg.readInt16(); // 'Range' + msg.skip(24); // unused + msg.readInt8(); // Can be increased + } + } + break; + + case SMSG_GUILD_NOTICE: + msg.readString(60); // Mes1 + msg.readString(120); // Mes2 + break; + + case SMSG_GUILD_INVITE: + { + int guildId = msg.readInt32(); + std::string guildName = msg.readString(24); + + socialWindow->showGuildInvite(guildName, guildId, ""); + } + break; + + case SMSG_GUILD_INVITE_ACK: + { + int flag = msg.readInt8(); + + switch (flag) + { + case 0: + guildTab->chatLog(_("Could not inivte user to guild."), + BY_SERVER); + break; + + case 1: + guildTab->chatLog(_("User rejected guild invite."), + BY_SERVER); + break; + + case 2: + guildTab->chatLog(_("User is now part of your guild."), + BY_SERVER); + break; + + case 3: + guildTab->chatLog(_("Your guild is full."), + BY_SERVER); + break; + + default: + guildTab->chatLog(_("Unknown guild invite response."), + BY_SERVER); + break; + } + } + break; + + case SMSG_GUILD_LEAVE: + msg.readString(24); // Name + msg.readString(40); // Message + break; + + case SMSG_GUILD_EXPULSION: + msg.readString(24); // Name (of expulsed?) + msg.readString(40); // Message + msg.skip(24); // unused ("dummy") + break; + + case SMSG_GUILD_EXPULSION_LIST: + { + int length = msg.readInt16(); + int count = (length - 4) / 88; + + for (int i = 0; i < count; i++) + { + msg.readString(24); // Name (of expulsed?) + msg.readString(24); // 'Acc' (name of expulser?) + msg.readString(24); // Message + } + } + break; + + case SMSG_GUILD_MESSAGE: + { + int msgLength = msg.readInt16() - 4; + if (msgLength <= 0) + { + return; + } + guildTab->chatLog(msg.readString(msgLength)); + } + break; + + case SMSG_GUILD_SKILL_UP: + msg.readInt16(); // Skill ID + msg.readInt16(); // Level + msg.readInt16(); // SP + msg.readInt16(); // 'Range' + msg.readInt8(); // unused? (always 1) + break; + + case SMSG_GUILD_REQ_ALLIANCE: + msg.readInt32(); // Account ID + msg.readString(24); // Name + break; + + case SMSG_GUILD_REQ_ALLIANCE_ACK: + msg.readInt32(); // Flag + break; + + case SMSG_GUILD_DEL_ALLIANCE: + msg.readInt32(); // Guild ID + msg.readInt32(); // Flag + break; + + case SMSG_GUILD_OPPOSITION_ACK: + msg.readInt8(); // Flag + break; + + case SMSG_GUILD_BROKEN: + msg.readInt32(); // Flag + break; + } +} + +void GuildHandler::create(const std::string &name) +{ + localChatTab->chatLog(_("Guild creation isn't supported yet."), + BY_SERVER); + return; + + MessageOut msg(CMSG_GUILD_CREATE); + msg.writeInt32(0); // Unused + msg.writeString(name, 24); +} + +void GuildHandler::invite(int guildId, const std::string &name) +{ + // TODO? +} + +void GuildHandler::invite(int guildId, Player *player) +{ + MessageOut msg(CMSG_GUILD_INVITE); + msg.writeInt32(player->getId()); + msg.writeInt32(0); // Unused + msg.writeInt32(0); // Unused +} + +void GuildHandler::inviteResponse(int guildId, bool response) +{ + MessageOut msg(CMSG_GUILD_INVITE_REPLY); + msg.writeInt32(guildId); + msg.writeInt8(response); + msg.writeInt8(0); // Unused + msg.writeInt16(0); // Unused +} + +void GuildHandler::leave(int guildId) +{ + MessageOut msg(CMSG_GUILD_LEAVE); + msg.writeInt32(guildId); + msg.writeInt32(0); // Account ID + msg.writeInt32(player_node->getId()); + msg.writeString("", 30); // Message +} + +void GuildHandler::kick(GuildMember *member, std::string reason) +{ + MessageOut msg(CMSG_GUILD_EXPULSION); + msg.writeInt32(member->getGuild()->getId()); + msg.writeInt32(member->getID()); // Account ID + msg.writeInt32(0); // Char ID + msg.writeString(reason, 40); // Message +} + +void GuildHandler::chat(int guildId, const std::string &text) +{ + MessageOut msg(CMSG_GUILD_MESSAGE); + msg.writeInt16(text.size() + 4); + msg.writeString(text); +} + +void GuildHandler::memberList(int guildId) +{ + // TODO four types of info requests: + // 0 = basic info + alliance info + // 1 = position name list + member list + // 2 = position name list + position info list + // 3 = skill info + // 4 = expulsion list + + MessageOut msg(CMSG_GUILD_REQUEST_INFO); + msg.writeInt32(1); // Request member list +} + +void GuildHandler::changeMemberPostion(GuildMember *member, int level) +{ + // TODO +} + +void GuildHandler::requestAlliance(int guildId, int otherGuildId) +{ + // TODO +} + +void GuildHandler::requestAllianceResponse(int guildId, int otherGuildId, + bool response) +{ + // TODO +} + +void GuildHandler::endAlliance(int guildId, int otherGuildId) +{ + // TODO +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/guildhandler.h b/src/net/tmwa/guildhandler.h new file mode 100644 index 00000000..39dbe486 --- /dev/null +++ b/src/net/tmwa/guildhandler.h @@ -0,0 +1,71 @@ +/* + * The Mana Client + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_GUILDHANDLER_H +#define NET_TA_GUILDHANDLER_H + +#include "net/guildhandler.h" + +#include "net/tmwa/messagehandler.h" + +namespace TmwAthena { + +class GuildHandler : public Net::GuildHandler, public MessageHandler +{ + public: + GuildHandler(); + + ~GuildHandler(); + + void handleMessage(Net::MessageIn &msg); + + void create(const std::string &name); + + void invite(int guildId, const std::string &name); + + void invite(int guildId, Player *player); + + void inviteResponse(int guildId, bool response); + + void leave(int guildId); + + void kick(GuildMember *member, std::string reason = ""); + + void chat(int guildId, const std::string &text); + + void memberList(int guildId); + + void changeMemberPostion(GuildMember *member, int level); + + void requestAlliance(int guildId, int otherGuildId); + + void requestAllianceResponse(int guildId, int otherGuildId, + bool response); + + void endAlliance(int guildId, int otherGuildId); + + private: + // TmwAthena (and eAthena) only supports one guild per player + Guild *mGuild; +}; + +} + +#endif // NET_TA_GUILDHANDLER_H diff --git a/src/net/tmwa/inventoryhandler.cpp b/src/net/tmwa/inventoryhandler.cpp new file mode 100644 index 00000000..fd979dc6 --- /dev/null +++ b/src/net/tmwa/inventoryhandler.cpp @@ -0,0 +1,519 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/inventoryhandler.h" + +#include "configuration.h" +#include "equipment.h" +#include "inventory.h" +#include "item.h" +#include "itemshortcut.h" +#include "localplayer.h" +#include "log.h" + +#include "gui/widgets/chattab.h" + +#include "net/messagein.h" +#include "net/messageout.h" + +#include "net/tmwa/protocol.h" + +#include "resources/iteminfo.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#include + +extern Net::InventoryHandler *inventoryHandler; + +const Equipment::Slot EQUIP_POINTS[Equipment::EQUIP_VECTOREND] = { + Equipment::EQUIP_LEGS_SLOT, + Equipment::EQUIP_FIGHT1_SLOT, + Equipment::EQUIP_GLOVES_SLOT, + Equipment::EQUIP_RING2_SLOT, + Equipment::EQUIP_RING1_SLOT, + Equipment::EQUIP_FIGHT2_SLOT, + Equipment::EQUIP_FEET_SLOT, + Equipment::EQUIP_NECK_SLOT, + Equipment::EQUIP_HEAD_SLOT, + Equipment::EQUIP_TORSO_SLOT, + Equipment::EQUIP_PROJECTILE_SLOT}; + +namespace TmwAthena { + +int getSlot(int eAthenaSlot) +{ + if (eAthenaSlot == 0) + { + return Equipment::EQUIP_VECTOREND; + } + + if (eAthenaSlot & 0x8000) + return Equipment::EQUIP_PROJECTILE_SLOT; + + int mask = 1; + int position = 0; + while (!(eAthenaSlot & mask)) + { + mask <<= 1; + position++; + } + return EQUIP_POINTS[position]; +} + +enum { debugInventory = 1 }; + +InventoryHandler::InventoryHandler() +{ + static const Uint16 _messages[] = { + SMSG_PLAYER_INVENTORY, + SMSG_PLAYER_INVENTORY_ADD, + SMSG_PLAYER_INVENTORY_REMOVE, + SMSG_PLAYER_INVENTORY_USE, + SMSG_ITEM_USE_RESPONSE, + SMSG_PLAYER_STORAGE_ITEMS, + SMSG_PLAYER_STORAGE_EQUIP, + SMSG_PLAYER_STORAGE_STATUS, + SMSG_PLAYER_STORAGE_ADD, + SMSG_PLAYER_STORAGE_REMOVE, + SMSG_PLAYER_STORAGE_CLOSE, + SMSG_PLAYER_EQUIPMENT, + SMSG_PLAYER_EQUIP, + SMSG_PLAYER_UNEQUIP, + SMSG_PLAYER_ARROW_EQUIP, + SMSG_PLAYER_ATTACK_RANGE, + 0 + }; + handledMessages = _messages; + inventoryHandler = this; + + mStorage = 0; + mStorageWindow = 0; +} + +InventoryHandler::~InventoryHandler() +{ + if (mStorageWindow) + { + mStorageWindow->close(); + mStorageWindow = 0; + } + + delete mStorage; +} + +void InventoryHandler::handleMessage(Net::MessageIn &msg) +{ + int number, flag; + int index, amount, itemId, equipType, arrow; + int identified, cards[4], itemType; + Inventory *inventory = player_node->getInventory(); + + switch (msg.getId()) + { + case SMSG_PLAYER_INVENTORY: + case SMSG_PLAYER_STORAGE_ITEMS: + if (msg.getId() == SMSG_PLAYER_INVENTORY) + { + // Clear inventory - this will be a complete refresh + mEquips.clear(); + player_node->mEquipment->setBackend(&mEquips); + + inventory->clear(); + } + else + { + mInventoryItems.clear(); + } + + msg.readInt16(); // length + number = (msg.getLength() - 4) / 18; + + for (int loop = 0; loop < number; loop++) + { + index = msg.readInt16(); + itemId = msg.readInt16(); + itemType = msg.readInt8(); + identified = msg.readInt8(); + amount = msg.readInt16(); + arrow = msg.readInt16(); + for (int i = 0; i < 4; i++) + cards[i] = msg.readInt16(); + + index -= (msg.getId() == SMSG_PLAYER_INVENTORY) ? + INVENTORY_OFFSET : STORAGE_OFFSET; + + if (debugInventory) + { + logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " + "Qty: %d, Cards: %d, %d, %d, %d", + index, itemId, itemType, identified, amount, + cards[0], cards[1], cards[2], cards[3]); + } + + if (msg.getId() == SMSG_PLAYER_INVENTORY) + { + // Trick because arrows are not considered equipment + bool isEquipment = arrow & 0x8000; + + inventory->setItem(index, itemId, amount, isEquipment); + } + else + { + mInventoryItems.push_back(InventoryItem(index, itemId, + amount, false)); + } + } + break; + + case SMSG_PLAYER_STORAGE_EQUIP: + msg.readInt16(); // length + number = (msg.getLength() - 4) / 20; + + for (int loop = 0; loop < number; loop++) + { + index = msg.readInt16() - STORAGE_OFFSET; + itemId = msg.readInt16(); + itemType = msg.readInt8(); + identified = msg.readInt8(); + amount = 1; + msg.readInt16(); // Equip Point? + msg.readInt16(); // Another Equip Point? + msg.readInt8(); // Attribute (broken) + msg.readInt8(); // Refine level + for (int i = 0; i < 4; i++) + cards[i] = msg.readInt16(); + + if (debugInventory) + { + logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " + "Qty: %d, Cards: %d, %d, %d, %d", + index, itemId, itemType, identified, amount, + cards[0], cards[1], cards[2], cards[3]); + } + + mInventoryItems.push_back(InventoryItem(index, itemId, amount, + false)); + } + break; + + case SMSG_PLAYER_INVENTORY_ADD: + index = msg.readInt16() - INVENTORY_OFFSET; + amount = msg.readInt16(); + itemId = msg.readInt16(); + identified = msg.readInt8(); + msg.readInt8(); // attribute + msg.readInt8(); // refine + for (int i = 0; i < 4; i++) + cards[i] = msg.readInt16(); + equipType = msg.readInt16(); + itemType = msg.readInt8(); + + { + const ItemInfo &itemInfo = ItemDB::get(itemId); + + if (msg.readInt8() > 0) + { + player_node->pickedUp(itemInfo, 0); + } + else + { + player_node->pickedUp(itemInfo, amount); + + Item *item = inventory->getItem(index); + + if (item && item->getId() == itemId) + amount += inventory->getItem(index)->getQuantity(); + + inventory->setItem(index, itemId, amount, equipType != 0); + } + } break; + + case SMSG_PLAYER_INVENTORY_REMOVE: + index = msg.readInt16() - INVENTORY_OFFSET; + amount = msg.readInt16(); + if (Item *item = inventory->getItem(index)) + { + item->increaseQuantity(-amount); + if (item->getQuantity() == 0) + inventory->removeItemAt(index); + } + break; + + case SMSG_PLAYER_INVENTORY_USE: + index = msg.readInt16() - INVENTORY_OFFSET; + msg.readInt16(); // item id + msg.readInt32(); // id + amount = msg.readInt16(); + msg.readInt8(); // type + + if (Item *item = inventory->getItem(index)) + item->setQuantity(amount); + break; + + case SMSG_ITEM_USE_RESPONSE: + index = msg.readInt16() - INVENTORY_OFFSET; + amount = msg.readInt16(); + + if (msg.readInt8() == 0) + { + localChatTab->chatLog(_("Failed to use item."), BY_SERVER); + } + else + { + if (Item *item = inventory->getItem(index)) + item->setQuantity(amount); + } + break; + + case SMSG_PLAYER_STORAGE_STATUS: + /* + * This is the closest we get to an "Open Storage" packet from the + * server. It always comes after the two SMSG_PLAYER_STORAGE_... + * packets that update storage contents. + */ + { + msg.readInt16(); // Used count + int size = msg.readInt16(); // Max size + + if (!mStorage) + mStorage = new Inventory(Inventory::STORAGE, size); + + InventoryItems::iterator it = mInventoryItems.begin(); + InventoryItems::iterator it_end = mInventoryItems.end(); + for (; it != it_end; it++) + mStorage->setItem((*it).slot, (*it).id, (*it).quantity, + (*it).equip); + mInventoryItems.clear(); + + if (!mStorageWindow) + mStorageWindow = new InventoryWindow(mStorage); + } + break; + + case SMSG_PLAYER_STORAGE_ADD: + // Move an item into storage + index = msg.readInt16() - STORAGE_OFFSET; + amount = msg.readInt32(); + itemId = msg.readInt16(); + identified = msg.readInt8(); + msg.readInt8(); // attribute + msg.readInt8(); // refine + for (int i = 0; i < 4; i++) + cards[i] = msg.readInt16(); + + if (Item *item = mStorage->getItem(index)) + { + item->setId(itemId); + item->increaseQuantity(amount); + } + else + { + mStorage->setItem(index, itemId, amount, false); + } + break; + + case SMSG_PLAYER_STORAGE_REMOVE: + // Move an item out of storage + index = msg.readInt16() - STORAGE_OFFSET; + amount = msg.readInt16(); + if (Item *item = mStorage->getItem(index)) + { + item->increaseQuantity(-amount); + if (item->getQuantity() == 0) + mStorage->removeItemAt(index); + } + break; + + case SMSG_PLAYER_STORAGE_CLOSE: + // Storage access has been closed + + // Storage window deletes itself + mStorageWindow = 0; + + mStorage->clear(); + delete mStorage; + mStorage = 0; + break; + + case SMSG_PLAYER_EQUIPMENT: + msg.readInt16(); // length + number = (msg.getLength() - 4) / 20; + + for (int loop = 0; loop < number; loop++) + { + index = msg.readInt16() - INVENTORY_OFFSET; + itemId = msg.readInt16(); + msg.readInt8(); // type + msg.readInt8(); // identify flag + msg.readInt16(); // equip type + equipType = msg.readInt16(); + msg.readInt8(); // attribute + msg.readInt8(); // refine + msg.skip(8); // card + + inventory->setItem(index, itemId, 1, true); + + if (equipType) + { + mEquips.setEquipment(getSlot(equipType), index); + } + } + break; + + case SMSG_PLAYER_EQUIP: + index = msg.readInt16() - INVENTORY_OFFSET; + equipType = msg.readInt16(); + flag = msg.readInt8(); + + if (!flag) + localChatTab->chatLog(_("Unable to equip."), BY_SERVER); + else + mEquips.setEquipment(getSlot(equipType), index); + break; + + case SMSG_PLAYER_UNEQUIP: + index = msg.readInt16() - INVENTORY_OFFSET; + equipType = msg.readInt16(); + flag = msg.readInt8(); + + if (!flag) + localChatTab->chatLog(_("Unable to unequip."), BY_SERVER); + else + mEquips.setEquipment(getSlot(equipType), -1); + break; + + case SMSG_PLAYER_ATTACK_RANGE: + player_node->setAttackRange(msg.readInt16()); + break; + + case SMSG_PLAYER_ARROW_EQUIP: + index = msg.readInt16(); + + if (index <= 1) + break; + + index -= INVENTORY_OFFSET; + + logger->log("Arrows equipped: %i", index); + mEquips.setEquipment(Equipment::EQUIP_PROJECTILE_SLOT, index); + break; + } +} + +void InventoryHandler::equipItem(const Item *item) +{ + if (!item) + return; + + MessageOut outMsg(CMSG_PLAYER_EQUIP); + outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); + outMsg.writeInt16(0); +} + +void InventoryHandler::unequipItem(const Item *item) +{ + if (!item) + return; + + MessageOut outMsg(CMSG_PLAYER_UNEQUIP); + outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); +} + +void InventoryHandler::useItem(const Item *item) +{ + if (!item) + return; + + MessageOut outMsg(CMSG_PLAYER_INVENTORY_USE); + outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); + outMsg.writeInt32(item->getId()); // unused +} + +void InventoryHandler::dropItem(const Item *item, int amount) +{ + // TODO: Fix wrong coordinates of drops, serverside? (what's wrong here?) + MessageOut outMsg(CMSG_PLAYER_INVENTORY_DROP); + outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); + outMsg.writeInt16(amount); +} + +bool InventoryHandler::canSplit(const Item *item) +{ + return false; +} + +void InventoryHandler::splitItem(const Item *item, int amount) +{ + // Not implemented for eAthena (possible?) +} + +void InventoryHandler::moveItem(int oldIndex, int newIndex) +{ + // Not implemented for eAthena (possible?) +} + +void InventoryHandler::openStorage(int type) +{ + // Doesn't apply to eAthena, since opening happens through NPCs? +} + +void InventoryHandler::closeStorage(int type) +{ + MessageOut outMsg(CMSG_CLOSE_STORAGE); +} + +void InventoryHandler::moveItem(int source, int slot, int amount, + int destination) +{ + if (source == Inventory::INVENTORY && destination == Inventory::STORAGE) + { + MessageOut outMsg(CMSG_MOVE_TO_STORAGE); + outMsg.writeInt16(slot + INVENTORY_OFFSET); + outMsg.writeInt32(amount); + } + else if (source == Inventory::STORAGE && destination == Inventory::INVENTORY) + { + MessageOut outMsg(CSMG_MOVE_FROM_STORAGE); + outMsg.writeInt16(slot + STORAGE_OFFSET); + outMsg.writeInt32(amount); + } +} + +size_t InventoryHandler::getSize(int type) const +{ + switch (type) + { + case Inventory::INVENTORY: + return 100; + case Inventory::STORAGE: + return 0; // Comes from server after items + case Inventory::TRADE: + return 12; + case GUILD_STORAGE: + return 0; // Comes from server after items + default: + return 0; + } +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/inventoryhandler.h b/src/net/tmwa/inventoryhandler.h new file mode 100644 index 00000000..82738afe --- /dev/null +++ b/src/net/tmwa/inventoryhandler.h @@ -0,0 +1,164 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_INVENTORYHANDLER_H +#define NET_TA_INVENTORYHANDLER_H + +#include "equipment.h" +#include "inventory.h" +#include "localplayer.h" + +#include "gui/inventorywindow.h" + +#include "net/inventoryhandler.h" +#include "net/net.h" + +#include "net/tmwa/messagehandler.h" + +#include + +namespace TmwAthena { + +class EquipBackend : public Equipment::Backend { + public: + EquipBackend() + { + memset(mEquipment, -1, sizeof(mEquipment)); + } + + Item *getEquipment(int index) const + { + int invyIndex = mEquipment[index]; + if (invyIndex == -1) + { + return NULL; + } + return player_node->getInventory()->getItem(invyIndex); + } + + void clear() + { + for (int i = 0; i < EQUIPMENT_SIZE; i++) + { + if (mEquipment[i] != -1) + { + Item* item = player_node->getInventory()->getItem(i); + if (item) + { + item->setEquipped(false); + } + } + + mEquipment[i] = -1; + } + } + + void setEquipment(int index, int inventoryIndex) + { + // Unequip existing item + Item* item = player_node->getInventory()->getItem(mEquipment[index]); + if (item) + { + item->setEquipped(false); + } + + mEquipment[index] = inventoryIndex; + + item = player_node->getInventory()->getItem(inventoryIndex); + if (item) + { + item->setEquipped(true); + } + } + + private: + int mEquipment[EQUIPMENT_SIZE]; +}; + +/** + * Used to cache storage data until we get size data for it. + */ +class InventoryItem +{ + public: + int slot; + int id; + int quantity; + bool equip; + + InventoryItem(int slot, int id, int quantity, bool equip) + { + this->slot = slot; + this->id = id; + this->quantity = quantity; + this->equip = equip; + } +}; + +typedef std::list InventoryItems; + +class InventoryHandler : public MessageHandler, public Net::InventoryHandler +{ + public: + enum { + GUILD_STORAGE = Inventory::TYPE_END, + CART + }; + + InventoryHandler(); + + ~InventoryHandler(); + + void handleMessage(Net::MessageIn &msg); + + void equipItem(const Item *item); + + void unequipItem(const Item *item); + + void useItem(const Item *item); + + void dropItem(const Item *item, int amount); + + bool canSplit(const Item *item); + + void splitItem(const Item *item, int amount); + + void moveItem(int oldIndex, int newIndex); + + void openStorage(int type); + + void closeStorage(int type); + + void moveItem(int source, int slot, int amount, + int destination); + + size_t getSize(int type) const; + + private: + EquipBackend mEquips; + InventoryItems mInventoryItems; + Inventory *mStorage; + InventoryWindow *mStorageWindow; +}; + +} // namespace TmwAthena + +#endif // NET_TA_INVENTORYHANDLER_H diff --git a/src/net/tmwa/itemhandler.cpp b/src/net/tmwa/itemhandler.cpp new file mode 100644 index 00000000..abc8103b --- /dev/null +++ b/src/net/tmwa/itemhandler.cpp @@ -0,0 +1,68 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/itemhandler.h" + +#include "flooritemmanager.h" + +#include "net/messagein.h" + +#include "net/tmwa/protocol.h" + +namespace TmwAthena { + +ItemHandler::ItemHandler() +{ + static const Uint16 _messages[] = { + SMSG_ITEM_VISIBLE, + SMSG_ITEM_DROPPED, + SMSG_ITEM_REMOVE, + 0 + }; + handledMessages = _messages; +} + +void ItemHandler::handleMessage(Net::MessageIn &msg) +{ + switch (msg.getId()) + { + case SMSG_ITEM_VISIBLE: + case SMSG_ITEM_DROPPED: + { + int id = msg.readInt32(); + int itemId = msg.readInt16(); + msg.readInt8(); // identify flag + int x = msg.readInt16(); + int y = msg.readInt16(); + msg.skip(4); // amount,subX,subY / subX,subY,amount + + floorItemManager->create(id, itemId, x, y); + } + break; + + case SMSG_ITEM_REMOVE: + if (FloorItem *item = floorItemManager->findById(msg.readInt32())) + floorItemManager->destroy(item); + break; + } +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/itemhandler.h b/src/net/tmwa/itemhandler.h new file mode 100644 index 00000000..712eb2bd --- /dev/null +++ b/src/net/tmwa/itemhandler.h @@ -0,0 +1,39 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_ITEMHANDLER_H +#define NET_TA_ITEMHANDLER_H + +#include "net/tmwa/messagehandler.h" + +namespace TmwAthena { + +class ItemHandler : public MessageHandler +{ + public: + ItemHandler(); + + virtual void handleMessage(Net::MessageIn &msg); +}; + +} // namespace TmwAthena + +#endif // NET_TA_ITEMHANDLER_H diff --git a/src/net/tmwa/loginhandler.cpp b/src/net/tmwa/loginhandler.cpp new file mode 100644 index 00000000..7d973ba3 --- /dev/null +++ b/src/net/tmwa/loginhandler.cpp @@ -0,0 +1,315 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/loginhandler.h" + +#include "client.h" +#include "log.h" + +#include "net/logindata.h" +#include "net/messagein.h" +#include "net/messageout.h" + +#include "net/tmwa/network.h" +#include "net/tmwa/protocol.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" +#include "utils/stringutils.h" + +extern Net::LoginHandler *loginHandler; + +namespace TmwAthena { + +extern ServerInfo charServer; + +LoginHandler::LoginHandler(): + mRegistrationEnabled(true) +{ + static const Uint16 _messages[] = { + SMSG_UPDATE_HOST, + SMSG_LOGIN_DATA, + SMSG_LOGIN_ERROR, + SMSG_CHAR_PASSWORD_RESPONSE, + SMSG_SERVER_VERSION_RESPONSE, + 0 + }; + handledMessages = _messages; + loginHandler = this; +} + +LoginHandler::~LoginHandler() +{ + delete_all(mWorlds); +} + +void LoginHandler::handleMessage(Net::MessageIn &msg) +{ + int code, worldCount; + + switch (msg.getId()) + { + case SMSG_CHAR_PASSWORD_RESPONSE: + { + // 0: acc not found, 1: success, 2: password mismatch, 3: pass too short + int errMsg = msg.readInt8(); + // Successful pass change + if (errMsg == 1) + { + Client::setState(STATE_CHANGEPASSWORD_SUCCESS); + } + // pass change failed + else + { + switch (errMsg) + { + case 0: + errorMessage = _("Account was not found. Please re-login."); + break; + case 2: + errorMessage = _("Old password incorrect."); + break; + case 3: + errorMessage = _("New password too short."); + break; + default: + errorMessage = _("Unknown error."); + break; + } + Client::setState(STATE_ACCOUNTCHANGE_ERROR); + } + } + break; + + case SMSG_UPDATE_HOST: + int len; + + len = msg.readInt16() - 4; + mUpdateHost = msg.readString(len); + loginData.updateHost = mUpdateHost; + + logger->log("Received update host \"%s\" from login server.", + mUpdateHost.c_str()); + break; + + case SMSG_LOGIN_DATA: + // Skip the length word + msg.skip(2); + + clearWorlds(); + + worldCount = (msg.getLength() - 47) / 32; + + mToken.session_ID1 = msg.readInt32(); + mToken.account_ID = msg.readInt32(); + mToken.session_ID2 = msg.readInt32(); + msg.skip(30); // unknown + mToken.sex = msg.readInt8() ? GENDER_MALE : GENDER_FEMALE; + + for (int i = 0; i < worldCount; i++) + { + WorldInfo *world = new WorldInfo; + + world->address = msg.readInt32(); + world->port = msg.readInt16(); + world->name = msg.readString(20); + world->online_users = msg.readInt32(); + world->updateHost = mUpdateHost; + msg.skip(2); // unknown + + logger->log("Network: Server: %s (%s:%d)", + world->name.c_str(), + ipToString(world->address), + world->port); + + mWorlds.push_back(world); + } + Client::setState(STATE_WORLD_SELECT); + break; + + case SMSG_LOGIN_ERROR: + code = msg.readInt8(); + logger->log("Login::error code: %i", code); + + switch (code) + { + case 0: + errorMessage = _("Unregistered ID."); + break; + case 1: + errorMessage = _("Wrong password."); + break; + case 2: + errorMessage = _("Account expired."); + break; + case 3: + errorMessage = _("Rejected from server."); + break; + case 4: + errorMessage = _("You have been permanently banned from " + "the game. Please contact the GM team."); + break; + case 6: + errorMessage = strprintf(_("You have been temporarily " + "banned from the game until " + "%s.\nPlease contact the GM " + "team via the forums."), + msg.readString(20).c_str()); + break; + case 9: + errorMessage = _("This user name is already taken."); + break; + default: + errorMessage = _("Unknown error."); + break; + } + Client::setState(STATE_ERROR); + break; + + case SMSG_SERVER_VERSION_RESPONSE: + { + // TODO: verify these! + msg.readInt8(); // -1 + msg.readInt8(); // T + msg.readInt8(); // M + msg.readInt8(); // W + + unsigned int options = msg.readInt32(); + + if (options & 1) + { + // Registeration not allowed + mRegistrationEnabled = false; + } + + //state = STATE_LOGIN; + } + break; + } +} + +void LoginHandler::connect() +{ + mNetwork->connect(mServer); + MessageOut outMsg(CMSG_SERVER_VERSION_REQUEST); +} + +bool LoginHandler::isConnected() +{ + return mNetwork->isConnected(); +} + +void LoginHandler::disconnect() +{ + if (mNetwork->getServer() == mServer) + mNetwork->disconnect(); +} + +bool LoginHandler::isRegistrationEnabled() +{ + return mRegistrationEnabled; +} + +void LoginHandler::getRegistrationDetails() +{ + // Not supported, so move on + Client::setState(STATE_REGISTER); +} + +void LoginHandler::loginAccount(LoginData *loginData) +{ + sendLoginRegister(loginData->username, loginData->password); +} + +void LoginHandler::logout() +{ + // TODO +} + +void LoginHandler::changeEmail(const std::string &email) +{ + // TODO +} + +void LoginHandler::changePassword(const std::string &username, + const std::string &oldPassword, + const std::string &newPassword) +{ + MessageOut outMsg(CMSG_CHAR_PASSWORD_CHANGE); + outMsg.writeString(oldPassword, 24); + outMsg.writeString(newPassword, 24); +} + +void LoginHandler::chooseServer(unsigned int server) +{ + if (server >= mWorlds.size()) + return; + + charServer.clear(); + charServer.hostname = ipToString(mWorlds[server]->address); + charServer.port = mWorlds[server]->port; + + Client::setState(STATE_UPDATE); +} + +void LoginHandler::registerAccount(LoginData *loginData) +{ + std::string username = loginData->username; + username.append((loginData->gender == GENDER_FEMALE) ? "_F" : "_M"); + + sendLoginRegister(username, loginData->password); +} + +void LoginHandler::unregisterAccount(const std::string &username, + const std::string &password) +{ + // TODO +} + +void LoginHandler::sendLoginRegister(const std::string &username, + const std::string &password) +{ + MessageOut outMsg(0x0064); + outMsg.writeInt32(0); // client version + outMsg.writeString(username, 24); + outMsg.writeString(password, 24); + + /* + * eAthena calls the last byte "client version 2", but it isn't used at + * at all. We're retasking it, as a bit mask: + * 0 - can handle the 0x63 "update host" packet + * 1 - defaults to the first char-server (instead of the last) + */ + outMsg.writeInt8(0x03); +} + +Worlds LoginHandler::getWorlds() const +{ + return mWorlds; +} + +void LoginHandler::clearWorlds() +{ + delete_all(mWorlds); + mWorlds.clear(); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/loginhandler.h b/src/net/tmwa/loginhandler.h new file mode 100644 index 00000000..455c75f1 --- /dev/null +++ b/src/net/tmwa/loginhandler.h @@ -0,0 +1,94 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TMWA_LOGINHANDLER_H +#define NET_TMWA_LOGINHANDLER_H + +#include "net/loginhandler.h" + +#include "net/tmwa/messagehandler.h" +#include "net/tmwa/token.h" + +#include + +struct LoginData; + +namespace TmwAthena { + +class LoginHandler : public MessageHandler, public Net::LoginHandler +{ + public: + LoginHandler(); + + ~LoginHandler(); + + void handleMessage(Net::MessageIn &msg); + + void connect(); + + bool isConnected(); + + void disconnect(); + + int supportedOptionalActions() const + { return SetGenderOnRegister; } + + bool isRegistrationEnabled(); + + void getRegistrationDetails(); + + unsigned int getMaxPasswordLength() const { return 25; } + + void loginAccount(LoginData *loginData); + + void logout(); + + void changeEmail(const std::string &email); + + void changePassword(const std::string &username, + const std::string &oldPassword, + const std::string &newPassword); + + void chooseServer(unsigned int server); + + void registerAccount(LoginData *loginData); + + void unregisterAccount(const std::string &username, + const std::string &password); + + Worlds getWorlds() const; + void clearWorlds(); + + const Token &getToken() const { return mToken; } + + private: + void sendLoginRegister(const std::string &username, + const std::string &password); + + bool mRegistrationEnabled; + std::string mUpdateHost; + Worlds mWorlds; + Token mToken; +}; + +} // namespace TmwAthena + +#endif // NET_TA_LOGINHANDLER_H diff --git a/src/net/tmwa/messagehandler.cpp b/src/net/tmwa/messagehandler.cpp new file mode 100644 index 00000000..65e61302 --- /dev/null +++ b/src/net/tmwa/messagehandler.cpp @@ -0,0 +1,47 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/messagehandler.h" + +#include "net/tmwa/network.h" + +#include + +namespace TmwAthena { + +MessageHandler::MessageHandler() + : mNetwork(NULL) +{ +} + +MessageHandler::~MessageHandler() +{ + if (mNetwork) + mNetwork->unregisterHandler(this); +} + +void MessageHandler::setNetwork(Network *network) +{ + assert(!(network && mNetwork)); + mNetwork = network; +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/messagehandler.h b/src/net/tmwa/messagehandler.h new file mode 100644 index 00000000..0fa2e80c --- /dev/null +++ b/src/net/tmwa/messagehandler.h @@ -0,0 +1,58 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_MESSAGEHANDLER_H +#define NET_TA_MESSAGEHANDLER_H + +#include "net/messagehandler.h" +#include "net/messagein.h" + +#include "net/tmwa/messageout.h" + +#include + +#include + +namespace TmwAthena { + +class Network; + +/** + * \ingroup Network + */ +class MessageHandler : public Net::MessageHandler +{ + public: + MessageHandler(); + + ~MessageHandler(); + + void setNetwork(Network *network); + + protected: + Network *mNetwork; +}; + +typedef const std::auto_ptr MessageHandlerPtr; + +} + +#endif // NET_TA_MESSAGEHANDLER_H diff --git a/src/net/tmwa/messagein.cpp b/src/net/tmwa/messagein.cpp new file mode 100644 index 00000000..0074cfdd --- /dev/null +++ b/src/net/tmwa/messagein.cpp @@ -0,0 +1,74 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/messagein.h" + +#include +#include + +#define MAKEWORD(low,high) \ + ((unsigned short)(((unsigned char)(low)) | \ + ((unsigned short)((unsigned char)(high))) << 8)) + +namespace TmwAthena { + +MessageIn::MessageIn(const char *data, unsigned int length): + Net::MessageIn(data, length) +{ + // Read the message ID + mId = readInt16(); +} + +int MessageIn::readInt16() +{ + Sint16 value = -1; + if (mPos + 2 <= mLength) + { +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + Sint16 swap; + memcpy(&swap, mData + mPos, sizeof(Sint16)); + value = SDL_Swap16(swap); +#else + memcpy(&value, mData + mPos, sizeof(Sint16)); +#endif + } + mPos += 2; + return value; +} + +int MessageIn::readInt32() +{ + Sint32 value = -1; + if (mPos + 4 <= mLength) + { +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + Sint32 swap; + memcpy(&swap, mData + mPos, sizeof(Sint32)); + value = SDL_Swap32(swap); +#else + memcpy(&value, mData + mPos, sizeof(Sint32)); +#endif + } + mPos += 4; + return value; +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/messagein.h b/src/net/tmwa/messagein.h new file mode 100644 index 00000000..aa94bba1 --- /dev/null +++ b/src/net/tmwa/messagein.h @@ -0,0 +1,51 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_MESSAGEIN_H +#define NET_TA_MESSAGEIN_H + +#include "net/messagein.h" + +#include +#include + +namespace TmwAthena { + +/** + * Used for parsing an incoming message. + * + * \ingroup Network + */ + class MessageIn : public Net::MessageIn +{ + public: + /** + * Constructor. + */ + MessageIn(const char *data, unsigned int length); + + int readInt16(); /**< Reads a short. */ + int readInt32(); /**< Reads a long. */ +}; + +} + +#endif // NET_TA_MESSAGEIN_H diff --git a/src/net/tmwa/messageout.cpp b/src/net/tmwa/messageout.cpp new file mode 100644 index 00000000..8b407c47 --- /dev/null +++ b/src/net/tmwa/messageout.cpp @@ -0,0 +1,128 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/messageout.h" + +#include "net/tmwa/network.h" + +#include +#include + +#include +#include + +namespace TmwAthena { + +MessageOut::MessageOut(short id): + Net::MessageOut(id) +{ + mNetwork = TmwAthena::Network::instance(); + mData = mNetwork->mOutBuffer + mNetwork->mOutSize; + writeInt16(id); +} + +void MessageOut::expand(size_t bytes) +{ + mNetwork->mOutSize += bytes; +} + +void MessageOut::writeInt16(Sint16 value) +{ + expand(2); +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + Sint16 swap=SDL_Swap16(value); + memcpy(mData + mPos, &swap, sizeof(Sint16)); +#else + memcpy(mData + mPos, &value, sizeof(Sint16)); +#endif + mPos += 2; +} + +void MessageOut::writeInt32(Sint32 value) +{ + expand(4); +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + Sint32 swap=SDL_Swap32(value); + memcpy(mData + mPos, &swap, sizeof(Sint32)); +#else + memcpy(mData + mPos, &value, sizeof(Sint32)); +#endif + mPos += 4; +} + +#define LOBYTE(w) ((unsigned char)(w)) +#define HIBYTE(w) ((unsigned char)(((unsigned short)(w)) >> 8)) + +void MessageOut::writeCoordinates(unsigned short x, unsigned short y, + unsigned char direction) +{ + char *data = mData + mPos; + mNetwork->mOutSize += 3; + mPos += 3; + + short temp; + temp = x; + temp <<= 6; + data[0] = 0; + data[1] = 1; + data[2] = 2; + data[0] = HIBYTE(temp); + data[1] = (unsigned char) temp; + temp = y; + temp <<= 4; + data[1] |= HIBYTE(temp); + data[2] = LOBYTE(temp); + + // Translate direction to eAthena format + switch (direction) + { + case 1: + direction = 0; + break; + case 3: + direction = 1; + break; + case 2: + direction = 2; + break; + case 6: + direction = 3; + break; + case 4: + direction = 4; + break; + case 12: + direction = 5; + break; + case 8: + direction = 6; + break; + case 9: + direction = 7; + break; + default: + // OOPSIE! Impossible or unknown + direction = (unsigned char) -1; + } + data[2] |= direction; +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/messageout.h b/src/net/tmwa/messageout.h new file mode 100644 index 00000000..c9d87a1b --- /dev/null +++ b/src/net/tmwa/messageout.h @@ -0,0 +1,64 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_MESSAGEOUT_H +#define NET_TA_MESSAGEOUT_H + +#include "net/messageout.h" + +#include +#include + +namespace TmwAthena { + +class Network; + +/** + * Used for building an outgoing message. + * + * \ingroup Network + */ +class MessageOut : public Net::MessageOut +{ + public: + /** + * Constructor. + */ + MessageOut(short id); + + void writeInt16(Sint16 value); /**< Writes a short. */ + void writeInt32(Sint32 value); /**< Writes a long. */ + + /** + * Encodes coordinates and direction in 3 bytes. + */ + void writeCoordinates(unsigned short x, unsigned short y, + unsigned char direction); + + private: + void expand(size_t size); + + Network *mNetwork; +}; + +} + +#endif // NET_TA_MESSAGEOUT_H diff --git a/src/net/tmwa/network.cpp b/src/net/tmwa/network.cpp new file mode 100644 index 00000000..ddfbbc5d --- /dev/null +++ b/src/net/tmwa/network.cpp @@ -0,0 +1,478 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/network.h" + +#include "log.h" + +#include "net/messagehandler.h" +#include "net/messagein.h" + +#include "net/tmwa/protocol.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#include +#include + +/** Warning: buffers and other variables are shared, + so there can be only one connection active at a time */ + +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, 50, 3, -1, 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, +// #0x2000 + 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, +}; + +const unsigned int BUFFER_SIZE = 65536; + +namespace TmwAthena { + +int networkThread(void *data) +{ + Network *network = static_cast(data); + + if (!network->realConnect()) + return -1; + + network->receive(); + + return 0; +} + +Network *Network::mInstance = 0; + +Network::Network(): + mSocket(0), + mInBuffer(new char[BUFFER_SIZE]), + mOutBuffer(new char[BUFFER_SIZE]), + mInSize(0), mOutSize(0), + mToSkip(0), + mState(IDLE), + mWorkerThread(0) +{ + SDLNet_Init(); + + mMutex = SDL_CreateMutex(); + mInstance = this; +} + +Network::~Network() +{ + clearHandlers(); + + if (mState != IDLE && mState != NET_ERROR) + disconnect(); + + SDL_DestroyMutex(mMutex); + mInstance = 0; + + delete[] mInBuffer; + delete[] mOutBuffer; + + SDLNet_Quit(); +} + +bool Network::connect(ServerInfo server) +{ + if (mState != IDLE && mState != NET_ERROR) + { + logger->log("Tried to connect an already connected socket!"); + assert(false); + return false; + } + + if (server.hostname.empty()) + { + setError(_("Empty address given to Network::connect()!")); + return false; + } + + logger->log("Network::Connecting to %s:%i", server.hostname.c_str(), + server.port); + + mServer.hostname = server.hostname; + mServer.port = server.port; + + // Reset to sane values + mOutSize = 0; + mInSize = 0; + mToSkip = 0; + + mState = CONNECTING; + mWorkerThread = SDL_CreateThread(networkThread, this); + if (!mWorkerThread) + { + setError("Unable to create network worker thread"); + return false; + } + + return true; +} + +void Network::disconnect() +{ + mState = IDLE; + + if (mWorkerThread) + { + SDL_WaitThread(mWorkerThread, NULL); + mWorkerThread = NULL; + } + + if (mSocket) + { + SDLNet_TCP_Close(mSocket); + mSocket = 0; + } +} + +void Network::registerHandler(MessageHandler *handler) +{ + for (const Uint16 *i = handler->handledMessages; *i; ++i) + { + mMessageHandlers[*i] = handler; + } + + handler->setNetwork(this); +} + +void Network::unregisterHandler(MessageHandler *handler) +{ + for (const Uint16 *i = handler->handledMessages; *i; ++i) + { + mMessageHandlers.erase(*i); + } + + handler->setNetwork(0); +} + +void Network::clearHandlers() +{ + MessageHandlerIterator i; + for (i = mMessageHandlers.begin(); i != mMessageHandlers.end(); ++i) + { + i->second->setNetwork(0); + } + mMessageHandlers.clear(); +} + +void Network::dispatchMessages() +{ + while (messageReady()) + { + MessageIn msg = getNextMessage(); + + MessageHandlerIterator iter = mMessageHandlers.find(msg.getId()); + + if (msg.getLength() == 0) + logger->error("Zero length packet received. Exiting."); + + if (iter != mMessageHandlers.end()) + { + iter->second->handleMessage(msg); + } + else + { + logger->log("Unhandled packet: %x", msg.getId()); + } + + skip(msg.getLength()); + } +} + +void Network::flush() +{ + if (!mOutSize || mState != CONNECTED) + return; + + int ret; + + + SDL_mutexP(mMutex); + ret = SDLNet_TCP_Send(mSocket, mOutBuffer, mOutSize); + if (ret < (int)mOutSize) + { + setError("Error in SDLNet_TCP_Send(): " + + std::string(SDLNet_GetError())); + } + mOutSize = 0; + SDL_mutexV(mMutex); +} + +void Network::skip(int len) +{ + SDL_mutexP(mMutex); + mToSkip += len; + if (!mInSize) + { + SDL_mutexV(mMutex); + return; + } + + if (mInSize >= mToSkip) + { + mInSize -= mToSkip; + memmove(mInBuffer, mInBuffer + mToSkip, mInSize); + mToSkip = 0; + } + else + { + mToSkip -= mInSize; + mInSize = 0; + } + SDL_mutexV(mMutex); +} + +bool Network::messageReady() +{ + int len = -1, msgId; + + SDL_mutexP(mMutex); + if (mInSize >= 2) + { + msgId = readWord(0); + if (msgId == SMSG_SERVER_VERSION_RESPONSE) + len = 10; + else + len = packet_lengths[msgId]; + + if (len == -1 && mInSize > 4) + len = readWord(2); + + } + + bool ret = (mInSize >= static_cast(len)); + SDL_mutexV(mMutex); + + return ret; +} + +MessageIn Network::getNextMessage() +{ + while (!messageReady()) + { + if (mState == NET_ERROR) + break; + } + + SDL_mutexP(mMutex); + int msgId = readWord(0); + int len; + if (msgId == SMSG_SERVER_VERSION_RESPONSE) + len = 10; + else + len = packet_lengths[msgId]; + + if (len == -1) + len = readWord(2); + +#ifdef DEBUG + logger->log("Received packet 0x%x of length %d\n", msgId, len); +#endif + + MessageIn msg(mInBuffer, len); + SDL_mutexV(mMutex); + + return msg; +} + +bool Network::realConnect() +{ + IPaddress ipAddress; + + if (SDLNet_ResolveHost(&ipAddress, mServer.hostname.c_str(), + mServer.port) == -1) + { + std::string errorMessage = _("Unable to resolve host \"") + + mServer.hostname + "\""; + setError(errorMessage); + logger->log("SDLNet_ResolveHost: %s", errorMessage.c_str()); + return false; + } + + mState = CONNECTING; + + mSocket = SDLNet_TCP_Open(&ipAddress); + if (!mSocket) + { + logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); + setError(SDLNet_GetError()); + return false; + } + + logger->log("Network::Started session with %s:%i", + ipToString(ipAddress.host), ipAddress.port); + + mState = CONNECTED; + + return true; +} + +void Network::receive() +{ + SDLNet_SocketSet set; + + if (!(set = SDLNet_AllocSocketSet(1))) + { + setError("Error in SDLNet_AllocSocketSet(): " + + std::string(SDLNet_GetError())); + return; + } + + if (SDLNet_TCP_AddSocket(set, mSocket) == -1) + { + setError("Error in SDLNet_AddSocket(): " + + std::string(SDLNet_GetError())); + } + + while (mState == CONNECTED) + { + // TODO Try to get this to block all the time while still being able + // to escape the loop + int numReady = SDLNet_CheckSockets(set, ((Uint32)500)); + int ret; + switch (numReady) + { + case -1: + logger->log("Error: SDLNet_CheckSockets"); + // FALLTHROUGH + case 0: + break; + + case 1: + // Receive data from the socket + SDL_mutexP(mMutex); + ret = SDLNet_TCP_Recv(mSocket, mInBuffer + mInSize, BUFFER_SIZE - mInSize); + + if (!ret) + { + // We got disconnected + mState = IDLE; + logger->log("Disconnected."); + } + else if (ret < 0) + { + setError(_("Connection to server terminated. ") + + std::string(SDLNet_GetError())); + } + else + { + mInSize += ret; + if (mToSkip) + { + if (mInSize >= mToSkip) + { + mInSize -= mToSkip; + memmove(mInBuffer, mInBuffer + mToSkip, mInSize); + mToSkip = 0; + } + else + { + mToSkip -= mInSize; + mInSize = 0; + } + } + } + SDL_mutexV(mMutex); + break; + + default: + // more than one socket is ready.. + // this should not happen since we only listen once socket. + std::stringstream errorStream; + errorStream << "Error in SDLNet_TCP_Recv(), " << numReady + << " sockets are ready: " << SDLNet_GetError(); + setError(errorStream.str()); + break; + } + } + + if (SDLNet_TCP_DelSocket(set, mSocket) == -1) + { + logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); + } + + SDLNet_FreeSocketSet(set); +} + +Network *Network::instance() +{ + return mInstance; +} + +void Network::setError(const std::string &error) +{ + logger->log("Network error: %s", error.c_str()); + mError = error; + mState = NET_ERROR; +} + +Uint16 Network::readWord(int pos) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + return SDL_Swap16((*(Uint16*)(mInBuffer+(pos)))); +#else + return (*(Uint16*)(mInBuffer+(pos))); +#endif +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/network.h b/src/net/tmwa/network.h new file mode 100644 index 00000000..2c19c218 --- /dev/null +++ b/src/net/tmwa/network.h @@ -0,0 +1,130 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_NETWORK_H +#define NET_TA_NETWORK_H + +#include "net/serverinfo.h" + +#include "net/tmwa/messagehandler.h" +#include "net/tmwa/messagein.h" +#include "net/tmwa/messageout.h" + +#include +#include + +#include +#include + +/** + * Protocol version, reported to the eAthena char and mapserver who can adjust + * the protocol accordingly. + */ +#define CLIENT_PROTOCOL_VERSION 1 + +namespace TmwAthena { + +class Network +{ + public: + Network(); + + ~Network(); + + bool connect(ServerInfo server); + + void disconnect(); + + ServerInfo getServer() const + { return mServer; } + + void registerHandler(MessageHandler *handler); + + void unregisterHandler(MessageHandler *handler); + + void clearHandlers(); + + int getState() const { return mState; } + + const std::string &getError() const { return mError; } + + bool isConnected() const { return mState == CONNECTED; } + + int getInSize() const { return mInSize; } + + void skip(int len); + + bool messageReady(); + + MessageIn getNextMessage(); + + void dispatchMessages(); + + void flush(); + + // ERROR replaced by NET_ERROR because already defined in Windows + enum { + IDLE, + CONNECTED, + CONNECTING, + DATA, + NET_ERROR + }; + + protected: + friend int networkThread(void *data); + friend class MessageOut; + + static Network *instance(); + + void setError(const std::string &error); + + Uint16 readWord(int pos); + + bool realConnect(); + + void receive(); + + TCPsocket mSocket; + + ServerInfo mServer; + + char *mInBuffer, *mOutBuffer; + unsigned int mInSize, mOutSize; + + unsigned int mToSkip; + + int mState; + std::string mError; + + SDL_Thread *mWorkerThread; + SDL_mutex *mMutex; + + typedef std::map MessageHandlers; + typedef MessageHandlers::iterator MessageHandlerIterator; + MessageHandlers mMessageHandlers; + + static Network *mInstance; +}; + +} // namespace TmwAthena + +#endif // NET_TA_NETWORK_H diff --git a/src/net/tmwa/npchandler.cpp b/src/net/tmwa/npchandler.cpp new file mode 100644 index 00000000..e6b16f2d --- /dev/null +++ b/src/net/tmwa/npchandler.cpp @@ -0,0 +1,226 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/npchandler.h" + +#include "beingmanager.h" +#include "localplayer.h" +#include "npc.h" + +#include "gui/npcdialog.h" + +#include "net/messagein.h" +#include "net/messageout.h" +#include "net/net.h" +#include "net/npchandler.h" + +#include "net/tmwa/protocol.h" + +#include + +extern Net::NpcHandler *npcHandler; + +namespace TmwAthena { + +NpcHandler::NpcHandler() +{ + static const Uint16 _messages[] = { + SMSG_NPC_CHOICE, + SMSG_NPC_MESSAGE, + SMSG_NPC_NEXT, + SMSG_NPC_CLOSE, + SMSG_NPC_INT_INPUT, + SMSG_NPC_STR_INPUT, + 0 + }; + handledMessages = _messages; + npcHandler = this; +} + +void NpcHandler::handleMessage(Net::MessageIn &msg) +{ + if (msg.getId() == SMSG_NPC_CHOICE || msg.getId() == SMSG_NPC_MESSAGE) + { + msg.readInt16(); // length + } + + int npcId = msg.readInt32(); + NpcDialogs::iterator diag = mNpcDialogs.find(npcId); + NpcDialog *dialog = 0; + + if (diag == mNpcDialogs.end()) + { + // Empty dialogs don't help + if (msg.getId() == SMSG_NPC_CLOSE) + { + closeDialog(npcId); + return; + } + else if (msg.getId() == SMSG_NPC_NEXT) + { + nextDialog(npcId); + return; + } + else + { + dialog = new NpcDialog(npcId); + Wrapper wrap; + wrap.dialog = dialog; + mNpcDialogs[npcId] = wrap; + } + } + else + { + dialog = diag->second.dialog; + } + + switch (msg.getId()) + { + case SMSG_NPC_CHOICE: + dialog->choiceRequest(); + dialog->parseListItems(msg.readString(msg.getLength() - 8)); + break; + + case SMSG_NPC_MESSAGE: + dialog->addText(msg.readString(msg.getLength() - 8)); + break; + + case SMSG_NPC_CLOSE: + // Show the close button + dialog->showCloseButton(); + break; + + case SMSG_NPC_NEXT: + // Show the next button + dialog->showNextButton(); + break; + + case SMSG_NPC_INT_INPUT: + // Request for an integer + dialog->integerRequest(0); + break; + + case SMSG_NPC_STR_INPUT: + // Request for a string + dialog->textRequest(""); + break; + } + + if (player_node->getCurrentAction() != Being::SIT) + player_node->setAction(Being::STAND); +} + +void NpcHandler::talk(int npcId) +{ + MessageOut outMsg(CMSG_NPC_TALK); + outMsg.writeInt32(npcId); + outMsg.writeInt8(0); // Unused +} + +void NpcHandler::nextDialog(int npcId) +{ + MessageOut outMsg(CMSG_NPC_NEXT_REQUEST); + outMsg.writeInt32(npcId); +} + +void NpcHandler::closeDialog(int npcId) +{ + MessageOut outMsg(CMSG_NPC_CLOSE); + outMsg.writeInt32(npcId); + + NpcDialogs::iterator it = mNpcDialogs.find(npcId); + if (it != mNpcDialogs.end()) + { + (*it).second.dialog->close(); + mNpcDialogs.erase(it); + } +} + +void NpcHandler::listInput(int npcId, int value) +{ + MessageOut outMsg(CMSG_NPC_LIST_CHOICE); + outMsg.writeInt32(npcId); + outMsg.writeInt8(value); +} + +void NpcHandler::integerInput(int npcId, int value) +{ + MessageOut outMsg(CMSG_NPC_INT_RESPONSE); + outMsg.writeInt32(npcId); + outMsg.writeInt32(value); +} + +void NpcHandler::stringInput(int npcId, const std::string &value) +{ + MessageOut outMsg(CMSG_NPC_STR_RESPONSE); + outMsg.writeInt16(value.length() + 9); + outMsg.writeInt32(npcId); + outMsg.writeString(value, value.length()); + outMsg.writeInt8(0); // Prevent problems with string reading +} + +void NpcHandler::sendLetter(int npcId, const std::string &recipient, + const std::string &text) +{ + // TODO +} + +void NpcHandler::startShopping(int beingId) +{ + // TODO +} + +void NpcHandler::buy(int beingId) +{ + MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST); + outMsg.writeInt32(beingId); + outMsg.writeInt8(0); // Buy +} + +void NpcHandler::sell(int beingId) +{ + MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST); + outMsg.writeInt32(beingId); + outMsg.writeInt8(1); // Sell +} + +void NpcHandler::buyItem(int beingId, int itemId, int amount) +{ + MessageOut outMsg(CMSG_NPC_BUY_REQUEST); + outMsg.writeInt16(8); // One item (length of packet) + outMsg.writeInt16(amount); + outMsg.writeInt16(itemId); +} + +void NpcHandler::sellItem(int beingId, int itemId, int amount) +{ + MessageOut outMsg(CMSG_NPC_SELL_REQUEST); + outMsg.writeInt16(8); // One item (length of packet) + outMsg.writeInt16(itemId + INVENTORY_OFFSET); + outMsg.writeInt16(amount); +} + +void NpcHandler::endShopping(int beingId) +{ + // TODO +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/npchandler.h b/src/net/tmwa/npchandler.h new file mode 100644 index 00000000..a40371a6 --- /dev/null +++ b/src/net/tmwa/npchandler.h @@ -0,0 +1,80 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_NPCHANDLER_H +#define NET_TA_NPCHANDLER_H + +#include "net/net.h" +#include "net/npchandler.h" + +#include "net/tmwa/messagehandler.h" + +#include + +class NpcDialog; + +namespace TmwAthena { + +class NpcHandler : public MessageHandler, public Net::NpcHandler +{ + public: + NpcHandler(); + + void handleMessage(Net::MessageIn &msg); + + void talk(int npcId); + + void nextDialog(int npcId); + + void closeDialog(int npcId); + + void listInput(int npcId, int value); + + void integerInput(int npcId, int value); + + void stringInput(int npcId, const std::string &value); + + void sendLetter(int npcId, const std::string &recipient, + const std::string &text); + + void startShopping(int beingId); + + void buy(int beingId); + + void sell(int beingId); + + void buyItem(int beingId, int itemId, int amount); + + void sellItem(int beingId, int itemId, int amount); + + void endShopping(int beingId); + + private: + typedef struct { + NpcDialog* dialog; + } Wrapper; + typedef std::map NpcDialogs; + NpcDialogs mNpcDialogs; +}; + +} // namespace TmwAthena + +#endif // NET_TA_NPCHANDLER_H diff --git a/src/net/tmwa/partyhandler.cpp b/src/net/tmwa/partyhandler.cpp new file mode 100644 index 00000000..440b75f4 --- /dev/null +++ b/src/net/tmwa/partyhandler.cpp @@ -0,0 +1,411 @@ +/* + * The Mana Client + * Copyright (C) 2008 Lloyd Bryant + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/partyhandler.h" + +#include "beingmanager.h" +#include "localplayer.h" +#include "log.h" + +#include "gui/socialwindow.h" + +#include "net/messagein.h" +#include "net/messageout.h" + +#include "net/tmwa/protocol.h" + +#include "net/tmwa/gui/partytab.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#define PARTY_ID 1 + +extern Net::PartyHandler *partyHandler; + +namespace TmwAthena { + +PartyTab *partyTab = 0; +Party *taParty; + +PartyHandler::PartyHandler(): + mShareExp(PARTY_SHARE_UNKNOWN), mShareItems(PARTY_SHARE_UNKNOWN) +{ + static const Uint16 _messages[] = { + SMSG_PARTY_CREATE, + SMSG_PARTY_INFO, + SMSG_PARTY_INVITE_RESPONSE, + SMSG_PARTY_INVITED, + SMSG_PARTY_SETTINGS, + SMSG_PARTY_MOVE, + SMSG_PARTY_LEAVE, + SMSG_PARTY_UPDATE_HP, + SMSG_PARTY_UPDATE_COORDS, + SMSG_PARTY_MESSAGE, + 0 + }; + handledMessages = _messages; + partyHandler = this; + taParty = Party::getParty(1); +} + +PartyHandler::~PartyHandler() +{ + delete partyTab; + partyTab = 0; +} + +void PartyHandler::handleMessage(Net::MessageIn &msg) +{ + switch (msg.getId()) + { + case SMSG_PARTY_CREATE: + if (msg.readInt8()) + localChatTab->chatLog(_("Could not create party."), BY_SERVER); + else + { + localChatTab->chatLog(_("Party successfully created."), + BY_SERVER); + } + break; + case SMSG_PARTY_INFO: + { + taParty->clearMembers(); + + int length = msg.readInt16(); + taParty->setName(msg.readString(24)); + int count = (length - 28) / 46; + + for (int i = 0; i < count; i++) + { + int id = msg.readInt32(); + std::string nick = msg.readString(24); + std::string map = msg.readString(16); + bool leader = msg.readInt8() == 0; + bool online = msg.readInt8() == 0; + + PartyMember *member = taParty->addMember(id, nick); + member->setLeader(leader); + member->setOnline(online); + } + + player_node->setParty(taParty); + } + break; + case SMSG_PARTY_INVITE_RESPONSE: + { + if (!partyTab) + break; + + std::string nick = msg.readString(24); + switch (msg.readInt8()) + { + case 0: + partyTab->chatLog(strprintf(_("%s is already a member of a party."), + nick.c_str()), BY_SERVER); + break; + case 1: + partyTab->chatLog(strprintf(_("%s refused your invitation."), + nick.c_str()), BY_SERVER); + break; + case 2: + partyTab->chatLog(strprintf(_("%s is now a member of your party."), + nick.c_str()), BY_SERVER); + break; + default: + partyTab->chatLog(strprintf(_("Unknown invite response for %s."), + nick.c_str()), BY_SERVER); + break; + } + break; + } + case SMSG_PARTY_INVITED: + { + int id = msg.readInt32(); + std::string partyName = msg.readString(24); + std::string nick = ""; + Being *being; + + if (!(being = beingManager->findBeing(id))) + { + if (being->getType() == Being::PLAYER) + { + nick = being->getName(); + } + } + + socialWindow->showPartyInvite(partyName, nick); + break; + } + case SMSG_PARTY_SETTINGS: + { + if (!partyTab) + { + if (!chatWindow) + break; + + partyTab = new PartyTab(); + } + + // These seem to indicate the sharing mode for exp and items + short exp = msg.readInt16(); + short item = msg.readInt16(); + + switch (exp) + { + case PARTY_SHARE: + if (mShareExp == PARTY_SHARE) + break; + mShareExp = PARTY_SHARE; + partyTab->chatLog(_("Experience sharing enabled."), BY_SERVER); + break; + case PARTY_SHARE_NO: + if (mShareExp == PARTY_SHARE_NO) + break; + mShareExp = PARTY_SHARE_NO; + partyTab->chatLog(_("Experience sharing disabled."), BY_SERVER); + break; + case PARTY_SHARE_NOT_POSSIBLE: + if (mShareExp == PARTY_SHARE_NOT_POSSIBLE) + break; + mShareExp = PARTY_SHARE_NOT_POSSIBLE; + partyTab->chatLog(_("Experience sharing not possible."), BY_SERVER); + break; + default: + logger->log("Unknown party exp option: %d\n", exp); + } + + switch (item) + { + case PARTY_SHARE: + if (mShareItems == PARTY_SHARE) + break; + mShareItems = PARTY_SHARE; + partyTab->chatLog(_("Item sharing enabled."), BY_SERVER); + break; + case PARTY_SHARE_NO: + if (mShareItems == PARTY_SHARE_NO) + break; + mShareItems = PARTY_SHARE_NO; + partyTab->chatLog(_("Item sharing disabled."), BY_SERVER); + break; + case PARTY_SHARE_NOT_POSSIBLE: + if (mShareItems == PARTY_SHARE_NOT_POSSIBLE) + break; + mShareItems = PARTY_SHARE_NOT_POSSIBLE; + partyTab->chatLog(_("Item sharing not possible."), BY_SERVER); + break; + default: + logger->log("Unknown party item option: %d\n", exp); + } + break; + } + case SMSG_PARTY_MOVE: + { + msg.readInt32(); // id + msg.skip(4); + msg.readInt16(); // x + msg.readInt16(); // y + msg.readInt8(); // online (if 0) + msg.readString(24); // party + msg.readString(24); // nick + msg.readString(16); // map + } + break; + case SMSG_PARTY_LEAVE: + { + int id = msg.readInt32(); + std::string nick = msg.readString(24); + msg.readInt8(); // fail + if (id == player_node->getId()) + { + taParty->removeFromMembers(); + taParty->clearMembers(); + localChatTab->chatLog(_("You have left the party."), + BY_SERVER); + if (partyTab) + { + delete partyTab; + partyTab = 0; + } + socialWindow->removeTab(taParty); + } + else + { + partyTab->chatLog(strprintf(_("%s has left your party."), + nick.c_str()), BY_SERVER); + + Being *b = beingManager->findBeing(id); + if (b->getType() == Being::PLAYER) + static_cast(b)->setParty(NULL); + + taParty->removeMember(id); + } + break; + } + case SMSG_PARTY_UPDATE_HP: + { + int id = msg.readInt32(); + int hp = msg.readInt16(); + int maxhp = msg.readInt16(); + PartyMember *m = taParty->getMember(id); + if (m) + { + m->setHp(hp); + m->setMaxHp(maxhp); + } + + // The server only sends this when the member is in range, so + // lets make sure they get the party hilight. + if (Being *b = beingManager->findBeing(id)) + { + static_cast(b)->setParty(taParty); + } + } + break; + case SMSG_PARTY_UPDATE_COORDS: + { + msg.readInt32(); // id + msg.readInt16(); // x + msg.readInt16(); // y + } + break; + case SMSG_PARTY_MESSAGE: + { + int msgLength = msg.readInt16() - 8; + if (msgLength <= 0) + { + return; + } + int id = msg.readInt32(); + std::string chatMsg = msg.readString(msgLength); + + PartyMember *member = taParty->getMember(id); + if (member) + partyTab->chatLog(member->getName(), chatMsg); + else + partyTab->chatLog(strprintf(_("An unknown member tried to " + "say: %s"), chatMsg.c_str()), BY_SERVER); + } + break; + } +} + +void PartyHandler::create(const std::string &name) +{ + MessageOut outMsg(CMSG_PARTY_CREATE); + outMsg.writeString(name.substr(0, 23), 24); +} + +void PartyHandler::join(int partyId) +{ + // TODO? +} + +void PartyHandler::invite(Player *player) +{ + MessageOut outMsg(CMSG_PARTY_INVITE); + outMsg.writeInt32(player->getId()); +} + +void PartyHandler::invite(const std::string &name) +{ + if (partyTab) + { + partyTab->chatLog(_("Inviting like this isn't supported at the moment."), + BY_SERVER); + } + else + { + localChatTab->chatLog(_("You can only inivte when you are in a party!"), + BY_SERVER); + } + + // TODO? +} + +void PartyHandler::inviteResponse(const std::string &inviter, bool accept) +{ + MessageOut outMsg(CMSG_PARTY_INVITED); + outMsg.writeInt32(player_node->getId()); + outMsg.writeInt32(accept ? 1 : 0); +} + +void PartyHandler::leave() +{ + MessageOut outMsg(CMSG_PARTY_LEAVE); +} + +void PartyHandler::kick(Player *player) +{ + MessageOut outMsg(CMSG_PARTY_KICK); + outMsg.writeInt32(player->getId()); + outMsg.writeString("", 24); //Unused +} + +void PartyHandler::kick(const std::string &name) +{ + PartyMember *m = taParty->getMember(name); + if (!m) + { + partyTab->chatLog(strprintf(_("%s is not in your party!"), name.c_str()), + BY_SERVER); + return; + } + + MessageOut outMsg(CMSG_PARTY_KICK); + outMsg.writeInt32(m->getID()); + outMsg.writeString(name, 24); //Unused +} + +void PartyHandler::chat(const std::string &text) +{ + MessageOut outMsg(CMSG_PARTY_MESSAGE); + outMsg.writeInt16(text.length() + 4); + outMsg.writeString(text, text.length()); +} + +void PartyHandler::requestPartyMembers() +{ + // Our eAthena doesn't have this message + // Not needed anyways +} + +void PartyHandler::setShareExperience(PartyShare share) +{ + if (share == PARTY_SHARE_NOT_POSSIBLE) + return; + + MessageOut outMsg(CMSG_PARTY_SETTINGS); + outMsg.writeInt16(share); + outMsg.writeInt16(mShareItems); +} + +void PartyHandler::setShareItems(PartyShare share) +{ + if (share == PARTY_SHARE_NOT_POSSIBLE) + return; + + MessageOut outMsg(CMSG_PARTY_SETTINGS); + outMsg.writeInt16(mShareExp); + outMsg.writeInt16(share); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/partyhandler.h b/src/net/tmwa/partyhandler.h new file mode 100644 index 00000000..fc8d741f --- /dev/null +++ b/src/net/tmwa/partyhandler.h @@ -0,0 +1,76 @@ +/* + * The Mana Client + * Copyright (C) 2008 Lloyd Bryant + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_PARTYHANDLER_H +#define NET_TA_PARTYHANDLER_H + +#include "net/net.h" +#include "net/partyhandler.h" + +#include "net/tmwa/messagehandler.h" + +#include "party.h" + +namespace TmwAthena { + +class PartyHandler : public MessageHandler, public Net::PartyHandler +{ + public: + PartyHandler(); + + ~PartyHandler(); + + void handleMessage(Net::MessageIn &msg); + + void create(const std::string &name = ""); + + void join(int partyId); + + void invite(Player *player); + + void invite(const std::string &name); + + void inviteResponse(const std::string &inviter, bool accept); + + void leave(); + + void kick(Player *player); + + void kick(const std::string &name); + + void chat(const std::string &text); + + void requestPartyMembers(); + + PartyShare getShareExperience() { return mShareExp; } + + void setShareExperience(PartyShare share); + + PartyShare getShareItems() { return mShareItems; } + + void setShareItems(PartyShare share); + + private: + PartyShare mShareExp, mShareItems; +}; + +} // namespace TmwAthena + +#endif // NET_TA_PARTYHANDLER_H diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp new file mode 100644 index 00000000..afa2c71b --- /dev/null +++ b/src/net/tmwa/playerhandler.cpp @@ -0,0 +1,652 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/playerhandler.h" + +#include "game.h" +#include "localplayer.h" +#include "log.h" +#include "npc.h" +#include "units.h" + +#include "gui/buy.h" +#include "gui/buysell.h" +#include "gui/gui.h" +#include "gui/npcdialog.h" +#include "gui/okdialog.h" +#include "gui/sell.h" +#include "gui/statuswindow.h" +#include "gui/viewport.h" + +#include "gui/widgets/chattab.h" + +#include "net/messagein.h" +#include "net/messageout.h" + +#include "net/tmwa/protocol.h" + +#include "utils/stringutils.h" +#include "utils/gettext.h" + +extern OkDialog *weightNotice; +extern OkDialog *deathNotice; + +// Max. distance we are willing to scroll after a teleport; +// everything beyond will reset the port hard. +static const int MAP_TELEPORT_SCROLL_DISTANCE = 8; + +#define ATTR_BONUS(atr) \ +(player_node->getAttributeEffective(atr) - player_node->getAttributeBase(atr)) + +// TODO Move somewhere else +namespace { + + /** + * Listener used for handling the overweigth message. + */ + struct WeightListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + weightNotice = NULL; + } + } weightListener; + + /** + * Listener used for handling death message. + */ + struct DeathListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + Net::getPlayerHandler()->respawn(); + deathNotice = NULL; + + BuyDialog::closeAll(); + BuySellDialog::closeAll(); + NpcDialog::closeAll(); + SellDialog::closeAll(); + + viewport->closePopupMenu(); + } + } deathListener; + +} // anonymous namespace + +static const char *randomDeathMessage() +{ + static char const *const deadMsg[] = + { + N_("You are dead."), + N_("We regret to inform you that your character was killed in " + "battle."), + N_("You are not that alive anymore."), + N_("The cold hands of the grim reaper are grabbing for your soul."), + N_("Game Over!"), + N_("Insert coin to continue."), + N_("No, kids. Your character did not really die. It... " + "err... went to a better place."), + N_("Your plan of breaking your enemies weapon by " + "bashing it with your throat failed."), + N_("I guess this did not run too well."), + // NetHack reference: + N_("Do you want your possessions identified?"), + // Secret of Mana reference: + N_("Sadly, no trace of you was ever found..."), + // Final Fantasy VI reference: + N_("Annihilated."), + // Earthbound reference: + N_("Looks like you got your head handed to you."), + // Leisure Suit Larry 1 reference: + N_("You screwed up again, dump your body down the tubes " + "and get you another one."), + // Monty Python references (Dead Parrot sketch mostly): + N_("You're not dead yet. You're just resting."), + N_("You are no more."), + N_("You have ceased to be."), + N_("You've expired and gone to meet your maker."), + N_("You're a stiff."), + N_("Bereft of life, you rest in peace."), + N_("If you weren't so animated, you'd be pushing up the daisies."), + N_("Your metabolic processes are now history."), + N_("You're off the twig."), + N_("You've kicked the bucket."), + N_("You've shuffled off your mortal coil, run down the " + "curtain and joined the bleedin' choir invisibile."), + N_("You are an ex-player."), + N_("You're pining for the fjords.") + }; + + const int random = rand() % (sizeof(deadMsg) / sizeof(deadMsg[0])); + return gettext(deadMsg[random]); +} + +extern Net::PlayerHandler *playerHandler; + +namespace TmwAthena { + +PlayerHandler::PlayerHandler() +{ + static const Uint16 _messages[] = { + SMSG_WALK_RESPONSE, + SMSG_PLAYER_WARP, + SMSG_PLAYER_STAT_UPDATE_1, + SMSG_PLAYER_STAT_UPDATE_2, + SMSG_PLAYER_STAT_UPDATE_3, + SMSG_PLAYER_STAT_UPDATE_4, + SMSG_PLAYER_STAT_UPDATE_5, + SMSG_PLAYER_STAT_UPDATE_6, + SMSG_PLAYER_ARROW_MESSAGE, + 0 + }; + handledMessages = _messages; + playerHandler = this; +} + +void PlayerHandler::handleMessage(Net::MessageIn &msg) +{ + switch (msg.getId()) + { + case SMSG_WALK_RESPONSE: + /* + * This client assumes that all walk messages succeed, + * and that the server will send a correction notice + * otherwise. + */ + break; + + case SMSG_PLAYER_WARP: + { + std::string mapPath = msg.readString(16); + int x = msg.readInt16(); + int y = msg.readInt16(); + + logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y); + + /* + * We must clear the local player's target *before* the call + * to changeMap, as it deletes all beings. + */ + player_node->stopAttack(); + + Game *game = Game::instance(); + + const std::string ¤tMapName = game->getCurrentMapName(); + bool sameMap = (currentMapName == mapPath); + + // Switch the actual map, deleting the previous one if necessary + mapPath = mapPath.substr(0, mapPath.rfind(".")); + game->changeMap(mapPath); + + float scrollOffsetX = 0.0f; + float scrollOffsetY = 0.0f; + + /* Scroll if neccessary */ + if (!sameMap + || (abs(x - player_node->getTileX()) > MAP_TELEPORT_SCROLL_DISTANCE) + || (abs(y - player_node->getTileY()) > MAP_TELEPORT_SCROLL_DISTANCE)) + { + Map *map = game->getCurrentMap(); + scrollOffsetX = (x - player_node->getTileX()) + * map->getTileWidth(); + scrollOffsetY = (y - player_node->getTileY()) + * map->getTileHeight(); + } + + player_node->setAction(Being::STAND); + player_node->setFrame(0); + player_node->setTileCoords(x, y); + + logger->log("Adjust scrolling by %d:%d", (int) scrollOffsetX, + (int) scrollOffsetY); + + viewport->scrollBy(scrollOffsetX, scrollOffsetY); + } + break; + + case SMSG_PLAYER_STAT_UPDATE_1: + { + int type = msg.readInt16(); + int value = msg.readInt32(); + + switch (type) + { + case 0x0000: + player_node->setWalkSpeed(Vector(value, value, 0)); + break; + case 0x0004: break; // manner + case 0x0005: player_node->setHp(value); break; + case 0x0006: player_node->setMaxHp(value); break; + case 0x0007: player_node->setMP(value); break; + case 0x0008: player_node->setMaxMP(value); break; + case 0x0009: player_node->setCharacterPoints(value); break; + case 0x000b: player_node->setLevel(value); break; + case 0x000c: player_node->setSkillPoints(value); break; + case 0x0018: + if (value >= player_node->getMaxWeight() / 2 && + player_node->getTotalWeight() < + player_node->getMaxWeight() / 2) + { + weightNotice = new OkDialog(_("Message"), + _("You are carrying more than " + "half your weight. You are " + "unable to regain health.")); + weightNotice->addActionListener( + &weightListener); + } + player_node->setTotalWeight(value); + break; + case 0x0019: player_node->setMaxWeight(value); break; + + case 0x0029: player_node->setAttributeEffective(ATK, value + + ATTR_BONUS(ATK)); + player_node->setAttributeBase(ATK, value); + break; + case 0x002a: value += player_node->getAttributeBase(ATK); + player_node->setAttributeEffective(ATK, value); break; + + case 0x002b: player_node->setAttributeEffective(MATK, value + + ATTR_BONUS(MATK)); + player_node->setAttributeBase(MATK, value); + if (statusWindow) + statusWindow->update(StatusWindow::MP); + break; + case 0x002c: value += player_node->getAttributeBase(MATK); + player_node->setAttributeEffective(MATK, value); + if (statusWindow) + statusWindow->update(StatusWindow::MP); + break; + case 0x002d: player_node->setAttributeEffective(DEF, value + + ATTR_BONUS(DEF)); + player_node->setAttributeBase(DEF, value); break; + case 0x002e: value += player_node->getAttributeBase(DEF); + player_node->setAttributeEffective(DEF, value); break; + + case 0x002f: player_node->setAttributeEffective(MDEF, value + + ATTR_BONUS(MDEF)); + player_node->setAttributeBase(MDEF, value); break; + case 0x0030: value += player_node->getAttributeBase(MDEF); + player_node->setAttributeEffective(MDEF, value); break; + + case 0x0031: player_node->setAttributeBase(HIT, value); + player_node->setAttributeEffective(HIT, value); break; + + case 0x0032: player_node->setAttributeEffective(FLEE, value + + ATTR_BONUS(FLEE)); + player_node->setAttributeBase(FLEE, value); break; + case 0x0033: value += player_node->getAttributeBase(FLEE); + player_node->setAttributeEffective(FLEE, value); break; + + case 0x0034: player_node->setAttributeBase(CRIT, value); + player_node->setAttributeEffective(CRIT, value); break; + + case 0x0035: player_node->setAttackSpeed(value); break; + case 0x0037: player_node->setAttributeBase(JOB, value); + player_node->setAttributeEffective(JOB, value); break; + case 500: player_node->setGMLevel(value); break; + } + + if (player_node->getHp() == 0 && !deathNotice) + { + deathNotice = new OkDialog(_("Message"), + randomDeathMessage(), + false); + deathNotice->addActionListener(&deathListener); + player_node->setAction(Being::DEAD); + } + } + break; + + case SMSG_PLAYER_STAT_UPDATE_2: + switch (msg.readInt16()) + { + case 0x0001: + player_node->setExp(msg.readInt32()); + break; + case 0x0002: + player_node->setExperience(JOB, msg.readInt32(), + player_node->getExperience(JOB).second); + break; + case 0x0014: { + int curGp = player_node->getMoney(); + player_node->setMoney(msg.readInt32()); + if (player_node->getMoney() > curGp) + localChatTab->chatLog(strprintf(_("You picked up " + "%s."), + Units::formatCurrency(player_node->getMoney() + - curGp).c_str()), BY_SERVER); + } + break; + case 0x0016: + player_node->setExpNeeded(msg.readInt32()); + break; + case 0x0017: + player_node->setExperience(JOB, + player_node->getExperience(JOB).first, + msg.readInt32()); + break; + } + break; + + case SMSG_PLAYER_STAT_UPDATE_3: // Update a base attribute + { + int type = msg.readInt32(); + int base = msg.readInt32(); + int bonus = msg.readInt32(); + + player_node->setAttributeBase(type, base); + player_node->setAttributeEffective(type, base + bonus); + } + break; + + case SMSG_PLAYER_STAT_UPDATE_4: // Attribute increase ack + { + int type = msg.readInt16(); + int ok = msg.readInt8(); + int value = msg.readInt8(); + + if (ok != 1) + { + localChatTab->chatLog(_("Cannot raise skill!"), + BY_SERVER); + } + + int bonus = ATTR_BONUS(type); + + player_node->setAttributeBase(type, value); + player_node->setAttributeEffective(type, value + bonus); + } + break; + + // Updates stats and status points + case SMSG_PLAYER_STAT_UPDATE_5: + player_node->setCharacterPoints(msg.readInt16()); + + { + int val = msg.readInt8(); + player_node->setAttributeEffective(STR, val + ATTR_BONUS(STR)); + player_node->setAttributeBase(STR, val); + if (val >= 99) + { + statusWindow->setPointsNeeded(STR, 0); + msg.readInt8(); + } + else + { + statusWindow->setPointsNeeded(STR, msg.readInt8()); + } + + val = msg.readInt8(); + player_node->setAttributeEffective(AGI, val + ATTR_BONUS(AGI)); + player_node->setAttributeBase(AGI, val); + if (val >= 99) + { + statusWindow->setPointsNeeded(AGI, 0); + msg.readInt8(); + } + else + { + statusWindow->setPointsNeeded(AGI, msg.readInt8()); + } + + val = msg.readInt8(); + player_node->setAttributeEffective(VIT, val + ATTR_BONUS(VIT)); + player_node->setAttributeBase(VIT, val); + if (val >= 99) + { + statusWindow->setPointsNeeded(VIT, 0); + msg.readInt8(); + } + else + { + statusWindow->setPointsNeeded(VIT, msg.readInt8()); + } + + val = msg.readInt8(); + player_node->setAttributeEffective(INT, val + ATTR_BONUS(INT)); + player_node->setAttributeBase(INT, val); + if (val >= 99) + { + statusWindow->setPointsNeeded(INT, 0); + msg.readInt8(); + } + else + { + statusWindow->setPointsNeeded(INT, msg.readInt8()); + } + + val = msg.readInt8(); + player_node->setAttributeEffective(DEX, val + ATTR_BONUS(DEX)); + player_node->setAttributeBase(DEX, val); + if (val >= 99) + { + statusWindow->setPointsNeeded(DEX, 0); + msg.readInt8(); + } + else + { + statusWindow->setPointsNeeded(DEX, msg.readInt8()); + } + + val = msg.readInt8(); + player_node->setAttributeEffective(LUK, val + ATTR_BONUS(LUK)); + player_node->setAttributeBase(LUK, val); + if (val >= 99) + { + statusWindow->setPointsNeeded(LUK, 0); + msg.readInt8(); + } + else + { + statusWindow->setPointsNeeded(LUK, msg.readInt8()); + } + + val = msg.readInt16(); // ATK + player_node->setAttributeBase(ATK, val); + val += msg.readInt16(); // ATK bonus + player_node->setAttributeEffective(ATK, val); + + val = msg.readInt16(); // MATK + player_node->setAttributeBase(MATK, val); + val += msg.readInt16(); // MATK bonus + player_node->setAttributeEffective(MATK, val); + statusWindow->update(StatusWindow::MP); + + val = msg.readInt16(); // DEF + player_node->setAttributeBase(DEF, val); + val += msg.readInt16(); // DEF bonus + player_node->setAttributeEffective(DEF, val); + + val = msg.readInt16(); // MDEF + player_node->setAttributeBase(MDEF, val); + val += msg.readInt16(); // MDEF bonus + player_node->setAttributeEffective(MDEF, val); + + val = msg.readInt16(); // HIT + player_node->setAttributeBase(HIT, val); + player_node->setAttributeEffective(HIT, val); + + val = msg.readInt16(); // FLEE + player_node->setAttributeBase(FLEE, val); + val += msg.readInt16(); // FLEE bonus + player_node->setAttributeEffective(FLEE, val); + + val = msg.readInt16(); + player_node->setAttributeBase(CRIT, val); + player_node->setAttributeEffective(CRIT, val); + } + + msg.readInt16(); // manner + break; + + case SMSG_PLAYER_STAT_UPDATE_6: + switch (msg.readInt16()) + { + case 0x0020: + statusWindow->setPointsNeeded(STR, msg.readInt8()); + break; + case 0x0021: + statusWindow->setPointsNeeded(AGI, msg.readInt8()); + break; + case 0x0022: + statusWindow->setPointsNeeded(VIT, msg.readInt8()); + break; + case 0x0023: + statusWindow->setPointsNeeded(INT, msg.readInt8()); + break; + case 0x0024: + statusWindow->setPointsNeeded(DEX, msg.readInt8()); + break; + case 0x0025: + statusWindow->setPointsNeeded(LUK, msg.readInt8()); + break; + } + break; + + case SMSG_PLAYER_ARROW_MESSAGE: + { + int type = msg.readInt16(); + + switch (type) + { + case 0: + localChatTab->chatLog(_("Equip arrows first."), + BY_SERVER); + break; + default: + logger->log("0x013b: Unhandled message %i", type); + break; + } + } + break; + } +} + +void PlayerHandler::attack(int id) +{ + MessageOut outMsg(CMSG_PLAYER_ATTACK); + outMsg.writeInt32(id); + outMsg.writeInt8(0); +} + +void PlayerHandler::emote(int emoteId) +{ + MessageOut outMsg(CMSG_PLAYER_EMOTE); + outMsg.writeInt8(emoteId); +} + +void PlayerHandler::increaseAttribute(int attr) +{ + if (attr >= STR && attr <= LUK) + { + MessageOut outMsg(CMSG_STAT_UPDATE_REQUEST); + outMsg.writeInt16(attr); + outMsg.writeInt8(1); + } +} + +void PlayerHandler::decreaseAttribute(int attr) +{ + // Supported by eA? +} + +void PlayerHandler::increaseSkill(int skillId) +{ + if (player_node->getSkillPoints() <= 0) + return; + + MessageOut outMsg(CMSG_SKILL_LEVELUP_REQUEST); + outMsg.writeInt16(skillId); +} + +void PlayerHandler::pickUp(FloorItem *floorItem) +{ + MessageOut outMsg(CMSG_ITEM_PICKUP); + outMsg.writeInt32(floorItem->getId()); +} + +void PlayerHandler::setDirection(char direction) +{ + MessageOut outMsg(CMSG_PLAYER_CHANGE_DIR); + outMsg.writeInt16(0); + outMsg.writeInt8(direction); +} + +void PlayerHandler::setDestination(int x, int y, int direction) +{ + MessageOut outMsg(CMSG_PLAYER_CHANGE_DEST); + outMsg.writeCoordinates(x, y, direction); +} + +void PlayerHandler::changeAction(Being::Action action) +{ + char type; + switch (action) + { + case Being::SIT: type = 2; break; + case Being::STAND: type = 3; break; + default: return; + } + + MessageOut outMsg(CMSG_PLAYER_CHANGE_ACT); + outMsg.writeInt32(0); + outMsg.writeInt8(type); +} + +void PlayerHandler::respawn() +{ + MessageOut outMsg(CMSG_PLAYER_RESTART); + outMsg.writeInt8(0); +} + +void PlayerHandler::ignorePlayer(const std::string &player, bool ignore) +{ + // TODO +} + +void PlayerHandler::ignoreAll(bool ignore) +{ + // TODO +} + +bool PlayerHandler::canUseMagic() +{ + return player_node->getAttributeEffective(MATK) > 0; +} + +bool PlayerHandler::canCorrectAttributes() +{ + return false; +} + +int PlayerHandler::getJobLocation() +{ + return JOB; +} + +Vector PlayerHandler::getDefaultWalkSpeed() +{ + // Return an normalized speed for any side + // as the offset is calculated elsewhere. + return Vector(150, 150, 0); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/playerhandler.h b/src/net/tmwa/playerhandler.h new file mode 100644 index 00000000..cb352110 --- /dev/null +++ b/src/net/tmwa/playerhandler.h @@ -0,0 +1,66 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_PLAYERHANDLER_H +#define NET_TA_PLAYERHANDLER_H + +#include "net/net.h" +#include "net/playerhandler.h" + +#include "net/tmwa/messagehandler.h" + +namespace TmwAthena { + +class PlayerHandler : public MessageHandler, public Net::PlayerHandler +{ + public: + PlayerHandler(); + + void handleMessage(Net::MessageIn &msg); + + void attack(int id); + void emote(int emoteId); + + void increaseAttribute(int attr); + void decreaseAttribute(int attr); + void increaseSkill(int skillId); + + void pickUp(FloorItem *floorItem); + void setDirection(char direction); + void setDestination(int x, int y, int direction = -1); + void changeAction(Being::Action action); + + void respawn(); + + void ignorePlayer(const std::string &player, bool ignore); + void ignoreAll(bool ignore); + + bool canUseMagic(); + bool canCorrectAttributes(); + + int getJobLocation(); + + Vector getDefaultWalkSpeed(); +}; + +} // namespace TmwAthena + +#endif // NET_TA_PLAYERHANDLER_H diff --git a/src/net/tmwa/protocol.h b/src/net/tmwa/protocol.h new file mode 100644 index 00000000..21d562bc --- /dev/null +++ b/src/net/tmwa/protocol.h @@ -0,0 +1,311 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TA_PROTOCOL_H +#define TA_PROTOCOL_H + +enum { + JOB = 0xa, + + STR = 0xd, + AGI, + VIT, + INT, + DEX, + LUK, + + ATK, + DEF, + MATK, + MDEF, + HIT, + FLEE, + CRIT +}; + +enum +{ + SPRITE_BASE = 0, + SPRITE_SHOE, + SPRITE_BOTTOMCLOTHES, + SPRITE_TOPCLOTHES, + SPRITE_MISC1, + SPRITE_MISC2, + SPRITE_HAIR, + SPRITE_HAT, + SPRITE_CAPE, + SPRITE_GLOVES, + SPRITE_WEAPON, + SPRITE_SHIELD, + SPRITE_VECTOREND +}; + +static const int INVENTORY_OFFSET = 2; +static const int STORAGE_OFFSET = 1; + +/********************************* + * Packets from server to client * + *********************************/ +#define SMSG_SERVER_VERSION_RESPONSE 0x7531 + +#define SMSG_SERVER_PING 0x007f /**< Contains server tick */ +#define SMSG_CONNECTION_PROBLEM 0x0081 + +#define SMSG_UPDATE_HOST 0x0063 /**< Custom update host packet */ +#define SMSG_LOGIN_DATA 0x0069 +#define SMSG_LOGIN_ERROR 0x006a + +#define SMSG_CHAR_LOGIN 0x006b +#define SMSG_CHAR_LOGIN_ERROR 0x006c +#define SMSG_CHAR_CREATE_SUCCEEDED 0x006d +#define SMSG_CHAR_CREATE_FAILED 0x006e +#define SMSG_CHAR_DELETE_SUCCEEDED 0x006f +#define SMSG_CHAR_DELETE_FAILED 0x0070 +#define SMSG_CHAR_MAP_INFO 0x0071 +#define SMSG_CHAR_PASSWORD_RESPONSE 0x0062 /**< Custom packet reply to password change request */ + +#define SMSG_CHAR_SWITCH_RESPONSE 0x00b3 +#define SMSG_CHANGE_MAP_SERVER 0x0092 + +#define SMSG_MAP_LOGIN_SUCCESS 0x0073 /**< Contains starting location */ +#define SMSG_MAP_QUIT_RESPONSE 0x018b +#define SMSG_PLAYER_UPDATE_1 0x01d8 +#define SMSG_PLAYER_UPDATE_2 0x01d9 +#define SMSG_PLAYER_MOVE 0x01da /**< A nearby player moves */ +#define SMSG_PLAYER_STOP 0x0088 /**< Stop walking, set position */ +#define SMSG_PLAYER_MOVE_TO_ATTACK 0x0139 /**< Move to within attack range */ +#define SMSG_PLAYER_STAT_UPDATE_1 0x00b0 +#define SMSG_PLAYER_STAT_UPDATE_2 0x00b1 +#define SMSG_PLAYER_STAT_UPDATE_3 0x0141 +#define SMSG_PLAYER_STAT_UPDATE_4 0x00bc +#define SMSG_PLAYER_STAT_UPDATE_5 0x00bd +#define SMSG_PLAYER_STAT_UPDATE_6 0x00be +#define SMSG_WHO_ANSWER 0x00c2 +#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_ATTACK_RANGE 0x013a +#define SMSG_PLAYER_ARROW_EQUIP 0x013c +#define SMSG_PLAYER_ARROW_MESSAGE 0x013b +#define SMSG_PLAYER_SKILLS 0x010f +#define SMSG_PLAYER_SKILL_UP 0x010e +#define SMSG_SKILL_FAILED 0x0110 +#define SMSG_SKILL_DAMAGE 0x01de +#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_SPAWN 0x007c /**< A being spawns nearby */ +#define SMSG_BEING_MOVE2 0x0086 /**< New eAthena being moves */ +#define SMSG_BEING_REMOVE 0x0080 +#define SMSG_BEING_CHANGE_LOOKS 0x00c3 +#define SMSG_BEING_CHANGE_LOOKS2 0x01d7 /**< Same as 0x00c3, but 16 bit ID */ +#define SMSG_BEING_SELFEFFECT 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_BEING_CHANGE_DIRECTION 0x009c +#define SMSG_BEING_RESURRECT 0x0148 + +#define SMSG_PLAYER_STATUS_CHANGE 0x0119 +#define SMSG_PLAYER_GUILD_PARTY_INFO 0x0195 +#define SMSG_BEING_STATUS_CHANGE 0x0196 + +#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_NPC_INT_INPUT 0x0142 /**< Integer input */ +#define SMSG_NPC_STR_INPUT 0x01d4 /**< String input */ +#define SMSG_PLAYER_CHAT 0x008e /**< Player talks */ +#define SMSG_WHISPER 0x0097 /**< Whisper Recieved */ +#define SMSG_WHISPER_RESPONSE 0x0098 +#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 + +#define SMSG_PARTY_CREATE 0x00fa +#define SMSG_PARTY_INFO 0x00fb +#define SMSG_PARTY_INVITE_RESPONSE 0x00fd +#define SMSG_PARTY_INVITED 0x00fe +#define SMSG_PARTY_SETTINGS 0x0101 +#define SMSG_PARTY_MOVE 0x0104 +#define SMSG_PARTY_LEAVE 0x0105 +#define SMSG_PARTY_UPDATE_HP 0x0106 +#define SMSG_PARTY_UPDATE_COORDS 0x0107 +#define SMSG_PARTY_MESSAGE 0x0109 + +#define SMSG_PLAYER_STORAGE_ITEMS 0x01f0 /**< Item list for storage */ +#define SMSG_PLAYER_STORAGE_EQUIP 0x00a6 /**< Equipment list for storage */ +#define SMSG_PLAYER_STORAGE_STATUS 0x00f2 /**< Slots used and total slots */ +#define SMSG_PLAYER_STORAGE_ADD 0x00f4 /**< Add item/equip to storage */ +#define SMSG_PLAYER_STORAGE_REMOVE 0x00f6 /**< Remove item/equip from storage */ +#define SMSG_PLAYER_STORAGE_CLOSE 0x00f8 /**< Storage access closed */ + +#define SMSG_ADMIN_KICK_ACK 0x00cd + +#define SMSG_GUILD_CREATE_RESPONSE 0x0167 +#define SMSG_GUILD_POSITION_INFO 0x016c +#define SMSG_GUILD_MEMBER_LOGIN 0x016d +#define SMSG_GUILD_MASTER_OR_MEMBER 0x014e +#define SMSG_GUILD_BASIC_INFO 0x01b6 +#define SMSG_GUILD_ALIANCE_INFO 0x014c +#define SMSG_GUILD_MEMBER_LIST 0x0154 +#define SMSG_GUILD_POS_NAME_LIST 0x0166 +#define SMSG_GUILD_POS_INFO_LIST 0x0160 +#define SMSG_GUILD_POSITION_CHANGED 0x0174 +#define SMSG_GUILD_MEMBER_POS_CHANGE 0x0156 +#define SMSG_GUILD_EMBLEM 0x0152 +#define SMSG_GUILD_SKILL_INFO 0x0162 +#define SMSG_GUILD_NOTICE 0x016f +#define SMSG_GUILD_INVITE 0x016a +#define SMSG_GUILD_INVITE_ACK 0x0169 +#define SMSG_GUILD_LEAVE 0x015a +#define SMSG_GUILD_EXPULSION 0x015c +#define SMSG_GUILD_EXPULSION_LIST 0x0163 +#define SMSG_GUILD_MESSAGE 0x017f +#define SMSG_GUILD_SKILL_UP 0x010e +#define SMSG_GUILD_REQ_ALLIANCE 0x0171 +#define SMSG_GUILD_REQ_ALLIANCE_ACK 0x0173 +#define SMSG_GUILD_DEL_ALLIANCE 0x0184 +#define SMSG_GUILD_OPPOSITION_ACK 0x0181 +#define SMSG_GUILD_BROKEN 0x015e + +#define SMSG_MVP 0x010c + +/********************************** + * Packets from client to server * + **********************************/ +#define CMSG_SERVER_VERSION_REQUEST 0x7530 + +#define CMSG_CHAR_PASSWORD_CHANGE 0x0061 /**< Custom change password packet */ +#define CMSG_CHAR_SERVER_CONNECT 0x0065 +#define CMSG_CHAR_SELECT 0x0066 +#define CMSG_CHAR_CREATE 0x0067 +#define CMSG_CHAR_DELETE 0x0068 + +#define CMSG_MAP_SERVER_CONNECT 0x0072 +#define CMSG_CLIENT_PING 0x007e /**< Send to server with tick */ +#define CMSG_MAP_LOADED 0x007d +#define CMSG_CLIENT_QUIT 0x018A + +#define CMSG_CHAT_MESSAGE 0x008c +#define CMSG_CHAT_WHISPER 0x0096 +#define CMSG_CHAT_ANNOUNCE 0x0099 +#define CMSG_CHAT_WHO 0x00c1 + +#define CMSG_SKILL_LEVELUP_REQUEST 0x0112 +#define CMSG_STAT_UPDATE_REQUEST 0x00bb +#define CMSG_SKILL_USE_BEING 0x0113 +#define CMSG_SKILL_USE_POSITION 0x0116 +// Variant of 0x116 with 80 char string at end (unsure of use) +#define CMSG_SKILL_USE_POSITION_MORE 0x0190 +#define CMSG_SKILL_USE_MAP 0x011b + +#define CMSG_PLAYER_INVENTORY_USE 0x00a7 +#define CMSG_PLAYER_INVENTORY_DROP 0x00a2 +#define CMSG_PLAYER_EQUIP 0x00a9 +#define CMSG_PLAYER_UNEQUIP 0x00ab + +#define CMSG_ITEM_PICKUP 0x009f +#define CMSG_PLAYER_CHANGE_DIR 0x009b +#define CMSG_PLAYER_CHANGE_DEST 0x0085 +#define CMSG_PLAYER_CHANGE_ACT 0x0089 +#define CMSG_PLAYER_RESTART 0x00b2 +#define CMSG_PLAYER_EMOTE 0x00bf +#define CMSG_PLAYER_ATTACK 0x0089 +#define CMSG_WHO_REQUEST 0x00c1 + +#define CMSG_NPC_TALK 0x0090 +#define CMSG_NPC_NEXT_REQUEST 0x00b9 +#define CMSG_NPC_CLOSE 0x0146 +#define CMSG_NPC_LIST_CHOICE 0x00b8 +#define CMSG_NPC_INT_RESPONSE 0x0143 +#define CMSG_NPC_STR_RESPONSE 0x01d5 +#define CMSG_NPC_BUY_SELL_REQUEST 0x00c5 +#define CMSG_NPC_BUY_REQUEST 0x00c8 +#define CMSG_NPC_SELL_REQUEST 0x00c9 + +#define CMSG_TRADE_REQUEST 0x00e4 +#define CMSG_TRADE_RESPONSE 0x00e6 +#define CMSG_TRADE_ITEM_ADD_REQUEST 0x00e8 +#define CMSG_TRADE_CANCEL_REQUEST 0x00ed +#define CMSG_TRADE_ADD_COMPLETE 0x00eb +#define CMSG_TRADE_OK 0x00ef + +#define CMSG_PARTY_CREATE 0x00f9 +#define CMSG_PARTY_INVITE 0x00fc +#define CMSG_PARTY_INVITED 0x00ff +#define CMSG_PARTY_LEAVE 0x0100 +#define CMSG_PARTY_SETTINGS 0x0102 +#define CMSG_PARTY_KICK 0x0103 +#define CMSG_PARTY_MESSAGE 0x0108 + +#define CMSG_MOVE_TO_STORAGE 0x00f3 /** Move item to storage */ +#define CSMG_MOVE_FROM_STORAGE 0x00f5 /** Remove item from storage */ +#define CMSG_CLOSE_STORAGE 0x00f7 /** Request storage close */ + +#define CMSG_ADMIN_ANNOUNCE 0x0099 +#define CMSG_ADMIN_LOCAL_ANNOUNCE 0x019C +#define CMSG_ADMIN_HIDE 0x019D +#define CMSG_ADMIN_KICK 0x00CC +#define CMSG_ADMIN_MUTE 0x0149 + +#define CMSG_GUILD_CHECK_MASTER 0x014d +#define CMSG_GUILD_REQUEST_INFO 0x014f +#define CMSG_GUILD_REQUEST_EMBLEM 0x0151 +#define CMSG_GUILD_CHANGE_EMBLEM 0x0153 +#define CMSG_GUILD_CHANGE_MEMBER_POS 0x0155 +#define CMSG_GUILD_LEAVE 0x0159 +#define CMSG_GUILD_EXPULSION 0x015b +#define CMSG_GUILD_BREAK 0x015d +#define CMSG_GUILD_CHANGE_POS_INFO 0x0161 +#define CMSG_GUILD_CREATE 0x0165 +#define CMSG_GUILD_INVITE 0x0168 +#define CMSG_GUILD_INVITE_REPLY 0x016b +#define CMSG_GUILD_CHANGE_NOTICE 0x016e +#define CMSG_GUILD_ALLIANCE_REQUEST 0x0170 +#define CMSG_GUILD_ALLIANCE_REPLY 0x0172 +#define CMSG_GUILD_MESSAGE 0x017e +#define CMSG_GUILD_OPPOSITION 0x0180 +#define CMSG_GUILD_ALLIANCE_DELETE 0x0183 + +#endif diff --git a/src/net/tmwa/specialhandler.cpp b/src/net/tmwa/specialhandler.cpp new file mode 100644 index 00000000..bd1b2e5a --- /dev/null +++ b/src/net/tmwa/specialhandler.cpp @@ -0,0 +1,255 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/specialhandler.h" + +#include "localplayer.h" +#include "log.h" + +#include "gui/skilldialog.h" + +#include "gui/widgets/chattab.h" + +#include "net/messagein.h" +#include "net/messageout.h" + +#include "net/tmwa/protocol.h" + +#include "utils/gettext.h" + +/** job dependend identifiers (?) */ +#define SKILL_BASIC 0x0001 +#define SKILL_WARP 0x001b +#define SKILL_STEAL 0x0032 +#define SKILL_ENVENOM 0x0034 + +/** basic skills identifiers */ +#define BSKILL_TRADE 0x0000 +#define BSKILL_EMOTE 0x0001 +#define BSKILL_SIT 0x0002 +#define BSKILL_CREATECHAT 0x0003 +#define BSKILL_JOINPARTY 0x0004 +#define BSKILL_SHOUT 0x0005 +#define BSKILL_PK 0x0006 // ?? +#define BSKILL_SETALLIGN 0x0007 // ?? + +/** reasons why action failed */ +#define RFAIL_SKILLDEP 0x00 +#define RFAIL_INSUFHP 0x01 +#define RFAIL_INSUFSP 0x02 +#define RFAIL_NOMEMO 0x03 +#define RFAIL_SKILLDELAY 0x04 +#define RFAIL_ZENY 0x05 +#define RFAIL_WEAPON 0x06 +#define RFAIL_REDGEM 0x07 +#define RFAIL_BLUEGEM 0x08 +#define RFAIL_OVERWEIGHT 0x09 +#define RFAIL_GENERIC 0x0a + +/** should always be zero if failed */ +#define SKILL_FAILED 0x00 + +extern Net::SpecialHandler *specialHandler; + +namespace TmwAthena { + +SpecialHandler::SpecialHandler() +{ + static const Uint16 _messages[] = { + SMSG_PLAYER_SKILLS, + SMSG_SKILL_FAILED, + SMSG_PLAYER_SKILL_UP, + 0 + }; + handledMessages = _messages; + specialHandler = this; +} + +void SpecialHandler::handleMessage(Net::MessageIn &msg) +{ + int skillCount; + int skillId; + + switch (msg.getId()) + { + case SMSG_PLAYER_SKILLS: + msg.readInt16(); // length + skillCount = (msg.getLength() - 4) / 37; + + for (int k = 0; k < skillCount; k++) + { + skillId = msg.readInt16(); + msg.readInt16(); // target type + msg.skip(2); // unused + int level = msg.readInt16(); + msg.readInt16(); // sp + msg.readInt16(); // range + msg.skip(24); // unused + int up = msg.readInt8(); + + player_node->setAttributeBase(skillId, level); + player_node->setAttributeEffective(skillId, level); + skillDialog->setModifiable(skillId, up); + } + break; + + case SMSG_PLAYER_SKILL_UP: + { + skillId = msg.readInt16(); + int level = msg.readInt16(); + msg.readInt16(); // sp + msg.readInt16(); // range + int up = msg.readInt8(); + + player_node->setAttributeBase(skillId, level); + player_node->setAttributeEffective(skillId, level); + skillDialog->setModifiable(skillId, up); + } + break; + + case SMSG_SKILL_FAILED: + // Action failed (ex. sit because you have not reached the + // right level) + skillId = msg.readInt16(); + short bskill = msg.readInt16(); + msg.readInt16(); // unknown + char success = msg.readInt8(); + char reason = msg.readInt8(); + if (success != SKILL_FAILED && bskill == BSKILL_EMOTE) + { + logger->log("Action: %d/%d", bskill, success); + } + + std::string msg; + if (success == SKILL_FAILED && skillId == SKILL_BASIC) + { + switch (bskill) + { + case BSKILL_TRADE: + msg = _("Trade failed!"); + break; + case BSKILL_EMOTE: + msg = _("Emote failed!"); + break; + case BSKILL_SIT: + msg = _("Sit failed!"); + break; + case BSKILL_CREATECHAT: + msg = _("Chat creating failed!"); + break; + case BSKILL_JOINPARTY: + msg = _("Could not join party!"); + break; + case BSKILL_SHOUT: + msg = _("Cannot shout!"); + break; + } + + msg += " "; + + switch (reason) + { + case RFAIL_SKILLDEP: + msg += _("You have not yet reached a high enough lvl!"); + break; + case RFAIL_INSUFHP: + msg += _("Insufficient HP!"); + break; + case RFAIL_INSUFSP: + msg += _("Insufficient SP!"); + break; + case RFAIL_NOMEMO: + msg += _("You have no memos!"); + break; + case RFAIL_SKILLDELAY: + msg += _("You cannot do that right now!"); + break; + case RFAIL_ZENY: + msg += _("Seems you need more money... ;-)"); + break; + case RFAIL_WEAPON: + msg += _("You cannot use this skill with that kind of weapon!"); + break; + case RFAIL_REDGEM: + msg += _("You need another red gem!"); + break; + case RFAIL_BLUEGEM: + msg += _("You need another blue gem!"); + break; + case RFAIL_OVERWEIGHT: + msg += _("You're carrying to much to do this!"); + break; + default: + msg += _("Huh? What's that?"); + break; + } + } + else + { + switch (skillId) + { + case SKILL_WARP : + msg = _("Warp failed..."); + break; + case SKILL_STEAL : + msg = _("Could not steal anything..."); + break; + case SKILL_ENVENOM : + msg = _("Poison had no effect..."); + break; + } + } + + localChatTab->chatLog(msg); + break; + } +} + +void SpecialHandler::use(int id) +{ + // TODO +} + +void SpecialHandler::use(int id, int level, int beingId) +{ + MessageOut outMsg(CMSG_SKILL_USE_BEING); + outMsg.writeInt16(level); + outMsg.writeInt16(id); + outMsg.writeInt16(beingId); +} + +void SpecialHandler::use(int id, int level, int x, int y) +{ + MessageOut outMsg(CMSG_SKILL_USE_POSITION); + outMsg.writeInt16(level); + outMsg.writeInt16(id); + outMsg.writeInt16(x); + outMsg.writeInt16(y); +} + +void SpecialHandler::use(int id, const std::string &map) +{ + MessageOut outMsg(CMSG_SKILL_USE_MAP); + outMsg.writeInt16(id); + outMsg.writeString(map, 16); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/specialhandler.h b/src/net/tmwa/specialhandler.h new file mode 100644 index 00000000..e8af0f69 --- /dev/null +++ b/src/net/tmwa/specialhandler.h @@ -0,0 +1,50 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_SKILLHANDLER_H +#define NET_TA_SKILLHANDLER_H + +#include "net/net.h" +#include "net/specialhandler.h" + +#include "net/tmwa/messagehandler.h" + +namespace TmwAthena { + +class SpecialHandler : public MessageHandler, public Net::SpecialHandler +{ + public: + SpecialHandler(); + + void handleMessage(Net::MessageIn &msg); + + void use(int id); + + void use(int id, int level, int beingId); + + void use(int id, int level, int x, int y); + + void use(int id, const std::string &map); +}; + +} // namespace TmwAthena + +#endif // NET_TA_SKILLHANDLER_H diff --git a/src/net/tmwa/token.h b/src/net/tmwa/token.h new file mode 100644 index 00000000..d2a21012 --- /dev/null +++ b/src/net/tmwa/token.h @@ -0,0 +1,43 @@ +/* + * The Mana Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "player.h" + +#ifndef NET_TA_TOKEN_H +#define NET_TA_TOKEN_H + +struct Token +{ + int account_ID; + int session_ID1; + int session_ID2; + Gender sex; + + void clear() + { + account_ID = 0; + session_ID1 = 0; + session_ID2 = 0; + sex = GENDER_UNSPECIFIED; + } +}; + +#endif // NET_TA_TOKEN_H diff --git a/src/net/tmwa/tradehandler.cpp b/src/net/tmwa/tradehandler.cpp new file mode 100644 index 00000000..9089f8e6 --- /dev/null +++ b/src/net/tmwa/tradehandler.cpp @@ -0,0 +1,288 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "net/tmwa/tradehandler.h" + +#include "inventory.h" +#include "item.h" +#include "localplayer.h" +#include "playerrelations.h" + +#include "gui/confirmdialog.h" +#include "gui/trade.h" + +#include "gui/widgets/chattab.h" + +#include "net/inventoryhandler.h" +#include "net/messagein.h" +#include "net/messageout.h" + +#include "net/tmwa/protocol.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +extern std::string tradePartnerName; +ConfirmDialog *confirmDlg; + +/** + * Listener for request trade dialogs + */ +namespace { + struct RequestTradeListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + confirmDlg = 0; + Net::getTradeHandler()->respond(event.getId() == "yes"); + } + } listener; +} + +extern Net::TradeHandler *tradeHandler; + +namespace TmwAthena { + +TradeHandler::TradeHandler() +{ + static const Uint16 _messages[] = { + SMSG_TRADE_REQUEST, + SMSG_TRADE_RESPONSE, + SMSG_TRADE_ITEM_ADD, + SMSG_TRADE_ITEM_ADD_RESPONSE, + SMSG_TRADE_OK, + SMSG_TRADE_CANCEL, + SMSG_TRADE_COMPLETE, + 0 + }; + handledMessages = _messages; + tradeHandler = this; + confirmDlg = 0; +} + + +void TradeHandler::handleMessage(Net::MessageIn &msg) +{ + switch (msg.getId()) + { + 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. + std::string tradePartnerNameTemp = msg.readString(24); + + if (player_relations.hasPermission(tradePartnerName, + PlayerRelation::TRADE)) + { + if (!player_node->tradeRequestOk() || confirmDlg) + { + Net::getTradeHandler()->respond(false); + break; + } + + tradePartnerName = tradePartnerNameTemp; + player_node->setTrading(true); + confirmDlg = new ConfirmDialog(_("Request for Trade"), + strprintf(_("%s wants to trade with you, do you " + "accept?"), tradePartnerName.c_str())); + confirmDlg->addActionListener(&listener); + } + else + { + Net::getTradeHandler()->respond(false); + break; + } + } + break; + + case SMSG_TRADE_RESPONSE: + switch (msg.readInt8()) + { + case 0: // Too far away + localChatTab->chatLog(_("Trading isn't possible. Trade " + "partner is too far away."), BY_SERVER); + break; + case 1: // Character doesn't exist + localChatTab->chatLog(_("Trading isn't possible. Character " + "doesn't exist."), BY_SERVER); + break; + case 2: // Invite request check failed... + localChatTab->chatLog(_("Trade cancelled due to an unknown " + "reason."), BY_SERVER); + break; + case 3: // Trade accepted + tradeWindow->reset(); + tradeWindow->setCaption(strprintf(_("Trade: You and %s"), + tradePartnerName.c_str())); + tradeWindow->setVisible(true); + break; + case 4: // Trade cancelled + if (player_relations.hasPermission(tradePartnerName, + PlayerRelation::SPEECH_LOG)) + localChatTab->chatLog(strprintf(_("Trade with %s " + "cancelled."), tradePartnerName.c_str()), + BY_SERVER); + // otherwise ignore silently + + tradeWindow->setVisible(false); + player_node->setTrading(false); + break; + default: // Shouldn't happen as well, but to be sure + localChatTab->chatLog(_("Unhandled trade cancel packet."), + BY_SERVER); + break; + } + break; + + case SMSG_TRADE_ITEM_ADD: + { + int amount = msg.readInt32(); + int type = msg.readInt16(); + msg.readInt8(); // identified flag + msg.readInt8(); // attribute + msg.readInt8(); // refine + msg.skip(8); // card (4 shorts) + + // TODO: handle also identified, etc + if (type == 0) + tradeWindow->setMoney(amount); + else + tradeWindow->addItem(type, false, amount, false); + } + break; + + case SMSG_TRADE_ITEM_ADD_RESPONSE: + // Trade: New Item add response (was 0x00ea, now 01b1) + { + const int index = msg.readInt16() - INVENTORY_OFFSET; + Item *item = player_node->getInventory()->getItem(index); + if (!item) + { + tradeWindow->receivedOk(true); + return; + } + int quantity = msg.readInt16(); + + switch (msg.readInt8()) + { + case 0: + // Successfully added item + if (item->isEquipment() && item->isEquipped()) + { + Net::getInventoryHandler()->unequipItem(item); + } + tradeWindow->addItem(item->getId(), true, quantity, + item->isEquipment()); + item->increaseQuantity(-quantity); + break; + case 1: + // Add item failed - player overweighted + localChatTab->chatLog(_("Failed adding item. Trade " + "partner is over weighted."), BY_SERVER); + break; + case 2: + // Add item failed - player has no free slot + localChatTab->chatLog(_("Failed adding item. Trade " + "partner has no free slot."), BY_SERVER); + break; + default: + localChatTab->chatLog(_("Failed adding item for " + "unknown reason."), BY_SERVER); + break; + } + } + break; + + case SMSG_TRADE_OK: + // 0 means ok from myself, 1 means ok from other; + tradeWindow->receivedOk(msg.readInt8() == 0); + break; + + case SMSG_TRADE_CANCEL: + localChatTab->chatLog(_("Trade canceled."), BY_SERVER); + tradeWindow->setVisible(false); + tradeWindow->reset(); + player_node->setTrading(false); + break; + + case SMSG_TRADE_COMPLETE: + localChatTab->chatLog(_("Trade completed."), BY_SERVER); + tradeWindow->setVisible(false); + tradeWindow->reset(); + player_node->setTrading(false); + break; + } +} + +void TradeHandler::request(Being *being) +{ + MessageOut outMsg(CMSG_TRADE_REQUEST); + outMsg.writeInt32(being->getId()); +} + +void TradeHandler::respond(bool accept) +{ + if (!accept) + player_node->setTrading(false); + + MessageOut outMsg(CMSG_TRADE_RESPONSE); + outMsg.writeInt8(accept ? 3 : 4); +} + +void TradeHandler::addItem(Item *item, int amount) +{ + MessageOut outMsg(CMSG_TRADE_ITEM_ADD_REQUEST); + outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET); + outMsg.writeInt32(amount); +} + +void TradeHandler::removeItem(int slotNum, int amount) +{ + // TODO +} + +void TradeHandler::setMoney(int amount) +{ + MessageOut outMsg(CMSG_TRADE_ITEM_ADD_REQUEST); + outMsg.writeInt16(0); + outMsg.writeInt32(amount); +} + +void TradeHandler::confirm() +{ + MessageOut outMsg(CMSG_TRADE_ADD_COMPLETE); +} + +void TradeHandler::finish() +{ + MessageOut outMsg(CMSG_TRADE_OK); +} + +void TradeHandler::cancel() +{ + MessageOut outMsg(CMSG_TRADE_CANCEL_REQUEST); +} + +} // namespace TmwAthena diff --git a/src/net/tmwa/tradehandler.h b/src/net/tmwa/tradehandler.h new file mode 100644 index 00000000..c396e8cc --- /dev/null +++ b/src/net/tmwa/tradehandler.h @@ -0,0 +1,58 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NET_TA_TRADEHANDLER_H +#define NET_TA_TRADEHANDLER_H + +#include "net/net.h" +#include "net/tradehandler.h" + +#include "net/tmwa/messagehandler.h" + +namespace TmwAthena { + +class TradeHandler : public MessageHandler, public Net::TradeHandler +{ + public: + TradeHandler(); + + void handleMessage(Net::MessageIn &msg); + + void request(Being *being); + + void respond(bool accept); + + void addItem(Item *item, int amount); + + void removeItem(int slotNum, int amount); + + void setMoney(int amount); + + void confirm(); + + void finish(); + + void cancel(); +}; + +} // namespace TmwAthena + +#endif // NET_TA_TRADEHANDLER_H diff --git a/src/player.cpp b/src/player.cpp index 9113b4ab..1f706cb8 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -73,7 +73,7 @@ Player::~Player() void Player::logic() { - if (Net::getNetworkType() == ServerInfo::EATHENA) + if (Net::getNetworkType() == ServerInfo::TMWATHENA) { switch (mAction) { diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp index f9acf1ce..e9afa7ef 100644 --- a/src/resources/monsterdb.cpp +++ b/src/resources/monsterdb.cpp @@ -31,7 +31,7 @@ #include "net/net.h" -#define OLD_EATHENA_OFFSET 1002 +#define OLD_TMWATHENA_OFFSET 1002 namespace { @@ -58,7 +58,7 @@ void MonsterDB::load() } int offset = XML::getProperty(rootNode, "offset", Net::getNetworkType() == - ServerInfo::EATHENA ? OLD_EATHENA_OFFSET : 0); + ServerInfo::TMWATHENA ? OLD_TMWATHENA_OFFSET : 0); //iterate s for_each_xml_child_node(monsterNode, rootNode) -- cgit v1.2.3-70-g09d2