summaryrefslogtreecommitdiff
path: root/src/gui/skilldialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/skilldialog.cpp')
-rw-r--r--src/gui/skilldialog.cpp523
1 files changed, 523 insertions, 0 deletions
diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp
new file mode 100644
index 000000000..04222d6f5
--- /dev/null
+++ b/src/gui/skilldialog.cpp
@@ -0,0 +1,523 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gui/skilldialog.h"
+
+#include "log.h"
+#include "playerinfo.h"
+#include "configuration.h"
+
+#include "gui/setup.h"
+#include "gui/theme.h"
+
+#include "gui/widgets/button.h"
+#include "gui/widgets/container.h"
+#include "gui/widgets/label.h"
+#include "gui/widgets/layouthelper.h"
+#include "gui/widgets/listbox.h"
+#include "gui/widgets/progressbar.h"
+#include "gui/widgets/scrollarea.h"
+#include "gui/widgets/tab.h"
+#include "gui/widgets/tabbedarea.h"
+#include "gui/widgets/windowcontainer.h"
+
+#include "net/net.h"
+#include "net/playerhandler.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+#include "utils/dtor.h"
+#include "utils/gettext.h"
+#include "utils/stringutils.h"
+#include "utils/xml.h"
+
+#include <guichan/font.hpp>
+
+#include <set>
+#include <string>
+
+class SkillModel;
+class SkillEntry;
+
+
+struct SkillInfo
+{
+ unsigned short id;
+ std::string name;
+ Image *icon;
+ bool modifiable;
+ bool visible;
+ SkillModel *model;
+
+ std::string skillLevel;
+ int skillLevelWidth;
+
+ std::string skillExp;
+ float progress;
+ gcn::Color color;
+
+ SkillInfo() :
+ id(0), name(""), icon(0), modifiable(false), visible(false),
+ model(0), skillLevel(""), skillLevelWidth(0), skillExp(""),
+ progress(0.0f)
+ {
+ }
+
+ ~SkillInfo()
+ {
+ if (icon)
+ icon->decRef();
+ }
+
+ void setIcon(const std::string &iconPath)
+ {
+ ResourceManager *res = ResourceManager::getInstance();
+ if (!iconPath.empty())
+ {
+ icon = res->getImage(iconPath);
+ }
+
+ if (!icon)
+ {
+ icon = Theme::getImageFromTheme(
+ paths.getStringValue("unknownItemFile"));
+ }
+ }
+
+ void update();
+
+ void draw(Graphics *graphics, int y, int width);
+};
+
+
+typedef std::vector<SkillInfo*> SkillList;
+
+class SkillModel : public gcn::ListModel
+{
+public:
+ int getNumberOfElements()
+ { return static_cast<int>(mVisibleSkills.size()); }
+
+ SkillInfo *getSkillAt(int i) const
+ { return mVisibleSkills.at(i); }
+
+ std::string getElementAt(int i)
+ {
+ if (getSkillAt(i))
+ return getSkillAt(i)->name;
+ else
+ return "";
+ }
+
+ void updateVisibilities();
+
+ void addSkill(SkillInfo *info)
+ { mSkills.push_back(info); }
+
+private:
+ SkillList mSkills;
+ SkillList mVisibleSkills;
+};
+
+class SkillListBox : public ListBox
+{
+public:
+ SkillListBox(SkillModel *model):
+ ListBox(model)
+ {}
+
+ SkillInfo *getSelectedInfo()
+ {
+ const int selected = getSelected();
+ if (!mListModel || selected < 0
+ || selected > mListModel->getNumberOfElements())
+ {
+ return 0;
+ }
+
+ return static_cast<SkillModel*>(mListModel)->getSkillAt(selected);
+ }
+
+ void draw(gcn::Graphics *gcnGraphics)
+ {
+ if (!mListModel)
+ return;
+
+ SkillModel* model = static_cast<SkillModel*>(mListModel);
+
+ updateAlpha();
+
+ Graphics *graphics = static_cast<Graphics*>(gcnGraphics);
+
+ graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT,
+ static_cast<int>(mAlpha * 255.0f)));
+ graphics->setFont(getFont());
+
+ // Draw filled rectangle around the selected list element
+ if (mSelected >= 0)
+ {
+ graphics->fillRectangle(gcn::Rectangle(0, getRowHeight()
+ * mSelected, getWidth(), getRowHeight()));
+ }
+
+ // Draw the list elements
+ graphics->setColor(Theme::getThemeColor(Theme::TEXT));
+ for (int i = 0, y = 1;
+ i < model->getNumberOfElements();
+ ++i, y += getRowHeight())
+ {
+ SkillInfo *e = model->getSkillAt(i);
+
+ if (e)
+ e->draw(graphics, y, getWidth());
+ }
+ }
+
+ unsigned int getRowHeight() const
+ { return 34; }
+};
+
+class SkillTab : public Tab
+{
+public:
+ SkillTab(const std::string &name, SkillListBox *listBox):
+ mListBox(listBox)
+ {
+ setCaption(name);
+ }
+
+ ~SkillTab()
+ {
+ delete mListBox;
+ mListBox = 0;
+ }
+
+ SkillInfo *getSelectedInfo()
+ {
+ if (mListBox)
+ return mListBox->getSelectedInfo();
+ else
+ return 0;
+ }
+
+private:
+ SkillListBox *mListBox;
+};
+
+SkillDialog::SkillDialog():
+ Window(_("Skills"))
+{
+ setWindowName("Skills");
+ setCloseButton(true);
+ setResizable(true);
+ setSaveVisible(true);
+ setDefaultSize(windowContainer->getWidth() - 280, 30, 275, 425);
+ setupWindow->registerWindowForReset(this);
+
+ mTabs = new TabbedArea();
+ mPointsLabel = new Label("0");
+ mIncreaseButton = new Button(_("Up"), "inc", this);
+
+ place(0, 0, mTabs, 5, 5);
+ place(0, 5, mPointsLabel, 4);
+ place(4, 5, mIncreaseButton);
+
+ setLocationRelativeTo(getParent());
+ loadWindowState();
+}
+
+SkillDialog::~SkillDialog()
+{
+ // Clear gui
+ loadSkills("");
+}
+
+void SkillDialog::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "inc")
+ {
+ SkillTab *tab = static_cast<SkillTab*>(mTabs->getSelectedTab());
+ if (tab)
+ {
+ if (SkillInfo *info = tab->getSelectedInfo())
+ Net::getPlayerHandler()->increaseSkill(info->id);
+ }
+ }
+ else if (event.getId() == "close")
+ {
+ setVisible(false);
+ }
+}
+
+std::string SkillDialog::update(int id)
+{
+ SkillMap::iterator i = mSkills.find(id);
+
+ if (i != mSkills.end())
+ {
+ SkillInfo *info = i->second;
+ if (info)
+ {
+ info->update();
+ return info->name;
+ }
+ }
+
+ return std::string();
+}
+
+void SkillDialog::update()
+{
+ mPointsLabel->setCaption(strprintf(_("Skill points available: %d"),
+ PlayerInfo::getAttribute(SKILL_POINTS)));
+ mPointsLabel->adjustSize();
+
+ for (SkillMap::iterator it = mSkills.begin(); it != mSkills.end(); it++)
+ {
+ if ((*it).second && (*it).second->modifiable)
+ (*it).second->update();
+ }
+}
+
+void SkillDialog::loadSkills(const std::string &file)
+{
+ // Fixes issues with removing tabs
+ if (mTabs->getSelectedTabIndex() != -1)
+ {
+ mTabs->setSelectedTab(static_cast<unsigned int>(0));
+
+ while (mTabs->getSelectedTabIndex() != -1)
+ {
+ gcn::Tab *tab = mTabs->getSelectedTab();
+ if (tab)
+ mTabs->removeTabWithIndex(mTabs->getSelectedTabIndex());
+ delete tab;
+ }
+ }
+
+ delete_all(mSkills);
+ mSkills.clear();
+
+ if (file.length() == 0)
+ return;
+
+ XML::Document doc(file);
+ xmlNodePtr root = doc.rootNode();
+
+ int setCount = 0;
+ std::string setName;
+ ScrollArea *scroll;
+ SkillListBox *listbox;
+ SkillTab *tab;
+
+ if (!root || !xmlStrEqual(root->name, BAD_CAST "skills"))
+ {
+ logger->log("Error loading skills file: %s", file.c_str());
+
+ if (Net::getNetworkType() == ServerInfo::TMWATHENA)
+ {
+ SkillModel *model = new SkillModel();
+ SkillInfo *skill = new SkillInfo;
+ skill->id = 1;
+ skill->name = "basic";
+ skill->setIcon("");
+ skill->modifiable = true;
+ skill->visible = true;
+ skill->model = model;
+ skill->update();
+
+ model->addSkill(skill);
+ mSkills[1] = skill;
+
+ model->updateVisibilities();
+
+ listbox = new SkillListBox(model);
+ scroll = new ScrollArea(listbox);
+ scroll->setOpaque(false);
+ scroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
+ scroll->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS);
+
+ tab = new SkillTab("Skills", listbox);
+
+ mTabs->addTab(tab, scroll);
+
+ update();
+ }
+ return;
+ }
+
+ for_each_xml_child_node(set, root)
+ {
+ if (xmlStrEqual(set->name, BAD_CAST "set"))
+ {
+ setCount++;
+ setName = XML::getProperty(set, "name",
+ strprintf(_("Skill Set %d"), setCount));
+
+ SkillModel *model = new SkillModel();
+
+ for_each_xml_child_node(node, set)
+ {
+ if (xmlStrEqual(node->name, BAD_CAST "skill"))
+ {
+ int id = atoi(XML::getProperty(node, "id", "-1").c_str());
+ std::string name = XML::getProperty(node, "name",
+ strprintf(_("Skill %d"), id));
+ std::string icon = XML::getProperty(node, "icon", "");
+
+ SkillInfo *skill = new SkillInfo;
+ skill->id = static_cast<short unsigned>(id);
+ skill->name = name;
+ skill->setIcon(icon);
+ skill->modifiable = false;
+ skill->visible = false;
+ skill->model = model;
+ skill->update();
+
+ model->addSkill(skill);
+
+ mSkills[id] = skill;
+ }
+ }
+
+ model->updateVisibilities();
+
+ // possible leak listbox, scroll
+ listbox = new SkillListBox(model);
+ scroll = new ScrollArea(listbox);
+ scroll->setOpaque(false);
+ scroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
+ scroll->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS);
+
+ tab = new SkillTab(setName, listbox);
+
+ mTabs->addTab(tab, scroll);
+ }
+ }
+ update();
+}
+
+void SkillDialog::setModifiable(int id, bool modifiable)
+{
+ SkillMap::iterator it = mSkills.find(id);
+
+ if (it != mSkills.end())
+ {
+ SkillInfo *info = it->second;
+ if (info)
+ {
+ info->modifiable = modifiable;
+ info->update();
+ }
+ }
+}
+
+void SkillModel::updateVisibilities()
+{
+ mVisibleSkills.clear();
+
+ for (SkillList::iterator it = mSkills.begin(); it != mSkills.end(); it++)
+ {
+ if ((*it)->visible)
+ mVisibleSkills.push_back((*it));
+ }
+}
+
+void SkillInfo::update()
+{
+ int baseLevel = PlayerInfo::getStatBase(id);
+ int effLevel = PlayerInfo::getStatEffective(id);
+
+ std::pair<int, int> exp = PlayerInfo::getStatExperience(id);
+
+ if (!modifiable && baseLevel == 0 && effLevel == 0 && exp.second == 0)
+ {
+ if (visible)
+ {
+ visible = false;
+ if (model)
+ model->updateVisibilities();
+ }
+
+ return;
+ }
+
+ bool updateVisibility = !visible;
+ visible = true;
+
+ if (effLevel != baseLevel)
+ {
+ skillLevel = strprintf(_("Lvl: %d (%+d)"), baseLevel,
+ effLevel - baseLevel);
+ }
+ else
+ {
+ if (baseLevel == 0)
+ skillLevel.clear();
+ else
+ skillLevel = strprintf(_("Lvl: %d"), baseLevel);
+ }
+ skillLevelWidth = -1;
+
+ if (exp.second)
+ {
+ skillExp = strprintf("%d / %d", exp.first, exp.second);
+ progress = static_cast<float>(exp.first)
+ / static_cast<float>(exp.second);
+ }
+ else
+ {
+ skillExp.clear();
+ progress = 0.0f;
+ }
+
+ color = Theme::getProgressColor(Theme::PROG_EXP, progress);
+
+ if (updateVisibility && model)
+ model->updateVisibilities();
+}
+
+void SkillInfo::draw(Graphics *graphics, int y, int width)
+{
+ graphics->drawImage(icon, 1, y);
+ graphics->drawText(name, 34, y);
+
+ if (skillLevelWidth < 0)
+ {
+ // Add one for padding
+ skillLevelWidth = graphics->getFont()->getWidth(skillLevel) + 1;
+ }
+
+ graphics->drawText(skillLevel, width - skillLevelWidth, y);
+
+ if (!skillExp.empty())
+ {
+ gcn::Rectangle rect(33, y + 15, width - 33, 17);
+
+ ProgressBar::render(graphics, rect, color, progress, skillExp);
+ }
+}
+
+SkillInfo* SkillDialog::getSkill(int id)
+{
+ return mSkills[id];
+}