diff options
author | funjoker <torti-esser@web.de> | 2017-03-20 08:54:29 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2017-03-20 08:54:29 +0100 |
commit | 945cfce1f63f2d629d32da8be2e696900e81d835 (patch) | |
tree | 5689e690facc26cfb0af9301a6ce683f2e9b6129 /src | |
parent | d4176eb2f1a1860ee0691111d62cb8b231ac2fff (diff) |
Core/Conditions: Implemented new condition type CONDITION_QUEST_OBJECTIVE_COMPLETE (#18235)
Closes #17863
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.cpp | 30 | ||||
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.h | 99 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 92 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 1 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 4 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.cpp | 1 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.h | 1 |
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; |