diff options
author | Thorbjørn Lindeijer <thorbjorn.lindeijer@nokia.com> | 2010-09-25 03:15:26 +0200 |
---|---|---|
committer | Thorbjørn Lindeijer <thorbjorn.lindeijer@nokia.com> | 2010-09-25 03:15:26 +0200 |
commit | 661d16e98c62dfff40f481177bf3f1a0c58c2124 (patch) | |
tree | a415866c4c94a0a0c53045a47220ca413ae9c5c9 | |
parent | 758d80263b1647c712c0e0cdd3dfca9945a1bb7e (diff) | |
parent | 7d0738df0d139af3175fcc1fec5b9be4a467f4f4 (diff) | |
download | mana-661d16e98c62dfff40f481177bf3f1a0c58c2124.tar.gz mana-661d16e98c62dfff40f481177bf3f1a0c58c2124.tar.bz2 mana-661d16e98c62dfff40f481177bf3f1a0c58c2124.tar.xz mana-661d16e98c62dfff40f481177bf3f1a0c58c2124.zip |
Merge branch '1.0'
Conflicts:
src/actorspritemanager.h
src/beingmanager.cpp
src/game.cpp
src/gui/beingpopup.cpp
src/gui/chat.cpp
src/gui/chat.h
src/gui/inventorywindow.h
src/gui/itempopup.cpp
src/gui/socialwindow.cpp
src/gui/statuswindow.cpp
src/gui/widgets/chattab.cpp
src/gui/widgets/chattab.h
src/net/tmwa/inventoryhandler.cpp
src/net/tmwa/partyhandler.cpp
src/party.cpp
src/sound.cpp
src/utils/stringutils.cpp
src/utils/stringutils.h
46 files changed, 572 insertions, 343 deletions
diff --git a/src/actorspritemanager.cpp b/src/actorspritemanager.cpp index 88618ccd..5d038a18 100644 --- a/src/actorspritemanager.cpp +++ b/src/actorspritemanager.cpp @@ -52,8 +52,50 @@ class FindBeingFunctor ActorSprite::Type type; } beingFinder; +class PlayerNamesLister : public AutoCompleteLister +{ + void getAutoCompleteList(std::vector<std::string>& names) const + { + names.clear(); + + const ActorSprites &mActors = actorSpriteManager->getAll(); + for_actors + { + if ((*it)->getType() == ActorSprite::FLOOR_ITEM) + continue; + + Being *being = static_cast<Being*>(*it); + if (being->getType() == Being::PLAYER && being->getName() != "") + names.push_back(being->getName()); + } + } +}; + +class PlayerNPCNamesLister : public AutoCompleteLister +{ + void getAutoCompleteList(std::vector<std::string>& names) const + { + names.clear(); + + const ActorSprites &mActors = actorSpriteManager->getAll(); + for_actors + { + if ((*it)->getType() == ActorSprite::FLOOR_ITEM) + continue; + + Being *being = static_cast<Being*>(*it); + if ((being->getType() == Being::PLAYER + || being->getType() == Being::NPC) + && being->getName() != "") + names.push_back(being->getName()); + } + } +}; + ActorSpriteManager::ActorSpriteManager() { + mPlayerNames = new PlayerNamesLister; + mPlayerNPCNames = new PlayerNPCNamesLister; } ActorSpriteManager::~ActorSpriteManager() @@ -278,24 +320,14 @@ bool ActorSpriteManager::hasActorSprite(ActorSprite *actor) const return false; } -void ActorSpriteManager::getPlayerNames(std::vector<std::string> &names, - bool npcNames) +AutoCompleteLister *ActorSpriteManager::getPlayerNameLister() { - names.clear(); - - for_actors - { - if ((*it)->getType() == ActorSprite::FLOOR_ITEM) - continue; + return mPlayerNames; +} - Being *being = static_cast<Being*>(*it); - if ((being->getType() == ActorSprite::PLAYER - || (being->getType() == ActorSprite::NPC && npcNames)) - && being->getName() != "") - { - names.push_back(being->getName()); - } - } +AutoCompleteLister *ActorSpriteManager::getPlayerNPCNameLister() +{ + return mPlayerNPCNames; } void ActorSpriteManager::updatePlayerNames() diff --git a/src/actorspritemanager.h b/src/actorspritemanager.h index d9d5b534..d6aa609b 100644 --- a/src/actorspritemanager.h +++ b/src/actorspritemanager.h @@ -26,6 +26,8 @@ #include "being.h" #include "flooritem.h" +#include "gui/widgets/textfield.h" + class LocalPlayer; class Map; @@ -147,12 +149,18 @@ class ActorSpriteManager */ void clear(); - void getPlayerNames(std::vector<std::string> &names, - bool npcNames); + AutoCompleteLister *getPlayerNameLister(); + + AutoCompleteLister *getPlayerNPCNameLister(); void updatePlayerNames(); protected: + friend class PlayerNamesLister; + friend class PlayerNPCNamesLister; + + AutoCompleteLister *mPlayerNames; + AutoCompleteLister *mPlayerNPCNames; ActorSprites mActors; ActorSprites mDeleteActors; Map *mMap; diff --git a/src/client.cpp b/src/client.cpp index 7ec5a155..ae9af8de 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -619,20 +619,13 @@ int Client::exec() case STATE_CHOOSE_SERVER: logger->log("State: CHOOSE SERVER"); - // Allow changing this using a server choice dialog - // We show the dialog box only if the command-line - // options weren't set. - if (mOptions.serverName.empty() && mOptions.serverPort == 0 - && !branding.getValue("onlineServerList", "a").empty()) - { - // Don't allow an alpha opacity - // lower than the default value - Theme::instance()->setMinimumOpacity(0.8f); - - mCurrentDialog = new ServerDialog(&mCurrentServer, - mConfigDir); - } - else + // If a server was passed on the command line, or branding + // provides a server and a blank server list, we skip the + // server selection dialog. + if ((!mOptions.serverName.empty() && mOptions.serverPort) + || (!branding.getValue("defaultServer","").empty() && + branding.getValue("defaultPort",0) && + branding.getValue("onlineServerList", "").empty())) { mState = STATE_CONNECT_SERVER; @@ -641,6 +634,15 @@ int Client::exec() mOptions.serverName.clear(); mOptions.serverPort = 0; } + else + { + // Don't allow an alpha opacity + // lower than the default value + Theme::instance()->setMinimumOpacity(0.8f); + + mCurrentDialog = new ServerDialog(&mCurrentServer, + mConfigDir); + } break; case STATE_CONNECT_SERVER: @@ -980,7 +982,7 @@ int Client::exec() case STATE_ERROR: logger->log("State: ERROR"); - logger->log("Error: %s\n", errorMessage.c_str()); + logger->log("Error: %s", errorMessage.c_str()); mCurrentDialog = new OkDialog(_("Error"), errorMessage); mCurrentDialog->addActionListener(&errorListener); mCurrentDialog = NULL; // OkDialog deletes itself @@ -1109,7 +1111,7 @@ void Client::initConfiguration() { // Fill configuration with defaults config.setValue("hwaccel", false); -#if (defined __APPLE__ || defined WIN32) && defined USE_OPENGL +#if defined __APPLE__ && defined USE_OPENGL config.setValue("opengl", true); #else config.setValue("opengl", false); diff --git a/src/game.cpp b/src/game.cpp index 9035ba6a..b50d0629 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -152,14 +152,14 @@ static void createGuiWindows() setupWindow->clearWindowsForReset(); // Create dialogs + miniStatusWindow = new MiniStatusWindow; + minimap = new Minimap; chatWindow = new ChatWindow; tradeWindow = new TradeWindow; equipmentWindow = new EquipmentWindow(PlayerInfo::getEquipment()); statusWindow = new StatusWindow; - miniStatusWindow = new MiniStatusWindow; inventoryWindow = new InventoryWindow(PlayerInfo::getInventory()); skillDialog = new SkillDialog; - minimap = new Minimap; helpWindow = new HelpWindow; debugWindow = new DebugWindow; itemShortcutWindow = new ShortcutWindow("ItemShortcut", @@ -356,10 +356,10 @@ void Game::logic() if (Client::getState() == STATE_CHANGE_MAP) return; // Not a problem here - if (Client::getState() != STATE_ERROR) - { - errorMessage = _("The connection to the server was lost."); - } + if (Client::getState() == STATE_ERROR) + return; // Disconnect gets handled by STATE_ERROR + + errorMessage = _("The connection to the server was lost."); if (!disconnectedDialog) { @@ -759,7 +759,7 @@ void Game::handleInput() // Moving player around if (player_node->isAlive() && !PlayerInfo::isTalking() && - !chatWindow->isInputFocused() && !quitDialog) + !chatWindow->isInputFocused() && !quitDialog && !TextDialog::isActive()) { // Get the state of the keyboard keys keyboard.refreshActiveKeys(); @@ -962,7 +962,12 @@ void Game::changeMap(const std::string &mapPath) std::string oldMusic = mCurrentMap ? mCurrentMap->getMusicFile() : ""; std::string newMusic = newMap ? newMap->getMusicFile() : ""; if (newMusic != oldMusic) - sound.playMusic(newMusic); + { + if (newMusic.empty()) + sound.stopMusic(); + else + sound.playMusic(newMusic); + } delete mCurrentMap; mCurrentMap = newMap; diff --git a/src/gui/beingpopup.cpp b/src/gui/beingpopup.cpp index ee9fd66d..ae0b43fd 100644 --- a/src/gui/beingpopup.cpp +++ b/src/gui/beingpopup.cpp @@ -65,25 +65,28 @@ void BeingPopup::show(int x, int y, Being *b) return; } + mBeingName->setCaption(b->getName()); + mBeingName->adjustSize(); + + int minWidth = mBeingName->getWidth(); + const int height = getFont()->getHeight(); + if (!(b->getPartyName().empty())) { - mBeingName->setCaption(b->getName()); - mBeingName->adjustSize(); - mBeingParty->setCaption(strprintf(_("Party: %s"), b->getPartyName().c_str())); mBeingParty->adjustSize(); - int minWidth = std::max(mBeingName->getWidth(), - mBeingParty->getWidth()); - - const int height = getFont()->getHeight(); + if (minWidth < mBeingParty->getWidth()) + minWidth = mBeingParty->getWidth(); setContentSize(minWidth + 10, (height * 2) + 10); - - position(x, y); - return; + } + else + { + mBeingParty->setCaption(""); + setContentSize(minWidth + 10, height + 10); } - setVisible(false); + position(x, y); } diff --git a/src/gui/charselectdialog.cpp b/src/gui/charselectdialog.cpp index 9d6050f8..1c292759 100644 --- a/src/gui/charselectdialog.cpp +++ b/src/gui/charselectdialog.cpp @@ -164,10 +164,10 @@ CharSelectDialog::CharSelectDialog(LoginData *loginData): addKeyListener(this); center(); - mCharacterEntries[0]->requestFocus(); setVisible(true); Net::getCharHandler()->setCharSelectDialog(this); + mCharacterEntries[0]->requestFocus(); } CharSelectDialog::~CharSelectDialog() @@ -328,10 +328,10 @@ CharacterDisplay::CharacterDisplay(CharSelectDialog *charSelectDialog): mCharacter(0), mPlayerBox(new PlayerBox) { - mButton = new Button("wwwwwwwww", "go", charSelectDialog); - mName = new Label("wwwwwwwwwwwwwwwwwwwwwwww"); - mLevel = new Label("(888)"); - mMoney = new Label("wwwwwwwww"); + mButton = new Button("", "go", charSelectDialog); + mName = new Label(""); + mLevel = new Label(""); + mMoney = new Label(""); mDelete = new Button(_("Delete"), "delete", charSelectDialog); @@ -347,15 +347,7 @@ CharacterDisplay::CharacterDisplay(CharSelectDialog *charSelectDialog): update(); - // Setting the width so that the largest label fits. - mName->adjustSize(); - mMoney->adjustSize(); - int width = 74; - if (width < 20 + mName->getWidth()) - width = 20 + mName->getWidth(); - if (width < 20 + mMoney->getWidth()) - width = 20 + mMoney->getWidth(); - h.reflowLayout(width, 112 + mName->getHeight() + mLevel->getHeight() + + h.reflowLayout(80, 112 + mName->getHeight() + mLevel->getHeight() + mMoney->getHeight() + mButton->getHeight() + mDelete->getHeight()); } diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index b1d4b131..8e0f5941 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -73,9 +73,21 @@ class ChatInput : public TextField, public gcn::FocusListener } }; +class ChatAutoComplete : public AutoCompleteLister +{ + void getAutoCompleteList(std::vector<std::string> &list) const + { + ChatTab *tab = static_cast<ChatTab*>(chatWindow->mChatTabs + ->getSelectedTab()); + + return tab->getAutoCompleteList(list); + } +}; ChatWindow::ChatWindow(): Window(_("Chat")), + mHistory(new TextHistory()), + mAutoComplete(new ChatAutoComplete), mTmpVisible(false) { listen("Chat"); @@ -108,9 +120,8 @@ ChatWindow::ChatWindow(): loadWindowState(); - // Add key listener to chat input to be able to respond to up/down - mChatInput->addKeyListener(this); - mCurHist = mHistory.end(); + mChatInput->setHistory(mHistory); + mChatInput->setAutoComplete(mAutoComplete); mReturnToggles = config.getBoolValue("ReturnToggles"); @@ -123,6 +134,8 @@ ChatWindow::~ChatWindow() delete mRecorder; removeAllWhispers(); delete mItemLinkHandler; + delete mHistory; + delete mAutoComplete; } void ChatWindow::resetToDefaultSize() @@ -177,14 +190,6 @@ void ChatWindow::action(const gcn::ActionEvent &event) if (!message.empty()) { - // If message different from previous, put it in the history - if (mHistory.empty() || message != mHistory.back()) - { - mHistory.push_back(message); - } - // Reset history iterator - mCurHist = mHistory.end(); - // Send the message to the server chatInput(message); @@ -370,48 +375,6 @@ void ChatWindow::mouseDragged(gcn::MouseEvent &event) } } - -void ChatWindow::keyPressed(gcn::KeyEvent &event) -{ - if (event.getKey().getValue() == Key::DOWN) - { - if (mCurHist != mHistory.end()) - { - // Move forward through the history - HistoryIterator prevHist = mCurHist++; - - if (mCurHist != mHistory.end()) - { - mChatInput->setText(*mCurHist); - mChatInput->setCaretPosition(mChatInput->getText().length()); - } - else - { - mChatInput->setText(""); - mCurHist = prevHist; - } - } - else if (mChatInput->getText() != "") - { - mChatInput->setText(""); - } - } - else if (event.getKey().getValue() == Key::UP && - mCurHist != mHistory.begin() && mHistory.size() > 0) - { - // Move backward through the history - mCurHist--; - mChatInput->setText(*mCurHist); - mChatInput->setCaretPosition(mChatInput->getText().length()); - } - else if (event.getKey().getValue() == Key::TAB && - mChatInput->getText() != "") - { - autoComplete(); - return; - } -} - void ChatWindow::event(const std::string &channel, const Mana::Event &event) { if (channel == "Notices") @@ -558,112 +521,3 @@ ChatTab *ChatWindow::addWhisperTab(const std::string &nick, bool switchTo) return ret; } - -void ChatWindow::autoComplete() -{ - int caretPos = mChatInput->getCaretPosition(); - int startName = 0; - const std::string inputText = mChatInput->getText(); - std::string name = inputText.substr(0, caretPos); - std::string newName(""); - - for (int f = caretPos - 1; f > -1; f --) - { - if (isWordSeparator(inputText[f])) - { - startName = f + 1; - name = inputText.substr(f + 1, caretPos - f); - break; - } - } - - if (caretPos - 1 + 1 == startName) - return; - - - ChatTab *cTab = static_cast<ChatTab*>(mChatTabs->getSelectedTab()); - std::vector<std::string> nameList; - cTab->getAutoCompleteList(nameList); - newName = autoComplete(nameList, name); - - if (newName == "") - { - actorSpriteManager->getPlayerNames(nameList, true); - newName = autoComplete(nameList, name); - } - if (newName == "") - { - newName = autoCompleteHistory(name); - } - - if (newName != "") - { - if(inputText[0] == '@' || inputText[0] == '/') - newName = "\"" + newName + "\""; - - mChatInput->setText(inputText.substr(0, startName) + newName - + inputText.substr(caretPos, inputText.length() - caretPos)); - - if (startName > 0) - mChatInput->setCaretPosition(caretPos - name.length() + newName.length() + 1); - else - mChatInput->setCaretPosition(caretPos - name.length() + newName.length()); - } -} - -std::string ChatWindow::autoComplete(std::vector<std::string> &names, - std::string partName) const -{ - std::vector<std::string>::iterator i = names.begin(); - toLower(partName); - std::string newName(""); - - while (i != names.end()) - { - if (!i->empty()) - { - std::string name = *i; - toLower(name); - - std::string::size_type pos = name.find(partName, 0); - if (pos == 0) - { - if (newName != "") - { - toLower(newName); - newName = findSameSubstring(name, newName); - } - else - { - newName = *i; - } - } - } - ++i; - } - - return newName; -} - -std::string ChatWindow::autoCompleteHistory(std::string partName) -{ - History::iterator i = mHistory.begin(); - std::vector<std::string> nameList; - - while (i != mHistory.end()) - { - std::string line = *i; - unsigned int f = 0; - while (f < line.length() && !isWordSeparator(line.at(f))) - { - f++; - } - line = line.substr(0, f); - if (line != "") - { - nameList.push_back(line); - } - ++i; - } - return autoComplete(nameList, partName); -} diff --git a/src/gui/chat.h b/src/gui/chat.h index db5fe293..3a001432 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -25,6 +25,7 @@ #include "listener.h" #include "gui/widgets/window.h" +#include "gui/widgets/textfield.h" #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> @@ -76,7 +77,6 @@ struct CHATLOG */ class ChatWindow : public Window, public gcn::ActionListener, - public gcn::KeyListener, public Mana::Listener { public: @@ -146,9 +146,6 @@ class ChatWindow : public Window, */ void chatInput(const std::string &msg); - /** Called when key is pressed */ - void keyPressed(gcn::KeyEvent &event); - /** Add the given text to the chat input. */ void addInputText(const std::string &text); @@ -158,7 +155,6 @@ class ChatWindow : public Window, /** Override to reset mTmpVisible */ void setVisible(bool visible); - void mousePressed(gcn::MouseEvent &event); void mouseDragged(gcn::MouseEvent &event); @@ -193,6 +189,7 @@ class ChatWindow : public Window, protected: friend class ChatTab; friend class WhisperTab; + friend class ChatAutoComplete; /** Remove the given tab from the window */ void removeTab(ChatTab *tab); @@ -204,13 +201,6 @@ class ChatWindow : public Window, void removeAllWhispers(); - void autoComplete(); - - std::string autoCompleteHistory(std::string partName); - - std::string autoComplete(std::vector<std::string> &names, - std::string partName) const; - /** Used for showing item popup on clicking links **/ ItemLinkHandler *mItemLinkHandler; Recorder *mRecorder; @@ -218,6 +208,9 @@ class ChatWindow : public Window, /** Input box for typing chat messages. */ ChatInput *mChatInput; + TextHistory *mHistory; + AutoCompleteLister *mAutoComplete; + private: bool mTmpVisible; @@ -228,10 +221,6 @@ class ChatWindow : public Window, /** Manage whisper tabs */ TabMap mWhispers; - typedef std::list<std::string> History; - typedef History::iterator HistoryIterator; - History mHistory; /**< Command history. */ - HistoryIterator mCurHist; /**< History iterator. */ bool mReturnToggles; /**< Marks whether <Return> toggles the chat log or not */ }; diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index 6ad1b05f..62b63f24 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -312,11 +312,19 @@ void InventoryWindow::valueChanged(const gcn::SelectionEvent &event) (item->getQuantity() - 1)); } + updateButtons(); +} + +void InventoryWindow::updateButtons() +{ + Item *item = mItems->getSelectedItem(); + if (!item || item->getQuantity() == 0) { mUseButton->setEnabled(false); mEquipButton->setEnabled(false); mDropButton->setEnabled(false); + mSplitButton->setEnabled(false); return; } @@ -347,7 +355,6 @@ void InventoryWindow::valueChanged(const gcn::SelectionEvent &event) mSplitButton->setEnabled(false); } - void InventoryWindow::setSplitAllowed(bool allowed) { mSplitButton->setVisible(allowed); diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index 1b68b897..99fc1c03 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -103,6 +103,11 @@ class InventoryWindow : public Window, */ void close(); + /** + * Updates the buttons. + */ + void updateButtons(); + void slotsChanged(Inventory* inventory); bool isMainInventory() { return mInventory->isMainInventory(); } diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp index ea33fda3..9b2df34d 100644 --- a/src/gui/itempopup.cpp +++ b/src/gui/itempopup.cpp @@ -51,22 +51,17 @@ ItemPopup::ItemPopup(): mItemName->setFont(boldFont); mItemName->setPosition(getPadding(), getPadding()); - const int fontHeight = getFont()->getHeight(); - // Item Description mItemDesc = new TextBox; mItemDesc->setEditable(false); - mItemDesc->setPosition(getPadding(), fontHeight); // Item Effect mItemEffect = new TextBox; mItemEffect->setEditable(false); - mItemEffect->setPosition(getPadding(), (fontHeight << 1) + (getPadding() << 1)); // Item Weight mItemWeight = new TextBox; mItemWeight->setEditable(false); - mItemWeight->setPosition(getPadding(), fontHeight * 3 + (getPadding() << 2)); mIcon = new Icon(0); @@ -158,28 +153,34 @@ void ItemPopup::setItem(const ItemInfo &item, bool showImage) const int numRowsDesc = mItemDesc->getNumberOfRows(); const int numRowsEffect = mItemEffect->getNumberOfRows(); const int numRowsWeight = mItemWeight->getNumberOfRows(); - const int height = getFont()->getHeight(); + const int fontHeight = getFont()->getHeight(); + + int nameHeight; + if (mIcon->getHeight() > 2 * fontHeight) + nameHeight = mIcon->getHeight(); + else + nameHeight = 2 * fontHeight; if (item.getEffect().empty()) { - setContentSize(minWidth, (numRowsDesc + numRowsWeight + getPadding()) * - height); + setContentSize(minWidth, nameHeight + + (numRowsDesc + numRowsWeight + 1) * fontHeight); - mItemWeight->setPosition(getPadding(), (numRowsDesc + getPadding()) * - height); + mItemWeight->setPosition(getPadding(), + nameHeight + (numRowsDesc + 1) * fontHeight); } else { - setContentSize(minWidth, (numRowsDesc + numRowsEffect + numRowsWeight + - getPadding()) * height); + setContentSize(minWidth, nameHeight + (numRowsDesc + numRowsEffect + + numRowsWeight + 1) * fontHeight); - mItemWeight->setPosition(getPadding(), (numRowsDesc + numRowsEffect + - getPadding()) * height); + mItemWeight->setPosition(getPadding(), nameHeight + (numRowsDesc + + numRowsEffect + 1) * fontHeight); } - mItemDesc->setPosition(getPadding(), 2 * height); - mItemEffect->setPosition(getPadding(), (numRowsDesc + getPadding()) * height); - + mItemDesc->setPosition(getPadding(), nameHeight); + mItemEffect->setPosition(getPadding(), nameHeight + + (numRowsDesc + 1) * fontHeight); } gcn::Color ItemPopup::getColor(ItemType type) diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp index dd447f95..993814ea 100644 --- a/src/gui/minimap.cpp +++ b/src/gui/minimap.cpp @@ -105,7 +105,8 @@ void Minimap::setMap(Map *map) if (minimapName.empty() && resman->exists(tempname)) minimapName = tempname; - mMapImage = resman->getImage(minimapName); + if (!minimapName.empty()) + mMapImage = resman->getImage(minimapName); } if (mMapImage) diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index 7a702cc2..e2257388 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -128,7 +128,8 @@ void PopupMenu::showPopup(int x, int y, Being *being) mBrowserBox->addRow(strprintf("@@follow|%s@@", strprintf(_("Follow %s"), name.c_str()).c_str())); - mBrowserBox->addRow(strprintf("@@guild|%s@@", + if (player_node->getNumberOfGuilds()) + mBrowserBox->addRow(strprintf("@@guild|%s@@", strprintf(_("Invite %s to join your guild"), name.c_str()).c_str())); if (player_node->isInParty()) diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index 83f01d7f..f33111d7 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -252,6 +252,8 @@ void SellDialog::setMoney(int amount) { mPlayerMoney = amount; mShopItemList->setPlayersMoney(amount); + + updateButtonsAndLabels(); } void SellDialog::updateButtonsAndLabels() diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index 115b582c..1657c8d3 100644 --- a/src/gui/serverdialog.cpp +++ b/src/gui/serverdialog.cpp @@ -679,7 +679,7 @@ int ServerDialog::downloadUpdate(void *ptr, DownloadStatus status, } else if (status < 0) { - logger->log("Error retreiving server list: %s\n", + logger->log("Error retreiving server list: %s", sd->mDownload->getError()); sd->mDownloadStatus = DOWNLOADING_ERROR; } diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index bbfae738..ae921d2f 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -222,11 +222,11 @@ Setup_Video::Setup_Video(): mParticleEffectsCheckBox(new CheckBox(_("Particle effects"), mParticleEffectsEnabled)), mNameCheckBox(new CheckBox(_("Show own name"), mNameEnabled)), - mNPCLogCheckBox(new CheckBox(_("Log NPC interations"), mNPCLogEnabled)), + mNPCLogCheckBox(new CheckBox(_("Log NPC interactions"), mNPCLogEnabled)), mPickupNotifyLabel(new Label(_("Show pickup notification"))), - // TRANSLATORS: Refers to "Show own name" + // TRANSLATORS: Refers to "Show pickup notification" mPickupChatCheckBox(new CheckBox(_("in chat"), mPickupChatEnabled)), - // TRANSLATORS: Refers to "Show own name" + // TRANSLATORS: Refers to "Show pickup notification" mPickupParticleCheckBox(new CheckBox(_("as particle"), mPickupParticleEnabled)), mSpeechSlider(new Slider(0, 3)), @@ -438,8 +438,18 @@ void Setup_Video::apply() config.setValue("opengl", mOpenGLCheckBox->isSelected()); // OpenGL can currently only be changed by restarting, notify user. - new OkDialog(_("Changing to OpenGL"), - _("Applying change to OpenGL requires restart.")); + if (mOpenGLCheckBox->isSelected()) + { + new OkDialog(_("Changing to OpenGL"), + _("Applying change to OpenGL requires restart. " + "In case OpenGL messes up your game graphics, restart " + "the game with the command line option \"--no-opengl\".")); + } + else + { + new OkDialog(_("Deactivating OpenGL"), + _("Applying change to OpenGL requires restart.")); + } } mFps = mFpsCheckBox->isSelected() ? (int) mFpsSlider->getValue() : 0; diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp index 168553f6..be46132e 100644 --- a/src/gui/skilldialog.cpp +++ b/src/gui/skilldialog.cpp @@ -74,9 +74,14 @@ struct SkillInfo float progress; gcn::Color color; + SkillInfo() : + icon(NULL) + {} + ~SkillInfo() { - icon->decRef(); + if (icon) + icon->decRef(); } void setIcon(const std::string &iconPath) @@ -86,7 +91,8 @@ struct SkillInfo { icon = res->getImage(iconPath); } - else + + if (!icon) { icon = Theme::getImageFromTheme( paths.getStringValue("unknownItemFile")); diff --git a/src/gui/socialwindow.cpp b/src/gui/socialwindow.cpp index 88cd5732..588ce5e7 100644 --- a/src/gui/socialwindow.cpp +++ b/src/gui/socialwindow.cpp @@ -120,11 +120,13 @@ public: if (event.getId() == "do invite") { std::string name = mInviteDialog->getText(); - Net::getGuildHandler()->invite(mGuild->getId(), name); - SERVER_NOTICE(strprintf(_("Invited user %s to guild %s."), - name.c_str(), - mGuild->getName().c_str())) + if (!name.empty()) + { + SERVER_NOTICE(strprintf(_("Invited user %s to guild %s."), + name.c_str(), + mGuild->getName().c_str())) + } mInviteDialog = NULL; } else if (event.getId() == "~do invite") @@ -151,7 +153,7 @@ protected: mInviteDialog = new TextDialog(_("Member Invite to Guild"), strprintf(_("Who would you like to invite to guild %s?"), mGuild->getName().c_str()), - socialWindow); + socialWindow, true); mInviteDialog->setActionEventId("do invite"); mInviteDialog->addActionListener(this); } @@ -184,7 +186,7 @@ public: mScroll = new ScrollArea(mList); mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); - mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); } ~PartyTab() @@ -200,10 +202,10 @@ public: if (event.getId() == "do invite") { std::string name = mInviteDialog->getText(); - Net::getPartyHandler()->invite(name); - SERVER_NOTICE(strprintf(_("Invited user %s to party."), - name.c_str())) + if (!name.empty()) + SERVER_NOTICE(strprintf(_("Invited user %s to party."), + name.c_str())) mInviteDialog = NULL; } else if (event.getId() == "~do invite") @@ -230,7 +232,7 @@ protected: mInviteDialog = new TextDialog(_("Member Invite to Party"), strprintf(_("Who would you like to invite to party %s?"), mParty->getName().c_str()), - socialWindow); + socialWindow, true); mInviteDialog->setActionEventId("do invite"); mInviteDialog->addActionListener(this); } @@ -319,7 +321,7 @@ SocialWindow::SocialWindow() : setCloseButton(true); setMinWidth(120); setMinHeight(55); - setDefaultSize(590, 200, 150, 60); + setDefaultSize(590, 200, 150, 124); setupWindow->registerWindowForReset(this); loadWindowState(); @@ -492,7 +494,8 @@ void SocialWindow::action(const gcn::ActionEvent &event) if (name.size() > 16) { - // TODO : State too many characters in input. + SERVER_NOTICE(_("Creating guild failed, please choose a " + "shorter name.")); return; } @@ -512,7 +515,8 @@ void SocialWindow::action(const gcn::ActionEvent &event) if (name.size() > 16) { - // TODO : State too many characters in input. + SERVER_NOTICE(_("Creating party failed, please choose a " + "shorter name.")); return; } diff --git a/src/gui/statuswindow.cpp b/src/gui/statuswindow.cpp index 493f5ee6..6535edf7 100644 --- a/src/gui/statuswindow.cpp +++ b/src/gui/statuswindow.cpp @@ -238,10 +238,7 @@ void StatusWindow::event(const std::string &channel, const Mana::Event &event) _("Character points: %d"), event.getInt("newValue"))); mCharacterPointsLabel->adjustSize(); - // Update all attributes - for (Attrs::iterator it = mAttrs.begin(); - it != mAttrs.end(); it++) - it->second->update(); + updateAttrs(); break; case CORR_POINTS: @@ -249,10 +246,7 @@ void StatusWindow::event(const std::string &channel, const Mana::Event &event) _("Correction points: %d"), event.getInt("newValue"))); mCorrectionPointsLabel->adjustSize(); - // Update all attributes - for (Attrs::iterator it = mAttrs.begin(); - it != mAttrs.end(); it++) - it->second->update(); + updateAttrs(); break; case LEVEL: @@ -286,6 +280,14 @@ void StatusWindow::event(const std::string &channel, const Mana::Event &event) } } +void StatusWindow::updateAttrs() +{ + for (Attrs::iterator it = mAttrs.begin(); it != mAttrs.end(); it++) + { + it->second->update(); + } +} + void StatusWindow::setPointsNeeded(int id, int needed) { Attrs::iterator it = mAttrs.find(id); diff --git a/src/gui/statuswindow.h b/src/gui/statuswindow.h index 5be09b6a..fd8c6319 100644 --- a/src/gui/statuswindow.h +++ b/src/gui/statuswindow.h @@ -51,6 +51,8 @@ class StatusWindow : public Window, public Mana::Listener void event(const std::string &channel, const Mana::Event &event); + void updateAttrs(); + void setPointsNeeded(int id, int needed); void addAttribute(int id, const std::string &name, bool modifiable, diff --git a/src/gui/textdialog.cpp b/src/gui/textdialog.cpp index 3e3aafe2..f88a6afa 100644 --- a/src/gui/textdialog.cpp +++ b/src/gui/textdialog.cpp @@ -21,6 +21,8 @@ #include "gui/textdialog.h" +#include "actorspritemanager.h" + #include "gui/widgets/button.h" #include "gui/widgets/label.h" #include "gui/widgets/textfield.h" @@ -30,14 +32,20 @@ int TextDialog::instances = 0; TextDialog::TextDialog(const std::string &title, const std::string &msg, - Window *parent): - Window(title, true, parent), - mTextField(new TextField) + Window *parent, bool autoCompleteEnabled): + Window(title, true, parent) { gcn::Label *textLabel = new Label(msg); mOkButton = new Button(_("OK"), "OK", this); gcn::Button *cancelButton = new Button(_("Cancel"), "CANCEL", this); + // In TextField the escape key will either cause autoComplete or lose focus + mTextField = new TextField("", ! autoCompleteEnabled); + if (autoCompleteEnabled) + mTextField->setAutoComplete(actorSpriteManager->getPlayerNameLister()); + + mTextField->addActionListener(this); + place(0, 0, textLabel, 4); place(0, 1, mTextField, 4); place(2, 2, mOkButton); diff --git a/src/gui/textdialog.h b/src/gui/textdialog.h index d4c611cc..aa8fcf8f 100644 --- a/src/gui/textdialog.h +++ b/src/gui/textdialog.h @@ -42,7 +42,7 @@ public: * @see Window::Window */ TextDialog(const std::string &title, const std::string &msg, - Window *parent = NULL); + Window *parent = NULL, bool autoCompleteEnabled = false); ~TextDialog(); diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp index 05f34760..e9162ab6 100644 --- a/src/gui/widgets/chattab.cpp +++ b/src/gui/widgets/chattab.cpp @@ -21,6 +21,7 @@ #include "gui/widgets/chattab.h" +#include "actorspritemanager.h" #include "chatlog.h" #include "commandhandler.h" #include "configuration.h" @@ -279,6 +280,11 @@ void ChatTab::handleCommand(const std::string &msg) commandHandler->handleCommand(msg, this); } +void ChatTab::getAutoCompleteList(std::vector<std::string> &names) const +{ + actorSpriteManager->getPlayerNPCNameLister()->getAutoCompleteList(names); +} + void ChatTab::saveToLogFile(std::string &msg) { if (chatLogger) diff --git a/src/gui/widgets/chattab.h b/src/gui/widgets/chattab.h index f5682668..1e187f23 100644 --- a/src/gui/widgets/chattab.h +++ b/src/gui/widgets/chattab.h @@ -25,6 +25,7 @@ #include "gui/chat.h" #include "gui/widgets/tab.h" +#include "gui/widgets/textfield.h" class BrowserBox; class Recorder; @@ -33,7 +34,7 @@ class ScrollArea; /** * A tab for the chat window. This is special to ease chat handling. */ -class ChatTab : public Tab +class ChatTab : public Tab, public AutoCompleteLister { public: /** @@ -100,6 +101,9 @@ class ChatTab : public Tab const std::string &args) { return false; } + + void getAutoCompleteList(std::vector<std::string> &names) const; + virtual void saveToLogFile(std::string &msg); protected: @@ -112,8 +116,6 @@ class ChatTab : public Tab virtual void handleCommand(const std::string &msg); - virtual void getAutoCompleteList(std::vector<std::string>&) const {} - void addRow(std::string &line); ScrollArea *mScrollArea; diff --git a/src/gui/widgets/shoplistbox.cpp b/src/gui/widgets/shoplistbox.cpp index c0a79500..ae7d4d9b 100644 --- a/src/gui/widgets/shoplistbox.cpp +++ b/src/gui/widgets/shoplistbox.cpp @@ -61,6 +61,11 @@ ShopListBox::ShopListBox(gcn::ListModel *listModel, ShopItems *shopListModel): mItemPopup = new ItemPopup; } +ShopListBox::~ShopListBox() +{ + delete mItemPopup; +} + void ShopListBox::setPlayersMoney(int money) { mPlayerMoney = money; @@ -167,3 +172,9 @@ void ShopListBox::mouseMoved(gcn::MouseEvent &event) } } } + +void ShopListBox::mouseExited(gcn::MouseEvent &event) +{ + mItemPopup->setVisible(false); +} + diff --git a/src/gui/widgets/shoplistbox.h b/src/gui/widgets/shoplistbox.h index 062ad93a..087bdd53 100644 --- a/src/gui/widgets/shoplistbox.h +++ b/src/gui/widgets/shoplistbox.h @@ -48,6 +48,11 @@ class ShopListBox : public ListBox ShopListBox(gcn::ListModel *listModel, ShopItems *shopListModel); /** + * Destructor + */ + ~ShopListBox(); + + /** * Draws the list box. */ void draw(gcn::Graphics *graphics); @@ -73,8 +78,16 @@ class ShopListBox : public ListBox */ void setPriceCheck(bool check); + /** + ** Show ItemTooltip + */ void mouseMoved(gcn::MouseEvent &event); + /** + ** Hide ItemTooltip + */ + void mouseExited(gcn::MouseEvent &event); + private: int mPlayerMoney; diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp index a774ab22..101c9546 100644 --- a/src/gui/widgets/tabbedarea.cpp +++ b/src/gui/widgets/tabbedarea.cpp @@ -103,16 +103,12 @@ void TabbedArea::addTab(const std::string &caption, gcn::Widget *widget) void TabbedArea::removeTab(Tab *tab) { - int tabIndexToBeSelected = -1; - if (tab == mSelectedTab) { - int index = getSelectedTabIndex(); - - if (index == (int)mTabs.size() - 1 && mTabs.size() == 1) - tabIndexToBeSelected = -1; + if (getNumberOfTabs() > 1) + setSelectedTab(std::max(0, getSelectedTabIndex() - 1)); else - tabIndexToBeSelected = index - 1; + mSelectedTab = 0; } TabContainer::iterator iter; @@ -137,16 +133,6 @@ void TabbedArea::removeTab(Tab *tab) } } - if (tabIndexToBeSelected == -1) - { - mSelectedTab = NULL; - mWidgetContainer->clear(); - } - else - { - setSelectedTab(tabIndexToBeSelected); - } - adjustSize(); adjustTabPositions(); } diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp index 9696cd59..d06df376 100644 --- a/src/gui/widgets/textfield.cpp +++ b/src/gui/widgets/textfield.cpp @@ -32,6 +32,7 @@ #include "utils/copynpaste.h" #include "utils/dtor.h" +#include "utils/stringutils.h" #include <guichan/font.hpp> @@ -43,7 +44,9 @@ ImageRect TextField::skin; TextField::TextField(const std::string &text, bool loseFocusOnTab): gcn::TextField(text), - mNumeric(false) + mNumeric(false), + mAutoComplete(NULL), + mHistory(NULL) { setFrameSize(2); @@ -209,6 +212,42 @@ void TextField::keyPressed(gcn::KeyEvent &keyEvent) } } break; + case Key::UP: + { + if (mHistory && !mHistory->atBegining() && !mHistory->empty()) + { + // Move backward through the history + mHistory->current--; + setText(*mHistory->current); + setCaretPosition(getText().length()); + } + } break; + + case Key::DOWN: + { + if (mHistory && !mHistory->atEnd()) + { + // Move forward through the history + TextHistoryIterator prevHist = mHistory->current++; + + if (!mHistory->atEnd()) + { + setText(*mHistory->current); + setCaretPosition(getText().length()); + } + else + { + setText(""); + mHistory->current = prevHist; + } + } + else if (getText() != "") + { + // Always clear (easy access to useful function) + setText(""); + } + } break; + case Key::DELETE: { unsigned sz = mText.size(); @@ -234,6 +273,18 @@ void TextField::keyPressed(gcn::KeyEvent &keyEvent) } break; case Key::ENTER: + if (mHistory) + { + // If the input is different from previous, put it in the history + if (!getText().empty() && (mHistory->empty() || + !mHistory->matchesLastEntry(getText()))) + { + mHistory->addEntry(getText()); + } + + mHistory->toEnd(); + } + distributeActionEvent(); break; @@ -246,6 +297,7 @@ void TextField::keyPressed(gcn::KeyEvent &keyEvent) break; case Key::TAB: + autoComplete(); if (mLoseFocusOnTab) return; break; @@ -259,6 +311,73 @@ void TextField::keyPressed(gcn::KeyEvent &keyEvent) fixScroll(); } +void TextField::autoComplete() +{ + if (mAutoComplete && mText.size() > 0) + { + const int caretPos = getCaretPosition(); + int startName = 0; + const std::string inputText = getText(); + std::string name = inputText.substr(0, caretPos); + std::string newName(""); + + for (int f = caretPos - 1; f > -1; f--) + { + if (isWordSeparator(inputText[f])) + { + startName = f + 1; + name = inputText.substr(f + 1, caretPos - startName); + break; + } + } + + if (caretPos == startName) + return; + + + std::vector<std::string> nameList; + mAutoComplete->getAutoCompleteList(nameList); + newName = autocomplete(nameList, name); + + if (newName == "" && mHistory) + { + + TextHistoryIterator i = mHistory->history.begin(); + std::vector<std::string> nameList; + + while (i != mHistory->history.end()) + { + std::string line = *i; + unsigned int f = 0; + while (f < line.length() && !isWordSeparator(line.at(f))) + { + f++; + } + line = line.substr(0, f); + if (line != "") + { + nameList.push_back(line); + } + ++i; + } + + newName = autocomplete(nameList, name); + } + + if (newName != "") + { + if(inputText[0] == '@' || inputText[0] == '/') + newName = "\"" + newName + "\""; + + setText(inputText.substr(0, startName) + newName + + inputText.substr(caretPos, inputText.length() + - caretPos)); + + setCaretPosition(caretPos - name.length() + newName.length()); + } + } +} + void TextField::handlePaste() { std::string text = getText(); diff --git a/src/gui/widgets/textfield.h b/src/gui/widgets/textfield.h index 58e37f5c..1963f9fa 100644 --- a/src/gui/widgets/textfield.h +++ b/src/gui/widgets/textfield.h @@ -24,9 +24,48 @@ #include <guichan/widgets/textfield.hpp> +#include <vector> + class ImageRect; class TextField; +typedef std::list<std::string> TextHistoryList; +typedef TextHistoryList::iterator TextHistoryIterator; + +struct TextHistory { + TextHistoryList history; /**< Command history. */ + TextHistoryIterator current; /**< History iterator. */ + + TextHistory() + { current = history.end(); } + + bool empty() const + { return history.empty(); } + + bool atBegining() const + { return current == history.begin(); } + + bool atEnd() const + { return current == history.end(); } + + void toBegining() + { current = history.begin(); } + + void toEnd() + { current = history.end(); } + + void addEntry(const std::string &text) + { history.push_back(text); } + + bool matchesLastEntry(const std::string &text) + { return history.back() == text; } +}; + +class AutoCompleteLister { +public: + virtual void getAutoCompleteList(std::vector<std::string>&) const {} +}; + /** * A text field. * @@ -90,7 +129,33 @@ class TextField : public gcn::TextField */ int getValue() const; + /** + * Sets the TextField's source of autocomplete. Passing null will + * disable autocomplete. + */ + void setAutoComplete(AutoCompleteLister *lister) + { mAutoComplete = lister; } + + /** + * Returns the TextField's source of autocomplete. + */ + AutoCompleteLister *getAutoComplete() const + { return mAutoComplete; } + + /** + * Sets the TextField's source of input history. + */ + void setHistory(TextHistory *history) + { mHistory = history; } + + /** + * Returns the TextField's source of input history. + */ + TextHistory *getHistory() const + { return mHistory; } + private: + void autoComplete(); void handlePaste(); static int instances; @@ -100,6 +165,10 @@ class TextField : public gcn::TextField int mMinimum; int mMaximum; bool mLoseFocusOnTab; + + AutoCompleteLister *mAutoComplete; + + TextHistory *mHistory; /**< Text history. */ }; #endif diff --git a/src/gui/windowmenu.cpp b/src/gui/windowmenu.cpp index 76e6bc1f..542ab4a0 100644 --- a/src/gui/windowmenu.cpp +++ b/src/gui/windowmenu.cpp @@ -72,6 +72,7 @@ WindowMenu::WindowMenu(): WindowMenu::~WindowMenu() { + delete mEmotePopup; } void WindowMenu::action(const gcn::ActionEvent &event) diff --git a/src/main.cpp b/src/main.cpp index f3962c40..b82881d7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,7 +74,7 @@ static void printVersion() static void parseOptions(int argc, char *argv[], Client::Options &options) { - const char *optstring = "hvud:U:P:Dc:p:C:L:"; + const char *optstring = "hvud:U:P:Dc:s:p:C:L:"; const struct option long_options[] = { { "config-dir", required_argument, 0, 'C' }, diff --git a/src/net/net.cpp b/src/net/net.cpp index 5e7c989f..7e7395a6 100644 --- a/src/net/net.cpp +++ b/src/net/net.cpp @@ -22,6 +22,7 @@ #include "net/net.h" #include "main.h" +#include "log.h" #include "net/adminhandler.h" #include "net/charhandler.h" @@ -41,6 +42,8 @@ #include "net/manaserv/generalhandler.h" +#include "utils/gettext.h" + Net::AdminHandler *adminHandler = NULL; Net::CharHandler *charHandler = NULL; Net::ChatHandler *chatHandler = NULL; @@ -124,12 +127,19 @@ namespace Net { ServerInfo::Type networkType = ServerInfo::UNKNOWN; -void connectToServer(const ServerInfo &server) +void connectToServer(ServerInfo &server) { if (server.type == ServerInfo::UNKNOWN) { // TODO: Query the server about itself and choose the netcode based on // that + + if (server.port == 6901) + server.type = ServerInfo::TMWATHENA; + else if (server.port == 9601) + server.type = ServerInfo::MANASERV; + else + logger->error(_("Unknown Server Type! Exiting.")); } if (networkType == server.type && getGeneralHandler() != NULL) diff --git a/src/net/net.h b/src/net/net.h index 9d9ee10e..6029f3ba 100644 --- a/src/net/net.h +++ b/src/net/net.h @@ -67,7 +67,7 @@ ServerInfo::Type getNetworkType(); /** * Handles server detection and connection */ -void connectToServer(const ServerInfo &server); +void connectToServer(ServerInfo &server); void unload(); diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp index 543beec2..97967eb9 100644 --- a/src/net/tmwa/beinghandler.cpp +++ b/src/net/tmwa/beinghandler.cpp @@ -47,6 +47,7 @@ BeingHandler::BeingHandler(bool enableSync): static const Uint16 _messages[] = { SMSG_BEING_VISIBLE, SMSG_BEING_MOVE, + SMSG_BEING_SPAWN, SMSG_BEING_MOVE2, SMSG_BEING_REMOVE, SMSG_SKILL_DAMAGE, @@ -227,6 +228,13 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); break; + case SMSG_BEING_SPAWN: + /* + * TODO: This packet might need handling in the future. + */ + // Do nothing. + break; + case SMSG_BEING_MOVE2: /* * A simplified movement packet, used by the diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp index 820864ce..1063ee39 100644 --- a/src/net/tmwa/charserverhandler.cpp +++ b/src/net/tmwa/charserverhandler.cpp @@ -77,6 +77,9 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg) msg.skip(2); // Length word msg.skip(20); // Unused + delete_all(mCharacters); + mCharacters.clear(); + // Derive number of characters from message length const int count = (msg.getLength() - 24) / 106; diff --git a/src/net/tmwa/guildhandler.cpp b/src/net/tmwa/guildhandler.cpp index 67fe5d98..39d49bc7 100644 --- a/src/net/tmwa/guildhandler.cpp +++ b/src/net/tmwa/guildhandler.cpp @@ -119,7 +119,7 @@ void GuildHandler::handleMessage(Net::MessageIn &msg) msg.readInt8(); // Unused std::string guildName = msg.readString(24); - logger->log("Guild position info: %d %d %d %s\n", guildId, + logger->log("Guild position info: %d %d %d %s", guildId, emblem, posMode, guildName.c_str()); } break; diff --git a/src/net/tmwa/inventoryhandler.cpp b/src/net/tmwa/inventoryhandler.cpp index 4a46e475..9fac8e8c 100644 --- a/src/net/tmwa/inventoryhandler.cpp +++ b/src/net/tmwa/inventoryhandler.cpp @@ -130,6 +130,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) int index, amount, itemId, equipType, arrow; int identified, cards[4], itemType; Inventory *inventory = PlayerInfo::getInventory(); + PlayerInfo::getEquipment()->setBackend(&mEquips); switch (msg.getId()) { @@ -139,8 +140,6 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) { // Clear inventory - this will be a complete refresh mEquips.clear(); - PlayerInfo::getEquipment()->setBackend(&mEquips); - inventory->clear(); } else @@ -242,6 +241,8 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) inventory->setItem(index, itemId, amount); } + + inventoryWindow->updateButtons(); } break; case SMSG_PLAYER_INVENTORY_REMOVE: @@ -252,6 +253,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) item->increaseQuantity(-amount); if (item->getQuantity() == 0) inventory->removeItemAt(index); + inventoryWindow->updateButtons(); } break; @@ -263,7 +265,15 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) msg.readInt8(); // type if (Item *item = inventory->getItem(index)) - item->setQuantity(amount); + { + if (amount) + item->setQuantity(amount); + else + inventory->removeItemAt(index); + + inventoryWindow->updateButtons(); + } + break; case SMSG_ITEM_USE_RESPONSE: @@ -277,7 +287,14 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) else { if (Item *item = inventory->getItem(index)) - item->setQuantity(amount); + { + if (amount) + item->setQuantity(amount); + else + inventory->removeItemAt(index); + + inventoryWindow->updateButtons(); + } } break; diff --git a/src/net/tmwa/inventoryhandler.h b/src/net/tmwa/inventoryhandler.h index 18d73517..79d3bc65 100644 --- a/src/net/tmwa/inventoryhandler.h +++ b/src/net/tmwa/inventoryhandler.h @@ -88,6 +88,8 @@ class EquipBackend : public Equipment::Backend { { item->setEquipped(true); } + + inventoryWindow->updateButtons(); } private: diff --git a/src/net/tmwa/network.cpp b/src/net/tmwa/network.cpp index ddfbbc5d..aff19b11 100644 --- a/src/net/tmwa/network.cpp +++ b/src/net/tmwa/network.cpp @@ -326,7 +326,7 @@ MessageIn Network::getNextMessage() len = readWord(2); #ifdef DEBUG - logger->log("Received packet 0x%x of length %d\n", msgId, len); + logger->log("Received packet 0x%x of length %d", msgId, len); #endif MessageIn msg(mInBuffer, len); diff --git a/src/net/tmwa/partyhandler.cpp b/src/net/tmwa/partyhandler.cpp index 3d7aa263..00b1e621 100644 --- a/src/net/tmwa/partyhandler.cpp +++ b/src/net/tmwa/partyhandler.cpp @@ -184,7 +184,7 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) partyTab->chatLog(_("Experience sharing not possible."), BY_SERVER); break; default: - logger->log("Unknown party exp option: %d\n", exp); + logger->log("Unknown party exp option: %d", exp); } switch (item) @@ -208,7 +208,7 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) partyTab->chatLog(_("Item sharing not possible."), BY_SERVER); break; default: - logger->log("Unknown party item option: %d\n", exp); + logger->log("Unknown party item option: %d", exp); } break; } @@ -322,17 +322,23 @@ void PartyHandler::invite(Being *being) void PartyHandler::invite(const std::string &name) { - if (partyTab) + Being *invitee = actorSpriteManager->findBeingByName(name, Being::PLAYER); + + if (invitee) { - partyTab->chatLog(_("Inviting like this isn't supported at the moment."), - BY_SERVER); + invite(invitee); + partyTab->chatLog(strprintf(_("Invited user %s to party."), + invitee->getName().c_str()), BY_SERVER); + } + else if (partyTab) + { + partyTab->chatLog(strprintf(_("Inviting failed, because you can't see " + "a player called %s."), name.c_str()), BY_SERVER); } else { SERVER_NOTICE(_("You can only inivte when you are in a party!")) } - - // TODO? } void PartyHandler::inviteResponse(const std::string &inviter, bool accept) diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp index 6a1e8918..ca42a5c9 100644 --- a/src/net/tmwa/playerhandler.cpp +++ b/src/net/tmwa/playerhandler.cpp @@ -286,6 +286,10 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) player_node->setAction(Being::DEAD); } } + + if (statusWindow) + statusWindow->updateAttrs(); + break; case SMSG_PLAYER_STAT_UPDATE_2: diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 8a703bc7..b167e956 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -322,6 +322,7 @@ void ItemDB::unload() delete_all(mItemInfos); mItemInfos.clear(); + mNamedItemInfos.clear(); mLoaded = false; } diff --git a/src/resources/theme.cpp b/src/resources/theme.cpp index 6633f1e0..0316b0bf 100644 --- a/src/resources/theme.cpp +++ b/src/resources/theme.cpp @@ -326,6 +326,7 @@ bool Theme::tryThemePath(std::string themePath) if (!themePath.empty()) { themePath = defaultThemePath + themePath; + if (PHYSFS_exists(themePath.c_str())) { mThemePath = themePath; @@ -338,6 +339,9 @@ bool Theme::tryThemePath(std::string themePath) void Theme::prepareThemePath() { + // Ensure the Theme object has been created + instance(); + // Try theme from settings if (!tryThemePath(config.getStringValue("theme"))) // Try theme from branding diff --git a/src/sound.cpp b/src/sound.cpp index a859cb6e..6fe9668d 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -195,12 +195,7 @@ void Sound::stopMusic() logger->log("Sound::stopMusic()"); - if (mMusic) - { - Mix_HaltMusic(); - Mix_FreeMusic(mMusic); - mMusic = NULL; - } + haltMusic(); } void Sound::fadeInMusic(const std::string &path, int ms) @@ -239,8 +234,7 @@ void Sound::playSfx(const std::string &path) return; ResourceManager *resman = ResourceManager::getInstance(); - SoundEffect *sample = resman->getSoundEffect( - paths.getStringValue("sfx") + path); + SoundEffect *sample = resman->getSoundEffect(path); if (sample) { logger->log("Sound::playSfx() Playing: %s", path.c_str()); diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp index 3988c769..4726f8a7 100644 --- a/src/utils/stringutils.cpp +++ b/src/utils/stringutils.cpp @@ -187,3 +187,38 @@ bool getBoolFromString(const std::string &text) else return (bool) atoi(txt.c_str()); } + +std::string autocomplete(std::vector<std::string> &candidates, + std::string base) +{ + std::vector<std::string>::iterator i = candidates.begin(); + toLower(base); + std::string newName(""); + + while (i != candidates.end()) + { + if (!i->empty()) + { + std::string name = *i; + toLower(name); + + std::string::size_type pos = name.find(base, 0); + if (pos == 0) + { + if (newName != "") + { + toLower(newName); + newName = findSameSubstring(name, newName); + } + else + { + newName = *i; + } + } + } + + ++i; + } + + return newName; +} diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h index 7c14b1e5..012ae98f 100644 --- a/src/utils/stringutils.h +++ b/src/utils/stringutils.h @@ -24,6 +24,7 @@ #include <string> #include <sstream> +#include <vector> /** * Trims spaces off the end and the beginning of the given string. @@ -133,4 +134,7 @@ const char* getSafeUtf8String(std::string text); */ bool getBoolFromString(const std::string &text); +std::string autocomplete(std::vector<std::string> &candidates, + std::string base); + #endif // UTILS_STRINGUTILS_H |