From 7c34adebb068549ca6a56bdf1b211398a0b1de11 Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Sun, 22 May 2011 00:23:08 +0300 Subject: Allow show equipment from other players from context menu "show items". Also allow undress separate items from players locally. --- src/actorspritemanager.cpp | 8 ++++- src/being.cpp | 80 ++++++++++++++++++++++++++++++++++++++++- src/being.h | 28 +++++++++++++++ src/game.cpp | 7 +++- src/gui/equipmentwindow.cpp | 73 ++++++++++++++++++++++++++++++++----- src/gui/equipmentwindow.h | 15 +++++++- src/gui/popupmenu.cpp | 48 ++++++++++++++++++++++++- src/gui/popupmenu.h | 2 ++ src/gui/viewport.cpp | 5 +++ src/gui/viewport.h | 2 ++ src/net/tmwa/inventoryhandler.h | 6 ++-- 11 files changed, 256 insertions(+), 18 deletions(-) diff --git a/src/actorspritemanager.cpp b/src/actorspritemanager.cpp index e7c28fd1e..9be75e0db 100644 --- a/src/actorspritemanager.cpp +++ b/src/actorspritemanager.cpp @@ -30,6 +30,7 @@ #include "playerrelations.h" #include "gui/chatwindow.h" +#include "gui/equipmentwindow.h" #include "gui/killstats.h" #include "gui/skilldialog.h" #include "gui/socialwindow.h" @@ -578,7 +579,12 @@ void ActorSpriteManager::logic() it != it_end; ++it) { if ((*it) && (*it)->getType() == Being::PLAYER) - static_cast(*it)->addToCache(); + { + Being *being = static_cast(*it); + being->addToCache(); + if (beingEquipmentWindow) + beingEquipmentWindow->resetBeing(being); + } if (player_node) { if (player_node->getTarget() == *it) diff --git a/src/being.cpp b/src/being.cpp index 6c0d3d679..df698cf30 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -29,6 +29,7 @@ #include "effectmanager.h" #include "graphics.h" #include "guild.h" +#include "item.h" #include "localplayer.h" #include "log.h" #include "map.h" @@ -43,6 +44,7 @@ #include "gui/buydialog.h" #include "gui/buyselldialog.h" +#include "gui/equipmentwindow.h" #include "gui/gui.h" #include "gui/npcdialog.h" #include "gui/npcpostdialog.h" @@ -55,6 +57,7 @@ #include "net/charhandler.h" #include "net/gamehandler.h" +#include "net/inventoryhandler.h" #include "net/net.h" #include "net/npchandler.h" #include "net/playerhandler.h" @@ -1574,6 +1577,9 @@ void Being::setSprite(unsigned int slot, int id, std::string color, if (slot >= mSpriteColors.size()) mSpriteColors.resize(slot + 1, ""); + if (slot >= mSpriteColorsIds.size()) + mSpriteColorsIds.resize(slot + 1, 1); + // id = 0 means unequip if (id == 0) { @@ -1613,7 +1619,10 @@ void Being::setSprite(unsigned int slot, int id, std::string color, { mSpriteIDs[slot] = id; mSpriteColors[slot] = color; + mSpriteColorsIds[slot] = colorId; recalcSpritesOrder(); + if (beingEquipmentWindow) + beingEquipmentWindow->updateBeing(this); } } @@ -2179,4 +2188,73 @@ void Being::updateHit(int amount) if (amount != mCriticalHit && (!mMaxHit || amount > mMaxHit)) mMaxHit = amount; } -} \ No newline at end of file +} + +Equipment *Being::getEquipment() +{ + Equipment *eq = new Equipment(); + Equipment::Backend *bk = new BeingEquipBackend(this); + eq->setBackend(bk); + return eq; +} + +void Being::undressItemById(int id) +{ + int sz = mSpriteIDs.size(); + + for (int f = 0; f < sz; f ++) + { + if (id == mSpriteIDs[f]) + { + setSprite(f, 0); + break; + } + } +} + +BeingEquipBackend::BeingEquipBackend(Being *being): + mBeing(being) +{ + memset(mEquipment, 0, sizeof(mEquipment)); + if (being) + { + int sz = being->mSpriteIDs.size(); + + for (int f = 0; f < sz; f ++) + { + int idx = Net::getInventoryHandler()->convertFromServerSlot(f); + int id = being->mSpriteIDs[f]; + if (id > 0 && idx >= 0 && idx < EQUIPMENT_SIZE) + { + mEquipment[idx] = new Item(id, 1, 0, + being->mSpriteColorsIds[f], true, true); + } + } + } +} + +BeingEquipBackend::~BeingEquipBackend() +{ + clear(); +} + +void BeingEquipBackend::clear() +{ + for (int i = 0; i < EQUIPMENT_SIZE; i++) + { + delete mEquipment[i]; + mEquipment[i] = 0; + } +} + +void BeingEquipBackend::setEquipment(int index, Item *item) +{ + mEquipment[index] = item; +} + +Item *BeingEquipBackend::getEquipment(int index) const +{ + if (index < 0 || index >= EQUIPMENT_SIZE) + return 0; + return mEquipment[index]; +} diff --git a/src/being.h b/src/being.h index 199cb4dc2..91cafa69a 100644 --- a/src/being.h +++ b/src/being.h @@ -31,6 +31,7 @@ #include "actorsprite.h" #include "configlistener.h" +#include "equipment.h" #include "map.h" #include "particlecontainer.h" #include "position.h" @@ -53,9 +54,11 @@ class AnimatedSprite; class BeingCacheEntry; +class Being; class BeingInfo; class FlashText; class Guild; +class Inventory; class ItemInfo; class Item; class Particle; @@ -74,9 +77,29 @@ enum Gender GENDER_UNSPECIFIED = 2 }; +class BeingEquipBackend : public Equipment::Backend +{ + public: + BeingEquipBackend(Being *being); + + virtual ~BeingEquipBackend(); + + Item *getEquipment(int index) const; + + void clear(); + + void setEquipment(int index, Item *item); + + private: + Item *mEquipment[EQUIPMENT_SIZE]; + Being *mBeing; +}; + class Being : public ActorSprite, public ConfigListener { public: + friend class BeingEquipBackend; + /** * Action the being is currently performing * WARNING: Has to be in sync with the same enum in the Being class @@ -687,6 +710,10 @@ class Being : public ActorSprite, public ConfigListener void updateHit(int amount); + Equipment *getEquipment(); + + void undressItemById(int id); + protected: /** * Sets the new path for this being. @@ -747,6 +774,7 @@ class Being : public ActorSprite, public ConfigListener std::vector mSpriteIDs; std::vector mSpriteColors; + std::vector mSpriteColorsIds; Gender mGender; // Character guild information diff --git a/src/game.cpp b/src/game.cpp index 999a89664..82a77c0bb 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -126,6 +126,7 @@ ShopWindow *shopWindow = NULL; SkillDialog *skillDialog = NULL; Minimap *minimap = NULL; EquipmentWindow *equipmentWindow = NULL; +EquipmentWindow *beingEquipmentWindow = NULL; TradeWindow *tradeWindow = NULL; HelpWindow *helpWindow = NULL; DebugWindow *debugWindow = NULL; @@ -189,7 +190,10 @@ static void createGuiWindows() // Create dialogs chatWindow = new ChatWindow; tradeWindow = new TradeWindow; - equipmentWindow = new EquipmentWindow(PlayerInfo::getEquipment()); + equipmentWindow = new EquipmentWindow(PlayerInfo::getEquipment(), + player_node); + beingEquipmentWindow = new EquipmentWindow(0, 0, true); + beingEquipmentWindow->setVisible(false); statusWindow = new StatusWindow; miniStatusWindow = new MiniStatusWindow; inventoryWindow = new InventoryWindow(PlayerInfo::getInventory()); @@ -292,6 +296,7 @@ static void destroyGuiWindows() del_0(skillDialog) del_0(minimap) del_0(equipmentWindow) + del_0(beingEquipmentWindow) del_0(tradeWindow) del_0(helpWindow) del_0(debugWindow) diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index d5bfa4ddc..2a0ad96bb 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -20,15 +20,17 @@ * along with this program. If not, see . */ +#include "gui/equipmentwindow.h" + #include "gui/widgets/button.h" +#include "being.h" #include "equipment.h" #include "graphics.h" #include "inventory.h" #include "item.h" #include "localplayer.h" -#include "gui/equipmentwindow.h" #include "gui/itempopup.h" #include "gui/theme.h" #include "gui/setup.h" @@ -69,21 +71,28 @@ static const int boxPosition[][2] = { 129, 123 }, // EQUIP_EVOL_RING2_SLOT }; -EquipmentWindow::EquipmentWindow(Equipment *equipment): +EquipmentWindow::EquipmentWindow(Equipment *equipment, Being *being, + bool foring): Window(_("Equipment")), mEquipment(equipment), - mSelected(-1) + mSelected(-1), + mForing(foring) { + mBeing = being; mItemPopup = new ItemPopup; if (setupWindow) setupWindow->registerWindowForReset(this); // Control that shows the Player - PlayerBox *playerBox = new PlayerBox; - playerBox->setDimension(gcn::Rectangle(50, 80, 74, 168)); - playerBox->setPlayer(player_node); + mPlayerBox = new PlayerBox; + mPlayerBox->setDimension(gcn::Rectangle(50, 80, 74, 168)); + mPlayerBox->setPlayer(being); + + if (foring) + setWindowName("Being equipment"); + else + setWindowName("Equipment"); - setWindowName("Equipment"); setCloseButton(true); setSaveVisible(true); setDefaultSize(180, 345, ImageRect::CENTER); @@ -95,7 +104,7 @@ EquipmentWindow::EquipmentWindow(Equipment *equipment): area.height - mUnequip->getHeight() - 5); mUnequip->setEnabled(false); - add(playerBox); + add(mPlayerBox); add(mUnequip); for (int i = 0; i < Equipment::EQUIP_VECTOREND; i++) @@ -138,6 +147,9 @@ void EquipmentWindow::draw(gcn::Graphics *graphics) g->drawRectangle(gcn::Rectangle(mEquipBox[i].posX, mEquipBox[i].posY, BOX_WIDTH, BOX_HEIGHT)); + if (!mEquipment) + continue; + Item *item = mEquipment->getEquipment(i); if (item) { @@ -165,6 +177,9 @@ void EquipmentWindow::draw(gcn::Graphics *graphics) void EquipmentWindow::action(const gcn::ActionEvent &event) { + if (!mEquipment) + return; + if (event.getId() == "unequip" && mSelected > -1) { Item *item = mEquipment->getEquipment(mSelected); @@ -175,6 +190,9 @@ void EquipmentWindow::action(const gcn::ActionEvent &event) Item *EquipmentWindow::getItem(int x, int y) const { + if (!mEquipment) + return 0; + for (int i = 0; i < Equipment::EQUIP_VECTOREND; i++) { gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY, @@ -190,11 +208,16 @@ void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent) { Window::mousePressed(mouseEvent); + if (!mEquipment) + return; + const int x = mouseEvent.getX(); const int y = mouseEvent.getY(); if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) { + if (mForing) + return; // Checks if any of the presses were in the equip boxes. for (int i = 0; i < Equipment::EQUIP_VECTOREND; i++) { @@ -216,7 +239,12 @@ void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent) const int mx = x + getX(); const int my = y + getY(); if (viewport) - viewport->showPopup(this, mx, my, item, true); + { + if (mForing) + viewport->showUndressPopup(mx, my, mBeing, item); + else + viewport->showPopup(this, mx, my, item, true); + } } } } @@ -259,3 +287,30 @@ void EquipmentWindow::setSelected(int index) if (mUnequip) mUnequip->setEnabled(mSelected != -1); } + +void EquipmentWindow::setBeing(Being *being) +{ + mPlayerBox->setPlayer(being); + mBeing = being; + if (!being) + { + delete mEquipment; + mEquipment = 0; + return; + } + mEquipment = being->getEquipment(); + if (!mEquipment) + return; +} + +void EquipmentWindow::updateBeing(Being *being) +{ + if (being == mBeing) + setBeing(being); +} + +void EquipmentWindow::resetBeing(Being *being) +{ + if (being == mBeing) + setBeing(0); +} diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h index ccb0332df..75118707d 100644 --- a/src/gui/equipmentwindow.h +++ b/src/gui/equipmentwindow.h @@ -36,9 +36,11 @@ #define _UNUSED_ #endif +class Being; class Inventory; class Item; class ItemPopup; +class PlayerBox; /** * Equipment dialog. @@ -51,7 +53,8 @@ class EquipmentWindow : public Window, public gcn::ActionListener /** * Constructor. */ - EquipmentWindow(Equipment *equipment); + EquipmentWindow(Equipment *equipment, Being *being, + bool mCloseOnHide = false); /** * Destructor. @@ -70,6 +73,12 @@ class EquipmentWindow : public Window, public gcn::ActionListener Item* getEquipment(int i) { return mEquipment ? mEquipment->getEquipment(i) : 0; } + void setBeing(Being *being); + + void updateBeing(Being *being); + + void resetBeing(Being *being); + private: void mouseExited(gcn::MouseEvent &event); void mouseMoved(gcn::MouseEvent &event); @@ -92,11 +101,15 @@ class EquipmentWindow : public Window, public gcn::ActionListener EquipBox mEquipBox[Equipment::EQUIP_VECTOREND]; /**addRow(strprintf("@@nuke|%s@@", _("Nuke"))); mBrowserBox->addRow(strprintf("@@move|%s@@", _("Move"))); + mBrowserBox->addRow(strprintf("@@items|%s@@", + _("Show Items"))); mBrowserBox->addRow(strprintf("@@undress|%s@@", _("Undress"))); if (player_relations.getDefault() & PlayerRelation::TRADE) @@ -633,6 +636,7 @@ void PopupMenu::showChatPopup(int x, int y, ChatTab *tab) mBrowserBox->addRow(strprintf("@@follow|%s@@", _("Follow"))); mBrowserBox->addRow(strprintf("@@imitation|%s@@", _("Imitation"))); mBrowserBox->addRow(strprintf("@@move|%s@@", _("Move"))); + mBrowserBox->addRow(strprintf("@@items|%s@@", _("Show Items"))); mBrowserBox->addRow(strprintf("@@undress|%s@@", _("Undress"))); if (player_relations.getDefault() & PlayerRelation::TRADE) @@ -1380,7 +1384,29 @@ void PopupMenu::handleLink(const std::string &link, } else if (link == "reset yellow") { - player_node->resetYellowBar(); + if (player_node) + player_node->resetYellowBar(); + } + else if (link == "items" && being) + { + if (being == player_node) + { + if (equipmentWindow && !equipmentWindow->isVisible()) + equipmentWindow->setVisible(true); + } + else + { + Equipment *eq = being->getEquipment(); + if (eq && beingEquipmentWindow) + { + beingEquipmentWindow->setBeing(being); + beingEquipmentWindow->setVisible(true); + } + } + } + else if (link == "undress item" && being && mItemId) + { + being->undressItemById(mItemId); } else if (link == "guild-pos" && !mNick.empty()) { @@ -1788,6 +1814,26 @@ void PopupMenu::showAttackMonsterPopup(int x, int y, std::string name, showPopup(x, y); } +void PopupMenu::showUndressPopup(int x, int y, Being *being, Item *item) +{ + if (!being || !item) + return; + + mBeingId = being->getId(); + mItem = item; + mItemId = item->getId(); + + mBrowserBox->clearRows(); + + mBrowserBox->addRow(strprintf("@@undress item|%s@@", _("Undress"))); + + mBrowserBox->addRow("##3---"); + mBrowserBox->addRow(strprintf("@@cancel|%s@@", _("Cancel"))); + + showPopup(x, y); + +} + void PopupMenu::showPopup(int x, int y) { setContentSize(mBrowserBox->getWidth() + 8, mBrowserBox->getHeight() + 8); diff --git a/src/gui/popupmenu.h b/src/gui/popupmenu.h index 208652083..e16a9fb4f 100644 --- a/src/gui/popupmenu.h +++ b/src/gui/popupmenu.h @@ -120,6 +120,8 @@ class PopupMenu : public Popup, public LinkHandler void showAttackMonsterPopup(int x, int y, std::string name, int type); + void showUndressPopup(int x, int y, Being *being, Item *item); + /** * Shows the related popup menu when right click on the chat * at the specified mouse coordinates. diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 1f2d06894..09fc7d24c 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -649,6 +649,11 @@ void Viewport::showAttackMonsterPopup(std::string name, int type) name, type); } +void Viewport::showUndressPopup(int x, int y, Being *being, Item *item) +{ + mPopupMenu->showUndressPopup(x, y, being, item); +} + void Viewport::closePopupMenu() { if (mPopupMenu) diff --git a/src/gui/viewport.h b/src/gui/viewport.h index d3a3bfe4b..7cd12365b 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -173,6 +173,8 @@ class Viewport : public WindowContainer, public gcn::MouseListener, */ void showChatPopup(ChatTab *tab); + void showUndressPopup(int x, int y, Being *being, Item *item); + /** * Closes the popup menu. Needed for when the player dies or switching * maps. diff --git a/src/net/tmwa/inventoryhandler.h b/src/net/tmwa/inventoryhandler.h index 5f674eab0..c6c680b13 100644 --- a/src/net/tmwa/inventoryhandler.h +++ b/src/net/tmwa/inventoryhandler.h @@ -25,6 +25,7 @@ #include "equipment.h" #include "inventory.h" +#include "log.h" #include "playerinfo.h" #include "gui/inventorywindow.h" @@ -58,9 +59,8 @@ class EquipBackend : public Equipment::Backend { int invyIndex = mEquipment[index]; if (invyIndex == -1) - { return NULL; - } + return PlayerInfo::getInventory()->getItem(invyIndex); } @@ -72,9 +72,7 @@ class EquipBackend : public Equipment::Backend { Item* item = PlayerInfo::getInventory()->getItem(i); if (item) - { item->setEquipped(false); - } } mEquipment[i] = -1; -- cgit v1.2.3-70-g09d2