diff options
Diffstat (limited to 'src')
142 files changed, 4056 insertions, 3118 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e4550c7..6a46aba4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,7 @@ FIND_PACKAGE(SDL REQUIRED) FIND_PACKAGE(SDL_image REQUIRED) FIND_PACKAGE(SDL_mixer REQUIRED) -FIND_PACKAGE(SDL_net REQUIRED) - +FIND_PACKAGE(ENet REQUIRED) FIND_PACKAGE(Libcurl REQUIRED) FIND_PACKAGE(LibXml2 REQUIRED) FIND_PACKAGE(PhysFS REQUIRED) @@ -28,7 +27,7 @@ INCLUDE_DIRECTORIES( ${SDL_INCLUDE_DIR} ${SDLIMAGE_INCLUDE_DIR} ${SDLMIXER_INCLUDE_DIR} - ${SDLNET_INCLUDE_DIR} + ${ENET_INCLUDE_DIR} ${PNG_INCLUDE_DIR} ${PHYSFS_INCLUDE_DIR} ${LIBCURL_INCLUDE_DIR} @@ -38,6 +37,8 @@ INCLUDE_DIRECTORIES( SET(SRCS graphic/imagerect.h + gui/box.cpp + gui/box.h gui/browserbox.cpp gui/browserbox.h gui/buddywindow.cpp @@ -50,8 +51,6 @@ SET(SRCS gui/buysell.h gui/chargedialog.cpp gui/chargedialog.h - gui/char_server.cpp - gui/char_server.h gui/char_select.cpp gui/char_select.h gui/chat.cpp @@ -74,14 +73,18 @@ SET(SRCS gui/gccontainer.h gui/gui.cpp gui/gui.h + gui/hbox.cpp + gui/hbox.h gui/help.cpp gui/help.h + gui/inttextbox.cpp + gui/inttextbox.h gui/inventorywindow.cpp gui/inventorywindow.h - gui/itemcontainer.cpp - gui/itemcontainer.h gui/item_amount.cpp gui/item_amount.h + gui/itemcontainer.cpp + gui/itemcontainer.h gui/linkhandler.h gui/listbox.cpp gui/listbox.h @@ -118,6 +121,8 @@ SET(SRCS gui/selectionlistener.h gui/sell.cpp gui/sell.h + gui/serverdialog.cpp + gui/serverdialog.h gui/setup_audio.cpp gui/setup_audio.h gui/setup.cpp @@ -143,38 +148,36 @@ SET(SRCS gui/textfield.h gui/trade.cpp gui/trade.h - gui/window.cpp - gui/window.h + gui/updatewindow.cpp + gui/updatewindow.h + gui/vbox.cpp + gui/vbox.h gui/windowcontainer.cpp gui/windowcontainer.h - gui/inttextbox.h - gui/inttextbox.cpp - gui/box.h - gui/box.cpp - gui/vbox.h - gui/vbox.cpp - gui/hbox.h - gui/hbox.cpp - gui/updatewindow.h - gui/updatewindow.cpp - net/beinghandler.h + gui/window.cpp + gui/window.h + gui/widgets/dropdown.cpp + gui/widgets/dropdown.h net/beinghandler.cpp - net/buysellhandler.h + net/beinghandler.h net/buysellhandler.cpp - net/charserverhandler.h + net/buysellhandler.h net/charserverhandler.cpp - net/chathandler.h + net/charserverhandler.h net/chathandler.cpp - net/equipmenthandler.h + net/chathandler.h + net/connection.cpp + net/connection.h net/equipmenthandler.cpp - net/inventoryhandler.h + net/equipmenthandler.h + net/internal.cpp + net/internal.h net/inventoryhandler.cpp - net/itemhandler.h + net/inventoryhandler.h net/itemhandler.cpp - net/loginhandler.h + net/itemhandler.h net/loginhandler.cpp - net/maploginhandler.cpp - net/maploginhandler.h + net/loginhandler.h net/messagehandler.cpp net/messagehandler.h net/messagein.cpp @@ -185,44 +188,57 @@ SET(SRCS net/network.h net/npchandler.cpp net/npchandler.h - net/packet.cpp - net/packet.h net/playerhandler.cpp net/playerhandler.h - net/protocol.cpp net/protocol.h net/skillhandler.cpp net/skillhandler.h net/tradehandler.cpp net/tradehandler.h + net/accountserver/account.cpp + net/accountserver/account.h + net/accountserver/accountserver.cpp + net/accountserver/accountserver.h + net/accountserver/internal.cpp + net/accountserver/internal.h + net/chatserver/chatserver.cpp + net/chatserver/chatserver.h + net/chatserver/internal.cpp + net/chatserver/internal.h + net/gameserver/gameserver.cpp + net/gameserver/gameserver.h + net/gameserver/internal.cpp + net/gameserver/internal.h + net/gameserver/player.cpp + net/gameserver/player.h resources/ambientoverlay.cpp resources/ambientoverlay.h + resources/buddylist.cpp + resources/buddylist.h resources/image.cpp resources/image.h resources/imagewriter.cpp resources/imagewriter.h - resources/iteminfo.h resources/iteminfo.cpp + resources/iteminfo.h resources/itemmanager.cpp resources/itemmanager.h resources/mapreader.cpp resources/mapreader.h - resources/music.h resources/music.cpp - resources/openglsdlimageloader.h + resources/music.h resources/openglsdlimageloader.cpp + resources/openglsdlimageloader.h resources/resource.cpp resources/resource.h resources/resourcemanager.cpp resources/resourcemanager.h - resources/sdlimageloader.h resources/sdlimageloader.cpp - resources/soundeffect.h + resources/sdlimageloader.h resources/soundeffect.cpp - resources/spriteset.h + resources/soundeffect.h resources/spriteset.cpp - resources/buddylist.h - resources/buddylist.cpp + resources/spriteset.h utils/dtor.h utils/tostring.h animatedsprite.cpp @@ -289,7 +305,7 @@ TARGET_LINK_LIBRARIES(tmw ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${SDLMIXER_LIBRARY} - ${SDLNET_LIBRARY} + ${ENET_LIBRARIES} ${PNG_LIBRARIES} ${PHYSFS_LIBRARY} ${LIBCURL_LIBRARIES} diff --git a/src/Makefile.am b/src/Makefile.am index 7d37edf8..8ab16e32 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,9 @@ +AUTOMAKE_OPTIONS = subdir-objects + bin_PROGRAMS = tmw tmw_SOURCES = graphic/imagerect.h \ + gui/widgets/dropdown.cpp \ + gui/widgets/dropdown.h \ gui/browserbox.cpp \ gui/browserbox.h \ gui/buddywindow.cpp \ @@ -12,8 +16,6 @@ tmw_SOURCES = graphic/imagerect.h \ gui/buysell.h \ gui/chargedialog.cpp \ gui/chargedialog.h \ - gui/char_server.cpp \ - gui/char_server.h \ gui/char_select.cpp \ gui/char_select.h \ gui/chat.cpp \ @@ -80,6 +82,8 @@ tmw_SOURCES = graphic/imagerect.h \ gui/selectionlistener.h \ gui/sell.cpp \ gui/sell.h \ + gui/serverdialog.cpp \ + gui/serverdialog.h \ gui/setup_audio.cpp \ gui/setup_audio.h \ gui/setup.cpp \ @@ -91,8 +95,6 @@ tmw_SOURCES = graphic/imagerect.h \ gui/setup_video.h \ gui/shop.cpp \ gui/shop.h \ - gui/shoplistbox.cpp \ - gui/shoplistbox.h \ gui/skill.cpp \ gui/skill.h \ gui/slider.cpp \ @@ -129,6 +131,8 @@ tmw_SOURCES = graphic/imagerect.h \ net/charserverhandler.cpp \ net/chathandler.h \ net/chathandler.cpp \ + net/connection.h \ + net/connection.cpp \ net/equipmenthandler.h \ net/equipmenthandler.cpp \ net/inventoryhandler.h \ @@ -137,8 +141,6 @@ tmw_SOURCES = graphic/imagerect.h \ net/itemhandler.cpp \ net/loginhandler.h \ net/loginhandler.cpp \ - net/maploginhandler.cpp \ - net/maploginhandler.h \ net/messagehandler.cpp \ net/messagehandler.h \ net/messagein.cpp \ @@ -149,16 +151,29 @@ tmw_SOURCES = graphic/imagerect.h \ net/network.h \ net/npchandler.cpp \ net/npchandler.h \ - net/packet.cpp \ - net/packet.h \ net/playerhandler.cpp \ net/playerhandler.h \ - net/protocol.cpp \ net/protocol.h \ net/skillhandler.cpp \ net/skillhandler.h \ net/tradehandler.cpp \ net/tradehandler.h \ + net/accountserver/account.cpp \ + net/accountserver/account.h \ + net/accountserver/accountserver.cpp \ + net/accountserver/accountserver.h \ + net/accountserver/internal.cpp \ + net/accountserver/internal.h \ + net/chatserver/chatserver.cpp \ + net/chatserver/chatserver.h \ + net/chatserver/internal.cpp \ + net/chatserver/internal.h \ + net/gameserver/gameserver.cpp \ + net/gameserver/gameserver.h \ + net/gameserver/internal.cpp \ + net/gameserver/internal.h \ + net/gameserver/player.cpp \ + net/gameserver/player.h \ resources/ambientoverlay.cpp \ resources/ambientoverlay.h \ resources/image.cpp \ @@ -250,9 +265,3 @@ tmw_SOURCES = graphic/imagerect.h \ INCLUDES = \ $(all_includes) \ -DTMW_DATADIR=\""$(pkgdatadir)/"\" - -# the library search path. -tmw_LDFLAGS = $(all_libraries) $(LIBSDL_RPATH) `pkg-config --libs libxml-2.0` -tmw_CXXFLAGS = -Wall -Werror $(OPENGL_CFLAGS) $(LIBSDL_CFLAGS) `pkg-config --cflags libxml-2.0` $(CURL_CFLAGS) -tmw_LDADD = $(LIBSDL_LIBS) -lguichan_sdl $(OPENGL_LIBS) $(CURL_LIBS) -tmw_TARGET = tmw diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp index e7439644..3815f04a 100644 --- a/src/animatedsprite.cpp +++ b/src/animatedsprite.cpp @@ -34,7 +34,8 @@ AnimatedSprite::AnimatedSprite(const std::string& animationFile, int variant): mAction(NULL), mDirection(DIRECTION_DOWN), mLastTime(0), - mSpeed(1.0f) + mSpeed(1.0f), + mAnimationFile(animationFile) { int size; ResourceManager *resman = ResourceManager::getInstance(); @@ -278,7 +279,8 @@ AnimatedSprite::play(SpriteAction action) if (i == mActions.end()) { - logger->log("Warning: no action \"%u\" defined!", action); + //logger->log("Warning: no action %u defined for \"%s\"!", + // action, mAnimationFile.c_str()); mAction = NULL; return; } diff --git a/src/animatedsprite.h b/src/animatedsprite.h index e87a9885..bda612ab 100644 --- a/src/animatedsprite.h +++ b/src/animatedsprite.h @@ -175,6 +175,7 @@ class AnimatedSprite SpriteDirection mDirection; int mLastTime; float mSpeed; + std::string mAnimationFile; }; #endif diff --git a/src/being.cpp b/src/being.cpp index 47f9965c..fa24ad69 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -23,6 +23,8 @@ #include "being.h" #include <algorithm> +#include <cassert> +#include <cmath> #include "animatedsprite.h" #include "equipment.h" @@ -45,20 +47,21 @@ PATH_NODE::PATH_NODE(Uint16 iX, Uint16 iY): { } -Being::Being(Uint32 id, Uint16 job, Map *map): +Being::Being(Uint16 id, Uint16 job, Map *map): mJob(job), mX(0), mY(0), mDirection(DOWN), - mAction(0), + mAction(STAND), mWalkTime(0), mEmotion(0), mEmotionTime(0), mAttackSpeed(350), mEquipment(new Equipment()), mId(id), + mSex(2), mWeapon(0), mWalkSpeed(150), + mSpeedModifier(1024), mMap(NULL), mHairStyle(0), mHairColor(0), - mSex(2), mSpeechTime(0), mDamageTime(0), mShowSpeech(false), mShowDamage(false), @@ -74,13 +77,157 @@ Being::~Being() setMap(NULL); } -void -Being::setDestination(Uint16 destX, Uint16 destY) +void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) { - if (mMap) + if (!mMap || (mX == dstX && mY == dstY)) + { + setPath(Path()); + return; + } + + if (mX / 32 == dstX / 32 && mY / 32 == dstY / 32) { - setPath(mMap->findPath(mX, mY, destX, destY)); + // The being is already on the last tile of the path. + Path p; + p.push_back(PATH_NODE(dstX, dstY)); + setPath(p); + return; } + + Path p1; + int p1_size, p1_length; + Uint16 *p1_dist; + int onPath = -1; + if (srcX / 32 == dstX / 32 && srcY / 32 == dstY / 32) + { + p1_dist = new Uint16[1]; + p1_size = 1; + p1_dist[0] = 0; + p1_length = 0; + } + else + { + p1 = mMap->findPath(srcX / 32, srcY / 32, dstX / 32, dstY / 32); + if (p1.empty()) + { + // No path? Better teleport. + mX = dstX; + mY = dstY; + setPath(p1); + return; + } + p1_size = p1.size(); + p1_dist = new Uint16[p1_size]; + int j = 0; + // Remove last tile so that it can be replaced by the exact destination. + p1.pop_back(); + for (Path::iterator i = p1.begin(), i_end = p1.end(); i != i_end; ++i) + { + // Get distance from source to tile i. + p1_dist[j] = mMap->getMetaTile(i->x, i->y)->Gcost; + // Check if the being is already walking on the path. + if (i->x == mX / 32 && i->y == mY / 32) + { + onPath = j; + } + // Set intermediate steps to tile centers. + i->x = i->x * 32 + 16; + i->y = i->y * 32 + 16; + ++j; + } + p1_length = mMap->getMetaTile(dstX / 32, dstY / 32)->Gcost; + p1_dist[p1_size - 1] = p1_length; + } + p1.push_back(PATH_NODE(dstX, dstY)); + + if (mX / 32 == srcX / 32 && mY / 32 == srcY / 32) + { + // The being is at the start of the path. + setPath(p1); + delete[] p1_dist; + return; + } + + if (onPath >= 0) + { + // The being is already on the path, but it needs to be slowed down. + for (int j = onPath; j >= 0; --j) + { + p1.pop_front(); + } + int r = p1_length - p1_dist[onPath]; // remaining length + assert(r > 0); + setPath(p1, p1_length * 1024 / r); + delete[] p1_dist; + return; + } + + Path bestPath; + int bestRating = -1, bestStart = 0, bestLength = 0; + int j = 0; + + for (Path::iterator i = p1.begin(), i_end = p1.end(); i != i_end; ++i) + { + // Look if it is worth passing by tile i. + Path p2 = mMap->findPath(mX / 32, mY / 32, i->x / 32, i->y / 32); + if (!p2.empty()) + { + int l1 = mMap->getMetaTile(i->x / 32, i->y / 32)->Gcost; + int l2 = p1_length - p1_dist[j]; + int r = l1 + l2 / 2; // TODO: tune rating formula + assert(r > 0); + if (bestRating < 0 || r < bestRating) + { + bestPath.swap(p2); + bestRating = r; + bestStart = j; + bestLength = l1 + l2; + } + } + ++j; + } + + if (bestRating < 0) + { + // Unable to reach the path? Better teleport. + mX = srcX; + mY = srcY; + setPath(p1); + delete[] p1_dist; + return; + } + + bestPath.pop_back(); + for (Path::iterator i = bestPath.begin(), i_end = bestPath.end(); i != i_end; ++i) + { + i->x = i->x * 32 + 16; + i->y = i->y * 32 + 16; + } + + // Concatenate paths. + for (int j = bestStart; j > 0; --j) + { + p1.pop_front(); + } + p1.splice(p1.begin(), bestPath); + + assert(bestLength > 0); + setPath(p1, p1_length * 1024 / bestLength); + delete[] p1_dist; +} + +void Being::adjustCourse(Uint16 srcX, Uint16 srcY) +{ + if (!mPath.empty()) + { + adjustCourse(srcX, srcY, mPath.back().x, mPath.back().y); + } +} + +void +Being::setDestination(Uint16 destX, Uint16 destY) +{ + adjustCourse(mX, mY, destX, destY); } void @@ -90,35 +237,29 @@ Being::clearPath() } void -Being::setPath(const Path &path) +Being::setPath(const Path &path, int mod) { mPath = path; + mSpeedModifier = mod >= 512 ? (mod <= 2048 ? mod : 2048) : 512; // TODO: tune bounds if (mAction != WALK && mAction != DEAD) { - nextStep(); mWalkTime = tick_time; + mStepTime = 0; + nextStep(); } } void Being::setHairColor(Uint16 color) { - mHairColor = color; - if (mHairColor < 1 || mHairColor > NR_HAIR_COLORS + 1) - { - mHairColor = 1; - } + mHairColor = (color < NR_HAIR_COLORS) ? color : 0; } void Being::setHairStyle(Uint16 style) { - mHairStyle = style; - if (mHairStyle < 1 || mHairStyle > NR_HAIR_STYLES) - { - mHairStyle = 1; - } + mHairStyle = (style < NR_HAIR_STYLES) ? style : 0; } void @@ -180,9 +321,6 @@ Being::setAction(Uint8 action) else { switch (getWeapon()) { - case 3: - currentAction = ACTION_ATTACK; - break; case 2: currentAction = ACTION_ATTACK_BOW; break; @@ -292,15 +430,25 @@ Being::nextStep() setDirection(dir); + mStepX = node.x - mX; + mStepY = node.y - mY; mX = node.x; mY = node.y; setAction(WALK); - mWalkTime += mWalkSpeed / 10; + mWalkTime += mStepTime / 10; + mStepTime = mWalkSpeed * (int)std::sqrt((double)mStepX * mStepX + (double)mStepY * mStepY) * + mSpeedModifier / (32 * 1024); } void Being::logic() { + // Determine whether the being should take another step + if (mAction == WALK && get_elapsed_time(mWalkTime) >= mStepTime) + { + nextStep(); + } + // Determine whether speech should still be displayed if (get_elapsed_time(mSpeechTime) > 5000) { @@ -314,8 +462,8 @@ Being::logic() } // Update pixel coordinates - mPx = mX * 32 + getXOffset(); - mPy = mY * 32 + getYOffset(); + mPx = mX - 16 + getXOffset(); + mPy = mY - 16 + getYOffset(); if (mEmotion != 0) { @@ -417,17 +565,12 @@ Being::getType() const void Being::setWeaponById(Uint16 weapon) { - //TODO: Use an external file to map weapon IDs to weapon types switch (weapon) { case 529: // iron arrows case 1199: // arrows break; - case 623: //scythe - setWeapon(3); - break; - case 1200: // bow case 530: // short bow case 545: // forest bow @@ -435,10 +578,6 @@ Being::setWeaponById(Uint16 weapon) break; case 521: // sharp knife - /* UNCOMMENT TO TEST SHARP KNIFE AS SCYTHE - * setWeapon(3) - * break; - */ case 522: // dagger case 536: // short sword case 1201: // knife @@ -454,24 +593,23 @@ Being::setWeaponById(Uint16 weapon) } } -int -Being::getOffset(char pos, char neg) const +int Being::getOffset(int step) const { // Check whether we're walking in the requested direction - if (mAction != WALK || !(mDirection & (pos | neg))) { + if (mAction != WALK || step == 0) { return 0; } - int offset = (get_elapsed_time(mWalkTime) * 32) / mWalkSpeed; + int offset = (get_elapsed_time(mWalkTime) * std::abs(step)) / mStepTime; // We calculate the offset _from_ the _target_ location - offset -= 32; + offset -= std::abs(step); if (offset > 0) { offset = 0; } // Going into negative direction? Invert the offset. - if (mDirection & pos) { + if (step < 0) { offset = -offset; } diff --git a/src/being.h b/src/being.h index 42f37058..d8db9375 100644 --- a/src/being.h +++ b/src/being.h @@ -33,7 +33,7 @@ #include "map.h" #include "animatedsprite.h" -#define NR_HAIR_STYLES 7 +#define NR_HAIR_STYLES 8 #define NR_HAIR_COLORS 10 class AnimatedSprite; @@ -98,11 +98,11 @@ class Being : public Sprite static const char UP = 4; static const char RIGHT = 8; + std::string mName; /**< Name of character */ Uint16 mJob; /**< Job (player job, npc, monster, ) */ - Uint16 mX, mY; /**< Tile coordinates */ + Uint16 mX, mY; /**< Pixel coordinates (tile center) */ Uint8 mDirection; /**< Facing direction */ Uint8 mAction; /**< Action the being is performing */ - Uint8 mFrame; Uint16 mWalkTime; Uint8 mEmotion; /**< Currently showing emotion */ Uint8 mEmotionTime; /**< Time until emotion disappears */ @@ -112,7 +112,7 @@ class Being : public Sprite /** * Constructor. */ - Being(Uint32 id, Uint16 job, Map *map); + Being(Uint16 id, Uint16 job, Map *map); /** * Destructor. @@ -127,7 +127,17 @@ class Being : public Sprite /** * Sets a new destination for this being to walk to. */ - virtual void setDestination(Uint16 destX, Uint16 destY); + void setDestination(Uint16 destX, Uint16 destY); + + /** + * Adjusts course to expected stat point. + */ + void adjustCourse(Uint16, Uint16); + + /** + * Adjusts course to expected start and end points. + */ + void adjustCourse(Uint16, Uint16, Uint16, Uint16); /** * Puts a "speech balloon" above this being for the specified amount @@ -248,7 +258,7 @@ class Being : public Sprite * * @param weapon the picture id */ - virtual void + void setWeapon(Uint16 weapon) { mWeapon = weapon; } /** @@ -274,14 +284,14 @@ class Being : public Sprite /** * Gets the sprite id. */ - Uint32 + Uint16 getId() const { return mId; } /** * Sets the sprite id. */ void - setId(Uint32 id) { mId = id; } + setId(Uint16 id) { mId = id; } /** * Sets the map the being is on @@ -324,13 +334,13 @@ class Being : public Sprite * Get the current X pixel offset. */ int - getXOffset() const { return getOffset(LEFT, RIGHT); } + getXOffset() const { return getOffset(mStepX); } /** * Get the current Y pixel offset. */ int - getYOffset() const { return getOffset(UP, DOWN); } + getYOffset() const { return getOffset(mStepY); } std::auto_ptr<Equipment> mEquipment; int mVisibleEquipment[6]; /**< Visible equipments */ @@ -340,13 +350,7 @@ class Being : public Sprite * Sets the new path for this being. */ void - setPath(const Path &path); - - /** - * Calculates the offset in the given directions. - * If walking in direction 'neg' the value is negated. - */ - int getOffset(char pos, char neg) const; + setPath(const Path &path, int mod = 1024); /** * Returns the sprite direction of this being. @@ -354,24 +358,29 @@ class Being : public Sprite SpriteDirection getSpriteDirection() const; - Uint32 mId; /**< Unique sprite id */ + Uint16 mId; /**< Unique being id */ + Uint8 mSex; /**< Character's gender */ Uint16 mWeapon; /**< Weapon picture id */ Uint16 mWalkSpeed; /**< Walking speed */ + Uint16 mSpeedModifier; /**< Modifier to keep course on sync (1024 = normal speed) */ Map *mMap; /**< Map on which this being resides */ - std::string mName; /**< Name of character */ SpriteIterator mSpriteIterator; Path mPath; std::string mSpeech; std::string mDamage; Uint16 mHairStyle, mHairColor; - Uint8 mSex; Uint32 mSpeechTime; Uint32 mDamageTime; bool mShowSpeech, mShowDamage; Sint32 mPx, mPy; /**< Pixel coordinates */ std::vector<AnimatedSprite*> mSprites; + + private: + Sint16 mStepX, mStepY; + Uint16 mStepTime; + int getOffset(int) const; }; #endif diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index 027e08d3..923283b5 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -28,9 +28,6 @@ #include "npc.h" #include "player.h" -#include "net/messageout.h" -#include "net/protocol.h" - #include "utils/dtor.h" class FindBeingFunctor @@ -39,8 +36,8 @@ class FindBeingFunctor bool operator() (Being *being) { Uint16 other_y = y + ((being->getType() == Being::NPC) ? 1 : 0); - return (being->mX == x && - (being->mY == y || being->mY == other_y) && + return (being->mX / 32 == x && + (being->mY / 32 == y || being->mY / 32 == other_y) && being->mAction != Being::MONSTER_DEAD && (type == Being::UNKNOWN || being->getType() == type)); } @@ -49,11 +46,6 @@ class FindBeingFunctor Being::Type type; } beingFinder; -BeingManager::BeingManager(Network *network): - mNetwork(network) -{ -} - void BeingManager::setMap(Map *map) { mMap = map; @@ -67,19 +59,21 @@ void BeingManager::setPlayer(LocalPlayer *player) mBeings.push_back(player); } -Being* BeingManager::createBeing(Uint32 id, Uint16 job) +Being* BeingManager::createBeing(Uint16 id, Uint16 job) { Being *being; if (job < 10) { being = new Player(id, job, mMap); - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x0094); - outMsg.writeInt32(id);//readLong(2)); + // XXX Convert for new server + /* + MessageOut outMsg(0x0094); + outMsg.writeLong(id); + */ } else if (job >= 100 & job < 200) - being = new NPC(id, job, mMap, mNetwork); + being = new NPC(id, job, mMap); else if (job >= 1000 && job < 1200) being = new Monster(id, job, mMap); else @@ -96,7 +90,7 @@ void BeingManager::destroyBeing(Being *being) delete being; } -Being* BeingManager::findBeing(Uint32 id) +Being* BeingManager::findBeing(Uint16 id) { for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++) { @@ -133,12 +127,12 @@ void BeingManager::logic() being->logic(); - if (being->mAction == Being::MONSTER_DEAD && being->mFrame >= 20) + /*if (being->mAction == Being::MONSTER_DEAD && being->mFrame >= 20) { delete being; i = mBeings.erase(i); } - else { + else*/ { i++; } } diff --git a/src/beingmanager.h b/src/beingmanager.h index 152fb640..15a347de 100644 --- a/src/beingmanager.h +++ b/src/beingmanager.h @@ -28,7 +28,6 @@ class LocalPlayer; class Map; -class Network; typedef std::list<Being*> Beings; typedef Beings::iterator BeingIterator; @@ -36,8 +35,6 @@ typedef Beings::iterator BeingIterator; class BeingManager { public: - BeingManager(Network *network); - /** * Sets the map on which beings are created */ @@ -51,7 +48,7 @@ class BeingManager /** * Create a being and add it to the list of beings. */ - Being* createBeing(Uint32 id, Uint16 job); + Being* createBeing(Uint16 id, Uint16 job); /** * Remove a Being. @@ -61,7 +58,7 @@ class BeingManager /** * Return a specific id Being. */ - Being* findBeing(Uint32 id); + Being* findBeing(Uint16 id); /** * Return a being at specific coordinates. @@ -95,7 +92,6 @@ class BeingManager protected: Beings mBeings; Map *mMap; - Network *mNetwork; }; extern BeingManager *beingManager; diff --git a/src/configuration.cpp b/src/configuration.cpp index 53f6785e..8bb0b8ca 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -79,6 +79,8 @@ void Configuration::write() // Do not attempt to write to file that cannot be opened for writing FILE *testFile = fopen(mConfigPath.c_str(), "w"); if (!testFile) { + logger->log("Configuration::write() couldn't open %s for writing", + mConfigPath.c_str()); return; } else { @@ -87,8 +89,12 @@ void Configuration::write() xmlTextWriterPtr writer = xmlNewTextWriterFilename(mConfigPath.c_str(), 0); - if (!writer) + if (!writer) { + logger->log("Configuration::write() error while creating writer"); return; + } + + logger->log("Configuration::write() writing configuration..."); xmlTextWriterSetIndent(writer, 1); xmlTextWriterStartDocument(writer, NULL, NULL, NULL); @@ -96,9 +102,6 @@ void Configuration::write() for (OptionIterator i = mOptions.begin(); i != mOptions.end(); i++) { - logger->log("Configuration::write(%s, \"%s\")", - i->first.c_str(), i->second.c_str()); - xmlTextWriterStartElement(writer, BAD_CAST "option"); xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST i->first.c_str()); diff --git a/src/engine.cpp b/src/engine.cpp index 868454d4..231313c4 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -34,16 +34,12 @@ #include "main.h" #include "localplayer.h" #include "log.h" -#include "main.h" #include "map.h" #include "sound.h" #include "gui/gui.h" #include "gui/minimap.h" -#include "net/messageout.h" -#include "net/protocol.h" - #include "resources/itemmanager.h" #include "resources/mapreader.h" #include "resources/resourcemanager.h" @@ -63,10 +59,9 @@ Spriteset *emotionset; Spriteset *npcset; std::vector<Spriteset *> weaponset; -Engine::Engine(Network *network): +Engine::Engine(): mShowDebugPath(false), - mCurrentMap(NULL), - mNetwork(network) + mCurrentMap(NULL) { // Load the sprite sets ResourceManager *resman = ResourceManager::getInstance(); @@ -113,7 +108,7 @@ void Engine::changeMap(const std::string &mapPath) beingManager->clear(); // Store full map path in global var - map_path = "maps/" + mapPath.substr(0, mapPath.rfind(".")) + ".tmx.gz"; + map_path = "maps/" + mapPath; // Attempt to load the new map Map *newMap = MapReader::readMap(map_path); @@ -147,10 +142,6 @@ void Engine::changeMap(const std::string &mapPath) } mCurrentMap = newMap; - - // Send "map loaded" - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_MAP_LOADED); } void Engine::logic() @@ -161,20 +152,12 @@ void Engine::logic() void Engine::draw(Graphics *graphics) { + int midTileX = graphics->getWidth() / 2; + int midTileY = graphics->getHeight() / 2; static int lastTick = tick_time; - // Avoid freaking out when tick_time overflows - if (tick_time < lastTick) - { - lastTick = tick_time; - } - - // calculate viewpoint - int midTileX = graphics->getWidth() / 32 / 2; - int midTileY = graphics->getHeight() / 32 / 2; - - int player_x = (player_node->mX - midTileX) * 32 + player_node->getXOffset(); - int player_y = (player_node->mY - midTileY) * 32 + player_node->getYOffset(); + int player_x = player_node->mX - midTileX + player_node->getXOffset(); + int player_y = player_node->mY - midTileY + player_node->getYOffset(); scrollLaziness = (int)config.getValue("ScrollLaziness", 32); scrollRadius = (int)config.getValue("ScrollRadius", 32); @@ -183,7 +166,9 @@ void Engine::draw(Graphics *graphics) scrollLaziness = 1; //avoids division by zero //apply lazy scrolling - while (lastTick < tick_time) + int nbTicks = get_elapsed_time(lastTick) / 10; + lastTick += nbTicks; + for (; nbTicks > 0; --nbTicks) { if (player_x > view_x + scrollRadius) { @@ -201,7 +186,6 @@ void Engine::draw(Graphics *graphics) { view_y += (player_y - view_y + scrollRadius) / scrollLaziness; } - lastTick++; } //auto center when player is off screen @@ -222,29 +206,36 @@ void Engine::draw(Graphics *graphics) if (view_y < 0) { view_y = 0; } - if (view_x > (mCurrentMap->getWidth() - midTileX) * 32) { - view_x = (mCurrentMap->getWidth() - midTileX) * 32; + if (view_x > mCurrentMap->getWidth() * 32 - midTileX) { + view_x = mCurrentMap->getWidth() * 32 - midTileX; } - if (view_y > (mCurrentMap->getHeight() - midTileY) * 32) { - view_y = (mCurrentMap->getHeight() - midTileY) * 32; + if (view_y > mCurrentMap->getHeight() * 32 - midTileY) { + view_y = mCurrentMap->getHeight() * 32 - midTileY; } } - camera_x = int(view_x + 16) / 32; - camera_y = int(view_y + 16) / 32; + camera_x = (int)view_x; + camera_y = (int)view_y; // Draw tiles and sprites if (mCurrentMap != NULL) { - mCurrentMap->draw(graphics, (int)view_x, (int)view_y, 0); - mCurrentMap->draw(graphics, (int)view_x, (int)view_y, 1); - mCurrentMap->draw(graphics, (int)view_x, (int)view_y, 2); + mCurrentMap->draw(graphics, camera_x, camera_y, 0); + mCurrentMap->draw(graphics, camera_x, camera_y, 1); + mCurrentMap->draw(graphics, camera_x, camera_y, 2); mCurrentMap->drawOverlay( graphics, view_x, view_y, (int)config.getValue("OverlayDetail", 2) ); } + else + { + // When no map is loaded, draw a replacement background + graphics->setColor(gcn::Color(128, 128, 128)); + graphics->fillRectangle(gcn::Rectangle(0, 0, + graphics->getWidth(), graphics->getHeight())); + } // Find a path from the player to the mouse, and draw it. This is for debug // purposes. @@ -254,18 +245,18 @@ void Engine::draw(Graphics *graphics) int mouseX, mouseY; SDL_GetMouseState(&mouseX, &mouseY); - int mouseTileX = mouseX / 32 + camera_x; - int mouseTileY = mouseY / 32 + camera_y; + int mouseTileX = (mouseX + camera_x) / 32; + int mouseTileY = (mouseY + camera_y) / 32; Path debugPath = mCurrentMap->findPath( - player_node->mX, player_node->mY, + player_node->mX / 32, player_node->mY / 32, mouseTileX, mouseTileY); graphics->setColor(gcn::Color(255, 0, 0)); for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++) { - int squareX = i->x * 32 - int(view_x) + 12; - int squareY = i->y * 32 - int(view_y) + 12; + int squareX = i->x * 32 - camera_x + 12; + int squareY = i->y * 32 - camera_y + 12; graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8)); graphics->drawText( @@ -278,9 +269,9 @@ void Engine::draw(Graphics *graphics) Beings &beings = beingManager->getAll(); for (BeingIterator i = beings.begin(); i != beings.end(); i++) { - (*i)->drawSpeech(graphics, -(int)view_x, -(int)view_y); - (*i)->drawName(graphics, -(int)view_x, -(int)view_y); - (*i)->drawEmotion(graphics, -(int)view_x, -(int)view_y); + (*i)->drawSpeech(graphics, -camera_x, -camera_y); + (*i)->drawName(graphics, -camera_x, -camera_y); + (*i)->drawEmotion(graphics, -camera_x, -camera_y); } // Draw target marker if needed @@ -291,8 +282,8 @@ void Engine::draw(Graphics *graphics) graphics->setColor(gcn::Color(255, 255, 255)); int dy = (target->getType() == Being::PLAYER) ? 90 : 52; - graphics->drawText("[TARGET]", target->getPixelX() - (int)view_x + 15, - target->getPixelY() - (int)view_y - dy, gcn::Graphics::CENTER); + graphics->drawText("[TARGET]", target->getPixelX() - camera_x + 15, + target->getPixelY() - camera_y - dy, gcn::Graphics::CENTER); } gui->draw(); diff --git a/src/engine.h b/src/engine.h index 3ae380d6..e8ef7e33 100644 --- a/src/engine.h +++ b/src/engine.h @@ -30,7 +30,6 @@ extern int camera_x, camera_y; class Graphics; class Map; -class Network; /** * Game engine that does the main drawing. @@ -41,7 +40,7 @@ class Engine /** * Constructor. */ - Engine(Network *network); + Engine(); /** * Destructor. @@ -77,7 +76,6 @@ class Engine bool mShowDebugPath; Map *mCurrentMap; - Network *mNetwork; int scrollRadius; int scrollLaziness; diff --git a/src/game.cpp b/src/game.cpp index b07c5c9a..5052f2ce 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -122,7 +122,7 @@ const int MAX_TIME = 10000; */ namespace { struct ExitListener : public gcn::ActionListener { - void action(const std::string& eventId, gcn::Widget* widget) { + void action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "yes") { done = true; } @@ -164,15 +164,15 @@ int get_elapsed_time(int start_time) /** * Create all the various globally accessible gui windows */ -void createGuiWindows(Network *network) +void createGuiWindows() { // Create dialogs - chatWindow = new ChatWindow(network); + chatWindow = new ChatWindow; menuWindow = new MenuWindow(); statusWindow = new StatusWindow(player_node); miniStatusWindow = new MiniStatusWindow(); - buyDialog = new BuyDialog(network); - sellDialog = new SellDialog(network); + buyDialog = new BuyDialog; + sellDialog = new SellDialog; buySellDialog = new BuySellDialog(); inventoryWindow = new InventoryWindow(); npcTextDialog = new NpcTextDialog(); @@ -183,7 +183,7 @@ void createGuiWindows(Network *network) minimap = new Minimap(); equipmentWindow = new EquipmentWindow(player_node->mEquipment.get()); chargeDialog = new ChargeDialog(); - tradeWindow = new TradeWindow(network); + tradeWindow = new TradeWindow; //buddyWindow = new BuddyWindow(); helpWindow = new HelpWindow(); debugWindow = new DebugWindow(); @@ -252,8 +252,7 @@ void destroyGuiWindows() delete debugWindow; } -Game::Game(Network *network): - mNetwork(network), +Game::Game(): mBeingHandler(new BeingHandler()), mBuySellHandler(new BuySellHandler()), mChatHandler(new ChatHandler()), @@ -265,10 +264,10 @@ Game::Game(Network *network): mSkillHandler(new SkillHandler()), mTradeHandler(new TradeHandler()) { - createGuiWindows(network); - engine = new Engine(network); + createGuiWindows(); + engine = new Engine; - beingManager = new BeingManager(network); + beingManager = new BeingManager; floorItemManager = new FloorItemManager(); // Initialize timers @@ -282,8 +281,6 @@ Game::Game(Network *network): // Initialize beings beingManager->setPlayer(player_node); - player_node->setNetwork(network); - engine->changeMap(map_path); Joystick::init(); // TODO: The user should be able to choose which one to use @@ -293,16 +290,16 @@ Game::Game(Network *network): joystick = new Joystick(0); } - network->registerHandler(mBeingHandler.get()); - network->registerHandler(mBuySellHandler.get()); - network->registerHandler(mChatHandler.get()); - network->registerHandler(mEquipmentHandler.get()); - network->registerHandler(mInventoryHandler.get()); - network->registerHandler(mItemHandler.get()); - network->registerHandler(mNpcHandler.get()); - network->registerHandler(mPlayerHandler.get()); - network->registerHandler(mSkillHandler.get()); - network->registerHandler(mTradeHandler.get()); + Net::registerHandler(mBeingHandler.get()); + Net::registerHandler(mBuySellHandler.get()); + Net::registerHandler(mChatHandler.get()); + Net::registerHandler(mEquipmentHandler.get()); + Net::registerHandler(mInventoryHandler.get()); + Net::registerHandler(mItemHandler.get()); + Net::registerHandler(mNpcHandler.get()); + Net::registerHandler(mPlayerHandler.get()); + Net::registerHandler(mSkillHandler.get()); + Net::registerHandler(mTradeHandler.get()); } Game::~Game() @@ -404,8 +401,7 @@ void Game::logic() } // Handle network stuff - mNetwork->flush(); - mNetwork->dispatchMessages(); + Net::flush(); } } @@ -509,14 +505,12 @@ void Game::handleInput() case SDLK_z: if (!chatWindow->isFocused()) { - FloorItem *item = floorItemManager->findByCoordinates( - player_node->mX, player_node->mY); + Uint16 x = player_node->mX / 32, y = player_node->mY / 32; + FloorItem *item = floorItemManager->findByCoordinates(x, y); // If none below the player, try the tile in front of // the player if (!item) { - Uint16 x = player_node->mX; - Uint16 y = player_node->mY; if (player_node->mDirection & Being::UP) y--; if (player_node->mDirection & Being::DOWN) @@ -638,8 +632,7 @@ void Game::handleInput() current_npc == 0 && !chatWindow->isFocused()) { - Uint16 x = player_node->mX; - Uint16 y = player_node->mY; + Uint16 x = player_node->mX / 32, y = player_node->mY / 32; unsigned char Direction = 0; // Translate pressed keys to movement and direction @@ -691,7 +684,7 @@ void Game::handleInput() if (player_node->mDirection & Being::RIGHT) targetX++; - // Attack priorioty is: Monster, Player, auto target + // Attack priority is: Monster, Player, auto target target = beingManager->findBeing( targetX, targetY, Being::MONSTER); if (!target) @@ -718,8 +711,7 @@ void Game::handleInput() { if (joystick->buttonPressed(1)) { - FloorItem *item = floorItemManager->findByCoordinates( - player_node->mX, player_node->mY); + FloorItem *item = floorItemManager->findByCoordinates(x, y); if (item) player_node->pickUp(item); @@ -33,7 +33,6 @@ #define SPEECH_MAX_TIME 100 class MessageHandler; -class Network; extern std::string map_path; extern volatile int fps; @@ -42,7 +41,7 @@ extern volatile int tick_time; class Game : public ConfigListener { public: - Game(Network *network); + Game(); ~Game(); void logic(); @@ -52,8 +51,6 @@ class Game : public ConfigListener void optionChanged(const std::string &name); private: - Network *mNetwork; - /** Used to determine whether to draw the next frame. */ int mDrawTime; diff --git a/src/gui/browserbox.h b/src/gui/browserbox.h index 95b181ad..a2c9dd9b 100644 --- a/src/gui/browserbox.h +++ b/src/gui/browserbox.h @@ -31,6 +31,7 @@ #include <guichan/mouselistener.hpp> #include "../guichanfwd.h" +#include "../main.h" class LinkHandler; diff --git a/src/gui/buddywindow.cpp b/src/gui/buddywindow.cpp index e4a96b67..145f0ad2 100644 --- a/src/gui/buddywindow.cpp +++ b/src/gui/buddywindow.cpp @@ -61,7 +61,7 @@ BuddyWindow::BuddyWindow(): add(cancel); } -void BuddyWindow::action(const std::string& eventId, gcn::Widget* widget) +void BuddyWindow::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "Talk") { int selected = mListbox->getSelected(); diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp index 0bf4c56d..73f696b7 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -26,28 +26,27 @@ #include <guichan/widgets/label.hpp> #include "button.h" +#include "listbox.h" #include "scrollarea.h" #include "shop.h" #include "slider.h" #include "../npc.h" +#include "../resources/iteminfo.h" #include "../resources/itemmanager.h" -#include "../net/messageout.h" -#include "../net/protocol.h" - #include "../utils/tostring.h" -BuyDialog::BuyDialog(Network *network): - Window("Buy"), mNetwork(network), +BuyDialog::BuyDialog(): + Window("Buy"), mMoney(0), mAmountItems(0), mMaxItems(0) { mShopItems = new ShopItems; - mShopItemList = new ShopListBox(mShopItems, mShopItems); - mScrollArea = new ScrollArea(mShopItemList); + mItemList = new ListBox(mShopItems); + mScrollArea = new ScrollArea(mItemList); mSlider = new Slider(1.0); mQuantityLabel = new gcn::Label("0"); mMoneyLabel = new gcn::Label("Price : 0 GP / 0 GP"); @@ -61,7 +60,7 @@ BuyDialog::BuyDialog(Network *network): setContentSize(260, 210); mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); mScrollArea->setDimension(gcn::Rectangle(5, 5, 250, 110)); - mShopItemList->setDimension(gcn::Rectangle(5, 5, 238, 110)); + mItemList->setDimension(gcn::Rectangle(5, 5, 238, 110)); mSlider->setDimension(gcn::Rectangle(5, 120, 200, 10)); mSlider->setEnabled(false); @@ -85,11 +84,11 @@ BuyDialog::BuyDialog(Network *network): mItemEffectLabel->setDimension(gcn::Rectangle(5, 150, 240, 14)); mItemDescLabel->setDimension(gcn::Rectangle(5, 169, 240, 14)); - mShopItemList->setEventId("item"); + mItemList->setEventId("item"); mSlider->setEventId("slider"); - mShopItemList->addActionListener(this); - mShopItemList->addSelectionListener(this); + mItemList->addActionListener(this); + mItemList->addSelectionListener(this); mSlider->addActionListener(this); add(mScrollArea); @@ -114,7 +113,6 @@ BuyDialog::~BuyDialog() void BuyDialog::setMoney(int amount) { mMoney = amount; - mShopItemList->setPlayersMoney(amount); mMoneyLabel->setCaption("Price : 0 GP / " + toString(mMoney) + " GP"); mMoneyLabel->adjustSize(); } @@ -127,7 +125,7 @@ void BuyDialog::reset() mAmountItems = 0; // Reset Previous Selected Items to prevent failing asserts - mShopItemList->setSelected(-1); + mItemList->setSelected(-1); mIncreaseButton->setEnabled(false); mDecreaseButton->setEnabled(false); mQuantityLabel->setCaption("0"); @@ -140,13 +138,20 @@ void BuyDialog::reset() void BuyDialog::addItem(short id, int price) { - mShopItems->addItem(id, price); - mShopItemList->adjustSize(); + ITEM_SHOP item_shop; + + item_shop.name = itemDb->getItemInfo(id).getName() + " " + + toString(price) + " GP"; + item_shop.price = price; + item_shop.id = id; + + mShopItems->push_back(item_shop); + mItemList->adjustSize(); } -void BuyDialog::action(const std::string& eventId, gcn::Widget* widget) +void BuyDialog::action(const std::string &eventId, gcn::Widget *widget) { - int selectedItem = mShopItemList->getSelected(); + int selectedItem = mItemList->getSelected(); if (eventId == "item") { @@ -164,7 +169,7 @@ void BuyDialog::action(const std::string& eventId, gcn::Widget* widget) // If no item was selected, none can be bought, otherwise // calculate how many the player can afford - mMaxItems = (mShopItemList->getSelected() == -1) ? 0 : + mMaxItems = (mItemList->getSelected() == -1) ? 0 : mMoney / mShopItems->at(selectedItem).price; // When at least one item can be bought, enable the slider and the @@ -179,7 +184,7 @@ void BuyDialog::action(const std::string& eventId, gcn::Widget* widget) } // The following actions require a valid selection - if (selectedItem < 0 || selectedItem >= int(mShopItems->getNumberOfElements())) + if (selectedItem < 0 || selectedItem >= int(mShopItems->size())) { return; } @@ -219,11 +224,13 @@ void BuyDialog::action(const std::string& eventId, gcn::Widget* widget) else if (eventId == "buy" && (mAmountItems > 0 && mAmountItems <= mMaxItems)) { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_NPC_BUY_REQUEST); - outMsg.writeInt16(8); - outMsg.writeInt16(mAmountItems); - outMsg.writeInt16(mShopItems->at(selectedItem).id); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_NPC_BUY_REQUEST); + outMsg.writeShort(8); + outMsg.writeShort(mAmountItems); + outMsg.writeShort(mShopItems->at(selectedItem).id); + */ // update money ! mMoney -= mAmountItems * mShopItems->at(selectedItem).price; @@ -262,7 +269,7 @@ void BuyDialog::action(const std::string& eventId, gcn::Widget* widget) void BuyDialog::selectionChanged(const SelectionEvent &event) { - int selectedItem = mShopItemList->getSelected(); + int selectedItem = mItemList->getSelected(); if (selectedItem > -1) { diff --git a/src/gui/buy.h b/src/gui/buy.h index 2af6cfe8..f5c163e1 100644 --- a/src/gui/buy.h +++ b/src/gui/buy.h @@ -28,11 +28,9 @@ #include "window.h" #include "selectionlistener.h" -#include "shoplistbox.h" #include "../guichanfwd.h" -class Network; class ShopItems; class ListBox; @@ -49,7 +47,7 @@ class BuyDialog : public Window, public gcn::ActionListener, SelectionListener * * @see Window::Window */ - BuyDialog(Network *network); + BuyDialog(); /** * Destructor @@ -94,12 +92,11 @@ class BuyDialog : public Window, public gcn::ActionListener, SelectionListener std::string getElementAt(int i); private: - Network *mNetwork; gcn::Button *mBuyButton; gcn::Button *mQuitButton; gcn::Button *mIncreaseButton; gcn::Button *mDecreaseButton; - ShopListBox *mShopItemList; + ListBox *mItemList; gcn::ScrollArea *mScrollArea; gcn::Label *mItemDescLabel; gcn::Label *mItemEffectLabel; diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp index e2e0e686..4bbbb2ff 100644 --- a/src/gui/buysell.cpp +++ b/src/gui/buysell.cpp @@ -52,7 +52,7 @@ BuySellDialog::BuySellDialog(): requestFocus(); } -void BuySellDialog::action(const std::string& eventId, gcn::Widget* widget) +void BuySellDialog::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "Buy") { current_npc->buy(); diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index fa4c0241..d825db31 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -37,7 +37,7 @@ #include "../localplayer.h" #include "../main.h" -#include "../net/messageout.h" +#include "../net/accountserver/account.h" #include "../utils/tostring.h" @@ -48,7 +48,7 @@ class CharDeleteConfirm : public ConfirmDialog { public: CharDeleteConfirm(CharSelectDialog *master); - void action(const std::string& eventId, gcn::Widget* widget); + void action(const std::string &eventId, gcn::Widget *widget); private: CharSelectDialog *master; }; @@ -60,7 +60,7 @@ CharDeleteConfirm::CharDeleteConfirm(CharSelectDialog *m): { } -void CharDeleteConfirm::action(const std::string& eventId, gcn::Widget* widget) +void CharDeleteConfirm::action(const std::string &eventId, gcn::Widget *widget) { //ConfirmDialog::action(eventId); if (eventId == "yes") { @@ -69,11 +69,9 @@ void CharDeleteConfirm::action(const std::string& eventId, gcn::Widget* widget) ConfirmDialog::action(eventId, widget); } -CharSelectDialog::CharSelectDialog(Network *network, - LockedArray<LocalPlayer*> *charInfo, - unsigned char sex): - Window("Select Character"), mNetwork(network), - mCharInfo(charInfo), mSex(sex), mCharSelected(false) +CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo): + Window("Select Character"), + mCharInfo(charInfo), mCharSelected(false) { mSelectButton = new Button("Ok", "ok", this); mCancelButton = new Button("Cancel", "cancel", this); @@ -84,9 +82,8 @@ CharSelectDialog::CharSelectDialog(Network *network, mNameLabel = new gcn::Label("Name"); mLevelLabel = new gcn::Label("Level"); - mJobLevelLabel = new gcn::Label("Job Level"); mMoneyLabel = new gcn::Label("Money"); - mPlayerBox = new PlayerBox(sex); + mPlayerBox = new PlayerBox(0); int w = 195; int h = 220; @@ -94,7 +91,6 @@ CharSelectDialog::CharSelectDialog(Network *network, mPlayerBox->setDimension(gcn::Rectangle(5, 5, w - 10, 90)); mNameLabel->setDimension(gcn::Rectangle(10, 100, 128, 16)); mLevelLabel->setDimension(gcn::Rectangle(10, 116, 128, 16)); - mJobLevelLabel->setDimension(gcn::Rectangle(10, 132, 128, 16)); mMoneyLabel->setDimension(gcn::Rectangle(10, 148, 128, 16)); mPreviousButton->setPosition(5, 170); mNextButton->setPosition(mPreviousButton->getWidth() + 10, 170); @@ -118,7 +114,6 @@ CharSelectDialog::CharSelectDialog(Network *network, add(mNextButton); add(mNameLabel); add(mLevelLabel); - add(mJobLevelLabel); add(mMoneyLabel); mSelectButton->requestFocus(); @@ -126,7 +121,7 @@ CharSelectDialog::CharSelectDialog(Network *network, updatePlayerInfo(); } -void CharSelectDialog::action(const std::string& eventId, gcn::Widget* widget) +void CharSelectDialog::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "ok" && n_character > 0) { @@ -137,11 +132,12 @@ void CharSelectDialog::action(const std::string& eventId, gcn::Widget* widget) mPreviousButton->setEnabled(false); mNextButton->setEnabled(false); mCharSelected = true; - attemptCharSelect(); + Net::AccountServer::Account::selectCharacter(mCharInfo->getPos()); + mCharInfo->lock(); } else if (eventId == "cancel") { - state = EXIT_STATE; + state = STATE_EXIT; } else if (eventId == "new") { @@ -149,7 +145,7 @@ void CharSelectDialog::action(const std::string& eventId, gcn::Widget* widget) { // Start new character dialog mCharInfo->lock(); - new CharCreateDialog(this, mCharInfo->getPos(), mNetwork, mSex); + new CharCreateDialog(this, mCharInfo->getPos()); mCharInfo->unlock(); } } @@ -178,21 +174,20 @@ void CharSelectDialog::updatePlayerInfo() if (pi) { mNameLabel->setCaption(pi->getName()); mLevelLabel->setCaption("Lvl: " + toString(pi->mLevel)); - mJobLevelLabel->setCaption("Job Lvl: " + toString(pi->mJobLevel)); - mMoneyLabel->setCaption("Gold: " + toString(pi->mGp)); + mMoneyLabel->setCaption("Money: " + toString(pi->mMoney)); if (!mCharSelected) { mNewCharButton->setEnabled(false); mDelCharButton->setEnabled(true); mSelectButton->setEnabled(true); } - mPlayerBox->mHairStyle = pi->getHairStyle() - 1; - mPlayerBox->mHairColor = pi->getHairColor() - 1; + mPlayerBox->mHairStyle = pi->getHairStyle(); + mPlayerBox->mHairColor = pi->getHairColor(); + mPlayerBox->mSex = pi->getSex(); mPlayerBox->mShowPlayer = true; } else { mNameLabel->setCaption("Name"); mLevelLabel->setCaption("Level"); - mJobLevelLabel->setCaption("Job Level"); mMoneyLabel->setCaption("Money"); mNewCharButton->setEnabled(true); mDelCharButton->setEnabled(false); @@ -206,20 +201,7 @@ void CharSelectDialog::updatePlayerInfo() void CharSelectDialog::attemptCharDelete() { - // Request character deletion - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x0068); - outMsg.writeInt32(mCharInfo->getEntry()->mCharId); - outMsg.writeString("a@a.com", 40); - mCharInfo->lock(); -} - -void CharSelectDialog::attemptCharSelect() -{ - // Request character selection - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x0066); - outMsg.writeInt8(mCharInfo->getPos()); + Net::AccountServer::Account::deleteCharacter(mCharInfo->getPos()); mCharInfo->lock(); } @@ -255,9 +237,8 @@ std::string CharSelectDialog::getName() return mNameLabel->getCaption(); } -CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network, - unsigned char sex): - Window("Create Character", true, parent), mNetwork(network), mSlot(slot) +CharCreateDialog::CharCreateDialog(Window *parent, int slot): + Window("Create Character", true, parent), mSlot(slot) { mNameField = new TextField(""); mNameLabel = new gcn::Label("Name:"); @@ -269,7 +250,7 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network, mHairStyleLabel = new gcn::Label("Hair Style:"); mCreateButton = new Button("Create", "create", this); mCancelButton = new Button("Cancel", "cancel", this); - mPlayerBox = new PlayerBox(sex); + mPlayerBox = new PlayerBox(0); mPlayerBox->mShowPlayer = true; mNameField->setEventId("create"); @@ -311,13 +292,21 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network, setLocationRelativeTo(getParent()); } -void CharCreateDialog::action(const std::string& eventId, gcn::Widget* widget) +void CharCreateDialog::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "create") { if (getName().length() >= 4) { // Attempt to create the character mCreateButton->setEnabled(false); - attemptCharCreate(); + Net::AccountServer::Account::createCharacter( + getName(), mPlayerBox->mHairStyle, mPlayerBox->mHairColor, + 0, // gender + 10, // STR + 10, // AGI + 10, // VIT + 10, // INT + 10, // DEX + 10); // LUK scheduleDelete(); } else { @@ -349,20 +338,3 @@ std::string CharCreateDialog::getName() { return mNameField->getText(); } - -void CharCreateDialog::attemptCharCreate() -{ - // Send character infos - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x0067); - outMsg.writeString(getName(), 24); - outMsg.writeInt8(5); - outMsg.writeInt8(5); - outMsg.writeInt8(5); - outMsg.writeInt8(5); - outMsg.writeInt8(5); - outMsg.writeInt8(5); - outMsg.writeInt8(mSlot); - outMsg.writeInt16(mPlayerBox->mHairColor + 1); - outMsg.writeInt16(mPlayerBox->mHairStyle + 1); -} diff --git a/src/gui/char_select.h b/src/gui/char_select.h index 0a1b5eac..6d9d1a83 100644 --- a/src/gui/char_select.h +++ b/src/gui/char_select.h @@ -32,7 +32,6 @@ #include <guichan/actionlistener.hpp> class LocalPlayer; -class Network; class PlayerBox; /** @@ -47,9 +46,7 @@ class CharSelectDialog : public Window, public gcn::ActionListener /** * Constructor. */ - CharSelectDialog(Network *network, - LockedArray<LocalPlayer*> *charInfo, - unsigned char sex); + CharSelectDialog(LockedArray<LocalPlayer*> *charInfo); void action(const std::string& eventId, gcn::Widget* widget); @@ -65,7 +62,6 @@ class CharSelectDialog : public Window, public gcn::ActionListener std::string getName(); private: - Network *mNetwork; LockedArray<LocalPlayer*> *mCharInfo; gcn::Button *mSelectButton; @@ -77,12 +73,10 @@ class CharSelectDialog : public Window, public gcn::ActionListener gcn::Label *mNameLabel; gcn::Label *mLevelLabel; - gcn::Label *mJobLevelLabel; gcn::Label *mMoneyLabel; PlayerBox *mPlayerBox; - unsigned char mSex; bool mCharSelected; /** @@ -107,15 +101,13 @@ class CharCreateDialog : public Window, public gcn::ActionListener /** * Constructor. */ - CharCreateDialog(Window *parent, int slot, Network *network, - unsigned char sex); + CharCreateDialog(Window *parent, int slot); void action(const std::string& eventId, gcn::Widget* widget); std::string getName(); private: - Network *mNetwork; gcn::TextField *mNameField; gcn::Label *mNameLabel; gcn::Button *mNextHairColorButton; diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp deleted file mode 100644 index 87ed9c17..00000000 --- a/src/gui/char_server.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#include "char_server.h" - -#include "button.h" -#include "listbox.h" -#include "scrollarea.h" - -#include "../logindata.h" -#include "../main.h" -#include "../serverinfo.h" - -#include "../net/network.h" // TODO this is just for iptostring, move that? - -#include "../utils/tostring.h" - -extern SERVER_INFO **server_info; - -/** - * The list model for the server list. - */ -class ServerListModel : public gcn::ListModel { - public: - virtual ~ServerListModel() {}; - - int getNumberOfElements(); - std::string getElementAt(int i); -}; - -ServerSelectDialog::ServerSelectDialog(LoginData *loginData): - Window("Select Server"), mLoginData(loginData) -{ - mServerListModel = new ServerListModel(); - mServerList = new ListBox(mServerListModel); - ScrollArea *mScrollArea = new ScrollArea(mServerList); - mOkButton = new Button("OK", "ok", this); - Button *mCancelButton = new Button("Cancel", "cancel", this); - - setContentSize(200, 100); - - mCancelButton->setPosition( - 200 - mCancelButton->getWidth() - 5, - 100 - mCancelButton->getHeight() - 5); - mOkButton->setPosition( - mCancelButton->getX() - mOkButton->getWidth() - 5, - 100 - mOkButton->getHeight() - 5); - mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mScrollArea->setDimension(gcn::Rectangle( - 5, 5, 200 - 2 * 5, - 100 - 3 * 5 - mCancelButton->getHeight() - - mScrollArea->getBorderSize())); - - mServerList->setEventId("ok"); - - //mServerList->addActionListener(this); - - add(mScrollArea); - add(mOkButton); - add(mCancelButton); - - if (n_server == 0) { - // Disable Ok button - mOkButton->setEnabled(false); - } else { - // Select first server - mServerList->setSelected(1); - } - - mOkButton->requestFocus(); - setLocationRelativeTo(getParent()); -} - -ServerSelectDialog::~ServerSelectDialog() -{ - delete mServerListModel; -} - -void -ServerSelectDialog::action(const std::string& eventId, gcn::Widget* widget) -{ - if (eventId == "ok") { - mOkButton->setEnabled(false); - const SERVER_INFO *si = server_info[mServerList->getSelected()]; - mLoginData->hostname = iptostring(si->address); - mLoginData->port = si->port; - state = CHAR_CONNECT_STATE; - } - else if (eventId == "cancel") { - state = LOGIN_STATE; - } -} - -int -ServerListModel::getNumberOfElements() -{ - return n_server; -} - -std::string -ServerListModel::getElementAt(int i) -{ - const SERVER_INFO *si = server_info[i]; - return si->name + " (" + toString(si->online_users) + ")"; -} diff --git a/src/gui/char_server.h b/src/gui/char_server.h deleted file mode 100644 index 3dd66566..00000000 --- a/src/gui/char_server.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#ifndef _CHAR_SEL_SERVER_H -#define _CHAR_SEL_SERVER_H - -#include <guichan/actionlistener.hpp> -#include <guichan/listmodel.hpp> - -#include "window.h" - -#include "../guichanfwd.h" - -class LoginData; -class ServerListModel; - -/** - * The server select dialog. - * - * \ingroup Interface - */ -class ServerSelectDialog : public Window, public gcn::ActionListener { - public: - /** - * Constructor - * - * @see Window::Window - */ - ServerSelectDialog(LoginData *loginData); - - /** - * Destructor. - */ - ~ServerSelectDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const std::string& eventId, gcn::Widget* widget); - - private: - LoginData *mLoginData; - ServerListModel *mServerListModel; - gcn::ListBox *mServerList; - gcn::Button *mOkButton; -}; - -#endif diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index f188b90e..3dc252ab 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -36,12 +36,12 @@ #include "../game.h" #include "../localplayer.h" -#include "../net/messageout.h" -#include "../net/protocol.h" +#include "../net/chatserver/chatserver.h" -ChatWindow::ChatWindow(Network *network): +#include "../net/gameserver/player.h" + +ChatWindow::ChatWindow(): Window(""), - mNetwork(network), mTmpVisible(false) { setWindowName("Chat"); @@ -180,7 +180,7 @@ ChatWindow::chatLog(CHATSKILL act) } void -ChatWindow::action(const std::string& eventId, gcn::Widget* widget) +ChatWindow::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "chatinput") { @@ -249,20 +249,12 @@ ChatWindow::chatSend(const std::string &nick, std::string msg) // Prepare ordinary message if (msg.substr(0, 1) != "/") { - msg = nick + " : " + msg; - - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_CHAT_MESSAGE); - outMsg.writeInt16(msg.length() + 4); - outMsg.writeString(msg, msg.length()); + Net::GameServer::Player::say(msg); } else if (msg.substr(0, IS_ANNOUNCE_LENGTH) == IS_ANNOUNCE) { msg.erase(0, IS_ANNOUNCE_LENGTH); - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x0099); - outMsg.writeInt16(msg.length() + 4); - outMsg.writeString(msg, msg.length()); + Net::ChatServer::announce(msg); } else if (msg.substr(0, IS_HELP_LENGTH) == IS_HELP) { @@ -278,8 +270,10 @@ ChatWindow::chatSend(const std::string &nick, std::string msg) } else if (msg.substr(0, IS_WHO_LENGTH) == IS_WHO) { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x00c1); + // XXX Convert for new server + /* + MessageOut outMsg(0x00c1); + */ } else { diff --git a/src/gui/chat.h b/src/gui/chat.h index 20841873..a0a3d1ec 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -35,7 +35,6 @@ #include "../guichanfwd.h" class BrowserBox; -class Network; class ScrollArea; #define BY_GM 0 // those should be self-explanatory =) @@ -116,7 +115,7 @@ class ChatWindow : public Window, public gcn::ActionListener, /** * Constructor. */ - ChatWindow(Network *network); + ChatWindow(); /** * Logic (updates components' size) @@ -188,7 +187,6 @@ class ChatWindow : public Window, public gcn::ActionListener, void setVisible(bool visible); private: - Network *mNetwork; bool mTmpVisible; /** One item in the chat log */ diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp index 3bd15589..ed2f8680 100644 --- a/src/gui/confirm_dialog.cpp +++ b/src/gui/confirm_dialog.cpp @@ -64,7 +64,7 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg, yesButton->requestFocus(); } -void ConfirmDialog::action(const std::string& eventId, gcn::Widget* widget) +void ConfirmDialog::action(const std::string &eventId, gcn::Widget *widget) { // Proxy button events to our listeners ActionListenerIterator i; diff --git a/src/gui/connection.cpp b/src/gui/connection.cpp index 8da36f20..1e0034fb 100644 --- a/src/gui/connection.cpp +++ b/src/gui/connection.cpp @@ -35,16 +35,25 @@ namespace { struct ConnectionActionListener : public gcn::ActionListener { - void action(const std::string& eventId, gcn::Widget* widget) { state = EXIT_STATE; } - } listener; + ConnectionActionListener(unsigned char previousState): + mPreviousState(previousState) {}; + + void action(const std::string &eventId, gcn::Widget *widget) { + state = mPreviousState; + } + + unsigned char mPreviousState; + }; } -ConnectionDialog::ConnectionDialog(): +ConnectionDialog::ConnectionDialog(unsigned char previousState): Window("Info"), mProgress(0) { setContentSize(200, 100); - Button *cancelButton = new Button("Cancel", "cancelButton", &listener); + ConnectionActionListener *connectionListener = new ConnectionActionListener(previousState); + + Button *cancelButton = new Button("Cancel", "cancelButton", connectionListener); mProgressBar = new ProgressBar(0.0, 200 - 10, 20, 128, 128, 128); gcn::Label *label = new gcn::Label("Connecting..."); diff --git a/src/gui/connection.h b/src/gui/connection.h index 7a072d2e..4b3187f6 100644 --- a/src/gui/connection.h +++ b/src/gui/connection.h @@ -41,7 +41,7 @@ class ConnectionDialog : public Window * * @see Window::Window */ - ConnectionDialog(); + ConnectionDialog(unsigned char previousState); void logic(); diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp index 2f788d05..d467d4d3 100644 --- a/src/gui/debugwindow.cpp +++ b/src/gui/debugwindow.cpp @@ -98,7 +98,7 @@ DebugWindow::logic() } void -DebugWindow::action(const std::string& eventId, gcn::Widget* widget) +DebugWindow::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "close") { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index b7f64274..38b17781 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -55,6 +55,9 @@ #include "../resources/image.h" #include "../resources/resourcemanager.h" #include "../resources/sdlimageloader.h" +#ifdef USE_OPENGL +#include "../resources/openglsdlimageloader.h" +#endif // Guichan stuff Gui *gui; @@ -233,7 +236,7 @@ Gui::mousePress(int mx, int my, int button) // Mouse pressed on window container (basically, the map) // Are we in-game yet? - if (state != GAME_STATE) + if (state != STATE_GAME) return; // Check if we are alive and kickin' @@ -244,8 +247,8 @@ Gui::mousePress(int mx, int my, int button) if (current_npc) return; - int tilex = mx / 32 + camera_x; - int tiley = my / 32 + camera_y; + int tilex = (mx + camera_x) / 32; + int tiley = (my + camera_y) / 32; // Right click might open a popup if (button == gcn::MouseInput::RIGHT) @@ -307,13 +310,14 @@ Gui::mousePress(int mx, int my, int button) player_node->pickUp(item); } // Just walk around - else if (engine->getCurrentMap()->getWalk(tilex, tiley)) + else if (engine->getCurrentMap() && + engine->getCurrentMap()->getWalk(tilex, tiley)) { // XXX XXX XXX REALLY UGLY! Uint8 *keys = SDL_GetKeyState(NULL); if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT])) { - player_node->setDestination(tilex, tiley); + player_node->setDestination(mx + camera_x, my + camera_y); player_node->stopAttack(); } } diff --git a/src/gui/help.cpp b/src/gui/help.cpp index 2b9b649a..e7429b29 100644 --- a/src/gui/help.cpp +++ b/src/gui/help.cpp @@ -54,7 +54,7 @@ HelpWindow::HelpWindow(): setLocationRelativeTo(getParent()); } -void HelpWindow::action(const std::string& eventId, gcn::Widget* widget) +void HelpWindow::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "close") { diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index eb85220b..452b7c16 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -98,7 +98,7 @@ void InventoryWindow::logic() mWeightLabel->adjustSize(); } -void InventoryWindow::action(const std::string& eventId, gcn::Widget* widget) +void InventoryWindow::action(const std::string &eventId, gcn::Widget *widget) { Item *item = mItems->getItem(); diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp index 3f8daddd..30c899a8 100644 --- a/src/gui/item_amount.cpp +++ b/src/gui/item_amount.cpp @@ -94,7 +94,7 @@ void ItemAmountWindow::resetAmount() mItemAmountTextBox->setInt(1); } -void ItemAmountWindow::action(const std::string& eventId, gcn::Widget* widget) +void ItemAmountWindow::action(const std::string &eventId, gcn::Widget *widget) { int amount = mItemAmountTextBox->getInt(); diff --git a/src/gui/login.cpp b/src/gui/login.cpp index 675de078..1d9b6e1e 100644 --- a/src/gui/login.cpp +++ b/src/gui/login.cpp @@ -43,7 +43,7 @@ WrongDataNoticeListener::setTarget(gcn::TextField *textField) } void -WrongDataNoticeListener::action(const std::string& eventId, gcn::Widget* widget) +WrongDataNoticeListener::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "ok") { @@ -59,53 +59,43 @@ LoginDialog::LoginDialog(LoginData *loginData): { gcn::Label *userLabel = new gcn::Label("Name:"); gcn::Label *passLabel = new gcn::Label("Password:"); - gcn::Label *serverLabel = new gcn::Label("Server:"); mUserField = new TextField(mLoginData->username); mPassField = new PasswordField(mLoginData->password); - mServerField = new TextField(mLoginData->hostname); mKeepCheck = new CheckBox("Keep", mLoginData->remember); mOkButton = new Button("OK", "ok", this); mCancelButton = new Button("Cancel", "cancel", this); mRegisterButton = new Button("Register", "register", this); - setContentSize(200, 100); + setContentSize(200, 91); userLabel->setPosition(5, 5); passLabel->setPosition(5, 14 + userLabel->getHeight()); - serverLabel->setPosition( - 5, 23 + userLabel->getHeight() + passLabel->getHeight()); mUserField->setPosition(65, 5); mPassField->setPosition(65, 14 + userLabel->getHeight()); - mServerField->setPosition( - 65, 23 + userLabel->getHeight() + passLabel->getHeight()); mUserField->setWidth(130); mPassField->setWidth(130); - mServerField->setWidth(130); - mKeepCheck->setPosition(4, 77); + mKeepCheck->setPosition(4, 68); mCancelButton->setPosition( 200 - mCancelButton->getWidth() - 5, - 100 - mCancelButton->getHeight() - 5); + 91 - mCancelButton->getHeight() - 5); mOkButton->setPosition( mCancelButton->getX() - mOkButton->getWidth() - 5, - 100 - mOkButton->getHeight() - 5); - mRegisterButton->setPosition(mKeepCheck->getX() + mKeepCheck->getWidth() + 10, - 100 - mRegisterButton->getHeight() - 5); + 91 - mOkButton->getHeight() - 5); + mRegisterButton->setPosition( + mKeepCheck->getX() + mKeepCheck->getWidth() + 10, + 91 - mRegisterButton->getHeight() - 5); mUserField->setEventId("ok"); mPassField->setEventId("ok"); - mServerField->setEventId("ok"); mUserField->addActionListener(this); mPassField->addActionListener(this); - mServerField->addActionListener(this); mKeepCheck->addActionListener(this); add(userLabel); add(passLabel); - add(serverLabel); add(mUserField); add(mPassField); - add(mServerField); add(mKeepCheck); add(mOkButton); add(mCancelButton); @@ -128,7 +118,7 @@ LoginDialog::~LoginDialog() } void -LoginDialog::action(const std::string& eventId, gcn::Widget* widget) +LoginDialog::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "ok") { @@ -141,24 +131,22 @@ LoginDialog::action(const std::string& eventId, gcn::Widget* widget) } else { - mLoginData->hostname = mServerField->getText(); mLoginData->username = mUserField->getText(); mLoginData->password = mPassField->getText(); mLoginData->remember = mKeepCheck->isMarked(); mOkButton->setEnabled(false); - //mCancelButton->setEnabled(false); mRegisterButton->setEnabled(false); - state = ACCOUNT_STATE; + state = STATE_LOGIN_ATTEMPT; } } else if (eventId == "cancel") { - state = EXIT_STATE; + state = STATE_EXIT; } else if (eventId == "register") { - state = REGISTER_STATE; + state = STATE_REGISTER; } } diff --git a/src/gui/login.h b/src/gui/login.h index 7218dca8..6d510da7 100644 --- a/src/gui/login.h +++ b/src/gui/login.h @@ -70,7 +70,6 @@ class LoginDialog : public Window, public gcn::ActionListener { private: gcn::TextField *mUserField; gcn::TextField *mPassField; - gcn::TextField *mServerField; gcn::CheckBox *mKeepCheck; gcn::Button *mOkButton; gcn::Button *mCancelButton; diff --git a/src/gui/menuwindow.cpp b/src/gui/menuwindow.cpp index 701d9366..a1b342f0 100644 --- a/src/gui/menuwindow.cpp +++ b/src/gui/menuwindow.cpp @@ -39,7 +39,7 @@ namespace { /** * Called when receiving actions from widget. */ - void action(const std::string& eventId, gcn::Widget* widget); + void action(const std::string &eventId, gcn::Widget *widget); } listener; } @@ -75,7 +75,7 @@ void MenuWindow::draw(gcn::Graphics *graphics) } -void MenuWindowListener::action(const std::string& eventId, gcn::Widget* widget) +void MenuWindowListener::action(const std::string &eventId, gcn::Widget *widget) { Window *window = NULL; if (eventId == "Status") diff --git a/src/gui/newskill.cpp b/src/gui/newskill.cpp index 59cdd9db..7f5de543 100644 --- a/src/gui/newskill.cpp +++ b/src/gui/newskill.cpp @@ -121,7 +121,7 @@ NewSkillDialog::NewSkillDialog(): setLocationRelativeTo(getParent()); } -void NewSkillDialog::action(const std::string& eventId, gcn::Widget* widget) +void NewSkillDialog::action(const std::string &eventId, gcn::Widget *widget) { int osp = startPoint; if (eventId == "close") diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp index 6b647032..5b7ca439 100644 --- a/src/gui/npc_text.cpp +++ b/src/gui/npc_text.cpp @@ -67,7 +67,7 @@ NpcTextDialog::addText(const std::string &text) } void -NpcTextDialog::action(const std::string& eventId, gcn::Widget* widget) +NpcTextDialog::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "ok") { diff --git a/src/gui/npclistdialog.cpp b/src/gui/npclistdialog.cpp index 895ef1f9..d1c3ddcb 100644 --- a/src/gui/npclistdialog.cpp +++ b/src/gui/npclistdialog.cpp @@ -91,7 +91,7 @@ NpcListDialog::reset() } void -NpcListDialog::action(const std::string& eventId, gcn::Widget* widget) +NpcListDialog::action(const std::string &eventId, gcn::Widget *widget) { int choice = 0; diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp index e527339e..906fd61f 100644 --- a/src/gui/ok_dialog.cpp +++ b/src/gui/ok_dialog.cpp @@ -54,7 +54,7 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg, okButton->requestFocus(); } -void OkDialog::action(const std::string& eventId, gcn::Widget* widget) +void OkDialog::action(const std::string &eventId, gcn::Widget *widget) { // Proxy button events to our listeners ActionListenerIterator i; diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp index 0a155573..46cd7e85 100644 --- a/src/gui/playerbox.cpp +++ b/src/gui/playerbox.cpp @@ -94,13 +94,13 @@ void PlayerBox::draw(gcn::Graphics *graphics) playerset[mSex]->get(0), 23, 12); // Draw his hair - if (mHairColor >= 0 && mHairStyle >= 0 && - mHairColor < NR_HAIR_COLORS && mHairStyle < NR_HAIR_STYLES) + if (mHairStyle > 0 && mHairColor < NR_HAIR_COLORS && + mHairStyle < NR_HAIR_STYLES) { int hf = 5 * mHairColor; if (hf >= 0 && hf < (int)hairset[mHairStyle]->size()) { dynamic_cast<Graphics*>(graphics)->drawImage( - hairset[mHairStyle]->get(hf), 35, 7); + hairset[mHairStyle - 1]->get(hf), 35, 7); } } } diff --git a/src/gui/playerbox.h b/src/gui/playerbox.h index 79f7c2aa..ec04eaf6 100644 --- a/src/gui/playerbox.h +++ b/src/gui/playerbox.h @@ -57,10 +57,10 @@ class PlayerBox : public gcn::ScrollArea */ void drawBorder(gcn::Graphics *graphics); - int mHairColor; /**< The hair color index */ - int mHairStyle; /**< The hair style index */ - unsigned char mSex; /**< Sex */ - bool mShowPlayer; /**< Wether to show the player or not */ + unsigned char mHairColor; /**< The hair color index */ + unsigned char mHairStyle; /**< The hair style index */ + unsigned char mSex; /**< Sex */ + bool mShowPlayer; /**< Wether to show the player or not */ private: static int instances; diff --git a/src/gui/register.cpp b/src/gui/register.cpp index 1c1f0a26..7cef62a2 100644 --- a/src/gui/register.cpp +++ b/src/gui/register.cpp @@ -44,24 +44,21 @@ RegisterDialog::RegisterDialog(LoginData *loginData): Window("Register"), mWrongDataNoticeListener(new WrongDataNoticeListener()), - mWrongRegisterNotice(0), mLoginData(loginData) { gcn::Label *userLabel = new gcn::Label("Name:"); gcn::Label *passwordLabel = new gcn::Label("Password:"); gcn::Label *confirmLabel = new gcn::Label("Confirm:"); - gcn::Label *serverLabel = new gcn::Label("Server:"); + gcn::Label *emailLabel = new gcn::Label("Email:"); mUserField = new TextField("player"); mPasswordField = new PasswordField(); mConfirmField = new PasswordField(); - mServerField = new TextField(); - mMaleButton = new RadioButton("Male", "sex", true); - mFemaleButton = new RadioButton("Female", "sex", false); + mEmailField = new TextField(); mRegisterButton = new Button("Register", "register", this); mCancelButton = new Button("Cancel", "cancel", this); - int width = 200; - int height = 150; + const int width = 200; + const int height = 130; setContentSize(width, height); mUserField->setPosition(65, 5); @@ -72,55 +69,49 @@ RegisterDialog::RegisterDialog(LoginData *loginData): mConfirmField->setPosition( 65, mPasswordField->getY() + mPasswordField->getHeight() + 7); mConfirmField->setWidth(130); - mServerField->setPosition( - 65, 23 + mConfirmField->getY() + mConfirmField->getHeight() + 7); - mServerField->setWidth(130); + mEmailField->setPosition( + 65, mConfirmField->getY() + mConfirmField->getHeight() + 7); + mEmailField->setWidth(130); userLabel->setPosition(5, mUserField->getY() + 1); passwordLabel->setPosition(5, mPasswordField->getY() + 1); confirmLabel->setPosition(5, mConfirmField->getY() + 1); - serverLabel->setPosition(5, mServerField->getY() + 1); + emailLabel->setPosition(5, mEmailField->getY() + 1); - mFemaleButton->setPosition(width - mFemaleButton->getWidth() - 10, - mConfirmField->getY() + mConfirmField->getHeight() + 7); - mMaleButton->setPosition(mFemaleButton->getX() - mMaleButton->getWidth() - 5, - mFemaleButton->getY()); - - mRegisterButton->setPosition(5, height - mRegisterButton->getHeight() - 5); - mCancelButton->setPosition(10 + mRegisterButton->getWidth(), - mRegisterButton->getY()); + mCancelButton->setPosition( + width - 5 - mCancelButton->getWidth(), + height - 5 - mCancelButton->getHeight()); + mRegisterButton->setPosition( + mCancelButton->getX() - 5 - mRegisterButton->getWidth(), + mCancelButton->getY()); add(userLabel); add(passwordLabel); - add(serverLabel); + add(emailLabel); add(confirmLabel); add(mUserField); add(mPasswordField); add(mConfirmField); - add(mServerField); - add(mMaleButton); - add(mFemaleButton); + add(mEmailField); add(mRegisterButton); add(mCancelButton); setLocationRelativeTo(getParent()); mUserField->requestFocus(); mUserField->setCaretPosition(mUserField->getText().length()); - - mServerField->setText(config.getValue("host", "")); } RegisterDialog::~RegisterDialog() { - delete mWrongRegisterNotice; + delete mWrongDataNoticeListener; } void -RegisterDialog::action(const std::string& eventId, gcn::Widget* widget) +RegisterDialog::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "cancel") { - state = EXIT_STATE; + state = STATE_LOGIN; } else if (eventId == "register") { @@ -176,6 +167,8 @@ RegisterDialog::action(const std::string& eventId, gcn::Widget* widget) error = 2; } + // TODO: Check if a valid email address was given + if (error > 0) { if (error == 1) @@ -189,22 +182,20 @@ RegisterDialog::action(const std::string& eventId, gcn::Widget* widget) mConfirmField->setText(""); } - delete mWrongRegisterNotice; - mWrongRegisterNotice = new OkDialog("Error", errorMsg.str()); - mWrongRegisterNotice->addActionListener(mWrongDataNoticeListener); + OkDialog *dlg = new OkDialog("Error", errorMsg.str()); + dlg->addActionListener(mWrongDataNoticeListener); } else { // No errors detected, register the new user. mRegisterButton->setEnabled(false); - mLoginData->hostname = config.getValue("host", "animesites.de"); mLoginData->port = (short)config.getValue("port", 0); mLoginData->username = mUserField->getText(); mLoginData->password = mPasswordField->getText(); - mLoginData->username += mFemaleButton->isMarked() ? "_F" : "_M"; + mLoginData->email = mEmailField->getText(); - state = ACCOUNT_STATE; + state = STATE_REGISTER_ATTEMPT; } } } diff --git a/src/gui/register.h b/src/gui/register.h index 5d3f6cd5..4c98788f 100644 --- a/src/gui/register.h +++ b/src/gui/register.h @@ -65,15 +65,12 @@ class RegisterDialog : public Window, public gcn::ActionListener { gcn::TextField *mUserField; gcn::TextField *mPasswordField; gcn::TextField *mConfirmField; - gcn::TextField *mServerField; + gcn::TextField *mEmailField; gcn::Button *mRegisterButton; gcn::Button *mCancelButton; - gcn::RadioButton *mMaleButton; - gcn::RadioButton *mFemaleButton; WrongDataNoticeListener *mWrongDataNoticeListener; - OkDialog *mWrongRegisterNotice; LoginData *mLoginData; }; diff --git a/src/gui/selectionlistener.h b/src/gui/selectionlistener.h index b39672b5..a2fc6533 100644 --- a/src/gui/selectionlistener.h +++ b/src/gui/selectionlistener.h @@ -18,7 +18,7 @@ * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id$ + * $Id: selectionlistener.h 2651 2006-09-03 16:47:48Z b_lindeijer $ */ #ifndef _TMW_SELECTIONLISTENER_H__ diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index 7f50c1e4..9c25aced 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -28,7 +28,7 @@ #include <guichan/widgets/label.hpp> #include "button.h" -#include "shoplistbox.h" +#include "listbox.h" #include "scrollarea.h" #include "shop.h" #include "slider.h" @@ -39,23 +39,19 @@ #include "../resources/iteminfo.h" #include "../resources/itemmanager.h" -#include "../net/messageout.h" -#include "../net/protocol.h" - #include "../utils/tostring.h" -SellDialog::SellDialog(Network *network): +SellDialog::SellDialog(): Window("Sell"), - mNetwork(network), mMaxItems(0), mAmountItems(0) { mShopItems = new ShopItems(); - mShopItemList = new ShopListBox(mShopItems, mShopItems); - ScrollArea *scrollArea = new ScrollArea(mShopItemList); + mItemList = new ListBox(mShopItems); + ScrollArea *scrollArea = new ScrollArea(mItemList); mSlider = new Slider(1.0); mQuantityLabel = new gcn::Label("0"); - mMoneyLabel = new gcn::Label("Money: 0 GP / Total: 0 GP"); + mMoneyLabel = new gcn::Label("Price: 0"); mItemDescLabel = new gcn::Label("Description:"); mItemEffectLabel = new gcn::Label("Effect:"); mIncreaseButton = new Button("+", "+", this); @@ -67,7 +63,7 @@ SellDialog::SellDialog(Network *network): setContentSize(260, 210); scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); scrollArea->setDimension(gcn::Rectangle(5, 5, 250, 110)); - mShopItemList->setDimension(gcn::Rectangle(5, 5, 238, 110)); + mItemList->setDimension(gcn::Rectangle(5, 5, 238, 110)); mSlider->setDimension(gcn::Rectangle(5, 120, 200, 10)); mSlider->setEnabled(false); @@ -91,13 +87,11 @@ SellDialog::SellDialog(Network *network): quitButton->setPosition(208, 186); - mShopItemList->setEventId("item"); + mItemList->setEventId("item"); mSlider->setEventId("mSlider"); - mShopItemList->setPriceCheck(false); - - mShopItemList->addActionListener(this); - mShopItemList->addSelectionListener(this); + mItemList->addActionListener(this); + mItemList->addSelectionListener(this); mSlider->addActionListener(this); add(scrollArea); @@ -127,14 +121,13 @@ void SellDialog::reset() mQuantityLabel->setCaption("0"); mQuantityLabel->adjustSize(); - mMoneyLabel->setCaption("Money: 0 GP / Total: " - + toString(mPlayerMoney) + " GP"); + mMoneyLabel->setCaption("Price: 0"); mMoneyLabel->adjustSize(); mItemDescLabel->setCaption(""); mItemEffectLabel->setCaption(""); // Reset Previous Selected Items to prevent failing asserts - mShopItemList->setSelected(-1); + mItemList->setSelected(-1); mIncreaseButton->setEnabled(false); mDecreaseButton->setEnabled(false); } @@ -151,15 +144,14 @@ void SellDialog::addItem(Item *item, int price) item_shop.index = item->getInvIndex(); item_shop.id = item->getId(); item_shop.quantity = item->getQuantity(); - item_shop.image = item->getInfo().getImage(); mShopItems->push_back(item_shop); - mShopItemList->adjustSize(); + mItemList->adjustSize(); } -void SellDialog::action(const std::string& eventId, gcn::Widget* widget) +void SellDialog::action(const std::string &eventId, gcn::Widget *widget) { - int selectedItem = mShopItemList->getSelected(); + int selectedItem = mItemList->getSelected(); if (eventId == "item") { @@ -168,22 +160,19 @@ void SellDialog::action(const std::string& eventId, gcn::Widget* widget) mDecreaseButton->setEnabled(false); mSellButton->setEnabled(false); + mQuantityLabel->setCaption("0"); mQuantityLabel->adjustSize(); - mMoneyLabel->setCaption("Money: 0 GP / Total: " - + toString(mPlayerMoney) + " GP"); + mMoneyLabel->setCaption("Price: 0"); mMoneyLabel->adjustSize(); if (selectedItem > -1) { mSlider->setEnabled(true); mIncreaseButton->setEnabled(true); mMaxItems = mShopItems->at(selectedItem).quantity; - mQuantityLabel->setCaption("0 / " + toString(mMaxItems)); } else { mSlider->setEnabled(false); mIncreaseButton->setEnabled(false); - mQuantityLabel->setCaption("0"); } - mQuantityLabel->adjustSize(); } else if (eventId == "quit") { @@ -192,7 +181,7 @@ void SellDialog::action(const std::string& eventId, gcn::Widget* widget) } // The following actions require a valid item selection - if (selectedItem == -1 || selectedItem >= int(mShopItems->getNumberOfElements())) { + if (selectedItem == -1 || selectedItem >= int(mShopItems->size())) { return; } @@ -226,23 +215,23 @@ void SellDialog::action(const std::string& eventId, gcn::Widget* widget) // Attempt sell assert(mAmountItems > 0 && mAmountItems <= mMaxItems); - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_NPC_SELL_REQUEST); - outMsg.writeInt16(8); - outMsg.writeInt16(mShopItems->at(selectedItem).index); - outMsg.writeInt16(mAmountItems); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_NPC_SELL_REQUEST); + outMsg.writeShort(8); + outMsg.writeShort(mShopItems->at(selectedItem).index); + outMsg.writeShort(mAmountItems); + */ mMaxItems -= mAmountItems; - mShopItems->getShop()->at(selectedItem).quantity = mMaxItems; mAmountItems = 0; mSlider->setValue(0); mSlider->setEnabled(mMaxItems != 0); // All were sold if (!mMaxItems) { - - mShopItemList->setSelected(-1); - mShopItems->getShop()->erase(mShopItems->getShop()->begin() + selectedItem); + mItemList->setSelected(-1); + mShopItems->erase(mShopItems->begin() + selectedItem); } // Update only when there are items left, the entry doesn't exist @@ -254,12 +243,11 @@ void SellDialog::action(const std::string& eventId, gcn::Widget* widget) if (updateButtonsAndLabels) { // Update labels - mQuantityLabel->setCaption(toString(mAmountItems) + " / " + toString(mMaxItems)); + mQuantityLabel->setCaption(toString(mAmountItems)); mQuantityLabel->adjustSize(); int price = mAmountItems * mShopItems->at(selectedItem).price; - mMoneyLabel->setCaption("Money: " + toString(price) + " GP / Total: " - + toString(price + mPlayerMoney) + " GP"); + mMoneyLabel->setCaption("Price: " + toString(price)); mMoneyLabel->adjustSize(); // Update Buttons @@ -271,7 +259,7 @@ void SellDialog::action(const std::string& eventId, gcn::Widget* widget) void SellDialog::selectionChanged(const SelectionEvent &event) { - int selectedItem = mShopItemList->getSelected(); + int selectedItem = mItemList->getSelected(); if (selectedItem > -1) { @@ -287,9 +275,3 @@ void SellDialog::selectionChanged(const SelectionEvent &event) mItemEffectLabel->setCaption("Effect"); } } - -void SellDialog::setMoney(int amount) -{ - mPlayerMoney = amount; - mShopItemList->setPlayersMoney(amount); -} diff --git a/src/gui/sell.h b/src/gui/sell.h index f27a9751..69f8b089 100644 --- a/src/gui/sell.h +++ b/src/gui/sell.h @@ -32,9 +32,8 @@ #include "../guichanfwd.h" class Item; -class Network; class ShopItems; -class ShopListBox; +class ListBox; /** * The sell dialog. @@ -49,7 +48,7 @@ class SellDialog : public Window, gcn::ActionListener, SelectionListener * * @see Window::Window */ - SellDialog(Network *network); + SellDialog(); /** * Destructor @@ -78,17 +77,11 @@ class SellDialog : public Window, gcn::ActionListener, SelectionListener */ void selectionChanged(const SelectionEvent &event); - /** - * Gives Player's Money amount - */ - void setMoney(int amount); - private: - Network *mNetwork; gcn::Button *mSellButton; gcn::Button *mIncreaseButton; gcn::Button *mDecreaseButton; - ShopListBox *mShopItemList; + ListBox *mItemList; gcn::Label *mMoneyLabel; gcn::Label *mItemDescLabel; gcn::Label *mItemEffectLabel; @@ -96,7 +89,6 @@ class SellDialog : public Window, gcn::ActionListener, SelectionListener gcn::Slider *mSlider; ShopItems *mShopItems; - int mPlayerMoney; int mMaxItems; int mAmountItems; diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp new file mode 100644 index 00000000..39abd5ed --- /dev/null +++ b/src/gui/serverdialog.cpp @@ -0,0 +1,246 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: login.cpp 2550 2006-08-20 00:56:23Z b_lindeijer $ + */ + +#include "serverdialog.h" + +#include <iostream> +#include <string> + +#include <guichan/widgets/label.hpp> + +#include "button.h" +#include "listbox.h" +#include "ok_dialog.h" +#include "scrollarea.h" +#include "textfield.h" + +#include "../configuration.h" +#include "../log.h" +#include "../logindata.h" +#include "../main.h" + +#include "../utils/tostring.h" + +const short MAX_SERVERLIST = 5; + +void +DropDownListener::action(const std::string &eventId, gcn::Widget *widget) +{ + if (eventId == "ok") + { + // Reset the text fields and give back the server dialog. + mServerNameField->setText(""); + mServerNameField->setCaretPosition(0); + mServerPortField->setText(""); + mServerPortField->setCaretPosition(0); + + mServerNameField->requestFocus(); + } + else if (eventId == "changeSelection") + { + // Change the textField Values according to new selection + if (currentSelectedIndex != mServersListBox->getSelected()) + { + Server myServer; + myServer = mServersListModel->getServer(mServersListBox->getSelected()); + mServerNameField->setText(myServer.serverName); + mServerPortField->setText(toString(myServer.port)); + currentSelectedIndex = mServersListBox->getSelected(); + } + } +} + +int ServersListModel::getNumberOfElements() +{ + return servers.size(); +} + +std::string ServersListModel::getElementAt(int elementIndex) +{ + std::string myServer = ""; + myServer = servers.at(elementIndex).serverName; + myServer += ":"; + myServer += toString(servers.at(elementIndex).port); + return myServer; +} + +void ServersListModel::addFirstElement(Server server) +{ + // Equivalent to push_front + std::vector<Server>::iterator MyIterator = servers.begin(); + servers.insert(MyIterator, 1, server); +} + +void ServersListModel::addElement(Server server) +{ + servers.push_back(server); +} + +ServerDialog::ServerDialog(LoginData *loginData): + Window("Choose your Mana World Server"), mLoginData(loginData) +{ + gcn::Label *serverLabel = new gcn::Label("Server:"); + gcn::Label *portLabel = new gcn::Label("Port:"); + mServerNameField = new TextField(mLoginData->hostname); + mPortField = new TextField(toString(mLoginData->port)); + + // Add the most used servers from config + mMostUsedServersListModel = new ServersListModel(); + Server currentServer; + std::string currentConfig = ""; + for (int i=0; i<=MAX_SERVERLIST; i++) + { + currentServer.serverName = ""; + currentServer.port = 0; + + currentConfig = "MostUsedServerName" + toString(i); + currentServer.serverName = config.getValue(currentConfig, ""); + + currentConfig = "MostUsedServerPort" + toString(i); + currentServer.port = (short)atoi(config.getValue(currentConfig, "").c_str()); + if (!currentServer.serverName.empty() || currentServer.port != 0) + { + mMostUsedServersListModel->addElement(currentServer); + } + } + + mMostUsedServersListBox = new ListBox(NULL); + mMostUsedServersListBox->setListModel(mMostUsedServersListModel); + mMostUsedServersScrollArea = new ScrollArea(); + mMostUsedServersDropDown = new DropDown(mMostUsedServersListModel, + mMostUsedServersScrollArea, mMostUsedServersListBox); + + mDropDownListener = new DropDownListener(mServerNameField, mPortField, + mMostUsedServersListModel, mMostUsedServersListBox); + + mOkButton = new Button("OK", "ok", this); + mCancelButton = new Button("Cancel", "cancel", this); + + setContentSize(200, 100); + + serverLabel->setPosition(10, 5); + portLabel->setPosition(10, 14 + serverLabel->getHeight()); + + mServerNameField->setPosition(60, 5); + mPortField->setPosition(60, 14 + serverLabel->getHeight()); + mServerNameField->setWidth(130); + mPortField->setWidth(130); + + mMostUsedServersDropDown->setPosition(10, 10 + + portLabel->getY() + portLabel->getHeight()); + mMostUsedServersDropDown->setWidth(180); + + mCancelButton->setPosition( + 200 - mCancelButton->getWidth() - 5, + 100 - mCancelButton->getHeight() - 5); + mOkButton->setPosition( + mCancelButton->getX() - mOkButton->getWidth() - 5, + 100 - mOkButton->getHeight() - 5); + + mServerNameField->setEventId("ok"); + mPortField->setEventId("ok"); + mMostUsedServersDropDown->setEventId("changeSelection"); + + mServerNameField->addActionListener(this); + mPortField->addActionListener(this); + mMostUsedServersDropDown->addActionListener(mDropDownListener); + + add(serverLabel); + add(portLabel); + add(mServerNameField); + add(mPortField); + add(mMostUsedServersDropDown); + add(mOkButton); + add(mCancelButton); + + setLocationRelativeTo(getParent()); + + if (mServerNameField->getText().empty()) { + mServerNameField->requestFocus(); + } else { + if (mPortField->getText().empty()) { + mPortField->requestFocus(); + } else { + mOkButton->requestFocus(); + } + } +} + +ServerDialog::~ServerDialog() +{ + delete mDropDownListener; +} + +void +ServerDialog::action(const std::string &eventId, gcn::Widget *widget) +{ + if (eventId == "ok") + { + // Check login + if (mServerNameField->getText().empty() || mPortField->getText().empty()) + { + OkDialog *dlg = new OkDialog("Error", "Enter the chosen server."); + dlg->addActionListener(mDropDownListener); + } + else + { + mLoginData->hostname = mServerNameField->getText(); + mLoginData->port = (short) atoi(mPortField->getText().c_str()); + mOkButton->setEnabled(false); + mCancelButton->setEnabled(false); + + // First, look if the entry is a new one. + Server currentServer; + bool newEntry = true; + for (int i = 0; i < mMostUsedServersListModel->getNumberOfElements(); i++) + { + currentServer = mMostUsedServersListModel->getServer(i); + if (currentServer.serverName == mLoginData->hostname && + currentServer.port == mLoginData->port) + newEntry = false; + } + // Then, add it to config if it's really new + currentServer.serverName = mLoginData->hostname; + currentServer.port = mLoginData->port; + if (newEntry) + mMostUsedServersListModel->addFirstElement(currentServer); + // Write the entry in config + std::string currentConfig = ""; + for (int i = 0; i < mMostUsedServersListModel->getNumberOfElements(); i++) + { + currentServer = mMostUsedServersListModel->getServer(i); + + currentConfig = "MostUsedServerName" + toString(i); + config.setValue(currentConfig, currentServer.serverName); + + currentConfig = "MostUsedServerPort" + toString(i); + config.setValue(currentConfig, toString(currentServer.port)); + } + state = STATE_CONNECT_ACCOUNT; + } + } + else if (eventId == "cancel") + { + state = STATE_EXIT; + } +} diff --git a/src/gui/serverdialog.h b/src/gui/serverdialog.h new file mode 100644 index 00000000..5b265c17 --- /dev/null +++ b/src/gui/serverdialog.h @@ -0,0 +1,153 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: login.h 2486 2006-07-30 14:33:28Z b_lindeijer $ + */ + +#ifndef _TMW_SERVERDIALOG_H +#define _TMW_SERVERDIALOG_H + +#include <iosfwd> +#include <vector> + +#include <guichan/actionlistener.hpp> +#include <guichan/listmodel.hpp> +#include "./widgets/dropdown.h" + +#include "login.h" +#include "window.h" + +#include "../guichanfwd.h" + +#include "../net/network.h" + +class LoginData; + +/** + * A server structure to keep pairs of servers and ports. + */ +struct Server { + Server(): + serverName(""), + port(0) {}; + + std::string serverName; + short port; +}; + +/** + * Server and Port List Model + */ +class ServersListModel : public gcn::ListModel +{ + public: + /** + * Used to get number of line in the list + */ + int getNumberOfElements(); + /** + * Used to get an element from the list + */ + std::string getElementAt(int elementIndex); + /** + * Used to get the corresponding Server struct + */ + Server getServer(int elementIndex) { return servers[elementIndex]; }; + /** + * Add an Element at the end of the server list + */ + void addElement(Server server); + /** + * Add an Element at the beginning of the server list + */ + void addFirstElement(Server server); + + private: + std::vector<Server> servers; +}; + +/** + * Listener used for handling the DropDown in the server Dialog. + */ +class DropDownListener : public gcn::ActionListener +{ + public: + DropDownListener(gcn::TextField *serverNameField, + gcn::TextField *serverPortField, + ServersListModel *serversListModel, + gcn::ListBox *serversListBox): + currentSelectedIndex(0), + mServerNameField(serverNameField), + mServerPortField(serverPortField), + mServersListModel(serversListModel), + mServersListBox(serversListBox) {}; + void action(const std::string& eventId, + gcn::Widget* widget); + private: + short currentSelectedIndex; + gcn::TextField *mServerNameField; + gcn::TextField *mServerPortField; + ServersListModel *mServersListModel; + gcn::ListBox *mServersListBox; +}; + + +/** + * The server choice dialog. + * + * \ingroup Interface + */ +class ServerDialog : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor + * + * @see Window::Window + */ + ServerDialog(LoginData *loginData); + + /** + * Destructor + */ + ~ServerDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const std::string& eventId, gcn::Widget* widget); + + private: + gcn::TextField *mServerNameField; + gcn::TextField *mPortField; + gcn::Button *mOkButton; + gcn::Button *mCancelButton; + + DropDown *mMostUsedServersDropDown; + gcn::ListBox *mMostUsedServersListBox; + gcn::ScrollArea *mMostUsedServersScrollArea; + ServersListModel *mMostUsedServersListModel; + + DropDownListener *mDropDownListener; + + LoginData *mLoginData; +}; + +#endif diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp index 7deb39ff..78b10498 100644 --- a/src/gui/setup.cpp +++ b/src/gui/setup.cpp @@ -85,7 +85,7 @@ Setup::~Setup() for_each(mTabs.begin(), mTabs.end(), make_dtor(mTabs)); } -void Setup::action(const std::string& event, gcn::Widget* widget) +void Setup::action(const std::string& event, gcn::Widget *widget) { if (event == "Apply") { diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp index ac5771ad..db88ff64 100644 --- a/src/gui/setup_audio.cpp +++ b/src/gui/setup_audio.cpp @@ -108,7 +108,7 @@ void Setup_Audio::cancel() config.setValue("musicVolume", mMusicVolume); } -void Setup_Audio::action(const std::string& event, gcn::Widget* widget) +void Setup_Audio::action(const std::string& event, gcn::Widget *widget) { if (event == "sfx") { diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index 22d0520e..7a4aae03 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -42,6 +42,7 @@ #include "../configuration.h" #include "../graphics.h" #include "../log.h" +#include "../main.h" #include "../utils/tostring.h" diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h index df6dc85e..482d1c65 100644 --- a/src/gui/setup_video.h +++ b/src/gui/setup_video.h @@ -44,7 +44,7 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, void action(const std::string &eventId, gcn::Widget *widget); /** Called when key is pressed */ - void keyPress(const gcn::Key &key); + void keyPress(const gcn::Key& key); private: bool mFullScreenEnabled; diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp index 3f30732a..3706cdf8 100644 --- a/src/gui/shop.cpp +++ b/src/gui/shop.cpp @@ -22,53 +22,13 @@ */ #include "shop.h" -#include "../utils/tostring.h" -#include "../resources/itemmanager.h" - -ShopItems::~ShopItems() -{ - clear(); -} int ShopItems::getNumberOfElements() { - return mItemsShop.size(); + return size(); } std::string ShopItems::getElementAt(int i) { - return mItemsShop.at(i).name; -} - -void ShopItems::addItem(short id, int price) -{ - ITEM_SHOP item_shop; - - item_shop.name = itemDb->getItemInfo(id).getName() - + " " + toString(price) + " GP"; - item_shop.price = price; - item_shop.id = id; - item_shop.image = itemDb->getItemInfo(id).getImage(); - - mItemsShop.push_back(item_shop); -} - -ITEM_SHOP ShopItems::at(int i) -{ - return mItemsShop.at(i); -} - -void ShopItems::push_back(ITEM_SHOP item_shop) -{ - mItemsShop.push_back(item_shop); -} - -void ShopItems::clear() -{ - mItemsShop.clear(); -} - -std::vector<ITEM_SHOP>* ShopItems::getShop() -{ - return &mItemsShop; + return at(i).name; } diff --git a/src/gui/shop.h b/src/gui/shop.h index de452b5c..fb1f33fd 100644 --- a/src/gui/shop.h +++ b/src/gui/shop.h @@ -28,34 +28,22 @@ #include <vector> #include <guichan/listmodel.hpp> -#include "../resources/image.h" struct ITEM_SHOP { - short id; std::string name; - Image *image; int price; + short id; int index; int quantity; }; -class ShopItems : public gcn::ListModel +class ShopItems : public std::vector<ITEM_SHOP>, public gcn::ListModel { public: /** * Destructor */ - ~ShopItems(); - - /** - * Adds an item and its associated picture - */ - void addItem(short id, int price); - - /** - * Convenience function for adding items - */ - void push_back(ITEM_SHOP item_shop); + virtual ~ShopItems() {}; /** * Returns the number of items in the shop. @@ -66,25 +54,6 @@ class ShopItems : public gcn::ListModel * Returns the name of item number i in the shop. */ std::string getElementAt(int i); - - /** - * Returns the item number i in the shop. - */ - ITEM_SHOP at(int i); - - /** - * Clear the vector. - */ - void clear(); - - /** - * Direct access to the vector - */ - std::vector<ITEM_SHOP>* getShop(); - - private: - std::vector<ITEM_SHOP> mItemsShop; - }; #endif diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp deleted file mode 100644 index 61abff35..00000000 --- a/src/gui/shoplistbox.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: listbox.cpp 2655 2006-09-03 21:25:02Z b_lindeijer $ - */ - -#include "shoplistbox.h" - -#include "selectionlistener.h" - -#include <guichan/font.hpp> -#include <guichan/graphics.hpp> -#include <guichan/listmodel.hpp> -#include <guichan/mouseinput.hpp> -#include <guichan/imagefont.hpp> -#include <guichan/basiccontainer.hpp> - -#include "../graphics.h" - -const int ITEM_SPRITE_HEIGHT = 32; - -ShopListBox::ShopListBox(gcn::ListModel *listModel): - gcn::ListBox(listModel), - mMousePressed(false), - mPlayerMoney(0) -{ - mRowHeight = getFont()->getHeight(); - mPriceCheck = true; -} - -ShopListBox::ShopListBox(gcn::ListModel *listModel, ShopItems *shopListModel): - gcn::ListBox(listModel), - mMousePressed(false), - mPlayerMoney(0), - mShopItems(shopListModel) -{ - mRowHeight = (getFont()->getHeight() > ITEM_SPRITE_HEIGHT ? - getFont()->getHeight() : ITEM_SPRITE_HEIGHT); - mPriceCheck = true; -} - - -void ShopListBox::setPlayersMoney(int money) -{ - mPlayerMoney = money; -} - -void ShopListBox::draw(gcn::Graphics *graphics) -{ - if (mListModel == NULL) { - return; - } - - graphics->setFont(getFont()); - - // Draw the list elements - for (int i = 0, y = 0; i < mListModel->getNumberOfElements(); ++i, y += mRowHeight) - { - graphics->setColor(gcn::Color(0xffffff)); - if (mShopItems != NULL) - { - if(mPlayerMoney < mShopItems->at(i).price && mPriceCheck) - { - graphics->setColor(gcn::Color(0x919191)); - } - } - graphics->fillRectangle(gcn::Rectangle(0, y, getWidth(), mRowHeight)); - if (mShopItems) - dynamic_cast<Graphics*>(graphics)->drawImage(mShopItems->at(i).image, 1, y); - graphics->drawText(mListModel->getElementAt(i), ITEM_SPRITE_HEIGHT, y); - } - - // Draw rectangle below the selected list element and the list element - // not shown. - if (mSelected >= 0) { - graphics->setColor(gcn::Color(110, 160, 255)); - graphics->fillRectangle(gcn::Rectangle(0, mRowHeight * mSelected, - getWidth(), mRowHeight)); - if (mShopItems) - dynamic_cast<Graphics*>(graphics)->drawImage( - mShopItems->at(mSelected).image, 1, mRowHeight * mSelected); - graphics->drawText(mListModel->getElementAt(mSelected), - ITEM_SPRITE_HEIGHT, mRowHeight * mSelected); - } -} - -void ShopListBox::setSelected(int selected) -{ - gcn::ListBox::setSelected(selected); - if (mListModel != NULL) - { - gcn::BasicContainer *par = getParent(); - if (par == NULL) - { - return; - } - - gcn::Rectangle scroll; - - if (mSelected < 0) - { - scroll.y = 0; - } - else - { - scroll.y = mRowHeight * mSelected; - } - - scroll.height = mRowHeight; - par->showWidgetPart(this, scroll); - } - fireSelectionChangedEvent(); -} - -void ShopListBox::mousePress(int x, int y, int button) -{ - - bool enoughMoney = false; - if (button == gcn::MouseInput::LEFT && hasMouse()) - { - if (mShopItems) - { - if(mPlayerMoney >= mShopItems->at(y / mRowHeight).price) - enoughMoney = true; - } - else // Old Behaviour - enoughMoney = true; - - if (!mPriceCheck) - enoughMoney = true; - - if (enoughMoney) - { - setSelected(y / mRowHeight); - generateAction(); - mMousePressed = true; - } - } -} - -void ShopListBox::mouseRelease(int x, int y, int button) -{ - gcn::ListBox::mouseRelease(x, y, button); - - mMousePressed = false; -} - -void ShopListBox::mouseMotion(int x, int y) -{ - gcn::ListBox::mouseMotion(x, y); - - // Pretend mouse is pressed continuously while dragged. Causes list - // selection to be updated as is default in many GUIs. - if (mMousePressed) - { - mousePress(x, y, gcn::MouseInput::LEFT); - } -} - -void ShopListBox::fireSelectionChangedEvent() -{ - SelectionEvent event(this); - SelectionListeners::iterator i_end = mListeners.end(); - SelectionListeners::iterator i; - - for (i = mListeners.begin(); i != i_end; ++i) - { - (*i)->selectionChanged(event); - } -} - -void ShopListBox::adjustSize() -{ - if (mListModel != NULL) - { - setHeight(mRowHeight * mListModel->getNumberOfElements()); - } -} - -void ShopListBox::setPriceCheck(bool check) -{ - mPriceCheck = check; -} diff --git a/src/gui/shoplistbox.h b/src/gui/shoplistbox.h deleted file mode 100644 index 2dff8977..00000000 --- a/src/gui/shoplistbox.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: listbox.h 2655 2006-09-03 21:25:02Z b_lindeijer $ - */ - -#ifndef _TMW_LISTBOX_H -#define _TMW_LISTBOX_H - -#include <guichan/widgets/listbox.hpp> -#include "shop.h" - -class SelectionListener; - -/** - * A list box, meant to be used inside a scroll area. Same as the Guichan list - * box except this one doesn't have a background, instead completely relying - * on the scroll area. It also adds selection listener functionality. - * - * \ingroup GUI - */ -class ShopListBox : public gcn::ListBox -{ - public: - /** - * Constructor. - */ - ShopListBox(gcn::ListModel *listModel); - - /** - * Constructor with shopitems - */ - ShopListBox(gcn::ListModel *listModel, ShopItems *shopListModel); - - /** - * Draws the list box. - */ - void draw(gcn::Graphics *graphics); - - void mousePress(int x, int y, int button); - void mouseRelease(int x, int y, int button); - void mouseMotion(int x, int y); - - /** - * Adds a listener to the list that's notified each time a change to - * the selection occurs. - */ - void addSelectionListener(SelectionListener *listener) - { - mListeners.push_back(listener); - } - - /** - * Removes a listener from the list that's notified each time a change - * to the selection occurs. - */ - void removeSelectionListener(SelectionListener *listener) - { - mListeners.remove(listener); - } - - /** - * Sets the index of the selected element. - */ - void setSelected(int selected); - - /** - * gives information about the current player's money - */ - void setPlayersMoney(int money); - - /** - * Adjust List draw size - */ - void adjustSize(); - - /** - * Set on/off the disabling of too expensive items. - * (Good for selling mode.) - */ - void setPriceCheck(bool check); - - private: - /** - * Sends out selection events to the list of selection listeners. - */ - void fireSelectionChangedEvent(); - - bool mMousePressed; /**< Keeps track of mouse pressed status. */ - - std::list<SelectionListener*> mListeners; - - int mPlayerMoney; - - /** - * Keeps another pointer to the same listModel, permitting to - * use the ShopItems specific functions. - */ - ShopItems *mShopItems; - - int mRowHeight; /**< Row Height */ - - bool mPriceCheck; - -}; - -#endif diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp index e824f2f0..4f552fd7 100644 --- a/src/gui/skill.cpp +++ b/src/gui/skill.cpp @@ -103,7 +103,7 @@ SkillDialog::~SkillDialog() cleanList(); } -void SkillDialog::action(const std::string& eventId, gcn::Widget* widget) +void SkillDialog::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "inc") { diff --git a/src/gui/status.cpp b/src/gui/status.cpp index 0f149403..b53e0942 100644 --- a/src/gui/status.cpp +++ b/src/gui/status.cpp @@ -48,7 +48,7 @@ StatusWindow::StatusWindow(LocalPlayer *player): // ---------------------- mLvlLabel = new gcn::Label("Level:"); - mGpLabel = new gcn::Label("Money:"); + mMoneyLabel = new gcn::Label("Money:"); mHpLabel = new gcn::Label("HP:"); mHpBar = new ProgressBar(1.0f, 80, 15, 0, 171, 34); @@ -71,7 +71,7 @@ StatusWindow::StatusWindow(LocalPlayer *player): mLvlLabel->setPosition(x, y); x += mLvlLabel->getWidth() + 40; - mGpLabel->setPosition(x, y); + mMoneyLabel->setPosition(x, y); y += mLvlLabel->getHeight() + 5; // Next Row x = 5; @@ -100,7 +100,7 @@ StatusWindow::StatusWindow(LocalPlayer *player): mJobValueLabel->setPosition(290, y); add(mLvlLabel); - add(mGpLabel); + add(mMoneyLabel); add(mHpLabel); add(mHpValueLabel); add(mMpLabel); @@ -227,8 +227,8 @@ void StatusWindow::update() mLvlLabel->setCaption("Level: " + toString(mPlayer->mLevel)); mLvlLabel->adjustSize(); - mGpLabel->setCaption("Money: " + toString(mPlayer->mGp) + " GP"); - mGpLabel->adjustSize(); + mMoneyLabel->setCaption("Money: " + toString(mPlayer->mMoney) + " GP"); + mMoneyLabel->adjustSize(); mJobXpLabel->setCaption("Job: " + toString(mPlayer->mJobLevel)); mJobXpLabel->adjustSize(); @@ -334,7 +334,7 @@ void StatusWindow::update() mStatsReflexPoints->adjustSize(); // Update Second column widgets position - mGpLabel->setPosition(mLvlLabel->getX() + mLvlLabel->getWidth() + 20, + mMoneyLabel->setPosition(mLvlLabel->getX() + mLvlLabel->getWidth() + 20, mLvlLabel->getY()); mXpLabel->setPosition( @@ -361,34 +361,34 @@ void StatusWindow::draw(gcn::Graphics *g) Window::draw(g); } -void StatusWindow::action(const std::string& eventId, gcn::Widget* widget) +void StatusWindow::action(const std::string &eventId, gcn::Widget *widget) { // Stats Part if (eventId.length() == 3) { if (eventId == "STR") { - player_node->raiseAttribute(LocalPlayer::STR); + mPlayer->raiseAttribute(LocalPlayer::STR); } if (eventId == "AGI") { - player_node->raiseAttribute(LocalPlayer::AGI); + mPlayer->raiseAttribute(LocalPlayer::AGI); } if (eventId == "VIT") { - player_node->raiseAttribute(LocalPlayer::VIT); + mPlayer->raiseAttribute(LocalPlayer::VIT); } if (eventId == "INT") { - player_node->raiseAttribute(LocalPlayer::INT); + mPlayer->raiseAttribute(LocalPlayer::INT); } if (eventId == "DEX") { - player_node->raiseAttribute(LocalPlayer::DEX); + mPlayer->raiseAttribute(LocalPlayer::DEX); } if (eventId == "LUK") { - player_node->raiseAttribute(LocalPlayer::LUK); + mPlayer->raiseAttribute(LocalPlayer::LUK); } } } diff --git a/src/gui/status.h b/src/gui/status.h index 6b963d24..fe2140e3 100644 --- a/src/gui/status.h +++ b/src/gui/status.h @@ -69,7 +69,7 @@ class StatusWindow : public Window, public gcn::ActionListener { /** * Status Part */ - gcn::Label *mLvlLabel, *mGpLabel, *mHpLabel, *mHpValueLabel; + gcn::Label *mLvlLabel, *mMoneyLabel, *mHpLabel, *mHpValueLabel; gcn::Label *mMpLabel, *mMpValueLabel; gcn::Label *mXpLabel, *mXpValueLabel, *mJobXpLabel, *mJobValueLabel; ProgressBar *mHpBar, *mMpBar; diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp index 5352b23d..2ac56ae5 100644 --- a/src/gui/trade.cpp +++ b/src/gui/trade.cpp @@ -38,16 +38,12 @@ #include "../inventory.h" #include "../item.h" -#include "../net/messageout.h" -#include "../net/protocol.h" - #include "../resources/iteminfo.h" #include "../utils/tostring.h" -TradeWindow::TradeWindow(Network *network): +TradeWindow::TradeWindow(): Window("Trade: You"), - mNetwork(network), mMyInventory(new Inventory()), mPartnerInventory(new Inventory()) { @@ -217,10 +213,12 @@ void TradeWindow::receivedOk(bool own) void TradeWindow::tradeItem(Item *item, int quantity) { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_TRADE_ITEM_ADD_REQUEST); - outMsg.writeInt16(item->getInvIndex()); - outMsg.writeInt32(quantity); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_TRADE_ITEM_ADD_REQUEST); + outMsg.writeShort(item->getInvIndex()); + outMsg.writeLong(quantity); + */ } void TradeWindow::selectionChanged(const SelectionEvent &event) @@ -258,7 +256,7 @@ void TradeWindow::selectionChanged(const SelectionEvent &event) } } -void TradeWindow::action(const std::string& eventId, gcn::Widget* widget) +void TradeWindow::action(const std::string &eventId, gcn::Widget *widget) { Item *item = inventoryWindow->getItem(); @@ -290,8 +288,10 @@ void TradeWindow::action(const std::string& eventId, gcn::Widget* widget) } else if (eventId == "cancel") { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_TRADE_CANCEL_REQUEST); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_TRADE_CANCEL_REQUEST); + */ } else if (eventId == "ok") { @@ -301,20 +301,27 @@ void TradeWindow::action(const std::string& eventId, gcn::Widget* widget) { mMoneyField->setText(toString(tempInt)); - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_TRADE_ITEM_ADD_REQUEST); - outMsg.writeInt16(0); - outMsg.writeInt32(tempInt); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_TRADE_ITEM_ADD_REQUEST); + outMsg.writeShort(0); + outMsg.writeLong(tempInt); + */ } else { mMoneyField->setText(""); } mMoneyField->setEnabled(false); - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_TRADE_ADD_COMPLETE); + + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_TRADE_ADD_COMPLETE); + */ } else if (eventId == "trade") { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_TRADE_OK); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_TRADE_OK); + */ } } diff --git a/src/gui/trade.h b/src/gui/trade.h index 339fc4e3..ebd05a52 100644 --- a/src/gui/trade.h +++ b/src/gui/trade.h @@ -36,7 +36,6 @@ class Inventory; class Item; class ItemContainer; -class Network; class ScrollArea; /** @@ -50,7 +49,7 @@ class TradeWindow : public Window, gcn::ActionListener, SelectionListener /** * Constructor. */ - TradeWindow(Network *network); + TradeWindow(); /** * Destructor. @@ -115,8 +114,6 @@ class TradeWindow : public Window, gcn::ActionListener, SelectionListener void action(const std::string &eventId, gcn::Widget *widget); private: - Network *mNetwork; - typedef std::auto_ptr<Inventory> InventoryPtr; InventoryPtr mMyInventory; InventoryPtr mPartnerInventory; diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index 89d1793e..510e10ba 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -86,8 +86,7 @@ UpdaterWindow::UpdaterWindow(): mCancelButton->requestFocus(); setLocationRelativeTo(getParent()); - mUpdateHost = - config.getValue("updatehost", "http://updates.themanaworld.org"); + mUpdateHost = config.getValue("updatehost", "themanaworld.org/files"); mBasePath = config.getValue("homeDir", "."); // Try to download the updates list @@ -130,7 +129,7 @@ void UpdaterWindow::enable() mPlayButton->requestFocus(); } -void UpdaterWindow::action(const std::string& eventId, gcn::Widget* widget) +void UpdaterWindow::action(const std::string &eventId, gcn::Widget *widget) { if (eventId == "cancel") { @@ -139,7 +138,7 @@ void UpdaterWindow::action(const std::string& eventId, gcn::Widget* widget) // Skip the updating process if (mDownloadStatus == UPDATE_COMPLETE) { - state = EXIT_STATE; + state = STATE_EXIT; } else { @@ -148,7 +147,7 @@ void UpdaterWindow::action(const std::string& eventId, gcn::Widget* widget) } else if (eventId == "play") { - state = LOGIN_STATE; + state = STATE_LOGIN; } } @@ -182,12 +181,6 @@ void UpdaterWindow::loadNews() setVisible(true); } -void UpdaterWindow::addRow(const std::string &row) -{ - mBrowserBox->addRow(row); - mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); -} - int UpdaterWindow::updateProgress(void *ptr, double dt, double dn, double ut, double un) { @@ -201,7 +194,7 @@ int UpdaterWindow::updateProgress(void *ptr, uw->mCurrentFile + " (" + toString((int)progress * 100) + "%)"); uw->setProgress(progress); - if (state != UPDATE_STATE || uw->mDownloadStatus == UPDATE_ERROR) + if (state != STATE_UPDATE || uw->mDownloadStatus == UPDATE_ERROR) { // If the action was canceled return an error code to stop the mThread return -1; @@ -343,11 +336,12 @@ void UpdaterWindow::logic() } mThread = NULL; } - addRow(""); - addRow("##1 The update process is incomplete."); - addRow("##1 It is strongly recommended that"); - addRow("##1 you try again later"); - addRow(mCurlError); + mBrowserBox->addRow(""); + mBrowserBox->addRow("##1 The update process is incomplete."); + mBrowserBox->addRow("##1 It is strongly recommended that"); + mBrowserBox->addRow("##1 you try again later"); + mBrowserBox->addRow(mCurlError); + mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); mDownloadStatus = UPDATE_COMPLETE; break; case UPDATE_NEWS: diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h index 5016036d..16442656 100644 --- a/src/gui/updatewindow.h +++ b/src/gui/updatewindow.h @@ -81,11 +81,6 @@ class UpdaterWindow : public Window, public gcn::ActionListener void action(const std::string& eventId, gcn::Widget* widget); - /** - * Add a row to the message field. - */ - void addRow(const std::string &row); - void logic(); int updateState; diff --git a/src/gui/vbox.cpp b/src/gui/vbox.cpp index eb838ead..b503508e 100644 --- a/src/gui/vbox.cpp +++ b/src/gui/vbox.cpp @@ -25,7 +25,7 @@ void VBox::draw(gcn::Graphics *graphics) { - if (mWidgets.size() == 0) + if (mWidgets.empty()) { return; } diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp new file mode 100644 index 00000000..34c6b93a --- /dev/null +++ b/src/gui/widgets/dropdown.cpp @@ -0,0 +1,191 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "dropdown.h" + +#include "../../graphics.h" + +#include "../../graphic/imagerect.h" + +#include "../../resources/image.h" +#include "../../resources/resourcemanager.h" + +#include "../../utils/dtor.h" + +int DropDown::instances = 0; +Image *DropDown::buttons[2][2]; +ImageRect DropDown::skin; + +DropDown::DropDown(gcn::ListModel *listModel, + gcn::ScrollArea *scrollArea, + gcn::ListBox *listBox): + gcn::DropDown::DropDown(listModel, + scrollArea, listBox) +{ + setBorderSize(2); + + // Initialize graphics + if (instances == 0) + { + // Load the background skin + ResourceManager *resman = ResourceManager::getInstance(); + + // Get the button skin + buttons[1][0] = + resman->getImage("graphics/gui/vscroll_up_default.png"); + buttons[0][0] = + resman->getImage("graphics/gui/vscroll_down_default.png"); + buttons[1][1] = + resman->getImage("graphics/gui/vscroll_up_pressed.png"); + buttons[0][1] = + resman->getImage("graphics/gui/vscroll_down_pressed.png"); + + // get the border skin + Image *boxBorder = resman->getImage("graphics/gui/deepbox.png"); + int gridx[4] = {0, 3, 28, 31}; + int gridy[4] = {0, 3, 28, 31}; + int a = 0, x, y; + + for (y = 0; y < 3; y++) { + for (x = 0; x < 3; x++) { + skin.grid[a] = boxBorder->getSubImage( + gridx[x], gridy[y], + gridx[x + 1] - gridx[x] + 1, + gridy[y + 1] - gridy[y] + 1); + a++; + } + } + + boxBorder->decRef(); + } + + instances++; +} + +DropDown::~DropDown() +{ + instances--; + // Free images memory + if (instances == 0) + { + buttons[0][0]->decRef(); + buttons[0][1]->decRef(); + buttons[1][0]->decRef(); + buttons[1][1]->decRef(); + + for_each(skin.grid, skin.grid + 9, dtor<Image*>()); + } +} + +void DropDown::draw(gcn::Graphics* graphics) +{ + int h; + + if (mDroppedDown) + { + h = mOldH; + } + else + { + h = getHeight(); + } + + int alpha = getBaseColor().a; + gcn::Color faceColor = getBaseColor(); + faceColor.a = alpha; + gcn::Color highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + gcn::Color shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + + graphics->setColor(getBackgroundColor()); + graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), h)); + + graphics->setColor(getForegroundColor()); + graphics->setFont(getFont()); + + if (mListBox->getListModel() && mListBox->getSelected() >= 0) + { + graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()), 1, 0); + } + + if (isFocused()) + { + graphics->setColor(highlightColor); + graphics->drawRectangle(gcn::Rectangle(0, 0, getWidth() - h, h)); + } + + drawButton(graphics); + + if (mDroppedDown) + { + drawChildren(graphics); + + // Draw two lines separating the ListBox with se selected + // element view. + graphics->setColor(highlightColor); + graphics->drawLine(0, h, getWidth(), h); + graphics->setColor(shadowColor); + graphics->drawLine(0, h + 1,getWidth(),h + 1); + } +} + +void DropDown::drawBorder(gcn::Graphics *graphics) +{ + int w, h, bs; + bs = getBorderSize(); + w = getWidth() + bs * 2; + h = getHeight() + bs * 2; + + dynamic_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, skin); +} + +void DropDown::drawButton(gcn::Graphics *graphics) +{ + + unsigned short state = 0; + unsigned short dir = 0; + gcn::Rectangle dim; + + if (mPushed) + state = 1; + + if (mDroppedDown) + dir = 1; + + int height; + if (mDroppedDown) + { + height = mOldH; + } + else + { + height = getHeight(); + } + int x = getWidth() - height; + int y = 0; + + dynamic_cast<Graphics*>(graphics)->drawImage( + buttons[dir][state], x, y + 1); +} diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h new file mode 100644 index 00000000..37e754af --- /dev/null +++ b/src/gui/widgets/dropdown.h @@ -0,0 +1,85 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef DROPDOWN_H +#define DROPDOWN_H + +#include <iosfwd> + +#include <guichan/widgets/dropdown.hpp> +#include "../scrollarea.h" +#include "../listbox.h" + +class Image; +class ImageRect; + + /** + * A drop down box from which you can select different values. It is one of + * the most complicated Widgets you will find in Guichan. For drawing the + * DroppedDown box it uses one ScrollArea and one ListBox. It also uses an + * internal FocusHandler to handle the focus of the internal ScollArea and + * ListBox. DropDown uses a ListModel to handle the list. To be able to use + * DropDown you must give DropDown an implemented ListModel which represents + * your list. + */ +class DropDown : public gcn::DropDown +{ + public: + /** + * Contructor. + * + * @param listModel the ListModel to use. + * @param scrollArea the ScrollArea to use. + * @param listBox the listBox to use. + * @see ListModel, ScrollArea, ListBox. + */ + DropDown(gcn::ListModel *listModel = NULL, + gcn::ScrollArea *scrollArea = NULL, + gcn::ListBox *listBox = NULL); + + /** + * Destructor. + */ + ~DropDown(); + + void draw(gcn::Graphics* graphics); + + void drawBorder(gcn::Graphics* graphics); + + + protected: + /** + * Draws the button with the little down arrow. + * + * @param graphics a Graphics object to draw with. + */ + void drawButton(gcn::Graphics *graphics); + + // Add own Images. + static int instances; + static Image *buttons[2][2]; + static ImageRect skin; +}; + +#endif // end DROPDOWN_H + diff --git a/src/gui/window.cpp b/src/gui/window.cpp index fe23c775..c7860021 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -196,7 +196,7 @@ void Window::setContentHeight(int height) resizeToContent(); } -void Window::setLocationRelativeTo(gcn::Widget* widget) +void Window::setLocationRelativeTo(gcn::Widget *widget) { int wx, wy; int x, y; @@ -249,16 +249,18 @@ void Window::setSticky(bool sticky) mSticky = sticky; } -bool Window::isSticky() { +bool Window::isSticky() +{ return mSticky; } -void Window::setVisible(bool visible) { - if(isSticky()) +void Window::setVisible(bool visible) +{ + if (isSticky()) { gcn::Window::setVisible(true); - } - else + } + else { gcn::Window::setVisible(visible); } diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 802da92f..6898dfb7 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -31,13 +31,13 @@ #include "main.h" #include "sound.h" -#include "net/messageout.h" -#include "net/protocol.h" +#include "net/gameserver/player.h" LocalPlayer *player_node = NULL; -LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map): - Player(id, job, map), +LocalPlayer::LocalPlayer(): + Player(65535, 0, NULL), + mLevel(1), mInventory(new Inventory()), mTarget(NULL), mPickUpTarget(NULL), mTrading(false), mLastAction(-1) @@ -50,26 +50,9 @@ LocalPlayer::~LocalPlayer() void LocalPlayer::logic() { - switch (mAction) { - case WALK: - mFrame = (get_elapsed_time(mWalkTime) * 6) / mWalkSpeed; - if (mFrame >= 6) { - nextStep(); - } - break; - - case ATTACK: - int frames = 4; - if (getWeapon() == 2) - { - frames = 5; - } - mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed; - if (mFrame >= frames) { - nextStep(); - attack(); - } - break; + if (mAction == ATTACK && get_elapsed_time(mWalkTime) >= mAttackSpeed) + { + attack(); } // Actions are allowed once per second @@ -115,10 +98,10 @@ Item* LocalPlayer::getInvItem(int index) void LocalPlayer::equipItem(Item *item) { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_PLAYER_EQUIP); - outMsg.writeInt16(item->getInvIndex()); - outMsg.writeInt16(0); + // XXX What's itemId and slot exactly? Same as eAthena? + /* + Net::GameServer::Player::equip(itemId, slot)); + */ } void LocalPlayer::unequipItem(Item *item) @@ -126,9 +109,11 @@ void LocalPlayer::unequipItem(Item *item) if (!item) return; - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_PLAYER_UNEQUIP); - outMsg.writeInt16(item->getInvIndex()); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_PLAYER_UNEQUIP); + outMsg.writeShort(item->getInvIndex()); + */ // Tidy equipment directly to avoid weapon still shown bug, by instance mEquipment->removeEquipment(item); @@ -136,34 +121,39 @@ void LocalPlayer::unequipItem(Item *item) void LocalPlayer::useItem(Item *item) { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_PLAYER_INVENTORY_USE); - outMsg.writeInt16(item->getInvIndex()); - outMsg.writeInt32(item->getId()); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_PLAYER_INVENTORY_USE); + outMsg.writeShort(item->getInvIndex()); + outMsg.writeLong(item->getId()); // Note: id is dest of item, usually player_node->account_ID ?? + */ } void LocalPlayer::dropItem(Item *item, int quantity) { - // TODO: Fix wrong coordinates of drops, serverside? - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_PLAYER_INVENTORY_DROP); - outMsg.writeInt16(item->getInvIndex()); - outMsg.writeInt16(quantity); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_PLAYER_INVENTORY_DROP); + outMsg.writeShort(item->getInvIndex()); + outMsg.writeShort(quantity); + */ } void LocalPlayer::pickUp(FloorItem *item) { - int dx = item->getX() - mX; - int dy = item->getY() - mY; + int dx = item->getX() - mX / 32; + int dy = item->getY() - mY / 32; if (dx * dx + dy * dy < 4) { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_ITEM_PICKUP); - outMsg.writeInt32(item->getId()); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_ITEM_PICKUP); + outMsg.writeLong(item->getId()); + */ mPickUpTarget = NULL; } else { - setDestination(item->getX(), item->getY()); + setDestination(item->getX() * 32 + 16, item->getY() * 32 + 16); mPickUpTarget = item; stopAttack(); } @@ -181,28 +171,28 @@ void LocalPlayer::walk(unsigned char dir) return; } - Sint16 dx = 0, dy = 0; + int dx = 0, dy = 0; if (dir & UP) - dy--; + dy -= 32; if (dir & DOWN) - dy++; + dy += 32; if (dir & LEFT) - dx--; + dx -= 32; if (dir & RIGHT) - dx++; + dx += 32; // Prevent skipping corners over colliding tiles - if (dx && mMap->tileCollides(mX + dx, mY)) - dx = 0; - if (dy && mMap->tileCollides(mX, mY + dy)) - dy = 0; + if (dx && mMap->tileCollides((mX + dx) / 32, mY / 32)) + dx = 16 - mX % 32; + if (dy && mMap->tileCollides(mX / 32, (mY + dy) / 32)) + dy = 16 - mY % 32; // Choose a straight direction when diagonal target is blocked - if (dx && dy && !mMap->getWalk(mX + dx, mY + dy)) - dx = 0; + if (dx && dy && !mMap->getWalk((mX + dx) / 32, (mY + dy) / 32)) + dx = 16 - mX % 32; // Walk to where the player can actually go - if ((dx || dy) && mMap->getWalk(mX + dx, mY + dy)) + if ((dx || dy) && mMap->getWalk((mX + dx) / 32, (mY + dy) / 32)) { setDestination(mX + dx, mY + dy); } @@ -218,11 +208,15 @@ void LocalPlayer::walk(unsigned char dir) void LocalPlayer::setDestination(Uint16 x, Uint16 y) { - char temp[3]; - MessageOut outMsg(mNetwork); - set_coordinates(temp, x, y, mDirection); - outMsg.writeInt16(0x0085); - outMsg.writeString(temp, 3); + // Fix coordinates so that the player does not seem to dig into walls. + int tx = x / 32, ty = y / 32, fx = x % 32, fy = y % 32; + if (fx != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty)) fx = 16; + if (fy != 16 && !mMap->getWalk(tx, ty + fy / 16 * 2 - 1)) fy = 16; + if (fx != 16 && fy != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty + fy / 16 * 2 - 1)) fx = 16; + x = tx * 32 + fx; + y = ty * 32 + fy; + + Net::GameServer::Player::walk(x, y); mPickUpTarget = NULL; @@ -231,36 +225,38 @@ void LocalPlayer::setDestination(Uint16 x, Uint16 y) void LocalPlayer::raiseAttribute(Attribute attr) { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_STAT_UPDATE_REQUEST); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_STAT_UPDATE_REQUEST); switch (attr) { case STR: - outMsg.writeInt16(0x000d); + outMsg.writeShort(0x000d); break; case AGI: - outMsg.writeInt16(0x000e); + outMsg.writeShort(0x000e); break; case VIT: - outMsg.writeInt16(0x000f); + outMsg.writeShort(0x000f); break; case INT: - outMsg.writeInt16(0x0010); + outMsg.writeShort(0x0010); break; case DEX: - outMsg.writeInt16(0x0011); + outMsg.writeShort(0x0011); break; case LUK: - outMsg.writeInt16(0x0012); + outMsg.writeShort(0x0012); break; } - outMsg.writeInt8(1); + outMsg.writeByte(1); + */ } void LocalPlayer::raiseSkill(Uint16 skillId) @@ -268,9 +264,11 @@ void LocalPlayer::raiseSkill(Uint16 skillId) if (mSkillPoint <= 0) return; - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_SKILL_LEVELUP_REQUEST); - outMsg.writeInt16(skillId); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_SKILL_LEVELUP_REQUEST); + outMsg.writeShort(skillId); + */ } void LocalPlayer::toggleSit() @@ -287,10 +285,12 @@ void LocalPlayer::toggleSit() default: return; } - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x0089); - outMsg.writeInt32(0); - outMsg.writeInt8(type); + // XXX Convert for new server + /* + MessageOut outMsg(0x0089); + outMsg.writeLong(0); + outMsg.writeByte(type); + */ } void LocalPlayer::emote(Uint8 emotion) @@ -299,9 +299,11 @@ void LocalPlayer::emote(Uint8 emotion) return; mLastAction = tick_time; - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x00bf); - outMsg.writeInt8(emotion); + // XXX Convert for new server + /* + MessageOut outMsg(0x00bf); + outMsg.writeByte(emotion); + */ } void LocalPlayer::tradeReply(bool accept) @@ -309,16 +311,20 @@ void LocalPlayer::tradeReply(bool accept) if (!accept) mTrading = false; - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_TRADE_RESPONSE); - outMsg.writeInt8(accept ? 3 : 4); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_TRADE_RESPONSE); + outMsg.writeByte(accept ? 3 : 4); + */ } void LocalPlayer::trade(Being *being) const { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_TRADE_REQUEST); - outMsg.writeInt32(being->getId()); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_TRADE_REQUEST); + outMsg.writeLong(being->getId()); + */ } bool LocalPlayer::tradeRequestOk() const @@ -368,10 +374,12 @@ void LocalPlayer::attack(Being *target, bool keep) else sound.playSfx("sfx/fist-swish.ogg"); - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x0089); - outMsg.writeInt32(target->getId()); - outMsg.writeInt8(0); + // XXX Convert for new server + /* + MessageOut outMsg(0x0089); + outMsg.writeLong(target->getId()); + outMsg.writeByte(0); + */ } void LocalPlayer::stopAttack() @@ -386,7 +394,9 @@ Being* LocalPlayer::getTarget() const void LocalPlayer::revive() { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x00b2); - outMsg.writeInt8(0); + // XXX Convert for new server + /* + MessageOut outMsg(0x00b2); + outMsg.writeByte(0); + */ } diff --git a/src/localplayer.h b/src/localplayer.h index a3fe91f7..dbf2a147 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -34,7 +34,6 @@ class FloorItem; class Inventory; class Item; -class Network; class LocalPlayer : public Player { @@ -43,12 +42,10 @@ class LocalPlayer : public Player STR = 0, AGI, VIT, INT, DEX, LUK }; - LocalPlayer(Uint32 id, Uint16 job, Map *map); + LocalPlayer(); virtual ~LocalPlayer(); - void setNetwork(Network *network) { mNetwork = network; } - virtual void logic(); virtual void nextStep(); @@ -115,7 +112,7 @@ class LocalPlayer : public Player /** * Sets a new destination for this being to walk to. */ - virtual void setDestination(Uint16 x, Uint16 y); + void setDestination(Uint16 x, Uint16 y); void raiseAttribute(Attribute attr); void raiseSkill(Uint16 skillId); @@ -132,7 +129,7 @@ class LocalPlayer : public Player Uint32 mJobLevel; Uint32 mXpForNextLevel, mJobXpForNextLevel; Uint16 mHp, mMaxHp, mMp, mMaxMp; - Uint32 mGp; + Uint32 mMoney; Uint32 mTotalWeight, mMaxWeight; @@ -150,7 +147,6 @@ class LocalPlayer : public Player std::auto_ptr<Inventory> mInventory; protected: - Network *mNetwork; Being *mTarget; FloorItem *mPickUpTarget; diff --git a/src/log.cpp b/src/log.cpp index 3d101d29..07eb55f7 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -31,6 +31,10 @@ #include <iostream> #include <sstream> +Logger::Logger(): + mLogToStandardOut(false) +{ +} Logger::~Logger() { @@ -85,6 +89,11 @@ void Logger::log(const char *log_text, ...) mLogFile << timeStr.str() << buf << std::endl; + if (mLogToStandardOut) + { + std::cout << timeStr.str() << buf << std::endl; + } + // Delete temporary buffer delete[] buf; } @@ -32,6 +32,11 @@ class Logger { public: /** + * Constructor. + */ + Logger(); + + /** * Destructor, closes log file. */ ~Logger(); @@ -42,6 +47,11 @@ class Logger void setLogFile(const std::string &logFilename); /** + * Sets whether the log should be written to standard output. + */ + void setLogToStandardOut(bool value) { mLogToStandardOut = value; } + + /** * Enters a message in the log. The message will be timestamped. */ void log(const char *log_text, ...); @@ -54,6 +64,7 @@ class Logger private: std::ofstream mLogFile; + bool mLogToStandardOut; }; extern Logger *logger; diff --git a/src/logindata.h b/src/logindata.h index f4fcd1b1..70b80bb7 100644 --- a/src/logindata.h +++ b/src/logindata.h @@ -29,12 +29,12 @@ struct LoginData std::string username; std::string password; std::string hostname; + std::string email; short port; int account_ID; int session_ID1; int session_ID2; - char sex; bool remember; }; diff --git a/src/main.cpp b/src/main.cpp index 13fc09f4..c1919bc0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,10 +55,10 @@ #endif #include "sound.h" -#include "gui/char_server.h" #include "gui/char_select.h" #include "gui/connection.h" #include "gui/gui.h" +#include "gui/serverdialog.h" #include "gui/login.h" #include "gui/ok_dialog.h" #include "gui/register.h" @@ -66,11 +66,16 @@ #include "gui/textfield.h" #include "net/charserverhandler.h" +#include "net/connection.h" #include "net/loginhandler.h" -#include "net/maploginhandler.h" -#include "net/messageout.h" #include "net/network.h" +#include "net/accountserver/accountserver.h" + +#include "net/chatserver/chatserver.h" + +#include "net/gameserver/gameserver.h" + #include "resources/image.h" #include "resources/resourcemanager.h" #include "resources/spriteset.h" @@ -79,18 +84,16 @@ #include "utils/tostring.h" // Account infos -char n_server, n_character; +char n_character; +std::string token; std::vector<Spriteset *> hairset; Spriteset *playerset[2]; Graphics *graphics; -// TODO Anyone knows a good location for this? Or a way to make it non-global? -class SERVER_INFO; -SERVER_INFO **server_info; - unsigned char state; std::string errorMessage; +std::string homeDir; unsigned char screen_mode; Sound sound; @@ -99,10 +102,16 @@ Music *bgm; Configuration config; /**< Xml file configuration reader */ Logger *logger; /**< Log object */ +Net::Connection *accountServerConnection = 0; +Net::Connection *gameServerConnection = 0; +Net::Connection *chatServerConnection = 0; + namespace { struct ErrorListener : public gcn::ActionListener { - void action(const std::string& eventId, gcn::Widget* widget) { state = LOGIN_STATE; } + void action(const std::string &eventId, gcn::Widget *widget) { + state = STATE_CHOOSE_SERVER; + } } errorListener; } @@ -118,37 +127,28 @@ struct Options Options(): printHelp(false), skipUpdate(false), - chooseDefault(false) + chooseDefault(false), + serverPort(0) {}; bool printHelp; bool skipUpdate; bool chooseDefault; - std::string username; - std::string password; std::string playername; + std::string password; std::string configPath; + + std::string serverName; + short serverPort; }; /** - * Do all initialization stuff + * Initializes the home directory. On UNIX and FreeBSD, ~/.tmw is used. On + * Windows and other systems we use the current working directory. */ -void init_engine(const Options &options) +void initHomeDir() { - // Initialize SDL - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { - std::cerr << "Could not initialize SDL: " << - SDL_GetError() << std::endl; - exit(1); - } - atexit(SDL_Quit); - - SDL_EnableUNICODE(1); - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - - std::string homeDir = ""; #if !(defined __USE_UNIX98 || defined __FreeBSD__) - // In Windows and other systems we currently store data next to executable. homeDir = "."; #else homeDir = std::string(PHYSFS_getUserDir()) + "/.tmw"; @@ -163,38 +163,16 @@ void init_engine(const Options &options) exit(1); } #endif +} - // Set log file - logger->setLogFile(homeDir + std::string("/tmw.log")); - - ResourceManager *resman = ResourceManager::getInstance(); - - if (!resman->setWriteDir(homeDir)) { - std::cout << homeDir - << " couldn't be set as home directory! Exitting." - << std::endl; - exit(1); - } - - // Add the user's homedir to PhysicsFS search path - resman->addToSearchPath(homeDir, false); - // Creating and checking the updates folder existence and rights. - if (!resman->isDirectory("/updates")) { - if (!resman->mkdir("/updates")) { - std::cout << homeDir << "/updates " - << "can't be made, but it doesn't exist! Exitting." - << std::endl; - exit(1); - } - } - - // Add the main data directory to our PhysicsFS search path - resman->addToSearchPath("data", true); - resman->addToSearchPath(TMW_DATADIR "data", true); - +/** + * Initialize configuration. + */ +void initConfiguration(const Options &options) +{ // Fill configuration with defaults config.setValue("host", "animesites.de"); - config.setValue("port", 6901); + config.setValue("port", 9601); config.setValue("hwaccel", 0); #if (defined __APPLE__ || defined WIN32) && defined USE_OPENGL config.setValue("opengl", 1); @@ -207,13 +185,13 @@ void init_engine(const Options &options) config.setValue("remember", 1); config.setValue("sfxVolume", 100); config.setValue("musicVolume", 60); - config.setValue("fpslimit", 60); - config.setValue("updatehost", "http://updates.themanaworld.org"); + config.setValue("fpslimit", 0); + config.setValue("updatehost", "http://themanaworld.org/files"); config.setValue("customcursor", 1); config.setValue("homeDir", homeDir); - // Checking if the configuration file exists... otherwise creates it with - // default options ! + // Checking if the configuration file exists... otherwise create it with + // default options. FILE *tmwFile = 0; std::string configPath = options.configPath; if (configPath == "") { @@ -228,15 +206,57 @@ void init_engine(const Options &options) } if (tmwFile == NULL) { std::cout << "Can't create " << configPath << ". " - "Using Defaults." << std::endl; + << "Using Defaults." << std::endl; } else { fclose(tmwFile); config.init(configPath); } +} + +/** + * Do all initialization stuff. + */ +void init_engine() +{ + // Initialize SDL + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { + std::cerr << "Could not initialize SDL: " << + SDL_GetError() << std::endl; + exit(1); + } + atexit(SDL_Quit); + + SDL_EnableUNICODE(1); + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); SDL_WM_SetCaption("The Mana World", NULL); SDL_WM_SetIcon(IMG_Load(TMW_DATADIR "data/icons/tmw-icon.png"), NULL); + ResourceManager *resman = ResourceManager::getInstance(); + + if (!resman->setWriteDir(homeDir)) { + std::cout << homeDir + << " couldn't be set as home directory! Exitting." + << std::endl; + exit(1); + } + + // Add the user's homedir to PhysicsFS search path + resman->addToSearchPath(homeDir, false); + // Creating and checking the updates folder existence and rights. + if (!resman->isDirectory("/updates")) { + if (!resman->mkdir("/updates")) { + std::cout << homeDir << "/updates " + << "can't be made, but it doesn't exist! Exitting." + << std::endl; + exit(1); + } + } + + // Add the main data directory to our PhysicsFS search path + resman->addToSearchPath("data", true); + resman->addToSearchPath(TMW_DATADIR "data", true); + #ifdef USE_OPENGL bool useOpenGL = (config.getValue("opengl", 0) == 1); @@ -250,8 +270,8 @@ void init_engine(const Options &options) graphics = new Graphics(); #endif - int width = (int)config.getValue("screenwidth", 800); - int height = (int)config.getValue("screenheight", 600); + int width = (int)config.getValue("screenwidth", defaultScreenWidth); + int height = (int)config.getValue("screenheight", defaultScreenHeight); int bpp = 0; bool fullscreen = ((int)config.getValue("screen", 0) == 1); bool hwaccel = ((int)config.getValue("hwaccel", 0) == 1); @@ -259,8 +279,9 @@ void init_engine(const Options &options) // Try to set the desired video mode if (!graphics->setVideoMode(width, height, bpp, fullscreen, hwaccel)) { - std::cerr << "Couldn't set " << width << "x" << height << "x" << - bpp << " video mode: " << SDL_GetError() << std::endl; + std::cerr << "Couldn't set " + << width << "x" << height << "x" << bpp << " video mode: " + << SDL_GetError() << std::endl; exit(1); } @@ -275,7 +296,7 @@ void init_engine(const Options &options) if (!playerset[1]) logger->error("Couldn't load female player spriteset!"); - for (int i=0; i < NR_HAIR_STYLES; i++) + for (int i = 0; i < NR_HAIR_STYLES - 1; i++) { Spriteset *tmp = ResourceManager::getInstance()->getSpriteset( "graphics/sprites/hairstyle" + toString(i + 1) + ".png", @@ -288,18 +309,19 @@ void init_engine(const Options &options) } gui = new Gui(graphics); - state = UPDATE_STATE; /**< Initial game state */ + state = STATE_CHOOSE_SERVER; /**< Initial game state */ // Initialize sound engine try { if (config.getValue("sound", 0) == 1) { sound.init(); } - sound.setSfxVolume((int)config.getValue("sfxVolume", 100)); - sound.setMusicVolume((int)config.getValue("musicVolume", 60)); + sound.setSfxVolume((int)config.getValue("sfxVolume", defaultSfxVolume)); + sound.setMusicVolume((int)config.getValue("musicVolume", + defaultMusicVolume)); } catch (const char *err) { - state = ERROR_STATE; + state = STATE_ERROR; errorMessage = err; logger->log("Warning: %s", err); } @@ -326,27 +348,27 @@ void exit_engine() sound.close(); ResourceManager::deleteInstance(); - delete logger; } void printHelp() { - std::cout - << "tmw" << std::endl << std::endl - << "Options: " << std::endl - << " -h --help : Display this help" << std::endl - << " -u --skipupdate : Skip the update process" << std::endl - << " -U --username : Login with this username" << std::endl - << " -P --password : Login with this password" << std::endl - << " -D --default : Bypass the login process with default settings" << std::endl - << " -p --playername : Login with this player" << std::endl - << " -C --configfile : Configuration file to use" - << std::endl; + std::cout << + "tmw\n\n" + "Options:\n" + " -h --help : Display this help\n" + " -u --skipupdate : Skip the update process\n" + " -U --username : Login with this username\n" + " -P --password : Login with this password\n" + " -D --default : Bypass the login process with default settings\n" + " -s --server : Login Server name or IP\n" + " -o --port : Login Server Port\n" + " -p --playername : Login with this player\n" + " -C --configfile : Configuration file to use\n"; } void parseOptions(int argc, char *argv[], Options &options) { - const char *optstring = "huU:P:Dp:C:"; + const char *optstring = "huU:P:Dp:s:o:C:"; const struct option long_options[] = { { "help", no_argument, 0, 'h' }, @@ -354,6 +376,8 @@ void parseOptions(int argc, char *argv[], Options &options) { "username", required_argument, 0, 'U' }, { "password", required_argument, 0, 'P' }, { "default", no_argument, 0, 'D' }, + { "server", required_argument, 0, 's' }, + { "port", required_argument, 0, 'o' }, { "playername", required_argument, 0, 'p' }, { "configfile", required_argument, 0, 'C' }, { 0 } @@ -375,7 +399,7 @@ void parseOptions(int argc, char *argv[], Options &options) options.skipUpdate = true; break; case 'U': - options.username = optarg; + options.playername = optarg; break; case 'P': options.password = optarg; @@ -383,6 +407,12 @@ void parseOptions(int argc, char *argv[], Options &options) case 'D': options.chooseDefault = true; break; + case 's': + options.serverName = optarg; + break; + case 'o': + options.serverPort = (short)atoi(optarg); + break; case 'p': options.playername = optarg; break; @@ -414,24 +444,20 @@ CharServerHandler charServerHandler; LoginData loginData; LoginHandler loginHandler; LockedArray<LocalPlayer*> charInfo(MAX_SLOT + 1); -MapLoginHandler mapLoginHandler; // TODO Find some nice place for these functions -void accountLogin(Network *network, LoginData *loginData) +void accountLogin(LoginData *loginData) { - logger->log("Trying to connect to account server..."); logger->log("Username is %s", loginData->username.c_str()); - network->connect(loginData->hostname, loginData->port); - network->registerHandler(&loginHandler); - loginHandler.setLoginData(loginData); + + Net::registerHandler(&loginHandler); + + charServerHandler.setCharInfo(&charInfo); + Net::registerHandler(&charServerHandler); // Send login infos - MessageOut outMsg(network); - outMsg.writeInt16(0x0064); - outMsg.writeInt32(0); // client version - outMsg.writeString(loginData->username, 24); - outMsg.writeString(loginData->password, 24); - outMsg.writeInt8(0); // unknown + Net::AccountServer::login(accountServerConnection, 0, + loginData->username, loginData->password); // Clear the password, avoids auto login when returning to login loginData->password = ""; @@ -445,51 +471,34 @@ void accountLogin(Network *network, LoginData *loginData) config.setValue("remember", loginData->remember); } -void charLogin(Network *network, LoginData *loginData) +void accountRegister(LoginData *loginData) { - logger->log("Trying to connect to char server..."); - network->connect(loginData->hostname, loginData->port); - network->registerHandler(&charServerHandler); + logger->log("Username is %s", loginData->username.c_str()); + + Net::registerHandler(&loginHandler); + charServerHandler.setCharInfo(&charInfo); - charServerHandler.setLoginData(loginData); + Net::registerHandler(&charServerHandler); - // Send login infos - MessageOut outMsg(network); - outMsg.writeInt16(0x0065); - outMsg.writeInt32(loginData->account_ID); - outMsg.writeInt32(loginData->session_ID1); - outMsg.writeInt32(loginData->session_ID2); - outMsg.writeInt16(0); // unknown - outMsg.writeInt8(loginData->sex); - - // We get 4 useless bytes before the real answer comes in - network->skip(4); + Net::AccountServer::registerAccount(accountServerConnection, 0, + loginData->username, loginData->password, loginData->email); } -void mapLogin(Network *network, LoginData *loginData) +void xmlNullLogger(void *ctx, const char *msg, ...) { - logger->log("Memorizing selected character %s", - player_node->getName().c_str()); - config.setValue("lastCharacter", player_node->getName()); - - MessageOut outMsg(network); - - logger->log("Trying to connect to map server..."); - logger->log("Map: %s", map_path.c_str()); + // Does nothing, that's the whole point of it +} - network->connect(loginData->hostname, loginData->port); - network->registerHandler(&mapLoginHandler); +// Initialize libxml2 and check for potential ABI mismatches between +// compiled version and the shared library actually used. +void initXML() +{ + logger->log("Initializing libxml2..."); + xmlInitParser(); + LIBXML_TEST_VERSION; - // Send login infos - outMsg.writeInt16(0x0072); - outMsg.writeInt32(loginData->account_ID); - outMsg.writeInt32(player_node->mCharId); - outMsg.writeInt32(loginData->session_ID1); - outMsg.writeInt32(loginData->session_ID2); - outMsg.writeInt8(loginData->sex); - - // We get 4 useless bytes before the real answer comes in - network->skip(4); + // Suppress libxml2 error messages + xmlSetGenericErrorFunc(NULL, xmlNullLogger); } /** Main */ @@ -498,42 +507,35 @@ int main(int argc, char *argv[]) #ifdef PACKAGE_VERSION std::cout << "The Mana World v" << PACKAGE_VERSION << std::endl; #endif - logger = new Logger(); + // Parse command line options Options options; - parseOptions(argc, argv, options); - if (options.printHelp) { printHelp(); return 0; } - // Initialize libxml2 and check for potential ABI mismatches between - // compiled version and the shared library actually used. - xmlInitParser(); - LIBXML_TEST_VERSION; - - // Redirect libxml errors to /dev/null - FILE *nullFile = fopen("/dev/null", "w"); - xmlSetGenericErrorFunc(nullFile, NULL); - // Initialize PhysicsFS PHYSFS_init(argv[0]); - init_engine(options); + initHomeDir(); + // Configure logger + logger = new Logger(); + logger->setLogFile(homeDir + std::string("/tmw.log")); + logger->setLogToStandardOut(config.getValue("logToStandardOut", 0)); - SDL_Event event; + initXML(); + initConfiguration(options); - if (options.skipUpdate && state != ERROR_STATE) { - state = LOGIN_STATE; - } - else { - state = UPDATE_STATE; - } - unsigned int oldstate = !state; // We start with a status change. + // Log the tmw version +#ifdef PACKAGE_VERSION + logger->log("The Mana World v%s", PACKAGE_VERSION); +#endif + + init_engine(); Window *currentDialog = NULL; Image *login_wallpaper = NULL; @@ -541,7 +543,22 @@ int main(int argc, char *argv[]) sound.playMusic(TMW_DATADIR "data/music/Magick - Real.ogg"); - loginData.username = options.username; + // Server choice + if (options.serverName.empty()) { + loginData.hostname = config.getValue("MostUsedServerName0", + defaultAccountServerName.c_str()); + } + else { + loginData.hostname = options.serverName; + } + if (options.serverPort == 0) { + loginData.port = (short)config.getValue("MostUsedServerPort0", + defaultAccountServerPort); + } else { + loginData.port = options.serverPort; + } + + loginData.username = options.playername; if (loginData.username.empty()) { if (config.getValue("remember", 0)) { loginData.username = config.getValue("username", ""); @@ -550,24 +567,29 @@ int main(int argc, char *argv[]) if (!options.password.empty()) { loginData.password = options.password; } - loginData.hostname = config.getValue("host", "animesites.de"); - loginData.port = (short)config.getValue("port", 0); + loginData.remember = config.getValue("remember", 0); - SDLNet_Init(); - Network *network = new Network(); - while (state != EXIT_STATE) + Net::initialize(); + accountServerConnection = Net::getConnection(); + gameServerConnection = Net::getConnection(); + chatServerConnection = Net::getConnection(); + + unsigned int oldstate = !state; // We start with a status change. + + SDL_Event event; + while (state != STATE_EXIT) { // Handle SDL events while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: - state = EXIT_STATE; + state = STATE_EXIT; break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) - state = EXIT_STATE; + state = STATE_EXIT; break; } @@ -575,13 +597,15 @@ int main(int argc, char *argv[]) } gui->logic(); - network->flush(); - network->dispatchMessages(); + Net::flush(); - if (network->getState() == Network::ERROR) + if (state > STATE_CONNECT_ACCOUNT && state < STATE_GAME) { - state = ERROR_STATE; - errorMessage = "Got disconnected from server!"; + if (!accountServerConnection->isConnected()) + { + state = STATE_ERROR; + errorMessage = "Got disconnected from account server!"; + } } if (!login_wallpaper) @@ -602,65 +626,103 @@ int main(int argc, char *argv[]) gui->draw(); graphics->updateScreen(); + // TODO: Add connect timeout to go back to choose server + if (state == STATE_CONNECT_ACCOUNT && + accountServerConnection->isConnected()) + { + if (options.skipUpdate) { + state = STATE_LOGIN; + } else { + state = STATE_UPDATE; + } + } + else if (state == STATE_CONNECT_GAME && + gameServerConnection->isConnected() && + chatServerConnection->isConnected()) + { + accountServerConnection->disconnect(); + Net::clearHandlers(); + state = STATE_GAME; + } + if (state != oldstate) { - switch (oldstate) + // Load updates after exiting the update state + if (oldstate == STATE_UPDATE) { - case UPDATE_STATE: - loadUpdates(); - // Reload the wallpaper in case that it was updated - login_wallpaper->decRef(); - login_wallpaper = ResourceManager::getInstance()-> - getImage("graphics/images/login_wallpaper.png"); - break; - - // Those states don't cause a network disconnect - case ACCOUNT_STATE: - case CHAR_CONNECT_STATE: - case CONNECTING_STATE: - break; - - default: - network->disconnect(); - network->clearHandlers(); - break; + loadUpdates(); + // Reload the wallpaper in case that it was updated + login_wallpaper->decRef(); + login_wallpaper = ResourceManager::getInstance()-> + getImage("graphics/images/login_wallpaper.png"); } oldstate = state; - if (currentDialog && state != ACCOUNT_STATE && - state != CHAR_CONNECT_STATE) { + // Get rid of the dialog of the previous state + if (currentDialog) { delete currentDialog; currentDialog = NULL; } switch (state) { - case LOGIN_STATE: - logger->log("State: LOGIN"); - if (!loginData.password.empty()) { - state = ACCOUNT_STATE; + case STATE_CHOOSE_SERVER: + logger->log("State: CHOOSE_SERVER"); + + // Allow changing this using a server choice dialog + // We show the dialog box only if the command-line options + // weren't set. + if (options.serverName.empty() && options.serverPort == 0) { + currentDialog = new ServerDialog(&loginData); } else { - currentDialog = new LoginDialog(&loginData); + state = STATE_CONNECT_ACCOUNT; + + // Reset options so that cancelling or connect timeout + // will show the server dialog + options.serverName = ""; + options.serverPort = 0; } break; - case REGISTER_STATE: + case STATE_CONNECT_ACCOUNT: + logger->log("State: CONNECT_ACCOUNT"); + logger->log("Trying to connect to account server..."); + accountServerConnection->connect(loginData.hostname, + loginData.port); + currentDialog = new ConnectionDialog(STATE_CHOOSE_SERVER); + break; + + case STATE_UPDATE: + logger->log("State: UPDATE"); + // TODO: Revive later + //currentDialog = new UpdaterWindow(); + state = STATE_LOGIN; + break; + + case STATE_LOGIN: + logger->log("State: LOGIN"); + currentDialog = new LoginDialog(&loginData); + // TODO: Restore autologin + //if (!loginData.password.empty()) { + // accountLogin(&loginData); + //} + break; + + case STATE_LOGIN_ATTEMPT: + accountLogin(&loginData); + break; + + case STATE_REGISTER: logger->log("State: REGISTER"); currentDialog = new RegisterDialog(&loginData); break; - case CHAR_SERVER_STATE: - logger->log("State: CHAR_SERVER"); - currentDialog = new ServerSelectDialog(&loginData); - if (options.chooseDefault || options.playername != "") { - ((ServerSelectDialog*)currentDialog)->action("ok", - NULL); - } + case STATE_REGISTER_ATTEMPT: + accountRegister(&loginData); break; - case CHAR_SELECT_STATE: + case STATE_CHAR_SELECT: logger->log("State: CHAR_SELECT"); - currentDialog = new CharSelectDialog(network, &charInfo, - 1 - loginData.sex); + currentDialog = new CharSelectDialog(&charInfo); if (((CharSelectDialog*)currentDialog)-> selectByName(options.playername)) @@ -673,66 +735,56 @@ int main(int argc, char *argv[]) ((CharSelectDialog*)currentDialog)->action("ok", NULL); break; - case GAME_STATE: - sound.fadeOutMusic(1000); - - currentDialog = NULL; - login_wallpaper->decRef(); - login_wallpaper = NULL; - - logger->log("State: GAME"); - game = new Game(network); - game->logic(); - delete game; - state = EXIT_STATE; - break; - - case UPDATE_STATE: - logger->log("State: UPDATE"); - currentDialog = new UpdaterWindow(); - break; - - case ERROR_STATE: + case STATE_ERROR: logger->log("State: ERROR"); currentDialog = new OkDialog("Error", errorMessage); currentDialog->addActionListener(&errorListener); currentDialog = NULL; // OkDialog deletes itself - network->disconnect(); - network->clearHandlers(); + gameServerConnection->disconnect(); + chatServerConnection->disconnect(); + Net::clearHandlers(); break; - case CONNECTING_STATE: - logger->log("State: CONNECTING"); - mapLogin(network, &loginData); - currentDialog = new ConnectionDialog(); + case STATE_CONNECT_GAME: + logger->log("State: CONNECT_GAME"); + currentDialog = new ConnectionDialog(STATE_CHAR_SELECT); break; - case CHAR_CONNECT_STATE: - printf("Char: %i\n", loginData.sex); - charLogin(network, &loginData); - break; + case STATE_GAME: + logger->log("Memorizing selected character %s", + player_node->getName().c_str()); + config.setValue("lastCharacter", player_node->getName()); - case ACCOUNT_STATE: - printf("Account: %i\n", loginData.sex); - accountLogin(network, &loginData); + Net::GameServer::connect(gameServerConnection, token); + Net::ChatServer::connect(chatServerConnection, token); + sound.fadeOutMusic(1000); + + currentDialog = NULL; + login_wallpaper->decRef(); + login_wallpaper = NULL; + + logger->log("State: GAME"); + game = new Game; + game->logic(); + delete game; + state = STATE_EXIT; break; default: - state = EXIT_STATE; + state = STATE_EXIT; break; } } } - delete network; - SDLNet_Quit(); + delete accountServerConnection; + delete gameServerConnection; + delete chatServerConnection; + Net::finalize(); - if (nullFile) - { - fclose(nullFile); - } logger->log("State: EXIT"); exit_engine(); PHYSFS_deinit(); + delete logger; return 0; } @@ -37,21 +37,22 @@ #define TMW_DATADIR "" #endif - +/* + * Client different States + */ enum { - EXIT_STATE, - LOGIN_STATE, - ACCOUNT_STATE, - REGISTER_STATE, - CHAR_CONNECT_STATE, - CHAR_SERVER_STATE, - CHAR_SELECT_STATE, - CHAR_NEW_STATE, - CHAR_DEL_STATE, - GAME_STATE, - ERROR_STATE, - UPDATE_STATE, - CONNECTING_STATE + STATE_CHOOSE_SERVER, + STATE_CONNECT_ACCOUNT, + STATE_UPDATE, + STATE_LOGIN, + STATE_LOGIN_ATTEMPT, + STATE_REGISTER, + STATE_REGISTER_ATTEMPT, + STATE_CHAR_SELECT, + STATE_ERROR, + STATE_CONNECT_GAME, + STATE_GAME, + STATE_EXIT }; /* length definitions for several char[]s in order @@ -65,7 +66,20 @@ enum { LEN_MIN_PASSWORD = 4 }; -extern char n_server, n_character; +// Default game values +// ------------------- +// Screen +const short defaultScreenWidth = 800; +const short defaultScreenHeight = 600; +// Sound +const short defaultSfxVolume = 100; +const short defaultMusicVolume = 60; +// Account Server Name and port +const std::string defaultAccountServerName = "animesites.de"; +const short defaultAccountServerPort = 9601; + +extern char n_character; +extern std::string token; extern unsigned char state; extern std::string errorMessage; diff --git a/src/map.cpp b/src/map.cpp index 05dea951..1cdc1077 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -287,14 +287,16 @@ Map::getWalk(int x, int y) return false; } + /* // Check for collision with a being Beings &beings = beingManager->getAll(); for (BeingIterator i = beings.begin(); i != beings.end(); i++) { // job 45 is a portal, they don't collide - if ((*i)->mX == x && (*i)->mY == y && (*i)->mJob != 45) { + if ((*i)->mX / 32 == x && (*i)->mY / 32 == y && (*i)->mJob != 45) { return false; } } + */ return true; } @@ -342,6 +344,8 @@ Map::removeSprite(SpriteIterator iterator) mSprites.erase(iterator); } +static int const basicCost = 100; + Path Map::findPath(int startX, int startY, int destX, int destY) { @@ -419,13 +423,27 @@ Map::findPath(int startX, int startY, int destX, int destY) } } - // Calculate G cost for this route, 10 for moving straight and - // 14 for moving diagonal - int Gcost = curr.tile->Gcost + ((dx == 0 || dy == 0) ? 10 : 14); + // Calculate G cost for this route, ~sqrt(2) for moving diagonal + int Gcost = curr.tile->Gcost + + (dx == 0 || dy == 0 ? basicCost : basicCost * 362 / 256); + + /* Demote an arbitrary direction to speed pathfinding by + adding a defect (TODO: change depending on the desired + visual effect, e.g. a cross-product defect toward + destination). + Important: as long as the total defect along any path is + less than the basicCost, the pathfinder will still find one + of the shortest paths! */ + if (dx == 0 || dy == 0) + { + // Demote horizontal and vertical directions, so that two + // consecutive directions cannot have the same Fcost. + ++Gcost; + } // Skip if Gcost becomes too much // Warning: probably not entirely accurate - if (Gcost > 200) + if (Gcost > 20 * basicCost) { continue; } @@ -433,8 +451,14 @@ Map::findPath(int startX, int startY, int destX, int destY) if (newTile->whichList != mOnOpenList) { // Found a new tile (not on open nor on closed list) - // Update Hcost of the new tile using Manhatten distance - newTile->Hcost = 10 * (abs(x - destX) + abs(y - destY)); + + /* Update Hcost of the new tile. The pathfinder does not + work reliably if the heuristic cost is higher than the + real cost. In particular, using Manhattan distance is + forbidden here. */ + int dx = std::abs(x - destX), dy = std::abs(y - destY); + newTile->Hcost = std::abs(dx - dy) * basicCost + + std::min(dx, dy) * (basicCost * 362 / 256); // Set the current tile as the parent of the new tile newTile->parentX = curr.x; diff --git a/src/monster.cpp b/src/monster.cpp index 8a7e2f32..a4317e5e 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -29,28 +29,12 @@ #include "utils/tostring.h" -Monster::Monster(Uint32 id, Uint16 job, Map *map): +Monster::Monster(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/monster" + toString(job - 1002) + ".xml", 0); } -void -Monster::logic() -{ - if (mAction != STAND) - { - mFrame = (get_elapsed_time(mWalkTime) * 4) / mWalkSpeed; - - if (mFrame >= 4 && mAction != MONSTER_DEAD) - { - nextStep(); - } - } - - Being::logic(); -} - Being::Type Monster::getType() const { diff --git a/src/monster.h b/src/monster.h index 4a82a461..0314a035 100644 --- a/src/monster.h +++ b/src/monster.h @@ -29,9 +29,7 @@ class Monster : public Being { public: - Monster(Uint32 id, Uint16 job, Map *map); - - virtual void logic(); + Monster(Uint16 id, Uint16 job, Map *map); virtual Type getType() const; }; diff --git a/src/net/accountserver/account.cpp b/src/net/accountserver/account.cpp new file mode 100644 index 00000000..385cd77a --- /dev/null +++ b/src/net/accountserver/account.cpp @@ -0,0 +1,116 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "account.h" + +#include "internal.h" + +#include "../connection.h" +#include "../messageout.h" +#include "../protocol.h" + +void Net::AccountServer::Account::createCharacter( + const std::string &name, char hairColor, char hairStyle, char gender, + short strength, short agility, short vitality, + short intelligence, short dexterity, short luck) +{ + MessageOut msg(PAMSG_CHAR_CREATE); + + msg.writeString(name); + msg.writeByte(hairStyle); + msg.writeByte(hairColor); + msg.writeByte(gender); + msg.writeShort(strength); + msg.writeShort(agility); + msg.writeShort(vitality); + msg.writeShort(intelligence); + msg.writeShort(dexterity); + msg.writeShort(luck); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::deleteCharacter(char slot) +{ + MessageOut msg(PAMSG_CHAR_DELETE); + + msg.writeByte(slot); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::selectCharacter(char slot) +{ + MessageOut msg(PAMSG_CHAR_SELECT); + + msg.writeByte(slot); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::unregister() +{ + MessageOut msg(PAMSG_UNREGISTER); + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::changeEmail(const std::string &email) +{ + MessageOut msg(PAMSG_EMAIL_CHANGE); + + msg.writeString(email); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::getEmail() +{ + MessageOut msg(PAMSG_EMAIL_GET); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::changePassword( + const std::string &oldPassword, const std::string &newPassword) +{ + MessageOut msg(PAMSG_PASSWORD_CHANGE); + + msg.writeString(oldPassword); + msg.writeString(newPassword); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::enterWorld() +{ + MessageOut msg(PAMSG_ENTER_WORLD); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::enterChat() +{ + MessageOut msg(PAMSG_ENTER_CHAT); + + Net::AccountServer::connection->send(msg); +} diff --git a/src/net/accountserver/account.h b/src/net/accountserver/account.h new file mode 100644 index 00000000..8e46eaa5 --- /dev/null +++ b/src/net/accountserver/account.h @@ -0,0 +1,60 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_NET_ACCOUNTSERVER_CHARACTER_H +#define _TMW_NET_ACCOUNTSERVER_CHARACTER_H + +#include <iosfwd> + +namespace Net +{ + namespace AccountServer + { + namespace Account + { + void createCharacter(const std::string &name, + char hairColor, char hairStyle, char gender, + short strength, short agility, short vitality, + short intelligence, short dexterity, short luck); + + void deleteCharacter(char slot); + + void selectCharacter(char slot); + + void unregister(); + + void changeEmail(const std::string &email); + + void getEmail(); + + void changePassword(const std::string &oldPassowrd, + const std::string &newPassword); + + void enterWorld(); + + void enterChat(); + } + } +} + +#endif diff --git a/src/net/accountserver/accountserver.cpp b/src/net/accountserver/accountserver.cpp new file mode 100644 index 00000000..8fde6d5e --- /dev/null +++ b/src/net/accountserver/accountserver.cpp @@ -0,0 +1,68 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "accountserver.h" + +#include "internal.h" + +#include "../connection.h" +#include "../messageout.h" +#include "../protocol.h" + +void Net::AccountServer::login(Net::Connection *connection, int version, + const std::string &username, const std::string &password) +{ + Net::AccountServer::connection = connection; + + MessageOut msg(PAMSG_LOGIN); + + msg.writeLong(version); + msg.writeString(username); + msg.writeString(password); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::registerAccount(Net::Connection *connection, + int version, const std::string &username, const std::string &password, + const std::string &email) +{ + Net::AccountServer::connection = connection; + + MessageOut msg(PAMSG_REGISTER); + + msg.writeLong(version); // client version + msg.writeString(username); + msg.writeString(password); + msg.writeString(email); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::logout() +{ + MessageOut msg(PAMSG_LOGOUT); + Net::AccountServer::connection->send(msg); + + Net::AccountServer::connection = 0; +} diff --git a/src/net/accountserver/accountserver.h b/src/net/accountserver/accountserver.h new file mode 100644 index 00000000..c05b5317 --- /dev/null +++ b/src/net/accountserver/accountserver.h @@ -0,0 +1,46 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_NET_ACCOUNTSERVER_ACCOUNTSERVER_H +#define _TMW_NET_ACCOUNTSERVER_ACCOUNTSERVER_H + +#include <iosfwd> + +namespace Net +{ + class Connection; + + namespace AccountServer + { + void login(Net::Connection *connection, int version, + const std::string &username, const std::string &password); + + void registerAccount(Net::Connection *connection, int version, + const std::string &username, const std::string &password, + const std::string &email); + + void logout(); + } +} + +#endif diff --git a/src/net/accountserver/internal.cpp b/src/net/accountserver/internal.cpp new file mode 100644 index 00000000..28a9695e --- /dev/null +++ b/src/net/accountserver/internal.cpp @@ -0,0 +1,34 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "internal.h" + +namespace Net +{ + class Connection; + + namespace AccountServer + { + Connection *connection = 0; + } +} diff --git a/src/net/maploginhandler.h b/src/net/accountserver/internal.h index fe597549..8af5ec04 100644 --- a/src/net/maploginhandler.h +++ b/src/net/accountserver/internal.h @@ -21,17 +21,17 @@ * $Id$ */ -#ifndef _TMW_NET_MAPLOGINHANDLER_H -#define _TMW_NET_MAPLOGINHANDLER_H +#ifndef _TMW_NET_ACCOUNTSERVER_INTERNAL_H +#define _TMW_NET_ACCOUNTSERVER_INTERNAL_H -#include "messagehandler.h" - -class MapLoginHandler : public MessageHandler +namespace Net { - public: - MapLoginHandler(); + class Connection; - void handleMessage(MessageIn *msg); -}; + namespace AccountServer + { + extern Connection *connection; + } +} #endif diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index cd5653fc..2d68dd28 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -41,42 +41,60 @@ const int EMOTION_TIME = 150; /**< Duration of emotion icon */ BeingHandler::BeingHandler() { static const Uint16 _messages[] = { - SMSG_BEING_VISIBLE, - SMSG_BEING_MOVE, - SMSG_BEING_REMOVE, - SMSG_BEING_ACTION, - SMSG_BEING_LEVELUP, - SMSG_BEING_EMOTION, - SMSG_BEING_CHANGE_LOOKS, - SMSG_BEING_NAME_RESPONSE, - SMSG_PLAYER_UPDATE_1, - SMSG_PLAYER_UPDATE_2, - SMSG_PLAYER_MOVE, - 0x0119, + //SMSG_BEING_VISIBLE, + //SMSG_BEING_MOVE, + //SMSG_BEING_REMOVE, + //SMSG_BEING_ACTION, + //SMSG_BEING_LEVELUP, + //SMSG_BEING_EMOTION, + //SMSG_BEING_CHANGE_LOOKS, + //SMSG_BEING_NAME_RESPONSE, + //SMSG_PLAYER_UPDATE_1, + //SMSG_PLAYER_UPDATE_2, + //SMSG_PLAYER_MOVE, + //0x0119, + GPMSG_BEING_ENTER, + GPMSG_BEING_LEAVE, + GPMSG_BEINGS_MOVE, 0 }; handledMessages = _messages; } -void BeingHandler::handleMessage(MessageIn *msg) +void BeingHandler::handleMessage(MessageIn &msg) { + /* Uint32 id; Uint16 job, speed; Sint16 param1; Sint8 type; Being *srcBeing, *dstBeing; + */ - switch (msg->getId()) + switch (msg.getId()) { + case GPMSG_BEING_ENTER: + handleBeingEnterMessage(msg); + break; + + case GPMSG_BEING_LEAVE: + handleBeingLeaveMessage(msg); + break; + + case GPMSG_BEINGS_MOVE: + handleBeingsMoveMessage(msg); + break; + + /* case SMSG_BEING_VISIBLE: case SMSG_BEING_MOVE: // Information about a being in range - id = msg->readInt32(); - speed = msg->readInt16(); - msg->readInt16(); // unknown - msg->readInt16(); // unknown - msg->readInt16(); // option - job = msg->readInt16(); // class + id = msg.readLong(); + speed = msg.readShort(); + msg.readShort(); // unknown + msg.readShort(); // unknown + msg.readShort(); // option + job = msg.readShort(); // class dstBeing = beingManager->findBeing(id); @@ -91,7 +109,7 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing = beingManager->createBeing(id, job); } - else if (msg->getId() == 0x0078) + else if (msg.getId() == 0x0078) { dstBeing->clearPath(); dstBeing->mFrame = 0; @@ -104,57 +122,56 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - dstBeing->setHairStyle(msg->readInt16()); - dstBeing->setWeapon(msg->readInt16()); - dstBeing->setVisibleEquipment(3, msg->readInt16()); // head bottom + dstBeing->setHairStyle(msg.readShort()); + dstBeing->setWeapon(msg.readShort()); + dstBeing->setVisibleEquipment(3, msg.readShort()); // head bottom - if (msg->getId() == SMSG_BEING_MOVE) + if (msg.getId() == SMSG_BEING_MOVE) { - msg->readInt32(); // server tick + msg.readLong(); // server tick } - msg->readInt16(); // shield - dstBeing->setVisibleEquipment(4, msg->readInt16()); // head top - dstBeing->setVisibleEquipment(5, msg->readInt16()); // head mid - dstBeing->setHairColor(msg->readInt16()); - msg->readInt16(); // unknown - msg->readInt16(); // head dir - msg->readInt16(); // guild - msg->readInt16(); // unknown - msg->readInt16(); // unknown - msg->readInt16(); // manner - msg->readInt16(); // karma - msg->readInt8(); // unknown - dstBeing->setSex(1 - msg->readInt8()); // sex - - if (msg->getId() == SMSG_BEING_MOVE) + msg.readShort(); // shield + dstBeing->setVisibleEquipment(4, msg.readShort()); // head top + dstBeing->setVisibleEquipment(5, msg.readShort()); // head mid + dstBeing->setHairColor(msg.readShort()); + msg.readShort(); // unknown + msg.readShort(); // head dir + msg.readShort(); // guild + msg.readShort(); // unknown + msg.readShort(); // unknown + msg.readShort(); // manner + msg.readShort(); // karma + msg.readByte(); // unknown + dstBeing->setSex(1 - msg.readByte()); // sex + + if (msg.getId() == SMSG_BEING_MOVE) { - Uint16 srcX, srcY, dstX, dstY; - msg->readCoordinatePair(srcX, srcY, dstX, dstY); - dstBeing->setAction(Being::STAND); - dstBeing->mX = srcX; - dstBeing->mY = srcY; - dstBeing->setDestination(dstX, dstY); + //Uint16 srcX, srcY, dstX, dstY; + //msg.readCoordinatePair(srcX, srcY, dstX, dstY); + //dstBeing->setAction(Being::STAND); + //dstBeing->mX = srcX; + //dstBeing->mY = srcY; + //dstBeing->setDestination(dstX, dstY); } else { - msg->readCoordinates(dstBeing->mX, dstBeing->mY, - dstBeing->mDirection); + //msg.readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection); } - msg->readInt8(); // unknown - msg->readInt8(); // unknown - msg->readInt8(); // unknown / sit + msg.readByte(); // unknown + msg.readByte(); // unknown + msg.readByte(); // unknown / sit break; case SMSG_BEING_REMOVE: // A being should be removed or has died - dstBeing = beingManager->findBeing(msg->readInt32()); + dstBeing = beingManager->findBeing(msg.readLong()); if (!dstBeing) break; - if (msg->readInt8() == 1) + if (msg.readByte() == 1) { // Death switch (dstBeing->getType()) @@ -182,15 +199,15 @@ void BeingHandler::handleMessage(MessageIn *msg) break; case SMSG_BEING_ACTION: - srcBeing = beingManager->findBeing(msg->readInt32()); - dstBeing = beingManager->findBeing(msg->readInt32()); - msg->readInt32(); // server tick - msg->readInt32(); // src speed - msg->readInt32(); // dst speed - param1 = msg->readInt16(); - msg->readInt16(); // param 2 - type = msg->readInt8(); - msg->readInt16(); // param 3 + srcBeing = beingManager->findBeing(msg.readLong()); + dstBeing = beingManager->findBeing(msg.readLong()); + msg.readLong(); // server tick + msg.readLong(); // src speed + msg.readLong(); // dst speed + param1 = msg.readShort(); + msg.readShort(); // param 2 + type = msg.readByte(); + msg.readShort(); // param 3 switch (type) { @@ -231,63 +248,63 @@ void BeingHandler::handleMessage(MessageIn *msg) break; case SMSG_BEING_LEVELUP: - if ((Uint32)msg->readInt32() == player_node->getId()) { + if ((Uint32) msg.readLong() == player_node->getId()) { logger->log("Level up"); sound.playSfx("sfx/levelup.ogg"); } else { logger->log("Someone else went level up"); } - msg->readInt32(); // type + msg.readLong(); // type break; case SMSG_BEING_EMOTION: - if (!(dstBeing = beingManager->findBeing(msg->readInt32()))) + if (!(dstBeing = beingManager->findBeing(msg.readLong()))) { break; } - dstBeing->mEmotion = msg->readInt8(); + dstBeing->mEmotion = msg.readByte(); dstBeing->mEmotionTime = EMOTION_TIME; break; case SMSG_BEING_CHANGE_LOOKS: { - if (!(dstBeing = beingManager->findBeing(msg->readInt32()))) + if (!(dstBeing = beingManager->findBeing(msg.readLong()))) { break; } - - int type = msg->readInt8(); + + int type = msg.readByte(); switch (type) { case 1: - dstBeing->setHairStyle(msg->readInt8()); + dstBeing->setHairStyle(msg.readByte()); break; case 2: - dstBeing->setWeapon(msg->readInt8()); + dstBeing->setWeapon(msg.readByte()); break; case 3: case 4: case 5: // Equip/unequip head 3. Bottom 4. Top 5. Middle - dstBeing->setVisibleEquipment(type, msg->readInt8()); + dstBeing->setVisibleEquipment(type, msg.readByte()); // First 3 slots of mVisibleEquipments are reserved for // later use, probably accessories. break; case 6: - dstBeing->setHairColor(msg->readInt8()); + dstBeing->setHairColor(msg.readByte()); break; default: - printf("c3: %i\n", msg->readInt8()); // unsupported + printf("c3: %i\n", msg.readByte()); // unsupported break; } } break; case SMSG_BEING_NAME_RESPONSE: - if ((dstBeing = beingManager->findBeing(msg->readInt32()))) + if ((dstBeing = beingManager->findBeing(msg.readLong()))) { - dstBeing->setName(msg->readString(24)); + dstBeing->setName(msg.readString(24)); } break; @@ -295,12 +312,12 @@ void BeingHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_UPDATE_2: case SMSG_PLAYER_MOVE: // An update about a player, potentially including movement. - id = msg->readInt32(); - speed = msg->readInt16(); - msg->readInt16(); // option 1 - msg->readInt16(); // option 2 - msg->readInt16(); // option - job = msg->readInt16(); + id = msg.readLong(); + speed = msg.readShort(); + msg.readShort(); // option 1 + msg.readShort(); // option 2 + msg.readShort(); // option + job = msg.readShort(); dstBeing = beingManager->findBeing(id); @@ -311,58 +328,57 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - dstBeing->setHairStyle(msg->readInt16()); - dstBeing->setWeaponById(msg->readInt16()); // item id 1 - msg->readInt16(); // item id 2 - dstBeing->setVisibleEquipment(3, msg->readInt16()); // head bottom + dstBeing->setHairStyle(msg.readShort()); + dstBeing->setWeaponById(msg.readShort()); // item id 1 + msg.readShort(); // item id 2 + dstBeing->setVisibleEquipment(3, msg.readShort()); // head bottom - if (msg->getId() == SMSG_PLAYER_MOVE) + if (msg.getId() == SMSG_PLAYER_MOVE) { - msg->readInt32(); // server tick + msg.readLong(); // server tick } - dstBeing->setVisibleEquipment(4, msg->readInt16()); // head top - dstBeing->setVisibleEquipment(5, msg->readInt16()); // head mid - dstBeing->setHairColor(msg->readInt16()); - msg->readInt16(); // unknown - msg->readInt16(); // head dir - msg->readInt32(); // guild - msg->readInt32(); // emblem - msg->readInt16(); // manner - msg->readInt8(); // karma - dstBeing->setSex(1 - msg->readInt8()); // sex - - if (msg->getId() == SMSG_PLAYER_MOVE) + dstBeing->setVisibleEquipment(4, msg.readShort()); // head top + dstBeing->setVisibleEquipment(5, msg.readShort()); // head mid + dstBeing->setHairColor(msg.readShort()); + msg.readShort(); // unknown + msg.readShort(); // head dir + msg.readLong(); // guild + msg.readLong(); // emblem + msg.readShort(); // manner + msg.readByte(); // karma + dstBeing->setSex(1 - msg.readByte()); // sex + + if (msg.getId() == SMSG_PLAYER_MOVE) { - Uint16 srcX, srcY, dstX, dstY; - msg->readCoordinatePair(srcX, srcY, dstX, dstY); - dstBeing->mX = srcX; - dstBeing->mY = srcY; - dstBeing->setDestination(dstX, dstY); + //Uint16 srcX, srcY, dstX, dstY; + //msg.readCoordinatePair(srcX, srcY, dstX, dstY); + //dstBeing->mX = srcX; + //dstBeing->mY = srcY; + //dstBeing->setDestination(dstX, dstY); } else { - msg->readCoordinates(dstBeing->mX, dstBeing->mY, - dstBeing->mDirection); + //msg.readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection); } - msg->readInt8(); // unknown - msg->readInt8(); // unknown + msg.readByte(); // unknown + msg.readByte(); // unknown - if (msg->getId() == SMSG_PLAYER_UPDATE_1) + if (msg.getId() == SMSG_PLAYER_UPDATE_1) { - if (msg->readInt8() == 2) + if (msg.readByte() == 2) { dstBeing->setAction(Being::SIT); } } - else if (msg->getId() == SMSG_PLAYER_MOVE) + else if (msg.getId() == SMSG_PLAYER_MOVE) { - msg->readInt8(); // unknown + msg.readByte(); // unknown } - msg->readInt8(); // Lv - msg->readInt8(); // unknown + msg.readByte(); // Lv + msg.readByte(); // unknown dstBeing->mWalkTime = tick_time; dstBeing->mFrame = 0; @@ -370,9 +386,107 @@ void BeingHandler::handleMessage(MessageIn *msg) case 0x0119: // Change in players look - printf("0x0119 %i %i %i %x %i\n", msg->readInt32(), - msg->readInt16(), msg->readInt16(), msg->readInt16(), - msg->readInt8()); + printf("0x0119 %li %i %i %x %i\n", msg.readLong(), + msg.readShort(), msg.readShort(), msg.readShort(), + msg.readByte()); break; + */ + } +} + +void +BeingHandler::handleBeingEnterMessage(MessageIn &msg) +{ + int type = msg.readByte(); // type + int id = msg.readShort(); + + switch (type) { + case OBJECT_PLAYER: + { + std::string name = msg.readString(); + Being *being; + if (player_node->getName() == name) + { + being = player_node; + being->setId(id); + } + else + { + being = beingManager->createBeing(id, 0); + being->setName(name); + } + being->setHairStyle(msg.readByte()); + being->setHairColor(msg.readByte()); + being->setSex(msg.readByte()); + } break; + case OBJECT_MONSTER: + { + int monsterId = msg.readShort(); + Being *being; + being = beingManager->createBeing(id, 1002 + monsterId); + being->setWalkSpeed(150); // TODO + } break; + } +} + +void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) +{ + Being *being = beingManager->findBeing(msg.readShort()); + if (!being) return; + if (being == player_node->getTarget()) + { + player_node->stopAttack(); + } + beingManager->destroyBeing(being); +} + +void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) +{ + while (msg.getUnreadLength()) + { + Uint16 id = msg.readShort(); + Uint8 flags = msg.readByte(); + Being *being = beingManager->findBeing(id); + int sx = 0, sy = 0, dx = 0, dy = 0; + if (flags & MOVING_POSITION) + { + Uint16 sx2, sy2; + msg.readCoordinates(sx2, sy2); + sx = sx2 * 32 + 16; + sy = sy2 * 32 + 16; + } + if (flags & MOVING_DESTINATION) + { + dx = msg.readShort(); + dy = msg.readShort(); + if (!(flags & MOVING_POSITION)) + { + sx = dx; + sy = dy; + } + } + if (!being || !(flags & (MOVING_POSITION | MOVING_DESTINATION))) + { + continue; + } + if (abs(being->mX - sx) + abs(being->mY - sy) > 4 * 32) + { + // Too large a desynchronization. + being->mX = sx; + being->mY = sy; + being->setDestination(dx, dy); + } + else if (!(flags & MOVING_POSITION)) + { + being->setDestination(dx, dy); + } + else if (!(flags & MOVING_DESTINATION)) + { + being->adjustCourse(sx, sy); + } + else + { + being->adjustCourse(sx, sy, dx, dy); + } } } diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h index 03012f39..59539ffe 100644 --- a/src/net/beinghandler.h +++ b/src/net/beinghandler.h @@ -31,7 +31,12 @@ class BeingHandler : public MessageHandler public: BeingHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); + + private: + void handleBeingEnterMessage(MessageIn &msg); + void handleBeingLeaveMessage(MessageIn &msg); + void handleBeingsMoveMessage(MessageIn &msg); }; #endif diff --git a/src/net/buysellhandler.cpp b/src/net/buysellhandler.cpp index d7f063a7..173c59d2 100644 --- a/src/net/buysellhandler.cpp +++ b/src/net/buysellhandler.cpp @@ -54,10 +54,10 @@ BuySellHandler::BuySellHandler() handledMessages = _messages; } -void BuySellHandler::handleMessage(MessageIn *msg) +void BuySellHandler::handleMessage(MessageIn &msg) { int n_items; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_NPC_BUY_SELL_CHOICE: buyDialog->setVisible(false); @@ -65,39 +65,38 @@ void BuySellHandler::handleMessage(MessageIn *msg) sellDialog->setVisible(false); sellDialog->reset(); buySellDialog->setVisible(true); - current_npc = dynamic_cast<NPC*>(beingManager->findBeing(msg->readInt32())); + current_npc = dynamic_cast<NPC*>(beingManager->findBeing(msg.readLong())); break; case SMSG_NPC_BUY: - msg->readInt16(); // length - n_items = (msg->getLength() - 4) / 11; + msg.readShort(); // length + n_items = (msg.getLength() - 4) / 11; buyDialog->reset(); - buyDialog->setMoney(player_node->mGp); + buyDialog->setMoney(player_node->mMoney); buyDialog->setVisible(true); for (int k = 0; k < n_items; k++) { - Sint32 value = msg->readInt32(); - msg->readInt32(); // DCvalue - msg->readInt8(); // type - Sint16 itemId = msg->readInt16(); + Sint32 value = msg.readLong(); + msg.readLong(); // DCvalue + msg.readByte(); // type + Sint16 itemId = msg.readShort(); buyDialog->addItem(itemId, value); } break; case SMSG_NPC_SELL: - msg->readInt16(); // length - n_items = (msg->getLength() - 4) / 10; + msg.readShort(); // length + n_items = (msg.getLength() - 4) / 10; if (n_items > 0) { - sellDialog->setMoney(player_node->mGp); sellDialog->reset(); sellDialog->setVisible(true); for (int k = 0; k < n_items; k++) { - Sint16 index = msg->readInt16(); - Sint32 value = msg->readInt32(); - msg->readInt32(); // OCvalue + Sint16 index = msg.readShort(); + Sint32 value = msg.readLong(); + msg.readLong(); // OCvalue Item *item = player_node->getInvItem(index); if (item && !(item->isEquipped())) { @@ -112,7 +111,7 @@ void BuySellHandler::handleMessage(MessageIn *msg) break; case SMSG_NPC_BUY_RESPONSE: - if (msg->readInt8() == 0) { + if (msg.readByte() == 0) { chatWindow->chatLog("Thanks for buying", BY_SERVER); } else { chatWindow->chatLog("Unable to buy", BY_SERVER); @@ -120,7 +119,7 @@ void BuySellHandler::handleMessage(MessageIn *msg) break; case SMSG_NPC_SELL_RESPONSE: - if (msg->readInt8() == 0) { + if (msg.readByte() == 0) { chatWindow->chatLog("Thanks for selling", BY_SERVER); } else { chatWindow->chatLog("Unable to sell", BY_SERVER); diff --git a/src/net/buysellhandler.h b/src/net/buysellhandler.h index 673aaac1..e242d373 100644 --- a/src/net/buysellhandler.h +++ b/src/net/buysellhandler.h @@ -31,7 +31,7 @@ class BuySellHandler : public MessageHandler public: BuySellHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp index 06ec78c1..f715b434 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/charserverhandler.cpp @@ -23,9 +23,9 @@ #include "charserverhandler.h" -#include "messagein.h" -#include "network.h" +#include "connection.h" #include "protocol.h" +#include "messagein.h" #include "../game.h" #include "../localplayer.h" @@ -35,66 +35,67 @@ #include "../gui/ok_dialog.h" +extern Net::Connection *gameServerConnection; +extern Net::Connection *chatServerConnection; + CharServerHandler::CharServerHandler() { static const Uint16 _messages[] = { - 0x006b, - 0x006c, - 0x006d, - 0x006e, - 0x006f, - 0x0070, - 0x0071, - 0x0081, + APMSG_CHAR_CREATE_RESPONSE, + APMSG_CHAR_DELETE_RESPONSE, + APMSG_CHAR_INFO, + APMSG_CHAR_SELECT_RESPONSE, 0 }; handledMessages = _messages; } -void CharServerHandler::handleMessage(MessageIn *msg) +void +CharServerHandler::handleMessage(MessageIn &msg) { int slot; LocalPlayer *tempPlayer; - logger->log("CharServerHandler: Packet ID: %x, Length: %d", - msg->getId(), msg->getLength()); - switch (msg->getId()) + switch (msg.getId()) { - case 0x006b: - // Skip length word and an additional mysterious 20 bytes - msg->skip(2 + 20); - - // Derive number of characters from message length - n_character = (msg->getLength() - 24) / 106; + case APMSG_CHAR_CREATE_RESPONSE: + handleCharCreateResponse(msg); + break; - for (int i = 0; i < n_character; i++) + case APMSG_CHAR_DELETE_RESPONSE: + { + int errMsg = msg.readByte(); + // Character deletion successful + if (errMsg == ERRMSG_OK) { - tempPlayer = readPlayerData(msg, slot); - mCharInfo->select(slot); - mCharInfo->setEntry(tempPlayer); - logger->log("CharServer: Player: %s (%d)", - tempPlayer->getName().c_str(), slot); + delete mCharInfo->getEntry(); + mCharInfo->setEntry(0); + mCharInfo->unlock(); + n_character--; + new OkDialog("Info", "Player deleted"); } - - state = CHAR_SELECT_STATE; - break; - - case 0x006c: - 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; + // Character deletion failed + else + { + std::string message = ""; + switch (errMsg) + { + case ERRMSG_NO_LOGIN: + message = "Not logged in"; + break; + case ERRMSG_INVALID_ARGUMENT: + message = "Selection out of range"; + break; + default: + message = "Unknown error"; + } + mCharInfo->unlock(); + new OkDialog("Error", message); } - mCharInfo->unlock(); + } break; - case 0x006d: + case APMSG_CHAR_INFO: tempPlayer = readPlayerData(msg, slot); mCharInfo->unlock(); mCharInfo->select(slot); @@ -102,107 +103,111 @@ void CharServerHandler::handleMessage(MessageIn *msg) n_character++; break; - case 0x006e: - new OkDialog("Error", "Failed to create character"); - break; - - case 0x006f: - delete mCharInfo->getEntry(); - mCharInfo->setEntry(0); - mCharInfo->unlock(); - n_character--; - new OkDialog("Info", "Player deleted"); + case APMSG_CHAR_SELECT_RESPONSE: + handleCharSelectResponse(msg); break; + } +} - case 0x0070: - mCharInfo->unlock(); - new OkDialog("Error", "Failed to delete character."); - break; +void +CharServerHandler::handleCharCreateResponse(MessageIn &msg) +{ + int errMsg = msg.readByte(); - case 0x0071: - player_node = mCharInfo->getEntry(); - msg->skip(4); // CharID, must be the same as player_node->charID - map_path = msg->readString(16); - mLoginData->hostname = iptostring(msg->readInt32()); - mLoginData->port = msg->readInt16(); - mCharInfo->unlock(); - mCharInfo->select(0); - // Clear unselected players infos - do - { - LocalPlayer *tmp = mCharInfo->getEntry(); - if (tmp != player_node) - delete tmp; - mCharInfo->next(); - } while (mCharInfo->getPos()); + // Character creation failed + if (errMsg != ERRMSG_OK) + { + std::string message = ""; + switch (errMsg) + { + case ERRMSG_NO_LOGIN: + message = "Not logged in"; + break; + case CREATE_TOO_MUCH_CHARACTERS: + message = "No empty slot"; + break; + case ERRMSG_INVALID_ARGUMENT: + message = "Invalid name"; + break; + case CREATE_EXISTS_NAME: + message = "Character's name already exists"; + break; + case CREATE_INVALID_HAIRSTYLE: + message = "Invalid hairstyle"; + break; + case CREATE_INVALID_HAIRCOLOR: + message = "Invalid hair color"; + break; + case CREATE_INVALID_GENDER: + message = "Invalid gender"; + break; + case CREATE_RAW_STATS_TOO_HIGH: + message = "Character's stats are too high"; + break; + case CREATE_RAW_STATS_TOO_LOW: + message = "Character's stats are too low"; + break; + case CREATE_RAW_STATS_INVALID_DIFF: + message = "Character's stats difference is too high"; + break; + case CREATE_RAW_STATS_EQUAL_TO_ZERO: + message = "One stat is zero"; + break; + default: + message = "Unknown error"; + break; + } + new OkDialog("Error", message); + } +} - state = CONNECTING_STATE; - break; +void +CharServerHandler::handleCharSelectResponse(MessageIn &msg) +{ + int errMsg = msg.readByte(); - case 0x0081: - switch (msg->readInt8()) { - case 1: - errorMessage = "Map server offline"; - break; - case 3: - errorMessage = "Speed hack detected"; - break; - case 8: - errorMessage = "Duplicated login"; - break; - default: - errorMessage = "Unkown error with 0x0081"; - break; - } - mCharInfo->unlock(); - state = ERROR_STATE; - break; + if (errMsg == ERRMSG_OK) + { + token = msg.readString(32); + std::string gameServer = msg.readString(); + unsigned short gameServerPort = msg.readShort(); + std::string chatServer = msg.readString(); + unsigned short chatServerPort = msg.readShort(); + + logger->log("Game server: %s:%d", gameServer.c_str(), gameServerPort); + logger->log("Chat server: %s:%d", chatServer.c_str(), chatServerPort); + + gameServerConnection->connect(gameServer, gameServerPort); + chatServerConnection->connect(chatServer, chatServerPort); + + // Keep the selected character and delete the others + player_node = mCharInfo->getEntry(); + mCharInfo->unlock(); + mCharInfo->select(0); + do { + LocalPlayer *tmp = mCharInfo->getEntry(); + if (tmp != player_node) + delete tmp; + mCharInfo->next(); + } while (mCharInfo->getPos()); + + state = STATE_CONNECT_GAME; } } -LocalPlayer* CharServerHandler::readPlayerData(MessageIn *msg, int &slot) +LocalPlayer* +CharServerHandler::readPlayerData(MessageIn &msg, int &slot) { - LocalPlayer *tempPlayer = new LocalPlayer(mLoginData->account_ID, 0, NULL); - tempPlayer->setSex(1 - mLoginData->sex); - - tempPlayer->mCharId = msg->readInt32(); - tempPlayer->mTotalWeight = 0; - tempPlayer->mMaxWeight = 0; - tempPlayer->mLastAttackTime = 0; - tempPlayer->mXp = msg->readInt32(); - tempPlayer->mGp = msg->readInt32(); - tempPlayer->mJobXp = msg->readInt32(); - tempPlayer->mJobLevel = msg->readInt32(); - msg->skip(8); // unknown - msg->readInt32(); // option - msg->readInt32(); // karma - msg->readInt32(); // manner - msg->skip(2); // unknown - tempPlayer->mHp = msg->readInt16(); - tempPlayer->mMaxHp = msg->readInt16(); - tempPlayer->mMp = msg->readInt16(); - tempPlayer->mMaxMp = msg->readInt16(); - msg->readInt16(); // speed - msg->readInt16(); // class - tempPlayer->setHairStyle(msg->readInt16()); - Uint16 weapon = msg->readInt16(); - if (weapon == 11) - weapon = 2; - tempPlayer->setWeapon(weapon); - tempPlayer->mLevel = msg->readInt16(); - msg->readInt16(); // skill point - tempPlayer->setVisibleEquipment(3, msg->readInt16()); // head bottom - msg->readInt16(); // shield - tempPlayer->setVisibleEquipment(4, msg->readInt16()); // head option top - tempPlayer->setVisibleEquipment(5, msg->readInt16()); // head option mid - tempPlayer->setHairColor(msg->readInt16()); - msg->readInt16(); // unknown - tempPlayer->setName(msg->readString(24)); + LocalPlayer *tempPlayer = new LocalPlayer; + slot = msg.readByte(); // character slot + tempPlayer->mName = msg.readString(); + tempPlayer->setSex(msg.readByte()); + tempPlayer->setHairStyle(msg.readByte()); + tempPlayer->setHairColor(msg.readByte()); + tempPlayer->mLevel = msg.readByte(); + tempPlayer->mMoney = msg.readShort(); for (int i = 0; i < 6; i++) { - tempPlayer->mAttr[i] = msg->readInt8(); + tempPlayer->mAttr[i] = msg.readByte(); } - slot = msg->readInt8(); // character slot - msg->readInt8(); // unknown - return tempPlayer; } diff --git a/src/net/charserverhandler.h b/src/net/charserverhandler.h index 16d2c361..342641d7 100644 --- a/src/net/charserverhandler.h +++ b/src/net/charserverhandler.h @@ -36,17 +36,26 @@ class CharServerHandler : public MessageHandler public: CharServerHandler(); - void handleMessage(MessageIn *msg); + void + handleMessage(MessageIn &msg); - void setCharInfo(LockedArray<LocalPlayer*> *charInfo) { mCharInfo = charInfo; }; - - void setLoginData(LoginData *loginData) { mLoginData = loginData; }; + void + setCharInfo(LockedArray<LocalPlayer*> *charInfo) + { + mCharInfo = charInfo; + } protected: - LoginData *mLoginData; + void + handleCharCreateResponse(MessageIn &msg); + + void + handleCharSelectResponse(MessageIn &msg); + LockedArray<LocalPlayer*> *mCharInfo; - LocalPlayer* readPlayerData(MessageIn *msg, int &slot); + LocalPlayer* + readPlayerData(MessageIn &msg, int &slot); }; #endif diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp index 9095a4e1..f765f0f4 100644 --- a/src/net/chathandler.cpp +++ b/src/net/chathandler.cpp @@ -42,35 +42,53 @@ extern Being *player_node; ChatHandler::ChatHandler() { static const Uint16 _messages[] = { + GPMSG_SAY, + /* SMSG_BEING_CHAT, SMSG_PLAYER_CHAT, SMSG_GM_CHAT, SMSG_WHO_ANSWER, 0x10c, // MVP + */ 0 }; handledMessages = _messages; } -void ChatHandler::handleMessage(MessageIn *msg) +void ChatHandler::handleMessage(MessageIn &msg) { Being *being; std::string chatMsg; - Sint16 chatMsgLength; + //Sint16 chatMsgLength; - switch (msg->getId()) + switch (msg.getId()) { + case GPMSG_SAY: + being = beingManager->findBeing(msg.readShort()); + chatMsg = msg.readString(); + if (being) + { + chatWindow->chatLog(being->getName() + " : " + chatMsg, being == player_node ? BY_PLAYER : BY_OTHER); + being->setSpeech(chatMsg, SPEECH_TIME); + } + else + { + chatWindow->chatLog("John Doe : " + chatMsg, BY_OTHER); + } + break; + + /* // Received speech from being case SMSG_BEING_CHAT: - chatMsgLength = msg->readInt16() - 8; - being = beingManager->findBeing(msg->readInt32()); + chatMsgLength = msg.readShort() - 8; + being = beingManager->findBeing(msg.readLong()); if (!being || chatMsgLength <= 0) { break; } - chatMsg = msg->readString(chatMsgLength); + chatMsg = msg.readString(chatMsgLength); chatWindow->chatLog(chatMsg, BY_OTHER); chatMsg.erase(0, chatMsg.find(" : ", 0) + 3); being->setSpeech(chatMsg, SPEECH_TIME); @@ -78,16 +96,16 @@ void ChatHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_CHAT: case SMSG_GM_CHAT: - chatMsgLength = msg->readInt16() - 4; + chatMsgLength = msg.readShort() - 4; if (chatMsgLength <= 0) { break; } - chatMsg = msg->readString(chatMsgLength); + chatMsg = msg.readString(chatMsgLength); - if (msg->getId() == SMSG_PLAYER_CHAT) + if (msg.getId() == SMSG_PLAYER_CHAT) { chatWindow->chatLog(chatMsg, BY_PLAYER); @@ -105,14 +123,15 @@ void ChatHandler::handleMessage(MessageIn *msg) break; case SMSG_WHO_ANSWER: - chatWindow->chatLog("Online users: " + toString(msg->readInt32()), + chatWindow->chatLog("Online users: " + toString(msg.readLong()), BY_SERVER); break; case 0x010c: // Display MVP player - msg->readInt32(); // id + msg.readLong(); // id chatWindow->chatLog("MVP player", BY_SERVER); break; + */ } } diff --git a/src/net/chathandler.h b/src/net/chathandler.h index eed19206..e9db3575 100644 --- a/src/net/chathandler.h +++ b/src/net/chathandler.h @@ -31,7 +31,7 @@ class ChatHandler : public MessageHandler public: ChatHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/chatserver/chatserver.cpp b/src/net/chatserver/chatserver.cpp new file mode 100644 index 00000000..e6a3331d --- /dev/null +++ b/src/net/chatserver/chatserver.cpp @@ -0,0 +1,116 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "chatserver.h" + +#include "internal.h" + +#include "../connection.h" +#include "../messageout.h" +#include "../protocol.h" + +using Net::ChatServer::connection; + +void Net::ChatServer::connect(Net::Connection *connection, + const std::string &token) +{ + Net::ChatServer::connection = connection; + + MessageOut msg(PCMSG_CONNECT); + + msg.writeString(token, 32); + + connection->send(msg); +} + +void Net::ChatServer::chat(short channel, const std::string &text) +{ + MessageOut msg(PCMSG_CHAT); + + msg.writeString(text); + msg.writeShort(channel); + + connection->send(msg); +} + +void Net::ChatServer::announce(const std::string &text) +{ + MessageOut msg(PCMSG_ANNOUNCE); + + msg.writeString(text); + + connection->send(msg); +} + +void Net::ChatServer::privMsg(const std::string &recipient, + const std::string &text) +{ + MessageOut msg(PCMSG_PRIVMSG); + + msg.writeString(recipient); + msg.writeString(text); + + connection->send(msg); +} + +void Net::ChatServer::registerChannel(const std::string &name, + const std::string &annoucement, const std::string &password, + char isPrivate) +{ + MessageOut msg(PCMSG_REGISTER_CHANNEL); + + msg.writeByte(isPrivate); + msg.writeString(name); + msg.writeString(annoucement); + msg.writeString(password); + + connection->send(msg); +} + +void Net::ChatServer::unregisterChannel(short channel) +{ + MessageOut msg(PCMSG_UNREGISTER_CHANNEL); + + msg.writeShort(channel); + + connection->send(msg); +} + +void Net::ChatServer::enterChannel(short channel, const std::string &password) +{ + MessageOut msg(PCMSG_ENTER_CHANNEL); + + msg.writeShort(channel); + msg.writeString(password); + + connection->send(msg); +} + +void Net::ChatServer::quitChannel(short channel) +{ + MessageOut msg(PCMSG_QUIT_CHANNEL); + + msg.writeShort(channel); + + connection->send(msg); +} diff --git a/src/net/chatserver/chatserver.h b/src/net/chatserver/chatserver.h new file mode 100644 index 00000000..93fe17c4 --- /dev/null +++ b/src/net/chatserver/chatserver.h @@ -0,0 +1,55 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_NET_CHATSERVER_CHATSERVER_H +#define _TMW_NET_CHATSERVER_CHATSERVER_H + +#include <iosfwd> + +namespace Net +{ + class Connection; + + namespace ChatServer + { + void connect(Net::Connection *connection, const std::string &token); + + void chat(short channel, const std::string &text); + + void announce(const std::string &text); + + void privMsg(const std::string &recipient, const std::string &text); + + void registerChannel(const std::string &name, + const std::string &announcement, const std::string &password, + char isPrivate); + + void unregisterChannel(short channel); + + void enterChannel(short channel, const std::string &password); + + void quitChannel(short channel); + } +} + +#endif diff --git a/src/net/chatserver/internal.cpp b/src/net/chatserver/internal.cpp new file mode 100644 index 00000000..c1f7a3f7 --- /dev/null +++ b/src/net/chatserver/internal.cpp @@ -0,0 +1,34 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "internal.h" + +namespace Net +{ + class Connection; + + namespace ChatServer + { + Connection *connection = 0; + } +} diff --git a/src/net/packet.cpp b/src/net/chatserver/internal.h index e77ac117..7579972b 100644 --- a/src/net/packet.cpp +++ b/src/net/chatserver/internal.h @@ -21,20 +21,17 @@ * $Id$ */ -#include "packet.h" +#ifndef _TMW_NET_CHATSERVER_INTERNAL_H +#define _TMW_NET_CHATSERVER_INTERNAL_H -#include <cstring> - -Packet::Packet(const char *data, int length): - mLength(length) +namespace Net { - // Create a copy of the data - mData = new char[mLength]; - memcpy(mData, data, mLength); -} + class Connection; -Packet::~Packet() -{ - // Clean up the data - delete[] mData; + namespace ChatServer + { + extern Connection *connection; + } } + +#endif diff --git a/src/net/connection.cpp b/src/net/connection.cpp new file mode 100644 index 00000000..a17bc727 --- /dev/null +++ b/src/net/connection.cpp @@ -0,0 +1,104 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "connection.h" + +#include <string> + +#include "internal.h" +#include "messageout.h" + +#include "../log.h" + +Net::Connection::Connection(ENetHost *client): + mConnection(0), mClient(client) +{ + Net::connections++; +} + +Net::Connection::~Connection() +{ + Net::connections--; +} + +bool Net::Connection::connect(const std::string &address, short port) +{ + logger->log("Net::Connection::connect(%s, %i)", address.c_str(), port); + + if (address.empty()) + { + logger->log("Net::Connection::connect() got empty address!"); + mState = ERROR; + return false; + } + + ENetAddress enetAddress; + + enet_address_set_host(&enetAddress, address.c_str()); + enetAddress.port = port; + + // Initiate the connection, allocating channel 0. + mConnection = enet_host_connect(mClient, &enetAddress, 1); + + if (!mConnection) + { + logger->log("Unable to initiate connection to the server."); + mState = ERROR; + return false; + } + + return true; +} + +void Net::Connection::disconnect() +{ + if (!mConnection) + return; + + enet_peer_disconnect(mConnection, 0); + enet_host_flush(mClient); + enet_peer_reset(mConnection); + + mConnection = 0; +} + +bool Net::Connection::isConnected() +{ + return mConnection && mConnection->state == ENET_PEER_STATE_CONNECTED; +} + +void Net::Connection::send(const MessageOut &msg) +{ + if (!isConnected()) + { + logger->log("Warning: cannot send message to not connected server!"); + return; + } + + logger->log("Sending message of size %d...", msg.getDataSize()); + + ENetPacket *packet = enet_packet_create(msg.getData(), + msg.getDataSize(), + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(mConnection, 0, packet); +} diff --git a/src/net/connection.h b/src/net/connection.h new file mode 100644 index 00000000..179367c6 --- /dev/null +++ b/src/net/connection.h @@ -0,0 +1,78 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_NET_CONNECTION_H +#define _TMW_NET_CONNECTION_H + +#include <iosfwd> + +#include <enet/enet.h> + +class MessageOut; + +namespace Net +{ + class Connection + { + public: + enum State { + OK, ERROR + }; + + ~Connection(); + + /** + * Connects to the given server with the specified address and port. + * This method is non-blocking, use isConnected to check whether the + * server is connected. + */ + bool connect(const std::string &address, short port); + + /** + * Disconnects from the given server. + */ + void disconnect(); + + State getState() { return mState; } + + /** + * Returns whether the server is connected. + */ + bool isConnected(); + + /** + * Sends a message. + */ + void send(const MessageOut &msg); + + private: + friend Connection *Net::getConnection(); + Connection(ENetHost *client); + + ENetPeer *mConnection; + ENetHost *mClient; + State mState; + }; +} + +#endif diff --git a/src/net/equipmenthandler.cpp b/src/net/equipmenthandler.cpp index 01760eeb..1c0fd4ca 100644 --- a/src/net/equipmenthandler.cpp +++ b/src/net/equipmenthandler.cpp @@ -48,7 +48,7 @@ EquipmentHandler::EquipmentHandler() handledMessages = _messages; } -void EquipmentHandler::handleMessage(MessageIn *msg) +void EquipmentHandler::handleMessage(MessageIn &msg) { Sint32 itemCount; Sint16 index, equipPoint, itemId; @@ -57,23 +57,22 @@ void EquipmentHandler::handleMessage(MessageIn *msg) Being *being; Item *item; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_PLAYER_EQUIPMENT: - msg->readInt16(); // length - itemCount = (msg->getLength() - 4) / 20; + msg.readShort(); // length + itemCount = (msg.getLength() - 4) / 20; for (int loop = 0; loop < itemCount; loop++) { - index = msg->readInt16(); - itemId = msg->readInt16(); - msg->readInt8(); // type - msg->readInt8(); // identify flag - msg->readInt16(); // equip type - equipPoint = msg->readInt16(); - msg->readInt8(); // attribute - msg->readInt8(); // refine - msg->skip(8); // card + index = msg.readShort(); + itemId = msg.readShort(); + msg.readByte(); // type + msg.readByte(); // identify flag + msg.readShort(); // equip type + equipPoint = msg.readShort(); + msg.readByte(); // attribute + msg.readByte(); // refine player_node->addInvItem(index, itemId, 1, true); @@ -93,9 +92,9 @@ void EquipmentHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_EQUIP: - index = msg->readInt16(); - equipPoint = msg->readInt16(); - type = msg->readInt8(); + index = msg.readShort(); + equipPoint = msg.readShort(); + type = msg.readByte(); logger->log("Equipping: %i %i %i", index, equipPoint, type); @@ -129,10 +128,10 @@ void EquipmentHandler::handleMessage(MessageIn *msg) case 0x01d7: // Equipment related - being = beingManager->findBeing(msg->readInt32()); - msg->readInt8(); // equip point - itemId = msg->readInt16(); - msg->readInt16(); // item id 2 + being = beingManager->findBeing(msg.readLong()); + msg.readByte(); // equip point + itemId = msg.readShort(); + msg.readShort(); // item id 2 if (!being) break; @@ -141,9 +140,9 @@ void EquipmentHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_UNEQUIP: - index = msg->readInt16(); - equipPoint = msg->readInt16(); - type = msg->readInt8(); + index = msg.readShort(); + equipPoint = msg.readShort(); + type = msg.readByte(); if (!type) { chatWindow->chatLog("Unable to unequip.", BY_SERVER); @@ -193,7 +192,7 @@ void EquipmentHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_ARROW_EQUIP: - itemId = msg->readInt16(); + itemId = msg.readShort(); if (itemId <= 1) break; diff --git a/src/net/equipmenthandler.h b/src/net/equipmenthandler.h index 656f7a73..c9c65d67 100644 --- a/src/net/equipmenthandler.h +++ b/src/net/equipmenthandler.h @@ -31,7 +31,7 @@ class EquipmentHandler : public MessageHandler public: EquipmentHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/gameserver/gameserver.cpp b/src/net/gameserver/gameserver.cpp new file mode 100644 index 00000000..04e5bb08 --- /dev/null +++ b/src/net/gameserver/gameserver.cpp @@ -0,0 +1,42 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "gameserver.h" + +#include "internal.h" + +#include "../connection.h" +#include "../messageout.h" +#include "../protocol.h" + +void Net::GameServer::connect(Net::Connection *connection, + const std::string &token) +{ + Net::GameServer::connection = connection; + + MessageOut msg(PGMSG_CONNECT); + + msg.writeString(token, 32); + + Net::GameServer::connection->send(msg); +} diff --git a/src/net/packet.h b/src/net/gameserver/gameserver.h index 84d16d5e..ee49d7e3 100644 --- a/src/net/packet.h +++ b/src/net/gameserver/gameserver.h @@ -21,27 +21,19 @@ * $Id$ */ -#ifndef _TMW_PACKET_ -#define _TMW_PACKET_ +#ifndef _TMW_NET_GAMESERVER_GAMESERVER_H +#define _TMW_NET_GAMESERVER_GAMESERVER_H -/** - * A packet wraps a certain amount of bytes for sending and receiving. - */ -class Packet -{ - public: - /** - * Constructor. - */ - Packet(const char *data, int length); +#include <iosfwd> - /** - * Destructor. - */ - ~Packet(); +namespace Net +{ + class Connection; - char *mData; /**< Packet data */ - unsigned int mLength; /**< Length of data in bytes */ -}; + namespace GameServer + { + void connect(Net::Connection *connection, const std::string &token); + } +} #endif diff --git a/src/net/gameserver/internal.cpp b/src/net/gameserver/internal.cpp new file mode 100644 index 00000000..328b4863 --- /dev/null +++ b/src/net/gameserver/internal.cpp @@ -0,0 +1,34 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "internal.h" + +namespace Net +{ + class Connection; + + namespace GameServer + { + Connection *connection = 0; + } +} diff --git a/src/net/gameserver/internal.h b/src/net/gameserver/internal.h new file mode 100644 index 00000000..567e15d2 --- /dev/null +++ b/src/net/gameserver/internal.h @@ -0,0 +1,37 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_NET_GAMESERVER_INTERNAL_H +#define _TMW_NET_GAMESERVER_INTERNAL_H + +namespace Net +{ + class Connection; + + namespace GameServer + { + extern Connection *connection; + } +} + +#endif diff --git a/src/net/gameserver/player.cpp b/src/net/gameserver/player.cpp new file mode 100644 index 00000000..1f27276a --- /dev/null +++ b/src/net/gameserver/player.cpp @@ -0,0 +1,68 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "player.h" + +#include "internal.h" + +#include "../connection.h" +#include "../messageout.h" +#include "../protocol.h" + +void Net::GameServer::Player::say(const std::string &text) +{ + MessageOut msg(PGMSG_SAY); + + msg.writeString(text); + + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::walk(short x, short y) +{ + MessageOut msg(PGMSG_WALK); + + msg.writeShort(x); + msg.writeShort(y); + + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::useItem(int itemId) +{ + MessageOut msg(PGMSG_USE_ITEM); + + msg.writeLong(itemId); + + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::equip(int itemId, char slot) +{ + MessageOut msg(PGMSG_EQUIP); + + msg.writeLong(itemId); + msg.writeByte(slot); + + Net::GameServer::connection->send(msg); +} diff --git a/src/net/gameserver/player.h b/src/net/gameserver/player.h new file mode 100644 index 00000000..34d5bb45 --- /dev/null +++ b/src/net/gameserver/player.h @@ -0,0 +1,46 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_NET_GAMESERVER_PLAYER_H +#define _TMW_NET_GAMESERVER_PLAYER_H + +#include <iosfwd> + +namespace Net +{ + class Connection; + + namespace GameServer + { + namespace Player + { + void say(const std::string &text); + void walk(short x, short y); +// void pickUp(...); + void useItem(int itemId); + void equip(int itemId, char slot); + } + } +} + +#endif diff --git a/src/net/internal.cpp b/src/net/internal.cpp new file mode 100644 index 00000000..358aa143 --- /dev/null +++ b/src/net/internal.cpp @@ -0,0 +1,29 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "internal.h" + +namespace Net +{ + int connections = 0; +} diff --git a/src/net/internal.h b/src/net/internal.h new file mode 100644 index 00000000..e1ef648a --- /dev/null +++ b/src/net/internal.h @@ -0,0 +1,32 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_NET_INTERNAL_H +#define _TMW_NET_INTERNAL_H + +namespace Net +{ + extern int connections; +} + +#endif diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp index afe653eb..3f7e8709 100644 --- a/src/net/inventoryhandler.cpp +++ b/src/net/inventoryhandler.cpp @@ -47,29 +47,27 @@ InventoryHandler::InventoryHandler() handledMessages = _messages; } -void InventoryHandler::handleMessage(MessageIn *msg) +void InventoryHandler::handleMessage(MessageIn &msg) { Sint32 number; Sint16 index, amount, itemId, equipType; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_PLAYER_INVENTORY: // Only called on map load / warp. First reset all items // to not load them twice on map change. player_node->clearInventory(); - msg->readInt16(); // length - number = (msg->getLength() - 4) / 18; + msg.readShort(); // length + number = (msg.getLength() - 4) / 18; for (int loop = 0; loop < number; loop++) { - index = msg->readInt16(); - itemId = msg->readInt16(); - msg->readInt8(); // type - msg->readInt8(); // identify flag - amount = msg->readInt16(); - msg->skip(2); // unknown - msg->skip(8); // card (4 shorts) + index = msg.readShort(); + itemId = msg.readShort(); + msg.readByte(); // type + msg.readByte(); // identify flag + amount = msg.readShort(); player_node->addInvItem(index, itemId, amount, false); @@ -82,17 +80,16 @@ void InventoryHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_INVENTORY_ADD: - index = msg->readInt16(); - amount = msg->readInt16(); - itemId = msg->readInt16(); - msg->readInt8(); // identify flag - msg->readInt8(); // attribute - msg->readInt8(); // refine - msg->skip(8); // card - equipType = msg->readInt16(); - msg->readInt8(); // type - - if (msg->readInt8()> 0) { + index = msg.readShort(); + amount = msg.readShort(); + itemId = msg.readShort(); + msg.readByte(); // identify flag + msg.readByte(); // attribute + msg.readByte(); // refine + equipType = msg.readShort(); + msg.readByte(); // type + + if (msg.readByte()> 0) { chatWindow->chatLog("Unable to pick up item", BY_SERVER); } else { const ItemInfo &itemInfo = itemDb->getItemInfo(itemId); @@ -103,26 +100,26 @@ void InventoryHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_INVENTORY_REMOVE: - index = msg->readInt16(); - amount = msg->readInt16(); + index = msg.readShort(); + amount = msg.readShort(); player_node->getInvItem(index)->increaseQuantity(-amount); break; case SMSG_PLAYER_INVENTORY_USE: - index = msg->readInt16(); - msg->readInt16(); // item id - msg->readInt32(); // id - amount = msg->readInt16(); - msg->readInt8(); // type + index = msg.readShort(); + msg.readShort(); // item id + msg.readLong(); // id + amount = msg.readShort(); + msg.readByte(); // type player_node->getInvItem(index)->setQuantity(amount); break; case SMSG_ITEM_USE_RESPONSE: - index = msg->readInt16(); - amount = msg->readInt16(); + index = msg.readShort(); + amount = msg.readShort(); - if (msg->readInt8() == 0) { + if (msg.readByte() == 0) { chatWindow->chatLog("Failed to use item", BY_SERVER); } else { player_node->getInvItem(index)->setQuantity(amount); diff --git a/src/net/inventoryhandler.h b/src/net/inventoryhandler.h index aedbc3a1..4190bf83 100644 --- a/src/net/inventoryhandler.h +++ b/src/net/inventoryhandler.h @@ -31,7 +31,7 @@ class InventoryHandler : public MessageHandler public: InventoryHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/itemhandler.cpp b/src/net/itemhandler.cpp index 567a5382..2961f71b 100644 --- a/src/net/itemhandler.cpp +++ b/src/net/itemhandler.cpp @@ -40,29 +40,28 @@ ItemHandler::ItemHandler() handledMessages = _messages; } -void ItemHandler::handleMessage(MessageIn *msg) +void ItemHandler::handleMessage(MessageIn &msg) { Uint32 id; Uint16 x, y; Sint16 itemId; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_ITEM_VISIBLE: case SMSG_ITEM_DROPPED: - id = msg->readInt32(); - itemId = msg->readInt16(); - msg->readInt8(); // identify flag - x = msg->readInt16(); - y = msg->readInt16(); - msg->skip(4); // amount,subX,subY / subX,subY,amount + id = msg.readLong(); + itemId = msg.readShort(); + msg.readByte(); // identify flag + x = msg.readShort(); + y = msg.readShort(); floorItemManager->create(id, itemId, x, y, engine->getCurrentMap()); break; case SMSG_ITEM_REMOVE: FloorItem *item; - item = floorItemManager->findById(msg->readInt32()); + item = floorItemManager->findById(msg.readLong()); if (item) floorItemManager->destroy(item); break; diff --git a/src/net/itemhandler.h b/src/net/itemhandler.h index b2104722..5ffcb134 100644 --- a/src/net/itemhandler.h +++ b/src/net/itemhandler.h @@ -31,7 +31,7 @@ class ItemHandler : public MessageHandler public: ItemHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/loginhandler.cpp b/src/net/loginhandler.cpp index 195e54e9..73be4b2f 100644 --- a/src/net/loginhandler.cpp +++ b/src/net/loginhandler.cpp @@ -24,92 +24,87 @@ #include "loginhandler.h" #include "messagein.h" -#include "network.h" #include "protocol.h" -#include "../log.h" -#include "../logindata.h" #include "../main.h" -#include "../serverinfo.h" - -extern SERVER_INFO **server_info; LoginHandler::LoginHandler() { static const Uint16 _messages[] = { - 0x0069, - 0x006a, + APMSG_LOGIN_RESPONSE, + APMSG_REGISTER_RESPONSE, 0 }; handledMessages = _messages; } -void LoginHandler::handleMessage(MessageIn *msg) +void LoginHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { - case 0x0069: - // Skip the length word - msg->skip(2); - - n_server = (msg->getLength() - 47) / 32; - server_info = (SERVER_INFO**)malloc(sizeof(SERVER_INFO*) * n_server); - - mLoginData->session_ID1 = msg->readInt32(); - mLoginData->account_ID = msg->readInt32(); - mLoginData->session_ID2 = msg->readInt32(); - msg->skip(30); // unknown - mLoginData->sex = msg->readInt8(); - - for (int i = 0; i < n_server; i++) + case APMSG_LOGIN_RESPONSE: + { + int errMsg = msg.readByte(); + // Successful login + if (errMsg == ERRMSG_OK) { - server_info[i] = new SERVER_INFO; - - server_info[i]->address = msg->readInt32(); - server_info[i]->port = msg->readInt16(); - server_info[i]->name = msg->readString(20); - server_info[i]->online_users = msg->readInt32(); - msg->skip(2); // unknown - - logger->log("Network: Server: %s (%s:%d)", - server_info[i]->name.c_str(), - iptostring(server_info[i]->address), - server_info[i]->port); + state = STATE_CHAR_SELECT; } - state = CHAR_SERVER_STATE; + // Login failed + else + { + switch (errMsg) { + case LOGIN_INVALID_VERSION: + errorMessage = "Client has an insufficient version number to login."; + break; + case ERRMSG_INVALID_ARGUMENT: + errorMessage = "Wrong username or password"; + break; + case ERRMSG_FAILURE: + errorMessage = "Already logged in"; + break; + case LOGIN_SERVER_FULL: + errorMessage = "Server is full"; + break; + default: + errorMessage = "Unknown error"; + break; + } + state = STATE_ERROR; + } + } break; - - case 0x006a: - int loginError = msg->readInt8(); - logger->log("Login::error code: %i", loginError); - - switch (loginError) { - 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 blocked by the GM Team"; - break; - case 6: - errorMessage = "You have been banned for 5 minutes"; - break; - case 9: - errorMessage = "This account is already logged in"; - break; - default: - errorMessage = "Unknown error"; - break; + case APMSG_REGISTER_RESPONSE: + { + int errMsg = msg.readByte(); + // Successful registration + if (errMsg == ERRMSG_OK) + { + state = STATE_CHAR_SELECT; + } + // Registration failed + else + { + switch (errMsg) { + case REGISTER_INVALID_VERSION: + errorMessage = "Client has an insufficient version number to login."; + break; + case ERRMSG_INVALID_ARGUMENT: + errorMessage = "Wrong username, password or email address"; + break; + case REGISTER_EXISTS_USERNAME: + errorMessage = "Username already exists"; + break; + case REGISTER_EXISTS_EMAIL: + errorMessage = "Email address already exists"; + break; + default: + errorMessage = "Unknown error"; + break; + } + state = STATE_ERROR; } - state = ERROR_STATE; + } break; } } diff --git a/src/net/loginhandler.h b/src/net/loginhandler.h index 52014559..5bac079c 100644 --- a/src/net/loginhandler.h +++ b/src/net/loginhandler.h @@ -26,19 +26,12 @@ #include "messagehandler.h" -struct LoginData; - class LoginHandler : public MessageHandler { public: LoginHandler(); - void handleMessage(MessageIn *msg); - - void setLoginData(LoginData *loginData) { mLoginData = loginData; }; - - protected: - LoginData *mLoginData; + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/maploginhandler.cpp b/src/net/maploginhandler.cpp deleted file mode 100644 index 0afc8357..00000000 --- a/src/net/maploginhandler.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#include "maploginhandler.h" - -#include "messagein.h" -#include "protocol.h" - -#include "../localplayer.h" -#include "../log.h" -#include "../main.h" - -MapLoginHandler::MapLoginHandler() -{ - static const Uint16 _messages[] = { - SMSG_LOGIN_SUCCESS, - 0x0081, - 0 - }; - handledMessages = _messages; -} - -void MapLoginHandler::handleMessage(MessageIn *msg) -{ - unsigned char direction; - - switch (msg->getId()) - { - case SMSG_LOGIN_SUCCESS: - msg->readInt32(); // server tick - msg->readCoordinates(player_node->mX, player_node->mY, direction); - msg->skip(2); // unknown - logger->log("Protocol: Player start position: (%d, %d), Direction: %d", - player_node->mX, player_node->mY, direction); - state = GAME_STATE; - break; - - case 0x0081: - logger->log("Warning: Map server D/C"); - state = ERROR_STATE; - break; - } -} diff --git a/src/net/messagehandler.cpp b/src/net/messagehandler.cpp index 849b6716..b6074690 100644 --- a/src/net/messagehandler.cpp +++ b/src/net/messagehandler.cpp @@ -27,19 +27,7 @@ #include "network.h" -MessageHandler::MessageHandler(): - mNetwork(0) -{ -} - MessageHandler::~MessageHandler() { - if (mNetwork) - mNetwork->unregisterHandler(this); -} - -void MessageHandler::setNetwork(Network *network) -{ - assert(!(network && mNetwork)); - mNetwork = network; + Net::unregisterHandler(this); } diff --git a/src/net/messagehandler.h b/src/net/messagehandler.h index c09037f6..b21abd72 100644 --- a/src/net/messagehandler.h +++ b/src/net/messagehandler.h @@ -27,22 +27,15 @@ #include <SDL_types.h> class MessageIn; -class Network; class MessageHandler { public: const Uint16 *handledMessages; - MessageHandler(); virtual ~MessageHandler(); - virtual void handleMessage(MessageIn *msg) =0; - - void setNetwork(Network *network); - - protected: - Network *mNetwork; + virtual void handleMessage(MessageIn &msg) = 0; }; #endif diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp index bbc0a44c..a1707e06 100644 --- a/src/net/messagein.cpp +++ b/src/net/messagein.cpp @@ -1,5 +1,5 @@ /* - * The Mana World + * The Mana World Server * Copyright 2004 The Mana World Development Team * * This file is part of The Mana World. @@ -23,14 +23,9 @@ #include "messagein.h" -#include <cassert> -#include <SDL.h> -#include <SDL_endian.h> - -#define MAKEWORD(low,high) \ - ((unsigned short)(((unsigned char)(low)) | \ - ((unsigned short)((unsigned char)(high))) << 8)) +#include <string> +#include <enet/enet.h> MessageIn::MessageIn(const char *data, unsigned int length): mData(data), @@ -38,157 +33,78 @@ MessageIn::MessageIn(const char *data, unsigned int length): mPos(0) { // Read the message ID - mId = readInt16(); + mId = readShort(); } -Sint8 -MessageIn::readInt8() +MessageIn::~MessageIn() { - assert(mPos < mLength); - return mData[mPos++]; -} - -Sint16 -MessageIn::readInt16() -{ - assert(mPos + 2 <= mLength); - mPos += 2; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - return SDL_Swap16(*(Sint16*)(mData + (mPos - 2))); -#else - return (*(Sint16*)(mData + (mPos - 2))); -#endif } -Sint32 -MessageIn::readInt32() +char MessageIn::readByte() { - assert(mPos + 4 <= mLength); - mPos += 4; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - return SDL_Swap32(*(Sint32*)(mData + (mPos - 4))); -#else - return (*(Sint32*)(mData + (mPos - 4))); -#endif + char value = -1; + if (mPos < mLength) + { + value = mData[mPos]; + } + mPos += 1; + return value; } -void -MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction) +short MessageIn::readShort() { - assert(mPos + 3 <= mLength); - - const char *data = mData + mPos; - Sint16 temp; - - temp = MAKEWORD(data[1] & 0x00c0, data[0] & 0x00ff); - x = temp >> 6; - temp = MAKEWORD(data[2] & 0x00f0, data[1] & 0x003f); - y = temp >> 4; - - direction = data[2] & 0x000f; - - // Translate from eAthena format - switch (direction) + short value = -1; + if (mPos + 2 <= mLength) { - case 0: - direction = 1; - break; - case 1: - direction = 3; - break; - case 2: - direction = 2; - break; - case 3: - direction = 6; - break; - case 4: - direction = 4; - break; - case 5: - direction = 12; - break; - case 6: - direction = 8; - break; - case 7: - direction = 9; - break; - default: - // OOPSIE! Impossible or unknown - direction = 0; + uint16_t t; + memcpy(&t, mData + mPos, 2); + value = ENET_NET_TO_HOST_16(t); } - - mPos += 3; + mPos += 2; + return value; } -void -MessageIn::readCoordinatePair(Uint16 &srcX, Uint16 &srcY, - Uint16 &dstX, Uint16 &dstY) +long MessageIn::readLong() { - assert(mPos + 5 <= mLength); - - const char *data = mData + mPos; - Sint16 temp; - - temp = MAKEWORD(data[3], data[2] & 0x000f); - dstX = temp >> 2; - - dstY = MAKEWORD(data[4], data[3] & 0x0003); - - temp = MAKEWORD(data[1], data[0]); - srcX = temp >> 6; - - temp = MAKEWORD(data[2], data[1] & 0x003f); - srcY = temp >> 4; - - mPos += 5; + long value = -1; + if (mPos + 4 <= mLength) + { + uint32_t t; + memcpy(&t, mData + mPos, 4); + value = ENET_NET_TO_HOST_32(t); + } + mPos += 4; + return value; } -void -MessageIn::skip(unsigned int length) +void MessageIn::readCoordinates(Uint16 &x, Uint16 &y) { - assert(mPos + length <= mLength); - mPos += length; + if (mPos + 3 <= mLength) + { + unsigned char const *p = reinterpret_cast< unsigned char const * >(mData + mPos); + x = p[0] | ((p[1] & 0x07) << 8); + y = (p[1] >> 3) | ((p[2] & 0x3F) << 5); + } + mPos += 3; } -std::string -MessageIn::readString(int length) +std::string MessageIn::readString(int length) { // Get string length if (length < 0) { - length = readInt16(); + length = readShort(); } - // Make sure the string isn't erroneous + // Make sure the string isn't erroneus if (length < 0 || mPos + length > mLength) { mPos = mLength + 1; return ""; } // Read the string - char const *stringBeg = mData + mPos; - char const *stringEnd = (char const *)memchr(stringBeg, '\0', length); - std::string readString(stringBeg, - stringEnd ? stringEnd - stringBeg : length); + char const *stringBeg = mData + mPos, + *stringEnd = (char const *)memchr(stringBeg, '\0', length); + std::string readString(stringBeg, stringEnd ? stringEnd - stringBeg : length); mPos += length; return readString; } - -Sint8& operator<<(Sint8 &lhs, MessageIn &msg) -{ - lhs = msg.readInt8(); - return lhs; -} - -Sint16& operator<<(Sint16 &lhs, MessageIn &msg) -{ - lhs = msg.readInt16(); - return lhs; -} - -Sint32& operator<<(Sint32 &lhs, MessageIn &msg) -{ - lhs = msg.readInt32(); - return lhs; -} diff --git a/src/net/messagein.h b/src/net/messagein.h index d97cd8b6..68bbb933 100644 --- a/src/net/messagein.h +++ b/src/net/messagein.h @@ -1,5 +1,5 @@ /* - * The Mana World + * The Mana World Server * Copyright 2004 The Mana World Development Team * * This file is part of The Mana World. @@ -21,10 +21,11 @@ * $Id$ */ -#ifndef _TMW_MESSAGEIN_ -#define _TMW_MESSAGEIN_ +#ifndef _TMWSERV_MESSAGEIN_H_ +#define _TMWSERV_MESSAGEIN_H_ #include <string> + #include <SDL_types.h> /** @@ -32,10 +33,6 @@ */ class MessageIn { - friend Sint8& operator<<(Sint8 &lhs, MessageIn &msg); - friend Sint16& operator<<(Sint16 &lhs, MessageIn &msg); - friend Sint32& operator<<(Sint32 &lhs, MessageIn &msg); - public: /** * Constructor. @@ -43,55 +40,51 @@ class MessageIn MessageIn(const char *data, unsigned int length); /** - * Returns the message ID. + * Destructor. */ - short - getId() { return mId; } + ~MessageIn(); - /** - * Returns the message length. - */ - unsigned int - getLength() { return mLength; } + short getId() { return mId; } /**< Returns the message ID. */ - Sint8 readInt8(); /**< Reads a byte. */ - Sint16 readInt16(); /**< Reads a short. */ - Sint32 readInt32(); /**< Reads a long. */ + char readByte(); /**< Reads a byte. */ + short readShort(); /**< Reads a short. */ + long readLong(); /**< Reads a long. */ /** - * Reads a special 3 byte block used by eAthena, containing x and y - * coordinates and direction. + * Reads a 3-byte block containing tile-based coordinates. */ - void - readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction); + void readCoordinates(Uint16 &x, Uint16 &y); /** - * Reads a special 5 byte block used by eAthena, containing a source - * and destination coordinate pair. + * Reads a string. If a length is not given (-1), it is assumed + * that the length of the string is stored in a short at the + * start of the string. */ - void - readCoordinatePair(Uint16 &srcX, Uint16 &srcY, - Uint16 &dstX, Uint16 &dstY); + std::string readString(int length = -1); /** - * Skips a given number of bytes. + * Returns the message length. */ - void - skip(unsigned int length); + unsigned int + getLength() { return mLength; } /** - * Reads a string. If a length is not given (-1), it is assumed - * that the length of the string is stored in a short at the - * start of the string. + * Returns the length of unread data. */ - std::string - readString(int length = -1); + unsigned int + getUnreadLength() { return mLength - mPos; } private: const char* mData; /**< The message data. */ unsigned int mLength; /**< The length of the data. */ - unsigned int mPos; /**< The position in the data. */ short mId; /**< The message ID. */ + + /** + * Actual position in the packet. From 0 to packet->length. + * A value bigger than packet->length means EOP was reached when + * reading it. + */ + unsigned int mPos; }; #endif diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp index f6ed5de6..4d68c14f 100644 --- a/src/net/messageout.cpp +++ b/src/net/messageout.cpp @@ -1,5 +1,5 @@ /* - * The Mana World + * The Mana World Server * Copyright 2004 The Mana World Development Team * * This file is part of The Mana World. @@ -24,93 +24,92 @@ #include "messageout.h" #include <string> -#include <SDL.h> -#include <SDL_endian.h> -#include "network.h" -#include "packet.h" +#include <enet/enet.h> -MessageOut::MessageOut(Network *network): - mNetwork(network), +MessageOut::MessageOut(short id): mData(0), mDataSize(0), mPos(0) { - mData = mNetwork->mOutBuffer + mNetwork->mOutSize; + writeShort(id); } -void MessageOut::writeInt8(Sint8 value) +MessageOut::~MessageOut() { - mData[mPos] = value; - mPos += sizeof(Sint8); - mNetwork->mOutSize+= sizeof(Sint8); + if (mData) { + free(mData); + } } -void MessageOut::writeInt16(Sint16 value) +void +MessageOut::expand(size_t bytes) { -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - (*(Sint16 *)(mData + mPos)) = SDL_Swap16(value); -#else - (*(Sint16 *)(mData + mPos)) = value; -#endif - mPos += sizeof(Sint16); - mNetwork->mOutSize += sizeof(Sint16); + mData = (char*)realloc(mData, bytes); + mDataSize = bytes; } -void MessageOut::writeInt32(Sint32 value) +void +MessageOut::writeByte(char value) { -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - (*(Sint32 *)(mData + mPos)) = SDL_Swap32(value); -#else - (*(Sint32 *)(mData + mPos)) = value; -#endif - mPos += sizeof(Sint32); - mNetwork->mOutSize += sizeof(Sint32); + expand(mPos + 1); + mData[mPos] = value; + mPos += 1; } -void MessageOut::writeString(const std::string &string, int length) +void MessageOut::writeShort(short value) { - std::string toWrite = string; + expand(mPos + 2); + uint16_t t = ENET_HOST_TO_NET_16(value); + memcpy(mData + mPos, &t, 2); + mPos += 2; +} +void +MessageOut::writeLong(long value) +{ + expand(mPos + 4); + uint32_t t = ENET_HOST_TO_NET_32(value); + memcpy(mData + mPos, &t, 4); + mPos += 4; +} + +void +MessageOut::writeString(const std::string &string, int length) +{ + int stringLength = string.length(); if (length < 0) { // Write the length at the start if not fixed - writeInt16(string.length()); + writeShort(stringLength); + length = stringLength; } - else + else if (length < stringLength) { // Make sure the length of the string is no longer than specified - toWrite = string.substr(0, length); + stringLength = length; } + expand(mPos + length); // Write the actual string - memcpy(&mData[mPos], (void*)toWrite.c_str(), toWrite.length()); - mPos += toWrite.length(); - mNetwork->mOutSize += toWrite.length(); + memcpy(mData + mPos, string.c_str(), stringLength); // Pad remaining space with zeros - if (length > (int)toWrite.length()) + if (length > stringLength) { - memset(&mData[mPos], '\0', length - toWrite.length()); - mPos += length - toWrite.length(); - mNetwork->mOutSize += length - toWrite.length(); + memset(mData + mPos + stringLength, '\0', length - stringLength); } + mPos += length; } -MessageOut& operator<<(MessageOut &msg, const Sint8 &rhs) -{ - msg.writeInt8(rhs); - return msg; -} - -MessageOut& operator<<(MessageOut &msg, const Sint16 &rhs) +char* +MessageOut::getData() const { - msg.writeInt16(rhs); - return msg; + return mData; } -MessageOut& operator<<(MessageOut &msg, const Sint32 &rhs) +unsigned int +MessageOut::getDataSize() const { - msg.writeInt32(rhs); - return msg; + return mDataSize; } diff --git a/src/net/messageout.h b/src/net/messageout.h index f6468adb..af25e4b4 100644 --- a/src/net/messageout.h +++ b/src/net/messageout.h @@ -1,5 +1,5 @@ /* - * The Mana World + * The Mana World Server * Copyright 2004 The Mana World Development Team * * This file is part of The Mana World. @@ -21,32 +21,30 @@ * $Id$ */ -#ifndef _TMW_MESSAGEOUT_ -#define _TMW_MESSAGEOUT_ +#ifndef _TMWSERV_MESSAGEOUT_H_ +#define _TMWSERV_MESSAGEOUT_H_ #include <iosfwd> -#include <SDL_types.h> - -class Network; /** * Used for building an outgoing message. */ class MessageOut { - friend MessageOut& operator<<(MessageOut &msg, const Sint8 &rhs); - friend MessageOut& operator<<(MessageOut &msg, const Sint16 &rhs); - friend MessageOut& operator<<(MessageOut &msg, const Sint32 &rhs); - public: /** * Constructor. */ - MessageOut(Network *network); + MessageOut(short id); - void writeInt8(Sint8 value); /**< Writes a byte. */ - void writeInt16(Sint16 value); /**< Writes a short. */ - void writeInt32(Sint32 value); /**< Writes a long. */ + /** + * Destructor. + */ + ~MessageOut(); + + void writeByte(char value); /**< Writes a byte. */ + void writeShort(short value); /**< Writes a short. */ + void writeLong(long value); /**< Writes a long. */ /** * Writes a string. If a fixed length is not given (-1), it is stored @@ -54,8 +52,25 @@ class MessageOut */ void writeString(const std::string &string, int length = -1); + /** + * Returns the content of the message. + */ + char *getData() const; + + /** + * Returns the length of the data. + */ + unsigned int getDataSize() const; + private: - Network *mNetwork; + /** + * Expand the packet data to be able to hold more data. + * + * NOTE: For performance enhancements this method could allocate extra + * memory in advance instead of expanding size every time more data is + * added. + */ + void expand(size_t size); char *mData; /**< Data building up. */ unsigned int mDataSize; /**< Size of data. */ diff --git a/src/net/network.cpp b/src/net/network.cpp index 757a533e..b94c9eb8 100644 --- a/src/net/network.cpp +++ b/src/net/network.cpp @@ -23,422 +23,153 @@ #include "network.h" +#include <enet/enet.h> + +#include <map> + +#include "connection.h" +#include "internal.h" #include "messagehandler.h" #include "messagein.h" #include "../log.h" -/** 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, 0, 0, 0, 55, 17, 3, 37, 46, -1, 23, -1, 3,108, 3, 2, - 3, 28, 19, 11, 3, -1, 9, 5, 54, 53, 58, 60, 41, 2, 6, 6, -// #0x0080 - 7, 3, 2, 2, 2, 5, 16, 12, 10, 7, 29, 23, -1, -1, -1, 0, - 7, 22, 28, 2, 6, 30, -1, -1, 3, -1, -1, 5, 9, 17, 17, 6, - 23, 6, 6, -1, -1, -1, -1, 8, 7, 6, 7, 4, 7, 0, -1, 6, - 8, 8, 3, 3, -1, 6, 6, -1, 7, 6, 2, 5, 6, 44, 5, 3, -// #0x00C0 - 7, 2, 6, 8, 6, 7, -1, -1, -1, -1, 3, 3, 6, 6, 2, 27, - 3, 4, 4, 2, -1, -1, 3, -1, 6, 14, 3, -1, 28, 29, -1, -1, - 30, 30, 26, 2, 6, 26, 3, 3, 8, 19, 5, 2, 3, 2, 2, 2, - 3, 2, 6, 8, 21, 8, 8, 2, 2, 26, 3, -1, 6, 27, 30, 10, -// #0x0100 - 2, 6, 6, 30, 79, 31, 10, 10, -1, -1, 4, 6, 6, 2, 11, -1, - 10, 39, 4, 10, 31, 35, 10, 18, 2, 13, 15, 20, 68, 2, 3, 16, - 6, 14, -1, -1, 21, 8, 8, 8, 8, 8, 2, 2, 3, 4, 2, -1, - 6, 86, 6, -1, -1, 7, -1, 6, 3, 16, 4, 4, 4, 6, 24, 26, -// #0x0140 - 22, 14, 6, 10, 23, 19, 6, 39, 8, 9, 6, 27, -1, 2, 6, 6, - 110, 6, -1, -1, -1, -1, -1, 6, -1, 54, 66, 54, 90, 42, 6, 42, - -1, -1, -1, -1, -1, 30, -1, 3, 14, 3, 30, 10, 43, 14,186,182, - 14, 30, 10, 3, -1, 6,106, -1, 4, 5, 4, -1, 6, 7, -1, -1, -// #0x0180 - 6, 3,106, 10, 10, 34, 0, 6, 8, 4, 4, 4, 29, -1, 10, 6, - 90, 86, 24, 6, 30,102, 9, 4, 8, 4, 14, 10, 4, 6, 2, 6, - 3, 3, 35, 5, 11, 26, -1, 4, 4, 6, 10, 12, 6, -1, 4, 4, - 11, 7, -1, 67, 12, 18,114, 6, 3, 6, 26, 26, 26, 26, 2, 3, -// #0x01C0 - 2, 14, 10, -1, 22, 22, 4, 2, 13, 97, 0, 9, 9, 29, 6, 28, - 8, 14, 10, 35, 6, 8, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6, - 30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1, - -1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10, -// #0x200 - 26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const unsigned int BUFFER_SIZE = 65536; - -int networkThread(void *data) -{ - Network *network = static_cast<Network*>(data); - - if (!network->realConnect()) - return -1; - - network->receive(); - - return 0; +/** + * The local host which is shared for all outgoing connections. + */ +namespace { + ENetHost *client; } -Network::Network(): - mSocket(0), - mAddress(), mPort(0), - mInBuffer(new char[BUFFER_SIZE]), - mOutBuffer(new char[BUFFER_SIZE]), - mInSize(0), mOutSize(0), - mToSkip(0), - mState(IDLE), - mWorkerThread(0) -{ - mMutex = SDL_CreateMutex(); -} +typedef std::map<unsigned short, MessageHandler*> MessageHandlers; +typedef MessageHandlers::iterator MessageHandlerIterator; +static MessageHandlers mMessageHandlers; -Network::~Network() +void Net::initialize() { - clearHandlers(); - - if (mState != IDLE && mState != ERROR) - disconnect(); - - SDL_DestroyMutex(mMutex); - - delete[] mInBuffer; - delete[] mOutBuffer; -} - -bool Network::connect(const std::string &address, short port) -{ - if (mState != IDLE && mState != ERROR) - { - logger->log("Tried to connect an already connected socket!"); - return false; - } - - if (address.empty()) + if (enet_initialize()) { - logger->log("Empty address given to Network::connect()!"); - mState = ERROR; - return false; + logger->error("Failed to initialize ENet."); } - logger->log("Network::Connecting to %s:%i", address.c_str(), port); + client = enet_host_create(NULL, 3, 0, 0); - mAddress = address; - mPort = port; - - // Reset to sane values - mOutSize = 0; - mInSize = 0; - mToSkip = 0; - - mState = CONNECTING; - mWorkerThread = SDL_CreateThread(networkThread, this); - if (!mWorkerThread) + if (!client) { - logger->log("Unable to create network worker thread"); - mState = ERROR; - return false; + logger->error("Failed to create the local host."); } - - return true; } -void Network::disconnect() +void Net::finalize() { - mState = IDLE; + if (!client) + return; // Wasn't initialized at all - if (mWorkerThread) - { - SDL_WaitThread(mWorkerThread, NULL); - mWorkerThread = NULL; + if (Net::connections) { + logger->error("Tried to shutdown the network subsystem while there " + "are network connections left!"); } - if (mSocket) - { - SDLNet_TCP_Close(mSocket); - mSocket = 0; - } + clearHandlers(); + enet_deinitialize(); } -void Network::registerHandler(MessageHandler *handler) +Net::Connection *Net::getConnection() { - const Uint16 *i = handler->handledMessages; - - while(*i) + if (!client) { - mMessageHandlers[*i] = handler; - i++; + logger->error("Tried to instantiate a network object before " + "initializing the network subsystem!"); } - handler->setNetwork(this); + return new Net::Connection(client); } -void Network::unregisterHandler(MessageHandler *handler) +void +Net::registerHandler(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 (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) - { - logger->log("Error in SDLNet_TCP_Send(): %s", SDLNet_GetError()); - mState = ERROR; + mMessageHandlers[*i] = handler; } - mOutSize = 0; - SDL_mutexV(mMutex); } -void Network::skip(int len) +void +Net::unregisterHandler(MessageHandler *handler) { - SDL_mutexP(mMutex); - mToSkip += len; - if (!mInSize) - { - SDL_mutexV(mMutex); - return; - } - - if (mInSize >= mToSkip) - { - mInSize -= mToSkip; - memmove(mInBuffer, mInBuffer + mToSkip, mInSize); - mToSkip = 0; - } - else + for (const Uint16 *i = handler->handledMessages; *i; i++) { - mToSkip -= mInSize; - mInSize = 0; + mMessageHandlers.erase(*i); } - SDL_mutexV(mMutex); } -bool Network::messageReady() +void +Net::clearHandlers() { - int len = -1; - - SDL_mutexP(mMutex); - if (mInSize >= 2) - { - len = packet_lengths[readWord(0)]; - - if (len == -1 && mInSize > 4) - len = readWord(2); - - } - - bool ret = (mInSize >= static_cast<unsigned int>(len)); - SDL_mutexV(mMutex); - - return ret; + mMessageHandlers.clear(); } -MessageIn Network::getNextMessage() -{ - while (!messageReady()) - { - if (mState == ERROR) - break; - } - - SDL_mutexP(mMutex); - int msgId = readWord(0); - int len = packet_lengths[msgId]; - - if (len == -1) - len = readWord(2); - -#ifdef DEBUG - printf("Received packet 0x%x of length %d\n", msgId, length); -#endif - - MessageIn msg(mInBuffer, len); - SDL_mutexV(mMutex); - - return msg; -} -bool Network::realConnect() +/** + * Dispatches a message to the appropriate message handler and + * destroys it afterwards. + */ +namespace { - IPaddress ipAddress; - - if (SDLNet_ResolveHost(&ipAddress, mAddress.c_str(), mPort) == -1) - { - logger->log("Error in SDLNet_ResolveHost(): %s", SDLNet_GetError()); - mState = ERROR; - return false; - } - - mState = CONNECTING; - - mSocket = SDLNet_TCP_Open(&ipAddress); - if (!mSocket) - { - logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); - mState = ERROR; - return false; - } - - logger->log("Network::Started session with %s:%i", - iptostring(ipAddress.host), ipAddress.port); - - mState = CONNECTED; - - return true; + void + dispatchMessage(ENetPacket *packet) + { + MessageIn msg((const char *)packet->data, packet->dataLength); + + MessageHandlerIterator iter = mMessageHandlers.find(msg.getId()); + + if (iter != mMessageHandlers.end()) { + logger->log("Received packet %x (%i B)", + msg.getId(), msg.getLength()); + iter->second->handleMessage(msg); + } + else { + logger->log("Unhandled packet %x (%i B)", + msg.getId(), msg.getLength()); + } + + // Clean up the packet now that we're done using it. + enet_packet_destroy(packet); + } } -void Network::receive() +void Net::flush() { - SDLNet_SocketSet set; + ENetEvent event; - if (!(set = SDLNet_AllocSocketSet(1))) + // Wait up to 10 milliseconds for an event. + while (enet_host_service(client, &event, 10) > 0) { - logger->log("Error in SDLNet_AllocSocketSet(): %s", SDLNet_GetError()); - mState = ERROR; - return; - } - - if (SDLNet_TCP_AddSocket(set, mSocket) == -1) - { - logger->log("Error in SDLNet_AddSocket(): %s", SDLNet_GetError()); - mState = ERROR; - } - - 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) + switch (event.type) { - case -1: - logger->log("Error: SDLNet_CheckSockets"); - // FALLTHROUGH - case 0: + case ENET_EVENT_TYPE_CONNECT: + logger->log("Connected."); + // Store any relevant server information here. + event.peer->data = 0; + break; + + case ENET_EVENT_TYPE_RECEIVE: + dispatchMessage(event.packet); break; - case 1: - // Receive data from the socket - SDL_mutexP(mMutex); - ret = SDLNet_TCP_Recv(mSocket, mInBuffer + mInSize, BUFFER_SIZE - mInSize); + case ENET_EVENT_TYPE_DISCONNECT: + logger->log("Disconnected."); + // Reset the server information. + event.peer->data = 0; + break; - if (!ret) - { - // We got disconnected - mState = IDLE; - logger->log("Disconnected."); - } - else if (ret < 0) - { - logger->log("Error in SDLNet_TCP_Recv(): %s", SDLNet_GetError()); - mState = ERROR; - } - 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); + case ENET_EVENT_TYPE_NONE: + logger->log("No event during 10 milliseconds."); break; default: - // more than one socket is ready.. - // this should not happen since we only listen once socket. - logger->log("Error in SDLNet_TCP_Recv(), %d sockets are ready : %s", numReady, SDLNet_GetError()); - mState = ERROR; + logger->log("Unhandled enet event."); break; } } - - if (SDLNet_TCP_DelSocket(set, mSocket) == -1) - { - logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); - } - - SDLNet_FreeSocketSet(set); -} - -char *iptostring(int address) -{ - static char asciiIP[16]; - - sprintf(asciiIP, "%i.%i.%i.%i", - (unsigned char)(address), - (unsigned char)(address >> 8), - (unsigned char)(address >> 16), - (unsigned char)(address >> 24)); - - return asciiIP; -} - -Uint16 Network::readWord(int pos) -{ -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - return SDL_Swap16((*(Uint16*)(mInBuffer+(pos)))); -#else - return (*(Uint16*)(mInBuffer+(pos))); -#endif } diff --git a/src/net/network.h b/src/net/network.h index f4637f73..9ffcbb6d 100644 --- a/src/net/network.h +++ b/src/net/network.h @@ -21,83 +21,51 @@ * $Id$ */ -#ifndef _TMW_NETWORK_ -#define _TMW_NETWORK_ +#ifndef _TMW_NET_NETWORK_H +#define _TMW_NET_NETWORK_H -#include <map> -#include <SDL_net.h> -#include <SDL_thread.h> -#include <string> +#include <iosfwd> class MessageHandler; -class MessageIn; +class MessageOut; -class Network; - -class Network +namespace Net { - public: - friend int networkThread(void *data); - friend class MessageOut; - - Network(); - ~Network(); - - bool connect(const std::string &address, short port); - void disconnect(); - - void registerHandler(MessageHandler *handler); - void unregisterHandler(MessageHandler *handler); - void clearHandlers(); - - int getState() const { return mState; } - bool isConnected() const { return mState == CONNECTED; } - - int getInSize() const { return mInSize; } - - void skip(int len); - - bool messageReady(); - MessageIn getNextMessage(); - - void dispatchMessages(); - void flush(); - - enum { - IDLE, - CONNECTED, - CONNECTING, - DATA, - ERROR - }; - - protected: - Uint16 readWord(int pos); - - TCPsocket mSocket; - - std::string mAddress; - short mPort; - - char *mInBuffer, *mOutBuffer; - unsigned int mInSize, mOutSize; - - unsigned int mToSkip; - - int mState; - - SDL_Thread *mWorkerThread; - SDL_mutex *mMutex; - - typedef std::map<Uint16, MessageHandler*> MessageHandlers; - typedef MessageHandlers::iterator MessageHandlerIterator; - MessageHandlers mMessageHandlers; - - bool realConnect(); - void receive(); -}; - -/** Convert an address from int format to string */ -char *iptostring(int address); + class Connection; + + /** + * Initializes the network subsystem. + */ + void initialize(); + + /** + * Finalizes the network subsystem. + */ + void finalize(); + + Connection *getConnection(); + + /** + * Registers a message handler. A message handler handles a certain + * subset of incoming messages. + */ + void registerHandler(MessageHandler *handler); + + /** + * Unregisters a message handler. + */ + void unregisterHandler(MessageHandler *handler); + + /** + * Clears all registered message handlers. + */ + void clearHandlers(); + + /* + * Handles all events and dispatches incoming messages to the + * registered handlers + */ + void flush(); +} #endif diff --git a/src/net/npchandler.cpp b/src/net/npchandler.cpp index a803710e..9c89e71f 100644 --- a/src/net/npchandler.cpp +++ b/src/net/npchandler.cpp @@ -47,21 +47,23 @@ NPCHandler::NPCHandler() handledMessages = _messages; } -void NPCHandler::handleMessage(MessageIn *msg) +void NPCHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { case SMSG_NPC_CHOICE: - msg->readInt16(); // length - current_npc = dynamic_cast<NPC*>(beingManager->findBeing(msg->readInt32())); - npcListDialog->parseItems(msg->readString(msg->getLength() - 8)); + msg.readShort(); // length + current_npc = dynamic_cast<NPC*>( + beingManager->findBeing(msg.readLong())); + npcListDialog->parseItems(msg.readString(msg.getLength() - 8)); npcListDialog->setVisible(true); break; case SMSG_NPC_MESSAGE: - msg->readInt16(); // length - current_npc = dynamic_cast<NPC*>(beingManager->findBeing(msg->readInt32())); - npcTextDialog->addText(msg->readString(msg->getLength() - 8)); + msg.readShort(); // length + current_npc = dynamic_cast<NPC*>( + beingManager->findBeing(msg.readLong())); + npcTextDialog->addText(msg.readString(msg.getLength() - 8)); npcListDialog->setVisible(false); npcTextDialog->setVisible(true); break; diff --git a/src/net/npchandler.h b/src/net/npchandler.h index 903ecd10..0cb40f64 100644 --- a/src/net/npchandler.h +++ b/src/net/npchandler.h @@ -31,7 +31,7 @@ class NPCHandler : public MessageHandler public: NPCHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index 3786cd0b..6eb80d59 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -46,7 +46,9 @@ OkDialog *deathNotice = NULL; namespace { struct WeightListener : public gcn::ActionListener { - void action(const std::string& eventId, gcn::Widget* widget) { weightNotice = NULL; } + void action(const std::string &eventId, gcn::Widget *widget) { + weightNotice = NULL; + } } weightListener; } @@ -56,7 +58,7 @@ namespace { // TODO Move somewhere else namespace { struct DeathListener : public gcn::ActionListener { - void action(const std::string& eventId, gcn::Widget* widget) { + void action(const std::string &eventId, gcn::Widget *widget) { player_node->revive(); deathNotice = NULL; } @@ -66,61 +68,36 @@ namespace { 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, + //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, + GPMSG_PLAYER_MAP_CHANGE, 0 }; handledMessages = _messages; } -void PlayerHandler::handleMessage(MessageIn *msg) +void PlayerHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { - case SMSG_WALK_RESPONSE: - // It is assumed by the client any request to walk actually - // succeeds on the server. The plan is to have a correction - // message when the server senses the client has the wrong - // idea. - break; - - case SMSG_PLAYER_WARP: - { - std::string mapPath = msg->readString(16); - Uint16 x = msg->readInt16(); - Uint16 y = msg->readInt16(); - - logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y); - - // Switch the actual map, deleting the previous one - engine->changeMap(mapPath); - - current_npc = 0; - - player_node->setAction(Being::STAND); - player_node->stopAttack(); - player_node->mFrame = 0; - player_node->mX = x; - player_node->mY = y; - } + case GPMSG_PLAYER_MAP_CHANGE: + handleMapChangeMessage(msg); break; case SMSG_PLAYER_STAT_UPDATE_1: { - Sint16 type = msg->readInt16(); - Uint32 value = msg->readInt32(); + Sint16 type = msg.readShort(); + Uint32 value = msg.readLong(); switch (type) { //case 0x0000: - // player_node->setWalkSpeed(msg->readInt32()); + // player_node->setWalkSpeed(msg.readLong()); // break; case 0x0005: player_node->mHp = value; break; case 0x0006: player_node->mMaxHp = value; break; @@ -169,30 +146,30 @@ void PlayerHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_STAT_UPDATE_2: - switch (msg->readInt16()) { + switch (msg.readShort()) { case 0x0001: - player_node->mXp = msg->readInt32(); + player_node->mXp = msg.readLong(); break; case 0x0002: - player_node->mJobXp = msg->readInt32(); + player_node->mJobXp = msg.readLong(); break; case 0x0014: - player_node->mGp = msg->readInt32(); + player_node->mMoney = msg.readLong(); break; case 0x0016: - player_node->mXpForNextLevel = msg->readInt32(); + player_node->mXpForNextLevel = msg.readLong(); break; case 0x0017: - player_node->mJobXpForNextLevel = msg->readInt32(); + player_node->mJobXpForNextLevel = msg.readLong(); break; } break; case SMSG_PLAYER_STAT_UPDATE_3: { - Sint32 type = msg->readInt32(); - Sint32 base = msg->readInt32(); - Sint32 bonus = msg->readInt32(); + Sint32 type = msg.readLong(); + Sint32 base = msg.readLong(); + Sint32 bonus = msg.readLong(); Sint32 total = base + bonus; switch (type) { @@ -214,9 +191,9 @@ void PlayerHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_STAT_UPDATE_4: { - Sint16 type = msg->readInt16(); - Sint8 fail = msg->readInt8(); - Sint8 value = msg->readInt8(); + Sint16 type = msg.readShort(); + Sint8 fail = msg.readByte(); + Sint8 value = msg.readByte(); if (fail != 1) break; @@ -240,60 +217,60 @@ void PlayerHandler::handleMessage(MessageIn *msg) // Updates stats and status points case SMSG_PLAYER_STAT_UPDATE_5: - player_node->mStatsPointsToAttribute = msg->readInt16(); - player_node->mAttr[LocalPlayer::STR] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::STR] = msg->readInt8(); - player_node->mAttr[LocalPlayer::AGI] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::AGI] = msg->readInt8(); - player_node->mAttr[LocalPlayer::VIT] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::VIT] = msg->readInt8(); - player_node->mAttr[LocalPlayer::INT] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::INT] = msg->readInt8(); - player_node->mAttr[LocalPlayer::DEX] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::DEX] = msg->readInt8(); - player_node->mAttr[LocalPlayer::LUK] = msg->readInt8(); - player_node->mAttrUp[LocalPlayer::LUK] = msg->readInt8(); - player_node->ATK = msg->readInt16(); // ATK - player_node->ATK_BONUS = msg->readInt16(); // ATK bonus - player_node->MATK = msg->readInt16(); // MATK max - player_node->MATK_BONUS = msg->readInt16(); // MATK min - player_node->DEF = msg->readInt16(); // DEF - player_node->DEF_BONUS = msg->readInt16(); // DEF bonus - player_node->MDEF = msg->readInt16(); // MDEF - player_node->MDEF_BONUS = msg->readInt16(); // MDEF bonus - player_node->HIT = msg->readInt16(); // HIT - player_node->FLEE = msg->readInt16(); // FLEE - player_node->FLEE_BONUS = msg->readInt16(); // FLEE bonus - msg->readInt16(); // critical - msg->readInt16(); // unknown + player_node->mStatsPointsToAttribute = msg.readShort(); + player_node->mAttr[LocalPlayer::STR] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::STR] = msg.readByte(); + player_node->mAttr[LocalPlayer::AGI] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::AGI] = msg.readByte(); + player_node->mAttr[LocalPlayer::VIT] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::VIT] = msg.readByte(); + player_node->mAttr[LocalPlayer::INT] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::INT] = msg.readByte(); + player_node->mAttr[LocalPlayer::DEX] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::DEX] = msg.readByte(); + player_node->mAttr[LocalPlayer::LUK] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::LUK] = msg.readByte(); + player_node->ATK = msg.readShort(); // ATK + player_node->ATK_BONUS = msg.readShort(); // ATK bonus + player_node->MATK = msg.readShort(); // MATK max + player_node->MATK_BONUS = msg.readShort(); // MATK min + player_node->DEF = msg.readShort(); // DEF + player_node->DEF_BONUS = msg.readShort(); // DEF bonus + player_node->MDEF = msg.readShort(); // MDEF + player_node->MDEF_BONUS = msg.readShort(); // MDEF bonus + player_node->HIT = msg.readShort(); // HIT + player_node->FLEE = msg.readShort(); // FLEE + player_node->FLEE_BONUS = msg.readShort(); // FLEE bonus + msg.readShort(); // critical + msg.readShort(); // unknown break; case SMSG_PLAYER_STAT_UPDATE_6: - switch (msg->readInt16()) { + switch (msg.readShort()) { case 0x0020: - player_node->mAttrUp[LocalPlayer::STR] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::STR] = msg.readByte(); break; case 0x0021: - player_node->mAttrUp[LocalPlayer::AGI] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::AGI] = msg.readByte(); break; case 0x0022: - player_node->mAttrUp[LocalPlayer::VIT] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::VIT] = msg.readByte(); break; case 0x0023: - player_node->mAttrUp[LocalPlayer::INT] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::INT] = msg.readByte(); break; case 0x0024: - player_node->mAttrUp[LocalPlayer::DEX] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::DEX] = msg.readByte(); break; case 0x0025: - player_node->mAttrUp[LocalPlayer::LUK] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::LUK] = msg.readByte(); break; } break; case SMSG_PLAYER_ARROW_MESSAGE: { - Sint16 type = msg->readInt16(); + Sint16 type = msg.readShort(); switch (type) { case 0: @@ -306,18 +283,38 @@ void PlayerHandler::handleMessage(MessageIn *msg) } } break; + } +} + +void +PlayerHandler::handleMapChangeMessage(MessageIn &msg) +{ + // { "mapname", x, y, B new server [, token, "gameserver", W port] } + + std::string mapName = msg.readString(); + unsigned short x = msg.readShort(); + unsigned short y = msg.readShort(); + unsigned char newServer = msg.readByte(); + + logger->log("Changing map to %s (%d, %d) on %s server", + mapName.c_str(), x, y, (newServer) ? "another" : "same"); - //Stop walking - //case 0x0088: // Disabled because giving some problems - //if (being = beingManager->findBeing(readInt32(2))) { - // if (being->getId() != player_node->getId()) { - // being->action = STAND; - // being->mFrame = 0; - // set_coordinates(being->coordinates, - // readWord(6), readWord(8), - // get_direction(being->coordinates)); - // } - //} - //break; + // Switch the actual map, deleting the previous one + engine->changeMap(mapName); + + current_npc = 0; + + player_node->setAction(Being::STAND); + player_node->stopAttack(); + + player_node->mX = x; + player_node->mY = y; + + if (newServer) + { + // TODO: Implement reconnecting to another game server + //std::string token = msg.readString(32); + //std::string gameServer = msg.readString(); + //unsigned short gameServerPort = msg.readShort(); } } diff --git a/src/net/playerhandler.h b/src/net/playerhandler.h index b28a23f5..9b6c9e01 100644 --- a/src/net/playerhandler.h +++ b/src/net/playerhandler.h @@ -31,7 +31,12 @@ class PlayerHandler : public MessageHandler public: PlayerHandler(); - void handleMessage(MessageIn *msg); + void + handleMessage(MessageIn &msg); + + private: + void + handleMapChangeMessage(MessageIn &msg); }; #endif diff --git a/src/net/protocol.cpp b/src/net/protocol.cpp deleted file mode 100644 index d3db50bf..00000000 --- a/src/net/protocol.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#include "protocol.h" - -#define LOBYTE(w) ((unsigned char)(w)) -#define HIBYTE(w) ((unsigned char)(((unsigned short)(w)) >> 8)) - -void set_coordinates(char *data, - unsigned short x, - unsigned short y, - unsigned char direction) -{ - 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; -} diff --git a/src/net/protocol.h b/src/net/protocol.h index 72b459ed..07b5c926 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -104,7 +104,147 @@ #define CMSG_PLAYER_EQUIP 0x00a9 #define CMSG_PLAYER_UNEQUIP 0x00ab -/** Encodes coords and direction in 3 bytes data */ -void set_coordinates(char *data, unsigned short x, unsigned short y, unsigned char direction); +/** + * Enumerated type for communicated messages + * - PAMSG_*: from client to account server + * - APMSG_*: from account server to client + * - PCMSG_*: from client to chat server + * - CPMSG_*: from chat server to client + * - PGMSG_*: from client to game server + * - GPMSG_*: from game server to client + * Components: B byte, W word, D double word, S variable-size string + * C tile-based coordinates (B*3) + */ +enum { + // Login/Register + PAMSG_REGISTER = 0x0000, // L version, S username, S password, S email + APMSG_REGISTER_RESPONSE = 0x0002, // B error + PAMSG_UNREGISTER = 0x0003, // - + APMSG_UNREGISTER_RESPONSE = 0x0004, // B error + PAMSG_LOGIN = 0x0010, // L version, S username, S password + APMSG_LOGIN_RESPONSE = 0x0012, // B error + PAMSG_LOGOUT = 0x0013, // - + APMSG_LOGOUT_RESPONSE = 0x0014, // B error + PAMSG_CHAR_CREATE = 0x0020, // S name, B hair style, B hair color, B gender, W*6 stats + APMSG_CHAR_CREATE_RESPONSE = 0x0021, // B error + PAMSG_CHAR_DELETE = 0x0022, // B index + APMSG_CHAR_DELETE_RESPONSE = 0x0023, // B error + APMSG_CHAR_INFO = 0x0024, // B index, S name, B gender, B hair style, B hair color, B level, W money, W*6 stats, S mapname, W*2 position + APMSG_CHAR_LIST_RESPONSE = 0x0025, // B number, { B index, S name, B gender, B hair style, B hair color, B level, W money, W*6 stats, S mapname, W*2 position }* + PAMSG_CHAR_SELECT = 0x0026, // B index + APMSG_CHAR_SELECT_RESPONSE = 0x0027, // B error, S mapname, W*2 position + PAMSG_EMAIL_CHANGE = 0x0030, // S email + APMSG_EMAIL_CHANGE_RESPONSE = 0x0031, // B error + PAMSG_EMAIL_GET = 0x0032, // - + APMSG_EMAIL_GET_RESPONSE = 0x0033, // B error, S email + PAMSG_PASSWORD_CHANGE = 0x0034, // S old password, S new password + APMSG_PASSWORD_CHANGE_RESPONSE = 0x0035, // B error + PAMSG_ENTER_WORLD = 0x0040, // - + APMSG_ENTER_WORLD_RESPONSE = 0x0041, // B error, S address, W port, B*32 token + PAMSG_ENTER_CHAT = 0x0042, // - + APMSG_ENTER_CHAT_RESPONSE = 0x0043, // B error, S address, W port, B*32 token + PGMSG_CONNECT = 0x0050, // B*32 token + GPMSG_CONNECT_RESPONSE = 0x0051, // B error + PCMSG_CONNECT = 0x0053, // B*32 token + CPMSG_CONNECT_RESPONSE = 0x0054, // B error + + // Game + GPMSG_PLAYER_MAP_CHANGE = 0x0100, // S filename, W x, W y, B newserv + // [, S32 token, S server, W port] + PGMSG_PICKUP = 0x0110, + GPMSG_PICKUP_RESPONSE = 0x0111, + GPMSG_BEING_ENTER = 0x0200, // B type, W being id + // player: S name, B hair style, B hair color, B gender + // monster: W type id + GPMSG_BEING_LEAVE = 0x0201, // W being id + PGMSG_WALK = 0x0260, // W*2 destination + GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position] [, W*2 destination] }* + PGMSG_SAY = 0x02A0, // S text + GPMSG_SAY = 0x02A1, // W being id, S text + PGMSG_USE_ITEM = 0x0300, // L item id + GPMSG_USE_RESPONSE = 0x0301, // B error + PGMSG_EQUIP = 0x0302, // L item id, B slot + GPMSG_EQUIP_RESPONSE = 0x0303, // B error + + // Chat + CPMSG_ERROR = 0x0401, // B error + CPMSG_ANNOUNCEMENT = 0x0402, // S text + CPMSG_PRIVMSG = 0x0403, // S user, S text + CPMSG_PUBMSG = 0x0404, // W channel, S user, S text + PCMSG_CHAT = 0x0410, // S text, W channel + PCMSG_ANNOUNCE = 0x0411, // S text + PCMSG_PRIVMSG = 0x0412, // S user, S text + // -- Channeling + PCMSG_REGISTER_CHANNEL = 0x0413, // B pub/priv, S name, S announcement, S password + CPMSG_REGISTER_CHANNEL_RESPONSE = 0x0414, // B error + PCMSG_UNREGISTER_CHANNEL = 0x0415, // W channel + CPMSG_UNREGISTER_CHANNEL_RESPONSE = 0x0416, // B error + CPMSG_CHANNEL_EVENT = 0x0418, // W channel, B event, S user + PCMSG_ENTER_CHANNEL = 0x0419, // W channel, S password + CPMSG_ENTER_CHANNEL_RESPONSE = 0x0420, // B error + PCMSG_QUIT_CHANNEL = 0x0421, // W channel + CPMSG_QUIT_CHANNEL_RESPONSE = 0x0422, // B error + + XXMSG_INVALID = 0x7FFF +}; + +// Generic return values + +enum { + ERRMSG_OK = 0, // everything is fine + ERRMSG_FAILURE, // the action failed + ERRMSG_NO_LOGIN, // the user is not yet logged + ERRMSG_NO_CHARACTER_SELECTED, // the user needs a character + ERRMSG_INSUFFICIENT_RIGHTS, // the user is not privileged + ERRMSG_INVALID_ARGUMENT // part of the received message was invalid +}; + +// Login specific return values +enum { + LOGIN_INVALID_VERSION = 0x40, // the user is using an incompatible protocol + LOGIN_SERVER_FULL // the server is overloaded +}; + +// Account register specific return values +enum { + REGISTER_INVALID_VERSION = 0x40, // the user is using an incompatible protocol + REGISTER_EXISTS_USERNAME, // there already is an account with this username + REGISTER_EXISTS_EMAIL // there already is an account with this email address +}; + +// Character creation specific return values +enum { + CREATE_INVALID_HAIRSTYLE = 0x40, + CREATE_INVALID_HAIRCOLOR, + CREATE_INVALID_GENDER, + CREATE_RAW_STATS_TOO_HIGH, + CREATE_RAW_STATS_TOO_LOW, + CREATE_RAW_STATS_INVALID_DIFF, + CREATE_RAW_STATS_EQUAL_TO_ZERO, + CREATE_EXISTS_NAME, + CREATE_TOO_MUCH_CHARACTERS +}; + +// Object type enumeration +enum { + // A simple item + OBJECT_ITEM = 0, + // An item that can be activated (doors, switchs, sign, ...) + OBJECT_ACTOR, + // Non-Playable-Character is an actor capable of movement and maybe actions + OBJECT_NPC, + // A monster (moving actor with AI. able to toggle map/quest actions, too) + OBJECT_MONSTER, + // A player + OBJECT_PLAYER +}; + +// Moving object flags +enum { + // Payload contains the current position. + MOVING_POSITION = 1, + // Payload contains the destination. + MOVING_DESTINATION = 2 +}; #endif diff --git a/src/net/skillhandler.cpp b/src/net/skillhandler.cpp index e9dc9c19..d9bea775 100644 --- a/src/net/skillhandler.cpp +++ b/src/net/skillhandler.cpp @@ -39,27 +39,27 @@ SkillHandler::SkillHandler() handledMessages = _messages; } -void SkillHandler::handleMessage(MessageIn *msg) +void SkillHandler::handleMessage(MessageIn &msg) { int skillCount; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_PLAYER_SKILLS: - msg->readInt16(); // length - skillCount = (msg->getLength() - 4) / 37; + msg.readShort(); // length + skillCount = (msg.getLength() - 4) / 37; skillDialog->cleanList(); for (int k = 0; k < skillCount; k++) { - Sint16 skillId = msg->readInt16(); - msg->readInt16(); // target type - msg->readInt16(); // unknown - Sint16 level = msg->readInt16(); - Sint16 sp = msg->readInt16(); - msg->readInt16(); // range - std::string skillName = msg->readString(24); - Sint8 up = msg->readInt8(); + Sint16 skillId = msg.readShort(); + msg.readShort(); // target type + msg.readShort(); // unknown + Sint16 level = msg.readShort(); + Sint16 sp = msg.readShort(); + msg.readShort(); // range + std::string skillName = msg.readString(24); + Sint8 up = msg.readByte(); if (level != 0 || up != 0) { @@ -77,11 +77,11 @@ void SkillHandler::handleMessage(MessageIn *msg) // Action failed (ex. sit because you have not reached the // right level) CHATSKILL action; - action.skill = msg->readInt16(); - action.bskill = msg->readInt16(); - action.unused = msg->readInt16(); // unknown - action.success = msg->readInt8(); - action.reason = msg->readInt8(); + action.skill = msg.readShort(); + action.bskill = msg.readShort(); + action.unused = msg.readShort(); // unknown + action.success = msg.readByte(); + action.reason = msg.readByte(); if (action.success != SKILL_FAILED && action.bskill == BSKILL_EMOTE) { diff --git a/src/net/skillhandler.h b/src/net/skillhandler.h index 820a7b6a..8c0653d4 100644 --- a/src/net/skillhandler.h +++ b/src/net/skillhandler.h @@ -31,7 +31,7 @@ class SkillHandler : public MessageHandler public: SkillHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/tradehandler.cpp b/src/net/tradehandler.cpp index 8f9788a2..2ebc160f 100644 --- a/src/net/tradehandler.cpp +++ b/src/net/tradehandler.cpp @@ -41,7 +41,7 @@ std::string tradePartnerName; namespace { struct RequestTradeListener : public gcn::ActionListener { - void action(const std::string& eventId, gcn::Widget* widget) + void action(const std::string &eventId, gcn::Widget *widget) { player_node->tradeReply(eventId == "yes"); }; @@ -63,9 +63,9 @@ TradeHandler::TradeHandler() handledMessages = _messages; } -void TradeHandler::handleMessage(MessageIn *msg) +void TradeHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { case SMSG_TRADE_REQUEST: // If a trade window or request window is already open, send a @@ -81,7 +81,7 @@ void TradeHandler::handleMessage(MessageIn *msg) } player_node->setTrading(true); - tradePartnerName = msg->readString(24); + tradePartnerName = msg.readString(24); ConfirmDialog *dlg; dlg = new ConfirmDialog("Request for trade", tradePartnerName + @@ -90,7 +90,7 @@ void TradeHandler::handleMessage(MessageIn *msg) break; case SMSG_TRADE_RESPONSE: - switch (msg->readInt8()) + switch (msg.readByte()) { case 0: // Too far away chatWindow->chatLog("Trading isn't possible. " @@ -126,12 +126,11 @@ void TradeHandler::handleMessage(MessageIn *msg) case SMSG_TRADE_ITEM_ADD: { - Sint32 amount = msg->readInt32(); - Sint16 type = msg->readInt16(); - msg->readInt8(); // identified flag - msg->readInt8(); // attribute - msg->readInt8(); // refine - msg->skip(8); // card (4 shorts) + Sint32 amount = msg.readLong(); + Sint16 type = msg.readShort(); + msg.readByte(); // identified flag + msg.readByte(); // attribute + msg.readByte(); // refine // TODO: handle also identified, etc if (type == 0) { @@ -145,10 +144,10 @@ void TradeHandler::handleMessage(MessageIn *msg) case SMSG_TRADE_ITEM_ADD_RESPONSE: // Trade: New Item add response (was 0x00ea, now 01b1) { - Item *item = player_node->getInvItem(msg->readInt16()); - Sint16 quantity = msg->readInt16(); + Item *item = player_node->getInvItem(msg.readShort()); + Sint16 quantity = msg.readShort(); - switch (msg->readInt8()) + switch (msg.readByte()) { case 0: // Successfully added item @@ -176,7 +175,7 @@ void TradeHandler::handleMessage(MessageIn *msg) case SMSG_TRADE_OK: // 0 means ok from myself, 1 means ok from other; - tradeWindow->receivedOk(msg->readInt8() == 0); + tradeWindow->receivedOk(msg.readByte() == 0); break; case SMSG_TRADE_CANCEL: diff --git a/src/net/tradehandler.h b/src/net/tradehandler.h index a1971004..1ab3c2e4 100644 --- a/src/net/tradehandler.h +++ b/src/net/tradehandler.h @@ -26,14 +26,12 @@ #include "messagehandler.h" -class Network; - class TradeHandler : public MessageHandler { public: TradeHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/npc.cpp b/src/npc.cpp index 6fa5ac37..3bd4371b 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -25,16 +25,13 @@ #include "animatedsprite.h" -#include "net/messageout.h" -#include "net/protocol.h" - class Spriteset; extern Spriteset *npcset; NPC *current_npc = 0; -NPC::NPC(Uint32 id, Uint16 job, Map *map, Network *network): - Being(id, job, map), mNetwork(network) +NPC::NPC(Uint16 id, Uint16 job, Map *map): + Being(id, job, map) { mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/npc.xml", job-100); } @@ -48,28 +45,34 @@ NPC::getType() const void NPC::talk() { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_NPC_TALK); - outMsg.writeInt32(mId); - outMsg.writeInt8(0); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_NPC_TALK); + outMsg.writeLong(mId); + outMsg.writeByte(0); current_npc = this; + */ } void NPC::nextDialog() { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_NPC_NEXT_REQUEST); - outMsg.writeInt32(mId); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_NPC_NEXT_REQUEST); + outMsg.writeLong(mId); + */ } void NPC::dialogChoice(char choice) { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_NPC_LIST_CHOICE); - outMsg.writeInt32(mId); - outMsg.writeInt8(choice); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_NPC_LIST_CHOICE); + outMsg.writeLong(mId); + outMsg.writeByte(choice); + */ } /* @@ -79,17 +82,21 @@ NPC::dialogChoice(char choice) void NPC::buy() { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST); - outMsg.writeInt32(mId); - outMsg.writeInt8(0); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST); + outMsg.writeLong(mId); + outMsg.writeByte(0); + */ } void NPC::sell() { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST); - outMsg.writeInt32(mId); - outMsg.writeInt8(1); + // XXX Convert for new server + /* + MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST); + outMsg.writeLong(mId); + outMsg.writeByte(1); + */ } @@ -26,12 +26,10 @@ #include "being.h" -class Network; - class NPC : public Being { public: - NPC(Uint32 id, Uint16 job, Map *map, Network *network); + NPC(Uint16 id, Uint16 job, Map *map); virtual Type getType() const; @@ -41,9 +39,6 @@ class NPC : public Being void buy(); void sell(); - - protected: - Network *mNetwork; }; extern NPC *current_npc; diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp index 2a6c931d..05bbb6b3 100644 --- a/src/openglgraphics.cpp +++ b/src/openglgraphics.cpp @@ -21,6 +21,8 @@ * $Id$ */ +#include "main.h" + #ifdef USE_OPENGL #include "openglgraphics.h" diff --git a/src/player.cpp b/src/player.cpp index 3f0ebfc4..12f5f3d5 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -26,43 +26,20 @@ #include "animatedsprite.h" #include "game.h" #include "graphics.h" +#include "log.h" #include "utils/tostring.h" #include "gui/gui.h" -Player::Player(Uint32 id, Uint16 job, Map *map): +Player::Player(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { - // Load the weapon sprite. - // When there are more different weapons this should be moved to the - // setWeapon Method. - setWeapon(0); -} - -void -Player::logic() -{ - switch (mAction) { - case WALK: - mFrame = (get_elapsed_time(mWalkTime) * 6) / mWalkSpeed; - if (mFrame >= 6) { - nextStep(); - } - break; - case ATTACK: - int frames = 4; - if (getWeapon() == 2) - { - frames = 5; - } - mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed; - if (mFrame >= frames) { - nextStep(); - } - break; - } - Being::logic(); + /* Load the weapon sprite. When there are more different weapons this + * should be moved to the setWeapon Method. + */ + mSprites[WEAPON_SPRITE] = + new AnimatedSprite("graphics/sprites/weapons.xml", 0); } Being::Type @@ -85,6 +62,13 @@ Player::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) void Player::setSex(Uint8 sex) { + // Players can only be male or female + if (sex > 1) + { + logger->log("Warning: unsupported gender %i, assuming male.", sex); + sex = 0; + } + if (sex != mSex) { delete mSprites[BASE_SPRITE]; @@ -98,48 +82,20 @@ Player::setSex(Uint8 sex) mSprites[BASE_SPRITE] = new AnimatedSprite( "graphics/sprites/player_female_base.xml", 0); } - resetAnimations(); - } - Being::setSex(sex); -} - -void -Player::setWeapon(Uint16 weapon) -{ - if (weapon != mWeapon) - { - delete mSprites[WEAPON_SPRITE]; - mSprites[WEAPON_SPRITE] = NULL; - - switch (weapon) - { - case 0: - mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-fist.xml", 0); - break; - case 1: - mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-dagger.xml", 0); - break; - case 2: - mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-bow.xml", 0); - break; - case 3: - mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-scythe.xml", 0); - break; - } + Being::setSex(sex); + resetAnimations(); } - Being::setWeapon(weapon); } - void Player::setHairColor(Uint16 color) { - if (color != mHairColor && mHairStyle > 0) + if (color != mHairColor) { AnimatedSprite *newHairSprite = new AnimatedSprite( "graphics/sprites/hairstyle" + toString(mHairStyle) + ".xml", - color - 1); + color); newHairSprite->setDirection(getSpriteDirection()); delete mSprites[HAIR_SPRITE]; @@ -155,11 +111,11 @@ Player::setHairColor(Uint16 color) void Player::setHairStyle(Uint16 style) { - if (style != mHairStyle && mHairColor > 0) + if (style != mHairStyle) { AnimatedSprite *newHairSprite = new AnimatedSprite( "graphics/sprites/hairstyle" + toString(style) + ".xml", - mHairColor - 1); + mHairColor); newHairSprite->setDirection(getSpriteDirection()); delete mSprites[HAIR_SPRITE]; diff --git a/src/player.h b/src/player.h index e23110be..6ff4babe 100644 --- a/src/player.h +++ b/src/player.h @@ -35,10 +35,10 @@ class AnimatedSprite; class Player : public Being { public: - Player(Uint32 id, Uint16 job, Map *map); - - virtual void - logic(); + /** + * Constructor. + */ + Player(Uint16 id, Uint16 job, Map *map); virtual Type getType() const; @@ -58,9 +58,6 @@ class Player : public Being virtual void setVisibleEquipment(Uint8 slot, Uint8 id); - virtual void - setWeapon(Uint16 weapon); - private: /** * Resets all animations associated with this player. This is used to diff --git a/src/resources/image.h b/src/resources/image.h index c769ecb6..a1ab7f48 100644 --- a/src/resources/image.h +++ b/src/resources/image.h @@ -24,6 +24,8 @@ #ifndef _TMW_IMAGE_H #define _TMW_IMAGE_H +#include "../main.h" + #include <SDL.h> #ifdef USE_OPENGL diff --git a/src/resources/openglsdlimageloader.cpp b/src/resources/openglsdlimageloader.cpp index c7ddec74..b3e1601e 100644 --- a/src/resources/openglsdlimageloader.cpp +++ b/src/resources/openglsdlimageloader.cpp @@ -21,14 +21,16 @@ * $Id: sdlimageloader.cpp 2121 2006-01-31 02:55:26Z der_doener $ */ -#ifdef USE_OPENGL - #include "openglsdlimageloader.h" #include <string> #include "resourcemanager.h" +#include "../main.h" + +#ifdef USE_OPENGL + SDL_Surface* OpenGLSDLImageLoader::loadSDLSurface(const std::string& filename) { ResourceManager *resman = ResourceManager::getInstance(); diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index e729ecfc..23a73497 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -73,7 +73,10 @@ void ResourceManager::cleanUp(Resource *res) { logger->log("ResourceManager::~ResourceManager() cleaning up %d " - "references to %s", res->mRefCount, res->mIdPath.c_str()); + "reference%s to %s", + res->mRefCount, + (res->mRefCount == 1) ? "" : "s", + res->mIdPath.c_str()); delete res; } @@ -119,9 +122,13 @@ ResourceManager::get(const E_RESOURCE_TYPE &type, const std::string &idPath) return resIter->second; } + logger->log("ResourceManager::get(%s)", idPath.c_str()); + int fileSize; void *buffer = loadFile(idPath, fileSize); + if (!buffer) { + logger->log("Warning: resource doesn't exist!"); return NULL; } @@ -258,10 +265,6 @@ ResourceManager::loadFile(const std::string &fileName, int &fileSize) return NULL; } - // Log the real dir of the file - logger->log("Loaded %s/%s", PHYSFS_getRealDir(fileName.c_str()), - fileName.c_str()); - // Get the size of the file fileSize = PHYSFS_fileLength(file); diff --git a/src/sound.cpp b/src/sound.cpp index 8b012176..182be3d6 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -208,6 +208,6 @@ void Sound::close() stopMusic(); mInstalled = false; - Mix_CloseAudio(); logger->log("Sound::close() Shutting down sound..."); + Mix_CloseAudio(); } @@ -7,8 +7,8 @@ A ICON MOVEABLE PURE LOADONCALL DISCARDABLE "data/icons/tmw-icon.ico" // TO CHANGE VERSION INFORMATION, EDIT PROJECT OPTIONS...
//
1 VERSIONINFO
-FILEVERSION 0,0,21,1
-PRODUCTVERSION 0,0,21,1
+FILEVERSION 0,1,0,0
+PRODUCTVERSION 0,1,0,0
FILETYPE VFT_APP
{
BLOCK "StringFileInfo"
@@ -16,14 +16,14 @@ FILETYPE VFT_APP BLOCK "040904E4"
{
VALUE "CompanyName", "The Mana World Development Team"
- VALUE "FileVersion", "0.0.21.1"
+ VALUE "FileVersion", "0.1.0"
VALUE "FileDescription", "The Mana World"
VALUE "InternalName", "tmw.exe"
VALUE "LegalCopyright", "2004-2006 (C)"
VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "tmw.exe"
VALUE "ProductName", "The Mana World MMORPG"
- VALUE "ProductVersion", "0.0.21.1"
+ VALUE "ProductVersion", "0.1.0"
}
}
BLOCK "VarFileInfo"
|