diff options
author | Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> | 2010-05-21 21:56:41 +0200 |
---|---|---|
committer | Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> | 2010-05-21 21:56:41 +0200 |
commit | 63b4c9869b6256ed7644113cd23305b07cf9df03 (patch) | |
tree | aff0d99f5b58cbaf4195ac755ecfb79f97bf7b65 | |
parent | 8c4c5a58c256cce7beb21b68c8a7d6b6ff5c4a3a (diff) | |
parent | 2953a3f92c5097bd99ff21f4536fe167a32d90c5 (diff) | |
download | mana-client-63b4c9869b6256ed7644113cd23305b07cf9df03.tar.gz mana-client-63b4c9869b6256ed7644113cd23305b07cf9df03.tar.bz2 mana-client-63b4c9869b6256ed7644113cd23305b07cf9df03.tar.xz mana-client-63b4c9869b6256ed7644113cd23305b07cf9df03.zip |
Merge branch '1.0'
Conflicts:
src/beingmanager.cpp
src/beingmanager.h
src/client.cpp
src/localplayer.cpp
48 files changed, 628 insertions, 149 deletions
@@ -8,4 +8,5 @@ Falkreon <Falkreon@.(none)> Ira Rice <irarice@gmail.com> Majin Sniper <sniper@livecd.janhome.net> Maximilian Philipps <turmfalke@Turmfalke.(none)> +remoitnane <remoit(DOT)nane(AT)gmail(DOT)com> Victor Fury <frictor@unknown> diff --git a/CMakeLists.txt b/CMakeLists.txt index 2836d1ef..15a55d91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,3 +54,20 @@ ENDIF() If(UNIX) INSTALL(FILES mana.desktop DESTINATION share/applications) ENDIF() + +SET(CPACK_PACKAGE_NAME "mana") +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Mana") +SET(CPACK_PACKAGE_VENDOR "Mana Development Team") +SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") +SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") +SET(CPACK_PACKAGE_INSTALL_DIRECTORY "Mana") +SET(CPACK_PACKAGE_VERSION_MAJOR ${VER_MAJOR}) +SET(CPACK_PACKAGE_VERSION_MINOR ${VER_MINOR}) +SET(CPACK_PACKAGE_VERSION_PATCH ${VER_RELEASE}) +IF(WIN32) + SET(CPACK_NSIS_DISPLAY_NAME "Mana") + SET(CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}/data/icons/mana.ico") + SET(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/packaging/windows/setup_welcome.bmp") + SET(CPACK_NSIS_URL_INFO_ABOUT "http://www.manasource.org") +ENDIF() +INCLUDE(CPack)
\ No newline at end of file diff --git a/data/graphics/gui/CMakeLists.txt b/data/graphics/gui/CMakeLists.txt index 9943fb0f..92a1e3ef 100644 --- a/data/graphics/gui/CMakeLists.txt +++ b/data/graphics/gui/CMakeLists.txt @@ -8,6 +8,7 @@ SET (FILES circle-gray.png circle-green.png close_button.png + colors.xml deepbox.png hscroll_left_default.png hscroll_left_highlight.png @@ -477,6 +477,8 @@ <Unit filename="src\net\manaserv\protocol.h" /> <Unit filename="src\net\manaserv\specialhandler.cpp" /> <Unit filename="src\net\manaserv\specialhandler.h" /> + <Unit filename="src\net\manaserv\stats.cpp" /> + <Unit filename="src\net\manaserv\stats.h" /> <Unit filename="src\net\manaserv\tradehandler.cpp" /> <Unit filename="src\net\manaserv\tradehandler.h" /> <Unit filename="src\net\messagehandler.h" /> @@ -369,6 +369,8 @@ ./src/net/manaserv/protocol.h ./src/net/manaserv/specialhandler.cpp ./src/net/manaserv/specialhandler.h +./src/net/manaserv/stats.cpp +./src/net/manaserv/stats.h ./src/net/manaserv/tradehandler.cpp ./src/net/manaserv/tradehandler.h ./src/net/messagehandler.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f8fd3ff..b287ec5e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,6 +41,8 @@ ENDIF() IF (WIN32) SET(EXTRA_LIBRARIES ws2_32 winmm) FIND_PACKAGE(LibIntl REQUIRED) +ELSEIF (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + FIND_PACKAGE(LibIntl REQUIRED) ELSEIF (CMAKE_SYSTEM_NAME STREQUAL SunOS) # explicit linking to libintl is required on Solaris SET(EXTRA_LIBRARIES intl) @@ -603,6 +605,8 @@ SET(SRCS_MANA net/manaserv/protocol.h net/manaserv/specialhandler.cpp net/manaserv/specialhandler.h + net/manaserv/stats.cpp + net/manaserv/stats.h net/manaserv/tradehandler.cpp net/manaserv/tradehandler.h ) diff --git a/src/Makefile.am b/src/Makefile.am index a34678a4..2b36250c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -455,6 +455,8 @@ mana_SOURCES += \ net/manaserv/protocol.h \ net/manaserv/specialhandler.cpp \ net/manaserv/specialhandler.h \ + net/manaserv/stats.cpp \ + net/manaserv/stats.h \ net/manaserv/tradehandler.cpp \ net/manaserv/tradehandler.h diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index 631aadab..a92e3faf 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -193,7 +193,8 @@ void BeingManager::clear() Being *BeingManager::findNearestLivingBeing(int x, int y, int maxTileDist, - ActorSprite::Type type) const + ActorSprite::Type type, + Being *excluded) const { Being *closestBeing = 0; int dist = 0; @@ -210,8 +211,9 @@ Being *BeingManager::findNearestLivingBeing(int x, int y, int d = abs(((int) pos.x) - x) + abs(((int) pos.y) - y); if ((being->getType() == type || type == ActorSprite::UNKNOWN) - && (d < dist || !closestBeing) // it is closer - && being->isAlive()) // no dead beings + && (d < dist || !closestBeing) // it is closer + && being->isAlive() // no dead beings + && being != excluded) { dist = d; closestBeing = being; @@ -225,7 +227,8 @@ Being *BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxDist, ActorSprite::Type type) const { const Vector &pos = aroundBeing->getPosition(); - return findNearestLivingBeing((int)pos.x, (int)pos.y, maxDist, type); + return findNearestLivingBeing((int)pos.x, (int)pos.y, maxDist, type, + aroundBeing); } bool BeingManager::hasBeing(Being *being) const diff --git a/src/beingmanager.h b/src/beingmanager.h index 1d9cc459..00575041 100644 --- a/src/beingmanager.h +++ b/src/beingmanager.h @@ -76,9 +76,11 @@ class BeingManager * @param maxTileDist Maximal distance in tiles. If minimal distance is * larger, no being is returned. * @param type The type of being to look for. + * @param excluded The being to exclude from the search. */ Being *findNearestLivingBeing(int x, int y, int maxTileDist, - ActorSprite::Type type = Being::UNKNOWN) const; + ActorSprite::Type type = Being::UNKNOWN, + Being *excluded = 0) const; /** * Returns a being nearest to another being. @@ -89,7 +91,7 @@ class BeingManager * @param type The type of being to look for. */ Being *findNearestLivingBeing(Being *aroundBeing, int maxTileDist, - ActorSprite::Type type = Being::UNKNOWN) const; + ActorSprite::Type type = Being::UNKNOWN) const; /** * Finds a being by name and (optionally) by type. diff --git a/src/client.cpp b/src/client.cpp index 75b24cc8..323d5b49 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -397,7 +397,7 @@ Client::Client(const Options &options): if (mCurrentServer.hostname.empty()) { mCurrentServer.hostname = branding.getValue("defaultServer", - "server.themanaworld.org").c_str(); + "").c_str(); } if (mCurrentServer.port == 0) @@ -405,7 +405,7 @@ Client::Client(const Options &options): mCurrentServer.port = (short) branding.getValue("defaultPort", DEFAULT_PORT); mCurrentServer.type = ServerInfo::parseType( - branding.getValue("defaultServerType", "eathena")); + branding.getValue("defaultServerType", "tmwathena")); } if (chatLogger) @@ -1113,8 +1113,7 @@ void Client::initConfiguration() config.setValue("sfxVolume", 100); config.setValue("musicVolume", 60); config.setValue("fpslimit", 60); - std::string defaultUpdateHost = branding.getValue("defaultUpdateHost", - "http://updates.themanaworld.org"); + std::string defaultUpdateHost = branding.getValue("defaultUpdateHost", ""); config.setValue("updatehost", defaultUpdateHost); config.setValue("customcursor", true); config.setValue("useScreenshotDirectorySuffix", true); @@ -1157,8 +1156,7 @@ void Client::initUpdatesDir() // If updatesHost is currently empty, fill it from config file if (mUpdateHost.empty()) { - mUpdateHost = - config.getValue("updatehost", "http://updates.themanaworld.org/"); + mUpdateHost = config.getValue("updatehost", ""); } // Remove any trailing slash at the end of the update host diff --git a/src/client.h b/src/client.h index 7a3648f4..836ac3f8 100644 --- a/src/client.h +++ b/src/client.h @@ -22,17 +22,17 @@ #ifndef CLIENT_H #define CLIENT_H -#include "net/serverinfo.h" - #include "configlistener.h" -#include <guichan/actionlistener.hpp> +#include "net/serverinfo.h" -#include <string> +#include <guichan/actionlistener.hpp> #include <SDL.h> #include <SDL_framerate.h> +#include <string> + class Button; class Desktop; class LoginData; diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index f214fde5..591ebd2f 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -60,7 +60,7 @@ InventoryWindow::InventoryWindow(Inventory *inventory): mInventory(inventory), mSplit(false) { - setWindowName(inventory->isMainInventory() ? "Inventory" : "Storage"); + setWindowName(isMainInventory() ? "Inventory" : "Storage"); setupWindow->registerWindowForReset(this); setResizable(true); setCloseButton(true); @@ -80,7 +80,7 @@ InventoryWindow::InventoryWindow(Inventory *inventory): mSlotsLabel = new Label(_("Slots:")); mSlotsBar = new ProgressBar(0.0f, 100, 20, Theme::PROG_INVY_SLOTS); - if (inventory->isMainInventory()) + if (isMainInventory()) { std::string equip = _("Equip"); std::string use = _("Use"); @@ -137,7 +137,7 @@ InventoryWindow::InventoryWindow(Inventory *inventory): loadWindowState(); slotsChanged(mInventory); - if (!inventory->isMainInventory()) + if (!isMainInventory()) setVisible(true); } @@ -158,6 +158,17 @@ void InventoryWindow::action(const gcn::ActionEvent &event) outfitWindow->requestMoveToTop(); } } + else if (event.getId() == "store") + { + if (!inventoryWindow->isVisible()) return; + + Item *item = inventoryWindow->getSelectedItem(); + + if (!item) + return; + + ItemAmountWindow::showWindow(ItemAmountWindow::StoreAdd, this, item); + } Item *item = mItems->getSelectedItem(); @@ -185,17 +196,6 @@ void InventoryWindow::action(const gcn::ActionEvent &event) ItemAmountWindow::showWindow(ItemAmountWindow::ItemSplit, this, item, (item->getQuantity() - 1)); } - else if (event.getId() == "store") - { - if (!inventoryWindow->isVisible()) return; - - Item *item = inventoryWindow->getSelectedItem(); - - if (!item) - return; - - ItemAmountWindow::showWindow(ItemAmountWindow::StoreAdd, this, item); - } else if (event.getId() == "retrieve") { Item *item = mItems->getSelectedItem(); @@ -229,7 +229,7 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event) */ const int mx = event.getX() + getX(); const int my = event.getY() + getY(); - viewport->showPopup(this, mx, my, item); + viewport->showPopup(this, mx, my, item, isMainInventory()); } if (event.getButton() == gcn::MouseEvent::LEFT) diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index 948482f5..f611e934 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -108,6 +108,8 @@ class InventoryWindow : public Window, void slotsChanged(Inventory* inventory); + bool isMainInventory() { return mInventory->isMainInventory(); } + /** * Returns true if any instances exist. */ diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp index 3f22c442..2618810b 100644 --- a/src/gui/itempopup.cpp +++ b/src/gui/itempopup.cpp @@ -28,17 +28,22 @@ #include "gui/gui.h" #include "gui/theme.h" +#include "gui/widgets/icon.h" #include "gui/widgets/textbox.h" #include "utils/gettext.h" #include "utils/stringutils.h" +#include "resources/image.h" +#include "resources/resourcemanager.h" + #include <guichan/font.hpp> #include <guichan/widgets/label.hpp> ItemPopup::ItemPopup(): - Popup("ItemPopup") + Popup("ItemPopup"), + mIcon(0) { // Item Name mItemName = new gcn::Label; @@ -62,28 +67,62 @@ ItemPopup::ItemPopup(): mItemWeight->setEditable(false); mItemWeight->setPosition(getPadding(), 3 * fontHeight + 4 * getPadding()); + mIcon = new Icon(0); + add(mItemName); add(mItemDesc); add(mItemEffect); add(mItemWeight); + add(mIcon); addMouseListener(this); } ItemPopup::~ItemPopup() { + if (mIcon) + { + Image *image = mIcon->getImage(); + if (image) + image->decRef(); + } } -void ItemPopup::setItem(const ItemInfo &item) +void ItemPopup::setItem(const ItemInfo &item, bool showImage) { if (item.getName() == mItemName->getCaption()) return; + int space = 0; + + Image *oldImage = mIcon->getImage(); + if (oldImage) + oldImage->decRef(); + + if (showImage) + { + ResourceManager *resman = ResourceManager::getInstance(); + Image *image = resman->getImage("graphics/items/" + item.getImageName()); + mIcon->setImage(image); + if (image) + { + int x = getPadding(); + int y = getPadding(); + mIcon->setPosition(x, y); + space = mIcon->getWidth(); + } + } + else + { + mIcon->setImage(0); + } + mItemType = item.getType(); mItemName->setCaption(item.getName()); mItemName->adjustSize(); mItemName->setForegroundColor(getColor(mItemType)); + mItemName->setPosition(getPadding() + space, getPadding()); mItemDesc->setTextWrapped(item.getDescription(), 196); mItemEffect->setTextWrapped(item.getEffect(), 196); @@ -91,7 +130,7 @@ void ItemPopup::setItem(const ItemInfo &item) Units::formatWeight(item.getWeight()).c_str()), 196); - int minWidth = mItemName->getWidth(); + int minWidth = mItemName->getWidth() + space; if (mItemDesc->getMinWidth() > minWidth) minWidth = mItemDesc->getMinWidth(); @@ -127,6 +166,7 @@ void ItemPopup::setItem(const ItemInfo &item) mItemDesc->setPosition(getPadding(), 2 * height); mItemEffect->setPosition(getPadding(), (numRowsDesc + getPadding()) * height); + } gcn::Color ItemPopup::getColor(ItemType type) @@ -171,3 +211,4 @@ void ItemPopup::mouseMoved(gcn::MouseEvent &event) // When the mouse moved on top of the popup, hide it setVisible(false); } + diff --git a/src/gui/itempopup.h b/src/gui/itempopup.h index 67d1eb2f..a3976a11 100644 --- a/src/gui/itempopup.h +++ b/src/gui/itempopup.h @@ -29,6 +29,7 @@ #include <guichan/mouselistener.hpp> +class Icon; class TextBox; /** @@ -50,7 +51,7 @@ class ItemPopup : public Popup /** * Sets the info to be displayed given a particular item. */ - void setItem(const ItemInfo &item); + void setItem(const ItemInfo &item, bool showImage = false); void mouseMoved(gcn::MouseEvent &mouseEvent); @@ -60,6 +61,7 @@ class ItemPopup : public Popup TextBox *mItemEffect; TextBox *mItemWeight; ItemType mItemType; + Icon *mIcon; static gcn::Color getColor(ItemType type); }; diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index 3eeb6f9c..25725a80 100644 --- a/src/gui/serverdialog.cpp +++ b/src/gui/serverdialog.cpp @@ -220,6 +220,8 @@ ServerDialog::ServerDialog(ServerInfo *serverInfo, const std::string &dir): mTypeListModel = new TypeListModel(); mTypeField = new DropDown(mTypeListModel); + mTypeField->setSelected((serverInfo->type == ServerInfo::MANASERV) ? + 1 : 0); mDescription = new Label(std::string()); diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index 8ce6eebd..ebe53261 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -81,6 +81,13 @@ class ModeListModel : public gcn::ListModel */ std::string getElementAt(int i) { return mVideoModes[i]; } + /** + * Returns the index corresponding to the given video mode. + * E.g.: "800x600". + * or -1 if not found. + */ + int getIndexOf(const std::string &widthXHeightMode); + private: std::vector<std::string> mVideoModes; }; @@ -108,6 +115,20 @@ ModeListModel::ModeListModel() } } +int ModeListModel::getIndexOf(const std::string &widthXHeightMode) +{ + std::string currentMode = ""; + for (int i = 0; i < getNumberOfElements(); i++) + { + currentMode = getElementAt(i); + if (currentMode == widthXHeightMode) + { + return i; + } + } + return -1; +} + const char *SIZE_NAME[4] = { N_("Tiny"), @@ -256,6 +277,11 @@ Setup_Video::Setup_Video(): mFpsSlider->setEnabled(mFps > 0); mFpsCheckBox->setSelected(mFps > 0); + // Pre-select the current video mode. + std::string videoMode = toString(graphics->getWidth()) + "x" + + toString(graphics->getHeight()); + mModeList->setSelected(mModeListModel->getIndexOf(videoMode)); + mModeList->setActionEventId("videomode"); mCustomCursorCheckBox->setActionEventId("customcursor"); mShowMonsterDamageCheckBox->setActionEventId("monsterdamage"); @@ -462,6 +488,14 @@ void Setup_Video::cancel() mFpsLabel->setCaption(text); config.setValue("screen", mFullScreenEnabled); + + // Set back to the current video mode. + std::string videoMode = toString(graphics->getWidth()) + "x" + + toString(graphics->getHeight()); + mModeList->setSelected(mModeListModel->getIndexOf(videoMode)); + config.setValue("screenwidth", graphics->getWidth()); + config.setValue("screenheight", graphics->getHeight()); + config.setValue("customcursor", mCustomCursorEnabled); config.setValue("showMonstersTakedDamage", mShowMonsterDamageEnabled); config.setValue("visiblenames", mVisibleNamesEnabled); diff --git a/src/gui/socialwindow.cpp b/src/gui/socialwindow.cpp index 8d833123..2043da52 100644 --- a/src/gui/socialwindow.cpp +++ b/src/gui/socialwindow.cpp @@ -326,6 +326,8 @@ SocialWindow::SocialWindow() : { addTab(player_node->getParty()); } + else + updateButtons(); } SocialWindow::~SocialWindow() @@ -360,6 +362,8 @@ bool SocialWindow::addTab(Guild *guild) mTabs->addTab(tab, tab->mScroll); + updateButtons(); + return true; } @@ -373,6 +377,8 @@ bool SocialWindow::removeTab(Guild *guild) delete it->second; mGuilds.erase(it); + updateButtons(); + return true; } @@ -386,6 +392,8 @@ bool SocialWindow::addTab(Party *party) mTabs->addTab(tab, tab->mScroll); + updateButtons(); + return true; } @@ -399,6 +407,8 @@ bool SocialWindow::removeTab(Party *party) delete it->second; mParties.erase(it); + updateButtons(); + return true; } @@ -451,11 +461,11 @@ void SocialWindow::action(const gcn::ActionEvent &event) else showPartyCreate(); } - else if (event.getId() == "invite") + else if (event.getId() == "invite" && mTabs->getSelectedTabIndex() > -1) { static_cast<SocialTab*>(mTabs->getSelectedTab())->invite(); } - else if (event.getId() == "leave") + else if (event.getId() == "leave" && mTabs->getSelectedTabIndex() > -1) { static_cast<SocialTab*>(mTabs->getSelectedTab())->leave(); } @@ -594,3 +604,10 @@ void SocialWindow::showPartyCreate() mPartyCreateDialog->setActionEventId("create party"); mPartyCreateDialog->addActionListener(this); } + +void SocialWindow::updateButtons() +{ + bool hasTabs = mTabs->getNumberOfTabs() > 0; + mInviteButton->setEnabled(hasTabs); + mLeaveButton->setEnabled(hasTabs); +} diff --git a/src/gui/socialwindow.h b/src/gui/socialwindow.h index d3e69cc5..885c0e54 100644 --- a/src/gui/socialwindow.h +++ b/src/gui/socialwindow.h @@ -77,6 +77,8 @@ public: protected: friend class SocialTab; + void updateButtons(); + int mGuildInvited; ConfirmDialog *mGuildAcceptDialog; TextDialog *mGuildCreateDialog; diff --git a/src/gui/statuswindow.cpp b/src/gui/statuswindow.cpp index 498a4523..2439a213 100644 --- a/src/gui/statuswindow.cpp +++ b/src/gui/statuswindow.cpp @@ -283,7 +283,8 @@ void StatusWindow::setPointsNeeded(int id, int needed) } void StatusWindow::addAttribute(int id, const std::string &name, - bool modifiable) + bool modifiable, + const std::string &description) { AttrDisplay *disp; diff --git a/src/gui/statuswindow.h b/src/gui/statuswindow.h index 13ee9a68..a1fc4b4b 100644 --- a/src/gui/statuswindow.h +++ b/src/gui/statuswindow.h @@ -61,7 +61,8 @@ class StatusWindow : public Window void setPointsNeeded(int id, int needed); - void addAttribute(int id, const std::string &name, bool modifiable); + void addAttribute(int id, const std::string &name, bool modifiable, + const std::string &description); static void updateHPBar(ProgressBar *bar, bool showMax = false); static void updateMPBar(ProgressBar *bar, bool showMax = false); diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index 975fdcff..7448a102 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -45,6 +45,9 @@ #include <iostream> #include <fstream> +const std::string xmlUpdateFile = "resources.xml"; +const std::string txtUpdateFile = "resources2.txt"; + /** * Load the given file into a vector of updateFiles. */ @@ -72,13 +75,10 @@ std::vector<updateFile> loadXMLFile(const std::string &fileName) file.type = XML::getProperty(fileNode, "type", "data"); file.desc = XML::getProperty(fileNode, "description", ""); if (XML::getProperty(fileNode, "required", "yes") == "yes") - { file.required = true; - } else - { file.required = false; - } + files.push_back(file); } @@ -344,7 +344,8 @@ void UpdaterWindow::download() { if (mDownloadStatus == UPDATE_RESOURCES) { - mDownload->setFile(mUpdatesDir + "/" + mCurrentFile, mCurrentChecksum); + mDownload->setFile(mUpdatesDir + "/" + mCurrentFile, + mCurrentChecksum); } else { @@ -353,9 +354,7 @@ void UpdaterWindow::download() } if (mDownloadStatus != UPDATE_RESOURCES) - { mDownload->noCache(); - } setLabel(mCurrentFile + " (0%)"); mDownloadComplete = false; @@ -368,9 +367,22 @@ void UpdaterWindow::loadUpdates() { ResourceManager *resman = ResourceManager::getInstance(); + if (!mUpdateFiles.size()) + { // updates not downloaded + mUpdateFiles = loadXMLFile(mUpdatesDir + "/" + xmlUpdateFile); + if (!mUpdateFiles.size()) + { + logger->log("Warning this server does not have a" + " %s file falling back to %s", xmlUpdateFile.c_str(), + txtUpdateFile.c_str()); + mUpdateFiles = loadTxtFile(mUpdatesDir + "/" + txtUpdateFile); + } + } + for (mUpdateIndex = 0; mUpdateIndex < mUpdateFiles.size(); mUpdateIndex++) { - resman->addToSearchPath(mUpdatesDir + "/" + mUpdateFiles[mUpdateIndex].name, false); + resman->addToSearchPath(mUpdatesDir + "/" + + mUpdateFiles[mUpdateIndex].name, false); } } @@ -433,7 +445,9 @@ void UpdaterWindow::logic() mUpdateFiles = loadXMLFile(mUpdatesDir + "/" + xmlUpdateFile); if (mUpdateFiles.size() == 0) { - logger->log("Warning this server does not have a %s file falling back to %s",xmlUpdateFile.c_str(),txtUpdateFile.c_str()); + logger->log("Warning this server does not have a %s" + " file falling back to %s", + xmlUpdateFile.c_str(), txtUpdateFile.c_str()); // If the resources.xml file fails, fall back onto a older version mCurrentFile = txtUpdateFile; diff --git a/src/gui/widgets/emoteshortcutcontainer.cpp b/src/gui/widgets/emoteshortcutcontainer.cpp index 2b07ad1e..82fb9f8d 100644 --- a/src/gui/widgets/emoteshortcutcontainer.cpp +++ b/src/gui/widgets/emoteshortcutcontainer.cpp @@ -124,11 +124,12 @@ void EmoteShortcutContainer::mouseDragged(gcn::MouseEvent &event) if (!mEmoteMoved && mEmoteClicked) { const int index = getIndexFromGrid(event.getX(), event.getY()); - const int emoteId = emoteShortcut->getEmote(index); if (index == -1) return; + const int emoteId = emoteShortcut->getEmote(index); + if (emoteId) { mEmoteMoved = emoteId; diff --git a/src/gui/widgets/icon.cpp b/src/gui/widgets/icon.cpp index ef22c37d..4e590212 100644 --- a/src/gui/widgets/icon.cpp +++ b/src/gui/widgets/icon.cpp @@ -30,20 +30,22 @@ Icon::Icon(const std::string &file) : mImage(0) { mImage = ResourceManager::getInstance()->getImage(file); - setSize(mImage->getWidth(), mImage->getHeight()); - + if (mImage) + setSize(mImage->getWidth(), mImage->getHeight()); } Icon::Icon(Image *image) : mImage(image) { - setSize(mImage->getWidth(), mImage->getHeight()); + if (mImage) + setSize(mImage->getWidth(), mImage->getHeight()); } void Icon::setImage(Image *image) { mImage = image; - setSize(mImage->getWidth(), mImage->getHeight()); + if (mImage) + setSize(mImage->getWidth(), mImage->getHeight()); } void Icon::draw(gcn::Graphics *g) diff --git a/src/gui/widgets/itemlinkhandler.cpp b/src/gui/widgets/itemlinkhandler.cpp index 0c51aeb3..b7341084 100644 --- a/src/gui/widgets/itemlinkhandler.cpp +++ b/src/gui/widgets/itemlinkhandler.cpp @@ -49,9 +49,8 @@ void ItemLinkHandler::handleLink(const std::string &link) if (id > 0) { - const ItemInfo &iteminfo = ItemDB::get(id); - - mItemPopup->setItem(iteminfo); + const ItemInfo &itemInfo = ItemDB::get(id); + mItemPopup->setItem(itemInfo, true); if (mItemPopup->isVisible()) mItemPopup->setVisible(false); diff --git a/src/gui/widgets/itemshortcutcontainer.cpp b/src/gui/widgets/itemshortcutcontainer.cpp index 92e3e2e5..83efd4d4 100644 --- a/src/gui/widgets/itemshortcutcontainer.cpp +++ b/src/gui/widgets/itemshortcutcontainer.cpp @@ -142,9 +142,13 @@ void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) if (!mItemMoved && mItemClicked) { const int index = getIndexFromGrid(event.getX(), event.getY()); + + if (index == -1) + return; + const int itemId = itemShortcut->getItem(index); - if (index == -1 || itemId < 0) + if (itemId < 0) return; Item *item = player_node->getInventory()->findItem(itemId); @@ -227,9 +231,13 @@ void ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event) void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event) { const int index = getIndexFromGrid(event.getX(), event.getY()); + + if (index == -1) + return; + const int itemId = itemShortcut->getItem(index); - if (index == -1 || itemId < 0) + if (itemId < 0) return; Item *item = player_node->getInventory()->findItem(itemId); diff --git a/src/gui/widgets/window.h b/src/gui/widgets/window.h index a8eb4e62..e62f4d92 100644 --- a/src/gui/widgets/window.h +++ b/src/gui/widgets/window.h @@ -180,12 +180,12 @@ class Window : public gcn::Window, gcn::WidgetListener void setVisible(bool visible, bool forceSticky); /** - * Returns whether the window will save it's visibility. + * Returns whether the window is visible by default. */ bool isDefaultVisible() const { return mDefaultVisible; } /** - * Returns whether the window will save it's visibility. + * Sets whether the window is visible by default. */ void setDefaultVisible(bool save) { mDefaultVisible = save; } @@ -195,7 +195,7 @@ class Window : public gcn::Window, gcn::WidgetListener bool willSaveVisible() const { return mSaveVisible; } /** - * Returns whether the window will save it's visibility. + * Sets whether the window will save it's visibility. */ void setSaveVisible(bool save) { mSaveVisible = save; } @@ -41,7 +41,7 @@ class Item /** * Destructor. */ - ~Item(); + virtual ~Item(); /** * Sets the item id, identifying the item type. diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 17384a1f..40592f59 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -121,6 +121,9 @@ LocalPlayer::~LocalPlayer() delete mInventory; config.removeListener("showownname", this); + + delete mAwayDialog; + delete mAwayListener; } void LocalPlayer::logic() @@ -1275,13 +1278,11 @@ bool LocalPlayer::withinAttackRange(Being *target) } else { - int dist_x = abs(target->getTileX() - getTileY()); - int dist_y = abs(target->getTileY() - getTileX()); + int dist_x = abs(target->getTileX() - getTileX()); + int dist_y = abs(target->getTileY() - getTileY()); if (dist_x > getAttackRange() || dist_y > getAttackRange()) - { return false; - } return true; } @@ -1377,10 +1378,8 @@ void LocalPlayer::changeAwayMode() config.getValue("afkMessage", "I am away from keyboard")); mAwayDialog->addActionListener(mAwayListener); } - else - { - mAwayDialog = 0; - } + + mAwayDialog = 0; } void LocalPlayer::setAway(const std::string &message) diff --git a/src/net/manaserv/beinghandler.cpp b/src/net/manaserv/beinghandler.cpp index 8d3ed21b..705074c1 100644 --- a/src/net/manaserv/beinghandler.cpp +++ b/src/net/manaserv/beinghandler.cpp @@ -159,7 +159,7 @@ void BeingHandler::handleBeingEnterMessage(Net::MessageIn &msg) switch (type) { - case OBJECT_PLAYER: + case OBJECT_CHARACTER: { std::string name = msg.readString(); if (player_node->getName() == name) diff --git a/src/net/manaserv/charhandler.cpp b/src/net/manaserv/charhandler.cpp index f8a1ac89..721780d2 100644 --- a/src/net/manaserv/charhandler.cpp +++ b/src/net/manaserv/charhandler.cpp @@ -150,13 +150,13 @@ void CharHandler::handleCharacterCreateResponse(Net::MessageIn &msg) case CREATE_INVALID_GENDER: errorMessage = _("Invalid gender."); break; - case CREATE_RAW_STATS_TOO_HIGH: + case CREATE_ATTRIBUTES_TOO_HIGH: errorMessage = _("Character's stats are too high."); break; - case CREATE_RAW_STATS_TOO_LOW: + case CREATE_ATTRIBUTES_TOO_LOW: errorMessage = _("Character's stats are too low."); break; - case CREATE_RAW_STATS_EQUAL_TO_ZERO: + case CREATE_ATTRIBUTES_EQUAL_TO_ZERO: errorMessage = _("One stat is zero."); break; default: diff --git a/src/net/manaserv/generalhandler.cpp b/src/net/manaserv/generalhandler.cpp index 454052f7..09f68c1e 100644 --- a/src/net/manaserv/generalhandler.cpp +++ b/src/net/manaserv/generalhandler.cpp @@ -29,7 +29,6 @@ #include "gui/register.h" #include "gui/skilldialog.h" #include "gui/specialswindow.h" -#include "gui/statuswindow.h" #include "net/manaserv/beinghandler.h" #include "net/manaserv/buysellhandler.h" @@ -47,6 +46,7 @@ #include "net/manaserv/partyhandler.h" #include "net/manaserv/playerhandler.h" #include "net/manaserv/specialhandler.h" +#include "net/manaserv/stats.h" #include "net/manaserv/tradehandler.h" #include "utils/gettext.h" @@ -90,16 +90,6 @@ GeneralHandler::GeneralHandler(): chatServerConnection = getConnection(); generalHandler = this; - - std::list<ItemDB::Stat> stats; - stats.push_back(ItemDB::Stat("str", N_("Strength %+d"))); - stats.push_back(ItemDB::Stat("agi", N_("Agility %+d"))); - stats.push_back(ItemDB::Stat("dex", N_("Dexterity %+d"))); - stats.push_back(ItemDB::Stat("vit", N_("Vitality %+d"))); - stats.push_back(ItemDB::Stat("int", N_("Intelligence %+d"))); - stats.push_back(ItemDB::Stat("will", N_("Willpower %+d"))); - - ItemDB::setStatsList(stats); } void GeneralHandler::load() @@ -118,6 +108,9 @@ void GeneralHandler::load() registerHandler(mPartyHandler.get()); registerHandler(mPlayerHandler.get()); registerHandler(mTradeHandler.get()); + + Stats::load(); + Stats::informItemDB(); } void GeneralHandler::reload() @@ -136,6 +129,10 @@ void GeneralHandler::reload() netToken.clear(); gameServer.clear(); chatServer.clear(); + + Stats::unload(); + Stats::load(); + Stats::informItemDB(); } void GeneralHandler::unload() @@ -153,6 +150,7 @@ void GeneralHandler::unload() delete gameServerConnection; delete chatServerConnection; + Stats::unload(); finalize(); } @@ -176,12 +174,7 @@ void GeneralHandler::guiWindowsLoaded() player_node->setExpNeeded(100); - statusWindow->addAttribute(16, _("Strength"), true); - statusWindow->addAttribute(17, _("Agility"), true); - statusWindow->addAttribute(18, _("Dexterity"), true); - statusWindow->addAttribute(19, _("Vitality"), true); - statusWindow->addAttribute(20, _("Intelligence"), true); - statusWindow->addAttribute(21, _("Willpower"), true); + Stats::informStatusWindow(); } void GeneralHandler::guiWindowsUnloaded() diff --git a/src/net/manaserv/loginhandler.cpp b/src/net/manaserv/loginhandler.cpp index e51aef6f..cb25f584 100644 --- a/src/net/manaserv/loginhandler.cpp +++ b/src/net/manaserv/loginhandler.cpp @@ -89,8 +89,8 @@ void LoginHandler::handleMessage(Net::MessageIn &msg) case ERRMSG_FAILURE: errorMessage = _("Already logged in."); break; - case LOGIN_SERVER_FULL: - errorMessage = _("Server is full."); + case LOGIN_BANNED: + errorMessage = _("Account banned."); break; default: errorMessage = _("Unknown error."); @@ -268,8 +268,8 @@ void LoginHandler::handleLoginResponse(Net::MessageIn &msg) case ERRMSG_FAILURE: errorMessage = _("Already logged in."); break; - case LOGIN_SERVER_FULL: - errorMessage = _("Server is full."); + case LOGIN_BANNED: + errorMessage = _("Account banned"); break; case LOGIN_INVALID_TIME: errorMessage = _("Login attempt too soon after previous " diff --git a/src/net/manaserv/npchandler.cpp b/src/net/manaserv/npchandler.cpp index cb8aef4c..6c4a2706 100644 --- a/src/net/manaserv/npchandler.cpp +++ b/src/net/manaserv/npchandler.cpp @@ -224,4 +224,9 @@ void NpcHandler::endShopping(int beingId) // TODO } +void NpcHandler::clearDialogs() +{ + mNpcDialogs.clear(); +} + } // namespace ManaServ diff --git a/src/net/manaserv/npchandler.h b/src/net/manaserv/npchandler.h index 7f48c738..689fdc1d 100644 --- a/src/net/manaserv/npchandler.h +++ b/src/net/manaserv/npchandler.h @@ -66,6 +66,8 @@ class NpcHandler : public MessageHandler, public Net::NpcHandler void endShopping(int beingId); + void clearDialogs(); + private: typedef struct { NpcDialog* dialog; diff --git a/src/net/manaserv/playerhandler.cpp b/src/net/manaserv/playerhandler.cpp index 4514366a..60fa5b29 100644 --- a/src/net/manaserv/playerhandler.cpp +++ b/src/net/manaserv/playerhandler.cpp @@ -39,6 +39,7 @@ #include "net/manaserv/connection.h" #include "net/manaserv/messagein.h" #include "net/manaserv/messageout.h" +#include "net/manaserv/npchandler.h" #include "net/manaserv/protocol.h" /** @@ -56,6 +57,10 @@ namespace ManaServ { void RespawnRequestListener::action(const gcn::ActionEvent &event) { Net::getPlayerHandler()->respawn(); + + ManaServ::NpcHandler *handler = + static_cast<ManaServ::NpcHandler*>(Net::getNpcHandler()); + handler->clearDialogs(); } extern Connection *gameServerConnection; diff --git a/src/net/manaserv/protocol.h b/src/net/manaserv/protocol.h index dc120fa2..226a27a0 100644 --- a/src/net/manaserv/protocol.h +++ b/src/net/manaserv/protocol.h @@ -31,23 +31,26 @@ * - CPMSG_*: from chat server to client * - PGMSG_*: from client to game server * - GPMSG_*: from game server to client + * - GAMSG_*: from game server to account server * * 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) + * + * TODO - Document specific error codes for each packet */ enum { // Login/Register - PAMSG_REGISTER = 0x0000, // L version, S username, S password, S email, S captcha response - APMSG_REGISTER_RESPONSE = 0x0002, // B error [, S updatehost] - PAMSG_UNREGISTER = 0x0003, // - + PAMSG_REGISTER = 0x0000, // D version, S username, S password, S email, S captcha response + APMSG_REGISTER_RESPONSE = 0x0002, // B error, [S updatehost] + PAMSG_UNREGISTER = 0x0003, // S username, S password APMSG_UNREGISTER_RESPONSE = 0x0004, // B error PAMSG_REQUEST_REGISTER_INFO = 0x0005, // - APMSG_REGISTER_INFO_RESPONSE = 0x0006, // B byte registrationAllowed, byte minNameLength, byte maxNameLength, string captchaURL, string captchaInstructions - PAMSG_LOGIN = 0x0010, // L version, S username, S password - APMSG_LOGIN_RESPONSE = 0x0012, // B error [, S updatehost] + APMSG_REGISTER_INFO_RESPONSE = 0x0006, // B byte registration Allowed, byte minNameLength, byte maxNameLength, string captchaURL, string captchaInstructions + PAMSG_LOGIN = 0x0010, // D 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 @@ -87,7 +90,7 @@ enum { GPMSG_INVENTORY_FULL = 0x0121, // { B slot, W item id [, B amount] }* GPMSG_PLAYER_ATTRIBUTE_CHANGE = 0x0130, // { W attribute, W base value, W modified value }* GPMSG_PLAYER_EXP_CHANGE = 0x0140, // { W skill, D exp got, D exp needed }* - GPMSG_LEVELUP = 0x0150, // W new level + GPMSG_LEVELUP = 0x0150, // W new level, W character points, W correction points 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 @@ -95,7 +98,7 @@ enum { 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 }* + // character: 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 @@ -106,12 +109,13 @@ enum { 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_BEING_HEALTH_CHANGE = 0x0274, // W being id, W health GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, W*2 position, B speed] }* GPMSG_ITEMS = 0x0281, // { W item id, W*2 position }* PGMSG_ATTACK = 0x0290, // W being id - GPMSG_BEING_ATTACK = 0x0291, // W being id + GPMSG_BEING_ATTACK = 0x0291, // W being id, B direction, B attacktype PGMSG_USE_SPECIAL = 0x0292, // B specialID - GPMSG_SPECIAL_STATUS = 0x0293, // { B specialID, L current, L max, L recharge } + GPMSG_SPECIAL_STATUS = 0x0293, // { B specialID, D current, D max, D recharge } PGMSG_SAY = 0x02A0, // S text GPMSG_SAY = 0x02A1, // W being id, S text GPMSG_NPC_CHOICE = 0x02B0, // W being id, { S text }* @@ -125,11 +129,11 @@ enum { GPMSG_NPC_ERROR = 0x02B8, // B error GPMSG_NPC_CLOSE = 0x02B9, // W being id GPMSG_NPC_POST = 0x02D0, // W being id - PGMSG_NPC_POST_SEND = 0x02D1, // S name, S text, W item id + PGMSG_NPC_POST_SEND = 0x02D1, // W being id, { S name, S text, W item id } GPMSG_NPC_POST_GET = 0x02D2, // W being id, { S name, S text, W item id } - PGMSG_NPC_NUMBER = 0x02D3, // W being id, L number + PGMSG_NPC_NUMBER = 0x02D3, // W being id, D number PGMSG_NPC_STRING = 0x02D4, // W being id, S string - GPMSG_NPC_NUMBER = 0x02D5, // W being id, L max, L min, L default + GPMSG_NPC_NUMBER = 0x02D5, // W being id, D max, D min, D default GPMSG_NPC_STRING = 0x02D6, // W being id PGMSG_TRADE_REQUEST = 0x02C0, // W being id GPMSG_TRADE_REQUEST = 0x02C1, // W being id @@ -143,8 +147,8 @@ enum { GPMSG_TRADE_CONFIRM = 0x02C9, // - PGMSG_TRADE_ADD_ITEM = 0x02CA, // B slot, B amount GPMSG_TRADE_ADD_ITEM = 0x02CB, // W item id, B amount - PGMSG_TRADE_SET_MONEY = 0x02CC, // L amount - GPMSG_TRADE_SET_MONEY = 0x02CD, // L amount + PGMSG_TRADE_SET_MONEY = 0x02CC, // D amount + GPMSG_TRADE_SET_MONEY = 0x02CD, // D amount GPMSG_TRADE_BOTH_CONFIRM = 0x02CE, // - PGMSG_USE_ITEM = 0x0300, // B slot GPMSG_USE_RESPONSE = 0x0301, // B error @@ -174,7 +178,7 @@ enum { // Party PCMSG_PARTY_INVITE = 0x03A0, // S name - CPMSG_PARTY_INVITE_RESPONSE = 0x03A1, // B error + CPMSG_PARTY_INVITE_RESPONSE = 0x03A1, // B error, S name CPMSG_PARTY_INVITED = 0x03A2, // S name PCMSG_PARTY_ACCEPT_INVITE = 0x03A5, // S name CPMSG_PARTY_ACCEPT_INVITE_RESPONSE = 0x03A6, // B error, { S name } @@ -207,10 +211,34 @@ enum { 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 + // -- User modes PCMSG_USER_MODE = 0x0465, // W channel id, S name, B mode PCMSG_KICK_USER = 0x0466, // W channel id, S name + // Inter-server + GAMSG_REGISTER = 0x0500, // S address, W port, S password, D items db revision, { W map id }* + AGMSG_REGISTER_RESPONSE = 0x0501, // C item version, C password response + AGMSG_ACTIVE_MAP = 0x0502, // W map id + AGMSG_PLAYER_ENTER = 0x0510, // B*32 token, D id, S name, serialised character data + GAMSG_PLAYER_DATA = 0x0520, // D id, serialised character data + GAMSG_REDIRECT = 0x0530, // D id + AGMSG_REDIRECT_RESPONSE = 0x0531, // D id, B*32 token, S game address, W game port + GAMSG_PLAYER_RECONNECT = 0x0532, // D id, B*32 token + GAMSG_PLAYER_SYNC = 0x0533, // serialised sync data + GAMSG_SET_QUEST = 0x0540, // D id, S name, S value + GAMSG_GET_QUEST = 0x0541, // D id, S name + AGMSG_GET_QUEST_RESPONSE = 0x0542, // D id, S name, S value + GAMSG_BAN_PLAYER = 0x0550, // D id, W duration + GAMSG_CHANGE_PLAYER_LEVEL = 0x0555, // D id, W level + GAMSG_CHANGE_ACCOUNT_LEVEL = 0x0556, // D id, W level + GAMSG_STATISTICS = 0x0560, // { W map id, W thing nb, W monster nb, W player nb, { D character id }* }* + CGMSG_CHANGED_PARTY = 0x0590, // D character id, D party id + GCMSG_REQUEST_POST = 0x05A0, // D character id + CGMSG_POST_RESPONSE = 0x05A1, // D receiver id, { S sender name, S letter, W num attachments { W attachment item id, W quantity } } + GCMSG_STORE_POST = 0x05A5, // D sender id, S receiver name, S letter, { W attachment item id, W quantity } + CGMSG_STORE_POST_RESPONSE = 0x05A6, // D id, B error + GAMSG_TRANSACTION = 0x0600, // D character id, D action, S message + XXMSG_INVALID = 0x7FFF }; @@ -226,14 +254,35 @@ enum { 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 + ERRMSG_TIME_OUT, // data failed to arrive in due time + ERRMSG_LIMIT_REACHED // limit reached +}; + +// used in AGMSG_REGISTER_RESPONSE to show state of item db +enum { + DATA_VERSION_OK = 0x00, + DATA_VERSION_OUTDATED = 0x01 +}; + +// used in AGMSG_REGISTER_RESPNSE to show if password was accepted +enum { + PASSWORD_OK = 0x00, + PASSWORD_BAD = 0x01 +}; + +// used to identify part of sync message +enum { + SYNC_CHARACTER_POINTS = 0x01, // D charId, D charPoints, D corrPoints, B attribute id, D attribute value + SYNC_CHARACTER_SKILL = 0x02, // D charId, B skillId, D skill value + SYNC_ONLINE_STATUS = 0x03, // D charId, B 0x00 = offline, 0x01 = online + SYNC_END_OF_BUFFER = 0xFF // shows, that the buffer ends here. }; // Login specific return values enum { LOGIN_INVALID_VERSION = 0x40, // the user is using an incompatible protocol LOGIN_INVALID_TIME = 0x50, // the user tried logging in too fast - LOGIN_SERVER_FULL // the server is overloaded + LOGIN_BANNED // the user is currently banned }; // Account register specific return values @@ -249,9 +298,9 @@ 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_ATTRIBUTES_TOO_HIGH, + CREATE_ATTRIBUTES_TOO_LOW, + CREATE_ATTRIBUTES_EQUAL_TO_ZERO, CREATE_EXISTS_NAME, CREATE_TOO_MUCH_CHARACTERS }; @@ -263,18 +312,26 @@ enum AttribmodResponseCode { ATTRIBMOD_NO_POINTS_LEFT, ATTRIBMOD_DENIED }; + // Object type enumeration -enum { - // A simple item +enum ThingType +{ + // A simple item. OBJECT_ITEM = 0, - // An item that can be activated (doors, switchs, sign, ...) + // An item that toggle map/quest actions (doors, switchs, ...) + // and can speak (map panels). OBJECT_ACTOR, - // Non-Playable-Character is an actor capable of movement and maybe actions + // 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) + // A monster (moving actor with AI. Should be able to toggle map/quest + // actions, too). OBJECT_MONSTER, - // A player - OBJECT_PLAYER + // A normal being. + OBJECT_CHARACTER, + // A effect to be shown. + OBJECT_EFFECT, + // Server-only object. + OBJECT_OTHER }; // Moving object flags diff --git a/src/net/manaserv/stats.cpp b/src/net/manaserv/stats.cpp new file mode 100644 index 00000000..b79b1fd9 --- /dev/null +++ b/src/net/manaserv/stats.cpp @@ -0,0 +1,202 @@ +/* + * The Mana Client + * Copyright (C) 2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "net/manaserv/stats.h" + +#include "log.h" + +#include "gui/statuswindow.h" + +#include "resources/itemdb.h" + +#include "utils/gettext.h" +#include "utils/xml.h" + +#include <list> +#include <map> + +namespace ManaServ { +namespace Stats { + typedef struct { + unsigned int id; + std::string name; + std::string tag; + std::string effect; + std::string description; + bool modifiable; + } Stat; + + typedef std::map<unsigned int, Stat> StatMap; + StatMap stats; + + static void loadBuiltins() + { + { + Stat s; + s.id = 16; + s.name = _("Strength"); + s.tag = "str"; + s.effect = _("Strength %+d"); + s.description = ""; + s.modifiable = true; + + stats[s.id] = s; + } + + { + Stat s; + s.id = 17; + s.name = _("Agility"); + s.tag = "agi"; + s.effect = _("Agility %+d"); + s.description = ""; + s.modifiable = true; + + stats[s.id] = s; + } + + { + Stat s; + s.id = 18; + s.name = _("Dexterity"); + s.tag = "dex"; + s.effect = _("Dexterity %+d"); + s.description = ""; + s.modifiable = true; + + stats[s.id] = s; + } + + { + Stat s; + s.id = 19; + s.name = _("Vitality"); + s.tag = "vit"; + s.effect = _("Vitality %+d"); + s.description = ""; + s.modifiable = true; + + stats[s.id] = s; + } + + { + Stat s; + s.id = 20; + s.name = _("Intelligence"); + s.tag = "int"; + s.effect = _("Intelligence %+d"); + s.description = ""; + s.modifiable = true; + + stats[s.id] = s; + } + + { + Stat s; + s.id = 21; + s.name = _("Willpower"); + s.tag = "will"; + s.effect = _("Willpower %+d"); + s.description = ""; + s.modifiable = true; + + stats[s.id] = s; + } + } + + void load() + { + XML::Document doc("stats.xml"); + xmlNodePtr rootNode = doc.rootNode(); + + if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "stats")) + { + logger->log("Stats: Error while loading stats.xml!"); + loadBuiltins(); + return; + } + + for_each_xml_child_node(node, rootNode) + { + if (!xmlStrEqual(node->name, BAD_CAST "stat")) + continue; + + int id = XML::getProperty(node, "id", 0); + + if (id == 0) + { + logger->log("Stats: Invalid or missing stat ID in stats.xml!"); + continue; + } + else if (stats.find(id) != stats.end()) + { + logger->log("Stats: Redefinition of stat ID %d", id); + } + + std::string name = XML::getProperty(node, "name", ""); + + if (name.empty()) + { + logger->log("Stats: Invalid or missing stat name in " + "stats.xml!"); + continue; + } + + Stat s; + s.id = id; + s.name = name; + s.tag = XML::getProperty(node, "tag", ""); + s.effect = XML::getProperty(node, "effect", ""); + s.description = XML::getProperty(node, "desc", ""); + s.modifiable = XML::getProperty(node, "modifiable", "false") + == "true"; + + stats[id] = s; + } + } + + void unload() + { + stats.clear(); + } + + void informItemDB() + { + std::list<ItemDB::Stat> dbStats; + + StatMap::const_iterator it, it_end; + for (it = stats.begin(), it_end = stats.end(); it != it_end; it++) + if (!it->second.tag.empty()) + dbStats.push_back(ItemDB::Stat(it->second.tag, + it->second.effect)); + + ItemDB::setStatsList(dbStats); + } + + void informStatusWindow() + { + StatMap::const_iterator it, it_end; + for (it = stats.begin(), it_end = stats.end(); it != it_end; it++) + statusWindow->addAttribute(it->second.id, it->second.name, + it->second.modifiable, + it->second.description); + } +} // namespace Stats +} // namespace ManaServ diff --git a/src/net/manaserv/stats.h b/src/net/manaserv/stats.h new file mode 100644 index 00000000..c4afbd79 --- /dev/null +++ b/src/net/manaserv/stats.h @@ -0,0 +1,36 @@ +/* + * The Mana Client + * Copyright (C) 2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef NET_MANASERV_STATS_H +#define NET_MANASERV_STATS_H + +namespace ManaServ { +namespace Stats { + void load(); + + void unload(); + + void informItemDB(); + + void informStatusWindow(); +} // namespace Stats +} // namespace ManaServ + +#endif // NET_MANASERV_STATS_H diff --git a/src/net/tmwa/generalhandler.cpp b/src/net/tmwa/generalhandler.cpp index a975abe8..14f48055 100644 --- a/src/net/tmwa/generalhandler.cpp +++ b/src/net/tmwa/generalhandler.cpp @@ -98,12 +98,12 @@ GeneralHandler::GeneralHandler(): generalHandler = this; std::list<ItemDB::Stat> stats; - stats.push_back(ItemDB::Stat("str", N_("Strength %+d"))); - stats.push_back(ItemDB::Stat("agi", N_("Agility %+d"))); - stats.push_back(ItemDB::Stat("vit", N_("Vitality %+d"))); - stats.push_back(ItemDB::Stat("int", N_("Intelligence %+d"))); - stats.push_back(ItemDB::Stat("dex", N_("Dexterity %+d"))); - stats.push_back(ItemDB::Stat("luck", N_("Luck %+d"))); + stats.push_back(ItemDB::Stat("str", _("Strength %+d"))); + stats.push_back(ItemDB::Stat("agi", _("Agility %+d"))); + stats.push_back(ItemDB::Stat("vit", _("Vitality %+d"))); + stats.push_back(ItemDB::Stat("int", _("Intelligence %+d"))); + stats.push_back(ItemDB::Stat("dex", _("Dexterity %+d"))); + stats.push_back(ItemDB::Stat("luck", _("Luck %+d"))); ItemDB::setStatsList(stats); } @@ -214,20 +214,20 @@ void GeneralHandler::guiWindowsLoaded() inventoryWindow->setSplitAllowed(false); skillDialog->loadSkills("ea-skills.xml"); - statusWindow->addAttribute(STR, _("Strength"), true); - statusWindow->addAttribute(AGI, _("Agility"), true); - statusWindow->addAttribute(VIT, _("Vitality"), true); - statusWindow->addAttribute(INT, _("Intelligence"), true); - statusWindow->addAttribute(DEX, _("Dexterity"), true); - statusWindow->addAttribute(LUK, _("Luck"), true); - - statusWindow->addAttribute(ATK, _("Attack"), false); - statusWindow->addAttribute(DEF, _("Defense"), false); - statusWindow->addAttribute(MATK, _("M.Attack"), false); - statusWindow->addAttribute(MDEF, _("M.Defense"), false); - statusWindow->addAttribute(HIT, _("% Accuracy"), false); - statusWindow->addAttribute(FLEE, _("% Evade"), false); - statusWindow->addAttribute(CRIT, _("% Critical"), false); + statusWindow->addAttribute(STR, _("Strength"), true, ""); + statusWindow->addAttribute(AGI, _("Agility"), true, ""); + statusWindow->addAttribute(VIT, _("Vitality"), true, ""); + statusWindow->addAttribute(INT, _("Intelligence"), true, ""); + statusWindow->addAttribute(DEX, _("Dexterity"), true, ""); + statusWindow->addAttribute(LUK, _("Luck"), true, ""); + + statusWindow->addAttribute(ATK, _("Attack"), false, ""); + statusWindow->addAttribute(DEF, _("Defense"), false, ""); + statusWindow->addAttribute(MATK, _("M.Attack"), false, ""); + statusWindow->addAttribute(MDEF, _("M.Defense"), false, ""); + statusWindow->addAttribute(HIT, _("% Accuracy"), false, ""); + statusWindow->addAttribute(FLEE, _("% Evade"), false, ""); + statusWindow->addAttribute(CRIT, _("% Critical"), false, ""); } void GeneralHandler::guiWindowsUnloaded() diff --git a/src/net/tmwa/npchandler.cpp b/src/net/tmwa/npchandler.cpp index 9d7e72ea..b54a0ba7 100644 --- a/src/net/tmwa/npchandler.cpp +++ b/src/net/tmwa/npchandler.cpp @@ -222,4 +222,9 @@ void NpcHandler::endShopping(int beingId) // TODO } +void NpcHandler::clearDialogs() +{ + mNpcDialogs.clear(); +} + } // namespace TmwAthena diff --git a/src/net/tmwa/npchandler.h b/src/net/tmwa/npchandler.h index a40371a6..bd696bdd 100644 --- a/src/net/tmwa/npchandler.h +++ b/src/net/tmwa/npchandler.h @@ -67,6 +67,8 @@ class NpcHandler : public MessageHandler, public Net::NpcHandler void endShopping(int beingId); + void clearDialogs(); + private: typedef struct { NpcDialog* dialog; diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp index 62cdc168..84fcdeee 100644 --- a/src/net/tmwa/playerhandler.cpp +++ b/src/net/tmwa/playerhandler.cpp @@ -41,6 +41,7 @@ #include "net/messageout.h" #include "net/tmwa/protocol.h" +#include "net/tmwa/npchandler.h" #include "utils/stringutils.h" #include "utils/gettext.h" @@ -85,6 +86,10 @@ namespace { SellDialog::closeAll(); viewport->closePopupMenu(); + + TmwAthena::NpcHandler *handler = + static_cast<TmwAthena::NpcHandler*>(Net::getNpcHandler()); + handler->clearDialogs(); } } deathListener; diff --git a/src/particlecontainer.cpp b/src/particlecontainer.cpp index 175c1e87..6900539d 100644 --- a/src/particlecontainer.cpp +++ b/src/particlecontainer.cpp @@ -71,14 +71,17 @@ void ParticleList::addLocally(Particle *particle) void ParticleList::removeLocally(Particle *particle) { - for (std::list<Particle *>::iterator it = mElements.begin(); - it != mElements.end(); it++) + std::list<Particle *>::iterator it, it_end; + for (it = mElements.begin(), it_end = mElements.end(); + it != it_end;) { if (*it == particle) { (*it)->kill(); - mElements.erase(it); + it = mElements.erase(it); } + else + it++; } } diff --git a/src/resources/ambientlayer.cpp b/src/resources/ambientlayer.cpp index 780baf00..50fe8bd9 100644 --- a/src/resources/ambientlayer.cpp +++ b/src/resources/ambientlayer.cpp @@ -51,6 +51,7 @@ AmbientLayer::AmbientLayer(Image *img, float parallax, std::string idPath = mImage->getIdPath() + "_rescaled"; ResourceManager::getInstance()->addResource(idPath, rescaledOverlay); mImage = rescaledOverlay; + rescaledOverlay->incRef(); } else mImage->incRef(); diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index 219eb317..e8a2bd20 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -369,7 +369,7 @@ static void setTile(Map *map, MapLayer *layer, int x, int y, int gid) else { // Set collision tile - if (set && (gid - set->getFirstGid() != 0)) + if (set && (gid - set->getFirstGid() == 1)) map->blockTile(x, y, Map::BLOCKTYPE_WALL); } } diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index 3d23edcd..3013f20b 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -318,7 +318,11 @@ struct DyedImageLoader } int fileSize; void *buffer = l->manager->loadFile(path, fileSize); - if (!buffer) return NULL; + if (!buffer) + { + delete d; + return NULL; + } Resource *res = d ? Image::load(buffer, fileSize, *d) : Image::load(buffer, fileSize); free(buffer); diff --git a/src/statuseffect.cpp b/src/statuseffect.cpp index 66e8010d..49619f8a 100644 --- a/src/statuseffect.cpp +++ b/src/statuseffect.cpp @@ -169,6 +169,8 @@ void unloadMap(std::map<int, StatusEffect *> map) for (it = map.begin(); it != map.end(); it++) delete (*it).second; + + map.clear(); } void StatusEffect::unload() |