summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrei Karas <akaras@inbox.ru>2011-04-21 05:25:01 +0300
committerAndrei Karas <akaras@inbox.ru>2011-04-21 05:25:01 +0300
commit8037d33c9f429d4c0322da383cdda46776c3c14e (patch)
tree7460a6dd0c774817ff1dd92aa190776ae1684ed9 /src
parentd7eae524bf7e88ebb5a324431b74a77ce1e7fded (diff)
downloadmanaplus-8037d33c9f429d4c0322da383cdda46776c3c14e.tar.gz
manaplus-8037d33c9f429d4c0322da383cdda46776c3c14e.tar.bz2
manaplus-8037d33c9f429d4c0322da383cdda46776c3c14e.tar.xz
manaplus-8037d33c9f429d4c0322da383cdda46776c3c14e.zip
Impliment attack filter.
Add tab in social tab.
Diffstat (limited to 'src')
-rw-r--r--src/actorspritemanager.cpp112
-rw-r--r--src/defaults.cpp1
-rw-r--r--src/game.cpp1
-rw-r--r--src/gui/popupmenu.cpp182
-rw-r--r--src/gui/popupmenu.h3
-rw-r--r--src/gui/setup_other.cpp14
-rw-r--r--src/gui/setup_other.h3
-rw-r--r--src/gui/socialwindow.cpp160
-rw-r--r--src/gui/socialwindow.h4
-rw-r--r--src/gui/viewport.cpp6
-rw-r--r--src/gui/viewport.h2
-rw-r--r--src/gui/widgets/avatarlistbox.cpp25
-rw-r--r--src/localplayer.cpp75
-rw-r--r--src/localplayer.h47
-rw-r--r--src/map.h4
15 files changed, 621 insertions, 18 deletions
diff --git a/src/actorspritemanager.cpp b/src/actorspritemanager.cpp
index 44dc30892..bbcf29090 100644
--- a/src/actorspritemanager.cpp
+++ b/src/actorspritemanager.cpp
@@ -25,6 +25,7 @@
#include "configuration.h"
#include "localplayer.h"
#include "log.h"
+#include "main.h"
#include "playerinfo.h"
#include "playerrelations.h"
@@ -99,6 +100,7 @@ class SortBeingFunctor
return being1->getDistance() < being2->getDistance();
int d1, d2;
+#ifdef MANASERV_SUPPORT
if (Net::getNetworkType() == ServerInfo::MANASERV)
{
const Vector &pos1 = being1->getPosition();
@@ -109,6 +111,7 @@ class SortBeingFunctor
+ abs((static_cast<int>(pos2.y)) - y);
}
else
+#endif
{
d1 = abs(being1->getTileX() - x) + abs(being1->getTileY() - y);
d2 = abs(being2->getTileX() - x) + abs(being2->getTileY() - y);
@@ -116,9 +119,28 @@ class SortBeingFunctor
if (d1 != d2)
return d1 < d2;
+ if (beings)
+ {
+ int w1 = defaultIndex;
+ int w2 = defaultIndex;
+ std::map<std::string, int>::iterator it1
+ = beings->find(being1->getName());
+ std::map<std::string, int>::iterator it2
+ = beings->find(being2->getName());
+ if (it1 != beings->end())
+ w1 = (*it1).second;
+ if (it2 != beings->end())
+ w2 = (*it2).second;
+
+ if (w1 != w2)
+ return w1 < w2;
+ }
+
return (being1->getName() < being2->getName());
}
int x, y;
+ std::map<std::string, int> *beings;
+ int defaultIndex;
} beingSorter;
@@ -654,12 +676,31 @@ Being *ActorSpriteManager::findNearestLivingBeing(Being *aroundBeing,
return 0;
Being *closestBeing = 0;
+ std::set<std::string> attackMobs;
+ std::set<std::string> ignoreAttackMobs;
+ std::map<std::string, int> mobsMap;
+ int defaultIndex = 10000;
maxDist = maxDist * maxDist;
bool cycleSelect = (mCyclePlayers && type == Being::PLAYER)
|| (mCycleMonsters && type == Being::MONSTER);
+ bool filtered = config.getBoolValue("enableAttackFilter");
+ bool ignoreDefault = false;
+ if (filtered)
+ {
+ attackMobs = player_node->getAttackMobsSet();
+ ignoreAttackMobs = player_node->getIgnoreAttackMobsSet();
+ mobsMap = player_node->getAttackMobsMap();
+ beingSorter.beings = &mobsMap;
+ if (ignoreAttackMobs.find("") != ignoreAttackMobs.end())
+ ignoreDefault = true;
+ std::map<std::string, int>::iterator itr = mobsMap.find("");
+ if (itr != mobsMap.end())
+ defaultIndex = (*itr).second;
+ }
+
if (cycleSelect)
{
std::vector<Being*> sortedBeings;
@@ -676,6 +717,19 @@ Being *ActorSpriteManager::findNearestLivingBeing(Being *aroundBeing,
Being *being = static_cast<Being*>(*i);
+ if (filtered)
+ {
+ if (ignoreAttackMobs.find(being->getName())
+ != ignoreAttackMobs.end())
+ {
+ continue;
+ }
+ if (ignoreDefault && attackMobs.find(being->getName())
+ == attackMobs.end())
+ {
+ continue;
+ }
+ }
if (validateBeing(aroundBeing, being, type, 0, maxDist))
{
if (being != excluded)
@@ -689,7 +743,18 @@ Being *ActorSpriteManager::findNearestLivingBeing(Being *aroundBeing,
beingSorter.x = x;
beingSorter.y = y;
+ if (filtered)
+ {
+ beingSorter.beings = &mobsMap;
+ beingSorter.defaultIndex = defaultIndex;
+ }
+ else
+ {
+ beingSorter.beings = 0;
+ }
sort(sortedBeings.begin(), sortedBeings.end(), beingSorter);
+ if (filtered)
+ beingSorter.beings = 0;
if (player_node->getTarget() == NULL)
{
@@ -725,10 +790,26 @@ Being *ActorSpriteManager::findNearestLivingBeing(Being *aroundBeing,
}
Being *being = static_cast<Being*>(*i);
+ if (filtered)
+ {
+ if (ignoreAttackMobs.find(being->getName())
+ != ignoreAttackMobs.end())
+ {
+ continue;
+ }
+ if (ignoreDefault && attackMobs.find(being->getName())
+ == attackMobs.end())
+ {
+ continue;
+ }
+ }
+
// Being *being = (*i);
bool valid = validateBeing(aroundBeing, being, type, excluded, 50);
int d = being->getDistance();
+// logger->log("dist: %d", dist);
+// logger->log("name: %s, %d, %d", being->getName().c_str(), (int)valid, d);
if (being->getType() != Being::MONSTER
|| !mTargetOnlyReachable)
{ // if distance not calculated, use old distance
@@ -738,16 +819,31 @@ Being *ActorSpriteManager::findNearestLivingBeing(Being *aroundBeing,
// logger->log("being name:" + being->getName());
// logger->log("d:" + toString(d));
-// logger->log("valid:" + toString(valid));
+// logger->log("valid:" + toString(valid))
- if (valid && (d < dist || closestBeing == 0))
+ if (valid && (d <= dist || closestBeing == 0))
{
-// if ((being->getType() == type || type == Being::UNKNOWN)
-// && (d < dist || closestBeing == NULL) // it is closer
-// && (being->mAction != Being::DEAD // no dead beings
-// || (config.getValue("targetDeadPlayers", false) && type == Being::PLAYER))
-// && being != aroundBeing)
-// {
+ if (closestBeing && filtered && d == dist)
+ {
+ int w1 = defaultIndex;
+ int w2 = defaultIndex;
+ std::map<std::string, int>::iterator it1
+ = mobsMap.find(closestBeing->getName());
+ std::map<std::string, int>::iterator it2
+ = mobsMap.find(being->getName());
+ if (it1 != mobsMap.end())
+ w1 = (*it1).second;
+ if (it2 != mobsMap.end())
+ w2 = (*it2).second;
+
+ if (w2 < w1)
+ {
+ dist = d;
+ closestBeing = being;
+ }
+ continue;
+ }
+
dist = d;
closestBeing = being;
}
diff --git a/src/defaults.cpp b/src/defaults.cpp
index 7f9c31204..1446be4ec 100644
--- a/src/defaults.cpp
+++ b/src/defaults.cpp
@@ -196,6 +196,7 @@ DefaultsData* getConfigDefaults()
AddDEF(configData, "showBeingPopup", true);
AddDEF(configData, "showExtMinimaps", false);
AddDEF(configData, "hideChatInput", true);
+ AddDEF(configData, "enableAttackFilter", true);
return configData;
}
diff --git a/src/game.cpp b/src/game.cpp
index 9c1e4ca0d..d5ac15ef3 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -224,6 +224,7 @@ static void createGuiWindows()
whoIsOnline = new WhoIsOnline();
killStats = new KillStats;
socialWindow = new SocialWindow();
+ socialWindow->updateAttackFilter();
localChatTab = new ChatTab(_("General"));
localChatTab->setAllowHighlight(false);
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index 6c43fdfa1..06ee9a9b8 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -246,7 +246,32 @@ void PopupMenu::showPopup(int x, int y, Being *being)
mBrowserBox->addRow(_("@@attack|Attack@@"));
if (player_node->isGM())
+ {
+ mBrowserBox->addRow("##3---");
mBrowserBox->addRow(_("@@admin-kick|Kick@@"));
+ }
+
+ if (config.getBoolValue("enableAttackFilter"))
+ {
+ mBrowserBox->addRow("##3---");
+ if (player_node->isInAttackList(name))
+ {
+ mBrowserBox->addRow(
+ _("@@remove attack|Remove from attack list@@"));
+ }
+ else if (player_node->isInIgnoreAttackList(name))
+ {
+ mBrowserBox->addRow(
+ _("@@remove attack|Remove from ignore list@@"));
+ }
+ else
+ {
+ mBrowserBox->addRow(
+ _("@@add attack|Add to attack list@@"));
+ mBrowserBox->addRow(
+ _("@@add attack ignore|Add to ignore list@@"));
+ }
+ }
}
break;
@@ -1122,6 +1147,120 @@ void PopupMenu::handleLink(const std::string &link,
{
mTab->setNoAway(false);
}
+ else if (link == "remove attack" && being)
+ {
+ if (player_node && being->getType() == Being::MONSTER)
+ {
+ player_node->removeAttackMob(being->getName());
+ if (socialWindow)
+ socialWindow->updateAttackFilter();
+ }
+ }
+ else if (link == "add attack" && being)
+ {
+ if (player_node && being->getType() == Being::MONSTER)
+ {
+ player_node->addAttackMob(being->getName());
+ if (socialWindow)
+ socialWindow->updateAttackFilter();
+ }
+ }
+ else if (link == "add attack ignore" && being)
+ {
+ if (player_node && being->getType() == Being::MONSTER)
+ {
+ player_node->addIgnoreAttackMob(being->getName());
+ if (socialWindow)
+ socialWindow->updateAttackFilter();
+ }
+ }
+ else if (link == "attack moveup")
+ {
+ if (player_node)
+ {
+ int idx = player_node->getAttackMobIndex(mNick);
+ if (idx > 0)
+ {
+ std::list<std::string> mobs = player_node->getAttackMobs();
+ std::list<std::string>::iterator it = mobs.begin();
+ std::list<std::string>::iterator it2 = mobs.begin();
+ while (it != mobs.end())
+ {
+ if (*it == mNick)
+ {
+ -- it2;
+ mobs.splice(it2, mobs, it);
+ player_node->setAttackMobs(mobs);
+ player_node->rebuildAttackMobs();
+ break;
+ }
+ ++ it;
+ ++ it2;
+ }
+
+ if (socialWindow)
+ socialWindow->updateAttackFilter();
+ }
+ }
+ }
+ else if (link == "attack movedown")
+ {
+ if (player_node)
+ {
+ int idx = player_node->getAttackMobIndex(mNick);
+ int size = player_node->getAttackMobsSize();
+ if (idx + 1 < size)
+ {
+ std::list<std::string> mobs = player_node->getAttackMobs();
+ std::list<std::string>::iterator it = mobs.begin();
+ std::list<std::string>::iterator it2 = mobs.begin();
+ while (it != mobs.end())
+ {
+ if (*it == mNick)
+ {
+ ++ it2;
+ if (it2 == mobs.end())
+ break;
+
+ mobs.splice(it, mobs, it2);
+ player_node->setAttackMobs(mobs);
+ player_node->rebuildAttackMobs();
+ break;
+ }
+ ++ it;
+ ++ it2;
+ }
+
+ if (socialWindow)
+ socialWindow->updateAttackFilter();
+ }
+ }
+ }
+ else if (link == "attack remove")
+ {
+ if (player_node)
+ {
+ if (mNick.empty())
+ {
+ if (player_node->isInAttackList(mNick))
+ {
+ player_node->removeAttackMob(mNick);
+ player_node->addIgnoreAttackMob(mNick);
+ }
+ else
+ {
+ player_node->removeAttackMob(mNick);
+ player_node->addAttackMob(mNick);
+ }
+ }
+ else
+ {
+ player_node->removeAttackMob(mNick);
+ }
+ if (socialWindow)
+ socialWindow->updateAttackFilter();
+ }
+ }
else if (link == "guild-pos" && !mNick.empty())
{
showChangePos(getX(), getY());
@@ -1459,6 +1598,49 @@ void PopupMenu::showPopup(int x, int y, ProgressBar *b)
showPopup(x, y);
}
+void PopupMenu::showAttackMonsterPopup(int x, int y, std::string name,
+ bool isAttack)
+{
+ if (!player_node)
+ return;
+
+ mNick = name;
+
+ mBrowserBox->clearRows();
+
+ if (name.empty())
+ mBrowserBox->addRow(_("(default)"));
+ else
+ mBrowserBox->addRow(name);
+ if (isAttack)
+ {
+ int idx = player_node->getAttackMobIndex(name);
+ int size = player_node->getAttackMobsSize();
+ if (idx > 0)
+ {
+ mBrowserBox->addRow(strprintf(
+ "@@attack moveup|%s@@", _("Move up")));
+ }
+ if (idx + 1 < size)
+ {
+ mBrowserBox->addRow(strprintf(
+ "@@attack movedown|%s@@", _("Move down")));
+ }
+ mBrowserBox->addRow(strprintf(
+ "@@attack remove|%s@@", _("Remove")));
+ }
+ else
+ {
+ mBrowserBox->addRow(strprintf(
+ "@@attack remove|%s@@", _("Remove")));
+ }
+
+ mBrowserBox->addRow("##3---");
+ mBrowserBox->addRow(strprintf("@@cancel|%s@@", _("Cancel")));
+
+ showPopup(x, y);
+}
+
void PopupMenu::showPopup(int x, int y)
{
setContentSize(mBrowserBox->getWidth() + 8, mBrowserBox->getHeight() + 8);
diff --git a/src/gui/popupmenu.h b/src/gui/popupmenu.h
index 6dca1ff64..61720d417 100644
--- a/src/gui/popupmenu.h
+++ b/src/gui/popupmenu.h
@@ -117,6 +117,9 @@ class PopupMenu : public Popup, public LinkHandler
void showSpellPopup(int x, int y, TextCommand *cmd);
+ void showAttackMonsterPopup(int x, int y, std::string name,
+ bool isAttack);
+
/**
* Shows the related popup menu when right click on the chat
* at the specified mouse coordinates.
diff --git a/src/gui/setup_other.cpp b/src/gui/setup_other.cpp
index 7a43b5480..bc1a07ed3 100644
--- a/src/gui/setup_other.cpp
+++ b/src/gui/setup_other.cpp
@@ -66,6 +66,7 @@
#define ACTION_SHOW_JOB_EXP "show job exp"
#define ACTION_SHOW_BEING_POPUP "show being popup"
#define ACTION_SHOW_EXTENDED_MINIMAPS "show extended minimaps"
+#define ACTION_ENABLE_ATTACK_FILTER "attack filter"
Setup_Other::Setup_Other():
mShowMonstersTakedDamage(config.getBoolValue("showMonstersTakedDamage")),
@@ -94,6 +95,7 @@ Setup_Other::Setup_Other():
mShowJobExp(config.getBoolValue("showJobExp")),
mShowBeingPopup(config.getBoolValue("showBeingPopup")),
mShowExtMinimaps(config.getBoolValue("showExtMinimaps")),
+ mEnableAttackFilter(config.getBoolValue("enableAttackFilter")),
mEditDialog(0)
{
setName(_("Misc"));
@@ -187,6 +189,9 @@ Setup_Other::Setup_Other():
mShowExtMinimapsCheckBox = new CheckBox(_("Show extended minimaps"),
mShowExtMinimaps, this, ACTION_SHOW_EXTENDED_MINIMAPS);
+ mEnableAttackFilterCheckBox = new CheckBox(_("Enable attack filter"),
+ mEnableAttackFilter, this, ACTION_ENABLE_ATTACK_FILTER);
+
// Do the layout
LayoutHelper h(this);
ContainerPlacer place = h.getPlacer(0, 0);
@@ -205,6 +210,7 @@ Setup_Other::Setup_Other():
place(12, 8, mShowJobExpCheckBox, 10);
place(12, 9, mShowBeingPopupCheckBox, 10);
place(12, 10, mShowExtMinimapsCheckBox, 10);
+ place(12, 11, mEnableAttackFilterCheckBox, 10);
place(0, 3, mFloorItemsHighlightCheckBox, 12);
place(0, 4, mHighlightAttackRangeCheckBox, 12);
place(0, 5, mHighlightMonsterAttackRangeCheckBox, 12);
@@ -349,6 +355,10 @@ void Setup_Other::action(const gcn::ActionEvent &event)
{
mShowExtMinimaps = mShowExtMinimapsCheckBox->isSelected();
}
+ else if (event.getId() == ACTION_ENABLE_ATTACK_FILTER)
+ {
+ mEnableAttackFilter = mEnableAttackFilterCheckBox->isSelected();
+ }
}
void Setup_Other::cancel()
@@ -430,6 +440,9 @@ void Setup_Other::cancel()
mShowExtMinimaps = config.getBoolValue("showExtMinimaps");
mShowExtMinimapsCheckBox->setSelected(mShowExtMinimaps);
+
+ mEnableAttackFilter = config.getBoolValue("enableAttackFilter");
+ mEnableAttackFilterCheckBox->setSelected(mEnableAttackFilter);
}
void Setup_Other::apply()
@@ -460,6 +473,7 @@ void Setup_Other::apply()
config.setValue("showJobExp", mShowJobExp);
config.setValue("showBeingPopup", mShowBeingPopup);
config.setValue("showExtMinimaps", mShowExtMinimaps);
+ config.setValue("enableAttackFilter", mEnableAttackFilter);
logger->setDebugLog(mDebugLog);
}
diff --git a/src/gui/setup_other.h b/src/gui/setup_other.h
index 44daa1237..8bf4fe659 100644
--- a/src/gui/setup_other.h
+++ b/src/gui/setup_other.h
@@ -122,6 +122,9 @@ class Setup_Other : public SetupTab, public gcn::ActionListener
gcn::CheckBox *mShowExtMinimapsCheckBox;
bool mShowExtMinimaps;
+ gcn::CheckBox *mEnableAttackFilterCheckBox;
+ bool mEnableAttackFilter;
+
EditDialog *mEditDialog;
};
diff --git a/src/gui/socialwindow.cpp b/src/gui/socialwindow.cpp
index 8a134b5c3..c6ec12cd8 100644
--- a/src/gui/socialwindow.cpp
+++ b/src/gui/socialwindow.cpp
@@ -500,7 +500,6 @@ private:
class NavigationTab : public SocialTab
{
-
public:
NavigationTab()
{
@@ -768,6 +767,141 @@ protected:
};
+class AttackTab : public SocialTab
+{
+public:
+ AttackTab()
+ {
+ mBeings = new BeingsListModal();
+
+ mList = new AvatarListBox(mBeings);
+ mScroll = new ScrollArea(mList);
+
+ mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO);
+ mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS);
+
+ setCaption(_("Atk"));
+ }
+
+ ~AttackTab()
+ {
+ delete mList;
+ mList = 0;
+ delete mScroll;
+ mScroll = 0;
+ delete mBeings;
+ mBeings = 0;
+ }
+
+ void invite()
+ {
+ }
+
+ void leave()
+ {
+ }
+
+ void updateList()
+ {
+ if (!socialWindow || !player_node)
+ return;
+
+ std::vector<Avatar*> *avatars = mBeings->getMembers();
+
+ std::list<std::string> mobs = player_node->getAttackMobs();
+ std::list<std::string>::iterator i = mobs.begin();
+
+ std::vector<Avatar*>::iterator ia = avatars->begin();
+
+ while (ia != avatars->end())
+ {
+ delete *ia;
+ ++ ia;
+ }
+
+ avatars->clear();
+ Avatar *ava = new Avatar(_("Selected mobs"));
+ ava->setOnline(false);
+ ava->setLevel(-1);
+ ava->setType(MapItem::SEPARATOR);
+ ava->setX(0);
+ ava->setY(0);
+ avatars->push_back(ava);
+
+ while (i != mobs.end())
+ {
+ std::string name;
+ int level = -1;
+ if (*i == "")
+ {
+ name = _("(default)");
+ level = 0;
+ }
+ else
+ {
+ name = *i;
+ }
+ Avatar *ava = new Avatar(name);
+ ava->setOnline(true);
+ ava->setLevel(level);
+ ava->setType(MapItem::MONSTER);
+ ava->setX(0);
+ ava->setY(0);
+ avatars->push_back(ava);
+
+ ++ i;
+ }
+
+ ava = new Avatar(_("Ignore mobs"));
+ ava->setOnline(false);
+ ava->setLevel(-1);
+ ava->setType(MapItem::SEPARATOR);
+ ava->setX(0);
+ ava->setY(0);
+ avatars->push_back(ava);
+
+ mobs = player_node->getIgnoreAttackMobs();
+ i = mobs.begin();
+
+ while (i != mobs.end())
+ {
+ std::string name;
+ int level = -1;
+ if (*i == "")
+ {
+ name = _("(default)");
+ level = 0;
+ }
+ else
+ {
+ name = *i;
+ }
+ Avatar *ava = new Avatar(name);
+ ava->setOnline(false);
+ ava->setLevel(level);
+ ava->setType(MapItem::MONSTER);
+ ava->setX(0);
+ ava->setY(0);
+ avatars->push_back(ava);
+
+ ++ i;
+ }
+
+ }
+
+ void updateAvatar(std::string name _UNUSED_)
+ {
+ }
+
+ void resetDamage(std::string name _UNUSED_)
+ {
+ }
+
+private:
+ BeingsListModal *mBeings;
+
+};
+
class CreatePopup : public Popup, public LinkHandler
{
public:
@@ -866,6 +1000,16 @@ SocialWindow::SocialWindow() :
mNavigation = new NavigationTab();
mTabs->addTab(mNavigation, mNavigation->mScroll);
+ if (config.getBoolValue("enableAttackFilter"))
+ {
+ mAttackFilter = new AttackTab();
+ mTabs->addTab(mAttackFilter, mAttackFilter->mScroll);
+ }
+ else
+ {
+ mAttackFilter = 0;
+ }
+
if (player_node && player_node->getParty())
addTab(player_node->getParty());
@@ -899,6 +1043,10 @@ SocialWindow::~SocialWindow()
mCreatePopup = 0;
delete mPlayers;
mPlayers = 0;
+ delete mNavigation;
+ mNavigation = 0;
+ delete mAttackFilter;
+ mAttackFilter = 0;
}
bool SocialWindow::addTab(Guild *guild)
@@ -1204,7 +1352,7 @@ void SocialWindow::updateActiveList()
void SocialWindow::logic()
{
unsigned int nowTime = cur_time;
- if (nowTime - mLastUpdateTime > 1 && mNeedUpdate)
+ if (mNeedUpdate && nowTime - mLastUpdateTime > 1)
{
mPlayers->updateList();
mNeedUpdate = false;
@@ -1304,4 +1452,10 @@ void SocialWindow::prevTab()
tab--;
mTabs->setSelectedTab(tab);
-} \ No newline at end of file
+}
+
+void SocialWindow::updateAttackFilter()
+{
+ if (mAttackFilter)
+ mAttackFilter->updateList();
+}
diff --git a/src/gui/socialwindow.h b/src/gui/socialwindow.h
index 8d4e904f0..c9cd296dc 100644
--- a/src/gui/socialwindow.h
+++ b/src/gui/socialwindow.h
@@ -36,6 +36,7 @@
#define _UNUSED_
#endif
+class AttackTab;
class Button;
class ConfirmDialog;
class CreatePopup;
@@ -120,6 +121,8 @@ public:
void selectPortal(unsigned num);
+ void updateAttackFilter();
+
protected:
friend class SocialTab;
@@ -139,6 +142,7 @@ protected:
typedef std::map<Party*, SocialTab*> PartyMap;
PartyMap mParties;
+ SocialTab *mAttackFilter;
SocialTab *mPlayers;
SocialTab *mNavigation;
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index ef33aa75b..e34dd658a 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -620,6 +620,12 @@ void Viewport::showPopup(int x, int y, ProgressBar *bar)
mPopupMenu->showPopup(x, y, bar);
}
+void Viewport::showAttackMonsterPopup(std::string name, bool isAttack)
+{
+ mPopupMenu->showAttackMonsterPopup(getMouseX(), getMouseY(),
+ name, isAttack);
+}
+
void Viewport::closePopupMenu()
{
if (mPopupMenu)
diff --git a/src/gui/viewport.h b/src/gui/viewport.h
index 1daa871d1..d6e0fc3dc 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -160,6 +160,8 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
void showSpellPopup(TextCommand *cmd);
+ void showAttackMonsterPopup(std::string name, bool isAttack);
+
/**
* Shows the related popup menu when right click on the chat
* at the specified mouse coordinates.
diff --git a/src/gui/widgets/avatarlistbox.cpp b/src/gui/widgets/avatarlistbox.cpp
index c1458d3fd..8309ad156 100644
--- a/src/gui/widgets/avatarlistbox.cpp
+++ b/src/gui/widgets/avatarlistbox.cpp
@@ -114,10 +114,13 @@ void AvatarListBox::draw(gcn::Graphics *gcnGraphics)
if (!a)
continue;
- // Draw online status
- Image *icon = a->getOnline() ? onlineIcon : offlineIcon;
- if (icon)
- graphics->drawImage(icon, 2, y + 1);
+ if (a->getType() != MapItem::SEPARATOR)
+ {
+ // Draw online status
+ Image *icon = a->getOnline() ? onlineIcon : offlineIcon;
+ if (icon)
+ graphics->drawImage(icon, 2, y + 1);
+ }
if (a->getDisplayBold())
graphics->setFont(boldFont);
@@ -316,6 +319,20 @@ void AvatarListBox::mousePressed(gcn::MouseEvent &event)
model->getAvatarAt(selected)->getName());
}
}
+ else if (ava->getType() == MapItem::MONSTER)
+ {
+ if (model->getAvatarAt(selected)->getLevel() == 0)
+ {
+ viewport->showAttackMonsterPopup("",
+ model->getAvatarAt(selected)->getOnline());
+ }
+ else
+ {
+ viewport->showAttackMonsterPopup(
+ model->getAvatarAt(selected)->getName(),
+ model->getAvatarAt(selected)->getOnline());
+ }
+ }
else
{
Map *map = viewport->getMap();
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index ac113a54a..a4289b22b 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -179,6 +179,7 @@ LocalPlayer::LocalPlayer(int id, int subtype):
config.addListener("showJobExp", this);
setShowName(config.getBoolValue("showownname"));
beingInfoCache.clear();
+ addAttackMob("");
}
LocalPlayer::~LocalPlayer()
@@ -2568,12 +2569,19 @@ bool LocalPlayer::isReachable(Being *being, int maxCost)
if (being->isReachable() == Being::REACH_NO)
return false;
- if (being->getTileX() - 1 <= getTileX()
+ if (being->getTileX() == getTileX()
+ && being->getTileY() == getTileY())
+ {
+ being->setDistance(0);
+ being->setIsReachable(Being::REACH_YES);
+ return true;
+ }
+ else if (being->getTileX() - 1 <= getTileX()
&& being->getTileX() + 1 >= getTileX()
&& being->getTileY() - 1 <= getTileY()
&& being->getTileY() + 1 >= getTileY())
{
- being->setDistance(0);
+ being->setDistance(1);
being->setIsReachable(Being::REACH_YES);
return true;
}
@@ -3774,6 +3782,69 @@ void LocalPlayer::checkNewName(Being *being)
}
}
+void LocalPlayer::removeAttackMob(const std::string &name)
+{
+ mAttackMobs.remove(name);
+ mIgnoreAttackMobs.remove(name);
+ mAttackMobsSet.erase(name);
+ mIgnoreAttackMobsSet.erase(name);
+ rebuildAttackMobs();
+}
+
+void LocalPlayer::addAttackMob(std::string name)
+{
+ int size = getAttackMobsSize();
+ if (size > 0)
+ {
+ int idx = getAttackMobIndex("");
+ if (idx + 1 == size)
+ {
+ std::list<std::string>::iterator itr = mAttackMobs.end();
+ -- itr;
+ mAttackMobs.insert(itr, name);
+ }
+ else
+ {
+ mAttackMobs.push_back(name);
+ }
+ }
+ else
+ {
+ mAttackMobs.push_back(name);
+ }
+ mAttackMobsSet.insert(name);
+ rebuildAttackMobs();
+}
+
+void LocalPlayer::addIgnoreAttackMob(std::string name)
+{
+ mIgnoreAttackMobs.push_back(name);
+ mIgnoreAttackMobsSet.insert(name);
+ rebuildAttackMobs();
+}
+
+void LocalPlayer::rebuildAttackMobs()
+{
+ mAttackMobsMap.clear();
+ std::list<std::string>::iterator i = mAttackMobs.begin();
+ int cnt = 0;
+ while (i != mAttackMobs.end())
+ {
+ mAttackMobsMap[*i] = cnt;
+ ++ i;
+ ++ cnt;
+ }
+}
+
+int LocalPlayer::getAttackMobIndex(std::string name)
+{
+ std::map<std::string, int>::iterator i = mAttackMobsMap.find(name);
+ if (i == mAttackMobsMap.end())
+ return -1;
+
+ return (*i).second;
+}
+
void AwayListener::action(const gcn::ActionEvent &event)
{
if (event.getId() == "ok" && player_node && player_node->getAwayMode())
diff --git a/src/localplayer.h b/src/localplayer.h
index f5e15e5f6..904ce74db 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -450,6 +450,48 @@ class LocalPlayer : public Being, public ActorSpriteListener,
void checkNewName(Being *being);
+ bool isInAttackList(const std::string &name)
+ { return mAttackMobsSet.find(name) != mAttackMobsSet.end(); }
+
+ bool isInIgnoreAttackList(const std::string &name)
+ { return mIgnoreAttackMobsSet.find(name)
+ != mIgnoreAttackMobsSet.end(); }
+
+ bool isInAttackOrIgnoreList(const std::string &name)
+ { return mAttackMobsSet.find(name) != mAttackMobsSet.end() ||
+ mIgnoreAttackMobsSet.find(name) != mIgnoreAttackMobsSet.end(); }
+
+ void removeAttackMob(const std::string &name);
+
+ void addAttackMob(std::string name);
+
+ void addIgnoreAttackMob(std::string name);
+
+ std::list<std::string> getAttackMobs()
+ { return mAttackMobs; }
+
+ void setAttackMobs(std::list<std::string> mobs)
+ { mAttackMobs = mobs; }
+
+ int getAttackMobsSize()
+ { return mAttackMobs.size(); }
+
+ std::list<std::string> getIgnoreAttackMobs()
+ { return mIgnoreAttackMobs; }
+
+ std::set<std::string> getAttackMobsSet()
+ { return mAttackMobsSet; }
+
+ std::set<std::string> getIgnoreAttackMobsSet()
+ { return mIgnoreAttackMobsSet; }
+
+ void rebuildAttackMobs();
+
+ std::map<std::string, int> getAttackMobsMap()
+ { return mAttackMobsMap; }
+
+ int getAttackMobIndex(std::string name);
+
protected:
/** Whether or not the name settings have changed */
bool mUpdateName;
@@ -576,6 +618,11 @@ class LocalPlayer : public Being, public ActorSpriteListener,
bool mServerAttack;
std::string mLastHitFrom;
std::string mWaitFor;
+ std::list<std::string> mAttackMobs;
+ std::list<std::string> mIgnoreAttackMobs;
+ std::set<std::string> mAttackMobsSet;
+ std::set<std::string> mIgnoreAttackMobsSet;
+ std::map<std::string, int> mAttackMobsMap;
};
extern LocalPlayer *player_node;
diff --git a/src/map.h b/src/map.h
index 0c1c5b098..fbb8e1394 100644
--- a/src/map.h
+++ b/src/map.h
@@ -579,7 +579,9 @@ class MapItem
ARROW_LEFT = 6,
ARROW_RIGHT = 7,
PORTAL = 8,
- MUSIC = 9
+ MUSIC = 9,
+ MONSTER = 10,
+ SEPARATOR = 11
};
MapItem();