aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfunjoker <torti-esser@web.de>2017-03-20 08:54:29 +0100
committerShauren <shauren.trinity@gmail.com>2017-03-20 08:54:29 +0100
commit945cfce1f63f2d629d32da8be2e696900e81d835 (patch)
tree5689e690facc26cfb0af9301a6ce683f2e9b6129
parentd4176eb2f1a1860ee0691111d62cb8b231ac2fff (diff)
Core/Conditions: Implemented new condition type CONDITION_QUEST_OBJECTIVE_COMPLETE (#18235)
Closes #17863
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp30
-rw-r--r--src/server/game/Conditions/ConditionMgr.h99
-rw-r--r--src/server/game/Entities/Player/Player.cpp92
-rw-r--r--src/server/game/Entities/Player/Player.h1
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp6
-rw-r--r--src/server/game/Globals/ObjectMgr.h4
-rw-r--r--src/server/game/Quests/QuestDef.cpp1
-rw-r--r--src/server/game/Quests/QuestDef.h1
8 files changed, 137 insertions, 97 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index 917e61bb8d7..667b8b14889 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -110,7 +110,8 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND
{ "Charmed", false, false, false },
{ "Pet type", true, false, false },
{ "On Taxi", false, false, false },
- { "Quest state mask", true, true, false }
+ { "Quest state mask", true, true, false },
+ { "Objective Complete", true, false, false }
};
// Checks if object meets the condition
@@ -500,6 +501,20 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
}
break;
}
+ case CONDITION_QUEST_OBJECTIVE_COMPLETE:
+ {
+ if (Player* player = object->ToPlayer())
+ {
+ QuestObjective const* obj = sObjectMgr->GetQuestObjective(ConditionValue1);
+ if (!obj)
+ break;
+ Quest const* qInfo = sObjectMgr->GetQuestTemplate(obj->QuestID);
+ ASSERT(qInfo);
+
+ condMeets = (!player->GetQuestRewardStatus(obj->QuestID) && player->IsQuestObjectiveComplete(qInfo, *obj));
+ }
+ break;
+ }
default:
condMeets = false;
break;
@@ -696,6 +711,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() const
case CONDITION_QUESTSTATE:
mask |= GRID_MAP_TYPE_MASK_PLAYER;
break;
+ case CONDITION_QUEST_OBJECTIVE_COMPLETE:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
default:
ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
break;
@@ -2314,6 +2332,16 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const
}
break;
}
+ case CONDITION_QUEST_OBJECTIVE_COMPLETE:
+ {
+ QuestObjective const* obj = sObjectMgr->GetQuestObjective(cond->ConditionValue1);
+ if (!obj)
+ {
+ TC_LOG_ERROR("sql.sql", "%s points to non-existing quest objective (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1);
+ return false;
+ }
+ break;
+ }
case CONDITION_PET_TYPE:
if (cond->ConditionValue1 >= (1 << MAX_PET_TYPE))
{
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index aecccb82708..cf9ef40c2bf 100644
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -48,55 +48,56 @@ struct PlayerConditionEntry;
*/
enum ConditionTypes
{ // value1 value2 value3
- CONDITION_NONE = 0, // 0 0 0 always true
- CONDITION_AURA = 1, // spell_id effindex 0 true if target has aura of spell_id with effect effindex
- CONDITION_ITEM = 2, // item_id count bank true if has #count of item_ids (if 'bank' is set it searches in bank slots too)
- CONDITION_ITEM_EQUIPPED = 3, // item_id 0 0 true if has item_id equipped
- CONDITION_ZONEID = 4, // zone_id 0 0 true if in zone_id
- CONDITION_REPUTATION_RANK = 5, // faction_id rankMask 0 true if has min_rank for faction_id
- CONDITION_TEAM = 6, // player_team 0, 0 469 - Alliance, 67 - Horde)
- CONDITION_SKILL = 7, // skill_id skill_value 0 true if has skill_value for skill_id
- CONDITION_QUESTREWARDED = 8, // quest_id 0 0 true if quest_id was rewarded before
- CONDITION_QUESTTAKEN = 9, // quest_id 0, 0 true while quest active
- CONDITION_DRUNKENSTATE = 10, // DrunkenState 0, 0 true if player is drunk enough
- CONDITION_WORLD_STATE = 11, // index value 0 true if world has the value for the index
- CONDITION_ACTIVE_EVENT = 12, // event_id 0 0 true if event is active
- CONDITION_INSTANCE_INFO = 13, // entry data type true if the instance info defined by type (enum InstanceInfo) equals data.
- CONDITION_QUEST_NONE = 14, // quest_id 0 0 true if doesn't have quest saved
- CONDITION_CLASS = 15, // class 0 0 true if player's class is equal to class
- CONDITION_RACE = 16, // race 0 0 true if player's race is equal to race
- CONDITION_ACHIEVEMENT = 17, // achievement_id 0 0 true if achievement is complete
- CONDITION_TITLE = 18, // title id 0 0 true if player has title
- CONDITION_SPAWNMASK = 19, // spawnMask 0 0 true if in spawnMask
- CONDITION_GENDER = 20, // gender 0 0 true if player's gender is equal to gender
- CONDITION_UNIT_STATE = 21, // unitState 0 0 true if unit has unitState
- CONDITION_MAPID = 22, // map_id 0 0 true if in map_id
- CONDITION_AREAID = 23, // area_id 0 0 true if in area_id
- CONDITION_CREATURE_TYPE = 24, // cinfo.type 0 0 true if creature_template.type = value1
- CONDITION_SPELL = 25, // spell_id 0 0 true if player has learned spell
- CONDITION_PHASEID = 26, // phaseid 0 0 true if object is in phaseid
- CONDITION_LEVEL = 27, // level ComparisonType 0 true if unit's level is equal to param1 (param2 can modify the statement)
- CONDITION_QUEST_COMPLETE = 28, // quest_id 0 0 true if player has quest_id with all objectives complete, but not yet rewarded
- CONDITION_NEAR_CREATURE = 29, // creature entry distance dead (0/1) true if there is a creature of entry in range
- CONDITION_NEAR_GAMEOBJECT = 30, // gameobject entry distance 0 true if there is a gameobject of entry in range
- CONDITION_OBJECT_ENTRY_GUID = 31, // TypeID entry guid true if object is type TypeID and the entry is 0 or matches entry of the object or matches guid of the object
- CONDITION_TYPE_MASK = 32, // TypeMask 0 0 true if object is type object's TypeMask matches provided TypeMask
- CONDITION_RELATION_TO = 33, // ConditionTarget RelationType 0 true if object is in given relation with object specified by ConditionTarget
- CONDITION_REACTION_TO = 34, // ConditionTarget rankMask 0 true if object's reaction matches rankMask object specified by ConditionTarget
- CONDITION_DISTANCE_TO = 35, // ConditionTarget distance ComparisonType true if object and ConditionTarget are within distance given by parameters
- CONDITION_ALIVE = 36, // 0 0 0 true if unit is alive
- CONDITION_HP_VAL = 37, // hpVal ComparisonType 0 true if unit's hp matches given value
- CONDITION_HP_PCT = 38, // hpPct ComparisonType 0 true if unit's hp matches given pct
- CONDITION_REALM_ACHIEVEMENT = 39, // achievement_id 0 0 true if realm achievement is complete
- CONDITION_IN_WATER = 40, // 0 0 0 true if unit in water
- CONDITION_TERRAIN_SWAP = 41, // terrainSwap 0 0 true if object is in terrainswap
- CONDITION_STAND_STATE = 42, // stateType state 0 true if unit matches specified sitstate (0,x: has exactly state x; 1,0: any standing state; 1,1: any sitting state;)
- CONDITION_DAILY_QUEST_DONE = 43, // quest id 0 0 true if daily quest has been completed for the day
- CONDITION_CHARMED = 44, // 0 0 0 true if unit is currently charmed
- CONDITION_PET_TYPE = 45, // mask 0 0 true if player has a pet of given type(s)
- CONDITION_TAXI = 46, // 0 0 0 true if player is on taxi
- CONDITION_QUESTSTATE = 47, // quest_id state_mask 0 true if player is in any of the provided quest states for the quest (1 = not taken, 2 = completed, 8 = in progress, 32 = failed, 64 = rewarded)
- CONDITION_MAX = 48 // MAX
+ CONDITION_NONE = 0, // 0 0 0 always true
+ CONDITION_AURA = 1, // spell_id effindex 0 true if target has aura of spell_id with effect effindex
+ CONDITION_ITEM = 2, // item_id count bank true if has #count of item_ids (if 'bank' is set it searches in bank slots too)
+ CONDITION_ITEM_EQUIPPED = 3, // item_id 0 0 true if has item_id equipped
+ CONDITION_ZONEID = 4, // zone_id 0 0 true if in zone_id
+ CONDITION_REPUTATION_RANK = 5, // faction_id rankMask 0 true if has min_rank for faction_id
+ CONDITION_TEAM = 6, // player_team 0, 0 469 - Alliance, 67 - Horde)
+ CONDITION_SKILL = 7, // skill_id skill_value 0 true if has skill_value for skill_id
+ CONDITION_QUESTREWARDED = 8, // quest_id 0 0 true if quest_id was rewarded before
+ CONDITION_QUESTTAKEN = 9, // quest_id 0, 0 true while quest active
+ CONDITION_DRUNKENSTATE = 10, // DrunkenState 0, 0 true if player is drunk enough
+ CONDITION_WORLD_STATE = 11, // index value 0 true if world has the value for the index
+ CONDITION_ACTIVE_EVENT = 12, // event_id 0 0 true if event is active
+ CONDITION_INSTANCE_INFO = 13, // entry data type true if the instance info defined by type (enum InstanceInfo) equals data.
+ CONDITION_QUEST_NONE = 14, // quest_id 0 0 true if doesn't have quest saved
+ CONDITION_CLASS = 15, // class 0 0 true if player's class is equal to class
+ CONDITION_RACE = 16, // race 0 0 true if player's race is equal to race
+ CONDITION_ACHIEVEMENT = 17, // achievement_id 0 0 true if achievement is complete
+ CONDITION_TITLE = 18, // title id 0 0 true if player has title
+ CONDITION_SPAWNMASK = 19, // spawnMask 0 0 true if in spawnMask
+ CONDITION_GENDER = 20, // gender 0 0 true if player's gender is equal to gender
+ CONDITION_UNIT_STATE = 21, // unitState 0 0 true if unit has unitState
+ CONDITION_MAPID = 22, // map_id 0 0 true if in map_id
+ CONDITION_AREAID = 23, // area_id 0 0 true if in area_id
+ CONDITION_CREATURE_TYPE = 24, // cinfo.type 0 0 true if creature_template.type = value1
+ CONDITION_SPELL = 25, // spell_id 0 0 true if player has learned spell
+ CONDITION_PHASEID = 26, // phaseid 0 0 true if object is in phaseid
+ CONDITION_LEVEL = 27, // level ComparisonType 0 true if unit's level is equal to param1 (param2 can modify the statement)
+ CONDITION_QUEST_COMPLETE = 28, // quest_id 0 0 true if player has quest_id with all objectives complete, but not yet rewarded
+ CONDITION_NEAR_CREATURE = 29, // creature entry distance dead (0/1) true if there is a creature of entry in range
+ CONDITION_NEAR_GAMEOBJECT = 30, // gameobject entry distance 0 true if there is a gameobject of entry in range
+ CONDITION_OBJECT_ENTRY_GUID = 31, // TypeID entry guid true if object is type TypeID and the entry is 0 or matches entry of the object or matches guid of the object
+ CONDITION_TYPE_MASK = 32, // TypeMask 0 0 true if object is type object's TypeMask matches provided TypeMask
+ CONDITION_RELATION_TO = 33, // ConditionTarget RelationType 0 true if object is in given relation with object specified by ConditionTarget
+ CONDITION_REACTION_TO = 34, // ConditionTarget rankMask 0 true if object's reaction matches rankMask object specified by ConditionTarget
+ CONDITION_DISTANCE_TO = 35, // ConditionTarget distance ComparisonType true if object and ConditionTarget are within distance given by parameters
+ CONDITION_ALIVE = 36, // 0 0 0 true if unit is alive
+ CONDITION_HP_VAL = 37, // hpVal ComparisonType 0 true if unit's hp matches given value
+ CONDITION_HP_PCT = 38, // hpPct ComparisonType 0 true if unit's hp matches given pct
+ CONDITION_REALM_ACHIEVEMENT = 39, // achievement_id 0 0 true if realm achievement is complete
+ CONDITION_IN_WATER = 40, // 0 0 0 true if unit in water
+ CONDITION_TERRAIN_SWAP = 41, // terrainSwap 0 0 true if object is in terrainswap
+ CONDITION_STAND_STATE = 42, // stateType state 0 true if unit matches specified sitstate (0,x: has exactly state x; 1,0: any standing state; 1,1: any sitting state;)
+ CONDITION_DAILY_QUEST_DONE = 43, // quest id 0 0 true if daily quest has been completed for the day
+ CONDITION_CHARMED = 44, // 0 0 0 true if unit is currently charmed
+ CONDITION_PET_TYPE = 45, // mask 0 0 true if player has a pet of given type(s)
+ CONDITION_TAXI = 46, // 0 0 0 true if player is on taxi
+ CONDITION_QUESTSTATE = 47, // quest_id state_mask 0 true if player is in any of the provided quest states for the quest (1 = not taken, 2 = completed, 8 = in progress, 32 = failed, 64 = rewarded)
+ CONDITION_QUEST_OBJECTIVE_COMPLETE = 48, // ID 0 0 true if player has ID objective complete, but quest not yet rewarded
+ CONDITION_MAX = 49 // MAX
};
/*! Documentation on implementing a new ConditionSourceType:
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index bc2d1f0b194..26ed9f8263f 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -14629,48 +14629,8 @@ bool Player::CanCompleteQuest(uint32 quest_id)
{
for (QuestObjective const& obj : qInfo->GetObjectives())
{
- switch (obj.Type)
- {
- case QUEST_OBJECTIVE_MONSTER:
- case QUEST_OBJECTIVE_ITEM:
- 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;
- case QUEST_OBJECTIVE_MIN_REPUTATION:
- if (GetReputationMgr().GetReputation(obj.ObjectID) < obj.Amount)
- return false;
- break;
- case QUEST_OBJECTIVE_MAX_REPUTATION:
- if (GetReputationMgr().GetReputation(obj.ObjectID) > obj.Amount)
- return false;
- break;
- case QUEST_OBJECTIVE_MONEY:
- if (!HasEnoughMoney(uint64(obj.Amount)))
- return false;
- break;
- case QUEST_OBJECTIVE_AREATRIGGER:
- if (!GetQuestObjectiveData(qInfo, obj.StorageIndex))
- return false;
- break;
- case QUEST_OBJECTIVE_LEARNSPELL:
- 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);
- return false;
- }
+ if (!IsQuestObjectiveComplete(qInfo, obj))
+ return false;
}
if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED) && q_status.Timer == 0)
@@ -16795,6 +16755,54 @@ int32 Player::GetQuestObjectiveData(Quest const* quest, int8 storageIndex) const
return status.ObjectiveData[storageIndex];
}
+bool Player::IsQuestObjectiveComplete(Quest const* quest, QuestObjective const& objective) const
+{
+ switch (objective.Type)
+ {
+ case QUEST_OBJECTIVE_MONSTER:
+ case QUEST_OBJECTIVE_ITEM:
+ 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(quest, objective.StorageIndex) < objective.Amount)
+ return false;
+ break;
+ case QUEST_OBJECTIVE_MIN_REPUTATION:
+ if (GetReputationMgr().GetReputation(objective.ObjectID) < objective.Amount)
+ return false;
+ break;
+ case QUEST_OBJECTIVE_MAX_REPUTATION:
+ if (GetReputationMgr().GetReputation(objective.ObjectID) > objective.Amount)
+ return false;
+ break;
+ case QUEST_OBJECTIVE_MONEY:
+ if (!HasEnoughMoney(uint64(objective.Amount)))
+ return false;
+ break;
+ case QUEST_OBJECTIVE_AREATRIGGER:
+ if (!GetQuestObjectiveData(quest, objective.StorageIndex))
+ return false;
+ break;
+ case QUEST_OBJECTIVE_LEARNSPELL:
+ if (!HasSpell(objective.ObjectID))
+ return false;
+ break;
+ case QUEST_OBJECTIVE_CURRENCY:
+ if (!HasCurrency(objective.ObjectID, objective.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, objective.Type);
+ return false;
+ }
+
+ return true;
+}
+
void Player::SetQuestObjectiveData(Quest const* quest, int8 storageIndex, int32 data)
{
if (storageIndex < 0)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index dcfd2674057..d358a9a8ff2 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1618,6 +1618,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool CanShareQuest(uint32 questId) const;
int32 GetQuestObjectiveData(Quest const* quest, int8 storageIndex) const;
+ bool IsQuestObjectiveComplete(Quest const* quest, QuestObjective const& objective) const;
void SetQuestObjectiveData(Quest const* quest, int8 storageIndex, int32 data);
void SendQuestComplete(Quest const* quest) const;
void SendQuestReward(Quest const* quest, uint32 XP) const;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index b063d786aa5..5dde20e57f7 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -4310,7 +4310,7 @@ void ObjectMgr::LoadQuests()
for (QuestObjective const& obj : qinfo->GetObjectives())
{
// Store objective for lookup by id
- _questObjectives[obj.ID] = std::make_pair(&obj, qinfo->GetQuestId());
+ _questObjectives[obj.ID] = &obj;
// Check storage index for objectives which store data
if (obj.StorageIndex < 0)
@@ -5863,9 +5863,9 @@ void ObjectMgr::LoadQuestAreaTriggers()
for (auto const& pair : _questObjectives)
{
- QuestObjective const* objective = pair.second.first;
+ QuestObjective const* objective = pair.second;
if (objective->Type == QUEST_OBJECTIVE_AREATRIGGER)
- _questAreaTriggerStore[objective->ObjectID].insert(pair.second.second);
+ _questAreaTriggerStore[objective->ObjectID].insert(objective->QuestID);
}
TC_LOG_INFO("server.loading", ">> Loaded %u quest trigger points in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 21569d3e579..50744091984 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -720,7 +720,7 @@ class TC_GAME_API ObjectMgr
typedef std::unordered_map<uint32, Item*> ItemMap;
typedef std::unordered_map<uint32, Quest*> QuestMap;
- typedef std::unordered_map<uint32 /*questObjectiveId*/, std::pair<QuestObjective const*, uint32 /*questId*/>> QuestObjectivesByIdContainer;
+ typedef std::unordered_map<uint32 /*questObjectiveId*/, QuestObjective const*> QuestObjectivesByIdContainer;
typedef std::unordered_map<uint32, AreaTriggerStruct> AreaTriggerContainer;
@@ -826,7 +826,7 @@ class TC_GAME_API ObjectMgr
QuestObjective const* GetQuestObjective(uint32 questObjectiveId) const
{
auto itr = _questObjectives.find(questObjectiveId);
- return itr != _questObjectives.end() ? itr->second.first : nullptr;
+ return itr != _questObjectives.end() ? itr->second : nullptr;
}
std::unordered_set<uint32> const* GetQuestsForAreaTrigger(uint32 Trigger_ID) const
diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp
index 0dea1ed5335..6749f0ef5f2 100644
--- a/src/server/game/Quests/QuestDef.cpp
+++ b/src/server/game/Quests/QuestDef.cpp
@@ -217,6 +217,7 @@ void Quest::LoadQuestObjective(Field* fields)
{
QuestObjective obj;
obj.ID = fields[0].GetUInt32();
+ obj.QuestID = fields[1].GetUInt32();
obj.Type = fields[2].GetUInt8();
obj.StorageIndex = fields[3].GetInt8();
obj.ObjectID = fields[4].GetInt32();
diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
index e4590fb8234..024dc7976f2 100644
--- a/src/server/game/Quests/QuestDef.h
+++ b/src/server/game/Quests/QuestDef.h
@@ -271,6 +271,7 @@ struct QuestOfferRewardLocale
struct QuestObjective
{
uint32 ID = 0;
+ uint32 QuestID = 0;
uint8 Type = 0;
int8 StorageIndex = 0;
int32 ObjectID = 0;