/*
* The Mana Client
* Copyright (C) 2009-2012 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/specialswindow.h"
#include "log.h"
#include "gui/setup.h"
#include "gui/widgets/button.h"
#include "gui/widgets/container.h"
#include "gui/widgets/icon.h"
#include "gui/widgets/label.h"
#include "gui/widgets/progressbar.h"
#include "gui/widgets/windowcontainer.h"
#include "net/net.h"
#include "net/specialhandler.h"
#include "resources/specialdb.h"
#include "resources/theme.h"
#include "utils/dtor.h"
#include "utils/gettext.h"
#include "utils/stringutils.h"
#include "utils/xml.h"
#include "localplayer.h"
#include <string>
#define SPECIALS_WIDTH 200
#define SPECIALS_HEIGHT 32
class SpecialEntry : public Container
{
public:
SpecialEntry(SpecialInfo *info);
void update(int current, int needed);
protected:
friend class SpecialsWindow;
SpecialInfo *mInfo;
private:
Icon *mIcon; // icon to display
Label *mNameLabel; // name to display
Label *mLevelLabel; // level number label (only shown when applicable)
Button *mUse; // use button (only shown when applicable)
ProgressBar *mRechargeBar; // recharge bar (only shown when applicable)
};
SpecialsWindow::SpecialsWindow():
Window(_("Specials"))
{
setWindowName("Specials");
setCloseButton(true);
setResizable(true);
setSaveVisible(true);
setDefaultSize(windowContainer->getWidth() - 280, 40, SPECIALS_WIDTH + 20, 225);
setupWindow->registerWindowForReset(this);
center();
loadWindowState();
}
SpecialsWindow::~SpecialsWindow()
{
// Clear gui
}
void SpecialsWindow::action(const gcn::ActionEvent &event)
{
if (event.getId() == "use")
{
auto *disp = dynamic_cast<SpecialEntry*>(event.getSource()->getParent());
if (disp)
{
if (disp->mInfo->targetMode == SpecialInfo::TARGET_BEING)
{
Being *target = local_player->getTarget();
if (target)
Net::getSpecialHandler()->use(disp->mInfo->id, 1, target->getId());
else
Net::getSpecialHandler()->use(disp->mInfo->id);
}
else
{
// TODO: Allow the player to aim at a position on the map and
// Use special on the map position.
}
}
}
else if (event.getId() == "close")
{
setVisible(false);
}
}
void SpecialsWindow::draw(gcn::Graphics *graphics)
{
// update the progress bars
std::map<int, Special> specialData = PlayerInfo::getSpecialStatus();
bool foundNew = false;
unsigned int found = 0; // number of entries in specialData which match mEntries
for (auto &special : specialData)
{
auto e = mEntries.find(special.first);
if (e == mEntries.end())
{
// found a new special - abort update and rebuild from scratch
foundNew = true;
break;
}
else
{
// update progress bar of special
e->second->update(special.second.currentMana, special.second.neededMana);
found++;
}
}
// a rebuild is needed when a) the number of specials changed or b) an existing entry isn't found anymore
if (foundNew || found != mEntries.size())
rebuild(specialData);
Window::draw(graphics);
}
void SpecialsWindow::rebuild(const std::map<int, Special> &specialData)
{
delete_all(mEntries);
mEntries.clear();
int vPos = 0; //vertical position of next placed element
for (auto special : specialData)
{
logger->log("Updating special GUI for %d", special.first);
SpecialInfo *info = SpecialDB::get(special.first);
if (info)
{
info->rechargeCurrent = special.second.currentMana;
info->rechargeNeeded = special.second.neededMana;
auto* entry = new SpecialEntry(info);
entry->setPosition(0, vPos);
vPos += entry->getHeight() + 3;
add(entry);
mEntries[special.first] = entry;
}
else
{
logger->log("Warning: No info available of special %d", special.first);
}
}
}
SpecialEntry::SpecialEntry(SpecialInfo *info) :
mInfo(info),
mIcon(nullptr),
mLevelLabel(nullptr),
mUse(nullptr),
mRechargeBar(nullptr)
{
setSize(SPECIALS_WIDTH, SPECIALS_HEIGHT);
if (!info->icon.empty())
mIcon = new Icon(info->icon);
else
mIcon = new Icon(Theme::resolveThemePath("unknown-item.png"));
mIcon->setPosition(1, 0);
add(mIcon);
mNameLabel = new Label(info->name);
mNameLabel->setPosition(35, 0);
add(mNameLabel);
mUse = new Button("Use", "use", specialsWindow);
mUse->setPosition(getWidth() - mUse->getWidth(), 5);
add(mUse);
if (info->rechargeable)
{
float progress = (float)info->rechargeCurrent / (float)info->rechargeNeeded;
mRechargeBar = new ProgressBar(progress, 100, 10, Theme::PROG_MP);
mRechargeBar->setSmoothProgress(false);
mRechargeBar->setPosition(mNameLabel->getX(), 18);
add(mRechargeBar);
}
}
void SpecialEntry::update(int current, int needed)
{
if (mRechargeBar)
{
float progress = (float)current / (float)needed;
mRechargeBar->setProgress(progress);
}
}