diff options
Diffstat (limited to 'src')
463 files changed, 21798 insertions, 4944 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0176e617..4fa61ca7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,13 +2,15 @@ FIND_PACKAGE(SDL REQUIRED) FIND_PACKAGE(SDL_image REQUIRED) FIND_PACKAGE(SDL_mixer REQUIRED) FIND_PACKAGE(SDL_net REQUIRED) +FIND_PACKAGE(SDL_ttf REQUIRED) +FIND_PACKAGE(ENet REQUIRED) FIND_PACKAGE(CURL REQUIRED) FIND_PACKAGE(LibXml2 REQUIRED) FIND_PACKAGE(PhysFS REQUIRED) FIND_PACKAGE(PNG REQUIRED) SET(FLAGS "-DPACKAGE_VERSION=\\\"${VERSION}\\\"") -SET(FLAGS "${FLAGS} -DAETHYRA_DATADIR=\\\"${PKG_DATADIR}/\\\"") +SET(FLAGS "${FLAGS} -DTMW_DATADIR=\\\"${PKG_DATADIR}/\\\"") SET(GUICHAN_COMPONENTS "SDL") IF (WITH_OPENGL) @@ -28,6 +30,8 @@ INCLUDE_DIRECTORIES( ${SDLIMAGE_INCLUDE_DIR} ${SDLMIXER_INCLUDE_DIR} ${SDLNET_INCLUDE_DIR} + ${SDLTTF_INCLUDE_DIR} + ${ENET_INCLUDE_DIR} ${PNG_INCLUDE_DIR} ${PHYSFS_INCLUDE_DIR} ${CURL_INCLUDE_DIR} @@ -49,6 +53,8 @@ MARK_AS_ADVANCED(SDL_INCLUDE_DIR) MARK_AS_ADVANCED(SDL_LIBRARY) SET(SRCS + gui/widgets/avatar.cpp + gui/widgets/avatar.h gui/widgets/dropdown.cpp gui/widgets/dropdown.h gui/widgets/resizegrip.cpp @@ -71,6 +77,10 @@ SET(SRCS gui/buy.h gui/buysell.cpp gui/buysell.h + gui/changeemaildialog.cpp + gui/changeemaildialog.h + gui/changepassworddialog.cpp + gui/changepassworddialog.h gui/char_server.cpp gui/char_server.h gui/char_select.cpp @@ -101,8 +111,14 @@ SET(SRCS gui/gccontainer.h gui/gui.cpp gui/gui.h + gui/guildlistbox.cpp + gui/guildlistbox.h + gui/guildwindow.cpp + gui/guildwindow.h gui/help.cpp gui/help.h + gui/icon.cpp + gui/icon.h gui/inttextfield.cpp gui/inttextfield.h gui/inventorywindow.cpp @@ -124,6 +140,8 @@ SET(SRCS gui/listbox.h gui/login.cpp gui/login.h + gui/magic.cpp + gui/magic.h gui/menuwindow.cpp gui/menuwindow.h gui/minimap.cpp @@ -136,12 +154,16 @@ SET(SRCS gui/npclistdialog.h gui/npcstringdialog.cpp gui/npcstringdialog.h + gui/npcpostdialog.cpp + gui/npcpostdialog.h gui/npc_text.cpp gui/npc_text.h gui/ok_dialog.cpp gui/ok_dialog.h gui/palette.cpp gui/palette.h + gui/partywindow.h + gui/partywindow.cpp gui/passwordfield.cpp gui/passwordfield.h gui/playerbox.cpp @@ -152,6 +174,8 @@ SET(SRCS gui/popupmenu.h gui/progressbar.cpp gui/progressbar.h + gui/quitdialog.cpp + gui/quitdialog.h gui/radiobutton.cpp gui/radiobutton.h gui/recorder.cpp @@ -164,6 +188,8 @@ SET(SRCS gui/sdlinput.h gui/sell.cpp gui/sell.h + gui/serverdialog.cpp + gui/serverdialog.h gui/setup.cpp gui/setup.h gui/setup_audio.cpp @@ -205,6 +231,8 @@ SET(SRCS gui/table_model.h gui/textbox.cpp gui/textbox.h + gui/textdialog.cpp + gui/textdialog.h gui/textfield.cpp gui/textfield.h gui/textrenderer.h @@ -212,30 +240,40 @@ SET(SRCS gui/trade.h gui/truetypefont.cpp gui/truetypefont.h - gui/updatewindow.h + gui/unregisterdialog.cpp + gui/unregisterdialog.h gui/updatewindow.cpp + gui/updatewindow.h gui/viewport.cpp gui/viewport.h gui/window.cpp gui/window.h gui/windowcontainer.cpp gui/windowcontainer.h - net/beinghandler.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/guildhandler.cpp + net/guildhandler.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/loginhandler.h + net/logouthandler.cpp + net/logouthandler.h net/maploginhandler.cpp net/maploginhandler.h net/messagehandler.cpp @@ -258,6 +296,28 @@ SET(SRCS net/skillhandler.h net/tradehandler.cpp net/tradehandler.h + net/effecthandler.cpp + net/effecthandler.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/guild.cpp + net/chatserver/guild.h + net/chatserver/internal.cpp + net/chatserver/internal.h + net/chatserver/party.cpp + net/chatserver/party.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/action.cpp resources/action.h resources/ambientoverlay.cpp @@ -305,6 +365,8 @@ SET(SRCS utils/dtor.h utils/fastsqrt.h utils/gettext.h + utils/sha256.h + utils/sha256.cpp utils/stringutils.cpp utils/stringutils.h utils/strprintf.cpp @@ -319,6 +381,12 @@ SET(SRCS being.h beingmanager.cpp beingmanager.h + channel.cpp + channel.h + channelmanager.cpp + channelmanager.h + commandhandler.cpp + commandhandler.h configlistener.h configuration.cpp configuration.h @@ -339,6 +407,8 @@ SET(SRCS graphics.cpp graphics.h guichanfwd.h + guild.cpp + guild.h imageparticle.cpp imageparticle.h inventory.cpp @@ -398,17 +468,23 @@ SET(SRCS textparticle.cpp textparticle.h tileset.h + units.cpp + units.h vector.cpp vector.h + effectmanager.cpp + effectmanager.h ) -ADD_EXECUTABLE(aethyra ${SRCS}) +ADD_EXECUTABLE(tmw ${SRCS}) -TARGET_LINK_LIBRARIES(aethyra +TARGET_LINK_LIBRARIES(tmw ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${SDLMIXER_LIBRARY} ${SDLNET_LIBRARY} + ${SDLTTF_LIBRARY} + ${ENET_LIBRARIES} ${PNG_LIBRARIES} ${PHYSFS_LIBRARY} ${CURL_LIBRARIES} @@ -417,6 +493,6 @@ TARGET_LINK_LIBRARIES(aethyra ${OPENGL_LIBRARIES} ) -INSTALL(TARGETS aethyra RUNTIME DESTINATION ${PKG_BINDIR}) +INSTALL(TARGETS tmw RUNTIME DESTINATION ${PKG_BINDIR}) -SET_TARGET_PROPERTIES(aethyra PROPERTIES COMPILE_FLAGS "${FLAGS}") +SET_TARGET_PROPERTIES(tmw PROPERTIES COMPILE_FLAGS "${FLAGS}") diff --git a/src/Makefile.am b/src/Makefile.am index 5029697a..4c5893ac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,8 +1,18 @@ AUTOMAKE_OPTIONS = subdir-objects -bin_PROGRAMS = aethyra -aethyra_SOURCES = gui/widgets/dropdown.cpp \ - gui/widgets/dropdown.h \ +bin_PROGRAMS = tmw + +tmw_CXXFLAGS = -DPKG_DATADIR=\""$(pkgdatadir)/"\" \ + -DLOCALEDIR=\""$(localedir)"\" + +tmw_SOURCES = gui/widgets/avatar.cpp \ + gui/widgets/avatar.h \ + gui/widgets/channeltab.cpp \ + gui/widgets/channeltab.h \ + gui/widgets/chattab.cpp \ + gui/widgets/chattab.h \ + gui/widgets/dropdown.cpp \ + gui/widgets/dropdown.h \ gui/widgets/layout.cpp \ gui/widgets/layout.h \ gui/widgets/layouthelper.cpp \ @@ -15,6 +25,8 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ gui/widgets/tabbedarea.h \ gui/widgets/textpreview.cpp \ gui/widgets/textpreview.h \ + gui/widgets/whispertab.cpp \ + gui/widgets/whispertab.h \ gui/browserbox.cpp \ gui/browserbox.h \ gui/button.cpp \ @@ -25,8 +37,6 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ gui/buysell.h \ gui/char_select.cpp \ gui/char_select.h \ - gui/char_server.cpp \ - gui/char_server.h \ gui/chat.cpp \ gui/chat.h \ gui/chatinput.cpp \ @@ -35,8 +45,6 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ gui/checkbox.h \ gui/confirm_dialog.cpp \ gui/confirm_dialog.h \ - gui/connection.cpp \ - gui/connection.h \ gui/debugwindow.cpp \ gui/debugwindow.h \ gui/emotecontainer.cpp \ @@ -55,8 +63,10 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ gui/gui.h \ gui/help.cpp \ gui/help.h \ - gui/inttextfield.h \ + gui/icon.cpp \ + gui/icon.h \ gui/inttextfield.cpp \ + gui/inttextfield.h \ gui/inventorywindow.cpp \ gui/inventorywindow.h \ gui/itemcontainer.cpp \ @@ -106,8 +116,8 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ gui/progressbar.h \ gui/radiobutton.cpp \ gui/radiobutton.h \ - gui/recorder.cpp \ - gui/recorder.h \ + gui/recorder.cpp \ + gui/recorder.h \ gui/register.cpp \ gui/register.h \ gui/scrollarea.cpp \ @@ -139,24 +149,20 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ gui/shortcutwindow.h \ gui/shortcutcontainer.cpp \ gui/shortcutcontainer.h \ - gui/skill.cpp \ - gui/skill.h \ gui/skin.cpp \ gui/skin.h \ gui/slider.cpp \ gui/slider.h \ gui/speechbubble.cpp \ gui/speechbubble.h \ - gui/status.cpp \ - gui/status.h \ - gui/storagewindow.cpp \ - gui/storagewindow.h \ gui/table.cpp \ gui/table.h \ gui/table_model.cpp \ gui/table_model.h \ gui/textbox.cpp \ gui/textbox.h \ + gui/textdialog.cpp \ + gui/textdialog.h \ gui/textfield.cpp \ gui/textfield.h \ gui/textrenderer.h \ @@ -164,52 +170,20 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ gui/trade.h \ gui/truetypefont.cpp \ gui/truetypefont.h \ - gui/updatewindow.h \ gui/updatewindow.cpp \ + gui/updatewindow.h \ gui/viewport.cpp \ gui/viewport.h \ gui/window.cpp \ gui/window.h \ gui/windowcontainer.cpp \ gui/windowcontainer.h \ - net/beinghandler.h \ - net/beinghandler.cpp \ - net/buysellhandler.h \ - net/buysellhandler.cpp \ - net/charserverhandler.h \ - net/charserverhandler.cpp \ - net/chathandler.h \ - net/chathandler.cpp \ - net/equipmenthandler.h \ - net/equipmenthandler.cpp \ - net/inventoryhandler.h \ - net/inventoryhandler.cpp \ - net/itemhandler.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 \ net/messagein.h \ net/messageout.cpp \ net/messageout.h \ - net/network.cpp \ - net/network.h \ - net/npchandler.cpp \ - net/npchandler.h \ - net/partyhandler.cpp \ - net/partyhandler.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 \ resources/action.cpp \ resources/action.h \ resources/ambientoverlay.cpp \ @@ -257,6 +231,8 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ utils/dtor.h \ utils/fastsqrt.h \ utils/gettext.h \ + utils/sha256.cpp \ + utils/sha256.h \ utils/stringutils.cpp \ utils/stringutils.h \ utils/strprintf.cpp \ @@ -272,6 +248,12 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ being.h \ beingmanager.cpp \ beingmanager.h \ + channel.cpp \ + channel.h \ + channelmanager.cpp \ + channelmanager.h \ + commandhandler.cpp \ + commandhandler.h \ configlistener.h \ configuration.cpp \ configuration.h \ @@ -327,8 +309,6 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ particleemitter.cpp \ particleemitter.h \ particleemitterprop.h \ - party.cpp \ - party.h \ player.cpp \ player.h \ player_relations.cpp \ @@ -344,6 +324,8 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ sound.cpp \ sound.h \ sprite.h \ + statuseffect.cpp \ + statuseffect.h \ text.cpp \ text.h \ textmanager.cpp \ @@ -351,17 +333,147 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \ textparticle.cpp \ textparticle.h \ tileset.h \ + units.cpp \ + units.h \ vector.cpp \ vector.h -# set the include path found by configure -INCLUDES = \ - $(all_includes) \ - -DPKG_DATADIR=\""$(pkgdatadir)/"\" \ - -DLOCALEDIR=\""$(localedir)/"\" +if SERVER_TMWSERV +tmw_CXXFLAGS += -DTMWSERV_SUPPORT +tmw_SOURCES += \ + gui/buddywindow.cpp \ + gui/buddywindow.h \ + gui/changeemaildialog.cpp \ + gui/changeemaildialog.h \ + gui/changepassworddialog.cpp \ + gui/changepassworddialog.h \ + gui/connection.cpp \ + gui/connection.h \ + gui/guildlistbox.cpp \ + gui/guildlistbox.h \ + gui/guildwindow.cpp \ + gui/guildwindow.h \ + gui/magic.cpp \ + gui/magic.h \ + gui/npcpostdialog.cpp \ + gui/npcpostdialog.h \ + gui/partywindow.cpp \ + gui/partywindow.h \ + gui/quitdialog.cpp \ + gui/quitdialog.h \ + gui/serverdialog.cpp \ + gui/serverdialog.h \ + gui/skilldialog.cpp \ + gui/skilldialog.h \ + gui/statuswindow.cpp \ + gui/statuswindow.h \ + gui/unregisterdialog.cpp \ + gui/unregisterdialog.h \ + net/tmwserv/accountserver/account.cpp \ + net/tmwserv/accountserver/account.h \ + net/tmwserv/accountserver/accountserver.cpp \ + net/tmwserv/accountserver/accountserver.h \ + net/tmwserv/accountserver/internal.cpp \ + net/tmwserv/accountserver/internal.h \ + net/tmwserv/chatserver/chatserver.cpp \ + net/tmwserv/chatserver/chatserver.h \ + net/tmwserv/chatserver/guild.cpp \ + net/tmwserv/chatserver/guild.h \ + net/tmwserv/chatserver/internal.cpp \ + net/tmwserv/chatserver/internal.h \ + net/tmwserv/chatserver/party.cpp \ + net/tmwserv/chatserver/party.h \ + net/tmwserv/gameserver/gameserver.cpp \ + net/tmwserv/gameserver/gameserver.h \ + net/tmwserv/gameserver/internal.cpp \ + net/tmwserv/gameserver/internal.h \ + net/tmwserv/gameserver/player.cpp \ + net/tmwserv/gameserver/player.h \ + net/tmwserv/beinghandler.cpp \ + net/tmwserv/beinghandler.h \ + net/tmwserv/buysellhandler.cpp \ + net/tmwserv/buysellhandler.h \ + net/tmwserv/charserverhandler.cpp \ + net/tmwserv/charserverhandler.h \ + net/tmwserv/chathandler.cpp \ + net/tmwserv/chathandler.h \ + net/tmwserv/connection.cpp \ + net/tmwserv/connection.h \ + net/tmwserv/effecthandler.cpp \ + net/tmwserv/effecthandler.h \ + net/tmwserv/guildhandler.cpp \ + net/tmwserv/guildhandler.h \ + net/tmwserv/internal.cpp \ + net/tmwserv/internal.h \ + net/tmwserv/inventoryhandler.cpp \ + net/tmwserv/inventoryhandler.h \ + net/tmwserv/itemhandler.h \ + net/tmwserv/itemhandler.cpp \ + net/tmwserv/loginhandler.cpp \ + net/tmwserv/loginhandler.h \ + net/tmwserv/logouthandler.cpp \ + net/tmwserv/logouthandler.h \ + net/tmwserv/network.cpp \ + net/tmwserv/network.h \ + net/tmwserv/npchandler.cpp \ + net/tmwserv/npchandler.h \ + net/tmwserv/partyhandler.cpp \ + net/tmwserv/partyhandler.h \ + net/tmwserv/playerhandler.cpp \ + net/tmwserv/playerhandler.h \ + net/tmwserv/protocol.h \ + net/tmwserv/tradehandler.cpp \ + net/tmwserv/tradehandler.h \ + guild.cpp \ + guild.h +endif -# the library search path. -aethyra_LDFLAGS = $(all_libraries) $(LIBSDL_RPATH) `pkg-config --libs libxml-2.0` -aethyra_CXXFLAGS = -Wall $(LIBSDL_CFLAGS) `pkg-config --cflags libxml-2.0` $(CURL_CFLAGS) -aethyra_LDADD = $(LIBSDL_LIBS) -lguichan_sdl $(CURL_LIBS) -aethyra_TARGET = aethyra +if SERVER_EATHENA +tmw_CXXFLAGS += -DEATHENA_SUPPORT +tmw_SOURCES += \ + gui/char_server.cpp \ + gui/char_server.h \ + gui/skill.cpp \ + gui/skill.h \ + gui/status.cpp \ + gui/status.h \ + gui/storagewindow.cpp \ + gui/storagewindow.h \ + net/ea/beinghandler.cpp \ + net/ea/beinghandler.h \ + net/ea/buysellhandler.cpp \ + net/ea/buysellhandler.h \ + net/ea/charserverhandler.cpp \ + net/ea/charserverhandler.h \ + net/ea/chathandler.cpp \ + net/ea/chathandler.h \ + net/ea/equipmenthandler.cpp \ + net/ea/equipmenthandler.h \ + net/ea/inventoryhandler.cpp \ + net/ea/inventoryhandler.h \ + net/ea/itemhandler.cpp \ + net/ea/itemhandler.h \ + net/ea/loginhandler.cpp \ + net/ea/loginhandler.h \ + net/ea/maploginhandler.cpp \ + net/ea/maploginhandler.h \ + net/ea/network.cpp \ + net/ea/network.h \ + net/ea/npchandler.cpp \ + net/ea/npchandler.h \ + net/ea/partyhandler.cpp \ + net/ea/partyhandler.h \ + net/ea/playerhandler.cpp \ + net/ea/playerhandler.h \ + net/ea/protocol.cpp \ + net/ea/protocol.h \ + net/ea/skillhandler.cpp \ + net/ea/skillhandler.h \ + net/ea/tradehandler.cpp \ + net/ea/tradehandler.h \ + party.cpp \ + party.h +endif + +# set the include path found by configure +INCLUDES = $(all_includes) diff --git a/src/SDLMain.h b/src/SDLMain.h index 4683df57..4683df57 100755..100644 --- a/src/SDLMain.h +++ b/src/SDLMain.h diff --git a/src/SDLMain.m b/src/SDLMain.m index 3d02719c..3d02719c 100755..100644 --- a/src/SDLMain.m +++ b/src/SDLMain.m diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp index 108f5166..5a57b08c 100644 --- a/src/animatedsprite.cpp +++ b/src/animatedsprite.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,7 +51,7 @@ AnimatedSprite::AnimatedSprite(SpriteDef *sprite): play(ACTION_STAND); } -AnimatedSprite *AnimatedSprite::load(const std::string& filename, int variant) +AnimatedSprite *AnimatedSprite::load(const std::string &filename, int variant) { ResourceManager *resman = ResourceManager::getInstance(); SpriteDef *s = resman->getSprite(filename, variant); @@ -141,7 +140,7 @@ bool AnimatedSprite::updateCurrentAnimation(unsigned int time) return true; } -bool AnimatedSprite::draw(Graphics* graphics, int posX, int posY) const +bool AnimatedSprite::draw(Graphics *graphics, int posX, int posY) const { if (!mFrame || !mFrame->image) return false; diff --git a/src/animatedsprite.h b/src/animatedsprite.h index 756d9aed..43248731 100644 --- a/src/animatedsprite.h +++ b/src/animatedsprite.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,7 +50,8 @@ class AnimatedSprite * @param filename the file of the sprite to animate * @param variant the sprite variant */ - static AnimatedSprite *load(std::string const &filename, int variant = 0); + static AnimatedSprite *load(const std::string &filename, + int variant = 0); /** * Destructor. diff --git a/src/animationparticle.cpp b/src/animationparticle.cpp index 4e1c348b..9c1f7ccb 100644 --- a/src/animationparticle.cpp +++ b/src/animationparticle.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/animationparticle.h b/src/animationparticle.h index 444703f3..03065eb7 100644 --- a/src/animationparticle.h +++ b/src/animationparticle.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/being.cpp b/src/being.cpp index 8f00fd3c..e143d506 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,11 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> -#include <cmath> +#include "being.h" #include "animatedsprite.h" -#include "being.h" #include "configuration.h" #include "effectmanager.h" #include "game.h" @@ -36,6 +33,7 @@ #include "simpleanimation.h" #include "sound.h" #include "text.h" +#include "statuseffect.h" #include "gui/speechbubble.h" @@ -53,8 +51,22 @@ #include "utils/dtor.h" #include "utils/gettext.h" #include "utils/stringutils.h" +#include "utils/xml.h" + +#include <cassert> +#include <cmath> + +namespace { +const bool debug_movement = true; +} + +#define BEING_EFFECTS_FILE "effects.xml" +#define HAIR_FILE "hair.xml" + +int Being::mNumberOfHairColors = 1; int Being::mNumberOfHairstyles = 1; +std::vector<std::string> Being::hairColors; static const int X_SPEECH_OFFSET = 18; static const int Y_SPEECH_OFFSET = 60; @@ -63,35 +75,50 @@ static const int DEFAULT_WIDTH = 32; static const int DEFAULT_HEIGHT = 32; Being::Being(int id, int job, Map *map): - mJob(job), +#ifdef EATHENA_SUPPORT mX(0), mY(0), - mAction(STAND), mWalkTime(0), +#endif mEmotion(0), mEmotionTime(0), mSpeechTime(0), mAttackSpeed(350), + mAction(STAND), + mJob(job), mId(id), - mWalkSpeed(150), mDirection(DOWN), +#ifdef TMWSERV_SUPPORT + mSpriteDirection(DIRECTION_DOWN), +#endif mMap(NULL), - mName(""), mIsGM(false), mParticleEffects(config.getValue("particleeffects", 1)), mEquippedWeapon(NULL), - mHairStyle(1), mHairColor(0), +#ifdef TMWSERV_SUPPORT + mHairStyle(0), +#else + mHairStyle(1), +#endif + mHairColor(0), mGender(GENDER_UNSPECIFIED), mPx(0), mPy(0), + mStunMode(0), mSprites(VECTOREND_SPRITE, NULL), mSpriteIDs(VECTOREND_SPRITE, 0), mSpriteColors(VECTOREND_SPRITE, ""), - mChildParticleEffects(), + mStatusParticleEffects(&mStunParticleEffects, false), + mChildParticleEffects(&mStatusParticleEffects, false), + mMustResetParticles(false), +#ifdef TMWSERV_SUPPORT + mWalkSpeed(100), +#else + mWalkSpeed(150), +#endif mUsedTargetCursor(NULL) { setMap(map); - mSpeechBubble = new SpeechBubble(); + mSpeechBubble = new SpeechBubble; - mSpeech = ""; mNameColor = &guiPalette->getColor(Palette::CHAT); mText = 0; } @@ -111,12 +138,188 @@ Being::~Being() delete mText; } +void Being::setPosition(const Vector &pos) +{ + mPos = pos; + mDest = pos; + mPath.clear(); +} + +#ifdef EATHENA_SUPPORT void Being::setDestination(Uint16 destX, Uint16 destY) { if (mMap) - setPath(mMap->findPath(mX, mY, destX, destY)); + setPath(mMap->findPath(mX, mY, destX, destY, getWalkMask())); +} +#endif + +#ifdef TMWSERV_SUPPORT +void Being::adjustCourse(int srcX, int srcY, int dstX, int dstY) +{ + if (debug_movement) + printf("%p adjustCourse(%d, %d, %d, %d)\n", + (void*) this, srcX, srcY, dstX, dstY); + + mDest.x = dstX; + mDest.y = dstY; + + // Find a path to the destination when it is at least a tile away + if (mMap && fabsf((mDest - mPos).length()) > 32) { + setPath(mMap->findPath((int) mPos.x / 32, (int) mPos.y / 32, + dstX / 32, dstY / 32, getWalkMask())); + } else { + setPath(Path()); + } + + // TODO: Evaluate the implementation of this method + /* + if (mX / 32 == dstX / 32 && mY / 32 == dstY / 32) + { + // The being is already on the last tile of the path. + Path p; + p.push_back(Position(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, getWalkMask()); + if (p1.empty()) + { + // No path, but don't teleport since it could be user input. + 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; + } + // Do not set any offset for intermediate steps. + i->x = i->x * 32; + i->y = i->y * 32; + ++j; + } + p1_length = mMap->getMetaTile(dstX / 32, dstY / 32)->Gcost; + p1_dist[p1_size - 1] = p1_length; + } + p1.push_back(Position(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, getWalkMask()); + 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? Still, don't teleport since it could be + // user input instead of server command. + 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; + i->y = i->y * 32; + } + + // 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(int srcX, int srcY) +{ + if (debug_movement) + printf("%p adjustCourse(%d, %d)\n", (void*) this, srcX, srcY); + + if (!mPath.empty()) + adjustCourse(srcX, srcY, mPath.back().x * 32, mPath.back().y * 32); +} + +void Being::setDestination(int destX, int destY) +{ + if (debug_movement) + printf("%p setDestination(%d, %d)\n", (void*) this, destX, destY); + + adjustCourse((int) mPos.x, (int) mPos.y, destX, destY); +} +#endif // TMWSERV_SUPPORT + void Being::clearPath() { mPath.clear(); @@ -125,12 +328,15 @@ void Being::clearPath() void Being::setPath(const Path &path) { mPath = path; - +#ifdef TMWSERV_SUPPORT + std::cout << this << " New path: " << path << std::endl; +#else if (mAction != WALK && mAction != DEAD) { nextStep(); mWalkTime = tick_time; } +#endif } void Being::setHairStyle(int style, int color) @@ -139,7 +345,7 @@ void Being::setHairStyle(int style, int color) mHairColor = color < 0 ? mHairColor : color % ColorDB::size(); } -void Being::setSprite(int slot, int id, std::string color) +void Being::setSprite(int slot, int id, const std::string &color) { assert(slot >= BASE_SPRITE && slot < VECTOREND_SPRITE); mSpriteIDs[slot] = id; @@ -224,22 +430,40 @@ void Being::takeDamage(Being *attacker, int amount, AttackType type) color = &guiPalette->getColor(Palette::HIT_MONSTER_PLAYER); } - if (amount > 0 && type == CRITICAL) + // Show damage number + particleEngine->addTextSplashEffect(damage, +#ifdef TMWSERV_SUPPORT + (int) mPos.x + 16, + (int) mPos.y + 16, +#else + mPx + 16, mPy + 16, +#endif + color, font, true); + + if (amount > 0) { - particleEngine->addTextSplashEffect("crit!", mPx + 16, mPy + 16, - color, font, true); + if (type != CRITICAL) + { + effectManager->trigger(26, this); + } + else + { + effectManager->trigger(28, this); + } } - - // Show damage number - particleEngine->addTextSplashEffect(damage, mPx + 16, mPy + 16, - color, font, true); } +#ifdef TMWSERV_SUPPORT +void Being::handleAttack() +#else void Being::handleAttack(Being *victim, int damage, AttackType type) +#endif { setAction(Being::ATTACK); +#ifdef EATHENA_SUPPORT mFrame = 0; mWalkTime = tick_time; +#endif } void Being::setMap(Map *map) @@ -256,6 +480,7 @@ void Being::setMap(Map *map) // Clear particle effect list because child particles became invalid mChildParticleEffects.clear(); + mMustResetParticles = true; // Reset status particles on next redraw } void Being::controlParticle(Particle *particle) @@ -263,7 +488,7 @@ void Being::controlParticle(Particle *particle) mChildParticleEffects.addLocally(particle); } -void Being::setAction(Action action) +void Being::setAction(Action action, int attackType) { SpriteAction currentAction = ACTION_INVALID; @@ -316,8 +541,27 @@ void Being::setDirection(Uint8 direction) if (mDirection == direction) return; +#ifdef TMWSERV_SUPPORT + // if the direction does not change much, keep the common component + int mFaceDirection = mDirection & direction; + if (!mFaceDirection) + mFaceDirection = direction; + mDirection = direction; + + SpriteDirection dir; + if (mFaceDirection & UP) + dir = DIRECTION_UP; + else if (mFaceDirection & DOWN) + dir = DIRECTION_DOWN; + else if (mFaceDirection & RIGHT) + dir = DIRECTION_RIGHT; + else + dir = DIRECTION_LEFT; + mSpriteDirection = dir; +#else mDirection = direction; SpriteDirection dir = getSpriteDirection(); +#endif for (int i = 0; i < VECTOREND_SPRITE; i++) { @@ -326,6 +570,7 @@ void Being::setDirection(Uint8 direction) } } +#ifdef EATHENA_SUPPORT SpriteDirection Being::getSpriteDirection() const { SpriteDirection dir; @@ -365,7 +610,7 @@ void Being::nextStep() setDirection(dir); - if (mMap->tileCollides(pos.x, pos.y)) + if (!mMap->getWalk(pos.x, pos.y, getWalkMask())) { setAction(STAND); return; @@ -376,12 +621,13 @@ void Being::nextStep() setAction(WALK); mWalkTime += mWalkSpeed / 10; } +#endif void Being::logic() { // Reduce the time that speech is still displayed if (mSpeechTime > 0) - mSpeechTime--; + mSpeechTime--; // Remove text and speechbubbles if speech boxes aren't being used if (mSpeechTime == 0 && mText) @@ -390,6 +636,42 @@ void Being::logic() mText = 0; } +#ifdef TMWSERV_SUPPORT + const Vector dest = (mPath.empty()) ? + mDest : Vector(mPath.front().x * 32 + 16, + mPath.front().y * 32 + 16); + + Vector dir = dest - mPos; + const float length = dir.length(); + + // When we're over 2 pixels from our destination, move to it + // TODO: Should be possible to make it even pixel exact, but this solves + // the jigger caused by moving too far. + if (length > 2.0f) { + const float speed = mWalkSpeed / 100.0f; + mPos += dir / (length / speed); + + if (mAction != WALK) + setAction(WALK); + + // Update the player sprite direction + int direction = 0; + const float dx = std::abs(dir.x); + const float dy = std::abs(dir.y); + if (dx > dy) + direction |= (dir.x > 0) ? RIGHT : LEFT; + else + direction |= (dir.y > 0) ? DOWN : UP; + setDirection(direction); + } + else if (!mPath.empty()) { + // TODO: Pop as soon as there is a direct unblocked line to the next + // point on the path. + mPath.pop_front(); + } else if (mAction == WALK) { + setAction(STAND); + } +#else int oldPx = mPx; int oldPy = mPy; @@ -401,6 +683,7 @@ void Being::logic() { updateCoords(); } +#endif if (mEmotion != 0) { @@ -410,7 +693,7 @@ void Being::logic() } // Update sprite animations - if (mUsedTargetCursor != NULL) + if (mUsedTargetCursor) mUsedTargetCursor->update(tick_time * 10); for (int i = 0; i < VECTOREND_SPRITE; i++) @@ -419,22 +702,51 @@ void Being::logic() mSprites[i]->update(tick_time * 10); } + // Restart status/particle effects, if needed + if (mMustResetParticles) { + mMustResetParticles = false; + for (std::set<int>::iterator it = mStatusEffects.begin(); + it != mStatusEffects.end(); it++) { + const StatusEffect *effect = StatusEffect::getStatusEffect(*it, true); + if (effect && effect->particleEffectIsPersistent()) + updateStatusEffect(*it, true); + } + } + // Update particle effects - mChildParticleEffects.moveTo((float) mPx + 16.0f, (float) mPy + 32.0f); +#ifdef TMWSERV_SUPPORT + mChildParticleEffects.moveTo((float) mPx + 16.0f, + (float) mPy + 32.0f); +#else + mChildParticleEffects.moveTo(mPos.x, mPos.y); +#endif } void Being::draw(Graphics *graphics, int offsetX, int offsetY) const { +#ifdef TMWSERV_SUPPORT + int px = (int) mPos.x + offsetX; + int py = (int) mPos.y + offsetY; +#else int px = mPx + offsetX; int py = mPy + offsetY; +#endif - if (mUsedTargetCursor != NULL) + if (mUsedTargetCursor) mUsedTargetCursor->draw(graphics, px, py); for (int i = 0; i < VECTOREND_SPRITE; i++) { if (mSprites[i]) + { +#ifdef TMWSERV_SUPPORT + // TODO: Eventually, we probably should fix all sprite offsets so + // that this translation isn't necessary anymore. + mSprites[i]->draw(graphics, px - 16, py - 32); +#else mSprites[i]->draw(graphics, px, py); +#endif + } } } @@ -443,8 +755,13 @@ void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY) if (!mEmotion) return; +#ifdef TMWSERV_SUPPORT + const int px = (int) mPos.x + offsetX; + const int py = (int) mPos.y + offsetY - 64; +#else const int px = mPx - offsetX; const int py = mPy - offsetY - 64; +#endif const int emotionIndex = mEmotion - 1; if (emotionIndex >= 0 && emotionIndex <= EmoteDB::getLast()) @@ -453,8 +770,13 @@ void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY) void Being::drawSpeech(int offsetX, int offsetY) { +#ifdef TMWSERV_SUPPORT + int px = (int) mPos.x - offsetX; + int py = (int) mPos.y - offsetY; +#else const int px = mPx - offsetX; const int py = mPy - offsetY; +#endif const int speech = (int) config.getValue("speech", NAME_IN_BUBBLE); // Draw speech above this being @@ -512,6 +834,63 @@ Being::Type Being::getType() const return UNKNOWN; } +void Being::setStatusEffectBlock(int offset, Uint16 newEffects) +{ + for (int i = 0; i < STATUS_EFFECTS; i++) { + int index = StatusEffect::blockEffectIndexToEffectIndex(offset + i); + + if (index != -1) + setStatusEffect(index, (newEffects & (1 << i)) > 0); + } +} + +void Being::handleStatusEffect(StatusEffect *effect, int effectId) +{ + if (!effect) + return; + + // TODO: Find out how this is meant to be used + // (SpriteAction != Being::Action) + //SpriteAction action = effect->getAction(); + //if (action != ACTION_INVALID) + // setAction(action); + + Particle *particle = effect->getParticle(); + + if (effectId >= 0) + mStatusParticleEffects.setLocally(effectId, particle); + else { + mStunParticleEffects.clearLocally(); + if (particle) + mStunParticleEffects.addLocally(particle); + } +} + +void Being::updateStunMode(int oldMode, int newMode) +{ + handleStatusEffect(StatusEffect::getStatusEffect(oldMode, false), -1); + handleStatusEffect(StatusEffect::getStatusEffect(newMode, true), -1); +} + +void Being::updateStatusEffect(int index, bool newStatus) +{ + handleStatusEffect(StatusEffect::getStatusEffect(index, newStatus), index); +} + +void Being::setStatusEffect(int index, bool active) +{ + const bool wasActive = mStatusEffects.find(index) != mStatusEffects.end(); + + if (active != wasActive) { + updateStatusEffect(index, active); + if (active) + mStatusEffects.insert(index); + else + mStatusEffects.erase(index); + } +} + +#ifdef EATHENA_SUPPORT int Being::getOffset(char pos, char neg) const { // Check whether we're walking in the requested direction @@ -531,6 +910,7 @@ int Being::getOffset(char pos, char neg) const return offset; } +#endif int Being::getWidth() const { @@ -554,6 +934,114 @@ void Being::setTargetAnimation(SimpleAnimation* animation) mUsedTargetCursor->reset(); } +struct EffectDescription { + std::string mGFXEffect; + std::string mSFXEffect; +}; + +static EffectDescription *default_effect = NULL; +static std::map<int, EffectDescription *> effects; +static bool effects_initialized = false; + +static EffectDescription *getEffectDescription(xmlNodePtr node, int *id) +{ + EffectDescription *ed = new EffectDescription; + + *id = atoi(XML::getProperty(node, "id", "-1").c_str()); + ed->mSFXEffect = XML::getProperty(node, "audio", ""); + ed->mGFXEffect = XML::getProperty(node, "particle", ""); + + return ed; +} + +static EffectDescription *getEffectDescription(int effectId) +{ + if (!effects_initialized) + { + XML::Document doc(BEING_EFFECTS_FILE); + xmlNodePtr root = doc.rootNode(); + + if (!root || !xmlStrEqual(root->name, BAD_CAST "being-effects")) + { + logger->log("Error loading being effects file: " + BEING_EFFECTS_FILE); + return NULL; + } + + for_each_xml_child_node(node, root) + { + int id; + + if (xmlStrEqual(node->name, BAD_CAST "effect")) + { + EffectDescription *EffectDescription = + getEffectDescription(node, &id); + effects[id] = EffectDescription; + } else if (xmlStrEqual(node->name, BAD_CAST "default")) + { + EffectDescription *EffectDescription = + getEffectDescription(node, &id); + + if (default_effect) + delete default_effect; + + default_effect = EffectDescription; + } + } + + effects_initialized = true; + } // done initializing + + EffectDescription *ed = effects[effectId]; + + if (!ed) + return default_effect; + else + return ed; +} + +void Being::internalTriggerEffect(int effectId, bool sfx, bool gfx) +{ + logger->log("Special effect #%d on %s", effectId, + getId() == player_node->getId() ? "self" : "other"); + + EffectDescription *ed = getEffectDescription(effectId); + + if (!ed) { + logger->log("Unknown special effect and no default recorded"); + return; + } + + if (gfx && !ed->mGFXEffect.empty()) { + Particle *selfFX; + + selfFX = particleEngine->addEffect(ed->mGFXEffect, 0, 0); + controlParticle(selfFX); + } + + if (sfx && !ed->mSFXEffect.empty()) { + sound.playSfx(ed->mSFXEffect); + } +} + +int Being::getHairStyleCount() +{ + return mNumberOfHairstyles; +} + +int Being::getHairColorCount() +{ + return mNumberOfHairColors; +} + +std::string Being::getHairColor(int index) +{ + if (index < 0 || index >= mNumberOfHairColors) + return "#000000"; + + return hairColors[index]; +} + void Being::load() { // Hairstyles are encoded as negative numbers. Count how far negative @@ -564,5 +1052,32 @@ void Being::load() hairstyles++; mNumberOfHairstyles = hairstyles; -} + XML::Document doc(HAIR_FILE); + xmlNodePtr root = doc.rootNode(); + + // Add an initial hair color + hairColors.resize(1, "#000000"); + + if (!root || !xmlStrEqual(root->name, BAD_CAST "colors")) + { + logger->log("Error loading being hair configuration file"); + } else { + for_each_xml_child_node(node, root) + { + if (xmlStrEqual(node->name, BAD_CAST "color")) + { + int index = atoi(XML::getProperty(node, "id", "-1").c_str()); + std::string value = XML::getProperty(node, "value", ""); + + if (index >= 0 && !value.empty()) { + if (index >= mNumberOfHairColors) { + mNumberOfHairColors = index + 1; + hairColors.resize(mNumberOfHairColors, "#000000"); + } + hairColors[index] = value; + } + } + } + } +} diff --git a/src/being.h b/src/being.h index 689eda02..158f2f72 100644 --- a/src/being.h +++ b/src/being.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,13 +26,15 @@ #include <SDL_types.h> +#include <set> #include <string> #include <vector> -#include <bitset> +#include "map.h" #include "particlecontainer.h" #include "position.h" #include "sprite.h" +#include "vector.h" #include "resources/spritedef.h" @@ -55,6 +56,8 @@ class SimpleAnimation; class SpeechBubble; class Text; +class StatusEffect; + typedef std::list<Sprite*> Sprites; typedef Sprites::iterator SpriteIterator; @@ -77,7 +80,9 @@ class Being : public Sprite }; /** - * Action the being is currently performing. + * Action the being is currently performing + * WARNING: Has to be in sync with the same enum in the Being class + * of the server! */ enum Action { @@ -95,14 +100,20 @@ class Being : public Sprite SHOE_SPRITE, BOTTOMCLOTHES_SPRITE, TOPCLOTHES_SPRITE, +#ifdef EATHENA_SUPPORT MISC1_SPRITE, MISC2_SPRITE, +#endif HAIR_SPRITE, HAT_SPRITE, +#ifdef EATHENA_SUPPORT CAPE_SPRITE, GLOVES_SPRITE, +#endif WEAPON_SPRITE, +#ifdef EATHENA_SUPPORT SHIELD_SPRITE, +#endif VECTOREND_SPRITE }; @@ -137,16 +148,18 @@ class Being : public Sprite */ enum { DOWN = 1, LEFT = 2, UP = 4, RIGHT = 8 }; - Uint16 mJob; /**< Job (player job, npc, monster, ) */ +#ifdef EATHENA_SUPPORT Uint16 mX, mY; /**< Tile coordinates */ - Action mAction; /**< Action the being is performing */ int mFrame; int mWalkTime; +#endif int mEmotion; /**< Currently showing emotion */ int mEmotionTime; /**< Time until emotion disappears */ int mSpeechTime; int mAttackSpeed; /**< Attack speed */ + Action mAction; /**< Action the being is performing */ + Uint16 mJob; /**< Job (player job, npc, monster, creature ) */ /** * Constructor. @@ -166,7 +179,26 @@ class Being : public Sprite /** * Sets a new destination for this being to walk to. */ +#ifdef EATHENA_SUPPORT virtual void setDestination(Uint16 destX, Uint16 destY); +#else + void setDestination(int x, int y); + + /** + * Returns the destination for this being. + */ + const Vector &getDestination() const { return mDest; } + + /** + * Adjusts course to expected start point. + */ + void adjustCourse(int srcX, int srcY); + + /** + * Adjusts course to expected start and end points. + */ + void adjustCourse(int srcX, int srcY, int destX, int destY); +#endif /** * Puts a "speech balloon" above this being for the specified amount @@ -193,19 +225,25 @@ class Being : public Sprite * @param damage the amount of damage dealt (0 means miss) * @param type the attack type */ +#ifdef TMWSERV_SUPPORT + virtual void handleAttack(); +#else virtual void handleAttack(Being *victim, int damage, AttackType type); +#endif /** * Returns the name of the being. */ - const std::string& getName() const { return mName; } + const std::string &getName() const + { return mName; } /** * Sets the name for the being. * * @param name The name that should appear. */ - virtual void setName(const std::string &name) { mName = name; } + virtual void setName(const std::string &name) + { mName = name; } /** * Gets the hair color for this being. @@ -230,7 +268,8 @@ class Being : public Sprite /** * Sets visible equipments for this being. */ - virtual void setSprite(int slot, int id, std::string color = ""); + virtual void setSprite(int slot, int id, + const std::string &color = ""); /** * Sets the gender of this being. @@ -242,10 +281,12 @@ class Being : public Sprite */ Gender getGender() const { return mGender; } +#ifdef EATHENA_SUPPORT /** * Makes this being take the next step of his path. */ virtual void nextStep(); +#endif /** * Triggers whether or not to show the name as a GM name. @@ -277,16 +318,17 @@ class Being : public Sprite /** * Gets the walk speed. + * @see setWalkSpeed(int) */ - Uint16 getWalkSpeed() const { return mWalkSpeed; } + int getWalkSpeed() const { return mWalkSpeed; } /** - * Sets the walk speed. + * Sets the walk speed (in pixels per second). */ - void setWalkSpeed(Uint16 speed) { mWalkSpeed = speed; } + void setWalkSpeed(int speed) { mWalkSpeed = speed; } /** - * Gets the sprite id. + * Gets the being id. */ int getId() const { return mId; } @@ -303,7 +345,12 @@ class Being : public Sprite /** * Sets the current action. */ - virtual void setAction(Action action); + virtual void setAction(Action action, int attackType = 0); + + /** + * Gets the current action. + */ + bool isAlive() { return mAction != DEAD; } /** * Returns the current direction. @@ -315,15 +362,22 @@ class Being : public Sprite */ void setDirection(Uint8 direction); +#ifdef EATHENA_SUPPORT /** * Gets the current action. */ int getWalkTime() { return mWalkTime; } +#endif /** * Returns the direction the being is facing. */ +#ifdef TMWSERV_SUPPORT + SpriteDirection getSpriteDirection() const + { return SpriteDirection(mSpriteDirection); } +#else SpriteDirection getSpriteDirection() const; +#endif /** * Draws this being to the given graphics context. @@ -335,32 +389,66 @@ class Being : public Sprite /** * Returns the pixel X coordinate. */ +#ifdef TMWSERV_SUPPORT + int getPixelX() const { return (int) mPos.x; } +#else int getPixelX() const { return mPx; } +#endif /** * Returns the pixel Y coordinate. * * @see Sprite::getPixelY() */ +#ifdef TMWSERV_SUPPORT + int getPixelY() const { return (int) mPos.y; } +#else int getPixelY() const { return mPy; } +#endif +#ifdef EATHENA_SUPPORT /** * Get the current X pixel offset. */ - int getXOffset() const { return getOffset(LEFT, RIGHT); } + int getXOffset() const + { return getOffset(LEFT, RIGHT); } /** * Get the current Y pixel offset. */ - int getYOffset() const { return getOffset(UP, DOWN); } + int getYOffset() const + { return getOffset(UP, DOWN); } +#endif + + /** + * Sets the position of this being. When the being was walking, it also + * clears the destination and the path. + */ + void setPosition(const Vector &pos); + + /** + * Overloaded method provided for convenience. + * + * @see setPosition(const Vector &pos) + */ + void setPosition(float x, float y, float z = 0.0f) + { + setPosition(Vector(x, y, z)); + } /** - * Returns the horizontal size of the current base sprite of the being + * Returns the position of this being. + */ + const Vector &getPosition() const { return mPos; } + + + /** + * Returns the horizontal size of the current base sprite of the being. */ virtual int getWidth() const; /** - * Returns the vertical size of the current base sprite of the being + * Returns the vertical size of the current base sprite of the being. */ virtual int getHeight() const; @@ -376,6 +464,18 @@ class Being : public Sprite void controlParticle(Particle *particle); /** + * Gets the way the object is blocked by other objects. + */ + virtual unsigned char getWalkMask() const + { return 0x00; } //can walk through everything + + /** + * Returns the path this being is following. An empty path is returned + * when this being isn't following any path currently. + */ + const Path &getPath() const { return mPath; } + + /** * Sets the target animation for this being. */ void setTargetAnimation(SimpleAnimation* animation); @@ -391,6 +491,48 @@ class Being : public Sprite mEmotionTime = emote_time; } + /** + * Sets the being's stun mode. If zero, the being is `normal', + * otherwise it is `stunned' in some fashion. + */ + void setStunMode(int stunMode) + { + if (mStunMode != stunMode) + updateStunMode(mStunMode, stunMode); + mStunMode = stunMode; + }; + + void setStatusEffect(int index, bool active); + + /** + * A status effect block is a 16 bit mask of status effects. + * We assign each such flag a block ID of offset + bitnr. + * + * These are NOT the same as the status effect indices. + */ + void setStatusEffectBlock(int offset, Uint16 flags); + + /** + * Triggers a visual effect, such as `level up' + * + * Only draws the visual effect, does not play sound effects + * + * \param effectId ID of the effect to trigger + */ + virtual void triggerEffect(int effectId) + { + internalTriggerEffect(effectId, false, true); + } + + // Target cursor being used by the being + Image *mTargetCursor; + + static int getHairColorCount(); + + static int getHairStyleCount(); + + static std::string getHairColor(int index); + virtual AnimatedSprite* getSprite(int index) const { return mSprites[index]; } @@ -407,9 +549,46 @@ class Being : public Sprite */ virtual void updateCoords() {} + /** + * Gets the way the object blocks pathfinding for other objects + */ + virtual Map::BlockType getBlockType() const + { return Map::BLOCKTYPE_NONE; } + + /** + * Trigger visual effect, with components + * + * \param effectId ID of the effect to trigger + * \param sfx Whether to trigger sound effects + * \param gfx Whether to trigger graphical effects + */ + void internalTriggerEffect(int effectId, bool sfx, bool gfx); + + /** + * Notify self that the stun mode has been updated. Invoked by + * setStunMode if something changed. + */ + virtual void updateStunMode(int oldMode, int newMode); + + /** + * Notify self that a status effect has flipped. + * The new flag is passed. + */ + virtual void updateStatusEffect(int index, bool newStatus); + + /** + * Handle an update to a status or stun effect + * + * \param The StatusEffect to effect + * \param effectId -1 for stun, otherwise the effect index + */ + virtual void handleStatusEffect(StatusEffect *effect, int effectId); + int mId; /**< Unique sprite id */ - Uint16 mWalkSpeed; /**< Walking speed */ Uint8 mDirection; /**< Facing direction */ +#ifdef TMWSERV_SUPPORT + Uint8 mSpriteDirection; /**< Facing direction */ +#endif Map *mMap; /**< Map on which this being resides */ std::string mName; /**< Name of character */ SpriteIterator mSpriteIterator; @@ -417,34 +596,51 @@ class Being : public Sprite bool mParticleEffects; /**< Whether to display particles or not */ /** Engine-related infos about weapon. */ - const ItemInfo* mEquippedWeapon; + const ItemInfo *mEquippedWeapon; - static int mNumberOfHairstyles; /** Number of hair styles in use */ + static std::vector<std::string> hairColors; + static int mNumberOfHairColors; /** Number of hair colors in use */ + static int mNumberOfHairstyles; /** Number of hair styles in use */ Path mPath; std::string mSpeech; Text *mText; - Uint16 mHairStyle, mHairColor; + int mHairStyle; + int mHairColor; Gender mGender; int mPx, mPy; /**< Pixel coordinates */ + Uint16 mStunMode; /**< Stun mode; zero if not stunned */ + std::set<int> mStatusEffects; /**< set of active status effects */ const gcn::Color* mNameColor; std::vector<AnimatedSprite*> mSprites; std::vector<int> mSpriteIDs; std::vector<std::string> mSpriteColors; + ParticleList mStunParticleEffects; + ParticleVector mStatusParticleEffects; ParticleList mChildParticleEffects; private: +#ifdef EATHENA_SUPPORT /** * Calculates the offset in the given directions. * If walking in direction 'neg' the value is negated. */ int getOffset(char pos, char neg) const; +#endif + + /** Reset particle status effects on next redraw? */ + bool mMustResetParticles; // Speech Bubble components SpeechBubble *mSpeechBubble; + int mWalkSpeed; /**< Walking speed (pixels/sec) */ + + Vector mPos; + Vector mDest; + // Target cursor being used SimpleAnimation* mUsedTargetCursor; }; diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index a3fb14ff..af968bdb 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,24 +20,37 @@ */ #include "beingmanager.h" + #include "localplayer.h" #include "monster.h" #include "npc.h" #include "player.h" +#ifdef EATHENA_SUPPORT #include "net/messageout.h" -#include "net/protocol.h" +#include "net/ea/protocol.h" +#else +#include "net/tmwserv/protocol.h" +#endif #include "utils/dtor.h" +#include <cassert> + class FindBeingFunctor { public: bool operator() (Being *being) { Uint16 other_y = y + ((being->getType() == Being::NPC) ? 1 : 0); +#ifdef TMWSERV_SUPPORT + const Vector &pos = being->getPosition(); + return ((int) pos.x / 32 == x && + ((int) pos.y / 32 == y || (int) pos.y / 32 == other_y) && +#else return (being->mX == x && (being->mY == y || being->mY == other_y) && +#endif being->mAction != Being::DEAD && (type == Being::UNKNOWN || being->getType() == type)); } @@ -47,10 +59,12 @@ class FindBeingFunctor Being::Type type; } beingFinder; +#ifdef EATHENA_SUPPORT BeingManager::BeingManager(Network *network): mNetwork(network) { } +#endif BeingManager::~BeingManager() { @@ -70,10 +84,30 @@ void BeingManager::setPlayer(LocalPlayer *player) mBeings.push_back(player); } +#ifdef TMWSERV_SUPPORT +Being *BeingManager::createBeing(int id, int type, int subtype) +#else Being *BeingManager::createBeing(int id, Uint16 job) +#endif { Being *being; +#ifdef TMWSERV_SUPPORT + switch (type) + { + case OBJECT_PLAYER: + being = new Player(id, subtype, mMap); + break; + case OBJECT_NPC: + being = new NPC(id, subtype, mMap); + break; + case OBJECT_MONSTER: + being = new Monster(id, subtype, mMap); + break; + default: + assert(false); + } +#else if (job <= 25 || (job >= 4001 && job <= 4049)) being = new Player(id, job, mMap); else if (job >= 46 && job <= 1000) @@ -90,15 +124,19 @@ Being *BeingManager::createBeing(int id, Uint16 job) outMsg.writeInt16(0x0094); outMsg.writeInt32(id);//readLong(2)); } +#endif mBeings.push_back(being); - return being; } void BeingManager::destroyBeing(Being *being) { mBeings.remove(being); +#ifdef TMWSERV_SUPPORT + if(being == player_node->getTarget()) + player_node->setTarget(NULL); +#endif delete being; } @@ -133,15 +171,15 @@ Being *BeingManager::findBeingByPixel(int x, int y) { Being *being = (*itr); - int xtol = being->getWidth(); - int uptol = being->getHeight() / 2; + int xtol = being->getWidth() / 2; + int uptol = being->getHeight(); if ((being->mAction != Being::DEAD) && (being != player_node) && - (being->getPixelX() <= x) && + (being->getPixelX() - xtol <= x) && (being->getPixelX() + xtol >= x) && (being->getPixelY() - uptol <= y) && - (being->getPixelY() + uptol >= y)) + (being->getPixelY() >= y)) { return being; } @@ -176,12 +214,14 @@ void BeingManager::logic() being->logic(); +#ifdef EATHENA_SUPPORT if (being->mAction == Being::DEAD && being->mFrame >= 20) { delete being; i = mBeings.erase(i); } else +#endif { i++; } @@ -206,13 +246,30 @@ Being *BeingManager::findNearestLivingBeing(int x, int y, int maxdist, Being *closestBeing = NULL; int dist = 0; +#ifdef TMWSERV_SUPPORT + //Why do we do this: + //For some reason x,y passed to this function is always + //in map coords, while down below its in pixels + // + //I believe there is a deeper problem under this, but + //for a temp solution we'll convert to coords to pixels + x = x * 32; + y = y * 32; + maxdist = maxdist * 32; +#endif + BeingIterator itr = mBeings.begin(); BeingIterator itr_end = mBeings.end(); for (; itr != itr_end; ++itr) { Being *being = (*itr); +#ifdef TMWSERV_SUPPORT + const Vector &pos = being->getPosition(); + int d = abs(((int) pos.x) - x) + abs(((int) pos.y) - y); +#else int d = abs(being->mX - x) + abs(being->mY - y); +#endif if ((being->getType() == type || type == Being::UNKNOWN) && (d < dist || closestBeing == NULL) // it is closer @@ -231,13 +288,25 @@ Being *BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxdist, { Being *closestBeing = NULL; int dist = 0; +#ifdef TMWSERV_SUPPORT + const Vector &apos = aroundBeing->getPosition(); + int x = apos.x; + int y = apos.y; + maxdist = maxdist * 32; +#else int x = aroundBeing->mX; int y = aroundBeing->mY; +#endif for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++) { Being *being = (*i); +#ifdef TMWSERV_SUPPORT + const Vector &pos = being->getPosition(); + int d = abs(((int) pos.x) - x) + abs(((int) pos.y) - y); +#else int d = abs(being->mX - x) + abs(being->mY - y); +#endif if ((being->getType() == type || type == Being::UNKNOWN) && (d < dist || closestBeing == NULL) // it is closer diff --git a/src/beingmanager.h b/src/beingmanager.h index 3284ce16..05821bcf 100644 --- a/src/beingmanager.h +++ b/src/beingmanager.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +26,9 @@ class LocalPlayer; class Map; +#ifdef EATHENA_SUPPORT class Network; +#endif typedef std::list<Being*> Beings; typedef Beings::iterator BeingIterator; @@ -35,7 +36,9 @@ typedef Beings::iterator BeingIterator; class BeingManager { public: +#ifdef EATHENA_SUPPORT BeingManager(Network *network); +#endif ~BeingManager(); @@ -52,7 +55,11 @@ class BeingManager /** * Create a being and add it to the list of beings. */ +#ifdef TMWSERV_SUPPORT + Being *createBeing(int id, int type, int subtype); +#else Being *createBeing(int id, Uint16 job); +#endif /** * Remove a Being. @@ -60,25 +67,25 @@ class BeingManager void destroyBeing(Being *being); /** - * Return a specific id Being. + * Returns a specific id Being. */ Being *findBeing(int id); - Being *findBeingByPixel(int x, int y); /** * Returns a being at specific coordinates. */ Being *findBeing(int x, int y, Being::Type type = Being::UNKNOWN); + Being *findBeingByPixel(int x, int y); - /** - * Returns a being nearest to specific coordinates. - * - * @param x X coordinate. - * @param y Y coordinate. - * @param maxdist Maximal distance. If minimal distance is larger, - * no being is returned. - * @param type The type of being to look for. - */ + /** + * Returns a being nearest to specific coordinates. + * + * @param x X coordinate. + * @param y Y coordinate. + * @param maxdist Maximal distance. If minimal distance is larger, + * no being is returned. + * @param type The type of being to look for. + */ Being *findNearestLivingBeing(int x, int y, int maxdist, Being::Type type = Being::UNKNOWN); @@ -122,7 +129,9 @@ class BeingManager protected: Beings mBeings; Map *mMap; +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif }; extern BeingManager *beingManager; diff --git a/src/channel.cpp b/src/channel.cpp new file mode 100644 index 00000000..3e4646fb --- /dev/null +++ b/src/channel.cpp @@ -0,0 +1,45 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "channel.h" + +#ifdef TMWSERV_SUPPORT +#include "net/tmwserv/chatserver/chatserver.h" +#include "net/tmwserv/gameserver/player.h" +#else +#include "net/messageout.h" +#include "net/ea/protocol.h" +#endif + +Channel::Channel(short id, + const std::string &name, + const std::string &announcement) : + mId(id), + mName(name), + mAnnouncement(announcement), + mTab(new ChannelTab(this)) +{ +} + +Channel::~Channel() +{ + delete mTab; +} diff --git a/src/channel.h b/src/channel.h new file mode 100644 index 00000000..b2080d4a --- /dev/null +++ b/src/channel.h @@ -0,0 +1,87 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CHANNEL_H +#define CHANNEL_H + +#include <string> + +#include "gui/widgets/channeltab.h" + +class Channel +{ + public: + /** + * Constructor. + * + * @param id the id associated with the channel. + * @param name the name of the channel. + * @param announcement a welcome message. + */ + Channel(short id, + const std::string &name, + const std::string &announcement = std::string()); + + ~Channel(); + + /** + * Get the id associated witht his channel + */ + int getId() const { return mId; } + + /** + * Get this channel's name + */ + const std::string &getName() const + { return mName; } + + /** + * Get the announcement message for this channel + */ + const std::string &getAnnouncement() const + { return mAnnouncement; } + + /** + * Sets the name of the channel. + */ + void setName(const std::string &channelName) + { mName = channelName; } + + /** + * Sets the announcement string of the channel. + */ + void setAnnouncement(const std::string &channelAnnouncement) + { mAnnouncement = channelAnnouncement; } + + ChannelTab *getTab() { return mTab; } + + protected: + friend class ChannelTab; + void setTab(ChannelTab *tab) { mTab = tab; } + + private: + unsigned short mId; + std::string mName; + std::string mAnnouncement; + ChannelTab *mTab; +}; + +#endif // CHANNEL_H diff --git a/src/channelmanager.cpp b/src/channelmanager.cpp new file mode 100644 index 00000000..6868c283 --- /dev/null +++ b/src/channelmanager.cpp @@ -0,0 +1,85 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "channelmanager.h" +#include "channel.h" + +#include "utils/dtor.h" + +ChannelManager::ChannelManager() +{ +} + +ChannelManager::~ChannelManager() +{ + delete_all(mChannels); + mChannels.clear(); +} + +Channel *ChannelManager::findById(int id) const +{ + Channel *channel = 0; + for (std::list<Channel*>::const_iterator itr = mChannels.begin(), + end = mChannels.end(); + itr != end; + itr++) + { + Channel *c = (*itr); + if (c->getId() == id) + { + channel = c; + break; + } + } + return channel; +} + +Channel *ChannelManager::findByName(const std::string &name) const +{ + Channel *channel = 0; + if (!name.empty()) + { + for (std::list<Channel*>::const_iterator itr = mChannels.begin(), + end = mChannels.end(); + itr != end; + itr++) + { + Channel *c = (*itr); + if (c->getName() == name) + { + channel = c; + break; + } + } + } + return channel; +} + +void ChannelManager::addChannel(Channel *channel) +{ + mChannels.push_back(channel); +} + +void ChannelManager::removeChannel(Channel *channel) +{ + mChannels.remove(channel); + delete channel; +} diff --git a/src/channelmanager.h b/src/channelmanager.h new file mode 100644 index 00000000..9b425159 --- /dev/null +++ b/src/channelmanager.h @@ -0,0 +1,48 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CHANNELMANAGER_H +#define CHANNELMANAGER_H + +#include <list> +#include <string> + +class Channel; + +class ChannelManager +{ +public: + ChannelManager(); + ~ChannelManager(); + + Channel *findById(int id) const; + Channel *findByName(const std::string &name) const; + + void addChannel(Channel *channel); + void removeChannel(Channel *channel); + +private: + std::list<Channel*> mChannels; +}; + +extern ChannelManager *channelManager; + +#endif diff --git a/src/commandhandler.cpp b/src/commandhandler.cpp new file mode 100644 index 00000000..f875fd85 --- /dev/null +++ b/src/commandhandler.cpp @@ -0,0 +1,593 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "commandhandler.h" +#include "channelmanager.h" +#include "channel.h" +#include "game.h" +#include "localplayer.h" + +#include "gui/widgets/channeltab.h" +#include "gui/widgets/chattab.h" +#include "gui/chat.h" + +#ifdef TMWSERV_SUPPORT +#include "net/tmwserv/chatserver/chatserver.h" +#include "net/tmwserv/gameserver/player.h" +#else +#include "party.h" +#include "net/messageout.h" +#include "net/ea/protocol.h" +#endif + +#include "utils/gettext.h" +#include "utils/stringutils.h" +#include "utils/strprintf.h" + +#ifdef TMWSERV_SUPPORT +CommandHandler::CommandHandler() +#else +CommandHandler::CommandHandler(Network *network): + mNetwork(network) +#endif +{} + +void CommandHandler::handleCommand(const std::string &command) +{ + std::string::size_type pos = command.find(' '); + std::string type(command, 0, pos); + std::string args(command, pos == std::string::npos ? command.size() : pos + 1); + + if (type == "announce") + { + handleAnnounce(args); + } + else if (type == "help") + { + handleHelp(args); + } + else if (type == "where") + { + handleWhere(); + } + else if (type == "who") + { + handleWho(); + } + else if (type == "msg" || type == "whisper" || type == "w") + { + handleMsg(args); + } +#ifdef TMWSERV_SUPPORT + else if (type == "join") + { + handleJoin(args); + } + else if (type == "list") + { + handleListChannels(); + } + else if (type == "users") + { + handleListUsers(); + } + else if (type == "quit") + { + handleQuit(); + } + else if (type == "topic") + { + handleTopic(args); + } + else if (type == "clear") + { + handleClear(); + } + else if (type == "op") + { + handleOp(args); + } + else if (type == "kick") + { + handleKick(args); + } +#endif + else if (type == "party") + { + handleParty(args); + } + else if (type == "me") + { + handleMe(args); + } + else if (type == "record") + { + handleRecord(args); + } + else if (type == "toggle") + { + handleToggle(args); + } + else if (type == "present") + { + handlePresent(args); + } + else + { + localChatTab->chatLog("Unknown command"); + } +} + +void CommandHandler::handleAnnounce(const std::string &args) +{ +#ifdef TMWSERV_SUPPORT + Net::ChatServer::announce(args); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0099); + outMsg.writeInt16(args.length() + 4); + outMsg.writeString(args, args.length()); +#endif +} + +void CommandHandler::handleHelp(const std::string &args) +{ + if (args == "") + { + localChatTab->chatLog(_("-- Help --")); + localChatTab->chatLog(_("/help > Display this help.")); + + localChatTab->chatLog(_("/where > Display map name")); + localChatTab->chatLog(_("/who > Display number of online users")); + localChatTab->chatLog(_("/me > Tell something about yourself")); + + localChatTab->chatLog(_("/msg > Send a private message to a user")); + localChatTab->chatLog(_("/whisper > Alias of msg")); + localChatTab->chatLog(_("/w > Alias of msg")); + +#ifdef TMWSERV_SUPPORT + localChatTab->chatLog(_("/list > Display all public channels")); + localChatTab->chatLog(_("/users > Lists the users in the current channel")); + localChatTab->chatLog(_("/join > Join or create a channel")); + localChatTab->chatLog(_("/topic > Set the topic of the current channel")); + localChatTab->chatLog(_("/quit > Leave a channel")); + localChatTab->chatLog(_("/clear > Clears this window")); + localChatTab->chatLog(_("/op > Make a user a channel operator")); + localChatTab->chatLog(_("/kick > Kick a user from the channel")); + + localChatTab->chatLog(_("/party > Invite a user to party")); +#else + localChatTab->chatLog(_("/party > Party-related commands")); +#endif + + localChatTab->chatLog(_("/record > Start recording the chat to an external file")); + localChatTab->chatLog(_("/toggle > Determine whether <return> toggles the chat log")); + localChatTab->chatLog(_("/present > Get list of players present (sent to chat log, if logging)")); + + localChatTab->chatLog(_("/announce > Global announcement (GM only)")); + + localChatTab->chatLog(_("For more information, type /help <command>")); + } + else if (args == "announce") + { + localChatTab->chatLog(_("Command: /announce <msg>")); + localChatTab->chatLog(_("*** only available to a GM ***")); + localChatTab->chatLog(_("This command sends the message <msg> to " + "all players currently online.")); + } + else if (args == "clear") + { + localChatTab->chatLog(_("Command: /clear")); + localChatTab->chatLog(_("This command clears the chat log of previous chat.")); + } + else if (args == "help") + { + localChatTab->chatLog(_("Command: /help")); + localChatTab->chatLog(_("This command displays a list of all commands available.")); + localChatTab->chatLog(_("Command: /help <command>")); + localChatTab->chatLog(_("This command displays help on <command>.")); + } + else if (args == "join") + { + localChatTab->chatLog(_("Command: /join <channel>")); + localChatTab->chatLog(_("This command makes you enter <channel>.")); + localChatTab->chatLog(_("If <channel> doesn't exist, it's created.")); + } + else if (args == "kick") + { + localChatTab->chatLog(_("Command: /kick <nick>")); + localChatTab->chatLog(_("This command makes <nick> leave the channel.")); + localChatTab->chatLog(_("If the <nick> has spaces in it, enclose it in " + "double quotes (\").")); + } + else if (args == "list") + { + localChatTab->chatLog(_("Command: /list")); + localChatTab->chatLog(_("This command shows a list of all channels.")); + } + else if (args == "me") + { + localChatTab->chatLog(_("Command: /me <message>")); + localChatTab->chatLog(_("This command tell others you are (doing) <msg>.")); + } + else if (args == "msg" || args == "whisper" || args == "w") + { + localChatTab->chatLog(_("Command: /msg <nick> <message>")); + localChatTab->chatLog(_("Command: /whisper <nick> <message>")); + localChatTab->chatLog(_("Command: /w <nick> <message>")); + localChatTab->chatLog(_("This command sends the text <message> to <nick>.")); + localChatTab->chatLog(_("If the <nick> has spaces in it, enclose it in " + "double quotes (\").")); + } + else if (args == "op") + { + localChatTab->chatLog(_("Command: /op <nick>")); + localChatTab->chatLog(_("This command makes <nick> a channel operator.")); + localChatTab->chatLog(_("If the <nick> has spaces in it, enclose it in " + "double quotes (\").")); + localChatTab->chatLog(_("Channel operators can kick and op other users " + "from the channel.")); + } +#ifdef TMWSERV_SUPPORT + else if (args == "party") + { + localChatTab->chatLog(_("Command: /party <nick>")); + localChatTab->chatLog(_("This command invites <nick> to party with you.")); + localChatTab->chatLog(_("If the <nick> has spaces in it, enclose it in " + "double quotes (\").")); +#else + else if (args.substr(0, 5) == "party") + { + playerParty->help(args); +#endif + } + else if (args == "present") + { + localChatTab->chatLog(_("Command: /present")); + localChatTab->chatLog(_("This command gets a list of players within hearing and " + "sends it to either the record log if recording, or the chat " + "log otherwise.")); + } + else if (args == "quit") + { + localChatTab->chatLog(_("Command: /quit")); + localChatTab->chatLog(_("This command leaves the current channel.")); + localChatTab->chatLog(_("If you're the last person in the channel, it will be deleted.")); + } + else if (args == "record") + { + localChatTab->chatLog(_("Command: /record <filename>")); + localChatTab->chatLog(_("This command starts recording the chat log to the file " + "<filename>.")); + localChatTab->chatLog(_("Command: /record")); + localChatTab->chatLog(_("This command finishes a recording session.")); + } + else if (args == "toggle") + { + localChatTab->chatLog(_("Command: /toggle <state>")); + localChatTab->chatLog(_("This command sets whether the return key should toggle the " + "chat log, or whether the chat log turns off automatically.")); + localChatTab->chatLog(_("<state> can be one of \"1\", \"yes\", \"true\" to " + "turn the toggle on, or \"0\", \"no\", \"false\" to turn the " + "toggle off.")); + localChatTab->chatLog(_("Command: /toggle")); + localChatTab->chatLog(_("This command displays the return toggle status.")); + } + else if (args == "topic") + { + localChatTab->chatLog(_("Command: /topic <message>")); + localChatTab->chatLog(_("This command sets the topic to <message>.")); + } + else if (args == "users") + { + localChatTab->chatLog(_("Command: /users <channel>")); + localChatTab->chatLog(_("This command shows the users in <channel>.")); + } + else if (args == "where") + { + localChatTab->chatLog(_("Command: /where")); + localChatTab->chatLog(_("This command displays the name of the current map.")); + } + else if (args == "who") + { + localChatTab->chatLog(_("Command: /who")); + localChatTab->chatLog(_("This command displays the number of players currently " + "online.")); + } + else + { + localChatTab->chatLog(_("Unknown command.")); + localChatTab->chatLog(_("Type /help for a list of commands.")); + } +} + +void CommandHandler::handleWhere() +{ + // TODO: add position + localChatTab->chatLog(map_path, BY_SERVER); +} + +void CommandHandler::handleWho() +{ +#ifdef TMWSERV_SUPPORT + //TODO +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x00c1); +#endif +} + +void CommandHandler::handleMsg(const std::string &args) +{ +#ifdef TMWSERV_SUPPORT + std::string::size_type pos = args.find(' '); + std::string recipient(args, 0, pos); + std::string text(args, pos+1); + Net::ChatServer::privMsg(recipient, text); +#else + std::string recvnick = ""; + std::string msg = ""; + + if (args.substr(0, 1) == "\"") + { + const std::string::size_type pos = args.find('"', 1); + if (pos != std::string::npos) + { + recvnick = args.substr(1, pos - 1); + msg = args.substr(pos + 2, args.length()); + } + } + else + { + const std::string::size_type pos = args.find(" "); + if (pos != std::string::npos) + { + recvnick = args.substr(0, pos); + msg = args.substr(pos + 1, args.length()); + } + else + { + recvnick = std::string(args); + msg = ""; + } + } + + trim(msg); + + if (msg.length() > 0) + { + std::string playerName = player_node->getName(); + std::string tempNick = recvnick; + + toLower(playerName); + toLower(tempNick); + + if (tempNick.compare(playerName) == 0 || args.empty()) + return; + + chatWindow->whisper(recvnick, msg, true); + } + else + localChatTab->chatLog("Cannont send empty whispers!"); +#endif +} + +void CommandHandler::handleClear() +{ + chatWindow->clearTab(); +} + +#ifdef TMWSERV_SUPPORT + +void CommandHandler::handleJoin(const std::string &args) +{ + std::string::size_type pos = args.find(' '); + std::string name(args, 0, pos); + std::string password(args, pos+1); + localChatTab->chatLog("Requesting to join channel " + name); + Net::ChatServer::enterChannel(name, password); +} + +void CommandHandler::handleListChannels() +{ + Net::ChatServer::getChannelList(); +} + +void CommandHandler::handleListUsers() +{ + Net::ChatServer::getUserList(chatWindow->getFocused()->getCaption()); +} + +void CommandHandler::handleTopic(const std::string &args) +{ + ChannelTab *tab = dynamic_cast<ChannelTab*>(chatWindow->getFocused()); + Channel *channel = tab ? tab->getChannel() : NULL; + if (channel) + { + Net::ChatServer::setChannelTopic(channel->getId(), args); + } + else + { + localChatTab->chatLog("Unable to set this channel's topic", BY_CHANNEL); + } +} + +void CommandHandler::handleQuit() +{ + ChannelTab *tab = dynamic_cast<ChannelTab*>(chatWindow->getFocused()); + Channel *channel = tab ? tab->getChannel() : NULL; + if (channel) + { + Net::ChatServer::quitChannel(channel->getId()); + } + else + { + localChatTab->chatLog("Unable to quit this channel", BY_CHANNEL); + } +} + +void CommandHandler::handleOp(const std::string &args) +{ + ChannelTab *tab = dynamic_cast<ChannelTab*>(chatWindow->getFocused()); + Channel *channel = tab ? tab->getChannel() : NULL; + if (channel) + { + // set the user mode 'o' to op a user + if (args != "") + { + Net::ChatServer::setUserMode(channel->getId(), args, 'o'); + } + } + else + { + localChatTab->chatLog("Unable to set this user's mode", BY_CHANNEL); + } +} + +void CommandHandler::handleKick(const std::string &args) +{ + ChannelTab *tab = dynamic_cast<ChannelTab*>(chatWindow->getFocused()); + Channel *channel = tab ? tab->getChannel() : NULL; + if (channel) + { + if (args != "") + { + Net::ChatServer::kickUser(channel->getId(), args); + } + } + else + { + localChatTab->chatLog("Unable to kick user", BY_CHANNEL); + } +} + +#endif + +void CommandHandler::handleParty(const std::string &args) +{ +#ifdef TMWSERV_SUPPORT + if (args != "") + { + player_node->inviteToParty(args); + } +#else + if (args.empty()) + { + localChatTab->chatLog(_("Unknown party command... Type \"/help\" party for more " + "information."), BY_SERVER); + return; + } + + const std::string::size_type space = args.find(" "); + std::string command; + std::string rest; + + if (space == std::string::npos) + { + command = args; + } + else + { + command = args.substr(0, space); + rest = args.substr(space + 1, args.length()); + } + + if (command == "prefix") + { + if (rest.empty()) + { + char temp[2] = "."; + *temp = chatWindow->getPartyPrefix(); + localChatTab->chatLog(_("The current party prefix is ") + std::string(temp)); + } + else if (rest.length() != 1) + { + localChatTab->chatLog(_("Party prefix must be one character long.")); + } + else + { + if (rest == "/") + { + localChatTab->chatLog(_("Cannot use a '/' as the prefix.")); + } + else + { + chatWindow->setPartyPrefix(rest.at(0)); + localChatTab->chatLog(_("Changing prefix to ") + rest); + } + } + } + else + playerParty->respond(command, rest); +#endif +} + +void CommandHandler::handleMe(const std::string &args) +{ + std::string action = strprintf("*%s*", args.c_str()); + chatWindow->chatSend(action); + //std::stringstream actionStr; + //actionStr << "*" << args << "*"; + //chatWindow->chatSend(actionStr.str()); +} + +void CommandHandler::handleRecord(const std::string &args) +{ + chatWindow->setRecordingFile(args); +} + +void CommandHandler::handleToggle(const std::string &args) +{ + if (args.empty()) + { + localChatTab->chatLog(chatWindow->getReturnTogglesChat() ? + _("Return toggles chat.") : _("Message closes chat.")); + return; + } + + std::string opt = args.substr(0, 1); + + if (opt == "1" || + opt == "y" || opt == "Y" || + opt == "t" || opt == "T") + { + localChatTab->chatLog(_("Return now toggles chat.")); + chatWindow->setReturnTogglesChat(true); + return; + } + else if (opt == "0" || + opt == "n" || opt == "N" || + opt == "f" || opt == "F") + { + localChatTab->chatLog(_("Message now closes chat.")); + chatWindow->setReturnTogglesChat(false); + return; + } + else + localChatTab->chatLog(_("Options to /toggle are \"yes\", \"no\", \"true\", " + "\"false\", \"1\", \"0\".")); +} + +void CommandHandler::handlePresent(const std::string &args) +{ + chatWindow->doPresent(); +} diff --git a/src/commandhandler.h b/src/commandhandler.h new file mode 100644 index 00000000..2adf4e1b --- /dev/null +++ b/src/commandhandler.h @@ -0,0 +1,154 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef COMMANDHANDLER_H +#define COMMANDHANDLER_H + +#include <string> + +#ifdef EATHENA_SUPPORT +class Network; +#endif + +/** + * A class to parse and handle user commands + */ +class CommandHandler +{ + public: + /** + * Constructor + */ +#ifdef TMWSERV_SUPPORT + CommandHandler(); +#else + CommandHandler(Network *network); +#endif + + /** + * Destructor + */ + ~CommandHandler() {} + + /** + * Parse and handle the given command. + */ + void handleCommand(const std::string &command); + + private: + /** + * Handle an announce command. + */ + void handleAnnounce(const std::string &args); + + /** + * Handle a help command. + */ + void handleHelp(const std::string &args); + + /** + * Handle a where command. + */ + void handleWhere(); + + /** + * Handle a who command. + */ + void handleWho(); + + /** + * Handle a msg command. + */ + void handleMsg(const std::string &args); + + /** + * Handle a join command. + */ + void handleJoin(const std::string &args); + + /** + * Handle a listchannels command. + */ + void handleListChannels(); + + /** + * Handle a listusers command. + */ + void handleListUsers(); + + /** + * Handle a topic command. + */ + void handleTopic(const std::string &args); + + /** + * Handle a quit command. + */ + void handleQuit(); + + /** + * Handle a clear command. + */ + void handleClear(); + + /** + * Handle a party command. + */ + void handleParty(const std::string &args); + + /** + * Handle a op command. + */ + void handleOp(const std::string &args); + + /** + * Handle a kick command. + */ + void handleKick(const std::string &args); + + /** + * Handle a me command. + */ + void handleMe(const std::string &args); + + /** + * Handle a record command. + */ + void handleRecord(const std::string &args); + + /** + * Handle a toggle command. + */ + void handleToggle(const std::string &args); + + /** + * Handle a present command. + */ + void handlePresent(const std::string &args); + +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif +}; + +extern CommandHandler *commandHandler; + +#endif // COMMANDHANDLER_H diff --git a/src/configlistener.h b/src/configlistener.h index edd9e90a..ec7d6a2c 100644 --- a/src/configlistener.h +++ b/src/configlistener.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/configuration.cpp b/src/configuration.cpp index 0df666ab..3c3ae1d5 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -57,7 +56,8 @@ void Configuration::setValue(const std::string &key, std::string value) } } -std::string ConfigurationObject::getValue(const std::string &key, std::string deflt) +std::string ConfigurationObject::getValue(const std::string &key, + std::string deflt) { OptionIterator iter = mOptions.find(key); return ((iter != mOptions.end()) ? iter->second : deflt); @@ -78,7 +78,7 @@ void ConfigurationObject::deleteList(const std::string &name) mContainerOptions[name].clear(); } -void ConfigurationObject::clear(void) +void ConfigurationObject::clear() { for (std::map<std::string, ConfigurationList>::const_iterator it = mContainerOptions.begin(); it != mContainerOptions.end(); it++) @@ -86,7 +86,7 @@ void ConfigurationObject::clear(void) mOptions.clear(); } -ConfigurationObject::~ConfigurationObject(void) +ConfigurationObject::~ConfigurationObject() { clear(); } @@ -106,7 +106,7 @@ void ConfigurationObject::initFromXML(xmlNodePtr parent_node) { if (xmlStrEqual(subnode->name, BAD_CAST name.c_str()) && subnode->type == XML_ELEMENT_NODE) { - ConfigurationObject *cobj = new ConfigurationObject(); + ConfigurationObject *cobj = new ConfigurationObject; cobj->initFromXML(subnode); // recurse diff --git a/src/configuration.h b/src/configuration.h index 3e201dcb..0134f29a 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -73,7 +72,7 @@ class ConfigurationObject friend class Configuration; public: - virtual ~ConfigurationObject(void); + virtual ~ConfigurationObject(); /** * Sets an option using a string value. @@ -110,7 +109,7 @@ class ConfigurationObject /** * Re-sets all data in the configuration */ - virtual void clear(void); + virtual void clear(); /** * Serialises a container into a list of configuration options @@ -127,7 +126,7 @@ class ConfigurationObject template <class IT, class T, class CONT> void setList(const std::string &name, IT begin, IT end, ConfigurationListManager<T, CONT> *manager) { - ConfigurationObject *nextobj = new ConfigurationObject(); + ConfigurationObject *nextobj = new ConfigurationObject; deleteList(name); ConfigurationList *list = &(mContainerOptions[name]); @@ -135,7 +134,7 @@ class ConfigurationObject ConfigurationObject *wrobj = manager->writeConfigItem(*it, nextobj); if (wrobj) { // wrote something assert (wrobj == nextobj); - nextobj = new ConfigurationObject(); + nextobj = new ConfigurationObject; list->push_back(wrobj); } else nextobj->clear(); // you never know... @@ -160,7 +159,7 @@ class ConfigurationObject { ConfigurationList *list = &(mContainerOptions[name]); CONT container = empty; - + for (ConfigurationList::const_iterator it = list->begin(); it != list->end(); it++) container = manager->readConfigItem(*it, container); @@ -189,7 +188,7 @@ class ConfigurationObject class Configuration : public ConfigurationObject { public: - virtual ~Configuration(void) {} + virtual ~Configuration() {} /** * Reads config file and parse all options into memory. @@ -216,6 +215,7 @@ class Configuration : public ConfigurationObject virtual void setValue(const std::string &key, std::string value); virtual void setValue(const std::string &key, float value); + private: typedef std::list<ConfigListener*> Listeners; typedef Listeners::iterator ListenerIterator; @@ -226,6 +226,7 @@ class Configuration : public ConfigurationObject std::string mConfigPath; /**< Location of config file */ }; +extern Configuration branding; extern Configuration config; #endif diff --git a/src/effectmanager.cpp b/src/effectmanager.cpp index 567e692b..d9234f66 100644 --- a/src/effectmanager.cpp +++ b/src/effectmanager.cpp @@ -3,8 +3,7 @@ * Copyright (C) 2008 Fate <fate.tmw@googlemail.com> * Copyright (C) 2008 Chuck Miller <shadowmil@gmail.com> * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,8 +45,6 @@ EffectManager::EffectManager() for_each_xml_child_node(node, root) { - //int id; - if (xmlStrEqual(node->name, BAD_CAST "effect")) { EffectDescription ed; @@ -61,7 +58,6 @@ EffectManager::EffectManager() EffectManager::~EffectManager() { - } bool EffectManager::trigger(int id, Being* being) diff --git a/src/effectmanager.h b/src/effectmanager.h index c69ade09..01c5a6b8 100644 --- a/src/effectmanager.h +++ b/src/effectmanager.h @@ -3,8 +3,7 @@ * Copyright (C) 2008 Fate <fate.tmw@googlemail.com> * Copyright (C) 2008 Chuck Miller <shadowmil@gmail.com> * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/emoteshortcut.cpp b/src/emoteshortcut.cpp index b229ec70..46e13782 100644 --- a/src/emoteshortcut.cpp +++ b/src/emoteshortcut.cpp @@ -2,8 +2,7 @@ * Extended support for activating emotes * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra derived from original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/emoteshortcut.h b/src/emoteshortcut.h index 3fe911dd..ceb51a9b 100644 --- a/src/emoteshortcut.h +++ b/src/emoteshortcut.h @@ -2,8 +2,7 @@ * Extended support for activating emotes * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra derived from original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/engine.cpp b/src/engine.cpp index 8ef2b9c6..da4eb336 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,17 +33,25 @@ #include "gui/minimap.h" #include "gui/viewport.h" +#ifdef EATHENA_SUPPORT #include "net/messageout.h" -#include "net/protocol.h" +#include "net/ea/protocol.h" +#endif #include "resources/mapreader.h" +#include "resources/monsterdb.h" #include "resources/resourcemanager.h" #include "utils/stringutils.h" +#ifdef TMWSERV_SUPPORT +Engine::Engine(): + mCurrentMap(NULL) +#else Engine::Engine(Network *network): mCurrentMap(NULL), mNetwork(network) +#endif { } @@ -58,6 +65,7 @@ void Engine::changeMap(const std::string &mapPath) // Clean up floor items, beings and particles floorItemManager->clear(); beingManager->clear(); + particleEngine->clear(); // Unset the map of the player so that its particles are cleared before // being deleted in the next step @@ -69,7 +77,11 @@ void Engine::changeMap(const std::string &mapPath) mMapName = mapPath; // Store full map path in global var +#ifdef TMWSERV_SUPPORT + map_path = "maps/" + mapPath + ".tmx"; +#else map_path = "maps/" + mapPath.substr(0, mapPath.rfind(".")) + ".tmx"; +#endif ResourceManager *resman = ResourceManager::getInstance(); if (!resman->exists(map_path)) map_path += ".gz"; @@ -107,6 +119,12 @@ void Engine::changeMap(const std::string &mapPath) else minimap->setProportion(0.5); } + if (newMap->hasProperty("name")) + { + minimap->setCaption(newMap->getProperty("name")); + } else { + minimap->setCaption("Map"); + } minimap->setMapImage(mapImage); beingManager->setMap(newMap); particleEngine->setMap(newMap); @@ -131,15 +149,18 @@ void Engine::changeMap(const std::string &mapPath) mCurrentMap = newMap; +#ifdef EATHENA_SUPPORT // Send "map loaded" MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_MAP_LOADED); +#endif } void Engine::logic() { beingManager->logic(); particleEngine->update(); - mCurrentMap->update(); + if (mCurrentMap) + mCurrentMap->update(); gui->logic(); } diff --git a/src/engine.h b/src/engine.h index e2fec2f6..60b1f6c8 100644 --- a/src/engine.h +++ b/src/engine.h @@ -2,8 +2,7 @@ * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,7 +25,9 @@ #include <string> class Map; +#ifdef EATHENA_SUPPORT class Network; +#endif /** * Game engine. Actually hardly does anything anymore except keeping track of @@ -38,7 +39,11 @@ class Engine /** * Constructor. */ +#ifdef EATHENA_SUPPORT Engine(Network *network); +#else + Engine(); +#endif /** * Destructor. @@ -58,13 +63,15 @@ class Engine void changeMap(const std::string &mapName); /** - * Performs engine logic. + * Performs engine logic. This method is called 100 times per second. */ void logic(); private: Map *mCurrentMap; +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif std::string mMapName; }; diff --git a/src/equipment.cpp b/src/equipment.cpp index 558df216..c8e58b8c 100644 --- a/src/equipment.cpp +++ b/src/equipment.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,19 +21,57 @@ #include "equipment.h" #include "item.h" +#ifdef EATHENA_SUPPORT #include "inventory.h" #include "localplayer.h" +#endif -Equipment::Equipment(): - mArrows(0) +#include <algorithm> + +Equipment::Equipment() +#ifdef EATHENA_SUPPORT + : mArrows(0) +#endif { +#ifdef TMWSERV_SUPPORT + std::fill_n(mEquipment, EQUIPMENT_SIZE, (Item*) 0); +#else std::fill_n(mEquipment, EQUIPMENT_SIZE, 0); +#endif +} + +#ifdef TMWSERV_SUPPORT + +Equipment::~Equipment() +{ + clear(); } +void Equipment::clear() +{ + for (int i = 0; i < EQUIPMENT_SIZE; ++i) + delete mEquipment[i]; + + std::fill_n(mEquipment, EQUIPMENT_SIZE, (Item*) 0); +} + +void Equipment::setEquipment(int index, int id) +{ + if (mEquipment[index] && mEquipment[index]->getId() == id) + return; + + delete mEquipment[index]; + mEquipment[index] = (id > 0) ? new Item(id) : 0; +} + +#else + void Equipment::setEquipment(int index, int inventoryIndex) { mEquipment[index] = inventoryIndex; - Item* item = player_node->getInventory()->getItem(inventoryIndex); + Item *item = player_node->getInventory()->getItem(inventoryIndex); if (item) item->setEquipped(true); } + +#endif diff --git a/src/equipment.h b/src/equipment.h index d75069dc..7605175a 100644 --- a/src/equipment.h +++ b/src/equipment.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,9 +22,13 @@ #ifndef EQUIPMENT_H #define EQUIPMENT_H -class Item; - +#ifdef TMWSERV_SUPPORT +#define EQUIPMENT_SIZE 11 +#else #define EQUIPMENT_SIZE 10 +#endif + +class Item; class Equipment { @@ -35,17 +38,40 @@ class Equipment */ Equipment(); +#ifdef TMWSERV_SUPPORT + /** + * Destructor. + */ + ~Equipment(); +#endif + /** * Get equipment at the given slot. */ +#ifdef TMWSERV_SUPPORT + Item* getEquipment(int index) +#else int getEquipment(int index) const +#endif { return mEquipment[index]; } +#ifdef TMWSERV_SUPPORT + /** + * Clears equipment. + */ + void clear(); +#endif + /** * Set equipment at the given slot. */ +#ifdef TMWSERV_SUPPORT + void setEquipment(int index, int id); +#else void setEquipment(int index, int inventoryIndex); +#endif +#ifdef EATHENA_SUPPORT /** * Remove equipment from the given slot. */ @@ -60,10 +86,15 @@ class Equipment * Set the item used in the arrow slot. */ void setArrows(int arrows) { mArrows = arrows; } +#endif private: +#ifdef TMWSERV_SUPPORT + Item* mEquipment[EQUIPMENT_SIZE]; +#else int mEquipment[EQUIPMENT_SIZE]; int mArrows; +#endif }; #endif diff --git a/src/floor_item.cpp b/src/floor_item.cpp index 82506f8f..000835ad 100644 --- a/src/floor_item.cpp +++ b/src/floor_item.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +26,11 @@ #include "resources/image.h" -FloorItem::FloorItem(int id, int itemId, int x, int y, Map *map): +FloorItem::FloorItem(int id, + int itemId, + int x, + int y, + Map *map): mId(id), mX(x), mY(y), diff --git a/src/floor_item.h b/src/floor_item.h index 0972a983..7ca0f5a3 100644 --- a/src/floor_item.h +++ b/src/floor_item.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,7 +42,11 @@ class FloorItem : public Sprite /** * Constructor. */ - FloorItem(int id, int itemId, int x, int y, Map *map); + FloorItem(int id, + int itemId, + int x, + int y, + Map *map); /** * Destructor. diff --git a/src/flooritemmanager.cpp b/src/flooritemmanager.cpp index 97b3ca5b..5d2799d4 100644 --- a/src/flooritemmanager.cpp +++ b/src/flooritemmanager.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +29,8 @@ FloorItemManager::~FloorItemManager() clear(); } -FloorItem* FloorItemManager::create(int id, int itemId, int x, int y, Map *map) +FloorItem *FloorItemManager::create(int id, int itemId, + int x, int y, Map *map) { FloorItem *floorItem = new FloorItem(id, itemId, x, y, map); mFloorItems.push_back(floorItem); diff --git a/src/flooritemmanager.h b/src/flooritemmanager.h index 1a6e8e0a..704b39fd 100644 --- a/src/flooritemmanager.h +++ b/src/flooritemmanager.h @@ -2,8 +2,7 @@ * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/game.cpp b/src/game.cpp index 7f0186d1..91d8fa3a 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +27,8 @@ #include <guichan/exception.hpp> #include "beingmanager.h" +#include "channelmanager.h" +#include "commandhandler.h" #include "configuration.h" #include "effectmanager.h" #include "emoteshortcut.h" @@ -42,8 +43,12 @@ #include "log.h" #include "npc.h" #include "particle.h" +#ifdef EATHENA_SUPPORT +#include "party.h" +#endif #include "player_relations.h" +#include "gui/widgets/chattab.h" #include "gui/buy.h" #include "gui/buysell.h" #include "gui/chat.h" @@ -70,23 +75,47 @@ #include "gui/setup.h" #include "gui/skill.h" #include "gui/status.h" -#include "gui/storagewindow.h" #include "gui/trade.h" #include "gui/viewport.h" +#ifdef TMWSERV_SUPPORT +#include "gui/buddywindow.h" +#include "gui/guildwindow.h" +#include "gui/magic.h" +#include "gui/npcpostdialog.h" +#include "gui/partywindow.h" +#include "gui/quitdialog.h" +#else +#include "gui/storagewindow.h" +#endif -#include "net/beinghandler.h" -#include "net/buysellhandler.h" -#include "net/chathandler.h" -#include "net/equipmenthandler.h" -#include "net/inventoryhandler.h" -#include "net/itemhandler.h" +#ifdef TMWSERV_SUPPORT +#include "net/tmwserv/chathandler.h" +#include "net/tmwserv/itemhandler.h" +#include "net/tmwserv/npchandler.h" +#include "net/tmwserv/playerhandler.h" +#include "net/tmwserv/tradehandler.h" +#include "net/tmwserv/network.h" +#include "net/tmwserv/beinghandler.h" +#include "net/tmwserv/buysellhandler.h" +#include "net/tmwserv/effecthandler.h" +#include "net/tmwserv/guildhandler.h" +#include "net/tmwserv/inventoryhandler.h" +#include "net/tmwserv/partyhandler.h" +#else +#include "net/ea/network.h" +#include "net/ea/chathandler.h" +#include "net/ea/beinghandler.h" +#include "net/ea/buysellhandler.h" +#include "net/ea/equipmenthandler.h" +#include "net/ea/inventoryhandler.h" +#include "net/ea/itemhandler.h" +#include "net/ea/npchandler.h" +#include "net/ea/playerhandler.h" +#include "net/ea/tradehandler.h" +#include "net/ea/protocol.h" +#include "net/ea/skillhandler.h" #include "net/messageout.h" -#include "net/network.h" -#include "net/npchandler.h" -#include "net/playerhandler.h" -#include "net/protocol.h" -#include "net/skillhandler.h" -#include "net/tradehandler.h" +#endif #include "resources/imagewriter.h" @@ -105,7 +134,11 @@ Joystick *joystick = NULL; extern Window *weightNotice; extern Window *deathNotice; +#ifdef TMWSERV_SUPPORT +QuitDialog *quitDialog = NULL; +#else ConfirmDialog *exitConfirm = NULL; +#endif OkDialog *disconnectedDialog = NULL; ChatWindow *chatWindow; @@ -114,7 +147,9 @@ StatusWindow *statusWindow; MiniStatusWindow *miniStatusWindow; BuyDialog *buyDialog; SellDialog *sellDialog; +#ifdef EATHENA_SUPPORT BuySellDialog *buySellDialog; +#endif InventoryWindow *inventoryWindow; EmoteWindow *emoteWindow; NpcIntegerDialog *npcIntegerDialog; @@ -122,6 +157,15 @@ NpcListDialog *npcListDialog; NpcTextDialog *npcTextDialog; NpcStringDialog *npcStringDialog; SkillDialog *skillDialog; +#ifdef TMWSERV_SUPPORT +BuddyWindow *buddyWindow; +GuildWindow *guildWindow; +MagicDialog *magicDialog; +NpcPostDialog *npcPostDialog; +PartyWindow *partyWindow; +#else +StorageWindow *storageWindow; +#endif Minimap *minimap; EquipmentWindow *equipmentWindow; TradeWindow *tradeWindow; @@ -129,13 +173,19 @@ HelpWindow *helpWindow; DebugWindow *debugWindow; ShortcutWindow *itemShortcutWindow; ShortcutWindow *emoteShortcutWindow; -StorageWindow *storageWindow; BeingManager *beingManager = NULL; FloorItemManager *floorItemManager = NULL; -Particle* particleEngine = NULL; +ChannelManager *channelManager = NULL; +CommandHandler *commandHandler = NULL; +Particle *particleEngine = NULL; EffectManager *effectManager = NULL; +ChatTab *localChatTab = NULL; +#ifdef EATHENA_SUPPORT +Party *playerParty = NULL; +#endif + const int MAX_TIME = 10000; /** @@ -149,7 +199,9 @@ namespace { if (event.getId() == "yes" || event.getId() == "ok") done = true; +#ifdef EATHENA_SUPPORT exitConfirm = NULL; +#endif disconnectedDialog = NULL; } } exitListener; @@ -187,33 +239,56 @@ int get_elapsed_time(int start_time) /** * Create all the various globally accessible gui windows */ +#ifdef TMWSERV_SUPPORT +void createGuiWindows() +#else void createGuiWindows(Network *network) +#endif { // Create dialogs +#ifdef TMWSERV_SUPPORT + chatWindow = new ChatWindow; + buyDialog = new BuyDialog; + sellDialog = new SellDialog; + tradeWindow = new TradeWindow; + npcTextDialog = new NpcTextDialog; + npcIntegerDialog = new NpcIntegerDialog; + npcListDialog = new NpcListDialog; + npcStringDialog = new NpcStringDialog; + npcPostDialog = new NpcPostDialog(); + magicDialog = new MagicDialog(); + equipmentWindow = new EquipmentWindow(player_node->mEquipment.get()); + buddyWindow = new BuddyWindow(); + guildWindow = new GuildWindow(); + partyWindow = new PartyWindow(); +#else chatWindow = new ChatWindow(network); - menuWindow = new MenuWindow(); - statusWindow = new StatusWindow(player_node); - miniStatusWindow = new MiniStatusWindow(); buyDialog = new BuyDialog(network); sellDialog = new SellDialog(network); buySellDialog = new BuySellDialog(network); - inventoryWindow = new InventoryWindow(); - emoteWindow = new EmoteWindow(); + tradeWindow = new TradeWindow(network); + equipmentWindow = new EquipmentWindow; npcTextDialog = new NpcTextDialog(network); npcIntegerDialog = new NpcIntegerDialog(network); npcListDialog = new NpcListDialog(network); npcStringDialog = new NpcStringDialog(network); - skillDialog = new SkillDialog(); - minimap = new Minimap(); - equipmentWindow = new EquipmentWindow(); - tradeWindow = new TradeWindow(network); - helpWindow = new HelpWindow(); - debugWindow = new DebugWindow(); + storageWindow = new StorageWindow(network); +#endif + menuWindow = new MenuWindow; + statusWindow = new StatusWindow(player_node); + miniStatusWindow = new MiniStatusWindow; + inventoryWindow = new InventoryWindow; + emoteWindow = new EmoteWindow; + skillDialog = new SkillDialog; + minimap = new Minimap; + helpWindow = new HelpWindow; + debugWindow = new DebugWindow; itemShortcutWindow = new ShortcutWindow("ItemShortcut", new ItemShortcutContainer); emoteShortcutWindow = new ShortcutWindow("emoteShortcut", new EmoteShortcutContainer); - storageWindow = new StorageWindow(network); + + localChatTab = new ChatTab(_("General")); // Set initial window visibility chatWindow->setVisible((bool) config.getValue( @@ -222,6 +297,8 @@ void createGuiWindows(Network *network) miniStatusWindow->getPopupName() + "Visible", true)); buyDialog->setVisible(false); sellDialog->setVisible(false); + minimap->setVisible((bool) config.getValue( + minimap->getWindowName() + "Visible", true)); tradeWindow->setVisible(false); menuWindow->setVisible((bool) config.getValue( menuWindow->getPopupName() + "Visible", true)); @@ -231,12 +308,21 @@ void createGuiWindows(Network *network) emoteShortcutWindow->getWindowName() + "Visible", true)); minimap->setVisible((bool) config.getValue( minimap->getWindowName() + "Visible", true)); +#ifdef EATHENA_SUPPORT buySellDialog->setVisible(false); +#endif npcTextDialog->setVisible(false); npcIntegerDialog->setVisible(false); npcListDialog->setVisible(false); npcStringDialog->setVisible(false); +#ifdef EATHENA_SUPPORT storageWindow->setVisible(false); +#endif + + if (config.getValue("logToChat", 0)) + { + logger->setChatWindow(chatWindow); + } } /** @@ -245,19 +331,29 @@ void createGuiWindows(Network *network) void destroyGuiWindows() { logger->setChatWindow(NULL); + delete localChatTab; // Need to do this first, so it can remove itself delete chatWindow; delete statusWindow; delete miniStatusWindow; delete menuWindow; delete buyDialog; delete sellDialog; +#ifdef EATHENA_SUPPORT delete buySellDialog; +#endif delete inventoryWindow; delete emoteWindow; delete npcIntegerDialog; delete npcListDialog; delete npcTextDialog; delete npcStringDialog; +#ifdef TMWSERV_SUPPORT + delete npcPostDialog; + delete magicDialog; + delete buddyWindow; + delete guildWindow; + delete partyWindow; +#endif delete skillDialog; delete minimap; delete equipmentWindow; @@ -266,36 +362,61 @@ void destroyGuiWindows() delete debugWindow; delete itemShortcutWindow; delete emoteShortcutWindow; +#ifdef EATHENA_SUPPORT delete storageWindow; +#endif } +#ifdef TMWSERV_SUPPORT +Game::Game(): + mBeingHandler(new BeingHandler()), + mGuildHandler(new GuildHandler()), + mPartyHandler(new PartyHandler()), + mEffectHandler(new EffectHandler()), +#else Game::Game(Network *network): mNetwork(network), mBeingHandler(new BeingHandler(config.getValue("EnableSync", 0) == 1)), - mBuySellHandler(new BuySellHandler()), - mChatHandler(new ChatHandler()), - mEquipmentHandler(new EquipmentHandler()), - mInventoryHandler(new InventoryHandler()), - mItemHandler(new ItemHandler()), - mNpcHandler(new NPCHandler()), - mPlayerHandler(new PlayerHandler()), - mSkillHandler(new SkillHandler()), - mTradeHandler(new TradeHandler()) + mEquipmentHandler(new EquipmentHandler), + mSkillHandler(new SkillHandler), +#endif + mBuySellHandler(new BuySellHandler), + mChatHandler(new ChatHandler), + mInventoryHandler(new InventoryHandler), + mItemHandler(new ItemHandler), + mNpcHandler(new NPCHandler), + mPlayerHandler(new PlayerHandler), + mTradeHandler(new TradeHandler), + mLastTarget(Being::UNKNOWN), + mLogicCounterId(0), mSecondsCounterId(0) { + done = false; + +#ifdef TMWSERV_SUPPORT + createGuiWindows(); + engine = new Engine; + + beingManager = new BeingManager; + commandHandler = new CommandHandler(); +#else createGuiWindows(network); engine = new Engine(network); beingManager = new BeingManager(network); - floorItemManager = new FloorItemManager(); - effectManager = new EffectManager(); + commandHandler = new CommandHandler(network); +#endif + + floorItemManager = new FloorItemManager; + channelManager = new ChannelManager(); + effectManager = new EffectManager; particleEngine = new Particle(NULL); particleEngine->setupEngine(); - // Initialize timers + // Initialize logic and seconds counters tick_time = 0; - SDL_AddTimer(10, nextTick, NULL); // Logic counter - SDL_AddTimer(1000, nextSecond, NULL); // Seconds counter + mLogicCounterId = SDL_AddTimer(10, nextTick, NULL); + mSecondsCounterId = SDL_AddTimer(1000, nextSecond, NULL); // Initialize frame limiting config.addListener("fpslimit", this); @@ -303,7 +424,10 @@ Game::Game(Network *network): // Initialize beings beingManager->setPlayer(player_node); +#ifdef EATHENA_SUPPORT player_node->setNetwork(network); + playerParty = new Party(network); +#endif Joystick::init(); // TODO: The user should be able to choose which one to use @@ -311,6 +435,19 @@ Game::Game(Network *network): if (Joystick::getNumberOfJoysticks() > 0) joystick = new Joystick(0); +#ifdef TMWSERV_SUPPORT + Net::registerHandler(mBeingHandler.get()); + Net::registerHandler(mBuySellHandler.get()); + Net::registerHandler(mChatHandler.get()); + Net::registerHandler(mGuildHandler.get()); + Net::registerHandler(mInventoryHandler.get()); + Net::registerHandler(mItemHandler.get()); + Net::registerHandler(mNpcHandler.get()); + Net::registerHandler(mPartyHandler.get()); + Net::registerHandler(mPlayerHandler.get()); + Net::registerHandler(mTradeHandler.get()); + Net::registerHandler(mEffectHandler.get()); +#else network->registerHandler(mBeingHandler.get()); network->registerHandler(mBuySellHandler.get()); network->registerHandler(mChatHandler.get()); @@ -336,24 +473,38 @@ Game::Game(Network *network): msg.writeInt32(tick_time); engine->changeMap(map_path); +#endif setupWindow->setInGame(true); } Game::~Game() { - delete player_node; +#ifdef TMWSERV_SUPPORT + Net::clearHandlers(); +#else + delete playerParty; +#endif + destroyGuiWindows(); delete beingManager; + delete player_node; delete floorItemManager; + delete channelManager; + delete commandHandler; delete joystick; delete particleEngine; delete engine; + viewport->setMap(NULL); + player_node = NULL; beingManager = NULL; floorItemManager = NULL; joystick = NULL; + + SDL_RemoveTimer(mLogicCounterId); + SDL_RemoveTimer(mSecondsCounterId); } static bool saveScreenshot() @@ -374,11 +525,11 @@ static bool saveScreenshot() filenameSuffix.str(""); filename << PHYSFS_getUserDir(); #if (defined __USE_UNIX98 || defined __FreeBSD__) - filenameSuffix << ".aethyra/"; + filenameSuffix << ".tmw/"; #elif defined __APPLE__ filenameSuffix << "Desktop/"; #endif - filenameSuffix << "Ae_Screenshot_" << screenshotCount << ".png"; + filenameSuffix << "TMW_Screenshot_" << screenshotCount << ".png"; filename << filenameSuffix.str(); testExists.open(filename.str().c_str(), std::ios::in); found = !testExists.is_open(); @@ -391,11 +542,11 @@ static bool saveScreenshot() { std::stringstream chatlogentry; chatlogentry << _("Screenshot saved to ~/") << filenameSuffix.str(); - chatWindow->chatLog(chatlogentry.str(), BY_SERVER); + localChatTab->chatLog(chatlogentry.str(), BY_SERVER); } else { - chatWindow->chatLog(_("Saving screenshot failed!"), BY_SERVER); + localChatTab->chatLog(_("Saving screenshot failed!"), BY_SERVER); logger->log("Error: could not save screenshot."); } @@ -467,6 +618,10 @@ void Game::logic() } // Handle network stuff +#ifdef TMWSERV_SUPPORT + Net::flush(); + // TODO: Fix notification when the connection is lost +#else mNetwork->flush(); mNetwork->dispatchMessages(); @@ -482,6 +637,7 @@ void Game::logic() disconnectedDialog->requestMoveToTop(); } } +#endif } } @@ -510,6 +666,23 @@ void Game::handleInput() return; } +#ifdef TMWSERV_SUPPORT + // send straight to gui for certain windows + if (npcPostDialog->isVisible()) + { + try + { + guiInput->pushInput(event); + } + catch (gcn::Exception e) + { + const char* err = e.getMessage().c_str(); + logger->log("Warning: guichan input exception: %s", err); + } + return; + } +#endif + // Mode switch to emotes if (keyboard.isKeyActive(keyboard.KEY_EMOTE)) { @@ -523,58 +696,54 @@ void Game::handleInput() } } - if (keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT) || - keyboard.isKeyActive(keyboard.KEY_OK)) - { - // Input chat window - if (!(chatWindow->isInputFocused() || - deathNotice || - weightNotice)) + if (!(chatWindow->isInputFocused() || deathNotice || weightNotice)) + if (keyboard.isKeyActive(keyboard.KEY_OK)) { - // Quit by pressing Enter if the exit confirm is there +#ifdef TMWSERV_SUPPORT + // Don not focus chat input when quit dialog is active + if (quitDialog != NULL && quitDialog->isVisible()) + continue; +#else if (exitConfirm && keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT)) done = true; +#endif // Close the Browser if opened else if (helpWindow->isVisible() && - keyboard.isKeyActive(keyboard.KEY_OK)) + keyboard.isKeyActive(keyboard.KEY_OK)) helpWindow->setVisible(false); // Close the config window, cancelling changes if opened else if (setupWindow->isVisible() && - keyboard.isKeyActive(keyboard.KEY_OK)) + keyboard.isKeyActive(keyboard.KEY_OK)) setupWindow->action(gcn::ActionEvent(NULL, "cancel")); // Submits the text and proceeds to the next dialog else if (npcStringDialog->isVisible() && - keyboard.isKeyActive(keyboard.KEY_OK)) + keyboard.isKeyActive(keyboard.KEY_OK)) npcStringDialog->action(gcn::ActionEvent(NULL, "ok")); // Proceed to the next dialog option, or close the window else if (npcTextDialog->isVisible() && - keyboard.isKeyActive(keyboard.KEY_OK)) + keyboard.isKeyActive(keyboard.KEY_OK)) npcTextDialog->action(gcn::ActionEvent(NULL, "ok")); // Choose the currently highlighted dialogue option else if (npcListDialog->isVisible() && - keyboard.isKeyActive(keyboard.KEY_OK)) + keyboard.isKeyActive(keyboard.KEY_OK)) npcListDialog->action(gcn::ActionEvent(NULL, "ok")); // Submits the text and proceeds to the next dialog else if (npcIntegerDialog->isVisible() && - keyboard.isKeyActive(keyboard.KEY_OK)) + keyboard.isKeyActive(keyboard.KEY_OK)) npcIntegerDialog->action(gcn::ActionEvent(NULL, "ok")); - else if (!(keyboard.getKeyValue( - KeyboardConfig::KEY_TOGGLE_CHAT) == - keyboard.getKeyValue( - KeyboardConfig::KEY_OK) && - (helpWindow->isVisible() || - setupWindow->isVisible() || - npcStringDialog->isVisible() || - npcTextDialog->isVisible() || - npcListDialog->isVisible() || - npcIntegerDialog->isVisible()))) + /* + else if (guildWindow->isVisible()) { - chatWindow->requestChatFocus(); - used = true; + // TODO: Check if a dialog is open and close it if so } + */ + } + if (keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT)) + { + if (chatWindow->requestChatFocus()) + used = true; } - } const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); switch (tKey) @@ -607,6 +776,17 @@ void Game::handleInput() break; // Quitting confirmation dialog case KeyboardConfig::KEY_QUIT: +#ifdef TMWSERV_SUPPORT + if (!quitDialog) + { + quitDialog = new QuitDialog(&done, &quitDialog); + quitDialog->requestMoveToTop(); + } + else + { + quitDialog->action(gcn::ActionEvent(NULL, "cancel")); + } +#else if (!exitConfirm) { exitConfirm = new ConfirmDialog(_("Quit"), @@ -619,6 +799,7 @@ void Game::handleInput() { exitConfirm->action(gcn::ActionEvent(NULL, _("no"))); } +#endif break; default: break; @@ -649,25 +830,34 @@ void Game::handleInput() { case KeyboardConfig::KEY_PICKUP: { - FloorItem *item = floorItemManager->findByCoordinates( - player_node->mX, - player_node->mY); +#ifdef TMWSERV_SUPPORT + const Vector &pos = player_node->getPosition(); + Uint16 x = (int) pos.x / 32; + Uint16 y = (int) pos.y / 32; +#else + Uint16 x = player_node->mX; + Uint16 y = player_node->mY; +#endif + 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->getDirection() & Being::UP) - y--; - if (player_node->getDirection() & Being::DOWN) - y++; - if (player_node->getDirection() & Being::LEFT) - x--; - if (player_node->getDirection() & Being::RIGHT) - x++; - item = floorItemManager->findByCoordinates(x, y); + // Temporary until tile-based picking is + // removed. + switch (player_node->getSpriteDirection()) + { + case DIRECTION_UP : --y; break; + case DIRECTION_DOWN : ++y; break; + case DIRECTION_LEFT : --x; break; + case DIRECTION_RIGHT: ++x; break; + default: break; + } + + item = floorItemManager->findByCoordinates( + x, y); } if (item) @@ -693,6 +883,10 @@ void Game::handleInput() equipmentWindow->setVisible(false); helpWindow->setVisible(false); debugWindow->setVisible(false); +#ifdef TMWSERV_SUPPORT + guildWindow->setVisible(false); + buddyWindow->setVisible(false); +#endif } break; case KeyboardConfig::KEY_WINDOW_STATUS: @@ -744,16 +938,16 @@ void Game::handleInput() unsigned int deflt = player_relations.getDefault(); if (deflt & PlayerRelation::TRADE) { - chatWindow->chatLog( - _("Ignoring incoming trade requests"), - BY_SERVER); + localChatTab->chatLog( + _("Ignoring incoming trade requests"), + BY_SERVER); deflt &= ~PlayerRelation::TRADE; } else { - chatWindow->chatLog( - _("Accepting incoming trade requests"), - BY_SERVER); + localChatTab->chatLog( + _("Accepting incoming trade requests"), + BY_SERVER); deflt |= PlayerRelation::TRADE; } @@ -791,6 +985,7 @@ void Game::handleInput() logger->log("Warning: guichan input exception: %s", err); } } + } // End while // If the user is configuring the keys then don't respond. @@ -799,7 +994,10 @@ void Game::handleInput() // Moving player around if (player_node->mAction != Being::DEAD && - current_npc == 0 && !chatWindow->isInputFocused()) +#ifdef EATHENA_SUPPORT + current_npc == 0 && +#endif + !chatWindow->isInputFocused()) { // Get the state of the keyboard keys keyboard.refreshActiveKeys(); @@ -813,41 +1011,67 @@ void Game::handleInput() return; } +#ifdef TMWSERV_SUPPORT + const Vector &pos = player_node->getPosition(); + const Uint16 x = (int) pos.x / 32; + const Uint16 y = (int) pos.y / 32; +#else const Uint16 x = player_node->mX; const Uint16 y = player_node->mY; +#endif unsigned char direction = 0; // Translate pressed keys to movement and direction if (keyboard.isKeyActive(keyboard.KEY_MOVE_UP) || - (joystick && joystick->isUp())) + (joystick && joystick->isUp())) { direction |= Being::UP; } else if (keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN) || - (joystick && joystick->isDown())) + (joystick && joystick->isDown())) { direction |= Being::DOWN; } if (keyboard.isKeyActive(keyboard.KEY_MOVE_LEFT) || - (joystick && joystick->isLeft())) + (joystick && joystick->isLeft())) { direction |= Being::LEFT; } else if (keyboard.isKeyActive(keyboard.KEY_MOVE_RIGHT) || - (joystick && joystick->isRight())) + (joystick && joystick->isRight())) { direction |= Being::RIGHT; } +#ifdef TMWSERV_SUPPORT + // First if player is pressing key for the direction he is already + // going + if (direction == player_node->getWalkingDir()) + { + player_node->setWalkingDir(direction); + } + // Else if he is pressing a key, and its different from what he has + // been pressing, stop (do not send this stop to the server) and + // start in the new direction + else if (direction && direction != player_node->getWalkingDir()) + { + player_node->stopWalking(false); + player_node->setWalkingDir(direction); + } + // Else, he is not pressing a key, stop (sending to server) + else + { + player_node->stopWalking(true); + } +#else player_node->setWalkingDir(direction); // Attacking monsters if (keyboard.isKeyActive(keyboard.KEY_ATTACK) || (joystick && joystick->buttonPressed(0))) { - Being *target = beingManager->findNearestLivingBeing(x, y, 20, - Being::MONSTER); + Being *target = NULL; bool newTarget = !keyboard.isKeyActive(keyboard.KEY_TARGET); // A set target has highest priority @@ -864,47 +1088,41 @@ void Game::handleInput() default: break; } - // Attack priorioty is: Monster, Player, auto target - target = beingManager->findBeing(targetX, targetY, - Being::MONSTER); - if (!target) - target = beingManager->findBeing(targetX, targetY, - Being::PLAYER); + // Only auto target Monsters + target = beingManager->findNearestLivingBeing(targetX, targetY, + 20, Being::MONSTER); } player_node->attack(target, newTarget); } +#endif - // Target the nearest player if 'q' is pressed - if ( keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) && - !keyboard.isKeyActive(keyboard.KEY_TARGET) ) - { - Being *target = beingManager->findNearestLivingBeing(player_node, - 20, Being::PLAYER); - - player_node->setTarget(target); - } - - // Target the nearest monster if 'a' pressed - if ((keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) || - (joystick && joystick->buttonPressed(3))) && - !keyboard.isKeyActive(keyboard.KEY_TARGET)) + // Target the nearest player/monster/npc + if ((keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) || + keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) || + keyboard.isKeyActive(keyboard.KEY_TARGET_NPC) || + (joystick && joystick->buttonPressed(3))) && + !keyboard.isKeyActive(keyboard.KEY_TARGET)) { - Being *target = beingManager->findNearestLivingBeing( - x, y, 20, Being::MONSTER); - - player_node->setTarget(target); - } + Being::Type currentTarget = Being::UNKNOWN; + if (keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) || + (joystick && joystick->buttonPressed(3))) + currentTarget = Being::MONSTER; + else if (keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER)) + currentTarget = Being::PLAYER; + else if (keyboard.isKeyActive(keyboard.KEY_TARGET_NPC)) + currentTarget = Being::NPC; - // Target the nearest npc if 'n' pressed - if ( keyboard.isKeyActive(keyboard.KEY_TARGET_NPC) && - !keyboard.isKeyActive(keyboard.KEY_TARGET) ) - { - Being *target = beingManager->findNearestLivingBeing( - x, y, 20, Being::NPC); + Being *target = beingManager->findNearestLivingBeing(player_node, + 20, currentTarget); - player_node->setTarget(target); - } + if (target && (target != player_node->getTarget() || + currentTarget != mLastTarget)) + { + player_node->setTarget(target); + mLastTarget = currentTarget; + } + } else mLastTarget = Being::UNKNOWN; // Reset last target // Talk to the nearest NPC if 't' pressed if ( keyboard.isKeyActive(keyboard.KEY_TALK) ) @@ -914,12 +1132,6 @@ void Game::handleInput() { Being *target = player_node->getTarget(); - if (!target) - { - target = beingManager->findNearestLivingBeing( - x, y, 20, Being::NPC); - } - if (target) { if (target->getType() == Being::NPC) @@ -928,11 +1140,13 @@ void Game::handleInput() } } +#ifdef EATHENA_SUPPORT // Stop attacking if shift is pressed if (keyboard.isKeyActive(keyboard.KEY_TARGET)) { player_node->stopAttack(); } +#endif if (joystick) { @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,10 +24,14 @@ #include <memory> +#include "SDL.h" + #include "configlistener.h" class MessageHandler; +#ifdef EATHENA_SUPPORT class Network; +#endif extern std::string map_path; extern volatile int fps; @@ -37,7 +40,11 @@ extern volatile int tick_time; class Game : public ConfigListener { public: +#ifdef TMWSERV_SUPPORT + Game(); +#else Game(Network *network); +#endif ~Game(); void logic(); @@ -47,7 +54,9 @@ class Game : public ConfigListener void optionChanged(const std::string &name); private: +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif /** Used to determine whether to draw the next frame. */ int mDrawTime; @@ -57,15 +66,27 @@ class Game : public ConfigListener typedef const std::auto_ptr<MessageHandler> MessageHandlerPtr; MessageHandlerPtr mBeingHandler; +#ifdef TMWSERV_SUPPORT + MessageHandlerPtr mGuildHandler; + MessageHandlerPtr mPartyHandler; + MessageHandlerPtr mEffectHandler; +#else + MessageHandlerPtr mEquipmentHandler; + MessageHandlerPtr mSkillHandler; +#endif MessageHandlerPtr mBuySellHandler; MessageHandlerPtr mChatHandler; - MessageHandlerPtr mEquipmentHandler; MessageHandlerPtr mInventoryHandler; MessageHandlerPtr mItemHandler; MessageHandlerPtr mNpcHandler; MessageHandlerPtr mPlayerHandler; - MessageHandlerPtr mSkillHandler; + MessageHandlerPtr mPostHandler; MessageHandlerPtr mTradeHandler; + + int mLastTarget; + + SDL_TimerID mLogicCounterId; + SDL_TimerID mSecondsCounterId; }; /** diff --git a/src/graphics.cpp b/src/graphics.cpp index ca86f536..2fbf5e20 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -242,7 +241,7 @@ void Graphics::updateScreen() SDL_Flip(mScreen); } -SDL_Surface* Graphics::getScreenshot() +SDL_Surface *Graphics::getScreenshot() { #if SDL_BYTEORDER == SDL_BIG_ENDIAN int rmask = 0xff000000; diff --git a/src/graphics.h b/src/graphics.h index ec0b5e9c..2b6ca60e 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -59,7 +58,7 @@ struct ImageRect RIGHT = 5, LOWER_LEFT = 6, LOWER_CENTER = 7, - LOWER_RIGHT = 8, + LOWER_RIGHT = 8 }; Image *grid[9]; diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp index 46c8bdf1..2f667237 100644 --- a/src/gui/browserbox.cpp +++ b/src/gui/browserbox.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -419,4 +418,3 @@ void BrowserBox::draw(gcn::Graphics *graphics) setHeight((mTextRows.size() + wrappedLines) * font->getHeight()); } } - diff --git a/src/gui/browserbox.h b/src/gui/browserbox.h index 500c9fba..090c03e1 100644 --- a/src/gui/browserbox.h +++ b/src/gui/browserbox.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -163,4 +162,3 @@ class BrowserBox : public gcn::Widget, public gcn::MouseListener }; #endif - diff --git a/src/gui/buddywindow.cpp b/src/gui/buddywindow.cpp new file mode 100644 index 00000000..37301c86 --- /dev/null +++ b/src/gui/buddywindow.cpp @@ -0,0 +1,68 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "buddywindow.h" +#include "chat.h" +#include "icon.h" + +#include "widgets/avatar.h" + +#include "../resources/resourcemanager.h" +#include "../utils/gettext.h" + +extern ChatWindow *chatWindow; + +BuddyWindow::BuddyWindow(): + Window(_("Buddy")) +{ + setVisible(false); + setWindowName("Buddy Window"); + setCaption(_("Buddy List")); + setResizable(true); + setCloseButton(true); + setMinWidth(110); + setMinHeight(200); + setDefaultSize(124, 41, 288, 330); + + Image *addImg = ResourceManager::getInstance()->getImage("buddyadd.png"); + Image *delImg = ResourceManager::getInstance()->getImage("buddydel.png"); + + if (addImg && delImg) + { + Icon *addBuddy = new Icon(addImg); + Icon *delBuddy = new Icon(delImg); + + add(addBuddy); + add(delBuddy); + } + + loadWindowState(); +} + +void BuddyWindow::action(const gcn::ActionEvent &event) +{ + +} + +void BuddyWindow::draw(gcn::Graphics *graphics) +{ + Window::draw(graphics); +} diff --git a/src/gui/buddywindow.h b/src/gui/buddywindow.h new file mode 100644 index 00000000..aa654477 --- /dev/null +++ b/src/gui/buddywindow.h @@ -0,0 +1,60 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef BUDDYWINDOW_H +#define BUDDYWINDOW_H + +#include <guichan/actionlistener.hpp> +#include <guichan/actionevent.hpp> + +#include "window.h" + +class Avatar; + +/** + * Window showing buddy list. + * + * \ingroup Interface + */ +class BuddyWindow : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + */ + BuddyWindow(); + + /** + * Performs action. + */ + void action(const gcn::ActionEvent &event); + + /** + * Draws the window + */ + void draw(gcn::Graphics *graphics); + + + private: + std::list<Avatar*> mBuddyList; +}; + +#endif /* BUDDYWINDOW_H */ diff --git a/src/gui/button.cpp b/src/gui/button.cpp index 16a2853c..28b7c0d7 100644 --- a/src/gui/button.cpp +++ b/src/gui/button.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,7 +66,7 @@ Button::Button(): init(); } -Button::Button(const std::string& caption, const std::string &actionEventId, +Button::Button(const std::string &caption, const std::string &actionEventId, gcn::ActionListener *listener): gcn::Button(caption), mIsLogged(false) diff --git a/src/gui/button.h b/src/gui/button.h index f21d2661..abaf5c43 100644 --- a/src/gui/button.h +++ b/src/gui/button.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp index 43c423f1..6df2ae25 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,29 +19,45 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "button.h" -#include "buy.h" -#include "label.h" -#include "scrollarea.h" -#include "shop.h" -#include "shoplistbox.h" -#include "slider.h" +#include "gui/buy.h" -#include "widgets/layout.h" +#include "gui/button.h" +#include "gui/label.h" +#include "gui/scrollarea.h" +#include "gui/shop.h" +#include "gui/shoplistbox.h" +#include "gui/slider.h" -#include "../npc.h" +#include "gui/widgets/layout.h" -#include "../net/messageout.h" -#include "../net/protocol.h" +#include "npc.h" +#include "shopitem.h" +#include "units.h" -#include "../utils/gettext.h" -#include "../utils/strprintf.h" +#ifdef TMWSERV_SUPPORT +#include "net/tmwserv/gameserver/player.h" +#else +#include "net/messageout.h" +#include "net/ea/protocol.h" +#endif +#include "resources/iteminfo.h" + +#include "utils/gettext.h" +#include "utils/strprintf.h" + +#ifdef TMWSERV_SUPPORT +BuyDialog::BuyDialog(): +#else BuyDialog::BuyDialog(Network *network): - Window("Buy"), mNetwork(network), +#endif + Window(_("Buy")), +#ifndef TMWSERV_SUPPORT + mNetwork(network), +#endif mMoney(0), mAmountItems(0), mMaxItems(0) { - setWindowName(_("Buy")); + setWindowName("Buy"); setResizable(true); setCloseButton(true); setMinWidth(260); @@ -56,10 +71,10 @@ BuyDialog::BuyDialog(Network *network): mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); mSlider = new Slider(1.0); - mQuantityLabel = new Label(strprintf("%d / %d", mAmountItems, mMaxItems)); mQuantityLabel->setAlignment(gcn::Graphics::CENTER); - mMoneyLabel = new Label(strprintf(_("Price: %d GP / Total: %d GP"), 0, 0)); + mMoneyLabel = new gcn::Label(strprintf(_("Price: %s / Total: %s"), + "", "")); mIncreaseButton = new Button("+", "+", this); mDecreaseButton = new Button("-", "-", this); @@ -99,6 +114,7 @@ BuyDialog::BuyDialog(Network *network): Layout &layout = getLayout(); layout.setRowHeight(0, Layout::AUTO_SET); + center(); loadWindowState(); } @@ -127,9 +143,9 @@ void BuyDialog::reset() setMoney(0); } -void BuyDialog::addItem(int id, int price) +void BuyDialog::addItem(int id, int amount, int price) { - mShopItems->addItem(id, price); + mShopItems->addItem(id, amount, price); mShopItemList->adjustSize(); } @@ -179,11 +195,16 @@ void BuyDialog::action(const gcn::ActionEvent &event) else if (event.getId() == "buy" && mAmountItems > 0 && mAmountItems <= mMaxItems) { +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::tradeWithNPC + (mShopItems->at(selectedItem)->getId(), mAmountItems); +#else MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_BUY_REQUEST); outMsg.writeInt16(8); outMsg.writeInt16(mAmountItems); outMsg.writeInt16(mShopItems->at(selectedItem)->getId()); +#endif // Update money and adjust the max number of items that can be bought mMaxItems -= mAmountItems; @@ -250,7 +271,16 @@ void BuyDialog::updateButtonsAndLabels() // Update quantity and money labels mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems)); mMoneyLabel->setCaption - (strprintf(_("Price: %d GP / Total: %d GP"), price, mMoney - price)); + (strprintf(_("Price: %s / Total: %s"), + Units::formatCurrency(price).c_str(), + Units::formatCurrency(mMoney - price).c_str())); +} + +void BuyDialog::logic() +{ + Window::logic(); + + if (!current_npc) setVisible(false); } void BuyDialog::setVisible(bool visible) diff --git a/src/gui/buy.h b/src/gui/buy.h index ffd3f5c9..200394b9 100644 --- a/src/gui/buy.h +++ b/src/gui/buy.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,11 +25,13 @@ #include <guichan/actionlistener.hpp> #include <guichan/selectionlistener.hpp> -#include <SDL_types.h> - #include "window.h" +#include "../guichanfwd.h" + +#ifndef TMWSERV_SUPPORT class Network; +#endif class ShopItems; class ShopListBox; class ListBox; @@ -49,7 +50,11 @@ class BuyDialog : public Window, public gcn::ActionListener, * * @see Window::Window */ +#ifdef TMWSERV_SUPPORT + BuyDialog(); +#else BuyDialog(Network *network); +#endif /** * Destructor @@ -69,7 +74,7 @@ class BuyDialog : public Window, public gcn::ActionListener, /** * Adds an item to the shop inventory. */ - void addItem(int id, int price); + void addItem(int id, int amount, int price); /** * Called when receiving actions from the widgets. @@ -97,6 +102,11 @@ class BuyDialog : public Window, public gcn::ActionListener, void updateButtonsAndLabels(); /** + * Check for current NPC + */ + void logic(); + + /** * Sets the visibility of this window. */ void setVisible(bool visible); @@ -106,7 +116,9 @@ class BuyDialog : public Window, public gcn::ActionListener, */ void close(); private: +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif gcn::Button *mBuyButton; gcn::Button *mQuitButton; gcn::Button *mAddMaxButton; @@ -122,9 +134,9 @@ class BuyDialog : public Window, public gcn::ActionListener, ShopItems *mShopItems; - Uint32 mMoney; - Uint32 mAmountItems; - Uint32 mMaxItems; + int mMoney; + int mAmountItems; + int mMaxItems; }; extern BuyDialog *buyDialog; diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp index df222797..b9a6a1dc 100644 --- a/src/gui/buysell.cpp +++ b/src/gui/buysell.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,7 +25,9 @@ #include "../npc.h" #include "../net/messageout.h" -#include "../net/protocol.h" +#ifdef EATHENA_SUPPORT +#include "../net/ea/protocol.h" +#endif #include "../utils/gettext.h" @@ -43,16 +44,18 @@ BuySellDialog::BuySellDialog(Network *network): for (const char **curBtn = buttonNames; *curBtn; curBtn++) { Button *btn = new Button(gettext(*curBtn), *curBtn, this); - if (!buyButton) buyButton = btn; // For focus request + if (!buyButton) + buyButton = btn; // For focus request btn->setPosition(x, y); add(btn); x += btn->getWidth() + 10; } buyButton->requestFocus(); - setDefaultSize(x + getPadding(), (2 * y + buyButton->getHeight() + - getTitleBarHeight()), ImageRect::CENTER); + setContentSize(x, 2 * y + buyButton->getHeight()); + center(); + setDefaultSize(); loadWindowState(); } @@ -77,7 +80,7 @@ void BuySellDialog::action(const gcn::ActionEvent &event) setVisible(false); int action = 0; - NPC::mTalking = false; + NPC::isTalking = false; if (event.getId() == "Buy") { @@ -93,8 +96,10 @@ void BuySellDialog::action(const gcn::ActionEvent &event) return; } +#ifdef EATHENA_SUPPORT MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST); outMsg.writeInt32(current_npc); outMsg.writeInt8(action); +#endif } diff --git a/src/gui/buysell.h b/src/gui/buysell.h index c6989709..4b137554 100644 --- a/src/gui/buysell.h +++ b/src/gui/buysell.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,8 +45,6 @@ class BuySellDialog : public Window, public gcn::ActionListener BuySellDialog(Network *network); /** -<<<<<<< HEAD:src/gui/buysell.h -======= * Check for current NPC */ void logic(); @@ -55,7 +52,6 @@ class BuySellDialog : public Window, public gcn::ActionListener void setVisible(bool visible); /** ->>>>>>> f64903f... Fix up the NPC interraction widnows a bit:src/gui/buysell.h * Called when receiving actions from the widgets. */ void action(const gcn::ActionEvent &event); diff --git a/src/gui/changeemaildialog.cpp b/src/gui/changeemaildialog.cpp new file mode 100644 index 00000000..0ed95bd7 --- /dev/null +++ b/src/gui/changeemaildialog.cpp @@ -0,0 +1,167 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "changeemaildialog.h" + +#include <string> +#include <sstream> + +#include <guichan/widgets/label.hpp> + +#include "../main.h" +#include "../log.h" +#include "../logindata.h" + +#include "button.h" +#include "register.h" +#include "textfield.h" +#include "ok_dialog.h" + +#include "../utils/gettext.h" +#include "../utils/strprintf.h" + +ChangeEmailDialog::ChangeEmailDialog(Window *parent, LoginData *loginData): + Window(_("Change Email Address"), true, parent), + mWrongDataNoticeListener(new WrongDataNoticeListener()), + mLoginData(loginData) +{ + gcn::Label *accountLabel = new gcn::Label(strprintf(_("Account: %s"), + mLoginData->username.c_str())); + gcn::Label *newEmailLabel = new gcn::Label(_("Type New Email Address twice:")); + mFirstEmailField = new TextField(); + mSecondEmailField = new TextField(); + mChangeEmailButton = new Button(_("Change Email Address"), "change_email", this); + mCancelButton = new Button(_("Cancel"), "cancel", this); + + const int width = 200; + const int height = 130; + setContentSize(width, height); + + accountLabel->setPosition(5, 5); + accountLabel->setWidth(130); + + newEmailLabel->setPosition( + 5, accountLabel->getY() + accountLabel->getHeight() + 7); + newEmailLabel->setWidth(width - 5); + + mFirstEmailField->setPosition( + 5, newEmailLabel->getY() + newEmailLabel->getHeight() + 7); + mFirstEmailField->setWidth(130); + + mSecondEmailField->setPosition( + 5, mFirstEmailField->getY() + mFirstEmailField->getHeight() + 7); + mSecondEmailField->setWidth(130); + + mCancelButton->setPosition( + width - 5 - mCancelButton->getWidth(), + height - 5 - mCancelButton->getHeight()); + mChangeEmailButton->setPosition( + mCancelButton->getX() - 5 - mChangeEmailButton->getWidth(), + mCancelButton->getY()); + + add(accountLabel); + add(newEmailLabel); + add(mFirstEmailField); + add(mSecondEmailField); + add(mChangeEmailButton); + add(mCancelButton); + + setLocationRelativeTo(getParent()); + setVisible(true); + mFirstEmailField->requestFocus(); + + mFirstEmailField->setActionEventId("change_email"); + mSecondEmailField->setActionEventId("change_email"); +} + +ChangeEmailDialog::~ChangeEmailDialog() +{ + delete mWrongDataNoticeListener; +} + +void +ChangeEmailDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "cancel") + { + scheduleDelete(); + } + else if (event.getId() == "change_email") + { + + const std::string username = mLoginData->username.c_str(); + const std::string newFirstEmail = mFirstEmailField->getText(); + const std::string newSecondEmail = mSecondEmailField->getText(); + logger->log("ChangeEmailDialog::Email change, Username is %s", + username.c_str()); + + std::stringstream errorMsg; + int error = 0; + + if (newFirstEmail.length() < LEN_MIN_PASSWORD) + { + // First email address too short + errorMsg << "The new email address needs to be at least " + << LEN_MIN_PASSWORD + << " characters long."; + error = 1; + } + else if (newFirstEmail.length() > LEN_MAX_PASSWORD - 1 ) + { + // First email address too long + errorMsg << "The new email address needs to be less than " + << LEN_MAX_PASSWORD + << " characters long."; + error = 1; + } + else if (newFirstEmail != newSecondEmail) + { + // Second Pass mismatch + errorMsg << "The email address entries mismatch."; + error = 2; + } + + if (error > 0) + { + if (error == 1) + { + mWrongDataNoticeListener->setTarget(this->mFirstEmailField); + } + else if (error == 2) + { + mWrongDataNoticeListener->setTarget(this->mSecondEmailField); + } + + OkDialog *dlg = new OkDialog("Error", errorMsg.str()); + dlg->addActionListener(mWrongDataNoticeListener); + } + else + { + // No errors detected, change account password. + mChangeEmailButton->setEnabled(false); + // Set the new email address + mLoginData->newEmail = newFirstEmail; + state = STATE_CHANGEEMAIL_ATTEMPT; + scheduleDelete(); + } + + } +} diff --git a/src/gui/changeemaildialog.h b/src/gui/changeemaildialog.h new file mode 100644 index 00000000..145c54b1 --- /dev/null +++ b/src/gui/changeemaildialog.h @@ -0,0 +1,72 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GUI_CHANGEEMAIL_H +#define GUI_CHANGEEMAIL_H + +#include <iosfwd> +#include <guichan/actionlistener.hpp> + +#include "window.h" +#include "../guichanfwd.h" + +class LoginData; +class OkDialog; +class WrongDataNoticeListener; + +/** + * The Change email dialog. + * + * \ingroup Interface + */ +class ChangeEmailDialog : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + * + * @see Window::Window + */ + ChangeEmailDialog(Window *parent, LoginData *loginData); + + /** + * Destructor. + */ + ~ChangeEmailDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + private: + gcn::TextField *mFirstEmailField; + gcn::TextField *mSecondEmailField; + + gcn::Button *mChangeEmailButton; + gcn::Button *mCancelButton; + + WrongDataNoticeListener *mWrongDataNoticeListener; + + LoginData *mLoginData; +}; + +#endif // GUI_CHANGEEMAIL_H diff --git a/src/gui/changepassworddialog.cpp b/src/gui/changepassworddialog.cpp new file mode 100644 index 00000000..7c1e5bcd --- /dev/null +++ b/src/gui/changepassworddialog.cpp @@ -0,0 +1,193 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "changepassworddialog.h" + +#include <string> +#include <sstream> + +#include <guichan/widgets/label.hpp> + +#include "../main.h" +#include "../log.h" +#include "../logindata.h" + +#include "button.h" +#include "register.h" +#include "passwordfield.h" +#include "textfield.h" +#include "ok_dialog.h" + +#include "../utils/gettext.h" +#include "../utils/strprintf.h" + +ChangePasswordDialog::ChangePasswordDialog(Window *parent, LoginData *loginData): + Window(_("Change Password"), true, parent), + mWrongDataNoticeListener(new WrongDataNoticeListener()), + mLoginData(loginData) +{ + gcn::Label *accountLabel = new gcn::Label(strprintf(_("Account: %s"), + mLoginData->username.c_str())); + gcn::Label *oldPassLabel = new gcn::Label(_("Password:")); + mOldPassField = new PasswordField(); + gcn::Label *newPassLabel = new gcn::Label(_("Type New Password twice:")); + mFirstPassField = new PasswordField(); + mSecondPassField = new PasswordField(); + mChangePassButton = new Button(_("Change Password"), "change_password", this); + mCancelButton = new Button(_("Cancel"), "cancel", this); + + const int width = 200; + const int height = 170; + setContentSize(width, height); + + accountLabel->setPosition(5, 5); + accountLabel->setWidth(130); + oldPassLabel->setPosition( + 5, accountLabel->getY() + accountLabel->getHeight() + 7); + oldPassLabel->setWidth(130); + + mOldPassField->setPosition( + 5, oldPassLabel->getY() + oldPassLabel->getHeight() + 7); + mOldPassField->setWidth(130); + + newPassLabel->setPosition( + 5, mOldPassField->getY() + mOldPassField->getHeight() + 7); + newPassLabel->setWidth(width - 5); + + mFirstPassField->setPosition( + 5, newPassLabel->getY() + newPassLabel->getHeight() + 7); + mFirstPassField->setWidth(130); + + mSecondPassField->setPosition( + 5, mFirstPassField->getY() + mFirstPassField->getHeight() + 7); + mSecondPassField->setWidth(130); + + mCancelButton->setPosition( + width - 5 - mCancelButton->getWidth(), + height - 5 - mCancelButton->getHeight()); + mChangePassButton->setPosition( + mCancelButton->getX() - 5 - mChangePassButton->getWidth(), + mCancelButton->getY()); + + add(accountLabel); + add(oldPassLabel); + add(mOldPassField); + add(newPassLabel); + add(mFirstPassField); + add(mSecondPassField); + add(mChangePassButton); + add(mCancelButton); + + setLocationRelativeTo(getParent()); + setVisible(true); + mOldPassField->requestFocus(); + + mOldPassField->setActionEventId("change_password"); + mFirstPassField->setActionEventId("change_password"); + mSecondPassField->setActionEventId("change_password"); +} + +ChangePasswordDialog::~ChangePasswordDialog() +{ + delete mWrongDataNoticeListener; +} + +void +ChangePasswordDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "cancel") + { + scheduleDelete(); + } + else if (event.getId() == "change_password") + { + + const std::string username = mLoginData->username.c_str(); + const std::string oldPassword = mOldPassField->getText(); + const std::string newFirstPass = mFirstPassField->getText(); + const std::string newSecondPass = mSecondPassField->getText(); + logger->log("ChangePasswordDialog::Password change, Username is %s", + username.c_str()); + + std::stringstream errorMsg; + int error = 0; + + // Check old Password + if (oldPassword.empty()) + { + // No old password + errorMsg << "Enter the old Password first."; + error = 1; + } + else if (newFirstPass.length() < LEN_MIN_PASSWORD) + { + // First password too short + errorMsg << "The new password needs to be at least " + << LEN_MIN_PASSWORD + << " characters long."; + error = 2; + } + else if (newFirstPass.length() > LEN_MAX_PASSWORD - 1 ) + { + // First password too long + errorMsg << "The new password needs to be less than " + << LEN_MAX_PASSWORD + << " characters long."; + error = 2; + } + else if (newFirstPass != newSecondPass) + { + // Second Pass mismatch + errorMsg << "The new password entries mismatch."; + error = 3; + } + + if (error > 0) + { + if (error == 1) + { + mWrongDataNoticeListener->setTarget(this->mOldPassField); + } + else if (error == 2) + { + mWrongDataNoticeListener->setTarget(this->mFirstPassField); + } + else if (error == 3) + { + mWrongDataNoticeListener->setTarget(this->mSecondPassField); + } + + OkDialog *dlg = new OkDialog("Error", errorMsg.str()); + dlg->addActionListener(mWrongDataNoticeListener); + } + else + { + // No errors detected, change account password. + mChangePassButton->setEnabled(false); + // Set the new password + mLoginData->password = oldPassword; + mLoginData->newPassword = newFirstPass; + state = STATE_CHANGEPASSWORD_ATTEMPT; + scheduleDelete(); + } + + } +} diff --git a/src/gui/changepassworddialog.h b/src/gui/changepassworddialog.h new file mode 100644 index 00000000..ad1c0b2a --- /dev/null +++ b/src/gui/changepassworddialog.h @@ -0,0 +1,72 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CHANGEPASSWORDDIALOG_H +#define CHANGEPASSWORDDIALOG_H + +#include <iosfwd> +#include <guichan/actionlistener.hpp> + +#include "window.h" +#include "../guichanfwd.h" + +class LoginData; +class OkDialog; +class WrongDataNoticeListener; + +/** + * The Change password dialog. + * + * \ingroup Interface + */ +class ChangePasswordDialog : public Window, public gcn::ActionListener { + public: + /** + * Constructor + * + * @see Window::Window + */ + ChangePasswordDialog(Window *parent,LoginData *loginData); + + /** + * Destructor + */ + ~ChangePasswordDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + private: + gcn::TextField *mOldPassField; + gcn::TextField *mFirstPassField; + gcn::TextField *mSecondPassField; + + gcn::Button *mChangePassButton; + gcn::Button *mCancelButton; + + WrongDataNoticeListener *mWrongDataNoticeListener; + + LoginData *mLoginData; +}; + +#endif diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index f88736c1..4ab3d9ef 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,13 +31,29 @@ #include "playerbox.h" #include "textfield.h" +#ifdef TMWSERV_SUPPORT +#include "radiobutton.h" +#include "slider.h" + +#include "unregisterdialog.h" +#include "changepassworddialog.h" +#include "changeemaildialog.h" + +#include "../logindata.h" + +#include "../net/tmwserv/accountserver/account.h" +#include "../net/tmwserv/charserverhandler.h" +#else +#include "../net/ea/charserverhandler.h" +#endif + #include "widgets/layout.h" #include "../game.h" #include "../localplayer.h" #include "../main.h" +#include "../units.h" -#include "../net/charserverhandler.h" #include "../net/messageout.h" #include "../resources/colordb.h" @@ -47,6 +62,8 @@ #include "../utils/strprintf.h" #include "../utils/stringutils.h" +#define MAX_SLOT 2 + // Defined in main.cpp, used here for setting the char create dialog extern CharServerHandler charServerHandler; @@ -79,30 +96,80 @@ void CharDeleteConfirm::action(const gcn::ActionEvent &event) ConfirmDialog::action(event); } +#ifdef TMWSERV_SUPPORT +CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo, + LoginData *loginData): + Window(_("Account and Character Management")), + mCharInfo(charInfo), mCharSelected(false), mLoginData(loginData) +#else CharSelectDialog::CharSelectDialog(Network *network, LockedArray<LocalPlayer*> *charInfo, Gender gender): Window(_("Select Character")), mNetwork(network), - mCharInfo(charInfo), mGender(gender), mCharSelected(false) + mCharInfo(charInfo), + mCharSelected(false), + mGender(gender) +#endif { + mSelectButton = new Button(_("Ok"), "ok", this); + mCancelButton = new Button(_("Cancel"), "cancel", this); + mPreviousButton = new Button(_("Previous"), "previous", this); + mNextButton = new Button(_("Next"), "next", this); + mNameLabel = new Label(strprintf(_("Name: %s"), "")); + mLevelLabel = new Label(strprintf(_("Level: %d"), 0)); +#ifdef TMWSERV_SUPPORT + mNewCharButton = new Button(_("New"), "new", this); + mDelCharButton = new Button(_("Delete"), "delete", this); + mUnRegisterButton = new Button(_("Unregister"), "unregister", this); + mChangePasswordButton = new Button(_("Change Password"), "change_password", this); + mChangeEmailButton = new Button(_("Change Email Address"), "change_email", this); + + mAccountNameLabel = new Label(strprintf(_("Account: %s"), mLoginData->username.c_str())); + mNameLabel = new Label(strprintf(_("Name: %s"), "")); + mLevelLabel = new Label(strprintf(_("Level: %d"), 0)); + mMoneyLabel = new Label(strprintf(_("Money: %d"), 0)); + + // Control that shows the Player + mPlayerBox = new PlayerBox; + mPlayerBox->setWidth(74); + + ContainerPlacer place; + place = getPlacer(0, 0); + place(0, 0, mAccountNameLabel); + place(0, 1, mUnRegisterButton); + place(0, 2, mChangePasswordButton); + place(1, 2, mChangeEmailButton); + place = getPlacer(0, 1); + place(0, 0, mPlayerBox, 1, 5).setPadding(3); + place(1, 0, mNameLabel, 3); + place(1, 1, mLevelLabel, 3); + place(1, 2, mMoneyLabel, 3); + place(1, 3, mPreviousButton); + place(2, 3, mNextButton); + place(1, 4, mNewCharButton); + place(2, 4, mDelCharButton); + place.getCell().matchColWidth(1, 2); + place = getPlacer(0, 2); + place(0, 0, mSelectButton); + place(1, 0, mCancelButton); + reflowLayout(265, 0); +#else + mCharInfo->select(0); + LocalPlayer *pi = mCharInfo->getEntry(); + if (pi) + mMoney = Units::formatCurrency(pi->getMoney()); // Control that shows the Player mPlayerBox = new PlayerBox; mPlayerBox->setWidth(74); - mNameLabel = new Label(strprintf(_("Name: %s"), "")); - mLevelLabel = new Label(strprintf(_("Level: %d"), 0)); mJobLevelLabel = new Label(strprintf(_("Job Level: %d"), 0)); - mMoneyLabel = new Label(strprintf(_("Money: %d"), 0)); + mMoneyLabel = new Label(strprintf(_("Money: %s"), mMoney.c_str())); const std::string tempString = getFont()->getWidth(_("New")) < getFont()->getWidth(_("Delete")) ? _("Delete") : _("New"); - mPreviousButton = new Button(_("Previous"), "previous", this); - mNextButton = new Button(_("Next"), "next", this); mNewDelCharButton = new Button(tempString, "newdel", this); - mSelectButton = new Button(_("Ok"), "ok", this); - mCancelButton = new Button(_("Cancel"), "cancel", this); ContainerPlacer place; place = getPlacer(0, 0); @@ -121,8 +188,9 @@ CharSelectDialog::CharSelectDialog(Network *network, place(5, 0, mSelectButton); reflowLayout(250, 0); +#endif - setLocationRelativeTo(getParent()); + center(); setVisible(true); mSelectButton->requestFocus(); updatePlayerInfo(); @@ -130,10 +198,21 @@ CharSelectDialog::CharSelectDialog(Network *network, void CharSelectDialog::action(const gcn::ActionEvent &event) { +#ifdef TMWSERV_SUPPORT + // The pointers are set to NULL if there is no character stored + if (event.getId() == "ok" && (mCharInfo->getEntry())) +#else if (event.getId() == "ok" && n_character > 0) +#endif { // Start game +#ifdef TMWSERV_SUPPORT + mNewCharButton->setEnabled(false); + mDelCharButton->setEnabled(false); + mUnRegisterButton->setEnabled(false); +#else mNewDelCharButton->setEnabled(false); +#endif mSelectButton->setEnabled(false); mPreviousButton->setEnabled(false); mNextButton->setEnabled(false); @@ -142,8 +221,35 @@ void CharSelectDialog::action(const gcn::ActionEvent &event) } else if (event.getId() == "cancel") { - state = EXIT_STATE; +#ifdef TMWSERV_SUPPORT + mCharInfo->clear(); + state = STATE_SWITCH_ACCOUNTSERVER_ATTEMPT; +#else + state = STATE_EXIT; +#endif + } +#ifdef TMWSERV_SUPPORT + else if (event.getId() == "new") + { + // TODO: Search the first free slot, and start CharCreateDialog + // maybe add that search to the constructor. + if (!(mCharInfo->getEntry())) + { + // Start new character dialog + CharCreateDialog *charCreateDialog = + new CharCreateDialog(this, mCharInfo->getPos()); + charServerHandler.setCharCreateDialog(charCreateDialog); + } + } + else if (event.getId() == "delete") + { + // Delete character + if (mCharInfo->getEntry()) + { + new CharDeleteConfirm(this); + } } +#else else if (event.getId() == "newdel") { // Check for a character @@ -160,14 +266,35 @@ void CharSelectDialog::action(const gcn::ActionEvent &event) charServerHandler.setCharCreateDialog(charCreateDialog); } } +#endif else if (event.getId() == "previous") { mCharInfo->prev(); + LocalPlayer *pi = mCharInfo->getEntry(); + if (pi) + mMoney = Units::formatCurrency(pi->getMoney()); } else if (event.getId() == "next") { mCharInfo->next(); + LocalPlayer *pi = mCharInfo->getEntry(); + if (pi) + mMoney = Units::formatCurrency(pi->getMoney()); + } +#ifdef TMWSERV_SUPPORT + else if (event.getId() == "unregister") + { + new UnRegisterDialog(this, mLoginData); + } + else if (event.getId() == "change_password") + { + new ChangePasswordDialog(this, mLoginData); } + else if (event.getId() == "change_email") + { + new ChangeEmailDialog(this, mLoginData); + } +#endif } void CharSelectDialog::updatePlayerInfo() @@ -176,13 +303,22 @@ void CharSelectDialog::updatePlayerInfo() if (pi) { - mNameLabel->setCaption(strprintf(_("Name: %s"), pi->getName().c_str())); - mLevelLabel->setCaption(strprintf(_("Level: %d"), pi->mLevel)); - mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"), pi->mJobLevel)); - mMoneyLabel->setCaption(strprintf(_("Gold: %d"), pi->mGp)); + mNameLabel->setCaption(strprintf(_("Name: %s"), + pi->getName().c_str())); + mLevelLabel->setCaption(strprintf(_("Level: %d"), pi->getLevel())); +#ifndef TMWSERV_SUPPORT + mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"), + pi->mJobLevel)); +#endif + mMoneyLabel->setCaption(strprintf(_("Money: %s"), mMoney.c_str())); if (!mCharSelected) { +#ifdef TMWSERV_SUPPORT + mNewCharButton->setEnabled(false); + mDelCharButton->setEnabled(true); +#else mNewDelCharButton->setCaption(_("Delete")); +#endif mSelectButton->setEnabled(true); } } @@ -190,9 +326,16 @@ void CharSelectDialog::updatePlayerInfo() { mNameLabel->setCaption(strprintf(_("Name: %s"), "")); mLevelLabel->setCaption(strprintf(_("Level: %d"), 0)); +#ifndef TMWSERV_SUPPORT mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"), 0)); +#endif mMoneyLabel->setCaption(strprintf(_("Money: %s"), "")); +#ifdef TMWSERV_SUPPORT + mNewCharButton->setEnabled(true); + mDelCharButton->setEnabled(false); +#else mNewDelCharButton->setCaption(_("New")); +#endif mSelectButton->setEnabled(false); } @@ -201,20 +344,28 @@ void CharSelectDialog::updatePlayerInfo() void CharSelectDialog::attemptCharDelete() { +#ifdef TMWSERV_SUPPORT + Net::AccountServer::Account::deleteCharacter(mCharInfo->getPos()); +#else // Request character deletion MessageOut outMsg(mNetwork); outMsg.writeInt16(0x0068); outMsg.writeInt32(mCharInfo->getEntry()->mCharId); outMsg.writeString("a@a.com", 40); +#endif mCharInfo->lock(); } void CharSelectDialog::attemptCharSelect() { +#ifdef TMWSERV_SUPPORT + Net::AccountServer::Account::selectCharacter(mCharInfo->getPos()); +#else // Request character selection MessageOut outMsg(mNetwork); outMsg.writeInt16(0x0066); outMsg.writeInt8(mCharInfo->getPos()); +#endif mCharInfo->lock(); } @@ -246,16 +397,29 @@ bool CharSelectDialog::selectByName(const std::string &name) return false; } +#ifdef TMWSERV_SUPPORT +CharCreateDialog::CharCreateDialog(Window *parent, int slot): +#else CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network, Gender gender): - Window(_("Create Character"), true, parent), mNetwork(network), mSlot(slot) +#endif + Window(_("Create Character"), true, parent), +#ifndef TMWSERV_SUPPORT + mNetwork(network), +#endif + mSlot(slot) { mPlayer = new Player(0, 0, NULL); +#ifdef TMWSERV_SUPPORT + mPlayer->setGender(GENDER_MALE); +#else mPlayer->setGender(gender); +#endif int numberOfHairColors = ColorDB::size(); - mPlayer->setHairStyle(rand() % mPlayer->getNumOfHairstyles(), rand() % numberOfHairColors); + mPlayer->setHairStyle(rand() % mPlayer->getNumOfHairstyles(), + rand() % numberOfHairColors); mNameField = new TextField(""); mNameLabel = new Label(_("Name:")); @@ -267,6 +431,19 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network, mHairStyleLabel = new Label(_("Hair Style:")); mCreateButton = new Button(_("Create"), "create", this); mCancelButton = new Button(_("Cancel"), "cancel", this); +#ifdef TMWSERV_SUPPORT + mMale = new RadioButton(_("Male"), "gender"); + mFemale = new RadioButton(_("Female"), "gender"); + + // Default to a Male character + mMale->setSelected(true); + + mMale->setActionEventId("gender"); + mFemale->setActionEventId("gender"); + + mMale->addActionListener(this); + mFemale->addActionListener(this); +#endif mPlayerBox = new PlayerBox(mPlayer); mPlayerBox->setWidth(74); @@ -274,6 +451,81 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network, mNameField->setActionEventId("create"); mNameField->addActionListener(this); +#ifdef TMWSERV_SUPPORT + mAttributeLabel[0] = new gcn::Label(_("Strength:")); + mAttributeLabel[1] = new gcn::Label(_("Agility:")); + mAttributeLabel[2] = new gcn::Label(_("Dexterity:")); + mAttributeLabel[3] = new gcn::Label(_("Vitality:")); + mAttributeLabel[4] = new gcn::Label(_("Intelligence:")); + mAttributeLabel[5] = new gcn::Label(_("Willpower:")); + for (int i = 0; i < 6; i++) + { + mAttributeLabel[i]->setWidth(70); + mAttributeSlider[i] = new Slider(1, 20); + mAttributeValue[i] = new gcn::Label("1"); + }; + + mAttributesLeft = new gcn::Label(strprintf(_("Please distribute %d points"), 99)); + + int w = 200; + int h = 330; + setContentSize(w, h); + mPlayerBox->setDimension(gcn::Rectangle(80, 30, 110, 85)); + mNameLabel->setPosition(5, 5); + mNameField->setDimension( + gcn::Rectangle(45, 5, w - 45 - 7, mNameField->getHeight())); + mPrevHairColorButton->setPosition(90, 35); + mNextHairColorButton->setPosition(165, 35); + mHairColorLabel->setPosition(5, 40); + mPrevHairStyleButton->setPosition(90, 64); + mNextHairStyleButton->setPosition(165, 64); + mHairStyleLabel->setPosition(5, 70); + for (int i=0; i<6; i++) + { + mAttributeSlider[i]->setValue(10); + mAttributeSlider[i]->setDimension(gcn::Rectangle( 75, 140 + i*20, + 100, 10)); + mAttributeSlider[i]->setActionEventId("statslider"); + mAttributeSlider[i]->addActionListener(this); + mAttributeValue[i]->setPosition(180, 140 + i*20); + mAttributeLabel[i]->setPosition(5, 140 + i*20); + }; + mAttributesLeft->setPosition(15, 280); + updateSliders(); + mCancelButton->setPosition( + w - 5 - mCancelButton->getWidth(), + h - 5 - mCancelButton->getHeight()); + mCreateButton->setPosition( + mCancelButton->getX() - 5 - mCreateButton->getWidth(), + h - 5 - mCancelButton->getHeight()); + + mMale->setPosition(30, 120); + mFemale->setPosition(100, 120); + + add(mPlayerBox); + add(mNameField); + add(mNameLabel); + add(mNextHairColorButton); + add(mPrevHairColorButton); + add(mHairColorLabel); + add(mNextHairStyleButton); + add(mPrevHairStyleButton); + add(mHairStyleLabel); + for (int i = 0; i < 6; i++) + { + add(mAttributeSlider[i]); + add(mAttributeValue[i]); + add(mAttributeLabel[i]); + }; + add(mAttributesLeft); + add(mCreateButton); + add(mCancelButton); + + add(mMale); + add(mFemale); + +#else + ContainerPlacer place; place = getPlacer(0, 0); @@ -292,8 +544,9 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network, place(5, 0, mCreateButton); reflowLayout(225, 0); +#endif - setLocationRelativeTo(getParent()); + center(); setVisible(true); mNameField->requestFocus(); } @@ -315,12 +568,35 @@ void CharCreateDialog::action(const gcn::ActionEvent &event) { // Attempt to create the character mCreateButton->setEnabled(false); +#ifdef TMWSERV_SUPPORT + unsigned int genderSelected; + if (mMale->isSelected()) { + genderSelected = GENDER_MALE; + } else { + genderSelected = GENDER_FEMALE; + } + + Net::AccountServer::Account::createCharacter( + getName(), + mPlayer->getHairStyle(), + mPlayer->getHairColor(), + genderSelected, // gender + (int) mAttributeSlider[0]->getValue(), // STR + (int) mAttributeSlider[1]->getValue(), // AGI + (int) mAttributeSlider[2]->getValue(), // DEX + (int) mAttributeSlider[3]->getValue(), // VIT + (int) mAttributeSlider[4]->getValue(), // INT + (int) mAttributeSlider[5]->getValue() // WILL + ); +#else attemptCharCreate(); +#endif } else { - new OkDialog("Error", - "Your name needs to be at least 4 characters.", this); + new OkDialog(_("Error"), + _("Your name needs to be at least 4 characters."), + this); } } else if (event.getId() == "cancel") @@ -339,6 +615,18 @@ void CharCreateDialog::action(const gcn::ActionEvent &event) mPlayer->setHairStyle(mPlayer->getHairStyle() + mPlayer->getNumOfHairstyles() - 1, mPlayer->getHairColor()); +#ifdef TMWSERV_SUPPORT + else if (event.getId() == "statslider") { + updateSliders(); + } + else if (event.getId() == "gender"){ + if (mMale->isSelected()) { + mPlayer->setGender(GENDER_MALE); + } else { + mPlayer->setGender(GENDER_FEMALE); + } + } +#endif } std::string CharCreateDialog::getName() @@ -348,11 +636,60 @@ std::string CharCreateDialog::getName() return name; } +#ifdef TMWSERV_SUPPORT +void CharCreateDialog::updateSliders() +{ + for (int i = 0; i < 6; i++) + { + // Update captions + mAttributeValue[i]->setCaption( + toString((int) (mAttributeSlider[i]->getValue()))); + mAttributeValue[i]->adjustSize(); + } + + // Update distributed points + int pointsLeft = 60 - getDistributedPoints(); + if (pointsLeft == 0) + { + mAttributesLeft->setCaption(_("Character stats OK")); + mCreateButton->setEnabled(true); + } + else + { + mCreateButton->setEnabled(false); + if (pointsLeft > 0) + { + mAttributesLeft->setCaption(strprintf(_("Please distribute %d points"), pointsLeft)); + } + else + { + mAttributesLeft->setCaption(strprintf(_("Please remove %d points"), -pointsLeft)); + } + } + + mAttributesLeft->adjustSize(); +} +#endif + void CharCreateDialog::unlock() { mCreateButton->setEnabled(true); } +#ifdef TMWSERV_SUPPORT +int CharCreateDialog::getDistributedPoints() +{ + int points = 0; + + for (int i = 0; i < 6; i++) + { + points += (int) mAttributeSlider[i]->getValue(); + } + return points; +} +#endif + +#ifndef TMWSERV_SUPPORT void CharCreateDialog::attemptCharCreate() { // Send character infos @@ -369,3 +706,4 @@ void CharCreateDialog::attemptCharCreate() outMsg.writeInt16(mPlayer->getHairColor()); outMsg.writeInt16(mPlayer->getHairStyle()); } +#endif diff --git a/src/gui/char_select.h b/src/gui/char_select.h index 037b809f..7f376692 100644 --- a/src/gui/char_select.h +++ b/src/gui/char_select.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,10 +27,16 @@ #include "window.h" #include "../being.h" +#include "../guichanfwd.h" #include "../lockedarray.h" -class LocalPlayer; +#ifdef TMWSERV_SUPPORT +#include "../logindata.h" +#else class Network; +#endif + +class LocalPlayer; class Player; class PlayerBox; @@ -47,9 +52,14 @@ class CharSelectDialog : public Window, public gcn::ActionListener /** * Constructor. */ +#ifdef TMWSERV_SUPPORT + CharSelectDialog(LockedArray<LocalPlayer*> *charInfo, + LoginData *loginData); +#else CharSelectDialog(Network *network, LockedArray<LocalPlayer*> *charInfo, Gender gender); +#endif void action(const gcn::ActionEvent &event); @@ -60,25 +70,40 @@ class CharSelectDialog : public Window, public gcn::ActionListener bool selectByName(const std::string &name); private: +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif LockedArray<LocalPlayer*> *mCharInfo; gcn::Button *mSelectButton; gcn::Button *mCancelButton; - gcn::Button *mNewDelCharButton; gcn::Button *mPreviousButton; gcn::Button *mNextButton; gcn::Label *mNameLabel; gcn::Label *mLevelLabel; - gcn::Label *mJobLevelLabel; gcn::Label *mMoneyLabel; + std::string mMoney; PlayerBox *mPlayerBox; - Gender mGender; bool mCharSelected; +#ifdef TMWSERV_SUPPORT + gcn::Button *mNewCharButton; + gcn::Button *mDelCharButton; + gcn::Button *mUnRegisterButton; + gcn::Button *mChangePasswordButton; + gcn::Button *mChangeEmailButton; + gcn::Label *mAccountNameLabel; + + LoginData *mLoginData; +#else + gcn::Button *mNewDelCharButton; + gcn::Label *mJobLevelLabel; + Gender mGender; +#endif + /** * Communicate character deletion to the server. */ @@ -93,7 +118,7 @@ class CharSelectDialog : public Window, public gcn::ActionListener /** * Character creation dialog. * - * \ingroup GUI + * \ingroup Interface */ class CharCreateDialog : public Window, public gcn::ActionListener { @@ -101,8 +126,12 @@ class CharCreateDialog : public Window, public gcn::ActionListener /** * Constructor. */ +#ifdef TMWSERV_SUPPORT + CharCreateDialog(Window *parent, int slot); +#else CharCreateDialog(Window *parent, int slot, Network *network, Gender gender); +#endif /** * Destructor. @@ -117,6 +146,12 @@ class CharCreateDialog : public Window, public gcn::ActionListener void unlock(); private: +#ifdef TMWSERV_SUPPORT + int getDistributedPoints(); + + void updateSliders(); +#endif + /** * Returns the name of the character to create. */ @@ -127,7 +162,9 @@ class CharCreateDialog : public Window, public gcn::ActionListener */ void attemptCharCreate(); +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif gcn::TextField *mNameField; gcn::Label *mNameLabel; gcn::Button *mNextHairColorButton; @@ -136,6 +173,20 @@ class CharCreateDialog : public Window, public gcn::ActionListener gcn::Button *mNextHairStyleButton; gcn::Button *mPrevHairStyleButton; gcn::Label *mHairStyleLabel; + +#ifdef TMWSERV_SUPPORT + gcn::RadioButton *mMale; + gcn::RadioButton *mFemale; + + gcn::Slider *mAttributeSlider[6]; + gcn::Label *mAttributeLabel[6]; + gcn::Label *mAttributeValue[6]; + gcn::Label *mAttributesLeft; + + static const int mMaxPoints = 60; + int mUsedPoints; +#endif + gcn::Button *mCreateButton; gcn::Button *mCancelButton; diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp index 6977a104..5cfcef4d 100644 --- a/src/gui/char_server.cpp +++ b/src/gui/char_server.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,7 +50,7 @@ ServerSelectDialog::ServerSelectDialog(LoginData *loginData, int nextState): mLoginData(loginData), mNextState(nextState) { - mServerListModel = new ServerListModel(); + mServerListModel = new ServerListModel; mServerList = new ListBox(mServerListModel); ScrollArea *mScrollArea = new ScrollArea(mServerList); mOkButton = new Button(_("OK"), "ok", this); @@ -86,7 +85,7 @@ ServerSelectDialog::ServerSelectDialog(LoginData *loginData, int nextState): // Select first server mServerList->setSelected(1); - setLocationRelativeTo(getParent()); + center(); setVisible(true); mOkButton->requestFocus(); } @@ -108,7 +107,7 @@ void ServerSelectDialog::action(const gcn::ActionEvent &event) state = mNextState; } else if (event.getId() == "cancel") - state = LOGIN_STATE; + state = STATE_LOGIN; } int ServerListModel::getNumberOfElements() diff --git a/src/gui/char_server.h b/src/gui/char_server.h index 207fb86e..49a5b47b 100644 --- a/src/gui/char_server.h +++ b/src/gui/char_server.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index 5ff9ed46..7861bdb6 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,68 +19,52 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <guichan/focushandler.hpp> - -#include "browserbox.h" #include "chat.h" -#include "chatinput.h" -#include "itemlinkhandler.h" -#include "recorder.h" -#include "scrollarea.h" -#include "sdlinput.h" -#include "windowcontainer.h" -#include "widgets/layout.h" +#include "gui/chatinput.h" +#include "gui/itemlinkhandler.h" +#include "gui/recorder.h" +#include "gui/scrollarea.h" +#include "gui/sdlinput.h" -#include "../beingmanager.h" -#include "../configuration.h" -#include "../game.h" -#include "../localplayer.h" -#include "../party.h" +#include "gui/widgets/tabbedarea.h" +#include "gui/widgets/whispertab.h" -#include "../net/messageout.h" -#include "../net/protocol.h" +#include "beingmanager.h" +#include "configuration.h" +#include "localplayer.h" -#include "../resources/iteminfo.h" -#include "../resources/itemdb.h" +#include "utils/dtor.h" +#include "utils/stringutils.h" -#include "../utils/gettext.h" -#include "../utils/strprintf.h" -#include "../utils/stringutils.h" +#include <guichan/focushandler.hpp> +#ifdef TMWSERV_SUPPORT +ChatWindow::ChatWindow(): + Window("Chat"), +#else ChatWindow::ChatWindow(Network * network): -Window(""), mNetwork(network), mTmpVisible(false) + Window(""), mNetwork(network), +#endif + mTmpVisible(false) { - setWindowName(_("Chat")); + setWindowName("Chat"); setResizable(true); setDefaultSize(600, 123, ImageRect::LOWER_LEFT); setMinWidth(150); setMinHeight(90); - mItemLinkHandler = new ItemLinkHandler(); + mItemLinkHandler = new ItemLinkHandler; mChatInput = new ChatInput; mChatInput->setActionEventId("chatinput"); mChatInput->addActionListener(this); - mTextOutput = new BrowserBox(BrowserBox::AUTO_WRAP); - mTextOutput->setOpaque(false); - mTextOutput->setMaxRow((int) config.getValue("ChatLogLength", 0)); - mTextOutput->setLinkHandler(mItemLinkHandler); - - mScrollArea = new ScrollArea(mTextOutput); - mScrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, - gcn::ScrollArea::SHOW_ALWAYS); - mScrollArea->setScrollAmount(0, 1); - mScrollArea->setOpaque(false); + mChatTabs = new TabbedArea(); - place(0, 0, mScrollArea, 5, 5).setPadding(0); - place(0, 5, mChatInput, 5).setPadding(1); - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - layout.setMargin(2); + add(mChatTabs); + add(mChatInput); loadWindowState(); @@ -89,28 +72,33 @@ Window(""), mNetwork(network), mTmpVisible(false) mChatInput->addKeyListener(this); mCurHist = mHistory.end(); +#ifdef EATHENA_SUPPORT // Read the party prefix std::string partyPrefix = config.getValue("PartyPrefix", "$"); mPartyPrefix = (partyPrefix.empty() ? '$' : partyPrefix.at(0)); mReturnToggles = config.getValue("ReturnToggles", "0") == "1"; - mRecorder = new Recorder(this); - mParty = new Party(this, mNetwork); // If the player had @assert on in the last session, ask the server to // run the @assert command for the player again. Convenience for GMs. - if (config.getValue(player_node->getName() + "GMassert", 0)) - chatSend(player_node->getName(), "@assert"); + if (config.getValue(player_node->getName() + "GMassert", 0)) { + std::string cmd = "@assert"; + chatSend(cmd); + } +#endif + mRecorder = new Recorder(this); } ChatWindow::~ChatWindow() { +#ifdef EATHENA_SUPPORT char partyPrefix[2] = "."; *partyPrefix = mPartyPrefix; config.setValue("PartyPrefix", partyPrefix); config.setValue("ReturnToggles", mReturnToggles ? "1" : "0"); delete mRecorder; +#endif + delete_all(mWhispers); delete mItemLinkHandler; - delete mParty; } void ChatWindow::resetToDefaultSize() @@ -119,178 +107,63 @@ void ChatWindow::resetToDefaultSize() Window::resetToDefaultSize(); } -void ChatWindow::chatLog(std::string line, int own, bool ignoreRecord) +void ChatWindow::adjustTabSize() { - // Trim whitespace - trim(line); - - if (line.empty()) - return; - - CHATLOG tmp; - tmp.own = own; - tmp.nick = ""; - tmp.text = line; - - std::string::size_type pos = line.find(" : "); - if (pos != std::string::npos) - { - tmp.nick = line.substr(0, pos); - tmp.text = line.substr(pos + 3); - } - else - { - // Fix the owner of welcome message. - if (line.substr(0, 7) == "Welcome") - { - own = BY_SERVER; - } - } - - // *implements actions in a backwards compatible way* - if (own == BY_PLAYER && - tmp.text.at(0) == '*' && - tmp.text.at(tmp.text.length()-1) == '*') - { - tmp.text[0] = ' '; - tmp.text.erase(tmp.text.length() - 1); - own = ACT_IS; - } + const gcn::Rectangle area = getChildrenArea(); - std::string lineColor = "##C"; - switch (own) - { - case BY_GM: - if (tmp.nick.empty()) - { - tmp.nick = std::string(_("Global announcement: ")); - lineColor = "##G"; - } - else - { - tmp.nick = strprintf(_("Global announcement from %s: "), - tmp.nick.c_str()); - lineColor = "##1"; // Equiv. to BrowserBox::RED - } - break; - case BY_PLAYER: - tmp.nick += CAT_NORMAL; - lineColor = "##Y"; - break; - case BY_OTHER: - tmp.nick += CAT_NORMAL; - lineColor = "##C"; - break; - case BY_SERVER: - tmp.nick = _("Server:"); - tmp.nick += " "; - tmp.text = line; - lineColor = "##S"; - break; - case BY_PARTY: - tmp.nick += CAT_NORMAL; - lineColor = "##P"; - break; - case ACT_WHISPER: - tmp.nick += CAT_WHISPER; - lineColor = "##W"; - break; - case ACT_IS: - tmp.nick += CAT_IS; - lineColor = "##I"; - break; - case BY_LOGGER: - tmp.nick = ""; - tmp.text = line; - lineColor = "##L"; - break; - } + mChatInput->setPosition(mChatInput->getFrameSize(), + area.height - mChatInput->getHeight() - + mChatInput->getFrameSize()); + mChatInput->setWidth(area.width - 2 * mChatInput->getFrameSize()); - if (tmp.nick == ": ") - { - tmp.nick = ""; - lineColor = "##S"; - } + mChatTabs->setWidth(area.width - 2 * mChatTabs->getFrameSize()); + mChatTabs->setHeight(area.height - 2 * mChatTabs->getFrameSize() - + (mChatInput->getHeight() + mChatInput->getFrameSize() * 2)); - if (tmp.nick.empty() && tmp.text.substr(0, 17) == "Visible GM status") - { - player_node->setGM(); + ChatTab *tab = getFocused(); + if (tab) { + gcn::Widget *content = tab->mScrollArea; + content->setSize(mChatTabs->getWidth() - 2 * content->getFrameSize(), + mChatTabs->getContainerHeight() - 2 * content->getFrameSize()); + content->logic(); } +} - // Get the current system time - time_t t; - time(&t); - - // Format the time string properly - std::stringstream timeStr; - timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "") - << (int) (((t / 60) / 60) % 24) - << ":" << (((t / 60) % 60 < 10) ? "0" : "") - << (int) ((t / 60) % 60) - << "] "; - - // Check for item link - std::string::size_type start = tmp.text.find('['); - while (start != std::string::npos && tmp.text[start+1] != '@') - { - std::string::size_type end = tmp.text.find(']', start); - if (start+1 != end && end != std::string::npos) - { - // Catch multiple embeds and ignore them - // so it doesn't crash the client. - while ((tmp.text.find('[', start + 1) != std::string::npos) && - (tmp.text.find('[', start + 1) < end)) - { - start = tmp.text.find('[', start + 1); - } - - std::string temp = tmp.text.substr(start+1, end - start - 1); +void ChatWindow::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); - trim(temp); + adjustTabSize(); +} - for (unsigned int i = 0; i < temp.size(); i++) - { - temp[i] = (char) tolower(temp[i]); - } +void ChatWindow::logic() +{ + Window::logic(); - const ItemInfo itemInfo = ItemDB::get(temp); - if (itemInfo.getName() != _("Unknown item")) - { - tmp.text.insert(end, "@@"); - tmp.text.insert(start+1, "|"); - tmp.text.insert(start+1, toString(itemInfo.getId())); - tmp.text.insert(start+1, "@@"); - } - } - start = tmp.text.find('[', start + 1); + Tab *tab = getFocused(); + if (tab != mCurrentTab) { + mCurrentTab = tab; + adjustTabSize(); } +} - line = lineColor + timeStr.str() + tmp.nick + tmp.text; - - // We look if the Vertical Scroll Bar is set at the max before - // adding a row, otherwise the max will always be a row higher - // at comparison. - if (mScrollArea->getVerticalScrollAmount() == - mScrollArea->getVerticalMaxScroll()) - { - mTextOutput->addRow(line); - mScrollArea->setVerticalScrollAmount(mScrollArea-> - getVerticalMaxScroll()); - } - else - { - mTextOutput->addRow(line); - } +ChatTab *ChatWindow::getFocused() const +{ + return dynamic_cast<ChatTab*>(mChatTabs->getSelectedTab()); +} - mRecorder->record(line.substr(3)); +void ChatWindow::clearTab(ChatTab *tab) +{ + if (tab) + tab->clearText(); } -void ChatWindow::chatLog(CHATSKILL act) +void ChatWindow::clearTab() { - chatLog(const_msg(act), BY_SERVER); + clearTab(getFocused()); } -void ChatWindow::action(const gcn::ActionEvent & event) +void ChatWindow::action(const gcn::ActionEvent &event) { if (event.getId() == "chatinput") { @@ -307,7 +180,7 @@ void ChatWindow::action(const gcn::ActionEvent & event) mCurHist = mHistory.end(); // Send the message to the server - chatSend(player_node->getName(), message); + chatSend(message); // Clear the text from the chat input mChatInput->setText(""); @@ -326,7 +199,7 @@ void ChatWindow::action(const gcn::ActionEvent & event) } } -void ChatWindow::requestChatFocus() +bool ChatWindow::requestChatFocus() { // Make sure chatWindow is visible if (!isVisible()) @@ -341,9 +214,14 @@ void ChatWindow::requestChatFocus() mTmpVisible = true; } + // Don't do anything else if the input is already visible and has focus + if (mChatInput->isVisible() && mChatInput->isFocused()) + return false; + // Give focus to the chat input mChatInput->setVisible(true); mChatInput->requestFocus(); + return true; } bool ChatWindow::isInputFocused() @@ -351,376 +229,74 @@ bool ChatWindow::isInputFocused() return mChatInput->isFocused(); } -void ChatWindow::whisper(const std::string &nick, std::string msg) +void ChatWindow::removeTab(ChatTab *tab) { - std::string recvnick = ""; - - if (msg.substr(0, 1) == "\"") - { - const std::string::size_type pos = msg.find('"', 1); - if (pos != std::string::npos) - { - recvnick = msg.substr(1, pos - 1); - msg.erase(0, pos + 2); - } - } - else - { - const std::string::size_type pos = msg.find(" "); - if (pos != std::string::npos) - { - recvnick = msg.substr(0, pos); - msg.erase(0, pos + 1); - } - } - - trim(msg); - - std::string playerName = player_node->getName(); - std::string tempNick = recvnick; - - toLower(playerName); - toLower(tempNick); - - if (tempNick.compare(playerName) == 0 || msg.empty()) - return; - - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_CHAT_WHISPER); - outMsg.writeInt16(msg.length() + 28); - outMsg.writeString(recvnick, 24); - outMsg.writeString(msg, msg.length()); - - chatLog(strprintf(_("Whispering to %s: %s"), - recvnick.c_str(), msg.c_str()), - BY_PLAYER); + // Prevent removal of the local chat tab + if (tab != localChatTab) mChatTabs->removeTab(tab); } -void ChatWindow::chatSend(const std::string &nick, std::string msg) +void ChatWindow::addTab(ChatTab *tab) { - /* Some messages are managed client side, while others - * require server handling by proper packet. Probably - * those if elses should be replaced by protocol calls */ - - trim(msg); + // Make sure we don't end up with duplicates in the gui + // TODO - if (msg.compare("") == 0) - return; - - // Send party message - if (msg.at(0) == mPartyPrefix) - { - msg.erase(0, 1); - std::size_t length = msg.length() + 1; + mChatTabs->addTab(tab, tab->mScrollArea); - if (length == 0) - { - chatLog(_("Trying to send a blank party message."), BY_SERVER); - return; - } - MessageOut outMsg(mNetwork); - - outMsg.writeInt16(CMSG_PARTY_MESSAGE); - outMsg.writeInt16(length + 4); - outMsg.writeString(msg, length); - return; - } - - // Prepare ordinary message - if (msg.substr(0, 1) != "/") - { - msg = nick + " : " + msg; - - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_CHAT_MESSAGE); - // Added + 1 in order to let eAthena parse admin commands correctly - outMsg.writeInt16(msg.length() + 4 + 1); - outMsg.writeString(msg, msg.length() + 1); - return; - } - - msg.erase(0, 1); - trim(msg); - - std::size_t space = msg.find(" "); - std::string command = msg.substr(0, space); - - if (space == std::string::npos) - { - msg = ""; - } - else - { - msg = msg.substr(space); - trim(msg); - } - - if (command == "announce") - { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x0099); - outMsg.writeInt16(msg.length() + 4); - outMsg.writeString(msg, msg.length()); - } - else if (command == "help") - { - trim(msg); - std::size_t space = msg.find(" "); - std::string msg1; - - if (space == std::string::npos) - { - msg1 = ""; - } - else - { - msg1 = msg.substr(space + 1, msg.length()); - msg = msg.substr(0, space); - } - - if (!msg.empty() && msg.at(0) == '/') - { - msg.erase(0, 1); - } + // Fix for layout issues when adding the first tab + if (tab == localChatTab) + adjustTabSize(); - trim(msg1); - help(msg, msg1); - } - else if (command == "where") - { - // Display the current map, X, and Y - std::ostringstream where; - where << map_path << " " << player_node->mX << "," << player_node->mY; - chatLog(where.str(), BY_SERVER); - } - else if (command == "who") - { - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x00c1); - } - else if (command == "clear") - mTextOutput->clearRows(); - else if (command == "whisper" || command == "msg" || command == "w") - whisper(nick, msg); - else if (command == "record") - mRecorder->changeRecordingStatus(msg); - else if (command == "toggle") - { - if (msg.empty()) - { - chatLog(mReturnToggles ? _("Return toggles chat.") - : _("Message closes chat."), BY_SERVER); - return; - } - - msg = msg.substr(0, 1); - - if (msg == "1" || - msg == "y" || msg == "Y" || - msg == "t" || msg == "T") - { - chatLog(_("Return now toggles chat."), BY_SERVER); - mReturnToggles = true; - return; - } - else if (msg == "0" || - msg == "n" || msg == "N" || - msg == "f" || msg == "F") - { - chatLog(_("Message now closes chat."), BY_SERVER); - mReturnToggles = false; - return; - } - else - chatLog(_("Options to /toggle are \"yes\", \"no\", \"true\", " - "\"false\", \"1\", \"0\"."), BY_SERVER); - } - else if (command == "party") - { - if (msg.empty()) - { - chatLog(_("Unknown party command... Type \"/help\" party for more " - "information."), BY_SERVER); - return; - } + // Update UI + logic(); +} - const std::string::size_type space = msg.find(" "); - std::string rest = (space == std::string::npos ? "" - : msg.substr(space + 1, msg.length())); +void ChatWindow::chatSend(std::string &msg) +{ + ChatTab *tab = getFocused(); + tab->chatSend(msg); +} - if (!rest.empty()) - { - msg = msg.substr(0, space); - trim(msg); - } +void ChatWindow::doPresent() +{ + Beings & beings = beingManager->getAll(); + std::string response = ""; - party(msg, rest); - return; - } - else if (command == "cast") + for (BeingIterator bi = beings.begin(), be = beings.end(); + bi != be; ++bi) { - /* - * This will eventually be replaced by a GUI, so - * we don't need to get too sophisticated - */ - MessageOut outMsg(mNetwork); - if (msg == "heal") - { - outMsg.writeInt16(0x03f3); - outMsg.writeInt16(0x01); - outMsg.writeInt32(0); - outMsg.writeInt8(0); - outMsg.writeInt8(0); - outMsg.writeString("", 24); - } - else if (msg == "gather") - { - outMsg.writeInt16(0x03f3); - outMsg.writeInt16(0x02); - outMsg.writeInt32(0); - outMsg.writeInt8(0); - outMsg.writeInt8(0); - outMsg.writeString("", 24); - } - else - chatLog(_("No such spell!"), BY_SERVER); - } - else if (command == "present") - { - Beings & beings = beingManager->getAll(); - std::string response = ""; - - for (BeingIterator bi = beings.begin(), be = beings.end(); - bi != be; ++bi) + if ((*bi)->getType() == Being::PLAYER) { - if ((*bi)->getType() == Being::PLAYER) + if (!response.empty()) { - if (!response.empty()) - { - response += ", "; - } - response += (*bi)->getName(); + response += ", "; } - } - - if (mRecorder->isRecording()) - { - // Get the current system time - time_t t; - time(&t); - - // Format the time string properly - std::stringstream timeStr; - timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "") - << (int) (((t / 60) / 60) % 24) - << ":" << (((t / 60) % 60 < 10) ? "0" : "") - << (int) ((t / 60) % 60) - << "] "; - - - mRecorder->record(timeStr.str() + _("Present: ") + response + "."); - chatLog(_("Attendance written to record log."), BY_SERVER, true); - } - else - { - chatLog(_("Present: ") + response, BY_SERVER); + response += (*bi)->getName(); } } - else if (command == "me") - { - std::stringstream actionStr; - actionStr << "*" << msg << "*"; - chatSend(player_node->getName(), actionStr.str()); - } - else - { - chatLog(_("Unknown command"), BY_SERVER); - } -} -std::string ChatWindow::const_msg(CHATSKILL act) -{ - std::string msg; - if (act.success == SKILL_FAILED && act.skill == SKILL_BASIC) + if (mRecorder->isRecording()) { - switch (act.bskill) - { - case BSKILL_TRADE: - msg = _("Trade failed!"); - break; - case BSKILL_EMOTE: - msg = _("Emote failed!"); - break; - case BSKILL_SIT: - msg = _("Sit failed!"); - break; - case BSKILL_CREATECHAT: - msg = _("Chat creating failed!"); - break; - case BSKILL_JOINPARTY: - msg = _("Could not join party!"); - break; - case BSKILL_SHOUT: - msg = _("Cannot shout!"); - break; - } + // Get the current system time + time_t t; + time(&t); - msg += " "; + // Format the time string properly + std::stringstream timeStr; + timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "") + << (int) (((t / 60) / 60) % 24) + << ":" << (((t / 60) % 60 < 10) ? "0" : "") + << (int) ((t / 60) % 60) + << "] "; - switch (act.reason) - { - case RFAIL_SKILLDEP: - msg += _("You have not yet reached a high enough lvl!"); - break; - case RFAIL_INSUFHP: - msg += _("Insufficient HP!"); - break; - case RFAIL_INSUFSP: - msg += _("Insufficient SP!"); - break; - case RFAIL_NOMEMO: - msg += _("You have no memos!"); - break; - case RFAIL_SKILLDELAY: - msg += _("You cannot do that right now!"); - break; - case RFAIL_ZENY: - msg += _("Seems you need more GP... ;-)"); - break; - case RFAIL_WEAPON: - msg += _("You cannot use this skill with that kind of weapon!"); - break; - case RFAIL_REDGEM: - msg += _("You need another red gem!"); - break; - case RFAIL_BLUEGEM: - msg += _("You need another blue gem!"); - break; - case RFAIL_OVERWEIGHT: - msg += _("You're carrying to much to do this!"); - break; - default: - msg += _("Huh? What's that?"); - break; - } + + mRecorder->record(timeStr.str() + _("Present: ") + response + "."); + localChatTab->chatLog(_("Attendance written to record log."), + BY_SERVER, true); } else { - switch (act.skill) - { - case SKILL_WARP : - msg = _("Warp failed..."); - break; - case SKILL_STEAL : - msg = _("Could not steal anything..."); - break; - case SKILL_ENVENOM : - msg = _("Poison had no effect..."); - break; - } + localChatTab->chatLog(_("Present: ") + response, BY_SERVER); } - - return msg; } void ChatWindow::scroll(int amount) @@ -728,16 +304,12 @@ void ChatWindow::scroll(int amount) if (!isVisible()) return; - int range = mScrollArea->getHeight() / 8 * amount; - gcn::Rectangle scr; - scr.y = mScrollArea->getVerticalScrollAmount() + range; - scr.height = abs(range); - mTextOutput->showPart(scr); + ChatTab *tab = getFocused(); + if (tab) tab->scroll(amount); } -void ChatWindow::keyPressed(gcn::KeyEvent & event) +void ChatWindow::keyPressed(gcn::KeyEvent &event) { - if (event.getKey().getValue() == Key::DOWN && mCurHist != mHistory.end()) { @@ -786,150 +358,36 @@ void ChatWindow::setVisible(bool isVisible) * For whatever reason, if setVisible is called, the mTmpVisible effect * should be disabled. */ - mTmpVisible = false; } -void ChatWindow::party(const std::string & command, const std::string & rest) +void ChatWindow::setRecordingFile(const std::string &msg) { - if (command == "prefix") - { - if (rest.empty()) - { - char temp[2] = "."; - *temp = mPartyPrefix; - chatLog(_("The current party prefix is ") + std::string(temp), - BY_SERVER); - } - else if (rest.length() != 1) - { - chatLog(_("Party prefix must be one character long."), BY_SERVER); - } - else - { - if (rest == "/") - { - chatLog(_("Cannot use a '/' as the prefix."), BY_SERVER); - } - else - { - mPartyPrefix = rest.at(0); - chatLog(_("Changing prefix to ") + rest, BY_SERVER); - } - } - } - else - mParty->respond(command, rest); + mRecorder->setRecordingFile(msg); } -void ChatWindow::help(const std::string & msg1, const std::string & msg2) +void ChatWindow::whisper(std::string nick, std::string mes, bool own) { - chatLog(_("-- Help --"), BY_SERVER); - if (msg1.empty()) - { - chatLog(_("/announce: Global announcement (GM only)"), BY_SERVER); - chatLog(_("/clear: Clears this window"), BY_SERVER); - chatLog(_("/help: Display this help"), BY_SERVER); - chatLog(_("/me <message>: Tell something about yourself"), BY_SERVER); - chatLog(_("/msg <nick> <message>: Alternate form for /whisper"), - BY_SERVER); - chatLog(_("/party <command> <params>: Party commands"), BY_SERVER); - chatLog(_("/present: Get list of players present"), BY_SERVER); - chatLog(_("/record <filename>: Start recording the chat to an " - "external file"), BY_SERVER); - chatLog(_("/toggle: Determine whether <return> toggles the chat log"), - BY_SERVER); - chatLog(_("/w <nick> <message>: Short form for /whisper"), BY_SERVER); - chatLog(_("/where: Display map name"), BY_SERVER); - chatLog(_("/whisper <nick> <message>: Sends a private <message> " - "to <nick>"), BY_SERVER); - chatLog(_("/who: Display number of online users"), BY_SERVER); - chatLog(_("For more information, type /help <command>"), BY_SERVER); - } - else if (msg1 == "announce") - { - chatLog(_("Command: /announce <msg>"), BY_SERVER); - chatLog(_("*** only available to a GM ***"), BY_SERVER); - chatLog(_("This command sends the message <msg> to " - "all players currently online."), BY_SERVER); - } - else if (msg1 == "clear") - { - chatLog(_("Command: /clear"), BY_SERVER); - chatLog(_("This command clears the chat log of previous chat."), - BY_SERVER); - } - else if (msg1 == "help") - { - chatLog(_("Command: /help"), BY_SERVER); - chatLog(_("This command displays a list of all commands available."), - BY_SERVER); - chatLog(_("Command: /help <command>"), BY_SERVER); - chatLog(_("This command displays help on <command>."), BY_SERVER); - } - else if (msg1 == "me") - { - chatLog(_("Command: /me <msg>"), BY_SERVER); - chatLog(_("This command tell others you are (doing) <msg>."), - BY_SERVER); - } - else if (msg1 == "party") - { - mParty->help(msg2); - } - else if (msg1 == "present") - { - chatLog(_("Command: /present"), BY_SERVER); - chatLog(_("This command gets a list of players within hearing and " - "sends it to either the record log if recording, or the chat " - "log otherwise."), BY_SERVER); - } - else if (msg1 == "record") - { - chatLog(_("Command: /record <filename>"), BY_SERVER); - chatLog(_("This command starts recording the chat log to the file " - "<filename>."), BY_SERVER); - chatLog(_("Command: /record"), BY_SERVER); - chatLog(_("This command finishes a recording session."), BY_SERVER); - } - else if (msg1 == "toggle") - { - chatLog(_("Command: /toggle <state>"), BY_SERVER); - chatLog(_("This command sets whether the return key should toggle the " - "chat log, or whether the chat log turns off automatically."), - BY_SERVER); - chatLog(_("<state> can be one of \"1\", \"yes\", \"true\" to " - "turn the toggle on, or \"0\", \"no\", \"false\" to turn the " - "toggle off."), BY_SERVER); - chatLog(_("Command: /toggle"), BY_SERVER); - chatLog(_("This command displays the return toggle status."), - BY_SERVER); - } - else if (msg1 == "where") - { - chatLog(_("Command: /where"), BY_SERVER); - chatLog(_("This command displays the name of the current map."), - BY_SERVER); - } - else if (msg1 == "whisper" || msg1 == "msg" || msg1 == "w") - { - chatLog(_("Command: /msg <nick> <msg>"), BY_SERVER); - chatLog(_("Command: /whisper <nick> <msg>"), BY_SERVER); - chatLog(_("Command: /w <nick> <msg>"), BY_SERVER); - chatLog(_("This command sends the message <msg> to <nick>."), - BY_SERVER); - chatLog(_("If the <nick> has spaces in it, enclose it in " - "double quotes (\")."), BY_SERVER); - } - else if (msg1 == "who") + if (mes.length() == 0) return; + std::string playerName = player_node->getName(); + std::string tempNick = nick; + + toLower(playerName); + toLower(tempNick); + + if (!own && tempNick.compare(playerName) == 0) + return; + + ChatTab *tab = mWhispers[tempNick]; + + if (!tab) { - chatLog(_("Command: /who"), BY_SERVER); - chatLog(_("This command displays the number of players currently " - "online."), BY_SERVER); + tab = new WhisperTab(tempNick); + mWhispers[tempNick] = tab; } + + if (own) + tab->chatSend(mes); else - { - chatLog(_("Unknown command."), BY_SERVER); - chatLog(_("Type /help for a list of commands."), BY_SERVER); - } + tab->chatLog(nick, mes); } diff --git a/src/gui/chat.h b/src/gui/chat.h index 8b710dc8..7c080960 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,29 +24,28 @@ #include <list> #include <string> +#include <map> #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> +#include <guichan/widget.hpp> +#include <guichan/widgetlistener.hpp> + +#include "widgets/chattab.h" #include "window.h" class BrowserBox; -class Network; +class Channel; +class ChatTab; class Recorder; -class Party; class ScrollArea; +class TabbedArea; class ItemLinkHandler; - -#define BY_GM 0 // those should be self-explanatory =) -#define BY_PLAYER 1 -#define BY_OTHER 2 -#define BY_SERVER 3 -#define BY_PARTY 4 - -#define ACT_WHISPER 5 // getting whispered at -#define ACT_IS 6 // equivalent to "/me" on IRC - -#define BY_LOGGER 7 +#ifdef EATHENA_SUPPORT +class Network; +#endif +class WhisperTab; /** * gets in between usernick and message text depending on @@ -57,47 +55,14 @@ class ItemLinkHandler; #define CAT_IS "" #define CAT_WHISPER " whispers: " -/** job dependend identifiers (?) */ -#define SKILL_BASIC 0x0001 -#define SKILL_WARP 0x001b -#define SKILL_STEAL 0x0032 -#define SKILL_ENVENOM 0x0034 - -/** basic skills identifiers */ -#define BSKILL_TRADE 0x0000 -#define BSKILL_EMOTE 0x0001 -#define BSKILL_SIT 0x0002 -#define BSKILL_CREATECHAT 0x0003 -#define BSKILL_JOINPARTY 0x0004 -#define BSKILL_SHOUT 0x0005 -#define BSKILL_PK 0x0006 // ?? -#define BSKILL_SETALLIGN 0x0007 // ?? - -/** reasons why action failed */ -#define RFAIL_SKILLDEP 0x00 -#define RFAIL_INSUFHP 0x01 -#define RFAIL_INSUFSP 0x02 -#define RFAIL_NOMEMO 0x03 -#define RFAIL_SKILLDELAY 0x04 -#define RFAIL_ZENY 0x05 -#define RFAIL_WEAPON 0x06 -#define RFAIL_REDGEM 0x07 -#define RFAIL_BLUEGEM 0x08 -#define RFAIL_OVERWEIGHT 0x09 -#define RFAIL_GENERIC 0x0a - -/** should always be zero if failed */ -#define SKILL_FAILED 0x00 - #define DEFAULT_CHAT_WINDOW_SCROLL 7 // 1 means `1/8th of the window size'. -struct CHATSKILL +/** One item in the chat log */ +struct CHATLOG { - short skill; - short bskill; - short unused; - char success; - char reason; + std::string nick; + std::string text; + int own; }; /** @@ -105,14 +70,19 @@ struct CHATSKILL * * \ingroup Interface */ -class ChatWindow : public Window, public gcn::ActionListener, +class ChatWindow : public Window, + public gcn::ActionListener, public gcn::KeyListener { public: /** * Constructor. */ +#ifdef TMWSERV_SUPPORT + ChatWindow(); +#else ChatWindow(Network *network); +#endif /** * Destructor: used to write back values to the config file @@ -120,23 +90,33 @@ class ChatWindow : public Window, public gcn::ActionListener, ~ChatWindow(); /** + * Called when the widget changes size. Used for adapting the size of + * the tabbed area. + */ + void widgetResized(const gcn::Event &event); + + void logic(); + + /** * Reset the chat window and recorder window attached to it to their * default positions. */ void resetToDefaultSize(); /** - * Adds a line of text to our message list. Parameters: - * - * @param line Text message. - * @parem own Type of message (usually the owner-type). + * Gets the focused tab. */ - void chatLog(std::string line, int own, bool ignoreRecord = false); + ChatTab* getFocused() const; /** - * Calls original chat_log() after processing the packet. + * Clear the given tab. */ - void chatLog(CHATSKILL); + void clearTab(ChatTab* tab); + + /** + * Clear the current tab. + */ + void clearTab(); /** * Performs action. @@ -145,8 +125,11 @@ class ChatWindow : public Window, public gcn::ActionListener, /** * Request focus for typing chat message. + * + * \returns true if the input was shown + * false otherwise */ - void requestChatFocus(); + bool requestChatFocus(); /** * Checks whether ChatWindow is Focused or not. @@ -154,30 +137,12 @@ class ChatWindow : public Window, public gcn::ActionListener, bool isInputFocused(); /** - * Determines whether to send a command or an ordinary message, then - * contructs packets & sends them. - * - * @param nick The character's name to display in front. - * @param msg The message text which is to be send. + * Passes the text to the current tab as input * - * NOTE: - * The nickname is required by the server, if not specified - * the message may not be sent unless a command was intended - * which requires another packet to be constructed! you can - * achieve this by putting a slash ("/") infront of the - * message followed by the command name and the message. - * of course all slash-commands need implemented handler- - * routines. ;-) - * remember, a line starting with "@" is not a command that needs - * to be parsed rather is sent using the normal chat-packet. + * @param msg The message text which is to be sent. * - * EXAMPLE: - * // for an global announcement /- command - * chatlog.chat_send("", "/announce Hello to all logged in users!"); - * // for simple message by a user /- message - * chatlog.chat_send("Zaeiru", "Hello to all users on the screen!"); */ - void chatSend(const std::string &nick, std::string msg); + void chatSend(std::string &msg); /** Called when key is pressed */ void keyPressed(gcn::KeyEvent &event); @@ -191,65 +156,77 @@ class ChatWindow : public Window, public gcn::ActionListener, /** Override to reset mTmpVisible */ void setVisible(bool visible); - /** - * Scrolls the chat window - * - * @param amount direction and amount to scroll. Negative numbers scroll - * up, positive numbers scroll down. The absolute amount indicates the - * amount of 1/8ths of chat window real estate that should be scrolled. - */ - void scroll(int amount); - /** - * party implements the partying chat commands + * Scrolls the chat window * - * @param command is the party command to perform - * @param msg is the remainder of the message + * @param amount direction and amount to scroll. Negative numbers scroll + * up, positive numbers scroll down. The absolute amount indicates the + * amount of 1/8ths of chat window real estate that should be scrolled. */ - void party(const std::string &command, const std::string &msg); + void scroll(int amount); + +#ifdef EATHENA_SUPPORT + char getPartyPrefix() const { return mPartyPrefix; } + void setPartyPrefix(char prefix) { mPartyPrefix = prefix; } +#endif /** - * help implements the /help command + * Sets the file being recorded to * - * @param msg1 is the command that the player needs help on - * @param msg2 is the sub-command relating to the command + * @param msg The file to write out to. If null, then stop recording. */ - void help(const std::string &msg1, const std::string &msg2); + void setRecordingFile(const std::string &msg); - private: + bool getReturnTogglesChat() const { return mReturnToggles; } + void setReturnTogglesChat(bool toggles) { mReturnToggles = toggles; } + + void doPresent(); + + void whisper(std::string nick, std::string mes, bool own = false); + + protected: + friend class ChatTab; + friend class WhisperTab; + /** Remove the given tab from the window */ + void removeTab(ChatTab *tab); + + /** Add the tab to the window */ + void addTab(ChatTab *tab); + + void adjustTabSize(); + +#ifdef EATHENA_SUPPORT Network *mNetwork; - bool mTmpVisible; + char mPartyPrefix; /**< Messages beginning with the prefix are sent to + the party */ +#endif + /** Used for showing item popup on clicking links **/ + ItemLinkHandler *mItemLinkHandler; + Recorder *mRecorder; - void whisper(const std::string &nick, std::string msg); + /** Input box for typing chat messages. */ + gcn::TextField *mChatInput; - /** One item in the chat log */ - struct CHATLOG - { - std::string nick; - std::string text; - int own; - }; + private: + bool mTmpVisible; - /** Constructs failed messages for actions */ - std::string const_msg(CHATSKILL); + /** Tabbed area for holding each channel. */ + TabbedArea *mChatTabs; + Tab *mCurrentTab; + + typedef std::map<const std::string, ChatTab*> TabMap; + /** Manage whisper tabs */ + TabMap mWhispers; - gcn::TextField *mChatInput; /**< Input box for typing chat messages */ - BrowserBox *mTextOutput; /**< Text box for displaying chat history */ - ScrollArea *mScrollArea; /**< Scroll area around text output */ - ItemLinkHandler *mItemLinkHandler; /** Used for showing item popup on - clicking links **/ typedef std::list<std::string> History; typedef History::iterator HistoryIterator; - History mHistory; /**< Command history */ - HistoryIterator mCurHist; /**< History iterator */ - Recorder *mRecorder; /**< Recording class */ - char mPartyPrefix; /**< Messages beginning with the prefix are - sent to the party */ - bool mReturnToggles; /**< Marks whether <Return> toggles the chat - log or not */ - Party *mParty; + History mHistory; /**< Command history. */ + HistoryIterator mCurHist; /**< History iterator. */ + bool mReturnToggles; /**< Marks whether <Return> toggles the chat log + or not */ }; + extern ChatWindow *chatWindow; #endif diff --git a/src/gui/chatinput.cpp b/src/gui/chatinput.cpp index 42c6d4de..43f3cde4 100644 --- a/src/gui/chatinput.cpp +++ b/src/gui/chatinput.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/chatinput.h b/src/gui/chatinput.h index 96c30b3f..3bc16928 100644 --- a/src/gui/chatinput.h +++ b/src/gui/chatinput.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +26,8 @@ #include "textfield.h" +#include <guichan/focuslistener.hpp> + /** * The chat input hides when it loses focus. It is also invisible by default. */ diff --git a/src/gui/checkbox.cpp b/src/gui/checkbox.cpp index f6cce581..2623e2c6 100644 --- a/src/gui/checkbox.cpp +++ b/src/gui/checkbox.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,7 +35,7 @@ Image *CheckBox::checkBoxChecked; Image *CheckBox::checkBoxDisabled; Image *CheckBox::checkBoxDisabledChecked; -CheckBox::CheckBox(const std::string& caption, bool selected): +CheckBox::CheckBox(const std::string &caption, bool selected): gcn::CheckBox(caption, selected) { if (instances == 0) diff --git a/src/gui/checkbox.h b/src/gui/checkbox.h index 93b62b9d..303782b0 100644 --- a/src/gui/checkbox.h +++ b/src/gui/checkbox.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,7 +37,7 @@ class CheckBox : public gcn::CheckBox /** * Constructor. */ - CheckBox(const std::string& caption, bool selected = false); + CheckBox(const std::string &caption, bool selected = false); /** * Destructor. diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp index 4c08eb73..e1c32759 100644 --- a/src/gui/confirm_dialog.cpp +++ b/src/gui/confirm_dialog.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +33,7 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg, Window *parent): Window(title, true, parent) { - mTextBox = new TextBox(); + mTextBox = new TextBox; mTextBox->setEditable(false); mTextBox->setOpaque(false); @@ -75,11 +74,11 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg, add(yesButton); add(noButton); - setLocationRelativeTo(getParent()); - if (getParent()) + { + center(); getParent()->moveToTop(this); - + } setVisible(true); yesButton->requestFocus(); } diff --git a/src/gui/confirm_dialog.h b/src/gui/confirm_dialog.h index 493e9dda..8d8c0436 100644 --- a/src/gui/confirm_dialog.h +++ b/src/gui/confirm_dialog.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,7 +55,6 @@ class ConfirmDialog : public Window, public gcn::ActionListener private: TextBox *mTextBox; ScrollArea *mTextArea; - gcn::Button *okButton; }; #endif diff --git a/src/gui/connection.cpp b/src/gui/connection.cpp index d4a2b18a..5fb21ff2 100644 --- a/src/gui/connection.cpp +++ b/src/gui/connection.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,31 +19,22 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <guichan/actionlistener.hpp> - #include "button.h" #include "connection.h" #include "label.h" #include "progressbar.h" #include "../main.h" +#include "../log.h" #include "../utils/gettext.h" -namespace -{ - struct ConnectionActionListener : public gcn::ActionListener - { - void action(const gcn::ActionEvent &event) { state = EXIT_STATE; } - } listener; -} - -ConnectionDialog::ConnectionDialog(): - Window("Info"), mProgress(0) +ConnectionDialog::ConnectionDialog(int previousState): + Window("Info"), mProgress(0), mPreviousState(previousState) { setContentSize(200, 100); - Button *cancelButton = new Button(_("Cancel"), "cancelButton", &listener); + Button *cancelButton = new Button(_("Cancel"), "cancelButton", this); mProgressBar = new ProgressBar(0.0, 200 - 10, 20, 128, 128, 128); gcn::Label *label = new Label(_("Connecting...")); @@ -56,10 +46,16 @@ ConnectionDialog::ConnectionDialog(): add(cancelButton); add(mProgressBar); - setLocationRelativeTo(getParent()); + center(); setVisible(true); } +void ConnectionDialog::action(gcn::ActionEvent const &) +{ + logger->log("Cancel pressed"); + state = mPreviousState; +} + void ConnectionDialog::logic() { mProgress += 0.005f; diff --git a/src/gui/connection.h b/src/gui/connection.h index f91a0ad1..0e347266 100644 --- a/src/gui/connection.h +++ b/src/gui/connection.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +22,8 @@ #ifndef CONNECTION_H #define CONNECTION_H +#include <guichan/actionlistener.hpp> + #include "window.h" class ProgressBar; @@ -32,7 +33,7 @@ class ProgressBar; * * \ingroup Interface */ -class ConnectionDialog : public Window +class ConnectionDialog : public Window, gcn::ActionListener { public: /** @@ -40,13 +41,20 @@ class ConnectionDialog : public Window * * @see Window::Window */ - ConnectionDialog(); + ConnectionDialog(int previousState); + + /** + * Called when the user presses Cancel. Restores the global state to + * the previous one. + */ + void action(gcn::ActionEvent const &); void logic(); private: ProgressBar *mProgressBar; float mProgress; + int mPreviousState; }; #endif diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp index 9b8ea6bd..a98c9af4 100644 --- a/src/gui/debugwindow.cpp +++ b/src/gui/debugwindow.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/debugwindow.h b/src/gui/debugwindow.h index c82521f9..8097132c 100644 --- a/src/gui/debugwindow.h +++ b/src/gui/debugwindow.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/emotecontainer.cpp b/src/gui/emotecontainer.cpp index 22b4cf50..ececd9aa 100644 --- a/src/gui/emotecontainer.cpp +++ b/src/gui/emotecontainer.cpp @@ -2,8 +2,7 @@ * Extended support for activating emotes * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra derived from original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/emotecontainer.h b/src/gui/emotecontainer.h index 7e88cb71..88df29fc 100644 --- a/src/gui/emotecontainer.h +++ b/src/gui/emotecontainer.h @@ -2,8 +2,7 @@ * Extended support for activating emotes * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra derived from original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/emoteshortcutcontainer.cpp b/src/gui/emoteshortcutcontainer.cpp index 47fb9b06..661f42a7 100644 --- a/src/gui/emoteshortcutcontainer.cpp +++ b/src/gui/emoteshortcutcontainer.cpp @@ -2,8 +2,7 @@ * Extended support for activating emotes * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra derived from original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/emoteshortcutcontainer.h b/src/gui/emoteshortcutcontainer.h index ff9f929c..2997cb09 100644 --- a/src/gui/emoteshortcutcontainer.h +++ b/src/gui/emoteshortcutcontainer.h @@ -2,8 +2,7 @@ * Extended support for activating emotes * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra derived from original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/emotewindow.cpp b/src/gui/emotewindow.cpp index 77168993..d4b3cf2e 100644 --- a/src/gui/emotewindow.cpp +++ b/src/gui/emotewindow.cpp @@ -2,7 +2,7 @@ * Extended support for activating emotes * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,7 +35,7 @@ EmoteWindow::EmoteWindow(): Window(_("Emote")) { - setWindowName(_("Emote")); + setWindowName("Emote"); setResizable(true); setCloseButton(true); setMinWidth(80); @@ -44,7 +44,7 @@ EmoteWindow::EmoteWindow(): mUseButton = new Button(_("Use"), "use", this); - mEmotes = new EmoteContainer(); + mEmotes = new EmoteContainer; mEmotes->addSelectionListener(this); mEmoteScroll = new ScrollArea(mEmotes); diff --git a/src/gui/emotewindow.h b/src/gui/emotewindow.h index 81ee4f05..8af24a7b 100644 --- a/src/gui/emotewindow.h +++ b/src/gui/emotewindow.h @@ -2,7 +2,7 @@ * Extended support for activating emotes * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index 168ae22f..96500e88 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra derived from original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,6 +37,7 @@ #include "../item.h" #include "../localplayer.h" +#include "../resources/image.h" #include "../resources/iteminfo.h" #include "../resources/resourcemanager.h" @@ -59,11 +59,19 @@ static const int boxPosition[][2] = { {129, 78} // EQUIP_AMMO_SLOT }; +#ifdef TMWSERV_SUPPORT +EquipmentWindow::EquipmentWindow(Equipment *equipment): +#else EquipmentWindow::EquipmentWindow(): +#endif Window(_("Equipment")), +#ifdef TMWSERV_SUPPORT + mEquipment(equipment), +#endif + mBackground(NULL), mSelected(-1) { - mItemPopup = new ItemPopup(); + mItemPopup = new ItemPopup; mItemPopup->setOpaque(false); // Control that shows the Player @@ -84,19 +92,31 @@ EquipmentWindow::EquipmentWindow(): add(mPlayerBox); add(mUnequip); +#ifdef TMWSERV_SUPPORT + for (int i = 0; i < EQUIPMENT_SIZE; i++) +#else for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) +#endif { mEquipBox[i].posX = boxPosition[i][0] + getPadding(); mEquipBox[i].posY = boxPosition[i][1] + getTitleBarHeight(); } + ResourceManager *resman = ResourceManager::getInstance(); + mBackground = resman->getImage("graphics/gui/equip_bg.png"); + mBackground->setAlpha(0.3); + +#ifdef EATHENA_SUPPORT mEquipment = player_node->mEquipment.get(); mInventory = player_node->getInventory(); +#endif } EquipmentWindow::~EquipmentWindow() { + mBackground->decRef(); delete mItemPopup; + delete mUnequip; } void EquipmentWindow::draw(gcn::Graphics *graphics) @@ -107,13 +127,15 @@ void EquipmentWindow::draw(gcn::Graphics *graphics) // Draw window graphics Window::draw(graphics); - Item* item; - Graphics *g = static_cast<Graphics*>(graphics); Window::drawChildren(graphics); +#ifdef TMWSERV_SUPPORT + for (int i = 0; i < EQUIPMENT_SIZE; i++) +#else for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) +#endif { if (i == mSelected) { @@ -131,14 +153,19 @@ void EquipmentWindow::draw(gcn::Graphics *graphics) g->drawRectangle(gcn::Rectangle(mEquipBox[i].posX, mEquipBox[i].posY, BOX_WIDTH, BOX_HEIGHT)); - item = (i != EQUIP_AMMO_SLOT) ? +#ifdef TMWSERV_SUPPORT + Item *item = mEquipment->getEquipment(i); +#else + Item *item = (i != EQUIP_AMMO_SLOT) ? mInventory->getItem(mEquipment->getEquipment(i)) : mInventory->getItem(mEquipment->getArrows()); +#endif if (item) { // Draw Item. - Image* image = item->getImage(); + Image *image = item->getImage(); g->drawImage(image, mEquipBox[i].posX, mEquipBox[i].posY); +#ifdef EATHENA_SUPPORT if (i == EQUIP_AMMO_SLOT) { g->setColor(guiPalette->getColor(Palette::TEXT)); @@ -147,6 +174,7 @@ void EquipmentWindow::draw(gcn::Graphics *graphics) mEquipBox[i].posY - getFont()->getHeight(), gcn::Graphics::CENTER); } +#endif } } } @@ -155,26 +183,38 @@ void EquipmentWindow::action(const gcn::ActionEvent &event) { if (event.getId() == "unequip" && mSelected > -1) { +#ifdef TMWSERV_SUPPORT + player_node->unequipItem(mSelected); +#else Item* item = (mSelected != EQUIP_AMMO_SLOT) ? mInventory->getItem(mEquipment->getEquipment(mSelected)) : mInventory->getItem(mEquipment->getArrows()); player_node->unequipItem(item); +#endif mSelected = -1; } } -Item* EquipmentWindow::getItem(const int &x, const int &y) +Item* EquipmentWindow::getItem(int x, int y) const { +#ifdef TMWSERV_SUPPORT + for (int i = 0; i < EQUIPMENT_SIZE; i++) +#else for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) +#endif { gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY, BOX_WIDTH, BOX_HEIGHT); if (tRect.isPointInRect(x, y)) { +#ifdef TMWSERV_SUPPORT + return mEquipment->getEquipment(i); +#else return (i != EQUIP_AMMO_SLOT) ? mInventory->getItem(mEquipment->getEquipment(i)) : mInventory->getItem(mEquipment->getArrows()); +#endif } } return NULL; @@ -192,11 +232,19 @@ void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent) if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) { // Checks if any of the presses were in the equip boxes. +#ifdef TMWSERV_SUPPORT + for (int i = 0; i < EQUIPMENT_SIZE; i++) +#else for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) +#endif { +#ifdef TMWSERV_SUPPORT + item = mEquipment->getEquipment(i); +#else item = (i != EQUIP_AMMO_SLOT) ? mInventory->getItem(mEquipment->getEquipment(i)) : mInventory->getItem(mEquipment->getArrows()); +#endif gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY, BOX_WIDTH, BOX_HEIGHT); diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h index 7fdbaac8..7f7150ff 100644 --- a/src/gui/equipmentwindow.h +++ b/src/gui/equipmentwindow.h @@ -1,33 +1,33 @@ /* - * Aethyra - * Copyright 2004 The Mana World Development Team + * The Mana World + * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra derived from original code - * from The Mana World. + * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef EQUIPMENT_WINDOW_H -#define EQUIPMENT_WINDOW_H +#ifndef EQUIPMENTWINDOW_H +#define EQUIPMENTWINDOW_H #include <guichan/actionlistener.hpp> #include "window.h" class Equipment; +class Image; class Inventory; class Item; class ItemPopup; @@ -53,7 +53,11 @@ class EquipmentWindow : public Window, public gcn::ActionListener /** * Constructor. */ +#ifdef TMWSERV_SUPPORT + EquipmentWindow(Equipment *equipment); +#else EquipmentWindow(); +#endif /** * Destructor. @@ -69,6 +73,23 @@ class EquipmentWindow : public Window, public gcn::ActionListener void mousePressed(gcn::MouseEvent& mouseEvent); +#ifdef TMWSERV_SUPPORT + enum{ + // Equipment rules: + EQUIP_TORSO_SLOT = 0, + EQUIP_ARMS_SLOT = 1, + EQUIP_HEAD_SLOT = 2, + EQUIP_LEGS_SLOT = 3, + EQUIP_FEET_SLOT = 4, + EQUIP_RING1_SLOT = 5, + EQUIP_RING2_SLOT = 6, + EQUIP_NECKLACE_SLOT = 7, + EQUIP_FIGHT1_SLOT = 8, + EQUIP_FIGHT2_SLOT = 9, + EQUIP_PROJECTILE_SLOT = 10, + EQUIP_VECTOREND + }; +#else enum { // Equipment rules: EQUIP_LEGS_SLOT = 0, @@ -84,17 +105,20 @@ class EquipmentWindow : public Window, public gcn::ActionListener EQUIP_AMMO_SLOT, EQUIP_VECTOREND }; - +#endif private: void mouseExited(gcn::MouseEvent &event); void mouseMoved(gcn::MouseEvent &event); - Item* getItem(const int &x, const int &y); + Item* getItem(int x, int y) const; Equipment *mEquipment; +#ifdef EATHENA_SUPPORT Inventory *mInventory; +#endif gcn::Button *mUnequip; /**< Button for unequipping. */ + Image *mBackground; /**< Background Image. */ EquipBox mEquipBox[EQUIP_VECTOREND]; /**< Equipment Boxes. */ ItemPopup *mItemPopup; diff --git a/src/gui/focushandler.cpp b/src/gui/focushandler.cpp index c642127d..b9cfd789 100644 --- a/src/gui/focushandler.cpp +++ b/src/gui/focushandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/focushandler.h b/src/gui/focushandler.h index fc5dd240..b0639bd8 100644 --- a/src/gui/focushandler.h +++ b/src/gui/focushandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/gccontainer.cpp b/src/gui/gccontainer.cpp index 7aebed15..8325ccd4 100644 --- a/src/gui/gccontainer.cpp +++ b/src/gui/gccontainer.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/gccontainer.h b/src/gui/gccontainer.h index 2071955d..da584a42 100644 --- a/src/gui/gccontainer.h +++ b/src/gui/gccontainer.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 5bdab453..87ce74fa 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,7 +94,7 @@ Gui::Gui(Graphics *graphics): mFocusHandler = new FocusHandler; // Initialize top GUI widget - WindowContainer *guiTop = new WindowContainer(); + WindowContainer *guiTop = new WindowContainer; guiTop->setDimension(gcn::Rectangle(0, 0, graphics->getWidth(), graphics->getHeight())); guiTop->setOpaque(false); @@ -105,7 +104,8 @@ Gui::Gui(Graphics *graphics): ResourceManager *resman = ResourceManager::getInstance(); // Set global font - std::string path = resman->getPath("fonts/dejavusans.ttf"); + std::string path = resman->getPath( + branding.getValue("font", "fonts/dejavusans.ttf")); try { const int fontSize = (int)config.getValue("fontSize", 11); @@ -119,7 +119,8 @@ Gui::Gui(Graphics *graphics): } // Set bold font - path = resman->getPath("fonts/dejavusans-bold.ttf"); + path = resman->getPath( + branding.getValue("boldFont", "fonts/dejavusans.ttf")); try { const int fontSize = (int)config.getValue("fontSize", 11); @@ -139,7 +140,7 @@ Gui::Gui(Graphics *graphics): config.addListener("customcursor", mConfigListener); // Create the viewport - viewport = new Viewport(); + viewport = new Viewport; viewport->setDimension(gcn::Rectangle(0, 0, graphics->getWidth(), graphics->getHeight())); guiTop->add(viewport); diff --git a/src/gui/gui.h b/src/gui/gui.h index 609648fd..2ce153db 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/guildlistbox.cpp b/src/gui/guildlistbox.cpp new file mode 100644 index 00000000..a4d39741 --- /dev/null +++ b/src/gui/guildlistbox.cpp @@ -0,0 +1,130 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "guildlistbox.h" + +#include "../graphics.h" + +#include "../resources/image.h" +#include "../resources/resourcemanager.h" + +#include <guichan/font.hpp> + +GuildListBox::GuildListBox(): + ListBox(NULL) +{ + onlineIcon = ResourceManager::getInstance()->getImage("graphics/gui/circle-green.png"); + offlineIcon = ResourceManager::getInstance()->getImage("graphics/gui/circle-gray.png"); +} + +void GuildListBox::draw(gcn::Graphics *gcnGraphics) +{ + if (!mListModel) + return; + + Graphics *graphics = static_cast<Graphics*>(gcnGraphics); + + graphics->setColor(gcn::Color(110, 160, 255)); + graphics->setFont(getFont()); + + int fontHeight = getFont()->getHeight(); + + // Draw rectangle below the selected list element + if (mSelected >= 0) { + graphics->fillRectangle(gcn::Rectangle(0, fontHeight * mSelected, + getWidth(), fontHeight)); + } + + // Draw the list elements + for (int i = 0, y = 0; + i < mListModel->getNumberOfElements(); + ++i, y += fontHeight) + { + // Draw online status + bool online = false; + UserMap::iterator itr = mUsers.find(mListModel->getElementAt(i)); + if (itr != mUsers.end()) + { + online = itr->second; + } + Image *icon = online ? onlineIcon : offlineIcon; + if (icon) + graphics->drawImage(icon, 1, y); + // Draw Name + graphics->setColor(gcn::Color(0, 0, 0)); + graphics->drawText(mListModel->getElementAt(i), 33, y); + } +} +/* +void GuildListBox::setSelected(int selected) +{ + if (!mListModel) + { + mSelected = -1; + } + else + { + // Update mSelected with bounds checking + mSelected = std::min(mListModel->getNumberOfElements() - 1, + std::max(-1, selected)); + + gcn::Widget *parent; + parent = (gcn::Widget*)getParent(); + if (parent) + { + gcn::Rectangle scroll; + scroll.y = (mSelected < 0) ? 0 : getFont()->getHeight() * mSelected; + scroll.height = getFont()->getHeight(); + parent->showWidgetPart(this, scroll); + } + } + + distributeValueChangedEvent(); +} +*/ +void GuildListBox::mousePressed(gcn::MouseEvent &event) +{ + if (event.getButton() == gcn::MouseEvent::LEFT) + { + int y = event.getY(); + setSelected(y / getFont()->getHeight()); + distributeActionEvent(); + } + // TODO: Add guild functions, ie private messaging + if (event.getButton() == gcn::MouseEvent::RIGHT) + { + // Show context menu + } +} + +void GuildListBox::setOnlineStatus(const std::string &user, bool online) +{ + UserMap::iterator itr = mUsers.find(user); + if (itr == mUsers.end()) + { + mUsers.insert(std::pair<std::string, bool>(user, online)); + } + else + { + itr->second = online; + } + adjustSize(); +} diff --git a/src/gui/guildlistbox.h b/src/gui/guildlistbox.h new file mode 100644 index 00000000..8d6e74f1 --- /dev/null +++ b/src/gui/guildlistbox.h @@ -0,0 +1,65 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GUI_GUILDLISTBOX_H +#define GUI_GUILDLISTBOX_H + +#include <map> +#include <string> +#include <vector> + +#include "listbox.h" + +class Image; + +class GuildListBox : public ListBox +{ +public: + /** + * Constructor + */ + GuildListBox(); + + /** + * Draws the list box. + */ + void draw(gcn::Graphics *gcnGraphics); + + void mousePressed(gcn::MouseEvent &event); + + /** + * Sets the index of the selected element. + */ +// void setSelected(int selected); + + /** + * Set whether a member is online or offline + */ + void setOnlineStatus(const std::string &user, bool online); + +private: + Image *onlineIcon; + Image *offlineIcon; + typedef std::map<std::string, bool> UserMap; + UserMap mUsers; +}; + +#endif diff --git a/src/gui/guildwindow.cpp b/src/gui/guildwindow.cpp new file mode 100644 index 00000000..c8a1872f --- /dev/null +++ b/src/gui/guildwindow.cpp @@ -0,0 +1,273 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * $$ + */ + +#include "guildwindow.h" + +#include "button.h" +#include "chat.h" +#include "confirm_dialog.h" +#include "guildlistbox.h" +#include "scrollarea.h" +#include "textdialog.h" +#include "windowcontainer.h" + +#include "widgets/layout.h" +#include "widgets/tabbedarea.h" + +#include "../guild.h" +#include "../log.h" +#include "../localplayer.h" + +#include "../net/tmwserv/chatserver/guild.h" +#include "../utils/dtor.h" +#include "../utils/gettext.h" + +#include <algorithm> + +#include <guichan/widgets/tab.hpp> + +GuildWindow::GuildWindow(): + Window(_("Guild")), + mFocus(false) +{ + setWindowName("Guild"); + setCaption(_("Guild")); + setResizable(false); + setCloseButton(true); + setMinWidth(200); + setMinHeight(280); + setDefaultSize(124, 41, 288, 330); + + // Set button events Id + mGuildButton[0] = new Button(_("Create Guild"), "CREATE_GUILD", this); + mGuildButton[1] = new Button(_("Invite User"), "INVITE_USER", this); + mGuildButton[2] = new Button(_("Quit Guild"), "QUIT_GUILD", this); + mGuildButton[1]->setEnabled(false); + mGuildButton[2]->setEnabled(false); + + mGuildTabs = new TabbedArea(); + + place(0, 0, mGuildButton[0]); + place(1, 0, mGuildButton[1]); + place(2, 0, mGuildButton[2]); + place(0, 1, mGuildTabs); + Layout &layout = getLayout(); + layout.setColWidth(0, 48); + layout.setColWidth(1, 65); + + loadWindowState(); +} + +GuildWindow::~GuildWindow() +{ + delete mGuildTabs; +} + +void GuildWindow::update() +{ + updateTab(); + + if (mGuildButton[2]->isEnabled() && mGuildTabs->getNumberOfTabs() <= 0) + { + mGuildButton[2]->setEnabled(false); + mGuildButton[1]->setEnabled(false); + } +} + +void GuildWindow::draw(gcn::Graphics *g) +{ + update(); + + Window::draw(g); +} + +void GuildWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + + // Stats Part + if (eventId == "CREATE_GUILD") + { + // Set focus so that guild name to be created can be typed. + mFocus = true; + guildDialog = new TextDialog("Guild Name", "Choose your guild's name", this); + guildDialog->setOKButtonActionId("CREATE_GUILD_OK"); + guildDialog->addActionListener(this); + } + else if (eventId == "INVITE_USER") + { + // TODO - Give feedback on whether the invite succeeded + mFocus = true; + inviteDialog = new TextDialog("Member Invite", "Who would you like to invite?", this); + inviteDialog->setOKButtonActionId("INVITE_USER_OK"); + inviteDialog->addActionListener(this); + } + else if (eventId == "QUIT_GUILD") + { + short guild = getSelectedGuild(); + if (guild) + { + Net::ChatServer::Guild::quitGuild(guild); + localChatTab->chatLog("Guild " + mGuildTabs->getSelectedTab()->getCaption() + " quit", BY_SERVER); + } + } + else if (eventId == "CREATE_GUILD_OK") + { + std::string name = guildDialog->getText(); + if(name.size() > 16) + { + // TODO : State too many characters in input. + return; + } + // Process guild name to be created, and unfocus. + Net::ChatServer::Guild::createGuild(name); + + // Defocus dialog + mFocus = false; + localChatTab->chatLog("Creating Guild called " + name, BY_SERVER); + guildDialog->scheduleDelete(); + } + else if (eventId == "INVITE_USER_OK") + { + std::string name = inviteDialog->getText(); + short selectedGuild = getSelectedGuild(); + + // Process invited user to be created and unfocus. + Net::ChatServer::Guild::invitePlayer(name, selectedGuild); + + // Defocus dialog + mFocus = false; + localChatTab->chatLog("Invited user " + name, BY_SERVER); + inviteDialog->scheduleDelete(); + } + else if (eventId == "yes") + { + logger->log("Sending invitation acceptance."); + Net::ChatServer::Guild::acceptInvite(invitedGuild); + } +} + +void GuildWindow::newGuildTab(const std::string &guildName) +{ + // Create new tab + GuildListBox *list = new GuildListBox(); + list->setListModel(player_node->getGuild(guildName)); + ScrollArea *sa = new ScrollArea(list); + sa->setDimension(gcn::Rectangle(5, 5, 135, 250)); + + // Add the listbox to the map + mGuildLists.insert(std::pair<std::string, GuildListBox*>(guildName, list)); + + mGuildTabs->addTab(guildName, sa); + mGuildTabs->setDimension(gcn::Rectangle(28,35,140,250)); + + updateTab(); +} + +void GuildWindow::updateTab() +{ + gcn::Tab *tab = mGuildTabs->getSelectedTab(); + if (tab) + { + setTab(tab->getCaption()); + } + mGuildTabs->logic(); +} + +void GuildWindow::setTab(const std::string &guildName) +{ + // Only enable invite button if user has rights + if(player_node->checkInviteRights(guildName)) + { + mGuildButton[1]->setEnabled(true); + } + else + { + mGuildButton[1]->setEnabled(false); + } + + mGuildButton[2]->setEnabled(true); +} + +bool GuildWindow::isWindowFocused() +{ + return mFocus; +} + +short GuildWindow::getSelectedGuild() +{ + if (mGuildTabs->getNumberOfTabs() > 0) + { + + Guild *guild = player_node->getGuild(mGuildTabs->getSelectedTab()->getCaption()); + + if (guild) + { + return guild->getId(); + } + } + + return 0; +} + +void GuildWindow::openAcceptDialog(const std::string &inviterName, + const std::string &guildName) +{ + std::string msg = inviterName + " has invited you to join the guild " + guildName; + localChatTab->chatLog(msg, BY_SERVER); + + acceptDialog = new ConfirmDialog("Accept Guild Invite", msg, this); + acceptDialog->addActionListener(this); + + invitedGuild = guildName; +} + +void GuildWindow::requestMemberList(short guildId) +{ + // Get the list of members for displaying in the guild window. + Net::ChatServer::Guild::getGuildMembers(guildId); +} + +void GuildWindow::removeTab(int guildId) +{ + Guild* guild = player_node->getGuild(guildId); + if (guild) + { + Tab *tab = mGuildTabs->getTab(guild->getName()); + if (tab) + { + mGuildTabs->removeTab(tab); + } + updateTab(); + } + mGuildTabs->logic(); +} + +void GuildWindow::setOnline(const std::string &guildName, const std::string &member, + bool online) +{ + GuildListMap::iterator itr = mGuildLists.find(guildName); + if (itr != mGuildLists.end()) + { + itr->second->setOnlineStatus(member, online); + } +} diff --git a/src/gui/guildwindow.h b/src/gui/guildwindow.h new file mode 100644 index 00000000..88a084e9 --- /dev/null +++ b/src/gui/guildwindow.h @@ -0,0 +1,135 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GUI_GUILDWINDOW_H +#define GUI_GUILDWINDOW_H + +#include <iosfwd> +#include <map> +#include <vector> + +#include <guichan/actionlistener.hpp> +#include <guichan/widgets/listbox.hpp> + +#include "window.h" + +#include "../guichanfwd.h" + +class LocalPlayer; +class TextDialog; +class ConfirmDialog; +class GuildListBox; +class ScrollArea; +class GCContainer; +class TabbedArea; + +class GuildWindow : public Window, public gcn::ActionListener +{ +public: + /** + * Constructor. + */ + GuildWindow(); + + /** + * Destructor. + */ + ~GuildWindow(); + + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event); + + /** + * Draw this window. + */ + void draw(gcn::Graphics *graphics); + + /** + * Updates this dialog. + */ + void update(); + + /** + * Create a new tab for a guild list. + */ + void newGuildTab(const std::string &guildName); + + /** + * Display guild's member list to active tab + */ + void setTab(const std::string &guildName); + + /** + * Update the contents of the active tab + */ + void updateTab(); + + /** + * Check if the window is in focus. + */ + bool isWindowFocused(); + + /** + * Create a dialog for accepting an invite + */ + void openAcceptDialog(const std::string &inviterName, const std::string &guildName); + + /** + * Request member list + */ + void requestMemberList(short guildId); + + /** + * Removes the selected tab + */ + void removeTab(int guildId); + + /** + * Set guild member status in userlist + */ + void setOnline(const std::string &guildName, const std::string &member, + bool online); + +protected: + /** + * Get selected guild tab + * @return Returns selected guild + */ + short getSelectedGuild(); + +private: + gcn::Button *mGuildButton[3]; + TextDialog *guildDialog; + TextDialog *inviteDialog; + ConfirmDialog *acceptDialog; + TabbedArea *mGuildTabs; + ScrollArea *mScrollArea; + bool mFocus; + std::string invitedGuild; + typedef std::map<std::string, GuildListBox*> GuildListMap; + GuildListMap mGuildLists; +}; + +extern GuildWindow *guildWindow; + +#endif diff --git a/src/gui/help.cpp b/src/gui/help.cpp index 0974abf7..4b4ba983 100644 --- a/src/gui/help.cpp +++ b/src/gui/help.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,12 +36,12 @@ HelpWindow::HelpWindow(): setMinWidth(300); setMinHeight(250); setContentSize(455, 350); - setWindowName(_("Help")); + setWindowName("Help"); setResizable(true); setDefaultSize(500, 400, ImageRect::CENTER); - mBrowserBox = new BrowserBox(); + mBrowserBox = new BrowserBox; mBrowserBox->setOpaque(false); mScrollArea = new ScrollArea(mBrowserBox); Button *okButton = new Button(_("Close"), "close", this); @@ -71,7 +70,7 @@ void HelpWindow::action(const gcn::ActionEvent &event) } } -void HelpWindow::handleLink(const std::string& link) +void HelpWindow::handleLink(const std::string &link) { std::string helpFile = link; loadHelp(helpFile); diff --git a/src/gui/help.h b/src/gui/help.h index 93d32c18..8764e733 100644 --- a/src/gui/help.h +++ b/src/gui/help.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,7 +49,7 @@ class HelpWindow : public Window, public LinkHandler, /** * Handles link action. */ - void handleLink(const std::string& link); + void handleLink(const std::string &link); /** * Loads help in the dialog. diff --git a/src/gui/icon.cpp b/src/gui/icon.cpp new file mode 100644 index 00000000..c4f0ecc3 --- /dev/null +++ b/src/gui/icon.cpp @@ -0,0 +1,58 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "icon.h" + +#include "../graphics.h" + +#include "../resources/image.h" +#include "../resources/resourcemanager.h" + +Icon::Icon(const std::string &file) + : mImage(0) +{ + mImage = ResourceManager::getInstance()->getImage(file); + setSize(mImage->getWidth(), mImage->getHeight()); + +} + +Icon::Icon(Image *image) + : mImage(image) +{ + setSize(mImage->getWidth(), mImage->getHeight()); +} + +void Icon::setImage(Image *image) +{ + mImage = image; + setSize(mImage->getWidth(), mImage->getHeight()); +} + +void Icon::draw(gcn::Graphics *g) +{ + if(mImage) + { + Graphics *graphics = static_cast<Graphics*>(g); + const int x = (getWidth() - mImage->getWidth()) / 2; + const int y = (getHeight() - mImage->getHeight()) / 2; + graphics->drawImage(mImage, x, y); + } +} diff --git a/src/gui/icon.h b/src/gui/icon.h new file mode 100644 index 00000000..f8d77e0f --- /dev/null +++ b/src/gui/icon.h @@ -0,0 +1,66 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ICON_H +#define ICON_H + +#include <guichan/widget.hpp> + +class Image; + +/** + * An icon. + * + * \ingroup GUI + */ +class Icon : public gcn::Widget +{ + public: + /** + * Constructor. + */ + Icon(const std::string &filename); + + /** + * Constructor, uses an existing Image. + */ + Icon(Image *image); + + /** + * Gets the current Image. + */ + Image *getImage() const { return mImage; } + + /** + * Sets the image to display. + */ + void setImage(Image *image); + + /** + * Draws the Icon. + */ + void draw(gcn::Graphics *g); + + private: + Image *mImage; +}; + +#endif // ICON_H diff --git a/src/gui/inttextfield.cpp b/src/gui/inttextfield.cpp index 40bbd887..d3fe448b 100644 --- a/src/gui/inttextfield.cpp +++ b/src/gui/inttextfield.cpp @@ -1,8 +1,8 @@ /* - * Aethyra - * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> + * The Mana World + * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -57,6 +57,16 @@ void IntTextField::setRange(int min, int max) { mMin = min; mMax = max; + + if (mValue < mMin) + mValue = mMin; + else if (mValue > mMax) + mValue = mMax; + + if (mDefault < mMin) + mDefault = mMin; + else if (mDefault > mMax) + mDefault = mMax; } int IntTextField::getValue() @@ -66,18 +76,28 @@ int IntTextField::getValue() void IntTextField::setValue(int i) { - if (i >= mMin && i <= mMax) - mValue = i; - else if (i < mMin) + if (i < mMin) mValue = mMin; else if (i > mMax) mValue = mMax; + else + mValue = i; const std::string valStr = toString(mValue); setText(valStr); setCaretPosition(valStr.length() + 1); } +void IntTextField::setDefaultValue(int value) +{ + if (value < mMin) + mDefault = mMin; + else if (value > mMax) + mDefault = mMax; + else + mDefault = value; +} + void IntTextField::reset() { setValue(mDefault); diff --git a/src/gui/inttextfield.h b/src/gui/inttextfield.h index f2e294ca..ec768bea 100644 --- a/src/gui/inttextfield.h +++ b/src/gui/inttextfield.h @@ -1,8 +1,8 @@ /* - * Aethyra - * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> + * The Mana World + * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,6 +56,11 @@ class IntTextField : public TextField void setValue(int value); /** + * Set the default value of the text box to the specified value. + */ + void setDefaultValue(int value); + + /** * Responds to key presses. */ void keyPressed(gcn::KeyEvent &event); diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index fef55b6c..21d2df3f 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +31,7 @@ #include "label.h" #include "progressbar.h" #include "scrollarea.h" +#include "sdlinput.h" #include "viewport.h" #include "widgets/layout.h" @@ -39,6 +39,7 @@ #include "../inventory.h" #include "../item.h" #include "../localplayer.h" +#include "../units.h" #include "../resources/iteminfo.h" @@ -48,14 +49,19 @@ InventoryWindow::InventoryWindow(int invSize): Window(_("Inventory")), mMaxSlots(invSize), + mSplit(false), mItemDesc(false) { - setWindowName(_("Inventory")); - setResizable(true); + setWindowName("Inventory"); + setResizable(false); setCloseButton(true); - + // LEEOR/TODO: Since this window is not resizable, do we really need to set these + // values or can we drop them? + setMinWidth(375); + setMinHeight(283); // If you adjust these defaults, don't forget to adjust the trade window's. setDefaultSize(375, 300, ImageRect::CENTER); + addKeyListener(this); std::string longestUseString = getFont()->getWidth(_("Equip")) > getFont()->getWidth(_("Use")) ? @@ -69,16 +75,23 @@ InventoryWindow::InventoryWindow(int invSize): mUseButton = new Button(longestUseString, "use", this); mDropButton = new Button(_("Drop"), "drop", this); - - mItems = new ItemContainer(player_node->getInventory(), 2); +#ifdef TMWSERV_SUPPORT + mSplitButton = new Button(_("Split"), "split", this); +#endif + +#ifdef TMWSERV_SUPPORT + mItems = new ItemContainer(player_node->getInventory(), 10, 5); +#else + mItems = new ItemContainer(player_node->getInventory(), 10, 5, 2); +#endif mItems->addSelectionListener(this); mInvenScroll = new ScrollArea(mItems); mInvenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mTotalWeight = player_node->mTotalWeight; - mMaxWeight = player_node->mMaxWeight; - mUsedSlots = player_node->getInventory()->getNumberOfSlotsUsed(); + mTotalWeight = -1; + mMaxWeight = -1; + mUsedSlots = -1; mSlotsLabel = new Label(_("Slots: ")); mWeightLabel = new Label(_("Weight: ")); @@ -93,12 +106,15 @@ InventoryWindow::InventoryWindow(int invSize): place(1, 0, mWeightBar, 3); place(4, 0, mSlotsLabel).setPadding(3); place(5, 0, mSlotsBar, 2); - place(0, 1, mInvenScroll, 7, 4); - place(5, 5, mDropButton); - place(6, 5, mUseButton); + place(0, 1, mInvenScroll, 100).setPadding(3); + place(0, 2, mUseButton); + place(1, 2, mDropButton); +#ifdef TMWSERV_SUPPORT + place(2, 2, mSplitButton); +#endif Layout &layout = getLayout(); - layout.setRowHeight(0, mDropButton->getHeight()); + layout.setRowHeight(0, Layout::AUTO_SET); loadWindowState(); } @@ -121,17 +137,18 @@ void InventoryWindow::logic() const int usedSlots = player_node->getInventory()->getNumberOfSlotsUsed(); - if (mMaxWeight != player_node->mMaxWeight || - mTotalWeight != player_node->mTotalWeight || mUsedSlots != usedSlots) + if (mMaxWeight != player_node->getMaxWeight() || + mTotalWeight != player_node->getTotalWeight() || + mUsedSlots != usedSlots) { - mTotalWeight = player_node->mTotalWeight; - mMaxWeight = player_node->mMaxWeight; + mTotalWeight = player_node->getTotalWeight(); + mMaxWeight = player_node->getMaxWeight(); mUsedSlots = usedSlots; // Weight Bar coloration if (mTotalWeight < (mMaxWeight / 3)) mWeightBar->setColor(0, 0, 255); // Blue - else if (mTotalWeight < ((mMaxWeight / 3) * 2)) + else if (mTotalWeight < ((mMaxWeight * 2) / 3)) mWeightBar->setColor(255, 255, 0); // Yellow else mWeightBar->setColor(255, 0, 0); // Red @@ -141,7 +158,9 @@ void InventoryWindow::logic() mWeightBar->setProgress((float) mTotalWeight / mMaxWeight); mSlotsBar->setText(strprintf("%d/%d", mUsedSlots, mMaxSlots)); - mWeightBar->setText(strprintf("%dg/%dg", mTotalWeight, mMaxWeight)); + mWeightBar->setText(strprintf("%s/%s", + Units::formatWeight(mTotalWeight).c_str(), + Units::formatWeight(mMaxWeight).c_str())); } } @@ -154,6 +173,14 @@ void InventoryWindow::action(const gcn::ActionEvent &event) if (event.getId() == "use") { +#ifdef TMWSERV_SUPPORT + if (item->isEquipment()) { + player_node->equipItem(item); + } + else { + player_node->useItem(item->getInvIndex()); + } +#else if (item->isEquipment()) { if (item->isEquipped()) @@ -163,19 +190,33 @@ void InventoryWindow::action(const gcn::ActionEvent &event) } else player_node->useItem(item); +#endif } else if (event.getId() == "drop") { - if (item->getQuantity() == 1) - player_node->dropItem(item, 1); - else - { + if (item->getQuantity() > 1) { // Choose amount of items to drop new ItemAmountWindow(AMOUNT_ITEM_DROP, this, item); } + else { + player_node->dropItem(item, 1); + } + mItems->selectNone(); + } + else if (event.getId() == "split") + { + if (item && !item->isEquipment() && item->getQuantity() > 1) { + new ItemAmountWindow(AMOUNT_ITEM_SPLIT, this, item, + (item->getQuantity() - 1)); + } } } +Item* InventoryWindow::getSelectedItem() const +{ + return mItems->getSelectedItem(); +} + void InventoryWindow::mouseClicked(gcn::MouseEvent &event) { Window::mouseClicked(event); @@ -196,15 +237,55 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event) } } +#ifdef TMWSERV_SUPPORT +void InventoryWindow::keyPressed(gcn::KeyEvent &event) +{ + switch (event.getKey().getValue()) + { + case Key::LEFT_SHIFT: + case Key::RIGHT_SHIFT: + mSplit = true; + break; + } +} + +void InventoryWindow::keyReleased(gcn::KeyEvent &event) +{ + switch (event.getKey().getValue()) + { + case Key::LEFT_SHIFT: + case Key::RIGHT_SHIFT: + mSplit = false; + break; + } +} +#endif + +void InventoryWindow::valueChanged(const gcn::SelectionEvent &event) +{ + if (mSplit) + { + Item *item = mItems->getSelectedItem(); + + if (item && !item->isEquipment() && item->getQuantity() > 1) + { + mSplit = false; + new ItemAmountWindow(AMOUNT_ITEM_SPLIT, this, item, (item->getQuantity() - 1)); + } + } +} + void InventoryWindow::updateButtons() { const Item *selectedItem = mItems->getSelectedItem(); if (selectedItem && selectedItem->isEquipment()) { +#ifdef EATHENA_SUPPORT if (selectedItem->isEquipped()) mUseButton->setCaption(_("Unequip")); else +#endif mUseButton->setCaption(_("Equip")); } else @@ -212,9 +293,15 @@ void InventoryWindow::updateButtons() mUseButton->setEnabled(selectedItem != 0); mDropButton->setEnabled(selectedItem != 0); -} -Item* InventoryWindow::getSelectedItem() const -{ - return mItems->getSelectedItem(); +#ifdef TMWSERV_SUPPORT + if (selectedItem && !selectedItem->isEquipment() && + selectedItem->getQuantity() > 1) + { + mSplitButton->setEnabled(true); + } + else { + mSplitButton->setEnabled(false); + } +#endif } diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index 5035bf1c..0bdc8809 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,13 +22,14 @@ #ifndef INVENTORYWINDOW_H #define INVENTORYWINDOW_H -#include <guichan/actionlistener.hpp> -#include <guichan/selectionlistener.hpp> - #include "window.h" #include "../inventory.h" +#include <guichan/actionlistener.hpp> +#include <guichan/keylistener.hpp> +#include <guichan/selectionlistener.hpp> + class Item; class ItemContainer; class ProgressBar; @@ -40,14 +40,20 @@ class TextBox; * * \ingroup Interface */ -class InventoryWindow : public Window, gcn::ActionListener, - gcn::SelectionListener +class InventoryWindow : public Window, + public gcn::ActionListener, + public gcn::KeyListener, + public gcn::SelectionListener { public: /** * Constructor. */ +#ifdef TMWSERV_SUPPORT + InventoryWindow(int invSize = (INVENTORY_SIZE)); +#else InventoryWindow(int invSize = (INVENTORY_SIZE - 2)); +#endif /** * Destructor. @@ -69,8 +75,28 @@ class InventoryWindow : public Window, gcn::ActionListener, */ Item* getSelectedItem() const; + /** + * Handles the mouse clicks. + */ void mouseClicked(gcn::MouseEvent &event); +#ifdef TMWSERV_SUPPORT + /** + * Handles the key presses. + */ + void keyPressed(gcn::KeyEvent &event); + + /** + * Handles the key releases. + */ + void keyReleased(gcn::KeyEvent &event); +#endif + + /** + * Updates labels to currently selected item. + */ + void valueChanged(const gcn::SelectionEvent &event); + private: void updateButtons(); /**< Updates button states. */ @@ -81,9 +107,12 @@ class InventoryWindow : public Window, gcn::ActionListener, int mUsedSlots; int mTotalWeight; int mMaxWeight; - gcn::Button *mUseButton, *mDropButton; - gcn::ScrollArea *mInvenScroll; - + gcn::Button *mUseButton; + gcn::Button *mDropButton; +#ifdef TMWSERV_SUPPORT + gcn::Button *mSplitButton; +#endif + gcn::ScrollArea *mInvenScroll; /**< Inventory Scroll Area. */ gcn::Label *mWeightLabel; gcn::Label *mSlotsLabel; @@ -92,6 +121,7 @@ class InventoryWindow : public Window, gcn::ActionListener, int mMaxSlots; + bool mSplit; bool mItemDesc; }; diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp index 5b3380c2..0f6aa593 100644 --- a/src/gui/item_amount.cpp +++ b/src/gui/item_amount.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +23,9 @@ #include "item_amount.h" #include "label.h" #include "slider.h" +#ifdef EATHENA_SUPPORT #include "storagewindow.h" +#endif #include "trade.h" #include "widgets/layout.h" @@ -35,12 +36,16 @@ #include "../utils/gettext.h" #include "../utils/strprintf.h" -ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item): +ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item, + int maxRange): Window("", true, parent), mItem(item), - mMax(item->getQuantity()), + mMax(maxRange), mUsage(usage) { + if (!mMax) + mMax = mItem->getQuantity(); + setCloseButton(true); // Integer field @@ -94,6 +99,9 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item): case AMOUNT_STORE_REMOVE: setCaption(_("Select amount of items to retrieve.")); break; + case AMOUNT_ITEM_SPLIT: + setCaption(_("Select amount of items to split.")); + break; default: break; } @@ -140,12 +148,18 @@ void ItemAmountWindow::action(const gcn::ActionEvent &event) case AMOUNT_ITEM_DROP: player_node->dropItem(mItem, amount); break; +#ifdef TMWSERV_SUPPORT + case AMOUNT_ITEM_SPLIT: + player_node->splitItem(mItem, amount); + break; +#else case AMOUNT_STORE_ADD: storageWindow->addStore(mItem, amount); break; case AMOUNT_STORE_REMOVE: storageWindow->removeStore(mItem, amount); break; +#endif default: return; break; diff --git a/src/gui/item_amount.h b/src/gui/item_amount.h index 34b33b37..344f8c28 100644 --- a/src/gui/item_amount.h +++ b/src/gui/item_amount.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,9 +33,10 @@ class Item; #define AMOUNT_ITEM_DROP 2 #define AMOUNT_STORE_ADD 3 #define AMOUNT_STORE_REMOVE 4 +#define AMOUNT_ITEM_SPLIT 5 /** - * Window used for selecting the amount of items to drop or trade. + * Window used for selecting the amount of items to drop, trade or split. * * \ingroup Interface */ @@ -46,7 +46,7 @@ class ItemAmountWindow : public Window, public gcn::ActionListener /** * Constructor. */ - ItemAmountWindow(int usage, Window *parent, Item *item); + ItemAmountWindow(int usage, Window *parent, Item *item, int maxRange = 0); /** * Called when receiving actions from widget. diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp index 8139e85e..960f58ad 100644 --- a/src/gui/itemcontainer.cpp +++ b/src/gui/itemcontainer.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,49 +19,72 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <guichan/mouseinput.hpp> -#include <guichan/selectionlistener.hpp> +#include "gui/itemcontainer.h" -#include "itemcontainer.h" -#include "itempopup.h" -#include "palette.h" -#include "viewport.h" +#include "gui/chat.h" +#include "gui/itempopup.h" +#include "gui/palette.h" +#include "gui/sdlinput.h" +#include "gui/viewport.h" -#include "../graphics.h" -#include "../inventory.h" -#include "../item.h" -#include "../itemshortcut.h" -#include "../localplayer.h" -#include "../log.h" +#include "graphics.h" +#include "inventory.h" +#include "item.h" +#include "itemshortcut.h" +#include "localplayer.h" +#include "log.h" -#include "../resources/image.h" -#include "../resources/resourcemanager.h" +#include "resources/image.h" +#include "resources/iteminfo.h" +#include "resources/resourcemanager.h" -#include "../utils/stringutils.h" +#include "utils/stringutils.h" -const int ItemContainer::gridWidth = 36; // item icon width + 4 -const int ItemContainer::gridHeight = 42; // item icon height + 10 +#include <guichan/mouseinput.hpp> +#include <guichan/selectionlistener.hpp> -static const int NO_ITEM = -1; +// TODO: Add support for adding items to the item shortcut window (global +// itemShortcut). -ItemContainer::ItemContainer(Inventory *inventory, int offset): +static const int BOX_WIDTH = 36; +static const int BOX_HEIGHT = 44; + +enum +{ + SEL_NONE = 0, + SEL_SELECTED, + SEL_SELECTING, + SEL_DESELECTING, + SEL_DRAGGING +}; + +ItemContainer::ItemContainer(Inventory *inventory, + int gridColumns, + int gridRows, + int offset): mInventory(inventory), - mSelectedItemIndex(NO_ITEM), - mLastSelectedItemId(NO_ITEM), - mOffset(offset) + mGridColumns(gridColumns), + mGridRows(gridRows), + mOffset(offset), + mSelectedItem(NULL), + mHighlightedItem(NULL), + mSelectionStatus(SEL_NONE), + mSwapItems(false), + mDescItems(false) { mItemPopup = new ItemPopup(); - mItemPopup->setOpaque(false); + setFocusable(true); ResourceManager *resman = ResourceManager::getInstance(); mSelImg = resman->getImage("graphics/gui/selection.png"); if (!mSelImg) logger->error("Unable to load selection.png"); - mMaxItems = mInventory->getLastUsedSlot() - (mOffset - 1); // Count from 0, usage from 2 - + addKeyListener(this); addMouseListener(this); - addWidgetListener(this); + + setSize((BOX_WIDTH - 1) * mGridColumns + 1, + (BOX_HEIGHT - 1) * mGridRows + 1); } ItemContainer::~ItemContainer() @@ -71,185 +93,214 @@ ItemContainer::~ItemContainer() delete mItemPopup; } -void ItemContainer::logic() -{ - if (!isVisible()) - return; - - gcn::Widget::logic(); - - int i = mInventory->getLastUsedSlot() - (mOffset - 1); // Count from 0, usage from 2 - - if (i != mMaxItems) - { - mMaxItems = i; - recalculateHeight(); - } -} - void ItemContainer::draw(gcn::Graphics *graphics) { - if (!isVisible()) - return; - - int columns = getWidth() / gridWidth; + Graphics *g = static_cast<Graphics*>(graphics); - // Have at least 1 column - if (columns < 1) - columns = 1; - - /* - * mOffset is used to compensate for some weirdness that eAthena inherited - * from Ragnarok Online. Inventory slots and cart slots are +2 from their - * actual index, while storage slots are +1. - */ - for (int i = mOffset; i < mInventory->getSize(); i++) + for (int i = 0; i < mGridColumns; i++) { - Item *item = mInventory->getItem(i); - - if (!item || item->getQuantity() <= 0) - continue; + for (int j = 0; j < mGridRows; j++) + { + // Items positions made to overlap on another. + int itemX = i * (BOX_WIDTH - 1); + int itemY = j * (BOX_HEIGHT - 1); - int itemX = ((i - mOffset) % columns) * gridWidth; - int itemY = ((i - mOffset) / columns) * gridHeight; + // Set color to black. + g->setColor(gcn::Color(0, 0, 0)); + // Draw box border. + g->drawRectangle( + gcn::Rectangle(itemX, itemY, BOX_WIDTH, BOX_HEIGHT)); - // Draw selection image below selected item - if (mSelectedItemIndex == i) - static_cast<Graphics*>(graphics)->drawImage(mSelImg, itemX, itemY); + Item *item = mInventory->getItem((j * mGridColumns) + i); - // Draw item icon - Image* image = item->getImage(); + if (!item || item->getId() == 0) + continue; - if (image) - static_cast<Graphics*>(graphics)->drawImage(image, itemX, itemY); + Image *image = item->getImage(); + if (image) + { + if (item == mSelectedItem) + { + if (mSelectionStatus == SEL_DRAGGING) { + // Reposition the coords to that of the cursor. + itemX = mDragPosX - (BOX_WIDTH / 2); + itemY = mDragPosY - (BOX_HEIGHT / 2); + } + else { + // Draw selected image. + g->drawImage(mSelImg, itemX, itemY); + } + } + g->drawImage(image, itemX, itemY); + } + if (item->getQuantity() > 1) { + // Draw item caption + g->drawText( + toString(item->getQuantity()), + itemX + BOX_WIDTH / 2, + itemY + BOX_HEIGHT - 14, + gcn::Graphics::CENTER); + } - // Draw item caption - graphics->setFont(getFont()); - graphics->setColor(guiPalette->getColor(Palette::TEXT)); - graphics->drawText( - (item->isEquipped() ? "Eq." : toString(item->getQuantity())), - itemX + gridWidth / 2, itemY + gridHeight - 11, - gcn::Graphics::CENTER); + } } -} -void ItemContainer::widgetResized(const gcn::Event &event) -{ - recalculateHeight(); + if (isFocused() && mHighlightedItem) { + // Items positions made to overlap on another. + const int i = mHighlightedItem->getInvIndex(); + const int itemX = (i % mGridColumns) * (BOX_WIDTH - 1); + const int itemY = (i / mGridColumns) * (BOX_HEIGHT - 1); + // Set color to orange. + g->setColor(gcn::Color(255, 128, 0)); + // Draw box border. + g->drawRectangle(gcn::Rectangle(itemX, itemY, BOX_WIDTH, BOX_HEIGHT)); + } } -void ItemContainer::recalculateHeight() +void ItemContainer::selectNone() { - int cols = getWidth() / gridWidth; - - if (cols < 1) - cols = 1; - - const int rows = (mMaxItems / cols) + (mMaxItems % cols > 0 ? 1 : 0); - const int height = rows * gridHeight + 8; - - if (height != getHeight()) - setHeight(height); + setSelectedItem(NULL); } -Item *ItemContainer::getSelectedItem() +void ItemContainer::setSelectedItem(Item *item) { - refindSelectedItem(); // Make sure that we're still current - - if (mSelectedItemIndex == NO_ITEM) - return NULL; - - return mInventory->getItem(mSelectedItemIndex); + if (mSelectedItem != item) + { + mSelectedItem = item; + distributeValueChangedEvent(); + } } -void ItemContainer::selectNone() +void ItemContainer::distributeValueChangedEvent() { - setSelectedItemIndex(NO_ITEM); -} + SelectionListenerIterator iter; -void ItemContainer::refindSelectedItem() -{ - if (mSelectedItemIndex != NO_ITEM) + for (iter = mSelectionListeners.begin(); iter != mSelectionListeners.end(); + ++iter) { - - if (mInventory->getItem(mSelectedItemIndex) && - mInventory->getItem(mSelectedItemIndex)->getId() == mLastSelectedItemId) - return; // we're already fine - - // Otherwise ensure the invariant: we must point to an item of the specified last ID, - // or nowhere at all. - - for (int i = 0; i <= mMaxItems + 1; i++) - if (mInventory->getItem(i) && - mInventory->getItem(i)->getId() == mLastSelectedItemId) - { - mSelectedItemIndex = i; - return; - } + gcn::SelectionEvent event(this); + (*iter)->valueChanged(event); } - - mLastSelectedItemId = mSelectedItemIndex = NO_ITEM; } -void ItemContainer::setSelectedItemIndex(int index) +void ItemContainer::keyPressed(gcn::KeyEvent &event) { - int newSelectedItemIndex; - - /* - * mOffset is used to compensate for some weirdness that eAthena inherited from - * Ragnarok Online. Inventory slots and cart slots are +2 from their actual index, - * while storage slots are +1. - */ - if (index < 0 || index > mMaxItems + mOffset || mInventory->getItem(index) == NULL) - newSelectedItemIndex = NO_ITEM; - else - newSelectedItemIndex = index; - if (mSelectedItemIndex != newSelectedItemIndex) + switch (event.getKey().getValue()) { - mSelectedItemIndex = newSelectedItemIndex; - - if (mSelectedItemIndex == NO_ITEM) - mLastSelectedItemId = NO_ITEM; - else - mLastSelectedItemId = mInventory->getItem(index)->getId(); - - distributeValueChangedEvent(); + case Key::LEFT: + moveHighlight(MOVE_SELECTED_LEFT); + break; + case Key::RIGHT: + moveHighlight(MOVE_SELECTED_RIGHT); + break; + case Key::UP: + moveHighlight(MOVE_SELECTED_UP); + break; + case Key::DOWN: + moveHighlight(MOVE_SELECTED_DOWN); + break; + case Key::SPACE: + keyAction(); + break; + case Key::LEFT_ALT: + case Key::RIGHT_ALT: + mSwapItems = true; + break; + case Key::RIGHT_CONTROL: + mDescItems = true; + break; } } -void ItemContainer::distributeValueChangedEvent() +void ItemContainer::keyReleased(gcn::KeyEvent &event) { - gcn::SelectionEvent event(this); - std::list<gcn::SelectionListener*>::iterator i_end = mListeners.end(); - std::list<gcn::SelectionListener*>::iterator i; - - for (i = mListeners.begin(); i != i_end; ++i) + switch (event.getKey().getValue()) { - (*i)->valueChanged(event); + case Key::LEFT_ALT: + case Key::RIGHT_ALT: + mSwapItems = false; + break; + case Key::RIGHT_CONTROL: + mDescItems = false; + break; } } void ItemContainer::mousePressed(gcn::MouseEvent &event) { const int button = event.getButton(); - if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT) { - int columns = getWidth() / gridWidth; - int mx = event.getX(); - int my = event.getY(); - int index = mx / gridWidth + ((my / gridHeight) * columns) + mOffset; - - itemShortcut->setItemSelected(-1); - setSelectedItemIndex(index); + const int index = getSlotIndex(event.getX(), event.getY()); + if (index == Inventory::NO_SLOT_INDEX) { + return; + } Item *item = mInventory->getItem(index); - if (item) + // put item name into chat window + if (mDescItems) + { + chatWindow->addItemText(item->getInfo().getName()); + } + + if (mSelectedItem && mSelectedItem == item) + { + mSelectionStatus = SEL_DESELECTING; + } + else if (item && item->getId()) + { + setSelectedItem(item); + mSelectionStatus = SEL_SELECTING; + itemShortcut->setItemSelected(item->getId()); + } + else + { + setSelectedItem(NULL); + mSelectionStatus = SEL_NONE; + } + } +} + +void ItemContainer::mouseDragged(gcn::MouseEvent &event) +{ + if (mSelectionStatus != SEL_NONE) + { + mSelectionStatus = SEL_DRAGGING; + mDragPosX = event.getX(); + mDragPosY = event.getY(); } } +void ItemContainer::mouseReleased(gcn::MouseEvent &event) +{ + switch (mSelectionStatus) + { + case SEL_SELECTING: + mSelectionStatus = SEL_SELECTED; + return; + case SEL_DESELECTING: + setSelectedItem(NULL); + mSelectionStatus = SEL_NONE; + return; + case SEL_DRAGGING: + mSelectionStatus = SEL_SELECTED; + break; + default: + return; + }; + + int index = getSlotIndex(event.getX(), event.getY()); + if (index == Inventory::NO_SLOT_INDEX) return; + Item *item = mInventory->getItem(index); + if (item == mSelectedItem) return; + player_node->moveInvItem(mSelectedItem, index); + setSelectedItem(NULL); + mSelectionStatus = SEL_NONE; +} + + // Show ItemTooltip void ItemContainer::mouseMoved(gcn::MouseEvent &event) { @@ -276,9 +327,95 @@ void ItemContainer::mouseExited(gcn::MouseEvent &event) int ItemContainer::getSlotIndex(const int posX, const int posY) const { - int columns = getWidth() / gridWidth; - int index = posX / gridWidth + ((posY / gridHeight) * columns) + mOffset; + if (getDimension().isPointInRect(posX, posY)) + { + // Takes into account, boxes are overlapping each other. + return (posY / (BOX_HEIGHT - 1)) * mGridColumns + (posX / (BOX_WIDTH - 1)); + } + return Inventory::NO_SLOT_INDEX; +} + +void ItemContainer::keyAction() +{ + // If there is no highlight then return. + if (!mHighlightedItem) + return; - return (index); + // If the highlight is on the selected item, then deselect it. + if (mHighlightedItem == mSelectedItem) + { + setSelectedItem(NULL); + mSelectionStatus = SEL_NONE; + } + // Check and swap items if necessary. + else if (mSwapItems && + mSelectedItem && + mHighlightedItem->getId()) + { + player_node->moveInvItem( + mSelectedItem, mHighlightedItem->getInvIndex()); + setSelectedItem(mHighlightedItem); + } + // If the highlight is on an item then select it. + else if (mHighlightedItem->getId()) + { + setSelectedItem(mHighlightedItem); + mSelectionStatus = SEL_SELECTED; + } + // If the highlight is on a blank space then move it. + else if (mSelectedItem) + { + player_node->moveInvItem( + mSelectedItem, mHighlightedItem->getInvIndex()); + setSelectedItem(NULL); + mSelectionStatus = SEL_NONE; + } } +void ItemContainer::moveHighlight(int direction) +{ + if (!mHighlightedItem) + { + if (mSelectedItem) { + mHighlightedItem = mSelectedItem; + } + else { + mHighlightedItem = mInventory->getItem(0); + } + return; + } + + switch (direction) + { + case MOVE_SELECTED_LEFT: + if (mHighlightedItem->getInvIndex() % mGridColumns == 0) + { + mHighlightedItem += mGridColumns; + } + mHighlightedItem--; + break; + case MOVE_SELECTED_RIGHT: + if ((mHighlightedItem->getInvIndex() % mGridColumns) == + (mGridColumns - 1)) + { + mHighlightedItem -= mGridColumns; + } + mHighlightedItem++; + break; + case MOVE_SELECTED_UP: + if (mHighlightedItem->getInvIndex() / mGridColumns == 0) + { + mHighlightedItem += (mGridColumns * mGridRows); + } + mHighlightedItem -= mGridColumns; + break; + case MOVE_SELECTED_DOWN: + if ((mHighlightedItem->getInvIndex() / mGridColumns) == + (mGridRows - 1)) + { + mHighlightedItem -= (mGridColumns * mGridRows); + } + mHighlightedItem += mGridColumns; + break; + } +} diff --git a/src/gui/itemcontainer.h b/src/gui/itemcontainer.h index fba4656f..38eaba01 100644 --- a/src/gui/itemcontainer.h +++ b/src/gui/itemcontainer.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,9 +24,9 @@ #include <list> +#include <guichan/keylistener.hpp> #include <guichan/mouselistener.hpp> #include <guichan/widget.hpp> -#include <guichan/widgetlistener.hpp> class Image; class Inventory; @@ -44,14 +43,19 @@ namespace gcn { * \ingroup GUI */ class ItemContainer : public gcn::Widget, - public gcn::MouseListener, - public gcn::WidgetListener + public gcn::KeyListener, + public gcn::MouseListener { public: /** * Constructor. Initializes the graphic. + * @param inventory + * @param gridColumns Amount of columns in grid. + * @param gridRows Amount of rows in grid. + * @param offset Index offset */ - ItemContainer(Inventory *inventory, int offset); + ItemContainer(Inventory *inventory, int gridColumns, int gridRows, + int offset = 0); /** * Destructor. @@ -59,19 +63,19 @@ class ItemContainer : public gcn::Widget, virtual ~ItemContainer(); /** - * Handles the logic of the ItemContainer + * Draws the items. */ - void logic(); + void draw(gcn::Graphics *graphics); /** - * Draws the items. + * Handles the key presses. */ - void draw(gcn::Graphics *graphics); + void keyPressed(gcn::KeyEvent &event); /** - * Called whenever the widget changes size. + * Handles the key releases. */ - void widgetResized(const gcn::Event &event); + void keyReleased(gcn::KeyEvent &event); /** * Handles mouse click. @@ -79,9 +83,20 @@ class ItemContainer : public gcn::Widget, void mousePressed(gcn::MouseEvent &event); /** + * Handles mouse dragged. + */ + void mouseDragged(gcn::MouseEvent &event); + + /** + * Handles mouse released. + */ + void mouseReleased(gcn::MouseEvent &event); + + /** * Returns the selected item. */ - Item* getSelectedItem(); + Item* getSelectedItem() const + { return mSelectedItem; } /** * Sets selected item to NULL. @@ -94,7 +109,7 @@ class ItemContainer : public gcn::Widget, */ void addSelectionListener(gcn::SelectionListener *listener) { - mListeners.push_back(listener); + mSelectionListeners.push_back(listener); } /** @@ -103,33 +118,50 @@ class ItemContainer : public gcn::Widget, */ void removeSelectionListener(gcn::SelectionListener *listener) { - mListeners.remove(listener); + mSelectionListeners.remove(listener); } + enum { + MOVE_SELECTED_LEFT, // 0 + MOVE_SELECTED_RIGHT, // 1 + MOVE_SELECTED_UP, // 2 + MOVE_SELECTED_DOWN // 3 + }; private: + /** + * Execute all the functionality associated with the action key. + */ + void keyAction(); + void mouseExited(gcn::MouseEvent &event); void mouseMoved(gcn::MouseEvent &event); /** + * Moves the highlight in the direction specified. + * + * @param direction The move direction of the highlighter. + */ + void moveHighlight(int direction); - * Sets the currently selected item. Invalid (e.g., negative) indices set `no item'. + /** + * Sets the currently selected item. */ - void setSelectedItemIndex(int index); + void setSelectedItem(Item *item); /** * Find the current item index by the most recently used item ID */ - void refindSelectedItem(void); + void refindSelectedItem(); /** * Determine and set the height of the container. */ - void recalculateHeight(void); + void recalculateHeight(); /** * Sends out selection events to the list of selection listeners. */ - void distributeValueChangedEvent(void); + void distributeValueChangedEvent(); /** * Gets the slot index based on the cursor position. @@ -138,22 +170,24 @@ class ItemContainer : public gcn::Widget, * @param posY The Y Coordinate position. * @return The slot index on success, -1 on failure. */ - int getSlotIndex(const int posX, const int posY) const; + int getSlotIndex(int posX, int posY) const; Inventory *mInventory; - Image *mSelImg; - - int mSelectedItemIndex; - int mLastSelectedItemId; // last selected item ID. If we lose the item, find again by ID. - int mMaxItems; + int mGridColumns, mGridRows; int mOffset; + Image *mSelImg; + Item *mSelectedItem, *mHighlightedItem; + int mSelectionStatus; + bool mSwapItems; + bool mDescItems; + int mDragPosX, mDragPosY; ItemPopup *mItemPopup; - std::list<gcn::SelectionListener*> mListeners; + typedef std::list<gcn::SelectionListener*> SelectionListenerList; + typedef SelectionListenerList::iterator SelectionListenerIterator; - static const int gridWidth; - static const int gridHeight; + SelectionListenerList mSelectionListeners; }; #endif diff --git a/src/gui/itemlinkhandler.cpp b/src/gui/itemlinkhandler.cpp index e9993c2d..29fa310d 100644 --- a/src/gui/itemlinkhandler.cpp +++ b/src/gui/itemlinkhandler.cpp @@ -1,22 +1,21 @@ /* - * Aethyra - * Copyright 2009 The Mana World Development Team + * The Mana World + * Copyright (C) 2009 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/gui/itemlinkhandler.h b/src/gui/itemlinkhandler.h index e4c3ea4a..c04afa9e 100644 --- a/src/gui/itemlinkhandler.h +++ b/src/gui/itemlinkhandler.h @@ -1,27 +1,26 @@ /* - * Aethyra - * Copyright 2009 The Mana World Development Team + * The Mana World + * Copyright (C) 2009 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef ITEM_LINK_HANDLER_H_ -#define ITEM_LINK_HANDLER_H_ +#ifndef ITEM_LINK_HANDLER_H +#define ITEM_LINK_HANDLER_H #include "linkhandler.h" diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp index f2ac374a..66729605 100644 --- a/src/gui/itempopup.cpp +++ b/src/gui/itempopup.cpp @@ -1,10 +1,9 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Legend of Mazzeroth Development Team * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Legend of Mazzeroth. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,6 +32,8 @@ #include "../graphics.h" +#include "../units.h" + #include "../resources/iteminfo.h" #include "../utils/gettext.h" @@ -41,15 +42,13 @@ ItemPopup::ItemPopup(): Popup("ItemPopup") { - mItemType = ""; - // Item Name - mItemName = new gcn::Label(""); + mItemName = new gcn::Label; mItemName->setFont(boldFont); mItemName->setPosition(2, 2); // Item Description - mItemDesc = new TextBox(); + mItemDesc = new TextBox; mItemDesc->setEditable(false); mItemDescScroll = new ScrollArea(mItemDesc); @@ -60,7 +59,7 @@ ItemPopup::ItemPopup(): mItemDescScroll->setPosition(2, getFont()->getHeight()); // Item Effect - mItemEffect = new TextBox(); + mItemEffect = new TextBox; mItemEffect->setEditable(false); mItemEffectScroll = new ScrollArea(mItemEffect); @@ -72,7 +71,7 @@ ItemPopup::ItemPopup(): (2 * getPadding())); // Item Weight - mItemWeight = new TextBox(); + mItemWeight = new TextBox; mItemWeight->setEditable(false); mItemWeightScroll = new ScrollArea(mItemWeight); @@ -111,9 +110,11 @@ void ItemPopup::setItem(const ItemInfo &item) mItemName->setWidth(boldFont->getWidth(item.getName())); mItemDesc->setTextWrapped(item.getDescription(), 196); mItemEffect->setTextWrapped(item.getEffect(), 196); - mItemWeight->setTextWrapped(_("Weight: ") + toString(item.getWeight()) + - _(" grams"), 196); + mItemWeight->setTextWrapped(_("Weight: ") + + Units::formatWeight(item.getWeight()), 196); +#ifdef EATHENA_SUPPORT mItemType = item.getType(); +#endif int minWidth = mItemName->getWidth(); @@ -161,11 +162,13 @@ void ItemPopup::setItem(const ItemInfo &item) void ItemPopup::updateColors() { +#ifdef EATHENA_SUPPORT mItemName->setForegroundColor(getColor(mItemType)); +#endif graphics->setColor(guiPalette->getColor(Palette::TEXT)); } -gcn::Color ItemPopup::getColor(const std::string& type) +gcn::Color ItemPopup::getColor(const std::string &type) { gcn::Color color; @@ -213,9 +216,9 @@ unsigned int ItemPopup::getNumRows() void ItemPopup::view(int x, int y) { if (graphics->getWidth() < (x + getWidth() + 5)) - x = graphics->getWidth() - getWidth(); + x = graphics->getWidth() - getWidth(); if ((y - getHeight() - 10) < 0) - y = 0; + y = 0; else y = y - getHeight() - 10; setPosition(x, y); diff --git a/src/gui/itempopup.h b/src/gui/itempopup.h index 29fd127a..0e386ef7 100644 --- a/src/gui/itempopup.h +++ b/src/gui/itempopup.h @@ -1,10 +1,9 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Legend of Mazzeroth Development Team * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Legend of Mazzeroth. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -78,7 +77,7 @@ class ItemPopup : public Popup ScrollArea *mItemEffectScroll; ScrollArea *mItemWeightScroll; - gcn::Color getColor(const std::string& type); + static gcn::Color getColor(const std::string &type); }; #endif // ITEMPOPUP_H diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp index a0697c5d..d4de3477 100644 --- a/src/gui/itemshortcutcontainer.cpp +++ b/src/gui/itemshortcutcontainer.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,24 +19,26 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "inventorywindow.h" -#include "itemshortcutcontainer.h" -#include "itempopup.h" -#include "palette.h" -#include "viewport.h" +#include "gui/itemshortcutcontainer.h" -#include "../configuration.h" -#include "../graphics.h" -#include "../inventory.h" -#include "../item.h" -#include "../itemshortcut.h" -#include "../keyboardconfig.h" -#include "../localplayer.h" +#include "gui/inventorywindow.h" +#include "gui/itempopup.h" +#include "gui/palette.h" +#include "gui/viewport.h" -#include "../resources/image.h" -#include "../resources/resourcemanager.h" +#include "configuration.h" +#include "graphics.h" +#include "inventory.h" +#include "item.h" +#include "itemshortcut.h" +#include "keyboardconfig.h" +#include "localplayer.h" -#include "../utils/stringutils.h" +#include "resources/image.h" +#include "resources/iteminfo.h" +#include "resources/resourcemanager.h" + +#include "utils/stringutils.h" ItemShortcutContainer::ItemShortcutContainer(): ShortcutContainer(), @@ -47,7 +48,7 @@ ItemShortcutContainer::ItemShortcutContainer(): addMouseListener(this); addWidgetListener(this); - mItemPopup = new ItemPopup(); + mItemPopup = new ItemPopup; mItemPopup->setOpaque(false); ResourceManager *resman = ResourceManager::getInstance(); @@ -109,7 +110,10 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics) if (image) { const std::string label = - item->isEquipped() ? "Eq." : toString(item->getQuantity()); +#ifdef EATHENA_SUPPORT + item->isEquipped() ? "Eq." : +#endif + toString(item->getQuantity()); g->drawImage(image, itemX, itemY); g->drawText(label, itemX + mBoxWidth / 2, itemY + mBoxHeight - 14, gcn::Graphics::CENTER); @@ -233,7 +237,7 @@ void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event) Item *item = player_node->getInventory()->findItem(itemId); - if (item) + if (item && inventoryWindow->isVisible()) { if (item->getInfo().getName() != mItemPopup->getItemName()) mItemPopup->setItem(item->getInfo()); diff --git a/src/gui/itemshortcutcontainer.h b/src/gui/itemshortcutcontainer.h index 0149754e..9d188bf0 100644 --- a/src/gui/itemshortcutcontainer.h +++ b/src/gui/itemshortcutcontainer.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/itemshortcutwindow.cpp b/src/gui/itemshortcutwindow.cpp new file mode 100644 index 00000000..6fe1a10b --- /dev/null +++ b/src/gui/itemshortcutwindow.cpp @@ -0,0 +1,71 @@ +/* + * The Mana World + * Copyright (C) 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "itemshortcutwindow.h" + +#include "itemshortcutcontainer.h" +#include "scrollarea.h" + +static const int SCROLL_PADDING = 0; + +ItemShortcutWindow::ItemShortcutWindow() +{ + setWindowName("ItemShortcut"); + // no title presented, title bar is padding so window can be moved. + gcn::Window::setTitleBarHeight(gcn::Window::getPadding()); + setShowTitle(false); + setResizable(true); + setDefaultSize(758, 174, 42, 426); + + mItems = new ItemShortcutContainer; + + const int border = SCROLL_PADDING * 2 + getPadding() * 2; + setMinWidth(mItems->getBoxWidth() + border); + setMinHeight(mItems->getBoxHeight() + border); + setMaxWidth(mItems->getBoxWidth() * mItems->getMaxItems() + border); + setMaxHeight(mItems->getBoxHeight() * mItems->getMaxItems() + border); + + mScrollArea = new ScrollArea(mItems); + mScrollArea->setPosition(SCROLL_PADDING, SCROLL_PADDING); + mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mScrollArea->setOpaque(false); + + add(mScrollArea); + + loadWindowState(); +} + +ItemShortcutWindow::~ItemShortcutWindow() +{ + delete mItems; + delete mScrollArea; +} + +void ItemShortcutWindow::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + + const gcn::Rectangle &area = getChildrenArea(); + + mScrollArea->setSize( + area.width - SCROLL_PADDING, + area.height - SCROLL_PADDING); +} diff --git a/src/gui/itemshortcutwindow.h b/src/gui/itemshortcutwindow.h new file mode 100644 index 00000000..baa34b13 --- /dev/null +++ b/src/gui/itemshortcutwindow.h @@ -0,0 +1,61 @@ +/* + * The Mana World + * Copyright (C) 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ITEMSHORTCUTWINDOW_H +#define ITEMSHORTCUTWINDOW_H + +#include "window.h" + +class ItemShortcutContainer; +class ScrollArea; + +/** + * A window around the ItemShortcutContainer. + * + * \ingroup Interface + */ +class ItemShortcutWindow : public Window +{ + public: + /** + * Constructor. + */ + ItemShortcutWindow(); + + /** + * Destructor. + */ + ~ItemShortcutWindow(); + + /** + * Called whenever the widget changes size. + */ + void widgetResized(const gcn::Event &event); + + private: + ItemShortcutContainer *mItems; + + ScrollArea *mScrollArea; +}; + +extern ItemShortcutWindow *itemShortcutWindow; + +#endif diff --git a/src/gui/label.cpp b/src/gui/label.cpp index f3e7bd04..d2fba12b 100644 --- a/src/gui/label.cpp +++ b/src/gui/label.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (c) 2009 Aethyra Development Team * - * This file is part of Aethyra based on original code - * from GUIChan. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include "label.h" #include "palette.h" @@ -27,12 +27,12 @@ Label::Label() : { } -Label::Label(const std::string& caption) : +Label::Label(const std::string &caption) : gcn::Label(caption) { } -void Label::draw(gcn::Graphics* graphics) +void Label::draw(gcn::Graphics *graphics) { setForegroundColor(guiPalette->getColor(Palette::TEXT)); gcn::Label::draw(static_cast<gcn::Graphics*>(graphics)); diff --git a/src/gui/label.h b/src/gui/label.h index 4a9bb805..dcda8e9d 100644 --- a/src/gui/label.h +++ b/src/gui/label.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (c) 2009 Aethyra Development Team * - * This file is part of Aethyra based on original code - * from GUIChan. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,12 +42,12 @@ class Label : public gcn::Label * Constructor. This version of the constructor sets the label with an * inintialization string. */ - Label(const std::string& caption); + Label(const std::string &caption); /** * Draws the label. */ - void draw(gcn::Graphics* graphics); + void draw(gcn::Graphics *graphics); }; #endif diff --git a/src/gui/linkhandler.h b/src/gui/linkhandler.h index ea1b25c8..30267f87 100644 --- a/src/gui/linkhandler.h +++ b/src/gui/linkhandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +24,8 @@ #include <string> +#include <string> + /** * A simple interface to windows that need to handle links from BrowserBox * widget. @@ -34,7 +35,7 @@ class LinkHandler public: virtual ~LinkHandler() { } - virtual void handleLink(const std::string& link) = 0; + virtual void handleLink(const std::string &link) = 0; }; #endif diff --git a/src/gui/listbox.cpp b/src/gui/listbox.cpp index 71e92eaf..7ba84ee7 100644 --- a/src/gui/listbox.cpp +++ b/src/gui/listbox.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/listbox.h b/src/gui/listbox.h index 09f00cdf..cfb58f15 100644 --- a/src/gui/listbox.h +++ b/src/gui/listbox.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/login.cpp b/src/gui/login.cpp index 7b9829fb..281a25a2 100644 --- a/src/gui/login.cpp +++ b/src/gui/login.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,70 +49,81 @@ LoginDialog::LoginDialog(LoginData *loginData): { gcn::Label *userLabel = new Label(_("Name:")); gcn::Label *passLabel = new Label(_("Password:")); +#ifdef EATHENA_SUPPORT gcn::Label *serverLabel = new Label(_("Server:")); gcn::Label *portLabel = new Label(_("Port:")); gcn::Label *dropdownLabel = new Label(_("Recent:")); std::vector<std::string> dfltServer; - dfltServer.push_back("www.aethyra.org"); - dfltServer.push_back("www.aethyra.org"); - dfltServer.push_back("209.168.213.109"); + dfltServer.push_back("server.themanaworld.org"); std::vector<std::string> dfltPort; - dfltPort.push_back("21001"); - dfltPort.push_back("22001"); - dfltPort.push_back("21001"); + dfltPort.push_back("6901"); mServerList = new DropDownList("MostRecent00", dfltServer, dfltPort, MAX_SERVER_LIST_SIZE); mServerListBox = new ListBox(mServerList); - mServerScrollArea = new ScrollArea(); + mServerScrollArea = new ScrollArea; +#endif mUserField = new TextField(mLoginData->username); mPassField = new PasswordField(mLoginData->password); +#ifdef EATHENA_SUPPORT mServerField = new TextField(mServerList->getServerAt(0)); mPortField = new TextField(mServerList->getPortAt(0)); mServerDropDown = new DropDown(mServerList, mServerScrollArea, mServerListBox); mServerDropDown->setOpaque(false); +#endif - mKeepCheck = new CheckBox(_("Keep"), mLoginData->remember); + mKeepCheck = new CheckBox(_("Remember Username"), mLoginData->remember); mOkButton = new Button(_("OK"), "ok", this); mCancelButton = new Button(_("Cancel"), "cancel", this); mRegisterButton = new Button(_("Register"), "register", this); mUserField->setActionEventId("ok"); mPassField->setActionEventId("ok"); +#ifdef EATHENA_SUPPORT mServerField->setActionEventId("ok"); + mPortField->setActionEventId("ok"); mServerDropDown->setActionEventId("changeSelection"); +#endif mUserField->addKeyListener(this); mPassField->addKeyListener(this); +#ifdef EATHENA_SUPPORT mServerField->addKeyListener(this); mPortField->addKeyListener(this); mServerDropDown->addKeyListener(this); +#endif mUserField->addActionListener(this); mPassField->addActionListener(this); +#ifdef EATHENA_SUPPORT mServerField->addActionListener(this); mPortField->addActionListener(this); mServerDropDown->addActionListener(this); mKeepCheck->addActionListener(this); +#endif place(0, 0, userLabel); place(0, 1, passLabel); +#ifdef EATHENA_SUPPORT place(0, 2, serverLabel); place(0, 3, portLabel); place(0, 4, dropdownLabel); +#endif place(1, 0, mUserField, 3).setPadding(1); place(1, 1, mPassField, 3).setPadding(1); +#ifdef EATHENA_SUPPORT place(1, 2, mServerField, 3).setPadding(1); place(1, 3, mPortField, 3).setPadding(1); place(1, 4, mServerDropDown, 3).setPadding(1); +#endif place(0, 5, mKeepCheck, 4); place(0, 6, mRegisterButton).setHAlign(LayoutCell::LEFT); place(2, 6, mCancelButton); place(3, 6, mOkButton); reflowLayout(250, 0); - setLocationRelativeTo(getParent()); + center(); setVisible(true); if (mUserField->getText().empty()) @@ -128,8 +138,10 @@ void LoginDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "ok" && canSubmit()) { +#ifdef EATHENA_SUPPORT mLoginData->hostname = mServerField->getText(); mLoginData->port = getUShort(mPortField->getText()); +#endif mLoginData->username = mUserField->getText(); mLoginData->password = mPassField->getText(); mLoginData->remember = mKeepCheck->isSelected(); @@ -137,21 +149,32 @@ void LoginDialog::action(const gcn::ActionEvent &event) mOkButton->setEnabled(false); mRegisterButton->setEnabled(false); +#ifdef EATHENA_SUPPORT mServerList->save(mServerField->getText(), mPortField->getText()); - state = ACCOUNT_STATE; + state = STATE_ACCOUNT; +#else + state = STATE_LOGIN_ATTEMPT; +#endif } +#ifdef EATHENA_SUPPORT else if (event.getId() == "changeSelection") { int selected = mServerListBox->getSelected(); mServerField->setText(mServerList->getServerAt(selected)); mPortField->setText(mServerList->getPortAt(selected)); } +#endif else if (event.getId() == "cancel") { - state = EXIT_STATE; +#ifdef TMWSERV_SUPPORT + state = STATE_SWITCH_ACCOUNTSERVER; +#else + state = STATE_EXIT; +#endif } else if (event.getId() == "register") { +#ifdef EATHENA_SUPPORT // Transfer these fields on to the register dialog mLoginData->hostname = mServerField->getText(); @@ -159,11 +182,12 @@ void LoginDialog::action(const gcn::ActionEvent &event) mLoginData->port = getUShort(mPortField->getText()); else mLoginData->port = 6901; +#endif mLoginData->username = mUserField->getText(); mLoginData->password = mPassField->getText(); - state = REGISTER_STATE; + state = STATE_REGISTER; } } @@ -176,11 +200,14 @@ bool LoginDialog::canSubmit() { return !mUserField->getText().empty() && !mPassField->getText().empty() && +#ifdef EATHENA_SUPPORT !mServerField->getText().empty() && isUShort(mPortField->getText()) && - state == LOGIN_STATE; +#endif + state == STATE_LOGIN; } +#ifdef EATHENA_SUPPORT bool LoginDialog::isUShort(const std::string &str) { if (str.empty()) @@ -305,3 +332,4 @@ std::string LoginDialog::DropDownList::getPortAt(int i) return mPorts.at(i); } +#endif diff --git a/src/gui/login.h b/src/gui/login.h index 4d63ec63..9a97cd4d 100644 --- a/src/gui/login.h +++ b/src/gui/login.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,13 +27,17 @@ #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> +#ifdef EATHENA_SUPPORT #include <guichan/listmodel.hpp> +#endif #include "window.h" -class DropDown; class LoginData; +#ifdef EATHENA_SUPPORT +class DropDown; class ScrollArea; +#endif /** * The login dialog. @@ -69,6 +72,7 @@ class LoginDialog : public Window, public gcn::ActionListener, */ bool canSubmit(); +#ifdef EATHENA_SUPPORT /** * Function to decide whether string is an unsigned short or not * @@ -87,11 +91,14 @@ class LoginDialog : public Window, public gcn::ActionListener, */ static unsigned short getUShort(const std::string &str); - DropDown *mServerDropDown; +#endif gcn::TextField *mUserField; gcn::TextField *mPassField; +#ifdef EATHENA_SUPPORT gcn::TextField *mServerField; gcn::TextField *mPortField; + DropDown *mServerDropDown; +#endif gcn::CheckBox *mKeepCheck; gcn::Button *mOkButton; gcn::Button *mCancelButton; @@ -99,6 +106,7 @@ class LoginDialog : public Window, public gcn::ActionListener, LoginData *mLoginData; +#ifdef EATHENA_SUPPORT /** * Helper class to keep a list of all the recent entries for the * dropdown @@ -126,6 +134,7 @@ class LoginDialog : public Window, public gcn::ActionListener, DropDownList *mServerList; gcn::ListBox *mServerListBox; gcn::ScrollArea *mServerScrollArea; +#endif }; #endif diff --git a/src/gui/magic.cpp b/src/gui/magic.cpp new file mode 100644 index 00000000..117c1f14 --- /dev/null +++ b/src/gui/magic.cpp @@ -0,0 +1,92 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/widgets/label.hpp> +#include <guichan/widgets/container.hpp> + +#include "magic.h" + +#include "button.h" + +#include "../localplayer.h" + +#include "../utils/dtor.h" +#include "../utils/gettext.h" + +MagicDialog::MagicDialog(): + Window(_("Magic")) +{ + setWindowName("Magic"); + setCloseButton(true); + setDefaultSize(255, 30, 175, 225); + + gcn::Button *spellButton1 = new Button(_("Cast Test Spell 1"), "spell_1", this); + gcn::Button *spellButton2 = new Button(_("Cast Test Spell 2"), "spell_2", this); + gcn::Button *spellButton3 = new Button(_("Cast Test Spell 3"), "spell_3", this); + + spellButton1->setPosition(10, 30); + spellButton2->setPosition(10, 60); + spellButton3->setPosition(10, 90); + + add(spellButton1); + add(spellButton2); + add(spellButton3); + + update(); + + setLocationRelativeTo(getParent()); + loadWindowState(); +} + +MagicDialog::~MagicDialog() +{ +} + +void MagicDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "spell_1") + { + player_node->useSpecial(1); + } + if (event.getId() == "spell_2") + { + player_node->useSpecial(2); + } + if (event.getId() == "spell_3") + { + player_node->useSpecial(3); + } + else if (event.getId() == "close") + { + setVisible(false); + } +} + +void MagicDialog::draw(gcn::Graphics *g) +{ + update(); + + Window::draw(g); +} + +void MagicDialog::update() +{ +} diff --git a/src/gui/magic.h b/src/gui/magic.h new file mode 100644 index 00000000..74529396 --- /dev/null +++ b/src/gui/magic.h @@ -0,0 +1,75 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MAGIC_H +#define MAGIC_H + +#include <guichan/actionlistener.hpp> + +#include "window.h" +#include "gccontainer.h" + +#include "../guichanfwd.h" + + +/** + * The skill dialog. + * + * \ingroup Interface + */ +class MagicDialog : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + */ + MagicDialog(); + + /** + * Destructor. + */ + ~MagicDialog(); + + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event); + + /** + * Update the tabs in this dialog + */ + void update(); + + /** + * Draw this window. + */ + void draw(gcn::Graphics *g); + + private: + +}; + + + + +extern MagicDialog *magicDialog; + +#endif diff --git a/src/gui/menuwindow.cpp b/src/gui/menuwindow.cpp index e1be908b..e6ae2d3b 100644 --- a/src/gui/menuwindow.cpp +++ b/src/gui/menuwindow.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,6 +39,11 @@ extern Window *emoteWindow; extern Window *setupWindow; extern Window *skillDialog; extern Window *statusWindow; +#ifdef TMWSERV_SUPPORT +extern Window *buddyWindow; +extern Window *guildWindow; +extern Window *magicDialog; +#endif namespace { struct MenuWindowListener : public gcn::ActionListener @@ -57,14 +61,19 @@ MenuWindow::MenuWindow(): // Buttons static const char *buttonNames[] = { - _("Chat"), - _("Status"), - _("Equipment"), - _("Inventory"), - _("Skills"), - _("Shortcut"), - _("Emote"), - _("Setup"), + N_("Chat"), + N_("Status"), + N_("Equipment"), + N_("Inventory"), + N_("Skills"), +#ifdef TMWSERV_SUPPORT + N_("Magic"), + N_("Guilds"), + N_("Buddys"), +#endif + N_("Shortcut"), + N_("Emote"), + N_("Setup"), 0 }; int x = 0, h = 0; @@ -91,35 +100,49 @@ void MenuWindowListener::action(const gcn::ActionEvent &event) { Window *window = NULL; - if (event.getId() == _("Chat")) + if (event.getId() == "Chat") { window = chatWindow; } - else if (event.getId() == _("Status")) + else if (event.getId() == "Status") { window = statusWindow; } - else if (event.getId() == _("Equipment")) + else if (event.getId() == "Equipment") { window = equipmentWindow; } - else if (event.getId() == _("Inventory")) + else if (event.getId() == "Inventory") { window = inventoryWindow; } - else if (event.getId() == _("Skills")) + else if (event.getId() == "Skills") { window = skillDialog; } - else if (event.getId() == _("Shortcut")) +#ifdef TMWSERV_SUPPORT + else if (event.getId() == "Magic") + { + window = magicDialog; + } + else if (event.getId() == "Guilds") + { + window = guildWindow; + } + else if (event.getId() == "Buddys") + { + window = buddyWindow; + } +#endif + else if (event.getId() == "Shortcut") { window = itemShortcutWindow; } - else if (event.getId() == _("Emote")) + else if (event.getId() == "Emote") { window = emoteWindow; } - else if (event.getId() == _("Setup")) + else if (event.getId() == "Setup") { window = setupWindow; } diff --git a/src/gui/menuwindow.h b/src/gui/menuwindow.h index e8dc0b2e..c3d5673e 100644 --- a/src/gui/menuwindow.h +++ b/src/gui/menuwindow.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp index f3da52c6..93a55688 100644 --- a/src/gui/minimap.cpp +++ b/src/gui/minimap.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004-2005 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,7 +40,7 @@ Minimap::Minimap(): mMapImage(NULL), mProportion(0.5) { - setWindowName(_("MiniMap")); + setWindowName("MiniMap"); mShow = config.getValue(getWindowName() + "Show", true); setDefaultSize(5, 25, 100, 100); setResizable(true); @@ -120,8 +119,14 @@ void Minimap::draw(gcn::Graphics *graphics) if (mMapImage->getWidth() > a.width || mMapImage->getHeight() > a.height) { +#ifdef TMWSERV_SUPPORT + const Vector &p = player_node->getPosition(); + mapOriginX = (int) (((a.width) / 2) - (int) (p.x * mProportion) / 32); + mapOriginY = (int) (((a.height) / 2) - (int) (p.y * mProportion) / 32); +#else mapOriginX = (int) (((a.width) / 2) - (player_node->mX * mProportion)); mapOriginY = (int) (((a.height) / 2) - (player_node->mY * mProportion)); +#endif const int minOriginX = a.width - mMapImage->getWidth(); const int minOriginY = a.height - mMapImage->getHeight(); @@ -172,10 +177,11 @@ void Minimap::draw(gcn::Graphics *graphics) } const int offset = (int) ((dotSize - 1) * mProportion); + const Vector &pos = being->getPosition(); graphics->fillRectangle(gcn::Rectangle( - (int) (being->mX * mProportion) + mapOriginX - offset, - (int) (being->mY * mProportion) + mapOriginY - offset, + (int) (pos.x * mProportion) / 32 + mapOriginX - offset, + (int) (pos.x * mProportion) / 32 + mapOriginY - offset, dotSize, dotSize)); } diff --git a/src/gui/minimap.h b/src/gui/minimap.h index 6e88f821..3ce0aacd 100644 --- a/src/gui/minimap.h +++ b/src/gui/minimap.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004-2005 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/ministatus.cpp b/src/gui/ministatus.cpp index 18b9d714..95577e69 100644 --- a/src/gui/ministatus.cpp +++ b/src/gui/ministatus.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +22,9 @@ #include "gui.h" #include "ministatus.h" #include "progressbar.h" +#include "status.h" +#include "../animatedsprite.h" #include "../configuration.h" #include "../graphics.h" #include "../localplayer.h" @@ -34,47 +35,56 @@ MiniStatusWindow::MiniStatusWindow(): Popup("MiniStatus") { mHpBar = new ProgressBar(1.0f, 100, 20, 0, 171, 34); +#ifdef EATHENA_SUPPORT mMpBar = new ProgressBar(1.0f, 100, 20, 26, 102, 230); mXpBar = new ProgressBar(1.0f, 100, 20, 143, 192, 211); +#endif mHpBar->setPosition(0, 3); +#ifdef EATHENA_SUPPORT mMpBar->setPosition(mHpBar->getWidth() + 3, 3); mXpBar->setPosition(mMpBar->getX() + mMpBar->getWidth() + 3, 3); +#endif add(mHpBar); +#ifdef EATHENA_SUPPORT add(mMpBar); add(mXpBar); +#endif +#ifdef EATHENA_SUPPORT setContentSize(mXpBar->getX() + mXpBar->getWidth(), mXpBar->getY() + mXpBar->getHeight()); +#else + setContentSize(mHpBar->getX() + mHpBar->getWidth(), + mHpBar->getY() + mHpBar->getHeight()); +#endif } -void MiniStatusWindow::update() +void MiniStatusWindow::setIcon(int index, AnimatedSprite *sprite) { - // HP Bar coloration - if (player_node->mHp < int(player_node->mMaxHp / 3)) - mHpBar->setColor(223, 32, 32); // Red - else if (player_node->mHp < int((player_node->mMaxHp / 3) * 2)) - mHpBar->setColor(230, 171, 34); // Orange - else - mHpBar->setColor(0, 171, 34); // Green + if (index >= (int) mIcons.size()) + mIcons.resize(index + 1, NULL); - float xp = (float) player_node->getXp() / player_node->mXpForNextLevel; + if (mIcons[index]) + delete mIcons[index]; - if (xp != xp) xp = 0.0f; // check for NaN - if (xp < 0.0f) xp = 0.0f; // make sure the experience isn't negative (uninitialized pointer most likely) - if (xp > 1.0f) xp = 1.0f; + mIcons[index] = sprite; +} - mHpBar->setProgress((float) player_node->mHp / player_node->mMaxHp); - mMpBar->setProgress((float) player_node->mMp / player_node->mMaxMp); - mXpBar->setProgress(xp); +void MiniStatusWindow::eraseIcon(int index) +{ + mIcons.erase(mIcons.begin() + index); +} - // Update labels - mHpBar->setText(toString(player_node->mHp)); - mMpBar->setText(toString(player_node->mMp)); +extern volatile int tick_time; - std::stringstream updatedText; - updatedText << (float) ((int) (xp * 10000.0f)) / 100.0f << "%"; +void MiniStatusWindow::update() +{ + StatusWindow::updateHPBar(mHpBar); +#ifdef EATHENA_SUPPORT + StatusWindow::updateMPBar(mMpBar); + StatusWindow::updateXPBar(mXpBar); // Displays the number of monsters to next lvl // (disabled for now but interesting idea) @@ -88,8 +98,11 @@ void MiniStatusWindow::update() << config.getValue("xpBarMonsterCounterName", "Monsters") <<" left..."; } */ +#endif - mXpBar->setText(updatedText.str()); + for (unsigned int i = 0; i < mIcons.size(); i++) + if (mIcons[i]) + mIcons[i]->update(tick_time * 10); } void MiniStatusWindow::draw(gcn::Graphics *graphics) @@ -97,3 +110,19 @@ void MiniStatusWindow::draw(gcn::Graphics *graphics) update(); drawChildren(graphics); } + +void MiniStatusWindow::drawIcons(Graphics *graphics) +{ + // Draw icons +#ifdef TMWSERV_SUPPORT + int icon_x = mHpBar->getX() + mHpBar->getWidth() + 4; +#else + int icon_x = mXpBar->getX() + mXpBar->getWidth() + 4; +#endif + for (unsigned int i = 0; i < mIcons.size(); i++) { + if (mIcons[i]) { + mIcons[i]->draw(graphics, icon_x, 3); + icon_x += 2 + mIcons[i]->getWidth(); + } + } +} diff --git a/src/gui/ministatus.h b/src/gui/ministatus.h index b3fc58fc..fd5a4e53 100644 --- a/src/gui/ministatus.h +++ b/src/gui/ministatus.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +24,10 @@ #include "popup.h" +#include <vector> + +class AnimatedSprite; +class Graphics; class ProgressBar; /** @@ -45,6 +48,15 @@ class MiniStatusWindow : public Popup */ void draw(gcn::Graphics *graphics); + /** + * Sets one of the icons. + */ + void setIcon(int index, AnimatedSprite *sprite); + + void eraseIcon(int index); + + void drawIcons(Graphics *graphics); + private: /** * Updates this dialog with values from player_node. @@ -55,8 +67,12 @@ class MiniStatusWindow : public Popup * Mini Status Bars */ ProgressBar *mHpBar; +#ifdef EATHENA_SUPPORT ProgressBar *mMpBar; ProgressBar *mXpBar; +#endif + + std::vector<AnimatedSprite *> mIcons; }; #endif diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp index f524f8ea..5158e966 100644 --- a/src/gui/npc_text.cpp +++ b/src/gui/npc_text.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,14 +29,26 @@ #include "../npc.h" #include "../net/messageout.h" -#include "../net/protocol.h" +#ifdef TMWSERV_SUPPORT +#include "../net/tmwserv/gameserver/player.h" +#else +#include "../net/ea/protocol.h" +#endif #include "../utils/gettext.h" -NpcTextDialog::NpcTextDialog(Network *network): - Window("NPC"), mNetwork(network) +#ifdef TMWSERV_SUPPORT +NpcTextDialog::NpcTextDialog() +#else +NpcTextDialog::NpcTextDialog(Network *network) +#endif + : Window(_("NPC")) +#ifdef EATHENA_SUPPORT + , mNetwork(network) +#endif + , mState(NPC_TEXT_STATE_WAITING) { - setWindowName(_("NPC")); + setWindowName("NPCText"); setResizable(true); setMinWidth(200); @@ -50,8 +61,7 @@ NpcTextDialog::NpcTextDialog(Network *network): mTextBox->setOpaque(false); mScrollArea = new ScrollArea(mTextBox); - mButton = new Button(_("OK"), "", this); - mButton->setActionEventId("ok"); + mButton = new Button(_("Waiting for server"), "ok", this); mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); mScrollArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); @@ -62,9 +72,16 @@ NpcTextDialog::NpcTextDialog(Network *network): Layout &layout = getLayout(); layout.setRowHeight(0, Layout::AUTO_SET); + center(); loadWindowState(); } +void NpcTextDialog::clearText() +{ + NPC::isTalking = false; + setText(""); +} + void NpcTextDialog::setText(const std::string &text) { mText = text; @@ -74,41 +91,64 @@ void NpcTextDialog::setText(const std::string &text) void NpcTextDialog::addText(const std::string &text) { setText(mText + text + "\n"); + mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); } -void NpcTextDialog::clearText() +void NpcTextDialog::showNextButton() { - NPC::mTalking = false; - setText(""); + mButton->setCaption(_("Next")); + mState = NPC_TEXT_STATE_NEXT; + mButton->setEnabled(true); +} + +void NpcTextDialog::showCloseButton() +{ + mButton->setCaption(_("Close")); + mState = NPC_TEXT_STATE_CLOSE; + mButton->setEnabled(true); } void NpcTextDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "ok") { - clearText(); - setVisible(false); - saveWindowState(); - - if (current_npc) + if (mState == NPC_TEXT_STATE_NEXT && current_npc) { nextDialog(); - - current_npc = 0; + addText("\n> Next\n"); + } else if (mState == NPC_TEXT_STATE_CLOSE || + (mState == NPC_TEXT_STATE_NEXT && !current_npc)) { + setText(""); + if (current_npc) nextDialog(); + setVisible(false); + current_npc = 0; + NPC::isTalking = false; + } else return; } + else return; + + mButton->setEnabled(false); + mButton->setCaption(_("Waiting for server")); + mState = NPC_TEXT_STATE_WAITING; } void NpcTextDialog::nextDialog(int npcID) { +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::talkToNPC(npcID, false); +#else MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_NEXT_REQUEST); outMsg.writeInt32(npcID); +#endif } void NpcTextDialog::closeDialog(int npcID) { +#ifdef EATHENA_SUPPORT MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_CLOSE); outMsg.writeInt32(npcID); +#endif } void NpcTextDialog::widgetResized(const gcn::Event &event) @@ -123,4 +163,3 @@ void NpcTextDialog::requestFocus() loadWindowState(); setVisible(true); } - diff --git a/src/gui/npc_text.h b/src/gui/npc_text.h index f01e3602..4c0c31e3 100644 --- a/src/gui/npc_text.h +++ b/src/gui/npc_text.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +30,9 @@ #include "../npc.h" +#ifdef EATHENA_SUPPORT class Network; +#endif class TextBox; /** @@ -47,7 +48,11 @@ class NpcTextDialog : public Window, public gcn::ActionListener * * @see Window::Window */ +#ifdef TMWSERV_SUPPORT + NpcTextDialog(); +#else NpcTextDialog(Network *network); +#endif /** * Called when receiving actions from the widgets. @@ -74,6 +79,10 @@ class NpcTextDialog : public Window, public gcn::ActionListener */ void addText(const std::string &string); + void showNextButton(); + + void showCloseButton(); + /** * Notifies the server that the client has performed a next action. */ @@ -99,12 +108,21 @@ class NpcTextDialog : public Window, public gcn::ActionListener void widgetResized(const gcn::Event &event); private: +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif gcn::ScrollArea *mScrollArea; TextBox *mTextBox; gcn::Button *mButton; std::string mText; + + enum NPCTextState { + NPC_TEXT_STATE_WAITING, + NPC_TEXT_STATE_NEXT, + NPC_TEXT_STATE_CLOSE + }; + NPCTextState mState; }; extern NpcTextDialog *npcTextDialog; diff --git a/src/gui/npcintegerdialog.cpp b/src/gui/npcintegerdialog.cpp index 27721f0c..a7ae2748 100644 --- a/src/gui/npcintegerdialog.cpp +++ b/src/gui/npcintegerdialog.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +21,7 @@ #include "button.h" #include "inttextfield.h" +#include "npc_text.h" #include "npcintegerdialog.h" #include "widgets/layout.h" @@ -29,23 +29,33 @@ #include "../npc.h" #include "../net/messageout.h" -#include "../net/protocol.h" +#ifdef EATHENA_SUPPORT +#include "../net/ea/protocol.h" +#endif #include "../utils/gettext.h" - -NpcIntegerDialog::NpcIntegerDialog(Network *network): - Window(_("NPC Number Request")), mNetwork(network) +#include "../utils/strprintf.h" + +#ifdef TMWSERV_SUPPORT +NpcIntegerDialog::NpcIntegerDialog() +#else +NpcIntegerDialog::NpcIntegerDialog(Network *network) +#endif + : Window(_("NPC Number Request")) +#ifdef EATHENA_SUPPORT + , mNetwork(network) +#endif { - mValueField = new IntTextField(); - setWindowName("NPCInput"); + setWindowName("NPCInteger"); + mValueField = new IntTextField; setDefaultSize(175, 75, ImageRect::CENTER); mDecButton = new Button("-", "decvalue", this); mIncButton = new Button("+", "incvalue", this); - okButton = new Button(_("OK"), "ok", this); - cancelButton = new Button(_("Cancel"), "cancel", this); - resetButton = new Button(_("Reset"), "reset", this); + gcn::Button *okButton = new Button(_("OK"), "ok", this); + gcn::Button *cancelButton = new Button(_("Cancel"), "cancel", this); + gcn::Button *resetButton = new Button(_("Reset"), "reset", this); mDecButton->adjustSize(); mDecButton->setWidth(mIncButton->getWidth()); @@ -61,12 +71,14 @@ NpcIntegerDialog::NpcIntegerDialog(Network *network): place(0, 0, resetButton); place(2, 0, cancelButton); place(3, 0, okButton); - //reflowLayout(175, 0); + reflowLayout(175, 0); + center(); + setDefaultSize(); loadWindowState(); } -void NpcIntegerDialog::setRange(const int min, const int max) +void NpcIntegerDialog::setRange(int min, int max) { mValueField->setRange(min, max); } @@ -88,11 +100,13 @@ void NpcIntegerDialog::action(const gcn::ActionEvent &event) if (event.getId() == "ok") { finish = true; + npcTextDialog->addText(strprintf("\n> %d\n", mValueField->getValue())); } else if (event.getId() == "cancel") { finish = true; mValueField->reset(); + npcTextDialog->addText(_("\n> Cancel\n")); } else if (event.getId() == "decvalue") { @@ -110,18 +124,24 @@ void NpcIntegerDialog::action(const gcn::ActionEvent &event) if (finish) { setVisible(false); - NPC::mTalking = false; + NPC::isTalking = false; +#ifdef EATHENA_SUPPORT MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_INT_RESPONSE); outMsg.writeInt32(current_npc); outMsg.writeInt32(mValueField->getValue()); +#endif - current_npc = 0; mValueField->reset(); } } +void NpcIntegerDialog::setDefaultValue(int value) +{ + mValueField->setDefaultValue(value); +} + bool NpcIntegerDialog::isInputFocused() { return mValueField->isFocused(); @@ -131,3 +151,13 @@ void NpcIntegerDialog::requestFocus() { mValueField->requestFocus(); } + +void NpcIntegerDialog::setVisible(bool visible) +{ + if (visible) { + npcTextDialog->setVisible(true); + requestFocus(); + } + + Window::setVisible(visible); +} diff --git a/src/gui/npcintegerdialog.h b/src/gui/npcintegerdialog.h index 15bdee48..df74c904 100644 --- a/src/gui/npcintegerdialog.h +++ b/src/gui/npcintegerdialog.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +26,9 @@ #include "window.h" +#ifdef EATHENA_SUPPORT class Network; +#endif class IntTextField; /** @@ -43,7 +44,11 @@ class NpcIntegerDialog : public Window, public gcn::ActionListener * * @see Window::Window */ +#ifdef TMWSERV_SUPPORT + NpcIntegerDialog(); +#else NpcIntegerDialog(Network *network); +#endif /** * Called when receiving actions from the widgets. @@ -66,7 +71,14 @@ class NpcIntegerDialog : public Window, public gcn::ActionListener * @param min The minimum value to allow * @param max The maximum value to allow */ - void setRange(const int min, const int max); + void setRange(int min, int max); + + /** + * Sets the default value. + * + * @param value The new default value + */ + void setDefaultValue(int value); /** * Checks whether NpcStringDialog is Focused or not. @@ -78,14 +90,15 @@ class NpcIntegerDialog : public Window, public gcn::ActionListener */ void requestFocus(); + void setVisible(bool visible); + private: +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif gcn::Button *mDecButton; gcn::Button *mIncButton; IntTextField *mValueField; - gcn::Button *okButton; - gcn::Button *cancelButton; - gcn::Button *resetButton; }; extern NpcIntegerDialog *npcIntegerDialog; diff --git a/src/gui/npclistdialog.cpp b/src/gui/npclistdialog.cpp index 505912ac..968e2514 100644 --- a/src/gui/npclistdialog.cpp +++ b/src/gui/npclistdialog.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +23,7 @@ #include "button.h" #include "listbox.h" +#include "npc_text.h" #include "npclistdialog.h" #include "scrollarea.h" @@ -32,14 +32,26 @@ #include "../npc.h" #include "../net/messageout.h" -#include "../net/protocol.h" +#ifdef TMWSERV_SUPPORT +#include "../net/tmwserv/gameserver/player.h" +#else +#include "../net/ea/protocol.h" +#endif #include "../utils/gettext.h" - -NpcListDialog::NpcListDialog(Network *network): - Window("NPC"), mNetwork(network) +#include "../utils/strprintf.h" + +#ifdef TMWSERV_SUPPORT +NpcListDialog::NpcListDialog() +#else +NpcListDialog::NpcListDialog(Network *network) +#endif + : Window("NPC") +#ifdef EATHENA_SUPPORT + , mNetwork(network) +#endif { - setWindowName(_("NPC")); + setWindowName("NPCList"); setResizable(true); setMinWidth(200); @@ -50,10 +62,10 @@ NpcListDialog::NpcListDialog(Network *network): mItemList = new ListBox(this); mItemList->setWrappingEnabled(true); - scrollArea = new ScrollArea(mItemList); + gcn::ScrollArea *scrollArea = new ScrollArea(mItemList); - okButton = new Button(_("OK"), "ok", this); - cancelButton = new Button(_("Cancel"), "cancel", this); + gcn::Button *okButton = new Button(_("OK"), "ok", this); + gcn::Button *cancelButton = new Button(_("Cancel"), "cancel", this); setContentSize(260, 175); scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); @@ -65,6 +77,7 @@ NpcListDialog::NpcListDialog(Network *network): Layout &layout = getLayout(); layout.setRowHeight(0, Layout::AUTO_SET); + center(); loadWindowState(); } @@ -78,6 +91,11 @@ std::string NpcListDialog::getElementAt(int i) return mItems[i]; } +void NpcListDialog::addItem(const std::string &item) +{ + mItems.push_back(item); +} + void NpcListDialog::parseItems(const std::string &itemString) { std::istringstream iss(itemString); @@ -89,7 +107,7 @@ void NpcListDialog::parseItems(const std::string &itemString) void NpcListDialog::reset() { - NPC::mTalking = false; + NPC::isTalking = false; mItemList->setSelected(-1); mItems.clear(); } @@ -97,18 +115,23 @@ void NpcListDialog::reset() void NpcListDialog::action(const gcn::ActionEvent &event) { int choice = 0; - if (event.getId() == "ok") { // Send the selected index back to the server int selectedIndex = mItemList->getSelected(); if (selectedIndex > -1) + { choice = selectedIndex + 1; + npcTextDialog->addText(strprintf("\n> \"%s\"\n", + mItems[selectedIndex].c_str())); + } } else if (event.getId() == "cancel") { choice = 0xff; // 0xff means cancel + npcTextDialog->addText(_("\n> Cancel\n")); + npcTextDialog->showCloseButton(); } if (choice) @@ -117,13 +140,25 @@ void NpcListDialog::action(const gcn::ActionEvent &event) saveWindowState(); reset(); +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::selectFromNPC(current_npc, choice); +#else MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_LIST_CHOICE); outMsg.writeInt32(current_npc); outMsg.writeInt8(choice); +#endif + } +} - current_npc = 0; +void NpcListDialog::setVisible(bool visible) +{ + if (visible) { + npcTextDialog->setVisible(true); + requestFocus(); } + + Window::setVisible(visible); } void NpcListDialog::requestFocus() diff --git a/src/gui/npclistdialog.h b/src/gui/npclistdialog.h index e3cf375b..6c1e02e3 100644 --- a/src/gui/npclistdialog.h +++ b/src/gui/npclistdialog.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,14 +22,16 @@ #ifndef GUI_NPCLISTDIALOG_H #define GUI_NPCLISTDIALOG_H -#include <vector> +#include "window.h" #include <guichan/actionlistener.hpp> #include <guichan/listmodel.hpp> -#include "window.h" +#include <vector> +#ifdef EATHENA_SUPPORT class Network; +#endif /** * The npc list dialog. @@ -46,7 +47,11 @@ class NpcListDialog : public Window, public gcn::ActionListener, * * @see Window::Window */ +#ifdef TMWSERV_SUPPORT + NpcListDialog(); +#else NpcListDialog(Network *network); +#endif /** * Called when receiving actions from the widgets. @@ -64,6 +69,11 @@ class NpcListDialog : public Window, public gcn::ActionListener, std::string getElementAt(int i); /** + * Adds an item to the option list. + */ + void addItem(const std::string &); + + /** * Fills the options list for an NPC dialog. * * @param itemString A string with the options separated with colons. @@ -75,6 +85,8 @@ class NpcListDialog : public Window, public gcn::ActionListener, */ void reset(); + void setVisible(bool visible); + /** * Requests the listbox to take focus for input and sets window width * to the last known setting. @@ -82,11 +94,10 @@ class NpcListDialog : public Window, public gcn::ActionListener, void requestFocus(); private: +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif gcn::ListBox *mItemList; - gcn::ScrollArea *scrollArea; - gcn::Button *okButton; - gcn::Button *cancelButton; std::vector<std::string> mItems; }; diff --git a/src/gui/npcpostdialog.cpp b/src/gui/npcpostdialog.cpp new file mode 100644 index 00000000..278bc397 --- /dev/null +++ b/src/gui/npcpostdialog.cpp @@ -0,0 +1,101 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "npcpostdialog.h" +#include "textbox.h" +#include "textfield.h" +#include "button.h" +#include "scrollarea.h" +#include "chat.h" + +#include "../net/tmwserv/gameserver/player.h" +#include "../utils/gettext.h" + +#include <guichan/widgets/label.hpp> + +NpcPostDialog::NpcPostDialog(): + Window(_("NPC")) +{ + setContentSize(400, 180); + + // create text field for receiver + gcn::Label *senderText = new gcn::Label("To:"); + senderText->setPosition(5, 5); + mSender = new TextField(); + mSender->setPosition(senderText->getWidth() + 5, 5); + mSender->setWidth(65); + + // create button for sending + Button *sendButton = new Button(_("Send"), "send", this); + sendButton->setPosition(400-sendButton->getWidth(), + 170-sendButton->getHeight()); + Button *cancelButton = new Button(_("Cancel"), "cancel", this); + cancelButton->setPosition(sendButton->getX() - (cancelButton->getWidth() + 2), + sendButton->getY()); + + // create textfield for letter + mText = new TextBox(); + mText->setHeight(400 - (mSender->getHeight() + sendButton->getHeight())); + mText->setEditable(true); + + // create scroll box for letter text + ScrollArea *scrollArea = new ScrollArea(mText); + scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + scrollArea->setDimension(gcn::Rectangle( + 5, mSender->getHeight() + 5, + 380, 140 - (mSender->getHeight() + sendButton->getHeight()))); + + add(senderText); + add(mSender); + add(scrollArea); + add(sendButton); + add(cancelButton); + + setLocationRelativeTo(getParent()); +} + +void NpcPostDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "send") + { + if (mSender->getText().empty() || mText->getText().empty()) + { + localChatTab->chatLog("Failed to send as sender or letter invalid"); + } + else + { + Net::GameServer::Player::sendLetter(mSender->getText(), mText->getText()); + } + setVisible(false); + clear(); + } + else if (event.getId() == "cancel") + { + setVisible(false); + clear(); + } +} + +void NpcPostDialog::clear() +{ + mSender->setText(""); + mText->setText(""); +} diff --git a/src/gui/npcpostdialog.h b/src/gui/npcpostdialog.h new file mode 100644 index 00000000..b970f5cf --- /dev/null +++ b/src/gui/npcpostdialog.h @@ -0,0 +1,57 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GUI_NPCPOSTDIALOG_H +#define GUI_NPCPOSTDIALOG_H + +#include <guichan/actionlistener.hpp> + +#include "window.h" + +class TextBox; +class TextField; + +class NpcPostDialog : public Window, public gcn::ActionListener +{ +public: + /** + * Constructor + */ + NpcPostDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + /** + * Clear the contents of the dialog + */ + void clear(); + +private: + TextBox *mText; + TextField *mSender; +}; + +extern NpcPostDialog *npcPostDialog; + +#endif diff --git a/src/gui/npcstringdialog.cpp b/src/gui/npcstringdialog.cpp index 43d0722f..c84de015 100644 --- a/src/gui/npcstringdialog.cpp +++ b/src/gui/npcstringdialog.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +20,7 @@ */ #include "button.h" +#include "npc_text.h" #include "npcstringdialog.h" #include "textfield.h" @@ -29,25 +29,38 @@ #include "../npc.h" #include "../net/messageout.h" -#include "../net/protocol.h" +#ifdef EATHENA_SUPPORT +#include "../net/ea/protocol.h" +#endif #include "../utils/gettext.h" - -NpcStringDialog::NpcStringDialog(Network *network): - Window(_("NPC Text Request")), mNetwork(network) +#include "../utils/strprintf.h" + +#ifdef TMWSERV_SUPPORT +NpcStringDialog::NpcStringDialog() +#else +NpcStringDialog::NpcStringDialog(Network *network) +#endif + : Window(_("NPC Text Request")) +#ifdef EATHENA_SUPPORT + , mNetwork(network) +#endif { - setWindowName("NPCInput"); + setWindowName("NPCString"); mValueField = new TextField(""); setDefaultSize(175, 75, ImageRect::CENTER); - okButton = new Button(_("OK"), "ok", this); - cancelButton = new Button(_("Cancel"), "cancel", this); + gcn::Button *okButton = new Button(_("OK"), "ok", this); + gcn::Button *cancelButton = new Button(_("Cancel"), "cancel", this); place(0, 0, mValueField, 3); place(1, 1, cancelButton); place(2, 1, okButton); + reflowLayout(175, 0); + center(); + setDefaultSize(); loadWindowState(); } @@ -59,27 +72,36 @@ std::string NpcStringDialog::getValue() void NpcStringDialog::setValue(const std::string &value) { mValueField->setText(value); + mDefault = value; } void NpcStringDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "cancel") - mValueField->setText(""); + { + mValueField->setText(mDefault); + npcTextDialog->addText(_("\n> Cancel\n")); + } + else + { + npcTextDialog->addText(strprintf("\n> \"%s\"\n", + mValueField->getText().c_str())); + } setVisible(false); - NPC::mTalking = false; + NPC::isTalking = false; std::string text = mValueField->getText(); mValueField->setText(""); +#ifdef EATHENA_SUPPORT MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_STR_RESPONSE); outMsg.writeInt16(text.length() + 9); outMsg.writeInt32(current_npc); outMsg.writeString(text, text.length()); outMsg.writeInt8(0); - - current_npc = 0; +#endif } bool NpcStringDialog::isInputFocused() @@ -91,3 +113,13 @@ void NpcStringDialog::requestFocus() { mValueField->requestFocus(); } + +void NpcStringDialog::setVisible(bool visible) +{ + if (visible) { + npcTextDialog->setVisible(true); + requestFocus(); + } + + Window::setVisible(visible); +} diff --git a/src/gui/npcstringdialog.h b/src/gui/npcstringdialog.h index ee620daf..94cd59b2 100644 --- a/src/gui/npcstringdialog.h +++ b/src/gui/npcstringdialog.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,11 +22,13 @@ #ifndef GUI_NPCSTRINGDIALOG_H #define GUI_NPCSTRINGDIALOG_H -#include <guichan/actionlistener.hpp> - #include "window.h" +#include <guichan/actionlistener.hpp> + +#ifdef EATHENA_SUPPORT class Network; +#endif /** * The npc integer input dialog. @@ -42,7 +43,11 @@ class NpcStringDialog : public Window, public gcn::ActionListener * * @see Window::Window */ +#ifdef TMWSERV_SUPPORT + NpcStringDialog(); +#else NpcStringDialog(Network *network); +#endif /** * Called when receiving actions from the widgets. @@ -71,11 +76,14 @@ class NpcStringDialog : public Window, public gcn::ActionListener */ void requestFocus(); + void setVisible(bool visible); + private: +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif gcn::TextField *mValueField; - gcn::Button *okButton; - gcn::Button *cancelButton; + std::string mDefault; }; extern NpcStringDialog *npcStringDialog; diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp index 84fa20ea..24ffa80c 100644 --- a/src/gui/ok_dialog.cpp +++ b/src/gui/ok_dialog.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,12 +33,12 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg, Window *parent): Window(title, true, parent) { - mTextBox = new TextBox(); + mTextBox = new TextBox; mTextBox->setEditable(false); mTextBox->setOpaque(false); mTextArea = new ScrollArea(mTextBox); - okButton = new Button(_("Ok"), "ok", this); + gcn::Button *okButton = new Button(_("Ok"), "ok", this); mTextArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); mTextArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); @@ -69,7 +68,7 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg, add(mTextArea); add(okButton); - setLocationRelativeTo(getParent()); + center(); setVisible(true); okButton->requestFocus(); } diff --git a/src/gui/ok_dialog.h b/src/gui/ok_dialog.h index 6cfe0798..46dd4db0 100644 --- a/src/gui/ok_dialog.h +++ b/src/gui/ok_dialog.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,13 +19,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _OK_DIALOG_H -#define _OK_DIALOG_H - -#include <guichan/actionlistener.hpp> +#ifndef OK_DIALOG_H +#define OK_DIALOG_H #include "window.h" +#include <guichan/actionlistener.hpp> + class ScrollArea; class TextBox; @@ -56,7 +55,6 @@ class OkDialog : public Window, public gcn::ActionListener private: TextBox *mTextBox; ScrollArea *mTextArea; - gcn::Button *okButton; }; #endif diff --git a/src/gui/palette.cpp b/src/gui/palette.cpp index 2efc60be..b176fcff 100644 --- a/src/gui/palette.cpp +++ b/src/gui/palette.cpp @@ -3,7 +3,7 @@ * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> * Copyright (C) 2009 The Mana World Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,8 +76,7 @@ const int Palette::GRADIENT_DELAY = 40; Palette::Palette() : mRainbowTime(tick_time), - mColVector(ColVector(TYPE_COUNT)), - mGradVector() + mColVector(ColVector(TYPE_COUNT)) { std::string indent = " "; addColor(TEXT, 0x000000, STATIC, _("Text")); @@ -346,4 +345,3 @@ void Palette::advanceGradient () mRainbowTime = tick_time; } } - diff --git a/src/gui/palette.h b/src/gui/palette.h index e894ba74..b2994351 100644 --- a/src/gui/palette.h +++ b/src/gui/palette.h @@ -3,7 +3,7 @@ * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> * Copyright (C) 2009 The Mana World Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -124,7 +124,7 @@ class Palette : public gcn::ListModel * * @return the requested color or Palette::BLACK */ - const gcn::Color& getColor(char c, bool &valid); + const gcn::Color &getColor(char c, bool &valid); /** * Gets the color associated with the type. Sets the alpha channel @@ -135,7 +135,7 @@ class Palette : public gcn::ListModel * * @return the requested color */ - inline const gcn::Color& getColor(ColorType type, int alpha = 255) + inline const gcn::Color &getColor(ColorType type, int alpha = 255) { gcn::Color* col = &mColVector[type].color; col->a = alpha; @@ -149,8 +149,10 @@ class Palette : public gcn::ListModel * * @return the requested committed color */ - inline const gcn::Color& getCommittedColor(ColorType type) - { return mColVector[type].committedColor; } + inline const gcn::Color &getCommittedColor(ColorType type) + { + return mColVector[type].committedColor; + } /** * Gets the test color associated with the specified type. @@ -159,8 +161,10 @@ class Palette : public gcn::ListModel * * @return the requested test color */ - inline const gcn::Color& getTestColor(ColorType type) - { return mColVector[type].testColor; } + inline const gcn::Color &getTestColor(ColorType type) + { + return mColVector[type].testColor; + } /** * Sets the test color associated with the specified type. @@ -169,7 +173,9 @@ class Palette : public gcn::ListModel * @param color the color that should be tested */ inline void setTestColor(ColorType type, gcn::Color color) - { mColVector[type].testColor = color; } + { + mColVector[type].testColor = color; + } /** * Gets the GradientType associated with the specified type. @@ -179,7 +185,9 @@ class Palette : public gcn::ListModel * @return the gradient type of the color with the given index */ inline GradientType getGradientType(ColorType type) - { return mColVector[type].grad; } + { + return mColVector[type].grad; + } /** * Get the character used by the specified color. @@ -188,7 +196,10 @@ class Palette : public gcn::ListModel * * @return the color char of the color with the given index */ - inline char getColorChar(ColorType type) { return mColVector[type].ch; } + inline char getColorChar(ColorType type) + { + return mColVector[type].ch; + } /** * Sets the color for the specified type. @@ -236,7 +247,10 @@ class Palette : public gcn::ListModel /** * Commit the colors */ - inline void commit() { commit(false); } + inline void commit() + { + commit(false); + } /** * Rollback the colors @@ -331,7 +345,7 @@ class Palette : public gcn::ListModel * * @return the transformed string */ - static std::string getConfigName(const std::string& typeName); + static std::string getConfigName(const std::string &typeName); }; extern Palette *guiPalette; diff --git a/src/gui/partywindow.cpp b/src/gui/partywindow.cpp new file mode 100644 index 00000000..3f857b5c --- /dev/null +++ b/src/gui/partywindow.cpp @@ -0,0 +1,145 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "partywindow.h" +#include "chat.h" + +#include "widgets/avatar.h" + +#include "../utils/gettext.h" +#include "../net/tmwserv/chatserver/party.h" + +PartyWindow::PartyWindow() : Window(_("Party")) +{ + setWindowName("Party"); + setVisible(false); + setResizable(false); + setCaption(_("Party")); + setCloseButton(true); + setMinWidth(110); + setMinHeight(200); + setDefaultSize(620, 300, 110, 200); + + loadWindowState(); +} + +PartyWindow::~PartyWindow() +{ + mPartyMembers.clear(); +} + +void PartyWindow::draw(gcn::Graphics *graphics) +{ + Window::draw(graphics); +} + +void PartyWindow::addPartyMember(const std::string &memberName) +{ + // check to see if player is already in the party + PartyList::iterator itr = mPartyMembers.begin(), + itr_end = mPartyMembers.end(); + + while (itr != itr_end) + { + if ((*itr).name == memberName) + { + // already in the party, dont add + return; + } + ++itr; + } + + // create new party member + PartyMember player; + player.name = memberName; + mPartyMembers.push_back(player); + + // add avatar of the new member to window + Avatar *avatar = new Avatar(memberName); + add(avatar, 0, (mPartyMembers.size() - 1)*14); + + // show the window + if (mPartyMembers.size() > 0) + { + setVisible(true); + } +} + +void PartyWindow::removePartyMember(const std::string &memberName) +{ + // remove the party member + PartyList::iterator itr = mPartyMembers.begin(), + itr_end = mPartyMembers.end(); + + while (itr != itr_end) + { + if ((*itr).name == memberName) + { + mPartyMembers.erase(itr); + break; + } + ++itr; + } + + // if no-one left, remove the party window + if (mPartyMembers.size() < 1) + { + setVisible(false); + } +} + +void PartyWindow::showPartyInvite(const std::string &inviter) +{ + // check there isnt already an invite showing + if (mPartyInviter != "") + { + localChatTab->chatLog("Received party request, but one already exists", + BY_SERVER); + return; + } + + // log invite + std::string msg = inviter + " has invited you to join their party"; + localChatTab->chatLog(msg, BY_SERVER); + + // show invite + acceptDialog = new ConfirmDialog("Accept Party Invite", msg, this); + acceptDialog->addActionListener(this); + + mPartyInviter = inviter; +} + +void PartyWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + + // check if they accepted the invite + if (eventId == "yes") + { + localChatTab->chatLog("Accepted invite from " + mPartyInviter); + Net::ChatServer::Party::acceptInvite(mPartyInviter); + mPartyInviter = ""; + } + else if (eventId == "no") + { + mPartyInviter = ""; + } +} diff --git a/src/gui/partywindow.h b/src/gui/partywindow.h new file mode 100644 index 00000000..b587cc42 --- /dev/null +++ b/src/gui/partywindow.h @@ -0,0 +1,96 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PARTYWINDOW_H +#define PARTYWINDOW_H + +#include "window.h" +#include "confirm_dialog.h" + +#include <string> +#include <vector> + +#include <guichan/actionevent.hpp> +#include <guichan/actionlistener.hpp> + +/** + * Party Member + * Used for storing players in the party + */ +struct PartyMember +{ + std::string name; + int vitality; +}; + +/** + * Party Window. + * + * \ingroup Interface + */ +class PartyWindow : public Window, gcn::ActionListener +{ + public: + /** + * Constructor. + */ + PartyWindow(); + + /** + * Release all the players created + */ + ~PartyWindow(); + + /** + * Draws the party window + */ + void draw(gcn::Graphics *graphics); + + /** + * Add party member + */ + void addPartyMember(const std::string &memberName); + + /** + * Remove party member + */ + void removePartyMember(const std::string &memberName); + + /** + * Show party invite + */ + void showPartyInvite(const std::string &inviter); + + /** + * Handle events + */ + void action(const gcn::ActionEvent &event); + + private: + typedef std::vector<PartyMember> PartyList; + PartyList mPartyMembers; + std::string mPartyInviter; + ConfirmDialog *acceptDialog; +}; + +extern PartyWindow *partyWindow; + +#endif diff --git a/src/gui/passwordfield.cpp b/src/gui/passwordfield.cpp index 073f5e36..fd8ebe22 100644 --- a/src/gui/passwordfield.cpp +++ b/src/gui/passwordfield.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +21,7 @@ #include "passwordfield.h" -PasswordField::PasswordField(const std::string& text): +PasswordField::PasswordField(const std::string &text): TextField(text) { } diff --git a/src/gui/passwordfield.h b/src/gui/passwordfield.h index adad54fe..3b0b5dab 100644 --- a/src/gui/passwordfield.h +++ b/src/gui/passwordfield.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,8 +22,6 @@ #ifndef PASSWORDFIELD_H #define PASSWORDFIELD_H -#include <string> - #include "textfield.h" /** @@ -38,7 +35,7 @@ class PasswordField : public TextField /** * Constructor, initializes the password field with the given string. */ - PasswordField(const std::string& text = ""); + PasswordField(const std::string &text = ""); /** * Draws the password field. diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp index 2a6cdb20..b7e553dc 100644 --- a/src/gui/playerbox.cpp +++ b/src/gui/playerbox.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -85,10 +84,14 @@ void PlayerBox::draw(gcn::Graphics *graphics) if (mPlayer) { // Draw character - int x, y, bs; - bs = getFrameSize(); - x = getWidth() / 2 - 16 + bs; - y = getHeight() / 2 + bs; + const int bs = getFrameSize(); +#ifdef TMWSERV_SUPPORT + const int x = getWidth() / 2 + bs; + const int y = getHeight() - bs - 8; + mPlayer->draw(static_cast<Graphics*>(graphics), x, y); +#else + const int x = getWidth() / 2 - 16 + bs; + const int y = getHeight() / 2 + bs; for (int i = 0; i < Being::VECTOREND_SPRITE; i++) { if (mPlayer->getSprite(i)) @@ -96,6 +99,7 @@ void PlayerBox::draw(gcn::Graphics *graphics) mPlayer->getSprite(i)->draw(static_cast<Graphics*>(graphics), x, y); } } +#endif } if (config.getValue("guialpha", 0.8) != mAlpha) diff --git a/src/gui/playerbox.h b/src/gui/playerbox.h index ee25520a..7c08defd 100644 --- a/src/gui/playerbox.h +++ b/src/gui/playerbox.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/popup.cpp b/src/gui/popup.cpp index f4c7d4a3..648a9d6a 100644 --- a/src/gui/popup.cpp +++ b/src/gui/popup.cpp @@ -1,9 +1,9 @@ /* - * Aethyra + * The Mana World + * Copyright (C) 2004 The Mana World Development Team * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,7 +32,7 @@ #include "../resources/image.h" -Popup::Popup(const std::string& name, const std::string& skin): +Popup::Popup(const std::string &name, const std::string &skin): mPopupName(name), mDefaultSkinPath(skin), mMinWidth(100), diff --git a/src/gui/popup.h b/src/gui/popup.h index c68c2098..6fbe796c 100644 --- a/src/gui/popup.h +++ b/src/gui/popup.h @@ -1,9 +1,9 @@ /* - * Aethyra + * The Mana World + * Copyright (C) 2004 The Mana World Development Team * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,7 +52,7 @@ class Popup : public gcn::Container * debugging purposes. * @param skin The location where the Popup's skin XML can be found. */ - Popup(const std::string& name = "", + Popup(const std::string &name = "", const std::string &skin = "graphics/gui/gui.xml"); /** @@ -97,39 +97,27 @@ class Popup : public gcn::Container */ void setMinWidth(int width); + int getMinWidth() const { return mMinWidth; } + /** * Sets the minimum height of the popup. */ void setMinHeight(int height); + int getMinHeight() const { return mMinHeight; } + /** * Sets the maximum width of the popup. */ void setMaxWidth(int width); + int getMaxWidth() const { return mMaxWidth; } + /** * Sets the minimum height of the popup. */ void setMaxHeight(int height); - /** - * Gets the minimum width of the popup. - */ - int getMinWidth() const { return mMinWidth; } - - /** - * Gets the minimum height of the popup. - */ - int getMinHeight() const { return mMinHeight; } - - /** - * Gets the maximum width of the popup. - */ - int getMaxWidth() const { return mMaxWidth; } - - /** - * Gets the minimum height of the popup. - */ int getMaxHeight() const { return mMaxHeight; } /** @@ -141,24 +129,16 @@ class Popup : public gcn::Container */ int getPadding() const { return mPadding; } - /** - * Sets the padding of the popup. The padding is the distance between the - * popup border and the content. - * - * @param padding The padding of the popup. - * @see getPadding - */ void setPadding(int padding) { mPadding = padding; } /** * Sets the name of the popup. This is only useful for debug purposes. */ - void setPopupName(const std::string &name) { mPopupName = name; } + void setPopupName(const std::string &name) + { mPopupName = name; } - /** - * Returns the name of the popup. This is only useful for debug purposes. - */ - const std::string& getPopupName() { return mPopupName; } + const std::string &getPopupName() const + { return mPopupName; } /** * Schedule this popup for deletion. It will be deleted at the start @@ -179,7 +159,7 @@ class Popup : public gcn::Container int mMaxHeight; /**< Maximum popup height */ int mPadding; /**< Holds the padding of the popup. */ - Skin* mSkin; /**< Skin in use by this popup */ + Skin *mSkin; /**< Skin in use by this popup */ }; #endif diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index 13adf827..0b019fef 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,30 +19,34 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> +#include "gui/popupmenu.h" + +#include "gui/browserbox.h" +#include "gui/chat.h" +#include "gui/inventorywindow.h" +#include "gui/item_amount.h" -#include "browserbox.h" -#include "chat.h" -#include "inventorywindow.h" -#include "item_amount.h" -#include "popupmenu.h" +#include "being.h" +#include "beingmanager.h" +#include "floor_item.h" +#include "graphics.h" +#include "item.h" +#include "localplayer.h" +#include "npc.h" +#include "player_relations.h" -#include "../being.h" -#include "../beingmanager.h" -#include "../floor_item.h" -#include "../graphics.h" -#include "../item.h" -#include "../localplayer.h" -#include "../npc.h" -#include "../player_relations.h" +#ifdef EATHENA_SUPPORT +#include "net/messageout.h" +#include "net/ea/protocol.h" +#endif -#include "../net/messageout.h" -#include "../net/protocol.h" +#include "resources/itemdb.h" +#include "resources/iteminfo.h" -#include "../resources/itemdb.h" +#include "utils/gettext.h" +#include "utils/strprintf.h" -#include "../utils/gettext.h" -#include "../utils/strprintf.h" +#include <cassert> extern std::string tradePartnerName; @@ -57,7 +60,7 @@ PopupMenu::PopupMenu(): setTitleBarHeight(0); setShowTitle(false); - mBrowserBox = new BrowserBox(); + mBrowserBox = new BrowserBox; mBrowserBox->setPosition(4, 4); mBrowserBox->setHighlightMode(BrowserBox::BACKGROUND); mBrowserBox->setOpaque(false); @@ -85,26 +88,28 @@ void PopupMenu::showPopup(int x, int y, Being *being) mBrowserBox->addRow("##3---"); switch (player_relations.getRelation(name)) { - case PlayerRelation::NEUTRAL: - mBrowserBox->addRow(strprintf(_("@@friend|Befriend %s@@"), name.c_str())); - - case PlayerRelation::FRIEND: - mBrowserBox->addRow(strprintf(_("@@disregard|Disregard %s@@"), name.c_str())); - mBrowserBox->addRow(strprintf(_("@@ignore|Ignore %s@@"), name.c_str())); - break; - - case PlayerRelation::DISREGARDED: - mBrowserBox->addRow(strprintf(_("@@unignore|Un-Ignore %s@@"), name.c_str())); - mBrowserBox->addRow(strprintf(_("@@ignore|Completely ignore %s@@"), name.c_str())); - break; - - case PlayerRelation::IGNORED: - mBrowserBox->addRow(strprintf(_("@@unignore|Un-Ignore %s@@"), name.c_str())); - break; + case PlayerRelation::NEUTRAL: + mBrowserBox->addRow(strprintf(_("@@friend|Befriend %s@@"), name.c_str())); + + case PlayerRelation::FRIEND: + mBrowserBox->addRow(strprintf(_("@@disregard|Disregard %s@@"), name.c_str())); + mBrowserBox->addRow(strprintf(_("@@ignore|Ignore %s@@"), name.c_str())); + break; + + case PlayerRelation::DISREGARDED: + mBrowserBox->addRow(strprintf(_("@@unignore|Un-Ignore %s@@"), name.c_str())); + mBrowserBox->addRow(strprintf(_("@@ignore|Completely ignore %s@@"), name.c_str())); + break; + + case PlayerRelation::IGNORED: + mBrowserBox->addRow(strprintf(_("@@unignore|Un-Ignore %s@@"), name.c_str())); + break; } //mBrowserBox->addRow(_("@@follow|Follow ") + name + "@@"); //mBrowserBox->addRow(_("@@buddy|Add ") + name + " to Buddy List@@"); + mBrowserBox->addRow(strprintf(_("@@guild|Invite %s@@"), name.c_str())); + mBrowserBox->addRow(strprintf(_("@@party|Invite %s to join your party@@"), name.c_str())); mBrowserBox->addRow("##3---"); mBrowserBox->addRow(strprintf(_("@@party-invite|Invite %s to party@@"), name.c_str())); @@ -145,51 +150,78 @@ void PopupMenu::showPopup(int x, int y, FloorItem *floorItem) showPopup(x, y); } -void PopupMenu::handleLink(const std::string& link) +void PopupMenu::handleLink(const std::string &link) { Being *being = beingManager->findBeing(mBeingId); // Talk To action - if (link == "talk" && being && being->getType() == Being::NPC && + if (link == "talk" && + being && + being->getType() == Being::NPC && current_npc == 0) { dynamic_cast<NPC*>(being)->talk(); } // Trade action - else if (link == "trade" && being && being->getType() == Being::PLAYER) + else if (link == "trade" && + being && + being->getType() == Being::PLAYER) { player_node->trade(being); tradePartnerName = being->getName(); } - +#ifdef EATHENA_SUPPORT // Attack action - else if (link == "attack" && being && being->getType() == Being::PLAYER) + else if (link == "attack" && + being && + being->getType() == Being::PLAYER) { player_node->attack(being, true); } - - else if (link == "unignore" && being && being->getType() == Being::PLAYER) +#endif + else if (link == "unignore" && + being && + being->getType() == Being::PLAYER) { player_relations.setRelation(being->getName(), PlayerRelation::NEUTRAL); } - else if (link == "ignore" && being && being->getType() == Being::PLAYER) + else if (link == "ignore" && + being && + being->getType() == Being::PLAYER) { player_relations.setRelation(being->getName(), PlayerRelation::IGNORED); } - else if (link == "disregard" && being && + else if (link == "disregard" && + being && being->getType() == Being::PLAYER) { player_relations.setRelation(being->getName(), PlayerRelation::DISREGARDED); } - else if (link == "friend" && being && being->getType() == Being::PLAYER) + else if (link == "friend" && + being && + being->getType() == Being::PLAYER) { player_relations.setRelation(being->getName(), PlayerRelation::FRIEND); } +#ifdef TMWSERV_SUPPORT + // Guild action + else if (link == "guild" && + being != NULL && + being->getType() == Being::PLAYER) + { + player_node->inviteToGuild(being); + } + // Add player to your party + else if (link == "party") + { + player_node->inviteToParty(being->getName()); + } +#endif /* // Follow Player action else if (link == "follow") @@ -222,6 +254,9 @@ void PopupMenu::handleLink(const std::string& link) assert(mItem); if (mItem->isEquipment()) { +#ifdef TMWSERV_SUPPORT + player_node->equipItem(mItem); +#else if (mItem->isEquipped()) { player_node->unequipItem(mItem); @@ -230,10 +265,15 @@ void PopupMenu::handleLink(const std::string& link) { player_node->equipItem(mItem); } +#endif } else { +#ifdef TMWSERV_SUPPORT + player_node->useItem(mItem->getInvIndex()); +#else player_node->useItem(mItem); +#endif } } @@ -242,17 +282,24 @@ void PopupMenu::handleLink(const std::string& link) chatWindow->addItemText(mItem->getInfo().getName()); } + else if (link == "split") + { + new ItemAmountWindow(AMOUNT_ITEM_SPLIT, inventoryWindow, mItem); + } else if (link == "drop") { new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem); } - else if (link == "party-invite" && being && +#ifdef EATHENA_SUPPORT + else if (link == "party-invite" && + being && being->getType() == Being::PLAYER) { MessageOut outMsg(player_node->getNetwork()); outMsg.writeInt16(CMSG_PARTY_INVITE); outMsg.writeInt32(being->getId()); } +#endif // Unknown actions else @@ -275,15 +322,23 @@ void PopupMenu::showPopup(int x, int y, Item *item) if (item->isEquipment()) { +#ifdef TMWSERV_SUPPORT + mBrowserBox->addRow(_("@@use|Equip@@")); +#else if (item->isEquipped()) mBrowserBox->addRow(_("@@use|Unequip@@")); else mBrowserBox->addRow(_("@@use|Equip@@")); +#endif } else mBrowserBox->addRow(_("@@use|Use@@")); mBrowserBox->addRow(_("@@drop|Drop@@")); +#ifdef TMWSERV_SUPPORT + if (!item->isEquipment()) + mBrowserBox->addRow(_("@@split|Split@@")); +#endif mBrowserBox->addRow(_("@@chat|Add to Chat@@")); mBrowserBox->addRow("##3---"); mBrowserBox->addRow(_("@@cancel|Cancel@@")); diff --git a/src/gui/popupmenu.h b/src/gui/popupmenu.h index 89152751..d9fb4777 100644 --- a/src/gui/popupmenu.h +++ b/src/gui/popupmenu.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -62,7 +61,7 @@ class PopupMenu : public Window, public LinkHandler /** * Handles link action. */ - void handleLink(const std::string& link); + void handleLink(const std::string &link); private: BrowserBox* mBrowserBox; diff --git a/src/gui/progressbar.cpp b/src/gui/progressbar.cpp index 1f21df79..02ddab16 100644 --- a/src/gui/progressbar.cpp +++ b/src/gui/progressbar.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,6 +43,9 @@ ProgressBar::ProgressBar(float progress, mRed(red), mGreen(green), mBlue(blue), mRedToGo(red), mGreenToGo(green), mBlueToGo(blue) { + mProgressToGo = mProgress = 0.0f; + mSmoothProgress = mSmoothColorChange = true; + setProgress(progress); setWidth(width); setHeight(height); @@ -93,13 +95,31 @@ ProgressBar::~ProgressBar() void ProgressBar::logic() { - // Smoothly changing the color for a nicer effect. - if (mRedToGo > mRed) mRed++; - if (mRedToGo < mRed) mRed--; - if (mGreenToGo > mGreen) mGreen++; - if (mGreenToGo < mGreen) mGreen--; - if (mBlueToGo > mBlue) mBlue++; - if (mBlueToGo < mBlue) mBlue--; + if (mSmoothColorChange) + { + // Smoothly changing the color for a nicer effect. + if (mRedToGo > mRed) mRed++; + if (mRedToGo < mRed) mRed--; + if (mGreenToGo > mGreen) mGreen++; + if (mGreenToGo < mGreen) mGreen--; + if (mBlueToGo > mBlue) mBlue++; + if (mBlueToGo < mBlue) mBlue--; + } + else + { + mRed = mRedToGo; + mGreen = mGreenToGo; + mBlue = mBlueToGo; + } + + if (mSmoothProgress) + { + // Smoothly showing the progressbar changes. + if (mProgressToGo > mProgress) mProgress = mProgress + 0.005f; + if (mProgressToGo < mProgress) mProgress = mProgress - 0.005f; + } + else + mProgress = mProgressToGo; } void ProgressBar::draw(gcn::Graphics *graphics) @@ -142,9 +162,9 @@ void ProgressBar::draw(gcn::Graphics *graphics) void ProgressBar::setProgress(float progress) { - if (progress < 0.0f) mProgress = 0.0; - else if (progress > 1.0f) mProgress = 1.0; - else mProgress = progress; + if (progress < 0.0f) mProgressToGo = 0.0; + else if (progress > 1.0f) mProgressToGo = 1.0; + else mProgressToGo = progress; } void ProgressBar::setColor(Uint8 red, Uint8 green, Uint8 blue) diff --git a/src/gui/progressbar.h b/src/gui/progressbar.h index 3c88f3a3..e75b1d44 100644 --- a/src/gui/progressbar.h +++ b/src/gui/progressbar.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -103,16 +102,35 @@ class ProgressBar : public gcn::Widget const std::string &text() const { return mText; } + /** + * Set wether the progress is moved smoothly. + */ + void setSmoothProgress(bool smoothProgress) + { mSmoothProgress = smoothProgress; } + + /** + * Set wether the color changing is made smoothly. + */ + void setSmoothColorChange(bool smoothColorChange) + { mSmoothColorChange = smoothColorChange; } + + private: - float mProgress; + float mProgress, mProgressToGo; + bool mSmoothProgress; + Uint8 mRed, mGreen, mBlue; Uint8 mRedToGo, mGreenToGo, mBlueToGo; + bool mSmoothColorChange; + std::string mText; bool mUpdated; static ImageRect mBorder; static int mInstances; static float mAlpha; + + static const gcn::Color TEXT_COLOR; }; #endif diff --git a/src/gui/quitdialog.cpp b/src/gui/quitdialog.cpp new file mode 100644 index 00000000..83794ffe --- /dev/null +++ b/src/gui/quitdialog.cpp @@ -0,0 +1,135 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "quitdialog.h" +#include <iostream> +#include <string> + +#include <guichan/widgets/label.hpp> + +#include "../main.h" + +#include "button.h" +#include "radiobutton.h" + +#include "../utils/gettext.h" + +QuitDialog::QuitDialog(bool* quitGame, QuitDialog** pointerToMe): + Window(_("Quit"), true, NULL), mQuitGame(quitGame), mMyPointer(pointerToMe) +{ + + mLogoutQuit = new RadioButton(_("Quit"), "quitdialog"); + mForceQuit = new RadioButton(_("Quit"), "quitdialog"); + mSwitchAccountServer = new RadioButton(_("Switch server"), "quitdialog"); + mSwitchCharacter = new RadioButton(_("Switch character"), "quitdialog"); + mOkButton = new Button(_("Ok"), "ok", this); + mCancelButton = new Button(_("Cancel"), "cancel", this); + + setContentSize(200, 91); + + mLogoutQuit->setPosition(5, 5); + mForceQuit->setPosition(5, 5); + mSwitchAccountServer->setPosition(5, 14 + mLogoutQuit->getHeight()); + mSwitchCharacter->setPosition(5, + 23 + mLogoutQuit->getHeight() + mSwitchAccountServer->getHeight()); + mCancelButton->setPosition( + 200 - mCancelButton->getWidth() - 5, + 91 - mCancelButton->getHeight() - 5); + mOkButton->setPosition( + mCancelButton->getX() - mOkButton->getWidth() - 5, + 91 - mOkButton->getHeight() - 5); + + //All states, when we're not logged in to someone. + if (state == STATE_CHOOSE_SERVER || + state == STATE_CONNECT_ACCOUNT || + state == STATE_LOGIN || + state == STATE_LOGIN_ATTEMPT || + state == STATE_UPDATE) + { + mForceQuit->setSelected(true); + add(mForceQuit); + } + else + { + // Only added if we are connected to an accountserver or gameserver + mLogoutQuit->setSelected(true); + add(mLogoutQuit); + add(mSwitchAccountServer); + + // Only added if we are connected to a gameserver + if (state == STATE_GAME) add(mSwitchCharacter); + } + + add(mOkButton); + add(mCancelButton); + + setLocationRelativeTo(getParent()); + setVisible(true); + + mOkButton->requestFocus(); + +} + +QuitDialog::~QuitDialog() +{ + if (mMyPointer) *mMyPointer = NULL; + // Optional widgets, so delete them by hand. + delete mForceQuit; + delete mLogoutQuit; + delete mSwitchAccountServer; + delete mSwitchCharacter; +} + +void +QuitDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "ok") + { + if (mForceQuit->isSelected()) + { + state = STATE_FORCE_QUIT; + } + else if (mLogoutQuit->isSelected()) + { + if ((state == STATE_GAME) && (mQuitGame)) + { + *mQuitGame = true; + } + state = STATE_EXIT; + } + else if (mSwitchAccountServer->isSelected()) + { + if ((state == STATE_GAME) && (mQuitGame)) + { + *mQuitGame = true; + } + state = STATE_SWITCH_ACCOUNTSERVER_ATTEMPT; + } + else if (mSwitchCharacter->isSelected()) + { + if (mQuitGame) *mQuitGame = true; + + state = STATE_SWITCH_CHARACTER; + } + + } + scheduleDelete(); +} diff --git a/src/gui/quitdialog.h b/src/gui/quitdialog.h new file mode 100644 index 00000000..aee671db --- /dev/null +++ b/src/gui/quitdialog.h @@ -0,0 +1,70 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef QUITDIALOG_H +#define QUITDIALOG_H + +#include <iosfwd> +#include <guichan/actionlistener.hpp> + +#include "window.h" +#include "../guichanfwd.h" +#include "../main.h" + +/** + * The quit dialog. + * + * \ingroup Interface + */ +class QuitDialog : public Window, public gcn::ActionListener { + public: + /** + * Constructor + * + * @quitGame; to be used for getting out of the while loop in Game + * @pointerToMe; will be set to NULL when the QuitDialog is destroyed + */ + QuitDialog(bool* quitGame, QuitDialog** pointerToMe); + + /** + * Destructor + */ + ~QuitDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + private: + gcn::RadioButton *mLogoutQuit; + gcn::RadioButton *mForceQuit; + gcn::RadioButton *mSwitchAccountServer; + gcn::RadioButton *mSwitchCharacter; + gcn::Button *mOkButton; + gcn::Button *mCancelButton; + + bool* mQuitGame; + QuitDialog** mMyPointer; + +}; + +#endif diff --git a/src/gui/radiobutton.cpp b/src/gui/radiobutton.cpp index c839238b..b05e37e6 100644 --- a/src/gui/radiobutton.cpp +++ b/src/gui/radiobutton.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,7 +34,7 @@ Image *RadioButton::radioChecked; Image *RadioButton::radioDisabled; Image *RadioButton::radioDisabledChecked; -RadioButton::RadioButton(const std::string& caption, const std::string& group, +RadioButton::RadioButton(const std::string &caption, const std::string &group, bool marked): gcn::RadioButton(caption, group, marked) { diff --git a/src/gui/radiobutton.h b/src/gui/radiobutton.h index cd501126..9aec3add 100644 --- a/src/gui/radiobutton.h +++ b/src/gui/radiobutton.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,7 +35,7 @@ class RadioButton : public gcn::RadioButton /* * Constructor. */ - RadioButton(const std::string& caption,const std::string& group, + RadioButton(const std::string &caption,const std::string &group, bool marked = false); /** diff --git a/src/gui/recorder.cpp b/src/gui/recorder.cpp index 9320e020..4f919bef 100644 --- a/src/gui/recorder.cpp +++ b/src/gui/recorder.cpp @@ -2,7 +2,7 @@ * A chat recorder * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #include "recorder.h" #include "windowcontainer.h" +#include "widgets/chattab.h" #include "widgets/layout.h" #include "../utils/stringutils.h" @@ -34,7 +35,7 @@ Recorder::Recorder(ChatWindow *chat, const std::string &title, const std::string &buttonTxt) : Window(title) { - setWindowName(_("Recorder")); + setWindowName("Recorder"); const int offsetX = 2 * getPadding() + 10; const int offsetY = getTitleBarHeight() + getPadding() + 10; @@ -66,7 +67,7 @@ void Recorder::record(const std::string &msg) } } -void Recorder::changeRecordingStatus(const std::string &msg) +void Recorder::setRecordingFile(const std::string &msg) { std::string msgCopy = msg; trim(msgCopy); @@ -82,16 +83,16 @@ void Recorder::changeRecordingStatus(const std::string &msg) * Message should go after mStream is closed so that it isn't * recorded. */ - mChat->chatLog(_("Finishing recording."), BY_SERVER); + localChatTab->chatLog(_("Finishing recording."), BY_SERVER); } else { - mChat->chatLog(_("Not currently recording."), BY_SERVER); + localChatTab->chatLog(_("Not currently recording."), BY_SERVER); } } else if (mStream.is_open()) { - mChat->chatLog(_("Already recording."), BY_SERVER); + localChatTab->chatLog(_("Already recording."), BY_SERVER); } else { @@ -99,19 +100,20 @@ void Recorder::changeRecordingStatus(const std::string &msg) * Message should go before mStream is opened so that it isn't * recorded. */ - mChat->chatLog(_("Starting to record..."), BY_SERVER); - std::string file = std::string(PHYSFS_getUserDir()) + "/.aethyra/" + msgCopy; + localChatTab->chatLog(_("Starting to record..."), BY_SERVER); + const std::string file = + std::string(PHYSFS_getUserDir()) + "/.tmw/" + msgCopy; mStream.open(file.c_str(), std::ios_base::trunc); if (mStream.is_open()) setVisible(true); else - mChat->chatLog(_("Failed to start recording."), BY_SERVER); + localChatTab->chatLog(_("Failed to start recording."), BY_SERVER); } } void Recorder::action(const gcn::ActionEvent &event) { - changeRecordingStatus(""); + setRecordingFile(""); } diff --git a/src/gui/recorder.h b/src/gui/recorder.h index 4f41ff42..39d00c2c 100644 --- a/src/gui/recorder.h +++ b/src/gui/recorder.h @@ -2,7 +2,7 @@ * A chat recorder * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,26 +41,26 @@ class Recorder : public Window, public gcn::ActionListener virtual ~Recorder(); - /* + /** * Outputs the message to the recorder file * * @param msg the line to write to the recorded file. */ void record(const std::string &msg); - /* - * Outputs the message to the recorder file + /** + * Sets the file being recorded to * * @param msg The file to write out to. If null, then stop recording. */ - void changeRecordingStatus(const std::string &msg); + void setRecordingFile(const std::string &msg); - /* + /** * Whether or not the recorder is in use. */ - bool isRecording() {return (bool) mStream.is_open();} + bool isRecording() { return (bool) mStream.is_open(); } - /* + /** * called when the button is pressed * * @param event is the event that is generated diff --git a/src/gui/register.cpp b/src/gui/register.cpp index 63a0d29c..5fb8b579 100644 --- a/src/gui/register.cpp +++ b/src/gui/register.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,20 +40,6 @@ #include "../utils/strprintf.h" #include "../utils/stringutils.h" -/** - * Listener used while dealing with wrong data. It is used to direct the focus - * to the field which contained wrong data when the Ok button was pressed on - * the error notice. - */ -class WrongDataNoticeListener : public gcn::ActionListener -{ - public: - void setTarget(gcn::TextField *textField); - void action(const gcn::ActionEvent &event); - private: - gcn::TextField *mTarget; -}; - void WrongDataNoticeListener::setTarget(gcn::TextField *textField) { mTarget = textField; @@ -74,15 +59,19 @@ RegisterDialog::RegisterDialog(LoginData *loginData): gcn::Label *userLabel = new Label(_("Name:")); gcn::Label *passwordLabel = new Label(_("Password:")); gcn::Label *confirmLabel = new Label(_("Confirm:")); +#ifdef EATHENA_SUPPORT gcn::Label *serverLabel = new Label(_("Server:")); gcn::Label *portLabel = new Label(_("Port:")); +#endif mUserField = new TextField(loginData->username); mPasswordField = new PasswordField(loginData->password); mConfirmField = new PasswordField; +#ifdef EATHENA_SUPPORT mServerField = new TextField(loginData->hostname); mPortField = new TextField(toString(loginData->port)); mMaleButton = new RadioButton(_("Male"), "sex", true); mFemaleButton = new RadioButton(_("Female"), "sex", false); +#endif mRegisterButton = new Button(_("Register"), "register", this); mCancelButton = new Button(_("Cancel"), "cancel", this); @@ -91,15 +80,19 @@ RegisterDialog::RegisterDialog(LoginData *loginData): place(0, 0, userLabel); place(0, 1, passwordLabel); place(0, 2, confirmLabel); +#ifdef EATHENA_SUPPORT place(1, 3, mMaleButton); place(2, 3, mFemaleButton); place(0, 4, serverLabel); place(0, 5, portLabel); +#endif place(1, 0, mUserField, 3).setPadding(2); place(1, 1, mPasswordField, 3).setPadding(2); place(1, 2, mConfirmField, 3).setPadding(2); +#ifdef EATHENA_SUPPORT place(1, 4, mServerField, 3).setPadding(2); place(1, 5, mPortField, 3).setPadding(2); +#endif place = getPlacer(0, 2); place(1, 0, mRegisterButton); place(2, 0, mCancelButton); @@ -108,8 +101,10 @@ RegisterDialog::RegisterDialog(LoginData *loginData): mUserField->addKeyListener(this); mPasswordField->addKeyListener(this); mConfirmField->addKeyListener(this); +#ifdef EATHENA_SUPPORT mServerField->addKeyListener(this); mPortField->addKeyListener(this); +#endif /* TODO: * This is a quick and dirty way to respond to the ENTER key, regardless of @@ -119,16 +114,20 @@ RegisterDialog::RegisterDialog(LoginData *loginData): mUserField->setActionEventId("register"); mPasswordField->setActionEventId("register"); mConfirmField->setActionEventId("register"); - mServerField->setActionEventId("register"); - mPortField->setActionEventId("register"); mUserField->addActionListener(this); mPasswordField->addActionListener(this); mConfirmField->addActionListener(this); + +#ifdef EATHENA_SUPPORT + mServerField->setActionEventId("register"); + mPortField->setActionEventId("register"); + mServerField->addActionListener(this); mPortField->addActionListener(this); +#endif - setLocationRelativeTo(getParent()); + center(); setVisible(true); mUserField->requestFocus(); mUserField->setCaretPosition(mUserField->getText().length()); @@ -145,7 +144,7 @@ void RegisterDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "cancel") { - state = LOGIN_STATE; + state = STATE_LOGIN; } else if (event.getId() == "register" && canSubmit()) { @@ -194,6 +193,8 @@ void RegisterDialog::action(const gcn::ActionEvent &event) error = 2; } + // TODO: Check if a valid email address was given + if (error > 0) { if (error == 1) @@ -209,23 +210,30 @@ void RegisterDialog::action(const gcn::ActionEvent &event) mWrongDataNoticeListener->setTarget(this->mPasswordField); } - OkDialog *mWrongRegisterNotice = - new OkDialog(_("Error"), errorMsg); - mWrongRegisterNotice->addActionListener(mWrongDataNoticeListener); + OkDialog *dlg = new OkDialog(_("Error"), errorMsg); + dlg->addActionListener(mWrongDataNoticeListener); } else { // No errors detected, register the new user. mRegisterButton->setEnabled(false); - mLoginData->hostname = mServerField->getText(); - mLoginData->port = getUShort(mPortField->getText()); mLoginData->username = mUserField->getText(); mLoginData->password = mPasswordField->getText(); +#ifdef EATHENA_SUPPORT + mLoginData->hostname = mServerField->getText(); + mLoginData->port = getUShort(mPortField->getText()); mLoginData->username += mFemaleButton->isSelected() ? "_F" : "_M"; +#else + mLoginData->email = mEmailField->getText(); +#endif mLoginData->registerLogin = true; - state = ACCOUNT_STATE; +#ifdef TMWSERV_SUPPORT + state = STATE_REGISTER_ATTEMPT; +#else + state = STATE_ACCOUNT; +#endif } } } @@ -240,11 +248,14 @@ bool RegisterDialog::canSubmit() const return !mUserField->getText().empty() && !mPasswordField->getText().empty() && !mConfirmField->getText().empty() && +#ifdef EATHENA_SUPPORT !mServerField->getText().empty() && isUShort(mPortField->getText()) && - state == REGISTER_STATE; +#endif + state == STATE_REGISTER; } +#ifdef EATHENA_SUPPORT bool RegisterDialog::isUShort(const std::string &str) { if (str.empty()) @@ -278,3 +289,4 @@ unsigned short RegisterDialog::getUShort(const std::string &str) } return static_cast<unsigned short>(l); } +#endif diff --git a/src/gui/register.h b/src/gui/register.h index 922320db..c37305e4 100644 --- a/src/gui/register.h +++ b/src/gui/register.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,7 +31,20 @@ class LoginData; class OkDialog; -class WrongDataNoticeListener; + +/** + * Listener used while dealing with wrong data. It is used to direct the focus + * to the field which contained wrong data when the Ok button was pressed on + * the error notice. + */ +class WrongDataNoticeListener : public gcn::ActionListener +{ + public: + void setTarget(gcn::TextField *textField); + void action(const gcn::ActionEvent &event); + private: + gcn::TextField *mTarget; +}; /** * The registration dialog. @@ -73,6 +85,7 @@ class RegisterDialog : public Window, public gcn::ActionListener, */ bool canSubmit() const; +#ifdef EATHENA_SUPPORT /** * Function to decide whether string is an unsigned short or not * @@ -90,17 +103,24 @@ class RegisterDialog : public Window, public gcn::ActionListener, * @return the value str represents */ static unsigned short getUShort(const std::string &str); +#endif gcn::TextField *mUserField; gcn::TextField *mPasswordField; gcn::TextField *mConfirmField; +#ifdef EATHENA_SUPPORT gcn::TextField *mServerField; gcn::TextField *mPortField; +#else + gcn::TextField *mEmailField; +#endif gcn::Button *mRegisterButton; gcn::Button *mCancelButton; +#ifdef EATHENA_SUPPORT gcn::RadioButton *mMaleButton; gcn::RadioButton *mFemaleButton; +#endif WrongDataNoticeListener *mWrongDataNoticeListener; diff --git a/src/gui/scrollarea.cpp b/src/gui/scrollarea.cpp index 156ff054..92bb94b8 100644 --- a/src/gui/scrollarea.cpp +++ b/src/gui/scrollarea.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,18 +35,16 @@ ImageRect ScrollArea::background; ImageRect ScrollArea::vMarker; Image *ScrollArea::buttons[4][2]; -ScrollArea::ScrollArea(bool gc, bool opaque): +ScrollArea::ScrollArea(): gcn::ScrollArea(), - mOpaque(opaque), - mGC(gc) + mOpaque(true) { init(); } -ScrollArea::ScrollArea(gcn::Widget *widget, bool gc, bool opaque): +ScrollArea::ScrollArea(gcn::Widget *widget): gcn::ScrollArea(widget), - mOpaque(opaque), - mGC(gc) + mOpaque(true) { init(); } @@ -55,8 +52,7 @@ ScrollArea::ScrollArea(gcn::Widget *widget, bool gc, bool opaque): ScrollArea::~ScrollArea() { // Garbage collection - if (mGC) - delete getContent(); + delete getContent(); instances--; @@ -224,14 +220,13 @@ void ScrollArea::drawFrame(gcn::Graphics *graphics) const int h = getHeight() + bs * 2; static_cast<Graphics*>(graphics)-> - drawImageRect(0, 0, w, h, background); + drawImageRect(0, 0, w, h, background); } } void ScrollArea::setOpaque(bool opaque) { mOpaque = opaque; - setFrameSize(mOpaque ? 2 : 0); } diff --git a/src/gui/scrollarea.h b/src/gui/scrollarea.h index 080b851c..e9aa5ed2 100644 --- a/src/gui/scrollarea.h +++ b/src/gui/scrollarea.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +30,10 @@ class ImageRect; /** * A scroll area. * + * Contrary to Guichan's scroll area, this scroll area takes ownership over its + * content. However, it won't delete a previously set content widget when + * setContent is called! + * * \ingroup GUI */ class ScrollArea : public gcn::ScrollArea @@ -39,12 +42,12 @@ class ScrollArea : public gcn::ScrollArea /** * Constructor. */ - ScrollArea(bool gc = true, bool opaque = true); + ScrollArea(); /** * Constructor. */ - ScrollArea(gcn::Widget *content, bool gc = true, bool opaque = true); + ScrollArea(gcn::Widget *content); /** * Destructor. @@ -107,7 +110,6 @@ class ScrollArea : public gcn::ScrollArea static Image *buttons[4][2]; bool mOpaque; - bool mGC; }; #endif diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index 591cf97b..e7671110 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,30 +19,44 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "button.h" -#include "label.h" -#include "scrollarea.h" -#include "sell.h" -#include "shop.h" -#include "shoplistbox.h" -#include "slider.h" +#include "gui/sell.h" -#include "widgets/layout.h" +#include "gui/button.h" +#include "gui/label.h" +#include "gui/scrollarea.h" +#include "gui/shop.h" +#include "gui/shoplistbox.h" +#include "gui/slider.h" -#include "../npc.h" +#include "gui/widgets/layout.h" -#include "../net/messageout.h" -#include "../net/protocol.h" +#include "npc.h" +#include "shopitem.h" +#include "units.h" -#include "../utils/gettext.h" -#include "../utils/strprintf.h" +#include "net/messageout.h" +#ifdef TMWSERV_SUPPORT +#include "net/tmwserv/gameserver/player.h" +#else +#include "net/ea/protocol.h" +#endif +#include "resources/iteminfo.h" + +#include "utils/gettext.h" +#include "utils/strprintf.h" + +#ifdef TMWSERV_SUPPORT +SellDialog::SellDialog(): + Window(_("Sell")), +#else SellDialog::SellDialog(Network *network): - Window("Sell"), + Window(_("Sell")), mNetwork(network), +#endif mMaxItems(0), mAmountItems(0) { - setWindowName(_("Sell")); + setWindowName("Sell"); setResizable(true); setCloseButton(true); setMinWidth(260); @@ -61,8 +74,8 @@ SellDialog::SellDialog(Network *network): mQuantityLabel = new Label(strprintf("%d / %d", mAmountItems, mMaxItems)); mQuantityLabel->setAlignment(gcn::Graphics::CENTER); - mMoneyLabel = new Label( - strprintf(_("Price: %d GP / Total: %d GP"), 0, 0)); + mMoneyLabel = new Label(strprintf(_("Price: %s / Total: %s"), + "", "")); mIncreaseButton = new Button("+", "+", this); mDecreaseButton = new Button("-", "-", this); @@ -103,6 +116,7 @@ SellDialog::SellDialog(Network *network): Layout &layout = getLayout(); layout.setRowHeight(0, Layout::AUTO_SET); + center(); loadWindowState(); } @@ -122,6 +136,16 @@ void SellDialog::reset() updateButtonsAndLabels(); } +#ifdef TMWSERV_SUPPORT + +void SellDialog::addItem(int item, int amount, int price) +{ + mShopItems->addItem(item, amount, price); + mShopItemList->adjustSize(); +} + +#else + void SellDialog::addItem(const Item *item, int price) { if (!item) @@ -133,6 +157,8 @@ void SellDialog::addItem(const Item *item, int price) mShopItemList->adjustSize(); } +#endif + void SellDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "quit") @@ -176,10 +202,14 @@ void SellDialog::action(const gcn::ActionEvent &event) else if (event.getId() == "sell" && mAmountItems > 0 && mAmountItems <= mMaxItems) { +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::tradeWithNPC + (mShopItems->at(selectedItem)->getId(), mAmountItems); +#else // Attempt sell MessageOut outMsg(mNetwork); - ShopItem* item = mShopItems->at(selectedItem); + ShopItem *item = mShopItems->at(selectedItem); int sellCount; mPlayerMoney += mAmountItems * mShopItems->at(selectedItem)->getPrice(); @@ -194,6 +224,7 @@ void SellDialog::action(const gcn::ActionEvent &event) mAmountItems -= sellCount; outMsg.writeInt16(sellCount); } +#endif mPlayerMoney += mAmountItems * mShopItems->at(selectedItem)->getPrice(); @@ -275,9 +306,16 @@ void SellDialog::updateButtonsAndLabels() // Update the quantity and money labels mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems)); - mMoneyLabel->setCaption - (strprintf(_("Price: %d GP / Total: %d GP"), - income, mPlayerMoney + income)); + mMoneyLabel->setCaption(strprintf(_("Price: %s / Total: %s"), + Units::formatCurrency(income).c_str(), + Units::formatCurrency(mPlayerMoney + income).c_str())); +} + +void SellDialog::logic() +{ + Window::logic(); + + if (!current_npc) setVisible(false); } void SellDialog::setVisible(bool visible) diff --git a/src/gui/sell.h b/src/gui/sell.h index 930f8bc1..b6388a1f 100644 --- a/src/gui/sell.h +++ b/src/gui/sell.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +30,9 @@ #include "window.h" class Item; +#ifdef EATHENA_SUPPORT class Network; +#endif class ShopItems; class ShopListBox; @@ -48,7 +49,11 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener * * @see Window::Window */ +#ifdef TMWSERV_SUPPORT + SellDialog(); +#else SellDialog(Network *network); +#endif /** * Destructor @@ -63,7 +68,11 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener /** * Adds an item to the inventory. */ +#ifdef TMWSERV_SUPPORT + void addItem(int item, int amount, int price); +#else void addItem(const Item *item, int price); +#endif /** * Called when receiving actions from the widgets. @@ -83,6 +92,11 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener void setMoney(int amount); /** + * Check for current NPC + */ + void logic(); + + /** * Sets the visibility of this window. */ void setVisible(bool visible); @@ -97,7 +111,9 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener */ void updateButtonsAndLabels(); +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif gcn::Button *mSellButton; gcn::Button *mQuitButton; gcn::Button *mAddMaxButton; diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp new file mode 100644 index 00000000..a57be06c --- /dev/null +++ b/src/gui/serverdialog.cpp @@ -0,0 +1,214 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <cstdlib> +#include <iostream> +#include <string> + +#include <guichan/widgets/label.hpp> + +#include "serverdialog.h" + +#include "button.h" +#include "listbox.h" +#include "ok_dialog.h" +#include "scrollarea.h" +#include "textfield.h" + +#include "widgets/layout.h" + +#include "../configuration.h" +#include "../log.h" +#include "../logindata.h" +#include "../main.h" + +#include "../utils/gettext.h" +#include "../utils/stringutils.h" + +const short MAX_SERVERLIST = 5; + +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 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); + + mOkButton = new Button(_("Ok"), "connect", this); + mCancelButton = new Button(_("Cancel"), "cancel", this); + + mServerNameField->setActionEventId("connect"); + mPortField->setActionEventId("connect"); + mMostUsedServersDropDown->setActionEventId("changeSelection"); + + mServerNameField->addActionListener(this); + mPortField->addActionListener(this); + mMostUsedServersDropDown->addActionListener(this); + + place(0, 0, serverLabel); + place(0, 1, portLabel); + place(1, 0, mServerNameField, 3).setPadding(2); + place(1, 1, mPortField, 3).setPadding(2); + place(0, 2, mMostUsedServersDropDown, 4).setPadding(2); + place(2, 3, mOkButton); + place(3, 3, mCancelButton); + reflowLayout(250, 0); + + setLocationRelativeTo(getParent()); + setVisible(true); + + if (mServerNameField->getText().empty()) { + mServerNameField->requestFocus(); + } else { + if (mPortField->getText().empty()) { + mPortField->requestFocus(); + } else { + mOkButton->requestFocus(); + } + } +} + +ServerDialog::~ServerDialog() +{ + delete mMostUsedServersListModel; + delete mMostUsedServersScrollArea; +} + +void +ServerDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "ok") + { + // Give focus back to the server dialog. + mServerNameField->requestFocus(); + } + else if (event.getId() == "changeSelection") + { + // Change the textField Values according to new selection + Server myServer = mMostUsedServersListModel->getServer + (mMostUsedServersListBox->getSelected()); + mServerNameField->setText(myServer.serverName); + mPortField->setText(toString(myServer.port)); + } + else if (event.getId() == "connect") + { + // Check login + if (mServerNameField->getText().empty() || mPortField->getText().empty()) + { + OkDialog *dlg = new OkDialog(_("Error"), + _("Please type both the address and the port of a server.")); + dlg->addActionListener(this); + } + 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 (event.getId() == "cancel") + { + state = STATE_FORCE_QUIT; + } +} diff --git a/src/gui/serverdialog.h b/src/gui/serverdialog.h new file mode 100644 index 00000000..492f5a2b --- /dev/null +++ b/src/gui/serverdialog.h @@ -0,0 +1,123 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SERVERDIALOG_H +#define 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/tmwserv/network.h" + +class LoginData; + +/** + * A server structure to keep pairs of servers and ports. + */ +struct Server { + Server(): + 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; +}; + +/** + * 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 gcn::ActionEvent &event); + + private: + gcn::TextField *mServerNameField; + gcn::TextField *mPortField; + gcn::Button *mOkButton; + gcn::Button *mCancelButton; + + DropDown *mMostUsedServersDropDown; + gcn::ListBox *mMostUsedServersListBox; + gcn::ScrollArea *mMostUsedServersScrollArea; + ServersListModel *mMostUsedServersListModel; + + LoginData *mLoginData; +}; + +#endif diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp index ca6b4010..72dfbce5 100644 --- a/src/gui/setup.cpp +++ b/src/gui/setup.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,7 +50,12 @@ extern Window *helpWindow; extern Window *debugWindow; extern Window *itemShortcutWindow; extern Window *emoteShortcutWindow; +#ifdef TMWSERV_SUPPORT +extern Window *magicDialog; +extern Window *guildWindow; +#else extern Window *storageWindow; +#endif Setup::Setup(): Window(_("Setup")) @@ -108,7 +112,7 @@ Setup::Setup(): add(panel); - setLocationRelativeTo(getParent()); + center(); setInGame(false); } @@ -141,7 +145,9 @@ void Setup::action(const gcn::ActionEvent &event) statusWindow->resetToDefaultSize(); buyDialog->resetToDefaultSize(); sellDialog->resetToDefaultSize(); +#ifdef EATHENA_SUPPORT buySellDialog->resetToDefaultSize(); +#endif inventoryWindow->resetToDefaultSize(); emoteWindow->resetToDefaultSize(); npcTextDialog->resetToDefaultSize(); @@ -154,7 +160,12 @@ void Setup::action(const gcn::ActionEvent &event) debugWindow->resetToDefaultSize(); itemShortcutWindow->resetToDefaultSize(); emoteShortcutWindow->resetToDefaultSize(); +#ifdef TMWSERV_SUPPORT + magicDialog->resetToDefaultSize(); + guildWindow->resetToDefaultSize(); +#else storageWindow->resetToDefaultSize(); +#endif } } diff --git a/src/gui/setup.h b/src/gui/setup.h index 663bdfcb..4c387d34 100644 --- a/src/gui/setup.h +++ b/src/gui/setup.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -63,7 +62,7 @@ class Setup : public Window, public gcn::ActionListener private: std::list<SetupTab*> mTabs; - gcn::Button* mResetWindows; + gcn::Button *mResetWindows; }; extern Setup* setupWindow; diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp index 08eda848..28a80b3d 100644 --- a/src/gui/setup_audio.cpp +++ b/src/gui/setup_audio.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,6 +42,7 @@ Setup_Audio::Setup_Audio(): mMusicSlider(new Slider(0, 128)) { setOpaque(false); + setDimension(gcn::Rectangle(0, 0, 250, 200)); gcn::Label *sfxLabel = new Label(_("Sfx volume")); gcn::Label *musicLabel = new Label(_("Music volume")); diff --git a/src/gui/setup_audio.h b/src/gui/setup_audio.h index aad16617..9e951895 100644 --- a/src/gui/setup_audio.h +++ b/src/gui/setup_audio.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/setup_colors.cpp b/src/gui/setup_colors.cpp index 108067f5..073bbc1a 100644 --- a/src/gui/setup_colors.cpp +++ b/src/gui/setup_colors.cpp @@ -2,7 +2,7 @@ * Configurable text colors * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -57,7 +57,7 @@ Setup_Colors::Setup_Colors() : mScroll = new ScrollArea(mColorBox); mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mTextPreview = new TextPreview(&rawmsg); + mTextPreview = new TextPreview(rawmsg); mPreview = new BrowserBox(BrowserBox::AUTO_WRAP); mPreview->setOpaque(false); @@ -83,7 +83,7 @@ Setup_Colors::Setup_Colors() : mRedLabel = new Label(_("Red: ")); - mRedText = new TextField(); + mRedText = new TextField; mRedText->setWidth(40); mRedText->setRange(0, 255); mRedText->setNumeric(true); @@ -99,7 +99,7 @@ Setup_Colors::Setup_Colors() : mGreenLabel = new Label(_("Green: ")); - mGreenText = new TextField(); + mGreenText = new TextField; mGreenText->setWidth(40); mGreenText->setRange(0, 255); mGreenText->setNumeric(true); @@ -115,7 +115,7 @@ Setup_Colors::Setup_Colors() : mBlueLabel = new Label(_("Blue: ")); - mBlueText = new TextField(); + mBlueText = new TextField; mBlueText->setWidth(40); mBlueText->setRange(0, 255); mBlueText->setNumeric(true); diff --git a/src/gui/setup_colors.h b/src/gui/setup_colors.h index 00f77d57..52d3f727 100644 --- a/src/gui/setup_colors.h +++ b/src/gui/setup_colors.h @@ -2,7 +2,7 @@ * Configurable text colors * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp index 4d80e0dd..59a882c7 100644 --- a/src/gui/setup_joystick.cpp +++ b/src/gui/setup_joystick.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/setup_joystick.h b/src/gui/setup_joystick.h index ae888206..eba8a2cc 100644 --- a/src/gui/setup_joystick.h +++ b/src/gui/setup_joystick.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/setup_keyboard.cpp b/src/gui/setup_keyboard.cpp index 0f79e3c6..aba8cf35 100644 --- a/src/gui/setup_keyboard.cpp +++ b/src/gui/setup_keyboard.cpp @@ -1,9 +1,9 @@ /* - * Aethyra - * Copyright (C) 2007 The Mana World Development Team + * Custom keyboard shortcuts configuration + * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> + * Copyright (C) 2009 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -69,7 +69,7 @@ class KeyListModel : public gcn::ListModel }; Setup_Keyboard::Setup_Keyboard(): - mKeyListModel(new KeyListModel()), + mKeyListModel(new KeyListModel), mKeyList(new ListBox(mKeyListModel)), mKeySetting(false) { diff --git a/src/gui/setup_keyboard.h b/src/gui/setup_keyboard.h index 5fa961ae..dee12135 100644 --- a/src/gui/setup_keyboard.h +++ b/src/gui/setup_keyboard.h @@ -1,9 +1,8 @@ /* - * Aethyra - * Copyright (C) 2007 The Mana World Development Team + * Custom keyboard shortcuts configuration + * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/setup_players.cpp b/src/gui/setup_players.cpp index 05748000..1451e71e 100644 --- a/src/gui/setup_players.cpp +++ b/src/gui/setup_players.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -69,9 +68,9 @@ static const char *RELATION_NAMES[PlayerRelation::RELATIONS_NR] = class PlayerRelationListModel : public gcn::ListModel { public: - virtual ~PlayerRelationListModel(void) { } + virtual ~PlayerRelationListModel() { } - virtual int getNumberOfElements(void) + virtual int getNumberOfElements() { return PlayerRelation::RELATIONS_NR; } @@ -87,30 +86,30 @@ public: class PlayerTableModel : public TableModel { public: - PlayerTableModel(void) : + PlayerTableModel() : mPlayers(NULL) { playerRelationsUpdated(); } - virtual ~PlayerTableModel(void) + virtual ~PlayerTableModel() { freeWidgets(); if (mPlayers) delete mPlayers; } - virtual int getRows(void) + virtual int getRows() { return mPlayers->size(); } - virtual int getColumns(void) + virtual int getColumns() { return COLUMNS_NR; } - virtual int getRowHeight(void) + virtual int getRowHeight() { return ROW_HEIGHT; } @@ -123,7 +122,7 @@ public: return RELATION_CHOICE_COLUMN_WIDTH; } - virtual void playerRelationsUpdated(void) + virtual void playerRelationsUpdated() { signalBeforeUpdate(); @@ -139,10 +138,10 @@ public: std::string name = (*player_names)[r]; gcn::Widget *widget = new Label(name); mWidgets.push_back(widget); - gcn::ListModel *playerRelation = new PlayerRelationListModel(); + gcn::ListModel *playerRelation = new PlayerRelationListModel; gcn::DropDown *choicebox = new DropDown(playerRelation, - new ScrollArea(), + new ScrollArea, new ListBox(playerRelation), false); choicebox->setSelected(player_relations.getRelation(name)); @@ -167,7 +166,7 @@ public: return mWidgets[WIDGET_AT(row, column)]; } - virtual void freeWidgets(void) + virtual void freeWidgets() { if (mPlayers) delete mPlayers; @@ -198,9 +197,9 @@ protected: class IgnoreChoicesListModel : public gcn::ListModel { public: - virtual ~IgnoreChoicesListModel(void) { } + virtual ~IgnoreChoicesListModel() { } - virtual int getNumberOfElements(void) + virtual int getNumberOfElements() { return player_relations.getPlayerIgnoreStrategies()->size(); } @@ -220,7 +219,7 @@ public: Setup_Players::Setup_Players(): mPlayerTableTitleModel(new StaticTableModel(1, COLUMNS_NR)), - mPlayerTableModel(new PlayerTableModel()), + mPlayerTableModel(new PlayerTableModel), mPlayerTable(new GuiTable(mPlayerTableModel)), mPlayerTitleTable(new GuiTable(mPlayerTableTitleModel)), mPlayerScrollArea(new ScrollArea(mPlayerTable)), @@ -240,8 +239,8 @@ Setup_Players::Setup_Players(): RELATION_CHOICE_COLUMN_WIDTH); mPlayerTitleTable->setBackgroundColor(gcn::Color(0xbf, 0xbf, 0xbf)); - gcn::ListModel *ignoreChoices = new IgnoreChoicesListModel(); - mIgnoreActionChoicesBox = new DropDown(ignoreChoices, new ScrollArea(), + gcn::ListModel *ignoreChoices = new IgnoreChoicesListModel; + mIgnoreActionChoicesBox = new DropDown(ignoreChoices, new ScrollArea, new ListBox(ignoreChoices), false); for (int i = 0; i < COLUMNS_NR; i++) @@ -294,7 +293,7 @@ Setup_Players::Setup_Players(): setDimension(gcn::Rectangle(0, 0, 325, 280)); } -Setup_Players::~Setup_Players(void) +Setup_Players::~Setup_Players() { player_relations.removeListener(this); } diff --git a/src/gui/setup_players.h b/src/gui/setup_players.h index 23a994a0..72d81f71 100644 --- a/src/gui/setup_players.h +++ b/src/gui/setup_players.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index e181f744..07f073db 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -109,6 +108,7 @@ Setup_Video::Setup_Video(): mFullScreenEnabled(config.getValue("screen", false)), mOpenGLEnabled(config.getValue("opengl", false)), mCustomCursorEnabled(config.getValue("customcursor", true)), + mVisibleNamesEnabled(config.getValue("visiblenames", 1)), mParticleEffectsEnabled(config.getValue("particleeffects", true)), mNameEnabled(config.getValue("showownname", false)), mPickupChatEnabled(config.getValue("showpickupchat", true)), @@ -121,8 +121,13 @@ Setup_Video::Setup_Video(): mFsCheckBox(new CheckBox(_("Full screen"), mFullScreenEnabled)), mOpenGLCheckBox(new CheckBox(_("OpenGL"), mOpenGLEnabled)), mCustomCursorCheckBox(new CheckBox(_("Custom cursor"), mCustomCursorEnabled)), + mVisibleNamesCheckBox(new CheckBox(_("Visible names"), mVisibleNamesEnabled)), mParticleEffectsCheckBox(new CheckBox(_("Particle effects"), mParticleEffectsEnabled)), mNameCheckBox(new CheckBox(_("Show name"), mNameEnabled)), + mPickupNotifyLabel(new Label(_("Show pickup notification"))), + mPickupChatCheckBox(new CheckBox(_("in chat"), mPickupChatEnabled)), + mPickupParticleCheckBox(new CheckBox(_("as particle"), + mPickupParticleEnabled)), mSpeechSlider(new Slider(0, 3)), mSpeechLabel(new Label("")), mAlphaSlider(new Slider(0.2, 1.0)), @@ -140,11 +145,7 @@ Setup_Video::Setup_Video(): mOverlayDetailField(new Label("")), mParticleDetail(3 - (int) config.getValue("particleEmitterSkip", 1)), mParticleDetailSlider(new Slider(0, 3)), - mParticleDetailField(new Label("")), - mPickupNotifyLabel(new Label(_("Show pickup notification"))), - mPickupChatCheckBox(new CheckBox(_("in chat"), mPickupChatEnabled)), - mPickupParticleCheckBox(new CheckBox(_("as particle"), - mPickupParticleEnabled)) + mParticleDetailField(new Label("")) { setOpaque(false); @@ -176,6 +177,7 @@ Setup_Video::Setup_Video(): mModeList->setActionEventId("videomode"); mCustomCursorCheckBox->setActionEventId("customcursor"); + mVisibleNamesCheckBox->setActionEventId("visiblenames"); mParticleEffectsCheckBox->setActionEventId("particleeffects"); mPickupChatCheckBox->setActionEventId("pickupchat"); mPickupParticleCheckBox->setActionEventId("pickupparticle"); @@ -195,6 +197,7 @@ Setup_Video::Setup_Video(): mModeList->addActionListener(this); mCustomCursorCheckBox->addActionListener(this); + mVisibleNamesCheckBox->addActionListener(this); mParticleEffectsCheckBox->addActionListener(this); mPickupChatCheckBox->addActionListener(this); mPickupParticleCheckBox->addActionListener(this); @@ -275,7 +278,8 @@ Setup_Video::Setup_Video(): place(1, 0, mFsCheckBox, 2); place(3, 0, mOpenGLCheckBox, 1); place(1, 1, mCustomCursorCheckBox, 3); - place(1, 2, mNameCheckBox, 3); + place(1, 2, mVisibleNamesCheckBox, 3); + place(3, 2, mNameCheckBox, 1); place(1, 3, mParticleEffectsCheckBox, 3); place(1, 4, mPickupNotifyLabel, 3); place(1, 5, mPickupChatCheckBox, 1); @@ -320,7 +324,7 @@ void Setup_Video::apply() * See http://libsdl.org/cgi/docwiki.cgi/SDL_SetVideoMode */ -#ifdef WIN32 +#if defined(WIN32) || defined(__APPLE__) // checks for opengl usage if (!(config.getValue("opengl", false) == 1)) { @@ -338,7 +342,7 @@ void Setup_Video::apply() logger->error(error.str()); } } -#ifdef WIN32 +#if defined(WIN32) || defined(__APPLE__) } else { @@ -365,6 +369,7 @@ void Setup_Video::apply() // We sync old and new values at apply time mFullScreenEnabled = config.getValue("screen", false); mCustomCursorEnabled = config.getValue("customcursor", true); + mVisibleNamesEnabled = config.getValue("visiblenames", 1); mParticleEffectsEnabled = config.getValue("particleeffects", true); mNameEnabled = config.getValue("showownname", false); mSpeechMode = (int) config.getValue("speech", 3); @@ -400,6 +405,7 @@ void Setup_Video::cancel() mFsCheckBox->setSelected(mFullScreenEnabled); mOpenGLCheckBox->setSelected(mOpenGLEnabled); mCustomCursorCheckBox->setSelected(mCustomCursorEnabled); + mVisibleNamesCheckBox->setSelected(mVisibleNamesEnabled); mParticleEffectsCheckBox->setSelected(mParticleEffectsEnabled); mSpeechSlider->setValue(mSpeechMode); mNameCheckBox->setSelected(mNameEnabled); @@ -414,6 +420,7 @@ void Setup_Video::cancel() config.setValue("screen", mFullScreenEnabled ? true : false); config.setValue("customcursor", mCustomCursorEnabled ? true : false); + config.setValue("visiblenames", mVisibleNamesEnabled ? 1 : 0); config.setValue("particleeffects", mParticleEffectsEnabled ? true : false); config.setValue("speech", mSpeechMode); config.setValue("showownname", mNameEnabled ? true : false); @@ -450,6 +457,11 @@ void Setup_Video::action(const gcn::ActionEvent &event) config.setValue("customcursor", mCustomCursorCheckBox->isSelected() ? true : false); } + else if (event.getId() == "visiblenames") + { + config.setValue("visiblenames", + mVisibleNamesCheckBox->isSelected() ? 1 : 0); + } else if (event.getId() == "particleeffects") { config.setValue("particleeffects", diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h index b491cf23..62b46646 100644 --- a/src/gui/setup_video.h +++ b/src/gui/setup_video.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,14 +42,13 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, void keyPressed(gcn::KeyEvent &event); private: - void updateSliders(bool originalValues); - int updateSlider(gcn::Slider *slider, gcn::TextField *field, const std::string &configName); bool mFullScreenEnabled; bool mOpenGLEnabled; bool mCustomCursorEnabled; + bool mVisibleNamesEnabled; bool mParticleEffectsEnabled; bool mNameEnabled; bool mPickupChatEnabled; @@ -72,9 +70,14 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, gcn::CheckBox *mFsCheckBox; gcn::CheckBox *mOpenGLCheckBox; gcn::CheckBox *mCustomCursorCheckBox; + gcn::CheckBox *mVisibleNamesCheckBox; gcn::CheckBox *mParticleEffectsCheckBox; gcn::CheckBox *mNameCheckBox; + gcn::Label *mPickupNotifyLabel; + gcn::CheckBox *mPickupChatCheckBox; + gcn::CheckBox *mPickupParticleCheckBox; + gcn::Slider *mSpeechSlider; gcn::Label *mSpeechLabel; gcn::Slider *mAlphaSlider; @@ -97,10 +100,6 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, int mParticleDetail; gcn::Slider *mParticleDetailSlider; gcn::Label *mParticleDetailField; - - gcn::Label *mPickupNotifyLabel; - gcn::CheckBox *mPickupChatCheckBox; - gcn::CheckBox *mPickupParticleCheckBox; }; #endif diff --git a/src/gui/setuptab.h b/src/gui/setuptab.h index 7e1bc36f..3e0c51e2 100644 --- a/src/gui/setuptab.h +++ b/src/gui/setuptab.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp index bd676bc0..4799ea42 100644 --- a/src/gui/shop.cpp +++ b/src/gui/shop.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,9 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "shop.h" +#include "gui/shop.h" -#include "../utils/dtor.h" +#include "shopitem.h" + +#include "utils/dtor.h" ShopItems::ShopItems(bool mergeDuplicates) : mMergeDuplicates(mergeDuplicates) @@ -44,9 +45,15 @@ std::string ShopItems::getElementAt(int i) return mShopItems.at(i)->getDisplayName(); } +void ShopItems::addItem(int id, int amount, int price) +{ + mShopItems.push_back(new ShopItem(-1, id, amount, price)); +} + +#ifdef EATHENA_SUPPORT void ShopItems::addItem(int inventoryIndex, int id, int quantity, int price) { - ShopItem* item = 0; + ShopItem *item = 0; if (mMergeDuplicates) { item = findItem(id); @@ -62,13 +69,9 @@ void ShopItems::addItem(int inventoryIndex, int id, int quantity, int price) mShopItems.push_back(item); } } +#endif -void ShopItems::addItem(int id, int price) -{ - addItem(-1, id, 0, price); -} - -ShopItem* ShopItems::at(int i) const +ShopItem *ShopItems::at(int i) const { return mShopItems.at(i); } @@ -84,7 +87,7 @@ void ShopItems::clear() mShopItems.clear(); } -ShopItem* ShopItems::findItem(int id) +ShopItem *ShopItems::findItem(int id) { ShopItem *item; diff --git a/src/gui/shop.h b/src/gui/shop.h index 118847f9..190ef655 100644 --- a/src/gui/shop.h +++ b/src/gui/shop.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,15 +19,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _SHOP_H -#define _SHOP_H - -#include <string> -#include <vector> +#ifndef SHOP_H +#define SHOP_H #include <guichan/listmodel.hpp> -#include "../shopitem.h" +#include <string> +#include <vector> class ShopItem; @@ -45,18 +42,21 @@ class ShopItems : public gcn::ListModel { public: /** - * Constructor. Creates a new ShopItems instance. + * Constructor. * * @param mergeDuplicates lets the Shop look for duplicate entries and * merges them to one item. */ ShopItems(bool mergeDuplicates = false); + ~ShopItems(); + /** - * Destructor. + * Adds an item to the list. */ - ~ShopItems(); + void addItem(int id, int amount, int price); +#ifdef EATHENA_SUPPORT /** * Adds an item to the list (used by sell dialog). Looks for * duplicate entries, if mergeDuplicates was turned on. @@ -67,20 +67,10 @@ class ShopItems : public gcn::ListModel * @param price price of the item */ void addItem(int inventoryIndex, int id, int amount, int price); - - /** - * Adds an item to the list (used by buy dialog). Looks for - * duplicate entries, if mergeDuplicates was turned on. - * - * @param id the id of the item - * @param price price of the item - */ - void addItem(int id, int price); +#endif /** * Returns the number of items in the shop. - * - * @return the number of items in the shop */ int getNumberOfElements(); @@ -94,7 +84,7 @@ class ShopItems : public gcn::ListModel /** * Returns the item number i in the shop. */ - ShopItem* at(int i) const; + ShopItem *at(int i) const; /** * Removes an element from the shop. @@ -104,7 +94,7 @@ class ShopItems : public gcn::ListModel void erase(int i); /** - * Clear the vector. + * Clears the list of items in the shop. */ void clear(); @@ -115,13 +105,13 @@ class ShopItems : public gcn::ListModel * * @return the item found or 0 */ - ShopItem* findItem(int id); + ShopItem *findItem(int id); - /** the shop storage */ + /** The list of items in the shop. */ std::vector<ShopItem*> mShopItems; - /** Look for duplicate entries on addition */ + /** Look for duplicate entries on addition. */ bool mMergeDuplicates; }; -#endif +#endif // SHOP_H diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp index 5c55069f..db39e82d 100644 --- a/src/gui/shoplistbox.cpp +++ b/src/gui/shoplistbox.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,15 +19,16 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <guichan/font.hpp> -#include <guichan/listmodel.hpp> +#include "gui/palette.h" +#include "gui/shop.h" +#include "gui/shoplistbox.h" -#include "palette.h" -#include "shop.h" -#include "shoplistbox.h" +#include "configuration.h" +#include "graphics.h" +#include "shopitem.h" -#include "../configuration.h" -#include "../graphics.h" +#include <guichan/font.hpp> +#include <guichan/listmodel.hpp> const int ITEM_ICON_SIZE = 32; diff --git a/src/gui/shoplistbox.h b/src/gui/shoplistbox.h index bed9902b..0b28b2f1 100644 --- a/src/gui/shoplistbox.h +++ b/src/gui/shoplistbox.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -89,4 +88,4 @@ class ShopListBox : public ListBox bool mPriceCheck; }; -#endif +#endif // SHOPLISTBOX_H diff --git a/src/gui/shortcutcontainer.cpp b/src/gui/shortcutcontainer.cpp index fcb33279..901095e5 100644 --- a/src/gui/shortcutcontainer.cpp +++ b/src/gui/shortcutcontainer.cpp @@ -1,9 +1,8 @@ /* - * Aethyra - * Copyright 2007 The Mana World Development Team + * The Mana World + * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/shortcutcontainer.h b/src/gui/shortcutcontainer.h index 3f2e1c60..7b09fb96 100644 --- a/src/gui/shortcutcontainer.h +++ b/src/gui/shortcutcontainer.h @@ -1,9 +1,8 @@ /* - * Aethyra - * Copyright 2007 The Mana World Development Team + * The Mana World + * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef SHORTCUTCONTAINER_H__ -#define SHORTCUTCONTAINER_H__ +#ifndef SHORTCUTCONTAINER_H +#define SHORTCUTCONTAINER_H #include <guichan/mouselistener.hpp> #include <guichan/widget.hpp> diff --git a/src/gui/shortcutwindow.cpp b/src/gui/shortcutwindow.cpp index 8342465a..dcc7f72e 100644 --- a/src/gui/shortcutwindow.cpp +++ b/src/gui/shortcutwindow.cpp @@ -1,9 +1,8 @@ /* - * Aethyra - * Copyright 2007 The Mana World Development Team + * The Mana World + * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/shortcutwindow.h b/src/gui/shortcutwindow.h index d79fffd2..eae881ba 100644 --- a/src/gui/shortcutwindow.h +++ b/src/gui/shortcutwindow.h @@ -1,9 +1,8 @@ /* - * Aethyra - * Copyright 2007 The Mana World Development Team + * The Mana World + * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp index 9fbae7a6..39ccbb06 100644 --- a/src/gui/skill.cpp +++ b/src/gui/skill.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,11 +45,14 @@ struct SkillInfo bool modifiable; }; -static const SkillInfo fakeSkillInfo = { _("???"), false }; +static const SkillInfo fakeSkillInfo = { + _("Mystery Skill"), + false +}; std::vector<SkillInfo> skill_db; -static void initSkillinfo(void); +static void initSkillinfo(); class SkillGuiTableModel : public StaticTableModel { @@ -76,12 +78,12 @@ public: return 35; } - virtual int getRowHeight(void) + virtual int getRowHeight() { return 12; } - virtual void update(void) + virtual void update() { mEntriesNr = mDialog->getSkills().size(); resize(); @@ -113,7 +115,6 @@ public: } } - private: SkillDialog *mDialog; int mEntriesNr; @@ -132,7 +133,7 @@ SkillDialog::SkillDialog(): mTable->setActionEventId("skill"); mTable->addActionListener(this); - setWindowName(_("Skills")); + setWindowName("Skills"); setCloseButton(true); setDefaultSize(255, 260, ImageRect::CENTER); @@ -155,7 +156,7 @@ SkillDialog::SkillDialog(): Layout &layout = getLayout(); layout.setRowHeight(0, Layout::AUTO_SET); - setLocationRelativeTo(getParent()); + center(); loadWindowState(); } @@ -234,7 +235,7 @@ bool SkillDialog::hasSkill(int id) void SkillDialog::addSkill(int id, int lvl, int mp) { - SKILL *tmp = new SKILL(); + SKILL *tmp = new SKILL; tmp->id = id; tmp->lv = lvl; tmp->sp = mp; @@ -255,11 +256,11 @@ void SkillDialog::setSkill(int id, int lvl, int mp) void SkillDialog::cleanList() { - for_each(mSkillList.begin(), mSkillList.end(), make_dtor(mSkillList)); + delete_all(mSkillList); mSkillList.clear(); } -static void initSkillinfo(void) +static void initSkillinfo() { SkillInfo emptySkillInfo = { "", false }; diff --git a/src/gui/skill.h b/src/gui/skill.h index bcdd515c..0600d106 100644 --- a/src/gui/skill.h +++ b/src/gui/skill.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -66,7 +65,7 @@ class SkillDialog : public Window, public gcn::ActionListener void setSkill(int id, int lv, int sp); void cleanList(); - const std::vector<SKILL*>& getSkills(void) const { return mSkillList; } + const std::vector<SKILL*>& getSkills() const { return mSkillList; } private: GuiTable *mTable; diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp new file mode 100644 index 00000000..e30299d4 --- /dev/null +++ b/src/gui/skilldialog.cpp @@ -0,0 +1,318 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/widgets/label.hpp> +#include <guichan/widgets/container.hpp> +#include <guichan/widgets/icon.hpp> + +#include "skilldialog.h" + +#include "icon.h" +#include "button.h" +#include "listbox.h" +#include "scrollarea.h" +#include "windowcontainer.h" +#include "progressbar.h" + +#include "widgets/tabbedarea.h" + +#include "../localplayer.h" + +#include "../utils/dtor.h" +#include "../utils/gettext.h" +#include "../utils/stringutils.h" + +class Skill_Tab : public GCContainer, public gcn::ActionListener +{ + public: + /** + * The type of this skill tab + */ + const std::string type; + + /** + * Constructor + */ + Skill_Tab(const std::string &type); + + /** + * Update this tab + */ + void update(); + + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event) {} + + private: + /** + * Update the information of a skill at + * the given index + */ + void updateSkill(int index); + + /** + * Gets the number of skills in this particular + * type of tab. + */ + int getSkillNum(); + + /** + * Get the first enumeration of this skill tab's + * skill type. + */ + int getSkillBegin(); + + /** + * Get the icon associated with the given index + */ + Icon* getIcon(int index); + + std::vector<Icon *> mSkillIcons; + std::vector<gcn::Label *> mSkillNameLabels; + std::vector<gcn::Label *> mSkillLevelLabels; + std::vector<gcn::Label *> mSkillExpLabels; + std::vector<ProgressBar *> mSkillProgress; +}; + + +SkillDialog::SkillDialog(): + Window(_("Skills")) +{ + setWindowName("Skills"); + setCloseButton(true); + setDefaultSize(windowContainer->getWidth() - 280, 30, 275, 425); + + TabbedArea *panel = new TabbedArea(); + panel->setDimension(gcn::Rectangle(5, 5, 270, 420)); + + Skill_Tab *tab; + + // Add each type of skill tab to the panel + tab = new Skill_Tab("Weapon"); + panel->addTab(_("Weapons"), tab); + mTabs.push_back(tab); + + tab = new Skill_Tab("Magic"); + panel->addTab(_("Magic"), tab); + mTabs.push_back(tab); + + tab = new Skill_Tab("Craft"); + panel->addTab(_("Crafts"), tab); + mTabs.push_back(tab); + + add(panel); + + update(); + + setLocationRelativeTo(getParent()); + loadWindowState(); +} + +SkillDialog::~SkillDialog() +{ + delete_all(mTabs); +} + +void SkillDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "skill") + { + } + else if (event.getId() == "close") + { + setVisible(false); + } +} + +void SkillDialog::draw(gcn::Graphics *g) +{ + update(); + + Window::draw(g); +} + +void SkillDialog::update() +{ + for(std::list<Skill_Tab*>::const_iterator i = mTabs.begin(); + i != mTabs.end(); ++i) + { + (*i)->update(); + } +} + +Skill_Tab::Skill_Tab(const std::string &type): type(type) +{ + setOpaque(false); + setDimension(gcn::Rectangle(0, 0, 270, 420)); + int skillNum = getSkillNum(); + + mSkillIcons.resize(skillNum); + mSkillNameLabels.resize(skillNum); + mSkillLevelLabels.resize(skillNum); + mSkillExpLabels.resize(skillNum); + mSkillProgress.resize(skillNum); + + // Set the initial positions of the skill information + for (int a=0; a < skillNum; a++) + { + mSkillIcons.at(a) = getIcon(a); + mSkillIcons.at(a)->setPosition(1, a*32); + add(mSkillIcons.at(a)); + + mSkillNameLabels.at(a) = new gcn::Label(""); + mSkillNameLabels.at(a)->setPosition(35, a*32 ); + add(mSkillNameLabels.at(a)); + + mSkillProgress.at(a) = new ProgressBar(0.0f, 200, 20, 150, 150, 150); + mSkillProgress.at(a)->setPosition(35, a*32 + 13); + add(mSkillProgress.at(a)); + + mSkillExpLabels.at(a) = new gcn::Label(""); + mSkillExpLabels.at(a)->setPosition(45, a*32 + 16); + add(mSkillExpLabels.at(a)); + + mSkillLevelLabels.at(a) = new gcn::Label(""); + mSkillLevelLabels.at(a)->setPosition(165, a*32); + add(mSkillLevelLabels.at(a)); + } + + update(); + +} + +int Skill_Tab::getSkillNum() +{ + int skillNum = 0; + + if (type == "Weapon") + { + skillNum = CHAR_SKILL_WEAPON_NB; + return skillNum; + } + else if (type == "Magic") + { + skillNum = CHAR_SKILL_MAGIC_NB; + return skillNum; + } + else if (type == "Craft") + { + skillNum = CHAR_SKILL_CRAFT_NB; + return skillNum; + } + else return skillNum; +} + +int Skill_Tab::getSkillBegin() +{ + int skillBegin = 0; + + if (type == "Weapon") + { + skillBegin = CHAR_SKILL_WEAPON_BEGIN - CHAR_SKILL_BEGIN; + return skillBegin; + } + else if (type == "Magic") + { + skillBegin = CHAR_SKILL_MAGIC_BEGIN - CHAR_SKILL_BEGIN; + return skillBegin; + } + else if (type == "Craft") + { + skillBegin = CHAR_SKILL_CRAFT_BEGIN - CHAR_SKILL_BEGIN; + return skillBegin; + } + else return skillBegin; +} + +Icon* Skill_Tab::getIcon(int index) +{ + int skillBegin = getSkillBegin(); + std::string icon = LocalPlayer::getSkillInfo(index + skillBegin).icon; + return new Icon(icon); +} + +void Skill_Tab::updateSkill(int index) +{ + int skillBegin = getSkillBegin(); + + int baseLevel = player_node->getAttributeBase(index + + skillBegin + + CHAR_SKILL_BEGIN); + + int effLevel = player_node->getAttributeEffective(index + + skillBegin + + CHAR_SKILL_BEGIN); + if(baseLevel <= 0) + { + mSkillProgress.at(index)->setVisible(false); + mSkillExpLabels.at(index)->setVisible(false); + mSkillLevelLabels.at(index)->setVisible(false); + mSkillNameLabels.at(index)->setVisible(false); + mSkillIcons.at(index)->setVisible(false); + } + else + { + mSkillProgress.at(index)->setVisible(true); + mSkillExpLabels.at(index)->setVisible(true); + mSkillLevelLabels.at(index)->setVisible(true); + mSkillNameLabels.at(index)->setVisible(true); + mSkillIcons.at(index)->setVisible(true); + std::string skillLevel("Lvl: " + toString(baseLevel)); + if (effLevel < baseLevel) + { + skillLevel.append(" - " + toString(baseLevel - effLevel)); + } + else if (effLevel > baseLevel) + { + skillLevel.append(" + " + toString(effLevel - baseLevel)); + } + mSkillLevelLabels.at(index)->setCaption(skillLevel); + + std::pair<int, int> exp = player_node->getExperience(index + skillBegin); + std::string sExp (toString(exp.first) + " / " + toString(exp.second)); + + + mSkillNameLabels.at(index)->setCaption(LocalPlayer::getSkillInfo(index + skillBegin).name); + mSkillNameLabels.at(index)->adjustSize(); + mSkillLevelLabels.at(index)->adjustSize(); + mSkillExpLabels.at(index)->setCaption(sExp); + mSkillExpLabels.at(index)->adjustSize(); + mSkillExpLabels.at(index)->setAlignment(gcn::Graphics::RIGHT); + + // More intense red as exp grows + int color = 150 - (int)(150 * ((float) exp.first / exp.second)); + mSkillProgress.at(index)->setColor(244, color, color); + mSkillProgress.at(index)->setProgress((float) exp.first / exp.second); + } +} + +void Skill_Tab::update() +{ + int skillNum = getSkillNum(); + + // Update the skill information for reach skill + for (int a = 0; a < skillNum; a++) + { + updateSkill(a); + } +} diff --git a/src/gui/skilldialog.h b/src/gui/skilldialog.h new file mode 100644 index 00000000..b79be800 --- /dev/null +++ b/src/gui/skilldialog.h @@ -0,0 +1,79 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SKILL_H +#define SKILL_H + +#include <vector> +#include <list> + +#include <guichan/listmodel.hpp> +#include <guichan/actionlistener.hpp> + +#include "window.h" +#include "gccontainer.h" + +#include "../guichanfwd.h" + +class ProgressBar; +class Icon; +class Skill_Tab; + +/** + * The skill dialog. + * + * \ingroup Interface + */ +class SkillDialog : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + */ + SkillDialog(); + + /** + * Destructor. + */ + ~SkillDialog(); + + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event); + + /** + * Update the tabs in this dialog + */ + void update(); + + /** + * Draw this window. + */ + void draw(gcn::Graphics *g); + + private: + std::list<Skill_Tab*> mTabs; +}; + +extern SkillDialog *skillDialog; + +#endif diff --git a/src/gui/skin.cpp b/src/gui/skin.cpp index 10b9885a..0d62fea5 100644 --- a/src/gui/skin.cpp +++ b/src/gui/skin.cpp @@ -34,7 +34,7 @@ #include "../utils/strprintf.h" #include "../utils/xml.h" -SkinLoader* skinLoader = NULL; +SkinLoader *skinLoader = NULL; ConfigListener *SkinLoader::skinConfigListener = NULL; class SkinConfigListener : public ConfigListener @@ -46,7 +46,7 @@ class SkinConfigListener : public ConfigListener } }; -Skin::Skin(ImageRect skin, Image* close, std::string filePath, std::string name): +Skin::Skin(ImageRect skin, Image *close, std::string filePath, std::string name): instances(0), mFilePath(filePath), mName(name), @@ -88,7 +88,7 @@ int Skin::getMinHeight() const border.grid[6]->getHeight(); } -Skin* SkinLoader::load(const std::string &filename, +Skin *SkinLoader::load(const std::string &filename, const std::string &defaultPath) { std::string filePath = filename; @@ -214,9 +214,9 @@ Skin* SkinLoader::load(const std::string &filename, delete doc; // Hard-coded for now until we update the above code to look for window buttons. - Image* closeImage = resman->getImage("graphics/gui/close_button.png"); + Image *closeImage = resman->getImage("graphics/gui/close_button.png"); - Skin* skin = new Skin(border, closeImage, filename); + Skin *skin = new Skin(border, closeImage, filename); mSkins[filename] = skin; diff --git a/src/gui/slider.cpp b/src/gui/slider.cpp index a2df59a4..cc381c32 100644 --- a/src/gui/slider.cpp +++ b/src/gui/slider.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/slider.h b/src/gui/slider.h index 35d875db..56ea334a 100644 --- a/src/gui/slider.h +++ b/src/gui/slider.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp index cd483c30..4fb3409c 100644 --- a/src/gui/speechbubble.cpp +++ b/src/gui/speechbubble.cpp @@ -1,9 +1,9 @@ /* - * Aethyra - * Copyright (C) 2008, The Legend of Mazzeroth Development Team + * Speech bubbles + * Copyright (C) 2008 The Legend of Mazzeroth Development Team + * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Legend of Mazzeroth. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,18 +34,17 @@ #include "../utils/gettext.h" SpeechBubble::SpeechBubble(): - Popup("Speech", "graphics/gui/speechbubble.xml"), - mText("") + Popup("Speech", "graphics/gui/speechbubble.xml") { setContentSize(140, 46); setMinWidth(29); setMinHeight(29); - mCaption = new gcn::Label(""); + mCaption = new gcn::Label; mCaption->setFont(boldFont); mCaption->setPosition(5, 3); - mSpeechBox = new TextBox(); + mSpeechBox = new TextBox; mSpeechBox->setEditable(false); mSpeechBox->setOpaque(false); mSpeechBox->setTextColor(&guiPalette->getColor(Palette::CHAT)); diff --git a/src/gui/speechbubble.h b/src/gui/speechbubble.h index 9eb400fb..3eead884 100644 --- a/src/gui/speechbubble.h +++ b/src/gui/speechbubble.h @@ -1,9 +1,9 @@ /* - * Aethyra - * Copyright (C) 2008, The Legend of Mazzeroth Development Team + * Speech bubbles + * Copyright (C) 2008 The Legend of Mazzeroth Development Team + * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Legend of Mazzeroth. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/status.cpp b/src/gui/status.cpp index 8dd32039..2f95f1c8 100644 --- a/src/gui/status.cpp +++ b/src/gui/status.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +28,7 @@ #include "widgets/layout.h" #include "../localplayer.h" +#include "../units.h" #include "../utils/gettext.h" #include "../utils/strprintf.h" @@ -36,9 +36,10 @@ StatusWindow::StatusWindow(LocalPlayer *player): Window(player->getName()), - mPlayer(player) + mPlayer(player), + mCurrency(0) { - setWindowName(_("Status")); + setWindowName("Status"); setCloseButton(true); setDefaultSize(400, 345, ImageRect::CENTER); @@ -48,7 +49,8 @@ StatusWindow::StatusWindow(LocalPlayer *player): mLvlLabel = new Label(strprintf(_("Level: %d"), 0)); mJobLvlLabel = new Label(strprintf(_("Job: %d"), 0)); - mGpLabel = new Label(strprintf(_("Money: %d GP"), 0)); + mGpLabel = new Label(strprintf(_("Money: %s"), + Units::formatCurrency(mCurrency).c_str())); mHpLabel = new Label(_("HP:")); mHpBar = new ProgressBar(1.0f, 80, 15, 0, 171, 34); @@ -77,8 +79,11 @@ StatusWindow::StatusWindow(LocalPlayer *player): mStatsDefenseLabel= new Label(_("Defense:")); mStatsMagicAttackLabel = new Label(_("M.Attack:")); mStatsMagicDefenseLabel = new Label(_("M.Defense:")); + // Gettext flag for next line: xgettext:no-c-format mStatsAccuracyLabel = new Label(_("% Accuracy:")); + // Gettext flag for next line: xgettext:no-c-format mStatsEvadeLabel = new Label(_("% Evade:")); + // Gettext flag for next line: xgettext:no-c-format mStatsReflexLabel = new Label(_("% Reflex:")); mStatsAttackPoints = new Label; @@ -161,42 +166,26 @@ void StatusWindow::update() { // Status Part // ----------- - mLvlLabel->setCaption(strprintf(_("Level: %d"), mPlayer->mLevel)); + mLvlLabel->setCaption(strprintf(_("Level: %d"), mPlayer->getLevel())); mLvlLabel->adjustSize(); mJobLvlLabel->setCaption(strprintf(_("Job: %d"), mPlayer->mJobLevel)); mJobLvlLabel->adjustSize(); - mGpLabel->setCaption(strprintf(_("Money: %d GP"), mPlayer->mGp)); - mGpLabel->adjustSize(); - - mHpBar->setText(toString(mPlayer->mHp) + - "/" + toString(mPlayer->mMaxHp)); - - mMpBar->setText(toString(mPlayer->mMp) + - "/" + toString(mPlayer->mMaxMp)); + if (mCurrency != mPlayer->getMoney()) { + mCurrency = mPlayer->getMoney(); + mGpLabel->setCaption(strprintf(_("Money: %s"), + Units::formatCurrency(mCurrency).c_str())); + mGpLabel->adjustSize(); + } - mXpBar->setText(toString(mPlayer->getXp()) + - "/" + toString(mPlayer->mXpForNextLevel)); + updateHPBar(mHpBar, true); - mJobBar->setText(toString(mPlayer->mJobXp) + - "/" + toString(mPlayer->mJobXpForNextLevel)); + updateMPBar(mMpBar, true); - // HP Bar coloration - if (mPlayer->mHp < int(mPlayer->mMaxHp / 3)) - mHpBar->setColor(223, 32, 32); // Red - else if (mPlayer->mHp < int((mPlayer->mMaxHp / 3) * 2)) - mHpBar->setColor(230, 171, 34); // Orange - else - mHpBar->setColor(0, 171, 34); // Green + updateXPBar(mXpBar, false); - mHpBar->setProgress((float) mPlayer->mHp / (float) mPlayer->mMaxHp); - mMpBar->setProgress((float) mPlayer->mMp / (float) mPlayer->mMaxMp); - - mXpBar->setProgress( - (float) mPlayer->getXp() / (float) mPlayer->mXpForNextLevel); - mJobBar->setProgress( - (float) mPlayer->mJobXp / (float) mPlayer->mJobXpForNextLevel); + updateJobBar(mJobBar, false); // Stats Part // ---------- @@ -291,3 +280,84 @@ void StatusWindow::action(const gcn::ActionEvent &event) player_node->raiseAttribute(LocalPlayer::LUK); } } + +void StatusWindow::updateHPBar(ProgressBar *bar, bool showMax) +{ + if (showMax) + bar->setText(toString(player_node->getHp()) + + "/" + toString(player_node->getMaxHp())); + else + bar->setText(toString(player_node->getHp())); + + // HP Bar coloration + if (player_node->getHp() < player_node->getMaxHp() / 3) + { + bar->setColor(223, 32, 32); // Red + } + else if (player_node->getHp() < (player_node->getMaxHp() / 3) * 2) + { + bar->setColor(230, 171, 34); // Orange + } + else + { + bar->setColor(0, 171, 34); // Green + } + + bar->setProgress((float) player_node->getHp() / (float) player_node->getMaxHp()); +} + +void StatusWindow::updateMPBar(ProgressBar *bar, bool showMax) +{ + if (showMax) + bar->setText(toString(player_node->mMp) + + "/" + toString(player_node->mMaxMp)); + else + bar->setText(toString(player_node->mMp)); + + + bar->setProgress((float) player_node->mMp / (float) player_node->mMaxMp); +} + +void StatusWindow::updateXPBar(ProgressBar *bar, bool percent) +{ + if (player_node->mXpForNextLevel == 0) { + bar->setText(_("Max level")); + bar->setProgress(1.0); + } else { + if (percent) + { + float xp = (float) player_node->getXp() / + player_node->mXpForNextLevel; + bar->setText(toString((float) ((int) (xp * 10000.0f)) / 100.0f) + + "%"); + } + else + bar->setText(toString(player_node->getXp()) + + "/" + toString(player_node->mXpForNextLevel)); + + bar->setProgress((float) player_node->getXp() / + (float) player_node->mXpForNextLevel); + } +} + +void StatusWindow::updateJobBar(ProgressBar *bar, bool percent) +{ + if (player_node->mJobXpForNextLevel == 0) { + bar->setText(_("Max level")); + bar->setProgress(1.0); + } else { + if (percent) + { + float xp = (float) player_node->mJobXp / + player_node->mJobXpForNextLevel; + bar->setText(toString((float) ((int) (xp * 10000.0f)) / 100.0f) + + "%"); + } + else + bar->setText(toString(player_node->mJobXp) + + "/" + toString(player_node->mJobXpForNextLevel)); + + bar->setProgress((float) player_node->mJobXp / + (float) player_node->mJobXpForNextLevel); + } +} diff --git a/src/gui/status.h b/src/gui/status.h index 5056f631..1425fe12 100644 --- a/src/gui/status.h +++ b/src/gui/status.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,6 +57,11 @@ class StatusWindow : public Window, public gcn::ActionListener */ void update(); + static void updateHPBar(ProgressBar *bar, bool showMax = false); + static void updateMPBar(ProgressBar *bar, bool showMax = false); + static void updateXPBar(ProgressBar *bar, bool percent = true); + static void updateJobBar(ProgressBar *bar, bool percent = true); + private: LocalPlayer *mPlayer; @@ -66,6 +70,7 @@ class StatusWindow : public Window, public gcn::ActionListener */ gcn::Label *mLvlLabel, *mJobLvlLabel; gcn::Label *mGpLabel; + int mCurrency; gcn::Label *mHpLabel, *mMpLabel, *mXpLabel, *mJobLabel; ProgressBar *mHpBar, *mMpBar; ProgressBar *mXpBar, *mJobBar; diff --git a/src/gui/statuswindow.cpp b/src/gui/statuswindow.cpp new file mode 100644 index 00000000..31b2da90 --- /dev/null +++ b/src/gui/statuswindow.cpp @@ -0,0 +1,376 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "statuswindow.h" + +#include <guichan/widgets/label.hpp> + +#include "button.h" +#include "progressbar.h" +#include "windowcontainer.h" + +#include "../localplayer.h" + +#include "../utils/strprintf.h" +#include "../utils/stringutils.h" + +StatusWindow::StatusWindow(LocalPlayer *player): + Window(player->getName()), + mPlayer(player) +{ + setWindowName("Status"); + setResizable(true); + setCloseButton(true); + setDefaultSize((windowContainer->getWidth() - 365) / 2, + (windowContainer->getHeight() - 255) / 2, 365, 275); + loadWindowState(); + + // ---------------------- + // Status Part + // ---------------------- + + mLvlLabel = new gcn::Label("Level:"); + mMoneyLabel = new gcn::Label("Money:"); + + mHpLabel = new gcn::Label("HP:"); + mHpBar = new ProgressBar(1.0f, 80, 15, 0, 171, 34); + mHpValueLabel = new gcn::Label(""); + + int y = 3; + int x = 5; + + mLvlLabel->setPosition(x, y); + x += mLvlLabel->getWidth() + 40; + mMoneyLabel->setPosition(x, y); + + y += mLvlLabel->getHeight() + 5; // Next Row + x = 5; + + mHpLabel->setPosition(x, y); + x += mHpLabel->getWidth() + 5; + mHpBar->setPosition(x, y); + x += mHpBar->getWidth() + 5; + mHpValueLabel->setPosition(x, y); + + y += mHpLabel->getHeight() + 5; // Next Row + x = 5; + + add(mLvlLabel); + add(mMoneyLabel); + add(mHpLabel); + add(mHpValueLabel); + add(mHpBar); + + // ---------------------- + // Stats Part + // ---------------------- + + // Static Labels + gcn::Label *mStatsTitleLabel = new gcn::Label("Stats"); + gcn::Label *mStatsTotalLabel = new gcn::Label("Total"); + + // Derived Stats +/* + mStatsAttackLabel = new gcn::Label("Attack:"); + mStatsDefenseLabel= new gcn::Label("Defense:"); + mStatsMagicAttackLabel = new gcn::Label("M.Attack:"); + mStatsMagicDefenseLabel = new gcn::Label("M.Defense:"); + mStatsAccuracyLabel = new gcn::Label("% Accuracy:"); + mStatsEvadeLabel = new gcn::Label("% Evade:"); + mStatsReflexLabel = new gcn::Label("% Reflex:"); + + mStatsAttackPoints = new gcn::Label(""); + mStatsDefensePoints = new gcn::Label(""); + mStatsMagicAttackPoints = new gcn::Label(""); + mStatsMagicDefensePoints = new gcn::Label(""); + mStatsAccuracyPoints = new gcn::Label("% Accuracy:"); + mStatsEvadePoints = new gcn::Label("% Evade:"); + mStatsReflexPoints = new gcn::Label("% Reflex:"); +*/ + // New labels + for (int i = 0; i < 6; i++) { + mStatsLabel[i] = new gcn::Label(); + mStatsDisplayLabel[i] = new gcn::Label(); + } + mCharacterPointsLabel = new gcn::Label(); + mCorrectionPointsLabel = new gcn::Label(); + + // Set button events Id + mStatsPlus[0] = new Button("+", "STR+", this); + mStatsPlus[1] = new Button("+", "AGI+", this); + mStatsPlus[2] = new Button("+", "DEX+", this); + mStatsPlus[3] = new Button("+", "VIT+", this); + mStatsPlus[4] = new Button("+", "INT+", this); + mStatsPlus[5] = new Button("+", "WIL+", this); + + mStatsMinus[0] = new Button("-", "STR-", this); + mStatsMinus[1] = new Button("-", "AGI-", this); + mStatsMinus[2] = new Button("-", "DEX-", this); + mStatsMinus[3] = new Button("-", "VIT-", this); + mStatsMinus[4] = new Button("-", "INT-", this); + mStatsMinus[5] = new Button("-", "WIL-", this); + + + + // Set position + mStatsTitleLabel->setPosition(mHpLabel->getX(), mHpLabel->getY() + 23 ); + mStatsTotalLabel->setPosition(110, mStatsTitleLabel->getY() + 15); + int totalLabelY = mStatsTotalLabel->getY(); + + for (int i = 0; i < 6; i++) + { + mStatsLabel[i]->setPosition(5, + mStatsTotalLabel->getY() + (i * 23) + 15); + mStatsMinus[i]->setPosition(85, totalLabelY + (i * 23) + 15); + mStatsDisplayLabel[i]->setPosition(125, + totalLabelY + (i * 23) + 15); + mStatsPlus[i]->setPosition(185, totalLabelY + (i * 23) + 15); + } + + mCharacterPointsLabel->setPosition(5, mStatsDisplayLabel[5]->getY() + 25); + mCorrectionPointsLabel->setPosition(5, mStatsDisplayLabel[5]->getY() + 35); +/* + mStatsAttackLabel->setPosition(220, mStatsLabel[0]->getY()); + mStatsDefenseLabel->setPosition(220, mStatsLabel[1]->getY()); + mStatsMagicAttackLabel->setPosition(220, mStatsLabel[2]->getY()); + mStatsMagicDefenseLabel->setPosition(220, mStatsLabel[3]->getY()); + mStatsAccuracyLabel->setPosition(220, mStatsLabel[4]->getY()); + mStatsEvadeLabel->setPosition(220, mStatsLabel[5]->getY()); + mStatsReflexLabel->setPosition(220, mStatsLabel[6]->getY()); + + mStatsAttackPoints->setPosition(310, mStatsLabel[0]->getY()); + mStatsDefensePoints->setPosition(310, mStatsLabel[1]->getY()); + mStatsMagicAttackPoints->setPosition(310, mStatsLabel[2]->getY()); + mStatsMagicDefensePoints->setPosition(310, mStatsLabel[3]->getY()); + mStatsAccuracyPoints->setPosition(310, mStatsLabel[4]->getY()); + mStatsEvadePoints->setPosition(310, mStatsLabel[5]->getY()); + mStatsReflexPoints->setPosition(310, mStatsLabel[6]->getY()); +*/ + // Assemble + add(mStatsTitleLabel); + add(mStatsTotalLabel); + for(int i = 0; i < 6; i++) + { + add(mStatsLabel[i]); + add(mStatsDisplayLabel[i]); + add(mStatsPlus[i]); + add(mStatsMinus[i]); + }/* + add(mStatsAttackLabel); + add(mStatsDefenseLabel); + add(mStatsMagicAttackLabel); + add(mStatsMagicDefenseLabel); + add(mStatsAccuracyLabel); + add(mStatsEvadeLabel); + add(mStatsReflexLabel); + + add(mStatsAttackPoints); + add(mStatsDefensePoints); + add(mStatsMagicAttackPoints); + add(mStatsMagicDefensePoints); + add(mStatsAccuracyPoints); + add(mStatsEvadePoints); + add(mStatsReflexPoints);*/ + + add(mCharacterPointsLabel); + add(mCorrectionPointsLabel); +} + +void StatusWindow::update() +{ + // Status Part + // ----------- + mLvlLabel->setCaption( "Level: " + + toString(mPlayer->getLevel()) + + " (" + + toString(mPlayer->getLevelProgress()) + + "%)"); + mLvlLabel->adjustSize(); + + mMoneyLabel->setCaption("Money: " + toString(mPlayer->getMoney()) + " GP"); + mMoneyLabel->adjustSize(); + + updateHPBar(mHpBar, true); + + // Stats Part + // ---------- + const std::string attrNames[6] = { + "Strength", + "Agility", + "Dexterity", + "Vitality", + "Intelligence", + "Willpower" + }; + int characterPoints = mPlayer->getCharacterPoints(); + int correctionPoints = mPlayer->getCorrectionPoints(); + // Update labels + for (int i = 0; i < 6; i++) + { + mStatsLabel[i]->setCaption(attrNames[i]); + mStatsDisplayLabel[i]->setCaption( + strprintf("%d / %d", + mPlayer->getAttributeEffective(CHAR_ATTR_BEGIN + i), + mPlayer->getAttributeBase(CHAR_ATTR_BEGIN + i))); + + mStatsLabel[i]->adjustSize(); + mStatsDisplayLabel[i]->adjustSize(); + + mStatsPlus[i]->setEnabled(characterPoints); + mStatsMinus[i]->setEnabled(correctionPoints); + } + mCharacterPointsLabel->setCaption("Character Points: " + + toString(characterPoints)); + mCharacterPointsLabel->adjustSize(); + + mCorrectionPointsLabel->setCaption("Correction Points: " + + toString(correctionPoints)); + mCorrectionPointsLabel->adjustSize(); +/* + // Derived Stats Points + + // Attack TODO: Count equipped Weapons and items attack bonuses + mStatsAttackPoints->setCaption( + toString(mPlayer->ATK + mPlayer->ATK_BONUS)); + mStatsAttackPoints->adjustSize(); + + // Defense TODO: Count equipped Armors and items defense bonuses + mStatsDefensePoints->setCaption( + toString(mPlayer->DEF + mPlayer->DEF_BONUS)); + mStatsDefensePoints->adjustSize(); + + // Magic Attack TODO: Count equipped items M.Attack bonuses + mStatsMagicAttackPoints->setCaption( + toString(mPlayer->MATK + mPlayer->MATK_BONUS)); + mStatsMagicAttackPoints->adjustSize(); + + // Magic Defense TODO: Count equipped items M.Defense bonuses + mStatsMagicDefensePoints->setCaption( + toString(mPlayer->MDEF + mPlayer->MDEF_BONUS)); + mStatsMagicDefensePoints->adjustSize(); + + // Accuracy % + mStatsAccuracyPoints->setCaption(toString(mPlayer->HIT)); + mStatsAccuracyPoints->adjustSize(); + + // Evasion % + mStatsEvadePoints->setCaption(toString(mPlayer->FLEE)); + mStatsEvadePoints->adjustSize(); + + // Reflex % + mStatsReflexPoints->setCaption(toString(mPlayer->DEX / 4)); // + counter + mStatsReflexPoints->adjustSize(); +*/ + // Update Second column widgets position + mMoneyLabel->setPosition(mLvlLabel->getX() + mLvlLabel->getWidth() + 20, + mLvlLabel->getY()); + +} + +void StatusWindow::draw(gcn::Graphics *g) +{ + update(); + + Window::draw(g); +} + +void StatusWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + + // Stats Part + if (eventId == "STR+") + { + mPlayer->raiseAttribute(LocalPlayer::STR); + } + else if (eventId == "AGI+") + { + mPlayer->raiseAttribute(LocalPlayer::AGI); + } + else if (eventId == "DEX+") + { + mPlayer->raiseAttribute(LocalPlayer::DEX); + } + else if (eventId == "VIT+") + { + mPlayer->raiseAttribute(LocalPlayer::VIT); + } + else if (eventId == "INT+") + { + mPlayer->raiseAttribute(LocalPlayer::INT); + } + else if (eventId == "WIL+") + { + mPlayer->raiseAttribute(LocalPlayer::WIL); + } + + else if (eventId == "STR-") + { + mPlayer->lowerAttribute(LocalPlayer::STR); + } + else if (eventId == "AGI-") + { + mPlayer->lowerAttribute(LocalPlayer::AGI); + } + else if (eventId == "DEX-") + { + mPlayer->lowerAttribute(LocalPlayer::DEX); + } + else if (eventId == "VIT-") + { + mPlayer->lowerAttribute(LocalPlayer::VIT); + } + else if (eventId == "INT-") + { + mPlayer->lowerAttribute(LocalPlayer::INT); + } + else if (eventId == "WIL-") + { + mPlayer->lowerAttribute(LocalPlayer::WIL); + } +} + +// WARNING: Duplicated method! + +void StatusWindow::updateHPBar(ProgressBar *bar, bool showMax) +{ + if (showMax) + bar->setText(toString(player_node->getHp()) + + "/" + toString(player_node->getMaxHp())); + else + bar->setText(toString(player_node->getHp())); + + // HP Bar coloration + if (player_node->getHp() < player_node->getMaxHp() / 3) + { + bar->setColor(223, 32, 32); // Red + } + else if (player_node->getHp() < (player_node->getMaxHp() / 3) * 2) + { + bar->setColor(230, 171, 34); // Orange + } + else + { + bar->setColor(0, 171, 34); // Green + } + + bar->setProgress((float) player_node->getHp() / (float) player_node->getMaxHp()); +} diff --git a/src/gui/statuswindow.h b/src/gui/statuswindow.h new file mode 100644 index 00000000..605145d3 --- /dev/null +++ b/src/gui/statuswindow.h @@ -0,0 +1,107 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef STATUS_H +#define STATUS_H + +#include <iosfwd> + +#include <guichan/actionlistener.hpp> + +#include "window.h" + +#include "../guichanfwd.h" + +class LocalPlayer; +class ProgressBar; + + +/** + * The player status dialog. + * + * \ingroup Interface + */ +class StatusWindow : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + */ + StatusWindow(LocalPlayer *player); + + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event); + + /** + * Draw this window + */ + void draw(gcn::Graphics *graphics); + + /** + * Updates this dialog with values from PLAYER_INFO *char_info + */ + void update(); + + static void updateHPBar(ProgressBar *bar, bool showMax = false); + + private: + LocalPlayer *mPlayer; + + /** + * Status Part + */ + gcn::Label *mLvlLabel, *mMoneyLabel, *mHpLabel, *mHpValueLabel; + ProgressBar *mHpBar; + + /** + * Derived Statistics captions + */ +/* + gcn::Label *mStatsAttackLabel, *mStatsDefenseLabel; + gcn::Label *mStatsMagicAttackLabel, *mStatsMagicDefenseLabel; + gcn::Label *mStatsAccuracyLabel, *mStatsEvadeLabel; + gcn::Label *mStatsReflexLabel; + + gcn::Label *mStatsAttackPoints, *mStatsDefensePoints; + gcn::Label *mStatsMagicAttackPoints, *mStatsMagicDefensePoints; + gcn::Label *mStatsAccuracyPoints, *mStatsEvadePoints; + gcn::Label *mStatsReflexPoints; +*/ + /** + * Stats captions. + */ + gcn::Label *mStatsLabel[6]; + gcn::Label *mStatsDisplayLabel[6]; + gcn::Label *mCharacterPointsLabel; + gcn::Label *mCorrectionPointsLabel; + + /** + * Stats buttons. + */ + gcn::Button *mStatsPlus[6]; + gcn::Button *mStatsMinus[6]; +}; + +extern StatusWindow *statusWindow; + +#endif diff --git a/src/gui/storagewindow.cpp b/src/gui/storagewindow.cpp index eb0cbc12..479348aa 100644 --- a/src/gui/storagewindow.cpp +++ b/src/gui/storagewindow.cpp @@ -39,10 +39,12 @@ #include "../inventory.h" #include "../item.h" #include "../localplayer.h" +#include "../units.h" #include "../net/messageout.h" -#include "../net/network.h" -#include "../net/protocol.h" +#ifdef EATHENA_SUPPORT +#include "../net/ea/protocol.h" +#endif #include "../resources/iteminfo.h" @@ -65,7 +67,7 @@ StorageWindow::StorageWindow(Network *network, int invSize): mStoreButton = new Button(_("Store"), "store", this); mRetrieveButton = new Button(_("Retrieve"), "retrieve", this); - mItems = new ItemContainer(player_node->getStorage(), 1); + mItems = new ItemContainer(player_node->getStorage(), 10, 5, 1); mItems->addSelectionListener(this); mInvenScroll = new ScrollArea(mItems); diff --git a/src/gui/storagewindow.h b/src/gui/storagewindow.h index 6a1c2cdb..cc0df2af 100644 --- a/src/gui/storagewindow.h +++ b/src/gui/storagewindow.h @@ -40,7 +40,8 @@ class TextBox; * * \ingroup Interface */ -class StorageWindow : public Window, gcn::ActionListener, gcn::SelectionListener +class StorageWindow : public Window, gcn::ActionListener, + gcn::SelectionListener { public: /** diff --git a/src/gui/table.cpp b/src/gui/table.cpp index 17d8bfbf..ec5b0480 100644 --- a/src/gui/table.cpp +++ b/src/gui/table.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra derived from original code - * from Guichan. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,7 +37,7 @@ class GuiTableActionListener : public gcn::ActionListener public: GuiTableActionListener(GuiTable *_table, gcn::Widget *_widget, int _row, int _column); - virtual ~GuiTableActionListener(void); + virtual ~GuiTableActionListener(); virtual void action(const gcn::ActionEvent& actionEvent); @@ -63,7 +62,7 @@ GuiTableActionListener::GuiTableActionListener(GuiTable *table, gcn::Widget *wid } } -GuiTableActionListener::~GuiTableActionListener(void) +GuiTableActionListener::~GuiTableActionListener() { if (mWidget) { @@ -97,13 +96,13 @@ GuiTable::GuiTable(TableModel *initial_model, gcn::Color background, addKeyListener(this); } -GuiTable::~GuiTable(void) +GuiTable::~GuiTable() { uninstallActionListeners(); delete mModel; } -TableModel* GuiTable::getModel(void) const +TableModel *GuiTable::getModel() const { return mModel; } @@ -126,7 +125,7 @@ void GuiTable::setModel(TableModel *new_model) } } -void GuiTable::recomputeDimensions(void) +void GuiTable::recomputeDimensions() { int rows_nr = mModel->getRows(); int columns_nr = mModel->getColumns(); @@ -154,12 +153,12 @@ void GuiTable::setSelected(int row, int column) mSelectedRow = row; } -int GuiTable::getSelectedRow(void) +int GuiTable::getSelectedRow() { return mSelectedRow; } -int GuiTable::getSelectedColumn(void) +int GuiTable::getSelectedColumn() { return mSelectedColumn; } @@ -169,7 +168,7 @@ void GuiTable::setLinewiseSelection(bool linewise) mLinewiseMode = linewise; } -int GuiTable::getRowHeight(void) +int GuiTable::getRowHeight() { if (mModel) return mModel->getRowHeight() + 1; // border @@ -201,7 +200,7 @@ void GuiTable::setSelectedRow(int selected) { mSelectedRow = 0; } - else if ((selected >= mModel->getRows() && !mWrappingEnabled) || + else if ((selected >= mModel->getRows() && !mWrappingEnabled) || (selected < 0 && mWrappingEnabled)) { mSelectedRow = mModel->getRows() - 1; @@ -226,7 +225,7 @@ void GuiTable::setSelectedColumn(int selected) { mSelectedColumn = 0; } - else if ((selected >= mModel->getColumns() && !mWrappingEnabled) || + else if ((selected >= mModel->getColumns() && !mWrappingEnabled) || (selected < 0 && mWrappingEnabled)) { mSelectedColumn = mModel->getColumns() - 1; @@ -240,11 +239,11 @@ void GuiTable::setSelectedColumn(int selected) void GuiTable::uninstallActionListeners(void) { - delete_all(action_listeners); - action_listeners.clear(); + delete_all(mActionListeners); + mActionListeners.clear(); } -void GuiTable::installActionListeners(void) +void GuiTable::installActionListeners() { if (!mModel) return; @@ -256,7 +255,7 @@ void GuiTable::installActionListeners(void) for (int column = 0; column < columns; ++column) { gcn::Widget *widget = mModel->getElementAt(row, column); - action_listeners.push_back(new GuiTableActionListener(this, widget, + mActionListeners.push_back(new GuiTableActionListener(this, widget, row, column)); } @@ -290,7 +289,7 @@ void GuiTable::draw(gcn::Graphics* graphics) int max_rows_nr = mModel->getRows() - first_row; // clip if neccessary: if (max_rows_nr < rows_nr) rows_nr = max_rows_nr; - + // Now determine the first and last column // Take the easy way out; these are usually bounded and all visible. int first_column = 0; @@ -338,7 +337,6 @@ void GuiTable::draw(gcn::Graphics* graphics) graphics->pushClipArea(bounds); widget->draw(graphics); graphics->popClipArea(); - } x_offset += width; @@ -369,7 +367,7 @@ void GuiTable::moveToBottom(gcn::Widget *widget) mTopWidget = NULL; } -gcn::Rectangle GuiTable::getChildrenArea(void) +gcn::Rectangle GuiTable::getChildrenArea() { return gcn::Rectangle(0, 0, getWidth(), getHeight()); } @@ -459,7 +457,7 @@ void GuiTable::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) mouseEvent.consume(); } } - + void GuiTable::mouseDragged(gcn::MouseEvent& mouseEvent) { } @@ -479,7 +477,7 @@ void GuiTable::modelUpdated(bool completed) } } -gcn::Widget* GuiTable::getWidgetAt(int x, int y) +gcn::Widget *GuiTable::getWidgetAt(int x, int y) { int row = getRowForY(y); int column = getColumnForX(x); @@ -531,12 +529,13 @@ void GuiTable::_setFocusHandler(gcn::FocusHandler* focusHandler) { gcn::Widget::_setFocusHandler(focusHandler); - if (mModel) - for (int r = 0; r < mModel->getRows(); ++r) - for (int c = 0; c < mModel->getColumns(); ++c) - { + if (mModel) { + for (int r = 0; r < mModel->getRows(); ++r) { + for (int c = 0; c < mModel->getColumns(); ++c) { gcn::Widget *w = mModel->getElementAt(r, c); if (w) w->_setFocusHandler(focusHandler); } + } + } } diff --git a/src/gui/table.h b/src/gui/table.h index a508d0e4..d73cf340 100644 --- a/src/gui/table.h +++ b/src/gui/table.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra derived from original code - * from Guichan. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,17 +46,19 @@ class GuiTable : public gcn::Widget, public gcn::KeyListener, public TableModelListener { - friend class GuiTableActionListener; // so that the action listener can call distributeActionEvent + // so that the action listener can call distributeActionEvent + friend class GuiTableActionListener; + public: GuiTable(TableModel * initial_model = NULL, gcn::Color background = 0xffffff, bool opacity = true); - virtual ~GuiTable(void); + virtual ~GuiTable(); /** * Retrieves the active table model */ - TableModel *getModel(void) const; + TableModel *getModel() const; /** * Sets the table model @@ -73,9 +74,9 @@ public: void setSelected(int row, int column); - int getSelectedRow(void); + int getSelectedRow(); - int getSelectedColumn(void); + int getSelectedColumn(); void setSelectedRow(int selected); @@ -137,25 +138,25 @@ public: virtual void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent); virtual void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent); - + virtual void mouseDragged(gcn::MouseEvent& mouseEvent); // Constraints inherited from TableModelListener virtual void modelUpdated(bool); protected: + /** Frees all action listeners on inner widgets. */ + virtual void uninstallActionListeners(); + /** Installs all action listeners on inner widgets. */ + virtual void installActionListeners(); - virtual void uninstallActionListeners(void); // frees all action listeners on inner widgets - virtual void installActionListeners(void); // installs all action listeners on inner widgets - - virtual int getRowHeight(void); + virtual int getRowHeight(); virtual int getColumnWidth(int i); - -private: +private: int getRowForY(int y); // -1 on error int getColumnForX(int x); // -1 on error - void recomputeDimensions(void); + void recomputeDimensions(); bool mLinewiseMode; bool mWrappingEnabled; bool mOpaque; @@ -172,11 +173,14 @@ private: int mSelectedRow; int mSelectedColumn; - int mPopFramesNr; // Number of frames to skip upwards when drawing the selected widget + /** Number of frames to skip upwards when drawing the selected widget. */ + int mPopFramesNr; - gcn::Widget *mTopWidget; // If someone moves a fresh widget to the top, we must display it + /** If someone moves a fresh widget to the top, we must display it. */ + gcn::Widget *mTopWidget; - std::vector<GuiTableActionListener *> action_listeners; // Vector for compactness; used as a list in practice. + /** Vector for compactness; used as a list in practice. */ + std::vector<GuiTableActionListener *> mActionListeners; }; diff --git a/src/gui/table_model.cpp b/src/gui/table_model.cpp index 8998961e..4fa13bae 100644 --- a/src/gui/table_model.cpp +++ b/src/gui/table_model.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,13 +35,13 @@ void TableModel::removeListener(TableModelListener *listener) listeners.erase(listener); } -void TableModel::signalBeforeUpdate(void) +void TableModel::signalBeforeUpdate() { for (std::set<TableModelListener *>::const_iterator it = listeners.begin(); it != listeners.end(); it++) (*it)->modelUpdated(false); } -void TableModel::signalAfterUpdate(void) +void TableModel::signalAfterUpdate() { for (std::set<TableModelListener *>::const_iterator it = listeners.begin(); it != listeners.end(); it++) (*it)->modelUpdated(true); @@ -61,12 +60,12 @@ StaticTableModel::StaticTableModel(int row, int column) : mWidths.resize(column, 1); } -StaticTableModel::~StaticTableModel(void) +StaticTableModel::~StaticTableModel() { delete_all(mTableModel); } -void StaticTableModel::resize(void) +void StaticTableModel::resize() { mRows = getRows(); mColumns = getColumns(); @@ -98,7 +97,7 @@ void StaticTableModel::set(int row, int column, gcn::Widget *widget) signalAfterUpdate(); } -gcn::Widget* StaticTableModel::getElementAt(int row, int column) +gcn::Widget *StaticTableModel::getElementAt(int row, int column) { return mTableModel[WIDGET_AT(row, column)]; } @@ -120,7 +119,7 @@ void StaticTableModel::fixRowHeight(int height) mHeight = -height; } -int StaticTableModel::getRowHeight(void) +int StaticTableModel::getRowHeight() { return abs(mHeight); } @@ -133,12 +132,12 @@ int StaticTableModel::getColumnWidth(int column) return abs(mWidths[column]); } -int StaticTableModel::getRows(void) +int StaticTableModel::getRows() { return mRows; } -int StaticTableModel::getColumns(void) +int StaticTableModel::getColumns() { return mColumns; } diff --git a/src/gui/table_model.h b/src/gui/table_model.h index 6edd7d65..9ca36120 100644 --- a/src/gui/table_model.h +++ b/src/gui/table_model.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,8 +29,9 @@ class TableModelListener { public: /** - * Must be invoked by the TableModel whenever a global change is about to occur or - * has occurred (e.g., when a row or column is being removed or added). + * Must be invoked by the TableModel whenever a global change is about to + * occur or has occurred (e.g., when a row or column is being removed or + * added). * * This method is triggered twice, once before and once after the update. * @@ -46,22 +46,22 @@ public: class TableModel { public: - virtual ~TableModel(void) { } + virtual ~TableModel() { } /** * Determines the number of rows (lines) in the table */ - virtual int getRows(void) = 0; + virtual int getRows() = 0; /** * Determines the number of columns in each row */ - virtual int getColumns(void) = 0; + virtual int getColumns() = 0; /** * Determines the height for each row */ - virtual int getRowHeight(void) = 0; + virtual int getRowHeight() = 0; /** * Determines the width of each individual column @@ -81,12 +81,12 @@ protected: /** * Tells all listeners that the table is about to see an update */ - virtual void signalBeforeUpdate(void); + virtual void signalBeforeUpdate(); /** * Tells all listeners that the table has seen an update */ - virtual void signalAfterUpdate(void); + virtual void signalAfterUpdate(); private: std::set<TableModelListener *> listeners; @@ -97,7 +97,7 @@ class StaticTableModel : public TableModel { public: StaticTableModel(int width, int height); - virtual ~StaticTableModel(void); + virtual ~StaticTableModel(); /** * Inserts a widget into the table model. @@ -107,7 +107,8 @@ public: virtual void set(int row, int column, gcn::Widget *widget); /** - * Fixes the column width for a given column; this overrides dynamic width inference. + * Fixes the column width for a given column; this overrides dynamic width + * inference. * * Semantics are undefined for width 0. */ @@ -123,17 +124,16 @@ public: /** * Resizes the table model */ - virtual void resize(void); + virtual void resize(); - virtual int getRows(void); - virtual int getColumns(void); - virtual int getRowHeight(void); - virtual int getWidth(void); - virtual int getHeight(void); + virtual int getRows(); + virtual int getColumns(); + virtual int getRowHeight(); + virtual int getWidth(); + virtual int getHeight(); virtual int getColumnWidth(int index); virtual gcn::Widget *getElementAt(int row, int column); - protected: int mRows, mColumns; int mHeight; diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp index 51a8efc6..10f727e3 100644 --- a/src/gui/textbox.cpp +++ b/src/gui/textbox.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/textbox.h b/src/gui/textbox.h index 20f4ebe2..5884e11c 100644 --- a/src/gui/textbox.h +++ b/src/gui/textbox.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/textdialog.cpp b/src/gui/textdialog.cpp new file mode 100644 index 00000000..8c65d64b --- /dev/null +++ b/src/gui/textdialog.cpp @@ -0,0 +1,91 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "textdialog.h" +#include "button.h" + +#include "../utils/gettext.h" + +#include <guichan/widgets/label.hpp> +#include <guichan/widgets/textfield.hpp> + +TextDialog::TextDialog(const std::string &title, const std::string &msg, + Window *parent): + Window(title, true, parent), + mTextField(new TextField) +{ + gcn::Label *textLabel = new gcn::Label(msg); + mOkButton = new Button(_("OK"), "OK", this); + gcn::Button *cancelButton = new Button(_("Cancel"), "CANCEL", this); + + int w = textLabel->getWidth() + 20; + int inWidth = mOkButton->getWidth() + cancelButton->getWidth() + 5; + int h = textLabel->getHeight() + 25 + mOkButton->getHeight() + mTextField->getHeight(); + + if (w < inWidth + 10) + w = inWidth + 10; + + setContentSize(w, h); + textLabel->setPosition(10, 10); + mTextField->setWidth(85); + mTextField->setPosition(10,20 + textLabel->getHeight()); + mOkButton->setPosition((w - inWidth) / 2, + h - 5 - cancelButton->getHeight()); + cancelButton->setPosition(mOkButton->getX() + mOkButton->getWidth() + 5, + h - 5 - cancelButton->getHeight()); + + add(textLabel); + add(mTextField); + add(mOkButton); + add(cancelButton); + + if (getParent()) { + setLocationRelativeTo(getParent()); + getParent()->moveToTop(this); + } + setVisible(true); + mTextField->requestFocus(); +} + +void TextDialog::action(const gcn::ActionEvent &event) +{ + // Proxy button events to our listeners + ActionListenerIterator i; + for (i = mActionListeners.begin(); i != mActionListeners.end(); ++i) + { + (*i)->action(event); + } + + if (event.getId() == "CANCEL" || event.getId() == "OK") + { + scheduleDelete(); + } +} + +const std::string &TextDialog::getText() const +{ + return mTextField->getText(); +} + +void TextDialog::setOKButtonActionId(const std::string &name) +{ + mOkButton->setActionEventId(name); +} diff --git a/src/gui/textdialog.h b/src/gui/textdialog.h new file mode 100644 index 00000000..3dc9259c --- /dev/null +++ b/src/gui/textdialog.h @@ -0,0 +1,66 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GUI_GUILD_DIALOG_H +#define GUI_GUILD_DIALOG_H + +#include <guichan/actionlistener.hpp> +#include "textfield.h" + +#include "window.h" + +/** +* An option dialog. + * + * \ingroup GUI + */ +class TextDialog : public Window, public gcn::ActionListener +{ +public: + /** + * Constructor. + * + * @see Window::Window + */ + TextDialog(const std::string &title, const std::string &msg, + Window *parent = NULL); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + /** + * Get the text in the textfield + */ + const std::string &getText() const; + + /** + * Set the OK button action id + */ + void setOKButtonActionId(const std::string &name); + +private: + TextField *mTextField; + gcn::Button *mOkButton; +}; + +#endif diff --git a/src/gui/textfield.cpp b/src/gui/textfield.cpp index 257ddaa1..42279fc4 100644 --- a/src/gui/textfield.cpp +++ b/src/gui/textfield.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +39,7 @@ int TextField::instances = 0; float TextField::mAlpha = config.getValue("guialpha", 0.8); ImageRect TextField::skin; -TextField::TextField(const std::string& text): +TextField::TextField(const std::string &text): gcn::TextField(text), mNumeric(false), mListener(0) diff --git a/src/gui/textfield.h b/src/gui/textfield.h index b82912c0..070d86ae 100644 --- a/src/gui/textfield.h +++ b/src/gui/textfield.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,12 +38,13 @@ class TextFieldListener * * \ingroup GUI */ -class TextField : public gcn::TextField { +class TextField : public gcn::TextField +{ public: /** * Constructor, initializes the text field with the given string. */ - TextField(const std::string& text = ""); + TextField(const std::string &text = ""); /** * Destructor. diff --git a/src/gui/textrenderer.h b/src/gui/textrenderer.h index c0f5a0e9..712c1312 100644 --- a/src/gui/textrenderer.h +++ b/src/gui/textrenderer.h @@ -2,7 +2,7 @@ * Text Renderer * Copyright (C) 2009 The Mana World Development Team * - * This file is part of Aethyra based on code from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,17 +35,22 @@ class TextRenderer /** * Renders a specified text. */ - static inline void renderText(gcn::Graphics *graphics, const std::string& - text, int x, int y, gcn::Graphics::Alignment align, - const gcn::Color color, gcn::Font *font, bool outline = false, - bool shadow = false, int alpha = 255) + static inline void renderText(gcn::Graphics *graphics, + const std::string &text, + int x, int y, + gcn::Graphics::Alignment align, + const gcn::Color &color, + gcn::Font *font, + bool outline = false, + bool shadow = false, int alpha = 255) { graphics->setFont(font); // Text shadow if (shadow) { - graphics->setColor(guiPalette->getColor(Palette::SHADOW, alpha / 2)); + graphics->setColor(guiPalette->getColor(Palette::SHADOW, + alpha / 2)); if (outline) { graphics->drawText(text, x + 2, y + 2, align); diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp index 82ac4647..2d80d12d 100644 --- a/src/gui/trade.cpp +++ b/src/gui/trade.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,24 +38,39 @@ #include "../inventory.h" #include "../item.h" #include "../localplayer.h" +#include "../units.h" +#ifdef TMWSERV_SUPPORT +#include "../net/tmwserv/gameserver/player.h" +#else #include "../net/messageout.h" -#include "../net/protocol.h" +#include "../net/ea/protocol.h" +#endif #include "../utils/gettext.h" -#include "../utils/strprintf.h" #include "../utils/stringutils.h" +#include "../utils/strprintf.h" +#ifdef TMWSERV_SUPPORT +TradeWindow::TradeWindow(): +#else TradeWindow::TradeWindow(Network *network): - Window("Trade"), +#endif + Window(_("Trade: You")), +#ifdef EATHENA_SUPPORT mNetwork(network), mMyInventory(new Inventory(INVENTORY_SIZE, 2)), mPartnerInventory(new Inventory(INVENTORY_SIZE, 2)) +#else + mMyInventory(new Inventory(INVENTORY_SIZE)), + mPartnerInventory(new Inventory(INVENTORY_SIZE)), + mStatus(PREPARING) +#endif { - setWindowName(_("Trade")); - setDefaultSize(342, 209, ImageRect::CENTER); + setWindowName("Trade"); setResizable(true); setCloseButton(true); + setDefaultSize(342, 209, ImageRect::CENTER); setMinWidth(342); setMinHeight(209); @@ -65,36 +79,58 @@ TradeWindow::TradeWindow(Network *network): getFont()->getWidth(_("Trade")) ? _("OK") : _("Trade"); - mAddButton = new Button(_("Add"), "add", this); + Button *addButton = new Button(_("Add"), "add", this); +#ifdef EATHENA_SUPPORT mOkButton = new Button(longestName, "ok", this); - - mMyItemContainer = new ItemContainer(mMyInventory.get(), 2); - mMyItemContainer->setWidth(160); +#else + Button *cancelButton = new Button(_("Cancel"), "cancel", this); +#endif + mTradeButton = new Button(_("Propose trade"), "trade", this); + mTradeButton->setWidth(8 + std::max( + mTradeButton->getFont()->getWidth(_("Propose trade")), + mTradeButton->getFont()->getWidth(_("Confirm trade")))); + +#ifdef TMWSERV_SUPPORT + mMyItemContainer = new ItemContainer(mMyInventory.get(), 4, 3, 0); +#else + mMyItemContainer = new ItemContainer(mMyInventory.get(), 4, 3, 2); +#endif mMyItemContainer->addSelectionListener(this); - mMyScroll = new ScrollArea(mMyItemContainer); + ScrollArea *myScroll = new ScrollArea(mMyItemContainer); - mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 2); - mPartnerItemContainer->setWidth(160); +#ifdef TMWSERV_SUPPORT + mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 4, 3, 0); +#else + mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 4, 3, 2); +#endif mPartnerItemContainer->addSelectionListener(this); - mPartnerScroll = new ScrollArea(mPartnerItemContainer); + ScrollArea *partnerScroll = new ScrollArea(mPartnerItemContainer); + + mMoneyLabel = new Label(strprintf(_("You get %s."), "")); + gcn::Label *mMoneyLabel2 = new Label(_("You give:")); - mMoneyLabel = new Label(strprintf(_("You get %d GP."), 0)); - mMoneyLabel2 = new Label(_("You give:")); mMoneyField = new TextField; - mMoneyField->setWidth(50); + mMoneyField->setWidth(40); + Button *moneyChange = new Button(_("Change"), "money", this); place(1, 0, mMoneyLabel); - place(0, 1, mMyScroll).setPadding(3); - place(1, 1, mPartnerScroll).setPadding(3); + place(0, 1, myScroll).setPadding(3); + place(1, 1, partnerScroll).setPadding(3); ContainerPlacer place; place = getPlacer(0, 0); place(0, 0, mMoneyLabel2); place(1, 0, mMoneyField); + place(2, 0, moneyChange).setHAlign(LayoutCell::LEFT); place = getPlacer(0, 2); - place(6, 0, mAddButton); - place(7, 0, mOkButton); + place(0, 0, addButton); +#ifdef EATHENA_SUPPORT + place(1, 0, mOkButton); +#else + place(2, 0, mTradeButton); + place(3, 0, cancelButton); +#endif Layout &layout = getLayout(); layout.extend(0, 2, 2, 1); layout.setRowHeight(1, Layout::AUTO_SET); @@ -102,7 +138,9 @@ TradeWindow::TradeWindow(Network *network): layout.setColWidth(0, Layout::AUTO_SET); layout.setColWidth(1, Layout::AUTO_SET); +#ifdef EATHENA_SUPPORT mOkButton->setCaption(_("OK")); +#endif loadWindowState(); } @@ -111,34 +149,37 @@ TradeWindow::~TradeWindow() { } -void TradeWindow::addMoney(int amount) +void TradeWindow::setMoney(int amount) { - mMoneyLabel->setCaption(strprintf(_("You get %d GP."), amount)); + mMoneyLabel->setCaption(strprintf(_("You get %s."), + Units::formatCurrency(amount).c_str())); mMoneyLabel->adjustSize(); +#ifdef TMWSERV_SUPPORT + setStatus(PREPARING); +#endif +} + +#ifdef TMWSERV_SUPPORT +void TradeWindow::addItem(int id, bool own, int quantity) +{ + (own ? mMyInventory : mPartnerInventory)->addItem(id, quantity); + setStatus(PREPARING); } +#endif +#ifdef EATHENA_SUPPORT void TradeWindow::addItem(int id, bool own, int quantity, bool equipment) { if (own) { - mMyItemContainer->setWidth(mMyScroll->getWidth()); mMyInventory->addItem(id, quantity, equipment); } else { - mPartnerItemContainer->setWidth(mPartnerScroll->getWidth()); mPartnerInventory->addItem(id, quantity, equipment); } } -void TradeWindow::removeItem(int id, bool own) -{ - if (own) - mMyInventory->removeItem(id); - else - mPartnerInventory->removeItem(id); -} - void TradeWindow::changeQuantity(int index, bool own, int quantity) { if (own) @@ -154,21 +195,36 @@ void TradeWindow::increaseQuantity(int index, bool own, int quantity) else mPartnerInventory->getItem(index)->increaseQuantity(quantity); } +#endif void TradeWindow::reset() { mMyInventory->clear(); mPartnerInventory->clear(); +#ifdef EATHENA_SUPPORT mOkButton->setCaption(_("OK")); mOkButton->setActionEventId("ok"); mOkButton->setEnabled(true); mOkOther = false; mOkMe = false; - mMoneyLabel->setCaption(strprintf(_("You get %d GP."), 0)); +#endif + mMoneyLabel->setCaption(strprintf(_("You get %s."), "")); mMoneyField->setEnabled(true); mMoneyField->setText(""); +#ifdef TMWSERV_SUPPORT + setStatus(PREPARING); +#endif } +#ifdef TMWSERV_SUPPORT + +void TradeWindow::receivedOk() +{ + setStatus(ACCEPTING); +} + +#else + void TradeWindow::receivedOk(bool own) { if (own) @@ -191,8 +247,15 @@ void TradeWindow::receivedOk(bool own) } } +#endif + void TradeWindow::tradeItem(Item *item, int quantity) { +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::tradeItem(item->getInvIndex(), quantity); + addItem(item->getId(), true, quantity); + item->increaseQuantity(-quantity); +#else // TODO: Our newer version of eAthena doesn't register this following // function. Detect the actual server version, and re-enable this // for that version only. @@ -201,6 +264,7 @@ void TradeWindow::tradeItem(Item *item, int quantity) outMsg.writeInt16(CMSG_TRADE_ITEM_ADD_REQUEST); outMsg.writeInt16(item->getInvIndex()); outMsg.writeInt32(quantity); +#endif } void TradeWindow::valueChanged(const gcn::SelectionEvent &event) @@ -217,6 +281,18 @@ void TradeWindow::valueChanged(const gcn::SelectionEvent &event) mMyItemContainer->selectNone(); } +#ifdef TMWSERV_SUPPORT +void TradeWindow::setStatus(Status s) +{ + if (s == mStatus) return; + mStatus = s; + + mTradeButton->setCaption + (s == PREPARING ? _("Propose trade") : _("Confirm trade")); + mTradeButton->setEnabled(s != PROPOSING); +} +#endif + void TradeWindow::action(const gcn::ActionEvent &event) { Item *item = inventoryWindow->getSelectedItem(); @@ -233,7 +309,7 @@ void TradeWindow::action(const gcn::ActionEvent &event) if (mMyInventory->contains(item)) { - chatWindow->chatLog(_("Failed adding item. You can not " + localChatTab->chatLog(_("Failed adding item. You can not " "overlap one kind of item on the window."), BY_SERVER); return; @@ -248,12 +324,24 @@ void TradeWindow::action(const gcn::ActionEvent &event) // Choose amount of items to trade new ItemAmountWindow(AMOUNT_TRADE_ADD, this, item); } + +#ifdef TMWSERV_SUPPORT + setStatus(PREPARING); +#endif } else if (event.getId() == "cancel") { + setVisible(false); + reset(); + player_node->setTrading(false); +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::acceptTrade(false); +#else MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_TRADE_CANCEL_REQUEST); +#endif } +#ifdef EATHENA_SUPPORT else if (event.getId() == "ok") { std::stringstream tempMoney(mMoneyField->getText()); @@ -275,15 +363,34 @@ void TradeWindow::action(const gcn::ActionEvent &event) MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_TRADE_ADD_COMPLETE); } +#endif else if (event.getId() == "trade") { +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::acceptTrade(true); + setStatus(PROPOSING); +#else MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_TRADE_OK); +#endif + } +#ifdef TMWSERV_SUPPORT + else if (event.getId() == "money") + { + int v = atoi(mMoneyField->getText().c_str()); + Net::GameServer::Player::tradeMoney(v); + mMoneyField->setText(strprintf("%d", v)); + setStatus(PREPARING); } +#endif } void TradeWindow::close() { +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::acceptTrade(false); +#else MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_TRADE_CANCEL_REQUEST); +#endif } diff --git a/src/gui/trade.h b/src/gui/trade.h index 76ba5a4c..4c215ba6 100644 --- a/src/gui/trade.h +++ b/src/gui/trade.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,7 +34,9 @@ class Inventory; class Item; class ItemContainer; +#ifdef EATHENA_SUPPORT class Network; +#endif class ScrollArea; /** @@ -49,7 +50,11 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener /** * Constructor. */ +#ifdef TMWSERV_SUPPORT + TradeWindow(); +#else TradeWindow(Network *network); +#endif /** * Destructor. @@ -57,24 +62,25 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener ~TradeWindow(); /** - * Add money to the trade window. + * Displays expected money in the trade window. */ - void addMoney(int quantity); + void setMoney(int quantity); /** * Add an item to the trade window. */ - void addItem(int id, bool own, int quantity, bool equipment); + void addItem(int id, bool own, int quantity); /** - * Remove a item from the trade window. + * Reset both item containers */ - void removeItem(int id, bool own); + void reset(); +#ifdef EATHENA_SUPPORT /** - * Reset both item containers + * Add an item to the trade window. */ - void reset(); + void addItem(int id, bool own, int quantity, bool equipment); /** * Change quantity of an item. @@ -85,11 +91,16 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener * Increase quantity of an item. */ void increaseQuantity(int index, bool own, int quantity); +#endif /** * Player received ok message from server */ +#ifdef TMWSERV_SUPPORT + void receivedOk(); +#else void receivedOk(bool own); +#endif /** * Send trade packet. @@ -114,7 +125,23 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener void close(); private: +#ifdef TMWSERV_SUPPORT + enum Status + { + PREPARING, /**< Players are adding items. */ + PROPOSING, /**< Local player is proposing a trade. */ + ACCEPTING /**< Distant player is proposing a trade. */ + }; + + /** + * Sets the current status of the trade. + */ + void setStatus(Status); +#endif + +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif typedef const std::auto_ptr<Inventory> InventoryPtr; InventoryPtr mMyInventory; @@ -124,11 +151,18 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener ItemContainer *mPartnerItemContainer; gcn::Label *mMoneyLabel; - gcn::Label *mMoneyLabel2; - gcn::Button *mAddButton, *mOkButton; - ScrollArea *mMyScroll, *mPartnerScroll; + gcn::Button *mTradeButton; +#ifdef EATHENA_SUPPORT + gcn::Button *mAddButton; + gcn::Button *mOkButton; +#endif gcn::TextField *mMoneyField; + +#ifdef TMWSERV_SUPPORT + Status mStatus; +#else bool mOkOther, mOkMe; +#endif }; extern TradeWindow *tradeWindow; diff --git a/src/gui/truetypefont.cpp b/src/gui/truetypefont.cpp index e50fb457..b4b839e9 100644 --- a/src/gui/truetypefont.cpp +++ b/src/gui/truetypefont.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,8 +43,7 @@ class TextChunk bool operator==(const TextChunk &chunk) const { - return ( - chunk.text == text && chunk.color == color); + return (chunk.text == text && chunk.color == color); } void generate(TTF_Font *font) @@ -134,12 +132,12 @@ void TrueTypeFont::drawString(gcn::Graphics *graphics, bool found = false; - for (CacheIterator i = cache.begin(); i != cache.end(); i++) + for (CacheIterator i = mCache.begin(); i != mCache.end(); ++i) { if (chunk == (*i)) { // Raise priority: move it to front - cache.splice(cache.begin(), cache, i); + mCache.splice(mCache.begin(), mCache, i); found = true; break; } @@ -148,19 +146,19 @@ void TrueTypeFont::drawString(gcn::Graphics *graphics, // Surface not found if (!found) { - if (cache.size() >= CACHE_SIZE) + if (mCache.size() >= CACHE_SIZE) { - cache.pop_back(); + mCache.pop_back(); } - cache.push_front(chunk); - cache.front().generate(mFont); + mCache.push_front(chunk); + mCache.front().generate(mFont); } - cache.front().img->setAlpha(alpha); - g->drawImage(cache.front().img, x, y); + mCache.front().img->setAlpha(alpha); + g->drawImage(mCache.front().img, x, y); } -int TrueTypeFont::getWidth(const std::string& text) const +int TrueTypeFont::getWidth(const std::string &text) const { int w, h; TTF_SizeUTF8(mFont, text.c_str(), &w, &h); diff --git a/src/gui/truetypefont.h b/src/gui/truetypefont.h index 085aa226..cbe64368 100644 --- a/src/gui/truetypefont.h +++ b/src/gui/truetypefont.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,8 +26,8 @@ #include <string> #include <guichan/font.hpp> -#ifndef __APPLE__ -#include <SDL/SDL_ttf.h> +#ifdef __APPLE__ +#include <SDL_ttf/SDL_ttf.h> #else #include <SDL_ttf.h> #endif @@ -56,20 +55,22 @@ class TrueTypeFont : public gcn::Font */ ~TrueTypeFont(); - virtual int getWidth(const std::string& text) const; + virtual int getWidth(const std::string &text) const; virtual int getHeight() const; /** * @see Font::drawString */ - void drawString(gcn::Graphics* graphics, const std::string& text, int x, int y); + void drawString(gcn::Graphics *graphics, + const std::string &text, + int x, int y); private: TTF_Font *mFont; // Word surfaces cache - std::list<TextChunk> cache; + std::list<TextChunk> mCache; }; #endif diff --git a/src/gui/unregisterdialog.cpp b/src/gui/unregisterdialog.cpp new file mode 100644 index 00000000..7906afc1 --- /dev/null +++ b/src/gui/unregisterdialog.cpp @@ -0,0 +1,141 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "unregisterdialog.h" + +#include <string> +#include <sstream> + +#include <guichan/widgets/label.hpp> + +#include "../main.h" +#include "../log.h" +#include "../logindata.h" + +#include "button.h" +#include "checkbox.h" +#include "register.h" +#include "passwordfield.h" +#include "textfield.h" +#include "ok_dialog.h" + +#include "../utils/gettext.h" +#include "../utils/strprintf.h" + +UnRegisterDialog::UnRegisterDialog(Window *parent, LoginData *loginData): + Window("Unregister", true, parent), + mWrongDataNoticeListener(new WrongDataNoticeListener()), + mLoginData(loginData) +{ + gcn::Label *userLabel = new gcn::Label(strprintf(_("Name: %s"), mLoginData->username.c_str())); + gcn::Label *passwordLabel = new gcn::Label(_("Password:")); + mPasswordField = new PasswordField(mLoginData->password); + mUnRegisterButton = new Button(_("Unregister"), "unregister", this); + mCancelButton = new Button(_("Cancel"), "cancel", this); + + const int width = 210; + const int height = 80; + setContentSize(width, height); + + userLabel->setPosition(5, 5); + userLabel->setWidth(width - 5); + mPasswordField->setPosition( + 68, userLabel->getY() + userLabel->getHeight() + 7); + mPasswordField->setWidth(130); + + passwordLabel->setPosition(5, mPasswordField->getY() + 1); + + mCancelButton->setPosition( + width - 5 - mCancelButton->getWidth(), + height - 5 - mCancelButton->getHeight()); + mUnRegisterButton->setPosition( + mCancelButton->getX() - 5 - mUnRegisterButton->getWidth(), + mCancelButton->getY()); + + add(userLabel); + add(passwordLabel); + add(mPasswordField); + add(mUnRegisterButton); + add(mCancelButton); + + setLocationRelativeTo(getParent()); + setVisible(true); + mPasswordField->requestFocus(); + mPasswordField->setActionEventId("cancel"); +} + +UnRegisterDialog::~UnRegisterDialog() +{ + delete mWrongDataNoticeListener; +} + +void +UnRegisterDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "cancel") + { + scheduleDelete(); + } + else if (event.getId() == "unregister") + { + const std::string username = mLoginData->username.c_str(); + const std::string password = mPasswordField->getText(); + logger->log("UnregisterDialog::unregistered, Username is %s", + username.c_str()); + + std::stringstream errorMsg; + bool error = false; + + // Check password + if (password.length() < LEN_MIN_PASSWORD) + { + // Pass too short + errorMsg << "The password needs to be at least " + << LEN_MIN_PASSWORD + << " characters long."; + error = true; + } + else if (password.length() > LEN_MAX_PASSWORD - 1 ) + { + // Pass too long + errorMsg << "The password needs to be less than " + << LEN_MAX_PASSWORD + << " characters long."; + error = true; + } + + if (error) + { + mWrongDataNoticeListener->setTarget(this->mPasswordField); + + OkDialog *dlg = new OkDialog("Error", errorMsg.str()); + dlg->addActionListener(mWrongDataNoticeListener); + } + else + { + // No errors detected, unregister the new user. + mUnRegisterButton->setEnabled(false); + mLoginData->password = password; + state = STATE_UNREGISTER_ATTEMPT; + scheduleDelete(); + } + } +} diff --git a/src/gui/unregisterdialog.h b/src/gui/unregisterdialog.h new file mode 100644 index 00000000..1e3cc88f --- /dev/null +++ b/src/gui/unregisterdialog.h @@ -0,0 +1,70 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef UNREGISTERDIALOG_H +#define UNREGISTERDIALOG_H + +#include <iosfwd> +#include <guichan/actionlistener.hpp> + +#include "window.h" +#include "../guichanfwd.h" + +class LoginData; +class OkDialog; +class WrongDataNoticeListener; + +/** + * The Unregister dialog. + * + * \ingroup Interface + */ +class UnRegisterDialog : public Window, public gcn::ActionListener { + public: + /** + * Constructor + * + * @see Window::Window + */ + UnRegisterDialog(Window *parent,LoginData *loginData); + + /** + * Destructor + */ + ~UnRegisterDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + private: + gcn::TextField *mPasswordField; + + gcn::Button *mUnRegisterButton; + gcn::Button *mCancelButton; + + WrongDataNoticeListener *mWrongDataNoticeListener; + + LoginData *mLoginData; +}; + +#endif diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index 927d6eaf..8c903c28 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -106,7 +105,7 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost, { mCurlError[0] = 0; - mBrowserBox = new BrowserBox(); + mBrowserBox = new BrowserBox; mScrollArea = new ScrollArea(mBrowserBox); mLabel = new Label(_("Connecting...")); mProgressBar = new ProgressBar(0.0, 310, 20, 168, 116, 31); @@ -130,7 +129,7 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost, Layout &layout = getLayout(); layout.setRowHeight(0, Layout::AUTO_SET); - setLocationRelativeTo(getParent()); + center(); setVisible(true); mCancelButton->requestFocus(); @@ -184,7 +183,7 @@ void UpdaterWindow::action(const gcn::ActionEvent &event) } else if (event.getId() == "play") { - state = LOADDATA_STATE; + state = STATE_LOADDATA; } } @@ -231,7 +230,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; @@ -359,7 +358,7 @@ int UpdaterWindow::downloadThread(void *ptr) // Remove the corrupted file ::remove(outFilename.c_str()); logger->log( - _("Checksum for file %s failed: (%lx/%lx)"), + "Checksum for file %s failed: (%lx/%lx)", uw->mCurrentFile.c_str(), adler, uw->mCurrentChecksum); attempts++; diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h index 234a6f57..ace398b4 100644 --- a/src/gui/updatewindow.h +++ b/src/gui/updatewindow.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +31,8 @@ #include "../utils/mutex.h" +#include "../utils/mutex.h" + class BrowserBox; class Button; class ProgressBar; diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 56274573..c840e456 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,12 +19,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "ministatus.h" #include "popupmenu.h" #include "viewport.h" #include "../beingmanager.h" #include "../configuration.h" #include "../flooritemmanager.h" +#include "../game.h" #include "../graphics.h" #include "../keyboardconfig.h" #include "../localplayer.h" @@ -50,8 +51,13 @@ Viewport::Viewport(): mTileViewX(0), mTileViewY(0), mShowDebugPath(false), + mVisibleNames(false), mPlayerFollowMouse(false), +#ifdef TMWSERV_SUPPORT + mLocalWalkTime(-1) +#else mWalkTime(0) +#endif { setOpaque(false); addMouseListener(this); @@ -60,16 +66,20 @@ Viewport::Viewport(): mScrollRadius = (int) config.getValue("ScrollRadius", 0); mScrollCenterOffsetX = (int) config.getValue("ScrollCenterOffsetX", 0); mScrollCenterOffsetY = (int) config.getValue("ScrollCenterOffsetY", 0); + mVisibleNames = config.getValue("visiblenames", 1); config.addListener("ScrollLaziness", this); config.addListener("ScrollRadius", this); + config.addListener("visiblenames", this); - mPopupMenu = new PopupMenu(); + mPopupMenu = new PopupMenu; } Viewport::~Viewport() { delete mPopupMenu; + + config.removeListener("visiblenames", this); } void Viewport::setMap(Map *map) @@ -77,6 +87,8 @@ void Viewport::setMap(Map *map) mMap = map; } +extern MiniStatusWindow *miniStatusWindow; + void Viewport::draw(gcn::Graphics *gcnGraphics) { static int lastTick = tick_time; @@ -97,6 +109,14 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) } // Calculate viewpoint +#ifdef TMWSERV_SUPPORT + int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 2; + int midTileY = (graphics->getHeight() + mScrollCenterOffsetX) / 2; + + const Vector &playerPos = player_node->getPosition(); + const int player_x = (int) playerPos.x - midTileX; + const int player_y = (int) playerPos.y - midTileY; +#else int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 32 / 2; int midTileY = (graphics->getHeight() + mScrollCenterOffsetY) / 32 / 2; @@ -104,6 +124,7 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) player_node->getXOffset(); int player_y = (player_node->mY - midTileY) * 32 + player_node->getYOffset(); +#endif if (mScrollLaziness < 1) mScrollLaziness = 1; // Avoids division by zero @@ -146,8 +167,10 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) }; // Don't move camera so that the end of the map is on screen - int viewXmax = (mMap->getWidth() * 32) - graphics->getWidth(); - int viewYmax = (mMap->getHeight() * 32) - graphics->getHeight(); + const int viewXmax = + mMap->getWidth() * mMap->getTileWidth() - graphics->getWidth(); + const int viewYmax = + mMap->getHeight() * mMap->getTileHeight() - graphics->getHeight(); if (mMap) { if (mPixelViewX < 0) @@ -168,30 +191,13 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) { mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY); - // Find a path from the player to the mouse, and draw it. This is for - // debug purposes. - if (mShowDebugPath) - { - // Get the current mouse position - SDL_GetMouseState(&mMouseX, &mMouseY); - - int mouseTileX = mMouseX / 32 + mTileViewX; - int mouseTileY = mMouseY / 32 + mTileViewY; - - Path debugPath = mMap->findPath(player_node->mX, player_node->mY, - mouseTileX, mouseTileY); - - graphics->setColor(gcn::Color(255, 0, 0)); - for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++) - { - int squareX = i->x * 32 - (int) mPixelViewX + 12; - int squareY = i->y * 32 - (int) mPixelViewY + 12; - - graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8)); - graphics->drawText(toString(mMap->getMetaTile(i->x, i->y)->Gcost), - squareX + 4, squareY + 12, - gcn::Graphics::CENTER); - } + if (mShowDebugPath) { + mMap->drawCollision(graphics, + (int) mPixelViewX, + (int) mPixelViewY); +#if 0 + drawDebugPath(graphics); +#endif } } @@ -215,6 +221,9 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) (*i)->drawEmotion(graphics, (int) mPixelViewX, (int) mPixelViewY); } + if (miniStatusWindow) + miniStatusWindow->drawIcons(graphics); + // Draw contained widgets WindowContainer::draw(gcnGraphics); } @@ -229,11 +238,51 @@ void Viewport::logic() Uint8 button = SDL_GetMouseState(&mMouseX, &mMouseY); if (mPlayerFollowMouse && button & SDL_BUTTON(1) && +#ifdef TMWSERV_SUPPORT + get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay) + { + mLocalWalkTime = tick_time; + player_node->setDestination(mMouseX + (int) mPixelViewX, + mMouseY + (int) mPixelViewY); +#else mWalkTime != player_node->mWalkTime) { player_node->setDestination(mMouseX / 32 + mTileViewX, mMouseY / 32 + mTileViewY); mWalkTime = player_node->mWalkTime; +#endif + } +} + +void Viewport::drawDebugPath(Graphics *graphics) +{ + // Get the current mouse position + SDL_GetMouseState(&mMouseX, &mMouseY); + + const int mouseTileX = (mMouseX + (int) mPixelViewX) / 32; + const int mouseTileY = (mMouseY + (int) mPixelViewY) / 32; + const Vector &playerPos = player_node->getPosition(); + + Path debugPath = mMap->findPath( + (int) playerPos.x / 32, + (int) playerPos.y / 32, + mouseTileX, mouseTileY, 0xFF); + + drawPath(graphics, debugPath); +} + +void Viewport::drawPath(Graphics *graphics, const Path &path) +{ + graphics->setColor(gcn::Color(255, 0, 0)); + for (Path::const_iterator i = path.begin(); i != path.end(); ++i) + { + int squareX = i->x * 32 - (int) mPixelViewX + 12; + int squareY = i->y * 32 - (int) mPixelViewY + 12; + + graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8)); + graphics->drawText( + toString(mMap->getMetaTile(i->x, i->y)->Gcost), + squareX + 4, squareY + 12, gcn::Graphics::CENTER); } } @@ -249,10 +298,10 @@ void Viewport::mousePressed(gcn::MouseEvent &event) mPlayerFollowMouse = false; - const int tilex = event.getX() / 32 + mTileViewX; - const int tiley = event.getY() / 32 + mTileViewY; - const int x = (int)((float) event.getX() + mPixelViewX); - const int y = (int)((float) event.getY() + mPixelViewY); + const int pixelx = event.getX() + (int) mPixelViewX; + const int pixely = event.getY() + (int) mPixelViewY; + const int tilex = pixelx / mMap->getTileWidth(); + const int tiley = pixely / mMap->getTileHeight(); // Right click might open a popup if (event.getButton() == gcn::MouseEvent::RIGHT) @@ -260,7 +309,7 @@ void Viewport::mousePressed(gcn::MouseEvent &event) Being *being; FloorItem *floorItem; - if ((being = beingManager->findBeingByPixel(x, y)) && + if ((being = beingManager->findBeingByPixel(pixelx, pixely)) && being != player_node) { mPopupMenu->showPopup(event.getX(), event.getY(), being); @@ -284,12 +333,13 @@ void Viewport::mousePressed(gcn::MouseEvent &event) // Left click can cause different actions if (event.getButton() == gcn::MouseEvent::LEFT) { - Being *being; FloorItem *item; +#ifdef EATHENA_SUPPORT + Being *being; // Interact with some being // if ((being = beingManager->findBeing(tilex, tiley))) - if ((being = beingManager->findBeingByPixel(x, y))) + if ((being = beingManager->findBeingByPixel(pixelx, pixely))) { switch (being->getType()) { @@ -320,22 +370,38 @@ void Viewport::mousePressed(gcn::MouseEvent &event) } } // Pick up some item - else if ((item = floorItemManager->findByCoordinates(tilex, tiley))) + else +#endif + if ((item = floorItemManager->findByCoordinates(tilex, tiley))) { player_node->pickUp(item); } // Just walk around else { +#ifdef TMWSERV_SUPPORT + // FIXME: REALLY UGLY! + Uint8 *keys = SDL_GetKeyState(NULL); + if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]) && + get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay) + { + mLocalWalkTime = tick_time; + player_node->setDestination(event.getX() + (int) mPixelViewX, + event.getY() + (int) mPixelViewY); + } +#else player_node->stopAttack(); player_node->setDestination(tilex, tiley); +#endif mPlayerFollowMouse = true; } } else if (event.getButton() == gcn::MouseEvent::MIDDLE) { // Find the being nearest to the clicked position - Being *target = beingManager->findBeingByPixel(x, y); + Being *target = beingManager->findNearestLivingBeing( + tilex, tiley, + 20, Being::MONSTER); if (target) player_node->setTarget(target); @@ -347,12 +413,22 @@ void Viewport::mouseDragged(gcn::MouseEvent &event) if (!mMap || !player_node) return; +#ifdef TMWSERV_SUPPORT + if (mPlayerFollowMouse + && get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay) + { + mLocalWalkTime = tick_time; + player_node->setDestination(event.getX() + (int) mPixelViewX, + event.getY() + (int) mPixelViewY); + } +#else if (mPlayerFollowMouse && mWalkTime == player_node->mWalkTime) { int destX = event.getX() / 32 + mTileViewX; int destY = event.getY() / 32 + mTileViewY; player_node->setDestination(destX, destY); } +#endif } void Viewport::mouseReleased(gcn::MouseEvent &event) @@ -369,4 +445,20 @@ void Viewport::optionChanged(const std::string &name) { mScrollLaziness = (int) config.getValue("ScrollLaziness", 32); mScrollRadius = (int) config.getValue("ScrollRadius", 32); + + if (name == "visiblenames") { + mVisibleNames = config.getValue("visiblenames", 1); + } +} + +void Viewport::mouseMoved(gcn::MouseEvent &event) +{ + // Check if we are on the map + if (!mMap || !player_node) + return; + + const int tilex = (event.getX() + (int) mPixelViewX) / 32; + const int tiley = (event.getY() + (int) mPixelViewY) / 32; + + mSelectedBeing = beingManager->findBeing(tilex, tiley); } diff --git a/src/gui/viewport.h b/src/gui/viewport.h index 12fdb187..c051e5a2 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +29,7 @@ #include "../configlistener.h" #include "../position.h" +class Being; class FloorItem; class Graphics; class ImageSet; @@ -37,6 +37,9 @@ class Item; class Map; class PopupMenu; +/** Delay between two mouse calls when dragging mouse and move the player */ +const int walkingMouseDelay = 500; + /** * The viewport on the map. Displays the current map and handles mouse input * and the popup menu. @@ -95,6 +98,11 @@ class Viewport : public WindowContainer, public gcn::MouseListener, void mouseReleased(gcn::MouseEvent &event); /** + * Handles mouse move on map. + */ + void mouseMoved(gcn::MouseEvent &event); + + /** * Shows a popup for an item. * TODO Find some way to get rid of Item here */ @@ -131,6 +139,17 @@ class Viewport : public WindowContainer, public gcn::MouseListener, void scrollBy(float x, float y) { mPixelViewX += x; mPixelViewY += y; } private: + /** + * Finds a path from the player to the mouse, and draws it. This is for + * debug purposes. + */ + void drawDebugPath(Graphics *graphics); + + /** + * Draws the given path. + */ + void drawPath(Graphics *graphics, const Path &path); + Map *mMap; /**< The current map. */ int mScrollRadius; @@ -144,11 +163,17 @@ class Viewport : public WindowContainer, public gcn::MouseListener, int mTileViewX; /**< Current viewpoint in tiles. */ int mTileViewY; /**< Current viewpoint in tiles. */ bool mShowDebugPath; /**< Show a path from player to pointer. */ + bool mVisibleNames; /**< Show target names. */ bool mPlayerFollowMouse; +#ifdef TMWSERV_SUPPORT + int mLocalWalkTime; /**< Timestamp before the next walk can be sent. */ +#else int mWalkTime; +#endif PopupMenu *mPopupMenu; /**< Popup menu. */ + Being *mSelectedBeing; /**< Current selected being. */ }; extern Viewport *viewport; /**< The viewport */ diff --git a/src/gui/widgets/avatar.cpp b/src/gui/widgets/avatar.cpp new file mode 100644 index 00000000..a36c0302 --- /dev/null +++ b/src/gui/widgets/avatar.cpp @@ -0,0 +1,55 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "gui/widgets/avatar.h" + +#include "gui/icon.h" + +#include "resources/image.h" +#include "resources/resourcemanager.h" + +#include <guichan/widgets/label.hpp> + +Avatar::Avatar(const std::string &name): + mName(name) +{ + setSize(110, 12); + mLabel = new gcn::Label(name); + mLabel->setSize(85, 12); + mLabel->setPosition(25, 0); + ResourceManager *resman = ResourceManager::getInstance(); + mStatusOffline = resman->getImage("graphics/gui/circle-gray.png"); + mStatusOnline = resman->getImage("graphics/gui/circle-green.png"); + mStatus = new Icon(mStatusOffline); + mStatus->setSize(25, 12); + mStatus->setPosition(0, 0); +} + +void Avatar::setOnline(bool online) +{ + mStatus->setImage(online ? mStatusOnline : mStatusOffline); +} + +void Avatar::draw(gcn::Graphics *g) +{ + mLabel->draw(g); + mStatus->draw(g); +} diff --git a/src/gui/widgets/avatar.h b/src/gui/widgets/avatar.h new file mode 100644 index 00000000..16972104 --- /dev/null +++ b/src/gui/widgets/avatar.h @@ -0,0 +1,61 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef AVATAR_H +#define AVATAR_H + +#include "guichanfwd.h" + +#include <guichan/widget.hpp> + +#include <string> + +class Image; +class Icon; + +class Avatar : public gcn::Widget +{ +public: + /** + * Constructor. + * @param name Character name + */ + Avatar(const std::string &name); + + /** + * Set the avatar online status. + */ + void setOnline(bool online); + + /** + * Draws the avatar. + */ + void draw(gcn::Graphics *g); + +private: + std::string mName; + Icon *mStatus; + Image *mStatusOnline; + Image *mStatusOffline; + gcn::Label *mLabel; +}; + +#endif // AVATAR_H diff --git a/src/gui/widgets/channeltab.cpp b/src/gui/widgets/channeltab.cpp new file mode 100644 index 00000000..f8c92a6e --- /dev/null +++ b/src/gui/widgets/channeltab.cpp @@ -0,0 +1,70 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/widgets/label.hpp> + +#include "channeltab.h" + +#include "../browserbox.h" +#include "../chatinput.h" +#include "../itemlinkhandler.h" +#include "../recorder.h" +#include "../scrollarea.h" + +#include "../../beingmanager.h" +#include "../../commandhandler.h" +#include "../../channel.h" +#include "../../configuration.h" +#include "../../game.h" +#include "../../localplayer.h" + +#ifdef TMWSERV_SUPPORT +#include "../../net/tmwserv/chatserver/chatserver.h" +#include "../../net/tmwserv/gameserver/player.h" +#else +#include "../../party.h" +#include "../../net/messageout.h" +#include "../../net/ea/protocol.h" +#endif + +#include "../../resources/iteminfo.h" +#include "../../resources/itemdb.h" + +#include "../../utils/dtor.h" +#include "../../utils/gettext.h" +#include "../../utils/strprintf.h" +#include "../../utils/stringutils.h" + +ChannelTab::ChannelTab(Channel *channel) : ChatTab(channel->getName()), + mChannel(channel) +{ + channel->setTab(this); +} + +ChannelTab::~ChannelTab() +{ +} + +void ChannelTab::sendChat(std::string &msg) { +#ifdef TMSERV_SUPPORT + Net::ChatServer::chat(getId(), msg); +#endif +} diff --git a/src/gui/widgets/channeltab.h b/src/gui/widgets/channeltab.h new file mode 100644 index 00000000..91b4f7c6 --- /dev/null +++ b/src/gui/widgets/channeltab.h @@ -0,0 +1,57 @@ +/* + * The Mana World + * Copyright (C) 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CHANNELTAB_H +#define CHANNELTAB_H + +#include "chattab.h" + +class Channel; + +/** + * A tab for a chat channel. + */ +class ChannelTab : public ChatTab +{ + public: + + Channel *getChannel() { return mChannel; } + + protected: + friend class Channel; + + /** + * Constructor. + */ + ChannelTab(Channel *channel); + + /** + * Destructor. + */ + ~ChannelTab(); + + void sendChat(std::string &msg); + + private: + Channel *mChannel; +}; + +#endif // CHANNELTAB_H diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp new file mode 100644 index 00000000..120d4e21 --- /dev/null +++ b/src/gui/widgets/chattab.cpp @@ -0,0 +1,324 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/widgets/label.hpp> + +#include "chattab.h" +#include "layouthelper.h" + +#include "../browserbox.h" +#include "../chatinput.h" +#include "../itemlinkhandler.h" +#include "../recorder.h" +#include "../scrollarea.h" + +#include "../../commandhandler.h" +#include "../../configuration.h" +#include "../../localplayer.h" + +#ifdef TMWSERV_SUPPORT +#include "../../net/tmwserv/chatserver/chatserver.h" +#include "../../net/tmwserv/gameserver/player.h" +#else +#include "../../net/messageout.h" +#include "../../net/ea/protocol.h" +#endif + +#include "../../resources/iteminfo.h" +#include "../../resources/itemdb.h" + +#include "../../utils/strprintf.h" +#include "../../utils/stringutils.h" + +ChatTab::ChatTab(const std::string &name) : Tab() +{ + setCaption(name); + + mTextOutput = new BrowserBox; + mTextOutput->setOpaque(false); + mTextOutput->setMaxRow((int) config.getValue("ChatLogLength", 0)); + mTextOutput->setLinkHandler(chatWindow->mItemLinkHandler); + + mScrollArea = new ScrollArea(mTextOutput); + mScrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, + gcn::ScrollArea::SHOW_ALWAYS); + mScrollArea->setScrollAmount(0, 1); + mScrollArea->setOpaque(false); + + chatWindow->addTab(this); +} + +ChatTab::~ChatTab() +{ + chatWindow->removeTab(this); + delete mTextOutput; + delete mScrollArea; +} + +void ChatTab::chatLog(const char* line, int own, bool ignoreRecord) +{ + chatLog(std::string(line), own, ignoreRecord); +} + +void ChatTab::chatLog(std::string line, int own, bool ignoreRecord) +{ + // Trim whitespace + trim(line); + + if (line.empty()) + return; + + CHATLOG tmp; + tmp.own = own; + tmp.nick = ""; + tmp.text = line; + + std::string::size_type pos = line.find(" : "); + if (pos != std::string::npos) + { + tmp.nick = line.substr(0, pos); + tmp.text = line.substr(pos + 3); + } + else + { + // Fix the owner of welcome message. + if (line.substr(0, 7) == "Welcome") + { + own = BY_SERVER; + } + } + + // *implements actions in a backwards compatible way* + if (own == BY_PLAYER && + tmp.text.at(0) == '*' && + tmp.text.at(tmp.text.length()-1) == '*') + { + tmp.text[0] = ' '; + tmp.text.erase(tmp.text.length() - 1); + own = ACT_IS; + } + + std::string lineColor = "##C"; + switch (own) + { + case BY_GM: + if (tmp.nick.empty()) + { + tmp.nick = std::string(_("Global announcement:")); + tmp.nick += " "; + lineColor = "##G"; + } + else + { + tmp.nick = strprintf(_("Global announcement from %s:"), + tmp.nick.c_str()); + tmp.nick += " "; + lineColor = "##1"; // Equiv. to BrowserBox::RED + } + break; + case BY_PLAYER: + tmp.nick += CAT_NORMAL; + lineColor = "##Y"; + break; + case BY_OTHER: + tmp.nick += CAT_NORMAL; + lineColor = "##C"; + break; + case BY_SERVER: + tmp.nick = _("Server:"); + tmp.nick += " "; + tmp.text = line; + lineColor = "##S"; + break; + case BY_CHANNEL: + tmp.nick = ""; + // TODO: Use a predefined color + lineColor = "##2"; // Equiv. to BrowserBox::GREEN + break; +#ifdef EATHENA_SUPPORT + case BY_PARTY: + tmp.nick += CAT_NORMAL; + lineColor = "##P"; + break; +#endif + case ACT_WHISPER: + tmp.nick = strprintf(_("%s whispers:"), tmp.nick.c_str()); + tmp.nick += " "; + lineColor = "##W"; + break; + case ACT_IS: + tmp.nick += CAT_IS; + lineColor = "##I"; + break; + case BY_LOGGER: + tmp.nick = ""; + tmp.text = line; + lineColor = "##L"; + break; + } + + if (tmp.nick == ": ") + { + tmp.nick = ""; + lineColor = "##S"; + } + +#ifdef EATHENA_SUPPORT + if (tmp.nick.empty() && tmp.text.substr(0, 17) == "Visible GM status") + { + player_node->setGM(); + } +#endif + + // Get the current system time + time_t t; + time(&t); + + // Format the time string properly + std::stringstream timeStr; + timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "") + << (int) (((t / 60) / 60) % 24) + << ":" << (((t / 60) % 60 < 10) ? "0" : "") + << (int) ((t / 60) % 60) + << "] "; + + line = lineColor + timeStr.str() + tmp.nick + tmp.text; + + // We look if the Vertical Scroll Bar is set at the max before + // adding a row, otherwise the max will always be a row higher + // at comparison. + if (mScrollArea->getVerticalScrollAmount() >= mScrollArea->getVerticalMaxScroll()) + { + mTextOutput->addRow(line); + mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); + } + else + { + mTextOutput->addRow(line); + } + + mScrollArea->logic(); + chatWindow->mRecorder->record(line.substr(3)); +} + +void ChatTab::chatLog(std::string &nick, std::string &msg) +{ + chatLog(nick + ": " + msg, nick == player_node->getName() ? BY_PLAYER : BY_OTHER, false); +} + +void ChatTab::chatSend(std::string &msg) +{ + trim(msg); + + if (msg.empty()) return; + +#ifdef EATHENA_SUPPORT + // Send party message + if (msg.at(0) == chatWindow->mPartyPrefix) + { + msg.erase(0, 1); + std::size_t length = msg.length() + 1; + + if (length == 0) + { + chatLog(_("Trying to send a blank party message."), BY_SERVER, true); + return; + } + MessageOut outMsg(chatWindow->mNetwork); + + outMsg.writeInt16(CMSG_PARTY_MESSAGE); + outMsg.writeInt16(length + 4); + outMsg.writeString(msg, length); + return; + } +#endif + + // Check for item link + std::string::size_type start = msg.find('['); + while (start != std::string::npos && msg[start+1] != '@') + { + std::string::size_type end = msg.find(']', start); + if (start+1 != end && end != std::string::npos) + { + // Catch multiple embeds and ignore them + // so it doesn't crash the client. + while ((msg.find('[', start + 1) != std::string::npos) && + (msg.find('[', start + 1) < end)) + { + start = msg.find('[', start + 1); + } + + std::string temp = msg.substr(start + 1, end - start - 1); + + toLower(trim(temp)); + + const ItemInfo itemInfo = ItemDB::get(temp); + if (itemInfo.getName() != _("Unknown item")) + { + msg.insert(end, "@@"); + msg.insert(start+1, "|"); + msg.insert(start+1, toString(itemInfo.getId())); + msg.insert(start+1, "@@"); + } + } + start = msg.find('[', start + 1); + } + + + // Prepare ordinary message + if (msg[0] != '/') + { + sendChat(msg); + } + else + { + commandHandler->handleCommand(std::string(msg, 1)); + } +} + +void ChatTab::scroll(int amount) +{ + int range = mScrollArea->getHeight() / 8 * amount; + gcn::Rectangle scr; + scr.y = mScrollArea->getVerticalScrollAmount() + range; + scr.height = abs(range); + mTextOutput->showPart(scr); +} + +void ChatTab::clearText() +{ + mTextOutput->clearRows(); +} + +void ChatTab::sendChat(std::string &msg) { +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::say(msg); +#else + msg = player_node->getName() + " : " + msg; + + MessageOut outMsg(chatWindow->mNetwork); + outMsg.writeInt16(CMSG_CHAT_MESSAGE); + // Added + 1 in order to let eAthena parse admin commands correctly + outMsg.writeInt16(msg.length() + 4 + 1); + outMsg.writeString(msg, msg.length() + 1); + return; +#endif +} diff --git a/src/gui/widgets/chattab.h b/src/gui/widgets/chattab.h new file mode 100644 index 00000000..a478abeb --- /dev/null +++ b/src/gui/widgets/chattab.h @@ -0,0 +1,118 @@ +/* + * The Mana World + * Copyright (C) 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CHATTAB_H +#define CHATTAB_H + +#include <guichan/widgets/container.hpp> + +#include "tab.h" + +#include "../chat.h" + +class BrowserBox; +class Recorder; +class ScrollArea; + +enum +{ + BY_GM, +#ifdef EATHENA_SUPPORT + BY_PARTY, +#endif + BY_PLAYER, + BY_OTHER, + BY_SERVER, + BY_CHANNEL, + ACT_WHISPER, // getting whispered at + ACT_IS, // equivalent to "/me" on IRC + BY_LOGGER +}; + +/** + * A tab for the chat window. This is special to ease chat handling. + */ +class ChatTab : public Tab +{ + public: + /** + * Constructor. + */ + ChatTab(const std::string &name); + + /** + * Destructor. + */ + ~ChatTab(); + + /** + * Adds a line of text to our message list. Parameters: + * + * @param line Text message. + * @param own Type of message (usually the owner-type). + * @param channelName which channel to send the message to. + * @param ignoreRecord should this not be recorded? + */ + void chatLog(std::string line, int own = BY_SERVER, bool ignoreRecord = false); + void chatLog(const char* line, int own = BY_SERVER, bool ignoreRecord = false); + + /** + * Adds the text to the message list + * + * @param msg The message text which is to be sent. + * + */ + void chatLog(std::string &nick, std::string &msg); + + /** + * Determines whether the message is a command or message, then + * sends the given message to the game server to be said, or to the + * command handler + * + * @param msg The message text which is to be sent. + * + */ + void chatSend(std::string &msg); + + /** + * Scrolls the chat window + * + * @param amount direction and amount to scroll. Negative numbers scroll + * up, positive numbers scroll down. The absolute amount indicates the + * amount of 1/8ths of chat window real estate that should be scrolled. + */ + void scroll(int amount); + + void clearText(); + + protected: + friend class ChatWindow; + + virtual void sendChat(std::string &msg); + + ScrollArea *mScrollArea; + BrowserBox *mTextOutput; + //Recorder *mRecorder; +}; + +extern ChatTab *localChatTab; + +#endif // CHATTAB_H diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp index 21fee368..21378772 100644 --- a/src/gui/widgets/dropdown.cpp +++ b/src/gui/widgets/dropdown.cpp @@ -1,9 +1,8 @@ /* - * Aethyra - * Copyright (C) 2008 The Mana World Development Team + * The Mana World + * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,28 +19,28 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> +#include "gui/widgets/dropdown.h" -#include "dropdown.h" +#include "gui/listbox.h" +#include "gui/palette.h" +#include "gui/scrollarea.h" -#include "../listbox.h" -#include "../palette.h" -#include "../scrollarea.h" +#include "configuration.h" +#include "graphics.h" -#include "../../configuration.h" -#include "../../graphics.h" +#include "resources/image.h" +#include "resources/resourcemanager.h" -#include "../../resources/image.h" -#include "../../resources/resourcemanager.h" +#include "utils/dtor.h" -#include "../../utils/dtor.h" +#include <algorithm> int DropDown::instances = 0; Image *DropDown::buttons[2][2]; ImageRect DropDown::skin; float DropDown::mAlpha = config.getValue("guialpha", 0.8); -DropDown::DropDown(gcn::ListModel *listModel, gcn::ScrollArea *scrollArea, +DropDown::DropDown(gcn::ListModel *listModel, gcn::ScrollArea *scrollArea, gcn::ListBox *listBox, bool opacity): gcn::DropDown::DropDown(listModel, scrollArea, listBox), mOpaque(opacity) diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h index 191740d9..601d55c8 100644 --- a/src/gui/widgets/dropdown.h +++ b/src/gui/widgets/dropdown.h @@ -1,9 +1,8 @@ /* - * Aethyra - * Copyright (C) 2008 The Mana World Development Team + * The Mana World + * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,15 +27,15 @@ 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. - */ +/** + * 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: @@ -58,9 +57,9 @@ class DropDown : public gcn::DropDown */ ~DropDown(); - void draw(gcn::Graphics* graphics); + void draw(gcn::Graphics *graphics); - void drawFrame(gcn::Graphics* graphics); + void drawFrame(gcn::Graphics *graphics); /** * Sets the widget to be opaque, that is sets the widget to display its @@ -68,7 +67,7 @@ class DropDown : public gcn::DropDown * * @param opaque True if the widget should be opaque, false otherwise. */ - void setOpaque(bool opaque) {mOpaque = opaque;} + void setOpaque(bool opaque) { mOpaque = opaque; } /** * Checks if the widget is opaque, that is if the widget area displays @@ -76,7 +75,7 @@ class DropDown : public gcn::DropDown * * @return True if the widget is opaque, false otherwise. */ - bool isOpaque() const {return mOpaque;} + bool isOpaque() const { return mOpaque; } protected: diff --git a/src/gui/widgets/layout.cpp b/src/gui/widgets/layout.cpp index 7fab91d7..9ca82fa3 100644 --- a/src/gui/widgets/layout.cpp +++ b/src/gui/widgets/layout.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,9 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> +#include "gui/widgets/layout.h" -#include "layout.h" +#include <cassert> ContainerPlacer ContainerPlacer::at(int x, int y) { diff --git a/src/gui/widgets/layout.h b/src/gui/widgets/layout.h index 04b75ca5..b9359e91 100644 --- a/src/gui/widgets/layout.h +++ b/src/gui/widgets/layout.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,10 +22,10 @@ #ifndef WIDGET_LAYOUT_H #define WIDGET_LAYOUT_H -#include <vector> - #include <guichan/widgets/container.hpp> +#include <vector> + class LayoutCell; /** diff --git a/src/gui/widgets/layouthelper.cpp b/src/gui/widgets/layouthelper.cpp index ed002f99..820d2d82 100644 --- a/src/gui/widgets/layouthelper.cpp +++ b/src/gui/widgets/layouthelper.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2009 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "layouthelper.h" +#include "gui/widgets/layouthelper.h" LayoutHelper::LayoutHelper(gcn::Container *container): mContainer(container) diff --git a/src/gui/widgets/layouthelper.h b/src/gui/widgets/layouthelper.h index 1125d209..ddcc6b26 100644 --- a/src/gui/widgets/layouthelper.h +++ b/src/gui/widgets/layouthelper.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2009 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +22,7 @@ #ifndef LAYOUTHELPER_H #define LAYOUTHELPER_H -#include "layout.h" +#include "gui/widgets/layout.h" #include <guichan/widgetlistener.hpp> diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp index 3dbf6d1a..1bb33e15 100644 --- a/src/gui/widgets/resizegrip.cpp +++ b/src/gui/widgets/resizegrip.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,15 +19,15 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <guichan/graphics.hpp> +#include "gui/widgets/resizegrip.h" -#include "resizegrip.h" +#include "configuration.h" +#include "graphics.h" -#include "../../configuration.h" -#include "../../graphics.h" +#include "resources/image.h" +#include "resources/resourcemanager.h" -#include "../../resources/image.h" -#include "../../resources/resourcemanager.h" +#include <guichan/graphics.hpp> Image *ResizeGrip::gripImage = 0; int ResizeGrip::mInstances = 0; diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h index 83af24da..40a40a0f 100644 --- a/src/gui/widgets/resizegrip.h +++ b/src/gui/widgets/resizegrip.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp index 942ad3ef..af31822e 100644 --- a/src/gui/widgets/tab.cpp +++ b/src/gui/widgets/tab.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,20 +19,21 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <guichan/widgets/label.hpp> +#include "gui/widgets/tab.h" + +#include "gui/widgets/tabbedarea.h" -#include "tab.h" -#include "tabbedarea.h" +#include "gui/palette.h" -#include "../palette.h" +#include "configuration.h" +#include "graphics.h" -#include "../../configuration.h" -#include "../../graphics.h" +#include "resources/image.h" +#include "resources/resourcemanager.h" -#include "../../resources/image.h" -#include "../../resources/resourcemanager.h" +#include "utils/dtor.h" -#include "../../utils/dtor.h" +#include <guichan/widgets/label.hpp> int Tab::mInstances = 0; float Tab::mAlpha = config.getValue("guialpha", 0.8); diff --git a/src/gui/widgets/tab.h b/src/gui/widgets/tab.h index 4b331d66..3af4e2bf 100644 --- a/src/gui/widgets/tab.h +++ b/src/gui/widgets/tab.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp index 2c454b69..8e93d394 100644 --- a/src/gui/widgets/tabbedarea.cpp +++ b/src/gui/widgets/tabbedarea.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "tabbedarea.h" -#include "tab.h" +#include "gui/widgets/tabbedarea.h" +#include "gui/widgets/tab.h" #include <guichan/widgets/container.hpp> @@ -72,7 +71,7 @@ gcn::Widget* TabbedArea::getWidget(const std::string &name) void TabbedArea::addTab(const std::string &caption, gcn::Widget *widget) { - Tab* tab = new Tab(); + Tab* tab = new Tab; tab->setCaption(caption); mTabsToDelete.push_back(tab); diff --git a/src/gui/widgets/tabbedarea.h b/src/gui/widgets/tabbedarea.h index 863ff79e..dffbd36b 100644 --- a/src/gui/widgets/tabbedarea.h +++ b/src/gui/widgets/tabbedarea.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +23,7 @@ #define TABBEDAREA_H #include <guichan/widget.hpp> +#include <guichan/widgets/container.hpp> #include <guichan/widgets/tabbedarea.hpp> #include <string> @@ -85,9 +85,10 @@ class TabbedArea : public gcn::TabbedArea */ void logic(); + int getContainerHeight() { return mWidgetContainer->getHeight(); } + private: typedef std::vector< std::pair<gcn::Tab*, gcn::Widget*> > TabContainer; }; #endif - diff --git a/src/gui/widgets/textpreview.cpp b/src/gui/widgets/textpreview.cpp index 5408eebe..d0bba285 100644 --- a/src/gui/widgets/textpreview.cpp +++ b/src/gui/widgets/textpreview.cpp @@ -2,7 +2,7 @@ * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on code from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,22 +19,22 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <typeinfo> +#include "gui/widgets/textpreview.h" -#include "textpreview.h" +#include "gui/gui.h" +#include "gui/palette.h" +#include "gui/textrenderer.h" +#include "gui/truetypefont.h" -#include "../gui.h" -#include "../palette.h" -#include "../textrenderer.h" -#include "../truetypefont.h" +#include "configuration.h" -#include "../../configuration.h" +#include <typeinfo> float TextPreview::mAlpha = config.getValue("guialpha", 0.8); -TextPreview::TextPreview(const std::string* text) +TextPreview::TextPreview(const std::string &text): + mText(text) { - mText = text; mTextAlpha = false; mFont = gui->getFont(); mTextColor = &guiPalette->getColor(Palette::TEXT); @@ -65,7 +65,7 @@ void TextPreview::draw(gcn::Graphics* graphics) if (mTextBGColor && typeid(*mFont) == typeid(TrueTypeFont)) { TrueTypeFont *font = static_cast<TrueTypeFont*>(mFont); - int x = font->getWidth(*mText) + 1 + 2 * ((mOutline || mShadow) ? 1 :0); + int x = font->getWidth(mText) + 1 + 2 * ((mOutline || mShadow) ? 1 :0); int y = font->getHeight() + 1 + 2 * ((mOutline || mShadow) ? 1 : 0); graphics->setColor(gcn::Color((int) mTextBGColor->r, (int) mTextBGColor->g, @@ -74,7 +74,7 @@ void TextPreview::draw(gcn::Graphics* graphics) graphics->fillRectangle(gcn::Rectangle(1, 1, x, y)); } - TextRenderer::renderText(graphics, *mText, 2, 2, gcn::Graphics::LEFT, + TextRenderer::renderText(graphics, mText, 2, 2, gcn::Graphics::LEFT, gcn::Color(mTextColor->r, mTextColor->g, mTextColor->b, alpha), mFont, mOutline, mShadow, alpha); diff --git a/src/gui/widgets/textpreview.h b/src/gui/widgets/textpreview.h index 8e116262..0ca343bf 100644 --- a/src/gui/widgets/textpreview.h +++ b/src/gui/widgets/textpreview.h @@ -2,7 +2,7 @@ * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on code from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,14 +32,14 @@ class TextPreview : public gcn::Widget { public: - TextPreview(const std::string* text); + TextPreview(const std::string &text); /** * Sets the color the text is printed in. * * @param color the color to set */ - inline void setTextColor(const gcn::Color* color) + inline void setTextColor(const gcn::Color *color) { mTextColor = color; } @@ -49,7 +49,7 @@ class TextPreview : public gcn::Widget * * @param alpha whether to use alpha values for the text or not */ - inline void useTextAlpha(bool alpha) + inline void useTextAlpha(bool alpha) { mTextAlpha = alpha; } @@ -60,7 +60,7 @@ class TextPreview : public gcn::Widget * * @param color the color to set */ - inline void setTextBGColor(const gcn::Color* color) + inline void setTextBGColor(const gcn::Color *color) { mTextBGColor = color; } @@ -70,7 +70,7 @@ class TextPreview : public gcn::Widget * * @param color the color to set */ - inline void setBGColor(const gcn::Color* color) + inline void setBGColor(const gcn::Color *color) { mBGColor = color; } @@ -124,14 +124,14 @@ class TextPreview : public gcn::Widget * Gets opacity for this widget (whether or not the background color * is shown below the widget) */ - bool isOpaque() { return mOpaque; } + bool isOpaque() const { return mOpaque; } private: gcn::Font *mFont; - const std::string* mText; - const gcn::Color* mTextColor; - const gcn::Color* mBGColor; - const gcn::Color* mTextBGColor; + std::string mText; + const gcn::Color *mTextColor; + const gcn::Color *mBGColor; + const gcn::Color *mTextBGColor; static float mAlpha; bool mTextAlpha; bool mOpaque; diff --git a/src/gui/widgets/whispertab.cpp b/src/gui/widgets/whispertab.cpp new file mode 100644 index 00000000..ba469c00 --- /dev/null +++ b/src/gui/widgets/whispertab.cpp @@ -0,0 +1,78 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/widgets/label.hpp> + +#include "whispertab.h" + +#include "../../beingmanager.h" +#include "../../commandhandler.h" +#include "../../channel.h" +#include "../../configuration.h" +#include "../../game.h" +#include "../../localplayer.h" + +#ifdef TMWSERV_SUPPORT +#include "../../net/tmwserv/chatserver/chatserver.h" +#include "../../net/tmwserv/gameserver/player.h" +#else +#include "../../party.h" +#include "../../net/messageout.h" +#include "../../net/ea/protocol.h" +#endif + +#include "../../resources/iteminfo.h" +#include "../../resources/itemdb.h" + +#include "../../utils/dtor.h" +#include "../../utils/gettext.h" +#include "../../utils/strprintf.h" +#include "../../utils/stringutils.h" + +WhisperTab::WhisperTab(const std::string &nick) : + ChatTab(nick), + mNick(nick) +{ +} + +WhisperTab::~WhisperTab() +{ +} + +void WhisperTab::sendChat(std::string &msg) { + if (msg.length() == 0) { + chatLog(_("Cannot send empty chat!"), BY_SERVER, false); + return; + } + +#ifdef TMWSERV_SUPPORT + Net::ChatServer::privMsg(mNick, msg); +#else + MessageOut outMsg(chatWindow->mNetwork); + outMsg.writeInt16(CMSG_CHAT_WHISPER); + outMsg.writeInt16(msg.length() + 28); + outMsg.writeString(mNick, 24); + outMsg.writeString(msg, msg.length()); +#endif + + chatLog(strprintf(_("%s: %s"), player_node->getName().c_str(), + msg.c_str()), BY_PLAYER, false); +} diff --git a/src/gui/widgets/whispertab.h b/src/gui/widgets/whispertab.h new file mode 100644 index 00000000..e3ebf0f3 --- /dev/null +++ b/src/gui/widgets/whispertab.h @@ -0,0 +1,55 @@ +/* + * The Mana World + * Copyright (C) 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef WHISPERTAB_H +#define WHISPERTAB_H + +#include "chattab.h" + +class Channel; + +/** + * A tab for whispers from a single player. + */ +class WhisperTab : public ChatTab +{ + public: + const std::string &getNick() const { return mNick; } + + protected: + friend class ChatWindow; + + /** + * Constructor. + * + * @param nick the name of the player this tab is whispering to + */ + WhisperTab(const std::string &nick); + + ~WhisperTab(); + + void sendChat(std::string &msg); + + private: + std::string mNick; +}; + +#endif // CHANNELTAB_H diff --git a/src/gui/window.cpp b/src/gui/window.cpp index 476dcd7e..3bc03fb8 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,7 +38,7 @@ int Window::instances = 0; int Window::mouseResize = 0; -Window::Window(const std::string& caption, bool modal, Window *parent, const std::string& skin): +Window::Window(const std::string &caption, bool modal, Window *parent, const std::string &skin): gcn::Window(caption), mGrip(0), mParent(parent), @@ -248,7 +247,7 @@ void Window::setResizable(bool r) if (r) { - mGrip = new ResizeGrip(); + mGrip = new ResizeGrip; mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); add(mGrip); @@ -282,7 +281,7 @@ void Window::setCloseButton(bool flag) mCloseButton = flag; } -bool Window::isResizable() +bool Window::isResizable() const { return mGrip; } @@ -546,6 +545,14 @@ void Window::setDefaultSize(int defaultX, int defaultY, mDefaultHeight = defaultHeight; } +void Window::setDefaultSize() +{ + mDefaultX = getX(); + mDefaultY = getY(); + mDefaultWidth = getWidth(); + mDefaultHeight = getHeight(); +} + void Window::setDefaultSize(int defaultWidth, int defaultHeight, ImageRect::ImagePosition position, int offsetX, int offsetY) @@ -666,3 +673,7 @@ void Window::reflowLayout(int w, int h) setContentSize(w, h); } +void Window::center() +{ + setLocationRelativeTo(getParent()); +} diff --git a/src/gui/window.h b/src/gui/window.h index 8907ead4..c41a4221 100644 --- a/src/gui/window.h +++ b/src/gui/window.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +29,6 @@ #include "../graphics.h" #include "../guichanfwd.h" -class GCContainer; class ContainerPlacer; class Layout; class LayoutCell; @@ -111,46 +109,34 @@ class Window : public gcn::Window, gcn::WidgetListener /** * Returns whether the window can be resized. */ - bool isResizable(); + bool isResizable() const; /** * Sets the minimum width of the window. */ void setMinWidth(int width); + int getMinWidth() const { return mMinWinWidth; } + /** * Sets the minimum height of the window. */ void setMinHeight(int height); + int getMinHeight() const { return mMinWinHeight; } + /** * Sets the maximum width of the window. */ void setMaxWidth(int width); + int getMaxWidth() const { return mMaxWinWidth; } + /** * Sets the minimum height of the window. */ void setMaxHeight(int height); - /** - * Gets the minimum width of the window. - */ - int getMinWidth() const { return mMinWinWidth; } - - /** - * Gets the minimum height of the window. - */ - int getMinHeight() const { return mMinWinHeight; } - - /** - * Gets the maximum width of the window. - */ - int getMaxWidth() const { return mMaxWinWidth; } - - /** - * Gets the minimum height of the window. - */ int getMaxHeight() const { return mMaxWinHeight; } /** @@ -226,7 +212,7 @@ class Window : public gcn::Window, gcn::WidgetListener /** * Returns the name of the window. This is not the window title. */ - const std::string& getWindowName() { return mWindowName; } + const std::string &getWindowName() const { return mWindowName; } /** * Reads the position (and the size for resizable windows) in the @@ -251,6 +237,11 @@ class Window : public gcn::Window, gcn::WidgetListener int defaultWidth, int defaultHeight); /** + * Set the default win pos and size tot he current ones. + */ + void setDefaultSize(); + + /** * Set the default win pos and size. * (which can be different of the actual ones.) * This version of setDefaultSize sets the window's position based @@ -292,6 +283,11 @@ class Window : public gcn::Window, gcn::WidgetListener ContainerPlacer getPlacer(int x, int y); /** + * Positions the window in the center of it's parent. + */ + void center(); + + /** * Overrideable functionality for when the window is to close. This * allows for class implementations to clean up or do certain actions * on window close they couldn't do otherwise. @@ -321,7 +317,6 @@ class Window : public gcn::Window, gcn::WidgetListener */ int getResizeHandles(gcn::MouseEvent &event); - GCContainer *mChrome; /**< Contained container */ ResizeGrip *mGrip; /**< Resize grip */ Window *mParent; /**< The parent window */ Layout *mLayout; /**< Layout handler */ diff --git a/src/gui/windowcontainer.cpp b/src/gui/windowcontainer.cpp index ad86a253..eda739b9 100644 --- a/src/gui/windowcontainer.cpp +++ b/src/gui/windowcontainer.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/windowcontainer.h b/src/gui/windowcontainer.h index 23b221cf..bc918184 100644 --- a/src/gui/windowcontainer.h +++ b/src/gui/windowcontainer.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/guichanfwd.h b/src/guichanfwd.h index 8859780f..4863421c 100644 --- a/src/guichanfwd.h +++ b/src/guichanfwd.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/guild.cpp b/src/guild.cpp new file mode 100644 index 00000000..62c6e3f4 --- /dev/null +++ b/src/guild.cpp @@ -0,0 +1,69 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "guild.h" + +Guild::Guild(short id, short rights): + mId(id), + mCanInviteUsers(false) +{ + // to invite, rights must be greater than 0 + if (rights > 0) + mCanInviteUsers = true; +} + +void Guild::addMember(const std::string &name) +{ + if (!isMember(name)) + { + mMembers.push_back(name); + } +} + +void Guild::removeMember(const std::string &name) +{ + std::vector<std::string>::iterator itr = mMembers.begin(), + itr_end = mMembers.end(); + while(itr != itr_end) + { + if((*itr) == name) + { + mMembers.erase(itr); + } + ++itr; + } +} + +bool Guild::isMember(const std::string &name) +{ + std::vector<std::string>::iterator itr = mMembers.begin(), + itr_end = mMembers.end(); + while(itr != itr_end) + { + if((*itr) == name) + { + return true; + } + ++itr; + } + + return false; +} diff --git a/src/guild.h b/src/guild.h new file mode 100644 index 00000000..9ae16f0b --- /dev/null +++ b/src/guild.h @@ -0,0 +1,108 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GUILD_H +#define GUILD_H + +#include <guichan/listmodel.hpp> + +#include <string> +#include <vector> + +class Guild : public gcn::ListModel +{ +public: + /** + * Constructor with guild id passed to it + */ + Guild(short id, short rights); + + /** + * Set the guild's name + */ + void setName(const std::string &name) + { + mName = name; + } + + /** + * Add member to the list + */ + void addMember(const std::string &name); + + /** + * Get the name of the guild + * @return returns name of the guild + */ + const std::string &getName() const + { + return mName; + } + + /** + * Get the id of the guild + * @return Returns the id of the guild + */ + short getId() const + { + return mId; + } + + /** + * Remove member from the guild + */ + void removeMember(const std::string &name); + + /** + * Get size of members list + * @return Returns the number of members in the guild. + */ + int getNumberOfElements() { + return mMembers.size(); + } + + /** + * Get member at i + * @return Returns the name of member. + */ + std::string getElementAt(int i) { + return mMembers[i]; + } + + /** + * Get whether user can invite users to this guild + * @return Returns true if user can invite users + */ + bool getInviteRights() + { + return mCanInviteUsers; + } + + bool isMember(const std::string &name); + +private: + std::string mName; + short mId; + std::vector<std::string> mMembers; + bool mCanInviteUsers; +}; + +#endif diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp index d2c955ee..557b3553 100644 --- a/src/imageparticle.cpp +++ b/src/imageparticle.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/imageparticle.h b/src/imageparticle.h index 3465b3e0..317b17ea 100644 --- a/src/imageparticle.h +++ b/src/imageparticle.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/inventory.cpp b/src/inventory.cpp index 3d1a4786..59f51e39 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +29,11 @@ struct SlotUsed : public std::unary_function<Item*, bool> { bool operator()(const Item *item) const { +#ifdef TMWSERV_SUPPORT + return item && item->getId() && item->getQuantity(); +#else return item && item->getId() != -1 && item->getQuantity() > 0; +#endif } }; @@ -50,15 +53,19 @@ Inventory::~Inventory() delete [] mItems; } -Item* Inventory::getItem(int index) const +Item *Inventory::getItem(int index) const { +#ifdef TMWSERV_SUPPORT + if (index < 0 || index >= mSize) +#else if (index < 0 || index >= mSize || !mItems[index] || mItems[index]->getQuantity() <= 0) +#endif return 0; return mItems[index]; } -Item* Inventory::findItem(int itemId) const +Item *Inventory::findItem(int itemId) const { for (int i = 0; i < mSize; i++) if (mItems[i] && mItems[i]->getId() == itemId) diff --git a/src/inventory.h b/src/inventory.h index e23f7657..008b7ec4 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,8 +24,12 @@ class Item; +#ifdef EATHENA_SUPPORT #define INVENTORY_SIZE 102 #define STORAGE_SIZE 301 +#else +#define INVENTORY_SIZE 50 +#endif class Inventory { @@ -34,7 +37,7 @@ class Inventory /** * Constructor. */ - Inventory(int size, int offset); + Inventory(int size, int offset = 0); /** * Destructor. @@ -62,12 +65,12 @@ class Inventory /** * Adds a new item in a free slot. */ - void addItem(int id, int quantity, bool equipment); + void addItem(int id, int quantity, bool equipment = false); /** * Sets the item at the given position. */ - void setItem(int index, int id, int quantity, bool equipment); + void setItem(int index, int id, int quantity, bool equipment = false); /** * Remove a item from the inventory. @@ -109,6 +112,7 @@ class Inventory */ int getInventorySize() const; + static const int NO_SLOT_INDEX = -1; /**< Slot has no index. */ protected: Item **mItems; /**< The holder of items */ int mSize; /**< The max number of inventory items */ diff --git a/src/item.cpp b/src/item.cpp index 2125756a..6f04b879 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,13 +22,20 @@ #include "item.h" #include "resources/image.h" +#include "resources/iteminfo.h" #include "resources/resourcemanager.h" -Item::Item(int id, int quantity, bool equipment, bool equipped): +Item::Item(int id, int quantity, bool equipment +#ifdef EATHENA_SUPPORT + , bool equipped +#endif + ): mImage(0), mQuantity(quantity), - mEquipment(equipment), - mEquipped(equipped) + mEquipment(equipment) +#ifdef EATHENA_SUPPORT + , mEquipped(equipped) +#endif { setId(id); } @@ -44,6 +50,11 @@ void Item::setId(int id) { mId = id; +#ifdef TMWSERV_SUPPORT + // Types 0 and 1 are not equippable items. + mEquipment = id && getInfo().getType() >= 2; +#endif + // Load the associated image if (mImage) mImage->decRef(); @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,8 +35,11 @@ class Item /** * Constructor. */ - Item(int id = -1, int quantity = 0, - bool equipment = false, bool equipped = false); + Item(int id = -1, int quantity = 0, bool equipment = false +#ifdef EATHENA_SUPPORT + , bool equipped = false +#endif + ); /** * Destructor. @@ -84,6 +86,7 @@ class Item */ bool isEquipment() const { return mEquipment; } +#ifdef EATHENA_SUPPORT /** * Sets whether this item is equipped. */ @@ -93,6 +96,7 @@ class Item * Returns whether this item is equipped. */ bool isEquipped() const { return mEquipped; } +#endif /** * Sets the inventory index of this item. @@ -114,7 +118,9 @@ class Item Image *mImage; /**< Item image. */ int mQuantity; /**< Number of items. */ bool mEquipment; /**< Item is equipment. */ +#ifdef EATHENA_SUPPORT bool mEquipped; /**< Item is equipped. */ +#endif int mInvIndex; /**< Inventory index. */ }; diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp index 0627ccda..2dea8c56 100644 --- a/src/itemshortcut.cpp +++ b/src/itemshortcut.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -73,14 +72,20 @@ void ItemShortcut::useItem(int index) { if (item->isEquipment()) { +#ifdef EATHENA_SUPPORT if (item->isEquipped()) player_node->unequipItem(item); else +#endif player_node->equipItem(item); } else { +#ifdef TMWSERV_SUPPORT + player_node->useItem(item->getInvIndex()); +#else player_node->useItem(item); +#endif } } } diff --git a/src/itemshortcut.h b/src/itemshortcut.h index 4203f600..95e17f44 100644 --- a/src/itemshortcut.h +++ b/src/itemshortcut.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/joystick.cpp b/src/joystick.cpp index 18a09207..b72c9103 100644 --- a/src/joystick.cpp +++ b/src/joystick.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,12 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> - #include "configuration.h" #include "joystick.h" #include "log.h" +#include <cassert> + int Joystick::joystickCount = 0; void Joystick::init() diff --git a/src/joystick.h b/src/joystick.h index 67b5ab70..4c5390c2 100644 --- a/src/joystick.h +++ b/src/joystick.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp index 8ed23c65..06ce4ac7 100644 --- a/src/keyboardconfig.cpp +++ b/src/keyboardconfig.cpp @@ -1,9 +1,8 @@ /* - * Aethyra - * Copyright (C) 2007 The Mana World Development Team + * Custom keyboard shortcuts configuration + * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/keyboardconfig.h b/src/keyboardconfig.h index 61d7887d..f7750b30 100644 --- a/src/keyboardconfig.h +++ b/src/keyboardconfig.h @@ -1,9 +1,8 @@ /* - * Aethyra - * Copyright (C) 2007 The Mana World Development Team + * Custom keyboard shortcuts configuration + * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/localplayer.cpp b/src/localplayer.cpp index f72aa59a..4dd8f05f 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,50 +33,95 @@ #include "particle.h" #include "simpleanimation.h" #include "sound.h" +#include "statuseffect.h" #include "text.h" #include "gui/gui.h" +#include "gui/ministatus.h" #include "gui/palette.h" +#ifdef EATHENA_SUPPORT #include "gui/storagewindow.h" +#endif +#ifdef TMWSERV_SUPPORT +#include "effectmanager.h" +#include "guild.h" + +#include "net/tmwserv/gameserver/player.h" +#include "net/tmwserv/chatserver/guild.h" +#include "net/tmwserv/chatserver/party.h" +#endif + +#ifdef EATHENA_SUPPORT #include "net/messageout.h" -#include "net/protocol.h" +#include "net/ea/protocol.h" +#endif #include "resources/animation.h" #include "resources/imageset.h" +#include "resources/iteminfo.h" #include "resources/resourcemanager.h" +#include "utils/gettext.h" #include "utils/stringutils.h" +#ifdef TMWSERV_SUPPORT +const short walkingKeyboardDelay = 100; +#endif + LocalPlayer *player_node = NULL; static const int NAME_X_OFFSET = 15; static const int NAME_Y_OFFSET = 30; +#ifdef TMWSERV_SUPPORT +LocalPlayer::LocalPlayer(): + Player(65535, 0, NULL), + mEquipment(new Equipment), + mAttributeBase(NB_CHARACTER_ATTRIBUTES, -1), + mAttributeEffective(NB_CHARACTER_ATTRIBUTES, -1), + mExpCurrent(CHAR_SKILL_NB, -1), + mExpNext(CHAR_SKILL_NB, -1), + mCharacterPoints(-1), + mCorrectionPoints(-1), + mLevelProgress(0), +#else LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map): Player(id, job, map), mCharId(0), mJobXp(0), - mLevel(0), mJobLevel(0), mXpForNextLevel(0), mJobXpForNextLevel(0), - mHp(0), mMaxHp(0), mMp(0), mMaxMp(0), - mGp(0), + mMp(0), mMaxMp(0), mAttackRange(0), - mTotalWeight(0), mMaxWeight(0), ATK(0), MATK(0), DEF(0), MDEF(0), HIT(0), FLEE(0), ATK_BONUS(0), MATK_BONUS(0), DEF_BONUS(0), MDEF_BONUS(0), FLEE_BONUS(0), mStatPoint(0), mSkillPoint(0), mStatsPointsToAttribute(0), - mEquipment(new Equipment()), - mXp(0), mNetwork(0), + mEquipment(new Equipment), + mNetwork(0), + mXp(0), + mInStorage(false), + mTargetTime(-1), + mLastTarget(-1), +#endif + mLevel(1), + mMoney(0), + mTotalWeight(1), mMaxWeight(1), + mHp(1), mMaxHp(1), mTarget(NULL), mPickUpTarget(NULL), mTrading(false), mGoingToTarget(false), - mTargetTime(-1), mLastAction(-1), - mLastTarget(-1), mWalkingDir(0), + mLastAction(-1), + mWalkingDir(0), mDestX(0), mDestY(0), +#ifdef TMWSERV_SUPPORT + mLocalWalkTime(-1), + mInventory(new Inventory(INVENTORY_SIZE)), + mExpMessageTime(0) +#else mInventory(new Inventory(INVENTORY_SIZE, 2)), mStorage(new Inventory(STORAGE_SIZE, 1)) +#endif { // Variable to keep the local player from doing certain actions before a map // is initialized. e.g. drawing a player's name using the TextManager, since @@ -92,7 +136,9 @@ LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map): LocalPlayer::~LocalPlayer() { delete mInventory; +#ifdef EATHENA_SUPPORT delete mStorage; +#endif for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) { @@ -105,6 +151,7 @@ LocalPlayer::~LocalPlayer() void LocalPlayer::logic() { +#ifdef EATHENA_SUPPORT switch (mAction) { case STAND: @@ -120,7 +167,7 @@ void LocalPlayer::logic() break; case WALK: - mFrame = (get_elapsed_time(mWalkTime) * 6) / mWalkSpeed; + mFrame = (get_elapsed_time(mWalkTime) * 6) / getWalkSpeed(); if (mFrame >= 6) nextStep(); break; @@ -161,11 +208,33 @@ void LocalPlayer::logic() break; } +#endif // Actions are allowed once per second if (get_elapsed_time(mLastAction) >= 1000) mLastAction = -1; +#ifdef TMWSERV_SUPPORT + // Show XP messages + if (!mExpMessages.empty()) + { + if (mExpMessageTime == 0) + { + const Vector &pos = getPosition(); + + particleEngine->addTextRiseFadeOutEffect( + mExpMessages.front(), + (int) pos.x + 16, + (int) pos.y - 16, + &guiPalette->getColor(Palette::EXP_INFO), + gui->getInfoParticleFont(), true); + + mExpMessages.pop_front(); + mExpMessageTime = 30; + } + mExpMessageTime--; + } +#else // Targeting allowed 4 times a second if (get_elapsed_time(mLastTarget) >= 250) mLastTarget = -1; @@ -180,21 +249,32 @@ void LocalPlayer::logic() if (mTarget) { - // Find whether target is in range - const int rangeX = abs(mTarget->mX - mX); - const int rangeY = abs(mTarget->mY - mY); - const int attackRange = getAttackRange(); - const int inRange = rangeX > attackRange || rangeY > attackRange ? 1 : 0; - - mTarget->setTargetAnimation( - mTargetCursor[inRange][mTarget->getTargetCursorSize()]); - - if (mTarget->mAction == DEAD) - stopAttack(); - - if (mKeepAttacking && mTarget) - attack(mTarget, true); + if (mTarget->getType() == Being::NPC) + { + // NPCs are always in range + mTarget->setTargetAnimation( + mTargetCursor[0][mTarget->getTargetCursorSize()]); + } + else + { + // Find whether target is in range + const int rangeX = abs(mTarget->mX - mX); + const int rangeY = abs(mTarget->mY - mY); + const int attackRange = getAttackRange(); + const int inRange = rangeX > attackRange || rangeY > attackRange + ? 1 : 0; + + mTarget->setTargetAnimation( + mTargetCursor[inRange][mTarget->getTargetCursorSize()]); + + if (mTarget->mAction == DEAD) + stopAttack(); + + if (mKeepAttacking && mTarget) + attack(mTarget, true); + } } +#endif Being::logic(); } @@ -225,6 +305,8 @@ void LocalPlayer::setName(const std::string &name) void LocalPlayer::nextStep() { + // TODO: Fix picking up when reaching target (this method is obsolete) + // TODO: Fix holding walking button to keep walking smoothly if (mPath.empty()) { if (mPickUpTarget) @@ -234,10 +316,13 @@ void LocalPlayer::nextStep() walk(mWalkingDir); } + // TODO: Fix automatically walking within range of target, when wanted if (mGoingToTarget && mTarget && withinAttackRange(mTarget)) { mAction = Being::STAND; +#ifdef EATHENA_SUPPORT attack(mTarget, true); +#endif mGoingToTarget = false; mPath.clear(); return; @@ -248,17 +333,99 @@ void LocalPlayer::nextStep() mPath.clear(); } +#ifdef EATHENA_SUPPORT Player::nextStep(); +#endif +} + +#ifdef TMWSERV_SUPPORT +bool LocalPlayer::checkInviteRights(const std::string &guildName) +{ + Guild *guild = getGuild(guildName); + if (guild) + { + return guild->getInviteRights(); + } + + return false; +} + +void LocalPlayer::inviteToGuild(Being *being) +{ + // TODO: Allow user to choose which guild to invite being to + // For now, just invite to the first guild you have permissions to invite with + std::map<int, Guild*>::iterator itr = mGuilds.begin(); + std::map<int, Guild*>::iterator itr_end = mGuilds.end(); + for (; itr != itr_end; ++itr) + { + if (checkInviteRights(itr->second->getName())) + { + Net::ChatServer::Guild::invitePlayer(being->getName(), itr->second->getId()); + return; + } + } +} + +void LocalPlayer::inviteToParty(const std::string &name) +{ + Net::ChatServer::Party::invitePlayer(name); +} + +void LocalPlayer::clearInventory() +{ + mEquipment->clear(); + mInventory->clear(); +} + +void LocalPlayer::setInvItem(int index, int id, int amount) +{ + mInventory->setItem(index, id, amount); +} + +#endif + +void LocalPlayer::moveInvItem(Item *item, int newIndex) +{ + // special case, the old and new cannot copy over each other. + if (item->getInvIndex() == newIndex) + return; + +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::moveItem( + item->getInvIndex(), newIndex, item->getQuantity()); +#endif + // TODO: eAthena support } void LocalPlayer::equipItem(Item *item) { +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::equip(item->getInvIndex()); +#else MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_PLAYER_EQUIP); outMsg.writeInt16(item->getInvIndex()); outMsg.writeInt16(0); +#endif +} + +#ifdef TMWSERV_SUPPORT + +void LocalPlayer::unequipItem(int slot) +{ + Net::GameServer::Player::unequip(slot); + + // Tidy equipment directly to avoid weapon still shown bug, for instance + mEquipment->setEquipment(slot, 0); +} + +void LocalPlayer::useItem(int slot) +{ + Net::GameServer::Player::useItem(slot); } +#else + void LocalPlayer::unequipItem(Item *item) { if (!item) @@ -281,48 +448,102 @@ void LocalPlayer::useItem(Item *item) // Note: id is dest of item, usually player_node->account_ID ?? } +#endif + void LocalPlayer::dropItem(Item *item, int quantity) { +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::drop(item->getInvIndex(), quantity); +#else // TODO: Fix wrong coordinates of drops, serverside? MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_PLAYER_INVENTORY_DROP); outMsg.writeInt16(item->getInvIndex()); outMsg.writeInt16(quantity); +#endif } +#ifdef TMWSERV_SUPPORT +void LocalPlayer::splitItem(Item *item, int quantity) +{ + int newIndex = mInventory->getFreeSlot(); + if (newIndex > Inventory::NO_SLOT_INDEX) + { + Net::GameServer::Player::moveItem( + item->getInvIndex(), newIndex, quantity); + } +} +#endif + void LocalPlayer::pickUp(FloorItem *item) { +#ifdef TMWSERV_SUPPORT + int dx = item->getX() - (int) getPosition().x / 32; + int dy = item->getY() - (int) getPosition().y / 32; +#else int dx = item->getX() - mX; int dy = item->getY() - mY; +#endif if (dx * dx + dy * dy < 4) { +#ifdef TMWSERV_SUPPORT + int id = item->getId(); + Net::GameServer::Player::pickUp(id >> 16, id & 0xFFFF); +#else MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_ITEM_PICKUP); outMsg.writeInt32(item->getId()); +#endif mPickUpTarget = NULL; } else { +#ifdef TMWSERV_SUPPORT + setDestination(item->getX() * 32 + 16, item->getY() * 32 + 16); +#else setDestination(item->getX(), item->getY()); +#endif mPickUpTarget = item; +#ifdef EATHENA_SUPPORT stopAttack(); +#endif } } void LocalPlayer::walk(unsigned char dir) { + // TODO: Evaluate the implementation of this method for tmwserv if (!mMap || !dir) return; +#ifdef TMWSERV_SUPPORT + const Vector &pos = getPosition(); + int dScaler; // Distance to walk +#endif + if (mAction == WALK && !mPath.empty()) { // Just finish the current action, otherwise we get out of sync +#ifdef TMWSERV_SUPPORT + Being::setDestination(pos.x, pos.y); +#else Being::setDestination(mX, mY); +#endif return; } int dx = 0, dy = 0; +#ifdef TMWSERV_SUPPORT + if (dir & UP) + dy -= 32; + if (dir & DOWN) + dy += 32; + if (dir & LEFT) + dx -= 32; + if (dir & RIGHT) + dx += 32; +#else if (dir & UP) dy--; if (dir & DOWN) @@ -331,26 +552,65 @@ void LocalPlayer::walk(unsigned char dir) dx--; if (dir & RIGHT) dx++; +#endif + // Prevent skipping corners over colliding tiles - if (dx && mMap->tileCollides(mX + dx, mY)) +#ifdef TMWSERV_SUPPORT + if (dx && !mMap->getWalk(((int) pos.x + dx) / 32, + (int) pos.y / 32, getWalkMask())) + dx = 16 - (int) pos.x % 32; + if (dy && !mMap->getWalk((int) pos.x / 32, + ((int) pos.y + dy) / 32, getWalkMask())) + dy = 16 - (int) pos.y % 32; +#else + if (dx && !mMap->getWalk(mX + dx, mY, getWalkMask())) dx = 0; - if (dy && mMap->tileCollides(mX, mY + dy)) + if (dy && !mMap->getWalk(mX, mY + dy, getWalkMask())) dy = 0; +#endif // Choose a straight direction when diagonal target is blocked - if (dx && dy && mMap->tileCollides(mX + dx, mY + dy)) +#ifdef TMWSERV_SUPPORT + if (dx && dy && !mMap->getWalk((pos.x + dx) / 32, + (pos.y + dy) / 32, getWalkMask())) + dx = 16 - (int) pos.x % 32; + + // Checks our path up to 5 tiles, if a blocking tile is found + // We go to the last good tile, and break out of the loop + for (dScaler = 1; dScaler <= 10; dScaler++) + { + if ( (dx || dy) && + !mMap->getWalk( ((int) pos.x + (dx * dScaler)) / 32, + ((int) pos.y + (dy * dScaler)) / 32, getWalkMask()) ) + { + dScaler--; + break; + } + } + + if (dScaler >= 0) + { + setDestination((int) pos.x + (dx * dScaler), (int) pos.y + (dy * dScaler)); + } +#else + if (dx && dy && !mMap->getWalk(mX + dx, mY + dy, getWalkMask())) dx = 0; // Walk to where the player can actually go - if ((dx || dy) && !mMap->tileCollides(mX + dx, mY + dy)) + if ((dx || dy) && mMap->getWalk(mX + dx, mY + dy, getWalkMask())) { setDestination(mX + dx, mY + dy); } +#endif else if (dir) { // If the being can't move, just change direction - // TODO: Communicate this to the server (waiting on tmwserv) +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::changeDir(dir); +#else + // TODO: Communicate this to the server +#endif setDirection(dir); } } @@ -362,6 +622,7 @@ Being* LocalPlayer::getTarget() const void LocalPlayer::setTarget(Being *target) { +#ifdef EATHENA_SUPPORT if (mLastTarget != -1 || target == this) return; @@ -379,32 +640,63 @@ void LocalPlayer::setTarget(Being *target) mKeepAttacking = false; mTargetTime = -1; } +#endif if (mTarget) mTarget->untarget(); if (mTarget && mTarget->getType() == Being::MONSTER) - static_cast<Monster *>(mTarget)->showName(false); + static_cast<Monster *>(mTarget)->setShowName(false); mTarget = target; if (target && target->getType() == Being::MONSTER) - static_cast<Monster *>(target)->showName(true); + static_cast<Monster *>(target)->setShowName(true); } +#ifdef TMWSERV_SUPPORT +void LocalPlayer::setDestination(int x, int y) +#else void LocalPlayer::setDestination(Uint16 x, Uint16 y) +#endif { +#ifdef TMWSERV_SUPPORT + // Fix coordinates so that the player does not seem to dig into walls. + const int tx = x / 32; + const int ty = y / 32; + int fx = x % 32; + int fy = y % 32; + + if (fx != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty, getWalkMask())) + fx = 16; + if (fy != 16 && !mMap->getWalk(tx, ty + fy / 16 * 2 - 1, getWalkMask())) + fy = 16; + if (fx != 16 && fy != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, + ty + fy / 16 * 2 - 1, + getWalkMask())) + fx = 16; + + x = tx * 32 + fx; + y = ty * 32 + fy; +#endif + // Only send a new message to the server when destination changes if (x != mDestX || y != mDestY) { mDestX = x; mDestY = y; +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::walk(x, y); + //Debugging fire burst + effectManager->trigger(15,x,y); +#else char temp[4] = ""; MessageOut outMsg(mNetwork); set_coordinates(temp, x, y, mDirection); outMsg.writeInt16(0x0085); outMsg.writeString(temp, 3); +#endif } mPickUpTarget = NULL; @@ -413,18 +705,36 @@ void LocalPlayer::setDestination(Uint16 x, Uint16 y) void LocalPlayer::setWalkingDir(int dir) { - if (mWalkingDir != dir) - { - mWalkingDir = dir; - } + mWalkingDir = dir; // If we're not already walking, start walking. - if (mAction != WALK && dir) + if (mAction != WALK && dir +#ifdef TMWSERV_SUPPORT + && get_elapsed_time(mLocalWalkTime) >= walkingKeyboardDelay +#endif + ) { walk(dir); } } +#ifdef TMWSERV_SUPPORT +void LocalPlayer::stopWalking(bool sendToServer) +{ + if (mAction == WALK && mWalkingDir) { + mWalkingDir = 0; + mLocalWalkTime = 0; + Being::setDestination(getPosition().x,getPosition().y); + if (sendToServer) + Net::GameServer::Player::walk(getPosition().x, getPosition().y); + setAction(STAND); + } + + clearPath(); +} +#endif + +#ifdef EATHENA_SUPPORT void LocalPlayer::raiseAttribute(Attribute attr) { MessageOut outMsg(mNetwork); @@ -468,6 +778,7 @@ void LocalPlayer::raiseSkill(Uint16 skillId) outMsg.writeInt16(CMSG_SKILL_LEVELUP_REQUEST); outMsg.writeInt16(skillId); } +#endif void LocalPlayer::toggleSit() { @@ -475,18 +786,23 @@ void LocalPlayer::toggleSit() return; mLastAction = tick_time; - char type; + Being::Action newAction; switch (mAction) { - case STAND: type = 2; break; - case SIT: type = 3; break; + case STAND: newAction = SIT; break; + case SIT: newAction = STAND; break; default: return; } +#ifdef TMWSERV_SUPPORT + setAction(newAction); + Net::GameServer::Player::changeAction(newAction); +#else MessageOut outMsg(mNetwork); outMsg.writeInt16(0x0089); outMsg.writeInt32(0); - outMsg.writeInt8(type); + outMsg.writeInt8((newAction == SIT) ? 2 : 3); +#endif } void LocalPlayer::emote(Uint8 emotion) @@ -495,11 +811,15 @@ void LocalPlayer::emote(Uint8 emotion) return; mLastAction = tick_time; + // XXX Convert for new server +#ifdef EATHENA_SUPPORT MessageOut outMsg(mNetwork); outMsg.writeInt16(0x00bf); outMsg.writeInt8(emotion); +#endif } +#ifdef EATHENA_SUPPORT void LocalPlayer::tradeReply(bool accept) { if (!accept) @@ -509,12 +829,21 @@ void LocalPlayer::tradeReply(bool accept) outMsg.writeInt16(CMSG_TRADE_RESPONSE); outMsg.writeInt8(accept ? 3 : 4); } +#endif void LocalPlayer::trade(Being *being) const { +#ifdef TMWSERV_SUPPORT + extern std::string tradePartnerName; + extern int tradePartnerID; + tradePartnerName = being->getName(); + tradePartnerID = being->getId(); + Net::GameServer::Player::requestTrade(tradePartnerID); +#else MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_TRADE_REQUEST); outMsg.writeInt32(being->getId()); +#endif } bool LocalPlayer::tradeRequestOk() const @@ -522,11 +851,70 @@ bool LocalPlayer::tradeRequestOk() const return !mTrading; } +#ifdef TMWSERV_SUPPORT + +void LocalPlayer::attack() +{ + if (mLastAction != -1) + return; + + // Can only attack when standing still + if (mAction != STAND && mAction != ATTACK) + return; + + //Face direction of the target + if(mTarget){ + unsigned char dir = 0; + int x = 0, y = 0; + Vector plaPos = this->getPosition(); + Vector tarPos = mTarget->getPosition(); + x = plaPos.x - tarPos.x; + y = plaPos.y - tarPos.y; + if(abs(x) < abs(y)){ + //Check to see if target is above me or below me + if(y > 0){ + dir = UP; + } else { + dir = DOWN; + } + } else { + //check to see if the target is to the left or right of me + if(x > 0){ + dir = LEFT; + } else { + dir = RIGHT; + } + } + setDirection(dir); + } + + mLastAction = tick_time; + + setAction(ATTACK); + + if (mEquippedWeapon) + { + std::string soundFile = mEquippedWeapon->getSound(EQUIP_EVENT_STRIKE); + if (soundFile != "") sound.playSfx(soundFile); + } + else { + sound.playSfx("sfx/fist-swish.ogg"); + } + Net::GameServer::Player::attack(getSpriteDirection()); +} + +void LocalPlayer::useSpecial(int special) +{ + Net::GameServer::Player::useSpecial(special); +} + +#else + void LocalPlayer::attack(Being *target, bool keep) { mKeepAttacking = keep; - if (!target) + if (!target || target->getType() == Being::NPC) return; if ((mTarget != target) || !mTarget) @@ -538,10 +926,8 @@ void LocalPlayer::attack(Being *target, bool keep) int dist_x = target->mX - mX; int dist_y = target->mY - mY; - // Must be standing and be within attack range to continue - if ((mAction != STAND) || (mAttackRange < abs(dist_x)) || - (mAttackRange < abs(dist_y))) - return; + // Must be standing to attack + if (mAction != STAND) return; if (abs(dist_y) >= abs(dist_x)) { @@ -558,9 +944,6 @@ void LocalPlayer::attack(Being *target, bool keep) setDirection(LEFT); } - // Implement charging attacks here - mLastAttackTime = 0; - mWalkTime = tick_time; mTargetTime = tick_time; @@ -597,13 +980,87 @@ void LocalPlayer::stopAttack() mLastTarget = -1; } +#endif // no TMWSERV_SUPPORT + void LocalPlayer::revive() { + // XXX Convert for new server +#ifdef EATHENA_SUPPORT MessageOut outMsg(mNetwork); outMsg.writeInt16(0x00b2); outMsg.writeInt8(0); +#endif +} + +#ifdef TMWSERV_SUPPORT + +void LocalPlayer::raiseAttribute(size_t attr) +{ + // we assume that the server allows the change. When not we will undo it later. + mCharacterPoints--; + mAttributeBase.at(attr)++; + Net::GameServer::Player::raiseAttribute(attr + CHAR_ATTR_BEGIN); +} + +void LocalPlayer::lowerAttribute(size_t attr) +{ + // we assume that the server allows the change. When not we will undo it later. + mCorrectionPoints--; + mCharacterPoints++; + mAttributeBase.at(attr)--; + Net::GameServer::Player::lowerAttribute(attr + CHAR_ATTR_BEGIN); +} + +const struct LocalPlayer::SkillInfo& LocalPlayer::getSkillInfo(int skill) +{ + static const SkillInfo skills[CHAR_SKILL_NB + 1] = + { + { _("Unarmed"), "graphics/images/unarmed.png" }, // CHAR_SKILL_WEAPON_NONE + { _("Knife"), "graphics/images/knife.png" }, // CHAR_SKILL_WEAPON_KNIFE + { _("Sword"), "graphics/images/sword.png" }, // CHAR_SKILL_WEAPON_SWORD + { _("Polearm"), "graphics/images/polearm.png" }, // CHAR_SKILL_WEAPON_POLEARM + { _("Staff"), "graphics/images/staff.png" }, // CHAR_SKILL_WEAPON_STAFF + { _("Whip"), "graphics/images/whip.png" }, // CHAR_SKILL_WEAPON_WHIP + { _("Bow"), "graphics/images/bow.png" }, // CHAR_SKILL_WEAPON_BOW + { _("Shooting"), "graphics/images/shooting.png" }, // CHAR_SKILL_WEAPON_SHOOTING + { _("Mace"), "graphics/images/mace.png" }, // CHAR_SKILL_WEAPON_MACE + { _("Axe"), "graphics/images/axe.png" }, // CHAR_SKILL_WEAPON_AXE + { _("Thrown"), "graphics/images/thrown.png" }, // CHAR_SKILL_WEAPON_THROWN + { _("Magic"), "graphics/images/magic.png" }, // CHAR_SKILL_MAGIC_IAMJUSTAPLACEHOLDER + { _("Craft"), "graphics/images/craft.png" }, // CHAR_SKILL_CRAFT_IAMJUSTAPLACEHOLDER + { _("Unknown Skill"), "graphics/images/unknown.png" } + }; + + if ((skill < 0) || (skill > CHAR_SKILL_NB)) + { + return skills[CHAR_SKILL_NB]; + } + else + { + return skills[skill]; + } } +void LocalPlayer::setExperience(int skill, int current, int next) +{ + int diff = current - mExpCurrent.at(skill); + if (mMap && mExpCurrent.at(skill) != -1 && diff > 0) + { + const std::string text = toString(diff) + " " + getSkillInfo(skill).name + " xp"; + mExpMessages.push_back(text); + } + + mExpCurrent.at(skill) = current; + mExpNext.at(skill) = next; +} + +std::pair<int, int> LocalPlayer::getExperience(int skill) +{ + return std::pair<int, int> (mExpCurrent.at(skill), mExpNext.at(skill)); +} + +#else + void LocalPlayer::setXp(int xp) { if (mMap && xp > mXp) @@ -618,7 +1075,9 @@ void LocalPlayer::setXp(int xp) mXp = xp; } -void LocalPlayer::pickedUp(std::string item) +#endif + +void LocalPlayer::pickedUp(const std::string &item) { if (mMap) { @@ -629,8 +1088,32 @@ void LocalPlayer::pickedUp(std::string item) } } +int LocalPlayer::getAttackRange() +{ +#ifdef TMWSERV_SUPPORT + Item *weapon = mEquipment->getEquipment(EQUIP_FIGHT1_SLOT); + if (weapon) + { + const ItemInfo info = weapon->getInfo(); + return info.getAttackRange(); + } + return 32; // unarmed range +#else + return mAttackRange; +#endif +} + bool LocalPlayer::withinAttackRange(Being *target) { +#ifdef TMWSERV_SUPPORT + const Vector &targetPos = target->getPosition(); + const Vector &pos = getPosition(); + const int dx = abs(targetPos.x - pos.x); + const int dy = abs(targetPos.y - pos.y); + const int range = getAttackRange(); + + return !(dx > range || dy > range); +#else int dist_x = abs(target->mX - mX); int dist_y = abs(target->mY - mY); @@ -640,14 +1123,64 @@ bool LocalPlayer::withinAttackRange(Being *target) } return true; +#endif } void LocalPlayer::setGotoTarget(Being *target) { +#ifdef TMWSERV_SUPPORT + mTarget = target; + mGoingToTarget = true; + const Vector &targetPos = target->getPosition(); + setDestination(targetPos.x, targetPos.y); +#else mLastTarget = -1; setTarget(target); mGoingToTarget = true; setDestination(target->mX, target->mY); +#endif +} + + +extern MiniStatusWindow *miniStatusWindow; + +void LocalPlayer::handleStatusEffect(StatusEffect *effect, int effectId) +{ + Being::handleStatusEffect(effect, effectId); + + + + if (effect) { + effect->deliverMessage(); + effect->playSFX(); + + AnimatedSprite *sprite = effect->getIcon(); + + if (!sprite) { + // delete sprite, if necessary + for (unsigned int i = 0; i < mStatusEffectIcons.size();) + if (mStatusEffectIcons[i] == effectId) { + mStatusEffectIcons.erase(mStatusEffectIcons.begin() + i); + miniStatusWindow->eraseIcon(i); + } else i++; + } else { + // replace sprite or append + bool found = false; + + for (unsigned int i = 0; i < mStatusEffectIcons.size(); i++) + if (mStatusEffectIcons[i] == effectId) { + miniStatusWindow->setIcon(i, sprite); + found = true; + break; + } + + if (!found) { // add new + int offset = mStatusEffectIcons.size(); + miniStatusWindow->setIcon(offset, sprite); + mStatusEffectIcons.push_back(effectId); + } + } + } } void LocalPlayer::initTargetCursor() @@ -679,7 +1212,7 @@ void LocalPlayer::loadTargetCursor(std::string filename, int width, int height, ResourceManager *resman = ResourceManager::getInstance(); currentImageSet = resman->getImageSet(filename, width, height); - Animation *anim = new Animation(); + Animation *anim = new Animation; for (unsigned int i = 0; i < currentImageSet->size(); ++i) { @@ -696,9 +1229,11 @@ void LocalPlayer::loadTargetCursor(std::string filename, int width, int height, mTargetCursor[index][size] = currentCursor; } +#ifdef EATHENA_SUPPORT void LocalPlayer::setInStorage(bool inStorage) { mInStorage = inStorage; storageWindow->setVisible(inStorage); } +#endif diff --git a/src/localplayer.h b/src/localplayer.h index bd59462e..99cb00d6 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,19 +23,106 @@ #define LOCALPLAYER_H #include <memory> +#include <vector> #include "player.h" -// TODO move into some sane place... -#define MAX_SLOT 2 - class Equipment; class FloorItem; class ImageSet; class Inventory; class Item; class Map; +#ifdef EATHENA_SUPPORT class Network; +#endif + +#ifdef TMWSERV_SUPPORT + +/** + * Attributes used during combat. Available to all the beings. + */ +enum +{ +BASE_ATTR_BEGIN = 0, + BASE_ATTR_PHY_ATK_MIN = BASE_ATTR_BEGIN, + BASE_ATTR_PHY_ATK_DELTA, + /**< Physical attack power. */ + BASE_ATTR_MAG_ATK, /**< Magical attack power. */ + BASE_ATTR_PHY_RES, /**< Resistance to physical damage. */ + BASE_ATTR_MAG_RES, /**< Resistance to magical damage. */ + BASE_ATTR_EVADE, /**< Ability to avoid hits. */ + BASE_ATTR_HIT, /**< Ability to hit stuff. */ + BASE_ATTR_HP, /**< Hit Points (Base value: maximum, Modded value: current) */ + BASE_ATTR_HP_REGEN,/**< number of HP regenerated every 10 game ticks */ + BASE_ATTR_END, + BASE_ATTR_NB = BASE_ATTR_END - BASE_ATTR_BEGIN, + + BASE_ELEM_BEGIN = BASE_ATTR_END, + BASE_ELEM_NEUTRAL = BASE_ELEM_BEGIN, + BASE_ELEM_FIRE, + BASE_ELEM_WATER, + BASE_ELEM_EARTH, + BASE_ELEM_AIR, + BASE_ELEM_SACRED, + BASE_ELEM_DEATH, + BASE_ELEM_END, + BASE_ELEM_NB = BASE_ELEM_END - BASE_ELEM_BEGIN, + + NB_BEING_ATTRIBUTES = BASE_ELEM_END +}; + +/** + * Attributes of characters. Used to derive being attributes. + */ +enum +{ + CHAR_ATTR_BEGIN = NB_BEING_ATTRIBUTES, + CHAR_ATTR_STRENGTH = CHAR_ATTR_BEGIN, + CHAR_ATTR_AGILITY, + CHAR_ATTR_DEXTERITY, + CHAR_ATTR_VITALITY, + CHAR_ATTR_INTELLIGENCE, + CHAR_ATTR_WILLPOWER, + CHAR_ATTR_END, + CHAR_ATTR_NB = CHAR_ATTR_END - CHAR_ATTR_BEGIN, + + CHAR_SKILL_BEGIN = CHAR_ATTR_END, + + CHAR_SKILL_WEAPON_BEGIN = CHAR_SKILL_BEGIN, + CHAR_SKILL_WEAPON_NONE = CHAR_SKILL_WEAPON_BEGIN, + CHAR_SKILL_WEAPON_KNIFE, + CHAR_SKILL_WEAPON_SWORD, + CHAR_SKILL_WEAPON_POLEARM, + CHAR_SKILL_WEAPON_STAFF, + CHAR_SKILL_WEAPON_WHIP, + CHAR_SKILL_WEAPON_BOW, + CHAR_SKILL_WEAPON_SHOOTING, + CHAR_SKILL_WEAPON_MACE, + CHAR_SKILL_WEAPON_AXE, + CHAR_SKILL_WEAPON_THROWN, + CHAR_SKILL_WEAPON_END, + CHAR_SKILL_WEAPON_NB = CHAR_SKILL_WEAPON_END - CHAR_SKILL_WEAPON_BEGIN, + + CHAR_SKILL_MAGIC_BEGIN = CHAR_SKILL_WEAPON_END, + CHAR_SKILL_MAGIC_IAMJUSTAPLACEHOLDER = CHAR_SKILL_MAGIC_BEGIN, + // add magic skills here + CHAR_SKILL_MAGIC_END, + CHAR_SKILL_MAGIC_NB = CHAR_SKILL_MAGIC_END - CHAR_SKILL_MAGIC_BEGIN, + + CHAR_SKILL_CRAFT_BEGIN = CHAR_SKILL_MAGIC_END, + CHAR_SKILL_CRAFT_IAMJUSTAPLACEHOLDER = CHAR_SKILL_CRAFT_BEGIN, + // add crafting skills here + CHAR_SKILL_CRAFT_END, + CHAR_SKILL_CRAFT_NB = CHAR_SKILL_CRAFT_END - CHAR_SKILL_CRAFT_BEGIN, + + CHAR_SKILL_END = CHAR_SKILL_CRAFT_END, + CHAR_SKILL_NB = CHAR_SKILL_END - CHAR_SKILL_BEGIN, + + NB_CHARACTER_ATTRIBUTES = CHAR_SKILL_END +}; + +#endif /** * The local player character. @@ -46,13 +132,21 @@ class LocalPlayer : public Player public: enum Attribute { +#ifdef TMWSERV_SUPPORT + STR = 0, AGI, DEX, VIT, INT, WIL, CHR +#else STR = 0, AGI, VIT, INT, DEX, LUK +#endif }; /** * Constructor. */ +#ifdef TMWSERV_SUPPORT + LocalPlayer(); +#else LocalPlayer(Uint32 id, Uint16 job, Map *map); +#endif /** * Destructor. @@ -60,8 +154,11 @@ class LocalPlayer : public Player ~LocalPlayer(); virtual void setName(const std::string &name); + +#ifdef EATHENA_SUPPORT void setNetwork(Network *network) { mNetwork = network; } Network *getNetwork() {return mNetwork; } +#endif virtual void logic(); /** @@ -75,10 +172,37 @@ class LocalPlayer : public Player */ Inventory* getInventory() const { return mInventory; } +#ifdef EATHENA_SUPPORT /** * Returns the player's storage */ Inventory* getStorage() const { return mStorage; } +#endif + +#ifdef TMWSERV_SUPPORT + /** + * Check the player has permission to invite users to specific guild + */ + bool checkInviteRights(const std::string &guildName); + + /** + * Invite a player to join guild + */ + void inviteToGuild(Being *being); + + /** + * Invite a player to join their party + */ + void inviteToParty(const std::string &name); + + void clearInventory(); + void setInvItem(int index, int id, int amount); +#endif + + /** + * Move the Inventory item from the old slot to the new slot. + */ + void moveInvItem(Item *item, int newIndex); /** * Equips an item. @@ -88,21 +212,37 @@ class LocalPlayer : public Player /** * Unequips an item. */ +#ifdef TMWSERV_SUPPORT + void unequipItem(int slot); +#else void unequipItem(Item *item); +#endif +#ifdef TMWSERV_SUPPORT + void useItem(int slot); +#else void useItem(Item *item); +#endif + void dropItem(Item *item, int quantity); + +#ifdef TMWSERV_SUPPORT + void splitItem(Item *item, int quantity); +#endif + void pickUp(FloorItem *item); +#ifdef EATHENA_SUPPORT /** * Sets the attack range. */ void setAttackRange(int range) { mAttackRange = range; } +#endif /** * Gets the attack range. */ - int getAttackRange() const { return mAttackRange; } + int getAttackRange(); /** * Sents a trade request to the given being. @@ -126,7 +266,12 @@ class LocalPlayer : public Player */ void setTrading(bool trading) { mTrading = trading; } +#ifdef TMWSERV_SUPPORT + void attack(); + void useSpecial(int id); +#else void attack(Being *target = NULL, bool keep = false); +#endif /** * Triggers whether or not to show the name as a GM name. @@ -136,7 +281,9 @@ class LocalPlayer : public Player */ virtual void setGM(); +#ifdef EATHENA_SUPPORT void stopAttack(); +#endif /** * Overridden to do nothing. The attacks of the local player are @@ -148,12 +295,15 @@ class LocalPlayer : public Player * @param type the attack type */ virtual void handleAttack(Being *victim, int damage, AttackType type) {} + virtual void handleAttack() {} + /** * Returns the current target of the player. Returns 0 if no being is * currently targeted. */ Being* getTarget() const; + /** * Sets the target being of the player. */ @@ -162,7 +312,11 @@ class LocalPlayer : public Player /** * Sets a new destination for this being to walk to. */ +#ifdef TMWSERV_SUPPORT + void setDestination(int x, int y); +#else virtual void setDestination(Uint16 x, Uint16 y); +#endif /** * Sets a new direction to keep walking in. @@ -170,6 +324,12 @@ class LocalPlayer : public Player void setWalkingDir(int dir); /** + * Gets the walking direction + */ + int getWalkingDir() const + { return mWalkingDir; } + + /** * Sets going to being to attack */ void setGotoTarget(Being *target); @@ -179,8 +339,26 @@ class LocalPlayer : public Player */ bool withinAttackRange(Being *target); +#ifdef EATHENA_SUPPORT void raiseAttribute(Attribute attr); void raiseSkill(Uint16 skillId); +#else + + /** + * Stops the player dead in his tracks + */ + void stopWalking(bool sendToServer = true); + + /** + * Uses a character point to raise an attribute + */ + void raiseAttribute(size_t attr); + + /** + * Uses a correction point to lower an attribute + */ + void lowerAttribute(size_t attr); +#endif void toggleSit(); void emote(Uint8 emotion); @@ -188,6 +366,12 @@ class LocalPlayer : public Player void revive(); /** + * Shows item pickup effect if the player is on a map. + */ + void pickedUp(const std::string &item); + +#ifdef EATHENA_SUPPORT + /** * Accessors for mInStorage */ bool getInStorage() { return mInStorage; } @@ -200,11 +384,6 @@ class LocalPlayer : public Player void setXp(int xp); /** - * Shows item pickup effect if the player is on a map. - */ - void pickedUp(std::string item); - - /** * Returns the amount of experience points. */ int getXp() const { return mXp; } @@ -212,16 +391,12 @@ class LocalPlayer : public Player Uint32 mCharId; /**< Used only during character selection. */ Uint32 mJobXp; - Uint16 mLevel; Uint32 mJobLevel; Uint32 mXpForNextLevel, mJobXpForNextLevel; - Uint16 mHp, mMaxHp, mMp, mMaxMp; - Uint32 mGp; + Uint16 mMp, mMaxMp; Uint16 mAttackRange; - int mTotalWeight, mMaxWeight; - Uint8 mAttr[6]; Uint8 mAttrUp[6]; @@ -230,6 +405,88 @@ class LocalPlayer : public Player Uint16 mStatPoint, mSkillPoint; Uint16 mStatsPointsToAttribute; +#endif + + int getHp() const + { return mHp; } + + int getMaxHp() const + { return mMaxHp; } + + void setHp(int value) + { mHp = value; } + + void setMaxHp(int value) + { mMaxHp = value; } + + int getLevel() const + { return mLevel; } + + void setLevel(int value) + { mLevel = value; } + +#ifdef TMWSERV_SUPPORT + void setLevelProgress(int percent) + { mLevelProgress = percent; } + + int getLevelProgress() const + { return mLevelProgress; } +#endif + + int getMoney() const + { return mMoney; } + + void setMoney(int value) + { mMoney = value; } + + int getTotalWeight() const + { return mTotalWeight; } + + void setTotalWeight(int value) + { mTotalWeight = value; } + + int getMaxWeight() const + { return mMaxWeight; } + + void setMaxWeight(int value) + { mMaxWeight = value; } + +#ifdef TMWSERV_SUPPORT + int getAttributeBase(int num) const + { return mAttributeBase[num]; } + + void setAttributeBase(int num, int value) + { mAttributeBase[num] = value; } + + int getAttributeEffective(int num) const + { return mAttributeEffective[num]; } + + void setAttributeEffective(int num, int value) + { mAttributeEffective[num] = value; } + + int getCharacterPoints() const + { return mCharacterPoints; } + + void setCharacterPoints(int n) + { mCharacterPoints = n; } + + int getCorrectionPoints() const + { return mCorrectionPoints; } + + void setCorrectionPoints(int n) + { mCorrectionPoints = n; } + + void setExperience(int skill, int current, int next); + + struct SkillInfo { + std::string name; + std::string icon; + }; + + static const SkillInfo& getSkillInfo(int skill); + + std::pair<int, int> getExperience(int skill); +#endif bool mUpdateName; /** Whether or not the name settings have changed */ @@ -240,27 +497,57 @@ class LocalPlayer : public Player const std::auto_ptr<Equipment> mEquipment; protected: + virtual void + handleStatusEffect(StatusEffect *effect, int effectId); + void walk(unsigned char dir); +#ifdef EATHENA_SUPPORT + Network *mNetwork; int mXp; /**< Experience points. */ + bool mInStorage; /**< Whether storage is currently accessible */ + int mTargetTime; /** How long the being has been targeted **/ + int mLastTarget; /** Time stamp of last targeting action, -1 if none. */ +#endif + +#ifdef TMWSERV_SUPPORT + // Character status: + std::vector<int> mAttributeBase; + std::vector<int> mAttributeEffective; + std::vector<int> mExpCurrent; + std::vector<int> mExpNext; + int mCharacterPoints; + int mCorrectionPoints; + int mLevelProgress; +#endif + int mLevel; + int mMoney; + int mTotalWeight; + int mMaxWeight; + int mHp; + int mMaxHp; - Network *mNetwork; Being *mTarget; FloorItem *mPickUpTarget; bool mTrading; - bool mInStorage; /**< Whether storage is currently accessible */ bool mGoingToTarget; bool mKeepAttacking; /** Whether or not to continue to attack */ - int mTargetTime; /** How long the being has been targeted **/ int mLastAction; /**< Time stamp of the last action, -1 if none. */ - int mLastTarget; /** Time stamp of last targeting action, -1 if none. */ int mWalkingDir; /**< The direction the player is walking in. */ int mDestX; /**< X coordinate of destination. */ int mDestY; /**< Y coordinate of destination. */ +#ifdef TMWSERV_SUPPORT + int mLocalWalkTime; /**< Timestamp used to control keyboard walk + messages flooding */ +#endif + + std::vector<int> mStatusEffectIcons; Inventory *mInventory; +#ifdef EATHENA_SUPPORT Inventory *mStorage; +#endif // Load the target cursors into memory void initTargetCursor(); @@ -276,6 +563,11 @@ class LocalPlayer : public Player /** Animated target cursors. */ SimpleAnimation *mTargetCursor[2][NUM_TC]; + +#ifdef TMWSERV_SUPPORT + std::list<std::string> mExpMessages; /**< Queued exp messages*/ + int mExpMessageTime; +#endif }; extern LocalPlayer *player_node; diff --git a/src/lockedarray.h b/src/lockedarray.h index 3ef2bb99..c4c83ea9 100644 --- a/src/lockedarray.h +++ b/src/lockedarray.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,7 +44,7 @@ class LockedArray bool isLocked() const { return mLocked; }; T getEntry() const { return mData[mCurEntry]; }; - void setEntry(T entry) { mData[mCurEntry] = entry; }; + void setEntry(T entry) { mData[mCurEntry] = entry; mFilled = true; }; void next(); void prev(); @@ -54,6 +53,11 @@ class LockedArray unsigned int getSize() const { return mSize; }; + /** + * Clears the array without changing size or data type + */ + void clear(); + protected: unsigned int mSize; @@ -61,11 +65,14 @@ class LockedArray unsigned int mCurEntry; bool mLocked; + + bool mFilled; }; template<class T> LockedArray<T>::LockedArray(unsigned int size): - mSize(size), mData(new T[size]), mCurEntry(0), mLocked(false) + mSize(size), mData(new T[size]), mCurEntry(0), mLocked(false), + mFilled(false) { std::fill_n(mData, mSize, (T)0); } @@ -106,4 +113,19 @@ void LockedArray<T>::select(unsigned int pos) mCurEntry = 0; } +template<class T> +void LockedArray<T>::clear() +{ + if (!mFilled) return; + + delete [] mData; + + mData = new T[mSize]; + + std::fill_n(mData, mSize, (T)0); + + mCurEntry = 0; + + mLocked = false; +} #endif diff --git a/src/log.cpp b/src/log.cpp index 29eeb010..75b015da 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -104,7 +103,7 @@ void Logger::log(const char *log_text, ...) if (mChatWindow) { - mChatWindow->chatLog(buf, BY_LOGGER); + localChatTab->chatLog(buf, BY_LOGGER); } // Delete temporary buffer @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/logindata.h b/src/logindata.h index 3f686a22..ae89eb5f 100644 --- a/src/logindata.h +++ b/src/logindata.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,21 +24,51 @@ #include <string> +#include <string> + struct LoginData { std::string username; std::string password; + std::string newPassword; std::string hostname; std::string updateHost; +#ifdef TMWSERV_SUPPORT + std::string email; + std::string newEmail; +#endif short port; +#ifdef EATHENA_SUPPORT int account_ID; int session_ID1; int session_ID2; char sex; +#endif bool remember; /**< Whether to store the username and host. */ bool registerLogin; /**< Whether an account is being registered. */ -}; + void clear() + { + username.clear(); + password.clear(); + newPassword.clear(); + hostname.clear(); + updateHost.clear(); +#ifdef TMWSERV_SUPPORT + email.clear(); + newEmail.clear(); #endif + port = 0; + +#ifdef EATHENA_SUPPORT + account_ID = 0; + session_ID1 = 0; + session_ID2 = 0; + sex = 0; +#endif + }; +}; + +#endif // LOGINDATA_H diff --git a/src/main.cpp b/src/main.cpp index 014154e2..2ce47ac6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,18 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <getopt.h> -#include <iostream> -#include <physfs.h> -#include <SDL_image.h> -#include <unistd.h> -#include <vector> - -#include <guichan/actionlistener.hpp> - -#include <libxml/parser.h> - -#include <SDL/SDL_ttf.h> +#include "main.h" #include "configuration.h" #include "emoteshortcut.h" @@ -43,16 +31,19 @@ #include "lockedarray.h" #include "log.h" #include "logindata.h" -#include "main.h" #ifdef USE_OPENGL #include "openglgraphics.h" #endif #include "player_relations.h" #include "serverinfo.h" #include "sound.h" +#include "statuseffect.h" +#include "units.h" #include "gui/button.h" +#ifdef EATHENA_SUPPORT #include "gui/char_server.h" +#endif #include "gui/char_select.h" #include "gui/gui.h" #include "gui/label.h" @@ -63,13 +54,35 @@ #include "gui/register.h" #include "gui/sdlinput.h" #include "gui/setup.h" +#ifdef TMWSERV_SUPPORT +#include "gui/connection.h" +#include "gui/quitdialog.h" +#include "gui/serverdialog.h" +#endif #include "gui/updatewindow.h" -#include "net/charserverhandler.h" -#include "net/loginhandler.h" -#include "net/maploginhandler.h" +#ifdef TMWSERV_SUPPORT +#include "net/tmwserv/charserverhandler.h" +#include "net/tmwserv/connection.h" +#include "net/tmwserv/loginhandler.h" +#include "net/tmwserv/logouthandler.h" +#include "net/tmwserv/network.h" +#else +#include "net/ea/charserverhandler.h" +#include "net/ea/loginhandler.h" +#include "net/ea/network.h" +#include "net/ea/maploginhandler.h" #include "net/messageout.h" -#include "net/network.h" +#endif + +#ifdef TMWSERV_SUPPORT +#include "net/tmwserv/accountserver/accountserver.h" +#include "net/tmwserv/accountserver/account.h" + +#include "net/tmwserv/chatserver/chatserver.h" + +#include "net/tmwserv/gameserver/gameserver.h" +#endif #include "resources/colordb.h" #include "resources/emotedb.h" @@ -79,8 +92,24 @@ #include "resources/npcdb.h" #include "resources/resourcemanager.h" +#ifdef TMWSERV_SUPPORT +#include "utils/dtor.h" +#endif #include "utils/gettext.h" #include "utils/stringutils.h" +#include "utils/strprintf.h" + +#include <SDL_image.h> + +#include <guichan/actionlistener.hpp> + +#include <libxml/parser.h> + +#include <getopt.h> +#include <iostream> +#include <physfs.h> +#include <unistd.h> +#include <vector> #ifdef __APPLE__ #include <CoreFoundation/CFBundle.h> @@ -109,29 +138,43 @@ namespace } listener; } +#ifdef TMWSERV_SUPPORT +std::string token; //used to store magic_token +#else // Account infos char n_server, n_character; -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; +#endif + +Graphics *graphics; unsigned char state; std::string errorMessage; -unsigned char screen_mode; Sound sound; Music *bgm; Configuration config; /**< XML file configuration reader */ +Configuration branding; /**< XML branding information reader */ Logger *logger; /**< Log object */ KeyboardConfig keyboard; +#ifdef TMWSERV_SUPPORT +Net::Connection *gameServerConnection = 0; +Net::Connection *chatServerConnection = 0; +Net::Connection *accountServerConnection = 0; +#endif + CharServerHandler charServerHandler; LoginData loginData; -LockedArray<LocalPlayer*> charInfo(MAX_SLOT + 1); +#ifdef TMWSERV_SUPPORT +LoginHandler loginHandler; +LogoutHandler logoutHandler; +#endif +LockedArray<LocalPlayer*> charInfo(maxSlot + 1); Palette *guiPalette; @@ -142,8 +185,10 @@ std::string homeDir; std::string updateHost; std::string updatesDir; +#ifdef EATHENA_SUPPORT LoginHandler loginHandler; MapLoginHandler mapLoginHandler; +#endif SDL_Surface *icon; @@ -160,8 +205,9 @@ struct Options printHelp(false), printVersion(false), skipUpdate(false), - chooseDefault(false) - {}; + chooseDefault(false), + serverPort(0) + {} bool printHelp; bool printVersion; @@ -169,10 +215,13 @@ struct Options bool chooseDefault; std::string username; std::string password; - std::string playername; + std::string character; std::string configPath; std::string updateHost; std::string dataPath; + + std::string serverName; + short serverPort; }; /** @@ -187,7 +236,7 @@ static void setUpdatesDir() if (updateHost.empty()) { updateHost = - config.getValue("updatehost", "http://www.aethyra.org/updates"); + config.getValue("updatehost", "http://updates.themanaworld.org/"); } // Remove any trailing slash at the end of the update host @@ -209,7 +258,7 @@ static void setUpdatesDir() { logger->log("Error: Invalid update host: %s", updateHost.c_str()); errorMessage = _("Invalid update host: ") + updateHost; - state = ERROR_STATE; + state = STATE_ERROR; } } else @@ -242,35 +291,39 @@ static void setUpdatesDir() logger->log("Error: %s can't be made, but doesn't exist!", newDir.c_str()); errorMessage = _("Error creating updates directory!"); - state = ERROR_STATE; + state = STATE_ERROR; } #else logger->log("Error: %s/%s can't be made, but doesn't exist!", homeDir.c_str(), updatesDir.c_str()); errorMessage = _("Error creating updates directory!"); - state = ERROR_STATE; + state = STATE_ERROR; #endif } } } /** - * 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. */ -static void init_engine(const Options &options) +static void initHomeDir() { - homeDir = std::string(PHYSFS_getUserDir()) + "/.aethyra"; + homeDir = std::string(PHYSFS_getUserDir()) + + "/." + + branding.getValue("appShort", "tmw"); #if defined WIN32 if (!CreateDirectory(homeDir.c_str(), 0) && GetLastError() != ERROR_ALREADY_EXISTS) #elif defined __APPLE__ - // Use Application Directory instead of .aethyra + // Use Application Directory instead of .tmw homeDir = std::string(PHYSFS_getUserDir()) + - "/Library/Application Support/Aethyra"; + "/Library/Application Support/" + + branding.getValue("appName", "The Mana World"); if ((mkdir(homeDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) && (errno != EEXIST)) #else - // Checking if /home/user/.Aethyra folder exists. + // Checking if /home/user/.tmw folder exists. if ((mkdir(homeDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) && (errno != EEXIST)) #endif @@ -280,20 +333,76 @@ static void init_engine(const Options &options) << std::endl; exit(1); } +} + +/** + * Initialize configuration. + */ +static void initConfiguration(const Options &options) +{ + // Fill configuration with defaults + logger->log("Initializing configuration..."); + std::string defaultHost = branding.getValue("defaultServer", + "server.themanaworld.org"); + config.setValue("host", defaultHost); +#ifdef TWMSERV_SUPPORT + int defaultPort = (int)branding.getValue("defaultPort", 9601); +#else + int defaultPort = (int)branding.getValue("defaultPort", 6901); +#endif + config.setValue("port", defaultPort); + config.setValue("hwaccel", 0); +#if (defined __APPLE__ || defined WIN32) && defined USE_OPENGL + config.setValue("opengl", 1); +#else + config.setValue("opengl", 0); +#endif + config.setValue("screen", 0); + config.setValue("sound", 1); + config.setValue("guialpha", 0.8f); + config.setValue("remember", 1); + config.setValue("sfxVolume", 100); + config.setValue("musicVolume", 60); + config.setValue("fpslimit", 0); + std::string defaultUpdateHost = branding.getValue("defaultUpdateHost", + "http://updates.themanaworld.org"); + config.setValue("updatehost", defaultUpdateHost); + config.setValue("customcursor", 1); + config.setValue("ChatLogLength", 128); + + // Checking if the configuration file exists... otherwise create it with + // default options. + FILE *configFile = 0; + std::string configPath = options.configPath; + + if (configPath.empty()) + configPath = homeDir + "/config.xml"; - // Set log file - logger->setLogFile(homeDir + std::string("/aethyra.log")); + configFile = fopen(configPath.c_str(), "r"); - #ifdef PACKAGE_VERSION - logger->log("Starting Aethyra Version %s", PACKAGE_VERSION); - #else - logger->log("Starting Aethyra - Version not defined")); - #endif + // If we can't read it, it doesn't exist ! + if (configFile == NULL) { + // We reopen the file in write mode and we create it + configFile = fopen(configPath.c_str(), "wt"); + } + if (configFile == NULL) { + std::cout << "Can't create " << configPath << ". " + << "Using Defaults." << std::endl; + } else { + fclose(configFile); + config.init(configPath); + } +} +/** + * Do all initialization stuff. + */ +static void initEngine(const Options &options) +{ // Initialize SDL logger->log("Initializing SDL..."); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { - std::cerr << _("Could not initialize SDL: ") << + std::cerr << "Could not initialize SDL: " << SDL_GetError() << std::endl; exit(1); } @@ -302,11 +411,13 @@ static void init_engine(const Options &options) SDL_EnableUNICODE(1); SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + SDL_WM_SetCaption(branding.getValue("appName", "The Mana World").c_str(), NULL); + ResourceManager *resman = ResourceManager::getInstance(); if (!resman->setWriteDir(homeDir)) { std::cout << homeDir - << _(" couldn't be set as home directory! Exiting.") + << " couldn't be set as home directory! Exiting." << std::endl; exit(1); } @@ -326,7 +437,7 @@ static void init_engine(const Options &options) if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX)) { - fprintf(stderr, _("Can't find Resources directory\n")); + fprintf(stderr, "Can't find Resources directory\n"); } CFRelease(resourcesURL); strncat(path, "/data", PATH_MAX - 1); @@ -335,51 +446,6 @@ static void init_engine(const Options &options) resman->addToSearchPath(PKG_DATADIR "data", true); #endif - // Fill configuration with defaults - logger->log("Initializing configuration..."); - config.setValue("host", "www.aethyra.org"); - config.setValue("port", 21001); - config.setValue("hwaccel", 0); -#if (defined __APPLE__ || defined WIN32) && defined USE_OPENGL - config.setValue("opengl", 1); -#else - config.setValue("opengl", 0); -#endif - config.setValue("screen", 0); - config.setValue("sound", 1); - config.setValue("guialpha", 0.8f); - config.setValue("remember", 1); - config.setValue("sfxVolume", 100); - config.setValue("musicVolume", 60); - config.setValue("fpslimit", 0); - config.setValue("updatehost", "http://www.aethyra.org/updates"); - config.setValue("customcursor", 1); - config.setValue("ChatLogLength", 128); - - // Checking if the configuration file exists... otherwise creates it with - // default options ! - FILE *configFile = 0; - std::string configPath = options.configPath; - - if (configPath.empty()) - configPath = homeDir + "/config.xml"; - - configFile = fopen(configPath.c_str(), "r"); - - // If we can't read it, it doesn't exist ! - if (configFile == NULL) { - // We reopen the file in write mode and we create it - configFile = fopen(configPath.c_str(), "wt"); - } - if (configFile == NULL) { - std::cout << "Can't create " << configPath << ". " - "Using Defaults." << std::endl; - } else { - fclose(configFile); - config.init(configPath); - } - - SDL_WM_SetCaption("Aethyra", NULL); #ifdef WIN32 static SDL_SysWMinfo pInfo; SDL_GetWMInfo(&pInfo); @@ -389,7 +455,7 @@ static void init_engine(const Options &options) SetClassLong(pInfo.window, GCL_HICON, (LONG) icon); } #else - icon = IMG_Load(PKG_DATADIR "data/icons/aethyra.png"); + icon = IMG_Load(resman->getPath(branding.getValue("appIcon", "data/icons/tmw.png")).c_str()); if (icon) { SDL_SetAlpha(icon, SDL_SRCALPHA, SDL_ALPHA_OPAQUE); @@ -404,10 +470,10 @@ static void init_engine(const Options &options) Image::setLoadAsOpenGL(useOpenGL); // Create the graphics context - graphics = useOpenGL ? new OpenGLGraphics() : new Graphics(); + graphics = useOpenGL ? new OpenGLGraphics : new Graphics; #else // Create the graphics context - graphics = new Graphics(); + graphics = new Graphics; #endif const int width = (int) config.getValue("screenwidth", defaultScreenWidth); @@ -429,13 +495,17 @@ static void init_engine(const Options &options) graphics->_beginDraw(); // Initialize the item shortcuts. - itemShortcut = new ItemShortcut(); + itemShortcut = new ItemShortcut; // Initialize the emote shortcuts. - emoteShortcut = new EmoteShortcut(); + emoteShortcut = new EmoteShortcut; gui = new Gui(graphics); - state = LOGIN_STATE; /**< Initial game state */ +#ifdef TMWSERV_SUPPORT + state = STATE_CHOOSE_SERVER; /**< Initial game state */ +#else + state = STATE_LOGIN; /**< Initial game state */ +#endif // Initialize sound engine try @@ -450,7 +520,7 @@ static void init_engine(const Options &options) } catch (const char *err) { - state = ERROR_STATE; + state = STATE_ERROR; errorMessage = err; logger->log("Warning: %s", err); } @@ -463,7 +533,7 @@ static void init_engine(const Options &options) } /** Clear the engine */ -static void exit_engine() +static void exitEngine() { // Before config.write() since it writes the shortcuts to the config delete itemShortcut; @@ -486,9 +556,9 @@ static void exit_engine() ItemDB::unload(); MonsterDB::unload(); NPCDB::unload(); + StatusEffect::unload(); ResourceManager::deleteInstance(); - delete logger; SDL_FreeSurface(icon); } @@ -496,16 +566,19 @@ static void exit_engine() static void printHelp() { std::cout - << _("aethyra") << std::endl << std::endl + << _("tmw") << std::endl << std::endl << _("Options: ") << std::endl << _(" -C --configfile : Configuration file to use") << std::endl << _(" -d --data : Directory to load game data from") << std::endl << _(" -D --default : Bypass the login process with default settings") << std::endl << _(" -h --help : Display this help") << std::endl + << _(" -S --homedir : Directory to use as home directory") << std::endl << _(" -H --updatehost : Use this update host") << std::endl - << _(" -p --playername : Login with this player") << std::endl << _(" -P --password : Login with this password") << std::endl + << _(" -c --character : Login with this character") << std::endl + << _(" -o --port : Login Server Port") << std::endl + << _(" -s --server : Login Server name or IP") << std::endl << _(" -u --skipupdate : Skip the update downloads") << std::endl << _(" -U --username : Login with this username") << std::endl << _(" -v --version : Display the version") << std::endl; @@ -514,26 +587,28 @@ static void printHelp() static void printVersion() { #ifdef PACKAGE_VERSION - std::cout << _("Aethyra version ") << PACKAGE_VERSION << - std::endl; + std::cout << _("The Mana World version ") << PACKAGE_VERSION << std::endl; #else - std::cout << _("Aethyra version ") << + std::cout << _("The Mana World version ") << _("(local build?, PACKAGE_VERSION is not defined)") << std::endl; #endif } static void parseOptions(int argc, char *argv[], Options &options) { - const char *optstring = "hvud:U:P:Dp:C:H:"; + const char *optstring = "hvud:U:P:Dc:s:o:C:H:S:"; const struct option long_options[] = { { "configfile", required_argument, 0, 'C' }, { "data", required_argument, 0, 'd' }, { "default", no_argument, 0, 'D' }, - { "playername", required_argument, 0, 'p' }, { "password", required_argument, 0, 'P' }, + { "character", required_argument, 0, 'c' }, { "help", no_argument, 0, 'h' }, + { "homedir", required_argument, 0, 'S' }, { "updatehost", required_argument, 0, 'H' }, + { "port", required_argument, 0, 'o' }, + { "server", required_argument, 0, 's' }, { "skipupdate", no_argument, 0, 'u' }, { "username", required_argument, 0, 'U' }, { "version", no_argument, 0, 'v' }, @@ -566,12 +641,18 @@ static void parseOptions(int argc, char *argv[], Options &options) case 'H': options.updateHost = optarg; break; - case 'p': - options.playername = optarg; + case 'c': + options.character = optarg; break; case 'P': options.password = optarg; break; + case 's': + options.serverName = optarg; + break; + case 'o': + options.serverPort = (short)atoi(optarg); + break; case 'u': options.skipUpdate = true; break; @@ -581,6 +662,9 @@ static void parseOptions(int argc, char *argv[], Options &options) case 'v': options.printVersion = true; break; + case 'S': + homeDir = optarg; + break; } } } @@ -610,20 +694,64 @@ struct ErrorListener : public gcn::ActionListener { void action(const gcn::ActionEvent &event) { - state = loginData.registerLogin ? REGISTER_STATE : LOGIN_STATE; +#ifdef TMWSERV_SUPPORT + state = STATE_CHOOSE_SERVER; +#else + state = loginData.registerLogin ? STATE_REGISTER : STATE_LOGIN; +#endif } } errorListener; +#ifdef TMWSERV_SUPPORT +struct AccountListener : public gcn::ActionListener +{ + void action(const gcn::ActionEvent &event) + { + state = STATE_CHAR_SELECT; + } +} accountListener; + +struct LoginListener : public gcn::ActionListener +{ + void action(const gcn::ActionEvent &event) + { + state = STATE_LOGIN; + } +} loginListener; +#endif + +} // namespace + // TODO Find some nice place for these functions +#ifdef TMWSERV_SUPPORT +static void accountLogin(LoginData *loginData) +#else static void accountLogin(Network *network, LoginData *loginData) +#endif { +#ifdef EATHENA_SUPPORT logger->log("Trying to connect to account server..."); +#endif logger->log("Username is %s", loginData->username.c_str()); +#ifdef EATHENA_SUPPORT network->connect(loginData->hostname, loginData->port); network->registerHandler(&loginHandler); +#endif loginHandler.setLoginData(loginData); +#ifdef TMWSERV_SUPPORT + Net::registerHandler(&loginHandler); + + charServerHandler.setCharInfo(&charInfo); + Net::registerHandler(&charServerHandler); +#endif // Send login infos +#ifdef TMWSERV_SUPPORT + Net::AccountServer::login(accountServerConnection, + 0, // client version + loginData->username, + loginData->password); +#else MessageOut outMsg(network); outMsg.writeInt16(0x0064); outMsg.writeInt32(0); // client version @@ -637,16 +765,19 @@ static void accountLogin(Network *network, LoginData *loginData) * 0 here. */ outMsg.writeInt8(0x01); +#endif // Clear the password, avoids auto login when returning to login loginData->password = ""; +#ifdef EATHENA_SUPPORT // Remove _M or _F from username after a login for registration purpose if (loginData->registerLogin) { loginData->username = loginData->username.substr(0, loginData->username.length() - 2); } +#endif // TODO This is not the best place to save the config, but at least better // than the login gui window @@ -658,16 +789,13 @@ static void accountLogin(Network *network, LoginData *loginData) config.setValue("remember", loginData->remember); } -inline int MIN(int x, int y) -{ - return x < y ? x : y; -} +#ifdef EATHENA_SUPPORT static void positionDialog(Window *dialog, int screenWidth, int screenHeight) { dialog->setPosition( - MIN(screenWidth * 5 / 8, screenWidth - dialog->getWidth()), - MIN(screenHeight * 5 / 8, screenHeight - dialog->getHeight())); + (screenWidth - dialog->getWidth()) / 2, + (screenHeight - dialog->getHeight()) / 2); } static void charLogin(Network *network, LoginData *loginData) @@ -719,7 +847,143 @@ static void mapLogin(Network *network, LoginData *loginData) network->skip(4); } -} // namespace +#else + +static void accountRegister(LoginData *loginData) +{ + logger->log("Username is %s", loginData->username.c_str()); + + Net::registerHandler(&loginHandler); + + charServerHandler.setCharInfo(&charInfo); + Net::registerHandler(&charServerHandler); + + Net::AccountServer::registerAccount(accountServerConnection, + 0, // client version + loginData->username, + loginData->password, + loginData->email); +} + +static void accountUnRegister(LoginData *loginData) +{ + Net::registerHandler(&logoutHandler); + + Net::AccountServer::Account::unregister(loginData->username, + loginData->password); + +} + +static void accountChangePassword(LoginData *loginData) +{ + Net::registerHandler(&loginHandler); + + Net::AccountServer::Account::changePassword(loginData->username, + loginData->password, + loginData->newPassword); +} + +static void accountChangeEmail(LoginData *loginData) +{ + Net::registerHandler(&loginHandler); + + Net::AccountServer::Account::changeEmail(loginData->newEmail); +} + +static void switchCharacter(std::string *passToken) +{ + Net::registerHandler(&logoutHandler); + + logoutHandler.reset(); + logoutHandler.setScenario(LOGOUT_SWITCH_CHARACTER, passToken); + + Net::GameServer::logout(true); + Net::ChatServer::logout(); +} + +static void switchAccountServer() +{ + Net::registerHandler(&logoutHandler); + + logoutHandler.reset(); + logoutHandler.setScenario(LOGOUT_SWITCH_ACCOUNTSERVER); + + //Can't logout if we were not logged in ... + if (accountServerConnection->isConnected()) + { + Net::AccountServer::logout(); + } + else + { + logoutHandler.setAccountLoggedOut(); + } + + if (gameServerConnection->isConnected()) + { + Net::GameServer::logout(false); + } + else + { + logoutHandler.setGameLoggedOut(); + } + + if (chatServerConnection->isConnected()) + { + Net::ChatServer::logout(); + } + else + { + logoutHandler.setChatLoggedOut(); + } +} + +static void logoutThenExit() +{ + Net::registerHandler(&logoutHandler); + + logoutHandler.reset(); + logoutHandler.setScenario(LOGOUT_EXIT); + + // Can't logout if we were not logged in ... + if (accountServerConnection->isConnected()) + { + Net::AccountServer::logout(); + } + else + { + logoutHandler.setAccountLoggedOut(); + } + + if (gameServerConnection->isConnected()) + { + Net::GameServer::logout(false); + } + else + { + logoutHandler.setGameLoggedOut(); + } + + if (chatServerConnection->isConnected()) + { + Net::ChatServer::logout(); + } + else + { + logoutHandler.setChatLoggedOut(); + } +} + +static void reconnectAccount(const std::string &passToken) +{ + Net::registerHandler(&loginHandler); + + charServerHandler.setCharInfo(&charInfo); + Net::registerHandler(&charServerHandler); + + Net::AccountServer::reconnectAccount(accountServerConnection, passToken); +} + +#endif static void initInternationalization() { @@ -737,17 +1001,30 @@ static void initInternationalization() #endif } +static void xmlNullLogger(void *ctx, const char *msg, ...) +{ + // Does nothing, that's the whole point of it +} + +// Initialize libxml2 and check for potential ABI mismatches between +// compiled version and the shared library actually used. +static void initXML() +{ + xmlInitParser(); + LIBXML_TEST_VERSION; + + // Suppress libxml2 error messages + xmlSetGenericErrorFunc(NULL, xmlNullLogger); +} + extern "C" char const *_nl_locale_name_default(void); /** Main */ int main(int argc, char *argv[]) { - logger = new Logger(); - + // Parse command line options Options options; - parseOptions(argc, argv, options); - if (options.printHelp) { printHelp(); @@ -761,36 +1038,54 @@ int main(int argc, char *argv[]) initInternationalization(); - // 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); + initXML(); - SDL_Event event; + // load branding information + branding.init("data/branding.xml"); - unsigned int oldstate = !state; // We start with a status change. + initHomeDir(); + // Configure logger + logger = new Logger(); + logger->setLogFile(homeDir + std::string("/tmw.log")); + logger->setLogToStandardOut(config.getValue("logToStandardOut", 0)); + + // Log the tmw version +#ifdef PACKAGE_VERSION +#ifdef TMWSERV_SUPPORT + logger->log("The Mana World v%s TMWServ", PACKAGE_VERSION); +#else + logger->log("The Mana World v%s eAthena", PACKAGE_VERSION); +#endif +#else + logger->log("The Mana World - version not defined"); +#endif + + initConfiguration(options); + + initEngine(options); // Needs to be created in main, as the updater uses it guiPalette = new Palette; Game *game = NULL; Window *currentDialog = NULL; +#ifdef TMWSERV_SUPPORT + QuitDialog* quitDialog = NULL; +#endif Image *login_wallpaper = NULL; - setupWindow = new Setup(); + setupWindow = new Setup; gcn::Container *top = static_cast<gcn::Container*>(gui->getTop()); #ifdef PACKAGE_VERSION - gcn::Label *versionLabel = new Label(PACKAGE_VERSION); - top->add(versionLabel, 2, 2); +#ifdef TMWSERV_SUPPORT + gcn::Label *versionLabel = new Label(strprintf("%s TMWserv", PACKAGE_VERSION)); +#else + gcn::Label *versionLabel = new Label(strprintf("%s eAthena", PACKAGE_VERSION)); +#endif + top->add(versionLabel, 25, 2); #endif ProgressBar *progressBar = new ProgressBar(0.0f, 100, 20, 168, 116, 31); gcn::Label *progressLabel = new Label(); @@ -802,7 +1097,22 @@ int main(int argc, char *argv[]) setup->setPosition(top->getWidth() - setup->getWidth() - 3, 3); top->add(setup); - sound.playMusic("Magick - Real.ogg"); + sound.playMusic(branding.getValue("loginMusic", "")); + + // Server choice + if (options.serverName.empty()) { + loginData.hostname = config.getValue("MostUsedServerName0", + branding.getValue("defaultServer", "server.themanaworld.org").c_str()); + } + else { + loginData.hostname = options.serverName; + } + if (options.serverPort == 0) { + loginData.port = (short)config.getValue("MostUsedServerPort0", + branding.getValue("defaultPort", 9601)); + } else { + loginData.port = options.serverPort; + } loginData.username = options.username; if (loginData.username.empty()) { @@ -813,18 +1123,30 @@ int main(int argc, char *argv[]) if (!options.password.empty()) { loginData.password = options.password; } - loginData.hostname = config.getValue("host", "www.aethyra.org"); - loginData.port = (short)config.getValue("port", 21001); + +#ifdef EATHENA_SUPPORT + loginData.hostname = config.getValue("host", "server.themanaworld.org"); + loginData.port = (short)config.getValue("port", 6901); +#endif loginData.remember = config.getValue("remember", 0); loginData.registerLogin = false; +#ifdef TMWSERV_SUPPORT + Net::initialize(); + accountServerConnection = Net::getConnection(); + gameServerConnection = Net::getConnection(); + chatServerConnection = Net::getConnection(); +#else SDLNet_Init(); - Network *network = new Network(); + Network *network = new Network; +#endif // Set the most appropriate wallpaper, based on screen width int screenWidth = (int) config.getValue("screenwidth", defaultScreenWidth); +#ifdef EATHENA_SUPPORT int screenHeight = static_cast<int>(config.getValue("screenheight", defaultScreenHeight)); +#endif std::string wallpaperName; wallpaperName = "graphics/images/login_wallpaper.png"; @@ -837,12 +1159,22 @@ int main(int argc, char *argv[]) else if (screenWidth >= 1600) wallpaperName = "graphics/images/login_wallpaper_1600x1200.png"; - login_wallpaper = ResourceManager::getInstance()-> getImage(wallpaperName); + if (!ResourceManager::getInstance()->exists(wallpaperName)) + wallpaperName = "graphics/images/login_wallpaper.png"; + + login_wallpaper = ResourceManager::getInstance()->getImage(wallpaperName); if (!login_wallpaper) logger->log("Couldn't load %s as wallpaper", wallpaperName.c_str()); - while (state != EXIT_STATE) + unsigned int oldstate = !state; // We start with a status change. + + SDL_Event event; +#ifdef TMWSERV_SUPPORT + while (state != STATE_FORCE_QUIT) +#else + while (state != STATE_EXIT) +#endif { // Handle SDL events while (SDL_PollEvent(&event)) @@ -850,32 +1182,50 @@ int main(int argc, char *argv[]) switch (event.type) { case SDL_QUIT: - state = EXIT_STATE; +#ifdef TMWSERV_SUPPORT + state = STATE_FORCE_QUIT; +#else + state = STATE_EXIT; +#endif break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) - state = EXIT_STATE; - + { +#ifdef TMWSERV_SUPPORT + if (!quitDialog) + quitDialog = new QuitDialog(NULL, &quitDialog); + else + quitDialog->requestMoveToTop(); +#else + state = STATE_EXIT; +#endif + } break; } guiInput->pushInput(event); } +#ifdef TMWSERV_SUPPORT + Net::flush(); +#else network->flush(); network->dispatchMessages(); +#endif gui->logic(); +#ifdef EATHENA_SUPPORT if (network->getState() == Network::NET_ERROR) { - state = ERROR_STATE; + state = STATE_ERROR; if (!network->getError().empty()) errorMessage = network->getError(); else errorMessage = _("Got disconnected from server!"); } +#endif if (progressBar->isVisible()) { @@ -887,7 +1237,7 @@ int main(int argc, char *argv[]) if (graphics->getWidth() > login_wallpaper->getWidth() || graphics->getHeight() > login_wallpaper->getHeight()) { - graphics->setColor(gcn::Color(255, 255, 255)); + graphics->setColor(gcn::Color(64, 64, 64)); graphics->fillRectangle(gcn::Rectangle( 0, 0, graphics->getWidth(), graphics->getHeight())); } @@ -897,11 +1247,320 @@ int main(int argc, char *argv[]) gui->draw(); graphics->updateScreen(); +#ifdef TMWSERV_SUPPORT + // TODO: Add connect timeouts + if (state == STATE_CONNECT_ACCOUNT && + accountServerConnection->isConnected()) + { + if (options.skipUpdate) { + state = STATE_LOADDATA; + } else { + state = STATE_UPDATE; + } + } + else if (state == STATE_CONNECT_GAME && + gameServerConnection->isConnected() && + chatServerConnection->isConnected()) + { + accountServerConnection->disconnect(); + Net::clearHandlers(); + + state = STATE_GAME; + } + else if (state == STATE_RECONNECT_ACCOUNT && + accountServerConnection->isConnected()) + { + reconnectAccount(token); + state = STATE_WAIT; + } + + if (state != oldstate) + { + // Load updates after exiting the update state + if (oldstate == STATE_UPDATE) + { + loadUpdates(); + // Reload the wallpaper in case that it was updated + login_wallpaper->decRef(); + login_wallpaper = ResourceManager::getInstance()->getImage( + branding.getValue("loginWallpaper", + "graphics/images/login_wallpaper.png")); + } + + oldstate = state; + + // Get rid of the dialog of the previous state + if (currentDialog) { + delete currentDialog; + currentDialog = NULL; + } + // State has changed, while the quitDialog was active, it might + // not be correct anymore + if (quitDialog) { + quitDialog->scheduleDelete(); + } + + switch (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 { + state = STATE_CONNECT_ACCOUNT; + + // Reset options so that cancelling or connect + // timeout will show the server dialog. + options.serverName.clear(); + options.serverPort = 0; + } + break; + + 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_SWITCH_ACCOUNTSERVER_ATTEMPT); + break; + + case STATE_UPDATE: + // Determine which source to use for the update host + if (!options.updateHost.empty()) + updateHost = options.updateHost; + else + updateHost = loginData.updateHost; + + setUpdatesDir(); + logger->log("State: UPDATE"); + currentDialog = new UpdaterWindow(updateHost, + homeDir + "/" + updatesDir); + break; + + case STATE_LOGIN: + logger->log("State: LOGIN"); + if (options.username.empty() + || options.password.empty()) { + currentDialog = new LoginDialog(&loginData); + } else { + state = STATE_LOGIN_ATTEMPT; + // Clear the password so that when login fails, the + // dialog will show up next time. + options.password.clear(); + } + break; + + case STATE_LOADDATA: + logger->log("State: LOADDATA"); + + // Add customdata directory + ResourceManager::getInstance()->searchAndAddArchives( + "customdata/", + "zip", + false); + + // Load XML databases + ColorDB::load(); + ItemDB::load(); + MonsterDB::load(); + NPCDB::load(); + EmoteDB::load(); + Units::loadUnits(); + + state = STATE_LOGIN; + break; + + case STATE_LOGIN_ATTEMPT: + accountLogin(&loginData); + break; + + case STATE_LOGIN_ERROR: + logger->log("State: LOGIN ERROR"); + currentDialog = new OkDialog("Error ", errorMessage); + currentDialog->addActionListener(&loginListener); + currentDialog = NULL; // OkDialog deletes itself + break; + + case STATE_SWITCH_ACCOUNTSERVER: + logger->log("State: SWITCH_ACCOUNTSERVER"); + + gameServerConnection->disconnect(); + chatServerConnection->disconnect(); + accountServerConnection->disconnect(); + + state = STATE_CHOOSE_SERVER; + break; + + case STATE_SWITCH_ACCOUNTSERVER_ATTEMPT: + logger->log("State: SWITCH_ACCOUNTSERVER_ATTEMPT"); + switchAccountServer(); + + state = STATE_SWITCH_ACCOUNTSERVER; + break; + + case STATE_REGISTER: + logger->log("State: REGISTER"); + currentDialog = new RegisterDialog(&loginData); + break; + + case STATE_REGISTER_ATTEMPT: + accountRegister(&loginData); + break; + + case STATE_CHAR_SELECT: + logger->log("State: CHAR_SELECT"); + currentDialog = + new CharSelectDialog(&charInfo, &loginData); + + if (((CharSelectDialog*) currentDialog)-> + selectByName(options.character)) { + ((CharSelectDialog*) currentDialog)->action( + gcn::ActionEvent(NULL, "ok")); + } else { + ((CharSelectDialog*) currentDialog)->selectByName( + config.getValue("lastCharacter", "")); + } + + break; + + case STATE_CHANGEEMAIL_ATTEMPT: + logger->log("State: CHANGE EMAIL ATTEMPT"); + accountChangeEmail(&loginData); + break; + + case STATE_CHANGEEMAIL: + logger->log("State: CHANGE EMAIL"); + currentDialog = new OkDialog("Email Address change", + "Email Address changed successfully!"); + currentDialog->addActionListener(&accountListener); + currentDialog = NULL; // OkDialog deletes itself + loginData.email = loginData.newEmail; + loginData.newEmail = ""; + break; + + case STATE_CHANGEPASSWORD_ATTEMPT: + logger->log("State: CHANGE PASSWORD ATTEMPT"); + accountChangePassword(&loginData); + break; + + case STATE_CHANGEPASSWORD: + logger->log("State: CHANGE PASSWORD"); + currentDialog = new OkDialog("Password change", + "Password changed successfully!"); + currentDialog->addActionListener(&accountListener); + currentDialog = NULL; // OkDialog deletes itself + loginData.password = loginData.newPassword; + loginData.newPassword = ""; + break; + + case STATE_UNREGISTER_ATTEMPT: + logger->log("State: UNREGISTER ATTEMPT"); + accountUnRegister(&loginData); + break; + + case STATE_UNREGISTER: + logger->log("State: UNREGISTER"); + accountServerConnection->disconnect(); + currentDialog = new OkDialog("Unregister successful", + "Farewell, come back any time ...."); + loginData.clear(); + //The errorlistener sets the state to STATE_CHOOSE_SERVER + currentDialog->addActionListener(&errorListener); + currentDialog = NULL; // OkDialog deletes itself + break; + + case STATE_ACCOUNTCHANGE_ERROR: + logger->log("State: ACCOUNT CHANGE ERROR"); + currentDialog = new OkDialog("Error ", errorMessage); + currentDialog->addActionListener(&accountListener); + currentDialog = NULL; // OkDialog deletes itself + break; + + + case STATE_ERROR: + logger->log("State: ERROR"); + currentDialog = new OkDialog("Error", errorMessage); + currentDialog->addActionListener(&errorListener); + currentDialog = NULL; // OkDialog deletes itself + gameServerConnection->disconnect(); + chatServerConnection->disconnect(); + Net::clearHandlers(); + break; + + case STATE_CONNECT_GAME: + logger->log("State: CONNECT_GAME"); + currentDialog = new ConnectionDialog(STATE_SWITCH_ACCOUNTSERVER_ATTEMPT); + break; + + case STATE_GAME: + logger->log("Memorizing selected character %s", + player_node->getName().c_str()); + config.setValue("lastCharacter", player_node->getName()); + + Net::GameServer::connect(gameServerConnection, token); + Net::ChatServer::connect(chatServerConnection, token); + sound.fadeOutMusic(1000); + +#ifdef PACKAGE_VERSION + delete versionLabel; + versionLabel = NULL; +#endif + currentDialog = NULL; + + logger->log("State: GAME"); + game = new Game; + game->logic(); + delete game; + + // If the quitdialog didn't set the next state + if (state == STATE_GAME) + { + state = STATE_EXIT; + } + break; + + case STATE_SWITCH_CHARACTER: + logger->log("State: SWITCH_CHARACTER"); + switchCharacter(&token); + break; + + case STATE_RECONNECT_ACCOUNT: + logger->log("State: RECONNECT_ACCOUNT"); + + // Done with game & chat + gameServerConnection->disconnect(); + chatServerConnection->disconnect(); + + accountServerConnection->connect( + loginData.hostname, + loginData.port); + break; + + case STATE_WAIT: + break; + + case STATE_EXIT: + logger->log("State: EXIT"); + logoutThenExit(); + break; + + default: + state = STATE_FORCE_QUIT; + break; + } + } + +#else // no TMWSERV_SUPPORT + if (state != oldstate) { switch (oldstate) { - case UPDATE_STATE: + case STATE_UPDATE: loadUpdates(); // Reload the wallpaper in case that it was updated login_wallpaper->decRef(); @@ -910,12 +1569,12 @@ int main(int argc, char *argv[]) break; // Those states don't cause a network disconnect - case LOADDATA_STATE: + case STATE_LOADDATA: break; - case ACCOUNT_STATE: - case CHAR_CONNECT_STATE: - case CONNECTING_STATE: + case STATE_ACCOUNT: + case STATE_CHAR_CONNECT: + case STATE_CONNECTING: progressBar->setVisible(false); progressLabel->setCaption(""); break; @@ -928,8 +1587,8 @@ int main(int argc, char *argv[]) oldstate = state; - if (currentDialog && state != ACCOUNT_STATE && - state != CHAR_CONNECT_STATE) + if (currentDialog && state != STATE_ACCOUNT && + state != STATE_CHAR_CONNECT) { delete currentDialog; currentDialog = NULL; @@ -937,7 +1596,7 @@ int main(int argc, char *argv[]) switch (state) { - case LOADDATA_STATE: + case STATE_LOADDATA: logger->log("State: LOADDATA"); // Add customdata directory @@ -952,18 +1611,22 @@ int main(int argc, char *argv[]) MonsterDB::load(); NPCDB::load(); EmoteDB::load(); + StatusEffect::load(); Being::load(); // Hairstyles - state = CHAR_CONNECT_STATE; + // Load units + Units::loadUnits(); + + state = STATE_CHAR_CONNECT; break; - case LOGIN_STATE: + case STATE_LOGIN: logger->log("State: LOGIN"); if (!loginData.password.empty()) { loginData.registerLogin = false; - state = ACCOUNT_STATE; + state = STATE_ACCOUNT; } else { @@ -973,13 +1636,13 @@ int main(int argc, char *argv[]) } break; - case REGISTER_STATE: + case STATE_REGISTER: logger->log("State: REGISTER"); currentDialog = new RegisterDialog(&loginData); positionDialog(currentDialog, screenWidth, screenHeight); break; - case CHAR_SERVER_STATE: + case STATE_CHAR_SERVER: logger->log("State: CHAR_SERVER"); if (n_server == 1) @@ -988,32 +1651,32 @@ int main(int argc, char *argv[]) loginData.hostname = ipToString(si->address); loginData.port = si->port; loginData.updateHost = si->updateHost; - state = UPDATE_STATE; + state = STATE_UPDATE; } else { - int nextState = UPDATE_STATE; + int nextState = STATE_UPDATE; currentDialog = new ServerSelectDialog(&loginData, nextState); positionDialog(currentDialog, screenWidth, screenHeight); if (options.chooseDefault - || !options.playername.empty()) + || !options.character.empty()) { ((ServerSelectDialog*) currentDialog)->action( gcn::ActionEvent(NULL, "ok")); } } break; - case CHAR_SELECT_STATE: + case STATE_CHAR_SELECT: logger->log("State: CHAR_SELECT"); currentDialog = new CharSelectDialog(network, &charInfo, - (loginData.sex == 0) ? - GENDER_FEMALE : GENDER_MALE); + (loginData.sex == 0) ? + GENDER_FEMALE : GENDER_MALE); positionDialog(currentDialog, screenWidth, screenHeight); if (((CharSelectDialog*) currentDialog)-> - selectByName(options.playername)) + selectByName(options.character)) options.chooseDefault = true; else ((CharSelectDialog*) currentDialog)->selectByName( @@ -1025,7 +1688,7 @@ int main(int argc, char *argv[]) break; - case GAME_STATE: + case STATE_GAME: sound.fadeOutMusic(1000); #ifdef PACKAGE_VERSION @@ -1046,13 +1709,13 @@ int main(int argc, char *argv[]) game = new Game(network); game->logic(); delete game; - state = EXIT_STATE; + state = STATE_EXIT; break; - case UPDATE_STATE: + case STATE_UPDATE: if (options.skipUpdate) { - state = LOADDATA_STATE; + state = STATE_LOADDATA; } else { @@ -1072,7 +1735,7 @@ int main(int argc, char *argv[]) } break; - case ERROR_STATE: + case STATE_ERROR: logger->log("State: ERROR"); currentDialog = new OkDialog(_("Error"), errorMessage); positionDialog(currentDialog, screenWidth, screenHeight); @@ -1082,7 +1745,7 @@ int main(int argc, char *argv[]) network->clearHandlers(); break; - case CONNECTING_STATE: + case STATE_CONNECTING: logger->log("State: CONNECTING"); progressBar->setVisible(true); progressLabel->setCaption( @@ -1091,7 +1754,7 @@ int main(int argc, char *argv[]) mapLogin(network, &loginData); break; - case CHAR_CONNECT_STATE: + case STATE_CHAR_CONNECT: progressBar->setVisible(true); progressLabel->setCaption( _("Connecting to character server...")); @@ -1099,7 +1762,7 @@ int main(int argc, char *argv[]) charLogin(network, &loginData); break; - case ACCOUNT_STATE: + case STATE_ACCOUNT: progressBar->setVisible(true); progressLabel->setCaption( _("Connecting to account server...")); @@ -1108,10 +1771,11 @@ int main(int argc, char *argv[]) break; default: - state = EXIT_STATE; + state = STATE_EXIT; break; } } +#endif /* * This loop can really stress the CPU, for no reason since it's * just constantly redrawing the wallpaper. Added the following @@ -1129,15 +1793,28 @@ int main(int argc, char *argv[]) delete setup; delete setupWindow; +#ifdef TMWSERV_SUPPORT + if (accountServerConnection) + accountServerConnection->disconnect(); + if (gameServerConnection) + gameServerConnection->disconnect(); + if (chatServerConnection) + chatServerConnection->disconnect(); + + delete accountServerConnection; + delete gameServerConnection; + delete chatServerConnection; + Net::finalize(); +#else delete network; SDLNet_Quit(); +#endif - if (nullFile) - fclose(nullFile); - - logger->log("State: EXIT"); - exit_engine(); + logger->log("Quitting"); + exitEngine(); PHYSFS_deinit(); + delete logger; + return 0; } @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +22,35 @@ #ifndef MAIN_H #define MAIN_H +/** + * \mainpage + * + * \section Introduction Introduction + * + * This is the documentation for the client of The Mana World + * (http://themanaworld.org). It is always a work in progress, with the intent + * to make it easier for new developers to grow familiar with the source code. + * + * \section General General information + * + * During the game, the current Map is displayed by the main Viewport, which + * is the bottom-most widget in the WindowContainer. Aside the viewport, the + * window container keeps track of all the \link Window Windows\endlink + * displayed during the game. It is the <i>top</i> widget for Guichan. + * + * A Map is composed of several layers of \link Image Images\endlink (tiles), + * a layer with collision information and \link Sprite Sprites\endlink. The + * sprites define the visible part of \link Being Beings\endlink and + * \link FloorItem FloorItems\endlink, they are drawn from top to bottom + * by the map, interleaved with the tiles in the fringe layer. + * + * The server is split up into an \link Net::AccountServer account + * server\endlink, a \link Net::ChatServer chat server\endlink and a \link + * Net::GameServer game server\endlink. There may be multiple game servers. + * Handling of incoming messages is spread over several \link MessageHandler + * MessageHanders\endlink. + */ + #include <string> #ifdef HAVE_CONFIG_H @@ -41,20 +69,43 @@ * Client different States */ enum { - EXIT_STATE, - LOADDATA_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_EXIT, + STATE_LOADDATA, + STATE_LOGIN, + STATE_REGISTER, + STATE_CHAR_SELECT, + STATE_GAME, + STATE_ERROR, + STATE_UPDATE, +#ifdef TMWSERV_SUPPORT + STATE_CHOOSE_SERVER, + STATE_CONNECT_ACCOUNT, + STATE_LOGIN_ATTEMPT, + STATE_LOGIN_ERROR, + STATE_REGISTER_ATTEMPT, + STATE_ACCOUNTCHANGE_ERROR, + STATE_CHANGEEMAIL_ATTEMPT, + STATE_CHANGEEMAIL, + STATE_CHANGEPASSWORD_ATTEMPT, + STATE_CHANGEPASSWORD, + STATE_UNREGISTER_ATTEMPT, + STATE_UNREGISTER, + STATE_SWITCH_CHARACTER, + STATE_RECONNECT_ACCOUNT, + STATE_SWITCH_ACCOUNTSERVER_ATTEMPT, + STATE_SWITCH_ACCOUNTSERVER, + STATE_LOGOUT_ATTEMPT, + STATE_CONNECT_GAME, + STATE_WAIT, + STATE_FORCE_QUIT +#else + STATE_ACCOUNT, + STATE_CHAR_CONNECT, + STATE_CHAR_SERVER, + STATE_CHAR_NEW, + STATE_CHAR_DEL, + STATE_CONNECTING +#endif }; /* length definitions for several char[]s in order @@ -77,7 +128,15 @@ const short defaultScreenHeight = 600; const short defaultSfxVolume = 100; const short defaultMusicVolume = 60; +// Defines the number of usable player slots +const short maxSlot = 2; + +#ifdef TMWSERV_SUPPORT +extern std::string token; +#else extern char n_server, n_character; +#endif + extern unsigned char state; extern std::string errorMessage; diff --git a/src/map.cpp b/src/map.cpp index 877a8ba9..551c10f3 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -142,7 +141,11 @@ void MapLayer::draw(Graphics *graphics, int startX, int startY, // tiles have been drawn if (mIsFringeLayer) { +#ifdef TMWSERV_SUPPORT + while (si != sprites.end() && (*si)->getPixelY() <= y * 32) +#else while (si != sprites.end() && (*si)->getPixelY() <= y * 32 - 32) +#endif { (*si)->draw(graphics, -scrollX, -scrollY); si++; @@ -182,12 +185,21 @@ Map::Map(int width, int height, int tileWidth, int tileHeight): const int size = mWidth * mHeight; mMetaTiles = new MetaTile[size]; + for (int i = 0; i < NB_BLOCKTYPES; i++) + { + mOccupation[i] = new int[size]; + memset(mOccupation[i], 0, size * sizeof(int)); + } } Map::~Map() { // delete metadata, layers, tilesets and overlays delete[] mMetaTiles; + for (int i = 0; i < NB_BLOCKTYPES; i++) + { + delete[] mOccupation[i]; + } delete_all(mLayers); delete_all(mTilesets); delete_all(mOverlays); @@ -278,6 +290,59 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY) (int) config.getValue("OverlayDetail", 2)); } +void Map::drawCollision(Graphics *graphics, int scrollX, int scrollY) +{ + int endPixelY = graphics->getHeight() + scrollY + mTileHeight - 1; + int startX = scrollX / mTileWidth; + int startY = scrollY / mTileHeight; + int endX = (graphics->getWidth() + scrollX + mTileWidth - 1) / mTileWidth; + int endY = endPixelY / mTileHeight; + + if (startX < 0) startX = 0; + if (startY < 0) startY = 0; + if (endX > mWidth) endX = mWidth; + if (endY > mHeight) endY = mHeight; + + for (int y = startY; y < endY; y++) + { + for (int x = startX; x < endX; x++) + { + graphics->setColor(gcn::Color(0, 0, 0, 64)); + graphics->drawRectangle(gcn::Rectangle( + x * mTileWidth - scrollX, + y * mTileWidth - scrollY, + 33, 33)); + + if (!getWalk(x, y, BLOCKMASK_WALL)) + { + graphics->setColor(gcn::Color(0, 0, 200, 64)); + graphics->fillRectangle(gcn::Rectangle( + x * mTileWidth - scrollX, + y * mTileWidth - scrollY, + 32, 32)); + } + + if (!getWalk(x, y, BLOCKMASK_MONSTER)) + { + graphics->setColor(gcn::Color(200, 0, 0, 64)); + graphics->fillRectangle(gcn::Rectangle( + x * mTileWidth - scrollX, + y * mTileWidth - scrollY, + 32, 32)); + } + + if (!getWalk(x, y, BLOCKMASK_CHARACTER)) + { + graphics->setColor(gcn::Color(0, 200, 0, 64)); + graphics->fillRectangle(gcn::Rectangle( + x * mTileWidth - scrollX, + y * mTileWidth - scrollY, + 32, 32)); + } + } + } +} + void Map::drawOverlay(Graphics *graphics, float scrollX, float scrollY, int detail) { @@ -334,34 +399,46 @@ Tileset* Map::getTilesetWithGid(int gid) const containsGid.gid = gid; Tilesets::const_iterator i = find_if(mTilesets.begin(), mTilesets.end(), - containsGid); + containsGid); return (i == mTilesets.end()) ? NULL : *i; } -void Map::setWalk(int x, int y, bool walkable) +void Map::blockTile(int x, int y, BlockType type) { - mMetaTiles[x + y * mWidth].walkable = walkable; -} - -bool Map::occupied(int x, int y) const -{ - Beings &beings = beingManager->getAll(); - for (BeingIterator i = beings.begin(); i != beings.end(); i++) + if (type == BLOCKTYPE_NONE || !contains(x, y)) + return; + + int tileNum = x + y * mWidth; + + if ((++mOccupation[type][tileNum]) > 0) { - // job 45 is a portal, they don't collide - if ((*i)->mX == x && (*i)->mY == y && (*i)->mJob != 45) + switch (type) { - return true; + case BLOCKTYPE_WALL: + mMetaTiles[tileNum].blockmask |= BLOCKMASK_WALL; + break; + case BLOCKTYPE_CHARACTER: + mMetaTiles[tileNum].blockmask |= BLOCKMASK_CHARACTER; + break; + case BLOCKTYPE_MONSTER: + mMetaTiles[tileNum].blockmask |= BLOCKMASK_MONSTER; + break; + default: + // shut up! + break; } } - - return false; } -bool Map::tileCollides(int x, int y) const +bool Map::getWalk(int x, int y, char walkmask) const { - return !(contains(x, y) && mMetaTiles[x + y * mWidth].walkable); + // You can't walk outside of the map + if (!contains(x, y)) + return false; + + // Check if the tile is walkable + return !(mMetaTiles[x + y * mWidth].blockmask & walkmask); } bool Map::contains(int x, int y) const @@ -369,7 +446,7 @@ bool Map::contains(int x, int y) const return x >= 0 && y >= 0 && x < mWidth && y < mHeight; } -MetaTile* Map::getMetaTile(int x, int y) +MetaTile* Map::getMetaTile(int x, int y) const { return &mMetaTiles[x + y * mWidth]; } @@ -385,7 +462,9 @@ void Map::removeSprite(SpriteIterator iterator) mSprites.erase(iterator); } -Path Map::findPath(int startX, int startY, int destX, int destY) +static int const basicCost = 100; + +Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char walkmask, int maxCost) { // Path to be built up (empty by default) Path path; @@ -393,6 +472,9 @@ Path Map::findPath(int startX, int startY, int destX, int destY) // Declare open list, a list with open tiles sorted on F cost std::priority_queue<Location> openList; + // Return when destination not walkable + if (!getWalk(destX, destY, walkmask)) return path; + // Reset starting tile's G cost to 0 MetaTile *startTile = getMetaTile(startX, startY); startTile->Gcost = 0; @@ -437,35 +519,55 @@ Path Map::findPath(int startX, int startY, int destX, int destY) MetaTile *newTile = getMetaTile(x, y); - // Skip if the tile is on the closed list or collides unless - // its the destination tile + // Skip if the tile is on the closed list or is not walkable + // unless its the destination tile if (newTile->whichList == mOnClosedList || - (tileCollides(x, y) && !(x == destX && y == destY))) + ((newTile->blockmask & walkmask) && !(x == destX && y == destY))) { continue; } // When taking a diagonal step, verify that we can skip the - // corner. We allow skipping past beings but not past non- - // walkable tiles. + // corner. if (dx != 0 && dy != 0) { MetaTile *t1 = getMetaTile(curr.x, curr.y + dy); MetaTile *t2 = getMetaTile(curr.x + dx, curr.y); - if (!(t1->walkable && t2->walkable)) + if (t1->blockmask & walkmask && !(t2->blockmask & walkmask)) // I hope I didn't fuck this line up { continue; } } - // Calculate G cost for this route, 10 for moving straight and - // 14 for moving diagonal (sqrt(200) = 14.1421...) - 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; + } + + // It costs extra to walk through a being (needs to be enough + // to make it more attractive to walk around). + if (!getWalk(x, y, BLOCKMASK_CHARACTER | BLOCKMASK_MONSTER)) + { + Gcost += 3 * basicCost; + } // Skip if Gcost becomes too much // Warning: probably not entirely accurate - if (Gcost > 200) + if (Gcost > maxCost * basicCost) { continue; } @@ -473,8 +575,14 @@ Path 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; @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,7 +53,7 @@ struct MetaTile /** * Constructor. */ - MetaTile():whichList(0) {}; + MetaTile():whichList(0), blockmask(0) {}; // Pathfinding members int Fcost; /**< Estimation of total path cost */ @@ -63,7 +62,7 @@ struct MetaTile int whichList; /**< No list, open list or closed list */ int parentX; /**< X coordinate of parent tile */ int parentY; /**< Y coordinate of parent tile */ - bool walkable; /**< Can beings walk on this tile */ + unsigned char blockmask; /**< Blocking properties of this tile */ }; /** @@ -144,6 +143,15 @@ class MapLayer class Map : public Properties { public: + enum BlockType + { + BLOCKTYPE_NONE = -1, + BLOCKTYPE_WALL, + BLOCKTYPE_CHARACTER, + BLOCKTYPE_MONSTER, + NB_BLOCKTYPES + }; + /** * Constructor, taking map and tile size as parameters. */ @@ -176,6 +184,11 @@ class Map : public Properties void draw(Graphics *graphics, int scrollX, int scrollY); /** + * Visualizes collision layer for debugging + */ + void drawCollision(Graphics *graphics, int scrollX, int scrollY); + + /** * Adds a layer to this map. The map takes ownership of the layer. */ void addLayer(MapLayer *layer); @@ -193,17 +206,18 @@ class Map : public Properties /** * Get tile reference. */ - MetaTile *getMetaTile(int x, int y); + MetaTile *getMetaTile(int x, int y) const; /** - * Set walkability flag for a tile. + * Marks a tile as occupied */ - void setWalk(int x, int y, bool walkable); + void blockTile(int x, int y, BlockType type); /** - * Tell if a tile collides, not including a check on beings. + * Gets walkability for a tile with a blocking bitmask. When called + * without walkmask, only blocks against colliding tiles. */ - bool tileCollides(int x, int y) const; + bool getWalk(int x, int y, char walkmask = BLOCKMASK_WALL) const; /** * Returns the width of this map. @@ -228,7 +242,8 @@ class Map : public Properties /** * Find a path from one location to the next. */ - Path findPath(int startX, int startY, int destX, int destY); + Path findPath(int startX, int startY, int destX, int destY, + unsigned char walkmask, int maxCost = 20); /** * Adds a sprite to the map. @@ -269,14 +284,17 @@ class Map : public Properties int detail); /** - * Tells whether a tile is occupied by a being. + * Tells whether the given coordinates fall within the map boundaries. */ - bool occupied(int x, int y) const; + bool contains(int x, int y) const; /** - * Tells whether the given coordinates fall within the map boundaries. + * Blockmasks for different entities */ - bool contains(int x, int y) const; + static const unsigned char BLOCKMASK_WALL = 0x80; // = bin 1000 0000 + static const unsigned char BLOCKMASK_CHARACTER = 0x01;// = bin 0000 0001 + static const unsigned char BLOCKMASK_MONSTER = 0x02; // = bin 0000 0010 + int *mOccupation[NB_BLOCKTYPES]; int mWidth, mHeight; int mTileWidth, mTileHeight; diff --git a/src/monster.cpp b/src/monster.cpp index f71457df..eaea6225 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +39,7 @@ Monster::Monster(int id, Uint16 job, Map *map): Being(id, job, map), mText(0) { - const MonsterInfo& info = MonsterDB::get(job - 1002); + const MonsterInfo& info = getInfo(); // Setup Monster sprites int c = BASE_SPRITE; @@ -82,11 +81,12 @@ Monster::~Monster() delete mText; } +#ifdef EATHENA_SUPPORT void Monster::logic() { if (mAction != STAND) { - mFrame = (get_elapsed_time(mWalkTime) * 4) / mWalkSpeed; + mFrame = (get_elapsed_time(mWalkTime) * 4) / getWalkSpeed(); if (mFrame >= 4 && mAction != DEAD) { @@ -96,13 +96,14 @@ void Monster::logic() Being::logic(); } +#endif Being::Type Monster::getType() const { return MONSTER; } -void Monster::setAction(Action action) +void Monster::setAction(Action action, int attackType) { SpriteAction currentAction = ACTION_INVALID; int rotation = 0; @@ -118,11 +119,11 @@ void Monster::setAction(Action action) sound.playSfx(getInfo().getSound(MONSTER_EVENT_DIE)); break; case ATTACK: - currentAction = ACTION_ATTACK; + currentAction = getInfo().getAttackAction(attackType); mSprites[BASE_SPRITE]->reset(); //attack particle effect - particleEffect = getInfo().getAttackParticleEffect(); + particleEffect = getInfo().getAttackParticleEffect(attackType); if (!particleEffect.empty() && mParticleEffects) { switch (mDirection) @@ -163,6 +164,22 @@ void Monster::setAction(Action action) } } +#ifdef TMWSERV_SUPPORT + +void Monster::handleAttack() +{ + Being::handleAttack(); + + const MonsterInfo &mi = getInfo(); + + // TODO: It's not possible to determine hit or miss here, so this stuff + // probably needs to be moved somewhere else. We may lose synchronization + // between attack animation and the sound, unless we adapt the protocol... + sound.playSfx(mi.getSound(MONSTER_EVENT_HIT)); +} + +#else + void Monster::handleAttack(Being *victim, int damage, AttackType type) { Being::handleAttack(victim, damage, type); @@ -172,6 +189,8 @@ void Monster::handleAttack(Being *victim, int damage, AttackType type) MONSTER_EVENT_HIT : MONSTER_EVENT_MISS)); } +#endif + void Monster::takeDamage(Being *attacker, int amount, AttackType type) { if (amount > 0) sound.playSfx(getInfo().getSound(MONSTER_EVENT_HURT)); @@ -185,15 +204,17 @@ Being::TargetCursorSize Monster::getTargetCursorSize() const const MonsterInfo &Monster::getInfo() const { +#ifdef TMWSERV_SUPPORT + return MonsterDB::get(mJob); +#else return MonsterDB::get(mJob - 1002); +#endif } -void Monster::showName(bool show) +void Monster::setShowName(bool show) { - if (mText) - { - delete mText; - } + delete mText; + if (show) { mText = new Text(getInfo().getName(), mPx + NAME_X_OFFSET, diff --git a/src/monster.h b/src/monster.h index afb55769..cd2a8f0c 100644 --- a/src/monster.h +++ b/src/monster.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,9 +34,11 @@ class Monster : public Being ~Monster(); +#ifdef EATHENA_SUPPORT virtual void logic(); +#endif - virtual void setAction(Action action); + virtual void setAction(Action action, int attackType = 0); virtual Type getType() const; @@ -52,7 +53,11 @@ class Monster : public Being * @param damage the amount of damage dealt (0 means miss) * @param type the attack type */ +#ifdef TMWSERV_SUPPORT + virtual void handleAttack(); +#else virtual void handleAttack(Being *victim, int damage, AttackType type); +#endif /** * Puts a damage bubble above this monster and plays the hurt sound @@ -71,10 +76,22 @@ class Monster : public Being /** * Determine whether the mob should show it's name */ - void showName(bool show); + void setShowName(bool show); + + /** + * Gets the way the monster is blocked by other objects + */ + virtual unsigned char getWalkMask() const + { return 0x83; } // blocked by walls, other monsters and players ( bin 1000 0011) protected: /** + * Gets the way the monster blocks pathfinding for other objects + */ + virtual Map::BlockType getBlockType() const + { return Map::BLOCKTYPE_MONSTER; } + + /** * Update the text when the monster moves */ void updateCoords(); diff --git a/src/net/beinghandler.cpp b/src/net/ea/beinghandler.cpp index d1810537..237c9f1f 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/ea/beinghandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,21 +19,27 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "net/ea/beinghandler.h" + +#include "net/ea/protocol.h" + +#include "net/messagein.h" + +#include "being.h" +#include "beingmanager.h" +#include "effectmanager.h" +#include "game.h" +#include "localplayer.h" +#include "log.h" +#include "npc.h" +#include "player_relations.h" + +#include "gui/npc_text.h" + #include <iostream> #include <SDL_types.h> -#include "beinghandler.h" -#include "messagein.h" -#include "protocol.h" - -#include "../being.h" -#include "../beingmanager.h" -#include "../effectmanager.h" -#include "../game.h" -#include "../localplayer.h" -#include "../log.h" -#include "../npc.h" -#include "../player_relations.h" +extern NpcTextDialog *npcTextDialog; const int EMOTION_TIME = 150; /**< Duration of emotion icon */ @@ -58,35 +63,39 @@ BeingHandler::BeingHandler(bool enableSync): SMSG_PLAYER_STOP, SMSG_PLAYER_MOVE_TO_ATTACK, 0x0119, + 0x0196, 0 }; handledMessages = _messages; } -void BeingHandler::handleMessage(MessageIn *msg) +void BeingHandler::handleMessage(MessageIn &msg) { int id; Uint16 job, speed; Uint16 headTop, headMid, headBottom; - Uint16 shoes, gloves, cape, misc1, misc2; + Uint16 shoes, gloves; Uint16 weapon, shield; Uint16 gmstatus; int param1; + int stunMode; + Uint32 statusEffects; int type; + Uint16 status; Being *srcBeing, *dstBeing; - int hairStyle, hairColor; + int hairStyle, hairColor, flag; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_BEING_VISIBLE: case SMSG_BEING_MOVE: // Information about a being in range - id = msg->readInt32(); - speed = msg->readInt16(); - msg->readInt16(); // opt1 - msg->readInt16(); // opt2 - msg->readInt16(); // option - job = msg->readInt16(); // class + id = msg.readInt32(); + speed = msg.readInt16(); + stunMode = msg.readInt16(); // opt1 + statusEffects = msg.readInt16(); // opt2 + statusEffects |= ((Uint32)msg.readInt16()) << 16; // option + job = msg.readInt16(); // class dstBeing = beingManager->findBeing(id); @@ -101,7 +110,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; @@ -109,34 +118,35 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setAction(Being::STAND); } + // Prevent division by 0 when calculating frame if (speed == 0) { speed = 150; } dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - hairStyle = msg->readInt16(); - dstBeing->setSprite(Being::WEAPON_SPRITE, msg->readInt16()); - headBottom = msg->readInt16(); + hairStyle = msg.readInt16(); + dstBeing->setSprite(Being::WEAPON_SPRITE, msg.readInt16()); + headBottom = msg.readInt16(); - if (msg->getId() == SMSG_BEING_MOVE) + if (msg.getId() == SMSG_BEING_MOVE) { - msg->readInt32(); // server tick + msg.readInt32(); // server tick } - dstBeing->setSprite(Being::SHIELD_SPRITE, msg->readInt16()); - headTop = msg->readInt16(); - headMid = msg->readInt16(); - hairColor = msg->readInt16(); - shoes = msg->readInt16(); - gloves = msg->readInt16(); - msg->readInt16(); // guild - msg->readInt16(); // unknown - msg->readInt16(); // unknown - msg->readInt16(); // manner - msg->readInt16(); // karma - msg->readInt8(); // unknown + dstBeing->setSprite(Being::SHIELD_SPRITE, msg.readInt16()); + headTop = msg.readInt16(); + headMid = msg.readInt16(); + hairColor = msg.readInt16(); + shoes = msg.readInt16(); // clothes color - "abused" as shoes + gloves = msg.readInt16(); // head dir - "abused" as gloves + msg.readInt16(); // guild + msg.readInt16(); // unknown + msg.readInt16(); // unknown + msg.readInt16(); // manner + dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 + msg.readInt8(); // karma dstBeing->setGender( - (msg->readInt8() == 0) ? GENDER_FEMALE : GENDER_MALE); + (msg.readInt8() == 0) ? GENDER_FEMALE : GENDER_MALE); // Set these after the gender, as the sprites may be gender-specific dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom); @@ -146,10 +156,10 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setSprite(Being::GLOVES_SPRITE, gloves); dstBeing->setHairStyle(hairStyle, hairColor); - if (msg->getId() == SMSG_BEING_MOVE) + if (msg.getId() == SMSG_BEING_MOVE) { Uint16 srcX, srcY, dstX, dstY; - msg->readCoordinatePair(srcX, srcY, dstX, dstY); + msg.readCoordinatePair(srcX, srcY, dstX, dstY); dstBeing->setAction(Being::STAND); dstBeing->mX = srcX; dstBeing->mY = srcY; @@ -158,13 +168,17 @@ void BeingHandler::handleMessage(MessageIn *msg) else { Uint8 dir; - msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir); + msg.readCoordinates(dstBeing->mX, dstBeing->mY, dir); dstBeing->setDirection(dir); } - msg->readInt8(); // unknown - msg->readInt8(); // unknown - msg->readInt8(); // unknown / sit + msg.readInt8(); // unknown + msg.readInt8(); // unknown + msg.readInt8(); // unknown / sit + + dstBeing->setStunMode(stunMode); + dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); + dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); break; case SMSG_BEING_MOVE2: @@ -173,11 +187,11 @@ void BeingHandler::handleMessage(MessageIn *msg) * later versions of eAthena for both mobs and * players */ - dstBeing = beingManager->findBeing(msg->readInt32()); + dstBeing = beingManager->findBeing(msg.readInt32()); Uint16 srcX, srcY, dstX, dstY; - msg->readCoordinatePair(srcX, srcY, dstX, dstY); - msg->readInt32(); // Server tick + msg.readCoordinatePair(srcX, srcY, dstX, dstY); + msg.readInt32(); // Server tick /* * This packet doesn't have enough info to actually @@ -196,11 +210,12 @@ void BeingHandler::handleMessage(MessageIn *msg) case SMSG_BEING_REMOVE: // A being should be removed or has died - id = msg->readInt32(); - dstBeing = beingManager->findBeing(id); + id = msg.readInt32(); if (id == current_npc) - current_npc = 0; + npcTextDialog->showCloseButton(); + + dstBeing = beingManager->findBeing(id); if (!dstBeing) break; @@ -209,7 +224,7 @@ void BeingHandler::handleMessage(MessageIn *msg) if (dstBeing == player_node->getTarget()) player_node->stopAttack(); - if (msg->readInt8() == 1) + if (msg.readInt8() == 1) dstBeing->setAction(Being::DEAD); else beingManager->destroyBeing(dstBeing); @@ -217,15 +232,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.readInt32()); + dstBeing = beingManager->findBeing(msg.readInt32()); + msg.readInt32(); // server tick + msg.readInt32(); // src speed + msg.readInt32(); // dst speed + param1 = msg.readInt16(); + msg.readInt16(); // param 2 + type = msg.readInt8(); + msg.readInt16(); // param 3 switch (type) { @@ -261,11 +276,11 @@ void BeingHandler::handleMessage(MessageIn *msg) break; case SMSG_BEING_SELFEFFECT: { - id = (Uint32)msg->readInt32(); + id = (Uint32)msg.readInt32(); if (!beingManager->findBeing(id)) break; - int effectType = msg->readInt32(); + int effectType = msg.readInt32(); Being* being = beingManager->findBeing(id); effectManager->trigger(effectType, being); @@ -274,13 +289,13 @@ void BeingHandler::handleMessage(MessageIn *msg) } case SMSG_BEING_EMOTION: - if (!(dstBeing = beingManager->findBeing(msg->readInt32()))) + if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) { break; } if (player_relations.hasPermission(dstBeing, PlayerRelation::EMOTE)) - dstBeing->setEmote(msg->readInt8(), EMOTION_TIME); + dstBeing->setEmote(msg.readInt8(), EMOTION_TIME); break; @@ -299,20 +314,20 @@ void BeingHandler::handleMessage(MessageIn *msg) * 16 bit value will be 0. */ - if (!(dstBeing = beingManager->findBeing(msg->readInt32()))) + if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) { break; } - int type = msg->readInt8(); + int type = msg.readInt8(); int id = 0; int id2 = 0; - if (msg->getId() == SMSG_BEING_CHANGE_LOOKS) { - id = msg->readInt8(); + if (msg.getId() == SMSG_BEING_CHANGE_LOOKS) { + id = msg.readInt8(); } else { // SMSG_BEING_CHANGE_LOOKS2 - id = msg->readInt16(); - id2 = msg->readInt16(); + id = msg.readInt16(); + id2 = msg.readInt16(); } switch (type) { @@ -362,9 +377,9 @@ void BeingHandler::handleMessage(MessageIn *msg) break; case SMSG_BEING_NAME_RESPONSE: - if ((dstBeing = beingManager->findBeing(msg->readInt32()))) + if ((dstBeing = beingManager->findBeing(msg.readInt32()))) { - dstBeing->setName(msg->readString(24)); + dstBeing->setName(msg.readString(24)); } break; @@ -372,12 +387,13 @@ 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(); - cape = msg->readInt16(); - misc1 = msg->readInt16(); - misc2 = msg->readInt16(); - job = msg->readInt16(); + id = msg.readInt32(); + speed = msg.readInt16(); + stunMode = msg.readInt16(); // opt1; Aethyra use this as cape + statusEffects = msg.readInt16(); // opt2; Aethyra use this as misc1 + statusEffects |= ((Uint32) msg.readInt16()) + << 16; // status.options; Aethyra uses this as misc2 + job = msg.readInt16(); dstBeing = beingManager->findBeing(id); @@ -388,27 +404,28 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - hairStyle = msg->readInt16(); - weapon = msg->readInt16(); - shield = msg->readInt16(); - headBottom = msg->readInt16(); + hairStyle = msg.readInt16(); + weapon = msg.readInt16(); + shield = msg.readInt16(); + headBottom = msg.readInt16(); - if (msg->getId() == SMSG_PLAYER_MOVE) + if (msg.getId() == SMSG_PLAYER_MOVE) { - msg->readInt32(); // server tick + msg.readInt32(); // server tick } - headTop = msg->readInt16(); - headMid = msg->readInt16(); - hairColor = msg->readInt16(); - shoes = msg->readInt16(); - gloves = msg->readInt16(); - msg->readInt32(); // guild - msg->readInt32(); // emblem - msg->readInt16(); // manner - msg->readInt8(); // karma + headTop = msg.readInt16(); + headMid = msg.readInt16(); + hairColor = msg.readInt16(); + msg.readInt16(); // clothes color - Aethyra-"abused" as shoes, we ignore it + msg.readInt16(); // head dir - Aethyra-"abused" as gloves, we ignore it + msg.readInt32(); // guild + msg.readInt16(); // emblem + msg.readInt16(); // manner + dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 + msg.readInt8(); // karma dstBeing->setGender( - (msg->readInt8() == 0) ? GENDER_FEMALE : GENDER_MALE); + (msg.readInt8() == 0) ? GENDER_FEMALE : GENDER_MALE); // Set these after the gender, as the sprites may be gender-specific dstBeing->setSprite(Being::WEAPON_SPRITE, weapon); @@ -416,19 +433,15 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom); dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid); dstBeing->setSprite(Being::HAT_SPRITE, headTop); - dstBeing->setSprite(Being::SHOE_SPRITE, shoes); - // Compensation for the unpatched TMW server - if (gloves > 10) - dstBeing->setSprite(Being::GLOVES_SPRITE, gloves); - dstBeing->setSprite(Being::CAPE_SPRITE, cape); - dstBeing->setSprite(Being::MISC1_SPRITE, misc1); - dstBeing->setSprite(Being::MISC2_SPRITE, misc2); + //dstBeing->setSprite(Being::CAPE_SPRITE, cape); + //dstBeing->setSprite(Being::MISC1_SPRITE, misc1); + //dstBeing->setSprite(Being::MISC2_SPRITE, misc2); dstBeing->setHairStyle(hairStyle, hairColor); - if (msg->getId() == SMSG_PLAYER_MOVE) + if (msg.getId() == SMSG_PLAYER_MOVE) { Uint16 srcX, srcY, dstX, dstY; - msg->readCoordinatePair(srcX, srcY, dstX, dstY); + msg.readCoordinatePair(srcX, srcY, dstX, dstY); dstBeing->mX = srcX; dstBeing->mY = srcY; dstBeing->setDestination(dstX, dstY); @@ -436,33 +449,37 @@ void BeingHandler::handleMessage(MessageIn *msg) else { Uint8 dir; - msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir); + msg.readCoordinates(dstBeing->mX, dstBeing->mY, dir); dstBeing->setDirection(dir); } - gmstatus = msg->readInt16(); + gmstatus = msg.readInt16(); if (gmstatus & 0x80) dstBeing->setGM(); - if (msg->getId() == SMSG_PLAYER_UPDATE_1) + if (msg.getId() == SMSG_PLAYER_UPDATE_1) { - switch (msg->readInt8()) + switch (msg.readInt8()) { case 2: dstBeing->setAction(Being::SIT); break; } } - else if (msg->getId() == SMSG_PLAYER_MOVE) + else if (msg.getId() == SMSG_PLAYER_MOVE) { - msg->readInt8(); // unknown + msg.readInt8(); // unknown } - msg->readInt8(); // Lv - msg->readInt8(); // unknown + msg.readInt8(); // Lv + msg.readInt8(); // unknown dstBeing->mWalkTime = tick_time; dstBeing->mFrame = 0; + + dstBeing->setStunMode(stunMode); + dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); + dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); break; case SMSG_PLAYER_STOP: @@ -478,12 +495,12 @@ void BeingHandler::handleMessage(MessageIn *msg) * of the config setting. */ - id = msg->readInt32(); + id = msg.readInt32(); if (mSync || id != player_node->getId()) { dstBeing = beingManager->findBeing(id); if (dstBeing) { - dstBeing->mX = msg->readInt16(); - dstBeing->mY = msg->readInt16(); + dstBeing->mX = msg.readInt16(); + dstBeing->mY = msg.readInt16(); if (dstBeing->mAction == Being::WALK) { dstBeing->mFrame = 0; dstBeing->setAction(Being::STAND); @@ -502,10 +519,30 @@ void BeingHandler::handleMessage(MessageIn *msg) break; case 0x0119: - // Change in players look - logger->log("0x0119 %i %i %i %x %i", msg->readInt32(), - msg->readInt16(), msg->readInt16(), msg->readInt16(), - msg->readInt8()); + // Change in players' flags + id = msg.readInt32(); + dstBeing = beingManager->findBeing(id); + stunMode = msg.readInt16(); + statusEffects = msg.readInt16(); + statusEffects |= ((Uint32) msg.readInt16()) << 16; + msg.readInt8(); + + if (dstBeing) { + dstBeing->setStunMode(stunMode); + dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); + dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); + } + break; + + case 0x0196: + // Status change + status = msg.readInt16(); + id = msg.readInt32(); + flag = msg.readInt8(); // 0: stop, 1: start + + dstBeing = beingManager->findBeing(id); + if (dstBeing) + dstBeing->setStatusEffect(status, flag); break; } } diff --git a/src/net/beinghandler.h b/src/net/ea/beinghandler.h index 5fbb57ce..1246f1c1 100644 --- a/src/net/beinghandler.h +++ b/src/net/ea/beinghandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,21 +19,21 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_BEINGHANDLER_H -#define NET_BEINGHANDLER_H +#ifndef NET_EA_BEINGHANDLER_H +#define NET_EA_BEINGHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class BeingHandler : public MessageHandler { public: BeingHandler(bool enableSync); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); private: // Should we honor server "Stop Walking" packets bool mSync; }; -#endif +#endif // NET_EA_BEINGHANDLER_H diff --git a/src/net/buysellhandler.cpp b/src/net/ea/buysellhandler.cpp index 287e5400..b99db6a4 100644 --- a/src/net/buysellhandler.cpp +++ b/src/net/ea/buysellhandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,24 +19,26 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <SDL_types.h> +#include "net/ea/buysellhandler.h" + +#include "net/ea/protocol.h" -#include "buysellhandler.h" -#include "messagein.h" -#include "protocol.h" +#include "net/messagein.h" -#include "../beingmanager.h" -#include "../inventory.h" -#include "../item.h" -#include "../localplayer.h" -#include "../npc.h" +#include "beingmanager.h" +#include "inventory.h" +#include "item.h" +#include "localplayer.h" +#include "npc.h" -#include "../gui/buy.h" -#include "../gui/buysell.h" -#include "../gui/chat.h" -#include "../gui/sell.h" +#include "gui/buy.h" +#include "gui/buysell.h" +#include "gui/chat.h" +#include "gui/sell.h" -#include "../utils/gettext.h" +#include "utils/gettext.h" + +#include <SDL_types.h> BuySellHandler::BuySellHandler() { @@ -52,51 +53,51 @@ 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); buyDialog->reset(); sellDialog->setVisible(false); sellDialog->reset(); - current_npc = msg->readInt32(); + current_npc = msg.readInt32(); buySellDialog->setVisible(true); break; case SMSG_NPC_BUY: - msg->readInt16(); // length - n_items = (msg->getLength() - 4) / 11; + msg.readInt16(); // length + n_items = (msg.getLength() - 4) / 11; buyDialog->reset(); - buyDialog->setMoney(player_node->mGp); + buyDialog->setMoney(player_node->getMoney()); buyDialog->setVisible(true); for (int k = 0; k < n_items; k++) { - int value = msg->readInt32(); - msg->readInt32(); // DCvalue - msg->readInt8(); // type - int itemId = msg->readInt16(); - buyDialog->addItem(itemId, value); + int value = msg.readInt32(); + msg.readInt32(); // DCvalue + msg.readInt8(); // type + int itemId = msg.readInt16(); + buyDialog->addItem(itemId, 0, value); } break; case SMSG_NPC_SELL: - msg->readInt16(); // length - n_items = (msg->getLength() - 4) / 10; + msg.readInt16(); // length + n_items = (msg.getLength() - 4) / 10; if (n_items > 0) { - sellDialog->setMoney(player_node->mGp); + sellDialog->setMoney(player_node->getMoney()); sellDialog->reset(); sellDialog->setVisible(true); for (int k = 0; k < n_items; k++) { - int index = msg->readInt16(); - int value = msg->readInt32(); - msg->readInt32(); // OCvalue + int index = msg.readInt16(); + int value = msg.readInt32(); + msg.readInt32(); // OCvalue Item *item = player_node->getInventory()->getItem(index); @@ -106,30 +107,30 @@ void BuySellHandler::handleMessage(MessageIn *msg) } else { - chatWindow->chatLog(_("Nothing to sell"), BY_SERVER); + localChatTab->chatLog(_("Nothing to sell"), BY_SERVER); current_npc = 0; } break; case SMSG_NPC_BUY_RESPONSE: - if (msg->readInt8() == 0) + if (msg.readInt8() == 0) { - chatWindow->chatLog(_("Thanks for buying"), BY_SERVER); + localChatTab->chatLog(_("Thanks for buying"), BY_SERVER); } else { // Reset player money since buy dialog already assumed purchase // would go fine - buyDialog->setMoney(player_node->mGp); - chatWindow->chatLog(_("Unable to buy"), BY_SERVER); + buyDialog->setMoney(player_node->getMoney()); + localChatTab->chatLog(_("Unable to buy"), BY_SERVER); } break; case SMSG_NPC_SELL_RESPONSE: - if (msg->readInt8() == 0) - chatWindow->chatLog(_("Thanks for selling"), BY_SERVER); + if (msg.readInt8() == 0) + localChatTab->chatLog(_("Thanks for selling"), BY_SERVER); else - chatWindow->chatLog(_("Unable to sell"), BY_SERVER); + localChatTab->chatLog(_("Unable to sell"), BY_SERVER); break; } diff --git a/src/net/ea/buysellhandler.h b/src/net/ea/buysellhandler.h new file mode 100644 index 00000000..7b85b65d --- /dev/null +++ b/src/net/ea/buysellhandler.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_EA_BUYSELLHANDLER_H +#define NET_EA_BUYSELLHANDLER_H + +#include "net/messagehandler.h" + +class BuySellHandler : public MessageHandler +{ + public: + BuySellHandler(); + + void handleMessage(MessageIn &msg); +}; + +#endif // NET_EA_BUYSELLHANDLER_H diff --git a/src/net/charserverhandler.cpp b/src/net/ea/charserverhandler.cpp index 95555300..d212ebfe 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/ea/charserverhandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,21 +19,23 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "charserverhandler.h" -#include "messagein.h" -#include "protocol.h" +#include "net/ea/charserverhandler.h" -#include "../game.h" -#include "../localplayer.h" -#include "../log.h" -#include "../logindata.h" -#include "../main.h" +#include "net/ea/protocol.h" -#include "../gui/char_select.h" -#include "../gui/ok_dialog.h" +#include "net/messagein.h" -#include "../utils/gettext.h" -#include "../utils/stringutils.h" +#include "game.h" +#include "localplayer.h" +#include "log.h" +#include "logindata.h" +#include "main.h" + +#include "gui/char_select.h" +#include "gui/ok_dialog.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" CharServerHandler::CharServerHandler(): mCharCreateDialog(0) @@ -53,17 +54,17 @@ CharServerHandler::CharServerHandler(): handledMessages = _messages; } -void CharServerHandler::handleMessage(MessageIn *msg) +void CharServerHandler::handleMessage(MessageIn &msg) { int slot, flags, code; LocalPlayer *tempPlayer; logger->log("CharServerHandler: Packet ID: %x, Length: %d", - msg->getId(), msg->getLength()); - switch (msg->getId()) + msg.getId(), msg.getLength()); + switch (msg.getId()) { case SMSG_CONNECTION_PROBLEM: - code = msg->readInt8(); + code = msg.readInt8(); logger->log("Connection problem: %i", code); switch (code) { @@ -86,32 +87,32 @@ void CharServerHandler::handleMessage(MessageIn *msg) errorMessage = _("Unknown connection error"); break; } - state = ERROR_STATE; + state = STATE_ERROR; break; case 0x006b: - msg->skip(2); // Length word - flags = msg->readInt32(); // Aethyra extensions flags + msg.skip(2); // Length word + flags = msg.readInt32(); // Aethyra extensions flags logger->log("Server flags are: %x", flags); - msg->skip(16); // Unused + msg.skip(16); // Unused // Derive number of characters from message length - n_character = (msg->getLength() - 24) / 106; + n_character = (msg.getLength() - 24) / 106; for (int i = 0; i < n_character; i++) { - tempPlayer = readPlayerData(*msg, slot); + tempPlayer = readPlayerData(msg, slot); mCharInfo->select(slot); mCharInfo->setEntry(tempPlayer); logger->log("CharServer: Player: %s (%d)", tempPlayer->getName().c_str(), slot); } - state = CHAR_SELECT_STATE; + state = STATE_CHAR_SELECT; break; case 0x006c: - switch (msg->readInt8()) { + switch (msg.readInt8()) { case 0: errorMessage = _("Access denied"); break; @@ -126,7 +127,7 @@ void CharServerHandler::handleMessage(MessageIn *msg) break; case 0x006d: - tempPlayer = readPlayerData(*msg, slot); + tempPlayer = readPlayerData(msg, slot); mCharInfo->unlock(); mCharInfo->select(slot); mCharInfo->setEntry(tempPlayer); @@ -164,10 +165,10 @@ void CharServerHandler::handleMessage(MessageIn *msg) case 0x0071: player_node = mCharInfo->getEntry(); slot = mCharInfo->getPos(); - 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(); + 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 @@ -183,7 +184,7 @@ void CharServerHandler::handleMessage(MessageIn *msg) } while (mCharInfo->getPos()); mCharInfo->select(slot); - state = CONNECTING_STATE; + state = STATE_CONNECTING; break; } } @@ -196,7 +197,7 @@ LocalPlayer *CharServerHandler::readPlayerData(MessageIn &msg, int &slot) tempPlayer->mCharId = msg.readInt32(); tempPlayer->setXp(msg.readInt32()); - tempPlayer->mGp = msg.readInt32(); + tempPlayer->setMoney(msg.readInt32()); tempPlayer->mJobXp = msg.readInt32(); tempPlayer->mJobLevel = msg.readInt32(); tempPlayer->setSprite(Being::SHOE_SPRITE, msg.readInt16()); @@ -207,8 +208,8 @@ LocalPlayer *CharServerHandler::readPlayerData(MessageIn &msg, int &slot) msg.readInt32(); // karma msg.readInt32(); // manner msg.skip(2); // unknown - tempPlayer->mHp = msg.readInt16(); - tempPlayer->mMaxHp = msg.readInt16(); + tempPlayer->setHp(msg.readInt16()); + tempPlayer->setMaxHp(msg.readInt16()); tempPlayer->mMp = msg.readInt16(); tempPlayer->mMaxMp = msg.readInt16(); msg.readInt16(); // speed @@ -216,7 +217,7 @@ LocalPlayer *CharServerHandler::readPlayerData(MessageIn &msg, int &slot) int hairStyle = msg.readInt16(); Uint16 weapon = msg.readInt16(); tempPlayer->setSprite(Being::WEAPON_SPRITE, weapon); - tempPlayer->mLevel = msg.readInt16(); + tempPlayer->setLevel(msg.readInt16()); msg.readInt16(); // skill point tempPlayer->setSprite(Being::BOTTOMCLOTHES_SPRITE, msg.readInt16()); // head bottom tempPlayer->setSprite(Being::SHIELD_SPRITE, msg.readInt16()); diff --git a/src/net/charserverhandler.h b/src/net/ea/charserverhandler.h index 2a5331b5..3b5a4cd8 100644 --- a/src/net/charserverhandler.h +++ b/src/net/ea/charserverhandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,12 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_CHARSERVERHANDLER_H -#define NET_CHARSERVERHANDLER_H +#ifndef NET_EA_CHARSERVERHANDLER_H +#define NET_EA_CHARSERVERHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" -#include "../lockedarray.h" +#include "lockedarray.h" class CharCreateDialog; class LocalPlayer; @@ -39,7 +38,7 @@ class CharServerHandler : public MessageHandler public: CharServerHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); void setCharInfo(LockedArray<LocalPlayer*> *charInfo) { mCharInfo = charInfo; } @@ -60,7 +59,7 @@ class CharServerHandler : public MessageHandler LockedArray<LocalPlayer*> *mCharInfo; CharCreateDialog *mCharCreateDialog; - LocalPlayer* readPlayerData(MessageIn &msg, int &slot); + LocalPlayer *readPlayerData(MessageIn &msg, int &slot); }; -#endif +#endif // NET_EA_CHARSERVERHANDLER_H diff --git a/src/net/chathandler.cpp b/src/net/ea/chathandler.cpp index 185ce7d8..14432b28 100644 --- a/src/net/chathandler.cpp +++ b/src/net/ea/chathandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,22 +19,23 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <SDL_types.h> -#include <string> +#include "net/ea/chathandler.h" + +#include "net/ea/protocol.h" -#include "chathandler.h" -#include "messagein.h" -#include "protocol.h" +#include "net/messagein.h" -#include "../being.h" -#include "../beingmanager.h" -#include "../game.h" -#include "../player_relations.h" +#include "being.h" +#include "beingmanager.h" +#include "game.h" +#include "player_relations.h" -#include "../gui/chat.h" +#include "gui/chat.h" -#include "../utils/gettext.h" -#include "../utils/stringutils.h" +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#include <string> extern Being *player_node; @@ -56,63 +56,62 @@ ChatHandler::ChatHandler() handledMessages = _messages; } -void ChatHandler::handleMessage(MessageIn *msg) +void ChatHandler::handleMessage(MessageIn &msg) { Being *being; std::string chatMsg; std::string nick; int chatMsgLength; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_WHISPER_RESPONSE: - switch (msg->readInt8()) + switch (msg.readInt8()) { case 0x00: // comment out since we'll local echo in chat.cpp instead, then only report failures - //chatWindow->chatLog("Whisper sent", BY_SERVER); + //localChatTab->chatLog("Whisper sent", BY_SERVER); break; case 0x01: - chatWindow->chatLog(_("Whisper could not be sent, user is offline"), BY_SERVER); + localChatTab->chatLog(_("Whisper could not be sent, user is offline"), BY_SERVER); break; case 0x02: - chatWindow->chatLog(_("Whisper could not be sent, ignored by user"), BY_SERVER); + localChatTab->chatLog(_("Whisper could not be sent, ignored by user"), BY_SERVER); break; } break; // Received whisper case SMSG_WHISPER: - chatMsgLength = msg->readInt16() - 28; - nick = msg->readString(24); + chatMsgLength = msg.readInt16() - 28; + nick = msg.readString(24); if (chatMsgLength <= 0) break; - chatMsg = msg->readString(chatMsgLength); - if (nick != SERVER_NAME) - chatMsg = nick + " : " + chatMsg; + chatMsg = msg.readString(chatMsgLength); - if (nick == SERVER_NAME) - chatWindow->chatLog(chatMsg, BY_SERVER); - else { + if (nick != SERVER_NAME) + { if (player_relations.hasPermission(nick, PlayerRelation::WHISPER)) - chatWindow->chatLog(chatMsg, ACT_WHISPER); + chatWindow->whisper(nick, chatMsg); + } + else + { + localChatTab->chatLog(chatMsg, BY_SERVER); } break; // Received speech from being case SMSG_BEING_CHAT: { - chatMsgLength = msg->readInt16() - 8; - being = beingManager->findBeing(msg->readInt32()); + chatMsgLength = msg.readInt16() - 8; + being = beingManager->findBeing(msg.readInt32()); if (!being || chatMsgLength <= 0) - { break; - } - chatMsg = msg->readString(chatMsgLength); + chatMsg = msg.readString(chatMsgLength); std::string::size_type pos = chatMsg.find(" : ", 0); std::string sender_name = ((pos == std::string::npos) @@ -122,7 +121,7 @@ void ChatHandler::handleMessage(MessageIn *msg) // We use getIgnorePlayer instead of ignoringPlayer here because ignorePlayer' side // effects are triggered right below for Being::IGNORE_SPEECH_FLOAT. if (player_relations.checkPermissionSilently(sender_name, PlayerRelation::SPEECH_LOG)) - chatWindow->chatLog(chatMsg, BY_OTHER); + localChatTab->chatLog(chatMsg, BY_OTHER); chatMsg.erase(0, pos + 3); trim(chatMsg); @@ -134,19 +133,17 @@ void ChatHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_CHAT: case SMSG_GM_CHAT: { - chatMsgLength = msg->readInt16() - 4; + chatMsgLength = msg.readInt16() - 4; if (chatMsgLength <= 0) - { break; - } - chatMsg = msg->readString(chatMsgLength); + chatMsg = msg.readString(chatMsgLength); std::string::size_type pos = chatMsg.find(" : ", 0); - if (msg->getId() == SMSG_PLAYER_CHAT) + if (msg.getId() == SMSG_PLAYER_CHAT) { - chatWindow->chatLog(chatMsg, BY_PLAYER); + localChatTab->chatLog(chatMsg, BY_PLAYER); if (pos != std::string::npos) chatMsg.erase(0, pos + 3); @@ -157,20 +154,20 @@ void ChatHandler::handleMessage(MessageIn *msg) } else { - chatWindow->chatLog(chatMsg, BY_GM); + localChatTab->chatLog(chatMsg, BY_GM); } break; } case SMSG_WHO_ANSWER: - chatWindow->chatLog("Online users: " + toString(msg->readInt32()), + localChatTab->chatLog("Online users: " + toString(msg.readInt32()), BY_SERVER); break; case 0x010c: // Display MVP player - msg->readInt32(); // id - chatWindow->chatLog("MVP player", BY_SERVER); + msg.readInt32(); // id + localChatTab->chatLog("MVP player", BY_SERVER); break; } } diff --git a/src/net/chathandler.h b/src/net/ea/chathandler.h index 9a47c633..62a8c663 100644 --- a/src/net/chathandler.h +++ b/src/net/ea/chathandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_CHATHANDLER_H -#define NET_CHATHANDLER_H +#ifndef NET_EA_CHATHANDLER_H +#define NET_EA_CHATHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class ChatHandler : public MessageHandler { public: ChatHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; -#endif +#endif // NET_EA_CHATHANDLER_H diff --git a/src/net/equipmenthandler.cpp b/src/net/ea/equipmenthandler.cpp index 9a6f424e..7a287bea 100644 --- a/src/net/equipmenthandler.cpp +++ b/src/net/ea/equipmenthandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,19 +19,21 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "equipmenthandler.h" -#include "messagein.h" -#include "protocol.h" +#include "net/ea/equipmenthandler.h" -#include "../equipment.h" -#include "../inventory.h" -#include "../item.h" -#include "../localplayer.h" -#include "../log.h" +#include "net/ea/protocol.h" -#include "../gui/chat.h" +#include "net/messagein.h" -#include "../utils/gettext.h" +#include "equipment.h" +#include "inventory.h" +#include "item.h" +#include "localplayer.h" +#include "log.h" + +#include "gui/chat.h" + +#include "utils/gettext.h" EquipmentHandler::EquipmentHandler() { @@ -47,7 +48,7 @@ EquipmentHandler::EquipmentHandler() handledMessages = _messages; } -void EquipmentHandler::handleMessage(MessageIn *msg) +void EquipmentHandler::handleMessage(MessageIn &msg) { int itemCount; int index, equipPoint, itemId; @@ -56,23 +57,23 @@ void EquipmentHandler::handleMessage(MessageIn *msg) Item *item; Inventory *inventory = player_node->getInventory(); - switch (msg->getId()) + switch (msg.getId()) { case SMSG_PLAYER_EQUIPMENT: - msg->readInt16(); // length - itemCount = (msg->getLength() - 4) / 20; + msg.readInt16(); // 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.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 inventory->setItem(index, itemId, 1, true); @@ -92,14 +93,14 @@ void EquipmentHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_EQUIP: - index = msg->readInt16(); - equipPoint = msg->readInt16(); - type = msg->readInt8(); + index = msg.readInt16(); + equipPoint = msg.readInt16(); + type = msg.readInt8(); logger->log("Equipping: %i %i %i", index, equipPoint, type); if (!type) { - chatWindow->chatLog(_("Unable to equip."), BY_SERVER); + localChatTab->chatLog(_("Unable to equip."), BY_SERVER); break; } @@ -132,12 +133,12 @@ void EquipmentHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_UNEQUIP: - index = msg->readInt16(); - equipPoint = msg->readInt16(); - type = msg->readInt8(); + index = msg.readInt16(); + equipPoint = msg.readInt16(); + type = msg.readInt8(); if (!type) { - chatWindow->chatLog(_("Unable to unequip."), BY_SERVER); + localChatTab->chatLog(_("Unable to unequip."), BY_SERVER); break; } @@ -170,11 +171,11 @@ void EquipmentHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_ATTACK_RANGE: - player_node->setAttackRange(msg->readInt16()); + player_node->setAttackRange(msg.readInt16()); break; case SMSG_PLAYER_ARROW_EQUIP: - index = msg->readInt16(); + index = msg.readInt16(); if (index <= 1) break; diff --git a/src/net/equipmenthandler.h b/src/net/ea/equipmenthandler.h index 08de3b36..2bb73c97 100644 --- a/src/net/equipmenthandler.h +++ b/src/net/ea/equipmenthandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_EQUIPMENTHANDLER_H -#define NET_EQUIPMENTHANDLER_H +#ifndef NET_EA_EQUIPMENTHANDLER_H +#define NET_EA_EQUIPMENTHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class EquipmentHandler : public MessageHandler { public: EquipmentHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; -#endif +#endif // NET_EA_EQUIPMENTHANDLER_H diff --git a/src/net/inventoryhandler.cpp b/src/net/ea/inventoryhandler.cpp index 9fcfedf1..21ae6dcb 100644 --- a/src/net/inventoryhandler.cpp +++ b/src/net/ea/inventoryhandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,27 +19,29 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <SDL_types.h> +#include "net/ea/inventoryhandler.h" + +#include "net/ea/protocol.h" -#include "inventoryhandler.h" -#include "messagein.h" -#include "protocol.h" +#include "net/messagein.h" -#include "../configuration.h" -#include "../inventory.h" -#include "../item.h" -#include "../itemshortcut.h" -#include "../localplayer.h" -#include "../log.h" +#include "configuration.h" +#include "inventory.h" +#include "item.h" +#include "itemshortcut.h" +#include "localplayer.h" +#include "log.h" -#include "../gui/chat.h" -#include "../gui/storagewindow.h" +#include "gui/chat.h" +#include "gui/storagewindow.h" -#include "../resources/iteminfo.h" +#include "resources/iteminfo.h" -#include "../utils/gettext.h" -#include "../utils/strprintf.h" -#include "../utils/stringutils.h" +#include "utils/gettext.h" +#include "utils/strprintf.h" +#include "utils/stringutils.h" + +#include <SDL_types.h> InventoryHandler::InventoryHandler() { @@ -61,7 +62,7 @@ InventoryHandler::InventoryHandler() handledMessages = _messages; } -void InventoryHandler::handleMessage(MessageIn *msg) +void InventoryHandler::handleMessage(MessageIn &msg) { int number; int index, amount, itemId, equipType, arrow; @@ -69,11 +70,11 @@ void InventoryHandler::handleMessage(MessageIn *msg) Inventory *inventory = player_node->getInventory(); Inventory *storage = player_node->getStorage(); - switch (msg->getId()) + switch (msg.getId()) { case SMSG_PLAYER_INVENTORY: case SMSG_PLAYER_STORAGE_ITEMS: - switch (msg->getId()) { + switch (msg.getId()) { case SMSG_PLAYER_INVENTORY: // Clear inventory - this will be a complete refresh inventory->clear(); @@ -91,20 +92,20 @@ void InventoryHandler::handleMessage(MessageIn *msg) logger->log("HOW DID WE GET HERE?"); return; } - msg->readInt16(); // length - number = (msg->getLength() - 4) / 18; + msg.readInt16(); // length + number = (msg.getLength() - 4) / 18; for (int loop = 0; loop < number; loop++) { - index = msg->readInt16(); - itemId = msg->readInt16(); - itemType = msg->readInt8(); - identified = msg->readInt8(); - amount = msg->readInt16(); - arrow = msg->readInt16(); + index = msg.readInt16(); + itemId = msg.readInt16(); + itemType = msg.readInt8(); + identified = msg.readInt8(); + amount = msg.readInt16(); + arrow = msg.readInt16(); for (int i = 0; i < 4; i++) - cards[i] = msg->readInt16(); + cards[i] = msg.readInt16(); - if (msg->getId() == SMSG_PLAYER_INVENTORY) { + if (msg.getId() == SMSG_PLAYER_INVENTORY) { inventory->setItem(index, itemId, amount, false); // Trick because arrows are not considered equipment @@ -121,21 +122,21 @@ void InventoryHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_STORAGE_EQUIP: - msg->readInt16(); // length - number = (msg->getLength() - 4) / 20; + msg.readInt16(); // length + number = (msg.getLength() - 4) / 20; for (int loop = 0; loop < number; loop++) { - index = msg->readInt16(); - itemId = msg->readInt16(); - itemType = msg->readInt8(); - identified = msg->readInt8(); + index = msg.readInt16(); + itemId = msg.readInt16(); + itemType = msg.readInt8(); + identified = msg.readInt8(); amount = 1; - msg->readInt16(); // Equip Point? - msg->readInt16(); // Another Equip Point? - msg->readInt8(); // Attribute (broken) - msg->readInt8(); // Refine level + msg.readInt16(); // Equip Point? + msg.readInt16(); // Another Equip Point? + msg.readInt8(); // Attribute (broken) + msg.readInt8(); // Refine level for (int i = 0; i < 4; i++) - cards[i] = msg->readInt16(); + cards[i] = msg.readInt16(); logger->log("Index:%d, ID:%d, Type:%d, Identified:%d, Qty:%d, Cards:%d, %d, %d, %d", index, itemId, itemType, identified, amount, cards[0], cards[1], cards[2], cards[3]); @@ -144,27 +145,27 @@ void InventoryHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_INVENTORY_ADD: - index = msg->readInt16(); - amount = msg->readInt16(); - itemId = msg->readInt16(); - identified = msg->readInt8(); - msg->readInt8(); // attribute - msg->readInt8(); // refine + index = msg.readInt16(); + amount = msg.readInt16(); + itemId = msg.readInt16(); + identified = msg.readInt8(); + msg.readInt8(); // attribute + msg.readInt8(); // refine for (int i = 0; i < 4; i++) - cards[i] = msg->readInt16(); - equipType = msg->readInt16(); - itemType = msg->readInt8(); + cards[i] = msg.readInt16(); + equipType = msg.readInt16(); + itemType = msg.readInt8(); - if (msg->readInt8() > 0) { + if (msg.readInt8() > 0) { if (config.getValue("showpickupchat", true)) { - chatWindow->chatLog(_("Unable to pick up item"), BY_SERVER); + localChatTab->chatLog(_("Unable to pick up item"), BY_SERVER); } } else { const ItemInfo &itemInfo = ItemDB::get(itemId); const std::string amountStr = (amount > 1) ? toString(amount) : "a"; if (config.getValue("showpickupchat", true)) { - chatWindow->chatLog(strprintf(_("You picked up %s [%s]"), + localChatTab->chatLog(strprintf(_("You picked up %s [%s]"), amountStr.c_str(), itemInfo.getName().c_str()), BY_SERVER); } @@ -182,8 +183,8 @@ void InventoryHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_INVENTORY_REMOVE: - index = msg->readInt16(); - amount = msg->readInt16(); + index = msg.readInt16(); + amount = msg.readInt16(); if (Item *item = inventory->getItem(index)) { item->increaseQuantity(-amount); if (item->getQuantity() == 0) @@ -192,22 +193,22 @@ void InventoryHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_INVENTORY_USE: - index = msg->readInt16(); - msg->readInt16(); // item id - msg->readInt32(); // id - amount = msg->readInt16(); - msg->readInt8(); // type + index = msg.readInt16(); + msg.readInt16(); // item id + msg.readInt32(); // id + amount = msg.readInt16(); + msg.readInt8(); // type if (Item *item = inventory->getItem(index)) item->setQuantity(amount); break; case SMSG_ITEM_USE_RESPONSE: - index = msg->readInt16(); - amount = msg->readInt16(); + index = msg.readInt16(); + amount = msg.readInt16(); - if (msg->readInt8() == 0) { - chatWindow->chatLog(_("Failed to use item"), BY_SERVER); + if (msg.readInt8() == 0) { + localChatTab->chatLog(_("Failed to use item"), BY_SERVER); } else { if (Item *item = inventory->getItem(index)) item->setQuantity(amount); @@ -218,25 +219,25 @@ void InventoryHandler::handleMessage(MessageIn *msg) /* * This is the closest we get to an "Open Storage" packet from the * server. It always comes after the two SMSG_PLAYER_STORAGE_... - * packets that update storage contents.. + * packets that update storage contents. */ player_node->setInStorage(true); - msg->readInt16(); // Storage capacity - msg->readInt16(); // Used count + msg.readInt16(); // Storage capacity + msg.readInt16(); // Used count break; case SMSG_PLAYER_STORAGE_ADD: /* * Move an item into storage */ - index = msg->readInt16(); - amount = msg->readInt32(); - itemId = msg->readInt16(); - identified = msg->readInt8(); - msg->readInt8(); // attribute - msg->readInt8(); // refine + index = msg.readInt16(); + amount = msg.readInt32(); + itemId = msg.readInt16(); + identified = msg.readInt8(); + msg.readInt8(); // attribute + msg.readInt8(); // refine for (int i = 0; i < 4; i++) - cards[i] = msg->readInt16(); + cards[i] = msg.readInt16(); if (Item *item = storage->getItem(index)) { item->setId(itemId); @@ -250,8 +251,8 @@ void InventoryHandler::handleMessage(MessageIn *msg) /* * Move an item out of storage */ - index = msg->readInt16(); - amount = msg->readInt16(); + index = msg.readInt16(); + amount = msg.readInt16(); if (Item *item = storage->getItem(index)) { item->increaseQuantity(-amount); if (item->getQuantity() == 0) diff --git a/src/net/ea/inventoryhandler.h b/src/net/ea/inventoryhandler.h new file mode 100644 index 00000000..7374fed9 --- /dev/null +++ b/src/net/ea/inventoryhandler.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_EA_INVENTORYHANDLER_H +#define NET_EA_INVENTORYHANDLER_H + +#include "net/messagehandler.h" + +class InventoryHandler : public MessageHandler +{ + public: + InventoryHandler(); + + void handleMessage(MessageIn &msg); +}; + +#endif // NET_EA_INVENTORYHANDLER_H diff --git a/src/net/itemhandler.cpp b/src/net/ea/itemhandler.cpp index d9d84248..427b29bd 100644 --- a/src/net/itemhandler.cpp +++ b/src/net/ea/itemhandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,12 +19,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "itemhandler.h" -#include "messagein.h" -#include "protocol.h" +#include "net/ea/itemhandler.h" -#include "../engine.h" -#include "../flooritemmanager.h" +#include "net/ea/protocol.h" + +#include "net/messagein.h" + +#include "engine.h" +#include "flooritemmanager.h" ItemHandler::ItemHandler() { @@ -38,29 +39,29 @@ ItemHandler::ItemHandler() handledMessages = _messages; } -void ItemHandler::handleMessage(MessageIn *msg) +void ItemHandler::handleMessage(MessageIn &msg) { Uint32 id; Uint16 x, y; int 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.readInt32(); + itemId = msg.readInt16(); + msg.readInt8(); // identify flag + x = msg.readInt16(); + y = msg.readInt16(); + msg.skip(4); // amount,subX,subY / subX,subY,amount floorItemManager->create(id, itemId, x, y, engine->getCurrentMap()); break; case SMSG_ITEM_REMOVE: FloorItem *item; - item = floorItemManager->findById(msg->readInt32()); + item = floorItemManager->findById(msg.readInt32()); if (item) floorItemManager->destroy(item); break; diff --git a/src/net/ea/itemhandler.h b/src/net/ea/itemhandler.h new file mode 100644 index 00000000..42a9e4e7 --- /dev/null +++ b/src/net/ea/itemhandler.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_EA_ITEMHANDLER_H +#define NET_EA_ITEMHANDLER_H + +#include "net/messagehandler.h" + +class ItemHandler : public MessageHandler +{ + public: + ItemHandler(); + + void handleMessage(MessageIn &msg); +}; + +#endif // NET_EA_ITEMHANDLER_H diff --git a/src/net/loginhandler.cpp b/src/net/ea/loginhandler.cpp index cf45dbd4..06bdb4bc 100644 --- a/src/net/loginhandler.cpp +++ b/src/net/ea/loginhandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,18 +19,20 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "loginhandler.h" -#include "messagein.h" -#include "protocol.h" +#include "net/ea/loginhandler.h" -#include "../log.h" -#include "../logindata.h" -#include "../main.h" -#include "../serverinfo.h" +#include "net/ea/protocol.h" -#include "../utils/gettext.h" -#include "../utils/strprintf.h" -#include "../utils/stringutils.h" +#include "net/messagein.h" + +#include "log.h" +#include "logindata.h" +#include "main.h" +#include "serverinfo.h" + +#include "utils/gettext.h" +#include "utils/strprintf.h" +#include "utils/stringutils.h" extern SERVER_INFO **server_info; @@ -47,14 +48,14 @@ LoginHandler::LoginHandler() handledMessages = _messages; } -void LoginHandler::handleMessage(MessageIn *msg) +void LoginHandler::handleMessage(MessageIn &msg) { int code; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_CONNECTION_PROBLEM: - code = msg->readInt8(); + code = msg.readInt8(); logger->log("Connection problem: %i", code); switch (code) { @@ -71,14 +72,14 @@ void LoginHandler::handleMessage(MessageIn *msg) errorMessage = _("Unknown connection error"); break; } - state = ERROR_STATE; + state = STATE_ERROR; break; case SMSG_UPDATE_HOST: int len; - len = msg->readInt16() - 4; - mUpdateHost = msg->readString(len); + len = msg.readInt16() - 4; + mUpdateHost = msg.readString(len); logger->log("Received update host \"%s\" from login server", mUpdateHost.c_str()); @@ -86,39 +87,39 @@ void LoginHandler::handleMessage(MessageIn *msg) case 0x0069: // Skip the length word - msg->skip(2); + msg.skip(2); - n_server = (msg->getLength() - 47) / 32; + 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(); + 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++) { 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(); + 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(); server_info[i]->updateHost = mUpdateHost; - msg->skip(2); // unknown + 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 = CHAR_SERVER_STATE; + state = STATE_CHAR_SERVER; break; case 0x006a: - code = msg->readInt8(); + code = msg.readInt8(); logger->log("Login::error code: %i", code); switch (code) { @@ -144,7 +145,7 @@ void LoginHandler::handleMessage(MessageIn *msg) "banned from the game until " "%s.\n Please contact the GM " "team via the forums."), - msg->readString(20).c_str()); + msg.readString(20).c_str()); break; case 9: errorMessage = _("This user name is already taken"); @@ -153,7 +154,7 @@ void LoginHandler::handleMessage(MessageIn *msg) errorMessage = _("Unknown error"); break; } - state = ERROR_STATE; + state = STATE_ERROR; break; } } diff --git a/src/net/loginhandler.h b/src/net/ea/loginhandler.h index 6b938627..074bc9e2 100644 --- a/src/net/loginhandler.h +++ b/src/net/ea/loginhandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,12 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_LOGINHANDLER_H -#define NET_LOGINHANDLER_H +#ifndef NET_EA_LOGINHANDLER_H +#define NET_EA_LOGINHANDLER_H -#include <string> +#include "net/messagehandler.h" -#include "messagehandler.h" +#include <string> struct LoginData; @@ -34,13 +33,13 @@ class LoginHandler : public MessageHandler public: LoginHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); - void setLoginData(LoginData *loginData) { mLoginData = loginData; }; + void setLoginData(LoginData *loginData) { mLoginData = loginData; } private: LoginData *mLoginData; std::string mUpdateHost; }; -#endif +#endif // NET_EA_LOGINHANDLER_H diff --git a/src/net/maploginhandler.cpp b/src/net/ea/maploginhandler.cpp index bcd3dd62..78f021b0 100644 --- a/src/net/maploginhandler.cpp +++ b/src/net/ea/maploginhandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,15 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "maploginhandler.h" -#include "messagein.h" -#include "protocol.h" +#include "net/ea/maploginhandler.h" -#include "../localplayer.h" -#include "../log.h" -#include "../main.h" +#include "net/ea/protocol.h" -#include "../utils/gettext.h" +#include "net/messagein.h" + +#include "localplayer.h" +#include "log.h" +#include "main.h" + +#include "utils/gettext.h" MapLoginHandler::MapLoginHandler() { @@ -40,15 +41,15 @@ MapLoginHandler::MapLoginHandler() handledMessages = _messages; } -void MapLoginHandler::handleMessage(MessageIn *msg) +void MapLoginHandler::handleMessage(MessageIn &msg) { int code; unsigned char direction; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_CONNECTION_PROBLEM: - code = msg->readInt8(); + code = msg.readInt8(); logger->log("Connection problem: %i", code); switch (code) { @@ -62,16 +63,16 @@ void MapLoginHandler::handleMessage(MessageIn *msg) errorMessage = _("Unknown connection error"); break; } - state = ERROR_STATE; + state = STATE_ERROR; break; case SMSG_LOGIN_SUCCESS: - msg->readInt32(); // server tick - msg->readCoordinates(player_node->mX, player_node->mY, direction); - msg->skip(2); // unknown + 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; + state = STATE_GAME; break; } } diff --git a/src/net/maploginhandler.h b/src/net/ea/maploginhandler.h index fb083b51..40f8e7bc 100644 --- a/src/net/maploginhandler.h +++ b/src/net/ea/maploginhandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_MAPLOGINHANDLER_H -#define NET_MAPLOGINHANDLER_H +#ifndef NET_EA_MAPLOGINHANDLER_H +#define NET_EA_MAPLOGINHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class MapLoginHandler : public MessageHandler { public: MapLoginHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; -#endif +#endif // NET_EA_MAPLOGINHANDLER_H diff --git a/src/net/network.cpp b/src/net/ea/network.cpp index 0126ad6d..e17b8f3b 100644 --- a/src/net/network.cpp +++ b/src/net/ea/network.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,14 +19,15 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <sstream> +#include "net/ea/network.h" + +#include "net/messagehandler.h" +#include "net/messagein.h" -#include "messagehandler.h" -#include "messagein.h" -#include "network.h" +#include "log.h" +#include "utils/stringutils.h" -#include "../log.h" -#include "../utils/stringutils.h" +#include <sstream> /** Warning: buffers and other variables are shared, so there can be only one connection active at a time */ @@ -208,7 +208,7 @@ void Network::dispatchMessages() MessageHandlerIterator iter = mMessageHandlers.find(msg.getId()); if (iter != mMessageHandlers.end()) - iter->second->handleMessage(&msg); + iter->second->handleMessage(msg); else logger->log("Unhandled packet: %x", msg.getId()); @@ -420,7 +420,7 @@ void Network::receive() SDLNet_FreeSocketSet(set); } -void Network::setError(const std::string& error) +void Network::setError(const std::string &error) { logger->log("Network error: %s", error.c_str()); mError = error; diff --git a/src/net/network.h b/src/net/ea/network.h index e264f8a5..651b1182 100644 --- a/src/net/network.h +++ b/src/net/ea/network.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NETWORK_ -#define NETWORK_ +#ifndef EA_NETWORK_H +#define EA_NETWORK_H #include <map> #include <SDL_net.h> @@ -61,7 +60,7 @@ class Network int getState() const { return mState; } - const std::string& getError() const { return mError; } + const std::string &getError() const { return mError; } bool isConnected() const { return mState == CONNECTED; } @@ -87,7 +86,7 @@ class Network }; protected: - void setError(const std::string& error); + void setError(const std::string &error); Uint16 readWord(int pos); diff --git a/src/net/npchandler.cpp b/src/net/ea/npchandler.cpp index 60a77af1..165cc2d3 100644 --- a/src/net/npchandler.cpp +++ b/src/net/ea/npchandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,20 +19,22 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <SDL_types.h> +#include "net/ea/npchandler.h" + +#include "net/ea/protocol.h" -#include "messagein.h" -#include "npchandler.h" -#include "protocol.h" +#include "net/messagein.h" -#include "../beingmanager.h" -#include "../localplayer.h" -#include "../npc.h" +#include "beingmanager.h" +#include "localplayer.h" +#include "npc.h" -#include "../gui/npc_text.h" -#include "../gui/npcintegerdialog.h" -#include "../gui/npclistdialog.h" -#include "../gui/npcstringdialog.h" +#include "gui/npc_text.h" +#include "gui/npcintegerdialog.h" +#include "gui/npclistdialog.h" +#include "gui/npcstringdialog.h" + +#include <SDL_types.h> NPCHandler::NPCHandler() { @@ -49,51 +50,61 @@ NPCHandler::NPCHandler() handledMessages = _messages; } -void NPCHandler::handleMessage(MessageIn *msg) +void NPCHandler::handleMessage(MessageIn &msg) { int id; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_NPC_CHOICE: - msg->readInt16(); // length - current_npc = msg->readInt32(); + msg.readInt16(); // length + current_npc = msg.readInt32(); player_node->setAction(LocalPlayer::STAND); - npcListDialog->parseItems(msg->readString(msg->getLength() - 8)); + npcListDialog->parseItems(msg.readString(msg.getLength() - 8)); npcListDialog->requestFocus(); break; case SMSG_NPC_MESSAGE: - msg->readInt16(); // length - current_npc = msg->readInt32(); + msg.readInt16(); // length + current_npc = msg.readInt32(); player_node->setAction(LocalPlayer::STAND); - npcTextDialog->addText(msg->readString(msg->getLength() - 8)); + npcTextDialog->addText(msg.readString(msg.getLength() - 8)); npcTextDialog->requestFocus(); break; case SMSG_NPC_CLOSE: - id = msg->readInt32(); - if (current_npc == id) - current_npc = 0; - npcTextDialog->closeDialog(id); + id = msg.readInt32(); + // If we're talking to that NPC, show the close button + if (id == current_npc) + npcTextDialog->showCloseButton(); + // Otherwise, move on as an empty dialog doesn't help + else + npcTextDialog->closeDialog(id); break; case SMSG_NPC_NEXT: - // Next button in NPC dialog, currently unused + id = msg.readInt32(); + // If we're talking to that NPC, show the next button + if (id == current_npc) + npcTextDialog->showNextButton(); + // Otherwise, move on as an empty dialog doesn't help + else + npcTextDialog->nextDialog(id); break; case SMSG_NPC_INT_INPUT: // Request for an integer - current_npc = msg->readInt32(); + current_npc = msg.readInt32(); player_node->setAction(LocalPlayer::STAND); npcIntegerDialog->setRange(0, 2147483647); + npcIntegerDialog->setDefaultValue(0); npcIntegerDialog->setVisible(true); npcIntegerDialog->requestFocus(); break; case SMSG_NPC_STR_INPUT: // Request for a string - current_npc = msg->readInt32(); + current_npc = msg.readInt32(); player_node->setAction(LocalPlayer::STAND); npcStringDialog->setValue(""); npcStringDialog->setVisible(true); diff --git a/src/net/ea/npchandler.h b/src/net/ea/npchandler.h new file mode 100644 index 00000000..8c252175 --- /dev/null +++ b/src/net/ea/npchandler.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_EA_NPCHANDLER_H +#define NET_EA_NPCHANDLER_H + +#include "net/messagehandler.h" + +class NPCHandler : public MessageHandler +{ + public: + NPCHandler(); + + void handleMessage(MessageIn &msg); +}; + +#endif // NET_EA_NPCHANDLER_H diff --git a/src/net/partyhandler.cpp b/src/net/ea/partyhandler.cpp index b65ff2c9..d903976e 100644 --- a/src/net/partyhandler.cpp +++ b/src/net/ea/partyhandler.cpp @@ -1,8 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,21 +15,20 @@ * 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 + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <guichan/actionlistener.hpp> +#include "net/ea/partyhandler.h" -#include "partyhandler.h" -#include "protocol.h" -#include "messagein.h" +#include "net/ea/protocol.h" -#include "../gui/chat.h" -#include "../gui/confirm_dialog.h" +#include "net/messagein.h" -#include "../beingmanager.h" -#include "../party.h" +#include "gui/chat.h" + +#include "beingmanager.h" +#include "party.h" PartyHandler::PartyHandler(Party *party) : mParty(party) { @@ -49,25 +48,25 @@ PartyHandler::PartyHandler(Party *party) : mParty(party) handledMessages = _messages; } -void PartyHandler::handleMessage(MessageIn *msg) +void PartyHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { case SMSG_PARTY_CREATE: - mParty->createResponse(msg->readInt8()); + mParty->createResponse(msg.readInt8()); break; case SMSG_PARTY_INFO: break; case SMSG_PARTY_INVITE: { - std::string nick = msg->readString(24); - int status = msg->readInt8(); + std::string nick = msg.readString(24); + int status = msg.readInt8(); mParty->inviteResponse(nick, status); break; } case SMSG_PARTY_INVITED: { - int id = msg->readInt32(); + int id = msg.readInt32(); Being *being = beingManager->findBeing(id); if (!being) { @@ -84,7 +83,7 @@ void PartyHandler::handleMessage(MessageIn *msg) { nick = being->getName(); gender = being->getGender(); - partyName = msg->readString(24); + partyName = msg.readString(24); } mParty->invitedAsk(nick, gender, partyName); break; @@ -95,9 +94,9 @@ void PartyHandler::handleMessage(MessageIn *msg) break; case SMSG_PARTY_LEAVE: { - /*int id = */msg->readInt32(); - std::string nick = msg->readString(24); - /*int fail = */msg->readInt8(); + /*int id = */msg.readInt32(); + std::string nick = msg.readString(24); + /*int fail = */msg.readInt8(); mParty->leftResponse(nick); break; } @@ -107,14 +106,14 @@ void PartyHandler::handleMessage(MessageIn *msg) break; case SMSG_PARTY_MESSAGE: { // new block to enable local variables - int msgLength = msg->readInt16() - 8; + int msgLength = msg.readInt16() - 8; if (msgLength <= 0) { return; } - int id = msg->readInt32(); + int id = msg.readInt32(); Being *being = beingManager->findBeing(id); - std::string chatMsg = msg->readString(msgLength); + std::string chatMsg = msg.readString(msgLength); mParty->receiveChat(being, chatMsg); } break; diff --git a/src/net/partyhandler.h b/src/net/ea/partyhandler.h index 158e89e6..851c4ae3 100644 --- a/src/net/partyhandler.h +++ b/src/net/ea/partyhandler.h @@ -1,8 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,14 +15,14 @@ * 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 + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef PARTYHANDLER_H -#define PARTYHANDLER_H +#ifndef NET_EA_PARTYHANDLER_H +#define NET_EA_PARTYHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class Party; @@ -31,9 +31,10 @@ class PartyHandler : public MessageHandler public: PartyHandler(Party *party); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); + private: Party *mParty; }; -#endif +#endif // NET_EA_PARTYHANDLER_H diff --git a/src/net/playerhandler.cpp b/src/net/ea/playerhandler.cpp index 3dd2bad2..00230ea3 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/ea/playerhandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,31 +19,34 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "messagein.h" -#include "playerhandler.h" -#include "protocol.h" - -#include "../engine.h" -#include "../localplayer.h" -#include "../log.h" -#include "../npc.h" - -#include "../gui/buy.h" -#include "../gui/buysell.h" -#include "../gui/chat.h" -#include "../gui/gui.h" -#include "../gui/npc_text.h" -#include "../gui/npcintegerdialog.h" -#include "../gui/npclistdialog.h" -#include "../gui/npcstringdialog.h" -#include "../gui/ok_dialog.h" -#include "../gui/sell.h" -#include "../gui/skill.h" -#include "../gui/storagewindow.h" -#include "../gui/viewport.h" - -#include "../utils/stringutils.h" -#include "../utils/gettext.h" +#include "net/ea/playerhandler.h" + +#include "net/ea/protocol.h" + +#include "net/messagein.h" + +#include "engine.h" +#include "localplayer.h" +#include "log.h" +#include "npc.h" +#include "units.h" + +#include "gui/buy.h" +#include "gui/buysell.h" +#include "gui/chat.h" +#include "gui/gui.h" +#include "gui/npc_text.h" +#include "gui/npcintegerdialog.h" +#include "gui/npclistdialog.h" +#include "gui/npcstringdialog.h" +#include "gui/ok_dialog.h" +#include "gui/sell.h" +#include "gui/skill.h" +#include "gui/storagewindow.h" +#include "gui/viewport.h" + +#include "utils/stringutils.h" +#include "utils/gettext.h" // TODO Move somewhere else OkDialog *weightNotice = NULL; @@ -54,11 +56,12 @@ OkDialog *deathNotice = NULL; // everything beyond will reset the port hard. static const int MAP_TELEPORT_SCROLL_DISTANCE = 8; -/** - * Listener used for handling the overweigth message. - */ // TODO Move somewhere else namespace { + + /** + * Listener used for handling the overweigth message. + */ struct WeightListener : public gcn::ActionListener { void action(const gcn::ActionEvent &event) @@ -66,13 +69,10 @@ namespace { weightNotice = NULL; } } weightListener; -} -/** - * Listener used for handling death message. - */ -// TODO Move somewhere else -namespace { + /** + * Listener used for handling death message. + */ struct DeathListener : public gcn::ActionListener { void action(const gcn::ActionEvent &event) @@ -90,10 +90,59 @@ namespace { buyDialog->setVisible(false); sellDialog->setVisible(false); buySellDialog->setVisible(false); + if (storageWindow->isVisible()) storageWindow->close(); - current_npc = 0; } } deathListener; + +} // anonymous namespace + +static const char *randomDeathMessage() +{ + static char const *const deadMsg[] = + { + N_("You are dead."), + N_("We regret to inform you that your character was killed in " + "battle."), + N_("You are not that alive anymore."), + N_("The cold hands of the grim reaper are grabbing for your soul."), + N_("Game Over!"), + N_("Insert coin to continue"), + N_("No, kids. Your character did not really die. It... " + "err... went to a better place."), + N_("Your plan of breaking your enemies weapon by " + "bashing it with your throat failed."), + N_("I guess this did not run too well."), + // NetHack reference: + N_("Do you want your possessions identified?"), + // Secret of Mana reference: + N_("Sadly, no trace of you was ever found..."), + // Final Fantasy VI reference: + N_("Annihilated."), + // Earthbound reference: + N_("Looks like you got your head handed to you."), + // Leisure Suit Larry 1 reference: + N_("You screwed up again, dump your body down the tubes " + "and get you another one."), + // Monty Python references (Dead Parrot sketch mostly): + N_("You're not dead yet. You're just resting."), + N_("You are no more."), + N_("You have ceased to be."), + N_("You've expired and gone to meet your maker."), + N_("You're a stiff."), + N_("Bereft of life, you rest in peace."), + N_("If you weren't so animated, you'd be pushing up the daisies."), + N_("Your metabolic processes are now history."), + N_("You're off the twig."), + N_("You've kicked the bucket."), + N_("You've shuffled off your mortal coil, run down the " + "curtain and joined the bleedin' choir invisibile."), + N_("You are an ex-player."), + N_("You're pining for the fjords.") + }; + + const int random = rand() % (sizeof(deadMsg) / sizeof(deadMsg[0])); + return gettext(deadMsg[random]); } PlayerHandler::PlayerHandler() @@ -113,9 +162,9 @@ PlayerHandler::PlayerHandler() handledMessages = _messages; } -void PlayerHandler::handleMessage(MessageIn *msg) +void PlayerHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { case SMSG_WALK_RESPONSE: /* @@ -127,10 +176,10 @@ void PlayerHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_WARP: { - std::string mapPath = msg->readString(16); + std::string mapPath = msg.readString(16); bool nearby; - Uint16 x = msg->readInt16(); - Uint16 y = msg->readInt16(); + Uint16 x = msg.readInt16(); + Uint16 y = msg.readInt16(); logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y); @@ -145,8 +194,6 @@ void PlayerHandler::handleMessage(MessageIn *msg) // Switch the actual map, deleting the previous one if necessary engine->changeMap(mapPath); - current_npc = 0; - float scrollOffsetX = 0.0f; float scrollOffsetY = 0.0f; @@ -173,30 +220,30 @@ void PlayerHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_STAT_UPDATE_1: { - int type = msg->readInt16(); - int value = msg->readInt32(); + int type = msg.readInt16(); + int value = msg.readInt32(); switch (type) { //case 0x0000: - // player_node->setWalkSpeed(msg->readInt32()); + // player_node->setWalkSpeed(msg.readInt32()); // break; - case 0x0005: player_node->mHp = value; break; - case 0x0006: player_node->mMaxHp = value; break; + case 0x0005: player_node->setHp(value); break; + case 0x0006: player_node->setMaxHp(value); break; case 0x0007: player_node->mMp = value; break; case 0x0008: player_node->mMaxMp = value; break; case 0x0009: player_node->mStatsPointsToAttribute = value; break; - case 0x000b: player_node->mLevel = value; break; + case 0x000b: player_node->setLevel(value); break; case 0x000c: player_node->mSkillPoint = value; skillDialog->update(); break; case 0x0018: - if (value >= player_node->mMaxWeight / 2 && - player_node->mTotalWeight < - player_node->mMaxWeight / 2) + if (value >= player_node->getMaxWeight() / 2 && + player_node->getTotalWeight() < + player_node->getMaxWeight() / 2) { weightNotice = new OkDialog(_("Message"), _("You are carrying more than " @@ -205,9 +252,9 @@ void PlayerHandler::handleMessage(MessageIn *msg) weightNotice->addActionListener( &weightListener); } - player_node->mTotalWeight = value; + player_node->setTotalWeight(value); break; - case 0x0019: player_node->mMaxWeight = value; break; + case 0x0019: player_node->setMaxWeight(value); break; case 0x0029: player_node->ATK = value; break; case 0x002b: player_node->MATK = value; break; case 0x002d: player_node->DEF = value; break; @@ -219,54 +266,10 @@ void PlayerHandler::handleMessage(MessageIn *msg) case 0x0037: player_node->mJobLevel = value; break; } - if (player_node->mHp == 0 && !deathNotice) + if (player_node->getHp() == 0 && !deathNotice) { - static char const *const deadMsg[] = - { - _("You are dead."), - _("We regret to inform you that your character was " - "killed in battle."), - _("You are not that alive anymore."), - _("The cold hands of the grim reaper are grabbing for " - "your soul."), - _("Game Over!"), - _("Insert coin to continue"), - _("No, kids. Your character did not really die. It... " - "err... went to a better place."), - _("Your plan of breaking your enemies weapon by " - "bashing it with your throat failed."), - _("I guess this did not run too well."), - // NetHack reference: - _("Do you want your possessions identified?"), - // Secret of Mana reference: - _("Sadly, no trace of you was ever found..."), - // Final Fantasy VI reference: - _("Annihilated."), - // Earthbound reference: - _("Looks like you got your head handed to you."), - // Leisure Suit Larry 1 reference: - _("You screwed up again, dump your body down the tubes " - "and get you another one."), - // Monty Python references (Dead Parrot sketch mostly): - _("You're not dead yet. You're just resting."), - _("You are no more."), - _("You have ceased to be."), - _("You've expired and gone to meet your maker."), - _("You're a stiff."), - _("Bereft of life, you rest in peace."), - _("If you weren't so animated, you'd be pushing up the " - "daisies."), - _("Your metabolic processes are now history."), - _("You're off the twig."), - _("You've kicked the bucket."), - _("You've shuffled off your mortal coil, run down the " - "curtain and joined the bleedin' choir invisibile."), - _("You are an ex-player."), - _("You're pining for the fjords.") - }; - std::string message(deadMsg[rand()%27]); - - deathNotice = new OkDialog(_("Message"), message); + deathNotice = new OkDialog(_("Message"), + randomDeathMessage()); deathNotice->addActionListener(&deathListener); player_node->setAction(Being::DEAD); } @@ -274,36 +277,36 @@ void PlayerHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_STAT_UPDATE_2: - switch (msg->readInt16()) { + switch (msg.readInt16()) { case 0x0001: - player_node->setXp(msg->readInt32()); + player_node->setXp(msg.readInt32()); break; case 0x0002: - player_node->mJobXp = msg->readInt32(); + player_node->mJobXp = msg.readInt32(); break; case 0x0014: { - Uint32 curGp = player_node->mGp; - player_node->mGp = msg->readInt32(); - if (player_node->mGp > curGp) - chatWindow->chatLog(_("You picked up ") + - toString(player_node->mGp - curGp) + " GP", - BY_SERVER); + int curGp = player_node->getMoney(); + player_node->setMoney(msg.readInt32()); + if (player_node->getMoney() > curGp) + localChatTab->chatLog(_("You picked up ") + + Units::formatCurrency(player_node->getMoney() + - curGp), BY_SERVER); } break; case 0x0016: - player_node->mXpForNextLevel = msg->readInt32(); + player_node->mXpForNextLevel = msg.readInt32(); break; case 0x0017: - player_node->mJobXpForNextLevel = msg->readInt32(); + player_node->mJobXpForNextLevel = msg.readInt32(); break; } break; case SMSG_PLAYER_STAT_UPDATE_3: { - int type = msg->readInt32(); - int base = msg->readInt32(); - int bonus = msg->readInt32(); + int type = msg.readInt32(); + int base = msg.readInt32(); + int bonus = msg.readInt32(); int total = base + bonus; switch (type) { @@ -325,9 +328,9 @@ void PlayerHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_STAT_UPDATE_4: { - int type = msg->readInt16(); - int fail = msg->readInt8(); - int value = msg->readInt8(); + int type = msg.readInt16(); + int fail = msg.readInt8(); + int value = msg.readInt8(); if (fail != 1) break; @@ -351,64 +354,64 @@ 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.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 break; case SMSG_PLAYER_STAT_UPDATE_6: - switch (msg->readInt16()) { + switch (msg.readInt16()) { case 0x0020: - player_node->mAttrUp[LocalPlayer::STR] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::STR] = msg.readInt8(); break; case 0x0021: - player_node->mAttrUp[LocalPlayer::AGI] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::AGI] = msg.readInt8(); break; case 0x0022: - player_node->mAttrUp[LocalPlayer::VIT] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::VIT] = msg.readInt8(); break; case 0x0023: - player_node->mAttrUp[LocalPlayer::INT] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::INT] = msg.readInt8(); break; case 0x0024: - player_node->mAttrUp[LocalPlayer::DEX] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::DEX] = msg.readInt8(); break; case 0x0025: - player_node->mAttrUp[LocalPlayer::LUK] = msg->readInt8(); + player_node->mAttrUp[LocalPlayer::LUK] = msg.readInt8(); break; } break; case SMSG_PLAYER_ARROW_MESSAGE: { - int type = msg->readInt16(); + int type = msg.readInt16(); switch (type) { case 0: - chatWindow->chatLog(_("Equip arrows first"), + localChatTab->chatLog(_("Equip arrows first"), BY_SERVER); break; default: diff --git a/src/net/playerhandler.h b/src/net/ea/playerhandler.h index 0500ae44..9fb2c982 100644 --- a/src/net/playerhandler.h +++ b/src/net/ea/playerhandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_PLAYERHANDLER_H -#define NET_PLAYERHANDLER_H +#ifndef NET_EA_PLAYERHANDLER_H +#define NET_EA_PLAYERHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class PlayerHandler : public MessageHandler { public: PlayerHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; -#endif +#endif // NET_EA_PLAYERHANDLER_H diff --git a/src/net/protocol.cpp b/src/net/ea/protocol.cpp index 563c1cc4..9d9db56f 100644 --- a/src/net/protocol.cpp +++ b/src/net/ea/protocol.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "protocol.h" +#include "net/ea/protocol.h" #define LOBYTE(w) ((unsigned char)(w)) #define HIBYTE(w) ((unsigned char)(((unsigned short)(w)) >> 8)) diff --git a/src/net/protocol.h b/src/net/ea/protocol.h index 645d667f..c96ff7b6 100644 --- a/src/net/protocol.h +++ b/src/net/ea/protocol.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef PROTOCOL_ -#define PROTOCOL_ +#ifndef EA_PROTOCOL_H +#define EA_PROTOCOL_H /********************************* * Packets from server to client * diff --git a/src/net/ea/skillhandler.cpp b/src/net/ea/skillhandler.cpp new file mode 100644 index 00000000..fcc0f4b2 --- /dev/null +++ b/src/net/ea/skillhandler.cpp @@ -0,0 +1,208 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/ea/skillhandler.h" + +#include "net/ea/protocol.h" + +#include "net/messagein.h" + +#include "log.h" + +#include "gui/chat.h" +#include "gui/skill.h" + +#include "utils/gettext.h" + +/** job dependend identifiers (?) */ +#define SKILL_BASIC 0x0001 +#define SKILL_WARP 0x001b +#define SKILL_STEAL 0x0032 +#define SKILL_ENVENOM 0x0034 + +/** basic skills identifiers */ +#define BSKILL_TRADE 0x0000 +#define BSKILL_EMOTE 0x0001 +#define BSKILL_SIT 0x0002 +#define BSKILL_CREATECHAT 0x0003 +#define BSKILL_JOINPARTY 0x0004 +#define BSKILL_SHOUT 0x0005 +#define BSKILL_PK 0x0006 // ?? +#define BSKILL_SETALLIGN 0x0007 // ?? + +/** reasons why action failed */ +#define RFAIL_SKILLDEP 0x00 +#define RFAIL_INSUFHP 0x01 +#define RFAIL_INSUFSP 0x02 +#define RFAIL_NOMEMO 0x03 +#define RFAIL_SKILLDELAY 0x04 +#define RFAIL_ZENY 0x05 +#define RFAIL_WEAPON 0x06 +#define RFAIL_REDGEM 0x07 +#define RFAIL_BLUEGEM 0x08 +#define RFAIL_OVERWEIGHT 0x09 +#define RFAIL_GENERIC 0x0a + +/** should always be zero if failed */ +#define SKILL_FAILED 0x00 + +SkillHandler::SkillHandler() +{ + static const Uint16 _messages[] = { + SMSG_PLAYER_SKILLS, + SMSG_SKILL_FAILED, + 0 + }; + handledMessages = _messages; +} + +void SkillHandler::handleMessage(MessageIn &msg) +{ + int skillCount; + + switch (msg.getId()) + { + case SMSG_PLAYER_SKILLS: + msg.readInt16(); // length + skillCount = (msg.getLength() - 4) / 37; + skillDialog->cleanList(); + + for (int k = 0; k < skillCount; k++) + { + int skillId = msg.readInt16(); + msg.readInt16(); // target type + msg.readInt16(); // unknown + int level = msg.readInt16(); + int sp = msg.readInt16(); + msg.readInt16(); // range + std::string skillName = msg.readString(24); + int up = msg.readInt8(); + + if (level != 0 || up != 0) + { + if (skillDialog->hasSkill(skillId)) { + skillDialog->setSkill(skillId, level, sp); + } + else { + skillDialog->addSkill(skillId, level, sp); + } + } + } + skillDialog->update(); + break; + + case SMSG_SKILL_FAILED: + // Action failed (ex. sit because you have not reached the + // right level) + short skill = msg.readInt16(); + short bskill = msg.readInt16(); + msg.readInt16(); // unknown + char success = msg.readInt8(); + char reason = msg.readInt8(); + if (success != SKILL_FAILED && bskill == BSKILL_EMOTE) + { + logger->log("Action: %d/%d", bskill, success); + } + + std::string msg; + if (success == SKILL_FAILED && skill == SKILL_BASIC) + { + switch (bskill) + { + case BSKILL_TRADE: + msg = _("Trade failed!"); + break; + case BSKILL_EMOTE: + msg = _("Emote failed!"); + break; + case BSKILL_SIT: + msg = _("Sit failed!"); + break; + case BSKILL_CREATECHAT: + msg = _("Chat creating failed!"); + break; + case BSKILL_JOINPARTY: + msg = _("Could not join party!"); + break; + case BSKILL_SHOUT: + msg = _("Cannot shout!"); + break; + } + + msg += " "; + + switch (reason) + { + case RFAIL_SKILLDEP: + msg += _("You have not yet reached a high enough lvl!"); + break; + case RFAIL_INSUFHP: + msg += _("Insufficient HP!"); + break; + case RFAIL_INSUFSP: + msg += _("Insufficient SP!"); + break; + case RFAIL_NOMEMO: + msg += _("You have no memos!"); + break; + case RFAIL_SKILLDELAY: + msg += _("You cannot do that right now!"); + break; + case RFAIL_ZENY: + msg += _("Seems you need more money... ;-)"); + break; + case RFAIL_WEAPON: + msg += _("You cannot use this skill with that kind of weapon!"); + break; + case RFAIL_REDGEM: + msg += _("You need another red gem!"); + break; + case RFAIL_BLUEGEM: + msg += _("You need another blue gem!"); + break; + case RFAIL_OVERWEIGHT: + msg += _("You're carrying to much to do this!"); + break; + default: + msg += _("Huh? What's that?"); + break; + } + } + else + { + switch (skill) + { + case SKILL_WARP : + msg = _("Warp failed..."); + break; + case SKILL_STEAL : + msg = _("Could not steal anything..."); + break; + case SKILL_ENVENOM : + msg = _("Poison had no effect..."); + break; + } + } + + localChatTab->chatLog(msg); + break; + } +} diff --git a/src/net/skillhandler.h b/src/net/ea/skillhandler.h index 689e42dc..f2c950c9 100644 --- a/src/net/skillhandler.h +++ b/src/net/ea/skillhandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_SKILLHANDLER_H -#define NET_SKILLHANDLER_H +#ifndef NET_EA_SKILLHANDLER_H +#define NET_EA_SKILLHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class SkillHandler : public MessageHandler { public: SkillHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; -#endif +#endif // NET_EA_SKILLHANDLER_H diff --git a/src/net/tradehandler.cpp b/src/net/ea/tradehandler.cpp index fd772d01..ea41ed70 100644 --- a/src/net/tradehandler.cpp +++ b/src/net/ea/tradehandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,20 +19,22 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "messagein.h" -#include "protocol.h" -#include "tradehandler.h" +#include "net/ea/tradehandler.h" -#include "../inventory.h" -#include "../item.h" -#include "../localplayer.h" -#include "../player_relations.h" +#include "net/ea/protocol.h" -#include "../gui/chat.h" -#include "../gui/confirm_dialog.h" -#include "../gui/trade.h" +#include "net/messagein.h" -#include "../utils/gettext.h" +#include "inventory.h" +#include "item.h" +#include "localplayer.h" +#include "player_relations.h" + +#include "gui/chat.h" +#include "gui/confirm_dialog.h" +#include "gui/trade.h" + +#include "utils/gettext.h" std::string tradePartnerName; @@ -46,7 +47,7 @@ namespace { void action(const gcn::ActionEvent &event) { player_node->tradeReply(event.getId() == "yes"); - }; + } } listener; } @@ -66,9 +67,9 @@ TradeHandler::TradeHandler() } -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 @@ -77,7 +78,7 @@ void TradeHandler::handleMessage(MessageIn *msg) // Note that it would be nice if the server would prevent this // situation, and that the requesting player would get a // special message about the player being occupied. - tradePartnerName = msg->readString(24); + tradePartnerName = msg.readString(24); if (player_relations.hasPermission(tradePartnerName, PlayerRelation::TRADE)) { @@ -102,18 +103,18 @@ void TradeHandler::handleMessage(MessageIn *msg) break; case SMSG_TRADE_RESPONSE: - switch (msg->readInt8()) + switch (msg.readInt8()) { case 0: // Too far away - chatWindow->chatLog(_("Trading isn't possible. Trade partner is too far away."), + localChatTab->chatLog(_("Trading isn't possible. Trade partner is too far away."), BY_SERVER); break; case 1: // Character doesn't exist - chatWindow->chatLog(_("Trading isn't possible. Character doesn't exist."), + localChatTab->chatLog(_("Trading isn't possible. Character doesn't exist."), BY_SERVER); break; case 2: // Invite request check failed... - chatWindow->chatLog(_("Trade cancelled due to an unknown reason."), + localChatTab->chatLog(_("Trade cancelled due to an unknown reason."), BY_SERVER); break; case 3: // Trade accepted @@ -125,7 +126,7 @@ void TradeHandler::handleMessage(MessageIn *msg) case 4: // Trade cancelled if (player_relations.hasPermission(tradePartnerName, PlayerRelation::SPEECH_LOG)) - chatWindow->chatLog(_("Trade with ") + tradePartnerName + + localChatTab->chatLog(_("Trade with ") + tradePartnerName + _(" cancelled"), BY_SERVER); // otherwise ignore silently @@ -133,7 +134,7 @@ void TradeHandler::handleMessage(MessageIn *msg) player_node->setTrading(false); break; default: // Shouldn't happen as well, but to be sure - chatWindow->chatLog(_("Unhandled trade cancel packet"), + localChatTab->chatLog(_("Unhandled trade cancel packet"), BY_SERVER); break; } @@ -141,16 +142,16 @@ void TradeHandler::handleMessage(MessageIn *msg) case SMSG_TRADE_ITEM_ADD: { - int amount = msg->readInt32(); - int type = msg->readInt16(); - msg->readInt8(); // identified flag - msg->readInt8(); // attribute - msg->readInt8(); // refine - msg->skip(8); // card (4 shorts) + int amount = msg.readInt32(); + int type = msg.readInt16(); + msg.readInt8(); // identified flag + msg.readInt8(); // attribute + msg.readInt8(); // refine + msg.skip(8); // card (4 shorts) // TODO: handle also identified, etc if (type == 0) { - tradeWindow->addMoney(amount); + tradeWindow->setMoney(amount); } else { tradeWindow->addItem(type, false, amount, false); } @@ -160,16 +161,16 @@ void TradeHandler::handleMessage(MessageIn *msg) case SMSG_TRADE_ITEM_ADD_RESPONSE: // Trade: New Item add response (was 0x00ea, now 01b1) { - const int index = msg->readInt16(); + const int index = msg.readInt16(); Item *item = player_node->getInventory()->getItem(index); if (!item) { tradeWindow->receivedOk(true); return; } - int quantity = msg->readInt16(); + int quantity = msg.readInt16(); - switch (msg->readInt8()) + switch (msg.readInt8()) { case 0: // Successfully added item @@ -183,16 +184,16 @@ void TradeHandler::handleMessage(MessageIn *msg) break; case 1: // Add item failed - player overweighted - chatWindow->chatLog(_("Failed adding item. Trade partner is over weighted."), + localChatTab->chatLog(_("Failed adding item. Trade partner is over weighted."), BY_SERVER); break; case 2: // Add item failed - player has no free slot - chatWindow->chatLog(_("Failed adding item. Trade partner has no free slot."), + localChatTab->chatLog(_("Failed adding item. Trade partner has no free slot."), BY_SERVER); break; default: - chatWindow->chatLog(_("Failed adding item for unknown reason."), + localChatTab->chatLog(_("Failed adding item for unknown reason."), BY_SERVER); break; } @@ -201,18 +202,18 @@ 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.readInt8() == 0); break; case SMSG_TRADE_CANCEL: - chatWindow->chatLog(_("Trade canceled."), BY_SERVER); + localChatTab->chatLog(_("Trade canceled."), BY_SERVER); tradeWindow->setVisible(false); tradeWindow->reset(); player_node->setTrading(false); break; case SMSG_TRADE_COMPLETE: - chatWindow->chatLog(_("Trade completed."), BY_SERVER); + localChatTab->chatLog(_("Trade completed."), BY_SERVER); tradeWindow->setVisible(false); tradeWindow->reset(); player_node->setTrading(false); diff --git a/src/net/tradehandler.h b/src/net/ea/tradehandler.h index 8f108248..e141f6b5 100644 --- a/src/net/tradehandler.h +++ b/src/net/ea/tradehandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,19 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_TRADEHANDLER_H -#define NET_TRADEHANDLER_H +#ifndef NET_EA_TRADEHANDLER_H +#define NET_EA_TRADEHANDLER_H -#include "messagehandler.h" - -class Network; +#include "net/messagehandler.h" class TradeHandler : public MessageHandler { public: TradeHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; -#endif +#endif // NET_EA_TRADEHANDLER_H diff --git a/src/net/messagehandler.cpp b/src/net/messagehandler.cpp index f45000be..4cb6af0b 100644 --- a/src/net/messagehandler.cpp +++ b/src/net/messagehandler.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,24 +19,37 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> +#include "net/messagehandler.h" + +#ifdef TMWSERV_SUPPORT +#include "net/tmwserv/network.h" +#else +#include "net/ea/network.h" +#endif -#include "messagehandler.h" -#include "network.h" +#include <cassert> -MessageHandler::MessageHandler(): - mNetwork(0) +MessageHandler::MessageHandler() +#ifdef EATHENA_SUPPORT + : mNetwork(0) +#endif { } MessageHandler::~MessageHandler() { +#ifdef TMWSERV_SUPPORT + Net::unregisterHandler(this); +#else if (mNetwork) mNetwork->unregisterHandler(this); +#endif } +#ifdef EATHENA_SUPPORT void MessageHandler::setNetwork(Network *network) { assert(!(network && mNetwork)); mNetwork = network; } +#endif diff --git a/src/net/messagehandler.h b/src/net/messagehandler.h index 7ff5194b..261a8351 100644 --- a/src/net/messagehandler.h +++ b/src/net/messagehandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,8 +25,13 @@ #include <SDL_types.h> class MessageIn; +#ifdef EATHENA_SUPPORT class Network; +#endif +/** + * \ingroup Network + */ class MessageHandler { public: @@ -36,12 +40,14 @@ class MessageHandler MessageHandler(); virtual ~MessageHandler(); - virtual void handleMessage(MessageIn *msg) =0; + virtual void handleMessage(MessageIn &msg) = 0; +#ifdef EATHENA_SUPPORT void setNetwork(Network *network); protected: Network *mNetwork; +#endif }; #endif diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp index f1ff4013..f365bb7f 100644 --- a/src/net/messagein.cpp +++ b/src/net/messagein.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,11 +19,16 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> +#include "net/messagein.h" + +#ifdef TMWSERV_SUPPORT +#include <enet/enet.h> +#else #include <SDL.h> #include <SDL_endian.h> +#endif -#include "messagein.h" +#include <cassert> #define MAKEWORD(low,high) \ ((unsigned short)(((unsigned char)(low)) | \ @@ -39,32 +43,68 @@ MessageIn::MessageIn(const char *data, unsigned int length): mId = readInt16(); } -Sint8 MessageIn::readInt8() +int MessageIn::readInt8() { - assert(mPos < mLength); - return mData[mPos++]; + int value = -1; + if (mPos < mLength) + { + value = (unsigned char) mData[mPos]; + } + mPos += 1; + return value; } -Sint16 MessageIn::readInt16() +int MessageIn::readInt16() { - assert(mPos + 2 <= mLength); - mPos += 2; + int value = -1; + if (mPos + 2 <= mLength) + { +#ifdef TMWSERV_SUPPORT + uint16_t t; + memcpy(&t, mData + mPos, 2); + value = (unsigned short) ENET_NET_TO_HOST_16(t); +#else #if SDL_BYTEORDER == SDL_BIG_ENDIAN - return SDL_Swap16(*(Sint16*)(mData + (mPos - 2))); + value = SDL_Swap16(*(Sint16*)(mData + mPos)); #else - return (*(Sint16*)(mData + (mPos - 2))); + value = (*(Sint16*)(mData + mPos)); #endif +#endif // TMWSERV_SUPPORT + } + mPos += 2; + return value; } -Sint32 MessageIn::readInt32() +int MessageIn::readInt32() { - assert(mPos + 4 <= mLength); - mPos += 4; + int value = -1; + if (mPos + 4 <= mLength) + { +#ifdef TMWSERV_SUPPORT + uint32_t t; + memcpy(&t, mData + mPos, 4); + value = ENET_NET_TO_HOST_32(t); +#else #if SDL_BYTEORDER == SDL_BIG_ENDIAN - return SDL_Swap32(*(Sint32*)(mData + (mPos - 4))); + value = SDL_Swap32(*(Sint32*)(mData + mPos)); #else - return (*(Sint32*)(mData + (mPos - 4))); + value = (*(Sint32*)(mData + mPos)); #endif +#endif // TMWSERV_SUPPORT + } + mPos += 4; + return value; +} + +void MessageIn::readCoordinates(Uint16 &x, Uint16 &y) +{ + 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; } void MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction) @@ -165,21 +205,3 @@ std::string MessageIn::readString(int 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 94f2bee7..0d0e9981 100644 --- a/src/net/messagein.h +++ b/src/net/messagein.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,13 +27,11 @@ /** * Used for parsing an incoming message. + * + * \ingroup Network */ 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. @@ -44,16 +41,27 @@ class MessageIn /** * Returns the message ID. */ - short getId() { return mId; } + int getId() const { return mId; } /** * Returns the message length. */ - unsigned int getLength() { return mLength; } + unsigned int getLength() const { return mLength; } + + /** + * Returns the length of unread data. + */ + unsigned int getUnreadLength() const { return mLength - mPos; } - Sint8 readInt8(); /**< Reads a byte. */ - Sint16 readInt16(); /**< Reads a short. */ - Sint32 readInt32(); /**< Reads a long. */ + int readInt8(); /**< Reads a byte. */ + int readInt16(); /**< Reads a short. */ + int readInt32(); /**< Reads a long. */ + + /** + * Reads a 3-byte block containing tile-based coordinates. Used by + * tmwserv. + */ + void readCoordinates(Uint16 &x, Uint16 &y); /** * Reads a special 3 byte block used by eAthena, containing x and y @@ -83,8 +91,14 @@ class MessageIn 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. */ + unsigned 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 ab17f537..4cb4dc36 100644 --- a/src/net/messageout.cpp +++ b/src/net/messageout.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,95 +19,132 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cstring> +#include "net/messageout.h" + +#ifdef TMWSERV_SUPPORT +#include <enet/enet.h> +#else +#include "net/ea/network.h" + #include <SDL.h> #include <SDL_endian.h> -#include <string> +#endif -#include "messageout.h" -#include "network.h" +#include <cstring> +#include <string> +#ifdef TMWSERV_SUPPORT +MessageOut::MessageOut(short id): + mData(0), +#else MessageOut::MessageOut(Network *network): mNetwork(network), - mData(0), +#endif mDataSize(0), mPos(0) { +#ifdef TMWSERV_SUPPORT + writeInt16(id); +#else mData = mNetwork->mOutBuffer + mNetwork->mOutSize; +#endif } +#ifdef TMWSERV_SUPPORT +MessageOut::~MessageOut() +{ + free(mData); +} + +void MessageOut::expand(size_t bytes) +{ + mData = (char*)realloc(mData, bytes); + mDataSize = bytes; +} +#endif + void MessageOut::writeInt8(Sint8 value) { +#ifdef TMWSERV_SUPPORT + expand(mPos + 1); +#else + mNetwork->mOutSize += 1; +#endif mData[mPos] = value; - mPos += sizeof(Sint8); - mNetwork->mOutSize+= sizeof(Sint8); + mPos += 1; } void MessageOut::writeInt16(Sint16 value) { +#ifdef TMWSERV_SUPPORT + expand(mPos + 2); + uint16_t t = ENET_HOST_TO_NET_16(value); + memcpy(mData + mPos, &t, 2); +#else #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); + mNetwork->mOutSize += 2; +#endif // TMWSERV_SUPPORT + mPos += 2; } void MessageOut::writeInt32(Sint32 value) { +#ifdef TMWSERV_SUPPORT + expand(mPos + 4); + uint32_t t = ENET_HOST_TO_NET_32(value); + memcpy(mData + mPos, &t, 4); +#else #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); + mNetwork->mOutSize += 4; +#endif // TMWSERV_SUPPORT + mPos += 4; } void MessageOut::writeString(const std::string &string, int length) { - std::string toWrite = string; - + int stringLength = string.length(); if (length < 0) { // Write the length at the start if not fixed - writeInt16(string.length()); + writeInt16(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; } +#ifdef TMWSERV_SUPPORT + expand(mPos + length); +#else + mNetwork->mOutSize += length; +#endif // 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 93f1c2e8..bc701b92 100644 --- a/src/net/messageout.h +++ b/src/net/messageout.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,26 +25,38 @@ #include <iosfwd> #include <SDL_types.h> +#ifdef EATHENA_SUPPORT class Network; +#endif /** * Used for building an outgoing message. + * + * With tmwserv, the message is sent using Net::Connection::send() when + * finished. + * + * \ingroup Network */ 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. */ +#ifdef TMWSERV_SUPPORT + MessageOut(short id); + + /** + * Destructor. + */ + ~MessageOut(); +#else MessageOut(Network *network); +#endif void writeInt8(Sint8 value); /**< Writes a byte. */ void writeInt16(Sint16 value); /**< Writes a short. */ - void writeInt32(Sint32 value); /**< Writes a long. */ + void writeInt32(Sint32 value); /**< Writes a long. */ /** * Writes a string. If a fixed length is not given (-1), it is stored @@ -53,8 +64,29 @@ 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: +#ifdef TMWSERV_SUPPORT + /** + * 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); +#else Network *mNetwork; +#endif char *mData; /**< Data building up. */ unsigned int mDataSize; /**< Size of data. */ diff --git a/src/net/skillhandler.cpp b/src/net/skillhandler.cpp deleted file mode 100644 index be757d7c..00000000 --- a/src/net/skillhandler.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Aethyra - * Copyright (C) 2004 The Mana World Development Team - * - * This file is part of Aethyra based on original code - * from The Mana World. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "messagein.h" -#include "protocol.h" -#include "skillhandler.h" - -#include "../log.h" - -#include "../gui/chat.h" -#include "../gui/skill.h" - -SkillHandler::SkillHandler() -{ - static const Uint16 _messages[] = { - SMSG_PLAYER_SKILLS, - SMSG_SKILL_FAILED, - 0 - }; - handledMessages = _messages; -} - -void SkillHandler::handleMessage(MessageIn *msg) -{ - int skillCount; - - switch (msg->getId()) - { - case SMSG_PLAYER_SKILLS: - msg->readInt16(); // length - skillCount = (msg->getLength() - 4) / 37; - skillDialog->cleanList(); - - for (int k = 0; k < skillCount; k++) - { - int skillId = msg->readInt16(); - msg->readInt16(); // target type - msg->readInt16(); // unknown - int level = msg->readInt16(); - int sp = msg->readInt16(); - msg->readInt16(); // range - std::string skillName = msg->readString(24); - int up = msg->readInt8(); - - if (level != 0 || up != 0) - { - if (skillDialog->hasSkill(skillId)) { - skillDialog->setSkill(skillId, level, sp); - } - else { - skillDialog->addSkill(skillId, level, sp); - } - } - } - skillDialog->update(); - break; - - case SMSG_SKILL_FAILED: - // 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(); - if (action.success != SKILL_FAILED && - action.bskill == BSKILL_EMOTE) - { - logger->log("Action: %d/%d", action.bskill, action.success); - } - chatWindow->chatLog(action); - break; - } -} diff --git a/src/net/tmwserv/accountserver/account.cpp b/src/net/tmwserv/accountserver/account.cpp new file mode 100644 index 00000000..e6c1830b --- /dev/null +++ b/src/net/tmwserv/accountserver/account.cpp @@ -0,0 +1,108 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "account.h" + +#include "internal.h" + +#include "net/tmwserv/connection.h" +#include "net/tmwserv/protocol.h" + +#include "net/messageout.h" + +#include "utils/sha256.h" + +#include <string> + +void Net::AccountServer::Account::createCharacter( + const std::string &name, char hairStyle, char hairColor, char gender, + short strength, short agility, short vitality, + short intelligence, short dexterity, short willpower) +{ + MessageOut msg(PAMSG_CHAR_CREATE); + + msg.writeString(name); + msg.writeInt8(hairStyle); + msg.writeInt8(hairColor); + msg.writeInt8(gender); + msg.writeInt16(strength); + msg.writeInt16(agility); + msg.writeInt16(vitality); + msg.writeInt16(intelligence); + msg.writeInt16(dexterity); + msg.writeInt16(willpower); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::deleteCharacter(char slot) +{ + MessageOut msg(PAMSG_CHAR_DELETE); + + msg.writeInt8(slot); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::selectCharacter(char slot) +{ + MessageOut msg(PAMSG_CHAR_SELECT); + + msg.writeInt8(slot); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::unregister(const std::string &username, + const std::string &password) +{ + MessageOut msg(PAMSG_UNREGISTER); + + msg.writeString(username); + msg.writeString(sha256(username + password)); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::changeEmail(const std::string &email) +{ + MessageOut msg(PAMSG_EMAIL_CHANGE); + + // Email is sent clearly so the server can validate the data. + // Encryption is assumed server-side. + msg.writeString(email); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::Account::changePassword( + const std::string &username, + const std::string &oldPassword, + const std::string &newPassword) +{ + MessageOut msg(PAMSG_PASSWORD_CHANGE); + + // Change password using SHA2 encryption + msg.writeString(sha256(username + oldPassword)); + msg.writeString(sha256(username + newPassword)); + + Net::AccountServer::connection->send(msg); +} diff --git a/src/net/tmwserv/accountserver/account.h b/src/net/tmwserv/accountserver/account.h new file mode 100644 index 00000000..03e83881 --- /dev/null +++ b/src/net/tmwserv/accountserver/account.h @@ -0,0 +1,54 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_ACCOUNTSERVER_CHARACTER_H +#define NET_ACCOUNTSERVER_CHARACTER_H + +#include <iosfwd> + +namespace Net +{ + namespace AccountServer + { + namespace Account + { + void createCharacter(const std::string &name, + char hairStyle, char hairColor, char gender, + short strength, short agility, short vitality, + short intelligence, short dexterity, short willpower); + + void deleteCharacter(char slot); + + void selectCharacter(char slot); + + void unregister(const std::string &username, + const std::string &password); + + void changeEmail(const std::string &email); + + void changePassword(const std::string &username, + const std::string &oldPassword, + const std::string &newPassword); + } + } +} + +#endif diff --git a/src/net/tmwserv/accountserver/accountserver.cpp b/src/net/tmwserv/accountserver/accountserver.cpp new file mode 100644 index 00000000..83895377 --- /dev/null +++ b/src/net/tmwserv/accountserver/accountserver.cpp @@ -0,0 +1,82 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "accountserver.h" + +#include "internal.h" + +#include "net/tmwserv/connection.h" +#include "net/tmwserv/protocol.h" + +#include "net/messageout.h" + +#include "utils/sha256.h" + +#include <string> + +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.writeInt32(version); + msg.writeString(username); + msg.writeString(sha256(username + 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.writeInt32(version); // client version + msg.writeString(username); + // When registering, the password and email hash is assumed by server. + // Hence, data can be validated safely server-side. + // This is the only time we send a clear password. + msg.writeString(password); + msg.writeString(email); + + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::logout() +{ + MessageOut msg(PAMSG_LOGOUT); + Net::AccountServer::connection->send(msg); +} + +void Net::AccountServer::reconnectAccount(Net::Connection *connection, + const std::string &passToken) +{ + Net::AccountServer::connection = connection; + + MessageOut msg(PAMSG_RECONNECT); + msg.writeString(passToken, 32); + Net::AccountServer::connection->send(msg); +} diff --git a/src/net/tmwserv/accountserver/accountserver.h b/src/net/tmwserv/accountserver/accountserver.h new file mode 100644 index 00000000..dd62fd25 --- /dev/null +++ b/src/net/tmwserv/accountserver/accountserver.h @@ -0,0 +1,47 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_ACCOUNTSERVER_ACCOUNTSERVER_H +#define 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(); + + void reconnectAccount(Net::Connection *connection, + const std::string &passToken); + } +} + +#endif diff --git a/src/net/tmwserv/accountserver/internal.cpp b/src/net/tmwserv/accountserver/internal.cpp new file mode 100644 index 00000000..de1d412c --- /dev/null +++ b/src/net/tmwserv/accountserver/internal.cpp @@ -0,0 +1,32 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "internal.h" + +namespace Net +{ + class Connection; + + namespace AccountServer + { + Connection *connection = 0; + } +} diff --git a/src/net/tmwserv/accountserver/internal.h b/src/net/tmwserv/accountserver/internal.h new file mode 100644 index 00000000..ff741872 --- /dev/null +++ b/src/net/tmwserv/accountserver/internal.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_ACCOUNTSERVER_INTERNAL_H +#define NET_ACCOUNTSERVER_INTERNAL_H + +namespace Net +{ + class Connection; + + namespace AccountServer + { + extern Connection *connection; + } +} + +#endif diff --git a/src/net/tmwserv/beinghandler.cpp b/src/net/tmwserv/beinghandler.cpp new file mode 100644 index 00000000..1a1744cc --- /dev/null +++ b/src/net/tmwserv/beinghandler.cpp @@ -0,0 +1,357 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/beinghandler.h" + +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "being.h" +#include "beingmanager.h" +#include "game.h" +#include "localplayer.h" +#include "log.h" +#include "main.h" +#include "npc.h" +#include "particle.h" +#include "sound.h" + +#include "gui/ok_dialog.h" + +#include "utils/gettext.h" + +#include "net/tmwserv/gameserver/player.h" + +const int EMOTION_TIME = 150; /**< Duration of emotion icon */ + +BeingHandler::BeingHandler() +{ + static const Uint16 _messages[] = { + GPMSG_BEING_ATTACK, + GPMSG_BEING_ENTER, + GPMSG_BEING_LEAVE, + GPMSG_BEINGS_MOVE, + GPMSG_BEINGS_DAMAGE, + GPMSG_BEING_ACTION_CHANGE, + GPMSG_BEING_LOOKS_CHANGE, + GPMSG_BEING_DIR_CHANGE, + 0 + }; + handledMessages = _messages; +} + +void BeingHandler::handleMessage(MessageIn &msg) +{ + 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 GPMSG_BEING_ATTACK: + handleBeingAttackMessage(msg); + break; + case GPMSG_BEINGS_DAMAGE: + handleBeingsDamageMessage(msg); + break; + case GPMSG_BEING_ACTION_CHANGE: + handleBeingActionChangeMessage(msg); + break; + case GPMSG_BEING_LOOKS_CHANGE: + handleBeingLooksChangeMessage(msg); + break; + case GPMSG_BEING_DIR_CHANGE: + handleBeingDirChangeMessage(msg); + break; + } +} + +static void handleLooks(Player *being, MessageIn &msg) +{ + // Order of sent slots. Has to be in sync with the server code. + static int const nb_slots = 4; + static int const slots[nb_slots] = + { Being::WEAPON_SPRITE, Being::HAT_SPRITE, Being::TOPCLOTHES_SPRITE, + Being::BOTTOMCLOTHES_SPRITE }; + + int mask = msg.readInt8(); + + if (mask & (1 << 7)) + { + // The equipment has to be cleared first. + for (int i = 0; i < nb_slots; ++i) + { + being->setSprite(slots[i], 0); + } + } + + // Fill slots enumerated by the bitmask. + for (int i = 0; i < nb_slots; ++i) + { + if (!(mask & (1 << i))) continue; + int id = msg.readInt16(); + being->setSprite(slots[i], id); + } +} + +void BeingHandler::handleBeingEnterMessage(MessageIn &msg) +{ + int type = msg.readInt8(); + int id = msg.readInt16(); + Being::Action action = (Being::Action)msg.readInt8(); + int px = msg.readInt16(); + int py = msg.readInt16(); + Being *being; + + switch (type) + { + case OBJECT_PLAYER: + { + std::string name = msg.readString(); + if (player_node->getName() == name) + { + being = player_node; + being->setId(id); + } + else + { + being = beingManager->createBeing(id, type, 0); + being->setName(name); + } + Player *p = static_cast< Player * >(being); + int hs = msg.readInt8(), hc = msg.readInt8(); + p->setHairStyle(hs, hc); + p->setGender(msg.readInt8() == GENDER_MALE ? + GENDER_MALE : GENDER_FEMALE); + handleLooks(p, msg); + } break; + + case OBJECT_MONSTER: + case OBJECT_NPC: + { + int subtype = msg.readInt16(); + being = beingManager->createBeing(id, type, subtype); + std::string name = msg.readString(); + if (name.length() > 0) being->setName(name); + } break; + + default: + return; + } + + being->setPosition(px, py); + being->setDestination(px, py); + being->setAction(action); +} + +void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) +{ + Being *being = beingManager->findBeing(msg.readInt16()); + if (!being) return; + + beingManager->destroyBeing(being); +} + +void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) +{ + while (msg.getUnreadLength()) + { + int id = msg.readInt16(); + int flags = msg.readInt8(); + Being *being = beingManager->findBeing(id); + int sx = 0; + int sy = 0; + int dx = 0; + int dy = 0; + int speed = 0; + + printf("handleBeingsMoveMessage for %p (%s | %s)\n", + (void*) being, + (flags & MOVING_POSITION) ? "pos" : "", + (flags & MOVING_DESTINATION) ? "dest" : ""); + + if (flags & MOVING_POSITION) + { + Uint16 sx2, sy2; + msg.readCoordinates(sx2, sy2); + sx = sx2 * 32 + 16; + sy = sy2 * 32 + 16; + speed = msg.readInt8(); + } + if (flags & MOVING_DESTINATION) + { + dx = msg.readInt16(); + dy = msg.readInt16(); + if (!(flags & MOVING_POSITION)) + { + sx = dx; + sy = dy; + } + } + if (!being || !(flags & (MOVING_POSITION | MOVING_DESTINATION))) + { + continue; + } + if (speed) + { + /* The speed on the server is the cost of moving from one tile to + * the next. Beings get 1000 cost units per second. The speed is + * transferred as devided by 10, so that slower speeds fit in a + * byte. Here we convert the speed to pixels per second. + */ + const float tilesPerSecond = 100.0f / speed; + being->setWalkSpeed((int) (tilesPerSecond * 32)); + } + + // Ignore messages from the server for the local player + if (being == player_node) + continue; + + // If being is a player, and he only moves a little, its ok to be a little out of sync + if (being->getType() == Being::PLAYER && abs(being->getPixelX() - dx) + + abs(being->getPixelY() - dy) < 2 * 32 && + (dx != being->getDestination().x && dy != being->getDestination().y)) + { + being->setDestination(being->getPixelX(),being->getPixelY()); + continue; + } + if (abs(being->getPixelX() - sx) + + abs(being->getPixelY() - sy) > 10 * 32) + { + // Too large a desynchronization. + being->setPosition(sx, 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); + } + } +} + +void BeingHandler::handleBeingAttackMessage(MessageIn &msg) +{ + Being *being = beingManager->findBeing(msg.readInt16()); + int direction = msg.readInt8(); + int attackType = msg.readInt8(); + + if (!being) return; + + switch (direction) + { + case DIRECTION_UP: being->setDirection(Being::UP); break; + case DIRECTION_DOWN: being->setDirection(Being::DOWN); break; + case DIRECTION_LEFT: being->setDirection(Being::LEFT); break; + case DIRECTION_RIGHT: being->setDirection(Being::RIGHT); break; + } + + being->setAction(Being::ATTACK, attackType); +} + +void BeingHandler::handleBeingsDamageMessage(MessageIn &msg) +{ + while (msg.getUnreadLength()) + { + Being *being = beingManager->findBeing(msg.readInt16()); + int damage = msg.readInt16(); + if (being) + { + being->takeDamage(0, damage, Being::HIT); + } + } +} + +void BeingHandler::handleBeingActionChangeMessage(MessageIn &msg) +{ + Being* being = beingManager->findBeing(msg.readInt16()); + Being::Action action = (Being::Action) msg.readInt8(); + if (!being) return; + + being->setAction(action); + + if (action == Being::DEAD && being==player_node) + { + static char const *const deadMsg[] = + { + _("You are dead."), + _("We regret to inform you that your character was killed in battle."), + _("You are not that alive anymore."), + _("The cold hands of the grim reaper are grabbing for your soul."), + _("Game Over!"), + _("No, kids. Your character did not really die. It... err... went to a better place."), + _("Your plan of breaking your enemies weapon by bashing it with your throat failed."), + _("I guess this did not run too well."), + _("Do you want your possessions identified?"), // Nethack reference + _("Sadly, no trace of you was ever found..."), // Secret of Mana reference + _("Annihilated."), // Final Fantasy VI reference + _("Looks like you got your head handed to you."), //Earthbound reference + _("You screwed up again, dump your body down the tubes and get you another one.") // Leisure Suit Larry 1 Reference + + }; + std::string message(deadMsg[rand()%13]); + message.append(_(" Press OK to respawn")); + OkDialog *dlg = new OkDialog(_("You died"), message); + dlg->addActionListener(&(Net::GameServer::Player::respawnListener)); + } +} + +void BeingHandler::handleBeingLooksChangeMessage(MessageIn &msg) +{ + Being *being = beingManager->findBeing(msg.readInt16()); + if (!being || being->getType() != Being::PLAYER) return; + Player * player = static_cast< Player * >(being); + handleLooks(player, msg); + if (msg.getUnreadLength()) + { + int style = msg.readInt16(); + int color = msg.readInt16(); + player->setHairStyle(style, color); + player->setGender((Gender)msg.readInt16()); + } +} + +void BeingHandler::handleBeingDirChangeMessage(MessageIn &msg) +{ + Being *being = beingManager->findBeing(msg.readInt16()); + if (!being) return; + int data = msg.readInt8(); + switch (data) + { + case DIRECTION_UP: being->setDirection(Being::UP); break; + case DIRECTION_DOWN: being->setDirection(Being::DOWN); break; + case DIRECTION_LEFT: being->setDirection(Being::LEFT); break; + case DIRECTION_RIGHT: being->setDirection(Being::RIGHT); break; + } +} diff --git a/src/net/tmwserv/beinghandler.h b/src/net/tmwserv/beinghandler.h new file mode 100644 index 00000000..0ca186f0 --- /dev/null +++ b/src/net/tmwserv/beinghandler.h @@ -0,0 +1,45 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_BEINGHANDLER_H +#define NET_TMWSERV_BEINGHANDLER_H + +#include "net/messagehandler.h" + +class BeingHandler : public MessageHandler +{ + public: + BeingHandler(); + + void handleMessage(MessageIn &msg); + + private: + void handleBeingAttackMessage(MessageIn &msg); + void handleBeingEnterMessage(MessageIn &msg); + void handleBeingLeaveMessage(MessageIn &msg); + void handleBeingsMoveMessage(MessageIn &msg); + void handleBeingsDamageMessage(MessageIn &msg); + void handleBeingActionChangeMessage(MessageIn &msg); + void handleBeingLooksChangeMessage(MessageIn &msg); + void handleBeingDirChangeMessage(MessageIn &msg); +}; + +#endif diff --git a/src/net/tmwserv/buysellhandler.cpp b/src/net/tmwserv/buysellhandler.cpp new file mode 100644 index 00000000..bab475d2 --- /dev/null +++ b/src/net/tmwserv/buysellhandler.cpp @@ -0,0 +1,91 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/buysellhandler.h" + +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "beingmanager.h" +#include "item.h" +#include "localplayer.h" +#include "npc.h" + +#include "gui/buy.h" +#include "gui/chat.h" +#include "gui/sell.h" + +extern BuyDialog *buyDialog; +extern SellDialog *sellDialog; +extern Window *buySellDialog; + +BuySellHandler::BuySellHandler() +{ + static const Uint16 _messages[] = { + GPMSG_NPC_BUY, + GPMSG_NPC_SELL, + 0 + }; + handledMessages = _messages; +} + +void BuySellHandler::handleMessage(MessageIn &msg) +{ + Being *being = beingManager->findBeing(msg.readInt16()); + if (!being || being->getType() != Being::NPC) + { + return; + } + + current_npc = being->getId(); + + switch (msg.getId()) + { + case GPMSG_NPC_BUY: + buyDialog->reset(); + buyDialog->setMoney(player_node->getMoney()); + buyDialog->setVisible(true); + + while (msg.getUnreadLength()) + { + int itemId = msg.readInt16(); + int amount = msg.readInt16(); + int value = msg.readInt16(); + buyDialog->addItem(itemId, amount, value); + } + break; + + case GPMSG_NPC_SELL: + sellDialog->setMoney(player_node->getMoney()); + sellDialog->reset(); + sellDialog->setVisible(true); + + while (msg.getUnreadLength()) + { + int itemId = msg.readInt16(); + int amount = msg.readInt16(); + int value = msg.readInt16(); + sellDialog->addItem(itemId, amount, value); + } + break; + } +} diff --git a/src/net/buysellhandler.h b/src/net/tmwserv/buysellhandler.h index 2b4aaf4f..32f273f1 100644 --- a/src/net/buysellhandler.h +++ b/src/net/tmwserv/buysellhandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_BUYSELLHANDLER_H -#define NET_BUYSELLHANDLER_H +#ifndef NET_TMWSERV_BUYSELLHANDLER_H +#define NET_TMWSERV_BUYSELLHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class BuySellHandler : public MessageHandler { public: BuySellHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/tmwserv/charserverhandler.cpp b/src/net/tmwserv/charserverhandler.cpp new file mode 100644 index 00000000..0779e499 --- /dev/null +++ b/src/net/tmwserv/charserverhandler.cpp @@ -0,0 +1,228 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/charserverhandler.h" + +#include "net/tmwserv/connection.h" +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "game.h" +#include "localplayer.h" +#include "log.h" +#include "logindata.h" +#include "main.h" + +#include "gui/ok_dialog.h" +#include "gui/char_select.h" + +extern Net::Connection *gameServerConnection; +extern Net::Connection *chatServerConnection; + +CharServerHandler::CharServerHandler(): + mCharCreateDialog(0) +{ + static const Uint16 _messages[] = { + APMSG_CHAR_CREATE_RESPONSE, + APMSG_CHAR_DELETE_RESPONSE, + APMSG_CHAR_INFO, + APMSG_CHAR_SELECT_RESPONSE, + 0 + }; + handledMessages = _messages; +} + +void CharServerHandler::handleMessage(MessageIn &msg) +{ + int slot; + LocalPlayer *tempPlayer; + + switch (msg.getId()) + { + case APMSG_CHAR_CREATE_RESPONSE: + handleCharCreateResponse(msg); + break; + + case APMSG_CHAR_DELETE_RESPONSE: + { + int errMsg = msg.readInt8(); + // Character deletion successful + if (errMsg == ERRMSG_OK) + { + delete mCharInfo->getEntry(); + mCharInfo->setEntry(0); + mCharInfo->unlock(); + new OkDialog("Info", "Player deleted"); + } + // 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); + } + } + break; + + case APMSG_CHAR_INFO: + tempPlayer = readPlayerData(msg, slot); + mCharInfo->unlock(); + mCharInfo->select(slot); + mCharInfo->setEntry(tempPlayer); + + // Close the character create dialog + if (mCharCreateDialog) + { + mCharCreateDialog->scheduleDelete(); + mCharCreateDialog = 0; + } + break; + + case APMSG_CHAR_SELECT_RESPONSE: + handleCharSelectResponse(msg); + break; + } +} + +void CharServerHandler::handleCharCreateResponse(MessageIn &msg) +{ + int errMsg = msg.readInt8(); + + // 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_EQUAL_TO_ZERO: + message = "One stat is zero"; + break; + default: + message = "Unknown error"; + break; + } + new OkDialog("Error", message); + } + + if (mCharCreateDialog) + mCharCreateDialog->unlock(); +} + +void CharServerHandler::handleCharSelectResponse(MessageIn &msg) +{ + int errMsg = msg.readInt8(); + + if (errMsg == ERRMSG_OK) + { + token = msg.readString(32); + std::string gameServer = msg.readString(); + unsigned short gameServerPort = msg.readInt16(); + std::string chatServer = msg.readString(); + unsigned short chatServerPort = msg.readInt16(); + + 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(); + int slot = mCharInfo->getPos(); + mCharInfo->unlock(); + mCharInfo->select(0); + + do { + LocalPlayer *tmp = mCharInfo->getEntry(); + if (tmp != player_node) + { + delete tmp; + mCharInfo->setEntry(0); + } + mCharInfo->next(); + } while (mCharInfo->getPos()); + mCharInfo->select(slot); + + mCharInfo->clear(); //player_node will be deleted by ~Game + + state = STATE_CONNECT_GAME; + } +} + +LocalPlayer* CharServerHandler::readPlayerData(MessageIn &msg, int &slot) +{ + LocalPlayer *tempPlayer = new LocalPlayer; + slot = msg.readInt8(); // character slot + tempPlayer->setName(msg.readString()); + tempPlayer->setGender(msg.readInt8() == GENDER_MALE ? GENDER_MALE : GENDER_FEMALE); + int hs = msg.readInt8(), hc = msg.readInt8(); + tempPlayer->setHairStyle(hs, hc); + tempPlayer->setLevel(msg.readInt16()); + tempPlayer->setCharacterPoints(msg.readInt16()); + tempPlayer->setCorrectionPoints(msg.readInt16()); + tempPlayer->setMoney(msg.readInt32()); + + for (int i = 0; i < 7; i++) + { + tempPlayer->setAttributeBase(i, msg.readInt8()); + } + + return tempPlayer; +} diff --git a/src/net/tmwserv/charserverhandler.h b/src/net/tmwserv/charserverhandler.h new file mode 100644 index 00000000..e1e13b55 --- /dev/null +++ b/src/net/tmwserv/charserverhandler.h @@ -0,0 +1,68 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_CHARSERVERHANDLER_H +#define NET_TMWSERV_CHARSERVERHANDLER_H + +#include "net/messagehandler.h" + +#include "lockedarray.h" + +class CharCreateDialog; +class LocalPlayer; +class LoginData; + +/** + * Deals with incoming messages related to character selection. + */ +class CharServerHandler : public MessageHandler +{ + public: + CharServerHandler(); + + void handleMessage(MessageIn &msg); + + void setCharInfo(LockedArray<LocalPlayer*> *charInfo) + { + mCharInfo = charInfo; + } + + /** + * Sets the character create dialog. The handler will clean up this + * dialog when a new character is succesfully created, and will unlock + * the dialog when a new character failed to be created. + */ + void setCharCreateDialog(CharCreateDialog *window) + { mCharCreateDialog = window; } + + protected: + void handleCharCreateResponse(MessageIn &msg); + + void handleCharSelectResponse(MessageIn &msg); + + LockedArray<LocalPlayer*> *mCharInfo; + CharCreateDialog *mCharCreateDialog; + + LocalPlayer* + readPlayerData(MessageIn &msg, int &slot); +}; + +#endif diff --git a/src/net/tmwserv/chathandler.cpp b/src/net/tmwserv/chathandler.cpp new file mode 100644 index 00000000..1c537e30 --- /dev/null +++ b/src/net/tmwserv/chathandler.cpp @@ -0,0 +1,285 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/chathandler.h" + +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "being.h" +#include "beingmanager.h" +#include "game.h" +#include "channel.h" +#include "channelmanager.h" + +#include "gui/widgets/channeltab.h" +#include "gui/chat.h" +#include "gui/guildwindow.h" + +#include <string> +#include <iostream> + +#include "utils/gettext.h" + +extern Being *player_node; + +ChatHandler::ChatHandler() +{ + static const Uint16 _messages[] = { + GPMSG_SAY, + CPMSG_ENTER_CHANNEL_RESPONSE, + CPMSG_LIST_CHANNELS_RESPONSE, + CPMSG_PUBMSG, + CPMSG_ANNOUNCEMENT, + CPMSG_PRIVMSG, + CPMSG_QUIT_CHANNEL_RESPONSE, + CPMSG_LIST_CHANNELUSERS_RESPONSE, + CPMSG_CHANNEL_EVENT, + 0 + }; + handledMessages = _messages; +} + +void ChatHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case GPMSG_SAY: + handleGameChatMessage(msg); + break; + + case CPMSG_ENTER_CHANNEL_RESPONSE: + handleEnterChannelResponse(msg); + break; + + case CPMSG_LIST_CHANNELS_RESPONSE: + handleListChannelsResponse(msg); + break; + + case CPMSG_PRIVMSG: + handlePrivateMessage(msg); + break; + + case CPMSG_ANNOUNCEMENT: + handleAnnouncement(msg); + break; + + case CPMSG_PUBMSG: + handleChatMessage(msg); + break; + + case CPMSG_QUIT_CHANNEL_RESPONSE: + handleQuitChannelResponse(msg); + break; + + case CPMSG_LIST_CHANNELUSERS_RESPONSE: + handleListChannelUsersResponse(msg); + break; + + case CPMSG_CHANNEL_EVENT: + handleChannelEvent(msg); + } +} + +void ChatHandler::handleGameChatMessage(MessageIn &msg) +{ + short id = msg.readInt16(); + std::string chatMsg = msg.readString(); + + if (id == 0) + { + localChatTab->chatLog(chatMsg, BY_SERVER); + return; + } + + Being *being = beingManager->findBeing(id); + + std::string mes; + if (being) + { + mes = being->getName() + " : " + chatMsg; + being->setSpeech(chatMsg, SPEECH_TIME); + } + else + mes = "Unknown : " + chatMsg; + + localChatTab->chatLog(mes, being == player_node ? BY_PLAYER : BY_OTHER); +} + +void ChatHandler::handleEnterChannelResponse(MessageIn &msg) +{ + if(msg.readInt8() == ERRMSG_OK) + { + short channelId = msg.readInt16(); + std::string channelName = msg.readString(); + std::string announcement = msg.readString(); + Channel *channel = new Channel(channelId, channelName, announcement); + channelManager->addChannel(channel); + ChatTab *tab = channel->getTab(); + tab->chatLog(_("Topic: ") + announcement, BY_CHANNEL); + + std::string user; + std::string userModes; + tab->chatLog("Players in this channel:", BY_CHANNEL); + while(msg.getUnreadLength()) + { + user = msg.readString(); + if (user == "") + return; + userModes = msg.readString(); + if (userModes.find('o') != std::string::npos) + { + user = "@" + user; + } + tab->chatLog(user, BY_CHANNEL); + } + + } + else + { + localChatTab->chatLog("Error joining channel", BY_SERVER); + } +} + +void ChatHandler::handleListChannelsResponse(MessageIn &msg) +{ + localChatTab->chatLog("Listing Channels", BY_SERVER); + while(msg.getUnreadLength()) + { + std::string channelName = msg.readString(); + if (channelName == "") + return; + std::ostringstream numUsers; + numUsers << msg.readInt16(); + channelName += " - "; + channelName += numUsers.str(); + localChatTab->chatLog(channelName, BY_SERVER); + } + localChatTab->chatLog("End of channel list", BY_SERVER); +} + +void ChatHandler::handlePrivateMessage(MessageIn &msg) +{ + std::string userNick = msg.readString(); + std::string chatMsg = msg.readString(); + + chatWindow->whisper(userNick, chatMsg); +} + +void ChatHandler::handleAnnouncement(MessageIn &msg) +{ + std::string chatMsg = msg.readString(); + localChatTab->chatLog(chatMsg, BY_GM); +} + +void ChatHandler::handleChatMessage(MessageIn &msg) +{ + short channelId = msg.readInt16(); + std::string userNick = msg.readString(); + std::string chatMsg = msg.readString(); + + Channel *channel = channelManager->findById(channelId); + channel->getTab()->chatLog(userNick, chatMsg); +} + +void ChatHandler::handleQuitChannelResponse(MessageIn &msg) +{ + if(msg.readInt8() == ERRMSG_OK) + { + short channelId = msg.readInt16(); + Channel *channel = channelManager->findById(channelId); + channelManager->removeChannel(channel); + } +} + +void ChatHandler::handleListChannelUsersResponse(MessageIn &msg) +{ + std::string channelName = msg.readString(); + std::string userNick; + std::string userModes; + Channel *channel = channelManager->findByName(channelName); + channel->getTab()->chatLog("Players in this channel:", BY_CHANNEL); + while(msg.getUnreadLength()) + { + userNick = msg.readString(); + if (userNick == "") + { + break; + } + userModes = msg.readString(); + if (userModes.find('o') != std::string::npos) + { + userNick = "@" + userNick; + } + localChatTab->chatLog(userNick, BY_CHANNEL, channel); + } +} + +void ChatHandler::handleChannelEvent(MessageIn &msg) +{ + short channelId = msg.readInt16(); + char eventId = msg.readInt8(); + std::string line = msg.readString(); + Channel *channel = channelManager->findById(channelId); + + if(channel) + { + switch(eventId) + { + case CHAT_EVENT_NEW_PLAYER: + line += " entered the channel."; + break; + + case CHAT_EVENT_LEAVING_PLAYER: + line += " left the channel."; + break; + + case CHAT_EVENT_TOPIC_CHANGE: + line = "Topic: " + line; + break; + + case CHAT_EVENT_MODE_CHANGE: + { + int first = line.find(":"); + int second = line.find(":", first+1); + std::string user1 = line.substr(0, first); + std::string user2 = line.substr(first+1, second); + std::string mode = line.substr(second+1, line.length()); + line = user1 + " has set mode " + mode + " on user " + user2; + } break; + + case CHAT_EVENT_KICKED_PLAYER: + { + int first = line.find(":"); + std::string user1 = line.substr(0, first); + std::string user2 = line.substr(first+1, line.length()); + line = user1 + " has kicked " + user2; + } break; + + default: + line = "Unknown channel event."; + } + + channel->getTab()->chatLog(line, BY_CHANNEL); + } +} + diff --git a/src/net/tmwserv/chathandler.h b/src/net/tmwserv/chathandler.h new file mode 100644 index 00000000..f0604da8 --- /dev/null +++ b/src/net/tmwserv/chathandler.h @@ -0,0 +1,84 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_CHATHANDLER_H +#define NET_TMWSERV_CHATHANDLER_H + +#include "net/messagehandler.h" + +class ChatHandler : public MessageHandler +{ + public: + ChatHandler(); + + /** + * Handle the given message appropriately. + */ + void handleMessage(MessageIn &msg); + + private: + /** + * Handle chat messages sent from the game server. + */ + void handleGameChatMessage(MessageIn &msg); + + /** + * Handle channel entry responses. + */ + void handleEnterChannelResponse(MessageIn &msg); + + /** + * Handle list channels responses. + */ + void handleListChannelsResponse(MessageIn &msg); + + /** + * Handle private messages. + */ + void handlePrivateMessage(MessageIn &msg); + + /** + * Handle announcements. + */ + void handleAnnouncement(MessageIn &msg); + + /** + * Handle chat messages. + */ + void handleChatMessage(MessageIn &msg); + + /** + * Handle quit channel responses. + */ + void handleQuitChannelResponse(MessageIn &msg); + + /** + * Handle list channel users responses. + */ + void handleListChannelUsersResponse(MessageIn &msg); + + /** + * Handle channel events. + */ + void handleChannelEvent(MessageIn &msg); +}; + +#endif diff --git a/src/net/tmwserv/chatserver/chatserver.cpp b/src/net/tmwserv/chatserver/chatserver.cpp new file mode 100644 index 00000000..49a17367 --- /dev/null +++ b/src/net/tmwserv/chatserver/chatserver.cpp @@ -0,0 +1,147 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "chatserver.h" + +#include "internal.h" + +#include "net/tmwserv/connection.h" +#include "net/tmwserv/protocol.h" + +#include "net/messageout.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::logout() +{ + MessageOut msg(PCMSG_DISCONNECT); + + connection->send(msg); +} + +void Net::ChatServer::chat(short channel, const std::string &text) +{ + MessageOut msg(PCMSG_CHAT); + + msg.writeString(text); + msg.writeInt16(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::enterChannel(const std::string &channel, const std::string &password) +{ + MessageOut msg(PCMSG_ENTER_CHANNEL); + + msg.writeString(channel); + msg.writeString(password); + + connection->send(msg); +} + +void Net::ChatServer::quitChannel(short channel) +{ + MessageOut msg(PCMSG_QUIT_CHANNEL); + + msg.writeInt16(channel); + + connection->send(msg); +} + +void Net::ChatServer::getChannelList() +{ + MessageOut msg(PCMSG_LIST_CHANNELS); + + connection->send(msg); +} + +void Net::ChatServer::getUserList(const std::string &channel) +{ + MessageOut msg(PCMSG_LIST_CHANNELUSERS); + + msg.writeString(channel); + + connection->send(msg); +} + +void Net::ChatServer::setChannelTopic(short channel, const std::string &topic) +{ + MessageOut msg(PCMSG_TOPIC_CHANGE); + + msg.writeInt16(channel); + msg.writeString(topic); + + connection->send(msg); +} + +void Net::ChatServer::setUserMode(short channel, const std::string &user, + unsigned char mode) +{ + MessageOut msg(PCMSG_USER_MODE); + + msg.writeInt16(channel); + msg.writeString(user); + msg.writeInt8(mode); + + connection->send(msg); +} + +void Net::ChatServer::kickUser(short channel, const std::string &user) +{ + MessageOut msg(PCMSG_KICK_USER); + + msg.writeInt16(channel); + msg.writeString(user); + + connection->send(msg); +} diff --git a/src/net/tmwserv/chatserver/chatserver.h b/src/net/tmwserv/chatserver/chatserver.h new file mode 100644 index 00000000..8a6025a7 --- /dev/null +++ b/src/net/tmwserv/chatserver/chatserver.h @@ -0,0 +1,60 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_CHATSERVER_CHATSERVER_H +#define NET_CHATSERVER_CHATSERVER_H + +#include <iosfwd> + +namespace Net +{ + class Connection; + + namespace ChatServer + { + void connect(Net::Connection *connection, const std::string &token); + + void logout(); + + 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 enterChannel(const std::string &channel, const std::string &password); + + void quitChannel(short channel); + + void getChannelList(); + + void getUserList(const std::string &channel); + + void setChannelTopic(short channel, const std::string &topic); + + void setUserMode(short channel, const std::string &user, unsigned char mode); + + void kickUser(short channel, const std::string &user); + + } +} + +#endif diff --git a/src/net/tmwserv/chatserver/guild.cpp b/src/net/tmwserv/chatserver/guild.cpp new file mode 100644 index 00000000..740e9efa --- /dev/null +++ b/src/net/tmwserv/chatserver/guild.cpp @@ -0,0 +1,95 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "guild.h" + +#include "internal.h" + +#include "net/tmwserv/connection.h" +#include "net/tmwserv/protocol.h" + +#include "net/messageout.h" + +#include "log.h" + +void Net::ChatServer::Guild::createGuild(const std::string &name) +{ + logger->log("Sending PCMSG_GUILD_CREATE"); + MessageOut msg(PCMSG_GUILD_CREATE); + + msg.writeString(name); + + Net::ChatServer::connection->send(msg); +} + +void Net::ChatServer::Guild::invitePlayer(const std::string &name, short guildId) +{ + logger->log("Sending PCMSG_GUILD_INVITE"); + MessageOut msg(PCMSG_GUILD_INVITE); + + msg.writeInt16(guildId); + msg.writeString(name); + + Net::ChatServer::connection->send(msg); +} + +void Net::ChatServer::Guild::acceptInvite(const std::string &name) +{ + logger->log("Sending PCMSG_GUILD_ACCEPT"); + MessageOut msg(PCMSG_GUILD_ACCEPT); + + msg.writeString(name); + + Net::ChatServer::connection->send(msg); +} + +void Net::ChatServer::Guild::getGuildMembers(short guildId) +{ + logger->log("Sending PCMSG_GUILD_GET_MEMBERS"); + MessageOut msg(PCMSG_GUILD_GET_MEMBERS); + + msg.writeInt16(guildId); + + Net::ChatServer::connection->send(msg); +} + +void Net::ChatServer::Guild::promoteMember(const std::string &name, + short guildId, short level) +{ + logger->log("Sending PCMSG_GUILD_PROMOTE_MEMBER"); + MessageOut msg(PCMSG_GUILD_PROMOTE_MEMBER); + + msg.writeInt16(guildId); + msg.writeString(name); + msg.writeInt8(level); + + Net::ChatServer::connection->send(msg); +} + +void Net::ChatServer::Guild::quitGuild(short guildId) +{ + logger->log("Sending PCMSG_GUILD_QUIT"); + MessageOut msg(PCMSG_GUILD_QUIT); + + msg.writeInt16(guildId); + + Net::ChatServer::connection->send(msg); +} diff --git a/src/net/tmwserv/chatserver/guild.h b/src/net/tmwserv/chatserver/guild.h new file mode 100644 index 00000000..2e9cf9a6 --- /dev/null +++ b/src/net/tmwserv/chatserver/guild.h @@ -0,0 +1,67 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_CHATSERVER_GUILD_H +#define NET_CHATSERVER_GUILD_H + +#include <iosfwd> + +namespace Net +{ + namespace ChatServer + { + namespace Guild + { + /** + * Create guild. + */ + void createGuild(const std::string &name); + + /** + * Invite a player to your guild. + */ + void invitePlayer(const std::string &name, short guildId); + + /** + * Accept an invite another player has sent to join their guild. + */ + void acceptInvite(const std::string &name); + + /** + * Get a list of members in a guild. + */ + void getGuildMembers(short guildId); + + /** + * Promote guild member + */ + void promoteMember(const std::string &name, short guildId, + short level); + + /** + * Quit guild. + */ + void quitGuild(short guildId); + } + } +} + +#endif diff --git a/src/net/tmwserv/chatserver/internal.cpp b/src/net/tmwserv/chatserver/internal.cpp new file mode 100644 index 00000000..52744804 --- /dev/null +++ b/src/net/tmwserv/chatserver/internal.cpp @@ -0,0 +1,32 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "internal.h" + +namespace Net +{ + class Connection; + + namespace ChatServer + { + Connection *connection = 0; + } +} diff --git a/src/net/tmwserv/chatserver/internal.h b/src/net/tmwserv/chatserver/internal.h new file mode 100644 index 00000000..162d54fb --- /dev/null +++ b/src/net/tmwserv/chatserver/internal.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_CHATSERVER_INTERNAL_H +#define NET_CHATSERVER_INTERNAL_H + +namespace Net +{ + class Connection; + + namespace ChatServer + { + extern Connection *connection; + } +} + +#endif diff --git a/src/net/tmwserv/chatserver/party.cpp b/src/net/tmwserv/chatserver/party.cpp new file mode 100644 index 00000000..e5bdd861 --- /dev/null +++ b/src/net/tmwserv/chatserver/party.cpp @@ -0,0 +1,69 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "party.h" + +#include "internal.h" + +#include "net/tmwserv/connection.h" +#include "net/tmwserv/protocol.h" + +#include "net/messageout.h" + +#include "log.h" + +void Net::ChatServer::Party::invitePlayer(const std::string &name) +{ + logger->log("Sending PCMSG_PARTY_INVITE"); + MessageOut msg(PCMSG_PARTY_INVITE); + + msg.writeString(name); + + Net::ChatServer::connection->send(msg); +} + +void Net::ChatServer::Party::acceptInvite(const std::string &name) +{ + logger->log("Sending PCMSG_PARTY_ACCEPT_INVITE"); + MessageOut msg(PCMSG_PARTY_ACCEPT_INVITE); + + msg.writeString(name); + + Net::ChatServer::connection->send(msg); +} + +void Net::ChatServer::Party::getPartyMembers() +{ + logger->log("Sending PCMSG_PARTY_GET_MEMBERS"); +// MessageOut msg(PCMSG_GUILD_GET_MEMBERS); + +// msg.writeInt16(guildId); + +// Net::ChatServer::connection->send(msg); +} + +void Net::ChatServer::Party::quitParty() +{ + logger->log("Sending PCMSG_PARTY_QUIT"); + MessageOut msg(PCMSG_PARTY_QUIT); + + Net::ChatServer::connection->send(msg); +} diff --git a/src/net/tmwserv/chatserver/party.h b/src/net/tmwserv/chatserver/party.h new file mode 100644 index 00000000..b3f0020b --- /dev/null +++ b/src/net/tmwserv/chatserver/party.h @@ -0,0 +1,56 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_CHATSERVER_PARTY_H +#define NET_CHATSERVER_PARTY_H + +#include <iosfwd> + +namespace Net +{ + namespace ChatServer + { + namespace Party + { + /** + * Invite a player to the party. + */ + void invitePlayer(const std::string &name); + + /** + * Accept an invite another player has sent to join their party + */ + void acceptInvite(const std::string &name); + + /** + * Get a list of party members + */ + void getPartyMembers(); + + /** + * Leave party + */ + void quitParty(); + } + } +} + +#endif diff --git a/src/net/tmwserv/connection.cpp b/src/net/tmwserv/connection.cpp new file mode 100644 index 00000000..0fcd530b --- /dev/null +++ b/src/net/tmwserv/connection.cpp @@ -0,0 +1,104 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/connection.h" + +#include "net/tmwserv/internal.h" + +#include "net/messageout.h" + +#include "log.h" + +#include <string> + +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 = NET_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 = NET_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 bool (mConnection) ? + (mConnection->state == ENET_PEER_STATE_CONNECTED) : false; +} + +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/tmwserv/connection.h b/src/net/tmwserv/connection.h new file mode 100644 index 00000000..447cf71c --- /dev/null +++ b/src/net/tmwserv/connection.h @@ -0,0 +1,80 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_CONNECTION_H +#define NET_TMWSERV_CONNECTION_H + +#include <iosfwd> + +#include <enet/enet.h> + +class MessageOut; + +namespace Net +{ + /** + * \ingroup Network + */ + class Connection + { + public: + enum State { + OK, + NET_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/tmwserv/effecthandler.cpp b/src/net/tmwserv/effecthandler.cpp new file mode 100644 index 00000000..d2b26fca --- /dev/null +++ b/src/net/tmwserv/effecthandler.cpp @@ -0,0 +1,59 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/effecthandler.h" + +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "effectmanager.h" + + +EffectHandler::EffectHandler() +{ + static const Uint16 _messages[] = { + GPMSG_CREATE_EFFECT, + 0 + }; + handledMessages = _messages; +} + +void EffectHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case GPMSG_CREATE_EFFECT: + handleCreateEffects(msg); + break; + default: + break; + } +} + +void EffectHandler::handleCreateEffects(MessageIn &msg) +{ + int id = msg.readInt16(); + Uint16 x = msg.readInt16(); + Uint16 y = msg.readInt16(); + effectManager->trigger(id, x, y); +} + diff --git a/src/net/tmwserv/effecthandler.h b/src/net/tmwserv/effecthandler.h new file mode 100644 index 00000000..894ad1c8 --- /dev/null +++ b/src/net/tmwserv/effecthandler.h @@ -0,0 +1,38 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_EFFECTSHANDLER_H +#define NET_TMWSERV_EFFECTSHANDLER_H + +#include "net/messagehandler.h" + +class EffectHandler : public MessageHandler +{ + public: + EffectHandler(); + + void handleMessage(MessageIn &msg); + + private: + void handleCreateEffects(MessageIn &msg); +}; + +#endif diff --git a/src/net/tmwserv/gameserver/gameserver.cpp b/src/net/tmwserv/gameserver/gameserver.cpp new file mode 100644 index 00000000..e70c4d19 --- /dev/null +++ b/src/net/tmwserv/gameserver/gameserver.cpp @@ -0,0 +1,50 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "gameserver.h" + +#include "internal.h" + +#include "net/tmwserv/connection.h" +#include "net/tmwserv/protocol.h" + +#include "net/messageout.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); +} + +void Net::GameServer::logout(bool reconnectAccount) +{ + MessageOut msg(PGMSG_DISCONNECT); + + msg.writeInt8((unsigned char) reconnectAccount); + + Net::GameServer::connection->send(msg); +} diff --git a/src/net/tmwserv/gameserver/gameserver.h b/src/net/tmwserv/gameserver/gameserver.h new file mode 100644 index 00000000..6de82c2e --- /dev/null +++ b/src/net/tmwserv/gameserver/gameserver.h @@ -0,0 +1,39 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_GAMESERVER_GAMESERVER_H +#define NET_GAMESERVER_GAMESERVER_H + +#include <iosfwd> + +namespace Net +{ + class Connection; + + namespace GameServer + { + void connect(Net::Connection *connection, const std::string &token); + + void logout(bool reconnectAccount); + } +} + +#endif diff --git a/src/net/tmwserv/gameserver/internal.cpp b/src/net/tmwserv/gameserver/internal.cpp new file mode 100644 index 00000000..27cb4a47 --- /dev/null +++ b/src/net/tmwserv/gameserver/internal.cpp @@ -0,0 +1,32 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "internal.h" + +namespace Net +{ + class Connection; + + namespace GameServer + { + Connection *connection = 0; + } +} diff --git a/src/net/tmwserv/gameserver/internal.h b/src/net/tmwserv/gameserver/internal.h new file mode 100644 index 00000000..6c6e2613 --- /dev/null +++ b/src/net/tmwserv/gameserver/internal.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_GAMESERVER_INTERNAL_H +#define NET_GAMESERVER_INTERNAL_H + +namespace Net +{ + class Connection; + + namespace GameServer + { + extern Connection *connection; + } +} + +#endif diff --git a/src/net/tmwserv/gameserver/player.cpp b/src/net/tmwserv/gameserver/player.cpp new file mode 100644 index 00000000..ec346d9f --- /dev/null +++ b/src/net/tmwserv/gameserver/player.cpp @@ -0,0 +1,203 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "player.h" + +#include "internal.h" + +#include "net/tmwserv/connection.h" +#include "net/tmwserv/protocol.h" + +#include "net/messageout.h" + +void RespawnRequestListener::action(const gcn::ActionEvent &event) +{ + Net::GameServer::Player::respawn(); +} + +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(int x, int y) +{ + MessageOut msg(PGMSG_WALK); + msg.writeInt16(x); + msg.writeInt16(y); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::pickUp(int x, int y) +{ + MessageOut msg(PGMSG_PICKUP); + msg.writeInt16(x); + msg.writeInt16(y); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::moveItem(int oldSlot, int newSlot, int amount) +{ + MessageOut msg(PGMSG_MOVE_ITEM); + msg.writeInt8(oldSlot); + msg.writeInt8(newSlot); + msg.writeInt8(amount); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::drop(int slot, int amount) +{ + MessageOut msg(PGMSG_DROP); + msg.writeInt8(slot); + msg.writeInt8(amount); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::equip(int slot) +{ + MessageOut msg(PGMSG_EQUIP); + msg.writeInt8(slot); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::unequip(int slot) +{ + MessageOut msg(PGMSG_UNEQUIP); + msg.writeInt8(slot); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::useItem(int slot) +{ + MessageOut msg(PGMSG_USE_ITEM); + msg.writeInt8(slot); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::attack(int direction) +{ + MessageOut msg(PGMSG_ATTACK); + msg.writeInt8(direction); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::useSpecial(int special) +{ + MessageOut msg(PGMSG_USE_SPECIAL); + msg.writeInt8(special); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::changeAction(Being::Action action) +{ + MessageOut msg(PGMSG_ACTION_CHANGE); + msg.writeInt8(action); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::talkToNPC(int id, bool restart) +{ + MessageOut msg(restart ? PGMSG_NPC_TALK : PGMSG_NPC_TALK_NEXT); + msg.writeInt16(id); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::selectFromNPC(int id, int choice) +{ + MessageOut msg(PGMSG_NPC_SELECT); + msg.writeInt16(id); + msg.writeInt8(choice); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::requestTrade(int id) +{ + MessageOut msg(PGMSG_TRADE_REQUEST); + msg.writeInt16(id); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::acceptTrade(bool accept) +{ + MessageOut msg(accept ? PGMSG_TRADE_ACCEPT : PGMSG_TRADE_CANCEL); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::tradeItem(int slot, int amount) +{ + MessageOut msg(PGMSG_TRADE_ADD_ITEM); + msg.writeInt8(slot); + msg.writeInt8(amount); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::tradeMoney(int amount) +{ + MessageOut msg(PGMSG_TRADE_SET_MONEY); + msg.writeInt32(amount); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::tradeWithNPC(int item, int amount) +{ + MessageOut msg(PGMSG_NPC_BUYSELL); + msg.writeInt16(item); + msg.writeInt16(amount); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::sendLetter(const std::string &player, + const std::string &text) +{ + MessageOut msg(PGMSG_NPC_POST_SEND); + msg.writeString(player); + msg.writeString(text); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::raiseAttribute(int attribute) +{ + MessageOut msg(PGMSG_RAISE_ATTRIBUTE); + msg.writeInt8(attribute); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::lowerAttribute(int attribute) +{ + MessageOut msg(PGMSG_LOWER_ATTRIBUTE); + msg.writeInt8(attribute); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::respawn() +{ + MessageOut msg(PGMSG_RESPAWN); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::changeDir(unsigned char dir) +{ + MessageOut msg(PGMSG_DIRECTION_CHANGE); + msg.writeInt8(dir); + Net::GameServer::connection->send(msg); +} diff --git a/src/net/tmwserv/gameserver/player.h b/src/net/tmwserv/gameserver/player.h new file mode 100644 index 00000000..3f33c7d5 --- /dev/null +++ b/src/net/tmwserv/gameserver/player.h @@ -0,0 +1,71 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_GAMESERVER_PLAYER_H +#define NET_GAMESERVER_PLAYER_H + +#include "being.h" + +#include <guichan/actionlistener.hpp> + +#include <iosfwd> + + +struct RespawnRequestListener : public gcn::ActionListener +{ + void action(const gcn::ActionEvent &event); +}; + +namespace Net +{ + namespace GameServer + { + namespace Player + { + void say(const std::string &text); + void walk(int x, int y); + void pickUp(int x, int y); + void moveItem(int oldSlot, int newSlot, int amount); + void drop(int slot, int amount); + void equip(int slot); + void unequip(int slot); + void useItem(int slot); + void attack(int direction); + void useSpecial(int special); + void changeAction(Being::Action action); + void talkToNPC(int id, bool restart); + void selectFromNPC(int id, int choice); + void requestTrade(int id); + void acceptTrade(bool accept); + void tradeItem(int slot, int amount); + void tradeMoney(int amount); + void tradeWithNPC(int item, int amount); + void sendLetter(const std::string &player, const std::string &text); + void raiseAttribute(int attribute); + void lowerAttribute(int attribute); + void respawn(); + static RespawnRequestListener respawnListener; + void changeDir(unsigned char dir); + } + } +} + +#endif diff --git a/src/net/tmwserv/guildhandler.cpp b/src/net/tmwserv/guildhandler.cpp new file mode 100644 index 00000000..21b43063 --- /dev/null +++ b/src/net/tmwserv/guildhandler.cpp @@ -0,0 +1,243 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/guildhandler.h" + +#include "net/messagein.h" + +#include "net/tmwserv/chatserver/chatserver.h" +#include "net/tmwserv/chatserver/guild.h" +#include "net/tmwserv/protocol.h" + +#include "gui/widgets/channeltab.h" +#include "gui/chat.h" +#include "gui/guildwindow.h" + +#include "guild.h" +#include "log.h" +#include "localplayer.h" +#include "channel.h" +#include "channelmanager.h" + +#include <iostream> + +GuildHandler::GuildHandler() +{ + static const Uint16 _messages[] = { + CPMSG_GUILD_CREATE_RESPONSE, + CPMSG_GUILD_INVITE_RESPONSE, + CPMSG_GUILD_ACCEPT_RESPONSE, + CPMSG_GUILD_GET_MEMBERS_RESPONSE, + CPMSG_GUILD_UPDATE_LIST, + CPMSG_GUILD_INVITED, + CPMSG_GUILD_REJOIN, + CPMSG_GUILD_QUIT_RESPONSE, + 0 + }; + handledMessages = _messages; + +} + +void GuildHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case CPMSG_GUILD_CREATE_RESPONSE: + { + logger->log("Received CPMSG_GUILD_CREATE_RESPONSE"); + if(msg.readInt8() == ERRMSG_OK) + { + // TODO - Acknowledge guild was created + localChatTab->chatLog("Guild created."); + joinedGuild(msg); + } + else + { + localChatTab->chatLog("Error creating guild."); + } + } break; + + case CPMSG_GUILD_INVITE_RESPONSE: + { + logger->log("Received CPMSG_GUILD_INVITE_RESPONSE"); + if(msg.readInt8() == ERRMSG_OK) + { + // TODO - Acknowledge invite was sent + localChatTab->chatLog("Invite sent."); + } + } break; + + case CPMSG_GUILD_ACCEPT_RESPONSE: + { + logger->log("Received CPMSG_GUILD_ACCEPT_RESPONSE"); + if(msg.readInt8() == ERRMSG_OK) + { + // TODO - Acknowledge accepted into guild + joinedGuild(msg); + } + } break; + + case CPMSG_GUILD_GET_MEMBERS_RESPONSE: + { + logger->log("Received CPMSG_GUILD_GET_MEMBERS_RESPONSE"); + if(msg.readInt8() == ERRMSG_OK) + { + std::string guildMember; + bool online; + std::string guildName; + Guild *guild; + + short guildId = msg.readInt16(); + guild = player_node->getGuild(guildId); + + if (!guild) + return; + + guildName = guild->getName(); + + while(msg.getUnreadLength()) + { + guildMember = msg.readString(); + online = msg.readInt8(); + if(guildMember != "") + { + guild->addMember(guildMember); + guildWindow->setOnline(guildName, guildMember, online); + } + } + + guildWindow->updateTab(); + } + } break; + + case CPMSG_GUILD_UPDATE_LIST: + { + logger->log("Received CPMSG_GUILD_UPDATE_LIST"); + short guildId = msg.readInt16(); + std::string guildMember = msg.readString(); + char eventId = msg.readInt8(); + + Guild *guild = player_node->getGuild(guildId); + if (guild) + { + switch(eventId) + { + case GUILD_EVENT_NEW_PLAYER: + guild->addMember(guildMember); + guildWindow->setOnline(guild->getName(), guildMember, true); + break; + + case GUILD_EVENT_LEAVING_PLAYER: + guild->removeMember(guildMember); + break; + + case GUILD_EVENT_ONLINE_PLAYER: + guildWindow->setOnline(guild->getName(), guildMember, true); + break; + + case GUILD_EVENT_OFFLINE_PLAYER: + guildWindow->setOnline(guild->getName(), guildMember, false); + break; + + default: + logger->log("Invalid guild event"); + } + } + guildWindow->updateTab(); + + + } break; + + case CPMSG_GUILD_INVITED: + { + logger->log("Received CPMSG_GUILD_INVITED"); + std::string inviterName = msg.readString(); + std::string guildName = msg.readString(); + + // Open a dialog asking if the player accepts joining the guild. + guildWindow->openAcceptDialog(inviterName, guildName); + } break; + + case CPMSG_GUILD_PROMOTE_MEMBER_RESPONSE: + { + logger->log("Received CPMSG_GUILD_PROMOTE_MEMBER_RESPONSE"); + + if (msg.readInt8() == ERRMSG_OK) + { + // promotion succeeded + localChatTab->chatLog("Member was promoted successfully"); + } + else + { + // promotion failed + localChatTab->chatLog("Failed to promote member"); + } + } + + case CPMSG_GUILD_REJOIN: + { + logger->log("Received CPMSG_GUILD_REJOIN"); + + joinedGuild(msg); + } break; + + case CPMSG_GUILD_QUIT_RESPONSE: + { + logger->log("Received CPMSG_GUILD_QUIT_RESPONSE"); + + if (msg.readInt8() == ERRMSG_OK) + { + // Must remove tab first, as it wont find the guild + // name after its removed from the player + int guildId = msg.readInt16(); + Guild *guild = player_node->getGuild(guildId); + if (guild) + { + Channel *channel = channelManager->findByName(guild->getName()); + channelManager->removeChannel(channel); + guildWindow->removeTab(guildId); + player_node->removeGuild(guildId); + } + } + } break; + } +} + +void GuildHandler::joinedGuild(MessageIn &msg) +{ + std::string guildName = msg.readString(); + short guildId = msg.readInt16(); + short permissions = msg.readInt16(); + short channelId = msg.readInt16(); + std::string announcement = msg.readString(); + + // Add guild to player and create new guild tab + Guild *guild = player_node->addGuild(guildId, permissions); + guild->setName(guildName); + guildWindow->newGuildTab(guildName); + guildWindow->requestMemberList(guildId); + + // Automatically create the guild channel + // COMMENT: Should this go here?? + Channel *channel = new Channel(channelId, guildName, announcement); + channelManager->addChannel(channel); + channel->getTab()->chatLog("Topic: " + announcement, BY_CHANNEL); +} diff --git a/src/net/tmwserv/guildhandler.h b/src/net/tmwserv/guildhandler.h new file mode 100644 index 00000000..9b900d9f --- /dev/null +++ b/src/net/tmwserv/guildhandler.h @@ -0,0 +1,40 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_GUILDHANDLER_H +#define NET_TMWSERV_GUILDHANDLER_H + +#include "net/messagehandler.h" + +#include <string> + +class GuildHandler : public MessageHandler +{ +public: + GuildHandler(); + + void handleMessage(MessageIn &msg); + +protected: + void joinedGuild(MessageIn &msg); +}; + +#endif diff --git a/src/net/tmwserv/internal.cpp b/src/net/tmwserv/internal.cpp new file mode 100644 index 00000000..253d4f5f --- /dev/null +++ b/src/net/tmwserv/internal.cpp @@ -0,0 +1,27 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/internal.h" + +namespace Net +{ + int connections = 0; +} diff --git a/src/net/tmwserv/internal.h b/src/net/tmwserv/internal.h new file mode 100644 index 00000000..17ee9081 --- /dev/null +++ b/src/net/tmwserv/internal.h @@ -0,0 +1,30 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_INTERNAL_H +#define NET_TMWSERV_INTERNAL_H + +namespace Net +{ + extern int connections; +} + +#endif diff --git a/src/net/tmwserv/inventoryhandler.cpp b/src/net/tmwserv/inventoryhandler.cpp new file mode 100644 index 00000000..f6522128 --- /dev/null +++ b/src/net/tmwserv/inventoryhandler.cpp @@ -0,0 +1,79 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/inventoryhandler.h" + +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "equipment.h" +#include "inventory.h" +#include "item.h" +#include "itemshortcut.h" +#include "localplayer.h" + +#include "gui/chat.h" + +#include "resources/iteminfo.h" + +InventoryHandler::InventoryHandler() +{ + static const Uint16 _messages[] = { + GPMSG_INVENTORY_FULL, + GPMSG_INVENTORY, + 0 + }; + handledMessages = _messages; +} + +void InventoryHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case GPMSG_INVENTORY_FULL: + player_node->clearInventory(); + // no break! + + case GPMSG_INVENTORY: + while (msg.getUnreadLength()) + { + int slot = msg.readInt8(); + if (slot == 255) + { + player_node->setMoney(msg.readInt32()); + continue; + } + + int id = msg.readInt16(); + if (slot < EQUIPMENT_SIZE) + { + player_node->mEquipment->setEquipment(slot, id); + } + else if (slot >= 32 && slot < 32 + INVENTORY_SIZE) + { + int amount = id ? msg.readInt8() : 0; + player_node->setInvItem(slot - 32, id, amount); + } + }; + break; + } +} diff --git a/src/net/inventoryhandler.h b/src/net/tmwserv/inventoryhandler.h index f87e1214..4144d89c 100644 --- a/src/net/inventoryhandler.h +++ b/src/net/tmwserv/inventoryhandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_INVENTORYHANDLER_H -#define NET_INVENTORYHANDLER_H +#ifndef NET_TMWSERV_INVENTORYHANDLER_H +#define NET_TMWSERV_INVENTORYHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class InventoryHandler : public MessageHandler { public: InventoryHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/tmwserv/itemhandler.cpp b/src/net/tmwserv/itemhandler.cpp new file mode 100644 index 00000000..4ed61266 --- /dev/null +++ b/src/net/tmwserv/itemhandler.cpp @@ -0,0 +1,66 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/itemhandler.h" + +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "engine.h" +#include "flooritemmanager.h" + +ItemHandler::ItemHandler() +{ + static const Uint16 _messages[] = { + GPMSG_ITEMS, + GPMSG_ITEM_APPEAR, + 0 + }; + handledMessages = _messages; +} + +void ItemHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case GPMSG_ITEM_APPEAR: + case GPMSG_ITEMS: + { + while (msg.getUnreadLength()) + { + int itemId = msg.readInt16(); + int x = msg.readInt16(); + int y = msg.readInt16(); + int id = (x << 16) | y; // dummy id + + if (itemId) + { + floorItemManager->create(id, itemId, x / 32, y / 32, engine->getCurrentMap()); + } + else if (FloorItem *item = floorItemManager->findById(id)) + { + floorItemManager->destroy(item); + } + } + } break; + } +} diff --git a/src/net/itemhandler.h b/src/net/tmwserv/itemhandler.h index 0f292d46..6a2a96c8 100644 --- a/src/net/itemhandler.h +++ b/src/net/tmwserv/itemhandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_ITEMHANDLER_H -#define NET_ITEMHANDLER_H +#ifndef NET_TMWSERV_ITEMHANDLER_H +#define NET_TMWSERV_ITEMHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class ItemHandler : public MessageHandler { public: ItemHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/tmwserv/loginhandler.cpp b/src/net/tmwserv/loginhandler.cpp new file mode 100644 index 00000000..ccba06ed --- /dev/null +++ b/src/net/tmwserv/loginhandler.cpp @@ -0,0 +1,226 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/loginhandler.h" + +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "logindata.h" +#include "main.h" + +LoginHandler::LoginHandler() +{ + static const Uint16 _messages[] = { + APMSG_LOGIN_RESPONSE, + APMSG_REGISTER_RESPONSE, + APMSG_RECONNECT_RESPONSE, + APMSG_PASSWORD_CHANGE_RESPONSE, + APMSG_EMAIL_CHANGE_RESPONSE, + 0 + }; + handledMessages = _messages; +} + +void LoginHandler::setLoginData(LoginData *loginData) +{ + mLoginData = loginData; +} + +void LoginHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case APMSG_LOGIN_RESPONSE: + handleLoginResponse(msg); + break; + case APMSG_REGISTER_RESPONSE: + handleRegisterResponse(msg); + break; + case APMSG_RECONNECT_RESPONSE: + { + int errMsg = msg.readInt8(); + // Successful login + if (errMsg == ERRMSG_OK) + { + state = STATE_CHAR_SELECT; + } + // Login failed + else + { + switch (errMsg) { + case ERRMSG_INVALID_ARGUMENT: + errorMessage = "Wrong magic_token"; + 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 APMSG_PASSWORD_CHANGE_RESPONSE: + { + int errMsg = msg.readInt8(); + // Successful pass change + if (errMsg == ERRMSG_OK) + { + state = STATE_CHANGEPASSWORD; + } + // pass change failed + else + { + switch (errMsg) { + case ERRMSG_INVALID_ARGUMENT: + errorMessage = "New password incorrect"; + break; + case ERRMSG_FAILURE: + errorMessage = "Old password incorrect"; + break; + case ERRMSG_NO_LOGIN: + errorMessage = "Account not connected. Please login first."; + break; + default: + errorMessage = "Unknown error"; + break; + } + state = STATE_ACCOUNTCHANGE_ERROR; + } + } + break; + + case APMSG_EMAIL_CHANGE_RESPONSE: + { + int errMsg = msg.readInt8(); + // Successful pass change + if (errMsg == ERRMSG_OK) + { + state = STATE_CHANGEEMAIL; + } + // pass change failed + else + { + switch (errMsg) { + case ERRMSG_INVALID_ARGUMENT: + errorMessage = "New email address incorrect"; + break; + case ERRMSG_FAILURE: + errorMessage = "Old email address incorrect"; + break; + case ERRMSG_NO_LOGIN: + errorMessage = "Account not connected. Please login first."; + break; + case ERRMSG_EMAIL_ALREADY_EXISTS: + errorMessage = "The new Email Address already exists."; + break; + default: + errorMessage = "Unknown error"; + break; + } + state = STATE_ACCOUNTCHANGE_ERROR; + } + } + break; + + } +} + +void LoginHandler::handleLoginResponse(MessageIn &msg) +{ + const int errMsg = msg.readInt8(); + + if (errMsg == ERRMSG_OK) + { + readUpdateHost(msg); + state = STATE_CHAR_SELECT; + } + else + { + switch (errMsg) { + case LOGIN_INVALID_VERSION: + errorMessage = "Client version is too old"; + 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_LOGIN_ERROR; + } +} + +void LoginHandler::handleRegisterResponse(MessageIn &msg) +{ + const int errMsg = msg.readInt8(); + + if (errMsg == ERRMSG_OK) + { + readUpdateHost(msg); + state = STATE_CHAR_SELECT; + } + else + { + switch (errMsg) { + case REGISTER_INVALID_VERSION: + errorMessage = "Client version is too old"; + 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_LOGIN_ERROR; + } +} + +void LoginHandler::readUpdateHost(MessageIn &msg) +{ + // Set the update host when included in the message + if (msg.getUnreadLength() > 0) + { + mLoginData->updateHost = msg.readString(); + } +} diff --git a/src/net/tmwserv/loginhandler.h b/src/net/tmwserv/loginhandler.h new file mode 100644 index 00000000..81dd273c --- /dev/null +++ b/src/net/tmwserv/loginhandler.h @@ -0,0 +1,47 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_LOGINHANDLER_H +#define NET_TMWSERV_LOGINHANDLER_H + +#include "net/messagehandler.h" + +class LoginData; + +class LoginHandler : public MessageHandler +{ + public: + LoginHandler(); + + void setLoginData(LoginData *loginData); + + void handleMessage(MessageIn &msg); + + private: + void handleLoginResponse(MessageIn &msg); + void handleRegisterResponse(MessageIn &msg); + + void readUpdateHost(MessageIn &msg); + + LoginData *mLoginData; +}; + +#endif // NET_TMWSERV_LOGINHANDLER_H diff --git a/src/net/tmwserv/logouthandler.cpp b/src/net/tmwserv/logouthandler.cpp new file mode 100644 index 00000000..8b0e2d6e --- /dev/null +++ b/src/net/tmwserv/logouthandler.cpp @@ -0,0 +1,218 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/logouthandler.h" + +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "main.h" + +LogoutHandler::LogoutHandler(): + mPassToken(NULL), + mScenario(LOGOUT_EXIT), + mLoggedOutAccount(false), + mLoggedOutGame(false), + mLoggedOutChat(false) +{ + static const Uint16 _messages[] = { + APMSG_LOGOUT_RESPONSE, + APMSG_UNREGISTER_RESPONSE, + GPMSG_DISCONNECT_RESPONSE, + CPMSG_DISCONNECT_RESPONSE, + 0 + }; + handledMessages = _messages; +} + +void LogoutHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case APMSG_LOGOUT_RESPONSE: + { + int errMsg = msg.readInt8(); + + // Successful logout + if (errMsg == ERRMSG_OK) + { + mLoggedOutAccount = true; + + switch (mScenario) + { + case LOGOUT_SWITCH_ACCOUNTSERVER: + if (mLoggedOutGame && mLoggedOutChat) + state = STATE_SWITCH_ACCOUNTSERVER; + break; + + case LOGOUT_EXIT: + default: + if (mLoggedOutGame && mLoggedOutChat) + state = STATE_FORCE_QUIT; + break; + } + } + // Logout failed + else + { + switch (errMsg) { + case ERRMSG_NO_LOGIN: + errorMessage = "Accountserver: Not logged in"; + break; + default: + errorMessage = "Accountserver: Unknown error"; + break; + } + state = STATE_ERROR; + } + } + break; + case APMSG_UNREGISTER_RESPONSE: + { + int errMsg = msg.readInt8(); + // Successful unregistration + if (errMsg == ERRMSG_OK) + { + state = STATE_UNREGISTER; + } + // Unregistration failed + else + { + switch (errMsg) { + case ERRMSG_INVALID_ARGUMENT: + errorMessage = + "Accountserver: Wrong username or password"; + break; + default: + errorMessage = "Accountserver: Unknown error"; + break; + } + state = STATE_ACCOUNTCHANGE_ERROR; + } + } + break; + case GPMSG_DISCONNECT_RESPONSE: + { + int errMsg = msg.readInt8(); + // Successful logout + if (errMsg == ERRMSG_OK) + { + mLoggedOutGame = true; + + switch (mScenario) + { + case LOGOUT_SWITCH_CHARACTER: + if (mPassToken) + { + *mPassToken = msg.readString(32); + mPassToken = NULL; + } + if (mLoggedOutChat) state = STATE_RECONNECT_ACCOUNT; + break; + + case LOGOUT_SWITCH_ACCOUNTSERVER: + if (mLoggedOutAccount && mLoggedOutChat) + state = STATE_SWITCH_ACCOUNTSERVER; + break; + + case LOGOUT_EXIT: + default: + if (mLoggedOutAccount && mLoggedOutChat) + state = STATE_FORCE_QUIT; + break; + } + } + // Logout failed + else + { + switch (errMsg) { + case ERRMSG_NO_LOGIN: + errorMessage = "Gameserver: Not logged in"; + break; + default: + errorMessage = "Gameserver: Unknown error"; + break; + } + state = STATE_ERROR; + } + } + break; + case CPMSG_DISCONNECT_RESPONSE: + { + int errMsg = msg.readInt8(); + // Successful logout + if (errMsg == ERRMSG_OK) + { + mLoggedOutChat = true; + + switch (mScenario) + { + case LOGOUT_SWITCH_CHARACTER: + if (mLoggedOutGame) state = STATE_RECONNECT_ACCOUNT; + break; + + case LOGOUT_SWITCH_ACCOUNTSERVER: + if (mLoggedOutAccount && mLoggedOutGame) + state = STATE_SWITCH_ACCOUNTSERVER; + break; + + case LOGOUT_EXIT: + default: + if (mLoggedOutAccount && mLoggedOutGame) + { + state = STATE_FORCE_QUIT; + } + break; + } + } + else + { + switch (errMsg) { + case ERRMSG_NO_LOGIN: + errorMessage = "Chatserver: Not logged in"; + break; + default: + errorMessage = "Chatserver: Unknown error"; + break; + } + state = STATE_ERROR; + } + } + break; + } +} + +void LogoutHandler::setScenario(unsigned short scenario, + std::string *passToken) +{ + mScenario = scenario; + mPassToken = passToken; +} + +void LogoutHandler::reset() +{ + mPassToken = NULL; + mScenario = LOGOUT_EXIT; + mLoggedOutAccount = false; + mLoggedOutGame = false; + mLoggedOutChat = false; +} diff --git a/src/net/tmwserv/logouthandler.h b/src/net/tmwserv/logouthandler.h new file mode 100644 index 00000000..6c69c8be --- /dev/null +++ b/src/net/tmwserv/logouthandler.h @@ -0,0 +1,62 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_LOGOUTHANDLER_H +#define NET_TMWSERV_LOGOUTHANDLER_H + +#include "net/messagehandler.h" + +#include <string> + +/** + * The different scenarios for which LogoutHandler can be used + */ +enum { + LOGOUT_EXIT, + LOGOUT_SWITCH_ACCOUNTSERVER, + LOGOUT_SWITCH_CHARACTER +}; + +class LogoutHandler : public MessageHandler +{ + public: + LogoutHandler(); + + void handleMessage(MessageIn &msg); + + void setScenario(unsigned short scenario, + std::string *passToken = NULL); + + void reset(); + + void setAccountLoggedOut() { mLoggedOutAccount = true; } + void setGameLoggedOut() { mLoggedOutGame = true; } + void setChatLoggedOut() { mLoggedOutChat = true; } + + private: + std::string* mPassToken; + unsigned short mScenario; + bool mLoggedOutAccount; + bool mLoggedOutGame; + bool mLoggedOutChat; +}; + +#endif diff --git a/src/net/tmwserv/network.cpp b/src/net/tmwserv/network.cpp new file mode 100644 index 00000000..d353da17 --- /dev/null +++ b/src/net/tmwserv/network.cpp @@ -0,0 +1,170 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/network.h" + +#include "net/tmwserv/connection.h" +#include "net/tmwserv/internal.h" + +#include "net/messagehandler.h" +#include "net/messagein.h" + +#include "log.h" + +#include <enet/enet.h> + +#include <map> + +/** + * The local host which is shared for all outgoing connections. + */ +namespace { + ENetHost *client; +} + +typedef std::map<unsigned short, MessageHandler*> MessageHandlers; +typedef MessageHandlers::iterator MessageHandlerIterator; +static MessageHandlers mMessageHandlers; + +void Net::initialize() +{ + if (enet_initialize()) + { + logger->error("Failed to initialize ENet."); + } + + client = enet_host_create(NULL, 3, 0, 0); + + if (!client) + { + logger->error("Failed to create the local host."); + } +} + +void Net::finalize() +{ + if (!client) + return; // Wasn't initialized at all + + if (Net::connections) { + logger->error("Tried to shutdown the network subsystem while there " + "are network connections left!"); + } + + clearHandlers(); + enet_deinitialize(); +} + +Net::Connection *Net::getConnection() +{ + if (!client) + { + logger->error("Tried to instantiate a network object before " + "initializing the network subsystem!"); + } + + return new Net::Connection(client); +} + +void Net::registerHandler(MessageHandler *handler) +{ + for (const Uint16 *i = handler->handledMessages; *i; i++) + { + mMessageHandlers[*i] = handler; + } +} + +void Net::unregisterHandler(MessageHandler *handler) +{ + for (const Uint16 *i = handler->handledMessages; *i; i++) + { + mMessageHandlers.erase(*i); + } +} + +void Net::clearHandlers() +{ + mMessageHandlers.clear(); +} + + +/** + * Dispatches a message to the appropriate message handler and + * destroys it afterwards. + */ +namespace +{ + 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 Net::flush() +{ + ENetEvent event; + + // Wait up to 10 milliseconds for an event. + while (enet_host_service(client, &event, 10) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + logger->log("Connected to port %d.", event.peer->address.port); + // Store any relevant server information here. + event.peer->data = 0; + break; + + case ENET_EVENT_TYPE_RECEIVE: + dispatchMessage(event.packet); + break; + + case ENET_EVENT_TYPE_DISCONNECT: + logger->log("Disconnected."); + // Reset the server information. + event.peer->data = 0; + break; + + case ENET_EVENT_TYPE_NONE: + logger->log("No event during 10 milliseconds."); + break; + + default: + logger->log("Unhandled enet event."); + break; + } + } +} diff --git a/src/net/tmwserv/network.h b/src/net/tmwserv/network.h new file mode 100644 index 00000000..1b5c7bc6 --- /dev/null +++ b/src/net/tmwserv/network.h @@ -0,0 +1,79 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_NETWORK_H +#define NET_TMWSERV_NETWORK_H + +#include <iosfwd> + +/** + * \defgroup Network Core network layer + */ + +class MessageHandler; +class MessageOut; + +/** + * \ingroup Network + */ +namespace Net +{ + class Connection; + + /** + * Initializes the network subsystem. + */ + void initialize(); + + /** + * Finalizes the network subsystem. + */ + void finalize(); + + /** + * Returns a new Connection object. Should be deleted by the caller. + */ + 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/tmwserv/npchandler.cpp b/src/net/tmwserv/npchandler.cpp new file mode 100644 index 00000000..bae5228c --- /dev/null +++ b/src/net/tmwserv/npchandler.cpp @@ -0,0 +1,83 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/npchandler.h" + +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "beingmanager.h" +#include "npc.h" + +#include "gui/npclistdialog.h" +#include "gui/npcpostdialog.h" +#include "gui/npc_text.h" + +NPCHandler::NPCHandler() +{ + static const Uint16 _messages[] = { + GPMSG_NPC_CHOICE, + GPMSG_NPC_POST, + GPMSG_NPC_MESSAGE, + GPMSG_NPC_ERROR, + 0 + }; + handledMessages = _messages; +} + +void NPCHandler::handleMessage(MessageIn &msg) +{ + Being *being = beingManager->findBeing(msg.readInt16()); + if (!being || being->getType() != Being::NPC) + { + return; + } + + current_npc = being->getId(); + + switch (msg.getId()) + { + case GPMSG_NPC_CHOICE: + npcListDialog->reset(); + while (msg.getUnreadLength()) + { + npcListDialog->addItem(msg.readString()); + } + npcListDialog->setVisible(true); + break; + + case GPMSG_NPC_POST: + npcTextDialog->setVisible(false); + npcPostDialog->clear(); + npcPostDialog->setVisible(true); + break; + + case GPMSG_NPC_ERROR: + current_npc = NULL; + case GPMSG_NPC_MESSAGE: + npcTextDialog->addText(msg.readString(msg.getUnreadLength())); + npcListDialog->setVisible(false); + npcTextDialog->setVisible(true); + npcPostDialog->setVisible(false); + break; + } +} diff --git a/src/net/npchandler.h b/src/net/tmwserv/npchandler.h index 35db2956..905c9b01 100644 --- a/src/net/npchandler.h +++ b/src/net/tmwserv/npchandler.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NET_NPCHANDLER_H -#define NET_NPCHANDLER_H +#ifndef NET_TMWSERV_NPCHANDLER_H +#define NET_TMWSERV_NPCHANDLER_H -#include "messagehandler.h" +#include "net/messagehandler.h" class NPCHandler : public MessageHandler { public: NPCHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/tmwserv/partyhandler.cpp b/src/net/tmwserv/partyhandler.cpp new file mode 100644 index 00000000..dfbcea80 --- /dev/null +++ b/src/net/tmwserv/partyhandler.cpp @@ -0,0 +1,105 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/partyhandler.h" + +#include "net/tmwserv/chatserver/chatserver.h" +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "gui/chat.h" +#include "gui/partywindow.h" + +#include "log.h" +#include "localplayer.h" + +#include <iostream> + +PartyHandler::PartyHandler() +{ + static const Uint16 _messages[] = { + CPMSG_PARTY_INVITE_RESPONSE, + CPMSG_PARTY_INVITED, + CPMSG_PARTY_ACCEPT_INVITE_RESPONSE, + CPMSG_PARTY_QUIT_RESPONSE, + CPMSG_PARTY_NEW_MEMBER, + CPMSG_PARTY_MEMBER_LEFT, + 0 + }; + handledMessages = _messages; + +} + +void PartyHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case CPMSG_PARTY_INVITE_RESPONSE: + { + if (msg.readInt8() == ERRMSG_OK) + { + + } + } break; + + case CPMSG_PARTY_INVITED: + { + std::string inviter = msg.readString(); + partyWindow->showPartyInvite(inviter); + } break; + + case CPMSG_PARTY_ACCEPT_INVITE_RESPONSE: + { + if (msg.readInt8() == ERRMSG_OK) + { + player_node->setInParty(true); + localChatTab->chatLog("Joined party"); + } + } + + case CPMSG_PARTY_QUIT_RESPONSE: + { + if (msg.readInt8() == ERRMSG_OK) + { + player_node->setInParty(false); + } + } break; + + case CPMSG_PARTY_NEW_MEMBER: + { + msg.readInt16(); // being id + std::string name = msg.readString(); + + localChatTab->chatLog(name + " joined the party"); + + if (!player_node->getInParty()) + player_node->setInParty(true); + + partyWindow->addPartyMember(name); + } break; + + case CPMSG_PARTY_MEMBER_LEFT: + { + partyWindow->removePartyMember(msg.readString()); + } break; + } +} diff --git a/src/net/tmwserv/partyhandler.h b/src/net/tmwserv/partyhandler.h new file mode 100644 index 00000000..66e29b0d --- /dev/null +++ b/src/net/tmwserv/partyhandler.h @@ -0,0 +1,38 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_PARTYHANDLER_H +#define NET_TMWSERV_PARTYHANDLER_H + +#include "net/messagehandler.h" + +#include <string> + +class PartyHandler : public MessageHandler +{ +public: + PartyHandler(); + + void handleMessage(MessageIn &msg); +}; + +#endif + diff --git a/src/net/tmwserv/playerhandler.cpp b/src/net/tmwserv/playerhandler.cpp new file mode 100644 index 00000000..863fcb65 --- /dev/null +++ b/src/net/tmwserv/playerhandler.cpp @@ -0,0 +1,329 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/playerhandler.h" + +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "engine.h" +#include "localplayer.h" +#include "log.h" +#include "particle.h" +#include "npc.h" + +#include "gui/buy.h" +#include "gui/chat.h" +#include "gui/gui.h" +#include "gui/npclistdialog.h" +#include "gui/npc_text.h" +#include "gui/ok_dialog.h" +#include "gui/sell.h" +#include "gui/skill.h" +#include "gui/viewport.h" + +// TODO Move somewhere else +OkDialog *weightNotice = NULL; +OkDialog *deathNotice = NULL; + +extern NpcListDialog *npcListDialog; +extern NpcTextDialog *npcTextDialog; +extern BuyDialog *buyDialog; +extern SellDialog *sellDialog; +extern Window *buySellDialog; + +/* Max. distance we are willing to scroll after a teleport; + * everything beyond will reset the port hard. + */ +static const int MAP_TELEPORT_SCROLL_DISTANCE = 8 * 32; + +/** + * Listener used for handling the overweigth message. + */ +// TODO Move somewhere else +namespace { + struct WeightListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + weightNotice = NULL; + } + } weightListener; +} + +/** + * Listener used for handling death message. + */ +// TODO Move somewhere else +namespace { + struct DeathListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + player_node->revive(); + deathNotice = NULL; + npcListDialog->setVisible(false); + npcTextDialog->setVisible(false); + buyDialog->setVisible(false); + sellDialog->setVisible(false); +#ifdef EATHENA_SUPPORT + buySellDialog->setVisible(false); +#endif + current_npc = 0; + } + } deathListener; +} + +PlayerHandler::PlayerHandler() +{ + static const Uint16 _messages[] = { + GPMSG_PLAYER_MAP_CHANGE, + GPMSG_PLAYER_SERVER_CHANGE, + GPMSG_PLAYER_ATTRIBUTE_CHANGE, + GPMSG_PLAYER_EXP_CHANGE, + GPMSG_LEVELUP, + GPMSG_LEVEL_PROGRESS, + GPMSG_RAISE_ATTRIBUTE_RESPONSE, + GPMSG_LOWER_ATTRIBUTE_RESPONSE, + 0 + }; + handledMessages = _messages; +} + +void PlayerHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case GPMSG_PLAYER_MAP_CHANGE: + handleMapChangeMessage(msg); + break; + + case GPMSG_PLAYER_SERVER_CHANGE: + { // TODO: Implement reconnecting to another game server + std::string token = msg.readString(32); + std::string address = msg.readString(); + int port = msg.readInt16(); + logger->log("Changing server to %s:%d", address.c_str(), port); + } break; + + case GPMSG_PLAYER_ATTRIBUTE_CHANGE: + { + logger->log("ATTRIBUTE UPDATE:"); + while (msg.getUnreadLength()) + { + int stat = msg.readInt8(); + int base = msg.readInt16(); + int value = msg.readInt16(); + logger->log("%d set to %d %d", stat, base, value); + + if (stat == BASE_ATTR_HP) + { + player_node->setMaxHp(base); + player_node->setHp(value); + } + else if (stat < NB_CHARACTER_ATTRIBUTES) + { + if (stat >= CHAR_SKILL_BEGIN && stat < CHAR_SKILL_END + && player_node->getAttributeBase(stat) < base + && player_node->getAttributeBase(stat) > -1) + { + Particle* effect = particleEngine->addEffect("graphics/particles/skillup.particle.xml", 0, 0); + player_node->controlParticle(effect); + } + + player_node->setAttributeBase(stat, base); + player_node->setAttributeEffective(stat, value); + } + else + { + logger->log("Warning: server wants to update unknown " + "attribute %d to %d", stat, value); + } + } + } break; + + case GPMSG_PLAYER_EXP_CHANGE: + { + logger->log("EXP Update"); + while (msg.getUnreadLength()) + { + int skill = msg.readInt8(); + int current = msg.readInt32(); + int next = msg.readInt32(); + + if (skill < CHAR_SKILL_NB) + { + player_node->setExperience(skill, current, next); + } + else + { + logger->log("Warning: server wants to update experience of unknown " + "skill %d to %d / %d", skill, current, next); + } + } + } break; + + case GPMSG_LEVELUP: + { + player_node->setLevel(msg.readInt16()); + player_node->setCharacterPoints(msg.readInt16()); + player_node->setCorrectionPoints(msg.readInt16()); + Particle* effect = particleEngine->addEffect("graphics/particles/levelup.particle.xml", 0, 0); + player_node->controlParticle(effect); + } break; + + + case GPMSG_LEVEL_PROGRESS: + { + logger->log("Level Progress Update"); + player_node->setLevelProgress(msg.readInt8()); + } break; + + + case GPMSG_RAISE_ATTRIBUTE_RESPONSE: + { + int errCode = msg.readInt8(); + int attrNum = msg.readInt8() - CHAR_ATTR_BEGIN; + switch (errCode) + { + case ATTRIBMOD_OK: + { + // feel(acknowledgment); + } break; + case ATTRIBMOD_INVALID_ATTRIBUTE: + { + logger->log("Warning: Server denied increase of attribute %d (unknown attribute) ", attrNum); + } break; + case ATTRIBMOD_NO_POINTS_LEFT: + { + // when the server says "you got no points" it + // has to be correct. The server is always right! + // undo attribute change and set points to 0 + logger->log("Warning: Server denied increase of attribute %d (no points left) ", attrNum); + int attrValue = player_node->getAttributeBase(attrNum) - 1; + player_node->setCharacterPoints(0); + player_node->setAttributeBase(attrNum, attrValue); + } break; + case ATTRIBMOD_DENIED: + { + // undo attribute change + logger->log("Warning: Server denied increase of attribute %d (reason unknown) ", attrNum); + int points = player_node->getCharacterPoints() - 1; + player_node->setCharacterPoints(points); + int attrValue = player_node->getAttributeBase(attrNum) - 1; + player_node->setAttributeBase(attrNum, attrValue); + } break; + } + } break; + + case GPMSG_LOWER_ATTRIBUTE_RESPONSE: + { + int errCode = msg.readInt8(); + int attrNum = msg.readInt8() - CHAR_ATTR_BEGIN; + switch (errCode) + { + case ATTRIBMOD_OK: + { + // feel(acknowledgment); + } break; + case ATTRIBMOD_INVALID_ATTRIBUTE: + { + logger->log("Warning: Server denied reduction of attribute %d (unknown attribute) ", attrNum); + } break; + case ATTRIBMOD_NO_POINTS_LEFT: + { + // when the server says "you got no points" it + // has to be correct. The server is always right! + // undo attribute change and set points to 0 + logger->log("Warning: Server denied reduction of attribute %d (no points left) ", attrNum); + int attrValue = player_node->getAttributeBase(attrNum) + 1; + player_node->setCorrectionPoints(0); + player_node->setAttributeBase(attrNum, attrValue); + break; + } break; + case ATTRIBMOD_DENIED: + { + // undo attribute change + logger->log("Warning: Server denied reduction of attribute %d (reason unknown) ", attrNum); + int charaPoints = player_node->getCharacterPoints() - 1; + player_node->setCharacterPoints(charaPoints); + int correctPoints = player_node->getCorrectionPoints() + 1; + player_node->setCorrectionPoints(correctPoints); + int attrValue = player_node->getAttributeBase(attrNum) + 1; + player_node->setAttributeBase(attrNum, attrValue); + } break; + } + + } break; + /* + case SMSG_PLAYER_ARROW_MESSAGE: + { + Sint16 type = msg.readInt16(); + + switch (type) { + case 0: + localChatTab->chatLog("Equip arrows first", + BY_SERVER); + break; + default: + logger->log("0x013b: Unhandled message %i", type); + break; + } + } + break; + */ + } +} + +void PlayerHandler::handleMapChangeMessage(MessageIn &msg) +{ + const std::string mapName = msg.readString(); + const unsigned short x = msg.readInt16(); + const unsigned short y = msg.readInt16(); + const bool nearby = (engine->getCurrentMapName() == mapName); + + logger->log("Changing map to %s (%d, %d)", mapName.c_str(), x, y); + + // Switch the actual map, deleting the previous one + engine->changeMap(mapName); + + current_npc = 0; + + const Vector &playerPos = player_node->getPosition(); + float scrollOffsetX = 0.0f; + float scrollOffsetY = 0.0f; + + /* Scroll if neccessary */ + if (!nearby + || (abs(x - (int) playerPos.x) > MAP_TELEPORT_SCROLL_DISTANCE) + || (abs(y - (int) playerPos.y) > MAP_TELEPORT_SCROLL_DISTANCE)) { + scrollOffsetX = x - (int) playerPos.x; + scrollOffsetY = y - (int) playerPos.y; + } + + player_node->setAction(Being::STAND); + player_node->setPosition(x, y); + + logger->log("Adjust scrolling by %d,%d", (int) scrollOffsetX, + (int) scrollOffsetY); + viewport->scrollBy(scrollOffsetX, scrollOffsetY); +} diff --git a/src/net/tmwserv/playerhandler.h b/src/net/tmwserv/playerhandler.h new file mode 100644 index 00000000..c8eacc38 --- /dev/null +++ b/src/net/tmwserv/playerhandler.h @@ -0,0 +1,38 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_PLAYERHANDLER_H +#define NET_TMWSERV_PLAYERHANDLER_H + +#include "net/messagehandler.h" + +class PlayerHandler : public MessageHandler +{ + public: + PlayerHandler(); + + void handleMessage(MessageIn &msg); + + private: + void handleMapChangeMessage(MessageIn &msg); +}; + +#endif diff --git a/src/net/tmwserv/protocol.h b/src/net/tmwserv/protocol.h new file mode 100644 index 00000000..7eb0b931 --- /dev/null +++ b/src/net/tmwserv/protocol.h @@ -0,0 +1,295 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TMWSERV_PROTOCOL_H +#define TMWSERV_PROTOCOL_H + +/** + * 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) + * + * Hosts: P (player's client), A (account server), C (char server), + * G (game server) + */ +enum { + // Login/Register + PAMSG_REGISTER = 0x0000, // L version, S username, S password, S email + APMSG_REGISTER_RESPONSE = 0x0002, // B error [, S updatehost] + PAMSG_UNREGISTER = 0x0003, // - + APMSG_UNREGISTER_RESPONSE = 0x0004, // B error + PAMSG_LOGIN = 0x0010, // L version, S username, S password + APMSG_LOGIN_RESPONSE = 0x0012, // B error [, S updatehost] + 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, W level, W character points, W correction points, D money, W*6 stats + PAMSG_CHAR_SELECT = 0x0026, // B index + APMSG_CHAR_SELECT_RESPONSE = 0x0027, // B error, B*32 token, S game address, W game port, S chat address, W chat port + PAMSG_EMAIL_CHANGE = 0x0030, // S email + APMSG_EMAIL_CHANGE_RESPONSE = 0x0031, // B error + PAMSG_PASSWORD_CHANGE = 0x0034, // S old password, S new password + APMSG_PASSWORD_CHANGE_RESPONSE = 0x0035, // B error + + PGMSG_CONNECT = 0x0050, // B*32 token + GPMSG_CONNECT_RESPONSE = 0x0051, // B error + PCMSG_CONNECT = 0x0053, // B*32 token + CPMSG_CONNECT_RESPONSE = 0x0054, // B error + + PGMSG_DISCONNECT = 0x0060, // B reconnect account + GPMSG_DISCONNECT_RESPONSE = 0x0061, // B error, B*32 token + PCMSG_DISCONNECT = 0x0063, // - + CPMSG_DISCONNECT_RESPONSE = 0x0064, // B error + + PAMSG_RECONNECT = 0x0065, // B*32 token + APMSG_RECONNECT_RESPONSE = 0x0066, // B error + + // Game + GPMSG_PLAYER_MAP_CHANGE = 0x0100, // S filename, W x, W y + GPMSG_PLAYER_SERVER_CHANGE = 0x0101, // B*32 token, S game address, W game port + PGMSG_PICKUP = 0x0110, // W*2 position + PGMSG_DROP = 0x0111, // B slot, B amount + PGMSG_EQUIP = 0x0112, // B slot + PGMSG_UNEQUIP = 0x0113, // B slot + PGMSG_MOVE_ITEM = 0x0114, // B slot1, B slot2, B amount + GPMSG_INVENTORY = 0x0120, // { B slot, W item id [, B amount] }* + GPMSG_INVENTORY_FULL = 0x0121, // { B slot, W item id [, B amount] }* + GPMSG_PLAYER_ATTRIBUTE_CHANGE = 0x0130, // { B attribute, W base value, W modified value }* + GPMSG_PLAYER_EXP_CHANGE = 0x0140, // { B skill, D exp got, D exp needed }* + GPMSG_LEVELUP = 0x0150, // W new level + GPMSG_LEVEL_PROGRESS = 0x0151, // B percent completed to next levelup + PGMSG_RAISE_ATTRIBUTE = 0x0160, // B attribute + GPMSG_RAISE_ATTRIBUTE_RESPONSE = 0x0161, // B error, B attribute + PGMSG_LOWER_ATTRIBUTE = 0x0170, // B attribute + GPMSG_LOWER_ATTRIBUTE_RESPONSE = 0x0171, // B error, B attribute + PGMSG_RESPAWN = 0x0180, // - + GPMSG_BEING_ENTER = 0x0200, // B type, W being id, B action, W*2 position + // player: S name, B hair style, B hair color, B gender, B item bitmask, { W item id }* + // monster: W type id + // npc: W type id + GPMSG_BEING_LEAVE = 0x0201, // W being id + GPMSG_ITEM_APPEAR = 0x0202, // W item id, W*2 position + GPMSG_BEING_LOOKS_CHANGE = 0x0210, // W weapon, W hat, W top clothes, W bottom clothes + PGMSG_WALK = 0x0260, // W*2 destination + PGMSG_ACTION_CHANGE = 0x0270, // B Action + GPMSG_BEING_ACTION_CHANGE = 0x0271, // W being id, B action + PGMSG_DIRECTION_CHANGE = 0x0272, // B Direction + GPMSG_BEING_DIR_CHANGE = 0x0273, // W being id, B direction + GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position, B speed] [, W*2 destination] }* + GPMSG_ITEMS = 0x0281, // { W item id, W*2 position }* + PGMSG_ATTACK = 0x0290, // B direction + PGMSG_USE_SPECIAL = 0x0292, // B specialID + GPMSG_BEING_ATTACK = 0x0291, // W being id + PGMSG_SAY = 0x02A0, // S text + GPMSG_SAY = 0x02A1, // W being id, S text + GPMSG_NPC_CHOICE = 0x02B0, // W being id, { S text }* + GPMSG_NPC_MESSAGE = 0x02B1, // W being id, B* text + PGMSG_NPC_TALK = 0x02B2, // W being id + PGMSG_NPC_TALK_NEXT = 0x02B3, // W being id + PGMSG_NPC_SELECT = 0x02B4, // W being id, B choice + GPMSG_NPC_BUY = 0x02B5, // W being id, { W item id, W amount, W cost }* + GPMSG_NPC_SELL = 0x02B6, // W being id, { W item id, W amount, W cost }* + PGMSG_NPC_BUYSELL = 0x02B7, // W item id, W amount + GPMSG_NPC_ERROR = 0x02B8, // B error + GPMSG_NPC_POST = 0x02D0, // W being id + PGMSG_NPC_POST_SEND = 0x02D1, // S name, S text, W item id + GPMSG_NPC_POST_GET = 0x02D2, // W being id, { S name, S text, W item id } + PGMSG_TRADE_REQUEST = 0x02C0, // W being id + GPMSG_TRADE_REQUEST = 0x02C1, // W being id + GPMSG_TRADE_START = 0x02C2, // - + GPMSG_TRADE_COMPLETE = 0x02C3, // - + PGMSG_TRADE_CANCEL = 0x02C4, // - + GPMSG_TRADE_CANCEL = 0x02C5, // - + PGMSG_TRADE_ACCEPT = 0x02C6, // - + GPMSG_TRADE_ACCEPT = 0x02C7, // - + PGMSG_TRADE_ADD_ITEM = 0x02C8, // B slot, B amount + GPMSG_TRADE_ADD_ITEM = 0x02C9, // W item id, B amount + PGMSG_TRADE_SET_MONEY = 0x02CA, // L amount + GPMSG_TRADE_SET_MONEY = 0x02CB, // L amount + PGMSG_USE_ITEM = 0x0300, // B slot + GPMSG_USE_RESPONSE = 0x0301, // B error + GPMSG_BEINGS_DAMAGE = 0x0310, // { W being id, W amount }* + GPMSG_CREATE_EFFECT = 0x0320, // W effect id, W*2 position + + // Guild + PCMSG_GUILD_CREATE = 0x0350, // S name + CPMSG_GUILD_CREATE_RESPONSE = 0x0351, // B error, W guild, B rights, W channel + PCMSG_GUILD_INVITE = 0x0352, // W id, S name + CPMSG_GUILD_INVITE_RESPONSE = 0x0353, // B error + PCMSG_GUILD_ACCEPT = 0x0354, // W id + CPMSG_GUILD_ACCEPT_RESPONSE = 0x0355, // B error, W guild, B rights, W channel + PCMSG_GUILD_GET_MEMBERS = 0x0356, // W id + CPMSG_GUILD_GET_MEMBERS_RESPONSE = 0x0357, // S names, B online + CPMSG_GUILD_UPDATE_LIST = 0x0358, // W id, S name, B event + PCMSG_GUILD_QUIT = 0x0360, // W id + CPMSG_GUILD_QUIT_RESPONSE = 0x0361, // B error + PCMSG_GUILD_PROMOTE_MEMBER = 0x0365, // W guild, S name, B rights + CPMSG_GUILD_PROMOTE_MEMBER_RESPONSE = 0x0366, // B error + + CPMSG_GUILD_INVITED = 0x0370, // S char name, S guild name, W id + CPMSG_GUILD_REJOIN = 0x0371, // S name, W guild, W rights, W channel, S announce + + // Party + PCMSG_PARTY_INVITE = 0x03A0, // S name + CPMSG_PARTY_INVITE_RESPONSE = 0x03A1, // B error + CPMSG_PARTY_INVITED = 0x03A2, // S name + PCMSG_PARTY_ACCEPT_INVITE = 0x03A5, // S name + CPMSG_PARTY_ACCEPT_INVITE_RESPONSE = 0x03A6, // B error, { S name } + PCMSG_PARTY_QUIT = 0x03AA, // - + CPMSG_PARTY_QUIT_RESPONSE = 0x03AB, // B error + CPMSG_PARTY_NEW_MEMBER = 0x03B0, // W being id, S name + CPMSG_PARTY_MEMBER_LEFT = 0x03B1, // W being id + + // 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 + CPMSG_CHANNEL_EVENT = 0x0430, // W channel, B event, S info + PCMSG_ENTER_CHANNEL = 0x0440, // S channel, S password + CPMSG_ENTER_CHANNEL_RESPONSE = 0x0441, // B error, W id, S name, S topic, S userlist + PCMSG_QUIT_CHANNEL = 0x0443, // W channel id + CPMSG_QUIT_CHANNEL_RESPONSE = 0x0444, // B error, W channel id + PCMSG_LIST_CHANNELS = 0x0445, // - + CPMSG_LIST_CHANNELS_RESPONSE = 0x0446, // S names, W number of users + PCMSG_LIST_CHANNELUSERS = 0x0460, // S channel + CPMSG_LIST_CHANNELUSERS_RESPONSE = 0x0461, // S channel, { S user, B mode } + PCMSG_TOPIC_CHANGE = 0x0462, // W channel id, S topic + // -- User mode + PCMSG_USER_MODE = 0x0465, // W channel id, S name, B mode + PCMSG_KICK_USER = 0x0466, // W channel id, S name + + 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 + ERRMSG_EMAIL_ALREADY_EXISTS, // The Email Address already exists + ERRMSG_ALREADY_TAKEN, // name used was already taken + ERRMSG_SERVER_FULL, // the server is overloaded + ERRMSG_TIME_OUT // data failed to arrive in due time +}; + +// 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_EQUAL_TO_ZERO, + CREATE_EXISTS_NAME, + CREATE_TOO_MUCH_CHARACTERS +}; + +// Character attribute modification specific return value +enum AttribmodResponseCode { + ATTRIBMOD_OK = ERRMSG_OK, + ATTRIBMOD_INVALID_ATTRIBUTE = 0x40, + ATTRIBMOD_NO_POINTS_LEFT, + ATTRIBMOD_DENIED +}; +// 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 +}; + +// Email change specific return values +enum { + EMAILCHG_EXISTS_EMAIL = 0x40 +}; + +// Chat errors return values +enum { + CHAT_USING_BAD_WORDS = 0x40, + CHAT_UNHANDLED_COMMAND +}; + +// Chat channels event values +enum { + CHAT_EVENT_NEW_PLAYER = 0, + CHAT_EVENT_LEAVING_PLAYER, + CHAT_EVENT_TOPIC_CHANGE, + CHAT_EVENT_MODE_CHANGE, + CHAT_EVENT_KICKED_PLAYER +}; + +// Guild member event values +enum { + GUILD_EVENT_NEW_PLAYER = 0, + GUILD_EVENT_LEAVING_PLAYER, + GUILD_EVENT_ONLINE_PLAYER, + GUILD_EVENT_OFFLINE_PLAYER +}; + +#endif diff --git a/src/net/tmwserv/tradehandler.cpp b/src/net/tmwserv/tradehandler.cpp new file mode 100644 index 00000000..85228355 --- /dev/null +++ b/src/net/tmwserv/tradehandler.cpp @@ -0,0 +1,137 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/tmwserv/tradehandler.h" + +#include "net/tmwserv/gameserver/player.h" +#include "net/tmwserv/protocol.h" + +#include "net/messagein.h" + +#include "beingmanager.h" +#include "item.h" +#include "localplayer.h" + +#include "gui/chat.h" +#include "gui/confirm_dialog.h" +#include "gui/trade.h" + +std::string tradePartnerName; +int tradePartnerID; + +/** + * Listener for request trade dialogs + */ +namespace { + struct RequestTradeListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + if (event.getId() == "yes") + Net::GameServer::Player::requestTrade(tradePartnerID); + else + Net::GameServer::Player::acceptTrade(false); + } + } listener; +} + +TradeHandler::TradeHandler(): + mAcceptTradeRequests(true) +{ + static const Uint16 _messages[] = { + GPMSG_TRADE_REQUEST, + GPMSG_TRADE_CANCEL, + GPMSG_TRADE_START, + GPMSG_TRADE_COMPLETE, + GPMSG_TRADE_ACCEPT, + GPMSG_TRADE_ADD_ITEM, + GPMSG_TRADE_SET_MONEY, + 0 + }; + handledMessages = _messages; +} + +void TradeHandler::setAcceptTradeRequests(bool acceptTradeRequests) +{ + mAcceptTradeRequests = acceptTradeRequests; + if (mAcceptTradeRequests) { + localChatTab->chatLog("Accepting incoming trade requests", BY_SERVER); + } else { + localChatTab->chatLog("Ignoring incoming trade requests", BY_SERVER); + } +} + +void TradeHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case GPMSG_TRADE_REQUEST: + { + Being *being = beingManager->findBeing(msg.readInt16()); + if (!being || !mAcceptTradeRequests) + { + Net::GameServer::Player::acceptTrade(false); + break; + } + player_node->setTrading(true); + tradePartnerName = being->getName(); + tradePartnerID = being->getId(); + ConfirmDialog *dlg = new ConfirmDialog("Request for trade", + tradePartnerName + " wants to trade with you, do you accept?"); + dlg->addActionListener(&listener); + } break; + + case GPMSG_TRADE_ADD_ITEM: + { + int type = msg.readInt16(); + int amount = msg.readInt8(); + tradeWindow->addItem(type, false, amount); + } break; + + case GPMSG_TRADE_SET_MONEY: + tradeWindow->setMoney(msg.readInt32()); + break; + + case GPMSG_TRADE_START: + tradeWindow->reset(); + tradeWindow->setCaption("Trading with " + tradePartnerName); + tradeWindow->setVisible(true); + break; + + case GPMSG_TRADE_ACCEPT: + tradeWindow->receivedOk(); + break; + + case GPMSG_TRADE_CANCEL: + localChatTab->chatLog("Trade canceled.", BY_SERVER); + tradeWindow->setVisible(false); + tradeWindow->reset(); + player_node->setTrading(false); + break; + + case GPMSG_TRADE_COMPLETE: + localChatTab->chatLog("Trade completed.", BY_SERVER); + tradeWindow->setVisible(false); + tradeWindow->reset(); + player_node->setTrading(false); + break; + } +} diff --git a/src/net/tmwserv/tradehandler.h b/src/net/tmwserv/tradehandler.h new file mode 100644 index 00000000..a064bbce --- /dev/null +++ b/src/net/tmwserv/tradehandler.h @@ -0,0 +1,53 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TMWSERV_TRADEHANDLER_H +#define NET_TMWSERV_TRADEHANDLER_H + +#include "net/messagehandler.h" + +class TradeHandler : public MessageHandler +{ + public: + TradeHandler(); + + void handleMessage(MessageIn &msg); + + /** + * Returns whether trade requests are accepted. + * + * @see setAcceptTradeRequests + */ + bool acceptTradeRequests() const + { return mAcceptTradeRequests; } + + /** + * Sets whether trade requests are accepted. When set to false, trade + * requests are automatically denied. When true, a popup will ask the + * player whether he wants to trade. + */ + void setAcceptTradeRequests(bool acceptTradeRequests); + + private: + bool mAcceptTradeRequests; +}; + +#endif diff --git a/src/npc.cpp b/src/npc.cpp index a6d60dbb..d0a1a523 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,19 +28,29 @@ #include "gui/npc_text.h" #include "gui/palette.h" +#ifdef TMWSERV_SUPPORT +#include "net/tmwserv/gameserver/player.h" +#else #include "net/messageout.h" -#include "net/protocol.h" +#include "net/ea/protocol.h" +#endif #include "resources/npcdb.h" -bool NPC::mTalking = false; +bool NPC::isTalking = false; int current_npc = 0; static const int NAME_X_OFFSET = 15; static const int NAME_Y_OFFSET = 30; +#ifdef TMWSERV_SUPPORT +NPC::NPC(Uint16 id, int job, Map *map): + Player(id, job, map) +#else NPC::NPC(int id, Uint16 job, Map *map, Network *network): - Player(id, job, map), mNetwork(network) + Player(id, job, map), + mNetwork(network) +#endif { NPCInfo info = NPCDB::get(job); @@ -110,18 +119,37 @@ Being::Type NPC::getType() const void NPC::talk() { - if (mTalking || !mNetwork) + if (isTalking) + return; + + isTalking = true; + +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::talkToNPC(mId, true); +#else + if (!mNetwork) return; - mTalking = true; MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_TALK); + //outMsg.writeInt16(CMSG_NPC_TALK); outMsg.writeInt32(mId); outMsg.writeInt8(0); +#endif } void NPC::updateCoords() { if (mName) - mName->adviseXY(mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET); + { +#ifdef TMWSERV_SUPPORT + const Vector &pos = getPosition(); + const int px = (int) pos.x + NAME_X_OFFSET; + const int py = (int) pos.y + NAME_Y_OFFSET; +#else + const int px = mPx + NAME_X_OFFSET; + const int py = mPy + NAME_Y_OFFSET; +#endif + mName->adviseXY(px, py); + } } @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,14 +24,20 @@ #include "player.h" +#ifdef EATHENA_SUPPORT class Network; +#endif class Graphics; class Text; class NPC : public Player { public: +#ifdef TMWSERV_SUPPORT + NPC(Uint16 id, int sprite, Map *map); +#else NPC(int id, Uint16 job, Map *map, Network *network); +#endif ~NPC(); @@ -42,12 +47,25 @@ class NPC : public Player virtual Type getType() const; - void talk();; + void talk(); - static bool mTalking; + /** + * Gets the way an NPC is blocked by other things on the map + */ + virtual unsigned char getWalkMask() const + { return 0x83; } // blocked like a monster by walls, monsters and characters ( bin 1000 0011) + static bool isTalking; protected: + /** + * Gets the way a monster blocks pathfinding for other objects + */ + virtual Map::BlockType getBlockType() const + { return Map::BLOCKTYPE_CHARACTER; } //blocks like a player character + +#ifdef EATHENA_SUPPORT Network *mNetwork; +#endif void updateCoords(); private: Text *mName; diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp index df8d264f..7a1d259e 100644 --- a/src/openglgraphics.cpp +++ b/src/openglgraphics.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,12 +26,12 @@ #include "resources/image.h" +#ifdef USE_OPENGL + #ifdef __APPLE__ #include <OpenGL/OpenGL.h> #endif -#ifdef USE_OPENGL - #ifndef GL_TEXTURE_RECTANGLE_ARB #define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 diff --git a/src/openglgraphics.h b/src/openglgraphics.h index a7181420..469e1f53 100644 --- a/src/openglgraphics.h +++ b/src/openglgraphics.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/particle.cpp b/src/particle.cpp index 0e412ada..21844f01 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -250,7 +249,7 @@ void Particle::moveTo(float x, float y) moveTo(Vector(x, y, mPos.z)); } -Particle* Particle::addEffect(const std::string &particleEffectFile, +Particle *Particle::addEffect(const std::string &particleEffectFile, int pixelX, int pixelY, int rotation) { Particle *newParticle = NULL; diff --git a/src/particle.h b/src/particle.h index 76beb8d1..f3f5571a 100644 --- a/src/particle.h +++ b/src/particle.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _PARTICLE_H -#define _PARTICLE_H +#ifndef PARTICLE_H +#define PARTICLE_H #include <list> #include <string> diff --git a/src/particlecontainer.cpp b/src/particlecontainer.cpp index 0ebf4bc3..63f89079 100644 --- a/src/particlecontainer.cpp +++ b/src/particlecontainer.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,15 +24,17 @@ #include "particle.h" #include "particlecontainer.h" -ParticleContainer::ParticleContainer(ParticleContainer *parent, bool delParent) : + +ParticleContainer::ParticleContainer(ParticleContainer *parent, + bool delParent): mDelParent(delParent), mNext(parent) -{}; +{} ParticleContainer::~ParticleContainer() { clearLocally(); - if (mNext && mDelParent) + if (mDelParent) delete mNext; } @@ -52,10 +53,12 @@ void ParticleContainer::moveTo(float x, float y) // -- particle list ---------------------------------------- -ParticleList::ParticleList(ParticleContainer *parent, bool delParent) : - ParticleContainer(parent, delParent) {}; +ParticleList::ParticleList(ParticleContainer *parent, bool delParent): + ParticleContainer(parent, delParent) +{} -ParticleList::~ParticleList() {} +ParticleList::~ParticleList() +{} void ParticleList::addLocally(Particle *particle) { @@ -71,10 +74,12 @@ void ParticleList::removeLocally(Particle *particle) { for (std::list<Particle *>::iterator it = mElements.begin(); it != mElements.end(); it++) + { if (*it == particle) { (*it)->kill(); mElements.erase(it); } + } } void ParticleList::clearLocally() @@ -82,7 +87,7 @@ void ParticleList::clearLocally() for (std::list<Particle *>::iterator it = mElements.begin(); it != mElements.end(); it++) (*it)->kill(); - + mElements.clear(); } @@ -106,10 +111,12 @@ void ParticleList::moveTo(float x, float y) // -- particle vector ---------------------------------------- -ParticleVector::ParticleVector(ParticleContainer *parent, bool delParent) : - ParticleContainer(parent, delParent) {}; +ParticleVector::ParticleVector(ParticleContainer *parent, bool delParent): + ParticleContainer(parent, delParent) +{} -ParticleVector::~ParticleVector() {}; +ParticleVector::~ParticleVector() +{} void ParticleVector::setLocally(int index, Particle *particle) { @@ -120,6 +127,8 @@ void ParticleVector::setLocally(int index, Particle *particle) if (mIndexedElements.size() <= (unsigned) index) mIndexedElements.resize(index + 1, NULL); + if (particle) + particle->disableAutoDelete(); mIndexedElements[index] = particle; } @@ -149,7 +158,7 @@ void ParticleVector::moveTo(float x, float y) ParticleContainer::moveTo(x, y); for (std::vector<Particle *>::iterator it = mIndexedElements.begin(); - it != mIndexedElements.end(); it++) + it != mIndexedElements.end(); it++) { if (*it) { (*it)->moveTo(x, y); @@ -160,5 +169,6 @@ void ParticleVector::moveTo(float x, float y) *it = NULL; } } + } } diff --git a/src/particlecontainer.h b/src/particlecontainer.h index 1e2f8ff7..26539dd7 100644 --- a/src/particlecontainer.h +++ b/src/particlecontainer.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -61,8 +60,8 @@ public: virtual void moveTo(float x, float y); protected: - bool mDelParent; /**< Delete mNext in destructor */ - ParticleContainer *mNext; /**< Contained container, if any */ + bool mDelParent; /**< Delete mNext in destructor */ + ParticleContainer *mNext; /**< Contained container, if any */ }; /** @@ -89,7 +88,7 @@ public: virtual void moveTo(float x, float y); protected: - std::list<Particle *> mElements; /**< Contained particle effects */ + std::list<Particle *> mElements; /**< Contained particle effects */ }; /** diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp index 84c4c1ec..25e6ade5 100644 --- a/src/particleemitter.cpp +++ b/src/particleemitter.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/particleemitter.h b/src/particleemitter.h index 835f39c5..67b35ae2 100644 --- a/src/particleemitter.h +++ b/src/particleemitter.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/particleemitterprop.h b/src/particleemitterprop.h index e3817763..e68ac222 100644 --- a/src/particleemitterprop.h +++ b/src/particleemitterprop.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/party.cpp b/src/party.cpp index a4f1b940..51a86360 100644 --- a/src/party.cpp +++ b/src/party.cpp @@ -1,8 +1,8 @@ /* - * Aethyra - * Copyright 2008 Lloyd Bryant <lloyd_bryant@netzero.net> + * The Mana World + * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,17 +23,17 @@ #include "localplayer.h" #include "party.h" +#include "gui/widgets/chattab.h" #include "gui/chat.h" #include "gui/confirm_dialog.h" #include "net/messageout.h" -#include "net/protocol.h" +#include "net/ea/protocol.h" #include "utils/gettext.h" #include "utils/strprintf.h" -Party::Party(ChatWindow *chat, Network *network) : - mChat(chat), +Party::Party(Network *network) : mNetwork(network), mInviteListener(network, &mInParty) { @@ -53,7 +53,7 @@ void Party::respond(const std::string &command, const std::string &args) } if (command == "settings") { - mChat->chatLog(_("Not yet implemented!"), BY_SERVER); + localChatTab->chatLog(_("Not yet implemented!"), BY_SERVER); return; /* MessageOut outMsg(mNetwork); @@ -62,14 +62,14 @@ void Party::respond(const std::string &command, const std::string &args) outMsg.writeInt16(0); // Item */ } - mChat->chatLog(_("Party command not known."), BY_SERVER); + localChatTab->chatLog(_("Party command not known."), BY_SERVER); } void Party::create(const std::string &party) { if (party.empty()) { - mChat->chatLog(_("Party name is missing."), BY_SERVER); + localChatTab->chatLog(_("Party name is missing."), BY_SERVER); return; } MessageOut outMsg(mNetwork); @@ -82,7 +82,7 @@ void Party::leave(const std::string &args) { MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_PARTY_LEAVE); - mChat->chatLog(_("Left party."), BY_SERVER); + localChatTab->chatLog(_("Left party."), BY_SERVER); mInParty = false; } @@ -90,12 +90,12 @@ void Party::createResponse(bool ok) { if (ok) { - mChat->chatLog(_("Party successfully created."), BY_SERVER); + localChatTab->chatLog(_("Party successfully created."), BY_SERVER); mInParty = true; } else { - mChat->chatLog(_("Could not create party."), BY_SERVER); + localChatTab->chatLog(_("Could not create party."), BY_SERVER); } } @@ -104,15 +104,15 @@ void Party::inviteResponse(const std::string &nick, int status) switch (status) { case 0: - mChat->chatLog(strprintf(_("%s is already a member of a party."), + localChatTab->chatLog(strprintf(_("%s is already a member of a party."), nick.c_str()), BY_SERVER); break; case 1: - mChat->chatLog(strprintf(_("%s refused your invitation."), + localChatTab->chatLog(strprintf(_("%s refused your invitation."), nick.c_str()), BY_SERVER); break; case 2: - mChat->chatLog(strprintf(_("%s is now a member of your party."), + localChatTab->chatLog(strprintf(_("%s is now a member of your party."), nick.c_str()), BY_SERVER); break; } @@ -124,7 +124,7 @@ void Party::invitedAsk(const std::string &nick, int gender, mPartyName = partyName; /* Quick and nasty - needs redoing */ if (nick.empty()) { - mChat->chatLog(_("You can\'t have a blank party name!"), BY_SERVER); + localChatTab->chatLog(_("You can\'t have a blank party name!"), BY_SERVER); return; } mCreating = false; @@ -147,7 +147,7 @@ void Party::InviteListener::action(const gcn::ActionEvent &event) void Party::leftResponse(const std::string &nick) { - mChat->chatLog(strprintf(_("%s has left your party."), nick.c_str()), + localChatTab->chatLog(strprintf(_("%s has left your party."), nick.c_str()), BY_SERVER); } @@ -159,47 +159,50 @@ void Party::receiveChat(Being *being, const std::string &msg) } if (being->getType() != Being::PLAYER) { - mChat->chatLog(_("Party chat received, but being is not a player"), + localChatTab->chatLog(_("Party chat received, but being is not a player"), BY_SERVER); return; } being->setSpeech(msg, SPEECH_TIME); - mChat->chatLog(being->getName() + " : " + msg, BY_PARTY); + localChatTab->chatLog(being->getName() + " : " + msg, BY_PARTY); } -void Party::help(const std::string &msg) +void Party::help(const std::string &args) { + // Strip "party " from the front + std::string msg = args.substr(6, args.length()); + if (msg.empty()) { - mChat->chatLog(_("Command: /party <command> <args>"), BY_SERVER); - mChat->chatLog(_("where <command> can be one of:"), BY_SERVER); - mChat->chatLog(_(" /new"), BY_SERVER); - mChat->chatLog(_(" /create"), BY_SERVER); - mChat->chatLog(_(" /prefix"), BY_SERVER); - mChat->chatLog(_(" /leave"), BY_SERVER); - mChat->chatLog(_("This command implements the partying function."), + localChatTab->chatLog(_("Command: /party <command> <args>"), BY_SERVER); + localChatTab->chatLog(_("where <command> can be one of:"), BY_SERVER); + localChatTab->chatLog(_(" /new"), BY_SERVER); + localChatTab->chatLog(_(" /create"), BY_SERVER); + localChatTab->chatLog(_(" /prefix"), BY_SERVER); + localChatTab->chatLog(_(" /leave"), BY_SERVER); + localChatTab->chatLog(_("This command implements the partying function."), BY_SERVER); - mChat->chatLog(_("Type /help party <command> for further help."), + localChatTab->chatLog(_("Type /help party <command> for further help."), BY_SERVER); return; } if (msg == "new" || msg == "create") { - mChat->chatLog(_("Command: /party new <party-name>"), BY_SERVER); - mChat->chatLog(_("Command: /party create <party-name>"), BY_SERVER); - mChat->chatLog(_("These commands create a new party <party-name."), + localChatTab->chatLog(_("Command: /party new <party-name>"), BY_SERVER); + localChatTab->chatLog(_("Command: /party create <party-name>"), BY_SERVER); + localChatTab->chatLog(_("These commands create a new party <party-name."), BY_SERVER); return; } if (msg == "prefix") { - mChat->chatLog(_("Command: /party prefix <prefix-char>"), BY_SERVER); - mChat->chatLog(_("This command sets the party prefix character."), + localChatTab->chatLog(_("Command: /party prefix <prefix-char>"), BY_SERVER); + localChatTab->chatLog(_("This command sets the party prefix character."), BY_SERVER); - mChat->chatLog(_("Any message preceded by <prefix-char> is sent to " + localChatTab->chatLog(_("Any message preceded by <prefix-char> is sent to " "the party instead of everyone."), BY_SERVER); - mChat->chatLog(_("Command: /party prefix"), BY_SERVER); - mChat->chatLog(_("This command reports the current party prefix " + localChatTab->chatLog(_("Command: /party prefix"), BY_SERVER); + localChatTab->chatLog(_("This command reports the current party prefix " "character."), BY_SERVER); return; } @@ -207,11 +210,11 @@ void Party::help(const std::string &msg) //if (msg == "info") if (msg == "leave") { - mChat->chatLog(_("Command: /party leave"), BY_SERVER); - mChat->chatLog(_("This command causes the player to leave the party."), + localChatTab->chatLog(_("Command: /party leave"), BY_SERVER); + localChatTab->chatLog(_("This command causes the player to leave the party."), BY_SERVER); return; } - mChat->chatLog(_("Unknown /party command."), BY_SERVER); - mChat->chatLog(_("Type /help party for a list of options."), BY_SERVER); + localChatTab->chatLog(_("Unknown /party command."), BY_SERVER); + localChatTab->chatLog(_("Type /help party for a list of options."), BY_SERVER); } diff --git a/src/party.h b/src/party.h index 0a19ae1d..d73b4a0f 100644 --- a/src/party.h +++ b/src/party.h @@ -1,8 +1,8 @@ /* - * Aethyra - * Copyright 2008 Lloyd Bryant <lloyd_bryant@netzero.net> + * The Mana World + * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ class Network; class Party { public: - Party(ChatWindow *chat, Network *network); + Party(Network *network); void respond(const std::string &command, const std::string &args); void create(const std::string &party); @@ -47,10 +47,9 @@ class Party void leftResponse(const std::string &nick); void receiveChat(Being *being, const std::string &msg); - void help(const std::string &msg); + void help(const std::string &args); private: - ChatWindow *mChat; std::string mPartyName; Network *mNetwork; bool mInParty; @@ -73,4 +72,6 @@ class Party InviteListener mInviteListener; }; +extern Party *playerParty; + #endif diff --git a/src/player.cpp b/src/player.cpp index ba4ed1ff..de4a012b 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +21,9 @@ #include "animatedsprite.h" #include "game.h" +#ifdef TMWSERV_SUPPORT +#include "guild.h" +#endif #include "localplayer.h" #include "particle.h" #include "player.h" @@ -31,6 +33,7 @@ #include "resources/colordb.h" #include "resources/itemdb.h" +#include "resources/iteminfo.h" #include "utils/strprintf.h" @@ -72,6 +75,7 @@ void Player::setName(const std::string &name) } } +#ifdef EATHENA_SUPPORT void Player::logic() { switch (mAction) @@ -89,7 +93,7 @@ void Player::logic() break; case WALK: - mFrame = (get_elapsed_time(mWalkTime) * 6) / mWalkSpeed; + mFrame = (get_elapsed_time(mWalkTime) * 6) / getWalkSpeed(); if (mFrame >= 6) nextStep(); @@ -137,6 +141,7 @@ void Player::logic() Being::logic(); } +#endif Being::Type Player::getType() const { @@ -183,7 +188,7 @@ void Player::setHairStyle(int style, int color) setAction(mAction); } -void Player::setSprite(int slot, int id, std::string color) +void Player::setSprite(int slot, int id, const std::string &color) { // id = 0 means unequip if (id == 0) @@ -191,8 +196,10 @@ void Player::setSprite(int slot, int id, std::string color) delete mSprites[slot]; mSprites[slot] = NULL; +#ifdef EATHENA_SUPPORT if (slot == WEAPON_SPRITE) mEquippedWeapon = NULL; +#endif } else { @@ -229,3 +236,55 @@ void Player::updateCoords() mName->adviseXY(mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET); } +#ifdef TMWSERV_SUPPORT + +Guild* Player::addGuild(short guildId, short rights) +{ + Guild *guild = new Guild(guildId, rights); + mGuilds.insert(std::pair<int, Guild*>(guildId, guild)); + return guild; +} + +void Player::removeGuild(int id) +{ + mGuilds.erase(id); +} + +Guild* Player::getGuild(const std::string &guildName) +{ + std::map<int, Guild*>::iterator itr, itr_end = mGuilds.end(); + for (itr = mGuilds.begin(); itr != itr_end; ++itr) + { + Guild *guild = itr->second; + if (guild->getName() == guildName) + { + return guild; + } + } + + return NULL; +} + +Guild* Player::getGuild(int id) +{ + std::map<int, Guild*>::iterator itr; + itr = mGuilds.find(id); + if (itr != mGuilds.end()) + { + return itr->second; + } + + return NULL; +} + +short Player::getNumberOfGuilds() +{ + return mGuilds.size(); +} + +void Player::setInParty(bool value) +{ + mInParty = value; +} + +#endif diff --git a/src/player.h b/src/player.h index b815b829..1904c6d9 100644 --- a/src/player.h +++ b/src/player.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +27,9 @@ class FlashText; class Graphics; class Map; +#ifdef TMWSERV_SUPPORT +class Guild; +#endif /** * A player being. Players have their name drawn beneath them. This class also @@ -37,6 +39,9 @@ class Map; class Player : public Being { public: + /** + * Constructor. + */ Player(int id, int job, Map *map); ~Player(); @@ -46,7 +51,9 @@ class Player : public Being */ virtual void setName(const std::string &name); +#ifdef EATHENA_SUPPORT virtual void logic(); +#endif virtual Type getType() const; @@ -67,17 +74,76 @@ class Player : public Being /** * Sets visible equipments for this player. */ - virtual void setSprite(int slot, int id, std::string color = ""); + virtual void setSprite(int slot, int id, const std::string &color = ""); /** * Flash the player's name */ void flash(int time); +#ifdef TMWSERV_SUPPORT + /** + * Adds a guild to the player. + */ + Guild* addGuild(short guildId, short rights); + + /** + * Removers a guild from the player. + */ + void removeGuild(int id); + + /** + * Returns a pointer to the specified guild. + */ + Guild* getGuild(const std::string &guildName); + + /** + * Returns a pointer to the guild with matching id. + */ + Guild* getGuild(int id); + + /** + * Get number of guilds the player belongs to. + */ + short getNumberOfGuilds(); + + /** + * Set the player in party + */ + void setInParty(bool value); + + /** + * Returns whether player is in the party + */ + bool getInParty() const { return mInParty; } +#endif + + /** + * Gets the way the character is blocked by other objects. + */ + virtual unsigned char getWalkMask() const + { return 0x82; } // blocked by walls and monsters (bin 1000 0010) + protected: + /** + * Gets the way the monster blocks pathfinding for other objects. + */ + virtual Map::BlockType getBlockType() const + { return Map::BLOCKTYPE_CHARACTER; } + virtual void updateCoords(); +#ifdef TMWSERV_SUPPORT + // Character guild information + std::map<int, Guild*> mGuilds; +#endif + FlashText *mName; + +#ifdef TMWSERV_SUPPORT + private: + bool mInParty; +#endif }; #endif diff --git a/src/player_relations.cpp b/src/player_relations.cpp index eec4153c..ef2ef1bc 100644 --- a/src/player_relations.cpp +++ b/src/player_relations.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -352,8 +351,6 @@ private: -static std::vector<PlayerIgnoreStrategy *> player_ignore_strategies; - std::vector<PlayerIgnoreStrategy *> * PlayerRelationsManager::getPlayerIgnoreStrategies() { diff --git a/src/player_relations.h b/src/player_relations.h index f4860e08..a6c6a115 100644 --- a/src/player_relations.h +++ b/src/player_relations.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,7 +94,6 @@ class PlayerRelationsManager { public: PlayerRelationsManager(); - ~PlayerRelationsManager(); /** diff --git a/src/position.cpp b/src/position.cpp index f370f27b..69d50476 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/position.h b/src/position.h index 1c961c46..cbcf8c99 100644 --- a/src/position.h +++ b/src/position.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/properties.h b/src/properties.h index ad5af1d6..a2ce5b88 100644 --- a/src/properties.h +++ b/src/properties.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,7 +45,8 @@ class Properties * @return the value of the given property or the given default when it * doesn't exist. */ - const std::string& getProperty(const std::string &name, const std::string &def = "") const + const std::string &getProperty(const std::string &name, + const std::string &def = "") const { PropertyMap::const_iterator i = mProperties.find(name); return (i != mProperties.end()) ? i->second : def; @@ -60,7 +60,7 @@ class Properties * @return the value of the given property, or 0.0f when it doesn't * exist. */ - float getFloatProperty(std::string const &name, float def = 0.0f) const + float getFloatProperty(const std::string &name, float def = 0.0f) const { PropertyMap::const_iterator i = mProperties.find(name); float ret = def; diff --git a/src/resources/action.cpp b/src/resources/action.cpp index 27369def..7bd7c54f 100644 --- a/src/resources/action.cpp +++ b/src/resources/action.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,10 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "action.h" -#include "animation.h" +#include "resources/action.h" -#include "../utils/dtor.h" +#include "resources/animation.h" + +#include "utils/dtor.h" Action::Action() { diff --git a/src/resources/action.h b/src/resources/action.h index 8dde068c..387f1b14 100644 --- a/src/resources/action.h +++ b/src/resources/action.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,19 +34,13 @@ class Animation; class Action { public: - /** - * Constructor. - */ Action(); - /** - * Destructor. - */ ~Action(); void setAnimation(int direction, Animation *animation); - Animation* getAnimation(int direction) const; + Animation *getAnimation(int direction) const; protected: typedef std::map<int, Animation*> Animations; diff --git a/src/resources/ambientoverlay.cpp b/src/resources/ambientoverlay.cpp index 9585f4f7..93c7c3e1 100644 --- a/src/resources/ambientoverlay.cpp +++ b/src/resources/ambientoverlay.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,10 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "ambientoverlay.h" -#include "image.h" +#include "resources/ambientoverlay.h" -#include "../graphics.h" +#include "resources/image.h" + +#include "graphics.h" AmbientOverlay::AmbientOverlay(Image *img, float parallax, float speedX, float speedY): diff --git a/src/resources/ambientoverlay.h b/src/resources/ambientoverlay.h index 142dfd2f..756d0eb7 100644 --- a/src/resources/ambientoverlay.h +++ b/src/resources/ambientoverlay.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,17 +31,14 @@ class AmbientOverlay /** * Constructor. * - * @param img the image this overlay displays - * @param parallax scroll factor based on camera position - * @param speedX scrolling speed in x-direction - * @param speedY scrolling speed in y-direction + * @param img the image this overlay displays + * @param parallax scroll factor based on camera position + * @param speedX scrolling speed in x-direction + * @param speedY scrolling speed in y-direction */ AmbientOverlay(Image *img, float parallax, float speedX, float speedY); - /** - * Destructor. - */ ~AmbientOverlay(); void update(int timePassed, float dx, float dy); diff --git a/src/resources/animation.cpp b/src/resources/animation.cpp index 901f4f25..40a2687f 100644 --- a/src/resources/animation.cpp +++ b/src/resources/animation.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,16 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "animation.h" +#include "resources/animation.h" -#include "../utils/dtor.h" +#include "utils/dtor.h" Animation::Animation(): mDuration(0) { } -void Animation::addFrame(Image *image, unsigned int delay, int offsetX, int offsetY) +void Animation::addFrame(Image *image, unsigned int delay, + int offsetX, int offsetY) { Frame frame = { image, delay, offsetX, offsetY }; mFrames.push_back(frame); diff --git a/src/resources/animation.h b/src/resources/animation.h index bc8431c7..f309dbf8 100644 --- a/src/resources/animation.h +++ b/src/resources/animation.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,15 +46,13 @@ struct Frame class Animation { public: - /** - * Constructor. - */ Animation(); /** * Appends a new animation at the end of the sequence. */ - void addFrame(Image *image, unsigned int delay, int offsetX, int offsetY); + void addFrame(Image *image, unsigned int delay, + int offsetX, int offsetY); /** * Appends an animation terminator that states that the animation @@ -66,7 +63,7 @@ class Animation /** * Returns the frame at the specified index. */ - Frame* getFrame(int index) { return &(mFrames[index]); } + Frame *getFrame(int index) { return &(mFrames[index]); } /** * Returns the length of this animation in frames. diff --git a/src/resources/colordb.cpp b/src/resources/colordb.cpp index c9252a8a..af498297 100644 --- a/src/resources/colordb.cpp +++ b/src/resources/colordb.cpp @@ -1,8 +1,8 @@ /* - * Color Database - * Copyright 2008 Aethyra Development Team + * Color database + * Copyright (C) 2008 Aethyra Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,17 +15,17 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <libxml/tree.h> +#include "resources/colordb.h" -#include "colordb.h" +#include "log.h" -#include "../log.h" +#include "utils/xml.h" -#include "../utils/xml.h" +#include <libxml/tree.h> #define HAIR_COLOR_FILE "colors.xml" #define TMW_COLOR_FILE "hair.xml" @@ -96,7 +96,7 @@ void ColorDB::unload() mLoaded = false; } -std::string& ColorDB::get(int id) +std::string &ColorDB::get(int id) { if (!mLoaded) load(); diff --git a/src/resources/colordb.h b/src/resources/colordb.h index d4568d54..92b63d77 100644 --- a/src/resources/colordb.h +++ b/src/resources/colordb.h @@ -1,8 +1,8 @@ /* - * Color Database - * Copyright 2008 Aethyra Development Team + * Color database + * Copyright (C) 2008 Aethyra Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,8 +15,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef COLOR_MANAGER_H @@ -26,7 +26,7 @@ #include <string> /** - * The class that holds the color information. + * Color information database. */ namespace ColorDB { @@ -40,13 +40,13 @@ namespace ColorDB */ void unload(); - std::string& get(int id); + std::string &get(int id); int size(); // Color DB typedef std::map<int, std::string> Colors; typedef Colors::iterator ColorIterator; -}; +} #endif diff --git a/src/resources/dye.cpp b/src/resources/dye.cpp index 35a8ca89..aa4d6835 100644 --- a/src/resources/dye.cpp +++ b/src/resources/dye.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,18 +19,22 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <sstream> +#include "resources/dye.h" -#include "dye.h" +#include "log.h" -#include "../log.h" +#include <sstream> DyePalette::DyePalette(const std::string &description) { int size = description.length(); - if (size == 0 || description[0] != '#') + if (size == 0) + return; + if (description[0] != '#') + { // TODO: load palette from file. return; + } int pos = 1; for (;;) diff --git a/src/resources/dye.h b/src/resources/dye.h index f39ba043..d0d010bc 100644 --- a/src/resources/dye.h +++ b/src/resources/dye.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/resources/emotedb.cpp b/src/resources/emotedb.cpp index ec87c5cd..3ee40f0e 100644 --- a/src/resources/emotedb.cpp +++ b/src/resources/emotedb.cpp @@ -1,8 +1,8 @@ /* * Emote database - * Copyright 2009 Aethyra Development Team + * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,16 +15,16 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "emotedb.h" +#include "resources/emotedb.h" -#include "../animatedsprite.h" -#include "../log.h" +#include "animatedsprite.h" +#include "log.h" -#include "../utils/xml.h" +#include "utils/xml.h" namespace { @@ -138,13 +138,13 @@ const EmoteInfo *EmoteDB::get(int id) } } -const AnimatedSprite* EmoteDB::getAnimation(int id) +const AnimatedSprite *EmoteDB::getAnimation(int id) { const EmoteInfo *info = get(id); return info->sprites.front()->sprite; } -const int& EmoteDB::getLast() +const int &EmoteDB::getLast() { return mLastEmote; } diff --git a/src/resources/emotedb.h b/src/resources/emotedb.h index 48e1d53c..375887d2 100644 --- a/src/resources/emotedb.h +++ b/src/resources/emotedb.h @@ -1,8 +1,8 @@ /* * Emote database - * Copyright 2009 Aethyra Development Team + * Copyright (C) 2009 Aethyra Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,8 +15,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EMOTE_DB_H @@ -55,7 +55,7 @@ namespace EmoteDB const AnimatedSprite *getAnimation(int id); - const int& getLast(); + const int &getLast(); typedef EmoteInfos::iterator EmoteInfosIterator; } diff --git a/src/resources/image.cpp b/src/resources/image.cpp index cff40197..0c542a8b 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,13 +19,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <SDL_image.h> +#include "resources/image.h" + +#include "resources/dye.h" -#include "dye.h" -#include "image.h" +#include "log.h" -#include "../log.h" -#include "../position.h" +#include <SDL_image.h> #ifdef USE_OPENGL bool Image::mUseOpenGL = false; @@ -316,7 +315,7 @@ void Image::setAlpha(float a) } } -Image* Image::merge(Image* image, const Position& pos) +Image* Image::merge(Image *image, int x, int y) { SDL_Surface* surface = new SDL_Surface(*(image->mImage)); @@ -326,20 +325,20 @@ Image* Image::merge(Image* image, const Position& pos) SDL_PixelFormat *current_fmt = mImage->format; SDL_PixelFormat *surface_fmt = surface->format; int current_offset, surface_offset; - Position offset(0, 0); + int offset_x, offset_y; SDL_LockSurface(surface); SDL_LockSurface(mImage); // for each pixel lines of a source image - for (offset.x = (pos.x > 0 ? 0 : -pos.x); offset.x < image->getWidth() && - pos.x + offset.x < getWidth(); offset.x++) + for (offset_x = (x > 0 ? 0 : -x); offset_x < image->getWidth() && + x + offset_x < getWidth(); offset_x++) { - for (offset.y = (pos.y > 0 ? 0 : -pos.y); offset.y < image->getHeight() - && pos.y + offset.y < getHeight(); offset.y++) + for (offset_y = (y > 0 ? 0 : -y); offset_y < image->getHeight() + && y + offset_y < getHeight(); offset_y++) { // Computing offset on both images - current_offset = (pos.y + offset.y) * getWidth() + pos.x + offset.x; - surface_offset = offset.y * surface->w + offset.x; + current_offset = (y + offset_y) * getWidth() + x + offset_x; + surface_offset = offset_y * surface->w + offset_x; // Retrieving a pixel to merge surface_pix = ((Uint32*) surface->pixels)[surface_offset]; @@ -386,12 +385,12 @@ Image* Image::merge(Image* image, const Position& pos) SDL_UnlockSurface(surface); SDL_UnlockSurface(mImage); - Image* newImage = new Image(surface); + Image *newImage = new Image(surface); return newImage; } -float Image::getAlpha() +float Image::getAlpha() const { return mAlpha; } diff --git a/src/resources/image.h b/src/resources/image.h index f6b77f26..3cfb9216 100644 --- a/src/resources/image.h +++ b/src/resources/image.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,9 +22,11 @@ #ifndef IMAGE_H #define IMAGE_H -#include <SDL.h> +#include "main.h" + +#include "resources/resource.h" -#include "../main.h" +#include <SDL.h> #ifdef USE_OPENGL @@ -38,12 +39,8 @@ #include <SDL_opengl.h> #endif -#include "resource.h" - class Dye; class Position; -class SDL_Rect; -class SDL_Surface; /** * Defines a class for loading and storing images. @@ -123,7 +120,7 @@ class Image : public Resource /** * Returns the alpha value of this image. */ - float getAlpha(); + float getAlpha() const; #ifdef USE_OPENGL /** @@ -140,7 +137,7 @@ class Image : public Resource * improve overall framerates. Don't use unless you are using it to * reduce the number of overall layers that need to be drawn through SDL. */ - Image* merge(Image* image, const Position& pos); + Image *merge(Image *image, int x, int y); protected: /** diff --git a/src/resources/imageloader.cpp b/src/resources/imageloader.cpp index fe420e89..694c57af 100644 --- a/src/resources/imageloader.cpp +++ b/src/resources/imageloader.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,14 +19,15 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> +#include "resources/imageloader.h" + +#include "resources/image.h" +#include "resources/resourcemanager.h" #include <guichan/color.hpp> #include <guichan/sdl/sdlpixel.hpp> -#include "image.h" -#include "imageloader.h" -#include "resourcemanager.h" +#include <cassert> ProxyImage::ProxyImage(SDL_Surface *s): mImage(NULL), mSDLImage(s) @@ -88,7 +88,7 @@ void ProxyImage::convertToDisplayFormat() mSDLImage = NULL; } -gcn::Image *ImageLoader::load(std::string const &filename, bool convert) +gcn::Image *ImageLoader::load(const std::string &filename, bool convert) { ResourceManager *resman = ResourceManager::getInstance(); ProxyImage *i = new ProxyImage(resman->loadSDLSurface(filename)); diff --git a/src/resources/imageloader.h b/src/resources/imageloader.h index 2695b99c..d3207715 100644 --- a/src/resources/imageloader.h +++ b/src/resources/imageloader.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,11 +22,11 @@ #ifndef IMAGELOADER_H #define IMAGELOADER_H -#include <string> - #include <guichan/image.hpp> #include <guichan/imageloader.hpp> +#include <string> + class Image; struct SDL_Surface; @@ -36,6 +35,7 @@ class ProxyImage : public gcn::Image public: ProxyImage(SDL_Surface *); ~ProxyImage(); + void free(); int getWidth() const; int getHeight() const; @@ -62,7 +62,8 @@ class ProxyImage : public gcn::Image class ImageLoader : public gcn::ImageLoader { public: - gcn::Image *load(std::string const &filename, bool convertToDisplayFormat); + gcn::Image *load(const std::string &filename, + bool convertToDisplayFormat); }; #endif diff --git a/src/resources/imageset.cpp b/src/resources/imageset.cpp index 33be1573..0c836134 100644 --- a/src/resources/imageset.cpp +++ b/src/resources/imageset.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,12 +19,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "image.h" -#include "imageset.h" +#include "resources/imageset.h" -#include "../log.h" +#include "resources/image.h" -#include "../utils/dtor.h" +#include "log.h" + +#include "utils/dtor.h" ImageSet::ImageSet(Image *img, int width, int height) { diff --git a/src/resources/imageset.h b/src/resources/imageset.h index ad209aaf..f4464017 100644 --- a/src/resources/imageset.h +++ b/src/resources/imageset.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,9 +22,9 @@ #ifndef IMAGESET_H #define IMAGESET_H -#include <vector> +#include "resources/resource.h" -#include "resource.h" +#include <vector> class Image; @@ -35,7 +34,7 @@ class Image; class ImageSet : public Resource { public: - /* + /** * Cuts the passed image in a grid of sub images. */ ImageSet(Image *img, int w, int h); @@ -48,12 +47,12 @@ class ImageSet : public Resource /** * Returns the width of the images in the image set. */ - int getWidth() const { return mWidth; }; + int getWidth() const { return mWidth; } /** * Returns the height of the images in the image set. */ - int getHeight() const { return mHeight; }; + int getHeight() const { return mHeight; } typedef std::vector<Image*>::size_type size_type; Image* get(size_type i) const; diff --git a/src/resources/imagewriter.cpp b/src/resources/imagewriter.cpp index 854753c1..097e0c05 100644 --- a/src/resources/imagewriter.cpp +++ b/src/resources/imagewriter.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,14 +19,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "resources/imagewriter.h" + +#include "log.h" + #include <png.h> #include <SDL.h> #include <string> -#include "imagewriter.h" - -#include "../log.h" - bool ImageWriter::writePNG(SDL_Surface *surface, const std::string &filename) { // TODO Maybe someone can make this look nice? diff --git a/src/resources/imagewriter.h b/src/resources/imagewriter.h index c69eb2d3..a9133846 100644 --- a/src/resources/imagewriter.h +++ b/src/resources/imagewriter.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <iosfwd> + struct SDL_Surface; class ImageWriter diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 49913300..db919b64 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,18 +19,22 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> +#include "resources/itemdb.h" -#include <libxml/tree.h> +#include "resources/iteminfo.h" +#include "resources/resourcemanager.h" -#include "itemdb.h" +#include "log.h" -#include "../log.h" +#include "utils/dtor.h" +#include "utils/gettext.h" +#include "utils/strprintf.h" +#include "utils/stringutils.h" +#include "utils/xml.h" -#include "../utils/dtor.h" -#include "../utils/gettext.h" -#include "../utils/stringutils.h" -#include "../utils/xml.h" +#include <libxml/tree.h> + +#include <cassert> namespace { @@ -45,6 +48,48 @@ namespace static void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node); static void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node); +static char const *const fields[][2] = +{ + { "attack", N_("Attack %+d") }, + { "defense", N_("Defense %+d") }, + { "hp", N_("HP %+d") }, + { "mp", N_("MP %+d") } +}; + +static ItemType itemTypeFromString(const std::string &name, int id = 0) +{ + if (name=="generic") return ITEM_UNUSABLE; + else if (name=="usable") return ITEM_USABLE; + else if (name=="equip-1hand") return ITEM_EQUIPMENT_ONE_HAND_WEAPON; + else if (name=="equip-2hand") return ITEM_EQUIPMENT_TWO_HANDS_WEAPON; + else if (name=="equip-torso") return ITEM_EQUIPMENT_TORSO; + else if (name=="equip-arms") return ITEM_EQUIPMENT_ARMS; + else if (name=="equip-head") return ITEM_EQUIPMENT_HEAD; + else if (name=="equip-legs") return ITEM_EQUIPMENT_LEGS; + else if (name=="equip-shield") return ITEM_EQUIPMENT_SHIELD; + else if (name=="equip-ring") return ITEM_EQUIPMENT_RING; + else if (name=="equip-necklace") return ITEM_EQUIPMENT_NECKLACE; + else if (name=="equip-feet") return ITEM_EQUIPMENT_FEET; + else if (name=="equip-ammo") return ITEM_EQUIPMENT_AMMO; + else return ITEM_UNUSABLE; +} + +static WeaponType weaponTypeFromString(const std::string &name, int id = 0) +{ + if (name=="knife") return WPNTYPE_KNIFE; + else if (name=="sword") return WPNTYPE_SWORD; + else if (name=="polearm") return WPNTYPE_POLEARM; + else if (name=="staff") return WPNTYPE_STAFF; + else if (name=="whip") return WPNTYPE_WHIP; + else if (name=="bow") return WPNTYPE_BOW; + else if (name=="shooting") return WPNTYPE_SHOOTING; + else if (name=="mace") return WPNTYPE_MACE; + else if (name=="axe") return WPNTYPE_AXE; + else if (name=="thrown") return WPNTYPE_THROWN; + + else return WPNTYPE_NONE; +} + void ItemDB::load() { if (mLoaded) @@ -52,7 +97,7 @@ void ItemDB::load() logger->log("Initializing item database..."); - mUnknown = new ItemInfo(); + mUnknown = new ItemInfo; mUnknown->setName(_("Unknown item")); mUnknown->setImageName(""); mUnknown->setSprite("error.xml", GENDER_MALE); @@ -83,61 +128,81 @@ void ItemDB::load() logger->log("ItemDB: Redefinition of item ID %d", id); } - std::string type = XML::getProperty(node, "type", "other"); + std::string typeStr = XML::getProperty(node, "type", "other"); int weight = XML::getProperty(node, "weight", 0); int view = XML::getProperty(node, "view", 0); std::string name = XML::getProperty(node, "name", ""); std::string image = XML::getProperty(node, "image", ""); std::string description = XML::getProperty(node, "description", ""); - std::string effect = XML::getProperty(node, "effect", ""); +#ifdef TMWSERV_SUPPORT + int weaponType = weaponTypeFromString(XML::getProperty(node, "weapon-type", "")); +#else int weaponType = XML::getProperty(node, "weapon_type", 0); +#endif + int attackRange = XML::getProperty(node, "attack-range", 0); + + ItemInfo *itemInfo = new ItemInfo; + itemInfo->setId(id); + itemInfo->setImageName(image); + itemInfo->setName(name.empty() ? _("Unnamed") : name); + itemInfo->setDescription(description); +#ifdef TMWSERV_SUPPORT + int type = itemTypeFromString(typeStr); + itemInfo->setType(type); +#else + itemInfo->setType(typeStr); +#endif + itemInfo->setView(view); + itemInfo->setWeight(weight); + itemInfo->setWeaponType(weaponType); + itemInfo->setAttackRange(attackRange); + +#ifdef TMWSERV_SUPPORT + std::string effect; + for (int i = 0; i < int(sizeof(fields) / sizeof(fields[0])); ++i) + { + int value = XML::getProperty(node, fields[i][0], 0); + if (!value) continue; + if (!effect.empty()) effect += " / "; + effect += strprintf(gettext(fields[i][1]), value); + } +#else + std::string effect = XML::getProperty(node, "effect", ""); +#endif + itemInfo->setEffect(effect); - if (id) + + for_each_xml_child_node(itemChild, node) { - ItemInfo *itemInfo = new ItemInfo; - itemInfo->setId(id); - itemInfo->setImageName(image); - itemInfo->setName(name.empty() ? _("Unnamed") : name); - itemInfo->setDescription(description); - itemInfo->setEffect(effect); - itemInfo->setType(type); - itemInfo->setView(view); - itemInfo->setWeight(weight); - itemInfo->setWeaponType(weaponType); - - for_each_xml_child_node(itemChild, node) + if (xmlStrEqual(itemChild->name, BAD_CAST "sprite")) { - if (xmlStrEqual(itemChild->name, BAD_CAST "sprite")) - { - std::string attackParticle = XML::getProperty( - itemChild, "particle-effect", ""); - itemInfo->setParticleEffect(attackParticle); - - loadSpriteRef(itemInfo, itemChild); - } - else if (xmlStrEqual(itemChild->name, BAD_CAST "sound")) - { - loadSoundRef(itemInfo, itemChild); - } + std::string attackParticle = XML::getProperty( + itemChild, "particle-effect", ""); + itemInfo->setParticleEffect(attackParticle); + + loadSpriteRef(itemInfo, itemChild); } + else if (xmlStrEqual(itemChild->name, BAD_CAST "sound")) + { + loadSoundRef(itemInfo, itemChild); + } + } + + mItemInfos[id] = itemInfo; + if (!name.empty()) + { + std::string temp = name; + toLower(trim(temp)); - mItemInfos[id] = itemInfo; - if (!name.empty()) + NamedItemInfoIterator itr = mNamedItemInfos.find(temp); + if (itr == mNamedItemInfos.end()) + { + mNamedItemInfos[temp] = itemInfo; + } + else { - std::string temp = name; - toLower(trim(temp)); - - NamedItemInfoIterator itr = mNamedItemInfos.find(temp); - if (itr == mNamedItemInfos.end()) - { - mNamedItemInfos[temp] = itemInfo; - } - else - { - logger->log("ItemDB: Duplicate name of item found item %d", - id); - } + logger->log("ItemDB: Duplicate name of item found item %d", id); } } diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h index 1e55f146..aa5edab5 100644 --- a/src/resources/itemdb.h +++ b/src/resources/itemdb.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,13 +23,12 @@ #define ITEM_MANAGER_H #include <map> - -#include "iteminfo.h" +#include <string> class ItemInfo; /** - * The namespace that holds the item information. + * Item information database. */ namespace ItemDB { @@ -44,8 +42,8 @@ namespace ItemDB */ void unload(); - const ItemInfo& get(int id); - const ItemInfo& get(const std::string &name); + const ItemInfo &get(int id); + const ItemInfo &get(const std::string &name); // Items database typedef std::map<int, ItemInfo*> ItemInfos; diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp index 8dcb1c32..63b0c00e 100644 --- a/src/resources/iteminfo.cpp +++ b/src/resources/iteminfo.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,10 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "itemdb.h" -#include "iteminfo.h" +#include "resources/iteminfo.h" -const std::string& ItemInfo::getSprite(Gender gender) const +#include "resources/itemdb.h" + +const std::string &ItemInfo::getSprite(Gender gender) const { if (mView) { @@ -45,6 +45,26 @@ void ItemInfo::setWeaponType(int type) // See server item.hpp file for type values. switch (type) { +#ifdef TMWSERV_SUPPORT + case WPNTYPE_NONE: + mAttackType = ACTION_DEFAULT; + break; + case WPNTYPE_KNIFE: + case WPNTYPE_SWORD: + mAttackType = ACTION_ATTACK_STAB; + break; + case WPNTYPE_THROWN: + mAttackType = ACTION_ATTACK_THROW; + break; + case WPNTYPE_BOW: + mAttackType = ACTION_ATTACK_BOW; + break; + case WPNTYPE_POLEARM: + mAttackType = ACTION_ATTACK_SWING; + break; + default: + mAttackType = ACTION_ATTACK; +#else case 0: // none mAttackType = ACTION_DEFAULT; break; @@ -63,6 +83,7 @@ void ItemInfo::setWeaponType(int type) break; default: mAttackType = ACTION_ATTACK; +#endif } } @@ -71,7 +92,7 @@ void ItemInfo::addSound(EquipmentSoundEvent event, const std::string &filename) mSounds[event].push_back("sfx/" + filename); } -const std::string& ItemInfo::getSound(EquipmentSoundEvent event) const +const std::string &ItemInfo::getSound(EquipmentSoundEvent event) const { static const std::string empty; std::map< EquipmentSoundEvent, std::vector<std::string> >::const_iterator i; diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h index 0ea59050..bcee1fbd 100644 --- a/src/resources/iteminfo.h +++ b/src/resources/iteminfo.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,20 +22,88 @@ #ifndef ITEMINFO_H #define ITEMINFO_H +#include "resources/spritedef.h" + +#include "being.h" + #include <map> #include <string> #include <vector> -#include "spritedef.h" - -#include "../being.h" - enum EquipmentSoundEvent { EQUIP_EVENT_STRIKE, EQUIP_EVENT_HIT }; +enum EquipmentSlot +{ + // Equipment rules: + // 1 Brest equipment + EQUIP_TORSO_SLOT = 0, + // 1 arms equipment + EQUIP_ARMS_SLOT = 1, + // 1 head equipment + EQUIP_HEAD_SLOT = 2, + // 1 legs equipment + EQUIP_LEGS_SLOT = 3, + // 1 feet equipment + EQUIP_FEET_SLOT = 4, + // 2 rings + EQUIP_RING1_SLOT = 5, + EQUIP_RING2_SLOT = 6, + // 1 necklace + EQUIP_NECKLACE_SLOT = 7, + // Fight: + // 2 one-handed weapons + // or 1 two-handed weapon + // or 1 one-handed weapon + 1 shield. + EQUIP_FIGHT1_SLOT = 8, + EQUIP_FIGHT2_SLOT = 9, + // Projectile: + // this item does not amount to one, it only indicates the chosen projectile. + EQUIP_PROJECTILE_SLOT = 10 +}; + + +/** + * Enumeration of available Item types. + */ +enum ItemType +{ + ITEM_UNUSABLE = 0, + ITEM_USABLE, // 1 + ITEM_EQUIPMENT_ONE_HAND_WEAPON, // 2 + ITEM_EQUIPMENT_TWO_HANDS_WEAPON,// 3 + ITEM_EQUIPMENT_TORSO,// 4 + ITEM_EQUIPMENT_ARMS,// 5 + ITEM_EQUIPMENT_HEAD,// 6 + ITEM_EQUIPMENT_LEGS,// 7 + ITEM_EQUIPMENT_SHIELD,// 8 + ITEM_EQUIPMENT_RING,// 9 + ITEM_EQUIPMENT_NECKLACE,// 10 + ITEM_EQUIPMENT_FEET,// 11 + ITEM_EQUIPMENT_AMMO// 12 +}; + +/** + * Enumeration of available weapon's types. + */ +enum WeaponType +{ + WPNTYPE_NONE = 0, + WPNTYPE_KNIFE, + WPNTYPE_SWORD, + WPNTYPE_POLEARM, + WPNTYPE_STAFF, + WPNTYPE_WHIP, + WPNTYPE_BOW, + WPNTYPE_SHOOTING, + WPNTYPE_MACE, + WPNTYPE_AXE, + WPNTYPE_THROWN +}; + /** * Defines a class for storing item infos. This includes information used when * the item is equipped. @@ -48,7 +115,9 @@ class ItemInfo * Constructor. */ ItemInfo(): - mType(""), +#ifdef TMWSERV_SUPPORT + mType(ITEM_UNUSABLE), +#endif mWeight(0), mView(0), mAttackType(ACTION_DEFAULT) @@ -64,7 +133,7 @@ class ItemInfo void setName(const std::string &name) { mName = name; } - const std::string& getName() const + const std::string &getName() const { return mName; } void setParticleEffect(const std::string &particleEffect) @@ -75,24 +144,32 @@ class ItemInfo void setImageName(const std::string &imageName) { mImageName = imageName; } - const std::string& getImageName() const + const std::string &getImageName() const { return mImageName; } void setDescription(const std::string &description) { mDescription = description; } - const std::string& getDescription() const + const std::string &getDescription() const { return mDescription; } void setEffect(const std::string &effect) { mEffect = effect; } - const std::string& getEffect() const { return mEffect; } + const std::string &getEffect() const { return mEffect; } - void setType(const std::string& type) +#ifdef TMWSERV_SUPPORT + void setType(short type) { mType = type; } - const std::string& getType() const { return mType; } + short getType() const + { return mType; } +#else + void setType(const std::string &type) + { mType = type; } + + const std::string &getType() const { return mType; } +#endif void setWeight(short weight) { mWeight = weight; } @@ -106,23 +183,33 @@ class ItemInfo void setSprite(const std::string &animationFile, Gender gender) { mAnimationFiles[gender] = animationFile; } - const std::string& getSprite(Gender gender) const; + const std::string &getSprite(Gender gender) const; void setWeaponType(int); SpriteAction getAttackType() const { return mAttackType; } + int getAttackRange() const + { return mAttackRange; } + + void setAttackRange(int r) + { mAttackRange = r; } + void addSound(EquipmentSoundEvent event, const std::string &filename); - const std::string& getSound(EquipmentSoundEvent event) const; + const std::string &getSound(EquipmentSoundEvent event) const; protected: std::string mImageName; /**< The filename of the icon image. */ std::string mName; std::string mDescription; /**< Short description. */ std::string mEffect; /**< Description of effects. */ +#ifdef TMWSERV_SUPPORT + char mType; /**< Item type. */ +#else std::string mType; /**< Item type. */ +#endif std::string mParticle; /**< Particle effect used with this item */ short mWeight; /**< Weight in grams. */ int mView; /**< Item ID of how this item looks. */ @@ -130,6 +217,7 @@ class ItemInfo // Equipment related members SpriteAction mAttackType; /**< Attack type, in case of weapon. */ + int mAttackRange; /**< Attack range, will be zero if non weapon. */ /** Maps gender to sprite filenames. */ std::map<int, std::string> mAnimationFiles; diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index e40acd77..50d7cf67 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,22 +19,22 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> -#include <iostream> -#include <zlib.h> +#include "resources/animation.h" +#include "resources/image.h" +#include "resources/mapreader.h" +#include "resources/resourcemanager.h" -#include "animation.h" -#include "image.h" -#include "mapreader.h" -#include "resourcemanager.h" +#include "log.h" +#include "map.h" +#include "tileset.h" -#include "../log.h" -#include "../map.h" -#include "../tileset.h" +#include "utils/base64.h" +#include "utils/stringutils.h" +#include "utils/xml.h" -#include "../utils/base64.h" -#include "../utils/stringutils.h" -#include "../utils/xml.h" +#include <cassert> +#include <iostream> +#include <zlib.h> const unsigned int DEFAULT_TILE_WIDTH = 32; const unsigned int DEFAULT_TILE_HEIGHT = 32; @@ -311,7 +310,8 @@ static void setTile(Map *map, MapLayer *layer, int x, int y, int gid) layer->setTile(x, y, img); } else { // Set collision tile - map->setWalk(x, y, (!set || (gid - set->getFirstGid() == 0))); + if (set && (gid - set->getFirstGid() != 0)) + map->blockTile(x, y, Map::BLOCKTYPE_WALL); } } @@ -361,12 +361,12 @@ void MapReader::readLayer(xmlNodePtr node, Map *map) xmlNodePtr dataChild = childNode->xmlChildrenNode; if (!dataChild) continue; - + int len = strlen((const char*)dataChild->content) + 1; unsigned char *charData = new unsigned char[len + 1]; const char *charStart = (const char*)dataChild->content; unsigned char *charIndex = charData; - + while (*charStart) { if (*charStart != ' ' && *charStart != '\t' && *charStart != '\n') @@ -428,10 +428,10 @@ void MapReader::readLayer(xmlNodePtr node, Map *map) } } else { - // Read plain XML map file - for_each_xml_child_node(childNode2, childNode) - { - if (!xmlStrEqual(childNode2->name, BAD_CAST "tile")) + // Read plain XML map file + for_each_xml_child_node(childNode2, childNode) + { + if (!xmlStrEqual(childNode2->name, BAD_CAST "tile")) continue; const int gid = XML::getProperty(childNode2, "gid", -1); @@ -445,12 +445,12 @@ void MapReader::readLayer(xmlNodePtr node, Map *map) } } } - + if (y < h) std::cerr << "TOO SMALL!\n"; if (x) std::cerr << "TOO SMALL!\n"; - + // There can be only one data element break; } @@ -524,7 +524,7 @@ Tileset *MapReader::readTileset(xmlNodePtr node, // create animation if (!set) continue; - Animation *ani = new Animation(); + Animation *ani = new Animation; for (int i = 0; ;i++) { std::map<std::string, int>::iterator iFrame, iDelay; diff --git a/src/resources/mapreader.h b/src/resources/mapreader.h index 2f64aa8c..0ed553c3 100644 --- a/src/resources/mapreader.h +++ b/src/resources/mapreader.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp index b1965989..7bbf9288 100644 --- a/src/resources/monsterdb.cpp +++ b/src/resources/monsterdb.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,14 +19,15 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "monsterdb.h" -#include "monsterinfo.h" +#include "resources/monsterdb.h" -#include "../log.h" +#include "resources/monsterinfo.h" -#include "../utils/dtor.h" -#include "../utils/gettext.h" -#include "../utils/xml.h" +#include "log.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" +#include "utils/xml.h" namespace { @@ -62,7 +62,7 @@ void MonsterDB::load() continue; } - MonsterInfo *currentInfo = new MonsterInfo(); + MonsterInfo *currentInfo = new MonsterInfo; currentInfo->setName(XML::getProperty(monsterNode, "name", _("unnamed"))); @@ -96,8 +96,7 @@ void MonsterDB::load() currentInfo->addSprite( (const char*) spriteNode->xmlChildrenNode->content); } - - if (xmlStrEqual(spriteNode->name, BAD_CAST "sound")) + else if (xmlStrEqual(spriteNode->name, BAD_CAST "sound")) { std::string event = XML::getProperty(spriteNode, "event", ""); const char *filename; @@ -127,15 +126,16 @@ void MonsterDB::load() currentInfo->getName().c_str()); } } - - if (xmlStrEqual(spriteNode->name, BAD_CAST "attack")) + else if (xmlStrEqual(spriteNode->name, BAD_CAST "attack")) { - std::string event = XML::getProperty( + const int id = XML::getProperty(spriteNode, "id", 0); + const std::string particleEffect = XML::getProperty( spriteNode, "particle-effect", ""); - currentInfo->addAttackParticleEffect(event); + SpriteAction spriteAction = SpriteDef::makeSpriteAction( + XML::getProperty(spriteNode, "action", "attack")); + currentInfo->addMonsterAttack(id, particleEffect, spriteAction); } - - if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx")) + else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx")) { currentInfo->addParticleEffect( (const char*) spriteNode->xmlChildrenNode->content); diff --git a/src/resources/monsterdb.h b/src/resources/monsterdb.h index e49901d5..27536ffc 100644 --- a/src/resources/monsterdb.h +++ b/src/resources/monsterdb.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,7 +35,7 @@ namespace MonsterDB void unload(); - const MonsterInfo& get(int id); + const MonsterInfo &get(int id); typedef std::map<int, MonsterInfo*> MonsterInfos; typedef MonsterInfos::iterator MonsterInfoIterator; diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp index 725e9cf5..06a6d3b6 100644 --- a/src/resources/monsterinfo.cpp +++ b/src/resources/monsterinfo.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,13 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "monsterinfo.h" +#include "resources/monsterinfo.h" -#include "../utils/dtor.h" +#include "utils/dtor.h" MonsterInfo::MonsterInfo() { - } MonsterInfo::~MonsterInfo() @@ -36,7 +34,7 @@ MonsterInfo::~MonsterInfo() mSounds.clear(); } -void MonsterInfo::addSound(MonsterSoundEvent event, std::string filename) +void MonsterInfo::addSound(MonsterSoundEvent event, const std::string &filename) { if (mSounds.find(event) == mSounds.end()) { @@ -46,24 +44,41 @@ void MonsterInfo::addSound(MonsterSoundEvent event, std::string filename) mSounds[event]->push_back("sfx/" + filename); } +const std::string &MonsterInfo::getSound(MonsterSoundEvent event) const +{ + static std::string empty(""); + std::map<MonsterSoundEvent, std::vector<std::string>* >::const_iterator i = + mSounds.find(event); + return (i == mSounds.end()) ? empty : + i->second->at(rand() % i->second->size()); +} -std::string MonsterInfo::getSound(MonsterSoundEvent event) const +const std::string &MonsterInfo::getAttackParticleEffect(int attackType) const { - std::map<MonsterSoundEvent, std::vector<std::string>* >::const_iterator i; + static std::string empty(""); + std::map<int, MonsterAttack*>::const_iterator i = + mMonsterAttacks.find(attackType); + return (i == mMonsterAttacks.end()) ? empty : (*i).second->particleEffect; +} - i = mSounds.find(event); +SpriteAction MonsterInfo::getAttackAction(int attackType) const +{ + std::map<int, MonsterAttack*>::const_iterator i = + mMonsterAttacks.find(attackType); + return (i == mMonsterAttacks.end()) ? ACTION_ATTACK : (*i).second->action; +} - if (i == mSounds.end()) - { - return ""; - } - else - { - return i->second->at(rand()%i->second->size()); - } +void MonsterInfo::addMonsterAttack(int id, + const std::string &particleEffect, + SpriteAction action) +{ + MonsterAttack *a = new MonsterAttack; + a->particleEffect = particleEffect; + a->action = action; + mMonsterAttacks[id] = a; } -void MonsterInfo::addParticleEffect(std::string filename) +void MonsterInfo::addParticleEffect(const std::string &filename) { mParticleEffects.push_back(filename); } diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h index 4a3208f4..f8dce13f 100644 --- a/src/resources/monsterinfo.h +++ b/src/resources/monsterinfo.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,13 +22,13 @@ #ifndef MONSTERINFO_H #define MONSTERINFO_H +#include "being.h" + #include <list> #include <map> #include <string> #include <vector> -#include "../being.h" - enum MonsterSoundEvent { MONSTER_EVENT_HIT, @@ -38,6 +37,12 @@ enum MonsterSoundEvent MONSTER_EVENT_DIE }; +struct MonsterAttack +{ + std::string particleEffect; + SpriteAction action; +}; + /** * Holds information about a certain type of monster. This includes the name * of the monster, the sprite to display and the sounds the monster makes. @@ -47,28 +52,23 @@ enum MonsterSoundEvent class MonsterInfo { public: - /** - * Constructor. - */ MonsterInfo(); - /** - * Destructor. - */ ~MonsterInfo(); - void setName(std::string name) { mName = name; } + void setName(const std::string &name) { mName = name; } - void addSprite(std::string filename) { mSprites.push_back(filename); } + void addSprite(const std::string &filename) + { mSprites.push_back(filename); } void setTargetCursorSize(Being::TargetCursorSize targetCursorSize) { mTargetCursorSize = targetCursorSize; } - void addSound(MonsterSoundEvent event, std::string filename); + void addSound(MonsterSoundEvent event, const std::string &filename); - void addParticleEffect(std::string filename); + void addParticleEffect(const std::string &filename); - const std::string& getName() const + const std::string &getName() const { return mName; } const std::list<std::string>& getSprites() const @@ -77,23 +77,26 @@ class MonsterInfo Being::TargetCursorSize getTargetCursorSize() const { return mTargetCursorSize; } - std::string getSound(MonsterSoundEvent event) const; + const std::string &getSound(MonsterSoundEvent event) const; + + void addMonsterAttack(int id, + const std::string &particleEffect, + SpriteAction action); - std::string getAttackParticleEffect() const { return mAttackParticle; } + const std::string &getAttackParticleEffect(int attackType) const; - void addAttackParticleEffect(const std::string &particleEffect) - { mAttackParticle = particleEffect; } + SpriteAction getAttackAction(int attackType) const; const std::list<std::string>& getParticleEffects() const { return mParticleEffects; } private: std::string mName; - std::string mAttackParticle; std::list<std::string> mSprites; Being::TargetCursorSize mTargetCursorSize; std::map<MonsterSoundEvent, std::vector<std::string>* > mSounds; + std::map<int, MonsterAttack*> mMonsterAttacks; std::list<std::string> mParticleEffects; }; -#endif +#endif // MONSTERINFO_H diff --git a/src/resources/music.cpp b/src/resources/music.cpp index 72094025..5937f96b 100644 --- a/src/resources/music.cpp +++ b/src/resources/music.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,9 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "music.h" +#include "resources/music.h" -#include "../log.h" +#include "log.h" Music::Music(Mix_Chunk *music): mChunk(music), diff --git a/src/resources/music.h b/src/resources/music.h index f89c0fb2..88ef93d0 100644 --- a/src/resources/music.h +++ b/src/resources/music.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,12 +22,13 @@ #ifndef MUSIC_H #define MUSIC_H +#include "resources/resource.h" + #ifdef __APPLE__ #include <SDL_mixer/SDL_mixer.h> #else #include <SDL_mixer.h> #endif -#include "resource.h" /** * Defines a class for loading and storing music. diff --git a/src/resources/npcdb.cpp b/src/resources/npcdb.cpp index 3e9decf1..6a880faa 100644 --- a/src/resources/npcdb.cpp +++ b/src/resources/npcdb.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,12 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "npcdb.h" +#include "resources/npcdb.h" -#include "../log.h" +#include "log.h" -#include "../utils/gettext.h" -#include "../utils/xml.h" +#include "utils/gettext.h" +#include "utils/xml.h" namespace { diff --git a/src/resources/npcdb.h b/src/resources/npcdb.h index 394154fa..af6764bf 100644 --- a/src/resources/npcdb.h +++ b/src/resources/npcdb.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/resources/resource.cpp b/src/resources/resource.cpp index ca9a69c3..86e85c9b 100644 --- a/src/resources/resource.cpp +++ b/src/resources/resource.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,10 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> +#include "resources/resource.h" + +#include "resources/resourcemanager.h" -#include "resource.h" -#include "resourcemanager.h" +#include <cassert> Resource::~Resource() { diff --git a/src/resources/resource.h b/src/resources/resource.h index f8822d72..5b70c720 100644 --- a/src/resources/resource.h +++ b/src/resources/resource.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,8 +55,8 @@ class Resource /** * Return the path identifying this resource. */ - const std::string& - getIdPath() { return mIdPath; } + const std::string &getIdPath() const + { return mIdPath; } protected: /** diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index d6ab39a0..33d5e3e5 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "resources/resourcemanager.h" + +#include "resources/dye.h" +#include "resources/image.h" +#include "resources/imageset.h" +#include "resources/music.h" +#include "resources/soundeffect.h" +#include "resources/spritedef.h" + +#include "log.h" + #include <cassert> #include <physfs.h> #include <SDL_image.h> @@ -27,16 +37,6 @@ #include <sys/time.h> -#include "dye.h" -#include "image.h" -#include "imageset.h" -#include "music.h" -#include "resourcemanager.h" -#include "soundeffect.h" -#include "spritedef.h" - -#include "../log.h" - ResourceManager *ResourceManager::instance = NULL; ResourceManager::ResourceManager() @@ -214,7 +214,7 @@ std::string ResourceManager::getPath(const std::string &file) return path; } -Resource *ResourceManager::get(std::string const &idPath, generator fun, +Resource *ResourceManager::get(const std::string &idPath, generator fun, void *data) { // Check if the id exists, and return the value if it does. @@ -266,7 +266,7 @@ struct ResourceLoader } }; -Resource *ResourceManager::load(std::string const &path, loader fun) +Resource *ResourceManager::load(const std::string &path, loader fun) { ResourceLoader l = { this, path, fun }; return get(path, ResourceLoader::load, &l); @@ -308,7 +308,7 @@ struct DyedImageLoader } }; -Image *ResourceManager::getImage(std::string const &idPath) +Image *ResourceManager::getImage(const std::string &idPath) { DyedImageLoader l = { this, idPath }; return static_cast<Image*>(get(idPath, DyedImageLoader::load, &l)); @@ -350,8 +350,7 @@ struct SpriteDefLoader } }; -SpriteDef *ResourceManager::getSprite - (std::string const &path, int variant) +SpriteDef *ResourceManager::getSprite(const std::string &path, int variant) { SpriteDefLoader l = { path, variant }; std::stringstream ss; @@ -380,7 +379,8 @@ void ResourceManager::release(Resource *res) ResourceManager *ResourceManager::getInstance() { // Create a new instance if necessary. - if (instance == NULL) instance = new ResourceManager(); + if (!instance) + instance = new ResourceManager; return instance; } @@ -441,7 +441,7 @@ std::vector<std::string> ResourceManager::loadTextFile(const std::string &fileNa return lines; } -SDL_Surface *ResourceManager::loadSDLSurface(const std::string& filename) +SDL_Surface *ResourceManager::loadSDLSurface(const std::string &filename) { int fileSize; void *buffer = loadFile(filename, fileSize); diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h index 10f6fffe..828c5b0a 100644 --- a/src/resources/resourcemanager.h +++ b/src/resources/resourcemanager.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -116,7 +115,7 @@ class ResourceManager * @return A valid resource or <code>NULL</code> if the resource could * not be generated. */ - Resource *get(std::string const &idPath, generator fun, void *data); + Resource *get(const std::string &idPath, generator fun, void *data); /** * Loads a resource from a file and adds it to the resource map. @@ -126,7 +125,7 @@ class ResourceManager * @return A valid resource or <code>NULL</code> if the resource could * not be loaded. */ - Resource *load(std::string const &path, loader fun); + Resource *load(const std::string &path, loader fun); /** * Convenience wrapper around ResourceManager::get for loading @@ -156,7 +155,7 @@ class ResourceManager * Creates a sprite definition based on a given path and the supplied * variant. */ - SpriteDef *getSprite(std::string const &path, int variant = 0); + SpriteDef *getSprite(const std::string &path, int variant = 0); /** * Releases a resource, placing it in the set of orphaned resources. @@ -184,7 +183,7 @@ class ResourceManager * Loads the given filename as an SDL surface. The returned surface is * expected to be freed by the caller using SDL_FreeSurface. */ - SDL_Surface *loadSDLSurface(const std::string& filename); + SDL_Surface *loadSDLSurface(const std::string &filename); /** * Returns an instance of the class, creating one if it does not diff --git a/src/resources/soundeffect.cpp b/src/resources/soundeffect.cpp index d1d24afb..bdb393ff 100644 --- a/src/resources/soundeffect.cpp +++ b/src/resources/soundeffect.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,9 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "soundeffect.h" +#include "resources/soundeffect.h" -#include "../log.h" +#include "log.h" SoundEffect::~SoundEffect() { diff --git a/src/resources/soundeffect.h b/src/resources/soundeffect.h index fe14df02..dd5d166f 100644 --- a/src/resources/soundeffect.h +++ b/src/resources/soundeffect.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,14 +22,14 @@ #ifndef SOUND_EFFECT_H #define SOUND_EFFECT_H +#include "resources/resource.h" + #ifdef __APPLE__ #include <SDL_mixer/SDL_mixer.h> #else #include <SDL_mixer.h> #endif -#include "resource.h" - /** * Defines a class for loading and storing sound effects. */ @@ -73,4 +72,4 @@ class SoundEffect : public Resource Mix_Chunk *mChunk; }; -#endif +#endif // SOUND_EFFECT_H diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp index d6cc8960..30d8e778 100644 --- a/src/resources/spritedef.cpp +++ b/src/resources/spritedef.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,20 +19,22 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <set> +#include "resources/spritedef.h" + +#include "resources/action.h" +#include "resources/animation.h" +#include "resources/dye.h" +#include "resources/image.h" +#include "resources/imageset.h" +#include "resources/resourcemanager.h" -#include "action.h" -#include "animation.h" -#include "dye.h" -#include "image.h" -#include "imageset.h" -#include "resourcemanager.h" -#include "spritedef.h" +#include "log.h" -#include "../log.h" -#include "../utils/xml.h" +#include "utils/xml.h" + +#include <set> -Action* SpriteDef::getAction(SpriteAction action) const +Action *SpriteDef::getAction(SpriteAction action) const { Actions::const_iterator i = mActions.find(action); @@ -46,7 +47,7 @@ Action* SpriteDef::getAction(SpriteAction action) const return i->second; } -SpriteDef *SpriteDef::load(std::string const &animationFile, int variant) +SpriteDef *SpriteDef::load(const std::string &animationFile, int variant) { std::string::size_type pos = animationFile.find('|'); std::string palettes; @@ -121,7 +122,7 @@ void SpriteDef::loadSprite(xmlNodePtr spriteNode, int variant, } } -void SpriteDef::loadImageSet(xmlNodePtr node, std::string const &palettes) +void SpriteDef::loadImageSet(xmlNodePtr node, const std::string &palettes) { const std::string name = XML::getProperty(node, "name", ""); @@ -167,7 +168,7 @@ void SpriteDef::loadAction(xmlNodePtr node, int variant_offset) actionName.c_str(), getIdPath().c_str()); return; } - Action *action = new Action(); + Action *action = new Action; mActions[actionType] = action; // When first action set it as default direction @@ -201,7 +202,7 @@ void SpriteDef::loadAnimation(xmlNodePtr animationNode, return; } - Animation *animation = new Animation(); + Animation *animation = new Animation; action->setAnimation(directionType, animation); // Get animation frames @@ -320,7 +321,7 @@ SpriteDef::~SpriteDef() } } -SpriteAction SpriteDef::makeSpriteAction(const std::string& action) +SpriteAction SpriteDef::makeSpriteAction(const std::string &action) { if (action.empty() || action == "default") { return ACTION_DEFAULT; @@ -349,6 +350,36 @@ SpriteAction SpriteDef::makeSpriteAction(const std::string& action) else if (action == "attack_throw") { return ACTION_ATTACK_THROW; } + else if (action == "special0") { + return ACTION_SPECIAL_0; + } + else if (action == "special1") { + return ACTION_SPECIAL_1; + } + else if (action == "special2") { + return ACTION_SPECIAL_2; + } + else if (action == "special3") { + return ACTION_SPECIAL_3; + } + else if (action == "special4") { + return ACTION_SPECIAL_4; + } + else if (action == "special5") { + return ACTION_SPECIAL_5; + } + else if (action == "special6") { + return ACTION_SPECIAL_6; + } + else if (action == "special7") { + return ACTION_SPECIAL_7; + } + else if (action == "special8") { + return ACTION_SPECIAL_8; + } + else if (action == "special9") { + return ACTION_SPECIAL_9; + } else if (action == "cast_magic") { return ACTION_CAST_MAGIC; } @@ -372,7 +403,7 @@ SpriteAction SpriteDef::makeSpriteAction(const std::string& action) } } -SpriteDirection SpriteDef::makeSpriteDirection(const std::string& direction) +SpriteDirection SpriteDef::makeSpriteDirection(const std::string &direction) { if (direction.empty() || direction == "default") { return DIRECTION_DEFAULT; @@ -391,5 +422,5 @@ SpriteDirection SpriteDef::makeSpriteDirection(const std::string& direction) } else { return DIRECTION_INVALID; - }; + } } diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h index 040d96e2..45b5b043 100644 --- a/src/resources/spritedef.h +++ b/src/resources/spritedef.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,13 +22,13 @@ #ifndef SPRITEDEF_H #define SPRITEDEF_H +#include "resources/resource.h" + #include <map> #include <string> #include <libxml/tree.h> -#include "resource.h" - class Action; class ImageSet; @@ -44,6 +43,16 @@ enum SpriteAction ACTION_ATTACK_STAB, ACTION_ATTACK_BOW, ACTION_ATTACK_THROW, + ACTION_SPECIAL_0, + ACTION_SPECIAL_1, + ACTION_SPECIAL_2, + ACTION_SPECIAL_3, + ACTION_SPECIAL_4, + ACTION_SPECIAL_5, + ACTION_SPECIAL_6, + ACTION_SPECIAL_7, + ACTION_SPECIAL_8, + ACTION_SPECIAL_9, ACTION_CAST_MAGIC, ACTION_USE_ITEM, ACTION_SIT, @@ -56,8 +65,8 @@ enum SpriteAction enum SpriteDirection { DIRECTION_DEFAULT = 0, - DIRECTION_DOWN, DIRECTION_UP, + DIRECTION_DOWN, DIRECTION_LEFT, DIRECTION_RIGHT, DIRECTION_INVALID @@ -72,13 +81,24 @@ class SpriteDef : public Resource /** * Loads a sprite definition file. */ - static SpriteDef *load(std::string const &file, int variant); + static SpriteDef *load(const std::string &file, int variant); /** * Returns the specified action. */ Action *getAction(SpriteAction action) const; + /** + * Converts a string into a SpriteAction enum. + */ + static SpriteAction makeSpriteAction(const std::string &action); + + /** + * Converts a string into a SpriteDirection enum. + */ + static SpriteDirection + makeSpriteDirection(const std::string &direction); + private: /** * Constructor. @@ -99,7 +119,7 @@ class SpriteDef : public Resource /** * Loads an imageset element. */ - void loadImageSet(xmlNodePtr node, std::string const &palettes); + void loadImageSet(xmlNodePtr node, const std::string &palettes); /** * Loads an action element. @@ -129,16 +149,6 @@ class SpriteDef : public Resource */ void substituteAction(SpriteAction complete, SpriteAction with); - /** - * Converts a string into a SpriteAction enum. - */ - static SpriteAction makeSpriteAction(const std::string &action); - - /** - * Converts a string into a SpriteDirection enum. - */ - static SpriteDirection makeSpriteDirection(const std::string &direction); - typedef std::map<std::string, ImageSet*> ImageSets; typedef ImageSets::iterator ImageSetIterator; @@ -148,4 +158,4 @@ class SpriteDef : public Resource Actions mActions; }; -#endif +#endif // SPRITEDEF_H diff --git a/src/serverinfo.h b/src/serverinfo.h index fc3ef032..c38d13c7 100644 --- a/src/serverinfo.h +++ b/src/serverinfo.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/shopitem.cpp b/src/shopitem.cpp index f1ef3dad..683cef7a 100644 --- a/src/shopitem.cpp +++ b/src/shopitem.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,20 +21,25 @@ #include "shopitem.h" -#include "utils/stringutils.h" +#include "units.h" -ShopItem::ShopItem (int inventoryIndex, int id, int quantity, int price) : - Item (id, 0), +#include "resources/iteminfo.h" + +ShopItem::ShopItem(int inventoryIndex, int id, + int quantity, int price) : + Item(id, 0), mPrice(price) { - mDisplayName = getInfo().getName() + " (" + toString(mPrice) + " GP)"; + mDisplayName = getInfo().getName() + + " (" + Units::formatCurrency(mPrice).c_str() + ")"; setInvIndex(inventoryIndex); addDuplicate(inventoryIndex, quantity); } ShopItem::ShopItem (int id, int price) : Item (id, 0), mPrice(price) { - mDisplayName = getInfo().getName() + " (" + toString(mPrice) + " GP)"; + mDisplayName = getInfo().getName() + + " (" + Units::formatCurrency(mPrice).c_str() + ")"; setInvIndex(-1); addDuplicate(-1, 0); } @@ -81,4 +85,3 @@ int ShopItem::sellCurrentDuplicate(int quantity) } return sellCount; } - diff --git a/src/shopitem.h b/src/shopitem.h index afc48bf5..f552c0fe 100644 --- a/src/shopitem.h +++ b/src/shopitem.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -118,12 +117,11 @@ class ShopItem : public Item * * @return the display name for the item in the shop list */ - const std::string& getDisplayName() const + const std::string &getDisplayName() const { return mDisplayName; } protected: int mPrice; - int mIndex; std::string mDisplayName; /** diff --git a/src/simpleanimation.cpp b/src/simpleanimation.cpp index c3584ede..65d8e8e2 100644 --- a/src/simpleanimation.cpp +++ b/src/simpleanimation.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,13 +34,13 @@ SimpleAnimation::SimpleAnimation(Animation *animation): mAnimationPhase(0), mCurrentFrame(mAnimation->getFrame(0)) { -}; +} SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): mAnimationTime(0), mAnimationPhase(0) { - mAnimation = new Animation(); + mAnimation = new Animation; ImageSet *imageset = ResourceManager::getInstance()->getImageSet( XML::getProperty(animationNode, "imageset", ""), diff --git a/src/simpleanimation.h b/src/simpleanimation.h index 5583e449..e48644d4 100644 --- a/src/simpleanimation.h +++ b/src/simpleanimation.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/sound.cpp b/src/sound.cpp index 5b8dedef..6e0b0da0 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/sound.h b/src/sound.h index 5c0c7ef8..c30ef7cd 100644 --- a/src/sound.h +++ b/src/sound.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +29,8 @@ #endif #include <string> +#include <string> + /** Sound engine * * \ingroup CORE diff --git a/src/sprite.h b/src/sprite.h index c2b0fc7c..a6384e94 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/statuseffect.cpp b/src/statuseffect.cpp new file mode 100644 index 00000000..077fbb63 --- /dev/null +++ b/src/statuseffect.cpp @@ -0,0 +1,174 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <map> + +#include "gui/chat.h" +#include "statuseffect.h" + +#include "log.h" +#include "utils/xml.h" + + +#define STATUS_EFFECTS_FILE "status-effects.xml" + +StatusEffect::StatusEffect() : + mPersistentParticleEffect(false) +{} + +StatusEffect::~StatusEffect() +{} + +void StatusEffect::playSFX() +{ + if (!mSFXEffect.empty()) + sound.playSfx(mSFXEffect); +} + +void StatusEffect::deliverMessage() +{ + if (!mMessage.empty()) + localChatTab->chatLog(mMessage, BY_SERVER); +} + +Particle *StatusEffect::getParticle() +{ + if (mParticleEffect.empty()) + return NULL; + else + return particleEngine->addEffect(mParticleEffect, 0, 0); +} + +AnimatedSprite *StatusEffect::getIcon() +{ + if (mIcon.empty()) + return NULL; + else { + AnimatedSprite *sprite = AnimatedSprite::load( + "graphics/sprites/" + mIcon); + if (false && sprite) { + sprite->play(ACTION_DEFAULT); + sprite->reset(); + } + return sprite; + } +} + +SpriteAction StatusEffect::getAction() +{ + if (mAction.empty()) + return ACTION_INVALID; + else + return SpriteDef::makeSpriteAction(mAction); +} + + +// -- initialisation and static parts -- + + +typedef std::map<int, StatusEffect *> status_effect_map[2]; + +static status_effect_map statusEffects; +static status_effect_map stunEffects; +static std::map<int, int> blockEffectIndexMap; + +int StatusEffect::blockEffectIndexToEffectIndex(int blockIndex) +{ + if (blockEffectIndexMap.find(blockIndex) == blockEffectIndexMap.end()) + return -1; + return blockEffectIndexMap[blockIndex]; +} + +StatusEffect *StatusEffect::getStatusEffect(int index, bool enabling) +{ + return statusEffects[enabling][index]; +} + +StatusEffect *StatusEffect::getStunEffect(int index, bool enabling) +{ + return stunEffects[enabling][index]; +} + +void StatusEffect::load() +{ + XML::Document doc(STATUS_EFFECTS_FILE); + xmlNodePtr rootNode = doc.rootNode(); + + if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "status-effects")) + { + logger->log("Error loading status effects file: " + STATUS_EFFECTS_FILE); + return; + } + + for_each_xml_child_node(node, rootNode) + { + status_effect_map *the_map = NULL; + + int index = atoi(XML::getProperty(node, "id", "-1").c_str()); + + if (xmlStrEqual(node->name, BAD_CAST "status-effect")) + { + the_map = &statusEffects; + int block_index = atoi(XML::getProperty(node, "block-id", "-1").c_str()); + + if (index >= 0 && block_index >= 0) + blockEffectIndexMap[block_index] = index; + + } else if (xmlStrEqual(node->name, BAD_CAST "stun-effect")) + the_map = &stunEffects; + + if (the_map) { + StatusEffect *startEffect = new StatusEffect; + StatusEffect *endEffect = new StatusEffect; + + startEffect->mMessage = XML::getProperty(node, "start-message", ""); + startEffect->mSFXEffect = XML::getProperty(node, "start-audio", ""); + startEffect->mParticleEffect = XML::getProperty(node, "start-particle", ""); + startEffect->mIcon = XML::getProperty(node, "icon", ""); + startEffect->mAction = XML::getProperty(node, "action", ""); + startEffect->mPersistentParticleEffect = (XML::getProperty(node, "persistent-particle-effect", "no")) != "no"; + + endEffect->mMessage = XML::getProperty(node, "end-message", ""); + endEffect->mSFXEffect = XML::getProperty(node, "end-audio", ""); + endEffect->mParticleEffect = XML::getProperty(node, "end-particle", ""); + + (*the_map)[1][index] = startEffect; + (*the_map)[0][index] = endEffect; + } + } +} + +void unloadMap(std::map<int, StatusEffect *> map) +{ + std::map<int, StatusEffect *>::iterator it; + + for (it = map.begin(); it != map.end(); it++) + delete (*it).second; +} + +void StatusEffect::unload() +{ + unloadMap(statusEffects[0]); + unloadMap(statusEffects[1]); + unloadMap(stunEffects[0]); + unloadMap(stunEffects[1]); +} diff --git a/src/statuseffect.h b/src/statuseffect.h new file mode 100644 index 00000000..f1af93d2 --- /dev/null +++ b/src/statuseffect.h @@ -0,0 +1,110 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef STATUS_EFFECT_H +#define STATUS_EFFECT_H + +#include "resources/animation.h" +#include "particle.h" +#include "animatedsprite.h" +#include "sound.h" + +class StatusEffect +{ +public: + StatusEffect(); + ~StatusEffect(); + + /** + * Plays the sound effect associated with this status effect, if possible. + */ + void playSFX(); + + /** + * Delivers the chat message associated with this status effect, if + * possible. + */ + void deliverMessage(); + + /** + * Creates the particle effect associated with this status effect, if + * possible. + */ + Particle *getParticle(); + + /** + * Retrieves the status icon for this effect, if applicable + */ + AnimatedSprite *getIcon(); + + /** + * Retrieves an action to perform, or ACTION_INVALID + */ + SpriteAction getAction(); + + /** + * Determines whether the particle effect should be restarted when the + * being changes maps + */ + bool particleEffectIsPersistent() const { return mPersistentParticleEffect; } + + + /** + * Retrieves a status effect. + * + * \param index Index of the status effect. + * \param enabling Whether to retrieve the activating effect (true) or + * the deactivating effect (false). + */ + static StatusEffect *getStatusEffect(int index, bool enabling); + + /** + * Retrieves a stun effect. + * + * \param index Index of the stun effect. + * \param enabling Whether to retrieve the activating effect (true) or + * the deactivating effect (false). + */ + static StatusEffect *getStunEffect(int index, bool enabling); + + /** + * Maps a block effect index to its corresponding effect index. Block + * effect indices are used for opt2/opt3/status.option blocks; their + * mapping to regular effect indices is handled in the config file. + * + * Returns -1 on failure. + */ + static int blockEffectIndexToEffectIndex(int blocKIndex); + + static void load(); + + static void unload(); +private: + + std::string mMessage; + std::string mSFXEffect; + std::string mParticleEffect; + std::string mIcon; + std::string mAction; + bool mPersistentParticleEffect; +}; + +#endif // !defined(STATUS_EFFECT_H) diff --git a/src/text.cpp b/src/text.cpp index 4e697f15..83bd6c24 100644 --- a/src/text.cpp +++ b/src/text.cpp @@ -3,7 +3,7 @@ * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net> * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,29 +20,58 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "text.h" + #include <guichan/font.hpp> -#include "text.h" +#include "configuration.h" #include "textmanager.h" +#include "resources/resourcemanager.h" +#include "resources/image.h" #include "gui/gui.h" #include "gui/palette.h" #include "gui/textrenderer.h" int Text::mInstances = 0; +ImageRect Text::mBubble; +Image *Text::mBubbleArrow; Text::Text(const std::string &text, int x, int y, - gcn::Graphics::Alignment alignment, const gcn::Color* color) : + gcn::Graphics::Alignment alignment, + const gcn::Color* color, bool isSpeech) : mText(text), - mColor(color) + mColor(color), + mIsSpeech(isSpeech) { if (textManager == 0) { - textManager = new TextManager(); + textManager = new TextManager; + ResourceManager *resman = ResourceManager::getInstance(); + Image *sbImage = resman->getImage("graphics/gui/bubble.png|W:#" + + config.getValue("speechBubblecolor", "000000")); + mBubble.grid[0] = sbImage->getSubImage(0, 0, 5, 5); + mBubble.grid[1] = sbImage->getSubImage(5, 0, 5, 5); + mBubble.grid[2] = sbImage->getSubImage(10, 0, 5, 5); + mBubble.grid[3] = sbImage->getSubImage(0, 5, 5, 5); + mBubble.grid[4] = sbImage->getSubImage(5, 5, 5, 5); + mBubble.grid[5] = sbImage->getSubImage(10, 5, 5, 5); + mBubble.grid[6] = sbImage->getSubImage(0, 10, 5, 5); + mBubble.grid[7] = sbImage->getSubImage(5, 10, 5, 5); + mBubble.grid[8] = sbImage->getSubImage(10, 10, 5, 5); + mBubbleArrow = sbImage->getSubImage(0, 15, 15, 10); + const float bubbleAlpha = config.getValue("speechBubbleAlpha", 1.0); + for (int i = 0; i < 9; i++) + { + mBubble.grid[i]->setAlpha(bubbleAlpha); + } + mBubbleArrow->setAlpha(bubbleAlpha); + sbImage->decRef(); } ++mInstances; mHeight = boldFont->getHeight(); mWidth = boldFont->getWidth(text); + switch (alignment) { case gcn::Graphics::LEFT: @@ -60,11 +89,6 @@ Text::Text(const std::string &text, int x, int y, textManager->addText(this); } -void Text::adviseXY(int x, int y) -{ - textManager->moveText(this, x - mXOffset, y); -} - Text::~Text() { textManager->removeText(this); @@ -72,16 +96,44 @@ Text::~Text() { delete textManager; textManager = 0; + delete mBubble.grid[0]; + delete mBubble.grid[1]; + delete mBubble.grid[2]; + delete mBubble.grid[3]; + delete mBubble.grid[4]; + delete mBubble.grid[5]; + delete mBubble.grid[6]; + delete mBubble.grid[7]; + delete mBubble.grid[8]; + delete mBubbleArrow; } } +void Text::adviseXY(int x, int y) +{ + textManager->moveText(this, x - mXOffset, y); +} + void Text::draw(gcn::Graphics *graphics, int xOff, int yOff) { graphics->setFont(boldFont); + if (mIsSpeech) { + static_cast<Graphics*>(graphics)->drawImageRect( + mX - xOff - 5, mY - yOff - 5, mWidth + 10, mHeight + 10, + mBubble); + /* + if (mWidth >= 15) { + static_cast<Graphics*>(graphics)->drawImage( + mBubbleArrow, mX - xOff - 7 + mWidth / 2, + mY - yOff + mHeight + 4); + } + */ + } + TextRenderer::renderText(graphics, mText, mX - xOff, mY - yOff, gcn::Graphics::LEFT, - *mColor, boldFont, true); + *mColor, boldFont, !mIsSpeech, true); } FlashText::FlashText(const std::string &text, int x, int y, @@ -3,7 +3,7 @@ * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net> * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,8 +24,8 @@ #define TEXT_H #include <guichan/color.hpp> -#include <guichan/graphics.hpp> +#include "graphics.h" #include "guichanfwd.h" class TextManager; @@ -40,7 +40,7 @@ class Text */ Text(const std::string &text, int x, int y, gcn::Graphics::Alignment alignment, - const gcn::Color *color); + const gcn::Color *color, bool isSpeech = false); /** * Destructor. The text is removed from the screen. @@ -66,6 +66,11 @@ class Text static int mInstances; /**< Instances of text. */ std::string mText; /**< The text to display. */ const gcn::Color *mColor; /**< The color of the text. */ + bool mIsSpeech; /**< Is this text a speech bubble? */ + + protected: + static ImageRect mBubble; /**< Speech bubble graphic */ + static Image *mBubbleArrow; /**< Speech bubble arrow graphic */ }; class FlashText : public Text @@ -81,12 +86,12 @@ class FlashText : public Text virtual ~FlashText() {} /** - * Flash the text for so many refreshes + * Flash the text for so many refreshes. */ void flash(int time) {mTime = time; } /** - * Draws the text + * Draws the text. */ virtual void draw(gcn::Graphics *graphics, int xOff, int yOff); diff --git a/src/textmanager.cpp b/src/textmanager.cpp index 0cf09478..6bc8f8b6 100644 --- a/src/textmanager.cpp +++ b/src/textmanager.cpp @@ -2,7 +2,7 @@ * Support for non-overlapping floating text * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net> * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "textmanager.h" + #include <cstring> #include "text.h" -#include "textmanager.h" TextManager *textManager = 0; diff --git a/src/textmanager.h b/src/textmanager.h index d6485e34..ee8e1209 100644 --- a/src/textmanager.h +++ b/src/textmanager.h @@ -2,7 +2,7 @@ * Support for non-overlapping floating text * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net> * - * This file is part of Aethyra. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/textparticle.cpp b/src/textparticle.cpp index 957d67c0..04b7abe1 100644 --- a/src/textparticle.cpp +++ b/src/textparticle.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/textparticle.h b/src/textparticle.h index 1a49b5ef..8b7d3e01 100644 --- a/src/textparticle.h +++ b/src/textparticle.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2006 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _TEXTPARTICLE_H -#define _TEXTPARTICLE_H +#ifndef TEXTPARTICLE_H +#define TEXTPARTICLE_H #include "guichanfwd.h" #include "particle.h" diff --git a/src/tileset.h b/src/tileset.h index 28f7d9d5..d4de7ba5 100644 --- a/src/tileset.h +++ b/src/tileset.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/aethyra.rc b/src/tmw.rc index e9d32be9..d9689f28 100644 --- a/src/aethyra.rc +++ b/src/tmw.rc @@ -1,22 +1,23 @@ -#include <windows.h> // include for version info constants
-
-#include "winver.h"
-
-A ICON MOVEABLE PURE LOADONCALL DISCARDABLE "data/icons/aethyra.ico"
-
-1 VERSIONINFO
-FILEVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD
-PRODUCTVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD
-FILETYPE VFT_APP {
- BLOCK "StringFileInfo" {
- BLOCK "040904E4" {
- VALUE "CompanyName", "Aethyra Development Team"
- VALUE "FileVersion", PACKAGE_VERSION
- VALUE "FileDescription", "Aethyra Experiment"
- VALUE "LegalCopyright", "2009 (C)"
- VALUE "OriginalFilename", "aethyra.exe"
- VALUE "ProductName", "Aethyra MMORPG"
- VALUE "ProductVersion", PACKAGE_VERSION
- }
- }
+#include <windows.h> // include for version info constants + +#include "winver.h" + +A ICON MOVEABLE PURE LOADONCALL DISCARDABLE "data/icons/tmw.ico" + +1 VERSIONINFO +FILEVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD +PRODUCTVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD +FILETYPE VFT_APP { + BLOCK "StringFileInfo" { + BLOCK "040904E4" { + VALUE "CompanyName", "The Mana World Development Team" + VALUE "FileVersion", PACKAGE_VERSION + VALUE "FileDescription", "The Mana World" + VALUE "LegalCopyright", "2004-2009 (C)" + VALUE "OriginalFilename", "tmw.exe" + VALUE "ProductName", "The Mana World MMORPG" + VALUE "ProductVersion", PACKAGE_VERSION + } + } } + diff --git a/src/units.cpp b/src/units.cpp new file mode 100644 index 00000000..acdbd564 --- /dev/null +++ b/src/units.cpp @@ -0,0 +1,234 @@ +/* + * Support for custom units + * Copyright (C) 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "units.h" + +#include "log.h" + +#include "utils/strprintf.h" +#include "utils/stringutils.h" +#include "utils/xml.h" + +#include <cmath> +#include <climits> +#include <vector> + +struct UnitLevel { + std::string symbol; + int count; + int round; +}; + +struct UnitDescription { + std::vector<struct UnitLevel> levels; + double conversion; + bool mix; +}; + +enum UnitType { + UNIT_WEIGHT = 0, + UNIT_CURRENCY = 1, + UNIT_END +}; + +struct UnitDescription units[UNIT_END]; + +void Units::loadUnits() +{ + { // Setup default weight + struct UnitDescription ud; + + ud.conversion = 1.0; + ud.mix = false; + + struct UnitLevel bu; + bu.symbol = "g"; + bu.count = 1; + bu.round = 0; + + ud.levels.push_back(bu); + + struct UnitLevel ul; + ul.symbol = "kg"; + ul.count = 1000; + ul.round = 2; + + ud.levels.push_back(ul); + + units[UNIT_WEIGHT] = ud; + } + + { // Setup default currency + struct UnitDescription ud; + + ud.conversion = 1.0; + ud.mix = false; + + struct UnitLevel bu; + bu.symbol = "¤"; + bu.count = 1; + bu.round = 0; + + ud.levels.push_back(bu); + + units[UNIT_CURRENCY] = ud; + } + + XML::Document doc("units.xml"); + xmlNodePtr root = doc.rootNode(); + + if (!root || !xmlStrEqual(root->name, BAD_CAST "units")) + { + logger->log("Error loading unit definition file: units.xml"); + return; + } + + for_each_xml_child_node(node, root) + { + if (xmlStrEqual(node->name, BAD_CAST "unit")) + { + struct UnitDescription ud; + int level = 1; + const std::string type = XML::getProperty(node, "type", ""); + ud.conversion = XML::getProperty(node, "conversion", 1.0); + ud.mix = XML::getProperty(node, "mix", "no") == "yes"; + + struct UnitLevel bu; + bu.symbol = XML::getProperty(node, "base", "¤"); + bu.count = 1; + bu.round = XML::getProperty(node, "round", 2); + + ud.levels.push_back(bu); + + for_each_xml_child_node(uLevel, node) + { + if (xmlStrEqual(uLevel->name, BAD_CAST "level")) + { + struct UnitLevel ul; + ul.symbol = XML::getProperty(uLevel, "symbol", + strprintf("¤%d",level)); + ul.count = XML::getProperty(uLevel, "count", -1); + ul.round = XML::getProperty(uLevel, "round", bu.round); + + if (ul.count > 0) + { + ud.levels.push_back(ul); + level++; + } + else + { + logger->log("Error bad unit count: %d for %s in %s", + ul.count, ul.symbol.c_str(), bu.symbol.c_str()); + } + } + } + + // Add one more level for saftey + struct UnitLevel ll; + ll.symbol = ""; + ll.count = INT_MAX; + ll.round = 0; + + ud.levels.push_back(ll); + + if (type == "weight") + units[UNIT_WEIGHT] = ud; + else if (type == "currency") + units[UNIT_CURRENCY] = ud; + else + logger->log("Error unknown unit type: %s", type.c_str()); + } + } +} + +std::string formatUnit(int value, int type) +{ + struct UnitDescription ud = units[type]; + struct UnitLevel ul; + + // Shortcut for 0; do the same for values less than 0 (for now) + if (value <= 0) { + ul = ud.levels[0]; + return strprintf("0%s", ul.symbol.c_str()); + } else { + double amount = ud.conversion * value; + + // If only the first level is needed, act like mix if false + if (ud.mix && ud.levels.size() > 0 && ud.levels[1].count < amount) + { + std::string output; + struct UnitLevel pl = ud.levels[0]; + ul = ud.levels[1]; + int levelAmount = (int) amount; + int nextAmount; + + levelAmount /= ul.count; + + amount -= levelAmount * ul.count; + + if (amount > 0) { + output = strprintf("%.*f%s", pl.round, amount, + pl.symbol.c_str()); + } + + for (unsigned int i = 2; i < ud.levels.size(); i++) + { + pl = ul; + ul = ud.levels[i]; + + nextAmount = levelAmount / ul.count; + levelAmount %= ul.count; + + if (levelAmount > 0) output = strprintf("%d%s", + levelAmount, pl.symbol.c_str()) + output; + + if (!nextAmount) break; + levelAmount = nextAmount; + } + + return output; + } + else + { + for (unsigned int i = 0; i < ud.levels.size(); i++) + { + ul = ud.levels[i]; + if (amount < ul.count && ul.count > 0) { + ul = ud.levels[i - 1]; + break; + } + amount /= ul.count; + } + + return strprintf("%.*f%s", ul.round, amount, ul.symbol.c_str()); + } + } +} + +std::string Units::formatCurrency(int value) +{ + return formatUnit(value, UNIT_CURRENCY); +} + +std::string Units::formatWeight(int value) +{ + return formatUnit(value, UNIT_WEIGHT); +} diff --git a/src/units.h b/src/units.h new file mode 100644 index 00000000..6aa07b70 --- /dev/null +++ b/src/units.h @@ -0,0 +1,46 @@ +/* + * Support for custom units + * Copyright (C) 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef UNITS_H +#define UNITS_H + +#include <string> + +class Units +{ + public: + /** + * Loads and parses the units.xml file (if found). + */ + static void loadUnits(); + + /** + * Formats the given number in the correct currency format. + */ + static std::string formatCurrency(int value); + + /** + * Formats the given number in the correct weight/mass format. + */ + static std::string formatWeight(int value); +}; + +#endif // UNITS_H diff --git a/src/utils/base64.cpp b/src/utils/base64.cpp index 9d8ba836..298841be 100644 --- a/src/utils/base64.cpp +++ b/src/utils/base64.cpp @@ -27,11 +27,11 @@ +----------------------------------------------------------------------+ */ +#include "utils/base64.h" + #include <stdlib.h> #include <string.h> -#include "base64.h" - static char base64_table[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', diff --git a/src/utils/dtor.h b/src/utils/dtor.h index 96ce63d4..e7240d12 100644 --- a/src/utils/dtor.h +++ b/src/utils/dtor.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +39,7 @@ public std::unary_function <std::pair<T1, T2>, void> void operator()(std::pair<T1, T2> &pair) { delete pair.second; } }; - template<class Cont> +template<class Cont> inline dtor<typename Cont::value_type> make_dtor(Cont const&) { return dtor<typename Cont::value_type>(); @@ -52,5 +51,4 @@ inline void delete_all(Container &c) std::for_each(c.begin(), c.end(), make_dtor(c)); } - #endif diff --git a/src/utils/gettext.h b/src/utils/gettext.h index f7286187..55e72555 100644 --- a/src/utils/gettext.h +++ b/src/utils/gettext.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,4 +41,4 @@ #endif -#endif +#endif // UTILS_GETTEXT_H diff --git a/src/utils/mutex.h b/src/utils/mutex.h index 569b6808..41701709 100644 --- a/src/utils/mutex.h +++ b/src/utils/mutex.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2008 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,9 +22,9 @@ #ifndef MUTEX_H #define MUTEX_H -#include <SDL_thread.h> +#include "log.h" -#include "../log.h" +#include <SDL_thread.h> /** * A mutex provides mutual exclusion of access to certain data that is diff --git a/src/utils/sha256.cpp b/src/utils/sha256.cpp new file mode 100644 index 00000000..4f23e01a --- /dev/null +++ b/src/utils/sha256.cpp @@ -0,0 +1,276 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file has been slighly modified as part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2008 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* m_sha256 - Based on m_opersha256 written by Special <john@yarbbles.com> + * Modified and improved by Craig Edwards, December 2006. + * + * + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 05/23/2005 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "utils/sha256.h" + +#include <memory.h> + +#ifdef HAS_STDINT +#include <stdint.h> +#endif +#ifndef HAS_STDINT +typedef unsigned int uint32_t; +#endif + +#define SHA256_BLOCK_SIZE (512 / 8) + +/** An sha 256 context, used by original m_opersha256 */ +class SHA256Context +{ + public: + unsigned int tot_len; + unsigned int len; + unsigned char block[2 * SHA256_BLOCK_SIZE]; + uint32_t h[8]; +}; + +#define SHA256_DIGEST_SIZE (256 / 8) + +#define SHFR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define CH(x, y, z) ((x & y) ^ (~x & z)) +#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) + +#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) +#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) + +#define UNPACK32(x, str) \ +{ \ + *((str) + 3) = (uint8_t) ((x) ); \ + *((str) + 2) = (uint8_t) ((x) >> 8); \ + *((str) + 1) = (uint8_t) ((x) >> 16); \ + *((str) + 0) = (uint8_t) ((x) >> 24); \ +} + +#define PACK32(str, x) \ +{ \ + *(x) = ((uint32_t) *((str) + 3) ) \ + | ((uint32_t) *((str) + 2) << 8) \ + | ((uint32_t) *((str) + 1) << 16) \ + | ((uint32_t) *((str) + 0) << 24); \ +} + +/* Macros used for loops unrolling */ + +#define SHA256_SCR(i) \ +{ \ + w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + + SHA256_F3(w[i - 15]) + w[i - 16]; \ +} + +const unsigned int sha256_h0[8] = +{ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +uint32_t sha256_k[64] = +{ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +void SHA256Init(SHA256Context *ctx) +{ + for (int i = 0; i < 8; i++) + ctx->h[i] = sha256_h0[i]; + ctx->len = 0; + ctx->tot_len = 0; +} + +void SHA256Transform(SHA256Context *ctx, + unsigned char *message, + unsigned int block_nb) +{ + uint32_t w[64]; + uint32_t wv[8]; + unsigned char *sub_block; + for (unsigned int i = 1; i <= block_nb; i++) + { + int j; + sub_block = message + ((i - 1) << 6); + + for (j = 0; j < 16; j++) + PACK32(&sub_block[j << 2], &w[j]); + for (j = 16; j < 64; j++) + SHA256_SCR(j); + for (j = 0; j < 8; j++) + wv[j] = ctx->h[j]; + for (j = 0; j < 64; j++) + { + uint32_t t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]; + uint32_t t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + for (j = 0; j < 8; j++) + ctx->h[j] += wv[j]; + } +} + +void SHA256Update(SHA256Context *ctx, + unsigned char *message, + unsigned int len) +{ + /* + * XXX here be dragons! + * After many hours of pouring over this, I think I've found the problem. + * When Special created our module from the reference one, he used: + * + * unsigned int rem_len = SHA256_BLOCK_SIZE - ctx->len; + * + * instead of the reference's version of: + * + * unsigned int tmp_len = SHA256_BLOCK_SIZE - ctx->len; + * unsigned int rem_len = len < tmp_len ? len : tmp_len; + * + * I've changed back to the reference version of this code, and it seems to work with no errors. + * So I'm inclined to believe this was the problem.. + * -- w00t (January 06, 2008) + */ + unsigned int tmp_len = SHA256_BLOCK_SIZE - ctx->len; + unsigned int rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&ctx->block[ctx->len], message, rem_len); + if (ctx->len + len < SHA256_BLOCK_SIZE) + { + ctx->len += len; + return; + } + unsigned int new_len = len - rem_len; + unsigned int block_nb = new_len / SHA256_BLOCK_SIZE; + unsigned char *shifted_message = message + rem_len; + SHA256Transform(ctx, ctx->block, 1); + SHA256Transform(ctx, shifted_message, block_nb); + rem_len = new_len % SHA256_BLOCK_SIZE; + memcpy(ctx->block, &shifted_message[block_nb << 6],rem_len); + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 6; +} + +void SHA256Final(SHA256Context *ctx, unsigned char *digest) +{ + unsigned int block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE))); + unsigned int len_b = (ctx->tot_len + ctx->len) << 3; + unsigned int pm_len = block_nb << 6; + memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + SHA256Transform(ctx, ctx->block, block_nb); + for (int i = 0 ; i < 8; i++) + UNPACK32(ctx->h[i], &digest[i << 2]); +} + +std::string SHA256Hash(const char *src, int len) +{ + // Generate the hash + unsigned char bytehash[SHA256_DIGEST_SIZE]; + SHA256Context ctx; + SHA256Init(&ctx); + SHA256Update(&ctx, (unsigned char *)src, (unsigned int)len); + SHA256Final(&ctx, bytehash); + // Convert it to hex + const char* hxc = "0123456789abcdef"; + std::string hash = ""; + for (int i = 0; i < SHA256_DIGEST_SIZE; i++) + { + hash += hxc[bytehash[i] / 16]; + hash += hxc[bytehash[i] % 16]; + } + return hash; +} + +std::string sha256(const std::string &string) +{ + return SHA256Hash(string.c_str(), string.length()); +} diff --git a/src/utils/sha256.h b/src/utils/sha256.h new file mode 100644 index 00000000..d0543cbf --- /dev/null +++ b/src/utils/sha256.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef UTILS_SHA256_H +#define UTILS_SHA256_H + +#include <string> + +/** + * Returns the SHA-256 hash for the given string. + * + * @param string the string to create the SHA-256 hash for + * @return the SHA-256 hash for the given string. + */ +std::string sha256(const std::string &string); + +#endif // UTILS_SHA256_H diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp index d414d665..6a88a12e 100644 --- a/src/utils/stringutils.cpp +++ b/src/utils/stringutils.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "stringutils.h" +#include "utils/stringutils.h" #include <algorithm> diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h index 7d8df748..8b8b7bc2 100644 --- a/src/utils/stringutils.h +++ b/src/utils/stringutils.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/utils/strprintf.cpp b/src/utils/strprintf.cpp index f90e6258..d960bc96 100644 --- a/src/utils/strprintf.cpp +++ b/src/utils/strprintf.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,11 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "utils/strprintf.h" + #include <cstdarg> #include <cstdio> -#include "strprintf.h" - std::string strprintf(char const *format, ...) { char buf[256]; @@ -46,4 +45,3 @@ std::string strprintf(char const *format, ...) delete [] buf2; return res; } - diff --git a/src/utils/strprintf.h b/src/utils/strprintf.h index 1d33c3f7..78e7a04c 100644 --- a/src/utils/strprintf.h +++ b/src/utils/strprintf.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp index 562f69e3..7a6f75de 100644 --- a/src/utils/xml.cpp +++ b/src/utils/xml.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,16 +19,16 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "xml.h" +#include "utils/xml.h" -#include "../log.h" +#include "log.h" -#include "../resources/resourcemanager.h" +#include "resources/resourcemanager.h" namespace XML { Document::Document(const std::string &filename): - mDoc(NULL) + mDoc(0) { int size; ResourceManager *resman = ResourceManager::getInstance(); @@ -88,7 +87,8 @@ namespace XML return ret; } - std::string getProperty(xmlNodePtr node, const char *name, const std::string &def) + std::string getProperty(xmlNodePtr node, const char *name, + const std::string &def) { xmlChar *prop = xmlGetProp(node, BAD_CAST name); if (prop) { @@ -108,4 +108,5 @@ namespace XML return NULL; } -} + +} // namespace XML diff --git a/src/utils/xml.h b/src/utils/xml.h index b7d67924..e7075279 100644 --- a/src/utils/xml.h +++ b/src/utils/xml.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,10 +22,10 @@ #ifndef XML_H #define XML_H -#include <string> - #include <libxml/tree.h> +#include <string> + /** * XML helper functions. */ @@ -82,7 +81,8 @@ namespace XML /** * Gets a string property from an xmlNodePtr. */ - std::string getProperty(xmlNodePtr node, const char *name, const std::string &def); + std::string getProperty(xmlNodePtr node, const char *name, + const std::string &def); /** * Finds the first child node with the given name @@ -93,4 +93,4 @@ namespace XML #define for_each_xml_child_node(var, parent) \ for (xmlNodePtr var = parent->xmlChildrenNode; var; var = var->next) -#endif +#endif // XML_H diff --git a/src/vector.cpp b/src/vector.cpp index bbfb1a70..9b573e88 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/vector.h b/src/vector.h index 48933155..6dd461ac 100644 --- a/src/vector.h +++ b/src/vector.h @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2007 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/winver.h b/src/winver.h index a10e2e76..4996bdfb 100644 --- a/src/winver.h +++ b/src/winver.h @@ -1,6 +1,6 @@ -/* VERSION DEFINITIONS */
-#define VER_MAJOR 0
-#define VER_MINOR 0
-#define VER_RELEASE 29
-#define VER_BUILD 0
+/* VERSION DEFINITIONS */ +#define VER_MAJOR 0 +#define VER_MINOR 0 +#define VER_RELEASE 29 +#define VER_BUILD 0 #define PACKAGE_VERSION "0.0.29" |