diff options
-rw-r--r-- | src/actorspritemanager.cpp | 17 | ||||
-rw-r--r-- | src/actorspritemanager.h | 3 | ||||
-rw-r--r-- | src/being.cpp | 23 | ||||
-rw-r--r-- | src/being.h | 6 | ||||
-rw-r--r-- | src/game.cpp | 3 | ||||
-rw-r--r-- | src/gui/questswindow.cpp | 148 | ||||
-rw-r--r-- | src/gui/questswindow.h | 21 | ||||
-rw-r--r-- | src/net/ea/beinghandler.cpp | 6 |
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; } |