aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Player/Player.cpp67
-rw-r--r--src/server/game/Entities/Player/Player.h3
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp37
-rw-r--r--src/server/game/Globals/ObjectMgr.h10
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp23
-rw-r--r--src/server/game/Quests/QuestDef.h4
6 files changed, 121 insertions, 23 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 8a3f4720a2b..40f6b748d59 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -6608,6 +6608,8 @@ void Player::ModifyCurrency(uint32 id, int32 count, bool printLog/* = true*/, bo
if (count > 0)
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CURRENCY, id, count);
+ CurrencyChanged(id, count);
+
if (currency->CategoryID == CURRENCY_CATEGORY_META_CONQUEST)
{
// count was changed to week limit, now we can modify original points.
@@ -13860,6 +13862,9 @@ bool Player::CanCompleteQuest(uint32 quest_id)
case QUEST_OBJECTIVE_GAMEOBJECT:
case QUEST_OBJECTIVE_PLAYERKILLS:
case QUEST_OBJECTIVE_TALKTO:
+ case QUEST_OBJECTIVE_WINPVPPETBATTLES:
+ case QUEST_OBJECTIVE_HAVE_CURRENCY:
+ case QUEST_OBJECTIVE_OBTAIN_CURRENCY:
if (GetQuestObjectiveData(qInfo, obj.StorageIndex) < obj.Amount)
return false;
break;
@@ -13883,6 +13888,10 @@ bool Player::CanCompleteQuest(uint32 quest_id)
if (!HasSpell(obj.ObjectID))
return false;
break;
+ case QUEST_OBJECTIVE_CURRENCY:
+ if (!HasCurrency(obj.ObjectID, obj.Amount))
+ return false;
+ break;
default:
TC_LOG_ERROR("entities.player.quest", "Player::CanCompleteQuest: Player '%s' (%s) tried to complete a quest (ID: %u) with an unknown objective type %u",
GetName().c_str(), GetGUID().ToString().c_str(), quest_id, obj.Type);
@@ -15685,7 +15694,7 @@ void Player::TalkedToCreature(uint32 entry, ObjectGuid guid)
}
}
-void Player::MoneyChanged(uint32 count)
+void Player::MoneyChanged(uint64 value)
{
for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
{
@@ -15706,7 +15715,7 @@ void Player::MoneyChanged(uint32 count)
if (q_status.Status == QUEST_STATUS_INCOMPLETE)
{
- if (int32(count) >= obj.Amount)
+ if (int64(value) >= obj.Amount)
{
if (CanCompleteQuest(questid))
CompleteQuest(questid);
@@ -15714,7 +15723,7 @@ void Player::MoneyChanged(uint32 count)
}
else if (q_status.Status == QUEST_STATUS_COMPLETE)
{
- if (int32(count) < obj.Amount)
+ if (int64(value) < obj.Amount)
IncompleteQuest(questid);
}
}
@@ -15770,6 +15779,58 @@ void Player::ReputationChanged(FactionEntry const* factionEntry)
}
}
+void Player::CurrencyChanged(uint32 currencyId, int32 change)
+{
+ for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
+ {
+ uint32 questid = GetQuestSlotQuestId(i);
+ if (!questid)
+ continue;
+
+ Quest const* qInfo = sObjectMgr->GetQuestTemplate(questid);
+ if (!qInfo)
+ continue;
+
+ for (QuestObjective const& obj : qInfo->GetObjectives())
+ {
+ if (uint32(obj.ObjectID) != currencyId)
+ continue;
+
+ if (obj.Type != QUEST_OBJECTIVE_HAVE_CURRENCY)
+ continue;
+
+ QuestStatusData& q_status = m_QuestStatus[questid];
+ int64 value = GetCurrency(currencyId);
+ if (obj.Type == QUEST_OBJECTIVE_CURRENCY || obj.Type == QUEST_OBJECTIVE_HAVE_CURRENCY)
+ {
+ if (obj.Type == QUEST_OBJECTIVE_HAVE_CURRENCY)
+ SetQuestObjectiveData(qInfo, obj.StorageIndex, int32(std::min<int64>(value, obj.Amount)));
+
+ if (q_status.Status == QUEST_STATUS_INCOMPLETE)
+ {
+ if (value >= obj.Amount)
+ {
+ if (CanCompleteQuest(questid))
+ CompleteQuest(questid);
+ }
+ }
+ else if (q_status.Status == QUEST_STATUS_COMPLETE)
+ {
+ if (value < obj.Amount)
+ IncompleteQuest(questid);
+ }
+ }
+ else if (obj.Type == QUEST_OBJECTIVE_OBTAIN_CURRENCY && value > 0) // currency losses are not accounted for in this objective type
+ {
+ int64 currentProgress = GetQuestObjectiveData(qInfo, obj.StorageIndex);
+ SetQuestObjectiveData(qInfo, obj.StorageIndex, int32(std::max(std::min<int64>(currentProgress + value, obj.Amount), SI64LIT(0))));
+ if (CanCompleteQuest(questid))
+ CompleteQuest(questid);
+ }
+ }
+ }
+}
+
bool Player::HasQuestForItem(uint32 itemid) const
{
for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 20d0bd57fca..c4f9ad3e05f 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1556,8 +1556,9 @@ class Player : public Unit, public GridObject<Player>
void KilledPlayerCredit();
void KillCreditGO(uint32 entry, ObjectGuid guid = ObjectGuid::Empty);
void TalkedToCreature(uint32 entry, ObjectGuid guid);
- void MoneyChanged(uint32 value);
+ void MoneyChanged(uint64 value);
void ReputationChanged(FactionEntry const* factionEntry);
+ void CurrencyChanged(uint32 currencyId, int32 change);
bool HasQuestForItem(uint32 itemId) const;
bool HasQuestForGO(int32 goId) const;
void UpdateForQuestWorldObjects();
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 2ac112f5400..d07ed98d2b3 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -4098,6 +4098,8 @@ void ObjectMgr::LoadQuests()
case QUEST_OBJECTIVE_TALKTO:
case QUEST_OBJECTIVE_PLAYERKILLS:
case QUEST_OBJECTIVE_AREATRIGGER:
+ case QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC:
+ case QUEST_OBJECTIVE_OBTAIN_CURRENCY:
TC_LOG_ERROR("sql.sql", "Quest %u objective %u has invalid StorageIndex = %d for objective type %u", qinfo->GetQuestId(), obj.ID, obj.StorageIndex, obj.Type);
break;
default:
@@ -4132,7 +4134,7 @@ void ObjectMgr::LoadQuests()
case QUEST_OBJECTIVE_MIN_REPUTATION:
case QUEST_OBJECTIVE_MAX_REPUTATION:
if (!sFactionStore.LookupEntry(obj.ObjectID))
- TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing faction id %u", qinfo->GetQuestId(), obj.ID, obj.ObjectID);
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing faction id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID);
break;
case QUEST_OBJECTIVE_PLAYERKILLS:
qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL);
@@ -4140,13 +4142,42 @@ void ObjectMgr::LoadQuests()
TC_LOG_ERROR("sql.sql", "Quest %u objective %u has invalid player kills count %d", qinfo->GetQuestId(), obj.ID, obj.Amount);
break;
case QUEST_OBJECTIVE_CURRENCY:
+ case QUEST_OBJECTIVE_HAVE_CURRENCY:
+ case QUEST_OBJECTIVE_OBTAIN_CURRENCY:
if (!sCurrencyTypesStore.LookupEntry(obj.ObjectID))
- TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing currency %u", qinfo->GetQuestId(), obj.ID, obj.ObjectID);
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing currency %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID);
if (obj.Amount <= 0)
TC_LOG_ERROR("sql.sql", "Quest %u objective %u has invalid currency amount %d", qinfo->GetQuestId(), obj.ID, obj.Amount);
break;
+ case QUEST_OBJECTIVE_LEARNSPELL:
+ if (!sSpellMgr->GetSpellInfo(obj.ObjectID))
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing spell id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID);
+ break;
+ case QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC:
+ if (obj.ObjectID && !sObjectMgr->GetCreatureTemplate(obj.ObjectID))
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing creature entry %u, quest can't be done.",
+ qinfo->GetQuestId(), obj.ID, uint32(obj.ObjectID));
+ break;
+ case QUEST_OBJECTIVE_DEFEATBATTLEPET:
+ if (!sBattlePetSpeciesStore.LookupEntry(obj.ObjectID))
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing battlepet species id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID);
+ break;
+ case QUEST_OBJECTIVE_CRITERIA_TREE:
+ if (!sCriteriaTreeStore.LookupEntry(obj.ObjectID))
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing criteria tree id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID);
+ break;
+ case QUEST_OBJECTIVE_AREATRIGGER:
+ if (sAreaTriggerStore.LookupEntry(uint32(obj.ObjectID)))
+ _questAreaTriggerStore[obj.ObjectID].insert(qinfo->ID);
+ else if (obj.ObjectID != -1)
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing areatrigger id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID);
+ break;
+ case QUEST_OBJECTIVE_MONEY:
+ case QUEST_OBJECTIVE_WINPVPPETBATTLES:
+ break;
default:
TC_LOG_ERROR("sql.sql", "Quest %u objective %u has unhandled type %u", qinfo->GetQuestId(), obj.ID, obj.Type);
+ break;
}
}
@@ -5543,7 +5574,7 @@ void ObjectMgr::LoadQuestAreaTriggers()
// continue; - quest modified to required objective and trigger can be allowed.
}
- _questAreaTriggerStore[trigger_ID] = quest_ID;
+ _questAreaTriggerStore[trigger_ID].insert(quest_ID);
} while (result->NextRow());
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 37ac4996931..364690dfd2e 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -812,12 +812,12 @@ class ObjectMgr
QuestMap const& GetQuestTemplates() const { return _questTemplates; }
- uint32 GetQuestForAreaTrigger(uint32 Trigger_ID) const
+ std::unordered_set<uint32> const* GetQuestsForAreaTrigger(uint32 Trigger_ID) const
{
- QuestAreaTriggerContainer::const_iterator itr = _questAreaTriggerStore.find(Trigger_ID);
+ auto itr = _questAreaTriggerStore.find(Trigger_ID);
if (itr != _questAreaTriggerStore.end())
- return itr->second;
- return 0;
+ return &itr->second;
+ return nullptr;
}
bool IsTavernAreaTrigger(uint32 Trigger_ID) const
@@ -1419,7 +1419,7 @@ class ObjectMgr
QuestMap _questTemplates;
typedef std::unordered_map<uint32, NpcText> NpcTextContainer;
- typedef std::unordered_map<uint32, uint32> QuestAreaTriggerContainer;
+ typedef std::unordered_map<uint32, std::unordered_set<uint32>> QuestAreaTriggerContainer;
typedef std::set<uint32> TavernAreaTriggerContainer;
typedef std::set<uint32> GameObjectForQuestContainer;
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index e43a7e2af0c..a51b61050ee 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -485,22 +485,25 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::Misc::AreaTrigger& pack
if (player->IsAlive())
{
- if (uint32 questId = sObjectMgr->GetQuestForAreaTrigger(packet.AreaTriggerID))
+ if (std::unordered_set<uint32> const* quests = sObjectMgr->GetQuestsForAreaTrigger(packet.AreaTriggerID))
{
- Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
- if (qInfo && player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE)
+ for (uint32 questId : *quests)
{
- for (uint8 j = 0; j < qInfo->Objectives.size(); ++j)
+ Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
+ if (qInfo && player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE)
{
- if (qInfo->Objectives[j].Type == QUEST_OBJECTIVE_AREATRIGGER)
+ for (uint8 j = 0; j < qInfo->Objectives.size(); ++j)
{
- player->SetQuestObjectiveData(qInfo, j, int32(true));
- break;
+ if (qInfo->Objectives[j].Type == QUEST_OBJECTIVE_AREATRIGGER)
+ {
+ player->SetQuestObjectiveData(qInfo, j, int32(true));
+ break;
+ }
}
- }
- if (player->CanCompleteQuest(questId))
- player->CompleteQuest(questId);
+ if (player->CanCompleteQuest(questId))
+ player->CompleteQuest(questId);
+ }
}
}
}
diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
index 7bd1f4bd647..8b27be40c20 100644
--- a/src/server/game/Quests/QuestDef.h
+++ b/src/server/game/Quests/QuestDef.h
@@ -231,7 +231,9 @@ enum QuestObjectiveType
QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC = 11,
QUEST_OBJECTIVE_DEFEATBATTLEPET = 12,
QUEST_OBJECTIVE_WINPVPPETBATTLES = 13,
- QUEST_OBJECTIVE_CRITERIA_TREE = 14
+ QUEST_OBJECTIVE_CRITERIA_TREE = 14,
+ QUEST_OBJECTIVE_HAVE_CURRENCY = 16, // requires the player to have X currency when turning in but does not consume it
+ QUEST_OBJECTIVE_OBTAIN_CURRENCY = 17 // requires the player to gain X currency after starting the quest but not required to keep it until the end (does not consume)
};
struct QuestTemplateLocale