diff options
Diffstat (limited to 'src/server/game/Conditions/ConditionMgr.cpp')
-rwxr-xr-x | src/server/game/Conditions/ConditionMgr.cpp | 1531 |
1 files changed, 1000 insertions, 531 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index a745c5a2f13..7d21f94f372 100755 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -26,209 +26,426 @@ #include "ConditionMgr.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "Spell.h" -// Checks if player meets the condition +// Checks if object meets the condition // Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI) -bool Condition::Meets(Player* player, Unit* invoker) +bool Condition::Meets(ConditionSourceInfo& sourceInfo) { - if (!player) + ASSERT(ConditionTarget < MAX_CONDITION_TARGETS); + WorldObject* object = sourceInfo.mConditionTargets[ConditionTarget]; + // object not present, return false + if (!object) { - sLog->outDebug(LOG_FILTER_CONDITIONSYS, "Condition player not found"); - return false; // player not present, return false + sLog->outDebug(LOG_FILTER_CONDITIONSYS, "Condition object not found for condition (Entry: %u Type: %u Group: %u)", SourceEntry, SourceType, SourceGroup); + return false; } - uint32 refId = mConditionValue3;//value 3 can be a 'quick' reference bool condMeets = false; - bool sendErrorMsg = false; - switch (mConditionType) + switch (ConditionType) { case CONDITION_NONE: condMeets = true; // empty condition, always met break; case CONDITION_AURA: - refId = 0; - if (!mConditionValue3) - condMeets = player->HasAuraEffect(mConditionValue1, mConditionValue2); - else if (Unit* target = player->GetSelectedUnit()) - condMeets = target->HasAuraEffect(mConditionValue1, mConditionValue2); + { + if (Unit* unit = object->ToUnit()) + condMeets = unit->HasAuraEffect(ConditionValue1, ConditionValue2); break; + } case CONDITION_ITEM: - condMeets = (mConditionValue2 && player->HasItemCount(mConditionValue1, mConditionValue2)) || (!mConditionValue2 && !player->HasItemCount(mConditionValue1, mConditionValue2));//HasItemCount returns false if 0 count is used + { + if (Player* player = object->ToPlayer()) + { + // don't allow 0 items (it's checked during table load) + ASSERT(ConditionValue2); + bool checkBank = ConditionValue3 ? true : false; + condMeets = player->HasItemCount(ConditionValue1, ConditionValue2, checkBank); + } break; + } case CONDITION_ITEM_EQUIPPED: - condMeets = player->HasItemOrGemWithIdEquipped(mConditionValue1, 1); + { + if (Player* player = object->ToPlayer()) + condMeets = player->HasItemOrGemWithIdEquipped(ConditionValue1, 1); break; + } case CONDITION_ZONEID: - condMeets = player->GetZoneId() == mConditionValue1; + condMeets = object->GetZoneId() == ConditionValue1; break; case CONDITION_REPUTATION_RANK: { - if (FactionEntry const* faction = sFactionStore.LookupEntry(mConditionValue1)) - condMeets = (mConditionValue2 & (1 << player->GetReputationMgr().GetRank(faction))); + if (Player* player = object->ToPlayer()) + { + if (FactionEntry const* faction = sFactionStore.LookupEntry(ConditionValue1)) + condMeets = (ConditionValue2 & (1 << player->GetReputationMgr().GetRank(faction))); + } break; } case CONDITION_ACHIEVEMENT: - condMeets = player->GetAchievementMgr().HasAchieved(mConditionValue1); + { + if (Player* player = object->ToPlayer()) + condMeets = player->GetAchievementMgr().HasAchieved(ConditionValue1); break; + } case CONDITION_TEAM: - condMeets = player->GetTeam() == mConditionValue1; + { + if (Player* player = object->ToPlayer()) + condMeets = player->GetTeam() == ConditionValue1; break; + } case CONDITION_CLASS: - condMeets = player->getClassMask() & mConditionValue1; + { + if (Unit* unit = object->ToUnit()) + condMeets = unit->getClassMask() & ConditionValue1; break; + } case CONDITION_RACE: - condMeets = player->getRaceMask() & mConditionValue1; + { + if (Unit* unit = object->ToUnit()) + condMeets = unit->getRaceMask() & ConditionValue1; break; + } case CONDITION_SKILL: - condMeets = player->HasSkill(mConditionValue1) && player->GetBaseSkillValue(mConditionValue1) >= mConditionValue2; + { + if (Player* player = object->ToPlayer()) + condMeets = player->HasSkill(ConditionValue1) && player->GetBaseSkillValue(ConditionValue1) >= ConditionValue2; break; + } case CONDITION_QUESTREWARDED: - condMeets = (player->GetQuestRewardStatus(mConditionValue1) == !mConditionValue2); + { + if (Player* player = object->ToPlayer()) + condMeets = (player->GetQuestRewardStatus(ConditionValue1) == !ConditionValue2); break; + } case CONDITION_QUESTTAKEN: { - QuestStatus status = player->GetQuestStatus(mConditionValue1); - condMeets = ((status == QUEST_STATUS_INCOMPLETE) == !mConditionValue2); + if (Player* player = object->ToPlayer()) + { + QuestStatus status = player->GetQuestStatus(ConditionValue1); + condMeets = ((status == QUEST_STATUS_INCOMPLETE) == !ConditionValue2); + } break; } case CONDITION_QUEST_COMPLETE: { - QuestStatus status = player->GetQuestStatus(mConditionValue1); - condMeets = ((status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(mConditionValue1)) == !mConditionValue2); + if (Player* player = object->ToPlayer()) + { + QuestStatus status = player->GetQuestStatus(ConditionValue1); + condMeets = ((status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(ConditionValue1)) == !ConditionValue2); + } break; } case CONDITION_QUEST_NONE: { - QuestStatus status = player->GetQuestStatus(mConditionValue1); - condMeets = ((status == QUEST_STATUS_NONE) == !mConditionValue2); + if (Player* player = object->ToPlayer()) + { + QuestStatus status = player->GetQuestStatus(ConditionValue1); + condMeets = ((status == QUEST_STATUS_NONE) == !ConditionValue2); + } break; } - case CONDITION_NO_AURA: - condMeets = !player->HasAuraEffect(mConditionValue1, mConditionValue2); - break; case CONDITION_ACTIVE_EVENT: - condMeets = sGameEventMgr->IsActiveEvent(mConditionValue1); + condMeets = sGameEventMgr->IsActiveEvent(ConditionValue1); break; case CONDITION_INSTANCE_DATA: { - Map* map = player->GetMap(); + Map* map = object->GetMap(); if (map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceScript()) - condMeets = ((InstanceMap*)map)->GetInstanceScript()->GetData(mConditionValue1) == mConditionValue2; + condMeets = ((InstanceMap*)map)->GetInstanceScript()->GetData(ConditionValue1) == ConditionValue2; break; } - case CONDITION_SPELL_SCRIPT_TARGET: - condMeets = true;//spell target condition is handled in spellsystem, here it is always true - refId = 0;//cant have references! use CONDITION_SOURCE_TYPE_SPELL for it + case CONDITION_MAPID: + condMeets = object->GetMapId() == ConditionValue1; break; - case CONDITION_CREATURE_TARGET: + case CONDITION_AREAID: + condMeets = object->GetAreaId() == ConditionValue1; + break; + case CONDITION_SPELL: { - Unit* target = player->GetSelectedUnit(); - if (target) - if (Creature* cTarget = target->ToCreature()) - if (cTarget->GetEntry() == mConditionValue1) - condMeets = true; + if (Player* player = object->ToPlayer()) + condMeets = player->HasSpell(ConditionValue1); break; } - case CONDITION_TARGET_HEALTH_BELOW_PCT: + case CONDITION_LEVEL: { - Unit* target = player->GetSelectedUnit(); - if (target) - condMeets = !target->HealthAbovePct(mConditionValue1); + if (Unit* unit = object->ToUnit()) + condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), static_cast<uint32>(unit->getLevel()), ConditionValue1); break; } - case CONDITION_TARGET_RANGE: + case CONDITION_DRUNKENSTATE: { - if (Unit* target = player->GetSelectedUnit()) - if (player->GetDistance(target) >= mConditionValue1 && (!mConditionValue2 || player->GetDistance(target) <= mConditionValue2)) - condMeets = true; + if (Player* player = object->ToPlayer()) + condMeets = (uint32)Player::GetDrunkenstateByValue(player->GetDrunkValue()) >= ConditionValue1; break; } - case CONDITION_MAPID: - condMeets = player->GetMapId() == mConditionValue1; + case CONDITION_NEAR_CREATURE: + { + condMeets = GetClosestCreatureWithEntry(object, ConditionValue1, (float)ConditionValue2) ? true : false; break; - case CONDITION_AREAID: - condMeets = player->GetAreaId() == mConditionValue1; + } + case CONDITION_NEAR_GAMEOBJECT: + { + condMeets = GetClosestGameObjectWithEntry(object, ConditionValue1, (float)ConditionValue2) ? true : false; break; - case CONDITION_ITEM_TARGET: + } + case CONDITION_OBJECT_ENTRY: { - condMeets = true;//handled in Item::IsTargetValidForItemUse - refId = 0;//cant have references for now + if (object->GetTypeId() == ConditionValue1) + condMeets = (!ConditionValue2) || (object->GetEntry() == ConditionValue2); break; } - case CONDITION_SPELL: - if (mConditionValue2 == 1) - condMeets = player->HasSpell(mConditionValue1); - else - condMeets = !player->HasSpell(mConditionValue1); + case CONDITION_TYPE_MASK: + { + condMeets = object->isType(ConditionValue1); break; - case CONDITION_NOITEM: - condMeets = !player->HasItemCount(mConditionValue1, 1, mConditionValue2 ? true : false); + } + case CONDITION_RELATION_TO: + { + if (WorldObject* toObject = sourceInfo.mConditionTargets[ConditionValue1]) + { + Unit* toUnit = toObject->ToUnit(); + Unit* unit = object->ToUnit(); + if (toUnit && unit) + { + switch (ConditionValue2) + { + case RELATION_SELF: + condMeets = unit == toUnit; + break; + case RELATION_IN_PARTY: + condMeets = unit->IsInPartyWith(toUnit); + break; + case RELATION_IN_RAID_OR_PARTY: + condMeets = unit->IsInRaidWith(toUnit); + break; + case RELATION_OWNED_BY: + condMeets = unit->GetOwnerGUID() == toUnit->GetGUID(); + break; + case RELATION_PASSENGER_OF: + condMeets = unit->IsOnVehicle(toUnit); + break; + } + } + } break; - case CONDITION_LEVEL: + } + case CONDITION_REACTION_TO: { - switch (mConditionValue2) + if (WorldObject* toObject = sourceInfo.mConditionTargets[ConditionValue1]) { - case LVL_COND_EQ: - condMeets = player->getLevel() == mConditionValue1; - break; - case LVL_COND_HIGH: - condMeets = player->getLevel() > mConditionValue1; - break; - case LVL_COND_LOW: - condMeets = player->getLevel() < mConditionValue1; - break; - case LVL_COND_HIGH_EQ: - condMeets = player->getLevel() >= mConditionValue1; - break; - case LVL_COND_LOW_EQ: - condMeets = player->getLevel() <= mConditionValue1; - break; + Unit* toUnit = toObject->ToUnit(); + Unit* unit = object->ToUnit(); + if (toUnit && unit) + condMeets = (1 << unit->GetReactionTo(toUnit)) & ConditionValue2; } break; } - case CONDITION_DRUNKENSTATE: + case CONDITION_DISTANCE_TO: { - condMeets = (uint32)Player::GetDrunkenstateByValue(player->GetDrunkValue()) >= mConditionValue1; + if (WorldObject* toObject = sourceInfo.mConditionTargets[ConditionValue1]) + condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue3), object->GetDistance(toObject), static_cast<float>(ConditionValue2)); break; } - case CONDITION_NEAR_CREATURE: + case CONDITION_ALIVE: { - condMeets = GetClosestCreatureWithEntry(player, mConditionValue1, (float)mConditionValue2) ? true : false; + if (Unit* unit = object->ToUnit()) + condMeets = unit->isAlive(); break; } - case CONDITION_NEAR_GAMEOBJECT: + case CONDITION_HP_VAL: + { + if (Unit* unit = object->ToUnit()) + condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), unit->GetHealth(), static_cast<uint32>(ConditionValue1)); + break; + } + case CONDITION_HP_PCT: { - condMeets = GetClosestGameObjectWithEntry(player, mConditionValue1, (float)mConditionValue2) ? true : false; + if (Unit* unit = object->ToUnit()) + condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), unit->GetHealthPct(), static_cast<float>(ConditionValue1)); + break; + } + case CONDITION_WORLD_STATE: + { + condMeets = ConditionValue2 == sWorld->getWorldState(ConditionValue1); + break; + } + case CONDITION_PHASEMASK: + { + condMeets = object->GetPhaseMask() & ConditionValue1; break; } default: condMeets = false; - refId = 0; break; } - switch (mSourceType) + + if (NegativeCondition) + condMeets = !condMeets; + + if (!condMeets) + sourceInfo.mLastFailedCondition = this; + + bool script = sScriptMgr->OnConditionCheck(this, sourceInfo); // Returns true by default. + return condMeets && script; +} + +uint32 Condition::GetSearcherTypeMaskForCondition() +{ + // build mask of types for which condition can return true + // this is used for speeding up gridsearches + if (NegativeCondition) + return (GRID_MAP_TYPE_MASK_ALL); + uint32 mask = 0; + switch (ConditionType) { - case CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET: - case CONDITION_SOURCE_TYPE_SPELL: - sendErrorMsg = true; + case CONDITION_NONE: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_AURA: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_ITEM: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_ITEM_EQUIPPED: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_ZONEID: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_REPUTATION_RANK: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_ACHIEVEMENT: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_TEAM: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_CLASS: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_RACE: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_SKILL: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_QUESTREWARDED: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_QUESTTAKEN: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_QUEST_COMPLETE: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_QUEST_NONE: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_ACTIVE_EVENT: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_INSTANCE_DATA: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_MAPID: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_AREAID: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_SPELL: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_LEVEL: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_DRUNKENSTATE: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_NEAR_CREATURE: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_NEAR_GAMEOBJECT: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_OBJECT_ENTRY: + switch (ConditionValue1) + { + case TYPEID_UNIT: + mask |= GRID_MAP_TYPE_MASK_CREATURE; + break; + case TYPEID_PLAYER: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case TYPEID_GAMEOBJECT: + mask |= GRID_MAP_TYPE_MASK_GAMEOBJECT; + break; + case TYPEID_CORPSE: + mask |= GRID_MAP_TYPE_MASK_CORPSE; + break; + default: + break; + } + case CONDITION_TYPE_MASK: + if (ConditionValue1 & TYPEMASK_UNIT) + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + if (ConditionValue1 & TYPEMASK_PLAYER) + mask |= GRID_MAP_TYPE_MASK_PLAYER; + if (ConditionValue1 & TYPEMASK_GAMEOBJECT) + mask |= GRID_MAP_TYPE_MASK_GAMEOBJECT; + if (ConditionValue1 & TYPEMASK_CORPSE) + mask |= GRID_MAP_TYPE_MASK_CORPSE; + break; + case CONDITION_RELATION_TO: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_REACTION_TO: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_DISTANCE_TO: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_ALIVE: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_HP_VAL: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_HP_PCT: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_WORLD_STATE: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_PHASEMASK: + mask |= GRID_MAP_TYPE_MASK_ALL; break; default: + ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!"); break; } + return mask; +} - bool refMeets = false; - if (condMeets && refId)//only have to check references if 'this' is met +uint32 Condition::GetMaxAvailableConditionTargets() +{ + // returns number of targets which are available for given source type + switch(SourceType) { - ConditionList ref = sConditionMgr->GetConditionReferences(refId); - refMeets = sConditionMgr->IsPlayerMeetToConditions(player, ref); + case CONDITION_SOURCE_TYPE_SPELL: + case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET: + case CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE: + case CONDITION_SOURCE_TYPE_VEHICLE_SPELL: + case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT: + case CONDITION_SOURCE_TYPE_GOSSIP_MENU: + case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: + case CONDITION_SOURCE_TYPE_SMART_EVENT: + return 2; + default: + return 1; } - else - refMeets = true; - - if (sendErrorMsg && ErrorTextd && (!condMeets || !refMeets))//send special error from DB - player->m_ConditionErrorMsgId = ErrorTextd; - - bool script = sScriptMgr->OnConditionCheck(this, player, invoker); // Returns true by default. - return condMeets && refMeets && script; } ConditionMgr::ConditionMgr() @@ -249,39 +466,80 @@ ConditionList ConditionMgr::GetConditionReferences(uint32 refId) return conditions; } -bool ConditionMgr::IsPlayerMeetToConditionList(Player* player, ConditionList const& conditions, Unit* invoker /*= NULL*/) +uint32 ConditionMgr::GetSearcherTypeMaskForConditionList(ConditionList const& conditions) +{ + if (conditions.empty()) + return GRID_MAP_TYPE_MASK_ALL; + // groupId, typeMask + std::map<uint32, uint32> ElseGroupStore; + for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i) + { + // no point of having not loaded conditions in list + ASSERT((*i)->isLoaded() && "ConditionMgr::GetSearcherTypeMaskForConditionList - not yet loaded condition found in list"); + std::map<uint32, uint32>::const_iterator itr = ElseGroupStore.find((*i)->ElseGroup); + // group not filled yet, fill with widest mask possible + if (itr == ElseGroupStore.end()) + ElseGroupStore[(*i)->ElseGroup] = GRID_MAP_TYPE_MASK_ALL; + // no point of checking anymore, empty mask + else if (!(*itr).second) + continue; + + if ((*i)->ReferenceId) // handle reference + { + ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find((*i)->ReferenceId); + ASSERT(ref != ConditionReferenceStore.end() && "ConditionMgr::GetSearcherTypeMaskForConditionList - incorrect reference"); + ElseGroupStore[(*i)->ElseGroup] &= GetSearcherTypeMaskForConditionList((*ref).second); + } + else // handle normal condition + { + // object will match conditions in one ElseGroupStore only when it matches all of them + // so, let's find a smallest possible mask which satisfies all conditions + ElseGroupStore[(*i)->ElseGroup] &= (*i)->GetSearcherTypeMaskForCondition(); + } + } + // object will match condition when one of the checks in ElseGroupStore is matching + // so, let's include all possible masks + uint32 mask = 0; + for (std::map<uint32, uint32>::const_iterator i = ElseGroupStore.begin(); i != ElseGroupStore.end(); ++i) + mask |= i->second; + + return mask; +} + +bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) { + // groupId, groupCheckPassed std::map<uint32, bool> ElseGroupStore; for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i) { - sLog->outDebug(LOG_FILTER_CONDITIONSYS, "ConditionMgr::IsPlayerMeetToConditionList condType: %u val1: %u", (*i)->mConditionType, (*i)->mConditionValue1); + sLog->outDebug(LOG_FILTER_CONDITIONSYS, "ConditionMgr::IsPlayerMeetToConditionList condType: %u val1: %u", (*i)->ConditionType, (*i)->ConditionValue1); if ((*i)->isLoaded()) { - std::map<uint32, bool>::const_iterator itr = ElseGroupStore.find((*i)->mElseGroup); + std::map<uint32, bool>::const_iterator itr = ElseGroupStore.find((*i)->ElseGroup); if (itr == ElseGroupStore.end()) - ElseGroupStore[(*i)->mElseGroup] = true; + ElseGroupStore[(*i)->ElseGroup] = true; else if (!(*itr).second) continue; - if ((*i)->mReferenceId)//handle reference + if ((*i)->ReferenceId)//handle reference { - ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find((*i)->mReferenceId); + ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find((*i)->ReferenceId); if (ref != ConditionReferenceStore.end()) { - if (!IsPlayerMeetToConditionList(player, (*ref).second, invoker)) - ElseGroupStore[(*i)->mElseGroup] = false; + if (!IsObjectMeetToConditionList(sourceInfo, (*ref).second)) + ElseGroupStore[(*i)->ElseGroup] = false; } else { sLog->outDebug(LOG_FILTER_CONDITIONSYS, "IsPlayerMeetToConditionList: Reference template -%u not found", - (*i)->mReferenceId);//checked at loading, should never happen + (*i)->ReferenceId);//checked at loading, should never happen } } else //handle normal condition { - if (!(*i)->Meets(player, invoker)) - ElseGroupStore[(*i)->mElseGroup] = false; + if (!(*i)->Meets(sourceInfo)) + ElseGroupStore[(*i)->ElseGroup] = false; } } } @@ -292,21 +550,52 @@ bool ConditionMgr::IsPlayerMeetToConditionList(Player* player, ConditionList con return false; } -bool ConditionMgr::IsPlayerMeetToConditions(Player* player, ConditionList const& conditions, Unit* invoker /*= NULL*/) +bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions) +{ + ConditionSourceInfo srcInfo = ConditionSourceInfo(object); + return IsObjectMeetToConditions(srcInfo, conditions); +} + +bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions) +{ + ConditionSourceInfo srcInfo = ConditionSourceInfo(object1, object2); + return IsObjectMeetToConditions(srcInfo, conditions); +} + +bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) { if (conditions.empty()) return true; - if (player) - player->m_ConditionErrorMsgId = 0; - - sLog->outDebug(LOG_FILTER_CONDITIONSYS, "ConditionMgr::IsPlayerMeetToConditions"); - bool result = IsPlayerMeetToConditionList(player, conditions, invoker); + sLog->outDebug(LOG_FILTER_CONDITIONSYS, "ConditionMgr::IsObjectMeetToConditions"); + return IsObjectMeetToConditionList(sourceInfo, conditions); +} - if (player && player->m_ConditionErrorMsgId && player->GetSession() && !result) - player->GetSession()->SendNotification(player->m_ConditionErrorMsgId); //m_ConditionErrorMsgId is set only if a condition was not met +bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const +{ + return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU || + sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION || + sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL || + sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || + sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || + sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT); +} - return result; +bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) const +{ + return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT); } ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) @@ -328,33 +617,50 @@ ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType return spellCond; } -ConditionList ConditionMgr::GetConditionsForVehicleSpell(uint32 creatureID, uint32 spellID) + +ConditionList ConditionMgr::GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) { ConditionList cond; - VehicleSpellConditionContainer::const_iterator itr = VehicleSpellConditionStore.find(creatureID); + CreatureSpellConditionContainer::const_iterator itr = SpellClickEventConditionStore.find(creatureId); + if (itr != SpellClickEventConditionStore.end()) + { + ConditionTypeContainer::const_iterator i = (*itr).second.find(spellId); + if (i != (*itr).second.end()) + { + cond = (*i).second; + sLog->outDebug(LOG_FILTER_CONDITIONSYS, "GetConditionsForSpellClickEvent: found conditions for Vehicle entry %u spell %u", creatureId, spellId); + } + } + return cond; +} + +ConditionList ConditionMgr::GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId) +{ + ConditionList cond; + CreatureSpellConditionContainer::const_iterator itr = VehicleSpellConditionStore.find(creatureId); if (itr != VehicleSpellConditionStore.end()) { - ConditionTypeContainer::const_iterator i = (*itr).second.find(spellID); + ConditionTypeContainer::const_iterator i = (*itr).second.find(spellId); if (i != (*itr).second.end()) { cond = (*i).second; - sLog->outDebug(LOG_FILTER_CONDITIONSYS, "GetConditionsForVehicleSpell: found conditions for Vehicle entry %u spell %u", creatureID, spellID); + sLog->outDebug(LOG_FILTER_CONDITIONSYS, "GetConditionsForVehicleSpell: found conditions for Vehicle entry %u spell %u", creatureId, spellId); } } return cond; } -ConditionList ConditionMgr::GetConditionsForSmartEvent(uint32 entry, uint32 eventId, uint32 sourceType) +ConditionList ConditionMgr::GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType) { ConditionList cond; - SmartEventConditionContainer::const_iterator itr = SmartEventConditionStore.find(std::make_pair(entry, sourceType)); + SmartEventConditionContainer::const_iterator itr = SmartEventConditionStore.find(std::make_pair(entryOrGuid, sourceType)); if (itr != SmartEventConditionStore.end()) { ConditionTypeContainer::const_iterator i = (*itr).second.find(eventId + 1); if (i != (*itr).second.end()) { cond = (*i).second; - sLog->outDebug(LOG_FILTER_CONDITIONSYS, "GetConditionsForSmartEvent: found conditions for Smart Event entry %u event_id %u", entry, eventId); + sLog->outDebug(LOG_FILTER_CONDITIONSYS, "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid %d event_id %u", entryOrGuid, eventId); } } return cond; @@ -388,10 +694,11 @@ void ConditionMgr::LoadConditions(bool isReload) sLog->outString("Re-Loading `gossip_menu_option` Table for Conditions!"); sObjectMgr->LoadGossipMenuItems(); + sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists(); } - QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, " - " ConditionValue1, ConditionValue2, ConditionValue3, ErrorTextId, ScriptName FROM conditions"); + QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, " + " ConditionValue1, ConditionValue2, ConditionValue3, NegativeCondition, ErrorTextId, ScriptName FROM conditions"); if (!result) { @@ -409,19 +716,24 @@ void ConditionMgr::LoadConditions(bool isReload) Condition* cond = new Condition(); int32 iSourceTypeOrReferenceId = fields[0].GetInt32(); - cond->mSourceGroup = fields[1].GetUInt32(); - cond->mSourceEntry = fields[2].GetUInt32(); - cond->mSourceId = fields[3].GetUInt32(); - cond->mElseGroup = fields[4].GetUInt32(); + cond->SourceGroup = fields[1].GetUInt32(); + cond->SourceEntry = fields[2].GetInt32(); + cond->SourceId = fields[3].GetUInt32(); + cond->ElseGroup = fields[4].GetUInt32(); int32 iConditionTypeOrReference = fields[5].GetInt32(); - cond->mConditionValue1 = fields[6].GetUInt32(); - cond->mConditionValue2 = fields[7].GetUInt32(); - cond->mConditionValue3 = fields[8].GetUInt32(); - cond->ErrorTextd = fields[9].GetUInt32(); - cond->mScriptId = sObjectMgr->GetScriptId(fields[10].GetCString()); + cond->ConditionTarget = fields[6].GetUInt8(); + cond->ConditionValue1 = fields[7].GetUInt32(); + cond->ConditionValue2 = fields[8].GetUInt32(); + cond->ConditionValue3 = fields[9].GetUInt32(); + cond->NegativeCondition = fields[10].GetUInt8(); + cond->ErrorTextId = fields[11].GetUInt32(); + cond->ScriptId = sObjectMgr->GetScriptId(fields[12].GetCString()); if (iConditionTypeOrReference >= 0) - cond->mConditionType = ConditionType(iConditionTypeOrReference); + cond->ConditionType = ConditionTypes(iConditionTypeOrReference); + + if (iSourceTypeOrReferenceId >= 0) + cond->SourceType = ConditionSourceType(iSourceTypeOrReferenceId); if (iConditionTypeOrReference < 0)//it has a reference { @@ -431,22 +743,26 @@ void ConditionMgr::LoadConditions(bool isReload) delete cond; continue; } - cond->mReferenceId = uint32(abs(iConditionTypeOrReference)); + cond->ReferenceId = uint32(abs(iConditionTypeOrReference)); const char* rowType = "reference template"; if (iSourceTypeOrReferenceId >= 0) rowType = "reference"; //check for useless data - if (cond->mConditionValue1) - sLog->outErrorDb("Condition %s %i has useless data in value1 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue1); - if (cond->mConditionValue2) - sLog->outErrorDb("Condition %s %i has useless data in value2 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue2); - if (cond->mConditionValue3) - sLog->outErrorDb("Condition %s %i has useless data in value3 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue3); - if (cond->mSourceGroup && iSourceTypeOrReferenceId < 0) - sLog->outErrorDb("Condition %s %i has useless data in SourceGroup (%u)!", rowType, iSourceTypeOrReferenceId, cond->mSourceGroup); - if (cond->mSourceEntry && iSourceTypeOrReferenceId < 0) - sLog->outErrorDb("Condition %s %i has useless data in SourceEntry (%u)!", rowType, iSourceTypeOrReferenceId, cond->mSourceEntry); + if (cond->ConditionTarget) + sLog->outErrorDb("Condition %s %i has useless data in ConditionTarget (%u)!", rowType, iSourceTypeOrReferenceId, cond->ConditionTarget); + if (cond->ConditionValue1) + sLog->outErrorDb("Condition %s %i has useless data in value1 (%u)!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue1); + if (cond->ConditionValue2) + sLog->outErrorDb("Condition %s %i has useless data in value2 (%u)!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Condition %s %i has useless data in value3 (%u)!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue3); + if (cond->NegativeCondition) + sLog->outErrorDb("Condition %s %i has useless data in NegativeCondition (%u)!", rowType, iSourceTypeOrReferenceId, cond->NegativeCondition); + if (cond->SourceGroup && iSourceTypeOrReferenceId < 0) + sLog->outErrorDb("Condition %s %i has useless data in SourceGroup (%u)!", rowType, iSourceTypeOrReferenceId, cond->SourceGroup); + if (cond->SourceEntry && iSourceTypeOrReferenceId < 0) + sLog->outErrorDb("Condition %s %i has useless data in SourceEntry (%u)!", rowType, iSourceTypeOrReferenceId, cond->SourceEntry); } else if (!isConditionTypeValid(cond))//doesn't have reference, validate ConditionType { @@ -467,8 +783,6 @@ void ConditionMgr::LoadConditions(bool isReload) continue; }//end of reference templates - cond->mSourceType = ConditionSourceType(iSourceTypeOrReferenceId); - //if not a reference and SourceType is invalid, skip if (iConditionTypeOrReference >= 0 && !isSourceTypeValid(cond)) { @@ -477,53 +791,60 @@ void ConditionMgr::LoadConditions(bool isReload) } //Grouping is only allowed for some types (loot templates, gossip menus, gossip items) - if (cond->mSourceGroup && !isGroupable(cond->mSourceType)) + if (cond->SourceGroup && !CanHaveSourceGroupSet(cond->SourceType)) { - sLog->outErrorDb("Condition type %u has not allowed grouping %u!", uint32(cond->mSourceType), cond->mSourceGroup); + sLog->outErrorDb("Condition type %u has not allowed value of SourceGroup = %u!", uint32(cond->SourceType), cond->SourceGroup); delete cond; continue; } - else if (cond->mSourceGroup) + if (cond->SourceId && !CanHaveSourceIdSet(cond->SourceType)) + { + sLog->outErrorDb("Condition type %u has not allowed value of SourceId = %u!", uint32(cond->SourceType), cond->SourceId); + delete cond; + continue; + } + + if (cond->SourceGroup) { bool valid = false; - //handle grouped conditions - switch (cond->mSourceType) + // handle grouped conditions + switch (cond->SourceType) { case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Creature.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Creature.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Disenchant.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Disenchant.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Fishing.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Fishing.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Gameobject.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Gameobject.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Item.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Item.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Mail.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Mail.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Milling.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Milling.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Pickpocketing.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Pickpocketing.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Prospecting.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Prospecting.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Reference.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Reference.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Skinning.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Skinning.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Spell.GetLootForConditionFill(cond->mSourceGroup)); + valid = addToLootTemplate(cond, LootTemplates_Spell.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_GOSSIP_MENU: valid = addToGossipMenus(cond); @@ -531,21 +852,44 @@ void ConditionMgr::LoadConditions(bool isReload) case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: valid = addToGossipMenuItems(cond); break; + case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT: + { + //if no list for npc create one + if (SpellClickEventConditionStore.find(cond->SourceGroup) == SpellClickEventConditionStore.end()) + { + ConditionTypeContainer cmap; + SpellClickEventConditionStore[cond->SourceGroup] = cmap; + } + //if no list for spellclick spell create one + if (SpellClickEventConditionStore[cond->SourceGroup].find(cond->SourceEntry) == SpellClickEventConditionStore[cond->SourceGroup].end()) + { + ConditionList clist; + SpellClickEventConditionStore[cond->SourceGroup][cond->SourceEntry] = clist; + } + SpellClickEventConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); + valid = true; + ++count; + continue; // do not add to m_AllocatedMemory to avoid double deleting + break; + } + case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET: + valid = addToSpellImplicitTargetConditions(cond); + break; case CONDITION_SOURCE_TYPE_VEHICLE_SPELL: { //if no list for vehicle create one - if (VehicleSpellConditionStore.find(cond->mSourceGroup) == VehicleSpellConditionStore.end()) + if (VehicleSpellConditionStore.find(cond->SourceGroup) == VehicleSpellConditionStore.end()) { ConditionTypeContainer cmap; - VehicleSpellConditionStore[cond->mSourceGroup] = cmap; + VehicleSpellConditionStore[cond->SourceGroup] = cmap; } //if no list for vehicle's spell create one - if (VehicleSpellConditionStore[cond->mSourceGroup].find(cond->mSourceEntry) == VehicleSpellConditionStore[cond->mSourceGroup].end()) + if (VehicleSpellConditionStore[cond->SourceGroup].find(cond->SourceEntry) == VehicleSpellConditionStore[cond->SourceGroup].end()) { ConditionList clist; - VehicleSpellConditionStore[cond->mSourceGroup][cond->mSourceEntry] = clist; + VehicleSpellConditionStore[cond->SourceGroup][cond->SourceEntry] = clist; } - VehicleSpellConditionStore[cond->mSourceGroup][cond->mSourceEntry].push_back(cond); + VehicleSpellConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); valid = true; ++count; continue; // do not add to m_AllocatedMemory to avoid double deleting @@ -553,18 +897,18 @@ void ConditionMgr::LoadConditions(bool isReload) case CONDITION_SOURCE_TYPE_SMART_EVENT: { // If the entry does not exist, create a new list - std::pair<uint32, uint32> key = std::make_pair(cond->mSourceEntry, cond->mSourceId); + std::pair<int32, uint32> key = std::make_pair(cond->SourceEntry, cond->SourceId); if (SmartEventConditionStore.find(key) == SmartEventConditionStore.end()) { ConditionTypeContainer cmap; SmartEventConditionStore[key] = cmap; } - if (SmartEventConditionStore[key].find(cond->mSourceGroup) == SmartEventConditionStore[key].end()) + if (SmartEventConditionStore[key].find(cond->SourceGroup) == SmartEventConditionStore[key].end()) { ConditionList clist; - SmartEventConditionStore[key][cond->mSourceGroup] = clist; + SmartEventConditionStore[key][cond->SourceGroup] = clist; } - SmartEventConditionStore[key][cond->mSourceGroup].push_back(cond); + SmartEventConditionStore[key][cond->SourceGroup].push_back(cond); valid = true; ++count; continue; @@ -575,7 +919,7 @@ void ConditionMgr::LoadConditions(bool isReload) if (!valid) { - sLog->outErrorDb("Not handled grouped condition, SourceGroup %u", cond->mSourceGroup); + sLog->outErrorDb("Not handled grouped condition, SourceGroup %u", cond->SourceGroup); delete cond; } else @@ -588,21 +932,21 @@ void ConditionMgr::LoadConditions(bool isReload) //handle not grouped conditions //make sure we have a storage list for our SourceType - if (ConditionStore.find(cond->mSourceType) == ConditionStore.end()) + if (ConditionStore.find(cond->SourceType) == ConditionStore.end()) { ConditionTypeContainer mTypeMap; - ConditionStore[cond->mSourceType] = mTypeMap;//add new empty list for SourceType + ConditionStore[cond->SourceType] = mTypeMap;//add new empty list for SourceType } //make sure we have a condition list for our SourceType's entry - if (ConditionStore[cond->mSourceType].find(cond->mSourceEntry) == ConditionStore[cond->mSourceType].end()) + if (ConditionStore[cond->SourceType].find(cond->SourceEntry) == ConditionStore[cond->SourceType].end()) { ConditionList mCondList; - ConditionStore[cond->mSourceType][cond->mSourceEntry] = mCondList; + ConditionStore[cond->SourceType][cond->SourceEntry] = mCondList; } //add new Condition to storage based on Type/Entry - ConditionStore[cond->mSourceType][cond->mSourceEntry].push_back(cond); + ConditionStore[cond->SourceType][cond->SourceEntry].push_back(cond); ++count; } while (result->NextRow()); @@ -615,26 +959,26 @@ bool ConditionMgr::addToLootTemplate(Condition* cond, LootTemplate* loot) { if (!loot) { - sLog->outErrorDb("ConditionMgr: LootTemplate %u not found", cond->mSourceGroup); + sLog->outErrorDb("ConditionMgr: LootTemplate %u not found", cond->SourceGroup); return false; } if (loot->addConditionItem(cond)) return true; - sLog->outErrorDb("ConditionMgr: Item %u not found in LootTemplate %u", cond->mSourceEntry, cond->mSourceGroup); + sLog->outErrorDb("ConditionMgr: Item %u not found in LootTemplate %u", cond->SourceEntry, cond->SourceGroup); return false; } bool ConditionMgr::addToGossipMenus(Condition* cond) { - GossipMenusMapBoundsNonConst pMenuBounds = sObjectMgr->GetGossipMenusMapBoundsNonConst(cond->mSourceGroup); + GossipMenusMapBoundsNonConst pMenuBounds = sObjectMgr->GetGossipMenusMapBoundsNonConst(cond->SourceGroup); if (pMenuBounds.first != pMenuBounds.second) { - for (GossipMenusMap::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr) + for (GossipMenusContainer::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr) { - if ((*itr).second.entry == cond->mSourceGroup && (*itr).second.text_id == cond->mSourceEntry) + if ((*itr).second.entry == cond->SourceGroup && (*itr).second.text_id == uint32(cond->SourceEntry)) { (*itr).second.conditions.push_back(cond); return true; @@ -642,18 +986,18 @@ bool ConditionMgr::addToGossipMenus(Condition* cond) } } - sLog->outErrorDb("addToGossipMenus: GossipMenu %u not found", cond->mSourceGroup); + sLog->outErrorDb("addToGossipMenus: GossipMenu %u not found", cond->SourceGroup); return false; } bool ConditionMgr::addToGossipMenuItems(Condition* cond) { - GossipMenuItemsMapBoundsNonConst pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBoundsNonConst(cond->mSourceGroup); + GossipMenuItemsMapBoundsNonConst pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBoundsNonConst(cond->SourceGroup); if (pMenuItemBounds.first != pMenuItemBounds.second) { - for (GossipMenuItemsMap::iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr) + for (GossipMenuItemsContainer::iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr) { - if ((*itr).second.MenuId == cond->mSourceGroup && (*itr).second.OptionIndex == cond->mSourceEntry) + if ((*itr).second.MenuId == cond->SourceGroup && (*itr).second.OptionIndex == uint32(cond->SourceEntry)) { (*itr).second.Conditions.push_back(cond); return true; @@ -661,380 +1005,402 @@ bool ConditionMgr::addToGossipMenuItems(Condition* cond) } } - sLog->outErrorDb("addToGossipMenuItems: GossipMenuId %u Item %u not found", cond->mSourceGroup, cond->mSourceEntry); + sLog->outErrorDb("addToGossipMenuItems: GossipMenuId %u Item %u not found", cond->SourceGroup, cond->SourceEntry); return false; } +bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) +{ + uint32 conditionEffMask = cond->SourceGroup; + SpellInfo* spellInfo = const_cast<SpellInfo*>(sSpellMgr->GetSpellInfo(cond->SourceEntry)); + ASSERT(spellInfo); + std::list<uint32> sharedMasks; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + // check if effect is already a part of some shared mask + bool found = false; + for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr) + { + if ((1<<i) & *itr) + { + found = true; + break; + } + } + if (found) + continue; + + // build new shared mask with found effect + uint32 sharedMask = (1<<i); + ConditionList* cmp = spellInfo->Effects[i].ImplicitTargetConditions; + for (uint8 effIndex = i+1; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + { + if (spellInfo->Effects[effIndex].ImplicitTargetConditions == cmp) + sharedMask |= 1<<effIndex; + } + sharedMasks.push_back(sharedMask); + } + + for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr) + { + // some effect indexes should have same data + if (uint32 commonMask = *itr & conditionEffMask) + { + uint8 firstEffIndex = 0; + for (; firstEffIndex < MAX_SPELL_EFFECTS; ++firstEffIndex) + if ((1<<firstEffIndex) & *itr) + break; + + // get shared data + ConditionList* sharedList = spellInfo->Effects[firstEffIndex].ImplicitTargetConditions; + + // there's already data entry for that sharedMask + if (sharedList) + { + // we have overlapping masks in db + if (conditionEffMask != *itr) + { + sLog->outErrorDb("SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set - " + "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring.", cond->SourceEntry, cond->SourceGroup); + return false; + } + } + // no data for shared mask, we can create new submask + else + { + // add new list, create new shared mask + sharedList = new ConditionList(); + for (uint8 i = firstEffIndex; i < MAX_SPELL_EFFECTS; ++i) + if ((1<<i) & commonMask) + spellInfo->Effects[i].ImplicitTargetConditions = sharedList; + } + sharedList->push_back(cond); + break; + } + } + return true; +} + bool ConditionMgr::isSourceTypeValid(Condition* cond) { - if (cond->mSourceType == CONDITION_SOURCE_TYPE_NONE || cond->mSourceType >= CONDITION_SOURCE_TYPE_MAX) + if (cond->SourceType == CONDITION_SOURCE_TYPE_NONE || cond->SourceType >= CONDITION_SOURCE_TYPE_MAX) { - sLog->outErrorDb("Invalid ConditionSourceType %u in `condition` table, ignoring.", uint32(cond->mSourceType)); + sLog->outErrorDb("Invalid ConditionSourceType %u in `condition` table, ignoring.", uint32(cond->SourceType)); return false; } - switch (cond->mSourceType) + switch (cond->SourceType) { case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: { - if (!LootTemplates_Creature.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Creature.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `creature_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `creature_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Creature.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Creature.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE: { - if (!LootTemplates_Disenchant.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Disenchant.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Disenchant.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Disenchant.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE: { - if (!LootTemplates_Fishing.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Fishing.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `fishing_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `fishing_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Fishing.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Fishing.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE: { - if (!LootTemplates_Gameobject.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Gameobject.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Gameobject.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Gameobject.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE: { - if (!LootTemplates_Item.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Item.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `item_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `item_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Item.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Item.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE: { - if (!LootTemplates_Mail.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Mail.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `mail_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `mail_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Mail.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Mail.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE: { - if (!LootTemplates_Milling.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Milling.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `milling_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `milling_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Milling.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Milling.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE: { - if (!LootTemplates_Pickpocketing.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Pickpocketing.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Pickpocketing.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Pickpocketing.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE: { - if (!LootTemplates_Prospecting.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Prospecting.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Prospecting.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Prospecting.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE: { - if (!LootTemplates_Reference.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Reference.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `reference_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `reference_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Reference.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Reference.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE: { - if (!LootTemplates_Skinning.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Skinning.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `skinning_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `skinning_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Skinning.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Skinning.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE: { - if (!LootTemplates_Spell.HaveLootFor(cond->mSourceGroup)) + if (!LootTemplates_Spell.HaveLootFor(cond->SourceGroup)) { - sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `spell_loot_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceGroup %u in `condition` table, does not exist in `spell_loot_template`, ignoring.", cond->SourceGroup); return false; } - LootTemplate* loot = LootTemplates_Spell.GetLootForConditionFill(cond->mSourceGroup); - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + LootTemplate* loot = LootTemplates_Spell.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); return false; } break; } - case CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET: + case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET: { - if (cond->mConditionType != CONDITION_SPELL_SCRIPT_TARGET) + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->SourceEntry); + if (!spellInfo) { - sLog->outErrorDb("SourceEntry %u in `condition` table, has ConditionType %u. Only CONDITION_SPELL_SCRIPT_TARGET(18) is valid for CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET(14), ignoring.", cond->mSourceEntry, uint32(cond->mConditionType)); + sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); return false; } - SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->mSourceEntry); - if (!spellProto) + if ((cond->SourceGroup > MAX_EFFECT_MASK) || !cond->SourceGroup) { - sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->mSourceEntry); + sLog->outErrorDb("SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set , ignoring.", cond->SourceEntry, cond->SourceGroup); return false; } - bool targetfound = false; + uint32 origGroup = cond->SourceGroup; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - if (spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_SRC_AREA_ENTRY || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ENTRY || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_NEARBY_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_NEARBY_ENTRY || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_NEARBY_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_GAMEOBJECT_NEARBY_ENTRY || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_SRC_AREA || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_GAMEOBJECT_SRC_AREA || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_DEST_AREA || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_GAMEOBJECT_DEST_AREA || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_DEST_NEARBY_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_DEST_NEARBY_ENTRY || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_CONE_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_CONE_ENTRY) + if (!((1<<i) & cond->SourceGroup)) + continue; + + switch (spellInfo->Effects[i].TargetA.GetSelectionCategory()) { - targetfound = true; - //break; + case TARGET_SELECT_CATEGORY_NEARBY: + case TARGET_SELECT_CATEGORY_CONE: + case TARGET_SELECT_CATEGORY_AREA: + continue; + default: + break; } - else if (cond->mConditionValue3 & (1 << i)) + + switch (spellInfo->Effects[i].TargetB.GetSelectionCategory()) { - cond->mConditionValue3 &= ~(1 << i); - sLog->outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DEST_NEARBY_ENTRY (46)" - ", TARGET_UNIT_SRC_AREA_ENTRY(7), TARGET_UNIT_DEST_AREA_ENTRY(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)" - "TARGET_GAMEOBJECT_SRC_AREA(51), TARGET_GAMEOBJECT_DEST_AREA(52) in effect %u", cond->mSourceEntry, uint32(i)); + case TARGET_SELECT_CATEGORY_NEARBY: + case TARGET_SELECT_CATEGORY_CONE: + case TARGET_SELECT_CATEGORY_AREA: + continue; + default: + break; } + + sLog->outErrorDb("SourceEntry %u SourceGroup %u in `condition` table - spell %u does not have implicit targets of types: _AREA_, _CONE_, _NEARBY_ for effect %u, SourceGroup needs correction, ignoring.", cond->SourceEntry, origGroup, cond->SourceEntry, uint32(i)); + cond->SourceGroup &= ~(1<<i); } - if (!targetfound && !cond->mConditionValue3) // cond->mConditionValue3 already errored up there - { - sLog->outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DEST_NEARBY_ENTRY (46)" - ", TARGET_UNIT_SRC_AREA_ENTRY(7), TARGET_UNIT_DEST_AREA_ENTRY(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)" - "TARGET_GAMEOBJECT_SRC_AREA(51), TARGET_GAMEOBJECT_DEST_AREA(52)", cond->mSourceEntry); - return false; - } - if ((cond->mConditionValue1 == SPELL_TARGET_TYPE_DEAD) && !spellProto->IsAllowingDeadTarget()) - { - sLog->outErrorDb("SourceEntry %u in `condition` table does have SPELL_TARGET_TYPE_DEAD specified but spell does not have SPELL_ATTR2_CAN_TARGET_DEAD", cond->mSourceEntry); + // all effects were removed, no need to add the condition at all + if (!cond->SourceGroup) return false; - } break; } case CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE: { - if (!sObjectMgr->GetCreatureTemplate(cond->mSourceEntry)) + if (!sObjectMgr->GetCreatureTemplate(cond->SourceEntry)) { - sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->mSourceEntry); + sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_SPELL: { - SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->mSourceEntry); + SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->SourceEntry); if (!spellProto) { - sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->mSourceEntry); + sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); return false; } break; } - case CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET: - { - if (cond->mConditionType != CONDITION_ITEM_TARGET) + case CONDITION_SOURCE_TYPE_QUEST_ACCEPT: + if (!sObjectMgr->GetQuestTemplate(cond->SourceEntry)) { - sLog->outErrorDb("SourceEntry %u in `condition` table, has ConditionType %u. Only CONDITION_ITEM_TARGET(24) is valid for CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET(18), ignoring.", cond->mSourceEntry, uint32(cond->mConditionType)); + sLog->outErrorDb("CONDITION_SOURCE_TYPE_QUEST_ACCEPT specifies non-existing quest (%u), skipped", cond->SourceEntry); return false; } - - ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->mSourceEntry); - if (!pItemProto) + break; + case CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK: + if (!sObjectMgr->GetQuestTemplate(cond->SourceEntry)) { - sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `item_tamplate`, ignoring.", cond->mSourceEntry); + sLog->outErrorDb("CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK specifies non-existing quest (%u), skipped", cond->SourceEntry); return false; } - - bool bIsItemSpellValid = false; - for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) - { - if (SpellInfo const* pSpellInfo = sSpellMgr->GetSpellInfo(pItemProto->Spells[i].SpellId)) - { - if (pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE || - pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE) - { - ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, pSpellInfo->Id);//script loading is done before item target loading - if (!conditions.empty()) - break; - - for (int j = 0; j < MAX_SPELL_EFFECTS; ++j) - { - if (pSpellInfo->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY || - pSpellInfo->Effects[j].TargetB.GetTarget() == TARGET_UNIT_TARGET_ENEMY || - pSpellInfo->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_ANY || - pSpellInfo->Effects[j].TargetB.GetTarget() == TARGET_UNIT_TARGET_ANY) - { - bIsItemSpellValid = true; - break; - } - } - - if (bIsItemSpellValid) - break; - } - } - } - - if (!bIsItemSpellValid) - { - sLog->outErrorDb("Conditions: CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET for item %u, which either doesn't have item spelltrigger or its spells don't have implicit target " - "TARGET_UNIT_TARGET_ENEMY(6), TARGET_UNIT_TARGET_ANY(25), or the spells are already listed in CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET conditions.", cond->mSourceEntry); - break; - } break; - } - case CONDITION_SOURCE_TYPE_QUEST_ACCEPT: - if (!sObjectMgr->GetQuestTemplate(cond->mSourceEntry)) + case CONDITION_SOURCE_TYPE_VEHICLE_SPELL: + if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup)) { - sLog->outErrorDb("CONDITION_SOURCE_TYPE_QUEST_ACCEPT specifies non-existing quest (%u), skipped", cond->mSourceEntry); + sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->SourceGroup); return false; } - break; - case CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK: - if (!sObjectMgr->GetQuestTemplate(cond->mSourceEntry)) + + if (!sSpellMgr->GetSpellInfo(cond->SourceEntry)) { - sLog->outErrorDb("CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK specifies non-existing quest (%u), skipped", cond->mSourceEntry); + sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); return false; } break; - case CONDITION_SOURCE_TYPE_VEHICLE_SPELL: - if (!sObjectMgr->GetCreatureTemplate(cond->mSourceGroup)) + case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT: + if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup)) { - sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->mSourceGroup); + sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->SourceGroup); return false; } - if (!sSpellMgr->GetSpellInfo(cond->mSourceEntry)) + if (!sSpellMgr->GetSpellInfo(cond->SourceEntry)) { - sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->mSourceEntry); + sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); return false; } break; @@ -1050,113 +1416,131 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) } bool ConditionMgr::isConditionTypeValid(Condition* cond) { - if (cond->mConditionType == CONDITION_NONE || cond->mConditionType >= CONDITION_MAX) + if (cond->ConditionType == CONDITION_NONE || cond->ConditionType >= CONDITION_MAX) { - sLog->outErrorDb("Invalid ConditionType %u at SourceEntry %u in `condition` table, ignoring.", uint32(cond->mConditionType), cond->mSourceEntry); + sLog->outErrorDb("Invalid ConditionType %u at SourceEntry %u in `condition` table, ignoring.", uint32(cond->ConditionType), cond->SourceEntry); return false; } - switch (cond->mConditionType) + if (cond->ConditionTarget >= cond->GetMaxAvailableConditionTargets()) + { + sLog->outErrorDb("SourceType %u, SourceEntry %u in `condition` table, has incorrect ConditionTarget set, ignoring.", cond->SourceType, cond->SourceEntry); + return false; + } + + switch (cond->ConditionType) { case CONDITION_AURA: { - if (!sSpellMgr->GetSpellInfo(cond->mConditionValue1)) + if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1)) { - sLog->outErrorDb("Aura condition has non existing spell (Id: %d), skipped", cond->mConditionValue1); + sLog->outErrorDb("Aura condition has non existing spell (Id: %d), skipped", cond->ConditionValue1); return false; } - if (cond->mConditionValue2 > 2) + if (cond->ConditionValue2 > EFFECT_2) { - sLog->outErrorDb("Aura condition has non existing effect index (%u) (must be 0..2), skipped", cond->mConditionValue2); + sLog->outErrorDb("Aura condition has non existing effect index (%u) (must be 0..2), skipped", cond->ConditionValue2); return false; } + if (cond->ConditionValue3) + sLog->outErrorDb("Aura condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ITEM: { - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->mConditionValue1); + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1); if (!proto) { - sLog->outErrorDb("Item condition has non existing item (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("Item condition has non existing item (%u), skipped", cond->ConditionValue1); return false; } - if (!cond->mConditionValue2) + if (!cond->ConditionValue2) { - sLog->outErrorDb("Item condition has 0 set for item count in value2 (%u), skipped", cond->mConditionValue2); + sLog->outErrorDb("Item condition has 0 set for item count in value2 (%u), skipped", cond->ConditionValue2); return false; } break; } case CONDITION_ITEM_EQUIPPED: { - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->mConditionValue1); + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1); if (!proto) { - sLog->outErrorDb("ItemEquipped condition has non existing item (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("ItemEquipped condition has non existing item (%u), skipped", cond->ConditionValue1); return false; } - if (cond->mConditionValue2) - sLog->outErrorDb("ItemEquipped condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue2) + sLog->outErrorDb("ItemEquipped condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("ItemEquipped condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ZONEID: { - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->mConditionValue1); + AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->ConditionValue1); if (!areaEntry) { - sLog->outErrorDb("Zone condition has non existing area (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("ZoneID condition has non existing area (%u), skipped", cond->ConditionValue1); return false; } if (areaEntry->zone != 0) { - sLog->outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", cond->mConditionValue1); + sLog->outErrorDb("ZoneID condition requires to be in area (%u) which is a subzone but zone expected, skipped", cond->ConditionValue1); return false; } - if (cond->mConditionValue2) - sLog->outErrorDb("Zone condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue2) + sLog->outErrorDb("ZoneID condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("ZoneID condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_REPUTATION_RANK: { - FactionEntry const* factionEntry = sFactionStore.LookupEntry(cond->mConditionValue1); + FactionEntry const* factionEntry = sFactionStore.LookupEntry(cond->ConditionValue1); if (!factionEntry) { - sLog->outErrorDb("Reputation condition has non existing faction (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("Reputation condition has non existing faction (%u), skipped", cond->ConditionValue1); return false; } + if (cond->ConditionValue3) + sLog->outErrorDb("Reputation condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_TEAM: { - if (cond->mConditionValue1 != ALLIANCE && cond->mConditionValue1 != HORDE) + if (cond->ConditionValue1 != ALLIANCE && cond->ConditionValue1 != HORDE) { - sLog->outErrorDb("Team condition specifies unknown team (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("Team condition specifies unknown team (%u), skipped", cond->ConditionValue1); return false; } - if (cond->mConditionValue2) - sLog->outErrorDb("Team condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue2) + sLog->outErrorDb("Team condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Team condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_SKILL: { - SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(cond->mConditionValue1); + SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(cond->ConditionValue1); if (!pSkill) { - sLog->outErrorDb("Skill condition specifies non-existing skill (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("Skill condition specifies non-existing skill (%u), skipped", cond->ConditionValue1); return false; } - if (cond->mConditionValue2 < 1 || cond->mConditionValue2 > sWorld->GetConfigMaxSkillValue()) + if (cond->ConditionValue2 < 1 || cond->ConditionValue2 > sWorld->GetConfigMaxSkillValue()) { - sLog->outErrorDb("Skill condition specifies invalid skill value (%u), skipped", cond->mConditionValue2); + sLog->outErrorDb("Skill condition specifies invalid skill value (%u), skipped", cond->ConditionValue2); return false; } + if (cond->ConditionValue3) + sLog->outErrorDb("Skill condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_QUESTREWARDED: @@ -1164,246 +1548,331 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) case CONDITION_QUEST_NONE: case CONDITION_QUEST_COMPLETE: { - if (!sObjectMgr->GetQuestTemplate(cond->mConditionValue1)) + if (!sObjectMgr->GetQuestTemplate(cond->ConditionValue1)) { - sLog->outErrorDb("Quest condition specifies non-existing quest (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("Quest condition specifies non-existing quest (%u), skipped", cond->ConditionValue1); return false; } - if (cond->mConditionValue2 > 1) - sLog->outErrorDb("Quest condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_NO_AURA: - { - if (!sSpellMgr->GetSpellInfo(cond->mConditionValue1)) - { - sLog->outErrorDb("Aura condition has non existing spell (Id: %d), skipped", cond->mConditionValue1); - return false; - } - - if (cond->mConditionValue2 > 2) - { - sLog->outErrorDb("Aura condition has non existing effect index (%u) in value2 (must be 0..2), skipped", cond->mConditionValue2); - return false; - } + if (cond->ConditionValue2 > 1) + sLog->outErrorDb("Quest condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Quest condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ACTIVE_EVENT: { GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap(); - if (cond->mConditionValue1 >=events.size() || !events[cond->mConditionValue1].isValid()) + if (cond->ConditionValue1 >=events.size() || !events[cond->ConditionValue1].isValid()) { - sLog->outErrorDb("Active event condition has non existing event id (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("ActiveEvent condition has non existing event id (%u), skipped", cond->ConditionValue1); return false; } - if (cond->mConditionValue2) - sLog->outErrorDb("Active event condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue2) + sLog->outErrorDb("ActiveEvent condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("ActiveEvent condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ACHIEVEMENT: { - AchievementEntry const* achievement = GetAchievementStore()->LookupEntry(cond->mConditionValue1); + AchievementEntry const* achievement = GetAchievementStore()->LookupEntry(cond->ConditionValue1); if (!achievement) { - sLog->outErrorDb("Achivemen condition has non existing achivement id (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("Achivement condition has non existing achivement id (%u), skipped", cond->ConditionValue1); return false; } - if (cond->mConditionValue2) - sLog->outErrorDb("Achivemen condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue2) + sLog->outErrorDb("Achivement condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Achivement condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_CLASS: { - if (!(cond->mConditionValue1 & CLASSMASK_ALL_PLAYABLE)) + if (!(cond->ConditionValue1 & CLASSMASK_ALL_PLAYABLE)) { - sLog->outErrorDb("Class condition has non existing classmask (%u), skipped", cond->mConditionValue1 & ~CLASSMASK_ALL_PLAYABLE); + sLog->outErrorDb("Class condition has non existing classmask (%u), skipped", cond->ConditionValue1 & ~CLASSMASK_ALL_PLAYABLE); return false; } - if (cond->mConditionValue2) - sLog->outErrorDb("Class condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue2) + sLog->outErrorDb("Class condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Class condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_RACE: { - if (!(cond->mConditionValue1 & RACEMASK_ALL_PLAYABLE)) + if (!(cond->ConditionValue1 & RACEMASK_ALL_PLAYABLE)) { - sLog->outErrorDb("Race condition has non existing racemask (%u), skipped", cond->mConditionValue1 & ~RACEMASK_ALL_PLAYABLE); + sLog->outErrorDb("Race condition has non existing racemask (%u), skipped", cond->ConditionValue1 & ~RACEMASK_ALL_PLAYABLE); return false; } - if (cond->mConditionValue2) - sLog->outErrorDb("Race condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue2) + sLog->outErrorDb("Race condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Race condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_SPELL_SCRIPT_TARGET: + case CONDITION_MAPID: { - if (cond->mConditionValue1 >= MAX_SPELL_TARGET_TYPE) + MapEntry const* me = sMapStore.LookupEntry(cond->ConditionValue1); + if (!me) { - sLog->outErrorDb("SpellTarget condition has non existing spell target type (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("Map condition has non existing map (%u), skipped", cond->ConditionValue1); return false; } - switch (cond->mConditionValue1) - { - case SPELL_TARGET_TYPE_GAMEOBJECT: - { - if (cond->mConditionValue2 && !sObjectMgr->GetGameObjectTemplate(cond->mConditionValue2)) - { - sLog->outErrorDb("SpellTarget condition has non existing gameobject (%u) as target, skipped", cond->mConditionValue2); - return false; - } - break; - } - case SPELL_TARGET_TYPE_CONTROLLED: - case SPELL_TARGET_TYPE_CREATURE: - case SPELL_TARGET_TYPE_DEAD: - { - if (cond->mConditionValue2 && !sObjectMgr->GetCreatureTemplate(cond->mConditionValue2)) - { - sLog->outErrorDb("SpellTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue2); - return false; - } - - const CreatureTemplate* cInfo = sObjectMgr->GetCreatureTemplate(cond->mConditionValue2); - if (cond->mSourceEntry == 30427 && !cInfo->SkinLootId) - { - sLog->outErrorDb("SpellTarget condition has creature entry %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!, skipped", cond->mConditionValue2); - return false; - } - break; - } - } + if (cond->ConditionValue2) + sLog->outErrorDb("Map condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Map condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_CREATURE_TARGET: + case CONDITION_SPELL: { - if (!cond->mConditionValue1 && !sObjectMgr->GetCreatureTemplate(cond->mConditionValue1)) + if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1)) { - sLog->outErrorDb("CreatureTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue1); + sLog->outErrorDb("Spell condition has non existing spell (Id: %d), skipped", cond->ConditionValue1); return false; } - if (cond->mConditionValue2) - sLog->outErrorDb("CreatureTarget condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue2) + sLog->outErrorDb("Spell condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Spell condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_TARGET_HEALTH_BELOW_PCT: + case CONDITION_LEVEL: { - if (cond->mConditionValue1 > 100) + if (cond->ConditionValue2 >= COMP_TYPE_MAX) { - sLog->outErrorDb("TargetHealthBelowPct condition has invalid data in value1 (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("Level condition has invalid option (%u), skipped", cond->ConditionValue2); return false; } - - if (cond->mConditionValue2) - sLog->outErrorDb("TargetHealthBelowPct condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Level condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_TARGET_RANGE: + case CONDITION_DRUNKENSTATE: { - if (cond->mConditionValue2 && cond->mConditionValue2 < cond->mConditionValue1)//maxDist can be 0 for infinit max range + if (cond->ConditionValue1 > DRUNKEN_SMASHED) + { + sLog->outErrorDb("DrunkState condition has invalid state (%u), skipped", cond->ConditionValue1); + return false; + } + if (cond->ConditionValue2) { - sLog->outErrorDb("TargetRange condition has max distance closer then min distance, skipped"); + sLog->outErrorDb("DrunkState condition has useless data in value2 (%u)!", cond->ConditionValue2); return false; } + if (cond->ConditionValue3) + sLog->outErrorDb("DrunkState condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_MAPID: + case CONDITION_NEAR_CREATURE: { - MapEntry const* me = sMapStore.LookupEntry(cond->mConditionValue1); - if (!me) + if (!sObjectMgr->GetCreatureTemplate(cond->ConditionValue1)) { - sLog->outErrorDb("Map condition has non existing map (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("NearCreature condition has non existing creature template entry (%u), skipped", cond->ConditionValue1); return false; } - - if (cond->mConditionValue2) - sLog->outErrorDb("Map condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("NearCreature condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_ITEM_TARGET: + case CONDITION_NEAR_GAMEOBJECT: { - if (!cond->mConditionValue1 || cond->mConditionValue1 > MAX_ITEM_REQ_TARGET_TYPE) + if (!sObjectMgr->GetGameObjectTemplate(cond->ConditionValue1)) { - sLog->outErrorDb("ItemTarget condition has incorrect target type (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("NearGameObject condition has non existing gameobject template entry (%u), skipped", cond->ConditionValue1); return false; } - - if (!cond->mConditionValue2 && !sObjectMgr->GetCreatureTemplate(cond->mConditionValue2)) + if (cond->ConditionValue3) + sLog->outErrorDb("NearGameObject condition has useless data in value3 (%u)!", cond->ConditionValue3); + break; + } + case CONDITION_OBJECT_ENTRY: + { + switch (cond->ConditionValue1) { - sLog->outErrorDb("ItemTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue2); - return false; + case TYPEID_UNIT: + if (cond->ConditionValue2 && !sObjectMgr->GetCreatureTemplate(cond->ConditionValue2)) + { + sLog->outErrorDb("ObjectEntry condition has non existing creature template entry (%u), skipped", cond->ConditionValue2); + return false; + } + break; + case TYPEID_GAMEOBJECT: + if (cond->ConditionValue2 && !sObjectMgr->GetGameObjectTemplate(cond->ConditionValue2)) + { + sLog->outErrorDb("ObjectEntry condition has non existing game object template entry (%u), skipped", cond->ConditionValue2); + return false; + } + break; + case TYPEID_PLAYER: + case TYPEID_CORPSE: + if (cond->ConditionValue2) + sLog->outErrorDb("ObjectEntry condition has useless data in value2 (%u)!", cond->ConditionValue2); + break; + default: + sLog->outErrorDb("ObjectEntry condition has wrong typeid set (%u), skipped", cond->ConditionValue1); + return false; } - - if (cond->mConditionValue3) - sLog->outErrorDb("ItemTarget condition has useless data in value3 (%u)!", cond->mConditionValue3); + if (cond->ConditionValue3) + sLog->outErrorDb("ObjectEntry condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_SPELL: + case CONDITION_TYPE_MASK: { - if (!sSpellMgr->GetSpellInfo(cond->mConditionValue1)) + if (!cond->ConditionValue1 || (cond->ConditionValue1 & ~(TYPEMASK_UNIT | TYPEMASK_PLAYER | TYPEMASK_GAMEOBJECT | TYPEMASK_CORPSE))) { - sLog->outErrorDb("Spell condition has non existing spell (Id: %d), skipped", cond->mConditionValue1); + sLog->outErrorDb("TypeMask condition has invalid typemask set (%u), skipped", cond->ConditionValue2); return false; } - - if (cond->mConditionValue2) - sLog->outErrorDb("Spell condition has useless data in value2 (%u)!", cond->mConditionValue2); + if (cond->ConditionValue2) + sLog->outErrorDb("TypeMask condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("TypeMask condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_NOITEM: + case CONDITION_RELATION_TO: { - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->mConditionValue1); - if (!proto) + if (cond->ConditionValue1 >= cond->GetMaxAvailableConditionTargets()) + { + sLog->outErrorDb("RelationTo condition has invalid ConditionValue1(ConditionTarget selection) (%u), skipped", cond->ConditionValue1); + return false; + } + if (cond->ConditionValue1 == cond->ConditionTarget) + { + sLog->outErrorDb("RelationTo condition has ConditionValue1(ConditionTarget selection) set to self (%u), skipped", cond->ConditionValue1); + return false; + } + if (cond->ConditionValue2 >= RELATION_MAX) { - sLog->outErrorDb("NoItem condition has non existing item (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("RelationTo condition has invalid ConditionValue2(RelationType) (%u), skipped", cond->ConditionValue2); return false; } + if (cond->ConditionValue3) + sLog->outErrorDb("RelationTo condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_LEVEL: + case CONDITION_REACTION_TO: { - if (cond->mConditionValue2 >= LVL_COND_MAX) + if (cond->ConditionValue1 >= cond->GetMaxAvailableConditionTargets()) + { + sLog->outErrorDb("ReactionTo condition has invalid ConditionValue1(ConditionTarget selection) (%u), skipped", cond->ConditionValue1); + return false; + } + if (cond->ConditionValue1 == cond->ConditionTarget) + { + sLog->outErrorDb("ReactionTo condition has ConditionValue1(ConditionTarget selection) set to self (%u), skipped", cond->ConditionValue1); + return false; + } + if (!cond->ConditionValue2) { - sLog->outErrorDb("Level condition has invalid option (%u), skipped", cond->mConditionValue2); + sLog->outErrorDb("mConditionValue2 condition has invalid ConditionValue2(rankMask) (%u), skipped", cond->ConditionValue2); return false; } break; } - case CONDITION_DRUNKENSTATE: + case CONDITION_DISTANCE_TO: { - if (cond->mConditionValue1 > DRUNKEN_SMASHED) + if (cond->ConditionValue1 >= cond->GetMaxAvailableConditionTargets()) + { + sLog->outErrorDb("DistanceTo condition has invalid ConditionValue1(ConditionTarget selection) (%u), skipped", cond->ConditionValue1); + return false; + } + if (cond->ConditionValue1 == cond->ConditionTarget) + { + sLog->outErrorDb("DistanceTo condition has ConditionValue1(ConditionTarget selection) set to self (%u), skipped", cond->ConditionValue1); + return false; + } + if (cond->ConditionValue3 >= COMP_TYPE_MAX) { - sLog->outErrorDb("DrunkState condition has invalid state (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("DistanceTo condition has invalid ComparisionType (%u), skipped", cond->ConditionValue3); return false; } break; } - case CONDITION_NEAR_CREATURE: + case CONDITION_ALIVE: + { + if (cond->ConditionValue1) + sLog->outErrorDb("Alive condition has useless data in value1 (%u)!", cond->ConditionValue1); + if (cond->ConditionValue2) + sLog->outErrorDb("Alive condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Alive condition has useless data in value3 (%u)!", cond->ConditionValue3); + break; + } + case CONDITION_HP_VAL: { - if (!sObjectMgr->GetCreatureTemplate(cond->mConditionValue1)) + if (cond->ConditionValue2 >= COMP_TYPE_MAX) { - sLog->outErrorDb("NearCreature condition has non existing creature template entry (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("HpVal condition has invalid ComparisionType (%u), skipped", cond->ConditionValue2); return false; } + if (cond->ConditionValue3) + sLog->outErrorDb("HpVal condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_NEAR_GAMEOBJECT: + case CONDITION_HP_PCT: { - if (!sObjectMgr->GetGameObjectTemplate(cond->mConditionValue1)) + if (cond->ConditionValue1 > 100) { - sLog->outErrorDb("NearGameObject condition has non existing gameobject template entry (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("HpPct condition has too big percent value (%u), skipped", cond->ConditionValue1); return false; } + if (cond->ConditionValue2 >= COMP_TYPE_MAX) + { + sLog->outErrorDb("HpPct condition has invalid ComparisionType (%u), skipped", cond->ConditionValue2); + return false; + } + if (cond->ConditionValue3) + sLog->outErrorDb("HpPct condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_AREAID: case CONDITION_INSTANCE_DATA: break; + case CONDITION_WORLD_STATE: + { + if (!sWorld->getWorldState(cond->ConditionValue1)) + { + sLog->outErrorDb("World state condition has non existing world state in value1 (%u), skipped", cond->ConditionValue1); + return false; + } + if (cond->ConditionValue3) + sLog->outErrorDb("World state condition has useless data in value3 (%u)!", cond->ConditionValue3); + break; + } + case CONDITION_PHASEMASK: + { + if (cond->ConditionValue2) + sLog->outErrorDb("Phasemask condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + sLog->outErrorDb("Phasemask condition has useless data in value3 (%u)!", cond->ConditionValue3); + break; + } + case CONDITION_UNUSED_18: + sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_18 in `conditions` table - ignoring"); + return false; + case CONDITION_UNUSED_19: + sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_19 in `conditions` table - ignoring"); + return false; + case CONDITION_UNUSED_20: + sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_20 in `conditions` table - ignoring"); + return false; + case CONDITION_UNUSED_21: + sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_21 in `conditions` table - ignoring"); + return false; + case CONDITION_UNUSED_24: + sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_24 in `conditions` table - ignoring"); + return false; default: break; } @@ -1434,7 +1903,7 @@ void ConditionMgr::Clean() ConditionStore.clear(); - for (VehicleSpellConditionContainer::iterator itr = VehicleSpellConditionStore.begin(); itr != VehicleSpellConditionStore.end(); ++itr) + for (CreatureSpellConditionContainer::iterator itr = VehicleSpellConditionStore.begin(); itr != VehicleSpellConditionStore.end(); ++itr) { for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) { |