summaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/browserbox.cpp1
-rw-r--r--src/gui/browserbox.h1
-rw-r--r--src/gui/buddywindow.cpp68
-rw-r--r--src/gui/buddywindow.h60
-rw-r--r--src/gui/buy.cpp24
-rw-r--r--src/gui/buy.h20
-rw-r--r--src/gui/buysell.cpp6
-rw-r--r--src/gui/changeemaildialog.cpp167
-rw-r--r--src/gui/changeemaildialog.h71
-rw-r--r--src/gui/changepassworddialog.cpp193
-rw-r--r--src/gui/changepassworddialog.h72
-rw-r--r--src/gui/char_select.cpp360
-rw-r--r--src/gui/char_select.h64
-rw-r--r--src/gui/char_server.cpp2
-rw-r--r--src/gui/chat.cpp715
-rw-r--r--src/gui/chat.h229
-rw-r--r--src/gui/chatinput.h2
-rw-r--r--src/gui/connection.cpp23
-rw-r--r--src/gui/connection.h13
-rw-r--r--src/gui/equipmentwindow.cpp57
-rw-r--r--src/gui/equipmentwindow.h27
-rw-r--r--src/gui/gui.cpp6
-rw-r--r--src/gui/guildlistbox.cpp130
-rw-r--r--src/gui/guildlistbox.h65
-rw-r--r--src/gui/guildwindow.cpp273
-rw-r--r--src/gui/guildwindow.h135
-rw-r--r--src/gui/icon.cpp58
-rw-r--r--src/gui/icon.h68
-rw-r--r--src/gui/inventorywindow.cpp136
-rw-r--r--src/gui/inventorywindow.h43
-rw-r--r--src/gui/item_amount.cpp19
-rw-r--r--src/gui/item_amount.h5
-rw-r--r--src/gui/itemcontainer.cpp433
-rw-r--r--src/gui/itemcontainer.h81
-rw-r--r--src/gui/itempopup.cpp4
-rw-r--r--src/gui/itemshortcutcontainer.cpp5
-rw-r--r--src/gui/itemshortcutwindow.cpp71
-rw-r--r--src/gui/itemshortcutwindow.h61
-rw-r--r--src/gui/linkhandler.h2
-rw-r--r--src/gui/login.cpp40
-rw-r--r--src/gui/login.h14
-rw-r--r--src/gui/magic.cpp92
-rw-r--r--src/gui/magic.h75
-rw-r--r--src/gui/menuwindow.cpp56
-rw-r--r--src/gui/minimap.cpp11
-rw-r--r--src/gui/ministatus.cpp18
-rw-r--r--src/gui/ministatus.h2
-rw-r--r--src/gui/npc_text.cpp25
-rw-r--r--src/gui/npc_text.h8
-rw-r--r--src/gui/npcintegerdialog.cpp17
-rw-r--r--src/gui/npcintegerdialog.h8
-rw-r--r--src/gui/npclistdialog.cpp26
-rw-r--r--src/gui/npclistdialog.h13
-rw-r--r--src/gui/npcpostdialog.cpp101
-rw-r--r--src/gui/npcpostdialog.h55
-rw-r--r--src/gui/npcstringdialog.cpp17
-rw-r--r--src/gui/npcstringdialog.h10
-rw-r--r--src/gui/partywindow.cpp145
-rw-r--r--src/gui/partywindow.h96
-rw-r--r--src/gui/passwordfield.h2
-rw-r--r--src/gui/playerbox.cpp13
-rw-r--r--src/gui/popupmenu.cpp46
-rw-r--r--src/gui/progressbar.cpp41
-rw-r--r--src/gui/progressbar.h19
-rw-r--r--src/gui/quitdialog.cpp135
-rw-r--r--src/gui/quitdialog.h70
-rw-r--r--src/gui/recorder.cpp4
-rw-r--r--src/gui/recorder.h14
-rw-r--r--src/gui/register.cpp61
-rw-r--r--src/gui/register.h23
-rw-r--r--src/gui/sell.cpp28
-rw-r--r--src/gui/sell.h12
-rw-r--r--src/gui/serverdialog.cpp214
-rw-r--r--src/gui/serverdialog.h123
-rw-r--r--src/gui/setup.cpp12
-rw-r--r--src/gui/setup_audio.cpp1
-rw-r--r--src/gui/setup_video.cpp15
-rw-r--r--src/gui/setup_video.h2
-rw-r--r--src/gui/shop.cpp12
-rw-r--r--src/gui/shop.h16
-rw-r--r--src/gui/skilldialog.cpp263
-rw-r--r--src/gui/skilldialog.h139
-rw-r--r--src/gui/speechbubble.cpp1
-rw-r--r--src/gui/speechbubble.h1
-rw-r--r--src/gui/status.cpp18
-rw-r--r--src/gui/status.h2
-rw-r--r--src/gui/statuswindow.cpp376
-rw-r--r--src/gui/statuswindow.h107
-rw-r--r--src/gui/storagewindow.cpp6
-rw-r--r--src/gui/textdialog.cpp91
-rw-r--r--src/gui/textdialog.h66
-rw-r--r--src/gui/trade.cpp161
-rw-r--r--src/gui/trade.h55
-rw-r--r--src/gui/unregisterdialog.cpp141
-rw-r--r--src/gui/unregisterdialog.h70
-rw-r--r--src/gui/updatewindow.cpp4
-rw-r--r--src/gui/updatewindow.h2
-rw-r--r--src/gui/viewport.cpp158
-rw-r--r--src/gui/viewport.h26
-rw-r--r--src/gui/widgets/avatar.cpp53
-rw-r--r--src/gui/widgets/avatar.h59
101 files changed, 6210 insertions, 1051 deletions
diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp
index 596174cc..2f667237 100644
--- a/src/gui/browserbox.cpp
+++ b/src/gui/browserbox.cpp
@@ -418,4 +418,3 @@ void BrowserBox::draw(gcn::Graphics *graphics)
setHeight((mTextRows.size() + wrappedLines) * font->getHeight());
}
}
-
diff --git a/src/gui/browserbox.h b/src/gui/browserbox.h
index 5dde402e..090c03e1 100644
--- a/src/gui/browserbox.h
+++ b/src/gui/browserbox.h
@@ -162,4 +162,3 @@ class BrowserBox : public gcn::Widget, public gcn::MouseListener
};
#endif
-
diff --git a/src/gui/buddywindow.cpp b/src/gui/buddywindow.cpp
new file mode 100644
index 00000000..25084593
--- /dev/null
+++ b/src/gui/buddywindow.cpp
@@ -0,0 +1,68 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "buddywindow.h"
+#include "chat.h"
+#include "icon.h"
+
+#include "widgets/avatar.h"
+
+#include "../resources/resourcemanager.h"
+#include "../utils/gettext.h"
+
+extern ChatWindow *chatWindow;
+
+BuddyWindow::BuddyWindow():
+ Window(_("Buddy"))
+{
+ setVisible(false);
+ setWindowName("Buddy Window");
+ setCaption(_("Buddy List"));
+ setResizable(true);
+ setCloseButton(true);
+ setMinWidth(110);
+ setMinHeight(200);
+ setDefaultSize(124, 41, 288, 330);
+
+ Image *addImg = ResourceManager::getInstance()->getImage("buddyadd.png");
+ Image *delImg = ResourceManager::getInstance()->getImage("buddydel.png");
+
+ if (addImg && delImg)
+ {
+ Icon *addBuddy = new Icon(addImg);
+ Icon *delBuddy = new Icon(delImg);
+
+ add(addBuddy);
+ add(delBuddy);
+ }
+
+ loadWindowState();
+}
+
+void BuddyWindow::action(const gcn::ActionEvent &event)
+{
+
+}
+
+void BuddyWindow::draw(gcn::Graphics *graphics)
+{
+ Window::draw(graphics);
+}
diff --git a/src/gui/buddywindow.h b/src/gui/buddywindow.h
new file mode 100644
index 00000000..dfe356d5
--- /dev/null
+++ b/src/gui/buddywindow.h
@@ -0,0 +1,60 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_BUDDYWINDOW_H
+#define _TMW_BUDDYWINDOW_H
+
+#include <guichan/actionlistener.hpp>
+#include <guichan/actionevent.hpp>
+
+#include "window.h"
+
+class Avatar;
+
+/**
+ * Window showing buddy list.
+ *
+ * \ingroup Interface
+ */
+class BuddyWindow : public Window, public gcn::ActionListener
+{
+ public:
+ /**
+ * Constructor.
+ */
+ BuddyWindow();
+
+ /**
+ * Performs action.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ /**
+ * Draws the window
+ */
+ void draw(gcn::Graphics *graphics);
+
+
+ private:
+ std::list<Avatar*> mBuddyList;
+};
+
+#endif /* _TMW_BUDDYWINDOW_H */
diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp
index c5c37601..0b572a23 100644
--- a/src/gui/buy.cpp
+++ b/src/gui/buy.cpp
@@ -32,14 +32,25 @@
#include "../npc.h"
#include "../units.h"
+#ifdef TMWSERV_SUPPORT
+#include "../net/tmwserv/gameserver/player.h"
+#else
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#include "../net/ea/protocol.h"
+#endif
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
+#ifdef TMWSERV_SUPPORT
+BuyDialog::BuyDialog():
+#else
BuyDialog::BuyDialog(Network *network):
- Window("Buy"), mNetwork(network),
+#endif
+ Window(_("Buy")),
+#ifndef TMWSERV_SUPPORT
+ mNetwork(network),
+#endif
mMoney(0), mAmountItems(0), mMaxItems(0)
{
setWindowName("Buy");
@@ -128,9 +139,9 @@ void BuyDialog::reset()
setMoney(0);
}
-void BuyDialog::addItem(int id, int price)
+void BuyDialog::addItem(int id, int amount, int price)
{
- mShopItems->addItem(id, price);
+ mShopItems->addItem(id, amount, price);
mShopItemList->adjustSize();
}
@@ -180,11 +191,16 @@ void BuyDialog::action(const gcn::ActionEvent &event)
else if (event.getId() == "buy" && mAmountItems > 0 &&
mAmountItems <= mMaxItems)
{
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::tradeWithNPC
+ (mShopItems->at(selectedItem)->getId(), mAmountItems);
+#else
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_NPC_BUY_REQUEST);
outMsg.writeInt16(8);
outMsg.writeInt16(mAmountItems);
outMsg.writeInt16(mShopItems->at(selectedItem)->getId());
+#endif
// Update money and adjust the max number of items that can be bought
mMaxItems -= mAmountItems;
diff --git a/src/gui/buy.h b/src/gui/buy.h
index 2e6b5377..200394b9 100644
--- a/src/gui/buy.h
+++ b/src/gui/buy.h
@@ -25,11 +25,13 @@
#include <guichan/actionlistener.hpp>
#include <guichan/selectionlistener.hpp>
-#include <SDL_types.h>
-
#include "window.h"
+#include "../guichanfwd.h"
+
+#ifndef TMWSERV_SUPPORT
class Network;
+#endif
class ShopItems;
class ShopListBox;
class ListBox;
@@ -48,7 +50,11 @@ class BuyDialog : public Window, public gcn::ActionListener,
*
* @see Window::Window
*/
+#ifdef TMWSERV_SUPPORT
+ BuyDialog();
+#else
BuyDialog(Network *network);
+#endif
/**
* Destructor
@@ -68,7 +74,7 @@ class BuyDialog : public Window, public gcn::ActionListener,
/**
* Adds an item to the shop inventory.
*/
- void addItem(int id, int price);
+ void addItem(int id, int amount, int price);
/**
* Called when receiving actions from the widgets.
@@ -110,7 +116,9 @@ class BuyDialog : public Window, public gcn::ActionListener,
*/
void close();
private:
+#ifdef EATHENA_SUPPORT
Network *mNetwork;
+#endif
gcn::Button *mBuyButton;
gcn::Button *mQuitButton;
gcn::Button *mAddMaxButton;
@@ -126,9 +134,9 @@ class BuyDialog : public Window, public gcn::ActionListener,
ShopItems *mShopItems;
- Uint32 mMoney;
- Uint32 mAmountItems;
- Uint32 mMaxItems;
+ int mMoney;
+ int mAmountItems;
+ int mMaxItems;
};
extern BuyDialog *buyDialog;
diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp
index 04a27b8c..c56f6435 100644
--- a/src/gui/buysell.cpp
+++ b/src/gui/buysell.cpp
@@ -25,7 +25,9 @@
#include "../npc.h"
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#ifdef EATHENA_SUPPORT
+#include "../net/ea/protocol.h"
+#endif
#include "../utils/gettext.h"
@@ -93,8 +95,10 @@ void BuySellDialog::action(const gcn::ActionEvent &event)
return;
}
+#ifdef EATHENA_SUPPORT
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST);
outMsg.writeInt32(current_npc);
outMsg.writeInt8(action);
+#endif
}
diff --git a/src/gui/changeemaildialog.cpp b/src/gui/changeemaildialog.cpp
new file mode 100644
index 00000000..c9bc2570
--- /dev/null
+++ b/src/gui/changeemaildialog.cpp
@@ -0,0 +1,167 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "changeemaildialog.h"
+
+#include <string>
+#include <sstream>
+
+#include <guichan/widgets/label.hpp>
+
+#include "../main.h"
+#include "../log.h"
+#include "../logindata.h"
+
+#include "button.h"
+#include "register.h"
+#include "textfield.h"
+#include "ok_dialog.h"
+
+#include "../utils/gettext.h"
+#include "../utils/strprintf.h"
+
+ChangeEmailDialog::ChangeEmailDialog(Window *parent, LoginData *loginData):
+ Window(_("Change Email Address"), true, parent),
+ mWrongDataNoticeListener(new WrongDataNoticeListener()),
+ mLoginData(loginData)
+{
+ gcn::Label *accountLabel = new gcn::Label(strprintf(_("Account: %s"),
+ mLoginData->username.c_str()));
+ gcn::Label *newEmailLabel = new gcn::Label(_("Type New Email Address twice:"));
+ mFirstEmailField = new TextField();
+ mSecondEmailField = new TextField();
+ mChangeEmailButton = new Button(_("Change Email Address"), "change_email", this);
+ mCancelButton = new Button(_("Cancel"), "cancel", this);
+
+ const int width = 200;
+ const int height = 130;
+ setContentSize(width, height);
+
+ accountLabel->setPosition(5, 5);
+ accountLabel->setWidth(130);
+
+ newEmailLabel->setPosition(
+ 5, accountLabel->getY() + accountLabel->getHeight() + 7);
+ newEmailLabel->setWidth(width - 5);
+
+ mFirstEmailField->setPosition(
+ 5, newEmailLabel->getY() + newEmailLabel->getHeight() + 7);
+ mFirstEmailField->setWidth(130);
+
+ mSecondEmailField->setPosition(
+ 5, mFirstEmailField->getY() + mFirstEmailField->getHeight() + 7);
+ mSecondEmailField->setWidth(130);
+
+ mCancelButton->setPosition(
+ width - 5 - mCancelButton->getWidth(),
+ height - 5 - mCancelButton->getHeight());
+ mChangeEmailButton->setPosition(
+ mCancelButton->getX() - 5 - mChangeEmailButton->getWidth(),
+ mCancelButton->getY());
+
+ add(accountLabel);
+ add(newEmailLabel);
+ add(mFirstEmailField);
+ add(mSecondEmailField);
+ add(mChangeEmailButton);
+ add(mCancelButton);
+
+ setLocationRelativeTo(getParent());
+ setVisible(true);
+ mFirstEmailField->requestFocus();
+
+ mFirstEmailField->setActionEventId("change_email");
+ mSecondEmailField->setActionEventId("change_email");
+}
+
+ChangeEmailDialog::~ChangeEmailDialog()
+{
+ delete mWrongDataNoticeListener;
+}
+
+void
+ChangeEmailDialog::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "cancel")
+ {
+ scheduleDelete();
+ }
+ else if (event.getId() == "change_email")
+ {
+
+ const std::string username = mLoginData->username.c_str();
+ const std::string newFirstEmail = mFirstEmailField->getText();
+ const std::string newSecondEmail = mSecondEmailField->getText();
+ logger->log("ChangeEmailDialog::Email change, Username is %s",
+ username.c_str());
+
+ std::stringstream errorMsg;
+ int error = 0;
+
+ if (newFirstEmail.length() < LEN_MIN_PASSWORD)
+ {
+ // First email address too short
+ errorMsg << "The new email address needs to be at least "
+ << LEN_MIN_PASSWORD
+ << " characters long.";
+ error = 1;
+ }
+ else if (newFirstEmail.length() > LEN_MAX_PASSWORD - 1 )
+ {
+ // First email address too long
+ errorMsg << "The new email address needs to be less than "
+ << LEN_MAX_PASSWORD
+ << " characters long.";
+ error = 1;
+ }
+ else if (newFirstEmail != newSecondEmail)
+ {
+ // Second Pass mismatch
+ errorMsg << "The email address entries mismatch.";
+ error = 2;
+ }
+
+ if (error > 0)
+ {
+ if (error == 1)
+ {
+ mWrongDataNoticeListener->setTarget(this->mFirstEmailField);
+ }
+ else if (error == 2)
+ {
+ mWrongDataNoticeListener->setTarget(this->mSecondEmailField);
+ }
+
+ OkDialog *dlg = new OkDialog("Error", errorMsg.str());
+ dlg->addActionListener(mWrongDataNoticeListener);
+ }
+ else
+ {
+ // No errors detected, change account password.
+ mChangeEmailButton->setEnabled(false);
+ // Set the new email address
+ mLoginData->newEmail = newFirstEmail;
+ state = STATE_CHANGEEMAIL_ATTEMPT;
+ scheduleDelete();
+ }
+
+ }
+}
diff --git a/src/gui/changeemaildialog.h b/src/gui/changeemaildialog.h
new file mode 100644
index 00000000..8ec3705d
--- /dev/null
+++ b/src/gui/changeemaildialog.h
@@ -0,0 +1,71 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_GUI_CHANGEEMAIL_H
+#define _TMW_GUI_CHANGEEMAIL_H
+
+#include <iosfwd>
+#include <guichan/actionlistener.hpp>
+
+#include "window.h"
+#include "../guichanfwd.h"
+
+class LoginData;
+class OkDialog;
+class WrongDataNoticeListener;
+
+/**
+ * The Change email dialog.
+ *
+ * \ingroup Interface
+ */
+class ChangeEmailDialog : public Window, public gcn::ActionListener {
+ public:
+ /**
+ * Constructor.
+ *
+ * @see Window::Window
+ */
+ ChangeEmailDialog(Window *parent, LoginData *loginData);
+
+ /**
+ * Destructor.
+ */
+ ~ChangeEmailDialog();
+
+ /**
+ * Called when receiving actions from the widgets.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ private:
+ gcn::TextField *mFirstEmailField;
+ gcn::TextField *mSecondEmailField;
+
+ gcn::Button *mChangeEmailButton;
+ gcn::Button *mCancelButton;
+
+ WrongDataNoticeListener *mWrongDataNoticeListener;
+
+ LoginData *mLoginData;
+};
+
+#endif
diff --git a/src/gui/changepassworddialog.cpp b/src/gui/changepassworddialog.cpp
new file mode 100644
index 00000000..8d667790
--- /dev/null
+++ b/src/gui/changepassworddialog.cpp
@@ -0,0 +1,193 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "changepassworddialog.h"
+
+#include <string>
+#include <sstream>
+
+#include <guichan/widgets/label.hpp>
+
+#include "../main.h"
+#include "../log.h"
+#include "../logindata.h"
+
+#include "button.h"
+#include "register.h"
+#include "passwordfield.h"
+#include "textfield.h"
+#include "ok_dialog.h"
+
+#include "../utils/gettext.h"
+#include "../utils/strprintf.h"
+
+ChangePasswordDialog::ChangePasswordDialog(Window *parent, LoginData *loginData):
+ Window(_("Change Password"), true, parent),
+ mWrongDataNoticeListener(new WrongDataNoticeListener()),
+ mLoginData(loginData)
+{
+ gcn::Label *accountLabel = new gcn::Label(strprintf(_("Account: %s"),
+ mLoginData->username.c_str()));
+ gcn::Label *oldPassLabel = new gcn::Label(_("Password:"));
+ mOldPassField = new PasswordField();
+ gcn::Label *newPassLabel = new gcn::Label(_("Type New Password twice:"));
+ mFirstPassField = new PasswordField();
+ mSecondPassField = new PasswordField();
+ mChangePassButton = new Button(_("Change Password"), "change_password", this);
+ mCancelButton = new Button(_("Cancel"), "cancel", this);
+
+ const int width = 200;
+ const int height = 170;
+ setContentSize(width, height);
+
+ accountLabel->setPosition(5, 5);
+ accountLabel->setWidth(130);
+ oldPassLabel->setPosition(
+ 5, accountLabel->getY() + accountLabel->getHeight() + 7);
+ oldPassLabel->setWidth(130);
+
+ mOldPassField->setPosition(
+ 5, oldPassLabel->getY() + oldPassLabel->getHeight() + 7);
+ mOldPassField->setWidth(130);
+
+ newPassLabel->setPosition(
+ 5, mOldPassField->getY() + mOldPassField->getHeight() + 7);
+ newPassLabel->setWidth(width - 5);
+
+ mFirstPassField->setPosition(
+ 5, newPassLabel->getY() + newPassLabel->getHeight() + 7);
+ mFirstPassField->setWidth(130);
+
+ mSecondPassField->setPosition(
+ 5, mFirstPassField->getY() + mFirstPassField->getHeight() + 7);
+ mSecondPassField->setWidth(130);
+
+ mCancelButton->setPosition(
+ width - 5 - mCancelButton->getWidth(),
+ height - 5 - mCancelButton->getHeight());
+ mChangePassButton->setPosition(
+ mCancelButton->getX() - 5 - mChangePassButton->getWidth(),
+ mCancelButton->getY());
+
+ add(accountLabel);
+ add(oldPassLabel);
+ add(mOldPassField);
+ add(newPassLabel);
+ add(mFirstPassField);
+ add(mSecondPassField);
+ add(mChangePassButton);
+ add(mCancelButton);
+
+ setLocationRelativeTo(getParent());
+ setVisible(true);
+ mOldPassField->requestFocus();
+
+ mOldPassField->setActionEventId("change_password");
+ mFirstPassField->setActionEventId("change_password");
+ mSecondPassField->setActionEventId("change_password");
+}
+
+ChangePasswordDialog::~ChangePasswordDialog()
+{
+ delete mWrongDataNoticeListener;
+}
+
+void
+ChangePasswordDialog::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "cancel")
+ {
+ scheduleDelete();
+ }
+ else if (event.getId() == "change_password")
+ {
+
+ const std::string username = mLoginData->username.c_str();
+ const std::string oldPassword = mOldPassField->getText();
+ const std::string newFirstPass = mFirstPassField->getText();
+ const std::string newSecondPass = mSecondPassField->getText();
+ logger->log("ChangePasswordDialog::Password change, Username is %s",
+ username.c_str());
+
+ std::stringstream errorMsg;
+ int error = 0;
+
+ // Check old Password
+ if (oldPassword.empty())
+ {
+ // No old password
+ errorMsg << "Enter the old Password first.";
+ error = 1;
+ }
+ else if (newFirstPass.length() < LEN_MIN_PASSWORD)
+ {
+ // First password too short
+ errorMsg << "The new password needs to be at least "
+ << LEN_MIN_PASSWORD
+ << " characters long.";
+ error = 2;
+ }
+ else if (newFirstPass.length() > LEN_MAX_PASSWORD - 1 )
+ {
+ // First password too long
+ errorMsg << "The new password needs to be less than "
+ << LEN_MAX_PASSWORD
+ << " characters long.";
+ error = 2;
+ }
+ else if (newFirstPass != newSecondPass)
+ {
+ // Second Pass mismatch
+ errorMsg << "The new password entries mismatch.";
+ error = 3;
+ }
+
+ if (error > 0)
+ {
+ if (error == 1)
+ {
+ mWrongDataNoticeListener->setTarget(this->mOldPassField);
+ }
+ else if (error == 2)
+ {
+ mWrongDataNoticeListener->setTarget(this->mFirstPassField);
+ }
+ else if (error == 3)
+ {
+ mWrongDataNoticeListener->setTarget(this->mSecondPassField);
+ }
+
+ OkDialog *dlg = new OkDialog("Error", errorMsg.str());
+ dlg->addActionListener(mWrongDataNoticeListener);
+ }
+ else
+ {
+ // No errors detected, change account password.
+ mChangePassButton->setEnabled(false);
+ // Set the new password
+ mLoginData->password = oldPassword;
+ mLoginData->newPassword = newFirstPass;
+ state = STATE_CHANGEPASSWORD_ATTEMPT;
+ scheduleDelete();
+ }
+
+ }
+}
diff --git a/src/gui/changepassworddialog.h b/src/gui/changepassworddialog.h
new file mode 100644
index 00000000..0cf744da
--- /dev/null
+++ b/src/gui/changepassworddialog.h
@@ -0,0 +1,72 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_CHANGEPASSWORDDIALOG_H
+#define _TMW_CHANGEPASSWORDDIALOG_H
+
+#include <iosfwd>
+#include <guichan/actionlistener.hpp>
+
+#include "window.h"
+#include "../guichanfwd.h"
+
+class LoginData;
+class OkDialog;
+class WrongDataNoticeListener;
+
+/**
+ * The Change password dialog.
+ *
+ * \ingroup Interface
+ */
+class ChangePasswordDialog : public Window, public gcn::ActionListener {
+ public:
+ /**
+ * Constructor
+ *
+ * @see Window::Window
+ */
+ ChangePasswordDialog(Window *parent,LoginData *loginData);
+
+ /**
+ * Destructor
+ */
+ ~ChangePasswordDialog();
+
+ /**
+ * Called when receiving actions from the widgets.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ private:
+ gcn::TextField *mOldPassField;
+ gcn::TextField *mFirstPassField;
+ gcn::TextField *mSecondPassField;
+
+ gcn::Button *mChangePassButton;
+ gcn::Button *mCancelButton;
+
+ WrongDataNoticeListener *mWrongDataNoticeListener;
+
+ LoginData *mLoginData;
+};
+
+#endif
diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp
index aaf4e8c4..7c0e2ab2 100644
--- a/src/gui/char_select.cpp
+++ b/src/gui/char_select.cpp
@@ -31,6 +31,22 @@
#include "playerbox.h"
#include "textfield.h"
+#ifdef TMWSERV_SUPPORT
+#include "radiobutton.h"
+#include "slider.h"
+
+#include "unregisterdialog.h"
+#include "changepassworddialog.h"
+#include "changeemaildialog.h"
+
+#include "../logindata.h"
+
+#include "../net/tmwserv/accountserver/account.h"
+#include "../net/tmwserv/charserverhandler.h"
+#else
+#include "../net/ea/charserverhandler.h"
+#endif
+
#include "widgets/layout.h"
#include "../game.h"
@@ -38,7 +54,6 @@
#include "../main.h"
#include "../units.h"
-#include "../net/charserverhandler.h"
#include "../net/messageout.h"
#include "../resources/colordb.h"
@@ -47,6 +62,8 @@
#include "../utils/strprintf.h"
#include "../utils/stringutils.h"
+#define MAX_SLOT 2
+
// Defined in main.cpp, used here for setting the char create dialog
extern CharServerHandler charServerHandler;
@@ -79,22 +96,72 @@ void CharDeleteConfirm::action(const gcn::ActionEvent &event)
ConfirmDialog::action(event);
}
+#ifdef TMWSERV_SUPPORT
+CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo,
+ LoginData *loginData):
+ Window(_("Account and Character Management")),
+ mCharInfo(charInfo), mCharSelected(false), mLoginData(loginData)
+#else
CharSelectDialog::CharSelectDialog(Network *network,
LockedArray<LocalPlayer*> *charInfo,
Gender gender):
Window(_("Select Character")), mNetwork(network),
- mCharInfo(charInfo), mGender(gender), mCharSelected(false)
+ mCharInfo(charInfo),
+ mCharSelected(false),
+ mGender(gender)
+#endif
{
+ mSelectButton = new Button(_("Ok"), "ok", this);
+ mCancelButton = new Button(_("Cancel"), "cancel", this);
+ mPreviousButton = new Button(_("Previous"), "previous", this);
+ mNextButton = new Button(_("Next"), "next", this);
+ mNameLabel = new Label(strprintf(_("Name: %s"), ""));
+ mLevelLabel = new Label(strprintf(_("Level: %d"), 0));
+#ifdef TMWSERV_SUPPORT
+ mNewCharButton = new Button(_("New"), "new", this);
+ mDelCharButton = new Button(_("Delete"), "delete", this);
+ mUnRegisterButton = new Button(_("Unregister"), "unregister", this);
+ mChangePasswordButton = new Button(_("Change Password"), "change_password", this);
+ mChangeEmailButton = new Button(_("Change Email Address"), "change_email", this);
+
+ mAccountNameLabel = new Label(strprintf(_("Account: %s"), mLoginData->username.c_str()));
+ mNameLabel = new Label(strprintf(_("Name: %s"), ""));
+ mLevelLabel = new Label(strprintf(_("Level: %d"), 0));
+ mMoneyLabel = new Label(strprintf(_("Money: %d"), 0));
+
+ // Control that shows the Player
+ mPlayerBox = new PlayerBox;
+ mPlayerBox->setWidth(74);
+
+ ContainerPlacer place;
+ place = getPlacer(0, 0);
+ place(0, 0, mAccountNameLabel);
+ place(0, 1, mUnRegisterButton);
+ place(0, 2, mChangePasswordButton);
+ place(1, 2, mChangeEmailButton);
+ place = getPlacer(0, 1);
+ place(0, 0, mPlayerBox, 1, 5).setPadding(3);
+ place(1, 0, mNameLabel, 3);
+ place(1, 1, mLevelLabel, 3);
+ place(1, 2, mMoneyLabel, 3);
+ place(1, 3, mPreviousButton);
+ place(2, 3, mNextButton);
+ place(1, 4, mNewCharButton);
+ place(2, 4, mDelCharButton);
+ place.getCell().matchColWidth(1, 2);
+ place = getPlacer(0, 2);
+ place(0, 0, mSelectButton);
+ place(1, 0, mCancelButton);
+ reflowLayout(265, 0);
+#else
mCharInfo->select(0);
LocalPlayer *pi = mCharInfo->getEntry();
if (pi)
- mMoney = Units::formatCurrency(pi->mGp);
+ mMoney = Units::formatCurrency(pi->getMoney());
// Control that shows the Player
mPlayerBox = new PlayerBox;
mPlayerBox->setWidth(74);
- mNameLabel = new Label(strprintf(_("Name: %s"), ""));
- mLevelLabel = new Label(strprintf(_("Level: %d"), 0));
mJobLevelLabel = new Label(strprintf(_("Job Level: %d"), 0));
mMoneyLabel = new Label(strprintf(_("Money: %s"), mMoney.c_str()));
@@ -102,11 +169,7 @@ CharSelectDialog::CharSelectDialog(Network *network,
getFont()->getWidth(_("Delete")) ?
_("Delete") : _("New");
- mPreviousButton = new Button(_("Previous"), "previous", this);
- mNextButton = new Button(_("Next"), "next", this);
mNewDelCharButton = new Button(tempString, "newdel", this);
- mSelectButton = new Button(_("Ok"), "ok", this);
- mCancelButton = new Button(_("Cancel"), "cancel", this);
ContainerPlacer place;
place = getPlacer(0, 0);
@@ -125,6 +188,7 @@ CharSelectDialog::CharSelectDialog(Network *network,
place(5, 0, mSelectButton);
reflowLayout(250, 0);
+#endif
center();
setVisible(true);
@@ -134,10 +198,21 @@ CharSelectDialog::CharSelectDialog(Network *network,
void CharSelectDialog::action(const gcn::ActionEvent &event)
{
+#ifdef TMWSERV_SUPPORT
+ // The pointers are set to NULL if there is no character stored
+ if (event.getId() == "ok" && (mCharInfo->getEntry()))
+#else
if (event.getId() == "ok" && n_character > 0)
+#endif
{
// Start game
+#ifdef TMWSERV_SUPPORT
+ mNewCharButton->setEnabled(false);
+ mDelCharButton->setEnabled(false);
+ mUnRegisterButton->setEnabled(false);
+#else
mNewDelCharButton->setEnabled(false);
+#endif
mSelectButton->setEnabled(false);
mPreviousButton->setEnabled(false);
mNextButton->setEnabled(false);
@@ -146,8 +221,35 @@ void CharSelectDialog::action(const gcn::ActionEvent &event)
}
else if (event.getId() == "cancel")
{
- state = EXIT_STATE;
+#ifdef TMWSERV_SUPPORT
+ mCharInfo->clear();
+ state = STATE_SWITCH_ACCOUNTSERVER_ATTEMPT;
+#else
+ state = STATE_EXIT;
+#endif
+ }
+#ifdef TMWSERV_SUPPORT
+ else if (event.getId() == "new")
+ {
+ // TODO: Search the first free slot, and start CharCreateDialog
+ // maybe add that search to the constructor.
+ if (!(mCharInfo->getEntry()))
+ {
+ // Start new character dialog
+ CharCreateDialog *charCreateDialog =
+ new CharCreateDialog(this, mCharInfo->getPos());
+ charServerHandler.setCharCreateDialog(charCreateDialog);
+ }
+ }
+ else if (event.getId() == "delete")
+ {
+ // Delete character
+ if (mCharInfo->getEntry())
+ {
+ new CharDeleteConfirm(this);
+ }
}
+#else
else if (event.getId() == "newdel")
{
// Check for a character
@@ -164,20 +266,35 @@ void CharSelectDialog::action(const gcn::ActionEvent &event)
charServerHandler.setCharCreateDialog(charCreateDialog);
}
}
+#endif
else if (event.getId() == "previous")
{
mCharInfo->prev();
LocalPlayer *pi = mCharInfo->getEntry();
if (pi)
- mMoney = Units::formatCurrency(pi->mGp);
+ mMoney = Units::formatCurrency(pi->getMoney());
}
else if (event.getId() == "next")
{
mCharInfo->next();
LocalPlayer *pi = mCharInfo->getEntry();
if (pi)
- mMoney = Units::formatCurrency(pi->mGp);
+ mMoney = Units::formatCurrency(pi->getMoney());
}
+#ifdef TMWSERV_SUPPORT
+ else if (event.getId() == "unregister")
+ {
+ new UnRegisterDialog(this, mLoginData);
+ }
+ else if (event.getId() == "change_password")
+ {
+ new ChangePasswordDialog(this, mLoginData);
+ }
+ else if (event.getId() == "change_email")
+ {
+ new ChangeEmailDialog(this, mLoginData);
+ }
+#endif
}
void CharSelectDialog::updatePlayerInfo()
@@ -188,13 +305,20 @@ void CharSelectDialog::updatePlayerInfo()
{
mNameLabel->setCaption(strprintf(_("Name: %s"),
pi->getName().c_str()));
- mLevelLabel->setCaption(strprintf(_("Level: %d"), pi->mLevel));
+ mLevelLabel->setCaption(strprintf(_("Level: %d"), pi->getLevel()));
+#ifndef TMWSERV_SUPPORT
mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"),
pi->mJobLevel));
+#endif
mMoneyLabel->setCaption(strprintf(_("Money: %s"), mMoney.c_str()));
if (!mCharSelected)
{
+#ifdef TMWSERV_SUPPORT
+ mNewCharButton->setEnabled(false);
+ mDelCharButton->setEnabled(true);
+#else
mNewDelCharButton->setCaption(_("Delete"));
+#endif
mSelectButton->setEnabled(true);
}
}
@@ -202,9 +326,16 @@ void CharSelectDialog::updatePlayerInfo()
{
mNameLabel->setCaption(strprintf(_("Name: %s"), ""));
mLevelLabel->setCaption(strprintf(_("Level: %d"), 0));
+#ifndef TMWSERV_SUPPORT
mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"), 0));
+#endif
mMoneyLabel->setCaption(strprintf(_("Money: %s"), ""));
+#ifdef TMWSERV_SUPPORT
+ mNewCharButton->setEnabled(true);
+ mDelCharButton->setEnabled(false);
+#else
mNewDelCharButton->setCaption(_("New"));
+#endif
mSelectButton->setEnabled(false);
}
@@ -213,20 +344,28 @@ void CharSelectDialog::updatePlayerInfo()
void CharSelectDialog::attemptCharDelete()
{
+#ifdef TMWSERV_SUPPORT
+ Net::AccountServer::Account::deleteCharacter(mCharInfo->getPos());
+#else
// Request character deletion
MessageOut outMsg(mNetwork);
outMsg.writeInt16(0x0068);
outMsg.writeInt32(mCharInfo->getEntry()->mCharId);
outMsg.writeString("a@a.com", 40);
+#endif
mCharInfo->lock();
}
void CharSelectDialog::attemptCharSelect()
{
+#ifdef TMWSERV_SUPPORT
+ Net::AccountServer::Account::selectCharacter(mCharInfo->getPos());
+#else
// Request character selection
MessageOut outMsg(mNetwork);
outMsg.writeInt16(0x0066);
outMsg.writeInt8(mCharInfo->getPos());
+#endif
mCharInfo->lock();
}
@@ -258,16 +397,29 @@ bool CharSelectDialog::selectByName(const std::string &name)
return false;
}
+#ifdef TMWSERV_SUPPORT
+CharCreateDialog::CharCreateDialog(Window *parent, int slot):
+#else
CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network,
Gender gender):
- Window(_("Create Character"), true, parent), mNetwork(network), mSlot(slot)
+#endif
+ Window(_("Create Character"), true, parent),
+#ifndef TMWSERV_SUPPORT
+ mNetwork(network),
+#endif
+ mSlot(slot)
{
mPlayer = new Player(0, 0, NULL);
+#ifdef TMWSERV_SUPPORT
+ mPlayer->setGender(GENDER_MALE);
+#else
mPlayer->setGender(gender);
+#endif
int numberOfHairColors = ColorDB::size();
- mPlayer->setHairStyle(rand() % mPlayer->getNumOfHairstyles(), rand() % numberOfHairColors);
+ mPlayer->setHairStyle(rand() % mPlayer->getNumOfHairstyles(),
+ rand() % numberOfHairColors);
mNameField = new TextField("");
mNameLabel = new Label(_("Name:"));
@@ -279,6 +431,19 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network,
mHairStyleLabel = new Label(_("Hair Style:"));
mCreateButton = new Button(_("Create"), "create", this);
mCancelButton = new Button(_("Cancel"), "cancel", this);
+#ifdef TMWSERV_SUPPORT
+ mMale = new RadioButton(_("Male"), "gender");
+ mFemale = new RadioButton(_("Female"), "gender");
+
+ // Default to a Male character
+ mMale->setSelected(true);
+
+ mMale->setActionEventId("gender");
+ mFemale->setActionEventId("gender");
+
+ mMale->addActionListener(this);
+ mFemale->addActionListener(this);
+#endif
mPlayerBox = new PlayerBox(mPlayer);
mPlayerBox->setWidth(74);
@@ -286,6 +451,81 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network,
mNameField->setActionEventId("create");
mNameField->addActionListener(this);
+#ifdef TMWSERV_SUPPORT
+ mAttributeLabel[0] = new gcn::Label(_("Strength:"));
+ mAttributeLabel[1] = new gcn::Label(_("Agility:"));
+ mAttributeLabel[2] = new gcn::Label(_("Dexterity:"));
+ mAttributeLabel[3] = new gcn::Label(_("Vitality:"));
+ mAttributeLabel[4] = new gcn::Label(_("Intelligence:"));
+ mAttributeLabel[5] = new gcn::Label(_("Willpower:"));
+ for (int i = 0; i < 6; i++)
+ {
+ mAttributeLabel[i]->setWidth(70);
+ mAttributeSlider[i] = new Slider(1, 20);
+ mAttributeValue[i] = new gcn::Label("1");
+ };
+
+ mAttributesLeft = new gcn::Label(strprintf(_("Please distribute %d points"), 99));
+
+ int w = 200;
+ int h = 330;
+ setContentSize(w, h);
+ mPlayerBox->setDimension(gcn::Rectangle(80, 30, 110, 85));
+ mNameLabel->setPosition(5, 5);
+ mNameField->setDimension(
+ gcn::Rectangle(45, 5, w - 45 - 7, mNameField->getHeight()));
+ mPrevHairColorButton->setPosition(90, 35);
+ mNextHairColorButton->setPosition(165, 35);
+ mHairColorLabel->setPosition(5, 40);
+ mPrevHairStyleButton->setPosition(90, 64);
+ mNextHairStyleButton->setPosition(165, 64);
+ mHairStyleLabel->setPosition(5, 70);
+ for (int i=0; i<6; i++)
+ {
+ mAttributeSlider[i]->setValue(10);
+ mAttributeSlider[i]->setDimension(gcn::Rectangle( 75, 140 + i*20,
+ 100, 10));
+ mAttributeSlider[i]->setActionEventId("statslider");
+ mAttributeSlider[i]->addActionListener(this);
+ mAttributeValue[i]->setPosition(180, 140 + i*20);
+ mAttributeLabel[i]->setPosition(5, 140 + i*20);
+ };
+ mAttributesLeft->setPosition(15, 280);
+ UpdateSliders();
+ mCancelButton->setPosition(
+ w - 5 - mCancelButton->getWidth(),
+ h - 5 - mCancelButton->getHeight());
+ mCreateButton->setPosition(
+ mCancelButton->getX() - 5 - mCreateButton->getWidth(),
+ h - 5 - mCancelButton->getHeight());
+
+ mMale->setPosition(30, 120);
+ mFemale->setPosition(100, 120);
+
+ add(mPlayerBox);
+ add(mNameField);
+ add(mNameLabel);
+ add(mNextHairColorButton);
+ add(mPrevHairColorButton);
+ add(mHairColorLabel);
+ add(mNextHairStyleButton);
+ add(mPrevHairStyleButton);
+ add(mHairStyleLabel);
+ for (int i = 0; i < 6; i++)
+ {
+ add(mAttributeSlider[i]);
+ add(mAttributeValue[i]);
+ add(mAttributeLabel[i]);
+ };
+ add(mAttributesLeft);
+ add(mCreateButton);
+ add(mCancelButton);
+
+ add(mMale);
+ add(mFemale);
+
+#else
+
ContainerPlacer place;
place = getPlacer(0, 0);
@@ -304,6 +544,7 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network,
place(5, 0, mCreateButton);
reflowLayout(225, 0);
+#endif
center();
setVisible(true);
@@ -327,12 +568,35 @@ void CharCreateDialog::action(const gcn::ActionEvent &event)
{
// Attempt to create the character
mCreateButton->setEnabled(false);
+#ifdef TMWSERV_SUPPORT
+ unsigned int genderSelected;
+ if (mMale->isSelected()) {
+ genderSelected = GENDER_MALE;
+ } else {
+ genderSelected = GENDER_FEMALE;
+ }
+
+ Net::AccountServer::Account::createCharacter(
+ getName(),
+ mPlayer->getHairStyle(),
+ mPlayer->getHairColor(),
+ genderSelected, // gender
+ (int) mAttributeSlider[0]->getValue(), // STR
+ (int) mAttributeSlider[1]->getValue(), // AGI
+ (int) mAttributeSlider[2]->getValue(), // DEX
+ (int) mAttributeSlider[3]->getValue(), // VIT
+ (int) mAttributeSlider[4]->getValue(), // INT
+ (int) mAttributeSlider[5]->getValue() // WILL
+ );
+#else
attemptCharCreate();
+#endif
}
else
{
- new OkDialog("Error",
- "Your name needs to be at least 4 characters.", this);
+ new OkDialog(_("Error"),
+ _("Your name needs to be at least 4 characters."),
+ this);
}
}
else if (event.getId() == "cancel")
@@ -351,6 +615,18 @@ void CharCreateDialog::action(const gcn::ActionEvent &event)
mPlayer->setHairStyle(mPlayer->getHairStyle() +
mPlayer->getNumOfHairstyles() - 1,
mPlayer->getHairColor());
+#ifdef TMWSERV_SUPPORT
+ else if (event.getId() == "statslider") {
+ UpdateSliders();
+ }
+ else if (event.getId() == "gender"){
+ if (mMale->isSelected()) {
+ mPlayer->setGender(GENDER_MALE);
+ } else {
+ mPlayer->setGender(GENDER_FEMALE);
+ }
+ }
+#endif
}
std::string CharCreateDialog::getName()
@@ -360,11 +636,60 @@ std::string CharCreateDialog::getName()
return name;
}
+#ifdef TMWSERV_SUPPORT
+void CharCreateDialog::UpdateSliders()
+{
+ for (int i = 0; i < 6; i++)
+ {
+ // Update captions
+ mAttributeValue[i]->setCaption(
+ toString((int) (mAttributeSlider[i]->getValue())));
+ mAttributeValue[i]->adjustSize();
+ }
+
+ // Update distributed points
+ int pointsLeft = 60 - getDistributedPoints();
+ if (pointsLeft == 0)
+ {
+ mAttributesLeft->setCaption(_("Character stats OK"));
+ mCreateButton->setEnabled(true);
+ }
+ else
+ {
+ mCreateButton->setEnabled(false);
+ if (pointsLeft > 0)
+ {
+ mAttributesLeft->setCaption(strprintf(_("Please distribute %d points"), pointsLeft));
+ }
+ else
+ {
+ mAttributesLeft->setCaption(strprintf(_("Please remove %d points"), -pointsLeft));
+ }
+ }
+
+ mAttributesLeft->adjustSize();
+}
+#endif
+
void CharCreateDialog::unlock()
{
mCreateButton->setEnabled(true);
}
+#ifdef TMWSERV_SUPPORT
+int CharCreateDialog::getDistributedPoints()
+{
+ int points = 0;
+
+ for (int i = 0; i < 6; i++)
+ {
+ points += (int) mAttributeSlider[i]->getValue();
+ }
+ return points;
+}
+#endif
+
+#ifndef TMWSERV_SUPPORT
void CharCreateDialog::attemptCharCreate()
{
// Send character infos
@@ -381,3 +706,4 @@ void CharCreateDialog::attemptCharCreate()
outMsg.writeInt16(mPlayer->getHairColor());
outMsg.writeInt16(mPlayer->getHairStyle());
}
+#endif
diff --git a/src/gui/char_select.h b/src/gui/char_select.h
index 28091a18..0ff1d18f 100644
--- a/src/gui/char_select.h
+++ b/src/gui/char_select.h
@@ -27,10 +27,16 @@
#include "window.h"
#include "../being.h"
+#include "../guichanfwd.h"
#include "../lockedarray.h"
-class LocalPlayer;
+#ifdef TMWSERV_SUPPORT
+#include "../logindata.h"
+#else
class Network;
+#endif
+
+class LocalPlayer;
class Player;
class PlayerBox;
@@ -46,9 +52,14 @@ class CharSelectDialog : public Window, public gcn::ActionListener
/**
* Constructor.
*/
+#ifdef TMWSERV_SUPPORT
+ CharSelectDialog(LockedArray<LocalPlayer*> *charInfo,
+ LoginData *loginData);
+#else
CharSelectDialog(Network *network,
LockedArray<LocalPlayer*> *charInfo,
Gender gender);
+#endif
void action(const gcn::ActionEvent &event);
@@ -59,25 +70,40 @@ class CharSelectDialog : public Window, public gcn::ActionListener
bool selectByName(const std::string &name);
private:
+#ifdef EATHENA_SUPPORT
Network *mNetwork;
+#endif
LockedArray<LocalPlayer*> *mCharInfo;
gcn::Button *mSelectButton;
gcn::Button *mCancelButton;
- gcn::Button *mNewDelCharButton;
gcn::Button *mPreviousButton;
gcn::Button *mNextButton;
gcn::Label *mNameLabel;
gcn::Label *mLevelLabel;
- gcn::Label *mJobLevelLabel;
- gcn::Label *mMoneyLabel; std::string mMoney;
+ gcn::Label *mMoneyLabel;
+ std::string mMoney;
PlayerBox *mPlayerBox;
- Gender mGender;
bool mCharSelected;
+#ifdef TMWSERV_SUPPORT
+ gcn::Button *mNewCharButton;
+ gcn::Button *mDelCharButton;
+ gcn::Button *mUnRegisterButton;
+ gcn::Button *mChangePasswordButton;
+ gcn::Button *mChangeEmailButton;
+ gcn::Label *mAccountNameLabel;
+
+ LoginData *mLoginData;
+#else
+ gcn::Button *mNewDelCharButton;
+ gcn::Label *mJobLevelLabel;
+ Gender mGender;
+#endif
+
/**
* Communicate character deletion to the server.
*/
@@ -92,7 +118,7 @@ class CharSelectDialog : public Window, public gcn::ActionListener
/**
* Character creation dialog.
*
- * \ingroup GUI
+ * \ingroup Interface
*/
class CharCreateDialog : public Window, public gcn::ActionListener
{
@@ -100,8 +126,12 @@ class CharCreateDialog : public Window, public gcn::ActionListener
/**
* Constructor.
*/
+#ifdef TMWSERV_SUPPORT
+ CharCreateDialog(Window *parent, int slot);
+#else
CharCreateDialog(Window *parent, int slot, Network *network,
Gender gender);
+#endif
/**
* Destructor.
@@ -116,6 +146,12 @@ class CharCreateDialog : public Window, public gcn::ActionListener
void unlock();
private:
+#ifdef TMWSERV_SUPPORT
+ int getDistributedPoints();
+
+ void UpdateSliders();
+#endif
+
/**
* Returns the name of the character to create.
*/
@@ -126,7 +162,9 @@ class CharCreateDialog : public Window, public gcn::ActionListener
*/
void attemptCharCreate();
+#ifdef EATHENA_SUPPORT
Network *mNetwork;
+#endif
gcn::TextField *mNameField;
gcn::Label *mNameLabel;
gcn::Button *mNextHairColorButton;
@@ -135,6 +173,20 @@ class CharCreateDialog : public Window, public gcn::ActionListener
gcn::Button *mNextHairStyleButton;
gcn::Button *mPrevHairStyleButton;
gcn::Label *mHairStyleLabel;
+
+#ifdef TMWSERV_SUPPORT
+ gcn::RadioButton *mMale;
+ gcn::RadioButton *mFemale;
+
+ gcn::Slider *mAttributeSlider[6];
+ gcn::Label *mAttributeLabel[6];
+ gcn::Label *mAttributeValue[6];
+ gcn::Label *mAttributesLeft;
+
+ static const int mMaxPoints = 60;
+ int mUsedPoints;
+#endif
+
gcn::Button *mCreateButton;
gcn::Button *mCancelButton;
diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp
index 22b0e7aa..5cfcef4d 100644
--- a/src/gui/char_server.cpp
+++ b/src/gui/char_server.cpp
@@ -107,7 +107,7 @@ void ServerSelectDialog::action(const gcn::ActionEvent &event)
state = mNextState;
}
else if (event.getId() == "cancel")
- state = LOGIN_STATE;
+ state = STATE_LOGIN;
}
int ServerListModel::getNumberOfElements()
diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp
index 94a554e8..597eddfd 100644
--- a/src/gui/chat.cpp
+++ b/src/gui/chat.cpp
@@ -31,25 +31,42 @@
#include "windowcontainer.h"
#include "widgets/layout.h"
+#include "widgets/tab.h"
+#include "widgets/tabbedarea.h"
#include "../beingmanager.h"
+#include "../commandhandler.h"
+#include "../channelmanager.h"
+#include "../channel.h"
#include "../configuration.h"
#include "../game.h"
#include "../localplayer.h"
-#include "../party.h"
+#ifdef TMWSERV_SUPPORT
+#include "../net/tmwserv/chatserver/chatserver.h"
+#include "../net/tmwserv/gameserver/player.h"
+#else
+#include "../party.h"
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#include "../net/ea/protocol.h"
+#endif
#include "../resources/iteminfo.h"
#include "../resources/itemdb.h"
+#include "../utils/dtor.h"
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
#include "../utils/stringutils.h"
+#ifdef TMWSERV_SUPPORT
+ChatWindow::ChatWindow():
+ Window("Chat"),
+#else
ChatWindow::ChatWindow(Network * network):
-Window(""), mNetwork(network), mTmpVisible(false)
+ Window(""), mNetwork(network),
+#endif
+ mTmpVisible(false)
{
setWindowName("Chat");
@@ -64,18 +81,10 @@ Window(""), mNetwork(network), mTmpVisible(false)
mChatInput->setActionEventId("chatinput");
mChatInput->addActionListener(this);
- mTextOutput = new BrowserBox(BrowserBox::AUTO_WRAP);
- mTextOutput->setOpaque(false);
- mTextOutput->setMaxRow((int) config.getValue("ChatLogLength", 0));
- mTextOutput->setLinkHandler(mItemLinkHandler);
+ mChatTabs = new TabbedArea();
+ createNewChannelTab("General");
- mScrollArea = new ScrollArea(mTextOutput);
- mScrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER,
- gcn::ScrollArea::SHOW_ALWAYS);
- mScrollArea->setScrollAmount(0, 1);
- mScrollArea->setOpaque(false);
-
- place(0, 0, mScrollArea, 5, 5).setPadding(0);
+ place(0, 0, mChatTabs, 5, 5).setPadding(0);
place(0, 5, mChatInput, 5).setPadding(1);
Layout &layout = getLayout();
@@ -88,28 +97,33 @@ Window(""), mNetwork(network), mTmpVisible(false)
mChatInput->addKeyListener(this);
mCurHist = mHistory.end();
+#ifdef EATHENA_SUPPORT
// Read the party prefix
std::string partyPrefix = config.getValue("PartyPrefix", "$");
mPartyPrefix = (partyPrefix.empty() ? '$' : partyPrefix.at(0));
mReturnToggles = config.getValue("ReturnToggles", "0") == "1";
mRecorder = new Recorder(this);
- mParty = new Party(this, mNetwork);
// If the player had @assert on in the last session, ask the server to
// run the @assert command for the player again. Convenience for GMs.
- if (config.getValue(player_node->getName() + "GMassert", 0))
- chatSend(player_node->getName(), "@assert");
+ if (config.getValue(player_node->getName() + "GMassert", 0)) {
+ std::string cmd = "@assert";
+ chatSend(cmd);
+ }
+#endif
}
ChatWindow::~ChatWindow()
{
+#ifdef EATHENA_SUPPORT
char partyPrefix[2] = ".";
*partyPrefix = mPartyPrefix;
config.setValue("PartyPrefix", partyPrefix);
config.setValue("ReturnToggles", mReturnToggles ? "1" : "0");
delete mRecorder;
- delete mItemLinkHandler;
delete mParty;
+#endif
+ delete mItemLinkHandler;
}
void ChatWindow::resetToDefaultSize()
@@ -118,8 +132,65 @@ void ChatWindow::resetToDefaultSize()
Window::resetToDefaultSize();
}
-void ChatWindow::chatLog(std::string line, int own, bool ignoreRecord)
+void ChatWindow::widgetResized(const gcn::Event &event)
{
+ Window::widgetResized(event);
+
+ const gcn::Rectangle area = getChildrenArea();
+
+ mChatInput->setPosition(mChatInput->getFrameSize(),
+ area.height - mChatInput->getHeight() -
+ mChatInput->getFrameSize());
+ mChatInput->setWidth(area.width - 2 * mChatInput->getFrameSize());
+
+ mChatTabs->setWidth(area.width - 2 * mChatTabs->getFrameSize());
+ mChatTabs->setHeight(area.height - 2 * mChatTabs->getFrameSize());
+
+ const std::string &channelName = getFocused();
+ ChannelMap::const_iterator chan = mChannels.find(channelName);
+ if (chan != mChannels.end()) {
+ ScrollArea *scroll = chan->second.scroll;
+ scroll->setWidth(area.width - 2 * scroll->getFrameSize());
+ scroll->setHeight(area.height - 2 * scroll->getFrameSize() -
+ mChatInput->getHeight() - 5);
+ scroll->logic();
+ }
+}
+
+void ChatWindow::logic()
+{
+ Window::logic();
+
+ const gcn::Rectangle area = getChildrenArea();
+
+ const std::string &channelName = getFocused();
+ ChannelMap::const_iterator chan = mChannels.find(channelName);
+ if (chan != mChannels.end()) {
+ ScrollArea *scroll = chan->second.scroll;
+ scroll->setWidth(area.width - 2 * scroll->getFrameSize());
+ scroll->setHeight(area.height - 2 * scroll->getFrameSize() -
+ mChatInput->getHeight() - 5);
+ scroll->logic();
+ }
+}
+
+void ChatWindow::chatLog(std::string line, int own, std::string channelName,
+ bool ignoreRecord)
+{
+ if(channelName.empty())
+#ifdef TMWSERV_SUPPORT
+ channelName = getFocused();
+#else
+ channelName = "General";
+#endif
+
+ ChannelMap::const_iterator chan = mChannels.find(channelName);
+ if (chan == mChannels.end())
+ return;
+
+ BrowserBox * const output = chan->second.browser;
+ ScrollArea * const scroll = chan->second.scroll;
+
// Trim whitespace
trim(line);
@@ -188,10 +259,17 @@ void ChatWindow::chatLog(std::string line, int own, bool ignoreRecord)
tmp.text = line;
lineColor = "##S";
break;
+ case BY_CHANNEL:
+ tmp.nick = "";
+ // TODO: Use a predefined color
+ lineColor = "##2"; // Equiv. to BrowserBox::GREEN
+ break;
+#ifdef EATHENA_SUPPORT
case BY_PARTY:
tmp.nick += CAT_NORMAL;
lineColor = "##P";
break;
+#endif
case ACT_WHISPER:
tmp.nick = strprintf(_("%s whispers:"), tmp.nick.c_str());
tmp.nick += " ";
@@ -214,10 +292,12 @@ void ChatWindow::chatLog(std::string line, int own, bool ignoreRecord)
lineColor = "##S";
}
+#ifdef EATHENA_SUPPORT
if (tmp.nick.empty() && tmp.text.substr(0, 17) == "Visible GM status")
{
player_node->setGM();
}
+#endif
// Get the current system time
time_t t;
@@ -272,24 +352,30 @@ void ChatWindow::chatLog(std::string line, int own, bool ignoreRecord)
// We look if the Vertical Scroll Bar is set at the max before
// adding a row, otherwise the max will always be a row higher
// at comparison.
- if (mScrollArea->getVerticalScrollAmount() ==
- mScrollArea->getVerticalMaxScroll())
+ if (scroll->getVerticalScrollAmount() >= scroll->getVerticalMaxScroll())
{
- mTextOutput->addRow(line);
- mScrollArea->setVerticalScrollAmount(mScrollArea->
- getVerticalMaxScroll());
+ output->addRow(line);
+ scroll->setVerticalScrollAmount(scroll->getVerticalMaxScroll());
}
else
{
- mTextOutput->addRow(line);
+ output->addRow(line);
}
+ scroll->logic();
mRecorder->record(line.substr(3));
}
-void ChatWindow::chatLog(CHATSKILL act)
+const std::string &ChatWindow::getFocused() const
{
- chatLog(const_msg(act), BY_SERVER);
+ return mChatTabs->getSelectedTab()->getCaption();
+}
+
+void ChatWindow::clearTab(const std::string &tab)
+{
+ ChannelMap::const_iterator chan = mChannels.find(tab);
+ if (chan != mChannels.end())
+ chan->second.browser->clearRows();
}
void ChatWindow::action(const gcn::ActionEvent &event)
@@ -309,7 +395,7 @@ void ChatWindow::action(const gcn::ActionEvent &event)
mCurHist = mHistory.end();
// Send the message to the server
- chatSend(player_node->getName(), message);
+ chatSend(message);
// Clear the text from the chat input
mChatInput->setText("");
@@ -358,62 +444,79 @@ bool ChatWindow::isInputFocused()
return mChatInput->isFocused();
}
-void ChatWindow::whisper(const std::string &nick, std::string msg)
+void ChatWindow::removeChannel(short channelId)
{
- std::string recvnick = "";
-
- if (msg.substr(0, 1) == "\"")
- {
- const std::string::size_type pos = msg.find('"', 1);
- if (pos != std::string::npos)
- {
- recvnick = msg.substr(1, pos - 1);
- msg.erase(0, pos + 2);
- }
- }
- else
- {
- const std::string::size_type pos = msg.find(" ");
- if (pos != std::string::npos)
- {
- recvnick = msg.substr(0, pos);
- msg.erase(0, pos + 1);
- }
- }
-
- trim(msg);
-
- std::string playerName = player_node->getName();
- std::string tempNick = recvnick;
+ removeChannel(channelManager->findById(channelId));
+}
- toLower(playerName);
- toLower(tempNick);
+void ChatWindow::removeChannel(const std::string &channelName)
+{
+ removeChannel(channelManager->findByName(channelName));
+}
- if (tempNick.compare(playerName) == 0 || msg.empty())
- return;
+void ChatWindow::removeChannel(Channel *channel)
+{
+ if (channel)
+ {
+ Tab *tab = mChatTabs->getTab(channel->getName());
+ if (!tab)
+ return;
+ clearTab(channel->getName());
+ mChatTabs->removeTab(tab);
+ mChannels.erase(channel->getName());
+ channelManager->removeChannel(channel);
- MessageOut outMsg(mNetwork);
- outMsg.writeInt16(CMSG_CHAT_WHISPER);
- outMsg.writeInt16(msg.length() + 28);
- outMsg.writeString(recvnick, 24);
- outMsg.writeString(msg, msg.length());
+ logic();
+ }
+}
- chatLog(strprintf(_("Whispering to %s: %s"),
- recvnick.c_str(), msg.c_str()),
- BY_PLAYER);
+void ChatWindow::createNewChannelTab(const std::string &channelName)
+{
+ // Create new channel
+ BrowserBox *textOutput = new BrowserBox(BrowserBox::AUTO_WRAP);
+ textOutput->setOpaque(false);
+ textOutput->disableLinksAndUserColors();
+ textOutput->setMaxRow((int) config.getValue("ChatLogLength", 0));
+ ScrollArea *scrollArea = new ScrollArea(textOutput);
+ scrollArea->setPosition(scrollArea->getFrameSize(), scrollArea->getFrameSize());
+ scrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, gcn::ScrollArea::SHOW_ALWAYS);
+ scrollArea->setOpaque(false);
+ scrollArea->setWidth(getChildrenArea().width - 2 * scrollArea->getFrameSize());
+ scrollArea->setHeight(getChildrenArea().height - 2 * scrollArea->getFrameSize() -
+ mChatInput->getHeight() - 5);
+ scrollArea->logic();
+ textOutput->setWidth(scrollArea->getChildrenArea().width);
+ textOutput->setHeight(scrollArea->getChildrenArea().height);
+
+ // Add channel to the tabbed area
+ mChatTabs->addTab(channelName, scrollArea);
+ mChannels.insert(
+ std::make_pair(channelName, ChatArea(textOutput, scrollArea)));
+
+ // Update UI
+ logic();
}
-void ChatWindow::chatSend(const std::string &nick, std::string msg)
+void ChatWindow::sendToChannel(short channelId,
+ const std::string &user,
+ const std::string &msg)
{
- /* Some messages are managed client side, while others
- * require server handling by proper packet. Probably
- * those if elses should be replaced by protocol calls */
+ Channel *channel = channelManager->findById(channelId);
+ if (channel)
+ {
+ std::string channelName = channel->getName();
+ chatLog(user + ": " + msg, user == player_node->getName() ? BY_PLAYER : BY_OTHER, channelName);
+ mChatTabs->getTab(channelName)->setHighlighted(true);
+ }
+}
+void ChatWindow::chatSend(std::string &msg)
+{
trim(msg);
- if (msg.compare("") == 0)
- return;
+ if (msg.empty()) return;
+#ifdef EATHENA_SUPPORT
// Send party message
if (msg.at(0) == mPartyPrefix)
{
@@ -432,11 +535,26 @@ void ChatWindow::chatSend(const std::string &nick, std::string msg)
outMsg.writeString(msg, length);
return;
}
+#endif
// Prepare ordinary message
- if (msg.substr(0, 1) != "/")
+ if (msg[0] != '/')
{
- msg = nick + " : " + msg;
+#ifdef TMWSERV_SUPPORT
+ if (getFocused() == "General")
+ {
+ Net::GameServer::Player::say(msg);
+ }
+ else
+ {
+ Channel *channel = channelManager->findByName(getFocused());
+ if (channel)
+ {
+ Net::ChatServer::chat(channel->getId(), msg);
+ }
+ }
+#else
+ msg = player_node->getName() + " : " + msg;
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_CHAT_MESSAGE);
@@ -444,290 +562,54 @@ void ChatWindow::chatSend(const std::string &nick, std::string msg)
outMsg.writeInt16(msg.length() + 4 + 1);
outMsg.writeString(msg, msg.length() + 1);
return;
- }
-
- msg.erase(0, 1);
- trim(msg);
-
- std::size_t space = msg.find(" ");
- std::string command = msg.substr(0, space);
-
- if (space == std::string::npos)
- {
- msg = "";
+#endif
}
else
{
- msg = msg.substr(space);
- trim(msg);
- }
-
- if (command == "announce")
- {
- MessageOut outMsg(mNetwork);
- outMsg.writeInt16(0x0099);
- outMsg.writeInt16(msg.length() + 4);
- outMsg.writeString(msg, msg.length());
- }
- else if (command == "help")
- {
- trim(msg);
- std::size_t space = msg.find(" ");
- std::string msg1;
-
- if (space == std::string::npos)
- {
- msg1 = "";
- }
- else
- {
- msg1 = msg.substr(space + 1, msg.length());
- msg = msg.substr(0, space);
- }
-
- if (!msg.empty() && msg.at(0) == '/')
- {
- msg.erase(0, 1);
- }
-
- trim(msg1);
- help(msg, msg1);
- }
- else if (command == "where")
- {
- // Display the current map, X, and Y
- std::ostringstream where;
- where << map_path << " " << player_node->mX << "," << player_node->mY;
- chatLog(where.str(), BY_SERVER);
- }
- else if (command == "who")
- {
- MessageOut outMsg(mNetwork);
- outMsg.writeInt16(0x00c1);
- }
- else if (command == "clear")
- mTextOutput->clearRows();
- else if (command == "whisper" || command == "msg" || command == "w")
- whisper(nick, msg);
- else if (command == "record")
- mRecorder->changeRecordingStatus(msg);
- else if (command == "toggle")
- {
- if (msg.empty())
- {
- chatLog(mReturnToggles ? _("Return toggles chat.")
- : _("Message closes chat."), BY_SERVER);
- return;
- }
-
- msg = msg.substr(0, 1);
-
- if (msg == "1" ||
- msg == "y" || msg == "Y" ||
- msg == "t" || msg == "T")
- {
- chatLog(_("Return now toggles chat."), BY_SERVER);
- mReturnToggles = true;
- return;
- }
- else if (msg == "0" ||
- msg == "n" || msg == "N" ||
- msg == "f" || msg == "F")
- {
- chatLog(_("Message now closes chat."), BY_SERVER);
- mReturnToggles = false;
- return;
- }
- else
- chatLog(_("Options to /toggle are \"yes\", \"no\", \"true\", "
- "\"false\", \"1\", \"0\"."), BY_SERVER);
+ commandHandler->handleCommand(std::string(msg, 1));
}
- else if (command == "party")
- {
- if (msg.empty())
- {
- chatLog(_("Unknown party command... Type \"/help\" party for more "
- "information."), BY_SERVER);
- return;
- }
-
- const std::string::size_type space = msg.find(" ");
- std::string rest = (space == std::string::npos ? ""
- : msg.substr(space + 1, msg.length()));
+}
- if (!rest.empty())
- {
- msg = msg.substr(0, space);
- trim(msg);
- }
+void ChatWindow::doPresent()
+{
+ Beings & beings = beingManager->getAll();
+ std::string response = "";
- party(msg, rest);
- return;
- }
- else if (command == "cast")
+ for (BeingIterator bi = beings.begin(), be = beings.end();
+ bi != be; ++bi)
{
- /*
- * This will eventually be replaced by a GUI, so
- * we don't need to get too sophisticated
- */
- MessageOut outMsg(mNetwork);
- if (msg == "heal")
- {
- outMsg.writeInt16(0x03f3);
- outMsg.writeInt16(0x01);
- outMsg.writeInt32(0);
- outMsg.writeInt8(0);
- outMsg.writeInt8(0);
- outMsg.writeString("", 24);
- }
- else if (msg == "gather")
+ if ((*bi)->getType() == Being::PLAYER)
{
- outMsg.writeInt16(0x03f3);
- outMsg.writeInt16(0x02);
- outMsg.writeInt32(0);
- outMsg.writeInt8(0);
- outMsg.writeInt8(0);
- outMsg.writeString("", 24);
- }
- else
- chatLog(_("No such spell!"), BY_SERVER);
- }
- else if (command == "present")
- {
- Beings & beings = beingManager->getAll();
- std::string response = "";
-
- for (BeingIterator bi = beings.begin(), be = beings.end();
- bi != be; ++bi)
- {
- if ((*bi)->getType() == Being::PLAYER)
+ if (!response.empty())
{
- if (!response.empty())
- {
- response += ", ";
- }
- response += (*bi)->getName();
+ response += ", ";
}
- }
-
- if (mRecorder->isRecording())
- {
- // Get the current system time
- time_t t;
- time(&t);
-
- // Format the time string properly
- std::stringstream timeStr;
- timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "")
- << (int) (((t / 60) / 60) % 24)
- << ":" << (((t / 60) % 60 < 10) ? "0" : "")
- << (int) ((t / 60) % 60)
- << "] ";
-
-
- mRecorder->record(timeStr.str() + _("Present: ") + response + ".");
- chatLog(_("Attendance written to record log."), BY_SERVER, true);
- }
- else
- {
- chatLog(_("Present: ") + response, BY_SERVER);
+ response += (*bi)->getName();
}
}
- else if (command == "me")
- {
- std::stringstream actionStr;
- actionStr << "*" << msg << "*";
- chatSend(player_node->getName(), actionStr.str());
- }
- else
- {
- chatLog(_("Unknown command"), BY_SERVER);
- }
-}
-std::string ChatWindow::const_msg(CHATSKILL act)
-{
- std::string msg;
- if (act.success == SKILL_FAILED && act.skill == SKILL_BASIC)
+ if (mRecorder->isRecording())
{
- switch (act.bskill)
- {
- case BSKILL_TRADE:
- msg = _("Trade failed!");
- break;
- case BSKILL_EMOTE:
- msg = _("Emote failed!");
- break;
- case BSKILL_SIT:
- msg = _("Sit failed!");
- break;
- case BSKILL_CREATECHAT:
- msg = _("Chat creating failed!");
- break;
- case BSKILL_JOINPARTY:
- msg = _("Could not join party!");
- break;
- case BSKILL_SHOUT:
- msg = _("Cannot shout!");
- break;
- }
+ // Get the current system time
+ time_t t;
+ time(&t);
- msg += " ";
+ // Format the time string properly
+ std::stringstream timeStr;
+ timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "")
+ << (int) (((t / 60) / 60) % 24)
+ << ":" << (((t / 60) % 60 < 10) ? "0" : "")
+ << (int) ((t / 60) % 60)
+ << "] ";
- switch (act.reason)
- {
- case RFAIL_SKILLDEP:
- msg += _("You have not yet reached a high enough lvl!");
- break;
- case RFAIL_INSUFHP:
- msg += _("Insufficient HP!");
- break;
- case RFAIL_INSUFSP:
- msg += _("Insufficient SP!");
- break;
- case RFAIL_NOMEMO:
- msg += _("You have no memos!");
- break;
- case RFAIL_SKILLDELAY:
- msg += _("You cannot do that right now!");
- break;
- case RFAIL_ZENY:
- msg += _("Seems you need more money... ;-)");
- break;
- case RFAIL_WEAPON:
- msg += _("You cannot use this skill with that kind of weapon!");
- break;
- case RFAIL_REDGEM:
- msg += _("You need another red gem!");
- break;
- case RFAIL_BLUEGEM:
- msg += _("You need another blue gem!");
- break;
- case RFAIL_OVERWEIGHT:
- msg += _("You're carrying to much to do this!");
- break;
- default:
- msg += _("Huh? What's that?");
- break;
- }
+
+ mRecorder->record(timeStr.str() + _("Present: ") + response + ".");
+ chatLog(_("Attendance written to record log."), BY_SERVER, std::string(), true);
}
else
{
- switch (act.skill)
- {
- case SKILL_WARP :
- msg = _("Warp failed...");
- break;
- case SKILL_STEAL :
- msg = _("Could not steal anything...");
- break;
- case SKILL_ENVENOM :
- msg = _("Poison had no effect...");
- break;
- }
+ chatLog(_("Present: ") + response, BY_SERVER);
}
-
- return msg;
}
void ChatWindow::scroll(int amount)
@@ -735,11 +617,18 @@ void ChatWindow::scroll(int amount)
if (!isVisible())
return;
- int range = mScrollArea->getHeight() / 8 * amount;
+ ChannelMap::const_iterator chan = mChannels.find(getFocused());
+ if (chan == mChannels.end())
+ return;
+
+ BrowserBox *browser = chan->second.browser;
+ ScrollArea *scroll = chan->second.scroll;
+
+ int range = scroll->getHeight() / 8 * amount;
gcn::Rectangle scr;
- scr.y = mScrollArea->getVerticalScrollAmount() + range;
+ scr.y = scroll->getVerticalScrollAmount() + range;
scr.height = abs(range);
- mTextOutput->showPart(scr);
+ browser->showPart(scr);
}
void ChatWindow::keyPressed(gcn::KeyEvent &event)
@@ -792,150 +681,16 @@ void ChatWindow::setVisible(bool isVisible)
* For whatever reason, if setVisible is called, the mTmpVisible effect
* should be disabled.
*/
-
mTmpVisible = false;
}
-void ChatWindow::party(const std::string & command, const std::string & rest)
+bool ChatWindow::tabExists(const std::string &tabName)
{
- if (command == "prefix")
- {
- if (rest.empty())
- {
- char temp[2] = ".";
- *temp = mPartyPrefix;
- chatLog(_("The current party prefix is ") + std::string(temp),
- BY_SERVER);
- }
- else if (rest.length() != 1)
- {
- chatLog(_("Party prefix must be one character long."), BY_SERVER);
- }
- else
- {
- if (rest == "/")
- {
- chatLog(_("Cannot use a '/' as the prefix."), BY_SERVER);
- }
- else
- {
- mPartyPrefix = rest.at(0);
- chatLog(_("Changing prefix to ") + rest, BY_SERVER);
- }
- }
- }
- else
- mParty->respond(command, rest);
+ Tab *tab = mChatTabs->getTab(tabName);
+ return tab != 0;
}
-void ChatWindow::help(const std::string & msg1, const std::string & msg2)
+void ChatWindow::setRecordingFile(const std::string &msg)
{
- chatLog(_("-- Help --"), BY_SERVER);
- if (msg1.empty())
- {
- chatLog(_("/announce: Global announcement (GM only)"), BY_SERVER);
- chatLog(_("/clear: Clears this window"), BY_SERVER);
- chatLog(_("/help: Display this help"), BY_SERVER);
- chatLog(_("/me <message>: Tell something about yourself"), BY_SERVER);
- chatLog(_("/msg <nick> <message>: Alternate form for /whisper"),
- BY_SERVER);
- chatLog(_("/party <command> <params>: Party commands"), BY_SERVER);
- chatLog(_("/present: Get list of players present"), BY_SERVER);
- chatLog(_("/record <filename>: Start recording the chat to an "
- "external file"), BY_SERVER);
- chatLog(_("/toggle: Determine whether <return> toggles the chat log"),
- BY_SERVER);
- chatLog(_("/w <nick> <message>: Short form for /whisper"), BY_SERVER);
- chatLog(_("/where: Display map name"), BY_SERVER);
- chatLog(_("/whisper <nick> <message>: Sends a private <message> "
- "to <nick>"), BY_SERVER);
- chatLog(_("/who: Display number of online users"), BY_SERVER);
- chatLog(_("For more information, type /help <command>"), BY_SERVER);
- }
- else if (msg1 == "announce")
- {
- chatLog(_("Command: /announce <msg>"), BY_SERVER);
- chatLog(_("*** only available to a GM ***"), BY_SERVER);
- chatLog(_("This command sends the message <msg> to "
- "all players currently online."), BY_SERVER);
- }
- else if (msg1 == "clear")
- {
- chatLog(_("Command: /clear"), BY_SERVER);
- chatLog(_("This command clears the chat log of previous chat."),
- BY_SERVER);
- }
- else if (msg1 == "help")
- {
- chatLog(_("Command: /help"), BY_SERVER);
- chatLog(_("This command displays a list of all commands available."),
- BY_SERVER);
- chatLog(_("Command: /help <command>"), BY_SERVER);
- chatLog(_("This command displays help on <command>."), BY_SERVER);
- }
- else if (msg1 == "me")
- {
- chatLog(_("Command: /me <msg>"), BY_SERVER);
- chatLog(_("This command tell others you are (doing) <msg>."),
- BY_SERVER);
- }
- else if (msg1 == "party")
- {
- mParty->help(msg2);
- }
- else if (msg1 == "present")
- {
- chatLog(_("Command: /present"), BY_SERVER);
- chatLog(_("This command gets a list of players within hearing and "
- "sends it to either the record log if recording, or the chat "
- "log otherwise."), BY_SERVER);
- }
- else if (msg1 == "record")
- {
- chatLog(_("Command: /record <filename>"), BY_SERVER);
- chatLog(_("This command starts recording the chat log to the file "
- "<filename>."), BY_SERVER);
- chatLog(_("Command: /record"), BY_SERVER);
- chatLog(_("This command finishes a recording session."), BY_SERVER);
- }
- else if (msg1 == "toggle")
- {
- chatLog(_("Command: /toggle <state>"), BY_SERVER);
- chatLog(_("This command sets whether the return key should toggle the "
- "chat log, or whether the chat log turns off automatically."),
- BY_SERVER);
- chatLog(_("<state> can be one of \"1\", \"yes\", \"true\" to "
- "turn the toggle on, or \"0\", \"no\", \"false\" to turn the "
- "toggle off."), BY_SERVER);
- chatLog(_("Command: /toggle"), BY_SERVER);
- chatLog(_("This command displays the return toggle status."),
- BY_SERVER);
- }
- else if (msg1 == "where")
- {
- chatLog(_("Command: /where"), BY_SERVER);
- chatLog(_("This command displays the name of the current map."),
- BY_SERVER);
- }
- else if (msg1 == "whisper" || msg1 == "msg" || msg1 == "w")
- {
- chatLog(_("Command: /msg <nick> <msg>"), BY_SERVER);
- chatLog(_("Command: /whisper <nick> <msg>"), BY_SERVER);
- chatLog(_("Command: /w <nick> <msg>"), BY_SERVER);
- chatLog(_("This command sends the message <msg> to <nick>."),
- BY_SERVER);
- chatLog(_("If the <nick> has spaces in it, enclose it in "
- "double quotes (\")."), BY_SERVER);
- }
- else if (msg1 == "who")
- {
- chatLog(_("Command: /who"), BY_SERVER);
- chatLog(_("This command displays the number of players currently "
- "online."), BY_SERVER);
- }
- else
- {
- chatLog(_("Unknown command."), BY_SERVER);
- chatLog(_("Type /help for a list of commands."), BY_SERVER);
- }
+ mRecorder->setRecordingFile(msg);
}
diff --git a/src/gui/chat.h b/src/gui/chat.h
index 09f3260b..3c553c67 100644
--- a/src/gui/chat.h
+++ b/src/gui/chat.h
@@ -24,6 +24,7 @@
#include <list>
#include <string>
+#include <map>
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
@@ -31,22 +32,30 @@
#include "window.h"
class BrowserBox;
-class Network;
+class Channel;
class Recorder;
-class Party;
class ScrollArea;
+class TabbedArea;
class ItemLinkHandler;
+#ifdef EATHENA_SUPPORT
+class Network;
+class Party;
+#endif
-#define BY_GM 0 // those should be self-explanatory =)
-#define BY_PLAYER 1
-#define BY_OTHER 2
-#define BY_SERVER 3
-#define BY_PARTY 4
-
-#define ACT_WHISPER 5 // getting whispered at
-#define ACT_IS 6 // equivalent to "/me" on IRC
-
-#define BY_LOGGER 7
+enum
+{
+ BY_GM,
+#ifdef EATHENA_SUPPORT
+ BY_PARTY,
+#endif
+ BY_PLAYER,
+ BY_OTHER,
+ BY_SERVER,
+ BY_CHANNEL,
+ ACT_WHISPER, // getting whispered at
+ ACT_IS, // equivalent to "/me" on IRC
+ BY_LOGGER
+};
/**
* gets in between usernick and message text depending on
@@ -56,62 +65,26 @@ class ItemLinkHandler;
#define CAT_IS ""
#define CAT_WHISPER " whispers: "
-/** job dependend identifiers (?) */
-#define SKILL_BASIC 0x0001
-#define SKILL_WARP 0x001b
-#define SKILL_STEAL 0x0032
-#define SKILL_ENVENOM 0x0034
-
-/** basic skills identifiers */
-#define BSKILL_TRADE 0x0000
-#define BSKILL_EMOTE 0x0001
-#define BSKILL_SIT 0x0002
-#define BSKILL_CREATECHAT 0x0003
-#define BSKILL_JOINPARTY 0x0004
-#define BSKILL_SHOUT 0x0005
-#define BSKILL_PK 0x0006 // ??
-#define BSKILL_SETALLIGN 0x0007 // ??
-
-/** reasons why action failed */
-#define RFAIL_SKILLDEP 0x00
-#define RFAIL_INSUFHP 0x01
-#define RFAIL_INSUFSP 0x02
-#define RFAIL_NOMEMO 0x03
-#define RFAIL_SKILLDELAY 0x04
-#define RFAIL_ZENY 0x05
-#define RFAIL_WEAPON 0x06
-#define RFAIL_REDGEM 0x07
-#define RFAIL_BLUEGEM 0x08
-#define RFAIL_OVERWEIGHT 0x09
-#define RFAIL_GENERIC 0x0a
-
-/** should always be zero if failed */
-#define SKILL_FAILED 0x00
-
#define DEFAULT_CHAT_WINDOW_SCROLL 7 // 1 means `1/8th of the window size'.
-struct CHATSKILL
-{
- short skill;
- short bskill;
- short unused;
- char success;
- char reason;
-};
-
/**
* The chat window.
*
* \ingroup Interface
*/
-class ChatWindow : public Window, public gcn::ActionListener,
+class ChatWindow : public Window,
+ public gcn::ActionListener,
public gcn::KeyListener
{
public:
/**
* Constructor.
*/
+#ifdef TMWSERV_SUPPORT
+ ChatWindow();
+#else
ChatWindow(Network *network);
+#endif
/**
* Destructor: used to write back values to the config file
@@ -119,6 +92,14 @@ class ChatWindow : public Window, public gcn::ActionListener,
~ChatWindow();
/**
+ * Called when the widget changes size. Used for adapting the size of
+ * the tabbed area.
+ */
+ void widgetResized(const gcn::Event &event);
+
+ void logic();
+
+ /**
* Reset the chat window and recorder window attached to it to their
* default positions.
*/
@@ -128,14 +109,24 @@ class ChatWindow : public Window, public gcn::ActionListener,
* Adds a line of text to our message list. Parameters:
*
* @param line Text message.
- * @parem own Type of message (usually the owner-type).
+ * @param own Type of message (usually the owner-type).
+ * @param channelName which channel to send the message to.
+ * @param ignoreRecord should this not be recorded?
*/
- void chatLog(std::string line, int own, bool ignoreRecord = false);
+ void chatLog(std::string line,
+ int own = BY_SERVER,
+ std::string channelName = "",
+ bool ignoreRecord = false);
/**
- * Calls original chat_log() after processing the packet.
+ * Gets the focused tab's name
*/
- void chatLog(CHATSKILL);
+ const std::string& getFocused() const;
+
+ /**
+ * Clear the tab with the given name
+ */
+ void clearTab(const std::string &tab);
/**
* Performs action.
@@ -155,31 +146,30 @@ class ChatWindow : public Window, public gcn::ActionListener,
*/
bool isInputFocused();
+ /** Called to remove the channel from the channel manager */
+ void removeChannel(short channelId);
+
+ void removeChannel(const std::string &channelName);
+
+ void removeChannel(Channel *channel);
+
+ /** Called to create a new channel tab */
+ void createNewChannelTab(const std::string &channelName);
+
+ /** Called to output text to a specific channel */
+ void sendToChannel(short channel,
+ const std::string &user,
+ const std::string &msg);
+
/**
- * Determines whether to send a command or an ordinary message, then
- * contructs packets & sends them.
- *
- * @param nick The character's name to display in front.
- * @param msg The message text which is to be send.
+ * Determines whether the message is a command or message, then
+ * sends the given message to the game server to be said, or to the
+ * command handler
*
- * NOTE:
- * The nickname is required by the server, if not specified
- * the message may not be sent unless a command was intended
- * which requires another packet to be constructed! you can
- * achieve this by putting a slash ("/") infront of the
- * message followed by the command name and the message.
- * of course all slash-commands need implemented handler-
- * routines. ;-)
- * remember, a line starting with "@" is not a command that needs
- * to be parsed rather is sent using the normal chat-packet.
+ * @param msg The message text which is to be sent.
*
- * EXAMPLE:
- * // for an global announcement /- command
- * chatlog.chat_send("", "/announce Hello to all logged in users!");
- * // for simple message by a user /- message
- * chatlog.chat_send("Zaeiru", "Hello to all users on the screen!");
*/
- void chatSend(const std::string &nick, std::string msg);
+ void chatSend(std::string &msg);
/** Called when key is pressed */
void keyPressed(gcn::KeyEvent &event);
@@ -193,37 +183,43 @@ class ChatWindow : public Window, public gcn::ActionListener,
/** Override to reset mTmpVisible */
void setVisible(bool visible);
- /**
- * Scrolls the chat window
- *
- * @param amount direction and amount to scroll. Negative numbers scroll
- * up, positive numbers scroll down. The absolute amount indicates the
- * amount of 1/8ths of chat window real estate that should be scrolled.
- */
- void scroll(int amount);
+ /** Check if tab with that name already exists */
+ bool tabExists(const std::string &tabName);
/**
- * party implements the partying chat commands
+ * Scrolls the chat window
*
- * @param command is the party command to perform
- * @param msg is the remainder of the message
+ * @param amount direction and amount to scroll. Negative numbers scroll
+ * up, positive numbers scroll down. The absolute amount indicates the
+ * amount of 1/8ths of chat window real estate that should be scrolled.
*/
- void party(const std::string &command, const std::string &msg);
+ void scroll(int amount);
+
+#ifdef EATHENA_SUPPORT
+ char getPartyPrefix() const { return mPartyPrefix; }
+ void setPartyPrefix(char prefix) { mPartyPrefix = prefix; }
+#endif
/**
- * help implements the /help command
+ * Sets the file being recorded to
*
- * @param msg1 is the command that the player needs help on
- * @param msg2 is the sub-command relating to the command
+ * @param msg The file to write out to. If null, then stop recording.
*/
- void help(const std::string &msg1, const std::string &msg2);
+ void setRecordingFile(const std::string &msg);
- private:
+ bool getReturnTogglesChat() const { return mReturnToggles; }
+ void setReturnTogglesChat(bool toggles) { mReturnToggles = toggles; }
+ void doPresent();
+
+ private:
+#ifdef EATHENA_SUPPORT
Network *mNetwork;
+#endif
bool mTmpVisible;
- void whisper(const std::string &nick, std::string msg);
+ int mItems;
+ int mItemsKeep;
/** One item in the chat log */
struct CHATLOG
@@ -233,25 +229,46 @@ class ChatWindow : public Window, public gcn::ActionListener,
int own;
};
- /** Constructs failed messages for actions */
- std::string const_msg(CHATSKILL);
+ /**
+ * A structure combining a BrowserBox with its ScrollArea.
+ */
+ struct ChatArea
+ {
+ ChatArea(BrowserBox *b, ScrollArea *s):
+ browser(b), scroll(s)
+ {}
+
+ BrowserBox *browser;
+ ScrollArea *scroll;
+ };
+
+ /** Used for showing item popup on clicking links **/
+ ItemLinkHandler *mItemLinkHandler;
+
+ /** Tabbed area for holding each channel. */
+ TabbedArea *mChatTabs;
+
+ /** Input box for typing chat messages. */
+ gcn::TextField *mChatInput;
+
+ typedef std::map<const std::string, ChatArea> ChannelMap;
+ /** Map each tab to its browser and scroll area. */
+ ChannelMap mChannels;
- gcn::TextField *mChatInput; /**< Input box for typing chat messages */
- BrowserBox *mTextOutput; /**< Text box for displaying chat history */
- ScrollArea *mScrollArea; /**< Scroll area around text output */
- ItemLinkHandler *mItemLinkHandler; /** Used for showing item popup on
- clicking links **/
typedef std::list<std::string> History;
typedef History::iterator HistoryIterator;
History mHistory; /**< Command history */
HistoryIterator mCurHist; /**< History iterator */
Recorder *mRecorder; /**< Recording class */
- char mPartyPrefix; /**< Messages beginning with the prefix are
- sent to the party */
bool mReturnToggles; /**< Marks whether <Return> toggles the chat
log or not */
+#ifdef EATHENA_SUPPORT
+ char mPartyPrefix; /**< Messages beginning with the prefix are
+ sent to the party */
Party *mParty;
+#endif
};
+
extern ChatWindow *chatWindow;
#endif
diff --git a/src/gui/chatinput.h b/src/gui/chatinput.h
index a4a50502..3bc16928 100644
--- a/src/gui/chatinput.h
+++ b/src/gui/chatinput.h
@@ -26,6 +26,8 @@
#include "textfield.h"
+#include <guichan/focuslistener.hpp>
+
/**
* The chat input hides when it loses focus. It is also invisible by default.
*/
diff --git a/src/gui/connection.cpp b/src/gui/connection.cpp
index 658eade7..5fb21ff2 100644
--- a/src/gui/connection.cpp
+++ b/src/gui/connection.cpp
@@ -19,31 +19,22 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/actionlistener.hpp>
-
#include "button.h"
#include "connection.h"
#include "label.h"
#include "progressbar.h"
#include "../main.h"
+#include "../log.h"
#include "../utils/gettext.h"
-namespace
-{
- struct ConnectionActionListener : public gcn::ActionListener
- {
- void action(const gcn::ActionEvent &event) { state = EXIT_STATE; }
- } listener;
-}
-
-ConnectionDialog::ConnectionDialog():
- Window("Info"), mProgress(0)
+ConnectionDialog::ConnectionDialog(int previousState):
+ Window("Info"), mProgress(0), mPreviousState(previousState)
{
setContentSize(200, 100);
- Button *cancelButton = new Button(_("Cancel"), "cancelButton", &listener);
+ Button *cancelButton = new Button(_("Cancel"), "cancelButton", this);
mProgressBar = new ProgressBar(0.0, 200 - 10, 20, 128, 128, 128);
gcn::Label *label = new Label(_("Connecting..."));
@@ -59,6 +50,12 @@ ConnectionDialog::ConnectionDialog():
setVisible(true);
}
+void ConnectionDialog::action(gcn::ActionEvent const &)
+{
+ logger->log("Cancel pressed");
+ state = mPreviousState;
+}
+
void ConnectionDialog::logic()
{
mProgress += 0.005f;
diff --git a/src/gui/connection.h b/src/gui/connection.h
index 3caa611f..0e347266 100644
--- a/src/gui/connection.h
+++ b/src/gui/connection.h
@@ -22,6 +22,8 @@
#ifndef CONNECTION_H
#define CONNECTION_H
+#include <guichan/actionlistener.hpp>
+
#include "window.h"
class ProgressBar;
@@ -31,7 +33,7 @@ class ProgressBar;
*
* \ingroup Interface
*/
-class ConnectionDialog : public Window
+class ConnectionDialog : public Window, gcn::ActionListener
{
public:
/**
@@ -39,13 +41,20 @@ class ConnectionDialog : public Window
*
* @see Window::Window
*/
- ConnectionDialog();
+ ConnectionDialog(int previousState);
+
+ /**
+ * Called when the user presses Cancel. Restores the global state to
+ * the previous one.
+ */
+ void action(gcn::ActionEvent const &);
void logic();
private:
ProgressBar *mProgressBar;
float mProgress;
+ int mPreviousState;
};
#endif
diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp
index 856d7d03..7ac9051f 100644
--- a/src/gui/equipmentwindow.cpp
+++ b/src/gui/equipmentwindow.cpp
@@ -37,6 +37,7 @@
#include "../item.h"
#include "../localplayer.h"
+#include "../resources/image.h"
#include "../resources/iteminfo.h"
#include "../resources/resourcemanager.h"
@@ -58,8 +59,16 @@ static const int boxPosition[][2] = {
{129, 78} // EQUIP_AMMO_SLOT
};
+#ifdef TMWSERV_SUPPORT
+EquipmentWindow::EquipmentWindow(Equipment *equipment):
+#else
EquipmentWindow::EquipmentWindow():
+#endif
Window(_("Equipment")),
+#ifdef TMWSERV_SUPPORT
+ mEquipment(equipment),
+#endif
+ mBackground(NULL),
mSelected(-1)
{
mItemPopup = new ItemPopup;
@@ -83,19 +92,31 @@ EquipmentWindow::EquipmentWindow():
add(mPlayerBox);
add(mUnequip);
+#ifdef TMWSERV_SUPPORT
+ for (int i = 0; i < EQUIPMENT_SIZE; i++)
+#else
for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++)
+#endif
{
mEquipBox[i].posX = boxPosition[i][0] + getPadding();
mEquipBox[i].posY = boxPosition[i][1] + getTitleBarHeight();
}
+ ResourceManager *resman = ResourceManager::getInstance();
+ mBackground = resman->getImage("graphics/gui/equip_bg.png");
+ mBackground->setAlpha(0.3);
+
+#ifdef EATHENA_SUPPORT
mEquipment = player_node->mEquipment.get();
mInventory = player_node->getInventory();
+#endif
}
EquipmentWindow::~EquipmentWindow()
{
+ mBackground->decRef();
delete mItemPopup;
+ delete mUnequip;
}
void EquipmentWindow::draw(gcn::Graphics *graphics)
@@ -106,13 +127,15 @@ void EquipmentWindow::draw(gcn::Graphics *graphics)
// Draw window graphics
Window::draw(graphics);
- Item* item;
-
Graphics *g = static_cast<Graphics*>(graphics);
Window::drawChildren(graphics);
+#ifdef TMWSERV_SUPPORT
+ for (int i = 0; i < EQUIPMENT_SIZE; i++)
+#else
for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++)
+#endif
{
if (i == mSelected)
{
@@ -130,14 +153,19 @@ void EquipmentWindow::draw(gcn::Graphics *graphics)
g->drawRectangle(gcn::Rectangle(mEquipBox[i].posX, mEquipBox[i].posY,
BOX_WIDTH, BOX_HEIGHT));
- item = (i != EQUIP_AMMO_SLOT) ?
+#ifdef TMWSERV_SUPPORT
+ Item *item = mEquipment->getEquipment(i);
+#else
+ Item *item = (i != EQUIP_AMMO_SLOT) ?
mInventory->getItem(mEquipment->getEquipment(i)) :
mInventory->getItem(mEquipment->getArrows());
+#endif
if (item)
{
// Draw Item.
- Image* image = item->getImage();
+ Image *image = item->getImage();
g->drawImage(image, mEquipBox[i].posX, mEquipBox[i].posY);
+#ifdef EATHENA_SUPPORT
if (i == EQUIP_AMMO_SLOT)
{
g->setColor(guiPalette->getColor(Palette::TEXT));
@@ -146,6 +174,7 @@ void EquipmentWindow::draw(gcn::Graphics *graphics)
mEquipBox[i].posY - getFont()->getHeight(),
gcn::Graphics::CENTER);
}
+#endif
}
}
}
@@ -154,26 +183,38 @@ void EquipmentWindow::action(const gcn::ActionEvent &event)
{
if (event.getId() == "unequip" && mSelected > -1)
{
+#ifdef TMWSERV_SUPPORT
+ player_node->unequipItem(mSelected);
+#else
Item* item = (mSelected != EQUIP_AMMO_SLOT) ?
mInventory->getItem(mEquipment->getEquipment(mSelected)) :
mInventory->getItem(mEquipment->getArrows());
player_node->unequipItem(item);
+#endif
mSelected = -1;
}
}
Item* EquipmentWindow::getItem(int x, int y) const
{
+#ifdef TMWSERV_SUPPORT
+ for (int i = 0; i < EQUIPMENT_SIZE; i++)
+#else
for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++)
+#endif
{
gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY,
BOX_WIDTH, BOX_HEIGHT);
if (tRect.isPointInRect(x, y))
{
+#ifdef TMWSERV_SUPPORT
+ return mEquipment->getEquipment(i);
+#else
return (i != EQUIP_AMMO_SLOT) ?
mInventory->getItem(mEquipment->getEquipment(i)) :
mInventory->getItem(mEquipment->getArrows());
+#endif
}
}
return NULL;
@@ -191,11 +232,19 @@ void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent)
if (mouseEvent.getButton() == gcn::MouseEvent::LEFT)
{
// Checks if any of the presses were in the equip boxes.
+#ifdef TMWSERV_SUPPORT
+ for (int i = 0; i < EQUIPMENT_SIZE; i++)
+#else
for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++)
+#endif
{
+#ifdef TMWSERV_SUPPORT
+ item = mEquipment->getEquipment(i);
+#else
item = (i != EQUIP_AMMO_SLOT) ?
mInventory->getItem(mEquipment->getEquipment(i)) :
mInventory->getItem(mEquipment->getArrows());
+#endif
gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY,
BOX_WIDTH, BOX_HEIGHT);
diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h
index 24438477..7f7150ff 100644
--- a/src/gui/equipmentwindow.h
+++ b/src/gui/equipmentwindow.h
@@ -27,6 +27,7 @@
#include "window.h"
class Equipment;
+class Image;
class Inventory;
class Item;
class ItemPopup;
@@ -52,7 +53,11 @@ class EquipmentWindow : public Window, public gcn::ActionListener
/**
* Constructor.
*/
+#ifdef TMWSERV_SUPPORT
+ EquipmentWindow(Equipment *equipment);
+#else
EquipmentWindow();
+#endif
/**
* Destructor.
@@ -68,6 +73,23 @@ class EquipmentWindow : public Window, public gcn::ActionListener
void mousePressed(gcn::MouseEvent& mouseEvent);
+#ifdef TMWSERV_SUPPORT
+ enum{
+ // Equipment rules:
+ EQUIP_TORSO_SLOT = 0,
+ EQUIP_ARMS_SLOT = 1,
+ EQUIP_HEAD_SLOT = 2,
+ EQUIP_LEGS_SLOT = 3,
+ EQUIP_FEET_SLOT = 4,
+ EQUIP_RING1_SLOT = 5,
+ EQUIP_RING2_SLOT = 6,
+ EQUIP_NECKLACE_SLOT = 7,
+ EQUIP_FIGHT1_SLOT = 8,
+ EQUIP_FIGHT2_SLOT = 9,
+ EQUIP_PROJECTILE_SLOT = 10,
+ EQUIP_VECTOREND
+ };
+#else
enum {
// Equipment rules:
EQUIP_LEGS_SLOT = 0,
@@ -83,7 +105,7 @@ class EquipmentWindow : public Window, public gcn::ActionListener
EQUIP_AMMO_SLOT,
EQUIP_VECTOREND
};
-
+#endif
private:
void mouseExited(gcn::MouseEvent &event);
@@ -92,8 +114,11 @@ class EquipmentWindow : public Window, public gcn::ActionListener
Item* getItem(int x, int y) const;
Equipment *mEquipment;
+#ifdef EATHENA_SUPPORT
Inventory *mInventory;
+#endif
gcn::Button *mUnequip; /**< Button for unequipping. */
+ Image *mBackground; /**< Background Image. */
EquipBox mEquipBox[EQUIP_VECTOREND]; /**< Equipment Boxes. */
ItemPopup *mItemPopup;
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index 83441e1b..87ce74fa 100644
--- a/src/gui/gui.cpp
+++ b/src/gui/gui.cpp
@@ -104,7 +104,8 @@ Gui::Gui(Graphics *graphics):
ResourceManager *resman = ResourceManager::getInstance();
// Set global font
- std::string path = resman->getPath("fonts/dejavusans.ttf");
+ std::string path = resman->getPath(
+ branding.getValue("font", "fonts/dejavusans.ttf"));
try
{
const int fontSize = (int)config.getValue("fontSize", 11);
@@ -118,7 +119,8 @@ Gui::Gui(Graphics *graphics):
}
// Set bold font
- path = resman->getPath("fonts/dejavusans-bold.ttf");
+ path = resman->getPath(
+ branding.getValue("boldFont", "fonts/dejavusans.ttf"));
try
{
const int fontSize = (int)config.getValue("fontSize", 11);
diff --git a/src/gui/guildlistbox.cpp b/src/gui/guildlistbox.cpp
new file mode 100644
index 00000000..556df3fe
--- /dev/null
+++ b/src/gui/guildlistbox.cpp
@@ -0,0 +1,130 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "guildlistbox.h"
+
+#include "../graphics.h"
+
+#include "../resources/image.h"
+#include "../resources/resourcemanager.h"
+
+#include <guichan/font.hpp>
+
+GuildListBox::GuildListBox():
+ ListBox(NULL)
+{
+ onlineIcon = ResourceManager::getInstance()->getImage("graphics/gui/circle-green.png");
+ offlineIcon = ResourceManager::getInstance()->getImage("graphics/gui/circle-gray.png");
+}
+
+void GuildListBox::draw(gcn::Graphics *gcnGraphics)
+{
+ if (!mListModel)
+ return;
+
+ Graphics *graphics = static_cast<Graphics*>(gcnGraphics);
+
+ graphics->setColor(gcn::Color(110, 160, 255));
+ graphics->setFont(getFont());
+
+ int fontHeight = getFont()->getHeight();
+
+ // Draw rectangle below the selected list element
+ if (mSelected >= 0) {
+ graphics->fillRectangle(gcn::Rectangle(0, fontHeight * mSelected,
+ getWidth(), fontHeight));
+ }
+
+ // Draw the list elements
+ for (int i = 0, y = 0;
+ i < mListModel->getNumberOfElements();
+ ++i, y += fontHeight)
+ {
+ // Draw online status
+ bool online = false;
+ UserMap::iterator itr = mUsers.find(mListModel->getElementAt(i));
+ if (itr != mUsers.end())
+ {
+ online = itr->second;
+ }
+ Image *icon = online ? onlineIcon : offlineIcon;
+ if (icon)
+ graphics->drawImage(icon, 1, y);
+ // Draw Name
+ graphics->setColor(gcn::Color(0, 0, 0));
+ graphics->drawText(mListModel->getElementAt(i), 33, y);
+ }
+}
+/*
+void GuildListBox::setSelected(int selected)
+{
+ if (!mListModel)
+ {
+ mSelected = -1;
+ }
+ else
+ {
+ // Update mSelected with bounds checking
+ mSelected = std::min(mListModel->getNumberOfElements() - 1,
+ std::max(-1, selected));
+
+ gcn::Widget *parent;
+ parent = (gcn::Widget*)getParent();
+ if (parent)
+ {
+ gcn::Rectangle scroll;
+ scroll.y = (mSelected < 0) ? 0 : getFont()->getHeight() * mSelected;
+ scroll.height = getFont()->getHeight();
+ parent->showWidgetPart(this, scroll);
+ }
+ }
+
+ distributeValueChangedEvent();
+}
+*/
+void GuildListBox::mousePressed(gcn::MouseEvent &event)
+{
+ if (event.getButton() == gcn::MouseEvent::LEFT)
+ {
+ int y = event.getY();
+ setSelected(y / getFont()->getHeight());
+ distributeActionEvent();
+ }
+ // TODO: Add guild functions, ie private messaging
+ if (event.getButton() == gcn::MouseEvent::RIGHT)
+ {
+ // Show context menu
+ }
+}
+
+void GuildListBox::setOnlineStatus(const std::string &user, bool online)
+{
+ UserMap::iterator itr = mUsers.find(user);
+ if (itr == mUsers.end())
+ {
+ mUsers.insert(std::pair<std::string, bool>(user, online));
+ }
+ else
+ {
+ itr->second = online;
+ }
+ adjustSize();
+}
diff --git a/src/gui/guildlistbox.h b/src/gui/guildlistbox.h
new file mode 100644
index 00000000..cc8e3ce7
--- /dev/null
+++ b/src/gui/guildlistbox.h
@@ -0,0 +1,65 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_GUI_GUILDLISTBOX_H
+#define _TMW_GUI_GUILDLISTBOX_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "listbox.h"
+
+class Image;
+
+class GuildListBox : public ListBox
+{
+public:
+ /**
+ * Constructor
+ */
+ GuildListBox();
+
+ /**
+ * Draws the list box.
+ */
+ void draw(gcn::Graphics *gcnGraphics);
+
+ void mousePressed(gcn::MouseEvent &event);
+
+ /**
+ * Sets the index of the selected element.
+ */
+// void setSelected(int selected);
+
+ /**
+ * Set whether a member is online or offline
+ */
+ void setOnlineStatus(const std::string &user, bool online);
+
+private:
+ Image *onlineIcon;
+ Image *offlineIcon;
+ typedef std::map<std::string, bool> UserMap;
+ UserMap mUsers;
+};
+
+#endif
diff --git a/src/gui/guildwindow.cpp b/src/gui/guildwindow.cpp
new file mode 100644
index 00000000..37d739e4
--- /dev/null
+++ b/src/gui/guildwindow.cpp
@@ -0,0 +1,273 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * $$
+ */
+
+#include "guildwindow.h"
+
+#include "button.h"
+#include "chat.h"
+#include "confirm_dialog.h"
+#include "guildlistbox.h"
+#include "scrollarea.h"
+#include "textdialog.h"
+#include "windowcontainer.h"
+
+#include "widgets/layout.h"
+#include "widgets/tabbedarea.h"
+
+#include "../guild.h"
+#include "../log.h"
+#include "../localplayer.h"
+
+#include "../net/tmwserv/chatserver/guild.h"
+#include "../utils/dtor.h"
+#include "../utils/gettext.h"
+
+#include <algorithm>
+
+#include <guichan/widgets/tab.hpp>
+
+GuildWindow::GuildWindow():
+ Window(_("Guild")),
+ mFocus(false)
+{
+ setWindowName("Guild");
+ setCaption(_("Guild"));
+ setResizable(false);
+ setCloseButton(true);
+ setMinWidth(200);
+ setMinHeight(280);
+ setDefaultSize(124, 41, 288, 330);
+
+ // Set button events Id
+ mGuildButton[0] = new Button(_("Create Guild"), "CREATE_GUILD", this);
+ mGuildButton[1] = new Button(_("Invite User"), "INVITE_USER", this);
+ mGuildButton[2] = new Button(_("Quit Guild"), "QUIT_GUILD", this);
+ mGuildButton[1]->setEnabled(false);
+ mGuildButton[2]->setEnabled(false);
+
+ mGuildTabs = new TabbedArea();
+
+ place(0, 0, mGuildButton[0]);
+ place(1, 0, mGuildButton[1]);
+ place(2, 0, mGuildButton[2]);
+ place(0, 1, mGuildTabs);
+ Layout &layout = getLayout();
+ layout.setColWidth(0, 48);
+ layout.setColWidth(1, 65);
+
+ loadWindowState();
+}
+
+GuildWindow::~GuildWindow()
+{
+ delete mGuildTabs;
+}
+
+void GuildWindow::update()
+{
+ updateTab();
+
+ if (mGuildButton[2]->isEnabled() && mGuildTabs->getNumberOfTabs() <= 0)
+ {
+ mGuildButton[2]->setEnabled(false);
+ mGuildButton[1]->setEnabled(false);
+ }
+}
+
+void GuildWindow::draw(gcn::Graphics *g)
+{
+ update();
+
+ Window::draw(g);
+}
+
+void GuildWindow::action(const gcn::ActionEvent &event)
+{
+ const std::string &eventId = event.getId();
+
+ // Stats Part
+ if (eventId == "CREATE_GUILD")
+ {
+ // Set focus so that guild name to be created can be typed.
+ mFocus = true;
+ guildDialog = new TextDialog("Guild Name", "Choose your guild's name", this);
+ guildDialog->setOKButtonActionId("CREATE_GUILD_OK");
+ guildDialog->addActionListener(this);
+ }
+ else if (eventId == "INVITE_USER")
+ {
+ // TODO - Give feedback on whether the invite succeeded
+ mFocus = true;
+ inviteDialog = new TextDialog("Member Invite", "Who would you like to invite?", this);
+ inviteDialog->setOKButtonActionId("INVITE_USER_OK");
+ inviteDialog->addActionListener(this);
+ }
+ else if (eventId == "QUIT_GUILD")
+ {
+ short guild = getSelectedGuild();
+ if (guild)
+ {
+ Net::ChatServer::Guild::quitGuild(guild);
+ chatWindow->chatLog("Guild " + mGuildTabs->getSelectedTab()->getCaption() + " quit", BY_SERVER);
+ }
+ }
+ else if (eventId == "CREATE_GUILD_OK")
+ {
+ std::string name = guildDialog->getText();
+ if(name.size() > 16)
+ {
+ // TODO : State too many characters in input.
+ return;
+ }
+ // Process guild name to be created, and unfocus.
+ Net::ChatServer::Guild::createGuild(name);
+
+ // Defocus dialog
+ mFocus = false;
+ chatWindow->chatLog("Creating Guild called " + name, BY_SERVER);
+ guildDialog->scheduleDelete();
+ }
+ else if (eventId == "INVITE_USER_OK")
+ {
+ std::string name = inviteDialog->getText();
+ short selectedGuild = getSelectedGuild();
+
+ // Process invited user to be created and unfocus.
+ Net::ChatServer::Guild::invitePlayer(name, selectedGuild);
+
+ // Defocus dialog
+ mFocus = false;
+ chatWindow->chatLog("Invited user " + name, BY_SERVER);
+ inviteDialog->scheduleDelete();
+ }
+ else if (eventId == "yes")
+ {
+ logger->log("Sending invitation acceptance.");
+ Net::ChatServer::Guild::acceptInvite(invitedGuild);
+ }
+}
+
+void GuildWindow::newGuildTab(const std::string &guildName)
+{
+ // Create new tab
+ GuildListBox *list = new GuildListBox();
+ list->setListModel(player_node->getGuild(guildName));
+ ScrollArea *sa = new ScrollArea(list);
+ sa->setDimension(gcn::Rectangle(5, 5, 135, 250));
+
+ // Add the listbox to the map
+ mGuildLists.insert(std::pair<std::string, GuildListBox*>(guildName, list));
+
+ mGuildTabs->addTab(guildName, sa);
+ mGuildTabs->setDimension(gcn::Rectangle(28,35,140,250));
+
+ updateTab();
+}
+
+void GuildWindow::updateTab()
+{
+ gcn::Tab *tab = mGuildTabs->getSelectedTab();
+ if (tab)
+ {
+ setTab(tab->getCaption());
+ }
+ mGuildTabs->logic();
+}
+
+void GuildWindow::setTab(const std::string &guildName)
+{
+ // Only enable invite button if user has rights
+ if(player_node->checkInviteRights(guildName))
+ {
+ mGuildButton[1]->setEnabled(true);
+ }
+ else
+ {
+ mGuildButton[1]->setEnabled(false);
+ }
+
+ mGuildButton[2]->setEnabled(true);
+}
+
+bool GuildWindow::isWindowFocused()
+{
+ return mFocus;
+}
+
+short GuildWindow::getSelectedGuild()
+{
+ if (mGuildTabs->getNumberOfTabs() > 0)
+ {
+
+ Guild *guild = player_node->getGuild(mGuildTabs->getSelectedTab()->getCaption());
+
+ if (guild)
+ {
+ return guild->getId();
+ }
+ }
+
+ return 0;
+}
+
+void GuildWindow::openAcceptDialog(const std::string &inviterName,
+ const std::string &guildName)
+{
+ std::string msg = inviterName + " has invited you to join the guild " + guildName;
+ chatWindow->chatLog(msg, BY_SERVER);
+
+ acceptDialog = new ConfirmDialog("Accept Guild Invite", msg, this);
+ acceptDialog->addActionListener(this);
+
+ invitedGuild = guildName;
+}
+
+void GuildWindow::requestMemberList(short guildId)
+{
+ // Get the list of members for displaying in the guild window.
+ Net::ChatServer::Guild::getGuildMembers(guildId);
+}
+
+void GuildWindow::removeTab(int guildId)
+{
+ Guild* guild = player_node->getGuild(guildId);
+ if (guild)
+ {
+ Tab *tab = mGuildTabs->getTab(guild->getName());
+ if (tab)
+ {
+ mGuildTabs->removeTab(tab);
+ }
+ updateTab();
+ }
+ mGuildTabs->logic();
+}
+
+void GuildWindow::setOnline(const std::string &guildName, const std::string &member,
+ bool online)
+{
+ GuildListMap::iterator itr = mGuildLists.find(guildName);
+ if (itr != mGuildLists.end())
+ {
+ itr->second->setOnlineStatus(member, online);
+ }
+}
diff --git a/src/gui/guildwindow.h b/src/gui/guildwindow.h
new file mode 100644
index 00000000..4f6b9cbb
--- /dev/null
+++ b/src/gui/guildwindow.h
@@ -0,0 +1,135 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_GUI_GUILDWINDOW_H
+#define _TMW_GUI_GUILDWINDOW_H
+
+#include <iosfwd>
+#include <map>
+#include <vector>
+
+#include <guichan/actionlistener.hpp>
+#include <guichan/widgets/listbox.hpp>
+
+#include "window.h"
+
+#include "../guichanfwd.h"
+
+class LocalPlayer;
+class TextDialog;
+class ConfirmDialog;
+class GuildListBox;
+class ScrollArea;
+class GCContainer;
+class TabbedArea;
+
+class GuildWindow : public Window, public gcn::ActionListener
+{
+public:
+ /**
+ * Constructor.
+ */
+ GuildWindow();
+
+ /**
+ * Destructor.
+ */
+ ~GuildWindow();
+
+ /**
+ * Called when receiving actions from widget.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ /**
+ * Draw this window.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Updates this dialog.
+ */
+ void update();
+
+ /**
+ * Create a new tab for a guild list.
+ */
+ void newGuildTab(const std::string &guildName);
+
+ /**
+ * Display guild's member list to active tab
+ */
+ void setTab(const std::string &guildName);
+
+ /**
+ * Update the contents of the active tab
+ */
+ void updateTab();
+
+ /**
+ * Check if the window is in focus.
+ */
+ bool isWindowFocused();
+
+ /**
+ * Create a dialog for accepting an invite
+ */
+ void openAcceptDialog(const std::string &inviterName, const std::string &guildName);
+
+ /**
+ * Request member list
+ */
+ void requestMemberList(short guildId);
+
+ /**
+ * Removes the selected tab
+ */
+ void removeTab(int guildId);
+
+ /**
+ * Set guild member status in userlist
+ */
+ void setOnline(const std::string &guildName, const std::string &member,
+ bool online);
+
+protected:
+ /**
+ * Get selected guild tab
+ * @return Returns selected guild
+ */
+ short getSelectedGuild();
+
+private:
+ gcn::Button *mGuildButton[3];
+ TextDialog *guildDialog;
+ TextDialog *inviteDialog;
+ ConfirmDialog *acceptDialog;
+ TabbedArea *mGuildTabs;
+ ScrollArea *mScrollArea;
+ bool mFocus;
+ std::string invitedGuild;
+ typedef std::map<std::string, GuildListBox*> GuildListMap;
+ GuildListMap mGuildLists;
+};
+
+extern GuildWindow *guildWindow;
+
+#endif
diff --git a/src/gui/icon.cpp b/src/gui/icon.cpp
new file mode 100644
index 00000000..1e352292
--- /dev/null
+++ b/src/gui/icon.cpp
@@ -0,0 +1,58 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "icon.h"
+
+#include "../graphics.h"
+
+#include "../resources/image.h"
+#include "../resources/resourcemanager.h"
+
+Icon::Icon(const std::string &file)
+ : mImage(0)
+{
+ mImage = ResourceManager::getInstance()->getImage(file);
+ setSize(mImage->getWidth(), mImage->getHeight());
+
+}
+
+Icon::Icon(Image *image)
+ : mImage(image)
+{
+ setSize(mImage->getWidth(), mImage->getHeight());
+}
+
+void Icon::setImage(Image *image)
+{
+ mImage = image;
+ setSize(mImage->getWidth(), mImage->getHeight());
+}
+
+void Icon::draw(gcn::Graphics *g)
+{
+ if(mImage)
+ {
+ Graphics *graphics = static_cast<Graphics*>(g);
+ const int x = (getWidth() - mImage->getWidth()) / 2;
+ const int y = (getHeight() - mImage->getHeight()) / 2;
+ graphics->drawImage(mImage, x, y);
+ }
+}
diff --git a/src/gui/icon.h b/src/gui/icon.h
new file mode 100644
index 00000000..9baf1a99
--- /dev/null
+++ b/src/gui/icon.h
@@ -0,0 +1,68 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _TMW_ICON_H
+#define _TMW_ICON_H
+
+#include <guichan/widget.hpp>
+
+class Image;
+
+
+/**
+ * An icon.
+ *
+ * \ingroup GUI
+ */
+class Icon : public gcn::Widget {
+ public:
+ /**
+ * Constructor.
+ */
+ Icon(const std::string &filename);
+
+ /**
+ * Constructor, uses an existing Image.
+ */
+ Icon(Image *image);
+
+ /**
+ * Gets the current Image.
+ */
+ Image* getImage() { return mImage; }
+
+ /**
+ * Sets the image to display.
+ */
+ void setImage(Image *image);
+
+ /**
+ * Draws the Icon.
+ */
+ void draw(gcn::Graphics *g);
+
+ private:
+
+ Image *mImage;
+};
+
+#endif
diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp
index 50fae483..0b554469 100644
--- a/src/gui/inventorywindow.cpp
+++ b/src/gui/inventorywindow.cpp
@@ -31,6 +31,7 @@
#include "label.h"
#include "progressbar.h"
#include "scrollarea.h"
+#include "sdlinput.h"
#include "viewport.h"
#include "widgets/layout.h"
@@ -43,20 +44,25 @@
#include "../resources/iteminfo.h"
#include "../utils/gettext.h"
-#include "../utils/strprintf.h"
#include "../utils/stringutils.h"
+#include "../utils/strprintf.h"
InventoryWindow::InventoryWindow(int invSize):
Window(_("Inventory")),
mMaxSlots(invSize),
+ mSplit(false),
mItemDesc(false)
{
setWindowName("Inventory");
- setResizable(true);
+ setResizable(false);
setCloseButton(true);
-
+ // LEEOR/TODO: Since this window is not resizable, do we really need to set these
+ // values or can we drop them?
+ setMinWidth(375);
+ setMinHeight(283);
// If you adjust these defaults, don't forget to adjust the trade window's.
setDefaultSize(375, 300, ImageRect::CENTER);
+ addKeyListener(this);
std::string longestUseString = getFont()->getWidth(_("Equip")) >
getFont()->getWidth(_("Use")) ?
@@ -70,8 +76,15 @@ InventoryWindow::InventoryWindow(int invSize):
mUseButton = new Button(longestUseString, "use", this);
mDropButton = new Button(_("Drop"), "drop", this);
-
- mItems = new ItemContainer(player_node->getInventory(), 2);
+#ifdef TMWSERV_SUPPORT
+ mSplitButton = new Button(_("Split"), "split", this);
+#endif
+
+#ifdef TMWSERV_SUPPORT
+ mItems = new ItemContainer(player_node->getInventory(), 10, 5);
+#else
+ mItems = new ItemContainer(player_node->getInventory(), 10, 5, 2);
+#endif
mItems->addSelectionListener(this);
mInvenScroll = new ScrollArea(mItems);
@@ -94,12 +107,15 @@ InventoryWindow::InventoryWindow(int invSize):
place(1, 0, mWeightBar, 3);
place(4, 0, mSlotsLabel).setPadding(3);
place(5, 0, mSlotsBar, 2);
- place(0, 1, mInvenScroll, 7, 4);
- place(5, 5, mDropButton);
- place(6, 5, mUseButton);
+ place(0, 1, mInvenScroll, 100).setPadding(3);
+ place(0, 2, mUseButton);
+ place(1, 2, mDropButton);
+#ifdef TMWSERV_SUPPORT
+ place(2, 2, mSplitButton);
+#endif
Layout &layout = getLayout();
- layout.setRowHeight(0, mDropButton->getHeight());
+ layout.setRowHeight(0, Layout::AUTO_SET);
loadWindowState();
}
@@ -120,21 +136,21 @@ void InventoryWindow::logic()
// redesign of InventoryWindow and ItemContainer probably.
updateButtons();
- if (mMaxWeight != player_node->mMaxWeight ||
- mTotalWeight != player_node->mTotalWeight ||
+ if (mMaxWeight != player_node->getMaxWeight() ||
+ mTotalWeight != player_node->getTotalWeight() ||
mUsedSlots != toString(player_node->getInventory()->getNumberOfSlotsUsed()))
{
- mTotalWeight = player_node->mTotalWeight;
- mMaxWeight = player_node->mMaxWeight;
+ mTotalWeight = player_node->getTotalWeight();
+ mMaxWeight = player_node->getMaxWeight();
mUsedSlots = toString(player_node->getInventory()->getNumberOfSlotsUsed());
// Weight Bar coloration
- if (int(player_node->mTotalWeight) < int(player_node->mMaxWeight / 3))
+ if (int(player_node->getTotalWeight()) < int(player_node->getMaxWeight() / 3))
{
mWeightBar->setColor(0, 0, 255); // Blue
}
- else if (int(player_node->mTotalWeight) <
- int((player_node->mMaxWeight / 3) * 2))
+ else if (int(player_node->getTotalWeight()) <
+ int((player_node->getMaxWeight() / 3) * 2))
{
mWeightBar->setColor(255, 255, 0); // Yellow
}
@@ -146,8 +162,8 @@ void InventoryWindow::logic()
// Adjust progress bars
mSlotsBar->setProgress((float)
player_node->getInventory()->getNumberOfSlotsUsed() / mMaxSlots);
- mWeightBar->setProgress((float) player_node->mTotalWeight /
- player_node->mMaxWeight);
+ mWeightBar->setProgress((float) player_node->getTotalWeight() /
+ player_node->getMaxWeight());
mSlotsBar->setText(strprintf("%s/%d", mUsedSlots.c_str(), mMaxSlots));
mWeightBar->setText(strprintf("%s/%s",
@@ -165,6 +181,14 @@ void InventoryWindow::action(const gcn::ActionEvent &event)
if (event.getId() == "use")
{
+#ifdef TMWSERV_SUPPORT
+ if (item->isEquipment()) {
+ player_node->equipItem(item);
+ }
+ else {
+ player_node->useItem(item->getInvIndex());
+ }
+#else
if (item->isEquipment())
{
if (item->isEquipped())
@@ -174,19 +198,33 @@ void InventoryWindow::action(const gcn::ActionEvent &event)
}
else
player_node->useItem(item);
+#endif
}
else if (event.getId() == "drop")
{
- if (item->getQuantity() == 1)
- player_node->dropItem(item, 1);
- else
- {
+ if (item->getQuantity() > 1) {
// Choose amount of items to drop
new ItemAmountWindow(AMOUNT_ITEM_DROP, this, item);
}
+ else {
+ player_node->dropItem(item, 1);
+ }
+ mItems->selectNone();
+ }
+ else if (event.getId() == "split")
+ {
+ if (item && !item->isEquipment() && item->getQuantity() > 1) {
+ new ItemAmountWindow(AMOUNT_ITEM_SPLIT, this, item,
+ (item->getQuantity() - 1));
+ }
}
}
+Item* InventoryWindow::getSelectedItem() const
+{
+ return mItems->getSelectedItem();
+}
+
void InventoryWindow::mouseClicked(gcn::MouseEvent &event)
{
Window::mouseClicked(event);
@@ -207,15 +245,55 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event)
}
}
+#ifdef TMWSERV_SUPPORT
+void InventoryWindow::keyPressed(gcn::KeyEvent &event)
+{
+ switch (event.getKey().getValue())
+ {
+ case Key::LEFT_SHIFT:
+ case Key::RIGHT_SHIFT:
+ mSplit = true;
+ break;
+ }
+}
+
+void InventoryWindow::keyReleased(gcn::KeyEvent &event)
+{
+ switch (event.getKey().getValue())
+ {
+ case Key::LEFT_SHIFT:
+ case Key::RIGHT_SHIFT:
+ mSplit = false;
+ break;
+ }
+}
+#endif
+
+void InventoryWindow::valueChanged(const gcn::SelectionEvent &event)
+{
+ if (mSplit)
+ {
+ Item *item = mItems->getSelectedItem();
+
+ if (item && !item->isEquipment() && item->getQuantity() > 1)
+ {
+ mSplit = false;
+ new ItemAmountWindow(AMOUNT_ITEM_SPLIT, this, item, (item->getQuantity() - 1));
+ }
+ }
+}
+
void InventoryWindow::updateButtons()
{
const Item *selectedItem = mItems->getSelectedItem();
if (selectedItem && selectedItem->isEquipment())
{
+#ifdef EATHENA_SUPPORT
if (selectedItem->isEquipped())
mUseButton->setCaption(_("Unequip"));
else
+#endif
mUseButton->setCaption(_("Equip"));
}
else
@@ -223,9 +301,15 @@ void InventoryWindow::updateButtons()
mUseButton->setEnabled(selectedItem != 0);
mDropButton->setEnabled(selectedItem != 0);
-}
-Item* InventoryWindow::getSelectedItem() const
-{
- return mItems->getSelectedItem();
+#ifdef TMWSERV_SUPPORT
+ if (selectedItem && !selectedItem->isEquipment() &&
+ selectedItem->getQuantity() > 1)
+ {
+ mSplitButton->setEnabled(true);
+ }
+ else {
+ mSplitButton->setEnabled(false);
+ }
+#endif
}
diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h
index e1196f78..95a47bdb 100644
--- a/src/gui/inventorywindow.h
+++ b/src/gui/inventorywindow.h
@@ -27,6 +27,7 @@
#include "../inventory.h"
#include <guichan/actionlistener.hpp>
+#include <guichan/keylistener.hpp>
#include <guichan/selectionlistener.hpp>
class Item;
@@ -39,14 +40,20 @@ class TextBox;
*
* \ingroup Interface
*/
-class InventoryWindow : public Window, gcn::ActionListener,
- gcn::SelectionListener
+class InventoryWindow : public Window,
+ public gcn::ActionListener,
+ public gcn::KeyListener,
+ public gcn::SelectionListener
{
public:
/**
* Constructor.
*/
+#ifdef TMWSERV_SUPPORT
+ InventoryWindow(int invSize = (INVENTORY_SIZE));
+#else
InventoryWindow(int invSize = (INVENTORY_SIZE - 2));
+#endif
/**
* Destructor.
@@ -68,8 +75,28 @@ class InventoryWindow : public Window, gcn::ActionListener,
*/
Item* getSelectedItem() const;
+ /**
+ * Handles the mouse clicks.
+ */
void mouseClicked(gcn::MouseEvent &event);
+#ifdef TMWSERV_SUPPORT
+ /**
+ * Handles the key presses.
+ */
+ void keyPressed(gcn::KeyEvent &event);
+
+ /**
+ * Handles the key releases.
+ */
+ void keyReleased(gcn::KeyEvent &event);
+#endif
+
+ /**
+ * Updates labels to currently selected item.
+ */
+ void valueChanged(const gcn::SelectionEvent &event);
+
private:
void updateButtons(); /**< Updates button states. */
@@ -78,10 +105,13 @@ class InventoryWindow : public Window, gcn::ActionListener,
std::string mWeight;
std::string mSlots;
std::string mUsedSlots;
- Uint32 mTotalWeight, mMaxWeight;
- gcn::Button *mUseButton, *mDropButton;
- gcn::ScrollArea *mInvenScroll;
-
+ int mTotalWeight, mMaxWeight;
+ gcn::Button *mUseButton;
+ gcn::Button *mDropButton;
+#ifdef TMWSERV_SUPPORT
+ gcn::Button *mSplitButton;
+#endif
+ gcn::ScrollArea *mInvenScroll; /**< Inventory Scroll Area. */
gcn::Label *mWeightLabel;
gcn::Label *mSlotsLabel;
@@ -90,6 +120,7 @@ class InventoryWindow : public Window, gcn::ActionListener,
int mMaxSlots;
+ bool mSplit;
bool mItemDesc;
};
diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp
index a8242aae..0f6aa593 100644
--- a/src/gui/item_amount.cpp
+++ b/src/gui/item_amount.cpp
@@ -23,7 +23,9 @@
#include "item_amount.h"
#include "label.h"
#include "slider.h"
+#ifdef EATHENA_SUPPORT
#include "storagewindow.h"
+#endif
#include "trade.h"
#include "widgets/layout.h"
@@ -34,12 +36,16 @@
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
-ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item):
+ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item,
+ int maxRange):
Window("", true, parent),
mItem(item),
- mMax(item->getQuantity()),
+ mMax(maxRange),
mUsage(usage)
{
+ if (!mMax)
+ mMax = mItem->getQuantity();
+
setCloseButton(true);
// Integer field
@@ -93,6 +99,9 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item):
case AMOUNT_STORE_REMOVE:
setCaption(_("Select amount of items to retrieve."));
break;
+ case AMOUNT_ITEM_SPLIT:
+ setCaption(_("Select amount of items to split."));
+ break;
default:
break;
}
@@ -139,12 +148,18 @@ void ItemAmountWindow::action(const gcn::ActionEvent &event)
case AMOUNT_ITEM_DROP:
player_node->dropItem(mItem, amount);
break;
+#ifdef TMWSERV_SUPPORT
+ case AMOUNT_ITEM_SPLIT:
+ player_node->splitItem(mItem, amount);
+ break;
+#else
case AMOUNT_STORE_ADD:
storageWindow->addStore(mItem, amount);
break;
case AMOUNT_STORE_REMOVE:
storageWindow->removeStore(mItem, amount);
break;
+#endif
default:
return;
break;
diff --git a/src/gui/item_amount.h b/src/gui/item_amount.h
index d8253e3c..344f8c28 100644
--- a/src/gui/item_amount.h
+++ b/src/gui/item_amount.h
@@ -33,9 +33,10 @@ class Item;
#define AMOUNT_ITEM_DROP 2
#define AMOUNT_STORE_ADD 3
#define AMOUNT_STORE_REMOVE 4
+#define AMOUNT_ITEM_SPLIT 5
/**
- * Window used for selecting the amount of items to drop or trade.
+ * Window used for selecting the amount of items to drop, trade or split.
*
* \ingroup Interface
*/
@@ -45,7 +46,7 @@ class ItemAmountWindow : public Window, public gcn::ActionListener
/**
* Constructor.
*/
- ItemAmountWindow(int usage, Window *parent, Item *item);
+ ItemAmountWindow(int usage, Window *parent, Item *item, int maxRange = 0);
/**
* Called when receiving actions from widget.
diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp
index 8a780eb4..38a41e0e 100644
--- a/src/gui/itemcontainer.cpp
+++ b/src/gui/itemcontainer.cpp
@@ -19,12 +19,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include <guichan/mouseinput.hpp>
#include <guichan/selectionlistener.hpp>
+#include "chat.h"
#include "itemcontainer.h"
#include "itempopup.h"
#include "palette.h"
+#include "sdlinput.h"
#include "viewport.h"
#include "../graphics.h"
@@ -39,29 +42,48 @@
#include "../utils/stringutils.h"
-const int ItemContainer::gridWidth = 36; // item icon width + 4
-const int ItemContainer::gridHeight = 42; // item icon height + 10
+// TODO: Add support for adding items to the item shortcut window (global
+// itemShortcut).
-static const int NO_ITEM = -1;
+static const int BOX_WIDTH = 36;
+static const int BOX_HEIGHT = 44;
-ItemContainer::ItemContainer(Inventory *inventory, int offset):
+enum
+{
+ SEL_NONE = 0,
+ SEL_SELECTED,
+ SEL_SELECTING,
+ SEL_DESELECTING,
+ SEL_DRAGGING
+};
+
+ItemContainer::ItemContainer(Inventory *inventory,
+ int gridColumns,
+ int gridRows,
+ int offset):
mInventory(inventory),
- mSelectedItemIndex(NO_ITEM),
- mLastSelectedItemId(NO_ITEM),
- mOffset(offset)
+ mGridColumns(gridColumns),
+ mGridRows(gridRows),
+ mOffset(offset),
+ mSelectedItem(NULL),
+ mHighlightedItem(NULL),
+ mSelectionStatus(SEL_NONE),
+ mSwapItems(false),
+ mDescItems(false)
{
- mItemPopup = new ItemPopup;
- mItemPopup->setOpaque(false);
+ mItemPopup = new ItemPopup();
+ setFocusable(true);
ResourceManager *resman = ResourceManager::getInstance();
mSelImg = resman->getImage("graphics/gui/selection.png");
if (!mSelImg) logger->error("Unable to load selection.png");
- mMaxItems = mInventory->getLastUsedSlot() - (mOffset - 1); // Count from 0, usage from 2
-
+ addKeyListener(this);
addMouseListener(this);
- addWidgetListener(this);
+
+ setSize((BOX_WIDTH - 1) * mGridColumns + 1,
+ (BOX_HEIGHT - 1) * mGridRows + 1);
}
ItemContainer::~ItemContainer()
@@ -70,185 +92,214 @@ ItemContainer::~ItemContainer()
delete mItemPopup;
}
-void ItemContainer::logic()
-{
- if (!isVisible())
- return;
-
- gcn::Widget::logic();
-
- int i = mInventory->getLastUsedSlot() - (mOffset - 1); // Count from 0, usage from 2
-
- if (i != mMaxItems)
- {
- mMaxItems = i;
- recalculateHeight();
- }
-}
-
void ItemContainer::draw(gcn::Graphics *graphics)
{
- if (!isVisible())
- return;
-
- int columns = getWidth() / gridWidth;
+ Graphics *g = static_cast<Graphics*>(graphics);
- // Have at least 1 column
- if (columns < 1)
- columns = 1;
-
- /*
- * mOffset is used to compensate for some weirdness that eAthena inherited
- * from Ragnarok Online. Inventory slots and cart slots are +2 from their
- * actual index, while storage slots are +1.
- */
- for (int i = mOffset; i < mInventory->getSize(); i++)
+ for (int i = 0; i < mGridColumns; i++)
{
- Item *item = mInventory->getItem(i);
+ for (int j = 0; j < mGridRows; j++)
+ {
+ // Items positions made to overlap on another.
+ int itemX = i * (BOX_WIDTH - 1);
+ int itemY = j * (BOX_HEIGHT - 1);
- if (!item || item->getQuantity() <= 0)
- continue;
+ // Set color to black.
+ g->setColor(gcn::Color(0, 0, 0));
+ // Draw box border.
+ g->drawRectangle(
+ gcn::Rectangle(itemX, itemY, BOX_WIDTH, BOX_HEIGHT));
- int itemX = ((i - mOffset) % columns) * gridWidth;
- int itemY = ((i - mOffset) / columns) * gridHeight;
+ Item *item = mInventory->getItem((j * mGridColumns) + i);
- // Draw selection image below selected item
- if (mSelectedItemIndex == i)
- static_cast<Graphics*>(graphics)->drawImage(mSelImg, itemX, itemY);
+ if (!item || item->getId() == 0)
+ continue;
- // Draw item icon
- Image* image = item->getImage();
+ Image *image = item->getImage();
+ if (image)
+ {
+ if (item == mSelectedItem)
+ {
+ if (mSelectionStatus == SEL_DRAGGING) {
+ // Reposition the coords to that of the cursor.
+ itemX = mDragPosX - (BOX_WIDTH / 2);
+ itemY = mDragPosY - (BOX_HEIGHT / 2);
+ }
+ else {
+ // Draw selected image.
+ g->drawImage(mSelImg, itemX, itemY);
+ }
+ }
+ g->drawImage(image, itemX, itemY);
+ }
+ if (item->getQuantity() > 1) {
+ // Draw item caption
+ g->drawText(
+ toString(item->getQuantity()),
+ itemX + BOX_WIDTH / 2,
+ itemY + BOX_HEIGHT - 14,
+ gcn::Graphics::CENTER);
+ }
- if (image)
- static_cast<Graphics*>(graphics)->drawImage(image, itemX, itemY);
+ }
+ }
- // Draw item caption
- graphics->setFont(getFont());
- graphics->setColor(guiPalette->getColor(Palette::TEXT));
- graphics->drawText(
- (item->isEquipped() ? "Eq." : toString(item->getQuantity())),
- itemX + gridWidth / 2, itemY + gridHeight - 11,
- gcn::Graphics::CENTER);
+ if (isFocused() && mHighlightedItem) {
+ // Items positions made to overlap on another.
+ const int i = mHighlightedItem->getInvIndex();
+ const int itemX = (i % mGridColumns) * (BOX_WIDTH - 1);
+ const int itemY = (i / mGridColumns) * (BOX_HEIGHT - 1);
+ // Set color to orange.
+ g->setColor(gcn::Color(255, 128, 0));
+ // Draw box border.
+ g->drawRectangle(gcn::Rectangle(itemX, itemY, BOX_WIDTH, BOX_HEIGHT));
}
}
-void ItemContainer::widgetResized(const gcn::Event &event)
+void ItemContainer::selectNone()
{
- recalculateHeight();
+ setSelectedItem(NULL);
}
-void ItemContainer::recalculateHeight()
+void ItemContainer::setSelectedItem(Item *item)
{
- int cols = getWidth() / gridWidth;
-
- if (cols < 1)
- cols = 1;
-
- const int rows = (mMaxItems / cols) + (mMaxItems % cols > 0 ? 1 : 0);
- const int height = rows * gridHeight + 8;
-
- if (height != getHeight())
- setHeight(height);
-}
-
-Item *ItemContainer::getSelectedItem()
-{
- refindSelectedItem(); // Make sure that we're still current
-
- if (mSelectedItemIndex == NO_ITEM)
- return NULL;
-
- return mInventory->getItem(mSelectedItemIndex);
+ if (mSelectedItem != item)
+ {
+ mSelectedItem = item;
+ distributeValueChangedEvent();
+ }
}
-void ItemContainer::selectNone()
+void ItemContainer::distributeValueChangedEvent()
{
- setSelectedItemIndex(NO_ITEM);
-}
+ SelectionListenerIterator iter;
-void ItemContainer::refindSelectedItem()
-{
- if (mSelectedItemIndex != NO_ITEM)
+ for (iter = mSelectionListeners.begin(); iter != mSelectionListeners.end();
+ ++iter)
{
- if (mInventory->getItem(mSelectedItemIndex) &&
- mInventory->getItem(mSelectedItemIndex)->getId() == mLastSelectedItemId)
- return; // we're already fine
-
- // Otherwise ensure the invariant: we must point to an item of the specified last ID,
- // or nowhere at all.
-
- for (int i = 0; i <= mMaxItems + 1; i++)
- if (mInventory->getItem(i) &&
- mInventory->getItem(i)->getId() == mLastSelectedItemId)
- {
- mSelectedItemIndex = i;
- return;
- }
+ gcn::SelectionEvent event(this);
+ (*iter)->valueChanged(event);
}
-
- mLastSelectedItemId = mSelectedItemIndex = NO_ITEM;
}
-void ItemContainer::setSelectedItemIndex(int index)
+void ItemContainer::keyPressed(gcn::KeyEvent &event)
{
- int newSelectedItemIndex;
-
- /*
- * mOffset is used to compensate for some weirdness that eAthena inherited from
- * Ragnarok Online. Inventory slots and cart slots are +2 from their actual index,
- * while storage slots are +1.
- */
- if (index < 0 || index > mMaxItems + mOffset || mInventory->getItem(index) == NULL)
- newSelectedItemIndex = NO_ITEM;
- else
- newSelectedItemIndex = index;
-
- if (mSelectedItemIndex != newSelectedItemIndex)
+ switch (event.getKey().getValue())
{
- mSelectedItemIndex = newSelectedItemIndex;
-
- if (mSelectedItemIndex == NO_ITEM)
- mLastSelectedItemId = NO_ITEM;
- else
- mLastSelectedItemId = mInventory->getItem(index)->getId();
-
- distributeValueChangedEvent();
+ case Key::LEFT:
+ moveHighlight(MOVE_SELECTED_LEFT);
+ break;
+ case Key::RIGHT:
+ moveHighlight(MOVE_SELECTED_RIGHT);
+ break;
+ case Key::UP:
+ moveHighlight(MOVE_SELECTED_UP);
+ break;
+ case Key::DOWN:
+ moveHighlight(MOVE_SELECTED_DOWN);
+ break;
+ case Key::SPACE:
+ keyAction();
+ break;
+ case Key::LEFT_ALT:
+ case Key::RIGHT_ALT:
+ mSwapItems = true;
+ break;
+ case Key::RIGHT_CONTROL:
+ mDescItems = true;
+ break;
}
}
-void ItemContainer::distributeValueChangedEvent()
+void ItemContainer::keyReleased(gcn::KeyEvent &event)
{
- gcn::SelectionEvent event(this);
- std::list<gcn::SelectionListener*>::iterator i_end = mListeners.end();
- std::list<gcn::SelectionListener*>::iterator i;
-
- for (i = mListeners.begin(); i != i_end; ++i)
+ switch (event.getKey().getValue())
{
- (*i)->valueChanged(event);
+ case Key::LEFT_ALT:
+ case Key::RIGHT_ALT:
+ mSwapItems = false;
+ break;
+ case Key::RIGHT_CONTROL:
+ mDescItems = false;
+ break;
}
}
void ItemContainer::mousePressed(gcn::MouseEvent &event)
{
const int button = event.getButton();
-
if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT)
{
- int columns = getWidth() / gridWidth;
- int mx = event.getX();
- int my = event.getY();
- int index = mx / gridWidth + ((my / gridHeight) * columns) + mOffset;
-
- itemShortcut->setItemSelected(-1);
- setSelectedItemIndex(index);
+ const int index = getSlotIndex(event.getX(), event.getY());
+ if (index == Inventory::NO_SLOT_INDEX) {
+ return;
+ }
Item *item = mInventory->getItem(index);
- if (item)
+ // put item name into chat window
+ if (mDescItems)
+ {
+ chatWindow->addItemText(item->getInfo().getName());
+ }
+
+ if (mSelectedItem && mSelectedItem == item)
+ {
+ mSelectionStatus = SEL_DESELECTING;
+ }
+ else if (item && item->getId())
+ {
+ setSelectedItem(item);
+ mSelectionStatus = SEL_SELECTING;
+
itemShortcut->setItemSelected(item->getId());
+ }
+ else
+ {
+ setSelectedItem(NULL);
+ mSelectionStatus = SEL_NONE;
+ }
}
}
+void ItemContainer::mouseDragged(gcn::MouseEvent &event)
+{
+ if (mSelectionStatus != SEL_NONE)
+ {
+ mSelectionStatus = SEL_DRAGGING;
+ mDragPosX = event.getX();
+ mDragPosY = event.getY();
+ }
+}
+
+void ItemContainer::mouseReleased(gcn::MouseEvent &event)
+{
+ switch (mSelectionStatus)
+ {
+ case SEL_SELECTING:
+ mSelectionStatus = SEL_SELECTED;
+ return;
+ case SEL_DESELECTING:
+ setSelectedItem(NULL);
+ mSelectionStatus = SEL_NONE;
+ return;
+ case SEL_DRAGGING:
+ mSelectionStatus = SEL_SELECTED;
+ break;
+ default:
+ return;
+ };
+
+ int index = getSlotIndex(event.getX(), event.getY());
+ if (index == Inventory::NO_SLOT_INDEX) return;
+ Item *item = mInventory->getItem(index);
+ if (item == mSelectedItem) return;
+ player_node->moveInvItem(mSelectedItem, index);
+ setSelectedItem(NULL);
+ mSelectionStatus = SEL_NONE;
+}
+
+
// Show ItemTooltip
void ItemContainer::mouseMoved(gcn::MouseEvent &event)
{
@@ -273,11 +324,97 @@ void ItemContainer::mouseExited(gcn::MouseEvent &event)
mItemPopup->setVisible(false);
}
-int ItemContainer::getSlotIndex(int posX, int posY) const
+int ItemContainer::getSlotIndex(const int posX, const int posY) const
{
- int columns = getWidth() / gridWidth;
- int index = posX / gridWidth + ((posY / gridHeight) * columns) + mOffset;
+ if (getDimension().isPointInRect(posX, posY))
+ {
+ // Takes into account, boxes are overlapping each other.
+ return (posY / (BOX_HEIGHT - 1)) * mGridColumns + (posX / (BOX_WIDTH - 1));
+ }
+ return Inventory::NO_SLOT_INDEX;
+}
- return (index);
+void ItemContainer::keyAction()
+{
+ // If there is no highlight then return.
+ if (!mHighlightedItem)
+ return;
+
+ // If the highlight is on the selected item, then deselect it.
+ if (mHighlightedItem == mSelectedItem)
+ {
+ setSelectedItem(NULL);
+ mSelectionStatus = SEL_NONE;
+ }
+ // Check and swap items if necessary.
+ else if (mSwapItems &&
+ mSelectedItem &&
+ mHighlightedItem->getId())
+ {
+ player_node->moveInvItem(
+ mSelectedItem, mHighlightedItem->getInvIndex());
+ setSelectedItem(mHighlightedItem);
+ }
+ // If the highlight is on an item then select it.
+ else if (mHighlightedItem->getId())
+ {
+ setSelectedItem(mHighlightedItem);
+ mSelectionStatus = SEL_SELECTED;
+ }
+ // If the highlight is on a blank space then move it.
+ else if (mSelectedItem)
+ {
+ player_node->moveInvItem(
+ mSelectedItem, mHighlightedItem->getInvIndex());
+ setSelectedItem(NULL);
+ mSelectionStatus = SEL_NONE;
+ }
}
+void ItemContainer::moveHighlight(int direction)
+{
+ if (!mHighlightedItem)
+ {
+ if (mSelectedItem) {
+ mHighlightedItem = mSelectedItem;
+ }
+ else {
+ mHighlightedItem = mInventory->getItem(0);
+ }
+ return;
+ }
+
+ switch (direction)
+ {
+ case MOVE_SELECTED_LEFT:
+ if (mHighlightedItem->getInvIndex() % mGridColumns == 0)
+ {
+ mHighlightedItem += mGridColumns;
+ }
+ mHighlightedItem--;
+ break;
+ case MOVE_SELECTED_RIGHT:
+ if ((mHighlightedItem->getInvIndex() % mGridColumns) ==
+ (mGridColumns - 1))
+ {
+ mHighlightedItem -= mGridColumns;
+ }
+ mHighlightedItem++;
+ break;
+ case MOVE_SELECTED_UP:
+ if (mHighlightedItem->getInvIndex() / mGridColumns == 0)
+ {
+ mHighlightedItem += (mGridColumns * mGridRows);
+ }
+ mHighlightedItem -= mGridColumns;
+ break;
+ case MOVE_SELECTED_DOWN:
+ if ((mHighlightedItem->getInvIndex() / mGridColumns) ==
+ (mGridRows - 1))
+ {
+ mHighlightedItem -= (mGridColumns * mGridRows);
+ }
+ mHighlightedItem += mGridColumns;
+ break;
+ }
+}
diff --git a/src/gui/itemcontainer.h b/src/gui/itemcontainer.h
index 5ad140be..38eaba01 100644
--- a/src/gui/itemcontainer.h
+++ b/src/gui/itemcontainer.h
@@ -24,9 +24,9 @@
#include <list>
+#include <guichan/keylistener.hpp>
#include <guichan/mouselistener.hpp>
#include <guichan/widget.hpp>
-#include <guichan/widgetlistener.hpp>
class Image;
class Inventory;
@@ -43,14 +43,19 @@ namespace gcn {
* \ingroup GUI
*/
class ItemContainer : public gcn::Widget,
- public gcn::MouseListener,
- public gcn::WidgetListener
+ public gcn::KeyListener,
+ public gcn::MouseListener
{
public:
/**
* Constructor. Initializes the graphic.
+ * @param inventory
+ * @param gridColumns Amount of columns in grid.
+ * @param gridRows Amount of rows in grid.
+ * @param offset Index offset
*/
- ItemContainer(Inventory *inventory, int offset);
+ ItemContainer(Inventory *inventory, int gridColumns, int gridRows,
+ int offset = 0);
/**
* Destructor.
@@ -58,19 +63,19 @@ class ItemContainer : public gcn::Widget,
virtual ~ItemContainer();
/**
- * Handles the logic of the ItemContainer
+ * Draws the items.
*/
- void logic();
+ void draw(gcn::Graphics *graphics);
/**
- * Draws the items.
+ * Handles the key presses.
*/
- void draw(gcn::Graphics *graphics);
+ void keyPressed(gcn::KeyEvent &event);
/**
- * Called whenever the widget changes size.
+ * Handles the key releases.
*/
- void widgetResized(const gcn::Event &event);
+ void keyReleased(gcn::KeyEvent &event);
/**
* Handles mouse click.
@@ -78,9 +83,20 @@ class ItemContainer : public gcn::Widget,
void mousePressed(gcn::MouseEvent &event);
/**
+ * Handles mouse dragged.
+ */
+ void mouseDragged(gcn::MouseEvent &event);
+
+ /**
+ * Handles mouse released.
+ */
+ void mouseReleased(gcn::MouseEvent &event);
+
+ /**
* Returns the selected item.
*/
- Item* getSelectedItem();
+ Item* getSelectedItem() const
+ { return mSelectedItem; }
/**
* Sets selected item to NULL.
@@ -93,7 +109,7 @@ class ItemContainer : public gcn::Widget,
*/
void addSelectionListener(gcn::SelectionListener *listener)
{
- mListeners.push_back(listener);
+ mSelectionListeners.push_back(listener);
}
/**
@@ -102,18 +118,35 @@ class ItemContainer : public gcn::Widget,
*/
void removeSelectionListener(gcn::SelectionListener *listener)
{
- mListeners.remove(listener);
+ mSelectionListeners.remove(listener);
}
+ enum {
+ MOVE_SELECTED_LEFT, // 0
+ MOVE_SELECTED_RIGHT, // 1
+ MOVE_SELECTED_UP, // 2
+ MOVE_SELECTED_DOWN // 3
+ };
private:
+ /**
+ * Execute all the functionality associated with the action key.
+ */
+ void keyAction();
+
void mouseExited(gcn::MouseEvent &event);
void mouseMoved(gcn::MouseEvent &event);
/**
+ * Moves the highlight in the direction specified.
+ *
+ * @param direction The move direction of the highlighter.
+ */
+ void moveHighlight(int direction);
- * Sets the currently selected item. Invalid (e.g., negative) indices set `no item'.
+ /**
+ * Sets the currently selected item.
*/
- void setSelectedItemIndex(int index);
+ void setSelectedItem(Item *item);
/**
* Find the current item index by the most recently used item ID
@@ -140,19 +173,21 @@ class ItemContainer : public gcn::Widget,
int getSlotIndex(int posX, int posY) const;
Inventory *mInventory;
- Image *mSelImg;
-
- int mSelectedItemIndex;
- int mLastSelectedItemId; // last selected item ID. If we lose the item, find again by ID.
- int mMaxItems;
+ int mGridColumns, mGridRows;
int mOffset;
+ Image *mSelImg;
+ Item *mSelectedItem, *mHighlightedItem;
+ int mSelectionStatus;
+ bool mSwapItems;
+ bool mDescItems;
+ int mDragPosX, mDragPosY;
ItemPopup *mItemPopup;
- std::list<gcn::SelectionListener*> mListeners;
+ typedef std::list<gcn::SelectionListener*> SelectionListenerList;
+ typedef SelectionListenerList::iterator SelectionListenerIterator;
- static const int gridWidth;
- static const int gridHeight;
+ SelectionListenerList mSelectionListeners;
};
#endif
diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp
index 61cb18fb..1b0a2bb2 100644
--- a/src/gui/itempopup.cpp
+++ b/src/gui/itempopup.cpp
@@ -110,7 +110,9 @@ void ItemPopup::setItem(const ItemInfo &item)
mItemEffect->setTextWrapped(item.getEffect(), 196);
mItemWeight->setTextWrapped(_("Weight: ") +
Units::formatWeight(item.getWeight()), 196);
+#ifdef EATHENA_SUPPORT
mItemType = item.getType();
+#endif
int minWidth = mItemName->getWidth();
@@ -165,7 +167,9 @@ void ItemPopup::setItem(const ItemInfo &item)
void ItemPopup::updateColors()
{
+#ifdef EATHENA_SUPPORT
mItemName->setForegroundColor(getColor(mItemType));
+#endif
graphics->setColor(guiPalette->getColor(Palette::TEXT));
}
diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp
index 9f77fd65..45a5ffa0 100644
--- a/src/gui/itemshortcutcontainer.cpp
+++ b/src/gui/itemshortcutcontainer.cpp
@@ -108,7 +108,10 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics)
if (image)
{
const std::string label =
- item->isEquipped() ? "Eq." : toString(item->getQuantity());
+#ifdef EATHENA_SUPPORT
+ item->isEquipped() ? "Eq." :
+#endif
+ toString(item->getQuantity());
g->drawImage(image, itemX, itemY);
g->drawText(label, itemX + mBoxWidth / 2,
itemY + mBoxHeight - 14, gcn::Graphics::CENTER);
diff --git a/src/gui/itemshortcutwindow.cpp b/src/gui/itemshortcutwindow.cpp
new file mode 100644
index 00000000..e21f421b
--- /dev/null
+++ b/src/gui/itemshortcutwindow.cpp
@@ -0,0 +1,71 @@
+/*
+ * The Mana World
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "itemshortcutwindow.h"
+
+#include "itemshortcutcontainer.h"
+#include "scrollarea.h"
+
+static const int SCROLL_PADDING = 0;
+
+ItemShortcutWindow::ItemShortcutWindow()
+{
+ setWindowName("ItemShortcut");
+ // no title presented, title bar is padding so window can be moved.
+ gcn::Window::setTitleBarHeight(gcn::Window::getPadding());
+ setShowTitle(false);
+ setResizable(true);
+ setDefaultSize(758, 174, 42, 426);
+
+ mItems = new ItemShortcutContainer;
+
+ const int border = SCROLL_PADDING * 2 + getPadding() * 2;
+ setMinWidth(mItems->getBoxWidth() + border);
+ setMinHeight(mItems->getBoxHeight() + border);
+ setMaxWidth(mItems->getBoxWidth() * mItems->getMaxItems() + border);
+ setMaxHeight(mItems->getBoxHeight() * mItems->getMaxItems() + border);
+
+ mScrollArea = new ScrollArea(mItems);
+ mScrollArea->setPosition(SCROLL_PADDING, SCROLL_PADDING);
+ mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mScrollArea->setOpaque(false);
+
+ add(mScrollArea);
+
+ loadWindowState();
+}
+
+ItemShortcutWindow::~ItemShortcutWindow()
+{
+ delete mItems;
+ delete mScrollArea;
+}
+
+void ItemShortcutWindow::widgetResized(const gcn::Event &event)
+{
+ Window::widgetResized(event);
+
+ const gcn::Rectangle &area = getChildrenArea();
+
+ mScrollArea->setSize(
+ area.width - SCROLL_PADDING,
+ area.height - SCROLL_PADDING);
+}
diff --git a/src/gui/itemshortcutwindow.h b/src/gui/itemshortcutwindow.h
new file mode 100644
index 00000000..017df5ec
--- /dev/null
+++ b/src/gui/itemshortcutwindow.h
@@ -0,0 +1,61 @@
+/*
+ * The Mana World
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_ITEMSHORTCUTWINDOW_H
+#define _TMW_ITEMSHORTCUTWINDOW_H
+
+#include "window.h"
+
+class ItemShortcutContainer;
+class ScrollArea;
+
+/**
+ * A window around the ItemShortcutContainer.
+ *
+ * \ingroup Interface
+ */
+class ItemShortcutWindow : public Window
+{
+ public:
+ /**
+ * Constructor.
+ */
+ ItemShortcutWindow();
+
+ /**
+ * Destructor.
+ */
+ ~ItemShortcutWindow();
+
+ /**
+ * Called whenever the widget changes size.
+ */
+ void widgetResized(const gcn::Event &event);
+
+ private:
+ ItemShortcutContainer *mItems;
+
+ ScrollArea *mScrollArea;
+};
+
+extern ItemShortcutWindow *itemShortcutWindow;
+
+#endif
diff --git a/src/gui/linkhandler.h b/src/gui/linkhandler.h
index ecc05b13..fc9da6da 100644
--- a/src/gui/linkhandler.h
+++ b/src/gui/linkhandler.h
@@ -24,6 +24,8 @@
#include <string>
+#include <string>
+
/**
* A simple interface to windows that need to handle links from BrowserBox
* widget.
diff --git a/src/gui/login.cpp b/src/gui/login.cpp
index 5eaf6626..281a25a2 100644
--- a/src/gui/login.cpp
+++ b/src/gui/login.cpp
@@ -49,6 +49,7 @@ LoginDialog::LoginDialog(LoginData *loginData):
{
gcn::Label *userLabel = new Label(_("Name:"));
gcn::Label *passLabel = new Label(_("Password:"));
+#ifdef EATHENA_SUPPORT
gcn::Label *serverLabel = new Label(_("Server:"));
gcn::Label *portLabel = new Label(_("Port:"));
gcn::Label *dropdownLabel = new Label(_("Recent:"));
@@ -60,15 +61,18 @@ LoginDialog::LoginDialog(LoginData *loginData):
MAX_SERVER_LIST_SIZE);
mServerListBox = new ListBox(mServerList);
mServerScrollArea = new ScrollArea;
+#endif
mUserField = new TextField(mLoginData->username);
mPassField = new PasswordField(mLoginData->password);
+#ifdef EATHENA_SUPPORT
mServerField = new TextField(mServerList->getServerAt(0));
mPortField = new TextField(mServerList->getPortAt(0));
mServerDropDown = new DropDown(mServerList,
mServerScrollArea,
mServerListBox);
mServerDropDown->setOpaque(false);
+#endif
mKeepCheck = new CheckBox(_("Remember Username"), mLoginData->remember);
mOkButton = new Button(_("OK"), "ok", this);
@@ -77,32 +81,42 @@ LoginDialog::LoginDialog(LoginData *loginData):
mUserField->setActionEventId("ok");
mPassField->setActionEventId("ok");
+#ifdef EATHENA_SUPPORT
mServerField->setActionEventId("ok");
mPortField->setActionEventId("ok");
mServerDropDown->setActionEventId("changeSelection");
+#endif
mUserField->addKeyListener(this);
mPassField->addKeyListener(this);
+#ifdef EATHENA_SUPPORT
mServerField->addKeyListener(this);
mPortField->addKeyListener(this);
mServerDropDown->addKeyListener(this);
+#endif
mUserField->addActionListener(this);
mPassField->addActionListener(this);
+#ifdef EATHENA_SUPPORT
mServerField->addActionListener(this);
mPortField->addActionListener(this);
mServerDropDown->addActionListener(this);
mKeepCheck->addActionListener(this);
+#endif
place(0, 0, userLabel);
place(0, 1, passLabel);
+#ifdef EATHENA_SUPPORT
place(0, 2, serverLabel);
place(0, 3, portLabel);
place(0, 4, dropdownLabel);
+#endif
place(1, 0, mUserField, 3).setPadding(1);
place(1, 1, mPassField, 3).setPadding(1);
+#ifdef EATHENA_SUPPORT
place(1, 2, mServerField, 3).setPadding(1);
place(1, 3, mPortField, 3).setPadding(1);
place(1, 4, mServerDropDown, 3).setPadding(1);
+#endif
place(0, 5, mKeepCheck, 4);
place(0, 6, mRegisterButton).setHAlign(LayoutCell::LEFT);
place(2, 6, mCancelButton);
@@ -124,8 +138,10 @@ void LoginDialog::action(const gcn::ActionEvent &event)
{
if (event.getId() == "ok" && canSubmit())
{
+#ifdef EATHENA_SUPPORT
mLoginData->hostname = mServerField->getText();
mLoginData->port = getUShort(mPortField->getText());
+#endif
mLoginData->username = mUserField->getText();
mLoginData->password = mPassField->getText();
mLoginData->remember = mKeepCheck->isSelected();
@@ -133,21 +149,32 @@ void LoginDialog::action(const gcn::ActionEvent &event)
mOkButton->setEnabled(false);
mRegisterButton->setEnabled(false);
+#ifdef EATHENA_SUPPORT
mServerList->save(mServerField->getText(), mPortField->getText());
- state = ACCOUNT_STATE;
+ state = STATE_ACCOUNT;
+#else
+ state = STATE_LOGIN_ATTEMPT;
+#endif
}
+#ifdef EATHENA_SUPPORT
else if (event.getId() == "changeSelection")
{
int selected = mServerListBox->getSelected();
mServerField->setText(mServerList->getServerAt(selected));
mPortField->setText(mServerList->getPortAt(selected));
}
+#endif
else if (event.getId() == "cancel")
{
- state = EXIT_STATE;
+#ifdef TMWSERV_SUPPORT
+ state = STATE_SWITCH_ACCOUNTSERVER;
+#else
+ state = STATE_EXIT;
+#endif
}
else if (event.getId() == "register")
{
+#ifdef EATHENA_SUPPORT
// Transfer these fields on to the register dialog
mLoginData->hostname = mServerField->getText();
@@ -155,11 +182,12 @@ void LoginDialog::action(const gcn::ActionEvent &event)
mLoginData->port = getUShort(mPortField->getText());
else
mLoginData->port = 6901;
+#endif
mLoginData->username = mUserField->getText();
mLoginData->password = mPassField->getText();
- state = REGISTER_STATE;
+ state = STATE_REGISTER;
}
}
@@ -172,11 +200,14 @@ bool LoginDialog::canSubmit()
{
return !mUserField->getText().empty() &&
!mPassField->getText().empty() &&
+#ifdef EATHENA_SUPPORT
!mServerField->getText().empty() &&
isUShort(mPortField->getText()) &&
- state == LOGIN_STATE;
+#endif
+ state == STATE_LOGIN;
}
+#ifdef EATHENA_SUPPORT
bool LoginDialog::isUShort(const std::string &str)
{
if (str.empty())
@@ -301,3 +332,4 @@ std::string LoginDialog::DropDownList::getPortAt(int i)
return mPorts.at(i);
}
+#endif
diff --git a/src/gui/login.h b/src/gui/login.h
index 1f0f2ddb..9a97cd4d 100644
--- a/src/gui/login.h
+++ b/src/gui/login.h
@@ -27,13 +27,17 @@
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
+#ifdef EATHENA_SUPPORT
#include <guichan/listmodel.hpp>
+#endif
#include "window.h"
-class DropDown;
class LoginData;
+#ifdef EATHENA_SUPPORT
+class DropDown;
class ScrollArea;
+#endif
/**
* The login dialog.
@@ -68,6 +72,7 @@ class LoginDialog : public Window, public gcn::ActionListener,
*/
bool canSubmit();
+#ifdef EATHENA_SUPPORT
/**
* Function to decide whether string is an unsigned short or not
*
@@ -86,11 +91,14 @@ class LoginDialog : public Window, public gcn::ActionListener,
*/
static unsigned short getUShort(const std::string &str);
- DropDown *mServerDropDown;
+#endif
gcn::TextField *mUserField;
gcn::TextField *mPassField;
+#ifdef EATHENA_SUPPORT
gcn::TextField *mServerField;
gcn::TextField *mPortField;
+ DropDown *mServerDropDown;
+#endif
gcn::CheckBox *mKeepCheck;
gcn::Button *mOkButton;
gcn::Button *mCancelButton;
@@ -98,6 +106,7 @@ class LoginDialog : public Window, public gcn::ActionListener,
LoginData *mLoginData;
+#ifdef EATHENA_SUPPORT
/**
* Helper class to keep a list of all the recent entries for the
* dropdown
@@ -125,6 +134,7 @@ class LoginDialog : public Window, public gcn::ActionListener,
DropDownList *mServerList;
gcn::ListBox *mServerListBox;
gcn::ScrollArea *mServerScrollArea;
+#endif
};
#endif
diff --git a/src/gui/magic.cpp b/src/gui/magic.cpp
new file mode 100644
index 00000000..0e56e853
--- /dev/null
+++ b/src/gui/magic.cpp
@@ -0,0 +1,92 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <guichan/widgets/label.hpp>
+#include <guichan/widgets/container.hpp>
+
+#include "magic.h"
+
+#include "button.h"
+
+#include "../localplayer.h"
+
+#include "../utils/dtor.h"
+#include "../utils/gettext.h"
+
+MagicDialog::MagicDialog():
+ Window(_("Magic"))
+{
+ setWindowName("Magic");
+ setCloseButton(true);
+ setDefaultSize(255, 30, 175, 225);
+
+ gcn::Button *spellButton1 = new Button(_("Cast Test Spell 1"), "spell_1", this);
+ gcn::Button *spellButton2 = new Button(_("Cast Test Spell 2"), "spell_2", this);
+ gcn::Button *spellButton3 = new Button(_("Cast Test Spell 3"), "spell_3", this);
+
+ spellButton1->setPosition(10, 30);
+ spellButton2->setPosition(10, 60);
+ spellButton3->setPosition(10, 90);
+
+ add(spellButton1);
+ add(spellButton2);
+ add(spellButton3);
+
+ update();
+
+ setLocationRelativeTo(getParent());
+ loadWindowState();
+}
+
+MagicDialog::~MagicDialog()
+{
+}
+
+void MagicDialog::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "spell_1")
+ {
+ player_node->useSpecial(1);
+ }
+ if (event.getId() == "spell_2")
+ {
+ player_node->useSpecial(2);
+ }
+ if (event.getId() == "spell_3")
+ {
+ player_node->useSpecial(3);
+ }
+ else if (event.getId() == "close")
+ {
+ setVisible(false);
+ }
+}
+
+void MagicDialog::draw(gcn::Graphics *g)
+{
+ update();
+
+ Window::draw(g);
+}
+
+void MagicDialog::update()
+{
+}
diff --git a/src/gui/magic.h b/src/gui/magic.h
new file mode 100644
index 00000000..48146b9c
--- /dev/null
+++ b/src/gui/magic.h
@@ -0,0 +1,75 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_MAGIC_H
+#define _TMW_MAGIC_H
+
+#include <guichan/actionlistener.hpp>
+
+#include "window.h"
+#include "gccontainer.h"
+
+#include "../guichanfwd.h"
+
+
+/**
+ * The skill dialog.
+ *
+ * \ingroup Interface
+ */
+class MagicDialog : public Window, public gcn::ActionListener
+{
+ public:
+ /**
+ * Constructor.
+ */
+ MagicDialog();
+
+ /**
+ * Destructor.
+ */
+ ~MagicDialog();
+
+ /**
+ * Called when receiving actions from widget.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ /**
+ * Update the tabs in this dialog
+ */
+ void update();
+
+ /**
+ * Draw this window.
+ */
+ void draw(gcn::Graphics *g);
+
+ private:
+
+};
+
+
+
+
+extern MagicDialog *magicDialog;
+
+#endif
diff --git a/src/gui/menuwindow.cpp b/src/gui/menuwindow.cpp
index 62f3766f..e6ae2d3b 100644
--- a/src/gui/menuwindow.cpp
+++ b/src/gui/menuwindow.cpp
@@ -39,6 +39,11 @@ extern Window *emoteWindow;
extern Window *setupWindow;
extern Window *skillDialog;
extern Window *statusWindow;
+#ifdef TMWSERV_SUPPORT
+extern Window *buddyWindow;
+extern Window *guildWindow;
+extern Window *magicDialog;
+#endif
namespace {
struct MenuWindowListener : public gcn::ActionListener
@@ -56,14 +61,19 @@ MenuWindow::MenuWindow():
// Buttons
static const char *buttonNames[] =
{
- _("Chat"),
- _("Status"),
- _("Equipment"),
- _("Inventory"),
- _("Skills"),
- _("Shortcut"),
- _("Emote"),
- _("Setup"),
+ N_("Chat"),
+ N_("Status"),
+ N_("Equipment"),
+ N_("Inventory"),
+ N_("Skills"),
+#ifdef TMWSERV_SUPPORT
+ N_("Magic"),
+ N_("Guilds"),
+ N_("Buddys"),
+#endif
+ N_("Shortcut"),
+ N_("Emote"),
+ N_("Setup"),
0
};
int x = 0, h = 0;
@@ -90,35 +100,49 @@ void MenuWindowListener::action(const gcn::ActionEvent &event)
{
Window *window = NULL;
- if (event.getId() == _("Chat"))
+ if (event.getId() == "Chat")
{
window = chatWindow;
}
- else if (event.getId() == _("Status"))
+ else if (event.getId() == "Status")
{
window = statusWindow;
}
- else if (event.getId() == _("Equipment"))
+ else if (event.getId() == "Equipment")
{
window = equipmentWindow;
}
- else if (event.getId() == _("Inventory"))
+ else if (event.getId() == "Inventory")
{
window = inventoryWindow;
}
- else if (event.getId() == _("Skills"))
+ else if (event.getId() == "Skills")
{
window = skillDialog;
}
- else if (event.getId() == _("Shortcut"))
+#ifdef TMWSERV_SUPPORT
+ else if (event.getId() == "Magic")
+ {
+ window = magicDialog;
+ }
+ else if (event.getId() == "Guilds")
+ {
+ window = guildWindow;
+ }
+ else if (event.getId() == "Buddys")
+ {
+ window = buddyWindow;
+ }
+#endif
+ else if (event.getId() == "Shortcut")
{
window = itemShortcutWindow;
}
- else if (event.getId() == _("Emote"))
+ else if (event.getId() == "Emote")
{
window = emoteWindow;
}
- else if (event.getId() == _("Setup"))
+ else if (event.getId() == "Setup")
{
window = setupWindow;
}
diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp
index d8c5d742..93a55688 100644
--- a/src/gui/minimap.cpp
+++ b/src/gui/minimap.cpp
@@ -119,8 +119,14 @@ void Minimap::draw(gcn::Graphics *graphics)
if (mMapImage->getWidth() > a.width ||
mMapImage->getHeight() > a.height)
{
+#ifdef TMWSERV_SUPPORT
+ const Vector &p = player_node->getPosition();
+ mapOriginX = (int) (((a.width) / 2) - (int) (p.x * mProportion) / 32);
+ mapOriginY = (int) (((a.height) / 2) - (int) (p.y * mProportion) / 32);
+#else
mapOriginX = (int) (((a.width) / 2) - (player_node->mX * mProportion));
mapOriginY = (int) (((a.height) / 2) - (player_node->mY * mProportion));
+#endif
const int minOriginX = a.width - mMapImage->getWidth();
const int minOriginY = a.height - mMapImage->getHeight();
@@ -171,10 +177,11 @@ void Minimap::draw(gcn::Graphics *graphics)
}
const int offset = (int) ((dotSize - 1) * mProportion);
+ const Vector &pos = being->getPosition();
graphics->fillRectangle(gcn::Rectangle(
- (int) (being->mX * mProportion) + mapOriginX - offset,
- (int) (being->mY * mProportion) + mapOriginY - offset,
+ (int) (pos.x * mProportion) / 32 + mapOriginX - offset,
+ (int) (pos.x * mProportion) / 32 + mapOriginY - offset,
dotSize, dotSize));
}
diff --git a/src/gui/ministatus.cpp b/src/gui/ministatus.cpp
index 9f789a9d..95577e69 100644
--- a/src/gui/ministatus.cpp
+++ b/src/gui/ministatus.cpp
@@ -35,19 +35,30 @@ MiniStatusWindow::MiniStatusWindow():
Popup("MiniStatus")
{
mHpBar = new ProgressBar(1.0f, 100, 20, 0, 171, 34);
+#ifdef EATHENA_SUPPORT
mMpBar = new ProgressBar(1.0f, 100, 20, 26, 102, 230);
mXpBar = new ProgressBar(1.0f, 100, 20, 143, 192, 211);
+#endif
mHpBar->setPosition(0, 3);
+#ifdef EATHENA_SUPPORT
mMpBar->setPosition(mHpBar->getWidth() + 3, 3);
mXpBar->setPosition(mMpBar->getX() + mMpBar->getWidth() + 3, 3);
+#endif
add(mHpBar);
+#ifdef EATHENA_SUPPORT
add(mMpBar);
add(mXpBar);
+#endif
+#ifdef EATHENA_SUPPORT
setContentSize(mXpBar->getX() + mXpBar->getWidth(),
mXpBar->getY() + mXpBar->getHeight());
+#else
+ setContentSize(mHpBar->getX() + mHpBar->getWidth(),
+ mHpBar->getY() + mHpBar->getHeight());
+#endif
}
void MiniStatusWindow::setIcon(int index, AnimatedSprite *sprite)
@@ -71,6 +82,7 @@ extern volatile int tick_time;
void MiniStatusWindow::update()
{
StatusWindow::updateHPBar(mHpBar);
+#ifdef EATHENA_SUPPORT
StatusWindow::updateMPBar(mMpBar);
StatusWindow::updateXPBar(mXpBar);
@@ -86,11 +98,11 @@ void MiniStatusWindow::update()
<< config.getValue("xpBarMonsterCounterName", "Monsters") <<" left...";
}
*/
+#endif
for (unsigned int i = 0; i < mIcons.size(); i++)
if (mIcons[i])
mIcons[i]->update(tick_time * 10);
-
}
void MiniStatusWindow::draw(gcn::Graphics *graphics)
@@ -102,7 +114,11 @@ void MiniStatusWindow::draw(gcn::Graphics *graphics)
void MiniStatusWindow::drawIcons(Graphics *graphics)
{
// Draw icons
+#ifdef TMWSERV_SUPPORT
+ int icon_x = mHpBar->getX() + mHpBar->getWidth() + 4;
+#else
int icon_x = mXpBar->getX() + mXpBar->getWidth() + 4;
+#endif
for (unsigned int i = 0; i < mIcons.size(); i++) {
if (mIcons[i]) {
mIcons[i]->draw(graphics, icon_x, 3);
diff --git a/src/gui/ministatus.h b/src/gui/ministatus.h
index 6e47f490..f6d80ca7 100644
--- a/src/gui/ministatus.h
+++ b/src/gui/ministatus.h
@@ -66,8 +66,10 @@ class MiniStatusWindow : public Popup
* Mini Status Bars
*/
ProgressBar *mHpBar;
+#ifdef EATHENA_SUPPORT
ProgressBar *mMpBar;
ProgressBar *mXpBar;
+#endif
std::vector<AnimatedSprite *> mIcons;
};
diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp
index 5bde7f36..5158e966 100644
--- a/src/gui/npc_text.cpp
+++ b/src/gui/npc_text.cpp
@@ -29,13 +29,24 @@
#include "../npc.h"
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#ifdef TMWSERV_SUPPORT
+#include "../net/tmwserv/gameserver/player.h"
+#else
+#include "../net/ea/protocol.h"
+#endif
#include "../utils/gettext.h"
-NpcTextDialog::NpcTextDialog(Network *network):
- Window(_("NPC")), mNetwork(network),
- mState(NPC_TEXT_STATE_WAITING)
+#ifdef TMWSERV_SUPPORT
+NpcTextDialog::NpcTextDialog()
+#else
+NpcTextDialog::NpcTextDialog(Network *network)
+#endif
+ : Window(_("NPC"))
+#ifdef EATHENA_SUPPORT
+ , mNetwork(network)
+#endif
+ , mState(NPC_TEXT_STATE_WAITING)
{
setWindowName("NPCText");
setResizable(true);
@@ -122,16 +133,22 @@ void NpcTextDialog::action(const gcn::ActionEvent &event)
void NpcTextDialog::nextDialog(int npcID)
{
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::talkToNPC(npcID, false);
+#else
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_NPC_NEXT_REQUEST);
outMsg.writeInt32(npcID);
+#endif
}
void NpcTextDialog::closeDialog(int npcID)
{
+#ifdef EATHENA_SUPPORT
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_NPC_CLOSE);
outMsg.writeInt32(npcID);
+#endif
}
void NpcTextDialog::widgetResized(const gcn::Event &event)
diff --git a/src/gui/npc_text.h b/src/gui/npc_text.h
index 011c7bcf..4c0c31e3 100644
--- a/src/gui/npc_text.h
+++ b/src/gui/npc_text.h
@@ -30,7 +30,9 @@
#include "../npc.h"
+#ifdef EATHENA_SUPPORT
class Network;
+#endif
class TextBox;
/**
@@ -46,7 +48,11 @@ class NpcTextDialog : public Window, public gcn::ActionListener
*
* @see Window::Window
*/
+#ifdef TMWSERV_SUPPORT
+ NpcTextDialog();
+#else
NpcTextDialog(Network *network);
+#endif
/**
* Called when receiving actions from the widgets.
@@ -102,7 +108,9 @@ class NpcTextDialog : public Window, public gcn::ActionListener
void widgetResized(const gcn::Event &event);
private:
+#ifdef EATHENA_SUPPORT
Network *mNetwork;
+#endif
gcn::ScrollArea *mScrollArea;
TextBox *mTextBox;
gcn::Button *mButton;
diff --git a/src/gui/npcintegerdialog.cpp b/src/gui/npcintegerdialog.cpp
index 896f3380..a7ae2748 100644
--- a/src/gui/npcintegerdialog.cpp
+++ b/src/gui/npcintegerdialog.cpp
@@ -29,13 +29,22 @@
#include "../npc.h"
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#ifdef EATHENA_SUPPORT
+#include "../net/ea/protocol.h"
+#endif
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
-NpcIntegerDialog::NpcIntegerDialog(Network *network):
- Window(_("NPC Number Request")), mNetwork(network)
+#ifdef TMWSERV_SUPPORT
+NpcIntegerDialog::NpcIntegerDialog()
+#else
+NpcIntegerDialog::NpcIntegerDialog(Network *network)
+#endif
+ : Window(_("NPC Number Request"))
+#ifdef EATHENA_SUPPORT
+ , mNetwork(network)
+#endif
{
setWindowName("NPCInteger");
mValueField = new IntTextField;
@@ -117,10 +126,12 @@ void NpcIntegerDialog::action(const gcn::ActionEvent &event)
setVisible(false);
NPC::isTalking = false;
+#ifdef EATHENA_SUPPORT
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_NPC_INT_RESPONSE);
outMsg.writeInt32(current_npc);
outMsg.writeInt32(mValueField->getValue());
+#endif
mValueField->reset();
}
diff --git a/src/gui/npcintegerdialog.h b/src/gui/npcintegerdialog.h
index 58f6970b..df74c904 100644
--- a/src/gui/npcintegerdialog.h
+++ b/src/gui/npcintegerdialog.h
@@ -26,7 +26,9 @@
#include "window.h"
+#ifdef EATHENA_SUPPORT
class Network;
+#endif
class IntTextField;
/**
@@ -42,7 +44,11 @@ class NpcIntegerDialog : public Window, public gcn::ActionListener
*
* @see Window::Window
*/
+#ifdef TMWSERV_SUPPORT
+ NpcIntegerDialog();
+#else
NpcIntegerDialog(Network *network);
+#endif
/**
* Called when receiving actions from the widgets.
@@ -87,7 +93,9 @@ class NpcIntegerDialog : public Window, public gcn::ActionListener
void setVisible(bool visible);
private:
+#ifdef EATHENA_SUPPORT
Network *mNetwork;
+#endif
gcn::Button *mDecButton;
gcn::Button *mIncButton;
IntTextField *mValueField;
diff --git a/src/gui/npclistdialog.cpp b/src/gui/npclistdialog.cpp
index ef8b0627..968e2514 100644
--- a/src/gui/npclistdialog.cpp
+++ b/src/gui/npclistdialog.cpp
@@ -32,13 +32,24 @@
#include "../npc.h"
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#ifdef TMWSERV_SUPPORT
+#include "../net/tmwserv/gameserver/player.h"
+#else
+#include "../net/ea/protocol.h"
+#endif
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
-NpcListDialog::NpcListDialog(Network *network):
- Window("NPC"), mNetwork(network)
+#ifdef TMWSERV_SUPPORT
+NpcListDialog::NpcListDialog()
+#else
+NpcListDialog::NpcListDialog(Network *network)
+#endif
+ : Window("NPC")
+#ifdef EATHENA_SUPPORT
+ , mNetwork(network)
+#endif
{
setWindowName("NPCList");
setResizable(true);
@@ -80,6 +91,11 @@ std::string NpcListDialog::getElementAt(int i)
return mItems[i];
}
+void NpcListDialog::addItem(const std::string &item)
+{
+ mItems.push_back(item);
+}
+
void NpcListDialog::parseItems(const std::string &itemString)
{
std::istringstream iss(itemString);
@@ -124,10 +140,14 @@ void NpcListDialog::action(const gcn::ActionEvent &event)
saveWindowState();
reset();
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::selectFromNPC(current_npc, choice);
+#else
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_NPC_LIST_CHOICE);
outMsg.writeInt32(current_npc);
outMsg.writeInt8(choice);
+#endif
}
}
diff --git a/src/gui/npclistdialog.h b/src/gui/npclistdialog.h
index f5f2147b..6c1e02e3 100644
--- a/src/gui/npclistdialog.h
+++ b/src/gui/npclistdialog.h
@@ -29,7 +29,9 @@
#include <vector>
+#ifdef EATHENA_SUPPORT
class Network;
+#endif
/**
* The npc list dialog.
@@ -45,7 +47,11 @@ class NpcListDialog : public Window, public gcn::ActionListener,
*
* @see Window::Window
*/
+#ifdef TMWSERV_SUPPORT
+ NpcListDialog();
+#else
NpcListDialog(Network *network);
+#endif
/**
* Called when receiving actions from the widgets.
@@ -63,6 +69,11 @@ class NpcListDialog : public Window, public gcn::ActionListener,
std::string getElementAt(int i);
/**
+ * Adds an item to the option list.
+ */
+ void addItem(const std::string &);
+
+ /**
* Fills the options list for an NPC dialog.
*
* @param itemString A string with the options separated with colons.
@@ -83,7 +94,9 @@ class NpcListDialog : public Window, public gcn::ActionListener,
void requestFocus();
private:
+#ifdef EATHENA_SUPPORT
Network *mNetwork;
+#endif
gcn::ListBox *mItemList;
std::vector<std::string> mItems;
diff --git a/src/gui/npcpostdialog.cpp b/src/gui/npcpostdialog.cpp
new file mode 100644
index 00000000..f8c0f4b2
--- /dev/null
+++ b/src/gui/npcpostdialog.cpp
@@ -0,0 +1,101 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "npcpostdialog.h"
+#include "textbox.h"
+#include "textfield.h"
+#include "button.h"
+#include "scrollarea.h"
+#include "chat.h"
+
+#include "../net/tmwserv/gameserver/player.h"
+#include "../utils/gettext.h"
+
+#include <guichan/widgets/label.hpp>
+
+NpcPostDialog::NpcPostDialog():
+ Window(_("NPC"))
+{
+ setContentSize(400, 180);
+
+ // create text field for receiver
+ gcn::Label *senderText = new gcn::Label("To:");
+ senderText->setPosition(5, 5);
+ mSender = new TextField();
+ mSender->setPosition(senderText->getWidth() + 5, 5);
+ mSender->setWidth(65);
+
+ // create button for sending
+ Button *sendButton = new Button(_("Send"), "send", this);
+ sendButton->setPosition(400-sendButton->getWidth(),
+ 170-sendButton->getHeight());
+ Button *cancelButton = new Button(_("Cancel"), "cancel", this);
+ cancelButton->setPosition(sendButton->getX() - (cancelButton->getWidth() + 2),
+ sendButton->getY());
+
+ // create textfield for letter
+ mText = new TextBox();
+ mText->setHeight(400 - (mSender->getHeight() + sendButton->getHeight()));
+ mText->setEditable(true);
+
+ // create scroll box for letter text
+ ScrollArea *scrollArea = new ScrollArea(mText);
+ scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ scrollArea->setDimension(gcn::Rectangle(
+ 5, mSender->getHeight() + 5,
+ 380, 140 - (mSender->getHeight() + sendButton->getHeight())));
+
+ add(senderText);
+ add(mSender);
+ add(scrollArea);
+ add(sendButton);
+ add(cancelButton);
+
+ setLocationRelativeTo(getParent());
+}
+
+void NpcPostDialog::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "send")
+ {
+ if (mSender->getText().empty() || mText->getText().empty())
+ {
+ chatWindow->chatLog("Failed to send as sender or letter invalid");
+ }
+ else
+ {
+ Net::GameServer::Player::sendLetter(mSender->getText(), mText->getText());
+ }
+ setVisible(false);
+ clear();
+ }
+ else if (event.getId() == "cancel")
+ {
+ setVisible(false);
+ clear();
+ }
+}
+
+void NpcPostDialog::clear()
+{
+ mSender->setText("");
+ mText->setText("");
+}
diff --git a/src/gui/npcpostdialog.h b/src/gui/npcpostdialog.h
new file mode 100644
index 00000000..1956c877
--- /dev/null
+++ b/src/gui/npcpostdialog.h
@@ -0,0 +1,55 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_GUI_NPCPOSTDIALOG_H
+#define _TMW_GUI_NPCPOSTDIALOG_H
+
+#include <guichan/actionlistener.hpp>
+
+#include "window.h"
+
+class TextBox;
+class TextField;
+
+class NpcPostDialog : public Window, public gcn::ActionListener
+{
+public:
+ /**
+ * Constructor
+ */
+ NpcPostDialog();
+
+ /**
+ * Called when receiving actions from the widgets.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ /**
+ * Clear the contents of the dialog
+ */
+ void clear();
+
+private:
+ TextBox *mText;
+ TextField *mSender;
+};
+
+#endif
diff --git a/src/gui/npcstringdialog.cpp b/src/gui/npcstringdialog.cpp
index c2379e7a..c84de015 100644
--- a/src/gui/npcstringdialog.cpp
+++ b/src/gui/npcstringdialog.cpp
@@ -29,13 +29,22 @@
#include "../npc.h"
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#ifdef EATHENA_SUPPORT
+#include "../net/ea/protocol.h"
+#endif
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
-NpcStringDialog::NpcStringDialog(Network *network):
- Window(_("NPC Text Request")), mNetwork(network)
+#ifdef TMWSERV_SUPPORT
+NpcStringDialog::NpcStringDialog()
+#else
+NpcStringDialog::NpcStringDialog(Network *network)
+#endif
+ : Window(_("NPC Text Request"))
+#ifdef EATHENA_SUPPORT
+ , mNetwork(network)
+#endif
{
setWindowName("NPCString");
mValueField = new TextField("");
@@ -85,12 +94,14 @@ void NpcStringDialog::action(const gcn::ActionEvent &event)
std::string text = mValueField->getText();
mValueField->setText("");
+#ifdef EATHENA_SUPPORT
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_NPC_STR_RESPONSE);
outMsg.writeInt16(text.length() + 9);
outMsg.writeInt32(current_npc);
outMsg.writeString(text, text.length());
outMsg.writeInt8(0);
+#endif
}
bool NpcStringDialog::isInputFocused()
diff --git a/src/gui/npcstringdialog.h b/src/gui/npcstringdialog.h
index 0c552baa..94cd59b2 100644
--- a/src/gui/npcstringdialog.h
+++ b/src/gui/npcstringdialog.h
@@ -26,9 +26,9 @@
#include <guichan/actionlistener.hpp>
+#ifdef EATHENA_SUPPORT
class Network;
-
-class Network;
+#endif
/**
* The npc integer input dialog.
@@ -43,7 +43,11 @@ class NpcStringDialog : public Window, public gcn::ActionListener
*
* @see Window::Window
*/
+#ifdef TMWSERV_SUPPORT
+ NpcStringDialog();
+#else
NpcStringDialog(Network *network);
+#endif
/**
* Called when receiving actions from the widgets.
@@ -75,7 +79,9 @@ class NpcStringDialog : public Window, public gcn::ActionListener
void setVisible(bool visible);
private:
+#ifdef EATHENA_SUPPORT
Network *mNetwork;
+#endif
gcn::TextField *mValueField;
std::string mDefault;
};
diff --git a/src/gui/partywindow.cpp b/src/gui/partywindow.cpp
new file mode 100644
index 00000000..d60974a8
--- /dev/null
+++ b/src/gui/partywindow.cpp
@@ -0,0 +1,145 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "partywindow.h"
+#include "chat.h"
+
+#include "widgets/avatar.h"
+
+#include "../utils/gettext.h"
+#include "../net/tmwserv/chatserver/party.h"
+
+PartyWindow::PartyWindow() : Window(_("Party"))
+{
+ setWindowName("Party");
+ setVisible(false);
+ setResizable(false);
+ setCaption(_("Party"));
+ setCloseButton(true);
+ setMinWidth(110);
+ setMinHeight(200);
+ setDefaultSize(620, 300, 110, 200);
+
+ loadWindowState();
+}
+
+PartyWindow::~PartyWindow()
+{
+ mPartyMembers.clear();
+}
+
+void PartyWindow::draw(gcn::Graphics *graphics)
+{
+ Window::draw(graphics);
+}
+
+void PartyWindow::addPartyMember(const std::string &memberName)
+{
+ // check to see if player is already in the party
+ PartyList::iterator itr = mPartyMembers.begin(),
+ itr_end = mPartyMembers.end();
+
+ while (itr != itr_end)
+ {
+ if ((*itr).name == memberName)
+ {
+ // already in the party, dont add
+ return;
+ }
+ ++itr;
+ }
+
+ // create new party member
+ PartyMember player;
+ player.name = memberName;
+ mPartyMembers.push_back(player);
+
+ // add avatar of the new member to window
+ Avatar *avatar = new Avatar(memberName);
+ add(avatar, 0, (mPartyMembers.size() - 1)*14);
+
+ // show the window
+ if (mPartyMembers.size() > 0)
+ {
+ setVisible(true);
+ }
+}
+
+void PartyWindow::removePartyMember(const std::string &memberName)
+{
+ // remove the party member
+ PartyList::iterator itr = mPartyMembers.begin(),
+ itr_end = mPartyMembers.end();
+
+ while (itr != itr_end)
+ {
+ if ((*itr).name == memberName)
+ {
+ mPartyMembers.erase(itr);
+ break;
+ }
+ ++itr;
+ }
+
+ // if no-one left, remove the party window
+ if (mPartyMembers.size() < 1)
+ {
+ setVisible(false);
+ }
+}
+
+void PartyWindow::showPartyInvite(const std::string &inviter)
+{
+ // check there isnt already an invite showing
+ if (mPartyInviter != "")
+ {
+ chatWindow->chatLog("Received party request, but one already exists",
+ BY_SERVER);
+ return;
+ }
+
+ // log invite
+ std::string msg = inviter + " has invited you to join their party";
+ chatWindow->chatLog(msg, BY_SERVER);
+
+ // show invite
+ acceptDialog = new ConfirmDialog("Accept Party Invite", msg, this);
+ acceptDialog->addActionListener(this);
+
+ mPartyInviter = inviter;
+}
+
+void PartyWindow::action(const gcn::ActionEvent &event)
+{
+ const std::string &eventId = event.getId();
+
+ // check if they accepted the invite
+ if (eventId == "yes")
+ {
+ chatWindow->chatLog("Accepted invite from " + mPartyInviter);
+ Net::ChatServer::Party::acceptInvite(mPartyInviter);
+ mPartyInviter = "";
+ }
+ else if (eventId == "no")
+ {
+ mPartyInviter = "";
+ }
+}
diff --git a/src/gui/partywindow.h b/src/gui/partywindow.h
new file mode 100644
index 00000000..e79bf392
--- /dev/null
+++ b/src/gui/partywindow.h
@@ -0,0 +1,96 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_PARTYWINDOW_H
+#define _TMW_PARTYWINDOW_H
+
+#include "window.h"
+#include "confirm_dialog.h"
+
+#include <string>
+#include <vector>
+
+#include <guichan/actionevent.hpp>
+#include <guichan/actionlistener.hpp>
+
+/**
+ * Party Member
+ * Used for storing players in the party
+ */
+struct PartyMember
+{
+ std::string name;
+ int vitality;
+};
+
+/**
+ * Party Window.
+ *
+ * \ingroup Interface
+ */
+class PartyWindow : public Window, gcn::ActionListener
+{
+ public:
+ /**
+ * Constructor.
+ */
+ PartyWindow();
+
+ /**
+ * Release all the players created
+ */
+ ~PartyWindow();
+
+ /**
+ * Draws the party window
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Add party member
+ */
+ void addPartyMember(const std::string &memberName);
+
+ /**
+ * Remove party member
+ */
+ void removePartyMember(const std::string &memberName);
+
+ /**
+ * Show party invite
+ */
+ void showPartyInvite(const std::string &inviter);
+
+ /**
+ * Handle events
+ */
+ void action(const gcn::ActionEvent &event);
+
+ private:
+ typedef std::vector<PartyMember> PartyList;
+ PartyList mPartyMembers;
+ std::string mPartyInviter;
+ ConfirmDialog *acceptDialog;
+};
+
+extern PartyWindow *partyWindow;
+
+#endif
diff --git a/src/gui/passwordfield.h b/src/gui/passwordfield.h
index 42f8d187..86195bd1 100644
--- a/src/gui/passwordfield.h
+++ b/src/gui/passwordfield.h
@@ -22,8 +22,6 @@
#ifndef PASSWORDFIELD_H
#define PASSWORDFIELD_H
-#include <string>
-
#include "textfield.h"
/**
diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp
index 7223c453..b7e553dc 100644
--- a/src/gui/playerbox.cpp
+++ b/src/gui/playerbox.cpp
@@ -84,10 +84,14 @@ void PlayerBox::draw(gcn::Graphics *graphics)
if (mPlayer)
{
// Draw character
- int x, y, bs;
- bs = getFrameSize();
- x = getWidth() / 2 - 16 + bs;
- y = getHeight() / 2 + bs;
+ const int bs = getFrameSize();
+#ifdef TMWSERV_SUPPORT
+ const int x = getWidth() / 2 + bs;
+ const int y = getHeight() - bs - 8;
+ mPlayer->draw(static_cast<Graphics*>(graphics), x, y);
+#else
+ const int x = getWidth() / 2 - 16 + bs;
+ const int y = getHeight() / 2 + bs;
for (int i = 0; i < Being::VECTOREND_SPRITE; i++)
{
if (mPlayer->getSprite(i))
@@ -95,6 +99,7 @@ void PlayerBox::draw(gcn::Graphics *graphics)
mPlayer->getSprite(i)->draw(static_cast<Graphics*>(graphics), x, y);
}
}
+#endif
}
if (config.getValue("guialpha", 0.8) != mAlpha)
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index 7627c1ad..9ff9b23f 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -36,8 +36,10 @@
#include "../npc.h"
#include "../player_relations.h"
+#ifdef EATHENA_SUPPORT
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#include "../net/ea/protocol.h"
+#endif
#include "../resources/itemdb.h"
@@ -102,6 +104,8 @@ void PopupMenu::showPopup(int x, int y, Being *being)
//mBrowserBox->addRow(_("@@follow|Follow ") + name + "@@");
//mBrowserBox->addRow(_("@@buddy|Add ") + name + " to Buddy List@@");
+ mBrowserBox->addRow(strprintf(_("@@guild|Invite %s@@"), name.c_str()));
+ mBrowserBox->addRow(strprintf(_("@@party|Invite %s to join your party@@"), name.c_str()));
mBrowserBox->addRow("##3---");
mBrowserBox->addRow(strprintf(_("@@party-invite|Invite %s to party@@"), name.c_str()));
@@ -163,7 +167,7 @@ void PopupMenu::handleLink(const std::string& link)
player_node->trade(being);
tradePartnerName = being->getName();
}
-
+#ifdef EATHENA_SUPPORT
// Attack action
else if (link == "attack" &&
being &&
@@ -171,7 +175,7 @@ void PopupMenu::handleLink(const std::string& link)
{
player_node->attack(being, true);
}
-
+#endif
else if (link == "unignore" &&
being &&
being->getType() == Being::PLAYER)
@@ -199,7 +203,21 @@ void PopupMenu::handleLink(const std::string& link)
{
player_relations.setRelation(being->getName(), PlayerRelation::FRIEND);
}
+#ifdef TMWSERV_SUPPORT
+ // Guild action
+ else if (link == "guild" &&
+ being != NULL &&
+ being->getType() == Being::PLAYER)
+ {
+ player_node->inviteToGuild(being);
+ }
+ // Add player to your party
+ else if (link == "party")
+ {
+ player_node->inviteToParty(being->getName());
+ }
+#endif
/*
// Follow Player action
else if (link == "follow")
@@ -232,6 +250,9 @@ void PopupMenu::handleLink(const std::string& link)
assert(mItem);
if (mItem->isEquipment())
{
+#ifdef TMWSERV_SUPPORT
+ player_node->equipItem(mItem);
+#else
if (mItem->isEquipped())
{
player_node->unequipItem(mItem);
@@ -240,10 +261,15 @@ void PopupMenu::handleLink(const std::string& link)
{
player_node->equipItem(mItem);
}
+#endif
}
else
{
+#ifdef TMWSERV_SUPPORT
+ player_node->useItem(mItem->getInvIndex());
+#else
player_node->useItem(mItem);
+#endif
}
}
@@ -252,10 +278,15 @@ void PopupMenu::handleLink(const std::string& link)
chatWindow->addItemText(mItem->getInfo().getName());
}
+ else if (link == "split")
+ {
+ new ItemAmountWindow(AMOUNT_ITEM_SPLIT, inventoryWindow, mItem);
+ }
else if (link == "drop")
{
new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem);
}
+#ifdef EATHENA_SUPPORT
else if (link == "party-invite" &&
being &&
being->getType() == Being::PLAYER)
@@ -264,6 +295,7 @@ void PopupMenu::handleLink(const std::string& link)
outMsg.writeInt16(CMSG_PARTY_INVITE);
outMsg.writeInt32(being->getId());
}
+#endif
// Unknown actions
else
@@ -286,15 +318,23 @@ void PopupMenu::showPopup(int x, int y, Item *item)
if (item->isEquipment())
{
+#ifdef TMWSERV_SUPPORT
+ mBrowserBox->addRow(_("@@use|Equip@@"));
+#else
if (item->isEquipped())
mBrowserBox->addRow(_("@@use|Unequip@@"));
else
mBrowserBox->addRow(_("@@use|Equip@@"));
+#endif
}
else
mBrowserBox->addRow(_("@@use|Use@@"));
mBrowserBox->addRow(_("@@drop|Drop@@"));
+#ifdef TMWSERV_SUPPORT
+ if (!item->isEquipment())
+ mBrowserBox->addRow(_("@@split|Split@@"));
+#endif
mBrowserBox->addRow(_("@@chat|Add to Chat@@"));
mBrowserBox->addRow("##3---");
mBrowserBox->addRow(_("@@cancel|Cancel@@"));
diff --git a/src/gui/progressbar.cpp b/src/gui/progressbar.cpp
index 58d7d815..02ddab16 100644
--- a/src/gui/progressbar.cpp
+++ b/src/gui/progressbar.cpp
@@ -43,6 +43,9 @@ ProgressBar::ProgressBar(float progress,
mRed(red), mGreen(green), mBlue(blue),
mRedToGo(red), mGreenToGo(green), mBlueToGo(blue)
{
+ mProgressToGo = mProgress = 0.0f;
+ mSmoothProgress = mSmoothColorChange = true;
+
setProgress(progress);
setWidth(width);
setHeight(height);
@@ -92,13 +95,31 @@ ProgressBar::~ProgressBar()
void ProgressBar::logic()
{
- // Smoothly changing the color for a nicer effect.
- if (mRedToGo > mRed) mRed++;
- if (mRedToGo < mRed) mRed--;
- if (mGreenToGo > mGreen) mGreen++;
- if (mGreenToGo < mGreen) mGreen--;
- if (mBlueToGo > mBlue) mBlue++;
- if (mBlueToGo < mBlue) mBlue--;
+ if (mSmoothColorChange)
+ {
+ // Smoothly changing the color for a nicer effect.
+ if (mRedToGo > mRed) mRed++;
+ if (mRedToGo < mRed) mRed--;
+ if (mGreenToGo > mGreen) mGreen++;
+ if (mGreenToGo < mGreen) mGreen--;
+ if (mBlueToGo > mBlue) mBlue++;
+ if (mBlueToGo < mBlue) mBlue--;
+ }
+ else
+ {
+ mRed = mRedToGo;
+ mGreen = mGreenToGo;
+ mBlue = mBlueToGo;
+ }
+
+ if (mSmoothProgress)
+ {
+ // Smoothly showing the progressbar changes.
+ if (mProgressToGo > mProgress) mProgress = mProgress + 0.005f;
+ if (mProgressToGo < mProgress) mProgress = mProgress - 0.005f;
+ }
+ else
+ mProgress = mProgressToGo;
}
void ProgressBar::draw(gcn::Graphics *graphics)
@@ -141,9 +162,9 @@ void ProgressBar::draw(gcn::Graphics *graphics)
void ProgressBar::setProgress(float progress)
{
- if (progress < 0.0f) mProgress = 0.0;
- else if (progress > 1.0f) mProgress = 1.0;
- else mProgress = progress;
+ if (progress < 0.0f) mProgressToGo = 0.0;
+ else if (progress > 1.0f) mProgressToGo = 1.0;
+ else mProgressToGo = progress;
}
void ProgressBar::setColor(Uint8 red, Uint8 green, Uint8 blue)
diff --git a/src/gui/progressbar.h b/src/gui/progressbar.h
index aa36e02b..e75b1d44 100644
--- a/src/gui/progressbar.h
+++ b/src/gui/progressbar.h
@@ -102,10 +102,27 @@ class ProgressBar : public gcn::Widget
const std::string &text() const
{ return mText; }
+ /**
+ * Set wether the progress is moved smoothly.
+ */
+ void setSmoothProgress(bool smoothProgress)
+ { mSmoothProgress = smoothProgress; }
+
+ /**
+ * Set wether the color changing is made smoothly.
+ */
+ void setSmoothColorChange(bool smoothColorChange)
+ { mSmoothColorChange = smoothColorChange; }
+
+
private:
- float mProgress;
+ float mProgress, mProgressToGo;
+ bool mSmoothProgress;
+
Uint8 mRed, mGreen, mBlue;
Uint8 mRedToGo, mGreenToGo, mBlueToGo;
+ bool mSmoothColorChange;
+
std::string mText;
bool mUpdated;
diff --git a/src/gui/quitdialog.cpp b/src/gui/quitdialog.cpp
new file mode 100644
index 00000000..563ed34a
--- /dev/null
+++ b/src/gui/quitdialog.cpp
@@ -0,0 +1,135 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "quitdialog.h"
+#include <iostream>
+#include <string>
+
+#include <guichan/widgets/label.hpp>
+
+#include "../main.h"
+
+#include "button.h"
+#include "radiobutton.h"
+
+#include "../utils/gettext.h"
+
+QuitDialog::QuitDialog(bool* quitGame, QuitDialog** pointerToMe):
+ Window(_("Quit"), true, NULL), mQuitGame(quitGame), mMyPointer(pointerToMe)
+{
+
+ mLogoutQuit = new RadioButton(_("Quit"), "quitdialog");
+ mForceQuit = new RadioButton(_("Quit"), "quitdialog");
+ mSwitchAccountServer = new RadioButton(_("Switch server"), "quitdialog");
+ mSwitchCharacter = new RadioButton(_("Switch character"), "quitdialog");
+ mOkButton = new Button(_("Ok"), "ok", this);
+ mCancelButton = new Button(_("Cancel"), "cancel", this);
+
+ setContentSize(200, 91);
+
+ mLogoutQuit->setPosition(5, 5);
+ mForceQuit->setPosition(5, 5);
+ mSwitchAccountServer->setPosition(5, 14 + mLogoutQuit->getHeight());
+ mSwitchCharacter->setPosition(5,
+ 23 + mLogoutQuit->getHeight() + mSwitchAccountServer->getHeight());
+ mCancelButton->setPosition(
+ 200 - mCancelButton->getWidth() - 5,
+ 91 - mCancelButton->getHeight() - 5);
+ mOkButton->setPosition(
+ mCancelButton->getX() - mOkButton->getWidth() - 5,
+ 91 - mOkButton->getHeight() - 5);
+
+ //All states, when we're not logged in to someone.
+ if (state == STATE_CHOOSE_SERVER ||
+ state == STATE_CONNECT_ACCOUNT ||
+ state == STATE_LOGIN ||
+ state == STATE_LOGIN_ATTEMPT ||
+ state == STATE_UPDATE)
+ {
+ mForceQuit->setSelected(true);
+ add(mForceQuit);
+ }
+ else
+ {
+ // Only added if we are connected to an accountserver or gameserver
+ mLogoutQuit->setSelected(true);
+ add(mLogoutQuit);
+ add(mSwitchAccountServer);
+
+ // Only added if we are connected to a gameserver
+ if (state == STATE_GAME) add(mSwitchCharacter);
+ }
+
+ add(mOkButton);
+ add(mCancelButton);
+
+ setLocationRelativeTo(getParent());
+ setVisible(true);
+
+ mOkButton->requestFocus();
+
+}
+
+QuitDialog::~QuitDialog()
+{
+ if (mMyPointer) *mMyPointer = NULL;
+ // Optional widgets, so delete them by hand.
+ delete mForceQuit;
+ delete mLogoutQuit;
+ delete mSwitchAccountServer;
+ delete mSwitchCharacter;
+}
+
+void
+QuitDialog::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "ok")
+ {
+ if (mForceQuit->isSelected())
+ {
+ state = STATE_FORCE_QUIT;
+ }
+ else if (mLogoutQuit->isSelected())
+ {
+ if ((state == STATE_GAME) && (mQuitGame))
+ {
+ *mQuitGame = true;
+ }
+ state = STATE_EXIT;
+ }
+ else if (mSwitchAccountServer->isSelected())
+ {
+ if ((state == STATE_GAME) && (mQuitGame))
+ {
+ *mQuitGame = true;
+ }
+ state = STATE_SWITCH_ACCOUNTSERVER_ATTEMPT;
+ }
+ else if (mSwitchCharacter->isSelected())
+ {
+ if (mQuitGame) *mQuitGame = true;
+
+ state = STATE_SWITCH_CHARACTER;
+ }
+
+ }
+ scheduleDelete();
+}
diff --git a/src/gui/quitdialog.h b/src/gui/quitdialog.h
new file mode 100644
index 00000000..018f1e52
--- /dev/null
+++ b/src/gui/quitdialog.h
@@ -0,0 +1,70 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_QUITDIALOG_H
+#define _TMW_QUITDIALOG_H
+
+#include <iosfwd>
+#include <guichan/actionlistener.hpp>
+
+#include "window.h"
+#include "../guichanfwd.h"
+#include "../main.h"
+
+/**
+ * The quit dialog.
+ *
+ * \ingroup Interface
+ */
+class QuitDialog : public Window, public gcn::ActionListener {
+ public:
+ /**
+ * Constructor
+ *
+ * @quitGame; to be used for getting out of the while loop in Game
+ * @pointerToMe; will be set to NULL when the QuitDialog is destroyed
+ */
+ QuitDialog(bool* quitGame, QuitDialog** pointerToMe);
+
+ /**
+ * Destructor
+ */
+ ~QuitDialog();
+
+ /**
+ * Called when receiving actions from the widgets.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ private:
+ gcn::RadioButton *mLogoutQuit;
+ gcn::RadioButton *mForceQuit;
+ gcn::RadioButton *mSwitchAccountServer;
+ gcn::RadioButton *mSwitchCharacter;
+ gcn::Button *mOkButton;
+ gcn::Button *mCancelButton;
+
+ bool* mQuitGame;
+ QuitDialog** mMyPointer;
+
+};
+
+#endif
diff --git a/src/gui/recorder.cpp b/src/gui/recorder.cpp
index 479ab76b..0536188c 100644
--- a/src/gui/recorder.cpp
+++ b/src/gui/recorder.cpp
@@ -66,7 +66,7 @@ void Recorder::record(const std::string &msg)
}
}
-void Recorder::changeRecordingStatus(const std::string &msg)
+void Recorder::setRecordingFile(const std::string &msg)
{
std::string msgCopy = msg;
trim(msgCopy);
@@ -114,5 +114,5 @@ void Recorder::changeRecordingStatus(const std::string &msg)
void Recorder::action(const gcn::ActionEvent &event)
{
- changeRecordingStatus("");
+ setRecordingFile("");
}
diff --git a/src/gui/recorder.h b/src/gui/recorder.h
index 0bbab012..39d00c2c 100644
--- a/src/gui/recorder.h
+++ b/src/gui/recorder.h
@@ -41,26 +41,26 @@ class Recorder : public Window, public gcn::ActionListener
virtual ~Recorder();
- /*
+ /**
* Outputs the message to the recorder file
*
* @param msg the line to write to the recorded file.
*/
void record(const std::string &msg);
- /*
- * Outputs the message to the recorder file
+ /**
+ * Sets the file being recorded to
*
* @param msg The file to write out to. If null, then stop recording.
*/
- void changeRecordingStatus(const std::string &msg);
+ void setRecordingFile(const std::string &msg);
- /*
+ /**
* Whether or not the recorder is in use.
*/
- bool isRecording() {return (bool) mStream.is_open();}
+ bool isRecording() { return (bool) mStream.is_open(); }
- /*
+ /**
* called when the button is pressed
*
* @param event is the event that is generated
diff --git a/src/gui/register.cpp b/src/gui/register.cpp
index 0e8a99ca..5fb8b579 100644
--- a/src/gui/register.cpp
+++ b/src/gui/register.cpp
@@ -40,20 +40,6 @@
#include "../utils/strprintf.h"
#include "../utils/stringutils.h"
-/**
- * Listener used while dealing with wrong data. It is used to direct the focus
- * to the field which contained wrong data when the Ok button was pressed on
- * the error notice.
- */
-class WrongDataNoticeListener : public gcn::ActionListener
-{
- public:
- void setTarget(gcn::TextField *textField);
- void action(const gcn::ActionEvent &event);
- private:
- gcn::TextField *mTarget;
-};
-
void WrongDataNoticeListener::setTarget(gcn::TextField *textField)
{
mTarget = textField;
@@ -73,15 +59,19 @@ RegisterDialog::RegisterDialog(LoginData *loginData):
gcn::Label *userLabel = new Label(_("Name:"));
gcn::Label *passwordLabel = new Label(_("Password:"));
gcn::Label *confirmLabel = new Label(_("Confirm:"));
+#ifdef EATHENA_SUPPORT
gcn::Label *serverLabel = new Label(_("Server:"));
gcn::Label *portLabel = new Label(_("Port:"));
+#endif
mUserField = new TextField(loginData->username);
mPasswordField = new PasswordField(loginData->password);
mConfirmField = new PasswordField;
+#ifdef EATHENA_SUPPORT
mServerField = new TextField(loginData->hostname);
mPortField = new TextField(toString(loginData->port));
mMaleButton = new RadioButton(_("Male"), "sex", true);
mFemaleButton = new RadioButton(_("Female"), "sex", false);
+#endif
mRegisterButton = new Button(_("Register"), "register", this);
mCancelButton = new Button(_("Cancel"), "cancel", this);
@@ -90,15 +80,19 @@ RegisterDialog::RegisterDialog(LoginData *loginData):
place(0, 0, userLabel);
place(0, 1, passwordLabel);
place(0, 2, confirmLabel);
+#ifdef EATHENA_SUPPORT
place(1, 3, mMaleButton);
place(2, 3, mFemaleButton);
place(0, 4, serverLabel);
place(0, 5, portLabel);
+#endif
place(1, 0, mUserField, 3).setPadding(2);
place(1, 1, mPasswordField, 3).setPadding(2);
place(1, 2, mConfirmField, 3).setPadding(2);
+#ifdef EATHENA_SUPPORT
place(1, 4, mServerField, 3).setPadding(2);
place(1, 5, mPortField, 3).setPadding(2);
+#endif
place = getPlacer(0, 2);
place(1, 0, mRegisterButton);
place(2, 0, mCancelButton);
@@ -107,8 +101,10 @@ RegisterDialog::RegisterDialog(LoginData *loginData):
mUserField->addKeyListener(this);
mPasswordField->addKeyListener(this);
mConfirmField->addKeyListener(this);
+#ifdef EATHENA_SUPPORT
mServerField->addKeyListener(this);
mPortField->addKeyListener(this);
+#endif
/* TODO:
* This is a quick and dirty way to respond to the ENTER key, regardless of
@@ -118,14 +114,18 @@ RegisterDialog::RegisterDialog(LoginData *loginData):
mUserField->setActionEventId("register");
mPasswordField->setActionEventId("register");
mConfirmField->setActionEventId("register");
- mServerField->setActionEventId("register");
- mPortField->setActionEventId("register");
mUserField->addActionListener(this);
mPasswordField->addActionListener(this);
mConfirmField->addActionListener(this);
+
+#ifdef EATHENA_SUPPORT
+ mServerField->setActionEventId("register");
+ mPortField->setActionEventId("register");
+
mServerField->addActionListener(this);
mPortField->addActionListener(this);
+#endif
center();
setVisible(true);
@@ -144,7 +144,7 @@ void RegisterDialog::action(const gcn::ActionEvent &event)
{
if (event.getId() == "cancel")
{
- state = LOGIN_STATE;
+ state = STATE_LOGIN;
}
else if (event.getId() == "register" && canSubmit())
{
@@ -193,6 +193,8 @@ void RegisterDialog::action(const gcn::ActionEvent &event)
error = 2;
}
+ // TODO: Check if a valid email address was given
+
if (error > 0)
{
if (error == 1)
@@ -208,23 +210,30 @@ void RegisterDialog::action(const gcn::ActionEvent &event)
mWrongDataNoticeListener->setTarget(this->mPasswordField);
}
- OkDialog *mWrongRegisterNotice =
- new OkDialog(_("Error"), errorMsg);
- mWrongRegisterNotice->addActionListener(mWrongDataNoticeListener);
+ OkDialog *dlg = new OkDialog(_("Error"), errorMsg);
+ dlg->addActionListener(mWrongDataNoticeListener);
}
else
{
// No errors detected, register the new user.
mRegisterButton->setEnabled(false);
- mLoginData->hostname = mServerField->getText();
- mLoginData->port = getUShort(mPortField->getText());
mLoginData->username = mUserField->getText();
mLoginData->password = mPasswordField->getText();
+#ifdef EATHENA_SUPPORT
+ mLoginData->hostname = mServerField->getText();
+ mLoginData->port = getUShort(mPortField->getText());
mLoginData->username += mFemaleButton->isSelected() ? "_F" : "_M";
+#else
+ mLoginData->email = mEmailField->getText();
+#endif
mLoginData->registerLogin = true;
- state = ACCOUNT_STATE;
+#ifdef TMWSERV_SUPPORT
+ state = STATE_REGISTER_ATTEMPT;
+#else
+ state = STATE_ACCOUNT;
+#endif
}
}
}
@@ -239,11 +248,14 @@ bool RegisterDialog::canSubmit() const
return !mUserField->getText().empty() &&
!mPasswordField->getText().empty() &&
!mConfirmField->getText().empty() &&
+#ifdef EATHENA_SUPPORT
!mServerField->getText().empty() &&
isUShort(mPortField->getText()) &&
- state == REGISTER_STATE;
+#endif
+ state == STATE_REGISTER;
}
+#ifdef EATHENA_SUPPORT
bool RegisterDialog::isUShort(const std::string &str)
{
if (str.empty())
@@ -277,3 +289,4 @@ unsigned short RegisterDialog::getUShort(const std::string &str)
}
return static_cast<unsigned short>(l);
}
+#endif
diff --git a/src/gui/register.h b/src/gui/register.h
index 9588e07e..c37305e4 100644
--- a/src/gui/register.h
+++ b/src/gui/register.h
@@ -31,7 +31,20 @@
class LoginData;
class OkDialog;
-class WrongDataNoticeListener;
+
+/**
+ * Listener used while dealing with wrong data. It is used to direct the focus
+ * to the field which contained wrong data when the Ok button was pressed on
+ * the error notice.
+ */
+class WrongDataNoticeListener : public gcn::ActionListener
+{
+ public:
+ void setTarget(gcn::TextField *textField);
+ void action(const gcn::ActionEvent &event);
+ private:
+ gcn::TextField *mTarget;
+};
/**
* The registration dialog.
@@ -72,6 +85,7 @@ class RegisterDialog : public Window, public gcn::ActionListener,
*/
bool canSubmit() const;
+#ifdef EATHENA_SUPPORT
/**
* Function to decide whether string is an unsigned short or not
*
@@ -89,17 +103,24 @@ class RegisterDialog : public Window, public gcn::ActionListener,
* @return the value str represents
*/
static unsigned short getUShort(const std::string &str);
+#endif
gcn::TextField *mUserField;
gcn::TextField *mPasswordField;
gcn::TextField *mConfirmField;
+#ifdef EATHENA_SUPPORT
gcn::TextField *mServerField;
gcn::TextField *mPortField;
+#else
+ gcn::TextField *mEmailField;
+#endif
gcn::Button *mRegisterButton;
gcn::Button *mCancelButton;
+#ifdef EATHENA_SUPPORT
gcn::RadioButton *mMaleButton;
gcn::RadioButton *mFemaleButton;
+#endif
WrongDataNoticeListener *mWrongDataNoticeListener;
diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp
index fe391636..22f56195 100644
--- a/src/gui/sell.cpp
+++ b/src/gui/sell.cpp
@@ -33,14 +33,23 @@
#include "../units.h"
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#ifdef TMWSERV_SUPPORT
+#include "../net/tmwserv/gameserver/player.h"
+#else
+#include "../net/ea/protocol.h"
+#endif
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
+#ifdef TMWSERV_SUPPORT
+SellDialog::SellDialog():
+ Window(_("Sell")),
+#else
SellDialog::SellDialog(Network *network):
Window(_("Sell")),
mNetwork(network),
+#endif
mMaxItems(0), mAmountItems(0)
{
setWindowName("Sell");
@@ -123,6 +132,16 @@ void SellDialog::reset()
updateButtonsAndLabels();
}
+#ifdef TMWSERV_SUPPORT
+
+void SellDialog::addItem(int item, int amount, int price)
+{
+ mShopItems->addItem(item, amount, price);
+ mShopItemList->adjustSize();
+}
+
+#else
+
void SellDialog::addItem(const Item *item, int price)
{
if (!item)
@@ -134,6 +153,8 @@ void SellDialog::addItem(const Item *item, int price)
mShopItemList->adjustSize();
}
+#endif
+
void SellDialog::action(const gcn::ActionEvent &event)
{
if (event.getId() == "quit")
@@ -177,6 +198,10 @@ void SellDialog::action(const gcn::ActionEvent &event)
else if (event.getId() == "sell" && mAmountItems > 0
&& mAmountItems <= mMaxItems)
{
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::tradeWithNPC
+ (mShopItems->at(selectedItem)->getId(), mAmountItems);
+#else
// Attempt sell
MessageOut outMsg(mNetwork);
@@ -195,6 +220,7 @@ void SellDialog::action(const gcn::ActionEvent &event)
mAmountItems -= sellCount;
outMsg.writeInt16(sellCount);
}
+#endif
mPlayerMoney +=
mAmountItems * mShopItems->at(selectedItem)->getPrice();
diff --git a/src/gui/sell.h b/src/gui/sell.h
index 45b6a704..b6388a1f 100644
--- a/src/gui/sell.h
+++ b/src/gui/sell.h
@@ -30,7 +30,9 @@
#include "window.h"
class Item;
+#ifdef EATHENA_SUPPORT
class Network;
+#endif
class ShopItems;
class ShopListBox;
@@ -47,7 +49,11 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener
*
* @see Window::Window
*/
+#ifdef TMWSERV_SUPPORT
+ SellDialog();
+#else
SellDialog(Network *network);
+#endif
/**
* Destructor
@@ -62,7 +68,11 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener
/**
* Adds an item to the inventory.
*/
+#ifdef TMWSERV_SUPPORT
+ void addItem(int item, int amount, int price);
+#else
void addItem(const Item *item, int price);
+#endif
/**
* Called when receiving actions from the widgets.
@@ -101,7 +111,9 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener
*/
void updateButtonsAndLabels();
+#ifdef EATHENA_SUPPORT
Network *mNetwork;
+#endif
gcn::Button *mSellButton;
gcn::Button *mQuitButton;
gcn::Button *mAddMaxButton;
diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp
new file mode 100644
index 00000000..a8074b0c
--- /dev/null
+++ b/src/gui/serverdialog.cpp
@@ -0,0 +1,214 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <cstdlib>
+#include <iostream>
+#include <string>
+
+#include <guichan/widgets/label.hpp>
+
+#include "serverdialog.h"
+
+#include "button.h"
+#include "listbox.h"
+#include "ok_dialog.h"
+#include "scrollarea.h"
+#include "textfield.h"
+
+#include "widgets/layout.h"
+
+#include "../configuration.h"
+#include "../log.h"
+#include "../logindata.h"
+#include "../main.h"
+
+#include "../utils/gettext.h"
+#include "../utils/stringutils.h"
+
+const short MAX_SERVERLIST = 5;
+
+int ServersListModel::getNumberOfElements()
+{
+ return servers.size();
+}
+
+std::string ServersListModel::getElementAt(int elementIndex)
+{
+ std::string myServer = "";
+ myServer = servers.at(elementIndex).serverName;
+ myServer += ":";
+ myServer += toString(servers.at(elementIndex).port);
+ return myServer;
+}
+
+void ServersListModel::addFirstElement(Server server)
+{
+ // Equivalent to push_front
+ std::vector<Server>::iterator MyIterator = servers.begin();
+ servers.insert(MyIterator, 1, server);
+}
+
+void ServersListModel::addElement(Server server)
+{
+ servers.push_back(server);
+}
+
+ServerDialog::ServerDialog(LoginData *loginData):
+ Window(_("Choose your server")), mLoginData(loginData)
+{
+ gcn::Label *serverLabel = new gcn::Label(_("Server:"));
+ gcn::Label *portLabel = new gcn::Label(_("Port:"));
+ mServerNameField = new TextField(mLoginData->hostname);
+ mPortField = new TextField(toString(mLoginData->port));
+
+ // Add the most used servers from config
+ mMostUsedServersListModel = new ServersListModel();
+ Server currentServer;
+ std::string currentConfig = "";
+ for (int i=0; i<=MAX_SERVERLIST; i++)
+ {
+ currentServer.serverName = "";
+ currentServer.port = 0;
+
+ currentConfig = "MostUsedServerName" + toString(i);
+ currentServer.serverName = config.getValue(currentConfig, "");
+
+ currentConfig = "MostUsedServerPort" + toString(i);
+ currentServer.port = (short)atoi(config.getValue(currentConfig, "").c_str());
+ if (!currentServer.serverName.empty() || currentServer.port != 0)
+ {
+ mMostUsedServersListModel->addElement(currentServer);
+ }
+ }
+
+ mMostUsedServersListBox = new ListBox(NULL);
+ mMostUsedServersListBox->setListModel(mMostUsedServersListModel);
+ mMostUsedServersScrollArea = new ScrollArea();
+ mMostUsedServersDropDown = new DropDown(mMostUsedServersListModel,
+ mMostUsedServersScrollArea, mMostUsedServersListBox);
+
+ mOkButton = new Button(_("Ok"), "connect", this);
+ mCancelButton = new Button(_("Cancel"), "cancel", this);
+
+ mServerNameField->setActionEventId("connect");
+ mPortField->setActionEventId("connect");
+ mMostUsedServersDropDown->setActionEventId("changeSelection");
+
+ mServerNameField->addActionListener(this);
+ mPortField->addActionListener(this);
+ mMostUsedServersDropDown->addActionListener(this);
+
+ place(0, 0, serverLabel);
+ place(0, 1, portLabel);
+ place(1, 0, mServerNameField, 3).setPadding(2);
+ place(1, 1, mPortField, 3).setPadding(2);
+ place(0, 2, mMostUsedServersDropDown, 4).setPadding(2);
+ place(2, 3, mOkButton);
+ place(3, 3, mCancelButton);
+ reflowLayout(250, 0);
+
+ setLocationRelativeTo(getParent());
+ setVisible(true);
+
+ if (mServerNameField->getText().empty()) {
+ mServerNameField->requestFocus();
+ } else {
+ if (mPortField->getText().empty()) {
+ mPortField->requestFocus();
+ } else {
+ mOkButton->requestFocus();
+ }
+ }
+}
+
+ServerDialog::~ServerDialog()
+{
+ delete mMostUsedServersListModel;
+ delete mMostUsedServersScrollArea;
+}
+
+void
+ServerDialog::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "ok")
+ {
+ // Give focus back to the server dialog.
+ mServerNameField->requestFocus();
+ }
+ else if (event.getId() == "changeSelection")
+ {
+ // Change the textField Values according to new selection
+ Server myServer = mMostUsedServersListModel->getServer
+ (mMostUsedServersListBox->getSelected());
+ mServerNameField->setText(myServer.serverName);
+ mPortField->setText(toString(myServer.port));
+ }
+ else if (event.getId() == "connect")
+ {
+ // Check login
+ if (mServerNameField->getText().empty() || mPortField->getText().empty())
+ {
+ OkDialog *dlg = new OkDialog(_("Error"),
+ _("Please type both the address and the port of a server."));
+ dlg->addActionListener(this);
+ }
+ else
+ {
+ mLoginData->hostname = mServerNameField->getText();
+ mLoginData->port = (short) atoi(mPortField->getText().c_str());
+ mOkButton->setEnabled(false);
+ mCancelButton->setEnabled(false);
+
+ // First, look if the entry is a new one.
+ Server currentServer;
+ bool newEntry = true;
+ for (int i = 0; i < mMostUsedServersListModel->getNumberOfElements(); i++)
+ {
+ currentServer = mMostUsedServersListModel->getServer(i);
+ if (currentServer.serverName == mLoginData->hostname &&
+ currentServer.port == mLoginData->port)
+ newEntry = false;
+ }
+ // Then, add it to config if it's really new
+ currentServer.serverName = mLoginData->hostname;
+ currentServer.port = mLoginData->port;
+ if (newEntry)
+ mMostUsedServersListModel->addFirstElement(currentServer);
+ // Write the entry in config
+ std::string currentConfig = "";
+ for (int i = 0; i < mMostUsedServersListModel->getNumberOfElements(); i++)
+ {
+ currentServer = mMostUsedServersListModel->getServer(i);
+
+ currentConfig = "MostUsedServerName" + toString(i);
+ config.setValue(currentConfig, currentServer.serverName);
+
+ currentConfig = "MostUsedServerPort" + toString(i);
+ config.setValue(currentConfig, toString(currentServer.port));
+ }
+ state = STATE_CONNECT_ACCOUNT;
+ }
+ }
+ else if (event.getId() == "cancel")
+ {
+ state = STATE_FORCE_QUIT;
+ }
+}
diff --git a/src/gui/serverdialog.h b/src/gui/serverdialog.h
new file mode 100644
index 00000000..16965571
--- /dev/null
+++ b/src/gui/serverdialog.h
@@ -0,0 +1,123 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_SERVERDIALOG_H
+#define _TMW_SERVERDIALOG_H
+
+#include <iosfwd>
+#include <vector>
+
+#include <guichan/actionlistener.hpp>
+#include <guichan/listmodel.hpp>
+#include "./widgets/dropdown.h"
+
+#include "login.h"
+#include "window.h"
+
+#include "../guichanfwd.h"
+
+#include "../net/tmwserv/network.h"
+
+class LoginData;
+
+/**
+ * A server structure to keep pairs of servers and ports.
+ */
+struct Server {
+ Server():
+ serverName(""),
+ port(0) {};
+
+ std::string serverName;
+ short port;
+};
+
+/**
+ * Server and Port List Model
+ */
+class ServersListModel : public gcn::ListModel
+{
+ public:
+ /**
+ * Used to get number of line in the list
+ */
+ int getNumberOfElements();
+ /**
+ * Used to get an element from the list
+ */
+ std::string getElementAt(int elementIndex);
+ /**
+ * Used to get the corresponding Server struct
+ */
+ Server getServer(int elementIndex) { return servers[elementIndex]; };
+ /**
+ * Add an Element at the end of the server list
+ */
+ void addElement(Server server);
+ /**
+ * Add an Element at the beginning of the server list
+ */
+ void addFirstElement(Server server);
+
+ private:
+ std::vector<Server> servers;
+};
+
+/**
+ * The server choice dialog.
+ *
+ * \ingroup Interface
+ */
+class ServerDialog : public Window, public gcn::ActionListener
+{
+ public:
+ /**
+ * Constructor
+ *
+ * @see Window::Window
+ */
+ ServerDialog(LoginData *loginData);
+
+ /**
+ * Destructor
+ */
+ ~ServerDialog();
+
+ /**
+ * Called when receiving actions from the widgets.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ private:
+ gcn::TextField *mServerNameField;
+ gcn::TextField *mPortField;
+ gcn::Button *mOkButton;
+ gcn::Button *mCancelButton;
+
+ DropDown *mMostUsedServersDropDown;
+ gcn::ListBox *mMostUsedServersListBox;
+ gcn::ScrollArea *mMostUsedServersScrollArea;
+ ServersListModel *mMostUsedServersListModel;
+
+ LoginData *mLoginData;
+};
+
+#endif
diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp
index 849a30c2..72dfbce5 100644
--- a/src/gui/setup.cpp
+++ b/src/gui/setup.cpp
@@ -50,7 +50,12 @@ extern Window *helpWindow;
extern Window *debugWindow;
extern Window *itemShortcutWindow;
extern Window *emoteShortcutWindow;
+#ifdef TMWSERV_SUPPORT
+extern Window *magicDialog;
+extern Window *guildWindow;
+#else
extern Window *storageWindow;
+#endif
Setup::Setup():
Window(_("Setup"))
@@ -140,7 +145,9 @@ void Setup::action(const gcn::ActionEvent &event)
statusWindow->resetToDefaultSize();
buyDialog->resetToDefaultSize();
sellDialog->resetToDefaultSize();
+#ifdef EATHENA_SUPPORT
buySellDialog->resetToDefaultSize();
+#endif
inventoryWindow->resetToDefaultSize();
emoteWindow->resetToDefaultSize();
npcTextDialog->resetToDefaultSize();
@@ -153,7 +160,12 @@ void Setup::action(const gcn::ActionEvent &event)
debugWindow->resetToDefaultSize();
itemShortcutWindow->resetToDefaultSize();
emoteShortcutWindow->resetToDefaultSize();
+#ifdef TMWSERV_SUPPORT
+ magicDialog->resetToDefaultSize();
+ guildWindow->resetToDefaultSize();
+#else
storageWindow->resetToDefaultSize();
+#endif
}
}
diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp
index 2ca39282..28a80b3d 100644
--- a/src/gui/setup_audio.cpp
+++ b/src/gui/setup_audio.cpp
@@ -42,6 +42,7 @@ Setup_Audio::Setup_Audio():
mMusicSlider(new Slider(0, 128))
{
setOpaque(false);
+ setDimension(gcn::Rectangle(0, 0, 250, 200));
gcn::Label *sfxLabel = new Label(_("Sfx volume"));
gcn::Label *musicLabel = new Label(_("Music volume"));
diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp
index 74574ec7..07f073db 100644
--- a/src/gui/setup_video.cpp
+++ b/src/gui/setup_video.cpp
@@ -108,6 +108,7 @@ Setup_Video::Setup_Video():
mFullScreenEnabled(config.getValue("screen", false)),
mOpenGLEnabled(config.getValue("opengl", false)),
mCustomCursorEnabled(config.getValue("customcursor", true)),
+ mVisibleNamesEnabled(config.getValue("visiblenames", 1)),
mParticleEffectsEnabled(config.getValue("particleeffects", true)),
mNameEnabled(config.getValue("showownname", false)),
mPickupChatEnabled(config.getValue("showpickupchat", true)),
@@ -120,6 +121,7 @@ Setup_Video::Setup_Video():
mFsCheckBox(new CheckBox(_("Full screen"), mFullScreenEnabled)),
mOpenGLCheckBox(new CheckBox(_("OpenGL"), mOpenGLEnabled)),
mCustomCursorCheckBox(new CheckBox(_("Custom cursor"), mCustomCursorEnabled)),
+ mVisibleNamesCheckBox(new CheckBox(_("Visible names"), mVisibleNamesEnabled)),
mParticleEffectsCheckBox(new CheckBox(_("Particle effects"), mParticleEffectsEnabled)),
mNameCheckBox(new CheckBox(_("Show name"), mNameEnabled)),
mPickupNotifyLabel(new Label(_("Show pickup notification"))),
@@ -175,6 +177,7 @@ Setup_Video::Setup_Video():
mModeList->setActionEventId("videomode");
mCustomCursorCheckBox->setActionEventId("customcursor");
+ mVisibleNamesCheckBox->setActionEventId("visiblenames");
mParticleEffectsCheckBox->setActionEventId("particleeffects");
mPickupChatCheckBox->setActionEventId("pickupchat");
mPickupParticleCheckBox->setActionEventId("pickupparticle");
@@ -194,6 +197,7 @@ Setup_Video::Setup_Video():
mModeList->addActionListener(this);
mCustomCursorCheckBox->addActionListener(this);
+ mVisibleNamesCheckBox->addActionListener(this);
mParticleEffectsCheckBox->addActionListener(this);
mPickupChatCheckBox->addActionListener(this);
mPickupParticleCheckBox->addActionListener(this);
@@ -274,7 +278,8 @@ Setup_Video::Setup_Video():
place(1, 0, mFsCheckBox, 2);
place(3, 0, mOpenGLCheckBox, 1);
place(1, 1, mCustomCursorCheckBox, 3);
- place(1, 2, mNameCheckBox, 3);
+ place(1, 2, mVisibleNamesCheckBox, 3);
+ place(3, 2, mNameCheckBox, 1);
place(1, 3, mParticleEffectsCheckBox, 3);
place(1, 4, mPickupNotifyLabel, 3);
place(1, 5, mPickupChatCheckBox, 1);
@@ -364,6 +369,7 @@ void Setup_Video::apply()
// We sync old and new values at apply time
mFullScreenEnabled = config.getValue("screen", false);
mCustomCursorEnabled = config.getValue("customcursor", true);
+ mVisibleNamesEnabled = config.getValue("visiblenames", 1);
mParticleEffectsEnabled = config.getValue("particleeffects", true);
mNameEnabled = config.getValue("showownname", false);
mSpeechMode = (int) config.getValue("speech", 3);
@@ -399,6 +405,7 @@ void Setup_Video::cancel()
mFsCheckBox->setSelected(mFullScreenEnabled);
mOpenGLCheckBox->setSelected(mOpenGLEnabled);
mCustomCursorCheckBox->setSelected(mCustomCursorEnabled);
+ mVisibleNamesCheckBox->setSelected(mVisibleNamesEnabled);
mParticleEffectsCheckBox->setSelected(mParticleEffectsEnabled);
mSpeechSlider->setValue(mSpeechMode);
mNameCheckBox->setSelected(mNameEnabled);
@@ -413,6 +420,7 @@ void Setup_Video::cancel()
config.setValue("screen", mFullScreenEnabled ? true : false);
config.setValue("customcursor", mCustomCursorEnabled ? true : false);
+ config.setValue("visiblenames", mVisibleNamesEnabled ? 1 : 0);
config.setValue("particleeffects", mParticleEffectsEnabled ? true : false);
config.setValue("speech", mSpeechMode);
config.setValue("showownname", mNameEnabled ? true : false);
@@ -449,6 +457,11 @@ void Setup_Video::action(const gcn::ActionEvent &event)
config.setValue("customcursor",
mCustomCursorCheckBox->isSelected() ? true : false);
}
+ else if (event.getId() == "visiblenames")
+ {
+ config.setValue("visiblenames",
+ mVisibleNamesCheckBox->isSelected() ? 1 : 0);
+ }
else if (event.getId() == "particleeffects")
{
config.setValue("particleeffects",
diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h
index 7d9732a1..d2680fa8 100644
--- a/src/gui/setup_video.h
+++ b/src/gui/setup_video.h
@@ -50,6 +50,7 @@ class Setup_Video : public SetupTab, public gcn::ActionListener,
bool mFullScreenEnabled;
bool mOpenGLEnabled;
bool mCustomCursorEnabled;
+ bool mVisibleNamesEnabled;
bool mParticleEffectsEnabled;
bool mNameEnabled;
bool mPickupChatEnabled;
@@ -71,6 +72,7 @@ class Setup_Video : public SetupTab, public gcn::ActionListener,
gcn::CheckBox *mFsCheckBox;
gcn::CheckBox *mOpenGLCheckBox;
gcn::CheckBox *mCustomCursorCheckBox;
+ gcn::CheckBox *mVisibleNamesCheckBox;
gcn::CheckBox *mParticleEffectsCheckBox;
gcn::CheckBox *mNameCheckBox;
diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp
index 85f238c0..3cdc304c 100644
--- a/src/gui/shop.cpp
+++ b/src/gui/shop.cpp
@@ -43,6 +43,12 @@ std::string ShopItems::getElementAt(int i)
return mShopItems.at(i)->getDisplayName();
}
+void ShopItems::addItem(int id, int amount, int price)
+{
+ mShopItems.push_back(new ShopItem(-1, id, amount, price));
+}
+
+#ifdef EATHENA_SUPPORT
void ShopItems::addItem(int inventoryIndex, int id, int quantity, int price)
{
ShopItem* item = 0;
@@ -61,11 +67,7 @@ void ShopItems::addItem(int inventoryIndex, int id, int quantity, int price)
mShopItems.push_back(item);
}
}
-
-void ShopItems::addItem(int id, int price)
-{
- addItem(-1, id, 0, price);
-}
+#endif
ShopItem* ShopItems::at(int i) const
{
diff --git a/src/gui/shop.h b/src/gui/shop.h
index 0c900d9d..6c3031af 100644
--- a/src/gui/shop.h
+++ b/src/gui/shop.h
@@ -57,6 +57,12 @@ class ShopItems : public gcn::ListModel
~ShopItems();
/**
+ * Adds an item to the list.
+ */
+ void addItem(int id, int amount, int price);
+
+#ifdef EATHENA_SUPPORT
+ /**
* Adds an item to the list (used by sell dialog). Looks for
* duplicate entries, if mergeDuplicates was turned on.
*
@@ -66,15 +72,7 @@ class ShopItems : public gcn::ListModel
* @param price price of the item
*/
void addItem(int inventoryIndex, int id, int amount, int price);
-
- /**
- * Adds an item to the list (used by buy dialog). Looks for
- * duplicate entries, if mergeDuplicates was turned on.
- *
- * @param id the id of the item
- * @param price price of the item
- */
- void addItem(int id, int price);
+#endif
/**
* Returns the number of items in the shop.
diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp
new file mode 100644
index 00000000..22d1db60
--- /dev/null
+++ b/src/gui/skilldialog.cpp
@@ -0,0 +1,263 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <guichan/widgets/label.hpp>
+#include <guichan/widgets/container.hpp>
+#include <guichan/widgets/icon.hpp>
+
+#include "skilldialog.h"
+
+#include "icon.h"
+#include "button.h"
+#include "listbox.h"
+#include "scrollarea.h"
+#include "windowcontainer.h"
+#include "progressbar.h"
+
+#include "widgets/tabbedarea.h"
+
+#include "../localplayer.h"
+
+#include "../utils/dtor.h"
+#include "../utils/gettext.h"
+#include "../utils/stringutils.h"
+
+SkillDialog::SkillDialog():
+ Window(_("Skills"))
+{
+ setWindowName("Skills");
+ setCloseButton(true);
+ setDefaultSize(windowContainer->getWidth() - 280, 30, 275, 425);
+
+ TabbedArea *panel = new TabbedArea();
+ panel->setDimension(gcn::Rectangle(5, 5, 270, 420));
+
+ Skill_Tab* tab;
+
+ // Add each type of skill tab to the panel
+ tab = new Skill_Tab("Weapon");
+ panel->addTab(_("Weapons"), tab);
+ mTabs.push_back(tab);
+
+ tab = new Skill_Tab("Magic");
+ panel->addTab(_("Magic"), tab);
+ mTabs.push_back(tab);
+
+ tab = new Skill_Tab("Craft");
+ panel->addTab(_("Crafts"), tab);
+ mTabs.push_back(tab);
+
+ add(panel);
+
+ update();
+
+ setLocationRelativeTo(getParent());
+ loadWindowState();
+}
+
+SkillDialog::~SkillDialog()
+{
+ delete_all(mTabs);
+}
+
+void SkillDialog::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "skill")
+ {
+ }
+ else if (event.getId() == "close")
+ {
+ setVisible(false);
+ }
+}
+
+void SkillDialog::draw(gcn::Graphics *g)
+{
+ update();
+
+ Window::draw(g);
+}
+
+void SkillDialog::update()
+{
+ for(std::list<Skill_Tab*>::const_iterator i = mTabs.begin();
+ i != mTabs.end(); ++i)
+ {
+ (*i)->update();
+ }
+}
+
+Skill_Tab::Skill_Tab(const std::string &type): type(type)
+{
+ setOpaque(false);
+ setDimension(gcn::Rectangle(0, 0, 270, 420));
+ int skillNum = getSkillNum();
+
+ mSkillIcons.resize(skillNum);
+ mSkillNameLabels.resize(skillNum);
+ mSkillLevelLabels.resize(skillNum);
+ mSkillExpLabels.resize(skillNum);
+ mSkillProgress.resize(skillNum);
+
+ // Set the initial positions of the skill information
+ for (int a=0; a < skillNum; a++)
+ {
+ mSkillIcons.at(a) = getIcon(a);
+ mSkillIcons.at(a)->setPosition(1, a*32);
+ add(mSkillIcons.at(a));
+
+ mSkillNameLabels.at(a) = new gcn::Label("");
+ mSkillNameLabels.at(a)->setPosition(35, a*32 );
+ add(mSkillNameLabels.at(a));
+
+ mSkillProgress.at(a) = new ProgressBar(0.0f, 200, 20, 150, 150, 150);
+ mSkillProgress.at(a)->setPosition(35, a*32 + 13);
+ add(mSkillProgress.at(a));
+
+ mSkillExpLabels.at(a) = new gcn::Label("");
+ mSkillExpLabels.at(a)->setPosition(45, a*32 + 16);
+ add(mSkillExpLabels.at(a));
+
+ mSkillLevelLabels.at(a) = new gcn::Label("");
+ mSkillLevelLabels.at(a)->setPosition(165, a*32);
+ add(mSkillLevelLabels.at(a));
+ }
+
+ update();
+
+}
+
+int Skill_Tab::getSkillNum()
+{
+ int skillNum = 0;
+
+ if (type == "Weapon")
+ {
+ skillNum = CHAR_SKILL_WEAPON_NB;
+ return skillNum;
+ }
+ else if (type == "Magic")
+ {
+ skillNum = CHAR_SKILL_MAGIC_NB;
+ return skillNum;
+ }
+ else if (type == "Craft")
+ {
+ skillNum = CHAR_SKILL_CRAFT_NB;
+ return skillNum;
+ }
+ else return skillNum;
+}
+
+int Skill_Tab::getSkillBegin()
+{
+ int skillBegin = 0;
+
+ if (type == "Weapon")
+ {
+ skillBegin = CHAR_SKILL_WEAPON_BEGIN - CHAR_SKILL_BEGIN;
+ return skillBegin;
+ }
+ else if (type == "Magic")
+ {
+ skillBegin = CHAR_SKILL_MAGIC_BEGIN - CHAR_SKILL_BEGIN;
+ return skillBegin;
+ }
+ else if (type == "Craft")
+ {
+ skillBegin = CHAR_SKILL_CRAFT_BEGIN - CHAR_SKILL_BEGIN;
+ return skillBegin;
+ }
+ else return skillBegin;
+}
+
+Icon* Skill_Tab::getIcon(int index)
+{
+ int skillBegin = getSkillBegin();
+ std::string icon = LocalPlayer::getSkillInfo(index + skillBegin).icon;
+ return new Icon(icon);
+}
+
+void Skill_Tab::updateSkill(int index)
+{
+ int skillBegin = getSkillBegin();
+
+ int baseLevel = player_node->getAttributeBase(index +
+ skillBegin +
+ CHAR_SKILL_BEGIN);
+
+ int effLevel = player_node->getAttributeEffective(index +
+ skillBegin +
+ CHAR_SKILL_BEGIN);
+ if(baseLevel <= 0)
+ {
+ mSkillProgress.at(index)->setVisible(false);
+ mSkillExpLabels.at(index)->setVisible(false);
+ mSkillLevelLabels.at(index)->setVisible(false);
+ mSkillNameLabels.at(index)->setVisible(false);
+ mSkillIcons.at(index)->setVisible(false);
+ }
+ else
+ {
+ mSkillProgress.at(index)->setVisible(true);
+ mSkillExpLabels.at(index)->setVisible(true);
+ mSkillLevelLabels.at(index)->setVisible(true);
+ mSkillNameLabels.at(index)->setVisible(true);
+ mSkillIcons.at(index)->setVisible(true);
+ std::string skillLevel("Lvl: " + toString(baseLevel));
+ if (effLevel < baseLevel)
+ {
+ skillLevel.append(" - " + toString(baseLevel - effLevel));
+ }
+ else if (effLevel > baseLevel)
+ {
+ skillLevel.append(" + " + toString(effLevel - baseLevel));
+ }
+ mSkillLevelLabels.at(index)->setCaption(skillLevel);
+
+ std::pair<int, int> exp = player_node->getExperience(index + skillBegin);
+ std::string sExp (toString(exp.first) + " / " + toString(exp.second));
+
+
+ mSkillNameLabels.at(index)->setCaption(LocalPlayer::getSkillInfo(index + skillBegin).name);
+ mSkillNameLabels.at(index)->adjustSize();
+ mSkillLevelLabels.at(index)->adjustSize();
+ mSkillExpLabels.at(index)->setCaption(sExp);
+ mSkillExpLabels.at(index)->adjustSize();
+ mSkillExpLabels.at(index)->setAlignment(gcn::Graphics::RIGHT);
+
+ // More intense red as exp grows
+ int color = 150 - (int)(150 * ((float) exp.first / exp.second));
+ mSkillProgress.at(index)->setColor(244, color, color);
+ mSkillProgress.at(index)->setProgress((float) exp.first / exp.second);
+ }
+}
+
+void Skill_Tab::update()
+{
+ int skillNum = getSkillNum();
+
+ // Update the skill information for reach skill
+ for (int a = 0; a < skillNum; a++)
+ {
+ updateSkill(a);
+ }
+}
diff --git a/src/gui/skilldialog.h b/src/gui/skilldialog.h
new file mode 100644
index 00000000..3d010daa
--- /dev/null
+++ b/src/gui/skilldialog.h
@@ -0,0 +1,139 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_SKILL_H
+#define _TMW_SKILL_H
+
+#include <vector>
+#include <list>
+
+#include <guichan/listmodel.hpp>
+#include <guichan/actionlistener.hpp>
+
+#include "window.h"
+#include "gccontainer.h"
+
+#include "../guichanfwd.h"
+
+class ProgressBar;
+class Icon;
+
+class Skill_Tab : public GCContainer, public gcn::ActionListener
+{
+ public:
+ /**
+ * The type of this skill tab
+ */
+ const std::string type;
+
+ /**
+ * Constructor
+ */
+ Skill_Tab(const std::string &type);
+
+ /**
+ * Update this tab
+ */
+ void update();
+
+ /**
+ * Called when receiving actions from widget.
+ */
+ void action(const gcn::ActionEvent &event) {}
+
+ private:
+ /**
+ * Update the information of a skill at
+ * the given index
+ */
+ void updateSkill(int index);
+
+ /**
+ * Gets the number of skills in this particular
+ * type of tab.
+ */
+ int getSkillNum();
+
+ /**
+ * Get the first enumeration of this skill tab's
+ * skill type.
+ */
+ int getSkillBegin();
+
+ /**
+ * Get the icon associated with the given index
+ */
+ Icon* getIcon(int index);
+
+ std::vector<Icon *> mSkillIcons;
+ std::vector<gcn::Label *> mSkillNameLabels;
+ std::vector<gcn::Label *> mSkillLevelLabels;
+ std::vector<gcn::Label *> mSkillExpLabels;
+ std::vector<ProgressBar *> mSkillProgress;
+};
+
+
+/**
+ * The skill dialog.
+ *
+ * \ingroup Interface
+ */
+class SkillDialog : public Window, public gcn::ActionListener
+{
+ public:
+ /**
+ * Constructor.
+ */
+ SkillDialog();
+
+ /**
+ * Destructor.
+ */
+ ~SkillDialog();
+
+ /**
+ * Called when receiving actions from widget.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ /**
+ * Update the tabs in this dialog
+ */
+ void update();
+
+ /**
+ * Draw this window.
+ */
+ void draw(gcn::Graphics *g);
+
+ private:
+
+
+ std::list<Skill_Tab*> mTabs;
+
+};
+
+
+
+
+extern SkillDialog *skillDialog;
+
+#endif
diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp
index de0c8406..73ada2e1 100644
--- a/src/gui/speechbubble.cpp
+++ b/src/gui/speechbubble.cpp
@@ -1,6 +1,7 @@
/*
* Speech bubbles
* Copyright (C) 2008 The Legend of Mazzeroth Development Team
+ * Copyright (C) 2008 The Mana World Development Team
*
* This file is part of The Mana World.
*
diff --git a/src/gui/speechbubble.h b/src/gui/speechbubble.h
index 8bb0e5ea..3eead884 100644
--- a/src/gui/speechbubble.h
+++ b/src/gui/speechbubble.h
@@ -1,6 +1,7 @@
/*
* Speech bubbles
* Copyright (C) 2008 The Legend of Mazzeroth Development Team
+ * Copyright (C) 2008 The Mana World Development Team
*
* This file is part of The Mana World.
*
diff --git a/src/gui/status.cpp b/src/gui/status.cpp
index a9af2ab4..2f95f1c8 100644
--- a/src/gui/status.cpp
+++ b/src/gui/status.cpp
@@ -166,14 +166,14 @@ void StatusWindow::update()
{
// Status Part
// -----------
- mLvlLabel->setCaption(strprintf(_("Level: %d"), mPlayer->mLevel));
+ mLvlLabel->setCaption(strprintf(_("Level: %d"), mPlayer->getLevel()));
mLvlLabel->adjustSize();
mJobLvlLabel->setCaption(strprintf(_("Job: %d"), mPlayer->mJobLevel));
mJobLvlLabel->adjustSize();
- if (mCurrency != mPlayer->mGp) {
- mCurrency = mPlayer->mGp;
+ if (mCurrency != mPlayer->getMoney()) {
+ mCurrency = mPlayer->getMoney();
mGpLabel->setCaption(strprintf(_("Money: %s"),
Units::formatCurrency(mCurrency).c_str()));
mGpLabel->adjustSize();
@@ -284,17 +284,17 @@ void StatusWindow::action(const gcn::ActionEvent &event)
void StatusWindow::updateHPBar(ProgressBar *bar, bool showMax)
{
if (showMax)
- bar->setText(toString(player_node->mHp) +
- "/" + toString(player_node->mMaxHp));
+ bar->setText(toString(player_node->getHp()) +
+ "/" + toString(player_node->getMaxHp()));
else
- bar->setText(toString(player_node->mHp));
+ bar->setText(toString(player_node->getHp()));
// HP Bar coloration
- if (player_node->mHp < player_node->mMaxHp / 3)
+ if (player_node->getHp() < player_node->getMaxHp() / 3)
{
bar->setColor(223, 32, 32); // Red
}
- else if (player_node->mHp < (player_node->mMaxHp / 3) * 2)
+ else if (player_node->getHp() < (player_node->getMaxHp() / 3) * 2)
{
bar->setColor(230, 171, 34); // Orange
}
@@ -303,7 +303,7 @@ void StatusWindow::updateHPBar(ProgressBar *bar, bool showMax)
bar->setColor(0, 171, 34); // Green
}
- bar->setProgress((float) player_node->mHp / (float) player_node->mMaxHp);
+ bar->setProgress((float) player_node->getHp() / (float) player_node->getMaxHp());
}
void StatusWindow::updateMPBar(ProgressBar *bar, bool showMax)
diff --git a/src/gui/status.h b/src/gui/status.h
index f3f54f4e..1425fe12 100644
--- a/src/gui/status.h
+++ b/src/gui/status.h
@@ -70,7 +70,7 @@ class StatusWindow : public Window, public gcn::ActionListener
*/
gcn::Label *mLvlLabel, *mJobLvlLabel;
gcn::Label *mGpLabel;
- Uint32 mCurrency;
+ int mCurrency;
gcn::Label *mHpLabel, *mMpLabel, *mXpLabel, *mJobLabel;
ProgressBar *mHpBar, *mMpBar;
ProgressBar *mXpBar, *mJobBar;
diff --git a/src/gui/statuswindow.cpp b/src/gui/statuswindow.cpp
new file mode 100644
index 00000000..8d4363d9
--- /dev/null
+++ b/src/gui/statuswindow.cpp
@@ -0,0 +1,376 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "statuswindow.h"
+
+#include <guichan/widgets/label.hpp>
+
+#include "button.h"
+#include "progressbar.h"
+#include "windowcontainer.h"
+
+#include "../localplayer.h"
+
+#include "../utils/strprintf.h"
+#include "../utils/stringutils.h"
+
+StatusWindow::StatusWindow(LocalPlayer *player):
+ Window(player->getName()),
+ mPlayer(player)
+{
+ setWindowName("Status");
+ setResizable(true);
+ setCloseButton(true);
+ setDefaultSize((windowContainer->getWidth() - 365) / 2,
+ (windowContainer->getHeight() - 255) / 2, 365, 275);
+ loadWindowState();
+
+ // ----------------------
+ // Status Part
+ // ----------------------
+
+ mLvlLabel = new gcn::Label("Level:");
+ mMoneyLabel = new gcn::Label("Money:");
+
+ mHpLabel = new gcn::Label("HP:");
+ mHpBar = new ProgressBar(1.0f, 80, 15, 0, 171, 34);
+ mHpValueLabel = new gcn::Label("");
+
+ int y = 3;
+ int x = 5;
+
+ mLvlLabel->setPosition(x, y);
+ x += mLvlLabel->getWidth() + 40;
+ mMoneyLabel->setPosition(x, y);
+
+ y += mLvlLabel->getHeight() + 5; // Next Row
+ x = 5;
+
+ mHpLabel->setPosition(x, y);
+ x += mHpLabel->getWidth() + 5;
+ mHpBar->setPosition(x, y);
+ x += mHpBar->getWidth() + 5;
+ mHpValueLabel->setPosition(x, y);
+
+ y += mHpLabel->getHeight() + 5; // Next Row
+ x = 5;
+
+ add(mLvlLabel);
+ add(mMoneyLabel);
+ add(mHpLabel);
+ add(mHpValueLabel);
+ add(mHpBar);
+
+ // ----------------------
+ // Stats Part
+ // ----------------------
+
+ // Static Labels
+ gcn::Label *mStatsTitleLabel = new gcn::Label("Stats");
+ gcn::Label *mStatsTotalLabel = new gcn::Label("Total");
+
+ // Derived Stats
+/*
+ mStatsAttackLabel = new gcn::Label("Attack:");
+ mStatsDefenseLabel= new gcn::Label("Defense:");
+ mStatsMagicAttackLabel = new gcn::Label("M.Attack:");
+ mStatsMagicDefenseLabel = new gcn::Label("M.Defense:");
+ mStatsAccuracyLabel = new gcn::Label("% Accuracy:");
+ mStatsEvadeLabel = new gcn::Label("% Evade:");
+ mStatsReflexLabel = new gcn::Label("% Reflex:");
+
+ mStatsAttackPoints = new gcn::Label("");
+ mStatsDefensePoints = new gcn::Label("");
+ mStatsMagicAttackPoints = new gcn::Label("");
+ mStatsMagicDefensePoints = new gcn::Label("");
+ mStatsAccuracyPoints = new gcn::Label("% Accuracy:");
+ mStatsEvadePoints = new gcn::Label("% Evade:");
+ mStatsReflexPoints = new gcn::Label("% Reflex:");
+*/
+ // New labels
+ for (int i = 0; i < 6; i++) {
+ mStatsLabel[i] = new gcn::Label();
+ mStatsDisplayLabel[i] = new gcn::Label();
+ }
+ mCharacterPointsLabel = new gcn::Label();
+ mCorrectionPointsLabel = new gcn::Label();
+
+ // Set button events Id
+ mStatsPlus[0] = new Button("+", "STR+", this);
+ mStatsPlus[1] = new Button("+", "AGI+", this);
+ mStatsPlus[2] = new Button("+", "DEX+", this);
+ mStatsPlus[3] = new Button("+", "VIT+", this);
+ mStatsPlus[4] = new Button("+", "INT+", this);
+ mStatsPlus[5] = new Button("+", "WIL+", this);
+
+ mStatsMinus[0] = new Button("-", "STR-", this);
+ mStatsMinus[1] = new Button("-", "AGI-", this);
+ mStatsMinus[2] = new Button("-", "DEX-", this);
+ mStatsMinus[3] = new Button("-", "VIT-", this);
+ mStatsMinus[4] = new Button("-", "INT-", this);
+ mStatsMinus[5] = new Button("-", "WIL-", this);
+
+
+
+ // Set position
+ mStatsTitleLabel->setPosition(mHpLabel->getX(), mHpLabel->getY() + 23 );
+ mStatsTotalLabel->setPosition(110, mStatsTitleLabel->getY() + 15);
+ int totalLabelY = mStatsTotalLabel->getY();
+
+ for (int i = 0; i < 6; i++)
+ {
+ mStatsLabel[i]->setPosition(5,
+ mStatsTotalLabel->getY() + (i * 23) + 15);
+ mStatsMinus[i]->setPosition(85, totalLabelY + (i * 23) + 15);
+ mStatsDisplayLabel[i]->setPosition(125,
+ totalLabelY + (i * 23) + 15);
+ mStatsPlus[i]->setPosition(185, totalLabelY + (i * 23) + 15);
+ }
+
+ mCharacterPointsLabel->setPosition(5, mStatsDisplayLabel[5]->getY() + 25);
+ mCorrectionPointsLabel->setPosition(5, mStatsDisplayLabel[5]->getY() + 35);
+/*
+ mStatsAttackLabel->setPosition(220, mStatsLabel[0]->getY());
+ mStatsDefenseLabel->setPosition(220, mStatsLabel[1]->getY());
+ mStatsMagicAttackLabel->setPosition(220, mStatsLabel[2]->getY());
+ mStatsMagicDefenseLabel->setPosition(220, mStatsLabel[3]->getY());
+ mStatsAccuracyLabel->setPosition(220, mStatsLabel[4]->getY());
+ mStatsEvadeLabel->setPosition(220, mStatsLabel[5]->getY());
+ mStatsReflexLabel->setPosition(220, mStatsLabel[6]->getY());
+
+ mStatsAttackPoints->setPosition(310, mStatsLabel[0]->getY());
+ mStatsDefensePoints->setPosition(310, mStatsLabel[1]->getY());
+ mStatsMagicAttackPoints->setPosition(310, mStatsLabel[2]->getY());
+ mStatsMagicDefensePoints->setPosition(310, mStatsLabel[3]->getY());
+ mStatsAccuracyPoints->setPosition(310, mStatsLabel[4]->getY());
+ mStatsEvadePoints->setPosition(310, mStatsLabel[5]->getY());
+ mStatsReflexPoints->setPosition(310, mStatsLabel[6]->getY());
+*/
+ // Assemble
+ add(mStatsTitleLabel);
+ add(mStatsTotalLabel);
+ for(int i = 0; i < 6; i++)
+ {
+ add(mStatsLabel[i]);
+ add(mStatsDisplayLabel[i]);
+ add(mStatsPlus[i]);
+ add(mStatsMinus[i]);
+ }/*
+ add(mStatsAttackLabel);
+ add(mStatsDefenseLabel);
+ add(mStatsMagicAttackLabel);
+ add(mStatsMagicDefenseLabel);
+ add(mStatsAccuracyLabel);
+ add(mStatsEvadeLabel);
+ add(mStatsReflexLabel);
+
+ add(mStatsAttackPoints);
+ add(mStatsDefensePoints);
+ add(mStatsMagicAttackPoints);
+ add(mStatsMagicDefensePoints);
+ add(mStatsAccuracyPoints);
+ add(mStatsEvadePoints);
+ add(mStatsReflexPoints);*/
+
+ add(mCharacterPointsLabel);
+ add(mCorrectionPointsLabel);
+}
+
+void StatusWindow::update()
+{
+ // Status Part
+ // -----------
+ mLvlLabel->setCaption( "Level: " +
+ toString(mPlayer->getLevel()) +
+ " (" +
+ toString(mPlayer->getLevelProgress()) +
+ "%)");
+ mLvlLabel->adjustSize();
+
+ mMoneyLabel->setCaption("Money: " + toString(mPlayer->getMoney()) + " GP");
+ mMoneyLabel->adjustSize();
+
+ updateHPBar(mHpBar, true);
+
+ // Stats Part
+ // ----------
+ const std::string attrNames[6] = {
+ "Strength",
+ "Agility",
+ "Dexterity",
+ "Vitality",
+ "Intelligence",
+ "Willpower"
+ };
+ int characterPoints = mPlayer->getCharacterPoints();
+ int correctionPoints = mPlayer->getCorrectionPoints();
+ // Update labels
+ for (int i = 0; i < 6; i++)
+ {
+ mStatsLabel[i]->setCaption(attrNames[i]);
+ mStatsDisplayLabel[i]->setCaption(
+ strprintf("%d / %d",
+ mPlayer->getAttributeEffective(CHAR_ATTR_BEGIN + i),
+ mPlayer->getAttributeBase(CHAR_ATTR_BEGIN + i)));
+
+ mStatsLabel[i]->adjustSize();
+ mStatsDisplayLabel[i]->adjustSize();
+
+ mStatsPlus[i]->setEnabled(characterPoints);
+ mStatsMinus[i]->setEnabled(correctionPoints);
+ }
+ mCharacterPointsLabel->setCaption("Character Points: " +
+ toString(characterPoints));
+ mCharacterPointsLabel->adjustSize();
+
+ mCorrectionPointsLabel->setCaption("Correction Points: " +
+ toString(correctionPoints));
+ mCorrectionPointsLabel->adjustSize();
+/*
+ // Derived Stats Points
+
+ // Attack TODO: Count equipped Weapons and items attack bonuses
+ mStatsAttackPoints->setCaption(
+ toString(mPlayer->ATK + mPlayer->ATK_BONUS));
+ mStatsAttackPoints->adjustSize();
+
+ // Defense TODO: Count equipped Armors and items defense bonuses
+ mStatsDefensePoints->setCaption(
+ toString(mPlayer->DEF + mPlayer->DEF_BONUS));
+ mStatsDefensePoints->adjustSize();
+
+ // Magic Attack TODO: Count equipped items M.Attack bonuses
+ mStatsMagicAttackPoints->setCaption(
+ toString(mPlayer->MATK + mPlayer->MATK_BONUS));
+ mStatsMagicAttackPoints->adjustSize();
+
+ // Magic Defense TODO: Count equipped items M.Defense bonuses
+ mStatsMagicDefensePoints->setCaption(
+ toString(mPlayer->MDEF + mPlayer->MDEF_BONUS));
+ mStatsMagicDefensePoints->adjustSize();
+
+ // Accuracy %
+ mStatsAccuracyPoints->setCaption(toString(mPlayer->HIT));
+ mStatsAccuracyPoints->adjustSize();
+
+ // Evasion %
+ mStatsEvadePoints->setCaption(toString(mPlayer->FLEE));
+ mStatsEvadePoints->adjustSize();
+
+ // Reflex %
+ mStatsReflexPoints->setCaption(toString(mPlayer->DEX / 4)); // + counter
+ mStatsReflexPoints->adjustSize();
+*/
+ // Update Second column widgets position
+ mMoneyLabel->setPosition(mLvlLabel->getX() + mLvlLabel->getWidth() + 20,
+ mLvlLabel->getY());
+
+}
+
+void StatusWindow::draw(gcn::Graphics *g)
+{
+ update();
+
+ Window::draw(g);
+}
+
+void StatusWindow::action(const gcn::ActionEvent &event)
+{
+ const std::string &eventId = event.getId();
+
+ // Stats Part
+ if (eventId == "STR+")
+ {
+ mPlayer->raiseAttribute(LocalPlayer::STR);
+ }
+ else if (eventId == "AGI+")
+ {
+ mPlayer->raiseAttribute(LocalPlayer::AGI);
+ }
+ else if (eventId == "DEX+")
+ {
+ mPlayer->raiseAttribute(LocalPlayer::DEX);
+ }
+ else if (eventId == "VIT+")
+ {
+ mPlayer->raiseAttribute(LocalPlayer::VIT);
+ }
+ else if (eventId == "INT+")
+ {
+ mPlayer->raiseAttribute(LocalPlayer::INT);
+ }
+ else if (eventId == "WIL+")
+ {
+ mPlayer->raiseAttribute(LocalPlayer::WIL);
+ }
+
+ else if (eventId == "STR-")
+ {
+ mPlayer->lowerAttribute(LocalPlayer::STR);
+ }
+ else if (eventId == "AGI-")
+ {
+ mPlayer->lowerAttribute(LocalPlayer::AGI);
+ }
+ else if (eventId == "DEX-")
+ {
+ mPlayer->lowerAttribute(LocalPlayer::DEX);
+ }
+ else if (eventId == "VIT-")
+ {
+ mPlayer->lowerAttribute(LocalPlayer::VIT);
+ }
+ else if (eventId == "INT-")
+ {
+ mPlayer->lowerAttribute(LocalPlayer::INT);
+ }
+ else if (eventId == "WIL-")
+ {
+ mPlayer->lowerAttribute(LocalPlayer::WIL);
+ }
+}
+
+// WARNING: Duplicated method!
+
+void StatusWindow::updateHPBar(ProgressBar *bar, bool showMax)
+{
+ if (showMax)
+ bar->setText(toString(player_node->getHp()) +
+ "/" + toString(player_node->getMaxHp()));
+ else
+ bar->setText(toString(player_node->getHp()));
+
+ // HP Bar coloration
+ if (player_node->getHp() < player_node->getMaxHp() / 3)
+ {
+ bar->setColor(223, 32, 32); // Red
+ }
+ else if (player_node->getHp() < (player_node->getMaxHp() / 3) * 2)
+ {
+ bar->setColor(230, 171, 34); // Orange
+ }
+ else
+ {
+ bar->setColor(0, 171, 34); // Green
+ }
+
+ bar->setProgress((float) player_node->getHp() / (float) player_node->getMaxHp());
+}
diff --git a/src/gui/statuswindow.h b/src/gui/statuswindow.h
new file mode 100644
index 00000000..05bac4e5
--- /dev/null
+++ b/src/gui/statuswindow.h
@@ -0,0 +1,107 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_STATUS_H
+#define _TMW_STATUS_H
+
+#include <iosfwd>
+
+#include <guichan/actionlistener.hpp>
+
+#include "window.h"
+
+#include "../guichanfwd.h"
+
+class LocalPlayer;
+class ProgressBar;
+
+
+/**
+ * The player status dialog.
+ *
+ * \ingroup Interface
+ */
+class StatusWindow : public Window, public gcn::ActionListener
+{
+ public:
+ /**
+ * Constructor.
+ */
+ StatusWindow(LocalPlayer *player);
+
+ /**
+ * Called when receiving actions from widget.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ /**
+ * Draw this window
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Updates this dialog with values from PLAYER_INFO *char_info
+ */
+ void update();
+
+ static void updateHPBar(ProgressBar *bar, bool showMax = false);
+
+ private:
+ LocalPlayer *mPlayer;
+
+ /**
+ * Status Part
+ */
+ gcn::Label *mLvlLabel, *mMoneyLabel, *mHpLabel, *mHpValueLabel;
+ ProgressBar *mHpBar;
+
+ /**
+ * Derived Statistics captions
+ */
+/*
+ gcn::Label *mStatsAttackLabel, *mStatsDefenseLabel;
+ gcn::Label *mStatsMagicAttackLabel, *mStatsMagicDefenseLabel;
+ gcn::Label *mStatsAccuracyLabel, *mStatsEvadeLabel;
+ gcn::Label *mStatsReflexLabel;
+
+ gcn::Label *mStatsAttackPoints, *mStatsDefensePoints;
+ gcn::Label *mStatsMagicAttackPoints, *mStatsMagicDefensePoints;
+ gcn::Label *mStatsAccuracyPoints, *mStatsEvadePoints;
+ gcn::Label *mStatsReflexPoints;
+*/
+ /**
+ * Stats captions.
+ */
+ gcn::Label *mStatsLabel[6];
+ gcn::Label *mStatsDisplayLabel[6];
+ gcn::Label *mCharacterPointsLabel;
+ gcn::Label *mCorrectionPointsLabel;
+
+ /**
+ * Stats buttons.
+ */
+ gcn::Button *mStatsPlus[6];
+ gcn::Button *mStatsMinus[6];
+};
+
+extern StatusWindow *statusWindow;
+
+#endif
diff --git a/src/gui/storagewindow.cpp b/src/gui/storagewindow.cpp
index 8484093a..81212ae8 100644
--- a/src/gui/storagewindow.cpp
+++ b/src/gui/storagewindow.cpp
@@ -42,7 +42,9 @@
#include "../units.h"
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#ifdef EATHENA_SUPPORT
+#include "../net/ea/protocol.h"
+#endif
#include "../resources/iteminfo.h"
@@ -66,7 +68,7 @@ StorageWindow::StorageWindow(Network *network, int invSize):
mStoreButton = new Button(_("Store"), "store", this);
mRetrieveButton = new Button(_("Retrieve"), "retrieve", this);
- mItems = new ItemContainer(player_node->getStorage(), 1);
+ mItems = new ItemContainer(player_node->getStorage(), 10, 5, 1);
mItems->addSelectionListener(this);
mInvenScroll = new ScrollArea(mItems);
diff --git a/src/gui/textdialog.cpp b/src/gui/textdialog.cpp
new file mode 100644
index 00000000..05e43906
--- /dev/null
+++ b/src/gui/textdialog.cpp
@@ -0,0 +1,91 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "textdialog.h"
+
+#include <guichan/widgets/label.hpp>
+#include <guichan/widgets/textfield.hpp>
+
+#include "button.h"
+
+TextDialog::TextDialog(const std::string &title, const std::string &msg,
+ Window *parent):
+ Window(title, true, parent),
+ textField(new TextField(""))
+{
+ gcn::Label *textLabel = new gcn::Label(msg);
+ okButton = new Button("OK", "OK", this);
+ gcn::Button *cancelButton = new Button("Cancel", "CANCEL", this);
+
+ int w = textLabel->getWidth() + 20;
+ int inWidth = okButton->getWidth() + cancelButton->getWidth() + 5;
+ int h = textLabel->getHeight() + 25 + okButton->getHeight() + textField->getHeight();
+
+ if (w < inWidth + 10) {
+ w = inWidth + 10;
+ }
+
+ setContentSize(w, h);
+ textLabel->setPosition(10, 10);
+ textField->setWidth(85);
+ textField->setPosition(10,20 + textLabel->getHeight());
+ okButton->setPosition((w - inWidth) / 2,
+ h - 5 - cancelButton->getHeight());
+ cancelButton->setPosition(okButton->getX() + okButton->getWidth() + 5,
+ h - 5 - cancelButton->getHeight());
+
+ add(textLabel);
+ add(textField);
+ add(okButton);
+ add(cancelButton);
+
+ if (getParent()) {
+ setLocationRelativeTo(getParent());
+ getParent()->moveToTop(this);
+ }
+ setVisible(true);
+ textField->requestFocus();
+}
+
+void TextDialog::action(const gcn::ActionEvent &event)
+{
+ // Proxy button events to our listeners
+ ActionListenerIterator i;
+ for (i = mActionListeners.begin(); i != mActionListeners.end(); ++i)
+ {
+ (*i)->action(event);
+ }
+
+ if(event.getId() == "CANCEL" || event.getId() == "OK")
+ {
+ scheduleDelete();
+ }
+}
+
+const std::string& TextDialog::getText() const
+{
+ return textField->getText();
+}
+
+void TextDialog::setOKButtonActionId(const std::string &name)
+{
+ okButton->setActionEventId(name);
+}
diff --git a/src/gui/textdialog.h b/src/gui/textdialog.h
new file mode 100644
index 00000000..8b4e2cc3
--- /dev/null
+++ b/src/gui/textdialog.h
@@ -0,0 +1,66 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_GUI_GUILD_DIALOG_H
+#define _TMW_GUI_GUILD_DIALOG_H
+
+#include <guichan/actionlistener.hpp>
+#include "textfield.h"
+
+#include "window.h"
+
+
+/**
+* An option dialog.
+ *
+ * \ingroup GUI
+ */
+class TextDialog : public Window, public gcn::ActionListener {
+public:
+ /**
+ * Constructor.
+ *
+ * @see Window::Window
+ */
+ TextDialog(const std::string &title, const std::string &msg,
+ Window *parent = NULL);
+
+ /**
+ * Called when receiving actions from the widgets.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ /**
+ * Get the text in the textfield
+ */
+ const std::string& getText() const;
+
+ /**
+ * Set the OK button action id
+ */
+ void setOKButtonActionId(const std::string &name);
+
+private:
+ TextField *textField;
+ gcn::Button *okButton;
+};
+
+#endif
diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp
index d7554de8..5be71a6f 100644
--- a/src/gui/trade.cpp
+++ b/src/gui/trade.cpp
@@ -40,23 +40,37 @@
#include "../localplayer.h"
#include "../units.h"
+#ifdef TMWSERV_SUPPORT
+#include "../net/tmwserv/gameserver/player.h"
+#else
#include "../net/messageout.h"
-#include "../net/protocol.h"
+#include "../net/ea/protocol.h"
+#endif
#include "../utils/gettext.h"
-#include "../utils/strprintf.h"
#include "../utils/stringutils.h"
+#include "../utils/strprintf.h"
+#ifdef TMWSERV_SUPPORT
+TradeWindow::TradeWindow():
+#else
TradeWindow::TradeWindow(Network *network):
- Window("Trade"),
+#endif
+ Window(_("Trade: You")),
+#ifdef EATHENA_SUPPORT
mNetwork(network),
mMyInventory(new Inventory(INVENTORY_SIZE, 2)),
mPartnerInventory(new Inventory(INVENTORY_SIZE, 2))
+#else
+ mMyInventory(new Inventory(INVENTORY_SIZE)),
+ mPartnerInventory(new Inventory(INVENTORY_SIZE)),
+ mStatus(PREPARING)
+#endif
{
- setWindowName(_("Trade"));
- setDefaultSize(342, 209, ImageRect::CENTER);
+ setWindowName("Trade");
setResizable(true);
setCloseButton(true);
+ setDefaultSize(342, 209, ImageRect::CENTER);
setMinWidth(342);
setMinHeight(209);
@@ -65,25 +79,40 @@ TradeWindow::TradeWindow(Network *network):
getFont()->getWidth(_("Trade")) ?
_("OK") : _("Trade");
- mAddButton = new Button(_("Add"), "add", this);
+ Button *mAddButton = new Button(_("Add"), "add", this);
+#ifdef EATHENA_SUPPORT
mOkButton = new Button(longestName, "ok", this);
-
- mMyItemContainer = new ItemContainer(mMyInventory.get(), 2);
- mMyItemContainer->setWidth(160);
+#endif
+ Button *mCancelButton = new Button(_("Cancel"), "cancel", this);
+ mTradeButton = new Button(_("Propose trade"), "trade", this);
+ mTradeButton->setWidth(8 + std::max(
+ mTradeButton->getFont()->getWidth(_("Propose trade")),
+ mTradeButton->getFont()->getWidth(_("Confirm trade"))));
+
+#ifdef TMWSERV_SUPPORT
+ mMyItemContainer = new ItemContainer(mMyInventory.get(), 4, 3, 0);
+#else
+ mMyItemContainer = new ItemContainer(mMyInventory.get(), 4, 3, 2);
+#endif
mMyItemContainer->addSelectionListener(this);
- mMyScroll = new ScrollArea(mMyItemContainer);
+ ScrollArea *mMyScroll = new ScrollArea(mMyItemContainer);
- mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 2);
- mPartnerItemContainer->setWidth(160);
+#ifdef TMWSERV_SUPPORT
+ mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 4, 3, 0);
+#else
+ mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 4, 3, 2);
+#endif
mPartnerItemContainer->addSelectionListener(this);
- mPartnerScroll = new ScrollArea(mPartnerItemContainer);
+ ScrollArea *mPartnerScroll = new ScrollArea(mPartnerItemContainer);
mMoneyLabel = new Label(strprintf(_("You get %s."), ""));
- mMoneyLabel2 = new Label(_("You give:"));
+ gcn::Label *mMoneyLabel2 = new Label(_("You give:"));
+
mMoneyField = new TextField;
- mMoneyField->setWidth(50);
+ mMoneyField->setWidth(40);
+ Button *mMoneyChange = new Button(_("Change"), "money", this);
place(1, 0, mMoneyLabel);
place(0, 1, mMyScroll).setPadding(3);
@@ -92,9 +121,15 @@ TradeWindow::TradeWindow(Network *network):
place = getPlacer(0, 0);
place(0, 0, mMoneyLabel2);
place(1, 0, mMoneyField);
+ place(2, 0, mMoneyChange).setHAlign(LayoutCell::LEFT);
place = getPlacer(0, 2);
- place(6, 0, mAddButton);
- place(7, 0, mOkButton);
+ place(0, 0, mAddButton);
+#ifdef EATHENA_SUPPORT
+ place(1, 0, mOkButton);
+#else
+ place(2, 0, mTradeButton);
+ place(3, 0, mCancelButton);
+#endif
Layout &layout = getLayout();
layout.extend(0, 2, 2, 1);
layout.setRowHeight(1, Layout::AUTO_SET);
@@ -102,7 +137,9 @@ TradeWindow::TradeWindow(Network *network):
layout.setColWidth(0, Layout::AUTO_SET);
layout.setColWidth(1, Layout::AUTO_SET);
+#ifdef EATHENA_SUPPORT
mOkButton->setCaption(_("OK"));
+#endif
loadWindowState();
}
@@ -111,35 +148,37 @@ TradeWindow::~TradeWindow()
{
}
-void TradeWindow::addMoney(int amount)
+void TradeWindow::setMoney(int amount)
{
mMoneyLabel->setCaption(strprintf(_("You get %s."),
Units::formatCurrency(amount).c_str()));
mMoneyLabel->adjustSize();
+#ifdef TMWSERV_SUPPORT
+ setStatus(PREPARING);
+#endif
+}
+
+#ifdef TMWSERV_SUPPORT
+void TradeWindow::addItem(int id, bool own, int quantity)
+{
+ (own ? mMyInventory : mPartnerInventory)->addItem(id, quantity);
+ setStatus(PREPARING);
}
+#endif
+#ifdef EATHENA_SUPPORT
void TradeWindow::addItem(int id, bool own, int quantity, bool equipment)
{
if (own)
{
- mMyItemContainer->setWidth(mMyScroll->getWidth());
mMyInventory->addItem(id, quantity, equipment);
}
else
{
- mPartnerItemContainer->setWidth(mPartnerScroll->getWidth());
mPartnerInventory->addItem(id, quantity, equipment);
}
}
-void TradeWindow::removeItem(int id, bool own)
-{
- if (own)
- mMyInventory->removeItem(id);
- else
- mPartnerInventory->removeItem(id);
-}
-
void TradeWindow::changeQuantity(int index, bool own, int quantity)
{
if (own)
@@ -155,21 +194,36 @@ void TradeWindow::increaseQuantity(int index, bool own, int quantity)
else
mPartnerInventory->getItem(index)->increaseQuantity(quantity);
}
+#endif
void TradeWindow::reset()
{
mMyInventory->clear();
mPartnerInventory->clear();
+#ifdef EATHENA_SUPPORT
mOkButton->setCaption(_("OK"));
mOkButton->setActionEventId("ok");
mOkButton->setEnabled(true);
mOkOther = false;
mOkMe = false;
+#endif
mMoneyLabel->setCaption(strprintf(_("You get %s."), ""));
mMoneyField->setEnabled(true);
mMoneyField->setText("");
+#ifdef TMWSERV_SUPPORT
+ setStatus(PREPARING);
+#endif
}
+#ifdef TMWSERV_SUPPORT
+
+void TradeWindow::receivedOk()
+{
+ setStatus(ACCEPTING);
+}
+
+#else
+
void TradeWindow::receivedOk(bool own)
{
if (own)
@@ -192,8 +246,15 @@ void TradeWindow::receivedOk(bool own)
}
}
+#endif
+
void TradeWindow::tradeItem(Item *item, int quantity)
{
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::tradeItem(item->getInvIndex(), quantity);
+ addItem(item->getId(), true, quantity);
+ item->increaseQuantity(-quantity);
+#else
// TODO: Our newer version of eAthena doesn't register this following
// function. Detect the actual server version, and re-enable this
// for that version only.
@@ -202,6 +263,7 @@ void TradeWindow::tradeItem(Item *item, int quantity)
outMsg.writeInt16(CMSG_TRADE_ITEM_ADD_REQUEST);
outMsg.writeInt16(item->getInvIndex());
outMsg.writeInt32(quantity);
+#endif
}
void TradeWindow::valueChanged(const gcn::SelectionEvent &event)
@@ -218,6 +280,18 @@ void TradeWindow::valueChanged(const gcn::SelectionEvent &event)
mMyItemContainer->selectNone();
}
+#ifdef TMWSERV_SUPPORT
+void TradeWindow::setStatus(Status s)
+{
+ if (s == mStatus) return;
+ mStatus = s;
+
+ mTradeButton->setCaption
+ (s == PREPARING ? _("Propose trade") : _("Confirm trade"));
+ mTradeButton->setEnabled(s != PROPOSING);
+}
+#endif
+
void TradeWindow::action(const gcn::ActionEvent &event)
{
Item *item = inventoryWindow->getSelectedItem();
@@ -249,12 +323,24 @@ void TradeWindow::action(const gcn::ActionEvent &event)
// Choose amount of items to trade
new ItemAmountWindow(AMOUNT_TRADE_ADD, this, item);
}
+
+#ifdef TMWSERV_SUPPORT
+ setStatus(PREPARING);
+#endif
}
else if (event.getId() == "cancel")
{
+ setVisible(false);
+ reset();
+ player_node->setTrading(false);
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::acceptTrade(false);
+#else
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_TRADE_CANCEL_REQUEST);
+#endif
}
+#ifdef EATHENA_SUPPORT
else if (event.getId() == "ok")
{
std::stringstream tempMoney(mMoneyField->getText());
@@ -276,15 +362,34 @@ void TradeWindow::action(const gcn::ActionEvent &event)
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_TRADE_ADD_COMPLETE);
}
+#endif
else if (event.getId() == "trade")
{
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::acceptTrade(true);
+ setStatus(PROPOSING);
+#else
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_TRADE_OK);
+#endif
+ }
+#ifdef TMWSERV_SUPPORT
+ else if (event.getId() == "money")
+ {
+ int v = atoi(mMoneyField->getText().c_str());
+ Net::GameServer::Player::tradeMoney(v);
+ mMoneyField->setText(strprintf("%d", v));
+ setStatus(PREPARING);
}
+#endif
}
void TradeWindow::close()
{
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::acceptTrade(false);
+#else
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_TRADE_CANCEL_REQUEST);
+#endif
}
diff --git a/src/gui/trade.h b/src/gui/trade.h
index 67138c24..4c215ba6 100644
--- a/src/gui/trade.h
+++ b/src/gui/trade.h
@@ -34,7 +34,9 @@
class Inventory;
class Item;
class ItemContainer;
+#ifdef EATHENA_SUPPORT
class Network;
+#endif
class ScrollArea;
/**
@@ -48,7 +50,11 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener
/**
* Constructor.
*/
+#ifdef TMWSERV_SUPPORT
+ TradeWindow();
+#else
TradeWindow(Network *network);
+#endif
/**
* Destructor.
@@ -56,24 +62,25 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener
~TradeWindow();
/**
- * Add money to the trade window.
+ * Displays expected money in the trade window.
*/
- void addMoney(int quantity);
+ void setMoney(int quantity);
/**
* Add an item to the trade window.
*/
- void addItem(int id, bool own, int quantity, bool equipment);
+ void addItem(int id, bool own, int quantity);
/**
- * Remove a item from the trade window.
+ * Reset both item containers
*/
- void removeItem(int id, bool own);
+ void reset();
+#ifdef EATHENA_SUPPORT
/**
- * Reset both item containers
+ * Add an item to the trade window.
*/
- void reset();
+ void addItem(int id, bool own, int quantity, bool equipment);
/**
* Change quantity of an item.
@@ -84,11 +91,16 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener
* Increase quantity of an item.
*/
void increaseQuantity(int index, bool own, int quantity);
+#endif
/**
* Player received ok message from server
*/
+#ifdef TMWSERV_SUPPORT
+ void receivedOk();
+#else
void receivedOk(bool own);
+#endif
/**
* Send trade packet.
@@ -113,7 +125,23 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener
void close();
private:
+#ifdef TMWSERV_SUPPORT
+ enum Status
+ {
+ PREPARING, /**< Players are adding items. */
+ PROPOSING, /**< Local player is proposing a trade. */
+ ACCEPTING /**< Distant player is proposing a trade. */
+ };
+
+ /**
+ * Sets the current status of the trade.
+ */
+ void setStatus(Status);
+#endif
+
+#ifdef EATHENA_SUPPORT
Network *mNetwork;
+#endif
typedef const std::auto_ptr<Inventory> InventoryPtr;
InventoryPtr mMyInventory;
@@ -123,11 +151,18 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener
ItemContainer *mPartnerItemContainer;
gcn::Label *mMoneyLabel;
- gcn::Label *mMoneyLabel2;
- gcn::Button *mAddButton, *mOkButton;
- ScrollArea *mMyScroll, *mPartnerScroll;
+ gcn::Button *mTradeButton;
+#ifdef EATHENA_SUPPORT
+ gcn::Button *mAddButton;
+ gcn::Button *mOkButton;
+#endif
gcn::TextField *mMoneyField;
+
+#ifdef TMWSERV_SUPPORT
+ Status mStatus;
+#else
bool mOkOther, mOkMe;
+#endif
};
extern TradeWindow *tradeWindow;
diff --git a/src/gui/unregisterdialog.cpp b/src/gui/unregisterdialog.cpp
new file mode 100644
index 00000000..1e09ca23
--- /dev/null
+++ b/src/gui/unregisterdialog.cpp
@@ -0,0 +1,141 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "unregisterdialog.h"
+
+#include <string>
+#include <sstream>
+
+#include <guichan/widgets/label.hpp>
+
+#include "../main.h"
+#include "../log.h"
+#include "../logindata.h"
+
+#include "button.h"
+#include "checkbox.h"
+#include "register.h"
+#include "passwordfield.h"
+#include "textfield.h"
+#include "ok_dialog.h"
+
+#include "../utils/gettext.h"
+#include "../utils/strprintf.h"
+
+UnRegisterDialog::UnRegisterDialog(Window *parent, LoginData *loginData):
+ Window("Unregister", true, parent),
+ mWrongDataNoticeListener(new WrongDataNoticeListener()),
+ mLoginData(loginData)
+{
+ gcn::Label *userLabel = new gcn::Label(strprintf(_("Name: %s"), mLoginData->username.c_str()));
+ gcn::Label *passwordLabel = new gcn::Label(_("Password:"));
+ mPasswordField = new PasswordField(mLoginData->password);
+ mUnRegisterButton = new Button(_("Unregister"), "unregister", this);
+ mCancelButton = new Button(_("Cancel"), "cancel", this);
+
+ const int width = 210;
+ const int height = 80;
+ setContentSize(width, height);
+
+ userLabel->setPosition(5, 5);
+ userLabel->setWidth(width - 5);
+ mPasswordField->setPosition(
+ 68, userLabel->getY() + userLabel->getHeight() + 7);
+ mPasswordField->setWidth(130);
+
+ passwordLabel->setPosition(5, mPasswordField->getY() + 1);
+
+ mCancelButton->setPosition(
+ width - 5 - mCancelButton->getWidth(),
+ height - 5 - mCancelButton->getHeight());
+ mUnRegisterButton->setPosition(
+ mCancelButton->getX() - 5 - mUnRegisterButton->getWidth(),
+ mCancelButton->getY());
+
+ add(userLabel);
+ add(passwordLabel);
+ add(mPasswordField);
+ add(mUnRegisterButton);
+ add(mCancelButton);
+
+ setLocationRelativeTo(getParent());
+ setVisible(true);
+ mPasswordField->requestFocus();
+ mPasswordField->setActionEventId("cancel");
+}
+
+UnRegisterDialog::~UnRegisterDialog()
+{
+ delete mWrongDataNoticeListener;
+}
+
+void
+UnRegisterDialog::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "cancel")
+ {
+ scheduleDelete();
+ }
+ else if (event.getId() == "unregister")
+ {
+ const std::string username = mLoginData->username.c_str();
+ const std::string password = mPasswordField->getText();
+ logger->log("UnregisterDialog::unregistered, Username is %s",
+ username.c_str());
+
+ std::stringstream errorMsg;
+ bool error = false;
+
+ // Check password
+ if (password.length() < LEN_MIN_PASSWORD)
+ {
+ // Pass too short
+ errorMsg << "The password needs to be at least "
+ << LEN_MIN_PASSWORD
+ << " characters long.";
+ error = true;
+ }
+ else if (password.length() > LEN_MAX_PASSWORD - 1 )
+ {
+ // Pass too long
+ errorMsg << "The password needs to be less than "
+ << LEN_MAX_PASSWORD
+ << " characters long.";
+ error = true;
+ }
+
+ if (error)
+ {
+ mWrongDataNoticeListener->setTarget(this->mPasswordField);
+
+ OkDialog *dlg = new OkDialog("Error", errorMsg.str());
+ dlg->addActionListener(mWrongDataNoticeListener);
+ }
+ else
+ {
+ // No errors detected, unregister the new user.
+ mUnRegisterButton->setEnabled(false);
+ mLoginData->password = password;
+ state = STATE_UNREGISTER_ATTEMPT;
+ scheduleDelete();
+ }
+ }
+}
diff --git a/src/gui/unregisterdialog.h b/src/gui/unregisterdialog.h
new file mode 100644
index 00000000..1e3cc88f
--- /dev/null
+++ b/src/gui/unregisterdialog.h
@@ -0,0 +1,70 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef UNREGISTERDIALOG_H
+#define UNREGISTERDIALOG_H
+
+#include <iosfwd>
+#include <guichan/actionlistener.hpp>
+
+#include "window.h"
+#include "../guichanfwd.h"
+
+class LoginData;
+class OkDialog;
+class WrongDataNoticeListener;
+
+/**
+ * The Unregister dialog.
+ *
+ * \ingroup Interface
+ */
+class UnRegisterDialog : public Window, public gcn::ActionListener {
+ public:
+ /**
+ * Constructor
+ *
+ * @see Window::Window
+ */
+ UnRegisterDialog(Window *parent,LoginData *loginData);
+
+ /**
+ * Destructor
+ */
+ ~UnRegisterDialog();
+
+ /**
+ * Called when receiving actions from the widgets.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ private:
+ gcn::TextField *mPasswordField;
+
+ gcn::Button *mUnRegisterButton;
+ gcn::Button *mCancelButton;
+
+ WrongDataNoticeListener *mWrongDataNoticeListener;
+
+ LoginData *mLoginData;
+};
+
+#endif
diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp
index 295b752e..8c903c28 100644
--- a/src/gui/updatewindow.cpp
+++ b/src/gui/updatewindow.cpp
@@ -183,7 +183,7 @@ void UpdaterWindow::action(const gcn::ActionEvent &event)
}
else if (event.getId() == "play")
{
- state = LOADDATA_STATE;
+ state = STATE_LOADDATA;
}
}
@@ -230,7 +230,7 @@ int UpdaterWindow::updateProgress(void *ptr,
uw->mCurrentFile + " (" + toString((int) (progress * 100)) + "%)");
uw->setProgress(progress);
- if (state != UPDATE_STATE || uw->mDownloadStatus == UPDATE_ERROR)
+ if (state != STATE_UPDATE || uw->mDownloadStatus == UPDATE_ERROR)
{
// If the action was canceled return an error code to stop the mThread
return -1;
diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h
index 4ada3c3a..ace398b4 100644
--- a/src/gui/updatewindow.h
+++ b/src/gui/updatewindow.h
@@ -31,6 +31,8 @@
#include "../utils/mutex.h"
+#include "../utils/mutex.h"
+
class BrowserBox;
class Button;
class ProgressBar;
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index 7f97d98c..c840e456 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -26,6 +26,7 @@
#include "../beingmanager.h"
#include "../configuration.h"
#include "../flooritemmanager.h"
+#include "../game.h"
#include "../graphics.h"
#include "../keyboardconfig.h"
#include "../localplayer.h"
@@ -50,8 +51,13 @@ Viewport::Viewport():
mTileViewX(0),
mTileViewY(0),
mShowDebugPath(false),
+ mVisibleNames(false),
mPlayerFollowMouse(false),
+#ifdef TMWSERV_SUPPORT
+ mLocalWalkTime(-1)
+#else
mWalkTime(0)
+#endif
{
setOpaque(false);
addMouseListener(this);
@@ -60,9 +66,11 @@ Viewport::Viewport():
mScrollRadius = (int) config.getValue("ScrollRadius", 0);
mScrollCenterOffsetX = (int) config.getValue("ScrollCenterOffsetX", 0);
mScrollCenterOffsetY = (int) config.getValue("ScrollCenterOffsetY", 0);
+ mVisibleNames = config.getValue("visiblenames", 1);
config.addListener("ScrollLaziness", this);
config.addListener("ScrollRadius", this);
+ config.addListener("visiblenames", this);
mPopupMenu = new PopupMenu;
}
@@ -70,6 +78,8 @@ Viewport::Viewport():
Viewport::~Viewport()
{
delete mPopupMenu;
+
+ config.removeListener("visiblenames", this);
}
void Viewport::setMap(Map *map)
@@ -99,6 +109,14 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
}
// Calculate viewpoint
+#ifdef TMWSERV_SUPPORT
+ int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 2;
+ int midTileY = (graphics->getHeight() + mScrollCenterOffsetX) / 2;
+
+ const Vector &playerPos = player_node->getPosition();
+ const int player_x = (int) playerPos.x - midTileX;
+ const int player_y = (int) playerPos.y - midTileY;
+#else
int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 32 / 2;
int midTileY = (graphics->getHeight() + mScrollCenterOffsetY) / 32 / 2;
@@ -106,6 +124,7 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
player_node->getXOffset();
int player_y = (player_node->mY - midTileY) * 32 +
player_node->getYOffset();
+#endif
if (mScrollLaziness < 1)
mScrollLaziness = 1; // Avoids division by zero
@@ -148,8 +167,10 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
};
// Don't move camera so that the end of the map is on screen
- int viewXmax = (mMap->getWidth() * 32) - graphics->getWidth();
- int viewYmax = (mMap->getHeight() * 32) - graphics->getHeight();
+ const int viewXmax =
+ mMap->getWidth() * mMap->getTileWidth() - graphics->getWidth();
+ const int viewYmax =
+ mMap->getHeight() * mMap->getTileHeight() - graphics->getHeight();
if (mMap)
{
if (mPixelViewX < 0)
@@ -170,30 +191,13 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
{
mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY);
- // Find a path from the player to the mouse, and draw it. This is for
- // debug purposes.
- if (mShowDebugPath)
- {
- // Get the current mouse position
- SDL_GetMouseState(&mMouseX, &mMouseY);
-
- int mouseTileX = mMouseX / 32 + mTileViewX;
- int mouseTileY = mMouseY / 32 + mTileViewY;
-
- Path debugPath = mMap->findPath(player_node->mX, player_node->mY,
- mouseTileX, mouseTileY);
-
- graphics->setColor(gcn::Color(255, 0, 0));
- for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++)
- {
- int squareX = i->x * 32 - (int) mPixelViewX + 12;
- int squareY = i->y * 32 - (int) mPixelViewY + 12;
-
- graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
- graphics->drawText(toString(mMap->getMetaTile(i->x, i->y)->Gcost),
- squareX + 4, squareY + 12,
- gcn::Graphics::CENTER);
- }
+ if (mShowDebugPath) {
+ mMap->drawCollision(graphics,
+ (int) mPixelViewX,
+ (int) mPixelViewY);
+#if 0
+ drawDebugPath(graphics);
+#endif
}
}
@@ -234,11 +238,51 @@ void Viewport::logic()
Uint8 button = SDL_GetMouseState(&mMouseX, &mMouseY);
if (mPlayerFollowMouse && button & SDL_BUTTON(1) &&
+#ifdef TMWSERV_SUPPORT
+ get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
+ {
+ mLocalWalkTime = tick_time;
+ player_node->setDestination(mMouseX + (int) mPixelViewX,
+ mMouseY + (int) mPixelViewY);
+#else
mWalkTime != player_node->mWalkTime)
{
player_node->setDestination(mMouseX / 32 + mTileViewX,
mMouseY / 32 + mTileViewY);
mWalkTime = player_node->mWalkTime;
+#endif
+ }
+}
+
+void Viewport::drawDebugPath(Graphics *graphics)
+{
+ // Get the current mouse position
+ SDL_GetMouseState(&mMouseX, &mMouseY);
+
+ const int mouseTileX = (mMouseX + (int) mPixelViewX) / 32;
+ const int mouseTileY = (mMouseY + (int) mPixelViewY) / 32;
+ const Vector &playerPos = player_node->getPosition();
+
+ Path debugPath = mMap->findPath(
+ (int) playerPos.x / 32,
+ (int) playerPos.y / 32,
+ mouseTileX, mouseTileY, 0xFF);
+
+ drawPath(graphics, debugPath);
+}
+
+void Viewport::drawPath(Graphics *graphics, const Path &path)
+{
+ graphics->setColor(gcn::Color(255, 0, 0));
+ for (Path::const_iterator i = path.begin(); i != path.end(); ++i)
+ {
+ int squareX = i->x * 32 - (int) mPixelViewX + 12;
+ int squareY = i->y * 32 - (int) mPixelViewY + 12;
+
+ graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
+ graphics->drawText(
+ toString(mMap->getMetaTile(i->x, i->y)->Gcost),
+ squareX + 4, squareY + 12, gcn::Graphics::CENTER);
}
}
@@ -254,10 +298,10 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
mPlayerFollowMouse = false;
- const int tilex = event.getX() / 32 + mTileViewX;
- const int tiley = event.getY() / 32 + mTileViewY;
- const int x = (int)((float) event.getX() + mPixelViewX);
- const int y = (int)((float) event.getY() + mPixelViewY);
+ const int pixelx = event.getX() + (int) mPixelViewX;
+ const int pixely = event.getY() + (int) mPixelViewY;
+ const int tilex = pixelx / mMap->getTileWidth();
+ const int tiley = pixely / mMap->getTileHeight();
// Right click might open a popup
if (event.getButton() == gcn::MouseEvent::RIGHT)
@@ -265,7 +309,7 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
Being *being;
FloorItem *floorItem;
- if ((being = beingManager->findBeingByPixel(x, y)) &&
+ if ((being = beingManager->findBeingByPixel(pixelx, pixely)) &&
being != player_node)
{
mPopupMenu->showPopup(event.getX(), event.getY(), being);
@@ -289,12 +333,13 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
// Left click can cause different actions
if (event.getButton() == gcn::MouseEvent::LEFT)
{
- Being *being;
FloorItem *item;
+#ifdef EATHENA_SUPPORT
+ Being *being;
// Interact with some being
// if ((being = beingManager->findBeing(tilex, tiley)))
- if ((being = beingManager->findBeingByPixel(x, y)))
+ if ((being = beingManager->findBeingByPixel(pixelx, pixely)))
{
switch (being->getType())
{
@@ -325,23 +370,38 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
}
}
// Pick up some item
- else if ((item = floorItemManager->findByCoordinates(tilex, tiley)))
+ else
+#endif
+ if ((item = floorItemManager->findByCoordinates(tilex, tiley)))
{
player_node->pickUp(item);
}
// Just walk around
else
{
+#ifdef TMWSERV_SUPPORT
+ // FIXME: REALLY UGLY!
+ Uint8 *keys = SDL_GetKeyState(NULL);
+ if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]) &&
+ get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
+ {
+ mLocalWalkTime = tick_time;
+ player_node->setDestination(event.getX() + (int) mPixelViewX,
+ event.getY() + (int) mPixelViewY);
+ }
+#else
player_node->stopAttack();
player_node->setDestination(tilex, tiley);
+#endif
mPlayerFollowMouse = true;
}
}
else if (event.getButton() == gcn::MouseEvent::MIDDLE)
{
// Find the being nearest to the clicked position
- Being *target = beingManager->findNearestLivingBeing(tilex, tiley, 20,
- Being::MONSTER);
+ Being *target = beingManager->findNearestLivingBeing(
+ tilex, tiley,
+ 20, Being::MONSTER);
if (target)
player_node->setTarget(target);
@@ -353,12 +413,22 @@ void Viewport::mouseDragged(gcn::MouseEvent &event)
if (!mMap || !player_node)
return;
+#ifdef TMWSERV_SUPPORT
+ if (mPlayerFollowMouse
+ && get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
+ {
+ mLocalWalkTime = tick_time;
+ player_node->setDestination(event.getX() + (int) mPixelViewX,
+ event.getY() + (int) mPixelViewY);
+ }
+#else
if (mPlayerFollowMouse && mWalkTime == player_node->mWalkTime)
{
int destX = event.getX() / 32 + mTileViewX;
int destY = event.getY() / 32 + mTileViewY;
player_node->setDestination(destX, destY);
}
+#endif
}
void Viewport::mouseReleased(gcn::MouseEvent &event)
@@ -375,4 +445,20 @@ void Viewport::optionChanged(const std::string &name)
{
mScrollLaziness = (int) config.getValue("ScrollLaziness", 32);
mScrollRadius = (int) config.getValue("ScrollRadius", 32);
+
+ if (name == "visiblenames") {
+ mVisibleNames = config.getValue("visiblenames", 1);
+ }
+}
+
+void Viewport::mouseMoved(gcn::MouseEvent &event)
+{
+ // Check if we are on the map
+ if (!mMap || !player_node)
+ return;
+
+ const int tilex = (event.getX() + (int) mPixelViewX) / 32;
+ const int tiley = (event.getY() + (int) mPixelViewY) / 32;
+
+ mSelectedBeing = beingManager->findBeing(tilex, tiley);
}
diff --git a/src/gui/viewport.h b/src/gui/viewport.h
index 6e7a2370..c051e5a2 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -29,6 +29,7 @@
#include "../configlistener.h"
#include "../position.h"
+class Being;
class FloorItem;
class Graphics;
class ImageSet;
@@ -36,6 +37,9 @@ class Item;
class Map;
class PopupMenu;
+/** Delay between two mouse calls when dragging mouse and move the player */
+const int walkingMouseDelay = 500;
+
/**
* The viewport on the map. Displays the current map and handles mouse input
* and the popup menu.
@@ -94,6 +98,11 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
void mouseReleased(gcn::MouseEvent &event);
/**
+ * Handles mouse move on map.
+ */
+ void mouseMoved(gcn::MouseEvent &event);
+
+ /**
* Shows a popup for an item.
* TODO Find some way to get rid of Item here
*/
@@ -130,6 +139,17 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
void scrollBy(float x, float y) { mPixelViewX += x; mPixelViewY += y; }
private:
+ /**
+ * Finds a path from the player to the mouse, and draws it. This is for
+ * debug purposes.
+ */
+ void drawDebugPath(Graphics *graphics);
+
+ /**
+ * Draws the given path.
+ */
+ void drawPath(Graphics *graphics, const Path &path);
+
Map *mMap; /**< The current map. */
int mScrollRadius;
@@ -143,11 +163,17 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
int mTileViewX; /**< Current viewpoint in tiles. */
int mTileViewY; /**< Current viewpoint in tiles. */
bool mShowDebugPath; /**< Show a path from player to pointer. */
+ bool mVisibleNames; /**< Show target names. */
bool mPlayerFollowMouse;
+#ifdef TMWSERV_SUPPORT
+ int mLocalWalkTime; /**< Timestamp before the next walk can be sent. */
+#else
int mWalkTime;
+#endif
PopupMenu *mPopupMenu; /**< Popup menu. */
+ Being *mSelectedBeing; /**< Current selected being. */
};
extern Viewport *viewport; /**< The viewport */
diff --git a/src/gui/widgets/avatar.cpp b/src/gui/widgets/avatar.cpp
new file mode 100644
index 00000000..9fcd00a6
--- /dev/null
+++ b/src/gui/widgets/avatar.cpp
@@ -0,0 +1,53 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "avatar.h"
+
+#include "../icon.h"
+
+#include "../../resources/image.h"
+#include "../../resources/resourcemanager.h"
+
+Avatar::Avatar(const std::string &name):
+ mName(name)
+{
+ setSize(110, 12);
+ mLabel = new gcn::Label(name);
+ mLabel->setSize(85, 12);
+ mLabel->setPosition(25, 0);
+ ResourceManager *resman = ResourceManager::getInstance();
+ mStatusOffline = resman->getImage("graphics/gui/circle-gray.png");
+ mStatusOnline = resman->getImage("graphics/gui/circle-green.png");
+ mStatus = new Icon(mStatusOffline);
+ mStatus->setSize(25, 12);
+ mStatus->setPosition(0, 0);
+}
+
+void Avatar::setOnline(bool online)
+{
+ mStatus->setImage(online ? mStatusOnline : mStatusOffline);
+}
+
+void Avatar::draw(gcn::Graphics *g)
+{
+ mLabel->draw(g);
+ mStatus->draw(g);
+}
diff --git a/src/gui/widgets/avatar.h b/src/gui/widgets/avatar.h
new file mode 100644
index 00000000..c6151020
--- /dev/null
+++ b/src/gui/widgets/avatar.h
@@ -0,0 +1,59 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_AVATAR_H
+#define _TMW_AVATAR_H
+
+#include <string>
+#include <guichan/widget.hpp>
+#include <guichan/widgets/label.hpp>
+
+class Image;
+class Icon;
+
+class Avatar : public gcn::Widget
+{
+public:
+ /**
+ * Constructor.
+ * @param name Character name
+ */
+ Avatar(const std::string &name);
+
+ /**
+ * Set the avatar online status.
+ */
+ void setOnline(bool online);
+
+ /**
+ * Draws the avatar.
+ */
+ void draw(gcn::Graphics *g);
+
+private:
+ std::string mName;
+ Icon *mStatus;
+ Image *mStatusOnline;
+ Image *mStatusOffline;
+ gcn::Label *mLabel;
+};
+
+#endif