summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/actorspritemanager.cpp64
-rw-r--r--src/actorspritemanager.h12
-rw-r--r--src/client.cpp34
-rw-r--r--src/game.cpp21
-rw-r--r--src/gui/beingpopup.cpp25
-rw-r--r--src/gui/charselectdialog.cpp20
-rw-r--r--src/gui/chat.cpp178
-rw-r--r--src/gui/chat.h21
-rw-r--r--src/gui/inventorywindow.cpp9
-rw-r--r--src/gui/inventorywindow.h5
-rw-r--r--src/gui/itempopup.cpp35
-rw-r--r--src/gui/minimap.cpp3
-rw-r--r--src/gui/popupmenu.cpp3
-rw-r--r--src/gui/sell.cpp2
-rw-r--r--src/gui/serverdialog.cpp2
-rw-r--r--src/gui/setup_video.cpp20
-rw-r--r--src/gui/skilldialog.cpp10
-rw-r--r--src/gui/socialwindow.cpp30
-rw-r--r--src/gui/statuswindow.cpp18
-rw-r--r--src/gui/statuswindow.h2
-rw-r--r--src/gui/textdialog.cpp14
-rw-r--r--src/gui/textdialog.h2
-rw-r--r--src/gui/widgets/chattab.cpp6
-rw-r--r--src/gui/widgets/chattab.h8
-rw-r--r--src/gui/widgets/shoplistbox.cpp11
-rw-r--r--src/gui/widgets/shoplistbox.h13
-rw-r--r--src/gui/widgets/tabbedarea.cpp20
-rw-r--r--src/gui/widgets/textfield.cpp121
-rw-r--r--src/gui/widgets/textfield.h69
-rw-r--r--src/gui/windowmenu.cpp1
-rw-r--r--src/main.cpp2
-rw-r--r--src/net/net.cpp12
-rw-r--r--src/net/net.h2
-rw-r--r--src/net/tmwa/beinghandler.cpp8
-rw-r--r--src/net/tmwa/charserverhandler.cpp3
-rw-r--r--src/net/tmwa/guildhandler.cpp2
-rw-r--r--src/net/tmwa/inventoryhandler.cpp25
-rw-r--r--src/net/tmwa/inventoryhandler.h2
-rw-r--r--src/net/tmwa/network.cpp2
-rw-r--r--src/net/tmwa/partyhandler.cpp20
-rw-r--r--src/net/tmwa/playerhandler.cpp4
-rw-r--r--src/resources/itemdb.cpp1
-rw-r--r--src/resources/theme.cpp4
-rw-r--r--src/sound.cpp10
-rw-r--r--src/utils/stringutils.cpp35
-rw-r--r--src/utils/stringutils.h4
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