/* * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version. * Copyright (C) 2008-2016 TrinityCore * Copyright (C) 2005-2009 MaNGOS */ #include "AchievementMgr.h" #include "ConditionMgr.h" #include "GameEventMgr.h" #include "InstanceScript.h" #include "ObjectMgr.h" #include "Player.h" #include "ReputationMgr.h" #include "ScriptedCreature.h" #include "ScriptMgr.h" #include "Spell.h" #include "SpellAuras.h" #include "SpellMgr.h" // Checks if object meets the condition // Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI) bool Condition::Meets(ConditionSourceInfo& sourceInfo) { ASSERT(ConditionTarget < MAX_CONDITION_TARGETS); WorldObject* object = sourceInfo.mConditionTargets[ConditionTarget]; // object not present, return false if (!object) { LOG_DEBUG("condition", "Condition object not found for condition (Entry: %u Type: %u Group: %u)", SourceEntry, SourceType, SourceGroup); return false; } bool condMeets = false; switch (ConditionType) { case CONDITION_NONE: condMeets = true; // empty condition, always met break; case CONDITION_AURA: { if (Unit* unit = object->ToUnit()) condMeets = unit->HasAuraEffect(ConditionValue1, ConditionValue2); break; } case CONDITION_ITEM: { if (Player* player = object->ToPlayer()) { // don't allow 0 items (it's checked during table load) ASSERT(ConditionValue2); bool checkBank = !!ConditionValue3; condMeets = player->HasItemCount(ConditionValue1, ConditionValue2, checkBank); } break; } case CONDITION_ITEM_EQUIPPED: { if (Player* player = object->ToPlayer()) condMeets = player->HasItemOrGemWithIdEquipped(ConditionValue1, 1); break; } case CONDITION_ZONEID: condMeets = object->GetZoneId() == ConditionValue1; break; case CONDITION_REPUTATION_RANK: { if (Player* player = object->ToPlayer()) { if (FactionEntry const* faction = sFactionStore.LookupEntry(ConditionValue1)) condMeets = (ConditionValue2 & (1 << player->GetReputationMgr().GetRank(faction))); } break; } case CONDITION_ACHIEVEMENT: { if (Player* player = object->ToPlayer()) condMeets = player->HasAchieved(ConditionValue1); break; } case CONDITION_TEAM: { if (Player* player = object->ToPlayer()) { // Xinef: DB Data compatibility... uint32 teamOld = player->GetTeamId() == TEAM_ALLIANCE ? ALLIANCE : HORDE; condMeets = teamOld == ConditionValue1; } break; } case CONDITION_CLASS: { if (Unit* unit = object->ToUnit()) condMeets = unit->getClassMask() & ConditionValue1; break; } case CONDITION_RACE: { if (Unit* unit = object->ToUnit()) condMeets = unit->getRaceMask() & ConditionValue1; break; } case CONDITION_GENDER: { if (Player* player = object->ToPlayer()) condMeets = player->getGender() == ConditionValue1; break; } case CONDITION_SKILL: { if (Player* player = object->ToPlayer()) condMeets = player->HasSkill(ConditionValue1) && player->GetBaseSkillValue(ConditionValue1) >= ConditionValue2; break; } case CONDITION_QUESTREWARDED: { if (Player* player = object->ToPlayer()) condMeets = player->GetQuestRewardStatus(ConditionValue1); break; } case CONDITION_QUESTTAKEN: { if (Player* player = object->ToPlayer()) { QuestStatus status = player->GetQuestStatus(ConditionValue1); condMeets = (status == QUEST_STATUS_INCOMPLETE); } break; } case CONDITION_QUEST_COMPLETE: { if (Player* player = object->ToPlayer()) { QuestStatus status = player->GetQuestStatus(ConditionValue1); condMeets = (status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(ConditionValue1)); } break; } case CONDITION_QUEST_NONE: { if (Player* player = object->ToPlayer()) { QuestStatus status = player->GetQuestStatus(ConditionValue1); condMeets = (status == QUEST_STATUS_NONE); } break; } case CONDITION_QUEST_SATISFY_EXCLUSIVE: { if (Player* player = object->ToPlayer()) { // Xinef: cannot be null, checked at loading const Quest* quest = sObjectMgr->GetQuestTemplate(ConditionValue1); condMeets = !player->IsQuestRewarded(ConditionValue1) && player->SatisfyQuestExclusiveGroup(quest, false); } break; } case CONDITION_ACTIVE_EVENT: condMeets = sGameEventMgr->IsActiveEvent(ConditionValue1); break; case CONDITION_INSTANCE_INFO: { Map* map = object->GetMap(); if (map->IsDungeon()) { if (InstanceScript const* instance = map->ToInstanceMap()->GetInstanceScript()) { switch (ConditionValue3) { case INSTANCE_INFO_DATA: condMeets = instance->GetData(ConditionValue1) == ConditionValue2; break; case INSTANCE_INFO_GUID_DATA: condMeets = instance->GetGuidData(ConditionValue1) == ObjectGuid(uint64(ConditionValue2)); break; case INSTANCE_INFO_BOSS_STATE: condMeets = instance->GetBossState(ConditionValue1) == EncounterState(ConditionValue2); break; case INSTANCE_INFO_DATA64: condMeets = instance->GetData64(ConditionValue1) == ConditionValue2; break; } } } break; } case CONDITION_MAPID: condMeets = object->GetMapId() == ConditionValue1; break; case CONDITION_AREAID: condMeets = object->GetAreaId() == ConditionValue1; break; case CONDITION_SPELL: { if (Player* player = object->ToPlayer()) condMeets = player->HasSpell(ConditionValue1); break; } case CONDITION_LEVEL: { if (Unit* unit = object->ToUnit()) condMeets = CompareValues(static_cast(ConditionValue2), static_cast(unit->getLevel()), ConditionValue1); break; } case CONDITION_DRUNKENSTATE: { if (Player* player = object->ToPlayer()) condMeets = (uint32)Player::GetDrunkenstateByValue(player->GetDrunkValue()) >= ConditionValue1; break; } case CONDITION_NEAR_CREATURE: { condMeets = static_cast(GetClosestCreatureWithEntry(object, ConditionValue1, static_cast(ConditionValue2),!ConditionValue3)); break; } case CONDITION_NEAR_GAMEOBJECT: { condMeets = static_cast(GetClosestGameObjectWithEntry(object, ConditionValue1, static_cast(ConditionValue2))); break; } case CONDITION_OBJECT_ENTRY_GUID: { if (ConditionValue3 == 1 && object->ToUnit()) // pussywizard: if == 1, ignore not attackable/selectable targets if (object->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) break; if (uint32(object->GetTypeId()) == ConditionValue1) { condMeets = !ConditionValue2 || (object->GetEntry() == ConditionValue2); if (ConditionValue3 > 1) { switch (object->GetTypeId()) { case TYPEID_UNIT: condMeets &= object->ToCreature()->GetSpawnId() == ConditionValue3; break; case TYPEID_GAMEOBJECT: condMeets &= object->ToGameObject()->GetSpawnId() == ConditionValue3; break; default: break; } } } break; } case CONDITION_TYPE_MASK: { condMeets = object->isType(ConditionValue1); break; } 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; case RELATION_CREATED_BY: condMeets = unit->GetCreatorGUID() == toUnit->GetGUID(); break; } } } break; } case CONDITION_REACTION_TO: { if (WorldObject* toObject = sourceInfo.mConditionTargets[ConditionValue1]) { Unit* toUnit = toObject->ToUnit(); Unit* unit = object->ToUnit(); if (toUnit && unit) condMeets = (1 << unit->GetReactionTo(toUnit)) & ConditionValue2; } break; } case CONDITION_DISTANCE_TO: { if (WorldObject* toObject = sourceInfo.mConditionTargets[ConditionValue1]) condMeets = CompareValues(static_cast(ConditionValue3), object->GetDistance(toObject), static_cast(ConditionValue2)); break; } case CONDITION_ALIVE: { if (Unit* unit = object->ToUnit()) condMeets = unit->IsAlive(); break; } case CONDITION_HP_VAL: { if (Unit* unit = object->ToUnit()) condMeets = CompareValues(static_cast(ConditionValue2), unit->GetHealth(), static_cast(ConditionValue1)); break; } case CONDITION_HP_PCT: { if (Unit* unit = object->ToUnit()) condMeets = CompareValues(static_cast(ConditionValue2), unit->GetHealthPct(), static_cast(ConditionValue1)); break; } case CONDITION_WORLD_STATE: { condMeets = ConditionValue2 == sWorld->getWorldState(ConditionValue1); break; } case CONDITION_PHASEMASK: { condMeets = object->GetPhaseMask() & ConditionValue1; break; } case CONDITION_TITLE: { if (Player* player = object->ToPlayer()) condMeets = player->HasTitle(ConditionValue1); break; } case CONDITION_SPAWNMASK: { condMeets = ((1 << object->GetMap()->GetSpawnMode()) & ConditionValue1); break; } case CONDITION_UNIT_STATE: { if (Unit* unit = object->ToUnit()) condMeets = unit->HasUnitState(ConditionValue1); break; } case CONDITION_CREATURE_TYPE: { if (Creature* creature = object->ToCreature()) condMeets = creature->GetCreatureTemplate()->type == ConditionValue1; break; } case CONDITION_REALM_ACHIEVEMENT: { AchievementEntry const* achievement = sAchievementStore.LookupEntry(ConditionValue1); if (achievement && sAchievementMgr->IsRealmCompleted(achievement)) condMeets = true; break; } case CONDITION_IN_WATER: { if (Unit* unit = object->ToUnit()) condMeets = unit->IsInWater(); break; } case CONDITION_QUESTSTATE: { if (Player* player = object->ToPlayer()) { uint32 queststateConditionValue1 = player->GetQuestStatus(ConditionValue1); if ( ((ConditionValue2 & (1 << QUEST_STATUS_NONE)) && (queststateConditionValue1 == QUEST_STATUS_NONE)) || ((ConditionValue2 & (1 << QUEST_STATUS_COMPLETE)) && (queststateConditionValue1 == QUEST_STATUS_COMPLETE)) || ((ConditionValue2 & (1 << QUEST_STATUS_INCOMPLETE)) && (queststateConditionValue1 == QUEST_STATUS_INCOMPLETE)) || ((ConditionValue2 & (1 << QUEST_STATUS_FAILED)) && (queststateConditionValue1 == QUEST_STATUS_FAILED)) || ((ConditionValue2 & (1 << QUEST_STATUS_REWARDED)) && player->GetQuestRewardStatus(ConditionValue1)) ) { condMeets = true; } } break; } case CONDITION_DAILY_QUEST_DONE: { if (Player* player = object->ToPlayer()) { condMeets = player->IsDailyQuestDone(ConditionValue1); } break; } case CONDITION_QUEST_OBJECTIVE_PROGRESS: { if (Player* player = object->ToPlayer()) { const Quest* quest = ASSERT_NOTNULL(sObjectMgr->GetQuestTemplate(ConditionValue1)); uint16 log_slot = player->FindQuestSlot(quest->GetQuestId()); if (log_slot >= MAX_QUEST_LOG_SIZE) break; if (player->GetQuestSlotCounter(log_slot, ConditionValue2) == ConditionValue3) condMeets = true; } break; } case CONDITION_HAS_AURA_TYPE: { if (Unit* unit = object->ToUnit()) condMeets = unit->HasAuraType(AuraType(ConditionValue1)); break; } default: condMeets = false; break; } if (NegativeCondition) condMeets = !condMeets; if (!condMeets) sourceInfo.mLastFailedCondition = this; //bool script = sScriptMgr->OnConditionCheck(this, sourceInfo); // Returns true by default. // pussywizard: optimization 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_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_QUEST_SATISFY_EXCLUSIVE: mask |= GRID_MAP_TYPE_MASK_PLAYER; break; case CONDITION_ACTIVE_EVENT: mask |= GRID_MAP_TYPE_MASK_ALL; break; case CONDITION_INSTANCE_INFO: 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_GUID: 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; } 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; case CONDITION_TITLE: mask |= GRID_MAP_TYPE_MASK_PLAYER; break; case CONDITION_SPAWNMASK: mask |= GRID_MAP_TYPE_MASK_ALL; break; case CONDITION_GENDER: mask |= GRID_MAP_TYPE_MASK_PLAYER; break; case CONDITION_UNIT_STATE: mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; break; case CONDITION_CREATURE_TYPE: mask |= GRID_MAP_TYPE_MASK_CREATURE; break; case CONDITION_REALM_ACHIEVEMENT: mask |= GRID_MAP_TYPE_MASK_ALL; break; case CONDITION_IN_WATER: mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; break; case CONDITION_QUESTSTATE: mask |= GRID_MAP_TYPE_MASK_PLAYER; break; case CONDITION_DAILY_QUEST_DONE: mask |= GRID_MAP_TYPE_MASK_PLAYER; break; case CONDITION_QUEST_OBJECTIVE_PROGRESS: mask |= GRID_MAP_TYPE_MASK_PLAYER; break; case CONDITION_HAS_AURA_TYPE: mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; break; default: ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!"); break; } return mask; } uint32 Condition::GetMaxAvailableConditionTargets() { // returns number of targets which are available for given source type switch(SourceType) { case CONDITION_SOURCE_TYPE_SMART_EVENT: return 3; 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_NPC_VENDOR: case CONDITION_SOURCE_TYPE_SPELL_PROC: return 2; default: return 1; } } ConditionMgr::ConditionMgr() { } ConditionMgr::~ConditionMgr() { Clean(); } ConditionMgr* ConditionMgr::instance() { static ConditionMgr instance; return &instance; } ConditionList ConditionMgr::GetConditionReferences(uint32 refId) { ConditionList conditions; ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find(refId); if (ref != ConditionReferenceStore.end()) conditions = (*ref).second; return conditions; } uint32 ConditionMgr::GetSearcherTypeMaskForConditionList(ConditionList const& conditions) { if (conditions.empty()) return GRID_MAP_TYPE_MASK_ALL; // groupId, typeMask std::map 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::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::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 ElseGroupStore; for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i) { LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList condType: %u val1: %u", (*i)->ConditionType, (*i)->ConditionValue1); if ((*i)->isLoaded()) { //! Find ElseGroup in ElseGroupStore std::map::const_iterator itr = ElseGroupStore.find((*i)->ElseGroup); //! If not found, add an entry in the store and set to true (placeholder) if (itr == ElseGroupStore.end()) ElseGroupStore[(*i)->ElseGroup] = true; else if (!(*itr).second) continue; if ((*i)->ReferenceId)//handle reference { ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find((*i)->ReferenceId); if (ref != ConditionReferenceStore.end()) { if (!IsObjectMeetToConditionList(sourceInfo, (*ref).second)) ElseGroupStore[(*i)->ElseGroup] = false; } else { LOG_DEBUG("condition", "IsPlayerMeetToConditionList: Reference template -%u not found", (*i)->ReferenceId); } } else //handle normal condition { if (!(*i)->Meets(sourceInfo)) ElseGroupStore[(*i)->ElseGroup] = false; } } } for (std::map::const_iterator i = ElseGroupStore.begin(); i != ElseGroupStore.end(); ++i) if (i->second) return true; return false; } 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; LOG_DEBUG("condition", "ConditionMgr::IsObjectMeetToConditions"); return IsObjectMeetToConditionList(sourceInfo, conditions); } 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 || sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR); } bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) const { return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT); } ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) { ConditionList spellCond; if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX) { ConditionContainer::const_iterator itr = ConditionStore.find(sourceType); if (itr != ConditionStore.end()) { ConditionTypeContainer::const_iterator i = (*itr).second.find(entry); if (i != (*itr).second.end()) { spellCond = (*i).second; LOG_DEBUG("condition", "GetConditionsForNotGroupedEntry: found conditions for type %u and entry %u", uint32(sourceType), entry); } } } return spellCond; } ConditionList ConditionMgr::GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) { ConditionList cond; 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; LOG_DEBUG("condition", "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); if (i != (*itr).second.end()) { cond = (*i).second; LOG_DEBUG("condition", "GetConditionsForVehicleSpell: found conditions for Vehicle entry %u spell %u", creatureId, spellId); } } return cond; } ConditionList ConditionMgr::GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType) { ConditionList cond; 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; LOG_DEBUG("condition", "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid %d event_id %u", entryOrGuid, eventId); } } return cond; } ConditionList ConditionMgr::GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId) { ConditionList cond; NpcVendorConditionContainer::const_iterator itr = NpcVendorConditionContainerStore.find(creatureId); if (itr != NpcVendorConditionContainerStore.end()) { ConditionTypeContainer::const_iterator i = (*itr).second.find(itemId); if (i != (*itr).second.end()) { cond = (*i).second; LOG_DEBUG("condition", "GetConditionsForNpcVendorEvent: found conditions for creature entry %u item %u", creatureId, itemId); } } return cond; } void ConditionMgr::LoadConditions(bool isReload) { uint32 oldMSTime = getMSTime(); Clean(); //must clear all custom handled cases (groupped types) before reload if (isReload) { LOG_INFO("server.loading", "Reseting Loot Conditions..."); LootTemplates_Creature.ResetConditions(); LootTemplates_Fishing.ResetConditions(); LootTemplates_Gameobject.ResetConditions(); LootTemplates_Item.ResetConditions(); LootTemplates_Mail.ResetConditions(); LootTemplates_Milling.ResetConditions(); LootTemplates_Pickpocketing.ResetConditions(); LootTemplates_Reference.ResetConditions(); LootTemplates_Skinning.ResetConditions(); LootTemplates_Disenchant.ResetConditions(); LootTemplates_Prospecting.ResetConditions(); LootTemplates_Spell.ResetConditions(); LOG_INFO("server.loading", "Re-Loading `gossip_menu` Table for Conditions!"); sObjectMgr->LoadGossipMenu(); LOG_INFO("server.loading", "Re-Loading `gossip_menu_option` Table for Conditions!"); sObjectMgr->LoadGossipMenuItems(); sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists(); } QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, " " ConditionValue1, ConditionValue2, ConditionValue3, NegativeCondition, ErrorType, ErrorTextId, ScriptName FROM conditions"); if (!result) { LOG_ERROR("server.loading", ">> Loaded 0 conditions. DB table `conditions` is empty!"); return; } uint32 count = 0; do { Field* fields = result->Fetch(); Condition* cond = new Condition(); int32 iSourceTypeOrReferenceId = fields[0].GetInt32(); cond->SourceGroup = fields[1].GetUInt32(); cond->SourceEntry = fields[2].GetInt32(); cond->SourceId = fields[3].GetInt32(); cond->ElseGroup = fields[4].GetUInt32(); int32 iConditionTypeOrReference = fields[5].GetInt32(); 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->ErrorType = fields[11].GetUInt32(); cond->ErrorTextId = fields[12].GetUInt32(); cond->ScriptId = sObjectMgr->GetScriptId(fields[13].GetCString()); if (iConditionTypeOrReference >= 0) cond->ConditionType = ConditionTypes(iConditionTypeOrReference); if (iSourceTypeOrReferenceId >= 0) cond->SourceType = ConditionSourceType(iSourceTypeOrReferenceId); if (iConditionTypeOrReference < 0)//it has a reference { if (iConditionTypeOrReference == iSourceTypeOrReferenceId)//self referencing, skip { LOG_ERROR("sql.sql", "Condition reference %i is referencing self, skipped", iSourceTypeOrReferenceId); delete cond; continue; } cond->ReferenceId = uint32(abs(iConditionTypeOrReference)); const char* rowType = "reference template"; if (iSourceTypeOrReferenceId >= 0) rowType = "reference"; //check for useless data if (cond->ConditionTarget) LOG_ERROR("sql.sql", "Condition %s %i has useless data in ConditionTarget (%u)!", rowType, iSourceTypeOrReferenceId, cond->ConditionTarget); if (cond->ConditionValue1) LOG_ERROR("sql.sql", "Condition %s %i has useless data in value1 (%u)!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue1); if (cond->ConditionValue2) LOG_ERROR("sql.sql", "Condition %s %i has useless data in value2 (%u)!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Condition %s %i has useless data in value3 (%u)!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue3); if (cond->NegativeCondition) LOG_ERROR("sql.sql", "Condition %s %i has useless data in NegativeCondition (%u)!", rowType, iSourceTypeOrReferenceId, cond->NegativeCondition); if (cond->SourceGroup && iSourceTypeOrReferenceId < 0) LOG_ERROR("sql.sql", "Condition %s %i has useless data in SourceGroup (%u)!", rowType, iSourceTypeOrReferenceId, cond->SourceGroup); if (cond->SourceEntry && iSourceTypeOrReferenceId < 0) LOG_ERROR("sql.sql", "Condition %s %i has useless data in SourceEntry (%u)!", rowType, iSourceTypeOrReferenceId, cond->SourceEntry); } else if (!isConditionTypeValid(cond))//doesn't have reference, validate ConditionType { delete cond; continue; } if (iSourceTypeOrReferenceId < 0)//it is a reference template { uint32 uRefId = abs(iSourceTypeOrReferenceId); if (ConditionReferenceStore.find(uRefId) == ConditionReferenceStore.end())//make sure we have a list for our conditions, based on reference id { ConditionList mCondList; ConditionReferenceStore[uRefId] = mCondList; } ConditionReferenceStore[uRefId].push_back(cond);//add to reference storage count++; continue; }//end of reference templates //if not a reference and SourceType is invalid, skip if (iConditionTypeOrReference >= 0 && !isSourceTypeValid(cond)) { delete cond; continue; } //Grouping is only allowed for some types (loot templates, gossip menus, gossip items) if (cond->SourceGroup && !CanHaveSourceGroupSet(cond->SourceType)) { LOG_ERROR("sql.sql", "Condition type %u has not allowed value of SourceGroup = %u!", uint32(cond->SourceType), cond->SourceGroup); delete cond; continue; } if (cond->SourceId && !CanHaveSourceIdSet(cond->SourceType)) { LOG_ERROR("sql.sql", "Condition type %u has not allowed value of SourceId = %u!", uint32(cond->SourceType), cond->SourceId); delete cond; continue; } if (cond->ErrorType && cond->SourceType != CONDITION_SOURCE_TYPE_SPELL) { LOG_ERROR("condition", "Condition type %u entry %i can't have ErrorType (%u), set to 0!", uint32(cond->SourceType), cond->SourceEntry, cond->ErrorType); cond->ErrorType = 0; } if (cond->ErrorTextId && !cond->ErrorType) { LOG_ERROR("condition", "Condition type %u entry %i has any ErrorType, ErrorTextId (%u) is set, set to 0!", uint32(cond->SourceType), cond->SourceEntry, cond->ErrorTextId); cond->ErrorTextId = 0; } if (cond->SourceGroup) { bool valid = false; // handle grouped conditions switch (cond->SourceType) { case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Creature.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Disenchant.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Fishing.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Gameobject.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Item.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Mail.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Milling.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Pickpocketing.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Prospecting.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Reference.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Skinning.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE: valid = addToLootTemplate(cond, LootTemplates_Spell.GetLootForConditionFill(cond->SourceGroup)); break; case CONDITION_SOURCE_TYPE_GOSSIP_MENU: valid = addToGossipMenus(cond); break; case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: valid = addToGossipMenuItems(cond); break; case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT: { SpellClickEventConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); valid = true; ++count; continue; // do not add to m_AllocatedMemory to avoid double deleting } case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET: valid = addToSpellImplicitTargetConditions(cond); break; case CONDITION_SOURCE_TYPE_VEHICLE_SPELL: { VehicleSpellConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); valid = true; ++count; continue; // do not add to m_AllocatedMemory to avoid double deleting } case CONDITION_SOURCE_TYPE_SMART_EVENT: { //! TODO: PAIR_32 ? std::pair key = std::make_pair(cond->SourceEntry, cond->SourceId); SmartEventConditionStore[key][cond->SourceGroup].push_back(cond); valid = true; ++count; continue; } case CONDITION_SOURCE_TYPE_NPC_VENDOR: { NpcVendorConditionContainerStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); valid = true; ++count; continue; } default: break; } if (!valid) { LOG_ERROR("sql.sql", "Not handled grouped condition, SourceGroup %u", cond->SourceGroup); delete cond; } else { AllocatedMemoryStore.push_back(cond); ++count; } continue; } //handle not grouped conditions //make sure we have a storage list for our SourceType if (ConditionStore.find(cond->SourceType) == ConditionStore.end()) { ConditionTypeContainer mTypeMap; 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->SourceType].find(cond->SourceEntry) == ConditionStore[cond->SourceType].end()) { ConditionList mCondList; ConditionStore[cond->SourceType][cond->SourceEntry] = mCondList; } //add new Condition to storage based on Type/Entry ConditionStore[cond->SourceType][cond->SourceEntry].push_back(cond); ++count; } while (result->NextRow()); LOG_INFO("server.loading", ">> Loaded %u conditions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); LOG_INFO("server.loading", " "); } bool ConditionMgr::addToLootTemplate(Condition* cond, LootTemplate* loot) { if (!loot) { LOG_ERROR("sql.sql", "ConditionMgr: LootTemplate %u not found", cond->SourceGroup); return false; } if (loot->addConditionItem(cond)) return true; LOG_ERROR("sql.sql", "ConditionMgr: Item %u not found in LootTemplate %u", cond->SourceEntry, cond->SourceGroup); return false; } bool ConditionMgr::addToGossipMenus(Condition* cond) { GossipMenusMapBoundsNonConst pMenuBounds = sObjectMgr->GetGossipMenusMapBoundsNonConst(cond->SourceGroup); if (pMenuBounds.first != pMenuBounds.second) { for (GossipMenusContainer::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr) { if ((*itr).second.MenuID == cond->SourceGroup && (*itr).second.TextID == uint32(cond->SourceEntry)) { (*itr).second.Conditions.push_back(cond); return true; } } } LOG_ERROR("sql.sql", "addToGossipMenus: GossipMenu %u not found", cond->SourceGroup); return false; } bool ConditionMgr::addToGossipMenuItems(Condition* cond) { GossipMenuItemsMapBoundsNonConst pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBoundsNonConst(cond->SourceGroup); if (pMenuItemBounds.first != pMenuItemBounds.second) { for (GossipMenuItemsContainer::iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr) { if ((*itr).second.MenuID == cond->SourceGroup && (*itr).second.OptionID == uint32(cond->SourceEntry)) { (*itr).second.Conditions.push_back(cond); return true; } } } LOG_ERROR("sql.sql", "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(sSpellMgr->AssertSpellInfo(cond->SourceEntry)); std::list 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::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::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; if (firstEffIndex >= MAX_SPELL_EFFECTS) return false; // 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) { LOG_ERROR("sql.sql", "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(); bool assigned = false; for (uint8 i = firstEffIndex; i < MAX_SPELL_EFFECTS; ++i) { if ((1 << i) & commonMask) { spellInfo->Effects[i].ImplicitTargetConditions = sharedList; assigned = true; } } if (!assigned) delete sharedList; } if (sharedList) sharedList->push_back(cond); break; } } return true; } bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (cond->SourceType == CONDITION_SOURCE_TYPE_NONE || cond->SourceType >= CONDITION_SOURCE_TYPE_MAX) { LOG_ERROR("sql.sql", "Invalid ConditionSourceType %u in `condition` table, ignoring.", uint32(cond->SourceType)); return false; } switch (cond->SourceType) { case CONDITION_SOURCE_TYPE_TERRAIN_SWAP: case CONDITION_SOURCE_TYPE_PHASE: case CONDITION_SOURCE_TYPE_GRAVEYARD: { LOG_ERROR("sql.sql", "ConditionSourceType %u in `condition` table is not supported on 3.3.5a, ignoring.", uint32(cond->SourceType)); return false; } case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: { if (!LootTemplates_Creature.HaveLootFor(cond->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `creature_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Creature.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Disenchant.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `fishing_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Fishing.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Gameobject.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `item_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Item.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `mail_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Mail.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `milling_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Milling.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Pickpocketing.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Prospecting.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `reference_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Reference.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `skinning_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Skinning.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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->SourceGroup)) { LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `spell_loot_template`, ignoring.", cond->SourceGroup); return false; } LootTemplate* loot = LootTemplates_Spell.GetLootForConditionFill(cond->SourceGroup); ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { LOG_ERROR("sql.sql", "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_IMPLICIT_TARGET: { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->SourceEntry); if (!spellInfo) { LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); return false; } if ((cond->SourceGroup > MAX_EFFECT_MASK) || !cond->SourceGroup) { LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set , ignoring.", cond->SourceEntry, cond->SourceGroup); return false; } uint32 origGroup = cond->SourceGroup; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (!((1 << i) & cond->SourceGroup)) continue; switch (spellInfo->Effects[i].TargetA.GetSelectionCategory()) { case TARGET_SELECT_CATEGORY_NEARBY: case TARGET_SELECT_CATEGORY_CONE: case TARGET_SELECT_CATEGORY_AREA: case TARGET_SELECT_CATEGORY_TRAJ: continue; default: break; } switch (spellInfo->Effects[i].TargetB.GetSelectionCategory()) { case TARGET_SELECT_CATEGORY_NEARBY: case TARGET_SELECT_CATEGORY_CONE: case TARGET_SELECT_CATEGORY_AREA: case TARGET_SELECT_CATEGORY_TRAJ: continue; default: break; } // Xinef: chain targets are treated as area targets! Apply conditions! if (spellInfo->Effects[i].ChainTarget > 1) continue; LOG_ERROR("sql.sql", "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); } // 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->SourceEntry)) { LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_SPELL: case CONDITION_SOURCE_TYPE_SPELL_PROC: { SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->SourceEntry); if (!spellProto) { LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_QUEST_AVAILABLE: if (!sObjectMgr->GetQuestTemplate(cond->SourceEntry)) { LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_QUEST_AVAILABLE specifies non-existing quest (%u), skipped", cond->SourceEntry); return false; } break; case CONDITION_SOURCE_TYPE_UNUSED_20: LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_UNUSED_20 is not in use. SourceEntry = (%u), skipped", cond->SourceEntry); break; case CONDITION_SOURCE_TYPE_VEHICLE_SPELL: case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT: if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup)) { LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->SourceGroup); return false; } if (!sSpellMgr->GetSpellInfo(cond->SourceEntry)) { LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); return false; } break; case CONDITION_SOURCE_TYPE_NPC_VENDOR: { if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup)) { LOG_ERROR("condition", "SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->SourceGroup); return false; } ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!itemTemplate) { LOG_ERROR("condition", "SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceEntry); return false; } break; } case CONDITION_SOURCE_TYPE_GOSSIP_MENU: case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: case CONDITION_SOURCE_TYPE_SMART_EVENT: case CONDITION_SOURCE_TYPE_NONE: default: break; } return true; } bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (cond->ConditionType == CONDITION_NONE || (cond->ConditionType >= CONDITION_TC_END && cond->ConditionType <= CONDITION_AC_START) || (cond->ConditionType >= CONDITION_AC_END) ) { LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table has an invalid ConditionType (%u), ignoring.", cond->SourceEntry, uint32(cond->ConditionType)); return false; } switch (cond->ConditionType) { case CONDITION_TERRAIN_SWAP: case CONDITION_DIFFICULTY_ID: LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table has a ConditionType that is not supported on 3.3.5a (%u), ignoring.", cond->SourceEntry, uint32(cond->ConditionType)); return false; case CONDITION_STAND_STATE: case CONDITION_CHARMED: case CONDITION_PET_TYPE: case CONDITION_TAXI: LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table has a ConditionType that is not yet supported on AzerothCore (%u), ignoring.", cond->SourceEntry, uint32(cond->ConditionType)); return false; default: break; } if (cond->ConditionTarget >= cond->GetMaxAvailableConditionTargets()) { LOG_ERROR("sql.sql", "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->ConditionValue1)) { LOG_ERROR("sql.sql", "Aura condition has non existing spell (Id: %d), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2 > EFFECT_2) { LOG_ERROR("sql.sql", "Aura condition has non existing effect index (%u) (must be 0..2), skipped", cond->ConditionValue2); return false; } if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Aura condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ITEM: { ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1); if (!proto) { LOG_ERROR("sql.sql", "Item condition has non existing item (%u), skipped", cond->ConditionValue1); return false; } if (!cond->ConditionValue2) { LOG_ERROR("sql.sql", "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->ConditionValue1); if (!proto) { LOG_ERROR("sql.sql", "ItemEquipped condition has non existing item (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2) LOG_ERROR("sql.sql", "ItemEquipped condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "ItemEquipped condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ZONEID: { AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(cond->ConditionValue1); if (!areaEntry) { LOG_ERROR("sql.sql", "ZoneID condition has non existing area (%u), skipped", cond->ConditionValue1); return false; } if (areaEntry->zone != 0) { LOG_ERROR("sql.sql", "ZoneID condition requires to be in area (%u) which is a subzone but zone expected, skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2) LOG_ERROR("sql.sql", "ZoneID condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "ZoneID condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_REPUTATION_RANK: { FactionEntry const* factionEntry = sFactionStore.LookupEntry(cond->ConditionValue1); if (!factionEntry) { LOG_ERROR("sql.sql", "Reputation condition has non existing faction (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Reputation condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_TEAM: { if (cond->ConditionValue1 != ALLIANCE && cond->ConditionValue1 != HORDE) { LOG_ERROR("sql.sql", "Team condition specifies unknown team (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2) LOG_ERROR("sql.sql", "Team condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Team condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_SKILL: { SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(cond->ConditionValue1); if (!pSkill) { LOG_ERROR("sql.sql", "Skill condition specifies non-existing skill (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2 < 1 || cond->ConditionValue2 > sWorld->GetConfigMaxSkillValue()) { LOG_ERROR("sql.sql", "Skill condition specifies invalid skill value (%u), skipped", cond->ConditionValue2); return false; } if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Skill condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_QUESTREWARDED: case CONDITION_QUESTTAKEN: case CONDITION_QUEST_NONE: case CONDITION_QUEST_COMPLETE: case CONDITION_DAILY_QUEST_DONE: case CONDITION_QUEST_SATISFY_EXCLUSIVE: { if (!sObjectMgr->GetQuestTemplate(cond->ConditionValue1)) { LOG_ERROR("sql.sql", "Quest condition specifies non-existing quest (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2 > 1) { LOG_ERROR("sql.sql", "Quest condition has useless data in value2 (%u)!", cond->ConditionValue2); } if (cond->ConditionValue3) { LOG_ERROR("sql.sql", "Quest condition has useless data in value3 (%u)!", cond->ConditionValue3); } break; } case CONDITION_QUESTSTATE: if (cond->ConditionValue2 >= (1 << MAX_QUEST_STATUS)) { LOG_ERROR("sql.sql", "ConditionType (%u) has invalid state mask (%u), skipped.", cond->ConditionType, cond->ConditionValue2); return false; } break; case CONDITION_ACTIVE_EVENT: { GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap(); if (cond->ConditionValue1 >= events.size() || !events[cond->ConditionValue1].isValid()) { LOG_ERROR("sql.sql", "ActiveEvent condition has non existing event id (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2) LOG_ERROR("sql.sql", "ActiveEvent condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "ActiveEvent condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ACHIEVEMENT: { AchievementEntry const* achievement = sAchievementStore.LookupEntry(cond->ConditionValue1); if (!achievement) { LOG_ERROR("sql.sql", "Achivement condition has non existing achivement id (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2) LOG_ERROR("sql.sql", "Achivement condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Achivement condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_CLASS: { if (!(cond->ConditionValue1 & CLASSMASK_ALL_PLAYABLE)) { LOG_ERROR("sql.sql", "Class condition has non existing classmask (%u), skipped", cond->ConditionValue1 & ~CLASSMASK_ALL_PLAYABLE); return false; } if (cond->ConditionValue2) LOG_ERROR("sql.sql", "Class condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Class condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_RACE: { if (!(cond->ConditionValue1 & RACEMASK_ALL_PLAYABLE)) { LOG_ERROR("sql.sql", "Race condition has non existing racemask (%u), skipped", cond->ConditionValue1 & ~RACEMASK_ALL_PLAYABLE); return false; } if (cond->ConditionValue2) LOG_ERROR("sql.sql", "Race condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Race condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_GENDER: { if (!Player::IsValidGender(uint8(cond->ConditionValue1))) { LOG_ERROR("condition", "Gender condition has invalid gender (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2) LOG_ERROR("condition", "Gender condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("condition", "Gender condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_MAPID: { MapEntry const* me = sMapStore.LookupEntry(cond->ConditionValue1); if (!me) { LOG_ERROR("sql.sql", "Map condition has non existing map (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2) LOG_ERROR("sql.sql", "Map condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Map condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_SPELL: { if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1)) { LOG_ERROR("sql.sql", "Spell condition has non existing spell (Id: %d), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2) LOG_ERROR("sql.sql", "Spell condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Spell condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_LEVEL: { if (cond->ConditionValue2 >= COMP_TYPE_MAX) { LOG_ERROR("sql.sql", "Level condition has invalid option (%u), skipped", cond->ConditionValue2); return false; } if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Level condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_DRUNKENSTATE: { if (cond->ConditionValue1 > DRUNKEN_SMASHED) { LOG_ERROR("sql.sql", "DrunkState condition has invalid state (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2) { LOG_ERROR("sql.sql", "DrunkState condition has useless data in value2 (%u)!", cond->ConditionValue2); return false; } if (cond->ConditionValue3) LOG_ERROR("sql.sql", "DrunkState condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_NEAR_CREATURE: { if (!sObjectMgr->GetCreatureTemplate(cond->ConditionValue1)) { LOG_ERROR("sql.sql", "NearCreature condition has non existing creature template entry (%u), skipped", cond->ConditionValue1); return false; } break; } case CONDITION_NEAR_GAMEOBJECT: { if (!sObjectMgr->GetGameObjectTemplate(cond->ConditionValue1)) { LOG_ERROR("sql.sql", "NearGameObject condition has non existing gameobject template entry (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue3) LOG_ERROR("sql.sql", "NearGameObject condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_OBJECT_ENTRY_GUID: { switch (cond->ConditionValue1) { case TYPEID_UNIT: if (cond->ConditionValue2 && !sObjectMgr->GetCreatureTemplate(cond->ConditionValue2)) { LOG_ERROR("sql.sql", "ObjectEntryGuid condition has non existing creature template entry (%u), skipped", cond->ConditionValue2); return false; } if (cond->ConditionValue3 > 1) { if (CreatureData const* creatureData = sObjectMgr->GetCreatureData(cond->ConditionValue3)) { if (cond->ConditionValue2 && creatureData->id != cond->ConditionValue2) { LOG_ERROR("sql.sql", "ObjectEntryGuid condition has guid %u set but does not match creature entry (%u), skipped", cond->ConditionValue3, cond->ConditionValue2); return false; } } else { LOG_ERROR("sql.sql", "ObjectEntryGuid condition has non existing creature guid (%u), skipped", cond->ConditionValue3); return false; } } break; case TYPEID_GAMEOBJECT: if (cond->ConditionValue2 && !sObjectMgr->GetGameObjectTemplate(cond->ConditionValue2)) { LOG_ERROR("sql.sql", "ObjectEntryGuid condition has non existing gameobject template entry (%u), skipped", cond->ConditionValue2); return false; } if (cond->ConditionValue3) { if (GameObjectData const* goData = sObjectMgr->GetGOData(cond->ConditionValue3)) { if (cond->ConditionValue2 && goData->id != cond->ConditionValue2) { LOG_ERROR("sql.sql", "ObjectEntryGuid condition has guid %u set but does not match gameobject entry (%u), skipped", cond->ConditionValue3, cond->ConditionValue2); return false; } } else { LOG_ERROR("sql.sql", "ObjectEntryGuid condition has non existing gameobject guid (%u), skipped", cond->ConditionValue3); return false; } } break; case TYPEID_PLAYER: case TYPEID_CORPSE: if (cond->ConditionValue2) LOG_ERROR("sql.sql", "ObjectEntryGuid condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "ObjectEntryGuid condition has useless data in value3 (%u)!", cond->ConditionValue3); break; default: LOG_ERROR("sql.sql", "ObjectEntryGuid condition has wrong typeid set (%u), skipped", cond->ConditionValue1); return false; } break; } case CONDITION_TYPE_MASK: { if (!cond->ConditionValue1 || (cond->ConditionValue1 & ~(TYPEMASK_UNIT | TYPEMASK_PLAYER | TYPEMASK_GAMEOBJECT | TYPEMASK_CORPSE))) { LOG_ERROR("sql.sql", "TypeMask condition has invalid typemask set (%u), skipped", cond->ConditionValue2); return false; } if (cond->ConditionValue2) LOG_ERROR("sql.sql", "TypeMask condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "TypeMask condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_RELATION_TO: { if (cond->ConditionValue1 >= cond->GetMaxAvailableConditionTargets()) { LOG_ERROR("sql.sql", "RelationTo condition has invalid ConditionValue1(ConditionTarget selection) (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue1 == cond->ConditionTarget) { LOG_ERROR("sql.sql", "RelationTo condition has ConditionValue1(ConditionTarget selection) set to self (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2 >= RELATION_MAX) { LOG_ERROR("sql.sql", "RelationTo condition has invalid ConditionValue2(RelationType) (%u), skipped", cond->ConditionValue2); return false; } if (cond->ConditionValue3) LOG_ERROR("sql.sql", "RelationTo condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_REACTION_TO: { if (cond->ConditionValue1 >= cond->GetMaxAvailableConditionTargets()) { LOG_ERROR("sql.sql", "ReactionTo condition has invalid ConditionValue1(ConditionTarget selection) (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue1 == cond->ConditionTarget) { LOG_ERROR("sql.sql", "ReactionTo condition has ConditionValue1(ConditionTarget selection) set to self (%u), skipped", cond->ConditionValue1); return false; } if (!cond->ConditionValue2) { LOG_ERROR("sql.sql", "mConditionValue2 condition has invalid ConditionValue2(rankMask) (%u), skipped", cond->ConditionValue2); return false; } break; } case CONDITION_DISTANCE_TO: { if (cond->ConditionValue1 >= cond->GetMaxAvailableConditionTargets()) { LOG_ERROR("sql.sql", "DistanceTo condition has invalid ConditionValue1(ConditionTarget selection) (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue1 == cond->ConditionTarget) { LOG_ERROR("sql.sql", "DistanceTo condition has ConditionValue1(ConditionTarget selection) set to self (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue3 >= COMP_TYPE_MAX) { LOG_ERROR("sql.sql", "DistanceTo condition has invalid ComparisionType (%u), skipped", cond->ConditionValue3); return false; } break; } case CONDITION_ALIVE: { if (cond->ConditionValue1) LOG_ERROR("sql.sql", "Alive condition has useless data in value1 (%u)!", cond->ConditionValue1); if (cond->ConditionValue2) LOG_ERROR("sql.sql", "Alive condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Alive condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_HP_VAL: { if (cond->ConditionValue2 >= COMP_TYPE_MAX) { LOG_ERROR("sql.sql", "HpVal condition has invalid ComparisionType (%u), skipped", cond->ConditionValue2); return false; } if (cond->ConditionValue3) LOG_ERROR("sql.sql", "HpVal condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_HP_PCT: { if (cond->ConditionValue1 > 100) { LOG_ERROR("sql.sql", "HpPct condition has too big percent value (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue2 >= COMP_TYPE_MAX) { LOG_ERROR("sql.sql", "HpPct condition has invalid ComparisionType (%u), skipped", cond->ConditionValue2); return false; } if (cond->ConditionValue3) LOG_ERROR("sql.sql", "HpPct condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_AREAID: case CONDITION_INSTANCE_INFO: break; case CONDITION_WORLD_STATE: { if (!sWorld->getWorldState(cond->ConditionValue1)) { LOG_ERROR("sql.sql", "World state condition has non existing world state in value1 (%u), skipped", cond->ConditionValue1); return false; } if (cond->ConditionValue3) LOG_ERROR("sql.sql", "World state condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_PHASEMASK: { if (cond->ConditionValue2) LOG_ERROR("sql.sql", "Phasemask condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) LOG_ERROR("sql.sql", "Phasemask condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_TITLE: { CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(cond->ConditionValue1); if (!titleEntry) { LOG_ERROR("sql.sql", "Title condition has non existing title in value1 (%u), skipped", cond->ConditionValue1); return false; } break; } case CONDITION_SPAWNMASK: { if (cond->ConditionValue1 > SPAWNMASK_RAID_ALL) { LOG_ERROR("condition", "SpawnMask condition has non existing SpawnMask in value1 (%u), skipped", cond->ConditionValue1); return false; } break; } case CONDITION_UNIT_STATE: { if (!(cond->ConditionValue1 & UNIT_STATE_ALL_STATE_SUPPORTED)) { LOG_ERROR("condition", "UnitState condition has non existing UnitState in value1 (%u), skipped", cond->ConditionValue1); return false; } break; } case CONDITION_CREATURE_TYPE: { if (!cond->ConditionValue1 || cond->ConditionValue1 > CREATURE_TYPE_GAS_CLOUD) { LOG_ERROR("condition", "CreatureType condition has non existing CreatureType in value1 (%u), skipped", cond->ConditionValue1); return false; } break; } case CONDITION_REALM_ACHIEVEMENT: { AchievementEntry const* achievement = sAchievementStore.LookupEntry(cond->ConditionValue1); if (!achievement) { LOG_ERROR("condition", "CONDITION_REALM_ACHIEVEMENT has non existing realm first achivement id (%u), skipped.", cond->ConditionValue1); return false; } break; } case CONDITION_IN_WATER: { break; } case CONDITION_QUEST_OBJECTIVE_PROGRESS: { const Quest* quest = sObjectMgr->GetQuestTemplate(cond->ConditionValue1); if (!quest) { LOG_ERROR("sql.sql", "CONDITION_QUEST_OBJECTIVE_PROGRESS points to non-existing quest (%u), skipped.", cond->ConditionValue1); return false; } if (cond->ConditionValue2 > 3) { LOG_ERROR("sql.sql", "CONDITION_QUEST_OBJECTIVE_PROGRESS has out-of-range quest objective index specified (%u), it must be a number between 0 and 3. skipped.", cond->ConditionValue2); return false; } if (quest->RequiredNpcOrGo[cond->ConditionValue2] == 0) { LOG_ERROR("sql.sql", "CONDITION_QUEST_OBJECTIVE_PROGRESS has quest objective %u for quest %u, but the field RequiredNPCOrGo%u is 0, skipped.", cond->ConditionValue2, cond->ConditionValue1, cond->ConditionValue2); return false; } if (cond->ConditionValue3 > quest->RequiredNpcOrGoCount[cond->ConditionValue2]) { LOG_ERROR("sql.sql", "CONDITION_QUEST_OBJECTIVE_PROGRESS has quest objective count %u in value3, but quest %u has a maximum objective count of %u in RequiredNPCOrGOCount%u, skipped.", cond->ConditionValue3, cond->ConditionValue2, quest->RequiredNpcOrGoCount[cond->ConditionValue2], cond->ConditionValue2); return false; } break; } case CONDITION_HAS_AURA_TYPE: { if (cond->ConditionValue1 == SPELL_AURA_NONE || cond->ConditionValue1 >= TOTAL_AURAS) { LOG_ERROR("sql.sql", "Has Aura Effect condition has non existing aura (%u), skipped", cond->ConditionValue1); return false; } break; } default: break; } return true; } void ConditionMgr::Clean() { for (ConditionReferenceContainer::iterator itr = ConditionReferenceStore.begin(); itr != ConditionReferenceStore.end(); ++itr) { for (ConditionList::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it) delete *it; itr->second.clear(); } ConditionReferenceStore.clear(); for (ConditionContainer::iterator itr = ConditionStore.begin(); itr != ConditionStore.end(); ++itr) { for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) { for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i) delete *i; it->second.clear(); } itr->second.clear(); } ConditionStore.clear(); for (CreatureSpellConditionContainer::iterator itr = VehicleSpellConditionStore.begin(); itr != VehicleSpellConditionStore.end(); ++itr) { for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) { for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i) delete *i; it->second.clear(); } itr->second.clear(); } VehicleSpellConditionStore.clear(); for (SmartEventConditionContainer::iterator itr = SmartEventConditionStore.begin(); itr != SmartEventConditionStore.end(); ++itr) { for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) { for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i) delete *i; it->second.clear(); } itr->second.clear(); } SmartEventConditionStore.clear(); for (CreatureSpellConditionContainer::iterator itr = SpellClickEventConditionStore.begin(); itr != SpellClickEventConditionStore.end(); ++itr) { for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) { for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i) delete *i; it->second.clear(); } itr->second.clear(); } SpellClickEventConditionStore.clear(); for (NpcVendorConditionContainer::iterator itr = NpcVendorConditionContainerStore.begin(); itr != NpcVendorConditionContainerStore.end(); ++itr) { for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) { for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i) delete *i; it->second.clear(); } itr->second.clear(); } NpcVendorConditionContainerStore.clear(); // this is a BIG hack, feel free to fix it if you can figure out the ConditionMgr ;) for (std::list::const_iterator itr = AllocatedMemoryStore.begin(); itr != AllocatedMemoryStore.end(); ++itr) delete *itr; AllocatedMemoryStore.clear(); }