diff options
author | Jared Adams <jaxad0127@gmail.com> | 2010-02-13 15:04:58 -0700 |
---|---|---|
committer | Jared Adams <jaxad0127@gmail.com> | 2010-02-13 15:08:54 -0700 |
commit | 8bc425ff48b7a874ca0fb9d2285044c75f3010ab (patch) | |
tree | 5904c7f53cde9ffbe7df2a63f088561141e06b66 | |
parent | 28c9cec5d39c9a1b98694eba9a28281cf111e34a (diff) | |
download | mana-8bc425ff48b7a874ca0fb9d2285044c75f3010ab.tar.gz mana-8bc425ff48b7a874ca0fb9d2285044c75f3010ab.tar.bz2 mana-8bc425ff48b7a874ca0fb9d2285044c75f3010ab.tar.xz mana-8bc425ff48b7a874ca0fb9d2285044c75f3010ab.zip |
Make NPC dialogs instance instead of global
This change allows players to talk to multiple NPCs at a time (if the server agrees). Manaserv's netcode allows multiple commerce instances too. eAthena's is limited to one commerce instance, due to protocol limitations.
-rw-r--r-- | src/game.cpp | 63 | ||||
-rw-r--r-- | src/gui/buy.cpp | 39 | ||||
-rw-r--r-- | src/gui/buy.h | 21 | ||||
-rw-r--r-- | src/gui/buysell.cpp | 44 | ||||
-rw-r--r-- | src/gui/buysell.h | 23 | ||||
-rw-r--r-- | src/gui/npcdialog.cpp | 74 | ||||
-rw-r--r-- | src/gui/npcdialog.h | 35 | ||||
-rw-r--r-- | src/gui/npcpostdialog.cpp | 40 | ||||
-rw-r--r-- | src/gui/npcpostdialog.h | 22 | ||||
-rw-r--r-- | src/gui/popupmenu.cpp | 4 | ||||
-rw-r--r-- | src/gui/sell.cpp | 39 | ||||
-rw-r--r-- | src/gui/sell.h | 22 | ||||
-rw-r--r-- | src/gui/viewport.cpp | 2 | ||||
-rw-r--r-- | src/gui/widgets/window.h | 2 | ||||
-rw-r--r-- | src/net/ea/buysellhandler.cpp | 30 | ||||
-rw-r--r-- | src/net/ea/buysellhandler.h | 6 | ||||
-rw-r--r-- | src/net/ea/npchandler.cpp | 97 | ||||
-rw-r--r-- | src/net/ea/npchandler.h | 11 | ||||
-rw-r--r-- | src/net/ea/playerhandler.cpp | 10 | ||||
-rw-r--r-- | src/net/manaserv/buysellhandler.cpp | 35 | ||||
-rw-r--r-- | src/net/manaserv/npchandler.cpp | 52 | ||||
-rw-r--r-- | src/net/manaserv/npchandler.h | 11 | ||||
-rw-r--r-- | src/net/manaserv/playerhandler.cpp | 43 | ||||
-rw-r--r-- | src/npc.cpp | 11 | ||||
-rw-r--r-- | src/npc.h | 2 |
25 files changed, 436 insertions, 302 deletions
diff --git a/src/game.cpp b/src/game.cpp index 56a25faf..62e7c515 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -41,8 +41,6 @@ #include "playerrelations.h" #include "sound.h" -#include "gui/buy.h" -#include "gui/buysell.h" #include "gui/chat.h" #include "gui/confirmdialog.h" #include "gui/debugwindow.h" @@ -59,7 +57,6 @@ #include "gui/outfitwindow.h" #include "gui/quitdialog.h" #include "gui/sdlinput.h" -#include "gui/sell.h" #include "gui/setup.h" #include "gui/socialwindow.h" #include "gui/specialswindow.h" @@ -112,13 +109,8 @@ OkDialog *disconnectedDialog = NULL; ChatWindow *chatWindow; StatusWindow *statusWindow; MiniStatusWindow *miniStatusWindow; -BuyDialog *buyDialog; -SellDialog *sellDialog; -BuySellDialog *buySellDialog; InventoryWindow *inventoryWindow; SkillDialog *skillDialog; -NpcDialog *npcDialog; -NpcPostDialog *npcPostDialog; StorageWindow *storageWindow; Minimap *minimap; EquipmentWindow *equipmentWindow; @@ -213,13 +205,8 @@ static void createGuiWindows() // Create dialogs chatWindow = new ChatWindow; - buyDialog = new BuyDialog; - sellDialog = new SellDialog; tradeWindow = new TradeWindow; - buySellDialog = new BuySellDialog; equipmentWindow = new EquipmentWindow(player_node->mEquipment.get()); - npcDialog = new NpcDialog; - npcPostDialog = new NpcPostDialog; storageWindow = new StorageWindow; statusWindow = new StatusWindow; miniStatusWindow = new MiniStatusWindow; @@ -259,12 +246,7 @@ static void destroyGuiWindows() del_0(chatWindow) del_0(statusWindow) del_0(miniStatusWindow) - del_0(buyDialog) - del_0(sellDialog) - del_0(buySellDialog) del_0(inventoryWindow) - del_0(npcDialog) - del_0(npcPostDialog) del_0(skillDialog) del_0(minimap) del_0(equipmentWindow) @@ -523,7 +505,7 @@ void Game::handleInput() // send straight to gui for certain windows if (quitDialog || TextDialog::isActive() || - npcPostDialog->isVisible()) + NpcPostDialog::isActive()) { try { @@ -553,37 +535,29 @@ void Game::handleInput() if (!chatWindow->isInputFocused() && !gui->getFocusHandler()->getModalFocused()) { + NpcDialog *dialog = NpcDialog::getActive(); if (keyboard.isKeyActive(keyboard.KEY_OK)) { // Close the Browser if opened - if (helpWindow->isVisible() && - keyboard.isKeyActive(keyboard.KEY_OK)) + if (helpWindow->isVisible()) helpWindow->setVisible(false); // Close the config window, cancelling changes if opened - else if (setupWindow->isVisible() && - keyboard.isKeyActive(keyboard.KEY_OK)) + else if (setupWindow->isVisible()) setupWindow->action(gcn::ActionEvent(NULL, "cancel")); - else if (npcDialog->isVisible() && - keyboard.isKeyActive(keyboard.KEY_OK)) - npcDialog->action(gcn::ActionEvent(NULL, "ok")); - /* - else if (guildWindow->isVisible()) - { - // TODO: Check if a dialog is open and close it if so - } - */ + else if (dialog) + dialog->action(gcn::ActionEvent(NULL, "ok")); } if (keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT)) { if (chatWindow->requestChatFocus()) used = true; } - if (npcDialog->isVisible()) + if (dialog) { if (keyboard.isKeyActive(keyboard.KEY_MOVE_UP)) - npcDialog->move(1); + dialog->move(1); else if (keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN)) - npcDialog->move(-1); + dialog->move(-1); } } @@ -705,8 +679,8 @@ void Game::handleInput() default: break; } - if (keyboard.isEnabled() && - !chatWindow->isInputFocused() && !npcDialog->isInputFocused()) + if (keyboard.isEnabled() && !chatWindow->isInputFocused() && + !NpcDialog::isAnyInputFocused()) { const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); @@ -888,7 +862,7 @@ void Game::handleInput() return; // Moving player around - if (player_node->isAlive() && current_npc == 0 && + if (player_node->isAlive() && !NPC::isTalking() && !chatWindow->isInputFocused() && !quitDialog) { // Get the state of the keyboard keys @@ -1006,15 +980,12 @@ void Game::handleInput() // Talk to the nearest NPC if 't' pressed if ( keyboard.isKeyActive(keyboard.KEY_TALK) ) { - if (!npcDialog->isVisible()) - { - Being *target = player_node->getTarget(); + Being *target = player_node->getTarget(); - if (target) - { - if (target->getType() == Being::NPC) - dynamic_cast<NPC*>(target)->talk(); - } + if (target) + { + if (target->getType() == Being::NPC) + dynamic_cast<NPC*>(target)->talk(); } } diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp index bc58ef09..71589374 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -43,12 +43,14 @@ #include "utils/gettext.h" #include "utils/stringutils.h" -BuyDialog::BuyDialog(): +BuyDialog::DialogList BuyDialog::instances; + +BuyDialog::BuyDialog(int npcId): Window(_("Buy")), - mMoney(0), mAmountItems(0), mMaxItems(0) + mNpcId(npcId), mMoney(0), mAmountItems(0), mMaxItems(0) { setWindowName("Buy"); - setupWindow->registerWindowForReset(this); + //setupWindow->registerWindowForReset(this); setResizable(true); setCloseButton(true); setMinWidth(260); @@ -107,11 +109,16 @@ BuyDialog::BuyDialog(): center(); loadWindowState(); + + instances.push_back(this); + setVisible(true); } BuyDialog::~BuyDialog() { delete mShopItems; + + instances.remove(this); } void BuyDialog::setMoney(int amount) @@ -186,7 +193,7 @@ void BuyDialog::action(const gcn::ActionEvent &event) else if (event.getId() == "buy" && mAmountItems > 0 && mAmountItems <= mMaxItems) { - Net::getNpcHandler()->buyItem(current_npc, + Net::getNpcHandler()->buyItem(mNpcId, mShopItems->at(selectedItem)->getId(), mAmountItems); @@ -251,23 +258,27 @@ void BuyDialog::updateButtonsAndLabels() Units::formatCurrency(mMoney - price).c_str())); } -void BuyDialog::logic() -{ - Window::logic(); - - if (!current_npc) setVisible(false); -} - void BuyDialog::setVisible(bool visible) { Window::setVisible(visible); if (visible) + { mShopItemList->requestFocus(); + } + else + { + scheduleDelete(); + } } -void BuyDialog::close() +void BuyDialog::closeAll() { - setVisible(false); - current_npc = 0; + DialogList::iterator it = instances.begin(); + DialogList::iterator it_end = instances.end(); + + for (; it != it_end; it++) + { + (*it)->close(); + } } diff --git a/src/gui/buy.h b/src/gui/buy.h index 68854a82..d44d63d2 100644 --- a/src/gui/buy.h +++ b/src/gui/buy.h @@ -47,7 +47,7 @@ class BuyDialog : public Window, public gcn::ActionListener, * * @see Window::Window */ - BuyDialog(); + BuyDialog(int npcId); /** * Destructor @@ -95,21 +95,26 @@ class BuyDialog : public Window, public gcn::ActionListener, void updateButtonsAndLabels(); /** - * Check for current NPC + * Sets the visibility of this window. */ - void logic(); + void setVisible(bool visible); /** - * Sets the visibility of this window. + * Returns true if any instances exist. */ - void setVisible(bool visible); + static bool isActive() { return instances.size() > 0; } /** - * Closes the Buy Window, as well as resetting the current npc. + * Closes all instances. */ - void close(); + static void closeAll(); private: + typedef std::list<BuyDialog*> DialogList; + static DialogList instances; + + int mNpcId; + gcn::Button *mBuyButton; gcn::Button *mQuitButton; gcn::Button *mAddMaxButton; @@ -128,6 +133,4 @@ class BuyDialog : public Window, public gcn::ActionListener, int mMaxItems; }; -extern BuyDialog *buyDialog; - #endif diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp index 1258e1d5..8a149a2d 100644 --- a/src/gui/buysell.cpp +++ b/src/gui/buysell.cpp @@ -32,12 +32,16 @@ #include "utils/gettext.h" -BuySellDialog::BuySellDialog(): +BuySellDialog::DialogList BuySellDialog::instances; + +BuySellDialog::BuySellDialog(int npcId): Window(_("Shop")), + mNpcId(npcId), mBuyButton(0) { setWindowName("BuySell"); - setupWindow->registerWindowForReset(this); + //setupWindow->registerWindowForReset(this); + setCloseButton(true); static const char *buttonNames[] = { N_("Buy"), N_("Sell"), N_("Cancel"), 0 @@ -60,14 +64,14 @@ BuySellDialog::BuySellDialog(): center(); setDefaultSize(); loadWindowState(); + + instances.push_back(this); + setVisible(true); } -void BuySellDialog::logic() +BuySellDialog::~BuySellDialog() { - Window::logic(); - - if (isVisible() && !current_npc) - setVisible(false); + instances.remove(this); } void BuySellDialog::setVisible(bool visible) @@ -75,24 +79,36 @@ void BuySellDialog::setVisible(bool visible) Window::setVisible(visible); if (visible) + { mBuyButton->requestFocus(); + } + else + { + scheduleDelete(); + } } void BuySellDialog::action(const gcn::ActionEvent &event) { - setVisible(false); - if (event.getId() == "Buy") { - Net::getNpcHandler()->buy(current_npc); + Net::getNpcHandler()->buy(mNpcId); } else if (event.getId() == "Sell") { - Net::getNpcHandler()->sell(current_npc); + Net::getNpcHandler()->sell(mNpcId); } - else if (event.getId() == "Cancel") + + close(); +} + +void BuySellDialog::closeAll() +{ + DialogList::iterator it = instances.begin(); + DialogList::iterator it_end = instances.end(); + + for (; it != it_end; it++) { - current_npc = 0; - return; + (*it)->close(); } } diff --git a/src/gui/buysell.h b/src/gui/buysell.h index 0294ad18..33314420 100644 --- a/src/gui/buysell.h +++ b/src/gui/buysell.h @@ -40,12 +40,9 @@ class BuySellDialog : public Window, public gcn::ActionListener * * @see Window::Window */ - BuySellDialog(); + BuySellDialog(int npcId); - /** - * Check for current NPC - */ - void logic(); + ~BuySellDialog(); void setVisible(bool visible); @@ -54,10 +51,22 @@ class BuySellDialog : public Window, public gcn::ActionListener */ void action(const gcn::ActionEvent &event); + /** + * Returns true if any instances exist. + */ + static bool isActive() { return instances.size() > 0; } + + /** + * Closes all instances. + */ + static void closeAll(); + private: + typedef std::list<BuySellDialog*> DialogList; + static DialogList instances; + + int mNpcId; gcn::Button *mBuyButton; }; -extern BuySellDialog *buySellDialog; - #endif diff --git a/src/gui/npcdialog.cpp b/src/gui/npcdialog.cpp index ae96c352..f1b671b1 100644 --- a/src/gui/npcdialog.cpp +++ b/src/gui/npcdialog.cpp @@ -46,9 +46,11 @@ #define CAPTION_CLOSE _("Close") #define CAPTION_SUBMIT _("Submit") -NpcDialog::NpcDialog() +NpcDialog::DialogList NpcDialog::instances; + +NpcDialog::NpcDialog(int npcId) : Window(_("NPC")), - mNpcId(0), + mNpcId(npcId), mDefaultInt(0), mInputState(NPC_INPUT_NONE), mActionState(NPC_ACTION_WAIT) @@ -56,7 +58,8 @@ NpcDialog::NpcDialog() // Basic Window Setup setWindowName("NpcText"); setResizable(true); - setupWindow->registerWindowForReset(this); + //setupWindow->registerWindowForReset(this); + setFocusable(true); setMinWidth(200); setMinHeight(150); @@ -111,17 +114,24 @@ NpcDialog::NpcDialog() center(); loadWindowState(); + + instances.push_back(this); + setVisible(true); + requestFocus(); } NpcDialog::~NpcDialog() { // These might not actually be in the layout, so lets be safe + delete mScrollArea; delete mItemList; delete mTextField; delete mIntField; delete mResetButton; delete mPlusButton; delete mMinusButton; + + instances.remove(this); } void NpcDialog::setText(const std::string &text) @@ -162,10 +172,7 @@ void NpcDialog::action(const gcn::ActionEvent &event) } else if (mActionState == NPC_ACTION_CLOSE) { - if (current_npc) - closeDialog(); - setVisible(false); - current_npc = 0; + closeDialog(); } else if (mActionState == NPC_ACTION_INPUT) { @@ -276,6 +283,22 @@ bool NpcDialog::isInputFocused() const return mTextField->isFocused() || mIntField->isFocused(); } +bool NpcDialog::isAnyInputFocused() +{ + DialogList::iterator it = instances.begin(); + DialogList::iterator it_end = instances.end(); + + for (; it != it_end; it++) + { + if ((*it)->isInputFocused()) + { + return true; + } + } + + return false; +} + void NpcDialog::integerRequest(int defaultValue, int min, int max) { mActionState = NPC_ACTION_INPUT; @@ -312,6 +335,43 @@ void NpcDialog::widgetResized(const gcn::Event &event) setText(mText); } +void NpcDialog::setVisible(bool visible) +{ + Window::setVisible(visible); + + if (!visible) + { + scheduleDelete(); + } +} + +NpcDialog *NpcDialog::getActive() +{ + DialogList::iterator it = instances.begin(); + DialogList::iterator it_end = instances.end(); + + for (; it != it_end; it++) + { + if ((*it)->isFocused()) + { + return (*it); + } + } + + return NULL; +} + +void NpcDialog::closeAll() +{ + DialogList::iterator it = instances.begin(); + DialogList::iterator it_end = instances.end(); + + for (; it != it_end; it++) + { + (*it)->close(); + } +} + void NpcDialog::buildLayout() { clearLayout(); diff --git a/src/gui/npcdialog.h b/src/gui/npcdialog.h index 327ab6dd..18e8a8ae 100644 --- a/src/gui/npcdialog.h +++ b/src/gui/npcdialog.h @@ -29,6 +29,7 @@ #include <guichan/actionlistener.hpp> #include <guichan/listmodel.hpp> +#include <list> #include <string> #include <vector> @@ -52,7 +53,7 @@ class NpcDialog : public Window, public gcn::ActionListener, * * @see Window::Window */ - NpcDialog(); + NpcDialog(int npcId); ~NpcDialog(); @@ -61,11 +62,6 @@ class NpcDialog : public Window, public gcn::ActionListener, */ void action(const gcn::ActionEvent &event); - void setNpc(int npc) - { mNpcId = npc; } - - void clearText(); - /** * Sets the text shows in the dialog. * @@ -136,6 +132,8 @@ class NpcDialog : public Window, public gcn::ActionListener, bool isInputFocused() const; + static bool isAnyInputFocused(); + /** * Requests a interger from the user. */ @@ -151,7 +149,28 @@ class NpcDialog : public Window, public gcn::ActionListener, */ void widgetResized(const gcn::Event &event); + void setVisible(bool visible); + + /** + * Returns true if any instances exist. + */ + static bool isActive() { return instances.size() > 0; } + + /** + * Returns the first active instance. Useful for pushing user + * interaction. + */ + static NpcDialog *getActive(); + + /** + * Closes all instances. + */ + static void closeAll(); + private: + typedef std::list<NpcDialog*> DialogList; + static DialogList instances; + void buildLayout(); int mNpcId; @@ -201,8 +220,4 @@ class NpcDialog : public Window, public gcn::ActionListener, NpcActionState mActionState; }; -// TODO: This should be made not to be global, later. - -extern NpcDialog* npcDialog; - #endif // NPCDIALOG_H diff --git a/src/gui/npcpostdialog.cpp b/src/gui/npcpostdialog.cpp index a05008ec..cb6660c6 100644 --- a/src/gui/npcpostdialog.cpp +++ b/src/gui/npcpostdialog.cpp @@ -35,8 +35,11 @@ #include "utils/gettext.h" -NpcPostDialog::NpcPostDialog(): - Window(_("NPC")) +NpcPostDialog::DialogList NpcPostDialog::instances; + +NpcPostDialog::NpcPostDialog(int npcId): + Window(_("NPC")), + mNpcId(npcId) { setContentSize(400, 180); @@ -74,6 +77,14 @@ NpcPostDialog::NpcPostDialog(): add(cancelButton); setLocationRelativeTo(getParent()); + + instances.push_back(this); + setVisible(true); +} + +NpcPostDialog::~NpcPostDialog() +{ + instances.remove(this); } void NpcPostDialog::action(const gcn::ActionEvent &event) @@ -87,21 +98,34 @@ void NpcPostDialog::action(const gcn::ActionEvent &event) } else { - Net::getNpcHandler()->sendLetter(current_npc, mSender->getText(), + Net::getNpcHandler()->sendLetter(mNpcId, mSender->getText(), mText->getText()); } setVisible(false); - clear(); } else if (event.getId() == "cancel") { setVisible(false); - clear(); } } -void NpcPostDialog::clear() +void NpcPostDialog::setVisible(bool visible) +{ + Window::setVisible(visible); + + if (!visible) + { + scheduleDelete(); + } +} + +void NpcPostDialog::closeAll() { - mSender->setText(""); - mText->setText(""); + DialogList::iterator it = instances.begin(); + DialogList::iterator it_end = instances.end(); + + for (; it != it_end; it++) + { + (*it)->close(); + } } diff --git a/src/gui/npcpostdialog.h b/src/gui/npcpostdialog.h index 355d0ae1..9364eb0e 100644 --- a/src/gui/npcpostdialog.h +++ b/src/gui/npcpostdialog.h @@ -35,23 +35,35 @@ public: /** * Constructor */ - NpcPostDialog(); + NpcPostDialog(int npcId); + + ~NpcPostDialog(); /** * Called when receiving actions from the widgets. */ void action(const gcn::ActionEvent &event); + void setVisible(bool visible); + + /** + * Returns true if any instances exist. + */ + static bool isActive() { return instances.size() > 0; } + /** - * Clear the contents of the dialog + * Closes all instances. */ - void clear(); + static void closeAll(); private: + typedef std::list<NpcPostDialog*> DialogList; + static DialogList instances; + + int mNpcId; + TextBox *mText; TextField *mSender; }; -extern NpcPostDialog *npcPostDialog; - #endif diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index 75259dda..878ba7b8 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -205,9 +205,7 @@ void PopupMenu::handleLink(const std::string &link) // Talk To action if (link == "talk" && - being && - being->getType() == Being::NPC && - current_npc == 0) + being && being->getType() == Being::NPC) { dynamic_cast<NPC*>(being)->talk(); } diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index 3e3fdad5..214c70ab 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -43,12 +43,14 @@ #include "utils/gettext.h" #include "utils/stringutils.h" -SellDialog::SellDialog(): +SellDialog::DialogList SellDialog::instances; + +SellDialog::SellDialog(int npcId): Window(_("Sell")), - mMaxItems(0), mAmountItems(0) + mNpcId(npcId), mMaxItems(0), mAmountItems(0) { setWindowName("Sell"); - setupWindow->registerWindowForReset(this); + //setupWindow->registerWindowForReset(this); setResizable(true); setCloseButton(true); setMinWidth(260); @@ -106,11 +108,16 @@ SellDialog::SellDialog(): center(); loadWindowState(); + + instances.push_back(this); + setVisible(true); } SellDialog::~SellDialog() { delete mShopItems; + + instances.remove(this); } void SellDialog::reset() @@ -190,7 +197,7 @@ void SellDialog::action(const gcn::ActionEvent &event) // the inventory index of the next Duplicate otherwise. itemIndex = item->getCurrentInvIndex(); sellCount = item->sellCurrentDuplicate(mAmountItems); - Net::getNpcHandler()->sellItem(current_npc, itemIndex, sellCount); + Net::getNpcHandler()->sellItem(mNpcId, itemIndex, sellCount); mAmountItems -= sellCount; } @@ -271,23 +278,27 @@ void SellDialog::updateButtonsAndLabels() Units::formatCurrency(mPlayerMoney + income).c_str())); } -void SellDialog::logic() -{ - Window::logic(); - - if (!current_npc) setVisible(false); -} - void SellDialog::setVisible(bool visible) { Window::setVisible(visible); if (visible) + { mShopItemList->requestFocus(); + } + else + { + scheduleDelete(); + } } -void SellDialog::close() +void SellDialog::closeAll() { - setVisible(false); - current_npc = 0; + DialogList::iterator it = instances.begin(); + DialogList::iterator it_end = instances.end(); + + for (; it != it_end; it++) + { + (*it)->close(); + } } diff --git a/src/gui/sell.h b/src/gui/sell.h index c2462762..0c768153 100644 --- a/src/gui/sell.h +++ b/src/gui/sell.h @@ -46,7 +46,7 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener * * @see Window::Window */ - SellDialog(); + SellDialog(int npcId); /** * Destructor @@ -81,25 +81,31 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener void setMoney(int amount); /** - * Check for current NPC + * Sets the visibility of this window. */ - void logic(); + void setVisible(bool visible); /** - * Sets the visibility of this window. + * Returns true if any instances exist. */ - void setVisible(bool visible); + static bool isActive() { return instances.size() > 0; } /** - * Closes the Buy Window, as well as resetting the current npc. + * Closes all instances. */ - void close(); + static void closeAll(); + private: + typedef std::list<SellDialog*> DialogList; + static DialogList instances; + /** * Updates the state of buttons and labels. */ void updateButtonsAndLabels(); + int mNpcId; + gcn::Button *mSellButton; gcn::Button *mQuitButton; gcn::Button *mAddMaxButton; @@ -118,6 +124,4 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener int mAmountItems; }; -extern SellDialog *sellDialog; - #endif diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index a0a92edd..61c17ac8 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -300,7 +300,7 @@ void Viewport::mousePressed(gcn::MouseEvent &event) return; // Check if we are busy - if (current_npc) + if (NPC::isTalking()) return; mPlayerFollowMouse = false; diff --git a/src/gui/widgets/window.h b/src/gui/widgets/window.h index 45dfc5db..37a6b1eb 100644 --- a/src/gui/widgets/window.h +++ b/src/gui/widgets/window.h @@ -171,7 +171,7 @@ class Window : public gcn::Window, gcn::WidgetListener * Overloads window setVisible by Guichan to allow sticky window * handling. */ - void setVisible(bool visible); + virtual void setVisible(bool visible); /** * Overloads window setVisible by Guichan to allow sticky window diff --git a/src/net/ea/buysellhandler.cpp b/src/net/ea/buysellhandler.cpp index 9d1aac78..db282e61 100644 --- a/src/net/ea/buysellhandler.cpp +++ b/src/net/ea/buysellhandler.cpp @@ -51,29 +51,29 @@ BuySellHandler::BuySellHandler() SMSG_NPC_SELL_RESPONSE, 0 }; + mNpcId = 0; handledMessages = _messages; } void BuySellHandler::handleMessage(Net::MessageIn &msg) { int n_items; + switch (msg.getId()) { case SMSG_NPC_BUY_SELL_CHOICE: - buyDialog->setVisible(false); - buyDialog->reset(); - sellDialog->setVisible(false); - sellDialog->reset(); - current_npc = msg.readInt32(); - buySellDialog->setVisible(true); + if (!BuySellDialog::isActive()) + { + mNpcId = msg.readInt32(); + new BuySellDialog(mNpcId); + } break; case SMSG_NPC_BUY: msg.readInt16(); // length n_items = (msg.getLength() - 4) / 11; - buyDialog->reset(); - buyDialog->setMoney(player_node->getMoney()); - buyDialog->setVisible(true); + mBuyDialog = new BuyDialog(mNpcId); + mBuyDialog->setMoney(player_node->getMoney()); for (int k = 0; k < n_items; k++) { @@ -81,7 +81,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) msg.readInt32(); // DCvalue msg.readInt8(); // type int itemId = msg.readInt16(); - buyDialog->addItem(itemId, 0, value); + mBuyDialog->addItem(itemId, 0, value); } break; @@ -90,9 +90,8 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) n_items = (msg.getLength() - 4) / 10; if (n_items > 0) { - sellDialog->setMoney(player_node->getMoney()); - sellDialog->reset(); - sellDialog->setVisible(true); + SellDialog *dialog = new SellDialog(mNpcId); + dialog->setMoney(player_node->getMoney()); for (int k = 0; k < n_items; k++) { @@ -103,13 +102,12 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) Item *item = player_node->getInventory()->getItem(index); if (item && !(item->isEquipped())) - sellDialog->addItem(item, value); + dialog->addItem(item, value); } } else { localChatTab->chatLog(_("Nothing to sell."), BY_SERVER); - current_npc = 0; } break; @@ -122,7 +120,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) { // Reset player money since buy dialog already assumed purchase // would go fine - buyDialog->setMoney(player_node->getMoney()); + mBuyDialog->setMoney(player_node->getMoney()); localChatTab->chatLog(_("Unable to buy."), BY_SERVER); } break; diff --git a/src/net/ea/buysellhandler.h b/src/net/ea/buysellhandler.h index 61736024..1d17905d 100644 --- a/src/net/ea/buysellhandler.h +++ b/src/net/ea/buysellhandler.h @@ -24,6 +24,8 @@ #include "net/ea/messagehandler.h" +class BuyDialog; + namespace EAthena { class BuySellHandler : public MessageHandler @@ -32,6 +34,10 @@ class BuySellHandler : public MessageHandler BuySellHandler(); virtual void handleMessage(Net::MessageIn &msg); + + private: + int mNpcId; + BuyDialog *mBuyDialog; }; } // namespace EAthena diff --git a/src/net/ea/npchandler.cpp b/src/net/ea/npchandler.cpp index 48cc6125..6fb719a1 100644 --- a/src/net/ea/npchandler.cpp +++ b/src/net/ea/npchandler.cpp @@ -57,72 +57,70 @@ NpcHandler::NpcHandler() void NpcHandler::handleMessage(Net::MessageIn &msg) { - int id; - bool resetPlayer = false; + bool resetPlayer = true; + + if (msg.getId() == SMSG_NPC_CHOICE || msg.getId() == SMSG_NPC_MESSAGE) + { + msg.readInt16(); // length + } + + int npcId = msg.readInt32(); + NpcDialogs::iterator diag = mNpcDialogs.find(npcId); + NpcDialog *dialog; + + if (diag == mNpcDialogs.end()) + { + // Empty dialogs don't help + if (msg.getId() == SMSG_NPC_CLOSE) + { + closeDialog(npcId); + } + else if (msg.getId() == SMSG_NPC_NEXT) + { + nextDialog(npcId); + } + else + { + dialog = new NpcDialog(npcId); + Wrapper wrap; + wrap.dialog = dialog; + mNpcDialogs[npcId] = wrap; + } + } + else + { + dialog = diag->second.dialog; + } switch (msg.getId()) { case SMSG_NPC_CHOICE: - msg.readInt16(); // length - current_npc = msg.readInt32(); - npcDialog->setNpc(current_npc); - npcDialog->choiceRequest(); - npcDialog->parseListItems(msg.readString(msg.getLength() - 8)); - npcDialog->setVisible(true); - resetPlayer = true; + dialog->choiceRequest(); + dialog->parseListItems(msg.readString(msg.getLength() - 8)); break; case SMSG_NPC_MESSAGE: - msg.readInt16(); // length - current_npc = msg.readInt32(); - npcDialog->setNpc(current_npc); - npcDialog->addText(msg.readString(msg.getLength() - 8)); - npcDialog->setVisible(true); - resetPlayer = true; + dialog->addText(msg.readString(msg.getLength() - 8)); break; case SMSG_NPC_CLOSE: - id = msg.readInt32(); - // If we're talking to that NPC, show the close button - if (id == current_npc) - { - npcDialog->showCloseButton(); - resetPlayer = true; - } - // Otherwise, move on as an empty dialog doesn't help - else - closeDialog(id); + // Show the close button + dialog->showCloseButton(); break; case SMSG_NPC_NEXT: - id = msg.readInt32(); - // If we're talking to that NPC, show the next button - if (id == current_npc) - { - npcDialog->showNextButton(); - resetPlayer = true; - } - // Otherwise, move on as an empty dialog doesn't help - else - nextDialog(id); + // Show the next button + dialog->showNextButton(); break; case SMSG_NPC_INT_INPUT: // Request for an integer - current_npc = msg.readInt32(); - npcDialog->setNpc(current_npc); - npcDialog->integerRequest(0); - npcDialog->setVisible(true); - resetPlayer = true; + dialog->integerRequest(0); break; case SMSG_NPC_STR_INPUT: // Request for a string - current_npc = msg.readInt32(); - npcDialog->setNpc(current_npc); - npcDialog->textRequest(""); - npcDialog->setVisible(true); - resetPlayer = true; + dialog->textRequest(""); break; } @@ -147,8 +145,13 @@ void NpcHandler::closeDialog(int npcId) { MessageOut outMsg(CMSG_NPC_CLOSE); outMsg.writeInt32(npcId); - npcDialog->setText(""); - npcDialog->setVisible(false); + + NpcDialogs::iterator it = mNpcDialogs.find(npcId); + if (it != mNpcDialogs.end()) + { + (*it).second.dialog->close(); + mNpcDialogs.erase(it); + } } void NpcHandler::listInput(int npcId, int value) diff --git a/src/net/ea/npchandler.h b/src/net/ea/npchandler.h index a42b88c5..072c97e3 100644 --- a/src/net/ea/npchandler.h +++ b/src/net/ea/npchandler.h @@ -27,6 +27,10 @@ #include "net/ea/messagehandler.h" +#include <map> + +class NpcDialog; + namespace EAthena { class NpcHandler : public MessageHandler, public Net::NpcHandler @@ -62,6 +66,13 @@ class NpcHandler : public MessageHandler, public Net::NpcHandler void sellItem(int beingId, int itemId, int amount); void endShopping(int beingId); + + private: + typedef struct { + NpcDialog* dialog; + } Wrapper; + typedef std::map<int, Wrapper> NpcDialogs; + NpcDialogs mNpcDialogs; }; } // namespace EAthena diff --git a/src/net/ea/playerhandler.cpp b/src/net/ea/playerhandler.cpp index 7fb4dab9..34e0daf4 100644 --- a/src/net/ea/playerhandler.cpp +++ b/src/net/ea/playerhandler.cpp @@ -80,15 +80,15 @@ namespace { { Net::getPlayerHandler()->respawn(); deathNotice = NULL; - buyDialog->setVisible(false); - sellDialog->setVisible(false); - buySellDialog->setVisible(false); + + BuyDialog::closeAll(); + BuySellDialog::closeAll(); + NpcDialog::closeAll(); + SellDialog::closeAll(); if (storageWindow->isVisible()) storageWindow->close(); viewport->closePopupMenu(); - npcDialog->closeDialog(); - current_npc = 0; } } deathListener; diff --git a/src/net/manaserv/buysellhandler.cpp b/src/net/manaserv/buysellhandler.cpp index e98dce98..9b7c0863 100644 --- a/src/net/manaserv/buysellhandler.cpp +++ b/src/net/manaserv/buysellhandler.cpp @@ -26,17 +26,14 @@ #include "localplayer.h" #include "npc.h" -#include "net/messagein.h" - -#include "net/manaserv/protocol.h" - #include "gui/buy.h" #include "gui/chat.h" #include "gui/sell.h" -extern BuyDialog *buyDialog; -extern SellDialog *sellDialog; -extern Window *buySellDialog; +#include "net/messagein.h" + +#include "net/manaserv/protocol.h" + namespace ManaServ { @@ -58,37 +55,43 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg) return; } - current_npc = being->getId(); + int npcId = being->getId(); switch (msg.getId()) { case GPMSG_NPC_BUY: - buyDialog->reset(); - buyDialog->setMoney(player_node->getMoney()); - buyDialog->setVisible(true); + { + BuyDialog* dialog = new BuyDialog(npcId); + + dialog->reset(); + dialog->setMoney(player_node->getMoney()); while (msg.getUnreadLength()) { int itemId = msg.readInt16(); int amount = msg.readInt16(); int value = msg.readInt16(); - buyDialog->addItem(itemId, amount, value); + dialog->addItem(itemId, amount, value); } break; + } case GPMSG_NPC_SELL: - sellDialog->setMoney(player_node->getMoney()); - sellDialog->reset(); - sellDialog->setVisible(true); + { + SellDialog* dialog = new SellDialog(npcId); + + dialog->reset(); + dialog->setMoney(player_node->getMoney()); while (msg.getUnreadLength()) { int itemId = msg.readInt16(); int amount = msg.readInt16(); int value = msg.readInt16(); - sellDialog->addItem(new Item(itemId, amount, false), value); + dialog->addItem(new Item(itemId, amount, false), value); } break; + } } } diff --git a/src/net/manaserv/npchandler.cpp b/src/net/manaserv/npchandler.cpp index 4e1a4f95..00f3a338 100644 --- a/src/net/manaserv/npchandler.cpp +++ b/src/net/manaserv/npchandler.cpp @@ -62,16 +62,29 @@ void NpcHandler::handleMessage(Net::MessageIn &msg) return; } - current_npc = being->getId(); - npcDialog->setNpc(current_npc); + int npcId = being->getId(); + NpcDialogs::iterator diag = mNpcDialogs.find(npcId); + NpcDialog *dialog; + + if (diag == mNpcDialogs.end()) + { + dialog = new NpcDialog(npcId); + Wrapper wrap; + wrap.dialog = dialog; + mNpcDialogs[npcId] = wrap; + } + else + { + dialog = diag->second.dialog; + } switch (msg.getId()) { case GPMSG_NPC_CHOICE: - npcDialog->choiceRequest(); + dialog->choiceRequest(); while (msg.getUnreadLength()) { - npcDialog->addChoice(msg.readString()); + dialog->addChoice(msg.readString()); } break; @@ -79,32 +92,35 @@ void NpcHandler::handleMessage(Net::MessageIn &msg) { int min_num = msg.readInt32(); int max_num = msg.readInt32(); - npcDialog->integerRequest(msg.readInt32(), min_num, max_num); + dialog->integerRequest(msg.readInt32(), min_num, max_num); break; } case GPMSG_NPC_STRING: - npcDialog->textRequest(""); + dialog->textRequest(""); break; case GPMSG_NPC_POST: - npcDialog->setVisible(false); - npcPostDialog->clear(); - npcPostDialog->setVisible(true); + { + new NpcPostDialog(npcId); break; + } case GPMSG_NPC_ERROR: - current_npc = NULL; + dialog->close(); + if (diag != mNpcDialogs.end()) + { + mNpcDialogs.erase(diag); + } break; case GPMSG_NPC_MESSAGE: - npcDialog->addText(msg.readString(msg.getUnreadLength())); - npcDialog->showNextButton(); - npcDialog->setVisible(true); + dialog->addText(msg.readString(msg.getUnreadLength())); + dialog->showNextButton(); break; case GPMSG_NPC_CLOSE: - npcDialog->showCloseButton(); + dialog->showCloseButton(); break; } } @@ -129,8 +145,12 @@ void NpcHandler::closeDialog(int npcId) msg.writeInt16(npcId); gameServerConnection->send(msg); - npcDialog->setVisible(false); - npcDialog->setText(""); + NpcDialogs::iterator it = mNpcDialogs.find(npcId); + if (it != mNpcDialogs.end()) + { + (*it).second.dialog->close(); + mNpcDialogs.erase(it); + } } void NpcHandler::listInput(int npcId, int value) diff --git a/src/net/manaserv/npchandler.h b/src/net/manaserv/npchandler.h index 8f353e5d..4b18487c 100644 --- a/src/net/manaserv/npchandler.h +++ b/src/net/manaserv/npchandler.h @@ -26,7 +26,9 @@ #include "net/manaserv/messagehandler.h" -#include <list> +#include <map> + +class NpcDialog; namespace ManaServ { @@ -63,6 +65,13 @@ class NpcHandler : public MessageHandler, public Net::NpcHandler void sellItem(int beingId, int itemId, int amount); void endShopping(int beingId); + + private: + typedef struct { + NpcDialog* dialog; + } Wrapper; + typedef std::map<int, Wrapper> NpcDialogs; + NpcDialogs mNpcDialogs; }; } // namespace ManaServ diff --git a/src/net/manaserv/playerhandler.cpp b/src/net/manaserv/playerhandler.cpp index 23158cc5..bff9512e 100644 --- a/src/net/manaserv/playerhandler.cpp +++ b/src/net/manaserv/playerhandler.cpp @@ -29,11 +29,9 @@ #include "particle.h" #include "npc.h" -#include "gui/buy.h" #include "gui/chat.h" #include "gui/gui.h" #include "gui/okdialog.h" -#include "gui/sell.h" #include "gui/viewport.h" #include "net/net.h" @@ -43,13 +41,6 @@ #include "net/manaserv/messageout.h" #include "net/manaserv/protocol.h" -extern OkDialog *weightNotice; -extern OkDialog *deathNotice; - -extern BuyDialog *buyDialog; -extern SellDialog *sellDialog; -extern Window *buySellDialog; - /** @see in game.cpp */ extern const int MILLISECONDS_IN_A_TICK; @@ -61,38 +52,6 @@ extern const int MILLISECONDS_IN_A_TICK; */ static const int MAP_TELEPORT_SCROLL_DISTANCE = 8 * 32; -/** - * Listener used for handling the overweigth message. - */ -// TODO Move somewhere else -namespace { - struct WeightListener : public gcn::ActionListener - { - void action(const gcn::ActionEvent &event) - { - weightNotice = NULL; - } - } weightListener; -} - -/** - * Listener used for handling death message. - */ -// TODO Move somewhere else -namespace { - struct DeathListener : public gcn::ActionListener - { - void action(const gcn::ActionEvent &event) - { - Net::getPlayerHandler()->respawn(); - deathNotice = NULL; - buyDialog->setVisible(false); - sellDialog->setVisible(false); - current_npc = 0; - } - } deathListener; -} - extern Net::PlayerHandler *playerHandler; namespace ManaServ { @@ -313,8 +272,6 @@ void PlayerHandler::handleMapChangeMessage(Net::MessageIn &msg) // Switch the actual map, deleting the previous one game->changeMap(mapName); - current_npc = 0; - const Vector &playerPos = player_node->getPosition(); float scrollOffsetX = 0.0f; float scrollOffsetY = 0.0f; diff --git a/src/npc.cpp b/src/npc.cpp index b9cb6b41..b546d665 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -37,8 +37,6 @@ #include "resources/npcdb.h" -int current_npc = 0; - NPC::NPC(int id, int job, Map *map): Player(id, job, map, true) { @@ -80,9 +78,6 @@ void NPC::setName(const std::string &name) void NPC::talk() { - if (isTalking()) - return; - Net::getNpcHandler()->talk(mId); } @@ -93,7 +88,7 @@ void NPC::setSprite(unsigned int slot, int id, const std::string &color) const bool NPC::isTalking() { - return npcDialog->isVisible() || buyDialog->isVisible() || - sellDialog->isVisible() || buySellDialog->isVisible() || - npcPostDialog->isVisible(); + return NpcDialog::isActive() || BuyDialog::isActive() || + SellDialog::isActive() || BuySellDialog::isActive() || + NpcPostDialog::isActive(); } @@ -68,6 +68,4 @@ class NPC : public Player virtual void updateColors() {} }; -extern int current_npc; - #endif |