summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/actorspritemanager.cpp17
-rw-r--r--src/actorspritemanager.h3
-rw-r--r--src/being.cpp23
-rw-r--r--src/being.h6
-rw-r--r--src/game.cpp3
-rw-r--r--src/gui/questswindow.cpp148
-rw-r--r--src/gui/questswindow.h21
-rw-r--r--src/net/ea/beinghandler.cpp6
8 files changed, 218 insertions, 9 deletions
diff --git a/src/actorspritemanager.cpp b/src/actorspritemanager.cpp
index f87f84a50..a9897872b 100644
--- a/src/actorspritemanager.cpp
+++ b/src/actorspritemanager.cpp
@@ -1651,3 +1651,20 @@ bool ActorSpriteManager::checkForPickup(const FloorItem *const item) const
}
return false;
}
+
+void ActorSpriteManager::updateEffects(const std::map<int, int> &addEffects,
+ const std::set<int> removeEffects)
+{
+ for_actors
+ {
+ if (!*it || (*it)->getType() != ActorSprite::NPC)
+ continue;
+ Being *const being = static_cast<Being*>(*it);
+ const int type = being->getSubType();
+ if (removeEffects.find(type) != removeEffects.end())
+ being->removeSpecialEffect();
+ const std::map<int, int>::const_iterator idAdd = addEffects.find(type);
+ if (idAdd != addEffects.end())
+ being->addSpecialEffect((*idAdd).second);
+ }
+}
diff --git a/src/actorspritemanager.h b/src/actorspritemanager.h
index 1056a7068..59cd53962 100644
--- a/src/actorspritemanager.h
+++ b/src/actorspritemanager.h
@@ -299,6 +299,9 @@ class ActorSpriteManager final: public ConfigListener
bool checkForPickup(const FloorItem *const item) const A_WARN_UNUSED;
+ void updateEffects(const std::map<int, int> &addEffects,
+ const std::set<int> removeEffects);
+
protected:
bool validateBeing(const Being *const aroundBeing,
Being *const being,
diff --git a/src/being.cpp b/src/being.cpp
index 7b494b4a7..b26b56c5d 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -247,9 +247,8 @@ Being::Being(const int id, const Type type, const uint16_t subtype,
mInactive(false),
mNumber(100),
mHairColor(0),
- mAfkParticle(nullptr)
+ mSpecialParticle(nullptr)
{
-
for (int f = 0; f < 20; f ++)
{
mSpriteRemap[f] = f;
@@ -2763,16 +2762,26 @@ int Being::getSpriteID(const int slot) const
void Being::addAfkEffect()
{
- if (effectManager && !mAfkParticle && mAwayEffect != -1)
- mAfkParticle = effectManager->triggerReturn(mAwayEffect, this);
+ addSpecialEffect(mAwayEffect);
}
void Being::removeAfkEffect()
{
- if (effectManager && mAfkParticle)
+ removeSpecialEffect();
+}
+
+void Being::addSpecialEffect(const int effect)
+{
+ if (effectManager && !mSpecialParticle && effect != -1)
+ mSpecialParticle = effectManager->triggerReturn(effect, this);
+}
+
+void Being::removeSpecialEffect()
+{
+ if (effectManager && mSpecialParticle)
{
- mChildParticleEffects.removeLocally(mAfkParticle);
- mAfkParticle = nullptr;
+ mChildParticleEffects.removeLocally(mSpecialParticle);
+ mSpecialParticle = nullptr;
}
}
diff --git a/src/being.h b/src/being.h
index 5649b94cd..00dfbfe74 100644
--- a/src/being.h
+++ b/src/being.h
@@ -862,6 +862,10 @@ class Being : public ActorSprite, public ConfigListener
void updateAwayEffect();
+ void addSpecialEffect(const int effect);
+
+ void removeSpecialEffect();
+
static uint8_t genderToInt(const Gender sex) A_WARN_UNUSED;
static Gender intToGender(uint8_t sex) A_WARN_UNUSED;
@@ -1018,7 +1022,7 @@ class Being : public ActorSprite, public ConfigListener
bool mInactive;
unsigned mNumber;
unsigned char mHairColor;
- Particle *mAfkParticle;
+ Particle *mSpecialParticle;
};
extern std::list<BeingCacheEntry*> beingInfoCache;
diff --git a/src/game.cpp b/src/game.cpp
index fa93f4d84..6f569f69a 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1062,6 +1062,9 @@ void Game::changeMap(const std::string &mapPath)
delete mCurrentMap;
mCurrentMap = newMap;
+ if (questsWindow)
+ questsWindow->setMap(mCurrentMap);
+
#ifdef USE_MUMBLE
if (mumbleManager)
mumbleManager->setMap(mapPath);
diff --git a/src/gui/questswindow.cpp b/src/gui/questswindow.cpp
index 076e042f9..390c60314 100644
--- a/src/gui/questswindow.cpp
+++ b/src/gui/questswindow.cpp
@@ -20,9 +20,11 @@
#include "gui/questswindow.h"
+#include "actorspritemanager.h"
#include "configuration.h"
#include "effectmanager.h"
#include "localplayer.h"
+#include "map.h"
#include "soundmanager.h"
#include "gui/gui.h"
@@ -37,6 +39,7 @@
#include "gui/widgets/scrollarea.h"
#include "gui/widgets/textfield.h"
+#include "utils/dtor.h"
#include "utils/gettext.h"
#include "utils/translation/podict.h"
@@ -96,6 +99,22 @@ class QuestsModel final : public ExtendedNamesModel
{ }
};
+struct QuestEffect final
+{
+ QuestEffect() :
+ var(0),
+ id(0),
+ effectId(0)
+ {
+ }
+
+ std::string map;
+ int var;
+ int id;
+ int effectId;
+ std::set<int> values;
+};
+
QuestsWindow::QuestsWindow() :
Window(_("Quests"), false, nullptr, "quests.xml"),
gcn::ActionListener(),
@@ -112,7 +131,8 @@ QuestsWindow::QuestsWindow() :
mCompleteIcon(Theme::getImageFromThemeXml("complete_icon.xml", "")),
mIncompleteIcon(Theme::getImageFromThemeXml("incomplete_icon.xml", "")),
mNewQuestEffectId(paths.getIntValue("newQuestEffectId")),
- mCompleteQuestEffectId(paths.getIntValue("completeQuestEffectId"))
+ mCompleteQuestEffectId(paths.getIntValue("completeQuestEffectId")),
+ mMap(nullptr)
{
setWindowName("Quests");
setResizable(true);
@@ -167,6 +187,9 @@ QuestsWindow::~QuestsWindow()
delete *it2;
}
}
+ delete_all(mAllEffects);
+ mAllEffects.clear();
+
delete mItemLinkHandler;
mItemLinkHandler = nullptr;
mQuests.clear();
@@ -201,6 +224,8 @@ void QuestsWindow::loadXml()
{
if (xmlNameEqual(questNode, "quest"))
loadQuest(id, questNode);
+ else if (xmlNameEqual(questNode, "effect"))
+ loadEffect(id, questNode);
}
}
}
@@ -250,6 +275,26 @@ void QuestsWindow::loadQuest(const int var, const XmlNodePtr node)
mQuests[var].push_back(quest);
}
+void QuestsWindow::loadEffect(const int var, const XmlNodePtr node)
+{
+ QuestEffect *const effect = new QuestEffect;
+
+ effect->map = XML::getProperty(node, "map", "");
+ effect->id = XML::getProperty(node, "npc", -1);
+ effect->effectId = XML::getProperty(node, "effect", -1);
+ const std::string values = XML::getProperty(node, "value", "");
+ effect->values = splitToIntSet(values, ',');
+
+ if (effect->map.empty() || effect->id == -1
+ || effect->effectId == -1 || values.empty())
+ {
+ delete effect;
+ return;
+ }
+ effect->var = var;
+ mAllEffects.push_back(effect);
+}
+
void QuestsWindow::action(const gcn::ActionEvent &event)
{
const std::string &eventId = event.getId();
@@ -389,6 +434,7 @@ void QuestsWindow::rebuild(const bool playSound)
}
}
}
+ updateEffects();
}
void QuestsWindow::showQuest(const QuestItem *const quest)
@@ -415,3 +461,103 @@ void QuestsWindow::showQuest(const QuestItem *const quest)
}
}
}
+
+void QuestsWindow::setMap(const Map *const map)
+{
+ if (mMap != map)
+ {
+ mMap = map;
+ mMapEffects.clear();
+ if (!mMap)
+ return;
+
+ const std::string name = mMap->getProperty("shortName");
+ logger->log("current map: " + name);
+ FOR_EACH (std::vector<QuestEffect*>::const_iterator, it, mAllEffects)
+ {
+ const QuestEffect *const effect = *it;
+ if (effect && name == effect->map)
+ mMapEffects.push_back(effect);
+ }
+ updateEffects();
+ }
+}
+
+void QuestsWindow::updateEffects()
+{
+ NpcQuestEffectMap oldNpc = mNpcEffects;
+ mNpcEffects.clear();
+
+ FOR_EACH (std::vector<const QuestEffect*>::const_iterator,
+ it, mMapEffects)
+ {
+ const QuestEffect *const effect = *it;
+ if (effect)
+ {
+ const std::map<int, int>::const_iterator
+ varIt = mVars.find(effect->var);
+ if (varIt != mVars.end())
+ {
+ const std::set<int> &vals = effect->values;
+ if (vals.find(mVars[effect->var]) != vals.end())
+ mNpcEffects[effect->id] = effect;
+ }
+ }
+ }
+ if (!actorSpriteManager)
+ return;
+
+ std::set<int> removeEffects;
+ std::map<int, int> addEffects;
+
+ // for old effects
+ FOR_EACH (NpcQuestEffectMapCIter, it, oldNpc)
+ {
+ const int id = (*it).first;
+ const QuestEffect *const effect = (*it).second;
+
+ const NpcQuestEffectMapCIter itNew = mNpcEffects.find(id);
+ if (itNew == mNpcEffects.end())
+ { // in new list no effect for this npc
+ removeEffects.insert(id);
+ }
+ else
+ { // in new list exists effect for this npc
+ const QuestEffect *const newEffect = (*itNew).second;
+ if (effect != newEffect)
+ { // new effects is not equal to old effect
+ addEffects[id] = newEffect->effectId;
+ removeEffects.insert(id);
+ }
+ }
+ }
+
+ // for new effects
+ FOR_EACH (NpcQuestEffectMapCIter, it, mNpcEffects)
+ {
+ const int id = (*it).first;
+ const QuestEffect *const effect = (*it).second;
+
+ const NpcQuestEffectMapCIter itNew = oldNpc.find(id);
+ // check if old effect was not present
+ if (itNew == oldNpc.end())
+ addEffects[id] = effect->effectId;
+ }
+ if (!removeEffects.empty() || !addEffects.empty())
+ actorSpriteManager->updateEffects(addEffects, removeEffects);
+}
+
+void QuestsWindow::addEffect(Being *const being)
+{
+ if (!being)
+ return;
+ const int id = being->getSubType();
+ const std::map<int, const QuestEffect*>::const_iterator
+ it = mNpcEffects.find(id);
+ if (it != mNpcEffects.end())
+ {
+ const QuestEffect *const effect = (*it).second;
+ if (effect)
+ being->addSpecialEffect(effect->effectId);
+ }
+}
diff --git a/src/gui/questswindow.h b/src/gui/questswindow.h
index 884b488c4..ad02c5397 100644
--- a/src/gui/questswindow.h
+++ b/src/gui/questswindow.h
@@ -32,15 +32,21 @@
#include <map>
#include <vector>
+class Being;
class Button;
class BrowserBox;
class ExtendedListBox;
class ItemLinkHandler;
+class Map;
class ScrollArea;
+class QuestEffect;
class QuestsModel;
struct QuestItem;
+typedef std::map<int, const QuestEffect*> NpcQuestEffectMap;
+typedef NpcQuestEffectMap::const_iterator NpcQuestEffectMapCIter;
+
class QuestsWindow final : public Window, public gcn::ActionListener
{
public:
@@ -66,11 +72,19 @@ class QuestsWindow final : public Window, public gcn::ActionListener
void showQuest(const QuestItem *const quest);
+ void setMap(const Map *const map);
+
+ void updateEffects();
+
+ void addEffect(Being *const being);
+
private:
void loadXml();
void loadQuest(const int var, const XmlNodePtr node);
+ void loadEffect(const int var, const XmlNodePtr node);
+
QuestsModel *mQuestsModel;
ExtendedListBox *mQuestsListBox;
ScrollArea *mQuestScrollArea;
@@ -78,13 +92,20 @@ class QuestsWindow final : public Window, public gcn::ActionListener
BrowserBox *mText;
ScrollArea *mTextScrollArea;
Button *mCloseButton;
+ //quest variables: var, value
std::map<int, int> mVars;
+ //quests: var, quests
std::map<int, std::vector<QuestItem*> > mQuests;
+ std::vector<QuestEffect*> mAllEffects;
+ std::vector<const QuestEffect*> mMapEffects;
+ //npc effects for current map and values: npc, effect
+ NpcQuestEffectMap mNpcEffects;
std::vector<QuestItem*> mQuestLinks;
Image *mCompleteIcon;
Image *mIncompleteIcon;
int mNewQuestEffectId;
int mCompleteQuestEffectId;
+ const Map *mMap;
};
extern QuestsWindow *questsWindow;
diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp
index 2dc2c619c..45645af31 100644
--- a/src/net/ea/beinghandler.cpp
+++ b/src/net/ea/beinghandler.cpp
@@ -41,6 +41,7 @@
#include "gui/outfitwindow.h"
#include "gui/socialwindow.h"
#include "gui/killstats.h"
+#include "gui/questswindow.h"
#include "utils/gettext.h"
@@ -95,6 +96,11 @@ Being *BeingHandler::createBeing(int id, short job)
if (socialWindow)
socialWindow->updateActiveList();
}
+ if (type == Being::NPC)
+ {
+ if (questsWindow)
+ questsWindow->addEffect(being);
+ }
return being;
}