diff options
Diffstat (limited to 'src')
34 files changed, 761 insertions, 236 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 76fd3545..91fe8e06 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -169,6 +169,8 @@ SET(SRCS gui/npcpostdialog.h gui/okdialog.cpp gui/okdialog.h + gui/outfitwindow.cpp + gui/outfitwindow.h gui/palette.cpp gui/palette.h gui/partywindow.cpp @@ -464,8 +466,8 @@ SET(SRCS_TMW gui/buddywindow.h gui/changeemaildialog.cpp gui/changeemaildialog.h - gui/connection.cpp - gui/connection.h + gui/connectiondialog.cpp + gui/connectiondialog.h gui/guildlistbox.cpp gui/guildlistbox.h gui/guildwindow.cpp diff --git a/src/Makefile.am b/src/Makefile.am index dd9177e4..23de64bc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -118,6 +118,8 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ gui/npcpostdialog.h \ gui/okdialog.cpp \ gui/okdialog.h \ + gui/outfitwindow.cpp \ + gui/outfitwindow.h \ gui/palette.cpp \ gui/palette.h \ gui/partywindow.cpp \ @@ -368,8 +370,8 @@ tmw_SOURCES += \ gui/buddywindow.h \ gui/changeemaildialog.cpp \ gui/changeemaildialog.h \ - gui/connection.cpp \ - gui/connection.h \ + gui/connectiondialog.cpp \ + gui/connectiondialog.h \ gui/guildlistbox.cpp \ gui/guildlistbox.h \ gui/guildwindow.cpp \ diff --git a/src/being.cpp b/src/being.cpp index 37cb6987..3593bb94 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -56,11 +56,6 @@ #include <cassert> #include <cmath> -namespace { -const bool debug_movement = true; -} - - #define BEING_EFFECTS_FILE "effects.xml" #define HAIR_FILE "hair.xml" @@ -157,169 +152,66 @@ void Being::setDestination(Uint16 destX, Uint16 destY) #endif #ifdef TMWSERV_SUPPORT -void Being::adjustCourse(int srcX, int srcY, int dstX, int dstY) + +void Being::adjustCourse(int srcX, int srcY) +{ + setDestination(srcX, srcY, mDest.x, mDest.y); +} + +void Being::setDestination(int dstX, int dstY) { - if (debug_movement) - printf("%p adjustCourse(%d, %d, %d, %d)\n", - (void*) this, srcX, srcY, dstX, dstY); + setDestination(mPos.x, mPos.y, dstX, dstY); +} +void Being::setDestination(int srcX, int srcY, int dstX, int 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()); - } + Path thisPath; - // TODO: Evaluate the implementation of this method - /* - if (mX / 32 == dstX / 32 && mY / 32 == dstY / 32) + if (mMap) { - // 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) + thisPath = mMap->findPath((int) srcX / 32, (int) srcY / 32, + dstX / 32, dstY / 32, getWalkMask()); + } + if (thisPath.empty()) { - // The being is at the start of the path. - setPath(p1); - delete[] p1_dist; + setPath(Path()); 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; - } + // FIXME: Look into making this code neater. + // Interpolate the offsets. Also convert from tile based to pixel based - Path bestPath; - int bestRating = -1, bestStart = 0, bestLength = 0; - int j = 0; + // Note: I divided the offsets by 32 then muilpied it back to get the top left + // Conner of where the tile is. (If you know a better way then please change it) - 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; - } + // Find the starting offset + int startX = srcX - ((srcX / 32) * 32 + 16); + int startY = srcY - ((srcY / 32) * 32 + 16); - 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; - } + // Find the ending offset + int endX = dstX - ((dstX / 32) * 32 + 16); + int endY = dstY - ((dstY / 32) * 32 + 16); - 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; - } + // Find the distance, and divide it by the number of steps + int changeX = (endX - startX) / thisPath.size(); + int changeY = (endY - startY) / thisPath.size(); - // Concatenate paths. - for (int j = bestStart; j > 0; --j) + // Convert the map path to pixels over tiles + // And add interpolation between the starting and ending offsets + Path::iterator it = thisPath.begin(); + int i = 0; + while(it != thisPath.end()) { - p1.pop_front(); + it->x = (it->x * 32 + 16) + startX + (changeX * i); + it->y = (it->y * 32 + 16) + startY + (changeY * i); + i++; + it++; } - 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); + setPath(thisPath); } #endif // TMWSERV_SUPPORT @@ -332,7 +224,7 @@ void Being::setPath(const Path &path) { mPath = path; #ifdef TMWSERV_SUPPORT - std::cout << this << " New path: " << path << std::endl; +// std::cout << this << " New path: " << path << std::endl; #else if (mAction != WALK && mAction != DEAD) { @@ -668,8 +560,8 @@ void Being::logic() #ifdef TMWSERV_SUPPORT const Vector dest = (mPath.empty()) ? - mDest : Vector(mPath.front().x * 32 + 16, - mPath.front().y * 32 + 16); + mDest : Vector(mPath.front().x, + mPath.front().y); Vector dir = dest - mPos; const float length = dir.length(); diff --git a/src/being.h b/src/being.h index 6c849350..040d55a9 100644 --- a/src/being.h +++ b/src/being.h @@ -183,12 +183,15 @@ class Being : public Sprite, public ConfigListener #ifdef EATHENA_SUPPORT virtual void setDestination(Uint16 destX, Uint16 destY); #else - void setDestination(int x, int y); + /** + * Creates a path for the being from sx,sy to ex,ey + */ + void setDestination(int sx, int sy, int ex, int ey); /** - * Returns the destination for this being. + * Creates a path for the being from currect position to ex and ey */ - const Vector &getDestination() const { return mDest; } + void setDestination(int ex, int ey); /** * Adjusts course to expected start point. @@ -196,9 +199,9 @@ class Being : public Sprite, public ConfigListener void adjustCourse(int srcX, int srcY); /** - * Adjusts course to expected start and end points. + * Returns the destination for this being. */ - void adjustCourse(int srcX, int srcY, int destX, int destY); + const Vector &getDestination() const { return mDest; } #endif /** diff --git a/src/commandhandler.cpp b/src/commandhandler.cpp index 0af77398..d2a303e8 100644 --- a/src/commandhandler.cpp +++ b/src/commandhandler.cpp @@ -25,6 +25,7 @@ #include "channel.h" #include "game.h" #include "localplayer.h" +#include "playerrelations.h" #include "gui/widgets/channeltab.h" #include "gui/widgets/chattab.h" @@ -76,6 +77,14 @@ void CommandHandler::handleCommand(const std::string &command, ChatTab *tab) { handleQuery(args, tab); } + else if (type == "ignore") + { + handleIgnore(args, tab); + } + else if (type == "unignore") + { + handleUnignore(args, tab); + } else if (type == "join") { handleJoin(args, tab); @@ -154,6 +163,9 @@ void CommandHandler::handleHelp(const std::string &args, ChatTab *tab) tab->chatLog(_("/query > Makes a tab for private messages with another user")); tab->chatLog(_("/q > Alias of query")); + tab->chatLog(_("/ignore > ignore a player")); + tab->chatLog(_("/unignore > stop ignoring a player")); + tab->chatLog(_("/list > Display all public channels")); tab->chatLog(_("/join > Join or create a channel")); @@ -192,6 +204,12 @@ void CommandHandler::handleHelp(const std::string &args, ChatTab *tab) tab->chatLog(_("Command: /clear")); tab->chatLog(_("This command clears the chat log of previous chat.")); } + else if (args == "ignore") + { + tab->chatLog(_("Command: /ignore <player>")); + tab->chatLog(_("This command ignores the given player reguardless of " + "current relations.")); + } else if (args == "join") { tab->chatLog(_("Command: /join <channel>")); @@ -257,6 +275,12 @@ void CommandHandler::handleHelp(const std::string &args, ChatTab *tab) tab->chatLog(_("Command: /toggle")); tab->chatLog(_("This command displays the return toggle status.")); } + else if (args == "unignore") + { + tab->chatLog(_("Command: /unignore <player>")); + tab->chatLog(_("This command stops ignoring the given player if they " + "are being ignored")); + } else if (args == "where") { tab->chatLog(_("Command: /where")); @@ -416,3 +440,47 @@ void CommandHandler::handlePresent(const std::string &args, ChatTab *tab) { chatWindow->doPresent(); } + +void CommandHandler::handleIgnore(const std::string &args, ChatTab *tab) +{ + if (args.empty()) + { + tab->chatLog(_("Please specify a name."), BY_SERVER); + return; + } + + if (player_relations.getRelation(args) == PlayerRelation::IGNORED) + { + tab->chatLog(_("Player already ignored!"), BY_SERVER); + return; + } + else + player_relations.setRelation(args, PlayerRelation::IGNORED); + + if (player_relations.getRelation(args) == PlayerRelation::IGNORED) + tab->chatLog(_("Player successfully ignored!"), BY_SERVER); + else + tab->chatLog(_("Player could not be ignored!"), BY_SERVER); +} + +void CommandHandler::handleUnignore(const std::string &args, ChatTab *tab) +{ + if (args.empty()) + { + tab->chatLog(_("Please specify a name."), BY_SERVER); + return; + } + + if (player_relations.getRelation(args) == PlayerRelation::IGNORED) + player_relations.removePlayer(args); + else + { + tab->chatLog(_("Player wasn't ignored!"), BY_SERVER); + return; + } + + if (player_relations.getRelation(args) != PlayerRelation::IGNORED) + tab->chatLog(_("Player no longer ignored!"), BY_SERVER); + else + tab->chatLog(_("Player could not be unignored!"), BY_SERVER); +} diff --git a/src/commandhandler.h b/src/commandhandler.h index 783e400d..eb73f239 100644 --- a/src/commandhandler.h +++ b/src/commandhandler.h @@ -54,7 +54,10 @@ class CommandHandler static char parseBoolean(const std::string &value); - private: + protected: + friend class ChatTab; + friend class WhisperTab; + /** * Handle an announce command. */ @@ -124,6 +127,16 @@ class CommandHandler * Handle a present command. */ void handlePresent(const std::string &args, ChatTab *tab); + + /** + * Handle an ignore command. + */ + void handleIgnore(const std::string &args, ChatTab *tab); + + /** + * Handle an unignore command. + */ + void handleUnignore(const std::string &args, ChatTab *tab); }; extern CommandHandler *commandHandler; diff --git a/src/game.cpp b/src/game.cpp index 82750dac..f1df57cc 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -58,6 +58,7 @@ #include "gui/ministatus.h" #include "gui/npcdialog.h" #include "gui/okdialog.h" +#include "gui/outfitwindow.h" #include "gui/sdlinput.h" #include "gui/sell.h" #include "gui/setup.h" @@ -139,6 +140,7 @@ HelpWindow *helpWindow; DebugWindow *debugWindow; ShortcutWindow *itemShortcutWindow; ShortcutWindow *emoteShortcutWindow; +OutfitWindow *outfitWindow; BeingManager *beingManager = NULL; FloorItemManager *floorItemManager = NULL; @@ -233,6 +235,7 @@ static void createGuiWindows() new ItemShortcutContainer); emoteShortcutWindow = new ShortcutWindow("EmoteShortcut", new EmoteShortcutContainer); + outfitWindow = new OutfitWindow(); localChatTab = new ChatTab(_("General")); @@ -278,6 +281,7 @@ static void destroyGuiWindows() delete itemShortcutWindow; delete emoteShortcutWindow; delete storageWindow; + delete outfitWindow; } Game::Game(): @@ -610,6 +614,65 @@ void Game::handleInput() } } + if (event.key.keysym.mod & KMOD_RCTRL && !chatWindow->isInputFocused()) + { + switch (event.key.keysym.sym) + { + case SDLK_1: + outfitWindow->wearOutfit(0); + used = true; + break; + + case SDLK_2: + outfitWindow->wearOutfit(1); + used = true; + break; + + case SDLK_3: + outfitWindow->wearOutfit(2); + used = true; + break; + + case SDLK_4: + outfitWindow->wearOutfit(3); + used = true; + break; + + case SDLK_5: + outfitWindow->wearOutfit(4); + used = true; + break; + + case SDLK_6: + outfitWindow->wearOutfit(5); + used = true; + break; + + case SDLK_7: + outfitWindow->wearOutfit(6); + used = true; + break; + + case SDLK_8: + outfitWindow->wearOutfit(7); + used = true; + break; + + case SDLK_9: + outfitWindow->wearOutfit(8); + used = true; + break; + + case SDLK_0: + outfitWindow->wearOutfit(9); + used = true; + break; + + default: + break; + } + } + const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); switch (tKey) { @@ -669,7 +732,7 @@ void Game::handleInput() default: break; } - if (keyboard.isEnabled() && + if (keyboard.isEnabled() && !chatWindow->isInputFocused() && !npcDialog->isInputFocused()) { const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); @@ -786,6 +849,9 @@ void Game::handleInput() case KeyboardConfig::KEY_WINDOW_EMOTE_SHORTCUT: requestedWindow = emoteShortcutWindow; break; + case KeyboardConfig::KEY_WINDOW_OUTFIT: + requestedWindow = outfitWindow; + break; case KeyboardConfig::KEY_SCREENSHOT: // Screenshot (picture, hence the p) saveScreenshot(); @@ -926,7 +992,7 @@ void Game::handleInput() } #else player_node->setWalkingDir(direction); - +#endif // Attacking monsters if (keyboard.isKeyActive(keyboard.KEY_ATTACK) || (joystick && joystick->buttonPressed(0))) @@ -943,7 +1009,11 @@ void Game::handleInput() // A set target has highest priority if (!player_node->getTarget()) { +#ifdef TMWSERV_SUPPORT + Uint16 targetX = x / 32, targetY = y / 32; +#else Uint16 targetX = x, targetY = y; +#endif // Only auto target Monsters target = beingManager->findNearestLivingBeing(targetX, targetY, 20, Being::MONSTER); @@ -951,8 +1021,6 @@ void Game::handleInput() player_node->attack(target, newTarget); } -#endif - // Target the nearest player/monster/npc if ((keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) || keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) || @@ -996,7 +1064,7 @@ void Game::handleInput() } // Stop attacking if the right key is pressed - if (!keyboard.isKeyActive(keyboard.KEY_ATTACK) + if (!keyboard.isKeyActive(keyboard.KEY_ATTACK) && keyboard.isKeyActive(keyboard.KEY_TARGET)) { player_node->stopAttack(); diff --git a/src/gui/connection.cpp b/src/gui/connectiondialog.cpp index 4863edcd..1c3b7ff5 100644 --- a/src/gui/connection.cpp +++ b/src/gui/connectiondialog.cpp @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "connection.h" +#include "connectiondialog.h" #include "gui/widgets/button.h" #include "gui/widgets/label.h" diff --git a/src/gui/connection.h b/src/gui/connectiondialog.h index d6059c3f..d6059c3f 100644 --- a/src/gui/connection.h +++ b/src/gui/connectiondialog.h diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index 47f66e76..06e43eac 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -79,6 +79,7 @@ InventoryWindow::InventoryWindow(int invSize): mUseButton = new Button(longestUseString, "use", this); mDropButton = new Button(_("Drop"), "drop", this); mSplitButton = new Button(_("Split"), "split", this); + mOutfitButton = new Button(_("Outfits"), "outfit", this); mItems = new ItemContainer(player_node->getInventory()); mItems->addSelectionListener(this); @@ -103,6 +104,7 @@ InventoryWindow::InventoryWindow(int invSize): place(0, 2, mUseButton); place(1, 2, mDropButton); place(2, 2, mSplitButton); + place(6, 2, mOutfitButton); Layout &layout = getLayout(); layout.setRowHeight(1, Layout::AUTO_SET); @@ -156,6 +158,16 @@ void InventoryWindow::logic() void InventoryWindow::action(const gcn::ActionEvent &event) { + if (event.getId() == "outfit") + { + extern Window *outfitWindow; + outfitWindow->setVisible(!outfitWindow->isVisible()); + if (outfitWindow->isVisible()) + { + outfitWindow->requestMoveToTop(); + } + } + Item *item = mItems->getSelectedItem(); if (!item) @@ -163,7 +175,7 @@ void InventoryWindow::action(const gcn::ActionEvent &event) if (event.getId() == "use") { - if (item->isEquipment()) + if (item->isEquipment()) { if (item->isEquipped()) Net::getInventoryHandler()->unequipItem(item); @@ -259,10 +271,10 @@ void InventoryWindow::updateButtons() mDropButton->setEnabled(false); return; } - + mUseButton->setEnabled(true); mDropButton->setEnabled(true); - + if (selectedItem->isEquipment()) { if (selectedItem->isEquipped()) diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index 6e34666d..fbda5ac7 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -109,6 +109,7 @@ class InventoryWindow : public Window, gcn::Button *mUseButton; gcn::Button *mDropButton; gcn::Button *mSplitButton; + gcn::Button *mOutfitButton; gcn::Label *mWeightLabel; gcn::Label *mSlotsLabel; diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp index 54aa818b..d8ae6e20 100644 --- a/src/gui/itemcontainer.cpp +++ b/src/gui/itemcontainer.cpp @@ -23,6 +23,7 @@ #include "gui/chat.h" #include "gui/itempopup.h" +#include "gui/outfitwindow.h" #include "gui/palette.h" #include "gui/sdlinput.h" #include "gui/viewport.h" @@ -162,6 +163,7 @@ void ItemContainer::selectNone() { setSelectedIndex(-1); mSelectionStatus = SEL_NONE; + outfitWindow->setItemSelected(-1); } void ItemContainer::setSelectedIndex(int newIndex) @@ -260,6 +262,8 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event) mSelectionStatus = SEL_SELECTING; itemShortcut->setItemSelected(item->getId()); + if (item->isEquipment()) + outfitWindow->setItemSelected(item->getId()); } else { diff --git a/src/gui/outfitwindow.cpp b/src/gui/outfitwindow.cpp new file mode 100644 index 00000000..f43e1440 --- /dev/null +++ b/src/gui/outfitwindow.cpp @@ -0,0 +1,306 @@ +/* + * 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 "outfitwindow.h" + +#include "configuration.h" +#include "localplayer.h" +#include "graphics.h" +#include "inventory.h" +#include "equipment.h" +#include "item.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/checkbox.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" + +#include "net/inventoryhandler.h" +#include "net/net.h" + +#include "resources/image.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#include <vector> + +OutfitWindow::OutfitWindow(): + Window(_("Outfits")), + mBoxWidth(33), + mBoxHeight(33), + mGridWidth(3), + mGridHeight(3), + mItemClicked(false), + mItemMoved(NULL), + mItemSelected(-1), + mCurrentOutfit(0) +{ + setWindowName("Outfits"); + setCloseButton(true); + setDefaultSize(250, 250, 118, 180); //160 + + mPreviousButton = new Button("<", "previous", this); + mNextButton = new Button(">", "next", this); + mCurrentLabel = new Label("Outfit: 1"); + mCurrentLabel->setAlignment(gcn::Graphics::CENTER); + mUnequipCheck = new CheckBox(_("Unequip first"), + config.getValue("OutfitUnequip", true)); + + place(0, 3, mPreviousButton, 1); + place(1, 3, mCurrentLabel, 2); + place(3, 3, mNextButton, 1); + place(0, 4, mUnequipCheck, 4); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + layout.setColWidth(4, Layout::CENTER); + + loadWindowState(); + + load(); +} + +OutfitWindow::~OutfitWindow() +{ + save(); +} + +void OutfitWindow::load() +{ + memset(mItems, -1, sizeof(mItems)); + for (int o = 0; o < 10; o++) + { + std::string outfit = config.getValue("Outfit" + toString(o), "-1"); + std::string buf; + std::stringstream ss(outfit); + + std::vector<int> tokens; + + while (ss >> buf) { + tokens.push_back(atoi(buf.c_str())); + } + + for (int i = 0; i < (int)tokens.size(); i++) + { + mItems[o][i] = tokens[i]; + } + } +} + +void OutfitWindow::save() +{ + std::string outfitStr; + for (int o = 0; o < 10; o++) + { + for (int i = 0; i < 9; i++) + { + outfitStr += mItems[o][i] ? toString(mItems[o][i]) : toString(-1); + if (i <8) outfitStr += " "; + } + config.setValue("Outfit" + toString(o), outfitStr); + outfitStr = ""; + } + config.setValue("OutfitUnequip", mUnequipCheck->isSelected()); +} + +void OutfitWindow::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "next") + { + if (mCurrentOutfit < 9) { + mCurrentOutfit++; + } else { + mCurrentOutfit = 0; + } + } + else if (event.getId() == "previous") + { + if (mCurrentOutfit > 0) { + mCurrentOutfit--; + } else { + mCurrentOutfit = 9; + } + } + mCurrentLabel->setCaption("Outfit: " + toString(mCurrentOutfit + 1)); +} + +void OutfitWindow::wearOutfit(int outfit) +{ + Item *item; + if (mUnequipCheck->isSelected()) + { + for (int i = 0; i < 11; i++) + { + //non vis is 3,4,7 + if (i != 3 && i != 4 && i != 7) + { +#ifdef TMWSERV_SUPPORT + if (!(item = player_node->mEquipment.get()->getEquipment(i))) + continue; +#else + if (!(item = player_node->getInventory()->getItem( + player_node->mEquipment.get()->getEquipment(i)))) + continue; +#endif + Net::getInventoryHandler()->unequipItem(item); + } + } + } + + for (int i = 0; i < 9; i++) + { + item = player_node->getInventory()->findItem(mItems[outfit][i]); + if (item && item->getQuantity()) + { + if (item->isEquipment()) { + Net::getInventoryHandler()->equipItem(item); + } + } + } +} + +void OutfitWindow::draw(gcn::Graphics *graphics) +{ + Window::draw(graphics); + Graphics *g = static_cast<Graphics*>(graphics); + + for (int i = 0; i < 9; i++) + { + const int itemX = 10 + (i % mGridWidth) * mBoxWidth; + const int itemY = 25 + (i / mGridWidth) * mBoxHeight; + + graphics->setColor(gcn::Color(0, 0, 0, 64)); + graphics->drawRectangle(gcn::Rectangle(itemX, itemY, 32, 32)); + graphics->setColor(gcn::Color(255, 255, 255, 32)); + graphics->fillRectangle(gcn::Rectangle(itemX, itemY, 32, 32)); + + if (mItems[mCurrentOutfit][i] < 0) + continue; + + Item *item = + player_node->getInventory()->findItem(mItems[mCurrentOutfit][i]); + if (item) { + // Draw item icon. + Image* image = item->getImage(); + if (image) { + g->drawImage(image, itemX, itemY); + } + } + } + if (mItemMoved) + { + // Draw the item image being dragged by the cursor. + Image* image = mItemMoved->getImage(); + if (image) + { + const int tPosX = mCursorPosX - (image->getWidth() / 2); + const int tPosY = mCursorPosY - (image->getHeight() / 2); + + g->drawImage(image, tPosX, tPosY); + } + } +} + + +void OutfitWindow::mouseDragged(gcn::MouseEvent &event) +{ + Window::mouseDragged(event); + if (event.getButton() == gcn::MouseEvent::LEFT) { + if (!mItemMoved && mItemClicked) { + const int index = getIndexFromGrid(event.getX(), event.getY()); + if (index == -1) { + return; + } + const int itemId = mItems[mCurrentOutfit][index]; + if (itemId < 0) + return; + Item *item = player_node->getInventory()->findItem(itemId); + if (item) + { + mItemMoved = item; + mItems[mCurrentOutfit][index] = -1; + } + } + if (mItemMoved) { + mCursorPosX = event.getX(); + mCursorPosY = event.getY(); + } + } +} + +void OutfitWindow::mousePressed(gcn::MouseEvent &event) +{ + Window::mousePressed(event); + const int index = getIndexFromGrid(event.getX(), event.getY()); + if (index == -1) { + return; + } + + // Stores the selected item if there is one. + if (isItemSelected()) { + mItems[mCurrentOutfit][index] = mItemSelected; + mItemSelected = -1; + } + else if (mItems[mCurrentOutfit][index]) { + mItemClicked = true; + } +} + +void OutfitWindow::mouseReleased(gcn::MouseEvent &event) +{ + Window::mouseReleased(event); + if (event.getButton() == gcn::MouseEvent::LEFT) + { + if (isItemSelected()) + { + mItemSelected = -1; + } + const int index = getIndexFromGrid(event.getX(), event.getY()); + if (index == -1) { + mItemMoved = NULL; + return; + } + if (mItemMoved) { + mItems[mCurrentOutfit][index] = mItemMoved->getId(); + mItemMoved = NULL; + } + if (mItemClicked) { + mItemClicked = false; + } + } +} + +int OutfitWindow::getIndexFromGrid(int pointX, int pointY) const +{ + const gcn::Rectangle tRect = gcn::Rectangle( + 10, 25, 10 + mGridWidth * mBoxWidth, 25 + mGridHeight * mBoxHeight); + if (!tRect.isPointInRect(pointX, pointY)) { + return -1; + } + const int index = (((pointY - 25) / mBoxHeight) * mGridWidth) + + (pointX - 10) / mBoxWidth; + if (index >= 9) + { + return -1; + } + return index; +} diff --git a/src/gui/outfitwindow.h b/src/gui/outfitwindow.h new file mode 100644 index 00000000..3e70815c --- /dev/null +++ b/src/gui/outfitwindow.h @@ -0,0 +1,92 @@ +/* + * 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 OUTFITWINDOW_H +#define OUTFITWINDOW_H + +#include "gui/widgets/window.h" + +#include <guichan/actionlistener.hpp> + +class Button; +class CheckBox; +class Item; +class Label; + +class OutfitWindow : public Window, gcn::ActionListener +{ + public: + /** + * Constructor. + */ + OutfitWindow(); + + /** + * Destructor. + */ + ~OutfitWindow(); + + void action(const gcn::ActionEvent &event); + + void draw(gcn::Graphics *graphics); + + void mousePressed(gcn::MouseEvent &event); + + void mouseDragged(gcn::MouseEvent &event); + + void mouseReleased(gcn::MouseEvent &event); + + void load(); + + void setItemSelected(int itemId) + { mItemSelected = itemId; } + + bool isItemSelected() + { return mItemSelected > -1; } + + void wearOutfit(int outfit); + + private: + Button *mPreviousButton; + Button *mNextButton; + Label *mCurrentLabel; + CheckBox *mUnequipCheck; + + int getIndexFromGrid(int pointX, int pointY) const; + + int mBoxWidth; + int mBoxHeight; + int mCursorPosX, mCursorPosY; + int mGridWidth, mGridHeight; + bool mItemClicked; + Item *mItemMoved; + + void save(); + + int mItems[10][9]; + int mItemSelected; + + int mCurrentOutfit; +}; + +extern OutfitWindow *outfitWindow; + +#endif diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index d954b99f..68b5fed3 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -202,9 +202,7 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) mMap->drawCollision(graphics, (int) mPixelViewX, (int) mPixelViewY); -#if EATHENA_SUPPORT drawDebugPath(graphics); -#endif } } @@ -364,24 +362,12 @@ void Viewport::mousePressed(gcn::MouseEvent &event) if (player_node->withinAttackRange(being) || keyboard.isKeyActive(keyboard.KEY_ATTACK)) { - player_node->setGotoTarget(being); -//TODO: This can be changed when TMWServ moves to target based combat -#ifdef TMWSERV_SUPPORT - player_node->attack(); -#else player_node->attack(being, !keyboard.isKeyActive(keyboard.KEY_TARGET)); -#endif - } else { -#ifdef TMWSERV_SUPPORT - player_node->setDestination(event.getX() + (int) mPixelViewX, - event.getY() + (int) mPixelViewY); -#else - player_node->setDestination(tilex, tiley); -#endif + player_node->setGotoTarget(being); } break; default: @@ -410,9 +396,9 @@ void Viewport::mousePressed(gcn::MouseEvent &event) event.getY() + (int) mPixelViewY); } #else - player_node->stopAttack(); player_node->setDestination(tilex, tiley); #endif + player_node->stopAttack(); mPlayerFollowMouse = true; } } diff --git a/src/gui/widgets/whispertab.cpp b/src/gui/widgets/whispertab.cpp index 23325108..43c63cc0 100644 --- a/src/gui/widgets/whispertab.cpp +++ b/src/gui/widgets/whispertab.cpp @@ -21,6 +21,7 @@ #include "whispertab.h" +#include "commandhandler.h" #include "localplayer.h" #include "gui/palette.h" @@ -65,6 +66,8 @@ void WhisperTab::handleCommand(const std::string &msg) void WhisperTab::showHelp() { + chatLog(_("/ignore > Ignore the other player")); + chatLog(_("/unignore > Stop ignoring the other player")); chatLog(_("/close > Close the whisper tab")); } @@ -78,6 +81,18 @@ bool WhisperTab::handleCommand(const std::string &type, chatLog(_("Command: /close")); chatLog(_("This command closes the current whisper tab.")); } + else if (args == "ignore") + { + chatLog(_("Command: /ignore")); + chatLog(_("This command ignores the other player reguardless of " + "current relations.")); + } + else if (args == "unignore") + { + chatLog(_("Command: /unignore <player>")); + chatLog(_("This command stops ignoring the other player if they " + "are being ignored")); + } else return false; } @@ -85,6 +100,14 @@ bool WhisperTab::handleCommand(const std::string &type, { delete this; } + else if (type == "ignore") + { + commandHandler->handleIgnore(mNick, this); + } + else if (type == "unignore") + { + commandHandler->handleUnignore(mNick, this); + } else return false; diff --git a/src/gui/windowmenu.cpp b/src/gui/windowmenu.cpp index 5e33a4ed..8964f072 100644 --- a/src/gui/windowmenu.cpp +++ b/src/gui/windowmenu.cpp @@ -48,7 +48,6 @@ extern Window *guildWindow; extern Window *magicDialog; #endif - WindowMenu::WindowMenu(): mEmotePopup(0) { diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp index 670a96be..8e021aa6 100644 --- a/src/keyboardconfig.cpp +++ b/src/keyboardconfig.cpp @@ -80,6 +80,7 @@ static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = { {"keyWindowDebug", SDLK_F10, _("Debug Window")}, {"keyWindowParty", SDLK_F11, _("Party Window")}, {"keyWindowEmoteBar", SDLK_F12, _("Emote Shortcut Window")}, + {"keyWindowOutfit", SDLK_o, _("Outfits Window")}, {"keyEmoteShortcut1", SDLK_1, strprintf(_("Emote Shortcut %d"), 1)}, {"keyEmoteShortcut2", SDLK_2, strprintf(_("Emote Shortcut %d"), 2)}, {"keyEmoteShortcut3", SDLK_3, strprintf(_("Emote Shortcut %d"), 3)}, diff --git a/src/keyboardconfig.h b/src/keyboardconfig.h index 68a5efa6..b6a07f16 100644 --- a/src/keyboardconfig.h +++ b/src/keyboardconfig.h @@ -191,6 +191,7 @@ class KeyboardConfig KEY_WINDOW_DEBUG, KEY_WINDOW_PARTY, KEY_WINDOW_EMOTE_SHORTCUT, + KEY_WINDOW_OUTFIT, KEY_EMOTE_1, KEY_EMOTE_2, KEY_EMOTE_3, diff --git a/src/localplayer.cpp b/src/localplayer.cpp index e9bc30f2..782a461a 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -71,7 +71,10 @@ #include <cassert> #ifdef TMWSERV_SUPPORT -const short walkingKeyboardDelay = 100; +// This is shorter then it really needs to be for normal use +// But if we ever wanted to increase player speed, having this lower +// Won't hurt +const short walkingKeyboardDelay = 40; #endif LocalPlayer *player_node = NULL; @@ -193,6 +196,8 @@ void LocalPlayer::logic() mLastTarget = -1; } +#endif + if (mTarget) { if (mTarget->getType() == Being::NPC) @@ -203,13 +208,18 @@ void LocalPlayer::logic() } else { +#ifdef TMWSERV_SUPPORT + // Find whether target is in range + const int rangeX = abs(mTarget->getPosition().x - getPosition().x); + const int rangeY = abs(mTarget->getPosition().y - getPosition().y); +#else // Find whether target is in range const int rangeX = abs(mTarget->mX - mX); const int rangeY = abs(mTarget->mY - mY); +#endif const int attackRange = getAttackRange(); const int inRange = rangeX > attackRange || rangeY > attackRange ? 1 : 0; - mTarget->setTargetAnimation( mTargetCursor[inRange][mTarget->getTargetCursorSize()]); @@ -220,7 +230,6 @@ void LocalPlayer::logic() attack(mTarget, true); } } -#endif Player::logic(); } @@ -280,9 +289,7 @@ void LocalPlayer::nextStep() if (mGoingToTarget && mTarget && withinAttackRange(mTarget)) { mAction = Being::STAND; -#ifdef EATHENA_SUPPORT attack(mTarget, true); -#endif mGoingToTarget = false; mPath.clear(); return; @@ -433,9 +440,9 @@ void LocalPlayer::walk(unsigned char dir) int dScaler; // Distance to walk - // Checks our path up to 5 tiles, if a blocking tile is found + // Checks our path up to 2 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++) + for (dScaler = 1; dScaler <= 2; dScaler++) { if ( (dx || dy) && !mMap->getWalk( ((int) pos.x + (dx * dScaler)) / 32, @@ -606,7 +613,7 @@ void LocalPlayer::emote(Uint8 emotion) } #ifdef TMWSERV_SUPPORT - +/* void LocalPlayer::attack() { if (mLastAction != -1) @@ -656,16 +663,25 @@ void LocalPlayer::attack() } Net::GameServer::Player::attack(getSpriteDirection()); } - +*/ void LocalPlayer::useSpecial(int special) { Net::GameServer::Player::useSpecial(special); } -#else +#endif void LocalPlayer::attack(Being *target, bool keep) { +#ifdef TMWSERV_SUPPORT + if (mLastAction != -1) + return; + + // Can only attack when standing still + if (mAction != STAND && mAction != ATTACK) + return; +#endif + mKeepAttacking = keep; if (!target || target->getType() == Being::NPC) @@ -676,14 +692,36 @@ void LocalPlayer::attack(Being *target, bool keep) mLastTarget = -1; setTarget(target); } - +#ifdef TMWSERV_SUPPORT + Vector plaPos = this->getPosition(); + Vector tarPos = mTarget->getPosition(); + int dist_x = plaPos.x - tarPos.x; + int dist_y = plaPos.y - tarPos.y; +#else int dist_x = target->mX - mX; int dist_y = target->mY - mY; // Must be standing to attack if (mAction != STAND) return; +#endif +#ifdef TMWSERV_SUPPORT + if (abs(dist_y) >= abs(dist_x)) + { + if (dist_y < 0) + setDirection(DOWN); + else + setDirection(UP); + } + else + { + if (dist_x < 0) + setDirection(RIGHT); + else + setDirection(LEFT); + } +#else if (abs(dist_y) >= abs(dist_x)) { if (dist_y > 0) @@ -698,9 +736,14 @@ void LocalPlayer::attack(Being *target, bool keep) else setDirection(LEFT); } +#endif +#ifdef TMWSERV_SUPPORT + mLastAction = tick_time; +#else mWalkTime = tick_time; mTargetTime = tick_time; +#endif setAction(ATTACK); @@ -715,14 +758,13 @@ void LocalPlayer::attack(Being *target, bool keep) sound.playSfx("sfx/fist-swish.ogg"); } - Net::getPlayerHandler()->attack(target); - + Net::getPlayerHandler()->attack(target->getId()); +#ifdef EATHENA_SUPPORT if (!keep) stopAttack(); +#endif } -#endif // no TMWSERV_SUPPORT - void LocalPlayer::stopAttack() { if (mTarget) @@ -845,7 +887,7 @@ int LocalPlayer::getAttackRange() const ItemInfo info = weapon->getInfo(); return info.getAttackRange(); } - return 32; // unarmed range + return 48; // unarmed range #else return mAttackRange; #endif diff --git a/src/localplayer.h b/src/localplayer.h index 4a85dd75..85681e03 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -214,11 +214,9 @@ 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 + void attack(Being *target = NULL, bool keep = false); /** * Triggers whether or not to show the name as a GM name. diff --git a/src/main.cpp b/src/main.cpp index 16cbbdfe..f37f9de9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -53,7 +53,7 @@ #include "gui/serverselectdialog.h" #include "gui/setup.h" #ifdef TMWSERV_SUPPORT -#include "gui/connection.h" +#include "gui/connectiondialog.h" #include "gui/quitdialog.h" #include "gui/serverdialog.h" #endif diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp index 34a0d70a..f149f15f 100644 --- a/src/net/ea/beinghandler.cpp +++ b/src/net/ea/beinghandler.cpp @@ -65,6 +65,7 @@ BeingHandler::BeingHandler(bool enableSync): SMSG_PLAYER_MOVE_TO_ATTACK, SMSG_PLAYER_STATUS_CHANGE, SMSG_BEING_STATUS_CHANGE, + SMSG_BEING_RESURRECT, 0 }; handledMessages = _messages; @@ -260,6 +261,24 @@ void BeingHandler::handleMessage(MessageIn &msg) break; + case SMSG_BEING_RESURRECT: + // A being changed mortality status + id = msg.readInt32(); + + dstBeing = beingManager->findBeing(id); + + if (!dstBeing) + break; + + // If this is player's current target, clear it. + if (dstBeing == player_node->getTarget()) + player_node->stopAttack(); + + if (msg.readInt8() == 1) + dstBeing->setAction(Being::STAND); + + break; + case SMSG_BEING_ACTION: srcBeing = beingManager->findBeing(msg.readInt32()); dstBeing = beingManager->findBeing(msg.readInt32()); diff --git a/src/net/ea/playerhandler.cpp b/src/net/ea/playerhandler.cpp index 2d953df1..c1b7cc84 100644 --- a/src/net/ea/playerhandler.cpp +++ b/src/net/ea/playerhandler.cpp @@ -422,10 +422,10 @@ void PlayerHandler::handleMessage(MessageIn &msg) } } -void PlayerHandler::attack(Being *being) +void PlayerHandler::attack(int id) { MessageOut outMsg(CMSG_PLAYER_ATTACK); - outMsg.writeInt32(being->getId()); + outMsg.writeInt32(id); outMsg.writeInt8(0); } diff --git a/src/net/ea/playerhandler.h b/src/net/ea/playerhandler.h index 808cd0ec..5dbc171b 100644 --- a/src/net/ea/playerhandler.h +++ b/src/net/ea/playerhandler.h @@ -35,7 +35,7 @@ class PlayerHandler : public MessageHandler, public Net::PlayerHandler void handleMessage(MessageIn &msg); - void attack(Being *being); + void attack(int id); void emote(int emoteId); diff --git a/src/net/ea/protocol.h b/src/net/ea/protocol.h index f8caf4c1..b3759946 100644 --- a/src/net/ea/protocol.h +++ b/src/net/ea/protocol.h @@ -87,6 +87,7 @@ static const int STORAGE_OFFSET = 1; #define SMSG_BEING_CHAT 0x008d /**< A being talks */ #define SMSG_BEING_NAME_RESPONSE 0x0095 /**< Has to be requested */ #define SMSG_BEING_CHANGE_DIRECTION 0x009c +#define SMSG_BEING_RESURRECT 0x0148 #define SMSG_PLAYER_STATUS_CHANGE 0x0119 #define SMSG_BEING_STATUS_CHANGE 0x0196 diff --git a/src/net/playerhandler.h b/src/net/playerhandler.h index df49756d..163b48f3 100644 --- a/src/net/playerhandler.h +++ b/src/net/playerhandler.h @@ -31,7 +31,7 @@ namespace Net { class PlayerHandler { public: - virtual void attack(Being *being) = 0; + virtual void attack(int id) = 0; virtual void emote(int emoteId) = 0; diff --git a/src/net/tmwserv/beinghandler.cpp b/src/net/tmwserv/beinghandler.cpp index 1ec13800..99491203 100644 --- a/src/net/tmwserv/beinghandler.cpp +++ b/src/net/tmwserv/beinghandler.cpp @@ -191,11 +191,6 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) 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; @@ -235,7 +230,7 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) // 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 && + abs(being->getPixelY() - dy) < 16 && (dx != being->getDestination().x && dy != being->getDestination().y)) { being->setDestination(being->getPixelX(),being->getPixelY()); @@ -258,7 +253,7 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) } else { - being->adjustCourse(sx, sy, dx, dy); + being->setDestination(sx, sy, dx, dy); } } } diff --git a/src/net/tmwserv/gameserver/player.cpp b/src/net/tmwserv/gameserver/player.cpp index 3f05c954..93853681 100644 --- a/src/net/tmwserv/gameserver/player.cpp +++ b/src/net/tmwserv/gameserver/player.cpp @@ -58,13 +58,6 @@ void Net::GameServer::Player::moveItem(int oldSlot, int newSlot, int amount) 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); diff --git a/src/net/tmwserv/gameserver/player.h b/src/net/tmwserv/gameserver/player.h index eddd9102..24b25dc7 100644 --- a/src/net/tmwserv/gameserver/player.h +++ b/src/net/tmwserv/gameserver/player.h @@ -43,7 +43,6 @@ namespace Net void walk(int x, int y); void pickUp(int x, int y); void moveItem(int oldSlot, int newSlot, int amount); - void attack(int direction); void useSpecial(int special); void requestTrade(int id); void acceptTrade(bool accept); diff --git a/src/net/tmwserv/playerhandler.cpp b/src/net/tmwserv/playerhandler.cpp index 931e4294..b378817f 100644 --- a/src/net/tmwserv/playerhandler.cpp +++ b/src/net/tmwserv/playerhandler.cpp @@ -332,9 +332,11 @@ void PlayerHandler::handleMapChangeMessage(MessageIn &msg) viewport->scrollBy(scrollOffsetX, scrollOffsetY); } -void PlayerHandler::attack(Being *being) +void PlayerHandler::attack(int id) { - // TODO + MessageOut msg(PGMSG_ATTACK); + msg.writeInt16(id); + Net::GameServer::connection->send(msg); } void PlayerHandler::emote(int emoteId) @@ -371,9 +373,6 @@ void PlayerHandler::setDestination(int x, int y, int /* direction */) msg.writeInt16(x); msg.writeInt16(y); Net::GameServer::connection->send(msg); - - // Debugging fire burst - effectManager->trigger(15, x, y); } void PlayerHandler::changeAction(Being::Action action) diff --git a/src/net/tmwserv/playerhandler.h b/src/net/tmwserv/playerhandler.h index 13ae8f39..164d30ae 100644 --- a/src/net/tmwserv/playerhandler.h +++ b/src/net/tmwserv/playerhandler.h @@ -34,7 +34,7 @@ class PlayerHandler : public MessageHandler, public Net::PlayerHandler void handleMessage(MessageIn &msg); - void attack(Being *being); + void attack(int id); void emote(int emoteId); diff --git a/src/net/tmwserv/protocol.h b/src/net/tmwserv/protocol.h index 7fa3b372..6124263a 100644 --- a/src/net/tmwserv/protocol.h +++ b/src/net/tmwserv/protocol.h @@ -106,7 +106,7 @@ enum { 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_ATTACK = 0x0290, // W being id PGMSG_USE_SPECIAL = 0x0292, // B specialID GPMSG_BEING_ATTACK = 0x0291, // W being id PGMSG_SAY = 0x02A0, // S text @@ -162,9 +162,11 @@ enum { 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 + PCMSG_GUILD_KICK_MEMBER = 0x0370, // W guild, S name + CPMSG_GUILD_KICK_MEMBER_RESPONSE = 0x0371, // 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 + CPMSG_GUILD_INVITED = 0x0388, // S char name, S guild name, W id + CPMSG_GUILD_REJOIN = 0x0389, // S name, W guild, W rights, W channel, S announce // Party PCMSG_PARTY_INVITE = 0x03A0, // S name diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 9a17eb3a..b25f754f 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -215,6 +215,10 @@ void ItemDB::load() } } + if (weaponType > 0) + if (attackRange == 0) + logger->log("ItemDB: Missing attack range from weapon %i!", id); + #define CHECK_PARAM(param, error_value) \ if (param == error_value) \ logger->log("ItemDB: Missing " #param " attribute for item %i!",id) |